killbill-uncached
Changes
catalog/src/test/resources/WeaponsHire.xml 91(+54 -37)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java 14(+7 -7)
entitlement/src/test/resources/testInput.xml 37(+13 -24)
Details
catalog/src/test/resources/WeaponsHire.xml 91(+54 -37)
diff --git a/catalog/src/test/resources/WeaponsHire.xml b/catalog/src/test/resources/WeaponsHire.xml
index 01d7cb4..3d36b9d 100644
--- a/catalog/src/test/resources/WeaponsHire.xml
+++ b/catalog/src/test/resources/WeaponsHire.xml
@@ -51,13 +51,13 @@ Use Cases to do:
<products>
<product name="Pistol">
<category>BASE</category>
- <available>
- <addonProduct>Telescopic-Scope</addonProduct>
- <addonProduct>Laser-Scope</addonProduct>
- </available>
</product>
<product name="Shotgun">
<category>BASE</category>
+ <available>
+ <addonProduct>Telescopic-Scope</addonProduct>
+ <addonProduct>Laser-Scope</addonProduct>
+ </available>
</product>
<product name="Assault-Rifle">
<category>BASE</category>
@@ -91,33 +91,18 @@ Use Cases to do:
<phaseType>TRIAL</phaseType>
<policy>IMMEDIATE</policy>
</changePolicyCase>
- <changePolicyCase>
- <toProduct>Pistol</toProduct>
- <policy>END_OF_TERM</policy>
- </changePolicyCase>
+ <changePolicyCase>
+ <toProduct>Assault-Rifle</toProduct>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <fromProduct>Pistol</fromProduct>
+ <toProduct>Shotgun</toProduct>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
<changePolicyCase>
<toPriceList>rescue</toPriceList>
<policy>END_OF_TERM</policy>
- </changePolicyCase>
- <changePolicyCase>
- <fromProduct>Pistol</fromProduct>
- <toProduct>Shotgun</toProduct>
- <policy>IMMEDIATE</policy>
- </changePolicyCase>
- <changePolicyCase>
- <fromProduct>Assault-Rifle</fromProduct>
- <toProduct>Shotgun</toProduct>
- <policy>END_OF_TERM</policy>
- </changePolicyCase>
- <changePolicyCase>
- <fromBillingPeriod>MONTHLY</fromBillingPeriod>
- <toProduct>Assault-Rifle</toProduct>
- <toBillingPeriod>MONTHLY</toBillingPeriod>
- <policy>END_OF_TERM</policy>
- </changePolicyCase>
- <changePolicyCase>
- <toProduct>Assault-Rifle</toProduct>
- <policy>IMMEDIATE</policy>
</changePolicyCase>
<changePolicyCase>
<fromBillingPeriod>MONTHLY</fromBillingPeriod>
@@ -135,9 +120,6 @@ Use Cases to do:
</changePolicy>
<changeAlignment>
<changeAlignmentCase>
- <alignment>START_OF_SUBSCRIPTION</alignment>
- </changeAlignmentCase>
- <changeAlignmentCase>
<toPriceList>rescue</toPriceList>
<alignment>CHANGE_OF_PLAN</alignment>
</changeAlignmentCase>
@@ -146,20 +128,27 @@ Use Cases to do:
<toPriceList>rescue</toPriceList>
<alignment>CHANGE_OF_PRICELIST</alignment>
</changeAlignmentCase>
+ <changeAlignmentCase>
+ <alignment>START_OF_SUBSCRIPTION</alignment>
+ </changeAlignmentCase>
</changeAlignment>
<cancelPolicy>
<cancelPolicyCase>
- <policy>END_OF_TERM</policy>
- </cancelPolicyCase>
- <cancelPolicyCase>
<phaseType>TRIAL</phaseType>
<policy>IMMEDIATE</policy>
</cancelPolicyCase>
+ <cancelPolicyCase>
+ <policy>END_OF_TERM</policy>
+ </cancelPolicyCase>
</cancelPolicy>
<createAlignment>
- <createAlignmentCase>
- <alignment>START_OF_BUNDLE</alignment>
- </createAlignmentCase>
+ <createAlignmentCase>
+ <product>Laser-Scope</product>
+ <alignment>START_OF_SUBSCRIPTION</alignment>
+ </createAlignmentCase>
+ <createAlignmentCase>
+ <alignment>START_OF_BUNDLE</alignment>
+ </createAlignmentCase>
</createAlignment>
<billingAlignment>
<billingAlignmentCase>
@@ -447,6 +436,20 @@ Use Cases to do:
</plan>
<plan name="laser-scope-monthly">
<product>Laser-Scope</product>
+ <initialPhases>
+ <phase type="DISCOUNT">
+ <duration>
+ <unit>MONTHS</unit>
+ <number>1</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>999.95</value></price>
+ <price><currency>EUR</currency><value>499.95</value></price>
+ <price><currency>GBP</currency><value>999.95</value></price>
+ </recurringPrice>
+ </phase>
+ </initialPhases>
<finalPhase type="EVERGREEN">
<duration>
<unit>UNLIMITED</unit>
@@ -461,6 +464,20 @@ Use Cases to do:
</plan>
<plan name="telescopic-scope-monthly">
<product>Telescopic-Scope</product>
+ <initialPhases>
+ <phase type="DISCOUNT">
+ <duration>
+ <unit>MONTHS</unit>
+ <number>1</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>399.95</value></price>
+ <price><currency>EUR</currency><value>299.95</value></price>
+ <price><currency>GBP</currency><value>399.95</value></price>
+ </recurringPrice>
+ </phase>
+ </initialPhases>
<finalPhase type="EVERGREEN">
<duration>
<unit>UNLIMITED</unit>
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
index ebee20e..51010db 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
@@ -122,7 +122,7 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
}
DateTime bundleStartDate = null;
- Subscription baseSubscription = dao.getBaseSubscription(bundleId);
+ SubscriptionData baseSubscription = (SubscriptionData) dao.getBaseSubscription(bundleId);
switch(plan.getProduct().getCategory()) {
case BASE:
if (baseSubscription != null) {
@@ -143,11 +143,11 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
}
SubscriptionData subscription = apiService.createPlan(new SubscriptionBuilder()
- .setId(UUID.randomUUID())
- .setBundleId(bundleId)
- .setCategory(plan.getProduct().getCategory())
- .setBundleStartDate(bundleStartDate)
- .setStartDate(effectiveDate),
+ .setId(UUID.randomUUID())
+ .setBundleId(bundleId)
+ .setCategory(plan.getProduct().getCategory())
+ .setBundleStartDate(bundleStartDate)
+ .setStartDate(effectiveDate),
plan, spec.getPhaseType(), realPriceList, requestedDate, effectiveDate, now);
return subscription;
@@ -156,7 +156,7 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
}
}
- private void checkAddonCreationRights(Subscription baseSubscription, Plan targetAddOnPlan)
+ private void checkAddonCreationRights(SubscriptionData baseSubscription, Plan targetAddOnPlan)
throws EntitlementUserApiException, CatalogApiException {
if (baseSubscription.getState() != SubscriptionState.ACTIVE) {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java
index 66635c3..94c35f9 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java
@@ -23,6 +23,9 @@ import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.Product;
import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
+import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.entitlement.api.user.SubscriptionTransition;
public class AddonUtils {
@@ -34,7 +37,11 @@ public class AddonUtils {
this.catalogService = catalogService;
}
- public boolean isAddonAvailable(Subscription baseSubscription, Plan targetAddOnPlan) {
+ public boolean isAddonAvailable(SubscriptionData baseSubscription, Plan targetAddOnPlan) {
+
+ if (baseSubscription.getState() == SubscriptionState.CANCELLED) {
+ return false;
+ }
Product targetAddonProduct = targetAddOnPlan.getProduct();
Product baseProduct = baseSubscription.getCurrentPlan().getProduct();
@@ -48,7 +55,12 @@ public class AddonUtils {
return false;
}
- public boolean isAddonIncluded(Subscription baseSubscription, Plan targetAddOnPlan) {
+ public boolean isAddonIncluded(SubscriptionData baseSubscription, Plan targetAddOnPlan) {
+
+ if (baseSubscription.getState() == SubscriptionState.CANCELLED) {
+ return false;
+ }
+
Product targetAddonProduct = targetAddOnPlan.getProduct();
Product baseProduct = baseSubscription.getCurrentPlan().getProduct();
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
index f03bcbc..73e488b 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
@@ -76,7 +76,6 @@ public class Engine implements EventListener, EntitlementService {
private final EntitlementBillingApi billingApi;
private final EntitlementTestApi testApi;
private final EntitlementMigrationApi migrationApi;
- private final CatalogService catalogService;
private final AddonUtils addonUtils;
private final EventBus eventBus;
@@ -86,8 +85,8 @@ public class Engine implements EventListener, EntitlementService {
public Engine(Clock clock, EntitlementDao dao, EventNotifier apiEventProcessor,
PlanAligner planAligner, EntitlementConfig config, DefaultEntitlementUserApi userApi,
DefaultEntitlementBillingApi billingApi, DefaultEntitlementTestApi testApi,
- DefaultEntitlementMigrationApi migrationApi, CatalogService catalogService,
- AddonUtils addonUtils, EventBus eventBus) {
+ DefaultEntitlementMigrationApi migrationApi, AddonUtils addonUtils, EventBus eventBus) {
+
super();
this.clock = clock;
this.dao = dao;
@@ -97,7 +96,6 @@ public class Engine implements EventListener, EntitlementService {
this.testApi = testApi;
this.billingApi = billingApi;
this.migrationApi = migrationApi;
- this.catalogService = catalogService;
this.addonUtils = addonUtils;
this.eventBus = eventBus;
@@ -162,7 +160,7 @@ public class Engine implements EventListener, EntitlementService {
onPhaseEvent(subscription);
} else if (event.getType() == EventType.API_USER &&
subscription.getCategory() == ProductCategory.BASE) {
- onBasePlanEvent(subscription, event);
+ onBasePlanEvent(subscription, (ApiEvent) event);
}
try {
eventBus.post(subscription.getTransitionFromEvent(event));
@@ -222,11 +220,11 @@ public class Engine implements EventListener, EntitlementService {
}
}
- private void onBasePlanEvent(SubscriptionData baseSubscription, EntitlementEvent event) {
+ private void onBasePlanEvent(SubscriptionData baseSubscription, ApiEvent event) {
DateTime now = clock.getUTCNow();
- List<Subscription> subscriptions = dao.getSubscriptions(baseSubscription.getId());
+ List<Subscription> subscriptions = dao.getSubscriptions(baseSubscription.getBundleId());
Iterator<Subscription> it = subscriptions.iterator();
while (it.hasNext()) {
SubscriptionData cur = (SubscriptionData) it.next();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
index a6536f4..d7b9bf4 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
@@ -68,9 +68,7 @@ public class TestUserApiAddOn extends TestApiBase {
BillingPeriod aoTerm = BillingPeriod.MONTHLY;
String aoPriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
- DateTime beforeAOCreation = clock.getUTCNow();
SubscriptionData aoSubscription = createSubscription(aoProduct, aoTerm, aoPriceList);
- DateTime afterAOCreation = clock.getUTCNow();
testListener.reset();
testListener.pushExpectedEvent(NextEvent.PHASE);
@@ -91,19 +89,10 @@ public class TestUserApiAddOn extends TestApiBase {
// FUTURE CANCELLATION
baseSubscription.cancel(now, false);
- // REFETCH AO SUBSCRIPTION AND CHECK THIS IS FUTURE CANCELLED
+ // REFETCH AO SUBSCRIPTION AND CHECK THIS IS ACTIVE
aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
assertEquals(aoSubscription.getState(), SubscriptionState.ACTIVE);
-
- /*
- * STEPH not true because this will only happen when CANCEL event is being processed
- * => isFutureCancelled is broken for AO
- SubscriptionTransition aaPendingSubscription = aoSubscription.getPendingTransition();
- assertNotNull(aaPendingSubscription);
- assertEquals(aaPendingSubscription.getTransitionType(), SubscriptionTransitionType.CANCEL);
- */
-
// MOVE AFTER CANCELLATION
testListener.reset();
testListener.pushExpectedEvent(NextEvent.CANCEL);
@@ -111,11 +100,10 @@ public class TestUserApiAddOn extends TestApiBase {
now = clock.getUTCNow();
assertTrue(testListener.isCompleted(5000));
- // REFETCH AO SUBSCRIPTION AND CHECK THIS IS FUTURE CANCELLED
+ // REFETCH AO SUBSCRIPTION AND CHECK THIS IS CANCELLED
aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
assertEquals(aoSubscription.getState(), SubscriptionState.CANCELLED);
-
} catch (Exception e) {
Assert.fail(e.getMessage());
}
@@ -123,6 +111,121 @@ public class TestUserApiAddOn extends TestApiBase {
@Test(enabled=true, groups={"sql"})
+ public void testChangeBPWthAddonNonIncluded() {
+ try {
+
+ String baseProduct = "Shotgun";
+ BillingPeriod baseTerm = BillingPeriod.MONTHLY;
+ String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
+
+ // CREATE BP
+ SubscriptionData baseSubscription = createSubscription(baseProduct, baseTerm, basePriceList);
+
+ String aoProduct = "Telescopic-Scope";
+ BillingPeriod aoTerm = BillingPeriod.MONTHLY;
+ String aoPriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
+
+ SubscriptionData aoSubscription = createSubscription(aoProduct, aoTerm, aoPriceList);
+
+ testListener.reset();
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+
+ // MOVE CLOCK AFTER TRIAL + AO DISCOUNT
+ Duration twoMonths = getDurationMonth(2);
+ clock.setDeltaFromReality(twoMonths, DAY_IN_MS);
+ assertTrue(testListener.isCompleted(5000));
+
+ // SET CTD TO CANCEL IN FUTURE
+ DateTime now = clock.getUTCNow();
+ Duration ctd = getDurationMonth(1);
+ DateTime newChargedThroughDate = DefaultClock.addDuration(now, ctd);
+ billingApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate);
+ baseSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(baseSubscription.getId());
+
+ // CHANGE IMMEDIATELY WITH TO BP WITH NON INCLUDED ADDON
+ String newBaseProduct = "Assault-Rifle";
+ BillingPeriod newBaseTerm = BillingPeriod.MONTHLY;
+ String newBasePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
+
+ testListener.reset();
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
+ baseSubscription.changePlan(newBaseProduct, newBaseTerm, newBasePriceList, now);
+ assertTrue(testListener.isCompleted(5000));
+
+ // REFETCH AO SUBSCRIPTION AND CHECK THIS CANCELLED
+ aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
+ assertEquals(aoSubscription.getState(), SubscriptionState.CANCELLED);
+
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ @Test(enabled=true, groups={"sql"})
+ public void testChangeBPWthAddonNonAvailable() {
+ try {
+
+ String baseProduct = "Shotgun";
+ BillingPeriod baseTerm = BillingPeriod.MONTHLY;
+ String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
+
+ // CREATE BP
+ SubscriptionData baseSubscription = createSubscription(baseProduct, baseTerm, basePriceList);
+
+ String aoProduct = "Telescopic-Scope";
+ BillingPeriod aoTerm = BillingPeriod.MONTHLY;
+ String aoPriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
+
+ SubscriptionData aoSubscription = createSubscription(aoProduct, aoTerm, aoPriceList);
+
+ testListener.reset();
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+ testListener.pushExpectedEvent(NextEvent.PHASE);
+
+ // MOVE CLOCK AFTER TRIAL + AO DISCOUNT
+ Duration twoMonths = getDurationMonth(2);
+ clock.setDeltaFromReality(twoMonths, DAY_IN_MS);
+ assertTrue(testListener.isCompleted(5000));
+
+ // SET CTD TO CANCEL IN FUTURE
+ DateTime now = clock.getUTCNow();
+ Duration ctd = getDurationMonth(1);
+ DateTime newChargedThroughDate = DefaultClock.addDuration(now, ctd);
+ billingApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate);
+ baseSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(baseSubscription.getId());
+
+ // CHANGE IMMEDIATELY WITH TO BP WITH NON AVAILABLE ADDON
+ String newBaseProduct = "Pistol";
+ BillingPeriod newBaseTerm = BillingPeriod.MONTHLY;
+ String newBasePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
+
+ baseSubscription.changePlan(newBaseProduct, newBaseTerm, newBasePriceList, now);
+
+
+ // REFETCH AO SUBSCRIPTION AND CHECK THIS IS ACTIVE
+ aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
+ assertEquals(aoSubscription.getState(), SubscriptionState.ACTIVE);
+
+ // MOVE AFTER CHANGE
+ testListener.reset();
+ testListener.pushExpectedEvent(NextEvent.CHANGE);
+ clock.addDeltaFromReality(ctd);
+ now = clock.getUTCNow();
+ assertTrue(testListener.isCompleted(5000));
+
+
+ // REFETCH AO SUBSCRIPTION AND CHECK THIS CANCELLED
+ aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
+ assertEquals(aoSubscription.getState(), SubscriptionState.CANCELLED);
+
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
+
+ @Test(enabled=false, groups={"sql"})
public void testAddonCreateWithBundleAlign() {
try {
String aoProduct = "Telescopic-Scope";
entitlement/src/test/resources/testInput.xml 37(+13 -24)
diff --git a/entitlement/src/test/resources/testInput.xml b/entitlement/src/test/resources/testInput.xml
index 7174893..3d36b9d 100644
--- a/entitlement/src/test/resources/testInput.xml
+++ b/entitlement/src/test/resources/testInput.xml
@@ -91,33 +91,18 @@ Use Cases to do:
<phaseType>TRIAL</phaseType>
<policy>IMMEDIATE</policy>
</changePolicyCase>
- <changePolicyCase>
- <toProduct>Pistol</toProduct>
- <policy>END_OF_TERM</policy>
- </changePolicyCase>
+ <changePolicyCase>
+ <toProduct>Assault-Rifle</toProduct>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <fromProduct>Pistol</fromProduct>
+ <toProduct>Shotgun</toProduct>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
<changePolicyCase>
<toPriceList>rescue</toPriceList>
<policy>END_OF_TERM</policy>
- </changePolicyCase>
- <changePolicyCase>
- <fromProduct>Pistol</fromProduct>
- <toProduct>Shotgun</toProduct>
- <policy>IMMEDIATE</policy>
- </changePolicyCase>
- <changePolicyCase>
- <fromProduct>Assault-Rifle</fromProduct>
- <toProduct>Shotgun</toProduct>
- <policy>END_OF_TERM</policy>
- </changePolicyCase>
- <changePolicyCase>
- <fromBillingPeriod>MONTHLY</fromBillingPeriod>
- <toProduct>Assault-Rifle</toProduct>
- <toBillingPeriod>MONTHLY</toBillingPeriod>
- <policy>END_OF_TERM</policy>
- </changePolicyCase>
- <changePolicyCase>
- <toProduct>Assault-Rifle</toProduct>
- <policy>IMMEDIATE</policy>
</changePolicyCase>
<changePolicyCase>
<fromBillingPeriod>MONTHLY</fromBillingPeriod>
@@ -157,6 +142,10 @@ Use Cases to do:
</cancelPolicyCase>
</cancelPolicy>
<createAlignment>
+ <createAlignmentCase>
+ <product>Laser-Scope</product>
+ <alignment>START_OF_SUBSCRIPTION</alignment>
+ </createAlignmentCase>
<createAlignmentCase>
<alignment>START_OF_BUNDLE</alignment>
</createAlignmentCase>