killbill-aplcache
Changes
account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountCreationEvent.java 13(+13 -0)
account/src/main/resources/org/killbill/billing/account/migration/V20160822115745__account_notes.sql 2(+2 -0)
account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java 3(+2 -1)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java 3(+2 -1)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java 3(+2 -1)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationParentInvoice.java 3(+2 -1)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithCatalogUpdate.java 136(+126 -10)
entitlement/src/main/java/org/killbill/billing/entitlement/logging/EntitlementLoggingHelper.java 20(+13 -7)
entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java 7(+4 -3)
entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java 7(+4 -3)
jaxrs/pom.xml 4(+4 -0)
junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java 8(+1 -7)
pom.xml 2(+1 -1)
subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java 18(+8 -10)
subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java 40(+14 -26)
subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java 2(+1 -1)
subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java 13(+7 -6)
subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java 54(+19 -35)
subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java 5(+3 -2)
subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiAddOn.java 4(+2 -2)
subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiChangePlan.java 21(+11 -10)
Details
diff --git a/account/src/main/java/org/killbill/billing/account/api/DefaultAccount.java b/account/src/main/java/org/killbill/billing/account/api/DefaultAccount.java
index 637907d..0fcf194 100644
--- a/account/src/main/java/org/killbill/billing/account/api/DefaultAccount.java
+++ b/account/src/main/java/org/killbill/billing/account/api/DefaultAccount.java
@@ -52,6 +52,7 @@ public class DefaultAccount extends EntityBase implements Account {
private final String country;
private final String postalCode;
private final String phone;
+ private final String notes;
private final Boolean isMigrated;
private final Boolean isNotifiedForInvoices;
@@ -82,6 +83,7 @@ public class DefaultAccount extends EntityBase implements Account {
data.getCountry(),
data.getPostalCode(),
data.getPhone(),
+ data.getNotes(),
data.isMigrated(),
data.isNotifiedForInvoices());
}
@@ -94,7 +96,7 @@ public class DefaultAccount extends EntityBase implements Account {
final DateTimeZone timeZone, final String locale,
final String address1, final String address2, final String companyName,
final String city, final String stateOrProvince, final String country,
- final String postalCode, final String phone,
+ final String postalCode, final String phone, final String notes,
final Boolean isMigrated, final Boolean isNotifiedForInvoices) {
this(id,
null,
@@ -118,6 +120,7 @@ public class DefaultAccount extends EntityBase implements Account {
country,
postalCode,
phone,
+ notes,
isMigrated,
isNotifiedForInvoices);
}
@@ -130,7 +133,7 @@ public class DefaultAccount extends EntityBase implements Account {
final DateTimeZone timeZone, final String locale,
final String address1, final String address2, final String companyName,
final String city, final String stateOrProvince, final String country,
- final String postalCode, final String phone,
+ final String postalCode, final String phone, final String notes,
final Boolean isMigrated, final Boolean isNotifiedForInvoices) {
super(id, createdDate, updatedDate);
this.externalKey = externalKey;
@@ -152,6 +155,7 @@ public class DefaultAccount extends EntityBase implements Account {
this.postalCode = postalCode;
this.country = country;
this.phone = phone;
+ this.notes = notes;
this.isMigrated = isMigrated;
this.isNotifiedForInvoices = isNotifiedForInvoices;
}
@@ -179,6 +183,7 @@ public class DefaultAccount extends EntityBase implements Account {
accountModelDao.getCountry(),
accountModelDao.getPostalCode(),
accountModelDao.getPhone(),
+ accountModelDao.getNotes(),
accountModelDao.getMigrated(),
accountModelDao.getIsNotifiedForInvoices());
}
@@ -290,6 +295,11 @@ public class DefaultAccount extends EntityBase implements Account {
}
@Override
+ public String getNotes() {
+ return notes;
+ }
+
+ @Override
public MutableAccountData toMutableAccountData() {
return new DefaultMutableAccountData(this);
}
@@ -350,6 +360,7 @@ public class DefaultAccount extends EntityBase implements Account {
accountData.setCountry(country != null ? country : currentAccount.getCountry());
accountData.setPostalCode(postalCode != null ? postalCode : currentAccount.getPostalCode());
accountData.setPhone(phone != null ? phone : currentAccount.getPhone());
+ accountData.setNotes(notes != null ? notes : currentAccount.getNotes());
accountData.setParentAccountId(parentAccountId != null ? parentAccountId : currentAccount.getParentAccountId());
accountData.setIsPaymentDelegatedToParent(isPaymentDelegatedToParent != null ? isPaymentDelegatedToParent : currentAccount.isPaymentDelegatedToParent());
final Boolean isMigrated = this.isMigrated != null ? this.isMigrated : currentAccount.isMigrated();
@@ -399,6 +410,7 @@ public class DefaultAccount extends EntityBase implements Account {
", stateOrProvince=" + stateOrProvince +
", postalCode=" + postalCode +
", country=" + country +
+ ", notes=" + notes +
"]";
}
@@ -479,6 +491,9 @@ public class DefaultAccount extends EntityBase implements Account {
if (timeZone != null ? !timeZone.equals(that.timeZone) : that.timeZone != null) {
return false;
}
+ if (notes != null ? !notes.equals(that.notes) : that.notes != null) {
+ return false;
+ }
return true;
}
@@ -505,6 +520,7 @@ public class DefaultAccount extends EntityBase implements Account {
result = 31 * result + (country != null ? country.hashCode() : 0);
result = 31 * result + (postalCode != null ? postalCode.hashCode() : 0);
result = 31 * result + (phone != null ? phone.hashCode() : 0);
+ result = 31 * result + (notes != null ? notes.hashCode() : 0);
result = 31 * result + (isMigrated != null ? isMigrated.hashCode() : 0);
result = 31 * result + (isNotifiedForInvoices != null ? isNotifiedForInvoices.hashCode() : 0);
return result;
diff --git a/account/src/main/java/org/killbill/billing/account/api/DefaultMutableAccountData.java b/account/src/main/java/org/killbill/billing/account/api/DefaultMutableAccountData.java
index 63de386..1f1c6fc 100644
--- a/account/src/main/java/org/killbill/billing/account/api/DefaultMutableAccountData.java
+++ b/account/src/main/java/org/killbill/billing/account/api/DefaultMutableAccountData.java
@@ -47,6 +47,7 @@ public class DefaultMutableAccountData implements MutableAccountData {
private String country;
private String postalCode;
private String phone;
+ private String notes;
private Boolean isMigrated;
private Boolean isNotifiedForInvoices;
@@ -57,7 +58,7 @@ public class DefaultMutableAccountData implements MutableAccountData {
final String locale, final String address1, final String address2,
final String companyName, final String city, final String stateOrProvince,
final String country, final String postalCode, final String phone,
- final boolean isMigrated, final boolean isNotifiedForInvoices) {
+ final String notes, final boolean isMigrated, final boolean isNotifiedForInvoices) {
this.externalKey = externalKey;
this.email = email;
this.name = name;
@@ -77,6 +78,7 @@ public class DefaultMutableAccountData implements MutableAccountData {
this.country = country;
this.postalCode = postalCode;
this.phone = phone;
+ this.notes = notes;
this.isMigrated = isMigrated;
this.isNotifiedForInvoices = isNotifiedForInvoices;
}
@@ -101,6 +103,7 @@ public class DefaultMutableAccountData implements MutableAccountData {
this.country = accountData.getCountry();
this.postalCode = accountData.getPostalCode();
this.phone = accountData.getPhone();
+ this.notes = accountData.getNotes();
this.isMigrated = accountData.isMigrated();
this.isNotifiedForInvoices = accountData.isNotifiedForInvoices();
}
@@ -276,6 +279,16 @@ public class DefaultMutableAccountData implements MutableAccountData {
}
@Override
+ public String getNotes() {
+ return notes;
+ }
+
+ @Override
+ public void setNotes(final String notes) {
+ this.notes = notes;
+ }
+
+ @Override
public Boolean isMigrated() {
return isMigrated;
}
diff --git a/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountCreationEvent.java b/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountCreationEvent.java
index b4189b0..1ddfd15 100644
--- a/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountCreationEvent.java
+++ b/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountCreationEvent.java
@@ -123,6 +123,7 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
private final String postalCode;
private final String country;
private final String phone;
+ private final String notes;
private final Boolean isMigrated;
private final Boolean isNotifiedForInvoices;
@@ -146,6 +147,7 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
d.getPostalCode(),
d.getCountry(),
d.getPhone(),
+ d.getNotes(),
d.getMigrated(),
d.getIsNotifiedForInvoices());
}
@@ -170,6 +172,7 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
@JsonProperty("postalCode") final String postalCode,
@JsonProperty("country") final String country,
@JsonProperty("phone") final String phone,
+ @JsonProperty("notes") final String notes,
@JsonProperty("isMigrated") final Boolean isMigrated,
@JsonProperty("isNotifiedForInvoices") final Boolean isNotifiedForInvoices) {
this.externalKey = externalKey;
@@ -191,6 +194,7 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
this.postalCode = postalCode;
this.country = country;
this.phone = phone;
+ this.notes = notes;
this.isMigrated = isMigrated;
this.isNotifiedForInvoices = isNotifiedForInvoices;
}
@@ -301,6 +305,11 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
}
@Override
+ public String getNotes() {
+ return notes;
+ }
+
+ @Override
public UUID getPaymentMethodId() {
return paymentMethodId;
}
@@ -396,6 +405,9 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
if (phone != null ? !phone.equals(that.phone) : that.phone != null) {
return false;
}
+ if (notes != null ? !notes.equals(that.notes) : that.notes != null) {
+ return false;
+ }
if (postalCode != null ? !postalCode.equals(that.postalCode) : that.postalCode != null) {
return false;
}
@@ -430,6 +442,7 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
result = 31 * result + (postalCode != null ? postalCode.hashCode() : 0);
result = 31 * result + (country != null ? country.hashCode() : 0);
result = 31 * result + (phone != null ? phone.hashCode() : 0);
+ result = 31 * result + (notes != null ? notes.hashCode() : 0);
result = 31 * result + (isMigrated != null ? isMigrated.hashCode() : 0);
result = 31 * result + (isNotifiedForInvoices != null ? isNotifiedForInvoices.hashCode() : 0);
return result;
diff --git a/account/src/main/java/org/killbill/billing/account/dao/AccountModelDao.java b/account/src/main/java/org/killbill/billing/account/dao/AccountModelDao.java
index 7ddf6cc..91fe1ce 100644
--- a/account/src/main/java/org/killbill/billing/account/dao/AccountModelDao.java
+++ b/account/src/main/java/org/killbill/billing/account/dao/AccountModelDao.java
@@ -57,6 +57,7 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
private String country;
private String postalCode;
private String phone;
+ private String notes;
private Boolean migrated;
private Boolean isNotifiedForInvoices;
@@ -69,7 +70,7 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
final int billingCycleDayLocal, final UUID paymentMethodId, final DateTimeZone timeZone,
final String locale, final String address1, final String address2, final String companyName,
final String city, final String stateOrProvince, final String country, final String postalCode,
- final String phone, final Boolean migrated, final Boolean notifiedForInvoices) {
+ final String phone, final String notes, final Boolean migrated, final Boolean notifiedForInvoices) {
super(id, createdDate, updatedDate);
this.externalKey = MoreObjects.firstNonNull(externalKey, id.toString());
this.email = email;
@@ -90,6 +91,7 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
this.country = country;
this.postalCode = postalCode;
this.phone = phone;
+ this.notes = notes;
this.migrated = migrated;
this.isNotifiedForInvoices = notifiedForInvoices;
}
@@ -117,6 +119,7 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
account.getCountry(),
account.getPostalCode(),
account.getPhone(),
+ account.getNotes(),
account.isMigrated(),
// There is a NOT NULL constraint on the is_notified_for_invoices column
MoreObjects.firstNonNull(account.isNotifiedForInvoices(), false));
@@ -282,6 +285,14 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
this.phone = phone;
}
+ public String getNotes() {
+ return notes;
+ }
+
+ public void setNotes(final String notes) {
+ this.notes = notes;
+ }
+
public Boolean getMigrated() {
return migrated;
}
@@ -323,6 +334,7 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
sb.append(", country='").append(country).append('\'');
sb.append(", postalCode='").append(postalCode).append('\'');
sb.append(", phone='").append(phone).append('\'');
+ sb.append(", notes='").append(notes).append('\'');
sb.append(", migrated=").append(migrated);
sb.append(", isNotifiedForInvoices=").append(isNotifiedForInvoices);
sb.append('}');
@@ -397,6 +409,9 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
if (phone != null ? !phone.equals(that.phone) : that.phone != null) {
return false;
}
+ if (notes != null ? !notes.equals(that.notes) : that.notes != null) {
+ return false;
+ }
if (postalCode != null ? !postalCode.equals(that.postalCode) : that.postalCode != null) {
return false;
}
@@ -432,6 +447,7 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
result = 31 * result + (country != null ? country.hashCode() : 0);
result = 31 * result + (postalCode != null ? postalCode.hashCode() : 0);
result = 31 * result + (phone != null ? phone.hashCode() : 0);
+ result = 31 * result + (notes != null ? notes.hashCode() : 0);
result = 31 * result + (migrated != null ? migrated.hashCode() : 0);
result = 31 * result + (isNotifiedForInvoices != null ? isNotifiedForInvoices.hashCode() : 0);
return result;
diff --git a/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg b/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg
index a2a86bb..d48a16b 100644
--- a/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg
+++ b/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg
@@ -24,6 +24,7 @@ tableFields(prefix) ::= <<
, <prefix>country
, <prefix>postal_code
, <prefix>phone
+, <prefix>notes
, <prefix>migrated
, <prefix>is_notified_for_invoices
, <prefix>created_by
@@ -52,6 +53,7 @@ tableValues() ::= <<
, :country
, :postalCode
, :phone
+, :notes
, :migrated
, :isNotifiedForInvoices
, :createdBy
@@ -70,7 +72,7 @@ update() ::= <<
currency = :currency, billing_cycle_day_local = :billingCycleDayLocal,
payment_method_id = :paymentMethodId, time_zone = :timeZone, locale = :locale,
address1 = :address1, address2 = :address2, company_name = :companyName, city = :city, state_or_province = :stateOrProvince,
- country = :country, postal_code = :postalCode, phone = :phone,
+ country = :country, postal_code = :postalCode, phone = :phone, notes = :notes,
is_notified_for_invoices = :isNotifiedForInvoices, updated_date = :updatedDate, updated_by = :updatedBy
WHERE id = :id <AND_CHECK_TENANT()>;
>>
diff --git a/account/src/main/resources/org/killbill/billing/account/ddl.sql b/account/src/main/resources/org/killbill/billing/account/ddl.sql
index 9699c67..b025697 100644
--- a/account/src/main/resources/org/killbill/billing/account/ddl.sql
+++ b/account/src/main/resources/org/killbill/billing/account/ddl.sql
@@ -23,6 +23,7 @@ CREATE TABLE accounts (
country varchar(50) DEFAULT NULL,
postal_code varchar(16) DEFAULT NULL,
phone varchar(25) DEFAULT NULL,
+ notes varchar(4096) DEFAULT NULL,
migrated boolean default false,
is_notified_for_invoices boolean NOT NULL,
created_date datetime NOT NULL,
@@ -60,6 +61,7 @@ CREATE TABLE account_history (
country varchar(50) DEFAULT NULL,
postal_code varchar(16) DEFAULT NULL,
phone varchar(25) DEFAULT NULL,
+ notes varchar(4096) DEFAULT NULL,
migrated boolean default false,
is_notified_for_invoices boolean NOT NULL,
change_type varchar(6) NOT NULL,
diff --git a/account/src/main/resources/org/killbill/billing/account/migration/V20160822115745__account_notes.sql b/account/src/main/resources/org/killbill/billing/account/migration/V20160822115745__account_notes.sql
new file mode 100644
index 0000000..3941016
--- /dev/null
+++ b/account/src/main/resources/org/killbill/billing/account/migration/V20160822115745__account_notes.sql
@@ -0,0 +1,2 @@
+alter table accounts add column notes varchar(4096) DEFAULT NULL after phone;
+alter table account_history add column notes varchar(4096) DEFAULT NULL after phone;
\ No newline at end of file
diff --git a/account/src/test/java/org/killbill/billing/account/AccountTestUtils.java b/account/src/test/java/org/killbill/billing/account/AccountTestUtils.java
index 61b1127..7934e12 100644
--- a/account/src/test/java/org/killbill/billing/account/AccountTestUtils.java
+++ b/account/src/test/java/org/killbill/billing/account/AccountTestUtils.java
@@ -101,10 +101,11 @@ public abstract class AccountTestUtils {
final String stateOrProvince = UUID.randomUUID().toString();
final String country = Locale.GERMANY.getCountry();
final String postalCode = UUID.randomUUID().toString().substring(0, 4);
+ final String notes = UUID.randomUUID().toString();
return new DefaultMutableAccountData(externalKey, email, name, firstNameLength, currency, null, false,
billCycleDayLocal, paymentMethodId, timeZone,
locale, address1, address2, companyName, city, stateOrProvince,
- country, postalCode, phone, false, true);
+ country, postalCode, phone, notes, false, true);
}
}
diff --git a/account/src/test/java/org/killbill/billing/account/api/TestDefaultAccount.java b/account/src/test/java/org/killbill/billing/account/api/TestDefaultAccount.java
index 1d8c654..f88b9e0 100644
--- a/account/src/test/java/org/killbill/billing/account/api/TestDefaultAccount.java
+++ b/account/src/test/java/org/killbill/billing/account/api/TestDefaultAccount.java
@@ -151,6 +151,7 @@ public class TestDefaultAccount extends AccountTestSuiteNoDB {
Assert.assertEquals(finalAccount.getCountry(), delegateAccount.getCountry());
Assert.assertEquals(finalAccount.getPostalCode(), delegateAccount.getPostalCode());
Assert.assertEquals(finalAccount.getPhone(), delegateAccount.getPhone());
+ Assert.assertEquals(finalAccount.getNotes(), delegateAccount.getNotes());
Assert.assertEquals(finalAccount.isMigrated(), delegateAccount.isMigrated());
Assert.assertEquals(finalAccount.isNotifiedForInvoices(), delegateAccount.isNotifiedForInvoices());
}
diff --git a/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApi.java b/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApi.java
index 05980b0..78df7a1 100644
--- a/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApi.java
+++ b/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApi.java
@@ -73,7 +73,7 @@ public class TestDefaultAccountUserApi extends AccountTestSuiteWithEmbeddedDB {
// Update the address and leave other fields null
final MutableAccountData mutableAccountData = new DefaultMutableAccountData(null, null, null, 0, null, null, false, 0, null,
null, null, null, null, null, null,
- null, null, null, null, false, false);
+ null, null, null, null, null, false, false);
final String newAddress1 = UUID.randomUUID().toString();
mutableAccountData.setAddress1(newAddress1);
diff --git a/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java b/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java
index 43bcb2f..793d689 100644
--- a/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java
+++ b/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java
@@ -76,11 +76,12 @@ public class TestDefaultAccountUserApiWithMocks extends AccountTestSuiteNoDB {
final String country = UUID.randomUUID().toString();
final String postalCode = UUID.randomUUID().toString();
final String phone = UUID.randomUUID().toString();
+ final String notes = UUID.randomUUID().toString();
final Boolean isMigrated = true;
final Boolean isNotifiedForInvoices = false;
final AccountData data = new DefaultAccount(id, externalKey, email, name, firstNameLength, currency, null, false, billCycleDay,
paymentMethodId, timeZone, locale, address1, address2, companyName,
- city, stateOrProvince, country, postalCode, phone, isMigrated, isNotifiedForInvoices);
+ city, stateOrProvince, country, postalCode, phone, notes, isMigrated, isNotifiedForInvoices);
accountUserApi.createAccount(data, callContext);
diff --git a/account/src/test/java/org/killbill/billing/account/api/user/TestEventJson.java b/account/src/test/java/org/killbill/billing/account/api/user/TestEventJson.java
index 26d49dc..c5176da 100644
--- a/account/src/test/java/org/killbill/billing/account/api/user/TestEventJson.java
+++ b/account/src/test/java/org/killbill/billing/account/api/user/TestEventJson.java
@@ -51,7 +51,7 @@ public class TestEventJson extends AccountTestSuiteNoDB {
@Test(groups = "fast", description="Test Account event serialization")
public void testAccountCreationEvent() throws Exception {
final DefaultAccountData data = new DefaultAccountData("dsfdsf", "bobo", 3, "bobo@yahoo.com", 12, "USD", null, false, UUID.randomUUID(),
- "UTC", "US", "21 avenue", "", "Gling", "San Franciso", "CA", "94110", "USA", "4126789887", false, false);
+ "UTC", "US", "21 avenue", "", "Gling", "San Franciso", "CA", "94110", "USA", "4126789887", "notes", false, false);
final DefaultAccountCreationEvent e = new DefaultAccountCreationEvent(data, UUID.randomUUID(), 1L, 2L, null);
final String json = mapper.writeValueAsString(e);
diff --git a/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java b/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
index 70fbbba..237b8f5 100644
--- a/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
+++ b/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
@@ -65,7 +65,7 @@ public class TestAccountDao extends AccountTestSuiteWithEmbeddedDB {
final AccountData accountData = new DefaultMutableAccountData(null, email, name, 0, null, null, false,
0, null, null, null, null,
null, null, null, null, null,
- null, null, false, true);
+ null, null, null, false, true);
final AccountModelDao account = new AccountModelDao(UUID.randomUUID(), accountData);
accountDao.create(account, internalCallContext);
diff --git a/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBase.java b/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBase.java
index 5382bba..5cda4c4 100644
--- a/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBase.java
+++ b/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBase.java
@@ -26,6 +26,7 @@ import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhase;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.PriceList;
import org.killbill.billing.catalog.api.Product;
import org.killbill.billing.catalog.api.ProductCategory;
@@ -52,15 +53,15 @@ public interface SubscriptionBase extends Entity, Blockable {
throws SubscriptionBaseApiException;
// Return the effective date of the change
- public DateTime changePlan(final String productName, final BillingPeriod term, final String priceList, final List<PlanPhasePriceOverride> overrides, final CallContext context)
+ public DateTime changePlan(final PlanSpecifier spec, final List<PlanPhasePriceOverride> overrides, final CallContext context)
throws SubscriptionBaseApiException;
// Return the effective date of the change
- public DateTime changePlanWithDate(final String productName, final BillingPeriod term, final String priceList, final List<PlanPhasePriceOverride> overrides, final DateTime requestedDate, final CallContext context)
+ public DateTime changePlanWithDate(final PlanSpecifier spec, final List<PlanPhasePriceOverride> overrides, final DateTime requestedDate, final CallContext context)
throws SubscriptionBaseApiException;
// Return the effective date of the change
- public DateTime changePlanWithPolicy(final String productName, final BillingPeriod term, final String priceList, final List<PlanPhasePriceOverride> overrides,
+ public DateTime changePlanWithPolicy(final PlanSpecifier spec, final List<PlanPhasePriceOverride> overrides,
final BillingActionPolicy policy, final CallContext context)
throws SubscriptionBaseApiException;
diff --git a/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java b/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java
index 2556f87..234f9f3 100644
--- a/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java
+++ b/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java
@@ -34,6 +34,7 @@ import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.entitlement.api.EntitlementAOStatusDryRun;
import org.killbill.billing.entitlement.api.EntitlementSpecifier;
import org.killbill.billing.events.EffectiveSubscriptionInternalEvent;
@@ -88,8 +89,7 @@ public interface SubscriptionBaseInternalApi {
public List<EffectiveSubscriptionInternalEvent> getBillingTransitions(SubscriptionBase subscription, InternalTenantContext context);
- public DateTime getDryRunChangePlanEffectiveDate(SubscriptionBase subscription, String productName, BillingPeriod term,
- String priceList, DateTime requestedDate, BillingActionPolicy policy, InternalTenantContext context) throws SubscriptionBaseApiException;
+ public DateTime getDryRunChangePlanEffectiveDate(SubscriptionBase subscription, PlanSpecifier spec, DateTime requestedDate, BillingActionPolicy policy, InternalTenantContext context) throws SubscriptionBaseApiException;
public List<EntitlementAOStatusDryRun> getDryRunChangePlanStatus(UUID subscriptionId, @Nullable String baseProductName,
DateTime requestedDate, InternalTenantContext context) throws SubscriptionBaseApiException;
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
index 9f64e78..beb7246 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
@@ -34,6 +34,7 @@ import org.killbill.billing.beatrix.integration.BeatrixIntegrationModule;
import org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.entitlement.api.BlockingApiException;
@@ -995,7 +996,7 @@ public class TestOverdueIntegration extends TestOverdueBase {
private void checkChangePlanWithOverdueState(final Entitlement entitlement, final boolean shouldFail, final boolean expectedPayment) {
if (shouldFail) {
try {
- entitlement.changePlan("Pistol", term, PriceListSet.DEFAULT_PRICELIST_NAME, null, ImmutableList.<PluginProperty>of(), callContext);
+ entitlement.changePlan(new PlanSpecifier("Pistol", term, PriceListSet.DEFAULT_PRICELIST_NAME), null, ImmutableList.<PluginProperty>of(), callContext);
} catch (EntitlementApiException e) {
assertTrue(e.getCause() instanceof BlockingApiException || e.getCode() == ErrorCode.SUB_CHANGE_NON_ACTIVE.getCode(),
String.format("Cause is %s, message is %s", e.getCause(), e.getMessage()));
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
index 919890e..f893c7e 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
@@ -20,6 +20,7 @@ package org.killbill.billing.beatrix.integration;
import java.util.List;
import org.joda.time.LocalDate;
+import org.killbill.billing.ErrorCode;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.api.TestApiListener.NextEvent;
import org.killbill.billing.catalog.api.BillingPeriod;
@@ -84,7 +85,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey2", null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
fail(); // force to fail is there is not an exception
} catch (final EntitlementApiException e) {
- assertTrue(e.getLocalizedMessage().startsWith("Could not find a plan matching: (product: 'Pistol', billing period: 'MONTHLY'"));
+ assertEquals(e.getCode(), ErrorCode.CAT_PLAN_NOT_FOUND.getCode());
}
// Move out a month and verify 'Pistol' plan continue working as expected.
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index 59a72b9..bab10ab 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -53,6 +53,7 @@ import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.catalog.api.PhaseType;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.entitlement.api.DefaultEntitlement;
@@ -665,9 +666,9 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
// Need to fetch again to get latest CTD updated from the system
Entitlement refreshedEntitlement = entitlementApi.getEntitlementForId(entitlement.getId(), callContext);
if (billingPolicy == null) {
- refreshedEntitlement = refreshedEntitlement.changePlan(productName, billingPeriod, priceList, null, ImmutableList.<PluginProperty>of(), callContext);
+ refreshedEntitlement = refreshedEntitlement.changePlan(new PlanSpecifier(productName, billingPeriod, priceList), null, ImmutableList.<PluginProperty>of(), callContext);
} else {
- refreshedEntitlement = refreshedEntitlement.changePlanOverrideBillingPolicy(productName, billingPeriod, priceList, null, null, billingPolicy, ImmutableList.<PluginProperty>of(), callContext);
+ refreshedEntitlement = refreshedEntitlement.changePlanOverrideBillingPolicy(new PlanSpecifier(productName, billingPeriod, priceList), null, null, billingPolicy, ImmutableList.<PluginProperty>of(), callContext);
}
return refreshedEntitlement;
} catch (final EntitlementApiException e) {
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationParentInvoice.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationParentInvoice.java
index 7724af0..e759270 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationParentInvoice.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationParentInvoice.java
@@ -27,6 +27,7 @@ import org.killbill.billing.api.TestApiListener.NextEvent;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.entitlement.api.DefaultEntitlement;
import org.killbill.billing.invoice.api.Invoice;
@@ -173,7 +174,7 @@ public class TestIntegrationParentInvoice extends TestIntegrationBase {
// upgrade plan
busHandler.pushExpectedEvents(NextEvent.CHANGE, NextEvent.INVOICE);
- baseEntitlementChild.changePlanOverrideBillingPolicy("Shotgun", BillingPeriod.MONTHLY, baseEntitlementChild.getLastActivePriceList().getName(), null, clock.getToday(childAccount.getTimeZone()), BillingActionPolicy.IMMEDIATE, null, callContext);
+ baseEntitlementChild.changePlanOverrideBillingPolicy(new PlanSpecifier("Shotgun", BillingPeriod.MONTHLY, baseEntitlementChild.getLastActivePriceList().getName()), null, clock.getToday(childAccount.getTimeZone()), BillingActionPolicy.IMMEDIATE, null, callContext);
assertListenerStatus();
// check parent invoice. Expected to have the same invoice item with the amount updated
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithCatalogUpdate.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithCatalogUpdate.java
index 0bbd002..7e1b7b3 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithCatalogUpdate.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithCatalogUpdate.java
@@ -26,14 +26,20 @@ import javax.inject.Inject;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
+import org.killbill.billing.ErrorCode;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.account.api.AccountData;
import org.killbill.billing.api.TestApiListener.NextEvent;
import org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck;
import org.killbill.billing.callcontext.DefaultCallContext;
+import org.killbill.billing.catalog.DefaultPlanPhasePriceOverride;
import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.CatalogUserApi;
+import org.killbill.billing.catalog.api.Plan;
+import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.catalog.api.SimplePlanDescriptor;
@@ -42,6 +48,7 @@ import org.killbill.billing.catalog.api.TimeUnit;
import org.killbill.billing.catalog.api.user.DefaultSimplePlanDescriptor;
import org.killbill.billing.entitlement.api.Entitlement;
import org.killbill.billing.entitlement.api.EntitlementApiException;
+import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoiceItemType;
import org.killbill.billing.payment.api.PaymentMethodPlugin;
import org.killbill.billing.payment.api.PluginProperty;
@@ -58,6 +65,7 @@ import com.google.common.collect.ImmutableList;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
public class TestIntegrationWithCatalogUpdate extends TestIntegrationBase {
@@ -94,7 +102,7 @@ public class TestIntegrationWithCatalogUpdate extends TestIntegrationBase {
StaticCatalog catalog = catalogUserApi.getCurrentCatalog("dummy", testCallContext);
assertEquals(catalog.getCurrentPlans().length, 1);
- final Entitlement baseEntitlement = createEntitlement("Foo", BillingPeriod.MONTHLY);
+ final Entitlement baseEntitlement = createEntitlement("foo-monthly", true);
invoiceChecker.checkInvoice(account.getId(), 1, testCallContext, new ExpectedInvoiceItemCheck(new LocalDate(2016, 6, 1), new LocalDate(2016, 7, 1), InvoiceItemType.RECURRING, BigDecimal.TEN));
@@ -104,10 +112,9 @@ public class TestIntegrationWithCatalogUpdate extends TestIntegrationBase {
catalog = catalogUserApi.getCurrentCatalog("dummy", testCallContext);
assertEquals(catalog.getCurrentPlans().length, 2);
-
// Change Plan to the newly added Plan and verify correct default rules behavior (IMMEDIATE change)
busHandler.pushExpectedEvents(NextEvent.CHANGE, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
- baseEntitlement.changePlan("SuperFoo", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null, ImmutableList.<PluginProperty>of(), testCallContext);
+ baseEntitlement.changePlan(new PlanSpecifier("SuperFoo", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), null, ImmutableList.<PluginProperty>of(), testCallContext);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 2, testCallContext,
@@ -116,17 +123,126 @@ public class TestIntegrationWithCatalogUpdate extends TestIntegrationBase {
assertListenerStatus();
}
+ @Test(groups = "slow")
+ public void testWithMultiplePlansForOneProduct() throws CatalogApiException, EntitlementApiException {
+
+ // Create a per-tenant catalog with one plan
+ final SimplePlanDescriptor desc1 = new DefaultSimplePlanDescriptor("xxx-monthly", "XXX", ProductCategory.BASE, account.getCurrency(), BigDecimal.TEN, BillingPeriod.MONTHLY, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of());
+ catalogUserApi.addSimplePlan(desc1, init, testCallContext);
+ StaticCatalog catalog = catalogUserApi.getCurrentCatalog("dummy", testCallContext);
+ assertEquals(catalog.getCurrentProducts().length, 1);
+ assertEquals(catalog.getCurrentPlans().length, 1);
+
+ final Entitlement baseEntitlement1 = createEntitlement("xxx-monthly", true);
+
+ // Add a second plan for same product but with a 14 days trial
+ final SimplePlanDescriptor desc2 = new DefaultSimplePlanDescriptor("xxx-14-monthly", "XXX", ProductCategory.BASE, account.getCurrency(), BigDecimal.TEN, BillingPeriod.MONTHLY, 14, TimeUnit.DAYS, ImmutableList.<String>of());
+ catalogUserApi.addSimplePlan(desc2, init, testCallContext);
+ catalog = catalogUserApi.getCurrentCatalog("dummy", testCallContext);
+ assertEquals(catalog.getCurrentProducts().length, 1);
+ assertEquals(catalog.getCurrentPlans().length, 2);
+
+ final Entitlement baseEntitlement2 = createEntitlement("xxx-14-monthly", false);
+
+ // Add a second plan for same product but with a 30 days trial
+ final SimplePlanDescriptor desc3 = new DefaultSimplePlanDescriptor("xxx-30-monthly", "XXX", ProductCategory.BASE, account.getCurrency(), BigDecimal.TEN, BillingPeriod.MONTHLY, 30, TimeUnit.DAYS, ImmutableList.<String>of());
+ catalogUserApi.addSimplePlan(desc3, init, testCallContext);
+ catalog = catalogUserApi.getCurrentCatalog("dummy", testCallContext);
+ assertEquals(catalog.getCurrentProducts().length, 1);
+ assertEquals(catalog.getCurrentPlans().length, 3);
- private Entitlement createEntitlement(String productName, BillingPeriod billingPeriod) throws EntitlementApiException {
- final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+ final Entitlement baseEntitlement3 = createEntitlement("xxx-30-monthly", false);
- busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
- final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), null, null, null, false, ImmutableList.<PluginProperty>of(), testCallContext);
+ // Move clock 14 days
+ busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
+ clock.addDays(14);
assertListenerStatus();
- return entitlement;
+
+ // Move clock 16 days
+ busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.NULL_INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
+ clock.addDays(16);
+ assertListenerStatus();
+ }
+
+ @Test(groups = "slow")
+ public void testError_CAT_MULTIPLE_MATCHING_PLANS_FOR_PRICELIST() throws Exception {
+
+ // Create a per-tenant catalog with one plan
+ final SimplePlanDescriptor desc1 = new DefaultSimplePlanDescriptor("zoe-monthly", "Zoe", ProductCategory.BASE, account.getCurrency(), BigDecimal.TEN, BillingPeriod.MONTHLY, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of());
+ catalogUserApi.addSimplePlan(desc1, init, testCallContext);
+ StaticCatalog catalog = catalogUserApi.getCurrentCatalog("dummy", testCallContext);
+ assertEquals(catalog.getCurrentPlans().length, 1);
+
+ final SimplePlanDescriptor desc2 = new DefaultSimplePlanDescriptor("zoe-14-monthly", "Zoe", ProductCategory.BASE, account.getCurrency(), BigDecimal.TEN, BillingPeriod.MONTHLY, 14, TimeUnit.DAYS, ImmutableList.<String>of());
+ catalogUserApi.addSimplePlan(desc2, init, testCallContext);
+ catalog = catalogUserApi.getCurrentCatalog("dummy", testCallContext);
+ assertEquals(catalog.getCurrentPlans().length, 2);
+
+ try {
+ final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Zoe", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+ entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), null, null, null, false, ImmutableList.<PluginProperty>of(), testCallContext);
+ fail("Creating entitlement should fail");
+ } catch (final EntitlementApiException e) {
+ assertEquals(e.getCode(), ErrorCode.CAT_MULTIPLE_MATCHING_PLANS_FOR_PRICELIST.getCode());
+ }
+ }
+
+ @Test(groups = "slow")
+ public void testWithPriceOverride() throws Exception {
+
+ // Create a per-tenant catalog with one plan
+ final SimplePlanDescriptor desc1 = new DefaultSimplePlanDescriptor("bar-monthly", "Bar", ProductCategory.BASE, account.getCurrency(), BigDecimal.TEN, BillingPeriod.MONTHLY, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of());
+ catalogUserApi.addSimplePlan(desc1, init, testCallContext);
+ StaticCatalog catalog = catalogUserApi.getCurrentCatalog("dummy", testCallContext);
+ assertEquals(catalog.getCurrentPlans().length, 1);
+
+ final Plan plan = catalog.getCurrentPlans()[0];
+ final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("bar-monthly", null);
+
+ final List<PlanPhasePriceOverride> overrides = new ArrayList<PlanPhasePriceOverride>();
+ overrides.add(new DefaultPlanPhasePriceOverride(plan.getFinalPhase().getName(), account.getCurrency(), null, BigDecimal.ONE));
+ final Entitlement baseEntitlement = createEntitlement(spec, overrides, true);
+
+ List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), false, testCallContext);
+ assertEquals(invoices.size(), 1);
+ assertEquals(invoices.get(0).getChargedAmount().compareTo(BigDecimal.ONE), 0);
+
+ busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
+ clock.addMonths(1);
+ assertListenerStatus();
+
+ invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), false, testCallContext);
+ assertEquals(invoices.size(), 2);
+ assertEquals(invoices.get(1).getChargedAmount().compareTo(BigDecimal.ONE), 0);
+
+ // Change plan to original (non overridden plan)
+ busHandler.pushExpectedEvents(NextEvent.CHANGE, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
+ baseEntitlement.changePlan(spec, null, ImmutableList.<PluginProperty>of(), testCallContext);
+ assertListenerStatus();
+
+ invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), false, testCallContext);
+ assertEquals(invoices.size(), 3);
+ assertEquals(invoices.get(2).getChargedAmount().compareTo(new BigDecimal("9.00")), 0); // 10 (recurring) - 1 (repair)
+
+ }
+
+ private Entitlement createEntitlement(final String planName, final boolean expectPayment) throws EntitlementApiException {
+ final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(planName, null);
+ return createEntitlement(spec, null, expectPayment);
}
+ private Entitlement createEntitlement(final PlanPhaseSpecifier spec, final List<PlanPhasePriceOverride> overrides, final boolean expectPayment) throws EntitlementApiException {
+ if (expectPayment) {
+ busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
+ } else {
+ busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
+ }
+ final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), overrides, null, null, false, ImmutableList.<PluginProperty>of(), testCallContext);
+ assertListenerStatus();
+ return entitlement;
+ }
+
private void setupTenant() throws TenantApiException {
final UUID uuid = UUID.randomUUID();
final String externalKey = uuid.toString();
@@ -136,7 +252,7 @@ public class TestIntegrationWithCatalogUpdate extends TestIntegrationBase {
tenant = tenantUserApi.createTenant(new DefaultTenant(uuid, init, init, externalKey, apiKey, apiSecret), callContext);
testCallContext = new DefaultCallContext(tenant.getId(), "tester", CallOrigin.EXTERNAL, UserType.TEST,
- "good reason", "trust me", uuid, clock);
+ "good reason", "trust me", uuid, clock);
}
private void setupAccount() throws Exception {
@@ -146,7 +262,7 @@ public class TestIntegrationWithCatalogUpdate extends TestIntegrationBase {
assertNotNull(account);
final PaymentMethodPlugin info = createPaymentMethodPlugin();
- paymentApi.addPaymentMethod(account, UUID.randomUUID().toString(), BeatrixIntegrationModule.NON_OSGI_PLUGIN_NAME, true, info, PLUGIN_PROPERTIES, testCallContext);
+ paymentApi.addPaymentMethod(account, UUID.randomUUID().toString(), BeatrixIntegrationModule.NON_OSGI_PLUGIN_NAME, true, info, PLUGIN_PROPERTIES, testCallContext);
}
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithPriceOverride.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithPriceOverride.java
index 230187b..0869e63 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithPriceOverride.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithPriceOverride.java
@@ -32,6 +32,7 @@ import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.entitlement.api.DefaultEntitlement;
@@ -120,7 +121,7 @@ public class TestWithPriceOverride extends TestIntegrationBase {
overrides.add(new DefaultPlanPhasePriceOverride("shotgun-monthly-evergreen", account.getCurrency(), null, new BigDecimal("279.95")));
busHandler.pushExpectedEvents(NextEvent.CHANGE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
- bpSubscription.changePlanOverrideBillingPolicy("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, overrides, new LocalDate(2012, 5, 1), BillingActionPolicy.IMMEDIATE, ImmutableList.<PluginProperty>of(), callContext);
+ bpSubscription.changePlanOverrideBillingPolicy(new PlanSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), overrides, new LocalDate(2012, 5, 1), BillingActionPolicy.IMMEDIATE, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 3, callContext,
@@ -167,7 +168,7 @@ public class TestWithPriceOverride extends TestIntegrationBase {
overrides.add(new DefaultPlanPhasePriceOverride("telescopic-scope-monthly-evergreen", account.getCurrency(), null, new BigDecimal("1200.00")));
busHandler.pushExpectedEvents(NextEvent.CHANGE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
- aoEntitlement.changePlanOverrideBillingPolicy("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, overrides, new LocalDate(2012, 5, 5), BillingActionPolicy.IMMEDIATE, ImmutableList.<PluginProperty>of(), callContext);
+ aoEntitlement.changePlanOverrideBillingPolicy(new PlanSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), overrides, new LocalDate(2012, 5, 5), BillingActionPolicy.IMMEDIATE, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
}
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceList.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceList.java
index f912ecd..23d83cb 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceList.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceList.java
@@ -16,7 +16,9 @@
package org.killbill.billing.catalog;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
@@ -70,43 +72,22 @@ public class DefaultPriceList extends ValidatingConfig<StandaloneCatalog> implem
* @see org.killbill.billing.catalog.IPriceList#findPlan(org.killbill.billing.catalog.api.IProduct, org.killbill.billing.catalog.api.BillingPeriod)
*/
@Override
- public DefaultPlan findPlan(final Product product, final BillingPeriod period) {
+ public DefaultPlan[] findPlans(final Product product, final BillingPeriod period) {
+ final List<DefaultPlan> result = new ArrayList<DefaultPlan>(plans.length);
for (final DefaultPlan cur : getPlans()) {
if (cur.getProduct().equals(product) &&
- (cur.getRecurringBillingPeriod() == null || cur.getRecurringBillingPeriod().equals(period))) {
- return cur;
+ (cur.getRecurringBillingPeriod() != null && cur.getRecurringBillingPeriod().equals(period))) {
+ result.add(cur);
}
}
- return null;
+ return result.toArray(new DefaultPlan[result.size()]);
}
@Override
public ValidationErrors validate(final StandaloneCatalog catalog, final ValidationErrors errors) {
- if (getPlans() != null) {
- for (final DefaultPlan cur : getPlans()) {
- final int numPlans = findNumberOfPlans(cur.getProduct(), cur.getRecurringBillingPeriod());
- if (numPlans > 1) {
- errors.add(new ValidationError(
- String.format("There are %d plans in pricelist %s and have the same product/billingPeriod (%s, %s)",
- numPlans, getName(), cur.getProduct().getName(), cur.getRecurringBillingPeriod()), catalog.getCatalogURI(),
- DefaultPriceListSet.class, getName()));
- }
- }
- }
return errors;
}
- private int findNumberOfPlans(final Product product, final BillingPeriod period) {
- int count = 0;
- for (final DefaultPlan cur : getPlans()) {
- if (cur.getProduct().equals(product) &&
- (cur.getRecurringBillingPeriod() == null || cur.getRecurringBillingPeriod().equals(period))) {
- count++;
- }
- }
- return count;
- }
-
public DefaultPriceList setName(final String name) {
this.name = name;
return this;
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceListSet.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceListSet.java
index 236cdef..7e0f5e0 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceListSet.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceListSet.java
@@ -26,7 +26,6 @@ import java.util.List;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.CatalogApiException;
-import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PriceList;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.Product;
@@ -53,18 +52,25 @@ public class DefaultPriceListSet extends ValidatingConfig<StandaloneCatalog> imp
this.childPriceLists = childPriceLists != null ? childPriceLists : new DefaultPriceList[0];
}
- public DefaultPlan getPlanFrom(final String priceListName, final Product product,
- final BillingPeriod period) throws CatalogApiException {
- DefaultPlan result = null;
+ public DefaultPlan getPlanFrom(final Product product, final BillingPeriod period, final String priceListName) throws CatalogApiException {
+
+ DefaultPlan[] plans = null;
final DefaultPriceList pl = findPriceListFrom(priceListName);
if (pl != null) {
- result = pl.findPlan(product, period);
+ plans = pl.findPlans(product, period);
}
- if (result != null) {
- return result;
+ if (plans.length == 0) {
+ plans = defaultPricelist.findPlans(product, period);
+ }
+ switch(plans.length) {
+ case 0:
+ return null;
+ case 1:
+ return plans[0];
+ default:
+ throw new CatalogApiException(ErrorCode.CAT_MULTIPLE_MATCHING_PLANS_FOR_PRICELIST,
+ priceListName, product.getName(), period);
}
-
- return defaultPricelist.findPlan(product, period);
}
public DefaultPriceList findPriceListFrom(final String priceListName) throws CatalogApiException {
@@ -142,8 +148,4 @@ public class DefaultPriceListSet extends ValidatingConfig<StandaloneCatalog> imp
return result;
}
- @Override
- public Plan getPlanListFrom(final String s, final Product product, final BillingPeriod billingPeriod) {
- return null;
- }
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCase.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCase.java
index fe34af6..49f5267 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCase.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCase.java
@@ -17,6 +17,7 @@
package org.killbill.billing.catalog.rules;
+import org.killbill.billing.catalog.DefaultPrice;
import org.killbill.billing.catalog.DefaultPriceList;
import org.killbill.billing.catalog.DefaultProduct;
import org.killbill.billing.catalog.StandaloneCatalog;
@@ -24,6 +25,7 @@ import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanSpecifier;
+import org.killbill.billing.catalog.api.PriceList;
import org.killbill.billing.catalog.api.Product;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.catalog.api.StaticCatalog;
@@ -50,10 +52,26 @@ public abstract class DefaultCase<T> extends ValidatingConfig<StandaloneCatalog>
}
protected boolean satisfiesCase(final PlanSpecifier planPhase, final StaticCatalog c) throws CatalogApiException {
- return (getProduct() == null || getProduct().equals(c.findCurrentProduct(planPhase.getProductName()))) &&
- (getProductCategory() == null || getProductCategory().equals(c.findCurrentProduct(planPhase.getProductName()).getCategory())) &&
- (getBillingPeriod() == null || getBillingPeriod().equals(planPhase.getBillingPeriod())) &&
- (getPriceList() == null || getPriceList().equals(c.findCurrentPricelist(planPhase.getPriceListName())));
+ final Product product;
+ final BillingPeriod billingPeriod;
+ final ProductCategory productCategory;
+ final PriceList priceList;
+ if (planPhase.getPlanName() != null) {
+ final Plan plan = c.findCurrentPlan(planPhase.getPlanName());
+ product = plan.getProduct();
+ billingPeriod = plan.getRecurringBillingPeriod();
+ productCategory = plan.getProduct().getCategory();
+ priceList = c.findCurrentPricelist(plan.getPriceListName());
+ } else {
+ product = c.findCurrentProduct(planPhase.getProductName());
+ billingPeriod = planPhase.getBillingPeriod();
+ productCategory = product.getCategory();
+ priceList = getPriceList() != null ? c.findCurrentPricelist(planPhase.getPriceListName()) : null;
+ }
+ return (getProduct() == null || getProduct().equals(product)) &&
+ (getProductCategory() == null || getProductCategory().equals(productCategory)) &&
+ (getBillingPeriod() == null || getBillingPeriod().equals(billingPeriod)) &&
+ (getPriceList() == null || getPriceList().equals(priceList));
}
public static <K> K getResult(final DefaultCase<K>[] cases, final PlanSpecifier planSpec, final StaticCatalog catalog) throws CatalogApiException {
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChange.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChange.java
index 525a5d7..a046406 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChange.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChange.java
@@ -77,16 +77,53 @@ public abstract class DefaultCaseChange<T> extends ValidatingConfig<StandaloneCa
public T getResult(final PlanPhaseSpecifier from,
final PlanSpecifier to, final StaticCatalog catalog) throws CatalogApiException {
+
+
+ final Product inFromProduct;
+ final BillingPeriod inFromBillingPeriod;
+ final ProductCategory inFromProductCategory;
+ final PriceList inFromPriceList;
+ if (from.getPlanName() != null) {
+ final Plan plan = catalog.findCurrentPlan(from.getPlanName());
+ inFromProduct = plan.getProduct();
+ inFromBillingPeriod = plan.getRecurringBillingPeriod();
+ inFromProductCategory = plan.getProduct().getCategory();
+ inFromPriceList = catalog.findCurrentPricelist(plan.getPriceListName());
+ } else {
+ inFromProduct = catalog.findCurrentProduct(from.getProductName());
+ inFromBillingPeriod = from.getBillingPeriod();
+ inFromProductCategory = inFromProduct.getCategory();
+ inFromPriceList = from.getPriceListName() != null ? catalog.findCurrentPricelist(from.getPriceListName()) : null;
+ }
+
+ final Product inToProduct;
+ final BillingPeriod inToBillingPeriod;
+ final ProductCategory inToProductCategory;
+ final PriceList inToPriceList;
+ if (to.getPlanName() != null) {
+ final Plan plan = catalog.findCurrentPlan(to.getPlanName());
+ inToProduct = plan.getProduct();
+ inToBillingPeriod = plan.getRecurringBillingPeriod();
+ inToProductCategory = plan.getProduct().getCategory();
+ inToPriceList = catalog.findCurrentPricelist(plan.getPriceListName());
+ } else {
+ inToProduct = catalog.findCurrentProduct(to.getProductName());
+ inToBillingPeriod = to.getBillingPeriod();
+ inToProductCategory = inToProduct.getCategory();
+ inToPriceList = to.getPriceListName() != null ? catalog.findCurrentPricelist(to.getPriceListName()) : null;
+ }
+
+
if (
(phaseType == null || from.getPhaseType() == phaseType) &&
- (fromProduct == null || fromProduct.equals(catalog.findCurrentProduct(from.getProductName()))) &&
- (fromProductCategory == null || fromProductCategory.equals(catalog.findCurrentProduct(from.getProductName()).getCategory())) &&
- (fromBillingPeriod == null || fromBillingPeriod.equals(from.getBillingPeriod())) &&
- (this.toProduct == null || this.toProduct.equals(catalog.findCurrentProduct(to.getProductName()))) &&
- (toProductCategory == null || toProductCategory.equals(catalog.findCurrentProduct(to.getProductName()).getCategory())) &&
- (toBillingPeriod == null || toBillingPeriod.equals(to.getBillingPeriod())) &&
- (fromPriceList == null || fromPriceList.equals(catalog.findCurrentPricelist(from.getPriceListName()))) &&
- (toPriceList == null || toPriceList.equals(catalog.findCurrentPricelist(to.getPriceListName())))
+ (fromProduct == null || fromProduct.equals(inFromProduct)) &&
+ (fromProductCategory == null || fromProductCategory.equals(inFromProductCategory)) &&
+ (fromBillingPeriod == null || fromBillingPeriod.equals(inFromBillingPeriod)) &&
+ (this.toProduct == null || this.toProduct.equals(inToProduct)) &&
+ (this.toProductCategory == null || this.toProductCategory.equals(inToProductCategory)) &&
+ (this.toBillingPeriod == null || this.toBillingPeriod.equals(inToBillingPeriod)) &&
+ (fromPriceList == null || fromPriceList.equals(inFromPriceList)) &&
+ (toPriceList == null || toPriceList.equals(inToPriceList))
) {
return getResult();
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCasePhase.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCasePhase.java
index f0a0011..cf656ef 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCasePhase.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCasePhase.java
@@ -33,8 +33,7 @@ public abstract class DefaultCasePhase<T> extends DefaultCaseStandardNaming<T> {
public T getResult(final PlanPhaseSpecifier specifier, final StaticCatalog c) throws CatalogApiException {
if ((phaseType == null || specifier.getPhaseType() == phaseType)
- && satisfiesCase(new PlanSpecifier(specifier), c)
- ) {
+ && satisfiesCase(new PlanSpecifier(specifier), c)) {
return getResult();
}
return null;
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultPlanRules.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultPlanRules.java
index 34dd757..99efa9c 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultPlanRules.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultPlanRules.java
@@ -119,21 +119,25 @@ public class DefaultPlanRules extends ValidatingConfig<StandaloneCatalog> implem
return (result != null) ? result : BillingAlignment.ACCOUNT;
}
- public PlanChangeResult planChange(final PlanPhaseSpecifier from, PlanSpecifier to, final StaticCatalog catalog) throws CatalogApiException {
- final DefaultPriceList toPriceList;
- if (to.getPriceListName() == null) { // Pricelist may be null because it is unspecified this is the principal use-case
- toPriceList = findPriceList(from, catalog);
- to = new PlanSpecifier(to.getProductName(), to.getBillingPeriod(), toPriceList.getName());
- } else {
- toPriceList = (DefaultPriceList) catalog.findCurrentPricelist(to.getPriceListName());
- }
+ public PlanChangeResult planChange(final PlanPhaseSpecifier from, final PlanSpecifier to, final StaticCatalog catalog) throws CatalogApiException {
+
+ final DefaultPriceList toPriceList = to.getPriceListName() != null ?
+ (DefaultPriceList) catalog.findCurrentPricelist(to.getPriceListName()) :
+ findPriceList(from, catalog);
+
+ // If we use old scheme {product, billingPeriod, pricelist}, ensure pricelist is correct
+ // (Pricelist may be null because if it is unspecified this is the principal use-case)
+ final PlanSpecifier toWithPriceList = to.getPlanName() == null ?
+ new PlanSpecifier(to.getProductName(), to.getBillingPeriod(), toPriceList.getName()) :
+ to;
- final BillingActionPolicy policy = getPlanChangePolicy(from, to, catalog);
+
+ final BillingActionPolicy policy = getPlanChangePolicy(from, toWithPriceList, catalog);
if (policy == BillingActionPolicy.ILLEGAL) {
- throw new IllegalPlanChange(from, to);
+ throw new IllegalPlanChange(from, toWithPriceList);
}
- final PlanAlignmentChange alignment = getPlanChangeAlignment(from, to, catalog);
+ final PlanAlignmentChange alignment = getPlanChangeAlignment(from, toWithPriceList, catalog);
return new PlanChangeResult(toPriceList, policy, alignment);
}
@@ -146,13 +150,6 @@ public class DefaultPlanRules extends ValidatingConfig<StandaloneCatalog> implem
public BillingActionPolicy getPlanChangePolicy(final PlanPhaseSpecifier from,
final PlanSpecifier to, final StaticCatalog catalog) throws CatalogApiException {
- if (from.getProductName().equals(to.getProductName()) &&
- from.getBillingPeriod() == to.getBillingPeriod() &&
- from.getPriceListName().equals(to.getPriceListName())) {
- return BillingActionPolicy.ILLEGAL;
- }
- //Plan toPlan = catalog.findPlan()
-
final BillingActionPolicy result = DefaultCaseChange.getResult(changeCase, from, to, catalog);
return (result != null) ? result : BillingActionPolicy.END_OF_TERM;
}
@@ -160,7 +157,8 @@ public class DefaultPlanRules extends ValidatingConfig<StandaloneCatalog> implem
private DefaultPriceList findPriceList(final PlanSpecifier specifier, final StaticCatalog catalog) throws CatalogApiException {
DefaultPriceList result = DefaultCase.getResult(priceListCase, specifier, catalog);
if (result == null) {
- result = (DefaultPriceList) catalog.findCurrentPricelist(specifier.getPriceListName());
+ final String priceListName = specifier.getPlanName() != null ? catalog.findCurrentPlan(specifier.getPlanName()).getPriceListName() : specifier.getPriceListName();
+ result = (DefaultPriceList) catalog.findCurrentPricelist(priceListName);
}
return result;
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
index f05318d..a2795e3 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
@@ -46,6 +46,7 @@ import org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.PriceList;
+import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.Product;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.catalog.api.StaticCatalog;
@@ -168,17 +169,26 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
*/
@Override
public DefaultPlan createOrFindCurrentPlan(final PlanSpecifier spec, final PlanPhasePriceOverridesWithCallContext unused) throws CatalogApiException {
- if (spec.getProductName() == null) {
- throw new CatalogApiException(ErrorCode.CAT_NULL_PRODUCT_NAME);
- }
- if (priceLists == null) {
- throw new CatalogApiException(ErrorCode.CAT_PRICE_LIST_NOT_FOUND, spec.getPriceListName());
+ final DefaultPlan result;
+ if (spec.getPlanName() != null) {
+ result = findCurrentPlan(spec.getPlanName());
+ } else {
+ if (spec.getProductName() == null) {
+ throw new CatalogApiException(ErrorCode.CAT_NULL_PRODUCT_NAME);
+ }
+ if (spec.getBillingPeriod() == null) {
+ throw new CatalogApiException(ErrorCode.CAT_NULL_BILLING_PERIOD);
+ }
+ final String inputOrDefaultPricelist = (spec.getPriceListName() == null) ? PriceListSet.DEFAULT_PRICELIST_NAME : spec.getPriceListName();
+ final Product product = findCurrentProduct(spec.getProductName());
+ result = priceLists.getPlanFrom(product, spec.getBillingPeriod(), inputOrDefaultPricelist);
}
- final Product product = findCurrentProduct(spec.getProductName());
- final DefaultPlan result = priceLists.getPlanFrom(spec.getPriceListName(), product, spec.getBillingPeriod());
if (result == null) {
- final String periodString = (spec.getBillingPeriod() == null) ? "NULL" : spec.getBillingPeriod().toString();
- throw new CatalogApiException(ErrorCode.CAT_PLAN_NOT_FOUND, spec.getProductName(), periodString, spec.getPriceListName());
+ throw new CatalogApiException(ErrorCode.CAT_PLAN_NOT_FOUND,
+ spec.getPlanName() != null ? spec.getPlanName() : "undefined",
+ spec.getProductName() != null ? spec.getProductName() : "undefined",
+ spec.getBillingPeriod() != null ? spec.getBillingPeriod() : "undefined",
+ spec.getPriceListName() != null ? spec.getPriceListName() : "undefined");
}
return result;
}
@@ -369,9 +379,9 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
for (BillingPeriod billingPeriod : BillingPeriod.values()) {
for (PriceList priceList : getPriceLists().getAllPriceLists()) {
if (priceListName == null || priceListName.equals(priceList.getName())) {
- Plan addonInList = priceList.findPlan(availAddon, billingPeriod);
- if ((addonInList != null)) {
- availAddons.add(new DefaultListing(addonInList, priceList));
+ Plan[] addonInList = priceList.findPlans(availAddon, billingPeriod);
+ for (Plan cur : addonInList) {
+ availAddons.add(new DefaultListing(cur, priceList));
}
}
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
index 90e499e..ea97bcb 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
@@ -128,11 +128,7 @@ public class VersionedCatalog extends ValidatingConfig<VersionedCatalog> impleme
public Plan findPlan(final StandaloneCatalog catalog) throws CatalogApiException {
- if (spec.getPlanName() != null) {
- return catalog.findCurrentPlan(spec.getPlanName());
- } else {
- return catalog.createOrFindCurrentPlan(new PlanSpecifier(spec.getProductName(), spec.getBillingPeriod(), spec.getPriceListName()), overrides);
- }
+ return catalog.createOrFindCurrentPlan(spec, overrides);
}
}
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCaseChange.java b/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCaseChange.java
index 92464c1..e207fff 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCaseChange.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCaseChange.java
@@ -632,7 +632,7 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
assertion(Result.FOO, cr,
product1.getName(), product2.getName(),
BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
- cat.getCurrentProducts()[1].getName(), priceList2.getName(),
+ priceList1.getName(), priceList2.getName(),
PhaseType.EVERGREEN, cat);
assertionException(cr,
@@ -711,7 +711,7 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
assertion(Result.FOO, cr,
product1.getName(), product2.getName(),
BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
- priceList1.getName(), cat.getCurrentProducts()[1].getName(),
+ priceList1.getName(), priceList2.getName(),
PhaseType.EVERGREEN, cat);
assertionNull(cr,
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/rules/TestPlanRules.java b/catalog/src/test/java/org/killbill/billing/catalog/rules/TestPlanRules.java
index d5acda6..66fa6bf 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/rules/TestPlanRules.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/rules/TestPlanRules.java
@@ -56,24 +56,6 @@ public class TestPlanRules extends CatalogTestSuiteNoDB {
}
@Test(groups = "fast")
- public void testCannotChangeToSamePlan() throws CatalogApiException {
- final DefaultProduct product1 = cat.getCurrentProducts()[0];
- final DefaultPriceList priceList1 = cat.findCurrentPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
-
- final PlanPhaseSpecifier from = new PlanPhaseSpecifier(product1.getName(), BillingPeriod.MONTHLY, priceList1.getName(), PhaseType.EVERGREEN);
- final PlanSpecifier to = new PlanSpecifier(product1.getName(), BillingPeriod.MONTHLY, priceList1.getName());
-
- try {
- cat.getPlanRules().planChange(from, to, cat);
- Assert.fail("We did not see an exception when trying to change plan to the same plan");
- } catch (IllegalPlanChange e) {
- // Correct - cannot change to the same plan
- } catch (CatalogApiException e) {
- Assert.fail("", e);
- }
- }
-
- @Test(groups = "fast")
public void testExistingPriceListIsKept() throws CatalogApiException {
final DefaultProduct product1 = cat.getCurrentProducts()[0];
final DefaultPriceList priceList1 = cat.findCurrentPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/TestPriceListSet.java b/catalog/src/test/java/org/killbill/billing/catalog/TestPriceListSet.java
index d38438a..8b3346a 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/TestPriceListSet.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/TestPriceListSet.java
@@ -52,10 +52,10 @@ public class TestPriceListSet extends CatalogTestSuiteNoDB {
};
final DefaultPriceListSet set = new DefaultPriceListSet(defaultPriceList, childPriceLists);
- Assert.assertEquals(set.getPlanFrom(PriceListSet.DEFAULT_PRICELIST_NAME, foo, BillingPeriod.ANNUAL).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
- Assert.assertEquals(set.getPlanFrom(PriceListSet.DEFAULT_PRICELIST_NAME, foo, BillingPeriod.MONTHLY).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
- Assert.assertEquals(set.getPlanFrom("child", foo, BillingPeriod.ANNUAL).getFinalPhase().getPhaseType(), PhaseType.DISCOUNT);
- Assert.assertEquals(set.getPlanFrom("child", foo, BillingPeriod.MONTHLY).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
+ Assert.assertEquals(set.getPlanFrom(foo, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
+ Assert.assertEquals(set.getPlanFrom(foo, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
+ Assert.assertEquals(set.getPlanFrom(foo, BillingPeriod.ANNUAL, "child").getFinalPhase().getPhaseType(), PhaseType.DISCOUNT);
+ Assert.assertEquals(set.getPlanFrom(foo, BillingPeriod.MONTHLY, "child").getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
}
@Test(groups = "fast")
@@ -65,8 +65,8 @@ public class TestPriceListSet extends CatalogTestSuiteNoDB {
final DefaultPlan[] defaultPlans = new DefaultPlan[]{
new MockPlan().setName("plan-foo-monthly").setProduct(foo).setFinalPhase(new MockPlanPhase().setRecurring(new MockRecurring(MONTHLY, null)).setPhaseType(EVERGREEN)),
new MockPlan().setName("plan-bar-monthly").setProduct(bar).setFinalPhase(new MockPlanPhase().setRecurring(new MockRecurring(MONTHLY, null)).setPhaseType(EVERGREEN)),
- new MockPlan().setName("plan-foo-annual").setProduct(foo).setFinalPhase(new MockPlanPhase().setRecurring(new MockRecurring(null, null)).setPhaseType(EVERGREEN)),
- new MockPlan().setName("plan-bar-annual").setProduct(bar).setFinalPhase(new MockPlanPhase().setRecurring(new MockRecurring(null, null)).setPhaseType(EVERGREEN))
+ new MockPlan().setName("plan-foo-annual").setProduct(foo).setFinalPhase(new MockPlanPhase().setRecurring(new MockRecurring(ANNUAL, null)).setPhaseType(EVERGREEN)),
+ new MockPlan().setName("plan-bar-annual").setProduct(bar).setFinalPhase(new MockPlanPhase().setRecurring(new MockRecurring(ANNUAL, null)).setPhaseType(EVERGREEN))
};
final DefaultPlan[] childPlans = new DefaultPlan[]{
new MockPlan().setName("plan-foo").setProduct(foo).setFinalPhase(new MockPlanPhase().setRecurring(new MockRecurring(ANNUAL, null)).setPhaseType(DISCOUNT)),
@@ -79,9 +79,9 @@ public class TestPriceListSet extends CatalogTestSuiteNoDB {
};
final DefaultPriceListSet set = new DefaultPriceListSet(defaultPriceList, childPriceLists);
- Assert.assertEquals(set.getPlanFrom("child", foo, BillingPeriod.ANNUAL).getFinalPhase().getPhaseType(), PhaseType.DISCOUNT);
- Assert.assertEquals(set.getPlanFrom("child", foo, BillingPeriod.MONTHLY).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
- Assert.assertEquals(set.getPlanFrom(PriceListSet.DEFAULT_PRICELIST_NAME, foo, BillingPeriod.ANNUAL).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
- Assert.assertEquals(set.getPlanFrom(PriceListSet.DEFAULT_PRICELIST_NAME, foo, BillingPeriod.MONTHLY).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
+ Assert.assertEquals(set.getPlanFrom(foo, BillingPeriod.ANNUAL, "child").getFinalPhase().getPhaseType(), PhaseType.DISCOUNT);
+ Assert.assertEquals(set.getPlanFrom(foo, BillingPeriod.MONTHLY, "child").getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
+ Assert.assertEquals(set.getPlanFrom(foo, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
+ Assert.assertEquals(set.getPlanFrom(foo, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
}
}
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
index 36f5347..3e5fa05 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
@@ -38,6 +38,7 @@ import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhase;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.PriceList;
import org.killbill.billing.catalog.api.Product;
import org.killbill.billing.catalog.api.ProductCategory;
@@ -526,9 +527,9 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
}
@Override
- public Entitlement changePlan(final String productName, final BillingPeriod billingPeriod, final String priceList, final List<PlanPhasePriceOverride> overrides, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+ public Entitlement changePlan(final PlanSpecifier spec, final List<PlanPhasePriceOverride> overrides, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
- logChangePlan(log, this, productName, billingPeriod, priceList, overrides, null, null);
+ logChangePlan(log, this, spec, overrides, null, null);
checkForPermissions(Permission.ENTITLEMENT_CAN_CHANGE_PLAN, callContext);
@@ -558,7 +559,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
final DateTime effectiveChangeDate;
try {
- effectiveChangeDate = subscriptionInternalApi.getDryRunChangePlanEffectiveDate(getSubscriptionBase(), productName, billingPeriod, priceList, null, null, context);
+ effectiveChangeDate = subscriptionInternalApi.getDryRunChangePlanEffectiveDate(getSubscriptionBase(), spec, null, null, context);
} catch (final SubscriptionBaseApiException e) {
throw new EntitlementApiException(e, e.getCode(), e.getMessage());
}
@@ -570,7 +571,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
}
try {
- getSubscriptionBase().changePlan(productName, billingPeriod, priceList, overrides, callContext);
+ getSubscriptionBase().changePlan(spec, overrides, callContext);
} catch (final SubscriptionBaseApiException e) {
throw new EntitlementApiException(e);
}
@@ -590,9 +591,9 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
}
@Override
- public Entitlement changePlanWithDate(final String productName, final BillingPeriod billingPeriod, final String priceList, final List<PlanPhasePriceOverride> overrides, @Nullable final LocalDate effectiveDate, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+ public Entitlement changePlanWithDate(final PlanSpecifier spec, final List<PlanPhasePriceOverride> overrides, @Nullable final LocalDate effectiveDate, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
- logChangePlan(log, this, productName, billingPeriod, priceList, overrides, effectiveDate, null);
+ logChangePlan(log, this, spec, overrides, effectiveDate, null);
checkForPermissions(Permission.ENTITLEMENT_CAN_CHANGE_PLAN, callContext);
@@ -623,7 +624,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
final DateTime resultingEffectiveDate;
try {
- resultingEffectiveDate = subscriptionInternalApi.getDryRunChangePlanEffectiveDate(getSubscriptionBase(), productName, billingPeriod, priceList, effectiveChangeDate, null, context);
+ resultingEffectiveDate = subscriptionInternalApi.getDryRunChangePlanEffectiveDate(getSubscriptionBase(), spec, effectiveChangeDate, null, context);
} catch (final SubscriptionBaseApiException e) {
throw new EntitlementApiException(e, e.getCode(), e.getMessage());
}
@@ -635,7 +636,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
}
try {
- getSubscriptionBase().changePlanWithDate(productName, billingPeriod, priceList, overrides, resultingEffectiveDate, callContext);
+ getSubscriptionBase().changePlanWithDate(spec, overrides, resultingEffectiveDate, callContext);
} catch (final SubscriptionBaseApiException e) {
throw new EntitlementApiException(e);
}
@@ -656,9 +657,9 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
}
@Override
- public Entitlement changePlanOverrideBillingPolicy(final String productName, final BillingPeriod billingPeriod, final String priceList, final List<PlanPhasePriceOverride> overrides, final LocalDate entitlementEffectiveDate, final BillingActionPolicy actionPolicy, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+ public Entitlement changePlanOverrideBillingPolicy(final PlanSpecifier spec, final List<PlanPhasePriceOverride> overrides, final LocalDate entitlementEffectiveDate, final BillingActionPolicy actionPolicy, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
- logChangePlan(log, this, productName, billingPeriod, priceList, overrides, entitlementEffectiveDate, actionPolicy);
+ logChangePlan(log, this, spec, overrides, entitlementEffectiveDate, actionPolicy);
checkForPermissions(Permission.ENTITLEMENT_CAN_CHANGE_PLAN, callContext);
@@ -688,7 +689,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
final DateTime effectiveChangeDate;
try {
- effectiveChangeDate = subscriptionInternalApi.getDryRunChangePlanEffectiveDate(getSubscriptionBase(), productName, billingPeriod, priceList, null, actionPolicy, context);
+ effectiveChangeDate = subscriptionInternalApi.getDryRunChangePlanEffectiveDate(getSubscriptionBase(), spec, null, actionPolicy, context);
} catch (final SubscriptionBaseApiException e) {
throw new EntitlementApiException(e, e.getCode(), e.getMessage());
}
@@ -700,7 +701,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
}
try {
- getSubscriptionBase().changePlanWithPolicy(productName, billingPeriod, priceList, overrides, actionPolicy, callContext);
+ getSubscriptionBase().changePlanWithPolicy(spec, overrides, actionPolicy, callContext);
} catch (final SubscriptionBaseApiException e) {
throw new EntitlementApiException(e);
}
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/logging/EntitlementLoggingHelper.java b/entitlement/src/main/java/org/killbill/billing/entitlement/logging/EntitlementLoggingHelper.java
index 743cc8a..7e7f2e2 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/logging/EntitlementLoggingHelper.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/logging/EntitlementLoggingHelper.java
@@ -25,6 +25,7 @@ import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.entitlement.api.BlockingState;
import org.killbill.billing.entitlement.api.Entitlement;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementActionPolicy;
@@ -197,7 +198,7 @@ public abstract class EntitlementLoggingHelper {
}
}
- public static void logChangePlan(final Logger log, final Entitlement entitlement, String productName, final BillingPeriod billingPeriod, final String priceList,
+ public static void logChangePlan(final Logger log, final Entitlement entitlement, final PlanSpecifier spec,
final List<PlanPhasePriceOverride> overrides, final LocalDate entitlementEffectiveDate, final BillingActionPolicy actionPolicy) {
if (log.isInfoEnabled()) {
final StringBuilder logLine = new StringBuilder("Change Entitlement Plan: ")
@@ -209,19 +210,24 @@ public abstract class EntitlementLoggingHelper {
.append(entitlementEffectiveDate)
.append("'");
}
- if (productName != null) {
+ if (spec.getPlanName() != null) {
+ logLine.append(", plan='")
+ .append(spec.getPlanName())
+ .append("'");
+ }
+ if (spec.getProductName() != null) {
logLine.append(", product='")
- .append(productName)
+ .append(spec.getProductName())
.append("'");
}
- if (billingPeriod != null) {
+ if (spec.getBillingPeriod() != null) {
logLine.append(", billingPeriod='")
- .append(billingPeriod)
+ .append(spec.getBillingPeriod())
.append("'");
}
- if (priceList != null) {
+ if (spec.getPriceListName() != null) {
logLine.append(", priceList='")
- .append(priceList)
+ .append(spec.getBillingPeriod())
.append("'");
}
logPlanPhasePriceOverrides(logLine, overrides);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
index 15cb7cb..692995f 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
@@ -27,6 +27,7 @@ import org.killbill.billing.api.TestApiListener.NextEvent;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.entitlement.EntitlementTestSuiteWithEmbeddedDB;
@@ -262,7 +263,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
// Immediate change during trial
testListener.pushExpectedEvent(NextEvent.CHANGE);
- entitlement.changePlan("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null, ImmutableList.<PluginProperty>of(), callContext);
+ entitlement.changePlan(new PlanSpecifier("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), null, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// Verify the change is immediate
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
index aef34c1..18a4beb 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
@@ -30,6 +30,7 @@ import org.killbill.billing.api.TestApiListener.NextEvent;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.entitlement.EntitlementService;
@@ -498,7 +499,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
assertListenerStatus();
try {
- entitlement.changePlan("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null, ImmutableList.<PluginProperty>of(), callContext);
+ entitlement.changePlan(new PlanSpecifier("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), null, ImmutableList.<PluginProperty>of(), callContext);
fail();
} catch (final EntitlementApiException e) {
assertEquals(e.getCode(), ErrorCode.BLOCK_BLOCKED_ACTION.getCode());
@@ -507,7 +508,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
}
try {
- entitlement.changePlanWithDate("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null, clock.getUTCToday(), ImmutableList.<PluginProperty>of(), callContext);
+ entitlement.changePlanWithDate(new PlanSpecifier("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), null, clock.getUTCToday(), ImmutableList.<PluginProperty>of(), callContext);
fail();
} catch (final EntitlementApiException e) {
assertEquals(e.getCode(), ErrorCode.BLOCK_BLOCKED_ACTION.getCode());
@@ -516,7 +517,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
}
try {
- entitlement.changePlanOverrideBillingPolicy("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null, clock.getUTCToday(), BillingActionPolicy.IMMEDIATE, ImmutableList.<PluginProperty>of(), callContext);
+ entitlement.changePlanOverrideBillingPolicy(new PlanSpecifier("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), null, clock.getUTCToday(), BillingActionPolicy.IMMEDIATE, ImmutableList.<PluginProperty>of(), callContext);
fail();
} catch (final EntitlementApiException e) {
assertEquals(e.getCode(), ErrorCode.BLOCK_BLOCKED_ACTION.getCode());
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java b/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
index 589189b..301d6f0 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
@@ -31,6 +31,7 @@ import org.killbill.billing.api.TestApiListener.NextEvent;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.entitlement.AccountEventsStreams;
@@ -232,7 +233,7 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
@Test(groups = "slow", description = "Verify add-ons blocking states are added for EOT change plans")
public void testChangePlanEOT() throws Exception {
// Change plan EOT to Assault-Rifle (Telescopic-Scope is included)
- final DefaultEntitlement changedBaseEntitlement = (DefaultEntitlement) baseEntitlement.changePlanWithDate("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null, new LocalDate(2013, 10, 7), ImmutableList.<PluginProperty>of(), callContext);
+ final DefaultEntitlement changedBaseEntitlement = (DefaultEntitlement) baseEntitlement.changePlanWithDate(new PlanSpecifier("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), null, new LocalDate(2013, 10, 7), ImmutableList.<PluginProperty>of(), callContext);
// No blocking event (EOT)
assertListenerStatus();
@@ -271,7 +272,7 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
assertListenerStatus();
// Change plan EOT to Assault-Rifle (Telescopic-Scope is included)
- final DefaultEntitlement changedBaseEntitlement = (DefaultEntitlement) baseEntitlement.changePlanWithDate("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null, new LocalDate(2013, 10, 7), ImmutableList.<PluginProperty>of(), callContext);
+ final DefaultEntitlement changedBaseEntitlement = (DefaultEntitlement) baseEntitlement.changePlanWithDate(new PlanSpecifier("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), null, new LocalDate(2013, 10, 7), ImmutableList.<PluginProperty>of(), callContext);
// No blocking event (EOT)
assertListenerStatus();
@@ -290,7 +291,7 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
// Change plan IMM (upgrade) to Assault-Rifle (Telescopic-Scope is included)
testListener.pushExpectedEvents(NextEvent.CHANGE, NextEvent.CANCEL, NextEvent.BLOCK);
- final DefaultEntitlement changedBaseEntitlement = (DefaultEntitlement) baseEntitlement.changePlan("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null, ImmutableList.<PluginProperty>of(), callContext);
+ final DefaultEntitlement changedBaseEntitlement = (DefaultEntitlement) baseEntitlement.changePlan(new PlanSpecifier("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), null, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// We need to add a 1s delay before invoking the eventsStreamBuilder in the checks below, because
jaxrs/pom.xml 4(+4 -0)
diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
index 20befb1..d477452 100644
--- a/jaxrs/pom.xml
+++ b/jaxrs/pom.xml
@@ -76,6 +76,10 @@
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
+ <groupId>net.sf.ehcache</groupId>
+ <artifactId>ehcache</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
</dependency>
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountJson.java
index 58d0576..e3d3e80 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountJson.java
@@ -62,6 +62,7 @@ public class AccountJson extends JsonBase {
private final String country;
private final String locale;
private final String phone;
+ private final String notes;
private final Boolean isMigrated;
private final Boolean isNotifiedForInvoices;
@@ -89,6 +90,7 @@ public class AccountJson extends JsonBase {
this.country = account.getCountry();
this.locale = account.getLocale();
this.phone = account.getPhone();
+ this.notes = account.getNotes();
this.isMigrated = account.isMigrated();
this.isNotifiedForInvoices = account.isNotifiedForInvoices();
}
@@ -114,6 +116,7 @@ public class AccountJson extends JsonBase {
@JsonProperty("country") final String country,
@JsonProperty("locale") final String locale,
@JsonProperty("phone") final String phone,
+ @JsonProperty("notes") final String notes,
@JsonProperty("isMigrated") final Boolean isMigrated,
@JsonProperty("isNotifiedForInvoices") final Boolean isNotifiedForInvoices,
@JsonProperty("accountBalance") final BigDecimal accountBalance,
@@ -141,6 +144,7 @@ public class AccountJson extends JsonBase {
this.country = country;
this.locale = locale;
this.phone = phone;
+ this.notes = notes;
this.isMigrated = isMigrated;
this.isNotifiedForInvoices = isNotifiedForInvoices;
this.accountCBA = accountCBA;
@@ -173,6 +177,11 @@ public class AccountJson extends JsonBase {
}
@Override
+ public String getNotes() {
+ return notes;
+ }
+
+ @Override
public Boolean isMigrated() {
return isMigrated;
}
@@ -360,6 +369,10 @@ public class AccountJson extends JsonBase {
return phone;
}
+ public String getNotes() {
+ return notes;
+ }
+
@JsonProperty("isMigrated")
public Boolean isMigrated() {
return isMigrated;
@@ -395,6 +408,7 @@ public class AccountJson extends JsonBase {
", country='" + country + '\'' +
", locale='" + locale + '\'' +
", phone='" + phone + '\'' +
+ ", notes='" + notes + '\'' +
", isMigrated=" + isMigrated +
", isNotifiedForInvoices=" + isNotifiedForInvoices +
'}';
@@ -474,6 +488,9 @@ public class AccountJson extends JsonBase {
if (phone != null ? !phone.equals(that.phone) : that.phone != null) {
return false;
}
+ if (notes != null ? !notes.equals(that.notes) : that.notes != null) {
+ return false;
+ }
if (postalCode != null ? !postalCode.equals(that.postalCode) : that.postalCode != null) {
return false;
}
@@ -511,6 +528,7 @@ public class AccountJson extends JsonBase {
result = 31 * result + (country != null ? country.hashCode() : 0);
result = 31 * result + (locale != null ? locale.hashCode() : 0);
result = 31 * result + (phone != null ? phone.hashCode() : 0);
+ result = 31 * result + (notes != null ? notes.hashCode() : 0);
result = 31 * result + (isMigrated != null ? isMigrated.hashCode() : 0);
result = 31 * result + (isNotifiedForInvoices != null ? isNotifiedForInvoices.hashCode() : 0);
return result;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
index 2365957..d83acaa 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
@@ -127,7 +127,9 @@ public class PhasePriceOverrideJson {
return new DefaultPlanPhasePriceOverride(input.getPhaseName(), currency, input.getFixedPrice(), input.getRecurringPrice());
} else {
final PhaseType phaseType = input.getPhaseType() != null ? PhaseType.valueOf(input.getPhaseType()) : null;
- final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier(spec.getProductName(), spec.getBillingPeriod(), spec.getPriceListName(), phaseType);
+ final PlanPhaseSpecifier planPhaseSpecifier = spec.getPlanName() != null ?
+ new PlanPhaseSpecifier(spec.getPlanName(), phaseType) :
+ new PlanPhaseSpecifier(spec.getProductName(), spec.getBillingPeriod(), spec.getPriceListName(), phaseType);
return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, currency, input.getFixedPrice(), input.getRecurringPrice());
}
}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java
index 5440c95..fd64e0a 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java
@@ -63,6 +63,8 @@ public class SubscriptionJson extends JsonBase {
private final String phaseType;
@ApiModelProperty(required = true)
private final String priceList;
+ @ApiModelProperty(required = true)
+ private final String planName;
//@ApiModelProperty(dataType = "org.killbill.billing.entitlement.api.Entitlement.EntitlementState")
@ApiModelProperty(dataType = "string", allowableValues = "PENDING,ACTIVE,BLOCKED,CANCELLED")
private final String state;
@@ -291,6 +293,7 @@ public class SubscriptionJson extends JsonBase {
@JsonProperty("billingPeriod") @Nullable final String billingPeriod,
@JsonProperty("phaseType") @Nullable final String phaseType,
@JsonProperty("priceList") @Nullable final String priceList,
+ @JsonProperty("planName") @Nullable final String planName,
@JsonProperty("state") @Nullable final String state,
@JsonProperty("sourceType") @Nullable final String sourceType,
@JsonProperty("cancelledDate") @Nullable final LocalDate cancelledDate,
@@ -308,6 +311,7 @@ public class SubscriptionJson extends JsonBase {
this.billingPeriod = billingPeriod;
this.phaseType = phaseType;
this.priceList = priceList;
+ this.planName = planName;
this.state = state;
this.sourceType = sourceType;
this.cancelledDate = cancelledDate;
@@ -354,6 +358,12 @@ public class SubscriptionJson extends JsonBase {
} else {
this.priceList = subscription.getLastActivePriceList().getName();
}
+ if (subscription.getLastActivePlan() == null) {
+ this.planName = firstEvent == null ? null : firstEvent.getNextPlan().getName();
+ } else {
+ this.planName = subscription.getLastActivePlan().getName();
+ }
+
this.state = subscription.getState().name();
this.sourceType = subscription.getSourceType().name();
@@ -426,6 +436,10 @@ public class SubscriptionJson extends JsonBase {
return priceList;
}
+ public String getPlanName() {
+ return planName;
+ }
+
public String getState() {
return state;
}
@@ -475,6 +489,7 @@ public class SubscriptionJson extends JsonBase {
sb.append(", billingPeriod='").append(billingPeriod).append('\'');
sb.append(", phaseType='").append(phaseType).append('\'');
sb.append(", priceList='").append(priceList).append('\'');
+ sb.append(", planName='").append(planName).append('\'');
sb.append(", state='").append(state).append('\'');
sb.append(", sourceType='").append(sourceType).append('\'');
sb.append(", cancelledDate=").append(cancelledDate);
@@ -532,6 +547,9 @@ public class SubscriptionJson extends JsonBase {
if (priceList != null ? !priceList.equals(that.priceList) : that.priceList != null) {
return false;
}
+ if (planName != null ? !planName.equals(that.planName) : that.planName != null) {
+ return false;
+ }
if (productCategory != null ? !productCategory.equals(that.productCategory) : that.productCategory != null) {
return false;
}
@@ -571,6 +589,7 @@ public class SubscriptionJson extends JsonBase {
result = 31 * result + (billingPeriod != null ? billingPeriod.hashCode() : 0);
result = 31 * result + (phaseType != null ? phaseType.hashCode() : 0);
result = 31 * result + (priceList != null ? priceList.hashCode() : 0);
+ result = 31 * result + (planName != null ? planName.hashCode() : 0);
result = 31 * result + (state != null ? state.hashCode() : 0);
result = 31 * result + (sourceType != null ? sourceType.hashCode() : 0);
result = 31 * result + (cancelledDate != null ? cancelledDate.hashCode() : 0);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AdminResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AdminResource.java
index 979d223..c964e67 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AdminResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AdminResource.java
@@ -17,19 +17,24 @@
package org.killbill.billing.jaxrs.resources;
+import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
+import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.AccountUserApi;
import org.killbill.billing.jaxrs.json.AdminPaymentJson;
import org.killbill.billing.jaxrs.util.Context;
@@ -41,10 +46,16 @@ import org.killbill.billing.payment.api.PaymentApiException;
import org.killbill.billing.payment.api.PaymentTransaction;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.payment.api.TransactionStatus;
+import org.killbill.billing.tenant.api.Tenant;
+import org.killbill.billing.tenant.api.TenantApiException;
+import org.killbill.billing.tenant.api.TenantUserApi;
import org.killbill.billing.util.api.AuditUserApi;
import org.killbill.billing.util.api.CustomFieldUserApi;
+import org.killbill.billing.util.api.RecordIdApi;
import org.killbill.billing.util.api.TagUserApi;
+import org.killbill.billing.util.cache.Cachable.CacheType;
import org.killbill.billing.util.callcontext.CallContext;
+import org.killbill.billing.util.callcontext.TenantContext;
import org.killbill.clock.Clock;
import com.google.common.base.Predicate;
@@ -55,6 +66,8 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Ehcache;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
@@ -64,11 +77,17 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
public class AdminResource extends JaxRsResourceBase {
private final AdminPaymentApi adminPaymentApi;
+ private final TenantUserApi tenantApi;
+ private final CacheManager cacheManager;
+ private final RecordIdApi recordIdApi;
@Inject
- public AdminResource(final JaxrsUriBuilder uriBuilder, final TagUserApi tagUserApi, final CustomFieldUserApi customFieldUserApi, final AuditUserApi auditUserApi, final AccountUserApi accountUserApi, final PaymentApi paymentApi, final AdminPaymentApi adminPaymentApi, final Clock clock, final Context context) {
+ public AdminResource(final JaxrsUriBuilder uriBuilder, final TagUserApi tagUserApi, final CustomFieldUserApi customFieldUserApi, final AuditUserApi auditUserApi, final AccountUserApi accountUserApi, final PaymentApi paymentApi, final AdminPaymentApi adminPaymentApi, final CacheManager cacheManager, final TenantUserApi tenantApi, final RecordIdApi recordIdApi, final Clock clock, final Context context) {
super(uriBuilder, tagUserApi, customFieldUserApi, auditUserApi, accountUserApi, paymentApi, null, clock, context);
this.adminPaymentApi = adminPaymentApi;
+ this.tenantApi = tenantApi;
+ this.recordIdApi = recordIdApi;
+ this.cacheManager = cacheManager;
}
@@ -104,4 +123,106 @@ public class AdminResource extends JaxRsResourceBase {
return Response.status(Status.OK).build();
}
+ @DELETE
+ @Path("/" + CACHE)
+ @Produces(APPLICATION_JSON)
+ @ApiOperation(value = "Invalidates the given Cache if specified, otherwise invalidates all caches")
+ @ApiResponses(value = {@ApiResponse(code = 400, message = "Cache name does not exist or is not alive")})
+ public Response invalidatesCache(@QueryParam("cacheName") final String cacheName,
+ @javax.ws.rs.core.Context final HttpServletRequest request) {
+ if (null != cacheName && !cacheName.isEmpty()) {
+ final Ehcache cache = cacheManager.getEhcache(cacheName);
+ // check if cache is null
+ if (cache == null) {
+ log.warn("Cache for specified cacheName='{}' does not exist or is not alive", cacheName);
+ return Response.status(Status.BAD_REQUEST).build();
+ }
+ // Clear given cache
+ cache.removeAll();
+ }
+ else {
+ // if not given a specific cacheName, clear all
+ cacheManager.clearAll();
+ }
+ return Response.status(Status.OK).build();
+ }
+
+ @DELETE
+ @Path("/" + CACHE + "/" + ACCOUNTS + "/{accountId:" + UUID_PATTERN + "}/")
+ @Produces(APPLICATION_JSON)
+ @ApiOperation(value = "Invalidates Caches per account level")
+ @ApiResponses(value = {})
+ public Response invalidatesCacheByAccount(@PathParam("accountId") final String accountId,
+ @javax.ws.rs.core.Context final HttpServletRequest request) {
+
+ // clear account-record-id cache by accountId
+ final Ehcache accountRecordIdCache = cacheManager.getEhcache(CacheType.ACCOUNT_RECORD_ID.getCacheName());
+ accountRecordIdCache.remove(accountId);
+
+ // clear account-immutable cache by accountId
+ final Ehcache accountImmutableCache = cacheManager.getEhcache(CacheType.ACCOUNT_IMMUTABLE.getCacheName());
+ accountImmutableCache.remove(UUID.fromString(accountId));
+
+ // clear account-bcd cache by accountId
+ final Ehcache accountBcdCache = cacheManager.getEhcache(CacheType.ACCOUNT_BCD.getCacheName());
+ accountBcdCache.remove(UUID.fromString(accountId));
+
+ return Response.status(Status.OK).build();
+ }
+
+ @DELETE
+ @Path("/" + CACHE + "/" + TENANTS)
+ @Produces(APPLICATION_JSON)
+ @ApiOperation(value = "Invalidates Caches per tenant level")
+ @ApiResponses(value = {})
+ public Response invalidatesCacheByTenant(@QueryParam("tenantApiKey") final String tenantApiKey,
+ @javax.ws.rs.core.Context final HttpServletRequest request) throws TenantApiException {
+
+ // creating Tenant Context from Request
+ TenantContext tenantContext = context.createContext(request);
+
+ Tenant currentTenant = tenantApi.getTenantById(tenantContext.getTenantId());
+
+ // getting Tenant Record Id
+ Long tenantRecordId = recordIdApi.getRecordId(tenantContext.getTenantId(), ObjectType.TENANT, tenantContext);
+
+ // clear tenant-record-id cache by tenantId
+ final Ehcache tenantRecordIdCache = cacheManager.getEhcache(CacheType.TENANT_RECORD_ID.getCacheName());
+ tenantRecordIdCache.remove(currentTenant.getId().toString());
+
+ // clear tenant-payment-state-machine-config cache by tenantRecordId
+ final Ehcache tenantPaymentStateMachineConfigCache = cacheManager.getEhcache(CacheType.TENANT_PAYMENT_STATE_MACHINE_CONFIG.getCacheName());
+ removeCacheByKey(tenantPaymentStateMachineConfigCache, tenantRecordId.toString());
+
+ // clear tenant cache by tenantApiKey
+ final Ehcache tenantCache = cacheManager.getEhcache(CacheType.TENANT.getCacheName());
+ tenantCache.remove(currentTenant.getApiKey());
+
+ // clear tenant-kv cache by tenantRecordId
+ final Ehcache tenantKvCache = cacheManager.getEhcache(CacheType.TENANT_KV.getCacheName());
+ removeCacheByKey(tenantKvCache, tenantRecordId.toString());
+
+ // clear tenant-config cache by tenantRecordId
+ final Ehcache tenantConfigCache = cacheManager.getEhcache(CacheType.TENANT_CONFIG.getCacheName());
+ tenantConfigCache.remove(tenantRecordId);
+
+ // clear tenant-overdue-config cache by tenantRecordId
+ final Ehcache tenantOverdueConfigCache = cacheManager.getEhcache(CacheType.TENANT_OVERDUE_CONFIG.getCacheName());
+ tenantOverdueConfigCache.remove(tenantRecordId);
+
+ // clear tenant-catalog cache by tenantRecordId
+ final Ehcache tenantCatalogCache = cacheManager.getEhcache(CacheType.TENANT_CATALOG.getCacheName());
+ tenantCatalogCache.remove(tenantRecordId);
+
+ return Response.status(Status.OK).build();
+ }
+
+ private void removeCacheByKey(final Ehcache tenantCache, final String tenantRecordId) {
+ for (Object key : tenantCache.getKeys()) {
+ if (null != key && key.toString().endsWith("::" + tenantRecordId)) {
+ tenantCache.remove(key);
+ }
+ }
+ }
+
}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
index 89473ac..808aba0 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
@@ -256,6 +256,8 @@ public interface JaxrsResource {
public static final String FORM = "form";
public static final String NOTIFICATION = "notification";
+ public static final String CANCEL_SCHEDULED_PAYMENT_TRANSACTION = "cancelScheduledPaymentTransaction";
+
public static final String INVOICE_TEMPLATE = "template";
public static final String INVOICE_MP_TEMPLATE = "manualPayTemplate";
@@ -270,6 +272,8 @@ public interface JaxrsResource {
public static final String BCD = "bcd";
public static final String TRANSFER_CREDIT = "transferCredit";
+ public static final String CACHE = "cache";
+
public static final String QUERY_INCLUDED_DELETED = "includedDeleted";
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
index 6b47e30..e0e13b8 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
@@ -784,6 +784,45 @@ public class PaymentResource extends ComboPaymentResource {
return createPaymentResponse(uriInfo, result, transactionType, paymentTransactionJson.getTransactionExternalKey());
}
+ @TimedResource(name = "cancelScheduledPaymentTransaction")
+ @DELETE
+ @Path("/{paymentTransactionId:" + UUID_PATTERN + "}/" + CANCEL_SCHEDULED_PAYMENT_TRANSACTION)
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ @ApiOperation(value = "Cancels a scheduled payment attempt retry")
+ @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid paymentTransactionId supplied")})
+ public Response cancelScheduledPaymentTransactionById(@PathParam("paymentTransactionId") final String paymentTransactionId,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment,
+ @javax.ws.rs.core.Context final UriInfo uriInfo,
+ @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
+ final CallContext callContext = context.createContext(createdBy, reason, comment, request);
+ paymentApi.cancelScheduledPaymentTransaction(UUID.fromString(paymentTransactionId), callContext);
+ return Response.status(Status.OK).build();
+ }
+
+ @TimedResource(name = "cancelScheduledPaymentTransaction")
+ @DELETE
+ @Path("/" + CANCEL_SCHEDULED_PAYMENT_TRANSACTION)
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ @ApiOperation(value = "Cancels a scheduled payment attempt retry")
+ @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid paymentTransactionExternalKey supplied")})
+ public Response cancelScheduledPaymentTransactionByExternalKey(@QueryParam(QUERY_TRANSACTION_EXTERNAL_KEY) final String paymentTransactionExternalKey,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment,
+ @javax.ws.rs.core.Context final UriInfo uriInfo,
+ @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
+ final CallContext callContext = context.createContext(createdBy, reason, comment, request);
+ paymentApi.cancelScheduledPaymentTransaction(paymentTransactionExternalKey, callContext);
+ return Response.status(Status.OK).build();
+ }
+
+
+
+
@TimedResource
@GET
@Path("/{paymentId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
index 563e877..8a9a799 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
@@ -173,10 +173,12 @@ public class SubscriptionResource extends JaxRsResourceBase {
@javax.ws.rs.core.Context final HttpServletRequest request,
@javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
verifyNonNullOrEmpty(entitlement, "SubscriptionJson body should be specified");
- verifyNonNullOrEmpty(entitlement.getProductName(), "SubscriptionJson productName needs to be set",
- entitlement.getProductCategory(), "SubscriptionJson productCategory needs to be set",
- entitlement.getBillingPeriod(), "SubscriptionJson billingPeriod needs to be set",
- entitlement.getPriceList(), "SubscriptionJson priceList needs to be set");
+ if (entitlement.getPlanName() == null) {
+ verifyNonNullOrEmpty(entitlement.getProductName(), "SubscriptionJson productName needs to be set",
+ entitlement.getProductCategory(), "SubscriptionJson productCategory needs to be set",
+ entitlement.getBillingPeriod(), "SubscriptionJson billingPeriod needs to be set",
+ entitlement.getPriceList(), "SubscriptionJson priceList needs to be set");
+ }
logDeprecationParameterWarningIfNeeded(QUERY_REQUESTED_DT, QUERY_ENTITLEMENT_REQUESTED_DT, QUERY_BILLING_REQUESTED_DT);
@@ -195,15 +197,14 @@ public class SubscriptionResource extends JaxRsResourceBase {
final Account account = getAccountFromSubscriptionJson(entitlement, callContext);
final PhaseType phaseType = entitlement.getPhaseType() != null ? PhaseType.valueOf(entitlement.getPhaseType()) : null;
- final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(entitlement.getProductName(),
+ final PlanPhaseSpecifier spec = entitlement.getPlanName() != null ?
+ new PlanPhaseSpecifier(entitlement.getPlanName(), phaseType) :
+ new PlanPhaseSpecifier(entitlement.getProductName(),
BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList(), phaseType);
final LocalDate resolvedEntitlementDate = requestedDate != null ? toLocalDate(requestedDate) : toLocalDate(entitlementDate);
final LocalDate resolvedBillingDate = requestedDate != null ? toLocalDate(requestedDate) : toLocalDate(billingDate);
- final PlanSpecifier planSpec = new PlanSpecifier(entitlement.getProductName(),
- BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList());
-
- final List<PlanPhasePriceOverride> overrides = PhasePriceOverrideJson.toPlanPhasePriceOverrides(entitlement.getPriceOverrides(), planSpec, account.getCurrency());
+ final List<PlanPhasePriceOverride> overrides = PhasePriceOverrideJson.toPlanPhasePriceOverrides(entitlement.getPriceOverrides(), spec, account.getCurrency());
final Entitlement result = createAddOnEntitlement ?
entitlementApi.addEntitlement(getBundleIdForAddOnCreation(entitlement), spec, overrides, resolvedEntitlementDate, resolvedBillingDate, isMigrated, pluginProperties, callContext) :
entitlementApi.createBaseEntitlement(account.getId(), spec, entitlement.getExternalKey(), overrides, resolvedEntitlementDate, resolvedBillingDate, isMigrated, pluginProperties, callContext);
@@ -263,10 +264,12 @@ public class SubscriptionResource extends JaxRsResourceBase {
for (SubscriptionJson entitlement : entitlements) {
verifyNonNullOrEmpty(entitlement, "SubscriptionJson body should be specified for each element");
- verifyNonNullOrEmpty(entitlement.getProductName(), "SubscriptionJson productName needs to be set for each element",
- entitlement.getProductCategory(), "SubscriptionJson productCategory needs to be set for each element",
- entitlement.getBillingPeriod(), "SubscriptionJson billingPeriod needs to be set for each element",
- entitlement.getPriceList(), "SubscriptionJson priceList needs to be set for each element");
+ if (entitlement.getPlanName() == null) {
+ verifyNonNullOrEmpty(entitlement.getProductName(), "SubscriptionJson productName needs to be set for each element",
+ entitlement.getProductCategory(), "SubscriptionJson productCategory needs to be set for each element",
+ entitlement.getBillingPeriod(), "SubscriptionJson billingPeriod needs to be set for each element",
+ entitlement.getPriceList(), "SubscriptionJson priceList needs to be set for each element");
+ }
}
logDeprecationParameterWarningIfNeeded(QUERY_REQUESTED_DT, QUERY_ENTITLEMENT_REQUESTED_DT, QUERY_BILLING_REQUESTED_DT);
@@ -309,12 +312,11 @@ public class SubscriptionResource extends JaxRsResourceBase {
for (final SubscriptionJson entitlement : entitlements) {
- final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier(entitlement.getProductName(),
+ final PlanPhaseSpecifier planPhaseSpecifier = entitlement.getPlanName() != null ?
+ new PlanPhaseSpecifier(entitlement.getPlanName(), null) :
+ new PlanPhaseSpecifier(entitlement.getProductName(),
BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList(), null);
-
- final PlanSpecifier planSpec = new PlanSpecifier(entitlement.getProductName(),
- BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList());
- final List<PlanPhasePriceOverride> overrides = PhasePriceOverrideJson.toPlanPhasePriceOverrides(entitlement.getPriceOverrides(), planSpec, account.getCurrency());
+ final List<PlanPhasePriceOverride> overrides = PhasePriceOverrideJson.toPlanPhasePriceOverrides(entitlement.getPriceOverrides(), planPhaseSpecifier, account.getCurrency());
EntitlementSpecifier specifier = new EntitlementSpecifier() {
@@ -394,9 +396,11 @@ public class SubscriptionResource extends JaxRsResourceBase {
@HeaderParam(HDR_COMMENT) final String comment,
@javax.ws.rs.core.Context final HttpServletRequest request) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
verifyNonNullOrEmpty(entitlement, "SubscriptionJson body should be specified");
- verifyNonNullOrEmpty(entitlement.getProductName(), "SubscriptionJson productName needs to be set",
- entitlement.getBillingPeriod(), "SubscriptionJson billingPeriod needs to be set",
- entitlement.getPriceList(), "SubscriptionJson priceList needs to be set");
+ if (entitlement.getPlanName() == null) {
+ verifyNonNullOrEmpty(entitlement.getProductName(), "SubscriptionJson productName needs to be set",
+ entitlement.getBillingPeriod(), "SubscriptionJson billingPeriod needs to be set",
+ entitlement.getPriceList(), "SubscriptionJson priceList needs to be set");
+ }
final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
final CallContext callContext = context.createContext(createdBy, reason, comment, request);
@@ -415,17 +419,19 @@ public class SubscriptionResource extends JaxRsResourceBase {
final Entitlement newEntitlement;
final Account account = accountUserApi.getAccountById(current.getAccountId(), callContext);
- final PlanSpecifier planSpec = new PlanSpecifier(entitlement.getProductName(),
+ final PlanSpecifier planSpec = entitlement.getPlanName() != null ?
+ new PlanSpecifier(entitlement.getPlanName()) :
+ new PlanSpecifier(entitlement.getProductName(),
BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList());
final List<PlanPhasePriceOverride> overrides = PhasePriceOverrideJson.toPlanPhasePriceOverrides(entitlement.getPriceOverrides(), planSpec, account.getCurrency());
if (requestedDate == null && policyString == null) {
- newEntitlement = current.changePlan(entitlement.getProductName(), BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList(), overrides, pluginProperties, ctx);
+ newEntitlement = current.changePlan(planSpec, overrides, pluginProperties, ctx);
} else if (policyString == null) {
- newEntitlement = current.changePlanWithDate(entitlement.getProductName(), BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList(), overrides, inputLocalDate, pluginProperties, ctx);
+ newEntitlement = current.changePlanWithDate(planSpec, overrides, inputLocalDate, pluginProperties, ctx);
} else {
final BillingActionPolicy policy = BillingActionPolicy.valueOf(policyString.toUpperCase());
- newEntitlement = current.changePlanOverrideBillingPolicy(entitlement.getProductName(), BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList(), overrides, inputLocalDate, policy, pluginProperties, ctx);
+ newEntitlement = current.changePlanOverrideBillingPolicy(planSpec, overrides, inputLocalDate, policy, pluginProperties, ctx);
}
isImmediateOp = newEntitlement.getLastActiveProduct().getName().equals(entitlement.getProductName()) &&
newEntitlement.getLastActivePlan().getRecurringBillingPeriod() == BillingPeriod.valueOf(entitlement.getBillingPeriod()) &&
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountJson.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountJson.java
index 240b0eb..b601e7c 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountJson.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountJson.java
@@ -49,6 +49,7 @@ public class TestAccountJson extends JaxrsTestSuiteNoDB {
final String country = UUID.randomUUID().toString();
final String locale = UUID.randomUUID().toString();
final String phone = UUID.randomUUID().toString();
+ final String notes = UUID.randomUUID().toString();
final Boolean isMigrated = true;
final Boolean isNotifiedForInvoice = false;
final String parentAccountId = UUID.randomUUID().toString();
@@ -56,7 +57,7 @@ public class TestAccountJson extends JaxrsTestSuiteNoDB {
final AccountJson accountJson = new AccountJson(accountId, name, length, externalKey,
email, billCycleDayLocal, currency, parentAccountId, true, paymentMethodId,
timeZone, address1, address2, postalCode, company, city, state,
- country, locale, phone, isMigrated, isNotifiedForInvoice, null, null, null);
+ country, locale, phone, notes, isMigrated, isNotifiedForInvoice, null, null, null);
Assert.assertEquals(accountJson.getAccountId(), accountId);
Assert.assertEquals(accountJson.getName(), name);
Assert.assertEquals(accountJson.getFirstNameLength(), length);
@@ -75,6 +76,7 @@ public class TestAccountJson extends JaxrsTestSuiteNoDB {
Assert.assertEquals(accountJson.getCountry(), country);
Assert.assertEquals(accountJson.getLocale(), locale);
Assert.assertEquals(accountJson.getPhone(), phone);
+ Assert.assertEquals(accountJson.getNotes(), notes);
Assert.assertEquals(accountJson.isMigrated(), isMigrated);
Assert.assertEquals(accountJson.isNotifiedForInvoices(), isNotifiedForInvoice);
Assert.assertEquals(accountJson.getParentAccountId(), parentAccountId);
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
index b700827..3dcd46f 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
@@ -69,6 +69,7 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuiteNoDB {
UUID.randomUUID().toString(),
UUID.randomUUID().toString(),
UUID.randomUUID().toString(),
+ UUID.randomUUID().toString(),
new LocalDate(),
new LocalDate(),
new LocalDate(),
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestEntitlementJsonWithEvents.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestEntitlementJsonWithEvents.java
index 529fc5a..f9e58bb 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestEntitlementJsonWithEvents.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestEntitlementJsonWithEvents.java
@@ -76,6 +76,7 @@ public class TestEntitlementJsonWithEvents extends JaxrsTestSuiteNoDB {
UUID.randomUUID().toString(),
UUID.randomUUID().toString(),
UUID.randomUUID().toString(),
+ UUID.randomUUID().toString(),
new LocalDate(),
new LocalDate(),
new LocalDate(),
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
index a73e8f2..fa032bb 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
@@ -237,19 +237,13 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
final Plan nextPlan = (transition.getNextPlan() != null) ? catalog.findPlan(transition.getNextPlan(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
final Plan plan = (transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ? nextPlan : prevPlan;
- final Product product = plan.getProduct();
final PlanPhase prevPhase = (transition.getPreviousPhase() != null) ? catalog.findPhase(transition.getPreviousPhase(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
final PlanPhase nextPhase = (transition.getNextPhase() != null) ? catalog.findPhase(transition.getNextPhase(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
-
final PlanPhase phase = (transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ? nextPhase : prevPhase;
- final BillingPeriod billingPeriod = phase.getRecurring() != null ? phase.getRecurring().getBillingPeriod() : BillingPeriod.NO_BILLING_PERIOD;
+ return new PlanPhaseSpecifier(plan.getName(), phase.getPhaseType());
- return new PlanPhaseSpecifier(product.getName(),
- billingPeriod,
- transition.getNextPriceList(),
- phase.getPhaseType());
}
private boolean is_AUTO_INVOICING_OFF(final List<Tag> tags) {
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
index f1430b9..d25b23d 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
@@ -596,6 +596,18 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
}
@Override
+ public void cancelScheduledPaymentTransaction(final String paymentTransactionExternalKey, final CallContext callContext) throws PaymentApiException {
+ checkNotNullParameter(paymentTransactionExternalKey, "paymentTransactionExternalKey");
+ paymentProcessor.cancelScheduledPaymentTransaction(null, paymentTransactionExternalKey, callContext);
+ }
+
+ @Override
+ public void cancelScheduledPaymentTransaction(final UUID paymentTransactionId, final CallContext callContext) throws PaymentApiException {
+ checkNotNullParameter(paymentTransactionId, "paymentTransactionId");
+ paymentProcessor.cancelScheduledPaymentTransaction(paymentTransactionId, null, callContext);
+ }
+
+ @Override
public Payment notifyPendingTransactionOfStateChanged(final Account account, final UUID paymentTransactionId, final boolean isSuccess, final CallContext callContext) throws PaymentApiException {
checkNotNullParameter(account, "account");
checkNotNullParameter(paymentTransactionId, "paymentTransactionId");
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
index c57de1c..e8981f9 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
@@ -353,6 +353,43 @@ public class PaymentProcessor extends ProcessorBase {
);
}
+ public void cancelScheduledPaymentTransaction(@Nullable final UUID paymentTransactionId, @Nullable final String paymentTransactionExternalKey, final CallContext callContext) throws PaymentApiException {
+
+ final InternalCallContext internalCallContextWithoutAccountRecordId = internalCallContextFactory.createInternalCallContextWithoutAccountRecordId(callContext);
+ final String effectivePaymentTransactionExternalKey;
+ if (paymentTransactionExternalKey == null) {
+ final PaymentTransactionModelDao transaction = paymentDao.getPaymentTransaction(paymentTransactionId, internalCallContextWithoutAccountRecordId);
+ effectivePaymentTransactionExternalKey = transaction.getTransactionExternalKey();
+ } else {
+ effectivePaymentTransactionExternalKey = paymentTransactionExternalKey;
+ }
+
+ final List<PaymentAttemptModelDao> attempts = paymentDao.getPaymentAttemptByTransactionExternalKey(effectivePaymentTransactionExternalKey, internalCallContextWithoutAccountRecordId);
+ if (attempts.isEmpty()) {
+ return;
+ }
+
+ final PaymentAttemptModelDao lastPaymentAttempt = attempts.get(attempts.size() - 1);
+ final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(lastPaymentAttempt.getAccountId(), callContext);
+
+ try {
+ final NotificationQueue retryQueue = notificationQueueService.getNotificationQueue(DefaultPaymentService.SERVICE_NAME, DefaultRetryService.QUEUE_NAME);
+ final List<NotificationEventWithMetadata<NotificationEvent>> notificationEventWithMetadatas =
+ retryQueue.getFutureNotificationForSearchKeys(internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId());
+
+ for (final NotificationEventWithMetadata<NotificationEvent> notificationEvent : notificationEventWithMetadatas) {
+ if (((PaymentRetryNotificationKey) notificationEvent.getEvent()).getAttemptId().equals(lastPaymentAttempt.getId())) {
+ retryQueue.removeNotification(notificationEvent.getRecordId());
+ break;
+ }
+ }
+ } catch (final NoSuchNotificationQueue noSuchNotificationQueue) {
+ log.error("ERROR Loading Notification Queue - " + noSuchNotificationQueue.getMessage());
+ throw new IllegalStateException(noSuchNotificationQueue);
+ }
+ }
+
+
private Payment performOperation(final boolean isApiPayment,
@Nullable final UUID attemptId,
final TransactionType transactionType,
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index 03d6a18..8c91c40 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
<parent>
<artifactId>killbill-oss-parent</artifactId>
<groupId>org.kill-bill.billing</groupId>
- <version>0.124-SNAPSHOT</version>
+ <version>0.127-SNAPSHOT</version>
</parent>
<artifactId>killbill</artifactId>
<version>0.17.3-SNAPSHOT</version>
diff --git a/profiles/killbill/src/main/resources/killbill-server.properties b/profiles/killbill/src/main/resources/killbill-server.properties
index 1790759..19f583a 100644
--- a/profiles/killbill/src/main/resources/killbill-server.properties
+++ b/profiles/killbill/src/main/resources/killbill-server.properties
@@ -22,7 +22,7 @@ org.killbill.jruby.context.version=RUBY2_0
# KILLBILL GENERIC PROPERTIES
#
# Database config
-org.killbill.dao.url=jdbc:mysql://127.0.0.1:3306/killbill
+org.killbill.dao.url=jdbc:mysql://127.0.0.1:3306/killbill_0_17_x
org.killbill.dao.user=root
org.killbill.dao.password=root
org.killbill.dao.logLevel=DEBUG
@@ -61,7 +61,7 @@ org.killbill.tenant.broadcast.rate=1s
# PLUGIN SPECIFIC PROPERTIES
#
# Database config (OSGI plugins)
-org.killbill.billing.osgi.dao.url=jdbc:mysql://127.0.0.1:3306/killbill
+org.killbill.billing.osgi.dao.url=jdbc:mysql://127.0.0.1:3306/killbill_0_17_x
org.killbill.billing.osgi.dao.user=root
org.killbill.billing.osgi.dao.password=root
@@ -82,7 +82,8 @@ org.killbill.server.test.mode=true
# Set payment calls to timeout after 5 sec -- mostly for integration tests
org.killbill.payment.plugin.timeout=5s
-org.killbill.payment.retry.days=
+org.killbill.payment.retry.days=1,1,1
+
org.killbill.notificationq.analytics.tableName=analytics_notifications
org.killbill.notificationq.analytics.historyTableName=analytics_notifications_history
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
index 4854bc7..8672065 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
@@ -236,11 +236,12 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
final String country = "France";
final String locale = "fr";
final String phone = "81 53 26 56";
+ final String notes = "notes";
final boolean isPaymentDelegatedToParent = parentAccountId != null;
// Note: the accountId payload is ignored on account creation
return new Account(accountId, name, length, externalKey, email, null, currency, parentAccountId, isPaymentDelegatedToParent, null, timeZone,
- address1, address2, postalCode, company, city, state, country, locale, phone, false, false, null, null);
+ address1, address2, postalCode, company, city, state, country, locale, phone, notes, false, false, null, null);
}
/**
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccount.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccount.java
index f1a2074..d714352 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccount.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccount.java
@@ -118,7 +118,7 @@ public class TestAccount extends TestJaxrsBase {
"zozo", 4, input.getExternalKey(), "rr@google.com", 18,
"USD", null, false, null, "UTC",
"bl1", "bh2", "", "", "ca", "San Francisco", "usa", "en", "415-255-2991",
- false, false, null, null);
+ "notes", false, false, null, null);
final Account updatedAccount = killBillClient.updateAccount(newInput, createdBy, reason, comment);
Assert.assertTrue(updatedAccount.equals(newInput));
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCache.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCache.java
new file mode 100644
index 0000000..23325ad
--- /dev/null
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCache.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2016 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.jaxrs;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.PriceListSet;
+import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.client.RequestOptions;
+import org.killbill.billing.client.model.Account;
+import org.killbill.billing.client.model.PaymentMethod;
+import org.killbill.billing.client.model.PaymentMethodPluginDetail;
+import org.killbill.billing.client.model.Subscription;
+import org.killbill.billing.client.model.Tenant;
+import org.killbill.billing.util.cache.Cachable.CacheType;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.io.Resources;
+import net.sf.ehcache.Ehcache;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+public class TestCache extends TestJaxrsBase {
+
+ @Test(groups = "slow", description = "Can Invalidate (clear) a Cache by name")
+ public void testInvalidateCacheByName() throws Exception {
+ // get Ehcache item with name "record-id"
+ final Ehcache cache = cacheManager.getEhcache(CacheType.RECORD_ID.getCacheName());
+ // verify that it is not null and has one stored key (the default tenant created for all integration tests)
+ assertNotNull(cache);
+ Assert.assertEquals(cache.getSize(), 1);
+
+ // invalidate the specified cache
+ killBillClient.invalidateCacheByName(cache.getName(), requestOptions);
+
+ // verify that now the cache is empty and has no keys stored
+ Assert.assertEquals(cache.getSize(), 0);
+ }
+
+ @Test(groups = "slow", description = "Can Invalidate (clear) all available Caches")
+ public void testInvalidateAllCaches() throws Exception {
+ // get Ehcache item with name "record-id"
+ final Ehcache cache = cacheManager.getEhcache(CacheType.RECORD_ID.getCacheName());
+ // verify that it is not null and has one stored key (the default tenant created for all integration tests)
+ assertNotNull(cache);
+ Assert.assertEquals(cache.getSize(), 1);
+
+ // invalidate all caches
+ killBillClient.invalidateAllCaches(requestOptions);
+
+ // verify that now the cache is empty and has no keys stored
+ Assert.assertEquals(cache.getSize(), 0);
+ }
+
+ @Test(groups = "slow", description = "Can Invalidate (clear) all Account Caches by accountId")
+ public void testInvalidateCacheByAccount() throws Exception {
+ final Account input = createAccountNoPMBundleAndSubscription();
+
+ // get all caches per account level
+ final Ehcache accountRecordIdCache = cacheManager.getEhcache(CacheType.ACCOUNT_RECORD_ID.getCacheName());
+ final Ehcache accountImmutableCache = cacheManager.getEhcache(CacheType.ACCOUNT_IMMUTABLE.getCacheName());
+ final Ehcache accountBcdCache = cacheManager.getEhcache(CacheType.ACCOUNT_BCD.getCacheName());
+
+ // verify that they are not null and have the accountId stored as a key (the account created before)
+ assertNotNull(accountRecordIdCache);
+ assertNotNull(accountRecordIdCache.get(input.getAccountId().toString()));
+ assertNotNull(accountImmutableCache);
+ assertNotNull(accountImmutableCache.get(input.getAccountId()));
+ assertNotNull(accountBcdCache);
+ assertNotNull(accountBcdCache.get(input.getAccountId()));
+
+ // invalidate caches per account level by accountId
+ killBillClient.invalidateCacheByAccount(input.getAccountId().toString(), requestOptions);
+
+ // verify that now the caches don't have the accountId key stored
+ Assert.assertNull(accountRecordIdCache.get(input.getAccountId().toString()));
+ Assert.assertNull(accountImmutableCache.get(input.getAccountId()));
+ Assert.assertNull(accountBcdCache.get(input.getAccountId()));
+ }
+
+ @Test(groups = "slow", description = "Can Invalidate (clear) all Tenant Caches for current Tenant")
+ public void testInvalidateCacheByTenant() throws Exception {
+ // creating a new Tenant for this test
+ final String testApiKey = "testApiKey";
+ final String testApiSecret = "testApiSecret";
+ final Tenant tenant = new Tenant();
+ tenant.setApiKey(testApiKey);
+ tenant.setApiSecret(testApiSecret);
+ loginTenant(testApiKey, testApiSecret);
+ Tenant currentTenant = killBillClient.createTenant(tenant, false, requestOptions);
+
+ // using custom RequestOptions with the new Tenant created before
+ RequestOptions inputOptions = RequestOptions.builder()
+ .withCreatedBy(createdBy)
+ .withReason(reason)
+ .withComment(comment)
+ .withTenantApiKey(currentTenant.getApiKey())
+ .withTenantApiSecret(currentTenant.getApiSecret())
+ .build();
+
+ // Uploading the test catalog using the new Tenant created before
+ killBillClient.uploadXMLCatalog(Resources.getResource("SpyCarAdvanced.xml").getPath(), inputOptions);
+
+ // creating an Account with PaymentMethod and a Subscription
+ createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoiceWithInputOptions(inputOptions);
+
+ // get all caches per tenant level
+ final Ehcache tenantRecordIdCache = cacheManager.getEhcache(CacheType.TENANT_RECORD_ID.getCacheName());
+ final Ehcache tenantPaymentStateMachineConfigCache = cacheManager.getEhcache(CacheType.TENANT_PAYMENT_STATE_MACHINE_CONFIG.getCacheName());
+ final Ehcache tenantCache = cacheManager.getEhcache(CacheType.TENANT.getCacheName());
+ final Ehcache tenantKvCache = cacheManager.getEhcache(CacheType.TENANT_KV.getCacheName());
+ final Ehcache tenantConfigCache = cacheManager.getEhcache(CacheType.TENANT_CONFIG.getCacheName());
+ final Ehcache tenantOverdueConfigCache = cacheManager.getEhcache(CacheType.TENANT_OVERDUE_CONFIG.getCacheName());
+ final Ehcache tenantCatalogCache = cacheManager.getEhcache(CacheType.TENANT_CATALOG.getCacheName());
+
+ // getting current Tenant's record Id from the specific Cache
+ Long tenantRecordId = (Long) tenantRecordIdCache.get(currentTenant.getTenantId().toString()).getObjectValue();
+
+ // verify that they are not null and have the expected tenant information
+ assertNotNull(tenantRecordIdCache);
+ assertNotNull(tenantRecordIdCache.get(currentTenant.getTenantId().toString()));
+ assertNotNull(tenantPaymentStateMachineConfigCache);
+ assertTrue(hasKeysByTenantRecordId(tenantPaymentStateMachineConfigCache, tenantRecordId.toString()));
+ assertNotNull(tenantCache);
+ assertNotNull(tenantCache.get(testApiKey));
+ assertNotNull(tenantKvCache);
+ assertTrue(hasKeysByTenantRecordId(tenantKvCache, tenantRecordId.toString()));
+ assertNotNull(tenantConfigCache);
+ assertNotNull(tenantConfigCache.get(tenantRecordId));
+ assertNotNull(tenantOverdueConfigCache);
+ assertNotNull(tenantOverdueConfigCache.get(tenantRecordId));
+ assertNotNull(tenantCatalogCache);
+ assertNotNull(tenantCatalogCache.get(tenantRecordId));
+
+ // invalidate caches per tenant level
+ killBillClient.invalidateCacheByTenant(inputOptions);
+
+ // verify that now the caches don't have the previous values
+ Assert.assertNull(tenantRecordIdCache.get(currentTenant.getTenantId().toString()));
+ assertFalse(hasKeysByTenantRecordId(tenantPaymentStateMachineConfigCache, tenantRecordId.toString()));
+ Assert.assertNull(tenantCache.get(testApiKey));
+ assertFalse(hasKeysByTenantRecordId(tenantKvCache, tenantRecordId.toString()));
+ Assert.assertNull(tenantConfigCache.get(tenantRecordId));
+ Assert.assertNull(tenantOverdueConfigCache.get(tenantRecordId));
+ Assert.assertNull(tenantCatalogCache.get(tenantRecordId));
+ }
+
+ private boolean hasKeysByTenantRecordId(final Ehcache tenantCache, final String tenantRecordId) {
+ for (String key : (List<String>) tenantCache.getKeys()) {
+ if (key.endsWith("::" + tenantRecordId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoiceWithInputOptions(final RequestOptions inputOptions) throws Exception {
+ Account account = killBillClient.createAccount(getAccount(), inputOptions);
+
+ final PaymentMethodPluginDetail info = new PaymentMethodPluginDetail();
+ info.setProperties(null);
+ final PaymentMethod paymentMethodJson = new PaymentMethod(null, UUID.randomUUID().toString(), account.getAccountId(), true, PLUGIN_NAME, info);
+ killBillClient.createPaymentMethod(paymentMethodJson, inputOptions);
+
+ final Subscription subscription = new Subscription();
+ subscription.setAccountId(account.getAccountId());
+ subscription.setExternalKey(UUID.randomUUID().toString());
+ subscription.setProductName("Sports");
+ subscription.setProductCategory(ProductCategory.BASE);
+ subscription.setBillingPeriod(BillingPeriod.MONTHLY);
+ subscription.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
+
+ clock.resetDeltaFromReality();
+ clock.setDay(new LocalDate(2013, 3, 1));
+ final Subscription subscriptionJson = killBillClient.createSubscription(subscription, clock.getUTCToday(), DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, inputOptions);
+
+ assertNotNull(subscriptionJson);
+ clock.addDays(32);
+ crappyWaitForLackOfProperSynchonization();
+ }
+}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
index 4acd0cd..84f3d50 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
@@ -52,17 +52,10 @@ public class TestCatalog extends TestJaxrsBase {
@Test(groups = "slow", description = "Upload and retrieve a per tenant catalog")
public void testMultiTenantCatalog() throws Exception {
- final String versionPath1 = Resources.getResource("versionedCatalog/WeaponsHireSmall-1.xml").getPath();
+ final String versionPath1 = Resources.getResource("SpyCarBasic.xml").getPath();
killBillClient.uploadXMLCatalog(versionPath1, createdBy, reason, comment);
String catalog = killBillClient.getXMLCatalog();
Assert.assertNotNull(catalog);
-
-
- final String versionPath2 = Resources.getResource("versionedCatalog/WeaponsHireSmall-2.xml").getPath();
- killBillClient.uploadXMLCatalog(versionPath2, createdBy, reason, comment);
- catalog = killBillClient.getXMLCatalog();
- Assert.assertNotNull(catalog);
-
//
// We can't deserialize the VersionedCatalog using our JAXB models because it contains several
// Standalone catalog and ids (JAXB name) are not unique across the various catalogs so deserialization would fail
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
index cdc1368..a298dc3 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
@@ -26,6 +26,8 @@ import java.util.UUID;
import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.DefaultPriceList;
+import org.killbill.billing.catalog.DefaultPriceListSet;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.PhaseType;
@@ -365,4 +367,37 @@ public class TestEntitlement extends TestJaxrsBase {
}
+
+ @Test(groups = "slow", description = "Can create subscription and change plan using planName")
+ public void testEntitlementUsingPlanName() throws Exception {
+ final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
+ clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
+
+ final Account accountJson = createAccountWithDefaultPaymentMethod();
+
+ final Subscription input = new Subscription();
+ input.setAccountId(accountJson.getAccountId());
+ input.setExternalKey("somethingSpecial");
+ input.setPlanName("shotgun-monthly");
+
+ final Subscription entitlementJson = killBillClient.createSubscription(input, null, DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, basicRequestOptions());
+ Assert.assertEquals(entitlementJson.getProductName(), "Shotgun");
+ Assert.assertEquals(entitlementJson.getBillingPeriod(), BillingPeriod.MONTHLY);
+ Assert.assertEquals(entitlementJson.getPriceList(), DefaultPriceListSet.DEFAULT_PRICELIST_NAME);
+ Assert.assertEquals(entitlementJson.getPlanName(), "shotgun-monthly");
+
+
+ final Subscription newInput = new Subscription();
+ newInput.setAccountId(entitlementJson.getAccountId());
+ newInput.setSubscriptionId(entitlementJson.getSubscriptionId());
+ newInput.setPlanName("pistol-monthly");
+ final Subscription newEntitlementJson = killBillClient.updateSubscription(newInput, null, null, DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, basicRequestOptions());
+ Assert.assertEquals(newEntitlementJson.getProductName(), "Pistol");
+ Assert.assertEquals(newEntitlementJson.getBillingPeriod(), BillingPeriod.MONTHLY);
+ Assert.assertEquals(newEntitlementJson.getPriceList(), DefaultPriceListSet.DEFAULT_PRICELIST_NAME);
+ Assert.assertEquals(newEntitlementJson.getPlanName(), "pistol-monthly");
+
+ }
+
+
}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java
index 3498ba8..d4ec7bf 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestJaxrsBase.java
@@ -74,6 +74,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.inject.Module;
import com.google.inject.util.Modules;
+import net.sf.ehcache.CacheManager;
public class TestJaxrsBase extends KillbillClient {
@@ -106,6 +107,9 @@ public class TestJaxrsBase extends KillbillClient {
@Inject
protected TenantCacheInvalidation tenantCacheInvalidation;
+ @Inject
+ protected CacheManager cacheManager;
+
protected DaoConfig daoConfig;
protected KillbillServerConfig serverConfig;
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
index 9c418c8..0baeb5e 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
@@ -172,8 +172,16 @@ public class TestPayment extends TestJaxrsBase {
Assert.assertEquals(invoicePayments.get(0).getTargetInvoiceId(), failedInvoiceId);
Assert.assertNotNull(invoicePayments.get(0).getPaymentAttempts());
+ Assert.assertEquals(invoicePayments.get(0).getPaymentAttempts().size(), 2);
Assert.assertEquals(invoicePayments.get(0).getPaymentAttempts().get(0).getStateName(), "RETRIED");
Assert.assertEquals(invoicePayments.get(0).getPaymentAttempts().get(1).getStateName(), "SCHEDULED");
+
+
+ // Remove the future notification and check SCHEDULED does not appear any longer
+ killBillClient.cancelScheduledPaymentTransaction(null, invoicePayments.get(0).getPaymentAttempts().get(1).getTransactionExternalKey(), inputOptions);
+ invoicePayments = killBillClient.getInvoicePayment(failedInvoiceId, inputOptions);
+ Assert.assertEquals(invoicePayments.get(0).getPaymentAttempts().size(), 1);
+ Assert.assertEquals(invoicePayments.get(0).getPaymentAttempts().get(0).getStateName(), "RETRIED");
}
@Test(groups = "slow")
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java b/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
index c69fb70..0d9d275 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
@@ -38,7 +38,6 @@ import org.killbill.billing.catalog.api.PlanAlignmentCreate;
import org.killbill.billing.catalog.api.PlanPhase;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
import org.killbill.billing.catalog.api.PlanSpecifier;
-import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
import org.killbill.billing.subscription.api.user.SubscriptionBaseTransitionData;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
@@ -116,7 +115,7 @@ public class PlanAligner extends BaseAligner {
final String priceList,
final DateTime effectiveDate,
final InternalTenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
- return getTimedPhaseOnChange(subscription, plan, priceList, effectiveDate, WhichPhase.CURRENT, context);
+ return getTimedPhaseOnChange(subscription, plan, effectiveDate, WhichPhase.CURRENT, context);
}
/**
@@ -136,7 +135,7 @@ public class PlanAligner extends BaseAligner {
final String priceList,
final DateTime effectiveDate,
final InternalTenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
- return getTimedPhaseOnChange(subscription, plan, priceList, effectiveDate, WhichPhase.NEXT, context);
+ return getTimedPhaseOnChange(subscription, plan, effectiveDate, WhichPhase.NEXT, context);
}
/**
@@ -170,9 +169,7 @@ public class PlanAligner extends BaseAligner {
subscription.getBundleStartDate(),
lastPlanTransition.getPreviousPhase(),
lastPlanTransition.getPreviousPlan(),
- lastPlanTransition.getPreviousPriceList().getName(),
lastPlanTransition.getNextPlan(),
- lastPlanTransition.getNextPriceList().getName(),
effectiveDate,
lastPlanTransition.getEffectiveTransitionTime(),
subscription.getAllTransitions().get(0).getNextPhase().getPhaseType(),
@@ -197,9 +194,7 @@ public class PlanAligner extends BaseAligner {
throws CatalogApiException, SubscriptionBaseApiException {
final Catalog catalog = catalogService.getFullCatalog(true, true, context);
- final PlanSpecifier planSpecifier = new PlanSpecifier(plan.getProduct().getName(),
- plan.getRecurringBillingPeriod(),
- priceList);
+ final PlanSpecifier planSpecifier = new PlanSpecifier(plan.getName());
final DateTime planStartDate;
final PlanAlignmentCreate alignment = catalog.planCreateAlignment(planSpecifier, effectiveDate);
@@ -219,7 +214,6 @@ public class PlanAligner extends BaseAligner {
private TimedPhase getTimedPhaseOnChange(final DefaultSubscriptionBase subscription,
final Plan nextPlan,
- final String nextPriceList,
final DateTime effectiveDate,
final WhichPhase which,
final InternalTenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
@@ -227,9 +221,7 @@ public class PlanAligner extends BaseAligner {
subscription.getBundleStartDate(),
subscription.getCurrentPhase(),
subscription.getCurrentPlan(),
- subscription.getCurrentPriceList().getName(),
nextPlan,
- nextPriceList,
effectiveDate,
// This method is only called while doing the change, hence we want to pass the change effective date
effectiveDate,
@@ -242,25 +234,17 @@ public class PlanAligner extends BaseAligner {
final DateTime bundleStartDate,
final PlanPhase currentPhase,
final Plan currentPlan,
- final String currentPriceList,
final Plan nextPlan,
- final String priceList,
final DateTime effectiveDate,
final DateTime lastOrCurrentChangeEffectiveDate,
final PhaseType originalInitialPhase,
final WhichPhase which,
final InternalTenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
final Catalog catalog = catalogService.getFullCatalog(true, true, context);
- final ProductCategory currentCategory = currentPlan.getProduct().getCategory();
- final PlanPhaseSpecifier fromPlanPhaseSpecifier = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
- currentPlan.getRecurringBillingPeriod(),
- currentPriceList,
+ final PlanPhaseSpecifier fromPlanPhaseSpecifier = new PlanPhaseSpecifier(currentPlan.getName(),
currentPhase.getPhaseType());
- final PlanSpecifier toPlanSpecifier = new PlanSpecifier(nextPlan.getProduct().getName(),
- nextPlan.getRecurringBillingPeriod(),
- priceList);
-
+ final PlanSpecifier toPlanSpecifier = new PlanSpecifier(nextPlan.getName());
final PhaseType initialPhase;
final DateTime planStartDate;
final PlanAlignmentChange alignment = catalog.planChangeAlignment(fromPlanPhaseSpecifier, toPlanSpecifier, effectiveDate);
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java b/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
index c6c1855..dc345c6 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
@@ -31,6 +31,7 @@ import org.killbill.billing.catalog.api.PhaseType;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanChangeResult;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
import org.killbill.billing.subscription.api.user.SubscriptionBuilder;
@@ -65,28 +66,25 @@ public interface SubscriptionBaseApiService {
throws SubscriptionBaseApiException;
// Return the effective date of the change
- public DateTime dryRunChangePlan(DefaultSubscriptionBase subscription, String productName, BillingPeriod term,
- String priceList, DateTime requestedDate, BillingActionPolicy policy, TenantContext context) throws SubscriptionBaseApiException;
+ public DateTime dryRunChangePlan(DefaultSubscriptionBase subscription, PlanSpecifier spec, DateTime requestedDate, BillingActionPolicy policy, TenantContext context) throws SubscriptionBaseApiException;
// Return the effective date of the change
- public DateTime changePlan(DefaultSubscriptionBase subscription, String productName, BillingPeriod term,
- String priceList, List<PlanPhasePriceOverride> overrides, CallContext context)
+ public DateTime changePlan(DefaultSubscriptionBase subscription, PlanSpecifier spec, List<PlanPhasePriceOverride> overrides, CallContext context)
throws SubscriptionBaseApiException;
// Return the effective date of the change
- public DateTime changePlanWithRequestedDate(DefaultSubscriptionBase subscription, String productName, BillingPeriod term,
- String priceList, List<PlanPhasePriceOverride> overrides, DateTime requestedDate, CallContext context)
+ public DateTime changePlanWithRequestedDate(DefaultSubscriptionBase subscription, PlanSpecifier spec,
+ List<PlanPhasePriceOverride> overrides, DateTime requestedDate, CallContext context)
throws SubscriptionBaseApiException;
// Return the effective date of the change
- public DateTime changePlanWithPolicy(DefaultSubscriptionBase subscription, String productName, BillingPeriod term,
- String priceList, List<PlanPhasePriceOverride> overrides, BillingActionPolicy policy, CallContext context)
+ public DateTime changePlanWithPolicy(DefaultSubscriptionBase subscription, PlanSpecifier spec,
+ List<PlanPhasePriceOverride> overrides, BillingActionPolicy policy, CallContext context)
throws SubscriptionBaseApiException;
public int cancelAddOnsIfRequiredOnBasePlanEvent(final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent event, final CallContext context) throws CatalogApiException;
- public PlanChangeResult getPlanChangeResult(final DefaultSubscriptionBase subscription, final String productName,
- final BillingPeriod term, final String priceList, final DateTime effectiveDate, TenantContext context) throws SubscriptionBaseApiException;
+ public PlanChangeResult getPlanChangeResult(final DefaultSubscriptionBase subscription, PlanSpecifier spec, final DateTime effectiveDate, TenantContext context) throws SubscriptionBaseApiException;
//
// Lower level APIs for dryRun functionality
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
index 2046509..dbf1446 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
@@ -48,7 +48,6 @@ import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
import org.killbill.billing.catalog.api.PlanSpecifier;
-import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
import org.killbill.billing.entitlement.api.EntitlementAOStatusDryRun;
@@ -146,7 +145,6 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
@Override
public SubscriptionBase createSubscription(final UUID bundleId, final PlanPhaseSpecifier spec, final List<PlanPhasePriceOverride> overrides, final DateTime requestedDateWithMs, final boolean isMigrated, final InternalCallContext context) throws SubscriptionBaseApiException {
try {
- final String realPriceList = (spec.getPriceListName() == null) ? PriceListSet.DEFAULT_PRICELIST_NAME : spec.getPriceListName();
final DateTime now = clock.getUTCNow();
final DateTime effectiveDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
/*
@@ -159,11 +157,11 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
final Catalog catalog = catalogService.getFullCatalog(true, true, context);
final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(overrides, callContext);
- final Plan plan = catalog.createOrFindPlan(new PlanSpecifier(spec.getProductName(), spec.getBillingPeriod(), realPriceList), overridesWithContext, effectiveDate);
+ final Plan plan = catalog.createOrFindPlan(spec, overridesWithContext, effectiveDate);
final PlanPhase phase = plan.getAllPhases()[0];
if (phase == null) {
throw new SubscriptionBaseError(String.format("No initial PlanPhase for Product %s, term %s and set %s does not exist in the catalog",
- spec.getProductName(), spec.getBillingPeriod().toString(), realPriceList));
+ spec.getProductName(), spec.getBillingPeriod().toString(), plan.getPriceListName()));
}
final SubscriptionBaseBundle bundle = dao.getSubscriptionBundleFromId(bundleId, context);
@@ -180,7 +178,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
.setBundleStartDate(bundleStartDate)
.setAlignStartDate(effectiveDate)
.setMigrated(isMigrated),
- plan, spec.getPhaseType(), realPriceList, effectiveDate, now, callContext);
+ plan, spec.getPhaseType(), plan.getPriceListName(), effectiveDate, now, callContext);
} catch (final CatalogApiException e) {
throw new SubscriptionBaseApiException(e);
}
@@ -206,15 +204,14 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
for (EntitlementSpecifier entitlement : entitlements) {
final PlanPhaseSpecifier spec = entitlement.getPlanPhaseSpecifier();
- final String realPriceList = (spec.getPriceListName() == null) ? PriceListSet.DEFAULT_PRICELIST_NAME : spec.getPriceListName();
final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(entitlement.getOverrides(), callContext);
- final Plan plan = catalog.createOrFindPlan(new PlanSpecifier(spec.getProductName(), spec.getBillingPeriod(), realPriceList), overridesWithContext, effectiveDate);
+ final Plan plan = catalog.createOrFindPlan(spec, overridesWithContext, effectiveDate);
final PlanPhase phase = plan.getAllPhases()[0];
if (phase == null) {
throw new SubscriptionBaseError(String.format("No initial PlanPhase for Product %s, term %s and set %s does not exist in the catalog",
- spec.getProductName(), spec.getBillingPeriod().toString(), realPriceList));
+ spec.getProductName(), spec.getBillingPeriod().toString(), plan.getPriceListName()));
}
if (first) {
@@ -225,7 +222,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
}
SubscriptionSpecifier subscription = new SubscriptionSpecifier();
- subscription.setRealPriceList(realPriceList);
+ subscription.setRealPriceList(plan.getPriceListName());
subscription.setEffectiveDate(effectiveDate);
subscription.setProcessedDate(now);
subscription.setPlan(plan);
@@ -464,14 +461,12 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
@Override
public DateTime getDryRunChangePlanEffectiveDate(final SubscriptionBase subscription,
- final String productName,
- final BillingPeriod term,
- final String priceList,
+ final PlanSpecifier spec,
final DateTime requestedDateWithMs,
final BillingActionPolicy requestedPolicy,
final InternalTenantContext context) throws SubscriptionBaseApiException {
final TenantContext tenantContext = internalCallContextFactory.createTenantContext(context);
- return apiService.dryRunChangePlan((DefaultSubscriptionBase) subscription, productName, term, priceList, requestedDateWithMs, requestedPolicy, tenantContext);
+ return apiService.dryRunChangePlan((DefaultSubscriptionBase) subscription, spec, requestedDateWithMs, requestedPolicy, tenantContext);
}
@Override
@@ -539,12 +534,11 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
List<SubscriptionBaseEvent> dryRunEvents = null;
try {
final PlanPhaseSpecifier inputSpec = dryRunArguments.getPlanPhaseSpecifier();
- final String realPriceList = (inputSpec != null && inputSpec.getPriceListName() != null) ? inputSpec.getPriceListName() : PriceListSet.DEFAULT_PRICELIST_NAME;
final Catalog catalog = catalogService.getFullCatalog(true, true, context);
final PlanPhasePriceOverridesWithCallContext overridesWithContext = null; // TODO not supported to dryRun with custom price
final Plan plan = (inputSpec != null && inputSpec.getProductName() != null && inputSpec.getBillingPeriod() != null) ?
- catalog.createOrFindPlan(new PlanSpecifier(inputSpec.getProductName(), inputSpec.getBillingPeriod(), realPriceList), overridesWithContext, utcNow) : null;
+ catalog.createOrFindPlan(inputSpec, overridesWithContext, utcNow) : null;
final TenantContext tenantContext = internalCallContextFactory.createTenantContext(context);
if (dryRunArguments != null) {
@@ -555,7 +549,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
final DateTime startEffectiveDate = dryRunArguments.getEffectiveDate() != null ? context.toUTCDateTime(dryRunArguments.getEffectiveDate()) : utcNow;
final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, startEffectiveDate, context);
final UUID subscriptionId = UUIDs.randomUUID();
- dryRunEvents = apiService.getEventsOnCreation(bundleId, subscriptionId, startEffectiveDate, bundleStartDate, plan, inputSpec.getPhaseType(), realPriceList,
+ dryRunEvents = apiService.getEventsOnCreation(bundleId, subscriptionId, startEffectiveDate, bundleStartDate, plan, inputSpec.getPhaseType(), plan.getPriceListName(),
startEffectiveDate, utcNow, context);
final SubscriptionBuilder builder = new SubscriptionBuilder()
.setId(subscriptionId)
@@ -574,15 +568,12 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
if (changeEffectiveDate == null) {
BillingActionPolicy policy = dryRunArguments.getBillingActionPolicy();
if (policy == null) {
- final PlanChangeResult planChangeResult = apiService.getPlanChangeResult(subscriptionForChange,
- dryRunArguments.getPlanPhaseSpecifier().getProductName(),
- dryRunArguments.getPlanPhaseSpecifier().getBillingPeriod(),
- dryRunArguments.getPlanPhaseSpecifier().getPriceListName(), utcNow, tenantContext);
+ final PlanChangeResult planChangeResult = apiService.getPlanChangeResult(subscriptionForChange, inputSpec, utcNow, tenantContext);
policy = planChangeResult.getPolicy();
}
changeEffectiveDate = subscriptionForChange.getPlanChangeEffectiveDate(policy);
}
- dryRunEvents = apiService.getEventsOnChangePlan(subscriptionForChange, plan, realPriceList, changeEffectiveDate, utcNow, true, context);
+ dryRunEvents = apiService.getEventsOnChangePlan(subscriptionForChange, plan, plan.getPriceListName(), changeEffectiveDate, utcNow, true, context);
break;
case STOP_BILLING:
@@ -593,9 +584,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
if (policy == null) {
final Plan currentPlan = subscriptionForCancellation.getCurrentPlan();
- final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
- subscriptionForCancellation.getCurrentPlan().getRecurringBillingPeriod(),
- subscriptionForCancellation.getCurrentPriceList().getName(),
+ final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(currentPlan.getName(),
subscriptionForCancellation.getCurrentPhase().getPhaseType());
policy = catalogService.getFullCatalog(true, true, context).planCancelPolicy(spec, utcNow);
}
@@ -706,13 +695,12 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
requestedDate = null;
} else if (bcd <= lastDayOfMonth) {
requestedDate = new LocalDate(startDate.getYear(), startDate.getMonthOfYear(), bcd);
- } else /* bcd > lastDayOfMonth && bcd > currentDay */{
+ } else /* bcd > lastDayOfMonth && bcd > currentDay */ {
requestedDate = new LocalDate(startDate.getYear(), startDate.getMonthOfYear(), lastDayOfMonth);
}
return requestedDate == null ? clock.getUTCNow() : internalCallContext.toUTCDateTime(requestedDate);
}
-
private DateTime getBundleStartDateWithSanity(final UUID bundleId, @Nullable final DefaultSubscriptionBase baseSubscription, final Plan plan,
final DateTime effectiveDate, final InternalTenantContext context) throws SubscriptionBaseApiException, CatalogApiException {
switch (plan.getProduct().getCategory()) {
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java b/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java
index 552f878..9c677fd 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java
@@ -124,7 +124,7 @@ public class DefaultSubscriptionBaseTimeline implements SubscriptionBaseTimeline
final String planNameWithClosure = planName;
final String planPhaseNameWithClosure = planPhaseName;
final Integer billCycleDayLocalWithClosure = billCycleDayLocal;
- final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, billingPeriod, priceListName, phaseType);
+ final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(planName, phaseType);
result.add(new ExistingEvent() {
@Override
public SubscriptionBaseTransitionType getSubscriptionTransitionType() {
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java
index b3f06f2..5251d1b 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java
@@ -35,6 +35,7 @@ import org.killbill.billing.catalog.api.PhaseType;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhase;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.PriceList;
import org.killbill.billing.catalog.api.Product;
import org.killbill.billing.catalog.api.ProductCategory;
@@ -241,21 +242,21 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
}
@Override
- public DateTime changePlan(final String productName, final BillingPeriod term, final String priceList,
+ public DateTime changePlan(final PlanSpecifier spec,
final List<PlanPhasePriceOverride> overrides, final CallContext context) throws SubscriptionBaseApiException {
- return apiService.changePlan(this, productName, term, priceList, overrides, context);
+ return apiService.changePlan(this, spec, overrides, context);
}
@Override
- public DateTime changePlanWithDate(final String productName, final BillingPeriod term, final String priceList, final List<PlanPhasePriceOverride> overrides,
+ public DateTime changePlanWithDate(final PlanSpecifier spec, final List<PlanPhasePriceOverride> overrides,
final DateTime requestedDate, final CallContext context) throws SubscriptionBaseApiException {
- return apiService.changePlanWithRequestedDate(this, productName, term, priceList, overrides, requestedDate, context);
+ return apiService.changePlanWithRequestedDate(this, spec, overrides, requestedDate, context);
}
@Override
- public DateTime changePlanWithPolicy(final String productName, final BillingPeriod term, final String priceList,
+ public DateTime changePlanWithPolicy(final PlanSpecifier spec,
final List<PlanPhasePriceOverride> overrides, final BillingActionPolicy policy, final CallContext context) throws SubscriptionBaseApiException {
- return apiService.changePlanWithPolicy(this, productName, term, priceList, overrides, policy, context);
+ return apiService.changePlanWithPolicy(this, spec, overrides, policy, context);
}
@Override
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
index 64cc8d9..cffcd6b 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
@@ -179,9 +179,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
final DateTime now = clock.getUTCNow();
final Plan currentPlan = subscription.getCurrentPlan();
- final PlanPhaseSpecifier planPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
- subscription.getCurrentPlan().getRecurringBillingPeriod(),
- subscription.getCurrentPriceList().getName(), null);
+ final PlanPhaseSpecifier planPhase = new PlanPhaseSpecifier(currentPlan.getName(), null);
try {
final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
@@ -299,9 +297,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
@Override
public DateTime dryRunChangePlan(final DefaultSubscriptionBase subscription,
- final String productName,
- final BillingPeriod term,
- final String priceList,
+ final PlanSpecifier spec,
@Nullable final DateTime requestedDateWithMs,
@Nullable final BillingActionPolicy requestedPolicy,
final TenantContext context) throws SubscriptionBaseApiException {
@@ -309,7 +305,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
BillingActionPolicy policyMaybeNull = requestedPolicy;
if (requestedDateWithMs == null && requestedPolicy == null) {
- final PlanChangeResult planChangeResult = getPlanChangeResult(subscription, productName, term, priceList, now, context);
+ final PlanChangeResult planChangeResult = getPlanChangeResult(subscription, spec, now, context);
policyMaybeNull = planChangeResult.getPolicy();
}
@@ -323,18 +319,17 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
}
@Override
- public DateTime changePlan(final DefaultSubscriptionBase subscription, final String productName, final BillingPeriod term,
- final String priceList, final List<PlanPhasePriceOverride> overrides, final CallContext context) throws SubscriptionBaseApiException {
+ public DateTime changePlan(final DefaultSubscriptionBase subscription, final PlanSpecifier spec, final List<PlanPhasePriceOverride> overrides, final CallContext context) throws SubscriptionBaseApiException {
final DateTime now = clock.getUTCNow();
validateEntitlementState(subscription);
- final PlanChangeResult planChangeResult = getPlanChangeResult(subscription, productName, term, priceList, now, context);
- final DateTime effectiveDate = dryRunChangePlan(subscription, productName, term, priceList, null, planChangeResult.getPolicy(), context);
+ final PlanChangeResult planChangeResult = getPlanChangeResult(subscription, spec, now, context);
+ final DateTime effectiveDate = dryRunChangePlan(subscription, spec, null, planChangeResult.getPolicy(), context);
validateEffectiveDate(subscription, effectiveDate);
try {
- doChangePlan(subscription, productName, term, planChangeResult.getNewPriceList().getName(), overrides, effectiveDate, context);
+ doChangePlan(subscription, spec, overrides, effectiveDate, context);
} catch (final CatalogApiException e) {
throw new SubscriptionBaseApiException(e);
}
@@ -343,15 +338,14 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
}
@Override
- public DateTime changePlanWithRequestedDate(final DefaultSubscriptionBase subscription, final String productName, final BillingPeriod term,
- final String priceList, final List<PlanPhasePriceOverride> overrides,
+ public DateTime changePlanWithRequestedDate(final DefaultSubscriptionBase subscription, final PlanSpecifier spec, final List<PlanPhasePriceOverride> overrides,
final DateTime requestedDateWithMs, final CallContext context) throws SubscriptionBaseApiException {
- final DateTime effectiveDate = dryRunChangePlan(subscription, productName, term, priceList, requestedDateWithMs, null, context);
+ final DateTime effectiveDate = dryRunChangePlan(subscription, spec, requestedDateWithMs, null, context);
validateEffectiveDate(subscription, effectiveDate);
validateEntitlementState(subscription);
try {
- doChangePlan(subscription, productName, term, priceList, overrides, effectiveDate, context);
+ doChangePlan(subscription, spec, overrides, effectiveDate, context);
} catch (final CatalogApiException e) {
throw new SubscriptionBaseApiException(e);
}
@@ -360,13 +354,12 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
}
@Override
- public DateTime changePlanWithPolicy(final DefaultSubscriptionBase subscription, final String productName, final BillingPeriod term,
- final String priceList, final List<PlanPhasePriceOverride> overrides, final BillingActionPolicy policy, final CallContext context) throws SubscriptionBaseApiException {
+ public DateTime changePlanWithPolicy(final DefaultSubscriptionBase subscription, final PlanSpecifier spec, final List<PlanPhasePriceOverride> overrides, final BillingActionPolicy policy, final CallContext context) throws SubscriptionBaseApiException {
validateEntitlementState(subscription);
- final DateTime effectiveDate = dryRunChangePlan(subscription, productName, term, priceList, null, policy, context);
+ final DateTime effectiveDate = dryRunChangePlan(subscription, spec, null, policy, context);
try {
- doChangePlan(subscription, productName, term, priceList, overrides, effectiveDate, context);
+ doChangePlan(subscription, spec, overrides, effectiveDate, context);
} catch (final CatalogApiException e) {
throw new SubscriptionBaseApiException(e);
}
@@ -375,22 +368,15 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
}
@Override
- public PlanChangeResult getPlanChangeResult(final DefaultSubscriptionBase subscription, final String productName,
- final BillingPeriod term, final String priceList, final DateTime effectiveDate, final TenantContext context) throws SubscriptionBaseApiException {
+ public PlanChangeResult getPlanChangeResult(final DefaultSubscriptionBase subscription, final PlanSpecifier toPlanPhase, final DateTime effectiveDate, final TenantContext context) throws SubscriptionBaseApiException {
final PlanChangeResult planChangeResult;
try {
final InternalTenantContext internalCallContext = createTenantContextFromBundleId(subscription.getBundleId(), context);
- final Product destProduct = catalogService.getFullCatalog(true, true, internalCallContext).findProduct(productName, effectiveDate);
final Plan currentPlan = subscription.getCurrentPlan();
+
final PriceList currentPriceList = subscription.getCurrentPriceList();
- final PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
- currentPlan.getRecurringBillingPeriod(),
- currentPriceList.getName(),
+ final PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getName(),
subscription.getCurrentPhase().getPhaseType());
- final PlanSpecifier toPlanPhase = new PlanSpecifier(productName,
- term,
- priceList);
-
planChangeResult = catalogService.getFullCatalog(true, true, internalCallContext).planChange(fromPlanPhase, toPlanPhase, effectiveDate);
} catch (final CatalogApiException e) {
throw new SubscriptionBaseApiException(e);
@@ -400,15 +386,13 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
}
private void doChangePlan(final DefaultSubscriptionBase subscription,
- final String newProductName,
- final BillingPeriod newBillingPeriod,
- final String newPriceList,
+ final PlanSpecifier spec,
final List<PlanPhasePriceOverride> overrides,
final DateTime effectiveDate,
final CallContext context) throws SubscriptionBaseApiException, CatalogApiException {
final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(overrides, context);
- final Plan newPlan = catalogService.getFullCatalog(true, true, internalCallContext).createOrFindPlan(new PlanSpecifier(newProductName, newBillingPeriod, newPriceList), overridesWithContext, effectiveDate, subscription.getStartDate());
+ final Plan newPlan = catalogService.getFullCatalog(true, true, internalCallContext).createOrFindPlan(spec, overridesWithContext, effectiveDate, subscription.getStartDate());
if (newPlan.getProduct().getCategory() != subscription.getCategory()) {
throw new SubscriptionBaseApiException(ErrorCode.SUB_CHANGE_INVALID, subscription.getId());
@@ -416,7 +400,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
final List<DefaultSubscriptionBase> addOnSubscriptionsToBeCancelled = new ArrayList<DefaultSubscriptionBase>();
final List<SubscriptionBaseEvent> addOnCancelEvents = new ArrayList<SubscriptionBaseEvent>();
- final List<SubscriptionBaseEvent> changeEvents = getEventsOnChangePlan(subscription, newPlan, newPriceList, effectiveDate, true, addOnSubscriptionsToBeCancelled, addOnCancelEvents, internalCallContext);
+ final List<SubscriptionBaseEvent> changeEvents = getEventsOnChangePlan(subscription, newPlan, newPlan.getPriceListName(), effectiveDate, true, addOnSubscriptionsToBeCancelled, addOnCancelEvents, internalCallContext);
dao.changePlan(subscription, changeEvents, addOnSubscriptionsToBeCancelled, addOnCancelEvents, internalCallContext);
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java b/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java
index 664d8cb..bbbd1e4 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestTransfer.java
@@ -28,6 +28,7 @@ import org.killbill.billing.api.TestApiListener.NextEvent;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.PhaseType;
import org.killbill.billing.catalog.api.Plan;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.Product;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
@@ -266,7 +267,7 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
final String newBaseProduct1 = "Assault-Rifle";
final BillingPeriod newBaseTerm1 = BillingPeriod.ANNUAL;
testListener.pushExpectedEvent(NextEvent.CHANGE);
- newBaseSubscription.changePlan(newBaseProduct1, newBaseTerm1, basePriceList, null, callContext);
+ newBaseSubscription.changePlan(new PlanSpecifier(newBaseProduct1, newBaseTerm1, basePriceList), null, callContext);
assertListenerStatus();
newPlan = newBaseSubscription.getCurrentPlan();
@@ -282,7 +283,7 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
final String newBaseProduct2 = "Pistol";
final BillingPeriod newBaseTerm2 = BillingPeriod.ANNUAL;
- newBaseSubscriptionWithCtd.changePlan(newBaseProduct2, newBaseTerm2, basePriceList, null, callContext);
+ newBaseSubscriptionWithCtd.changePlan(new PlanSpecifier(newBaseProduct2, newBaseTerm2, basePriceList), null, callContext);
newPlan = newBaseSubscriptionWithCtd.getCurrentPlan();
assertEquals(newPlan.getProduct().getName(), newBaseProduct1);
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiAddOn.java b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiAddOn.java
index 424475e..cb9e43a 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiAddOn.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiAddOn.java
@@ -311,7 +311,7 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
testListener.pushExpectedEvent(NextEvent.CHANGE);
testListener.pushExpectedEvent(NextEvent.CANCEL);
- baseSubscription.changePlan(newBaseProduct, newBaseTerm, newBasePriceList, null, callContext);
+ baseSubscription.changePlan(new PlanSpecifier(newBaseProduct, newBaseTerm, newBasePriceList), null, callContext);
assertListenerStatus();
// REFETCH AO SUBSCRIPTION AND CHECK THIS CANCELLED
@@ -367,7 +367,7 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
assertEquals(aoStatus.get(0).getPriceList(), aoSubscription.getCurrentPriceList().getName());
assertEquals(aoStatus.get(0).getReason(), DryRunChangeReason.AO_NOT_AVAILABLE_IN_NEW_PLAN);
- baseSubscription.changePlan(newBaseProduct, newBaseTerm, newBasePriceList, null, callContext);
+ baseSubscription.changePlan(new PlanSpecifier(newBaseProduct, newBaseTerm, newBasePriceList), null, callContext);
// REFETCH AO SUBSCRIPTION AND CHECK THIS IS ACTIVE
aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiChangePlan.java b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiChangePlan.java
index 01a93e7..26eb6ff 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiChangePlan.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiChangePlan.java
@@ -23,6 +23,7 @@ import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.catalog.api.PlanAlignmentCreate;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -84,7 +85,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
// CHANGE PLAN
testListener.pushExpectedEvent(NextEvent.CHANGE);
- subscription.changePlan(toProd, toTerm, toPlanSet, null, callContext);
+ subscription.changePlan(new PlanSpecifier(toProd, toTerm, toPlanSet), null, callContext);
assertListenerStatus();
// CHECK CHANGE PLAN
@@ -125,7 +126,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
// RE READ SUBSCRIPTION + CHANGE PLAN
subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
- subscription.changePlan(toProd, toTerm, toPlanSet, null, callContext);
+ subscription.changePlan(new PlanSpecifier(toProd, toTerm, toPlanSet), null, callContext);
assertListenerStatus();
// CHECK CHANGE PLAN
@@ -168,7 +169,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
clock.addDeltaFromReality(it.toDurationMillis());
// CHANGE PLAN IMM
- subscription.changePlan(toProd, toTerm, toPlanSet, null, callContext);
+ subscription.changePlan(new PlanSpecifier(toProd, toTerm, toPlanSet), null, callContext);
checkChangePlan(subscription, toProd, ProductCategory.BASE, toTerm, PhaseType.TRIAL);
assertListenerStatus();
@@ -222,7 +223,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
// CHANGE PLAN
currentTime = clock.getUTCNow();
- subscription.changePlan(toProd, toTerm, toPlanSet, null, callContext);
+ subscription.changePlan(new PlanSpecifier(toProd, toTerm, toPlanSet), null, callContext);
checkChangePlan(subscription, fromProd, ProductCategory.BASE, fromTerm, PhaseType.EVERGREEN);
@@ -288,12 +289,12 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
// CHANGE EOT
- subscription.changePlan("Pistol", BillingPeriod.MONTHLY, "gunclubDiscount", null, callContext);
+ subscription.changePlan(new PlanSpecifier("Pistol", BillingPeriod.MONTHLY, "gunclubDiscount"), null, callContext);
assertListenerStatus();
// CHANGE
testListener.pushExpectedEvent(NextEvent.CHANGE);
- subscription.changePlan("Assault-Rifle", BillingPeriod.ANNUAL, "gunclubDiscount", null, callContext);
+ subscription.changePlan(new PlanSpecifier("Assault-Rifle", BillingPeriod.ANNUAL, "gunclubDiscount"), null, callContext);
assertListenerStatus();
final Plan currentPlan = subscription.getCurrentPlan();
@@ -330,11 +331,11 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
// CHANGE EOT
- subscription.changePlan("Shotgun", BillingPeriod.MONTHLY, "gunclubDiscount", null, callContext);
+ subscription.changePlan(new PlanSpecifier("Shotgun", BillingPeriod.MONTHLY, "gunclubDiscount"), null, callContext);
assertListenerStatus();
// CHANGE EOT
- subscription.changePlan("Pistol", BillingPeriod.ANNUAL, "gunclubDiscount", null, callContext);
+ subscription.changePlan(new PlanSpecifier("Pistol", BillingPeriod.ANNUAL, "gunclubDiscount"), null, callContext);
assertListenerStatus();
// CHECK NO CHANGE OCCURED YET
@@ -396,7 +397,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
// CHANGE IMMEDIATE TO A 3 PHASES PLAN
testListener.pushExpectedEvent(NextEvent.CHANGE);
- subscription.changePlan("Assault-Rifle", BillingPeriod.ANNUAL, "gunclubDiscount", null, callContext);
+ subscription.changePlan(new PlanSpecifier("Assault-Rifle", BillingPeriod.ANNUAL, "gunclubDiscount"), null, callContext);
assertListenerStatus();
// CHECK EVERYTHING LOOKS CORRECT
@@ -450,7 +451,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
try {
- aoSubscription.changePlanWithDate(baseProduct, baseTerm, basePriceList, null, clock.getUTCNow(), callContext);
+ aoSubscription.changePlanWithDate(new PlanSpecifier(baseProduct, baseTerm, basePriceList), null, clock.getUTCNow(), callContext);
Assert.fail("Should not allow plan change across product type");
} catch (final SubscriptionBaseApiException e) {
Assert.assertEquals(e.getCode(), ErrorCode.SUB_CHANGE_INVALID.getCode());
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiError.java b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiError.java
index 46f3ab6..0c2e6c5 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiError.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiError.java
@@ -30,6 +30,7 @@ import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Duration;
import org.killbill.billing.catalog.api.PlanPhase;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.subscription.SubscriptionTestSuiteNoDB;
import org.killbill.billing.subscription.api.SubscriptionBase;
@@ -52,7 +53,7 @@ public class TestUserApiError extends SubscriptionTestSuiteNoDB {
// TODO: MARTIN TO FIX WITH CORRECT ERROR CODE. RIGHT NOW NPE
// WRONG BILLING PERIOD
- tCreateSubscriptionInternal(bundle.getId(), "Shotgun", null, PriceListSet.DEFAULT_PRICELIST_NAME, ErrorCode.CAT_PLAN_NOT_FOUND);
+ tCreateSubscriptionInternal(bundle.getId(), "Shotgun", null, PriceListSet.DEFAULT_PRICELIST_NAME, ErrorCode.CAT_NULL_BILLING_PERIOD);
// WRONG PLAN SET
tCreateSubscriptionInternal(bundle.getId(), "Shotgun", BillingPeriod.ANNUAL, "Whatever", ErrorCode.CAT_PRICE_LIST_NOT_FOUND);
}
@@ -106,7 +107,7 @@ public class TestUserApiError extends SubscriptionTestSuiteNoDB {
testListener.pushExpectedEvent(NextEvent.CANCEL);
subscription.cancelWithDate(clock.getUTCNow(), callContext);
try {
- subscription.changePlanWithDate("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null, clock.getUTCNow(), callContext);
+ subscription.changePlanWithDate(new PlanSpecifier("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), null, clock.getUTCNow(), callContext);
} catch (final SubscriptionBaseApiException e) {
assertEquals(e.getCode(), ErrorCode.SUB_CHANGE_NON_ACTIVE.getCode());
}
@@ -117,7 +118,7 @@ public class TestUserApiError extends SubscriptionTestSuiteNoDB {
final SubscriptionBase subscription = testUtil.createSubscription(bundle, "Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME);
try {
- subscription.changePlanWithPolicy("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null, BillingActionPolicy.ILLEGAL, callContext);
+ subscription.changePlanWithPolicy(new PlanSpecifier("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), null, BillingActionPolicy.ILLEGAL, callContext);
Assert.fail();
} catch (final SubscriptionBaseError error) {
assertTrue(true);
@@ -125,7 +126,7 @@ public class TestUserApiError extends SubscriptionTestSuiteNoDB {
}
// Assume the call takes less than a second
- assertEquals(DefaultClock.truncateMs(subscription.changePlanWithPolicy("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null, BillingActionPolicy.IMMEDIATE, callContext)),
+ assertEquals(DefaultClock.truncateMs(subscription.changePlanWithPolicy(new PlanSpecifier("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), null, BillingActionPolicy.IMMEDIATE, callContext)),
DefaultClock.truncateMs(clock.getUTCNow()));
assertEquals(subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext).getCurrentPlan().getRecurringBillingPeriod(), BillingPeriod.MONTHLY);
}
@@ -152,7 +153,7 @@ public class TestUserApiError extends SubscriptionTestSuiteNoDB {
subscription.cancelWithPolicy(BillingActionPolicy.END_OF_TERM, callContext);
try {
- subscription.changePlanWithDate("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null, clock.getUTCNow(), callContext);
+ subscription.changePlanWithDate(new PlanSpecifier("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), null, clock.getUTCNow(), callContext);
} catch (final SubscriptionBaseApiException e) {
assertEquals(e.getCode(), ErrorCode.SUB_CHANGE_FUTURE_CANCELLED.getCode());
}
diff --git a/util/src/test/java/org/killbill/billing/mock/api/MockAccountUserApi.java b/util/src/test/java/org/killbill/billing/mock/api/MockAccountUserApi.java
index 38f93a1..d6798fc 100644
--- a/util/src/test/java/org/killbill/billing/mock/api/MockAccountUserApi.java
+++ b/util/src/test/java/org/killbill/billing/mock/api/MockAccountUserApi.java
@@ -57,7 +57,8 @@ public class MockAccountUserApi implements AccountUserApi {
final String stateOrProvince,
final String country,
final String postalCode,
- final String phone) {
+ final String phone,
+ final String notes) {
final Account result = new MockAccountBuilder(id)
.externalKey(externalKey)
.email(email)
@@ -75,6 +76,7 @@ public class MockAccountUserApi implements AccountUserApi {
.country(country)
.postalCode(postalCode)
.phone(phone)
+ .notes(notes)
.isNotifiedForInvoices(false)
.build();
accounts.add(result);
diff --git a/util/src/test/java/org/killbill/billing/mock/MockAccountBuilder.java b/util/src/test/java/org/killbill/billing/mock/MockAccountBuilder.java
index 3058afa..36975d9 100644
--- a/util/src/test/java/org/killbill/billing/mock/MockAccountBuilder.java
+++ b/util/src/test/java/org/killbill/billing/mock/MockAccountBuilder.java
@@ -48,6 +48,7 @@ public class MockAccountBuilder {
private String country = "";
private String postalCode = "";
private String phone = "";
+ private String notes = "";
private boolean migrated;
private boolean isNotifiedForInvoices;
private DateTime createdDate = new DateTime(DateTimeZone.UTC);
@@ -80,6 +81,7 @@ public class MockAccountBuilder {
this.name(data.getName());
this.paymentMethodId(data.getPaymentMethodId());
this.phone(data.getPhone());
+ this.notes(data.getNotes());
this.postalCode(data.getPostalCode());
this.stateOrProvince(data.getStateOrProvince());
this.timeZone(data.getTimeZone());
@@ -187,6 +189,11 @@ public class MockAccountBuilder {
return this;
}
+ public MockAccountBuilder notes(final String notes) {
+ this.notes = notes;
+ return this;
+ }
+
public MockAccountBuilder migrated(final boolean migrated) {
this.migrated = migrated;
return this;
@@ -315,6 +322,11 @@ public class MockAccountBuilder {
}
@Override
+ public String getNotes() {
+ return notes;
+ }
+
+ @Override
public Boolean isMigrated() {
return migrated;
}
diff --git a/util/src/test/java/org/killbill/billing/mock/MockPriceList.java b/util/src/test/java/org/killbill/billing/mock/MockPriceList.java
index 3fddaf9..0d22447 100644
--- a/util/src/test/java/org/killbill/billing/mock/MockPriceList.java
+++ b/util/src/test/java/org/killbill/billing/mock/MockPriceList.java
@@ -42,8 +42,10 @@ public class MockPriceList implements PriceList {
}
@Override
- public Plan findPlan(final Product product, final BillingPeriod period) {
- return plan;
+ public Plan[] findPlans(final Product product, final BillingPeriod period) {
+ final Plan[] result = new Plan[1];
+ result[0] = plan;
+ return result;
}
public Plan getPlan() {
diff --git a/util/src/test/java/org/killbill/billing/mock/MockSubscription.java b/util/src/test/java/org/killbill/billing/mock/MockSubscription.java
index 6529062..c3287d1 100644
--- a/util/src/test/java/org/killbill/billing/mock/MockSubscription.java
+++ b/util/src/test/java/org/killbill/billing/mock/MockSubscription.java
@@ -21,6 +21,7 @@ import java.util.UUID;
import org.joda.time.DateTime;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
+import org.killbill.billing.catalog.api.PlanSpecifier;
import org.mockito.Mockito;
import org.killbill.billing.catalog.api.BillingActionPolicy;
@@ -81,20 +82,20 @@ public class MockSubscription implements SubscriptionBase {
}
@Override
- public DateTime changePlan(final String productName, final BillingPeriod term, final String priceList, final List<PlanPhasePriceOverride> overrides, final CallContext context) throws SubscriptionBaseApiException {
- return sub.changePlan(productName, term, priceList, overrides, context);
+ public DateTime changePlan(final PlanSpecifier spec, final List<PlanPhasePriceOverride> overrides, final CallContext context) throws SubscriptionBaseApiException {
+ return sub.changePlan(spec, overrides, context);
}
@Override
- public DateTime changePlanWithDate(final String productName, final BillingPeriod term, final String priceList, final List<PlanPhasePriceOverride> overrides, final DateTime requestedDate,
+ public DateTime changePlanWithDate(final PlanSpecifier spec, final List<PlanPhasePriceOverride> overrides, final DateTime requestedDate,
final CallContext context) throws SubscriptionBaseApiException {
- return sub.changePlanWithDate(productName, term, priceList, overrides, requestedDate, context);
+ return sub.changePlanWithDate(spec, overrides, requestedDate, context);
}
@Override
- public DateTime changePlanWithPolicy(final String productName, final BillingPeriod term, final String priceList,
+ public DateTime changePlanWithPolicy(final PlanSpecifier spec,
final List<PlanPhasePriceOverride> overrides, final BillingActionPolicy policy, final CallContext context) throws SubscriptionBaseApiException {
- return sub.changePlanWithPolicy(productName, term, priceList, overrides, policy, context);
+ return sub.changePlanWithPolicy(spec, overrides, policy, context);
}
@Override