killbill-memoizeit
Changes
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java 34(+31 -3)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java 4(+2 -2)
entitlement/src/test/resources/testInput.xml 22(+18 -4)
Details
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index 8336ddb..f2c6add 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -36,6 +36,10 @@ public enum ErrorCode {
ENT_CREATE_NO_BUNDLE(1012, "Bundle %s does not exist"),
ENT_CREATE_NO_BP(1013, "Missing Base Subscription for bundle %s"),
ENT_CREATE_BP_EXISTS(1015, "Subscription bundle %s already has a base subscription"),
+ ENT_CREATE_AO_BP_NON_ACTIVE(1017, "Can't create AddOn %s for non active Base Plan"),
+ ENT_CREATE_AO_ALREADY_INCLUDED(1018, "Can't create AddOn %s for BasePlan %s (Already included)"),
+ ENT_CREATE_AO_NOT_AVAILABLE(1019, "Can't create AddOn %s for BasePlan %s (Not available)"),
+
/* Change plan */
ENT_CHANGE_NON_ACTIVE(1021, "Subscription %s is in state %s"),
ENT_CHANGE_FUTURE_CANCELLED(1022, "Subscription %s is future cancelled"),
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
index 083aef5..2515bf5 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
@@ -163,9 +163,13 @@ public class PlanAligner {
PlanPhase currentPhase = subscription.getCurrentPhase();
Plan currentPlan = subscription.getCurrentPlan();
String currentPriceList = subscription.getCurrentPriceList();
+ ProductCategory currentCategory = currentPlan.getProduct().getCategory();
+ if (currentCategory != ProductCategory.BASE) {
+ throw new EntitlementError(String.format("Only implemented changePlan for BasePlan"));
+ }
PlanPhaseSpecifier fromPlanPhaseSpecifier = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
- currentPlan.getProduct().getCategory(),
+ currentCategory,
currentPlan.getBillingPeriod(),
currentPriceList,
currentPhase.getPhaseType());
@@ -208,6 +212,7 @@ public class PlanAligner {
DateTime curPhaseStart = (initialPhase == null) ? initialPhaseStartDate : null;
DateTime nextPhaseStart = null;
for (PlanPhase cur : plan.getAllPhases()) {
+ // For create we can specifcy the phase so skip any phase until we reach initialPhase
if (curPhaseStart == null) {
if (initialPhase != cur.getPhaseType()) {
continue;
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 8b6d59a..d252278 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
@@ -27,6 +27,8 @@ import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.catalog.api.Product;
+import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
import com.ning.billing.entitlement.engine.dao.EntitlementDao;
import com.ning.billing.entitlement.exceptions.EntitlementError;
@@ -87,6 +89,7 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
return dao.createSubscriptionBundle(bundle);
}
+
@Override
public Subscription createSubscription(UUID bundleId, PlanPhaseSpecifier spec, DateTime requestedDate) throws EntitlementUserApiException {
@@ -103,7 +106,7 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
Plan plan = catalogService.getCatalog().findPlan(spec.getProductName(), spec.getBillingPeriod(), realPriceList);
- PlanPhase phase = (plan.getInitialPhases() != null) ? plan.getInitialPhases()[0] : plan.getFinalPhase();
+ PlanPhase phase = plan.getAllPhases()[0];
if (phase == null) {
throw new EntitlementError(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));
@@ -116,7 +119,6 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
DateTime bundleStartDate = null;
Subscription baseSubscription = dao.getBaseSubscription(bundleId);
-
switch(plan.getProduct().getCategory()) {
case BASE:
if (baseSubscription != null) {
@@ -128,6 +130,7 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
if (baseSubscription == null) {
throw new EntitlementUserApiException(ErrorCode.ENT_CREATE_NO_BP, bundleId);
}
+ checkAddonCreationRights(baseSubscription, plan);
bundleStartDate = baseSubscription.getStartDate();
break;
default:
@@ -135,7 +138,7 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
plan.getProduct().getCategory().toString()));
}
- SubscriptionData subscription = apiService.createBasePlan(new SubscriptionBuilder()
+ SubscriptionData subscription = apiService.createPlan(new SubscriptionBuilder()
.setId(UUID.randomUUID())
.setBundleId(bundleId)
.setCategory(plan.getProduct().getCategory())
@@ -148,4 +151,29 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
throw new EntitlementUserApiException(e);
}
}
+
+ private void checkAddonCreationRights(Subscription baseSubscription, Plan targetAddOnPlan)
+ throws EntitlementUserApiException, CatalogApiException {
+
+ if (baseSubscription.getState() != SubscriptionState.ACTIVE) {
+ throw new EntitlementUserApiException(ErrorCode.ENT_CREATE_AO_BP_NON_ACTIVE, targetAddOnPlan.getName());
+ }
+
+ Product targetAddonProduct = targetAddOnPlan.getProduct();
+ Product baseProduct = baseSubscription.getCurrentPlan().getProduct();
+
+ Product [] includedAddOns = baseProduct.getIncluded();
+ for (Product curInc : includedAddOns) {
+ if (curInc.getName().equals(targetAddonProduct.getName())) {
+ throw new EntitlementUserApiException(ErrorCode.ENT_CREATE_AO_ALREADY_INCLUDED, targetAddOnPlan.getName(), baseProduct.getName());
+ }
+ }
+ Product[] availableAddOns = baseProduct.getAvailable();
+ for (Product curAv : availableAddOns) {
+ if (curAv.getName().equals(targetAddonProduct.getName())) {
+ return;
+ }
+ }
+ throw new EntitlementUserApiException(ErrorCode.ENT_CREATE_AO_NOT_AVAILABLE, targetAddOnPlan.getName(), baseProduct.getName());
+ }
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java
index 3aebac0..7ad6e03 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java
@@ -52,13 +52,13 @@ public class SubscriptionApiService {
- public SubscriptionData createBasePlan(SubscriptionBuilder builder, Plan plan, PhaseType initialPhase,
+ public SubscriptionData createPlan(SubscriptionBuilder builder, Plan plan, PhaseType initialPhase,
String realPriceList, DateTime requestedDate, DateTime effectiveDate, DateTime processedDate)
throws EntitlementUserApiException {
try {
- SubscriptionData subscription = new SubscriptionData(builder, this, clock);
+ SubscriptionData subscription = new SubscriptionData(builder, this, clock);
TimedPhase [] curAndNextPhases = planAligner.getCurrentAndNextTimedPhaseOnCreate(subscription, plan, initialPhase, realPriceList, effectiveDate);
ApiEventCreate creationEvent = new ApiEventCreate(new ApiEventBuilder()
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
index ff3a443..52e25f7 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
@@ -189,8 +189,13 @@ public abstract class TestApiBase {
}
protected SubscriptionData createSubscription(final String productName, final BillingPeriod term, final String planSet) throws EntitlementUserApiException {
+ return createSubscriptionWithBundle(bundle.getId(), productName, term, planSet);
+ }
+
+
+ protected SubscriptionData createSubscriptionWithBundle(final UUID bundleId, final String productName, final BillingPeriod term, final String planSet) throws EntitlementUserApiException {
testListener.pushExpectedEvent(NextEvent.CREATE);
- SubscriptionData subscription = (SubscriptionData) entitlementApi.createSubscription(bundle.getId(),
+ SubscriptionData subscription = (SubscriptionData) entitlementApi.createSubscription(bundleId,
new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSet, null),
clock.getUTCNow());
assertNotNull(subscription);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
index c32b654..2533855 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
@@ -68,9 +68,9 @@ public class TestUserApiError extends TestApiBase {
tCreateSubscriptionInternal(null, "Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, ErrorCode.ENT_CREATE_NO_BUNDLE);
}
- @Test(enabled=false)
+ @Test(enabled=true)
public void testCreateSubscriptionNoBP() {
- //tCreateSubscriptionInternal(bundle.getId(), "Shotgun", BillingPeriod.ANNUAL, IPriceListSet.DEFAULT_PRICELIST_NAME, ErrorCode.ENT_CREATE_NO_BP);
+ tCreateSubscriptionInternal(bundle.getId(), "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, ErrorCode.ENT_CREATE_NO_BP);
}
@Test(enabled=true)
@@ -84,6 +84,33 @@ public class TestUserApiError extends TestApiBase {
}
}
+ @Test(enabled=true)
+ public void testCreateSubscriptionAddOnNotAvailable() {
+ try {
+ UUID accountId = UUID.randomUUID();
+ SubscriptionBundle aoBundle = entitlementApi.createBundleForAccount(accountId, "myAOBundle");
+ createSubscriptionWithBundle(aoBundle.getId(), "Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+ tCreateSubscriptionInternal(aoBundle.getId(), "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, ErrorCode.ENT_CREATE_AO_NOT_AVAILABLE);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Assert.assertFalse(true);
+ }
+ }
+
+ @Test(enabled=true)
+ public void testCreateSubscriptionAddOnIncluded() {
+ try {
+ UUID accountId = UUID.randomUUID();
+ SubscriptionBundle aoBundle = entitlementApi.createBundleForAccount(accountId, "myAOBundle");
+ createSubscriptionWithBundle(aoBundle.getId(), "Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+ tCreateSubscriptionInternal(aoBundle.getId(), "Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, ErrorCode.ENT_CREATE_AO_ALREADY_INCLUDED);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Assert.assertFalse(true);
+ }
+ }
+
+
private void tCreateSubscriptionInternal(UUID bundleId, String productName,
BillingPeriod term, String planSet, ErrorCode expected) {
try {
entitlement/src/test/resources/testInput.xml 22(+18 -4)
diff --git a/entitlement/src/test/resources/testInput.xml b/entitlement/src/test/resources/testInput.xml
index 01d7cb4..8d6b56c 100644
--- a/entitlement/src/test/resources/testInput.xml
+++ b/entitlement/src/test/resources/testInput.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>
@@ -447,6 +447,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>