killbill-memoizeit
Changes
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java 111(+108 -3)
beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithEntilementPlugin.java 29(+17 -12)
entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultBaseEntitlementWithAddOnsSpecifier.java 75(+75 -0)
entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java 159(+87 -72)
entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementContext.java 58(+8 -50)
entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java 31(+21 -10)
entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementApiBase.java 32(+23 -9)
entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java 20(+14 -6)
entitlement/src/main/java/org/killbill/billing/entitlement/logging/EntitlementLoggingHelper.java 18(+17 -1)
entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java 98(+0 -98)
jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BulkBaseSubscriptionAndAddOnsJson.java 68(+68 -0)
pom.xml 2(+1 -1)
subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java 6(+3 -3)
subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java 160(+97 -63)
subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java 56(+43 -13)
subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseWithAddOns.java 55(+55 -0)
subscription/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionAndAddOnsSpecifier.java 55(+55 -0)
subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java 34(+21 -13)
Details
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 9badfbc..8599350 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
@@ -30,13 +30,12 @@ import org.joda.time.LocalDate;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingActionPolicy;
-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.BaseEntitlementWithAddOnsSpecifier;
import org.killbill.billing.entitlement.api.EntitlementAOStatusDryRun;
-import org.killbill.billing.entitlement.api.EntitlementSpecifier;
import org.killbill.billing.events.EffectiveSubscriptionInternalEvent;
import org.killbill.billing.invoice.api.DryRunArguments;
import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
@@ -49,8 +48,8 @@ public interface SubscriptionBaseInternalApi {
public SubscriptionBase createSubscription(UUID bundleId, PlanPhaseSpecifier spec, List<PlanPhasePriceOverride> overrides, DateTime requestedDateWithMs,
final boolean isMigrated, InternalCallContext context) throws SubscriptionBaseApiException;
- public List<SubscriptionBase> createBaseSubscriptionWithAddOns(UUID bundleId, Iterable<EntitlementSpecifier> entitlements, DateTime requestedDateWithMs,
- final boolean isMigrated, InternalCallContext context) throws SubscriptionBaseApiException;
+ public List<SubscriptionBaseWithAddOns> createBaseSubscriptionsWithAddOns(UUID accountId, Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifier,
+ InternalCallContext contextWithValidAccountRecordId) throws SubscriptionBaseApiException;
public void cancelBaseSubscriptions(Iterable<SubscriptionBase> subscriptions, BillingActionPolicy policy, InternalCallContext context) throws SubscriptionBaseApiException;
diff --git a/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseWithAddOns.java b/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseWithAddOns.java
new file mode 100644
index 0000000..5753c1a
--- /dev/null
+++ b/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseWithAddOns.java
@@ -0,0 +1,32 @@
+/*
+ * 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.subscription.api;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.killbill.billing.subscription.api.SubscriptionBase;
+
+public interface SubscriptionBaseWithAddOns {
+
+ public UUID getBundleId();
+
+ public List<SubscriptionBase> getSubscriptionBaseList();
+
+ public DateTime getEffectiveDate();
+}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java
index 3069314..16eadea 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java
@@ -20,6 +20,7 @@ package org.killbill.billing.beatrix.integration;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
+import java.util.UUID;
import org.joda.time.LocalDate;
import org.killbill.billing.account.api.Account;
@@ -30,6 +31,7 @@ import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.PhaseType;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
import org.killbill.billing.catalog.api.PriceListSet;
+import org.killbill.billing.entitlement.api.BaseEntitlementWithAddOnsSpecifier;
import org.killbill.billing.entitlement.api.DefaultEntitlementSpecifier;
import org.killbill.billing.entitlement.api.Entitlement;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
@@ -235,14 +237,117 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
specifierList.add(addOnEntitlementSpecifier1);
busHandler.pushExpectedEvents(NextEvent.BLOCK, NextEvent.BLOCK);
- final Entitlement baseEntitlement = entitlementApi.createBaseEntitlementWithAddOns(account.getId(), externalKey, specifierList, entitlementMigrationDate, billingMigrationDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = buildBaseEntitlementWithAddOnsSpecifier(entitlementMigrationDate, billingMigrationDate, externalKey, specifierList);
+ List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
+
+ final List<Entitlement> baseEntitlements = entitlementApi.createBaseEntitlementsWithAddOns(
+ account.getId(),
+ baseEntitlementWithAddOnsSpecifierList,
+ ImmutableList.<PluginProperty>of(),
+ callContext);
assertListenerStatus();
- Assert.assertEquals(baseEntitlement.getState(), EntitlementState.ACTIVE);
+ Assert.assertEquals(baseEntitlements.get(0).getState(), EntitlementState.ACTIVE);
// Billing starts straight on EVERGREEN
- busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.CREATE, NextEvent.INVOICE, NextEvent.NULL_INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addMonths(1);
+ busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.CREATE, NextEvent.INVOICE, NextEvent.NULL_INVOICE,
+ NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
assertListenerStatus();
}
+
+ @Test(groups = "slow")
+ public void testMigrationWithMultipleBundlesAndDifferentDates() throws Exception {
+
+ clock.setDay(new LocalDate(2016, 1, 1));
+ final AccountData accountData = getAccountData(1);
+ final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
+ accountChecker.checkAccount(account.getId(), accountData, callContext);
+
+ // We set both entitlement and billing date with desired value
+ final LocalDate entitlementMigrationDateBundle1 = new LocalDate(2015, 12, 20);
+ final LocalDate billingMigrationDateBundle1 = new LocalDate(2016, 2, 1);
+
+ // We set both entitlement and billing date with desired value
+ final LocalDate entitlementMigrationDateBundle2 = new LocalDate(2015, 12, 20);
+ final LocalDate billingMigrationDateBundle2 = new LocalDate(2016, 3, 1);
+
+ final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
+ final PlanPhaseSpecifier addOnSpec1 = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
+
+ final String externalKey = "baseExternalKey";
+ EntitlementSpecifier baseEntitlementSpecifier = new DefaultEntitlementSpecifier(baseSpec, null);
+ EntitlementSpecifier addOnEntitlementSpecifier1 = new DefaultEntitlementSpecifier(addOnSpec1, null);
+
+ final List<EntitlementSpecifier> specifierList = new ArrayList<EntitlementSpecifier>();
+ specifierList.add(baseEntitlementSpecifier);
+ specifierList.add(addOnEntitlementSpecifier1);
+
+ busHandler.pushExpectedEvents(NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.BLOCK);
+ BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifierBundle1 =
+ buildBaseEntitlementWithAddOnsSpecifier(entitlementMigrationDateBundle1, billingMigrationDateBundle1, externalKey, specifierList);
+ List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifierBundle2 =
+ buildBaseEntitlementWithAddOnsSpecifier(entitlementMigrationDateBundle2, billingMigrationDateBundle2, externalKey, specifierList);
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifierBundle1);
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifierBundle2);
+
+ final List<Entitlement> baseEntitlements = entitlementApi.createBaseEntitlementsWithAddOns(
+ account.getId(),
+ baseEntitlementWithAddOnsSpecifierList,
+ ImmutableList.<PluginProperty>of(),
+ callContext);
+ assertListenerStatus();
+ Assert.assertEquals(baseEntitlements.get(0).getState(), EntitlementState.ACTIVE);
+ Assert.assertEquals(baseEntitlements.get(1).getState(), EntitlementState.ACTIVE);
+
+ // Billing starts straight on EVERGREEN for Bundle 1 after 1 month
+ clock.addMonths(1);
+ busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.CREATE, NextEvent.INVOICE, NextEvent.NULL_INVOICE,
+ NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ assertListenerStatus();
+
+ // Billing starts straight on EVERGREEN for Bundle 2 after 2 months
+ clock.addMonths(1);
+ busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.CREATE, NextEvent.INVOICE,
+ NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE,
+ NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ assertListenerStatus();
+
+ // Next month we should still get one single invoice and payment / invoice payment
+ clock.addMonths(1);
+ busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+ assertListenerStatus();
+ }
+
+ private BaseEntitlementWithAddOnsSpecifier buildBaseEntitlementWithAddOnsSpecifier(final LocalDate entitlementMigrationDate, final LocalDate billingMigrationDate, final String externalKey, final List<EntitlementSpecifier> specifierList) {
+ return new BaseEntitlementWithAddOnsSpecifier() {
+ @Override
+ public UUID getBundleId() {
+ return null;
+ }
+ @Override
+ public String getExternalKey() {
+ return externalKey;
+ }
+ @Override
+ public Iterable<EntitlementSpecifier> getEntitlementSpecifier() {
+ return specifierList;
+ }
+ @Override
+ public LocalDate getEntitlementEffectiveDate() {
+ return entitlementMigrationDate;
+ }
+ @Override
+ public LocalDate getBillingEffectiveDate() {
+ return billingMigrationDate;
+ }
+ @Override
+ public boolean isMigrated() {
+ return false;
+ }
+ };
+ }
+
}
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
index 17d84b4..8b5ca40 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
@@ -22,12 +22,10 @@ import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
-import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.account.api.Account;
-import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.api.TestApiListener.NextEvent;
import org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck;
import org.killbill.billing.catalog.api.BillingActionPolicy;
@@ -35,6 +33,8 @@ import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.entitlement.api.BaseEntitlementWithAddOnsSpecifier;
+import org.killbill.billing.entitlement.api.DefaultBaseEntitlementWithAddOnsSpecifier;
import org.killbill.billing.entitlement.api.DefaultEntitlement;
import org.killbill.billing.entitlement.api.DefaultEntitlementSpecifier;
import org.killbill.billing.entitlement.api.Entitlement;
@@ -42,8 +42,6 @@ import org.killbill.billing.entitlement.api.Entitlement.EntitlementActionPolicy;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
import org.killbill.billing.entitlement.api.EntitlementApiException;
import org.killbill.billing.entitlement.api.EntitlementSpecifier;
-import org.killbill.billing.entitlement.api.Subscription;
-import org.killbill.billing.entitlement.api.SubscriptionApiException;
import org.killbill.billing.entitlement.api.SubscriptionEventType;
import org.killbill.billing.invoice.api.DryRunType;
import org.killbill.billing.invoice.api.Invoice;
@@ -56,7 +54,6 @@ import com.google.common.collect.ImmutableList;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertTrue;
public class TestSubscription extends TestIntegrationBase {
@@ -192,7 +189,7 @@ public class TestSubscription extends TestIntegrationBase {
}
@Test(groups = "slow")
- public void testCreateSubscriptionWithAddOns() throws Exception {
+ public void testCreateMultipleSubscriptionsWithAddOns() throws Exception {
final LocalDate initialDate = new LocalDate(2015, 10, 1);
clock.setDay(initialDate);
@@ -202,29 +199,51 @@ public class TestSubscription extends TestIntegrationBase {
final PlanPhaseSpecifier addOnSpec1 = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
final PlanPhaseSpecifier addOnSpec2 = new PlanPhaseSpecifier("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final String externalKey = "baseExternalKey";
- EntitlementSpecifier baseEntitlementSpecifier = new DefaultEntitlementSpecifier(baseSpec, null);
- EntitlementSpecifier addOnEntitlementSpecifier1 = new DefaultEntitlementSpecifier(addOnSpec1, null);
- EntitlementSpecifier addOnEntitlementSpecifier2 = new DefaultEntitlementSpecifier(addOnSpec2, null);
-
- final List<EntitlementSpecifier> specifierList = new ArrayList<EntitlementSpecifier>();
- specifierList.add(baseEntitlementSpecifier);
- specifierList.add(addOnEntitlementSpecifier1);
- specifierList.add(addOnEntitlementSpecifier2);
-
- busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
- final Entitlement entitlement = entitlementApi.createBaseEntitlementWithAddOns(account.getId(), externalKey, specifierList, initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext);
+ final String externalKeyA = "baseExternalKeyAAA";
+ final EntitlementSpecifier baseEntitlementSpecifier = new DefaultEntitlementSpecifier(baseSpec, null);
+ final EntitlementSpecifier addOnEntitlementSpecifier1 = new DefaultEntitlementSpecifier(addOnSpec1, null);
+ final EntitlementSpecifier addOnEntitlementSpecifier2 = new DefaultEntitlementSpecifier(addOnSpec2, null);
+
+ final List<EntitlementSpecifier> specifierListA = new ArrayList<EntitlementSpecifier>();
+ specifierListA.add(baseEntitlementSpecifier);
+ specifierListA.add(addOnEntitlementSpecifier1);
+ specifierListA.add(addOnEntitlementSpecifier2);
+
+ final String externalKeyB = "baseExternalKeyBBB";
+
+ final List<EntitlementSpecifier> specifierListB = new ArrayList<EntitlementSpecifier>();
+ specifierListB.add(baseEntitlementSpecifier);
+ specifierListB.add(addOnEntitlementSpecifier1);
+ specifierListB.add(addOnEntitlementSpecifier2);
+
+ final List<BaseEntitlementWithAddOnsSpecifier> entitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ final BaseEntitlementWithAddOnsSpecifier cartSpecifierA = new DefaultBaseEntitlementWithAddOnsSpecifier(null, externalKeyA, specifierListA, null, null, false);
+ final BaseEntitlementWithAddOnsSpecifier cartSpecifierB = new DefaultBaseEntitlementWithAddOnsSpecifier(null, externalKeyB, specifierListB, null, null, false);
+ entitlementWithAddOnsSpecifierList.add(cartSpecifierA);
+ entitlementWithAddOnsSpecifierList.add(cartSpecifierB);
+
+ busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK,
+ NextEvent.CREATE, NextEvent.BLOCK,
+ NextEvent.CREATE, NextEvent.BLOCK,
+ NextEvent.CREATE, NextEvent.BLOCK,
+ NextEvent.CREATE, NextEvent.BLOCK,
+ NextEvent.CREATE, NextEvent.BLOCK,
+ NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE,
+ NextEvent.NULL_INVOICE, NextEvent.NULL_INVOICE,
+ NextEvent.NULL_INVOICE,
+ NextEvent.INVOICE,
+ NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT
+ );
+ final List<Entitlement> allEntitlements = entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), entitlementWithAddOnsSpecifierList, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
checkNoMoreInvoiceToGenerate(account);
- assertNotNull(entitlement);
+ assertNotNull(allEntitlements);
+ assertEquals(allEntitlements.size(), 6);
- final List<Entitlement> allEntitlementsForBundle = entitlementApi.getAllEntitlementsForBundle(entitlement.getBundleId(), callContext);
- assertTrue(allEntitlementsForBundle.size() == 3);
-
- final Entitlement baseEntitlement = allEntitlementsForBundle.get(0);
- final Entitlement addOnEntitlement1 = allEntitlementsForBundle.get(1);
- final Entitlement addOnEntitlement2 = allEntitlementsForBundle.get(2);
+ final Entitlement baseEntitlement = allEntitlements.get(0);
+ final Entitlement addOnEntitlement1 = allEntitlements.get(1);
+ final Entitlement addOnEntitlement2 = allEntitlements.get(2);
assertEquals(baseEntitlement.getLastActiveProduct().getName(), "Shotgun");
assertEquals(baseEntitlement.getLastActiveProductCategory(), ProductCategory.BASE);
@@ -236,47 +255,84 @@ public class TestSubscription extends TestIntegrationBase {
assertEquals(addOnEntitlement2.getLastActiveProductCategory(), ProductCategory.ADD_ON);
final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), false, callContext);
- assertTrue(invoices.size() == 1); // ONLY ONE INVOICE
- assertTrue(invoices.get(0).getInvoiceItems().size() == 3);
+ assertEquals(invoices.size(), 1); // ONLY ONE INVOICE
+ assertEquals(invoices.get(0).getInvoiceItems().size(), 6);
final ImmutableList<ExpectedInvoiceItemCheck> toBeChecked = ImmutableList.<ExpectedInvoiceItemCheck>of(
new ExpectedInvoiceItemCheck(initialDate, new LocalDate(2015, 10, 31), InvoiceItemType.RECURRING, new BigDecimal("387.05")), // amount=387.05, rate=399.95 -> Telescopic-Scope
new ExpectedInvoiceItemCheck(initialDate, new LocalDate(2015, 10, 31), InvoiceItemType.RECURRING, new BigDecimal("967.69")), // amount=967.69, rate=999.95 -> Laser-Scope
+ new ExpectedInvoiceItemCheck(initialDate, null, InvoiceItemType.FIXED, new BigDecimal("0")), // Shotgun
+ new ExpectedInvoiceItemCheck(initialDate, new LocalDate(2015, 10, 31), InvoiceItemType.RECURRING, new BigDecimal("387.05")), // amount=387.05, rate=399.95 -> Telescopic-Scope
+ new ExpectedInvoiceItemCheck(initialDate, new LocalDate(2015, 10, 31), InvoiceItemType.RECURRING, new BigDecimal("967.69")), // amount=967.69, rate=999.95 -> Laser-Scope
new ExpectedInvoiceItemCheck(initialDate, null, InvoiceItemType.FIXED, new BigDecimal("0"))); // Shotgun
invoiceChecker.checkInvoice(invoices.get(0).getId(), callContext, toBeChecked);
}
- @Test(groups = "slow")
- public void testCreateSubscriptionWithAddOnsWithLimitException() throws Exception {
+ @Test(groups = "slow", expectedExceptions = EntitlementApiException.class, expectedExceptionsMessageRegExp = "Missing Base Subscription.")
+ public void testCreateMultipleSubscriptionsWithoutBase() throws Exception {
final LocalDate initialDate = new LocalDate(2015, 10, 1);
clock.setDay(initialDate);
final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final PlanPhaseSpecifier addOnSpec1 = new PlanPhaseSpecifier("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+ final PlanPhaseSpecifier addOnSpec1 = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
final PlanPhaseSpecifier addOnSpec2 = new PlanPhaseSpecifier("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final PlanPhaseSpecifier addOnSpec3 = new PlanPhaseSpecifier("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final String externalKey = "baseExternalKey";
- EntitlementSpecifier baseEntitlementSpecifier = new DefaultEntitlementSpecifier(baseSpec, null);
- EntitlementSpecifier addOnEntitlementSpecifier1 = new DefaultEntitlementSpecifier(addOnSpec1, null);
- EntitlementSpecifier addOnEntitlementSpecifier2 = new DefaultEntitlementSpecifier(addOnSpec2, null);
- EntitlementSpecifier addOnEntitlementSpecifier3 = new DefaultEntitlementSpecifier(addOnSpec3, null);
+ final String externalKeyA = "baseExternalKeyAAA";
+ final EntitlementSpecifier baseEntitlementSpecifier = new DefaultEntitlementSpecifier(baseSpec, null);
+ final EntitlementSpecifier addOnEntitlementSpecifier1 = new DefaultEntitlementSpecifier(addOnSpec1, null);
+ final EntitlementSpecifier addOnEntitlementSpecifier2 = new DefaultEntitlementSpecifier(addOnSpec2, null);
- final List<EntitlementSpecifier> specifierList = new ArrayList<EntitlementSpecifier>();
- specifierList.add(baseEntitlementSpecifier);
- specifierList.add(addOnEntitlementSpecifier1);
- specifierList.add(addOnEntitlementSpecifier2);
- specifierList.add(addOnEntitlementSpecifier3);
+ final List<EntitlementSpecifier> specifierListA = new ArrayList<EntitlementSpecifier>();
+ specifierListA.add(baseEntitlementSpecifier);
+ specifierListA.add(addOnEntitlementSpecifier1);
+ specifierListA.add(addOnEntitlementSpecifier2);
- // Trying to add the third add_on with the same plan should throw an exception (the limit is 2 for this plan)
- try {
- entitlementApi.createBaseEntitlementWithAddOns(account.getId(), externalKey, specifierList, initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext);
- } catch (final EntitlementApiException e) {
- assertEquals(e.getCode(), ErrorCode.SUB_CREATE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE.getCode());
- }
+ final String externalKeyB = "baseExternalKeyBBB";
+ final List<EntitlementSpecifier> specifierListB = new ArrayList<EntitlementSpecifier>();
+ specifierListB.add(addOnEntitlementSpecifier1);
+ specifierListB.add(addOnEntitlementSpecifier2);
+
+ final List<BaseEntitlementWithAddOnsSpecifier> entitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ final BaseEntitlementWithAddOnsSpecifier cartSpecifierA = new DefaultBaseEntitlementWithAddOnsSpecifier(null, externalKeyA, specifierListA, null, null, false);
+ final BaseEntitlementWithAddOnsSpecifier cartSpecifierB = new DefaultBaseEntitlementWithAddOnsSpecifier(null, externalKeyB, specifierListB, null, null, false);
+ entitlementWithAddOnsSpecifierList.add(cartSpecifierA);
+ entitlementWithAddOnsSpecifierList.add(cartSpecifierB);
+
+ entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), entitlementWithAddOnsSpecifierList, ImmutableList.<PluginProperty>of(), callContext);
+ }
+
+ @Test(groups = "slow", expectedExceptions = EntitlementApiException.class,
+ expectedExceptionsMessageRegExp = "Can't create AddOn laser-scope-monthly, the number of Subscriptions allowed by this Plan and Bundle has reached its limit")
+ public void testCreateMultipleSubscriptionsExceedLimit() throws Exception {
+ final LocalDate initialDate = new LocalDate(2015, 10, 1);
+ clock.setDay(initialDate);
+
+ final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
+
+ final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+ final PlanPhaseSpecifier addOnSpec1 = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+ final PlanPhaseSpecifier addOnSpec2 = new PlanPhaseSpecifier("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+
+ final String externalKeyA = "baseExternalKeyAAA";
+ final EntitlementSpecifier baseEntitlementSpecifier = new DefaultEntitlementSpecifier(baseSpec, null);
+ final EntitlementSpecifier addOnEntitlementSpecifier1 = new DefaultEntitlementSpecifier(addOnSpec1, null);
+ final EntitlementSpecifier addOnEntitlementSpecifier2 = new DefaultEntitlementSpecifier(addOnSpec2, null);
+
+ final List<EntitlementSpecifier> specifierListA = new ArrayList<EntitlementSpecifier>();
+ specifierListA.add(baseEntitlementSpecifier);
+ specifierListA.add(addOnEntitlementSpecifier1);
+ specifierListA.add(addOnEntitlementSpecifier2);
+ specifierListA.add(addOnEntitlementSpecifier2);
+ specifierListA.add(addOnEntitlementSpecifier2);
+
+ final List<BaseEntitlementWithAddOnsSpecifier> entitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ final BaseEntitlementWithAddOnsSpecifier cartSpecifierA = new DefaultBaseEntitlementWithAddOnsSpecifier(null, externalKeyA, specifierListA, null, null, false);
+ entitlementWithAddOnsSpecifierList.add(cartSpecifierA);
+
+ entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), entitlementWithAddOnsSpecifierList, ImmutableList.<PluginProperty>of(), callContext);
}
@Test(groups = "slow")
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithEntilementPlugin.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithEntilementPlugin.java
index e6f7499..b19e101 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithEntilementPlugin.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithEntilementPlugin.java
@@ -32,8 +32,9 @@ import org.killbill.billing.catalog.DefaultPlanPhasePriceOverride;
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.ProductCategory;
+import org.killbill.billing.entitlement.api.BaseEntitlementWithAddOnsSpecifier;
+import org.killbill.billing.entitlement.api.DefaultBaseEntitlementWithAddOnsSpecifier;
import org.killbill.billing.entitlement.api.DefaultEntitlement;
import org.killbill.billing.entitlement.api.DefaultEntitlementSpecifier;
import org.killbill.billing.entitlement.api.EntitlementSpecifier;
@@ -136,30 +137,34 @@ public class TestWithEntilementPlugin extends TestIntegrationBase {
@Override
public PriorEntitlementResult priorCall(final EntitlementContext entitlementContext, final Iterable<PluginProperty> properties) throws EntitlementPluginApiException {
if (planPhasePriceOverride != null) {
- final EntitlementSpecifier entitlementSpecifier = new DefaultEntitlementSpecifier(entitlementContext.getEntitlementSpecifiers().get(0).getPlanPhaseSpecifier(), planPhasePriceOverride);
+ final EntitlementSpecifier entitlementSpecifier = new DefaultEntitlementSpecifier(entitlementContext.getBaseEntitlementWithAddOnsSpecifiers().iterator().next().getEntitlementSpecifier().iterator().next().getPlanPhaseSpecifier(), planPhasePriceOverride);
final List<EntitlementSpecifier> entitlementSpecifiers = new ArrayList<EntitlementSpecifier>();
entitlementSpecifiers.add(entitlementSpecifier);
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier =
+ new DefaultBaseEntitlementWithAddOnsSpecifier(
+ entitlementContext.getBaseEntitlementWithAddOnsSpecifiers().iterator().next().getBundleId(),
+ entitlementContext.getBaseEntitlementWithAddOnsSpecifiers().iterator().next().getExternalKey(),
+ entitlementSpecifiers,
+ entitlementContext.getBaseEntitlementWithAddOnsSpecifiers().iterator().next().getEntitlementEffectiveDate(),
+ entitlementContext.getBaseEntitlementWithAddOnsSpecifiers().iterator().next().getBillingEffectiveDate(),
+ entitlementContext.getBaseEntitlementWithAddOnsSpecifiers().iterator().next().isMigrated()
+ );
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifiersList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifiersList.add(baseEntitlementWithAddOnsSpecifier);
+
return new PriorEntitlementResult() {
@Override
public boolean isAborted() {
return false;
}
@Override
- public LocalDate getAdjustedEntitlementEffectiveDate() {
- return null;
- }
- @Override
- public LocalDate getAdjustedBillingEffectiveDate() {
- return null;
- }
- @Override
public BillingActionPolicy getAdjustedBillingActionPolicy() {
return null;
}
@Override
- public List<EntitlementSpecifier> getAdjustedEntitlementSpecifiers() {
- return entitlementSpecifiers;
+ public List<BaseEntitlementWithAddOnsSpecifier> getAdjustedBaseEntitlementWithAddOnsSpecifiers() {
+ return baseEntitlementWithAddOnsSpecifiersList;
}
@Override
public Iterable<PluginProperty> getAdjustedPluginProperties() {
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultBaseEntitlementWithAddOnsSpecifier.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultBaseEntitlementWithAddOnsSpecifier.java
new file mode 100644
index 0000000..265d0b9
--- /dev/null
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultBaseEntitlementWithAddOnsSpecifier.java
@@ -0,0 +1,75 @@
+/*
+ * 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.entitlement.api;
+
+import java.util.UUID;
+
+import org.joda.time.LocalDate;
+
+public class DefaultBaseEntitlementWithAddOnsSpecifier implements BaseEntitlementWithAddOnsSpecifier {
+
+ private final UUID bundleId;
+ private final String externalKey;
+ private final Iterable<EntitlementSpecifier> entitlementSpecifier;
+ private final LocalDate entitlementEffectiveDate;
+ private final LocalDate billingEffectiveDate;
+ private final boolean isMigrated;
+
+ public DefaultBaseEntitlementWithAddOnsSpecifier(final UUID bundleId,
+ final String externalKey,
+ final Iterable<EntitlementSpecifier> entitlementSpecifier,
+ final LocalDate entitlementEffectiveDate,
+ final LocalDate billingEffectiveDate,
+ final boolean isMigrated) {
+ this.bundleId = bundleId;
+ this.externalKey = externalKey;
+ this.entitlementSpecifier = entitlementSpecifier;
+ this.entitlementEffectiveDate = entitlementEffectiveDate;
+ this.billingEffectiveDate = billingEffectiveDate;
+ this.isMigrated = isMigrated;
+ }
+
+ @Override
+ public UUID getBundleId() {
+ return bundleId;
+ }
+
+ @Override
+ public String getExternalKey() {
+ return externalKey;
+ }
+
+ @Override
+ public Iterable<EntitlementSpecifier> getEntitlementSpecifier() {
+ return entitlementSpecifier;
+ }
+
+ @Override
+ public LocalDate getEntitlementEffectiveDate() {
+ return entitlementEffectiveDate;
+ }
+
+ @Override
+ public LocalDate getBillingEffectiveDate() {
+ return billingEffectiveDate;
+ }
+
+ @Override
+ public boolean isMigrated() {
+ return isMigrated;
+ }
+}
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 1f84737..2cf1acc 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
@@ -34,7 +34,6 @@ import org.killbill.billing.ErrorCode;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingActionPolicy;
-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.PlanPhase;
@@ -322,14 +321,19 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
}
final LocalDate billingEffectiveDate = overrideBillingEffectiveDate ? entitlementEffectiveDate : null;
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
+ getBundleId(),
+ getExternalKey(),
+ null,
+ entitlementEffectiveDate,
+ billingEffectiveDate,
+ false);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.CANCEL_SUBSCRIPTION,
getAccountId(),
null,
- getBundleId(),
- getExternalKey(),
- null,
- entitlementEffectiveDate,
- billingEffectiveDate,
+ baseEntitlementWithAddOnsSpecifierList,
null,
properties,
callContext);
@@ -382,14 +386,19 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
// Get the latest state from disk
refresh(callContext);
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
+ getBundleId(),
+ getExternalKey(),
+ null,
+ null,
+ null,
+ false);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.UNCANCEL_SUBSCRIPTION,
getAccountId(),
null,
- getBundleId(),
- getExternalKey(),
- null,
- null,
- null,
+ baseEntitlementWithAddOnsSpecifierList,
null,
properties,
callContext);
@@ -460,14 +469,19 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
// Get the latest state from disk
refresh(callContext);
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
+ getBundleId(),
+ getExternalKey(),
+ null,
+ entitlementEffectiveDate,
+ entitlementEffectiveDate,
+ false);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.CANCEL_SUBSCRIPTION,
getAccountId(),
null,
- getBundleId(),
- getExternalKey(),
- null,
- entitlementEffectiveDate,
- null,
+ baseEntitlementWithAddOnsSpecifierList,
billingPolicy,
properties,
callContext);
@@ -537,14 +551,19 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
// Get the latest state from disk
refresh(callContext);
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
+ getBundleId(),
+ getExternalKey(),
+ null,
+ null,
+ null,
+ false);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.CHANGE_PLAN,
getAccountId(),
null,
- getBundleId(),
- getExternalKey(),
- null,
- null,
- null,
+ baseEntitlementWithAddOnsSpecifierList,
null,
properties,
callContext);
@@ -603,14 +622,19 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
// Get the latest state from disk
refresh(callContext);
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
+ getBundleId(),
+ getExternalKey(),
+ null,
+ effectiveDate,
+ effectiveDate,
+ false);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.CHANGE_PLAN,
getAccountId(),
null,
- getBundleId(),
- getExternalKey(),
- null,
- effectiveDate,
- effectiveDate,
+ baseEntitlementWithAddOnsSpecifierList,
null,
properties,
callContext);
@@ -623,7 +647,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
}
final InternalCallContext context = internalCallContextFactory.createInternalCallContext(getAccountId(), callContext);
- final DateTime effectiveChangeDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getBillingEffectiveDate(), context);
+ final DateTime effectiveChangeDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getBaseEntitlementWithAddOnsSpecifiers().iterator().next().getBillingEffectiveDate(), context);
final DateTime resultingEffectiveDate;
try {
@@ -671,14 +695,19 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
// Get the latest state from disk
refresh(callContext);
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
+ getBundleId(),
+ getExternalKey(),
+ null,
+ entitlementEffectiveDate,
+ null,
+ false);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.CHANGE_PLAN,
getAccountId(),
null,
- getBundleId(),
- getExternalKey(),
- null,
- entitlementEffectiveDate,
- null,
+ baseEntitlementWithAddOnsSpecifierList,
actionPolicy,
properties,
callContext);
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
index f26c167..bd890dc 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
@@ -20,6 +20,7 @@ package org.killbill.billing.entitlement.api;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -37,7 +38,6 @@ import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
-import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.entitlement.AccountEventsStreams;
import org.killbill.billing.entitlement.EntitlementService;
import org.killbill.billing.entitlement.EventsStream;
@@ -47,7 +47,6 @@ import org.killbill.billing.entitlement.block.BlockingChecker;
import org.killbill.billing.entitlement.dao.BlockingStateDao;
import org.killbill.billing.entitlement.engine.core.EntitlementUtils;
import org.killbill.billing.entitlement.engine.core.EventsStreamBuilder;
-import org.killbill.billing.entitlement.logging.EntitlementLoggingHelper;
import org.killbill.billing.entitlement.plugin.api.EntitlementContext;
import org.killbill.billing.entitlement.plugin.api.OperationType;
import org.killbill.billing.junction.DefaultBlockingState;
@@ -55,6 +54,7 @@ import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.security.api.SecurityApi;
import org.killbill.billing.subscription.api.SubscriptionBase;
import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
+import org.killbill.billing.subscription.api.SubscriptionBaseWithAddOns;
import org.killbill.billing.subscription.api.transfer.SubscriptionBaseTransferApi;
import org.killbill.billing.subscription.api.transfer.SubscriptionBaseTransferApiException;
import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
@@ -73,7 +73,7 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import static org.killbill.billing.entitlement.logging.EntitlementLoggingHelper.logCreateEntitlement;
-import static org.killbill.billing.entitlement.logging.EntitlementLoggingHelper.logCreateEntitlementWithAOs;
+import static org.killbill.billing.entitlement.logging.EntitlementLoggingHelper.logCreateEntitlementsWithAOs;
import static org.killbill.billing.entitlement.logging.EntitlementLoggingHelper.logPauseResumeEntitlement;
import static org.killbill.billing.entitlement.logging.EntitlementLoggingHelper.logTransferEntitlement;
@@ -133,14 +133,21 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
final EntitlementSpecifier entitlementSpecifier = new DefaultEntitlementSpecifier(planPhaseSpecifier, overrides);
final List<EntitlementSpecifier> entitlementSpecifierList = new ArrayList<EntitlementSpecifier>();
entitlementSpecifierList.add(entitlementSpecifier);
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
+ null,
+ externalKey,
+ entitlementSpecifierList,
+ entitlementEffectiveDate,
+ billingEffectiveDate,
+ isMigrated);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
+
+
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.CREATE_SUBSCRIPTION,
accountId,
null,
- null,
- externalKey,
- entitlementSpecifierList,
- entitlementEffectiveDate,
- billingEffectiveDate,
+ baseEntitlementWithAddOnsSpecifierList,
null,
properties,
callContext);
@@ -156,11 +163,11 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
final SubscriptionBaseBundle bundle = subscriptionBaseInternalApi.createBundleForAccount(accountId, externalKey, contextWithValidAccountRecordId);
- final DateTime billingRequestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getBillingEffectiveDate(), contextWithValidAccountRecordId);
- final EntitlementSpecifier specifier = getFirstEntitlementSpecifier(updatedPluginContext.getEntitlementSpecifiers());
+ final DateTime billingRequestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getBaseEntitlementWithAddOnsSpecifiers().iterator().next().getBillingEffectiveDate(), contextWithValidAccountRecordId);
+ final EntitlementSpecifier specifier = getFirstEntitlementSpecifier(updatedPluginContext.getBaseEntitlementWithAddOnsSpecifiers());
final SubscriptionBase subscription = subscriptionBaseInternalApi.createSubscription(bundle.getId(), specifier.getPlanPhaseSpecifier(), specifier.getOverrides(), billingRequestedDate, isMigrated, contextWithValidAccountRecordId);
- final DateTime entitlementRequestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEntitlementEffectiveDate(), contextWithValidAccountRecordId);
+ final DateTime entitlementRequestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getBaseEntitlementWithAddOnsSpecifiers().iterator().next().getEntitlementEffectiveDate(), contextWithValidAccountRecordId);
final BlockingState newBlockingState = new DefaultBlockingState(subscription.getId(), BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, EntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, false, entitlementRequestedDate);
entitlementUtils.setBlockingStatesAndPostBlockingTransitionEvent(ImmutableList.<BlockingState>of(newBlockingState), subscription.getBundleId(), contextWithValidAccountRecordId);
@@ -175,73 +182,69 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
return pluginExecution.executeWithPlugin(createBaseEntitlementWithPlugin, pluginContext);
}
- private EntitlementSpecifier getFirstEntitlementSpecifier(final List<EntitlementSpecifier> entitlementSpecifiers) throws SubscriptionBaseApiException {
- if ((entitlementSpecifiers == null) || entitlementSpecifiers.isEmpty()) {
- throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_INVALID_ENTITLEMENT_SPECIFIER);
+ private EntitlementSpecifier getFirstEntitlementSpecifier(final Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifiers) throws SubscriptionBaseApiException {
+ if ((baseEntitlementWithAddOnsSpecifiers == null) || baseEntitlementWithAddOnsSpecifiers.iterator().hasNext()) {
+ if ((baseEntitlementWithAddOnsSpecifiers.iterator().next().getEntitlementSpecifier() == null) || !baseEntitlementWithAddOnsSpecifiers.iterator().next().getEntitlementSpecifier().iterator().hasNext()) {
+ throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_INVALID_ENTITLEMENT_SPECIFIER);
+ }
}
- return entitlementSpecifiers.get(0);
+ return baseEntitlementWithAddOnsSpecifiers.iterator().next().getEntitlementSpecifier().iterator().next();
}
@Override
- public Entitlement createBaseEntitlementWithAddOns(final UUID accountId, final String externalKey, final Iterable<EntitlementSpecifier> entitlementSpecifiers,
- @Nullable LocalDate entitlementEffectiveDate, @Nullable LocalDate billingEffectiveDate, final boolean isMigrated,
- final Iterable<PluginProperty> properties, final CallContext callContext)
- throws EntitlementApiException {
+ public List<Entitlement> createBaseEntitlementsWithAddOns(final UUID accountId, final Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifiers, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
- logCreateEntitlementWithAOs(log, externalKey, entitlementSpecifiers, entitlementEffectiveDate, billingEffectiveDate);
+ logCreateEntitlementsWithAOs(log, baseEntitlementWithAddOnsSpecifiers);
-
- final List<EntitlementSpecifier> entitlementSpecifierList = new ArrayList<EntitlementSpecifier>();
- Iterables.addAll(entitlementSpecifierList, entitlementSpecifiers);
-
- final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.CREATE_SUBSCRIPTIONS_WITH_AO,
+ final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.CREATE_SHOPPING_CART_SUBSCRIPTIONS,
accountId,
null,
- null,
- externalKey,
- entitlementSpecifierList,
- entitlementEffectiveDate,
- billingEffectiveDate,
+ baseEntitlementWithAddOnsSpecifiers,
null,
properties,
callContext);
- final WithEntitlementPlugin<Entitlement> createBaseEntitlementWithAddOn = new WithEntitlementPlugin<Entitlement>() {
+ final WithEntitlementPlugin<List<Entitlement>> createBaseEntitlementsWithAddOns = new WithEntitlementPlugin<List<Entitlement>>() {
@Override
- public Entitlement doCall(final EntitlementApi entitlementApi, final EntitlementContext updatedPluginContext) throws EntitlementApiException {
+ public List<Entitlement> doCall(final EntitlementApi entitlementApi, final EntitlementContext updatedPluginContext) throws EntitlementApiException {
final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(accountId, callContext);
try {
- if (entitlementUtils.getFirstActiveSubscriptionIdForKeyOrNull(externalKey, contextWithValidAccountRecordId) != null) {
- throw new EntitlementApiException(new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS, externalKey));
- }
-
- final SubscriptionBaseBundle bundle = subscriptionBaseInternalApi.createBundleForAccount(accountId, externalKey, contextWithValidAccountRecordId);
-
- final DateTime billingRequestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getBillingEffectiveDate(), contextWithValidAccountRecordId);
- final List<SubscriptionBase> subscriptionBases = subscriptionBaseInternalApi.createBaseSubscriptionWithAddOns(bundle.getId(), entitlementSpecifiers, billingRequestedDate, isMigrated, contextWithValidAccountRecordId);
-
- final DateTime entitlementRequestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEntitlementEffectiveDate(), contextWithValidAccountRecordId);
- final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
- for (final SubscriptionBase cur : subscriptionBases) {
- final BlockingState blockingState = new DefaultBlockingState(cur.getId(), BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, EntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, false, entitlementRequestedDate);
- blockingStates.add(blockingState);
+ final List<SubscriptionBaseWithAddOns> subscriptionsWithAddOns = subscriptionBaseInternalApi.createBaseSubscriptionsWithAddOns(accountId, baseEntitlementWithAddOnsSpecifiers, contextWithValidAccountRecordId);
+ Map<BlockingState, UUID> blockingStateMap = new HashMap<BlockingState, UUID>();
+ int i = 0;
+ for (Iterator<BaseEntitlementWithAddOnsSpecifier> it = baseEntitlementWithAddOnsSpecifiers.iterator(); it.hasNext(); i++) {
+ BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = it.next();
+ for (SubscriptionBase subscriptionBase : subscriptionsWithAddOns.get(i).getSubscriptionBaseList()) {
+ final BlockingState blockingState = new DefaultBlockingState(subscriptionBase.getId(), BlockingStateType.SUBSCRIPTION,
+ DefaultEntitlementApi.ENT_STATE_START,
+ EntitlementService.ENTITLEMENT_SERVICE_NAME,
+ false, false, false,
+ dateHelper.fromLocalDateAndReferenceTime(baseEntitlementWithAddOnsSpecifier.getEntitlementEffectiveDate(), contextWithValidAccountRecordId));
+ blockingStateMap.put(blockingState, subscriptionsWithAddOns.get(i).getBundleId());
+ }
}
- final SubscriptionBase subscriptionBaseBP = subscriptionBases.get(0);
- entitlementUtils.setBlockingStatesAndPostBlockingTransitionEvent(blockingStates, subscriptionBaseBP.getBundleId(), contextWithValidAccountRecordId);
-
-
- return new DefaultEntitlement(accountId, subscriptionBaseBP.getId(), eventsStreamBuilder, entitlementApi, pluginExecution,
- blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
- entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory, callContext);
-
+ entitlementUtils.setBlockingStateAndPostBlockingTransitionEvent(blockingStateMap, contextWithValidAccountRecordId);
+ return buildEntitlementList(accountId, subscriptionsWithAddOns, callContext);
} catch (final SubscriptionBaseApiException e) {
throw new EntitlementApiException(e);
}
-
}
};
- return pluginExecution.executeWithPlugin(createBaseEntitlementWithAddOn, pluginContext);
+ return pluginExecution.executeWithPlugin(createBaseEntitlementsWithAddOns, pluginContext);
+ }
+
+ private List<Entitlement> buildEntitlementList(final UUID accountId, final List<SubscriptionBaseWithAddOns> subscriptionsWithAddOns, final CallContext callContext) throws EntitlementApiException {
+ List<Entitlement> result = new ArrayList<Entitlement>();
+ for (SubscriptionBaseWithAddOns subscriptionWithAddOns : subscriptionsWithAddOns) {
+ for (SubscriptionBase subscriptionBase : subscriptionWithAddOns.getSubscriptionBaseList()) {
+ Entitlement entitlement = new DefaultEntitlement(accountId, subscriptionBase.getId(), eventsStreamBuilder, entitlementApi, pluginExecution,
+ blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
+ entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory, callContext);
+ result.add(entitlement);
+ }
+ }
+ return result;
}
@Override
@@ -254,14 +257,20 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
final EntitlementSpecifier entitlementSpecifier = new DefaultEntitlementSpecifier(planPhaseSpecifier, overrides);
final List<EntitlementSpecifier> entitlementSpecifierList = new ArrayList<EntitlementSpecifier>();
entitlementSpecifierList.add(entitlementSpecifier);
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
+ bundleId,
+ null,
+ entitlementSpecifierList,
+ entitlementEffectiveDate,
+ billingEffectiveDate,
+ isMigrated);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
+
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.CREATE_SUBSCRIPTION,
null,
null,
- bundleId,
- null,
- entitlementSpecifierList,
- entitlementEffectiveDate,
- billingEffectiveDate,
+ baseEntitlementWithAddOnsSpecifierList,
null,
properties,
callContext);
@@ -281,13 +290,13 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
throw new EntitlementApiException(new BlockingApiException(ErrorCode.BLOCK_BLOCKED_ACTION, BlockingChecker.ACTION_CHANGE, BlockingChecker.TYPE_SUBSCRIPTION, eventsStreamForBaseSubscription.getEntitlementId().toString()));
}
- final DateTime billingRequestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getBillingEffectiveDate(), eventsStreamForBaseSubscription.getInternalTenantContext());
+ final DateTime billingRequestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getBaseEntitlementWithAddOnsSpecifiers().iterator().next().getBillingEffectiveDate(), eventsStreamForBaseSubscription.getInternalTenantContext());
try {
final InternalCallContext context = internalCallContextFactory.createInternalCallContext(eventsStreamForBaseSubscription.getAccountId(), callContext);
- final EntitlementSpecifier specifier = getFirstEntitlementSpecifier(updatedPluginContext.getEntitlementSpecifiers());
+ final EntitlementSpecifier specifier = getFirstEntitlementSpecifier(updatedPluginContext.getBaseEntitlementWithAddOnsSpecifiers());
final SubscriptionBase subscription = subscriptionBaseInternalApi.createSubscription(bundleId, specifier.getPlanPhaseSpecifier(), specifier.getOverrides(), billingRequestedDate, isMigrated, context);
- final DateTime entitlementRequestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEntitlementEffectiveDate(), eventsStreamForBaseSubscription.getInternalTenantContext());
+ final DateTime entitlementRequestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getBaseEntitlementWithAddOnsSpecifiers().iterator().next().getEntitlementEffectiveDate(), eventsStreamForBaseSubscription.getInternalTenantContext());
final BlockingState newBlockingState = new DefaultBlockingState(subscription.getId(), BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, EntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, false, entitlementRequestedDate);
entitlementUtils.setBlockingStatesAndPostBlockingTransitionEvent(ImmutableList.<BlockingState>of(newBlockingState), subscription.getBundleId(), context);
@@ -402,15 +411,21 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
logTransferEntitlement(log, sourceAccountId, destAccountId, externalKey, effectiveDate, billingPolicy);
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
+ null,
+ externalKey,
+ new ArrayList<EntitlementSpecifier>(),
+ effectiveDate,
+ effectiveDate,
+ false);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
+
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.TRANSFER_BUNDLE,
sourceAccountId,
destAccountId,
- null,
- externalKey,
- new ArrayList<EntitlementSpecifier>(),
- effectiveDate,
- effectiveDate,
- null,
+ baseEntitlementWithAddOnsSpecifierList,
+ billingPolicy,
properties,
context);
@@ -442,7 +457,7 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
throw new EntitlementApiException(new SubscriptionBaseApiException(ErrorCode.SUB_GET_INVALID_BUNDLE_KEY, externalKey));
}
- final DateTime requestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getBillingEffectiveDate(), contextWithSourceAccountRecordId);
+ final DateTime requestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getBaseEntitlementWithAddOnsSpecifiers().iterator().next().getBillingEffectiveDate(), contextWithSourceAccountRecordId);
final SubscriptionBaseBundle newBundle = subscriptionBaseTransferApi.transferBundle(sourceAccountId, destAccountId, externalKey, requestedDate, true, cancelImm, context);
@@ -460,7 +475,7 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements
final InternalCallContext contextWithDestAccountRecordId = internalCallContextFactory.createInternalCallContext(destAccountId, context);
blockingStates.clear();
- final DateTime entitlementRequestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEntitlementEffectiveDate(), contextWithDestAccountRecordId);
+ final DateTime entitlementRequestedDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getBaseEntitlementWithAddOnsSpecifiers().iterator().next().getEntitlementEffectiveDate(), contextWithDestAccountRecordId);
for (final SubscriptionBase subscriptionBase : subscriptionBaseInternalApi.getSubscriptionsForBundle(newBundle.getId(), null, contextWithDestAccountRecordId)) {
final BlockingState newBlockingState = new DefaultBlockingState(subscriptionBase.getId(), BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_START, EntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, false, entitlementRequestedDate);
blockingStates.put(newBlockingState, subscriptionBase.getBundleId());
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementContext.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementContext.java
index d5ec969..c868eff 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementContext.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementContext.java
@@ -23,7 +23,6 @@ import java.util.UUID;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
-import org.joda.time.LocalDate;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.entitlement.plugin.api.EntitlementContext;
import org.killbill.billing.entitlement.plugin.api.OperationType;
@@ -39,11 +38,7 @@ public class DefaultEntitlementContext implements EntitlementContext {
private final OperationType operationType;
private final UUID accountId;
private final UUID destinationAccountId;
- private final UUID bundleId;
- private final String externalKey;
- private final List<EntitlementSpecifier> entitlementSpecifiers;
- private final LocalDate entitlementEffectiveDate;
- private final LocalDate billingEffectiveDate;
+ private final Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifiers;
private final BillingActionPolicy billingActionPolicy;
private final Iterable<PluginProperty> pluginProperties;
private final UUID userToken;
@@ -62,11 +57,7 @@ public class DefaultEntitlementContext implements EntitlementContext {
this(prev.getOperationType(),
prev.getAccountId(),
prev.getDestinationAccountId(),
- prev.getBundleId(),
- prev.getExternalKey(),
- pluginResult != null && pluginResult.getAdjustedEntitlementSpecifiers() != null ? pluginResult.getAdjustedEntitlementSpecifiers() : prev.getEntitlementSpecifiers(),
- pluginResult != null && pluginResult.getAdjustedEntitlementEffectiveDate() != null ? pluginResult.getAdjustedEntitlementEffectiveDate() : prev.getEntitlementEffectiveDate(),
- pluginResult != null && pluginResult.getAdjustedBillingEffectiveDate() != null ? pluginResult.getAdjustedBillingEffectiveDate() : prev.getBillingEffectiveDate(),
+ pluginResult != null && pluginResult.getAdjustedBaseEntitlementWithAddOnsSpecifiers() != null ? pluginResult.getAdjustedBaseEntitlementWithAddOnsSpecifiers() : prev.getBaseEntitlementWithAddOnsSpecifiers(),
pluginResult != null && pluginResult.getAdjustedBillingActionPolicy() != null ? pluginResult.getAdjustedBillingActionPolicy() : prev.getBillingActionPolicy(),
pluginResult != null && pluginResult.getAdjustedPluginProperties() != null ? pluginResult.getAdjustedPluginProperties() : prev.getPluginProperties(),
prev);
@@ -75,15 +66,11 @@ public class DefaultEntitlementContext implements EntitlementContext {
public DefaultEntitlementContext(final OperationType operationType,
final UUID accountId,
final UUID destinationAccountId,
- final UUID bundleId,
- final String externalKey,
- final List<EntitlementSpecifier> entitlementSpecifiers,
- @Nullable final LocalDate entitlementEffectiveDate,
- @Nullable final LocalDate billingEffectiveDate,
+ final Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifiers,
@Nullable final BillingActionPolicy actionPolicy,
final Iterable<PluginProperty> pluginProperties,
final CallContext callContext) {
- this(operationType, accountId, destinationAccountId, bundleId, externalKey, entitlementSpecifiers, entitlementEffectiveDate, billingEffectiveDate, actionPolicy, pluginProperties,
+ this(operationType, accountId, destinationAccountId, baseEntitlementWithAddOnsSpecifiers, actionPolicy, pluginProperties,
callContext.getUserToken(), callContext.getUserName(), callContext.getCallOrigin(), callContext.getUserType(), callContext.getReasonCode(),
callContext.getComments(), callContext.getCreatedDate(), callContext.getUpdatedDate(), callContext.getTenantId());
}
@@ -92,11 +79,7 @@ public class DefaultEntitlementContext implements EntitlementContext {
public DefaultEntitlementContext(final OperationType operationType,
final UUID accountId,
final UUID destinationAccountId,
- final UUID bundleId,
- final String externalKey,
- final List<EntitlementSpecifier> entitlementSpecifiers,
- @Nullable final LocalDate entitlementEffectiveDate,
- @Nullable final LocalDate billingEffectiveDate,
+ final Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifiers,
@Nullable final BillingActionPolicy actionPolicy,
final Iterable<PluginProperty> pluginProperties,
final UUID userToken,
@@ -111,11 +94,7 @@ public class DefaultEntitlementContext implements EntitlementContext {
this.operationType = operationType;
this.accountId = accountId;
this.destinationAccountId = destinationAccountId;
- this.bundleId = bundleId;
- this.externalKey = externalKey;
- this.entitlementSpecifiers = entitlementSpecifiers;
- this.entitlementEffectiveDate = entitlementEffectiveDate;
- this.billingEffectiveDate = billingEffectiveDate;
+ this.baseEntitlementWithAddOnsSpecifiers = baseEntitlementWithAddOnsSpecifiers;
this.billingActionPolicy = actionPolicy;
this.pluginProperties = pluginProperties;
this.userToken = userToken;
@@ -145,29 +124,8 @@ public class DefaultEntitlementContext implements EntitlementContext {
}
@Override
- public UUID getBundleId() {
- return bundleId;
- }
-
- @Override
- public String getExternalKey() {
- return externalKey;
- }
-
- @Override
- public List<EntitlementSpecifier> getEntitlementSpecifiers() {
- return entitlementSpecifiers;
- }
-
-
- @Override
- public LocalDate getEntitlementEffectiveDate() {
- return entitlementEffectiveDate;
- }
-
- @Override
- public LocalDate getBillingEffectiveDate() {
- return billingEffectiveDate;
+ public Iterable<BaseEntitlementWithAddOnsSpecifier> getBaseEntitlementWithAddOnsSpecifiers() {
+ return baseEntitlementWithAddOnsSpecifiers;
}
@Override
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
index a6fbfb9..1ea62df 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
@@ -279,15 +279,21 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
throw new EntitlementApiException(e);
}
+
final LocalDate effectiveDate = new LocalDate(clock.getUTCNow(), account.getTimeZone());
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
+ bundleId,
+ newExternalKey,
+ new ArrayList<EntitlementSpecifier>(),
+ effectiveDate,
+ effectiveDate,
+ false);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.UPDATE_BUNDLE_EXTERNAL_KEY,
bundle.getAccountId(),
null,
- bundleId,
- newExternalKey,
- new ArrayList<EntitlementSpecifier>(),
- effectiveDate,
- effectiveDate,
+ baseEntitlementWithAddOnsSpecifierList,
null,
ImmutableList.<PluginProperty>of(),
callContext);
@@ -365,14 +371,19 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
final DateTime effectiveDate = inputEffectiveDate == null ? clock.getUTCNow() : internalCallContextWithValidAccountId.toUTCDateTime(inputEffectiveDate);
final DefaultBlockingState blockingState = new DefaultBlockingState(inputBlockingState, effectiveDate);
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
+ bundleId,
+ externalKey,
+ new ArrayList<EntitlementSpecifier>(),
+ internalCallContextWithValidAccountId.toLocalDate(effectiveDate),
+ internalCallContextWithValidAccountId.toLocalDate(effectiveDate),
+ false);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.ADD_BLOCKING_STATE,
accountId,
null,
- bundleId,
- externalKey,
- new ArrayList<EntitlementSpecifier>(),
- internalCallContextWithValidAccountId.toLocalDate(effectiveDate),
- null,
+ baseEntitlementWithAddOnsSpecifierList,
null,
properties,
callContext);
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementApiBase.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementApiBase.java
index 3044aca..f1c8e57 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementApiBase.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementApiBase.java
@@ -17,9 +17,11 @@
package org.killbill.billing.entitlement.api.svcs;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -34,8 +36,10 @@ import org.killbill.billing.entitlement.AccountEntitlements;
import org.killbill.billing.entitlement.AccountEventsStreams;
import org.killbill.billing.entitlement.EntitlementService;
import org.killbill.billing.entitlement.EventsStream;
+import org.killbill.billing.entitlement.api.BaseEntitlementWithAddOnsSpecifier;
import org.killbill.billing.entitlement.api.BlockingState;
import org.killbill.billing.entitlement.api.BlockingStateType;
+import org.killbill.billing.entitlement.api.DefaultBaseEntitlementWithAddOnsSpecifier;
import org.killbill.billing.entitlement.api.DefaultEntitlement;
import org.killbill.billing.entitlement.api.DefaultEntitlementApi;
import org.killbill.billing.entitlement.api.DefaultEntitlementContext;
@@ -138,15 +142,20 @@ public class DefaultEntitlementApiBase {
public void pause(final UUID bundleId, @Nullable final LocalDate localEffectiveDate, final Iterable<PluginProperty> properties, final InternalCallContext internalCallContext) throws EntitlementApiException {
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
+ bundleId,
+ null,
+ null,
+ localEffectiveDate,
+ localEffectiveDate,
+ false);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.PAUSE_BUNDLE,
null,
null,
- bundleId,
null,
null,
- localEffectiveDate,
- localEffectiveDate,
- null,
properties,
internalCallContextFactory.createCallContext(internalCallContext));
@@ -167,14 +176,19 @@ public class DefaultEntitlementApiBase {
public void resume(final UUID bundleId, @Nullable final LocalDate localEffectiveDate, final Iterable<PluginProperty> properties, final InternalCallContext internalCallContext) throws EntitlementApiException {
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
+ bundleId,
+ null,
+ null,
+ localEffectiveDate,
+ localEffectiveDate,
+ false);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.RESUME_BUNDLE,
null,
null,
- bundleId,
- null,
- null,
- localEffectiveDate,
- localEffectiveDate,
+ baseEntitlementWithAddOnsSpecifierList,
null,
properties,
internalCallContextFactory.createCallContext(internalCallContext));
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
index 3fc96da..2f7ad68 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
@@ -40,8 +40,10 @@ import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.entitlement.DefaultEntitlementService;
import org.killbill.billing.entitlement.EntitlementInternalApi;
import org.killbill.billing.entitlement.EntitlementService;
+import org.killbill.billing.entitlement.api.BaseEntitlementWithAddOnsSpecifier;
import org.killbill.billing.entitlement.api.BlockingState;
import org.killbill.billing.entitlement.api.BlockingStateType;
+import org.killbill.billing.entitlement.api.DefaultBaseEntitlementWithAddOnsSpecifier;
import org.killbill.billing.entitlement.api.DefaultEntitlement;
import org.killbill.billing.entitlement.api.DefaultEntitlementApi;
import org.killbill.billing.entitlement.api.DefaultEntitlementContext;
@@ -107,14 +109,20 @@ public class DefaultEntitlementInternalApi extends DefaultEntitlementApiBase imp
continue;
}
+ final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
+ entitlement.getBundleId(),
+ entitlement.getExternalKey(),
+ null,
+ effectiveDate,
+ null,
+ false);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
+
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.CANCEL_SUBSCRIPTION,
entitlement.getAccountId(),
null,
- entitlement.getBundleId(),
- entitlement.getExternalKey(),
- null,
- effectiveDate,
- null,
+ baseEntitlementWithAddOnsSpecifierList,
billingPolicy,
properties,
callContext);
@@ -219,7 +227,7 @@ public class DefaultEntitlementInternalApi extends DefaultEntitlementApiBase imp
@Override
public Entitlement doCall(final EntitlementApi entitlementApi, final EntitlementContext updatedPluginContext) throws EntitlementApiException {
- DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getEntitlementEffectiveDate(), internalCallContext);
+ DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(updatedPluginContext.getBaseEntitlementWithAddOnsSpecifiers().iterator().next().getEntitlementEffectiveDate(), internalCallContext);
// Avoid timing issues for IMM cancellations (we don't want an entitlement cancel date one second or so after the subscription cancel date or
// add-ons cancellations computations won't work).
if (effectiveDate.compareTo(entitlement.getSubscriptionBase().getEndDate()) > 0) {
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 7e7f2e2..8f47820 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
@@ -22,10 +22,10 @@ import java.util.UUID;
import org.joda.time.LocalDate;
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.BaseEntitlementWithAddOnsSpecifier;
import org.killbill.billing.entitlement.api.BlockingState;
import org.killbill.billing.entitlement.api.Entitlement;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementActionPolicy;
@@ -69,6 +69,22 @@ public abstract class EntitlementLoggingHelper {
}
}
+ public static void logCreateEntitlementsWithAOs(final Logger log, final Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementSpecifiersWithAddOns) {
+ if (log.isInfoEnabled()) {
+ final StringBuilder logLine = new StringBuilder("Create Entitlements with AddOns: ");
+
+ if (baseEntitlementSpecifiersWithAddOns != null && baseEntitlementSpecifiersWithAddOns.iterator().hasNext()) {
+ for (BaseEntitlementWithAddOnsSpecifier cur : baseEntitlementSpecifiersWithAddOns) {
+ logCreateEntitlementWithAOs(log, cur.getExternalKey(),
+ cur.getEntitlementSpecifier(),
+ cur.getEntitlementEffectiveDate(),
+ cur.getBillingEffectiveDate());
+ }
+ }
+ log.info(logLine.toString());
+ }
+ }
+
public static void logCreateEntitlementWithAOs(final Logger log,
final String externalKey,
final Iterable<EntitlementSpecifier> entitlementSpecifiers,
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
index fe59e7d..979dde2 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
@@ -500,104 +500,6 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
}
@Test(groups = "slow")
- public void testCreateBaseEntitlementWithAddOns() throws AccountApiException, EntitlementApiException, SubscriptionBaseApiException {
- final LocalDate initialDate = new LocalDate(2013, 8, 7);
- clock.setDay(initialDate);
-
- final Account account = createAccount(getAccountData(7));
-
- final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Cleaning", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
-
- final String externalKey = "baseExternalKey";
- EntitlementSpecifier baseEntitlementSpecifier = new DefaultEntitlementSpecifier(baseSpec, null);
- EntitlementSpecifier addOnEntitlementSpecifier = new DefaultEntitlementSpecifier(addOnSpec, null);
-
- final List<EntitlementSpecifier> specifierList = new ArrayList<EntitlementSpecifier>();
- specifierList.add(baseEntitlementSpecifier);
- specifierList.add(addOnEntitlementSpecifier);
-
- testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.CREATE, NextEvent.BLOCK);
- final Entitlement entitlement = entitlementApi.createBaseEntitlementWithAddOns(account.getId(), externalKey, specifierList, initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext);
- assertListenerStatus();
-
- assertNotNull(entitlement);
-
- final List<Entitlement> allEntitlementsForBundle = entitlementApi.getAllEntitlementsForBundle(entitlement.getBundleId(), callContext);
- assertTrue(allEntitlementsForBundle.size() == 2);
-
- final Entitlement baseEntitlement = allEntitlementsForBundle.get(0);
- final Entitlement addOnEntitlement = allEntitlementsForBundle.get(1);
-
- assertEquals(baseEntitlement.getLastActiveProduct().getName(), "Pistol");
- assertEquals(baseEntitlement.getLastActiveProductCategory(), ProductCategory.BASE);
-
- assertEquals(addOnEntitlement.getLastActiveProduct().getName(), "Cleaning");
- assertEquals(addOnEntitlement.getLastActiveProductCategory(), ProductCategory.ADD_ON);
-
- }
-
- @Test(groups = "slow")
- public void testCreateBaseEntitlementWithInvalidAddOn() throws AccountApiException, EntitlementApiException {
- final LocalDate initialDate = new LocalDate(2013, 8, 7);
- clock.setDay(initialDate);
-
- final Account account = createAccount(getAccountData(7));
-
- final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Invalid", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
-
- final String externalKey = "baseExternalKey";
- EntitlementSpecifier baseEntitlementSpecifier = new DefaultEntitlementSpecifier(baseSpec, null);
- EntitlementSpecifier addOnEntitlementSpecifier = new DefaultEntitlementSpecifier(addOnSpec, null);
-
- final List<EntitlementSpecifier> specifierList = new ArrayList<EntitlementSpecifier>();
- specifierList.add(baseEntitlementSpecifier);
- specifierList.add(addOnEntitlementSpecifier);
-
- try {
- entitlementApi.createBaseEntitlementWithAddOns(account.getId(), externalKey, specifierList, initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext);
- fail();
- } catch (EntitlementApiException e) {
- assertEquals(e.getMessage(), "Could not find any product named 'Invalid'");
- }
-
- final List<Entitlement> allEntitlementsForAccount = entitlementApi.getAllEntitlementsForAccountId(account.getId(), callContext);
- assertTrue(allEntitlementsForAccount.size() == 0);
-
- }
-
- @Test(groups = "slow")
- public void testCreateBaseEntitlementWithoutBaseEntitlement() throws AccountApiException, EntitlementApiException {
- final LocalDate initialDate = new LocalDate(2013, 8, 7);
- clock.setDay(initialDate);
-
- final Account account = createAccount(getAccountData(7));
-
- final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Cleaning", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
- final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Bullets", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
-
- final String externalKey = "addOnExternalKey";
- EntitlementSpecifier addOnEntitlementSpecifier1 = new DefaultEntitlementSpecifier(baseSpec, null);
- EntitlementSpecifier addOnEntitlementSpecifier2 = new DefaultEntitlementSpecifier(addOnSpec, null);
-
- final List<EntitlementSpecifier> specifierList = new ArrayList<EntitlementSpecifier>();
- specifierList.add(addOnEntitlementSpecifier1);
- specifierList.add(addOnEntitlementSpecifier2);
-
- try {
- entitlementApi.createBaseEntitlementWithAddOns(account.getId(), externalKey, specifierList, initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext);
- fail();
- } catch (EntitlementApiException e) {
- assertEquals(e.getMessage(), "Missing Base Subscription.");
- }
-
- final List<Entitlement> allEntitlementsForAccount = entitlementApi.getAllEntitlementsForAccountId(account.getId(), callContext);
- assertTrue(allEntitlementsForAccount.size() == 0);
- }
-
-
- @Test(groups = "slow")
public void testCreateBaseWithDifferentInTheFuture() throws AccountApiException, EntitlementApiException, SubscriptionApiException {
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BulkBaseSubscriptionAndAddOnsJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BulkBaseSubscriptionAndAddOnsJson.java
new file mode 100644
index 0000000..b5367d1
--- /dev/null
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BulkBaseSubscriptionAndAddOnsJson.java
@@ -0,0 +1,68 @@
+/*
+ * 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.json;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModelProperty;
+
+public class BulkBaseSubscriptionAndAddOnsJson {
+
+ @ApiModelProperty(required = true)
+ private final List<SubscriptionJson> baseEntitlementAndAddOns;
+
+ @JsonCreator
+ public BulkBaseSubscriptionAndAddOnsJson(
+ @JsonProperty("baseEntitlementAndAddOns") @Nullable final List<SubscriptionJson> baseEntitlementAndAddOns) {
+ this.baseEntitlementAndAddOns = baseEntitlementAndAddOns;
+ }
+
+ public List<SubscriptionJson> getBaseEntitlementAndAddOns() {
+ return baseEntitlementAndAddOns;
+ }
+
+ @Override
+ public String toString() {
+ return "BulkBaseSubscriptionAndAddOnsJson{" +
+ "baseEntitlementAndAddOns=" + baseEntitlementAndAddOns +
+ '}';
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final BulkBaseSubscriptionAndAddOnsJson that = (BulkBaseSubscriptionAndAddOnsJson) o;
+
+ return baseEntitlementAndAddOns != null ? baseEntitlementAndAddOns.equals(that.baseEntitlementAndAddOns) : that.baseEntitlementAndAddOns == null;
+
+ }
+
+ @Override
+ public int hashCode() {
+ return baseEntitlementAndAddOns != null ? baseEntitlementAndAddOns.hashCode() : 0;
+ }
+}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
index 265a1fa..fe76cbf 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
@@ -21,6 +21,7 @@ package org.killbill.billing.jaxrs.resources;
import java.math.BigDecimal;
import java.net.URI;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
@@ -265,17 +266,21 @@ public class AccountResource extends JaxRsResourceBase {
@ApiResponse(code = 404, message = "Account not found")})
public Response getAccountBundles(@PathParam("accountId") final String accountId,
@QueryParam(QUERY_EXTERNAL_KEY) final String externalKey,
+ @QueryParam(QUERY_BUNDLES_FILTER) final String bundlesFilter,
@javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, SubscriptionApiException {
final TenantContext tenantContext = context.createContext(request);
final UUID uuid = UUID.fromString(accountId);
- final Account account = accountUserApi.getAccountById(uuid, tenantContext);
+ final Account account = accountUserApi.getAccountById(uuid, tenantContext);
final List<SubscriptionBundle> bundles = (externalKey != null) ?
subscriptionApi.getSubscriptionBundlesForAccountIdAndExternalKey(uuid, externalKey, tenantContext) :
subscriptionApi.getSubscriptionBundlesForAccountId(uuid, tenantContext);
- final Collection<BundleJson> result = Collections2.transform(bundles, new Function<SubscriptionBundle, BundleJson>() {
+ boolean filter = (null != bundlesFilter && !bundlesFilter.isEmpty());
+
+ final Collection<BundleJson> result = Collections2.transform(
+ (filter) ? filterBundles(bundles, Arrays.asList(bundlesFilter.split(","))) : bundles, new Function<SubscriptionBundle, BundleJson>() {
@Override
public BundleJson apply(final SubscriptionBundle input) {
try {
@@ -289,6 +294,16 @@ public class AccountResource extends JaxRsResourceBase {
return Response.status(Status.OK).entity(result).build();
}
+ private List<SubscriptionBundle> filterBundles(final List<SubscriptionBundle> subscriptionBundlesForAccountId, final List<String> bundlesFilter) {
+ List<SubscriptionBundle> result = new ArrayList<SubscriptionBundle>();
+ for (SubscriptionBundle subscriptionBundle : subscriptionBundlesForAccountId) {
+ if (bundlesFilter.contains(subscriptionBundle.getId().toString())) {
+ result.add(subscriptionBundle);
+ }
+ }
+ return result;
+ }
+
@TimedResource
@GET
@Produces(APPLICATION_JSON)
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 071fbd0..cecf4f7 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
@@ -132,6 +132,7 @@ public interface JaxrsResource {
public static final String QUERY_BUNDLE_TRANSFER_ADDON = "transferAddOn";
public static final String QUERY_BUNDLE_TRANSFER_CANCEL_IMM = "cancelImmediately";
+ public static final String QUERY_BUNDLES_FILTER = "bundlesFilter";
public static final String QUERY_DELETE_DEFAULT_PM_WITH_AUTO_PAY_OFF = "deleteDefaultPmWithAutoPayOff";
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
index ce30ab9..591dbfc 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
@@ -609,7 +609,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
}
private URI getPaymentLocation(final UriInfo uriInfo, final Payment payment) {
- return uriBuilder.buildLocation(uriInfo, PaymentResource.class, "getPayment", payment.getId());
+ return uriBuilder.buildLocation(uriInfo, PaymentResource.class, "getPayment", payment.getId(), null);
}
private PaymentTransaction findCreatedTransaction(final Payment payment, final TransactionType transactionType, @Nullable final String transactionExternalKey) {
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 8a9a799..6532449 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
@@ -20,7 +20,9 @@ package org.killbill.billing.jaxrs.resources;
import java.math.BigDecimal;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeoutException;
@@ -48,11 +50,13 @@ import org.killbill.billing.account.api.AccountUserApi;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.CatalogApiException;
+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.ProductCategory;
+import org.killbill.billing.entitlement.api.BaseEntitlementWithAddOnsSpecifier;
import org.killbill.billing.entitlement.api.BlockingStateType;
import org.killbill.billing.entitlement.api.Entitlement;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementActionPolicy;
@@ -72,6 +76,7 @@ import org.killbill.billing.events.PaymentErrorInternalEvent;
import org.killbill.billing.events.PaymentInfoInternalEvent;
import org.killbill.billing.events.PaymentPluginErrorInternalEvent;
import org.killbill.billing.jaxrs.json.BlockingStateJson;
+import org.killbill.billing.jaxrs.json.BulkBaseSubscriptionAndAddOnsJson;
import org.killbill.billing.jaxrs.json.CustomFieldJson;
import org.killbill.billing.jaxrs.json.PhasePriceOverrideJson;
import org.killbill.billing.jaxrs.json.SubscriptionJson;
@@ -262,16 +267,6 @@ public class SubscriptionResource extends JaxRsResourceBase {
Preconditions.checkArgument(Iterables.size(entitlements) > 0, "Subscription list mustn't be null or empty.");
- for (SubscriptionJson entitlement : entitlements) {
- verifyNonNullOrEmpty(entitlement, "SubscriptionJson body should be specified 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);
final int baseSubscriptionsSize = Iterables.size(Iterables.filter(entitlements, new Predicate<SubscriptionJson>() {
@@ -291,6 +286,8 @@ public class SubscriptionResource extends JaxRsResourceBase {
verifyNumberOfElements(addOnSubscriptionsSize, entitlements.size() - 1, "It should be " + (entitlements.size() - 1) + " ADD_ON products.");
final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
+ final CallContext callContext = context.createContext(createdBy, reason, comment, request);
+
final SubscriptionJson baseEntitlement = Iterables.tryFind(entitlements, new Predicate<SubscriptionJson>() {
@Override
public boolean apply(final SubscriptionJson subscription) {
@@ -300,60 +297,210 @@ public class SubscriptionResource extends JaxRsResourceBase {
verifyNonNull(baseEntitlement.getAccountId(), "SubscriptionJson accountId needs to be set for BASE product.");
- final CallContext callContext = context.createContext(createdBy, reason, comment, request);
+ final EntitlementCallCompletionCallback<List<Entitlement>> callback = new EntitlementCallCompletionCallback<List<Entitlement>>() {
+ @Override
+ public List<Entitlement> doOperation(final CallContext ctx) throws InterruptedException, TimeoutException, EntitlementApiException, SubscriptionApiException, AccountApiException {
- final EntitlementCallCompletionCallback<Entitlement> callback = new EntitlementCallCompletionCallback<Entitlement>() {
+ final Account account = getAccountFromSubscriptionJson(baseEntitlement, callContext);
+
+ final List<EntitlementSpecifier> entitlementSpecifierList = buildEntitlementSpecifierList(entitlements, account.getCurrency());
+
+ final LocalDate resolvedEntitlementDate = requestedDate != null ? toLocalDate(requestedDate) : toLocalDate(entitlementDate);
+ final LocalDate resolvedBillingDate = requestedDate != null ? toLocalDate(requestedDate) : toLocalDate(billingDate);
+ final UUID bundleId = baseEntitlement.getBundleId() != null ? UUID.fromString(baseEntitlement.getBundleId()) : null;
+
+ BaseEntitlementWithAddOnsSpecifier baseEntitlementSpecifierWithAddOns = buildBaseEntitlementWithAddOnsSpecifier(entitlementSpecifierList, resolvedEntitlementDate, resolvedBillingDate, bundleId, baseEntitlement, isMigrated);
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementSpecifierWithAddOns);
+
+ return entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), baseEntitlementWithAddOnsSpecifierList, pluginProperties, callContext);
+ }
@Override
- public Entitlement doOperation(final CallContext ctx) throws InterruptedException, TimeoutException, EntitlementApiException, SubscriptionApiException, AccountApiException {
+ public boolean isImmOperation() {
+ return true;
+ }
+ @Override
+ public Response doResponseOk(final List<Entitlement> entitlements) {
+ return uriBuilder.buildResponse(uriInfo, BundleResource.class, "getBundle", entitlements.get(0).getBundleId());
+ }
+ };
+ final EntitlementCallCompletion<List<Entitlement>> callCompletionCreation = new EntitlementCallCompletion<List<Entitlement>>();
+ return callCompletionCreation.withSynchronization(callback, timeoutSec, callCompletion, callContext);
+ }
- List<EntitlementSpecifier> entitlementSpecifierList = new ArrayList<EntitlementSpecifier>();
- final Account account = getAccountFromSubscriptionJson(baseEntitlement, callContext);
+ @TimedResource
+ @POST
+ @Path("/createEntitlementsWithAddOns")
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ @ApiOperation(value = "Create multiple entitlements with addOn products")
+ @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid entitlements supplied")})
+ public Response createEntitlementsWithAddOns(final List<BulkBaseSubscriptionAndAddOnsJson> entitlementsWithAddOns,
+ @QueryParam(QUERY_REQUESTED_DT) final String requestedDate, /* This is deprecated, only used for backward compatibility */
+ @QueryParam(QUERY_ENTITLEMENT_REQUESTED_DT) final String entitlementDate,
+ @QueryParam(QUERY_BILLING_REQUESTED_DT) final String billingDate,
+ @QueryParam(QUERY_MIGRATED) @DefaultValue("false") final Boolean isMigrated,
+ @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
+ @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
+ @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+ @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 HttpServletRequest request,
+ @javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
+
+ Preconditions.checkArgument(Iterables.size(entitlementsWithAddOns) > 0, "Subscription bulk list mustn't be null or empty.");
- for (final SubscriptionJson entitlement : entitlements) {
+ logDeprecationParameterWarningIfNeeded(QUERY_REQUESTED_DT, QUERY_ENTITLEMENT_REQUESTED_DT, QUERY_BILLING_REQUESTED_DT);
- final PlanPhaseSpecifier planPhaseSpecifier = entitlement.getPlanName() != null ?
- new PlanPhaseSpecifier(entitlement.getPlanName(), null) :
- new PlanPhaseSpecifier(entitlement.getProductName(),
- BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList(), null);
- final List<PlanPhasePriceOverride> overrides = PhasePriceOverrideJson.toPlanPhasePriceOverrides(entitlement.getPriceOverrides(), planPhaseSpecifier, account.getCurrency());
+ final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
+ final CallContext callContext = context.createContext(createdBy, reason, comment, request);
- EntitlementSpecifier specifier = new EntitlementSpecifier() {
+ final Account account = accountUserApi.getAccountById(UUID.fromString(entitlementsWithAddOns.get(0).getBaseEntitlementAndAddOns().get(0).getAccountId()), callContext);
- @Override
- public PlanPhaseSpecifier getPlanPhaseSpecifier() {
- return planPhaseSpecifier;
- }
+ final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
+ for (BulkBaseSubscriptionAndAddOnsJson bulkBaseEntitlementWithAddOns : entitlementsWithAddOns) {
+ final Iterable<SubscriptionJson> baseEntitlements = Iterables.filter(
+ bulkBaseEntitlementWithAddOns.getBaseEntitlementAndAddOns(), new Predicate<SubscriptionJson>() {
+ @Override
+ public boolean apply(final SubscriptionJson subscription) {
+ return ProductCategory.BASE.toString().equalsIgnoreCase(subscription.getProductCategory());
+ }
+ });
+ Preconditions.checkArgument(Iterables.size(baseEntitlements) > 0, "SubscriptionJson Base Entitlement needs to be provided");
+ verifyNumberOfElements(Iterables.size(baseEntitlements), 1, "Only one BASE product is allowed per bundle.");
+
+ final Iterable<SubscriptionJson> entitlementsWithBundleSpecified = Iterables.filter(
+ bulkBaseEntitlementWithAddOns.getBaseEntitlementAndAddOns(), new Predicate<SubscriptionJson>() {
+ @Override
+ public boolean apply(final SubscriptionJson subscription) {
+ return subscription.getBundleId() != null;
+ }
+ }
+ );
+ Preconditions.checkArgument(Iterables.size(entitlementsWithBundleSpecified) == 0, "BundleId must not be specified when creating new bulks");
- @Override
- public List<PlanPhasePriceOverride> getOverrides() {
- return overrides;
- }
- };
+ SubscriptionJson baseEntitlement = baseEntitlements.iterator().next();
- entitlementSpecifierList.add(specifier);
+ final int addOnSubscriptionsSize = Iterables.size(Iterables.filter(bulkBaseEntitlementWithAddOns.getBaseEntitlementAndAddOns(), new Predicate<SubscriptionJson>() {
+ @Override
+ public boolean apply(final SubscriptionJson subscription) {
+ return subscription.getProductCategory().equals(ProductCategory.ADD_ON.toString());
}
+ }));
+ verifyNumberOfElements(addOnSubscriptionsSize, bulkBaseEntitlementWithAddOns.getBaseEntitlementAndAddOns().size() - 1, "It should be " + (bulkBaseEntitlementWithAddOns.getBaseEntitlementAndAddOns().size() - 1) + " ADD_ON products.");
- final LocalDate resolvedEntitlementDate = requestedDate != null ? toLocalDate(requestedDate) : toLocalDate(entitlementDate);
- final LocalDate resolvedBillingDate = requestedDate != null ? toLocalDate(requestedDate) : toLocalDate(billingDate);
- return entitlementApi.createBaseEntitlementWithAddOns(account.getId(), baseEntitlement.getExternalKey(), entitlementSpecifierList,
- resolvedEntitlementDate, resolvedBillingDate, isMigrated, pluginProperties, callContext);
- }
+ final List<EntitlementSpecifier> entitlementSpecifierList = buildEntitlementSpecifierList(bulkBaseEntitlementWithAddOns.getBaseEntitlementAndAddOns(), account.getCurrency());
+
+ // create the baseEntitlementSpecifierWithAddOns
+ final LocalDate resolvedEntitlementDate = requestedDate != null ? toLocalDate(requestedDate) : toLocalDate(entitlementDate);
+ final LocalDate resolvedBillingDate = requestedDate != null ? toLocalDate(requestedDate) : toLocalDate(billingDate);
+
+ BaseEntitlementWithAddOnsSpecifier baseEntitlementSpecifierWithAddOns = buildBaseEntitlementWithAddOnsSpecifier(entitlementSpecifierList, resolvedEntitlementDate, resolvedBillingDate, null, baseEntitlement, isMigrated);
+ baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementSpecifierWithAddOns);
+ }
+ final EntitlementCallCompletionCallback<List<Entitlement>> callback = new EntitlementCallCompletionCallback<List<Entitlement>>() {
+ @Override
+ public List<Entitlement> doOperation(final CallContext ctx) throws InterruptedException, TimeoutException, EntitlementApiException, SubscriptionApiException, AccountApiException {
+ return entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), baseEntitlementWithAddOnsSpecifierList, pluginProperties, callContext);
+ }
@Override
public boolean isImmOperation() {
return true;
}
-
@Override
- public Response doResponseOk(final Entitlement entitlement) {
- return uriBuilder.buildResponse(uriInfo, BundleResource.class, "getBundle", entitlement.getBundleId());
+ public Response doResponseOk(final List<Entitlement> entitlements) {
+ return uriBuilder.buildResponse(uriInfo, AccountResource.class, "getAccountBundles", entitlements.get(0).getAccountId(), buildQueryParams(buildBundleIdList(entitlements)));
}
+ };
+ final EntitlementCallCompletion<List<Entitlement>> callCompletionCreation = new EntitlementCallCompletion<List<Entitlement>>();
+ return callCompletionCreation.withSynchronization(callback, timeoutSec, callCompletion, callContext);
+ }
+ private List<EntitlementSpecifier> buildEntitlementSpecifierList(final List<SubscriptionJson> entitlements, final Currency currency) {
+ final List<EntitlementSpecifier> entitlementSpecifierList = new ArrayList<EntitlementSpecifier>();
+ for (final SubscriptionJson entitlement : entitlements) {
+ // verifications
+ verifyNonNullOrEmpty(entitlement, "SubscriptionJson body should be specified 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");
+ }
+ // create the entitlementSpecifier
+ final PlanPhaseSpecifier planPhaseSpecifier = entitlement.getPlanName() != null ?
+ new PlanPhaseSpecifier(entitlement.getPlanName(), null) :
+ new PlanPhaseSpecifier(entitlement.getProductName(),
+ BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList(), null);
+ final List<PlanPhasePriceOverride> overrides = PhasePriceOverrideJson.toPlanPhasePriceOverrides(entitlement.getPriceOverrides(), planPhaseSpecifier, currency);
+
+ EntitlementSpecifier specifier = new EntitlementSpecifier() {
+ @Override
+ public PlanPhaseSpecifier getPlanPhaseSpecifier() {
+ return planPhaseSpecifier;
+ }
+ @Override
+ public List<PlanPhasePriceOverride> getOverrides() {
+ return overrides;
+ }
+ };
+ entitlementSpecifierList.add(specifier);
+ }
+ return entitlementSpecifierList;
+ }
+
+ private BaseEntitlementWithAddOnsSpecifier buildBaseEntitlementWithAddOnsSpecifier(final List<EntitlementSpecifier> entitlementSpecifierList, final LocalDate resolvedEntitlementDate, final LocalDate resolvedBillingDate, final UUID bundleId, final SubscriptionJson baseEntitlement, final @QueryParam(QUERY_MIGRATED) @DefaultValue("false") Boolean isMigrated) {
+ return new BaseEntitlementWithAddOnsSpecifier() {
+ @Override
+ public UUID getBundleId() {
+ return bundleId;
+ }
+ @Override
+ public String getExternalKey() {
+ return baseEntitlement.getExternalKey();
+ }
+ @Override
+ public Iterable<EntitlementSpecifier> getEntitlementSpecifier() {
+ return entitlementSpecifierList;
+ }
+ @Override
+ public LocalDate getEntitlementEffectiveDate() {
+ return resolvedEntitlementDate;
+ }
+ @Override
+ public LocalDate getBillingEffectiveDate() {
+ return resolvedBillingDate;
+ }
+ @Override
+ public boolean isMigrated() {
+ return isMigrated;
+ }
};
+ }
- final EntitlementCallCompletion<Entitlement> callCompletionCreation = new EntitlementCallCompletion<Entitlement>();
- return callCompletionCreation.withSynchronization(callback, timeoutSec, callCompletion, callContext);
+ private List<String> buildBundleIdList(final List<Entitlement> entitlements) {
+ List<String> result = new ArrayList<String>();
+ for (Entitlement entitlement : entitlements) {
+ if (!result.contains(entitlement.getBundleId().toString())) {
+ result.add(entitlement.getBundleId().toString());
+ }
+ }
+ return result;
+ }
+
+ private Map<String, String> buildQueryParams(final List<String> bundleIdList) {
+ Map<String, String> queryParams = new HashMap<String, String>();
+ String value = "";
+ for (String bundleId : bundleIdList) {
+ if (value.equals("")) {
+ value += bundleId;
+ } else value+="," + bundleId;
+ }
+ queryParams.put(QUERY_BUNDLES_FILTER, value);
+ return queryParams;
}
@TimedResource
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
index ee09c1a..23d28b4 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
@@ -46,16 +46,30 @@ public class JaxrsUriBuilder {
public Response buildResponse(final UriInfo uriInfo, final Class<? extends JaxrsResource> theClass,
final String getMethodName, final Object objectId) {
- final URI location = buildLocation(uriInfo, theClass, getMethodName, objectId);
+ final URI location = buildLocation(uriInfo, theClass, getMethodName, objectId, null);
+ return !jaxrsConfig.isJaxrsLocationFullUrl() ?
+ Response.status(Response.Status.CREATED).header("Location", location.getPath()).build() :
+ Response.created(location).build();
+ }
+
+ public Response buildResponse(final UriInfo uriInfo, final Class<? extends JaxrsResource> theClass,
+ final String getMethodName, final Object objectId, final Map<String, String> params) {
+ final URI location = buildLocation(uriInfo, theClass, getMethodName, objectId, params);
return !jaxrsConfig.isJaxrsLocationFullUrl() ?
Response.status(Response.Status.CREATED).header("Location", location.getPath()).build() :
Response.created(location).build();
}
public URI buildLocation(final UriInfo uriInfo, final Class<? extends JaxrsResource> theClass,
- final String getMethodName, final Object objectId) {
+ final String getMethodName, final Object objectId, final Map<String, String> params) {
final UriBuilder uriBuilder = getUriBuilder(uriInfo.getBaseUri().getPath(), theClass, getMethodName);
+ if (null != params && !params.isEmpty()) {
+ for (final String key : params.keySet()) {
+ uriBuilder.queryParam(key, params.get(key));
+ }
+ }
+
if (jaxrsConfig.isJaxrsLocationFullUrl()) {
uriBuilder.scheme(uriInfo.getAbsolutePath().getScheme())
.host(uriInfo.getAbsolutePath().getHost())
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index 2254f5b..cfa80b9 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.135</version>
+ <version>0.136-SNAPSHOT</version>
</parent>
<artifactId>killbill</artifactId>
<version>0.17.9-SNAPSHOT</version>
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 a298dc3..fe19bb1 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,15 +26,17 @@ 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;
import org.killbill.billing.catalog.api.PriceListSet;
import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.client.KillBillClientException;
import org.killbill.billing.client.model.Account;
+import org.killbill.billing.client.model.BulkBaseSubscriptionAndAddOns;
import org.killbill.billing.client.model.Bundle;
+import org.killbill.billing.client.model.Bundles;
import org.killbill.billing.client.model.Invoice;
import org.killbill.billing.client.model.PhasePriceOverride;
import org.killbill.billing.client.model.Subscription;
@@ -44,9 +46,8 @@ import org.killbill.billing.util.api.AuditLevel;
import org.testng.Assert;
import org.testng.annotations.Test;
-import com.ning.http.client.Response;
-
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
@@ -268,7 +269,7 @@ public class TestEntitlement extends TestJaxrsBase {
subscriptions.add(base);
subscriptions.add(addOn1);
subscriptions.add(addOn2);
- final Bundle bundle = killBillClient.createSubscriptionWithAddOns(subscriptions, initialDate.toLocalDate(), 10, "createdBy", "", "");
+ final Bundle bundle = killBillClient.createSubscriptionWithAddOns(subscriptions, null, 10, "createdBy", "", "");
assertNotNull(bundle);
assertEquals(bundle.getExternalKey(), "base");
assertEquals(bundle.getSubscriptions().size(), 3);
@@ -277,6 +278,78 @@ public class TestEntitlement extends TestJaxrsBase {
assertEquals(invoices.size(), 1);
}
+ @Test(groups = "slow", description = "Create a bulk of base entitlement and addOns under the same transaction")
+ public void testCreateEntitlementsWithAddOns() 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 base = new Subscription();
+ base.setAccountId(accountJson.getAccountId());
+ base.setProductName("Shotgun");
+ base.setProductCategory(ProductCategory.BASE);
+ base.setBillingPeriod(BillingPeriod.MONTHLY);
+ base.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
+
+ final Subscription addOn1 = new Subscription();
+ addOn1.setAccountId(accountJson.getAccountId());
+ addOn1.setProductName("Telescopic-Scope");
+ addOn1.setProductCategory(ProductCategory.ADD_ON);
+ addOn1.setBillingPeriod(BillingPeriod.MONTHLY);
+ addOn1.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
+
+ final Subscription addOn2 = new Subscription();
+ addOn2.setAccountId(accountJson.getAccountId());
+ addOn2.setProductName("Laser-Scope");
+ addOn2.setProductCategory(ProductCategory.ADD_ON);
+ addOn2.setBillingPeriod(BillingPeriod.MONTHLY);
+ addOn2.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
+
+ final List<Subscription> subscriptions = new ArrayList<Subscription>();
+ subscriptions.add(base);
+ subscriptions.add(addOn1);
+ subscriptions.add(addOn2);
+
+ final List<BulkBaseSubscriptionAndAddOns> bulkList = new ArrayList<BulkBaseSubscriptionAndAddOns>();
+ bulkList.add(new BulkBaseSubscriptionAndAddOns(subscriptions));
+ bulkList.add(new BulkBaseSubscriptionAndAddOns(subscriptions));
+
+ final Bundles bundles = killBillClient.createSubscriptionsWithAddOns(bulkList, null, 10, requestOptions);
+
+ assertNotNull(bundles);
+ assertEquals(bundles.size(), 2);
+ assertFalse(bundles.get(0).getExternalKey().equals(bundles.get(1).getExternalKey()));
+
+ final List<Invoice> invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, false, false, requestOptions);
+ assertEquals(invoices.size(), 1);
+ }
+
+ @Test(groups = "slow", description = "Create a bulk of base entitlements and addOns under the same transaction",
+ expectedExceptions = KillBillClientException.class, expectedExceptionsMessageRegExp = "SubscriptionJson Base Entitlement needs to be provided")
+ public void testCreateEntitlementsWithoutBase() 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 addOn1 = new Subscription();
+ addOn1.setAccountId(accountJson.getAccountId());
+ addOn1.setProductName("Telescopic-Scope");
+ addOn1.setProductCategory(ProductCategory.ADD_ON);
+ addOn1.setBillingPeriod(BillingPeriod.MONTHLY);
+ addOn1.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
+
+ final List<Subscription> subscriptions = new ArrayList<Subscription>();
+ subscriptions.add(addOn1);
+
+ final List<BulkBaseSubscriptionAndAddOns> bulkList = new ArrayList<BulkBaseSubscriptionAndAddOns>();
+ bulkList.add(new BulkBaseSubscriptionAndAddOns(subscriptions));
+ bulkList.add(new BulkBaseSubscriptionAndAddOns(subscriptions));
+
+ killBillClient.createSubscriptionsWithAddOns(bulkList, null, 10, requestOptions);
+ }
+
@Test(groups = "slow", description = "Can create an entitlement in the future")
public void testCreateEntitlementInTheFuture() throws Exception {
final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
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 dc345c6..d1991cd 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
@@ -25,7 +25,6 @@ import org.joda.time.DateTime;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingActionPolicy;
-import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.PhaseType;
import org.killbill.billing.catalog.api.Plan;
@@ -33,9 +32,10 @@ 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.DefaultSubscriptionBaseWithAddOns;
+import org.killbill.billing.subscription.api.user.SubscriptionAndAddOnsSpecifier;
import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
import org.killbill.billing.subscription.api.user.SubscriptionBuilder;
-import org.killbill.billing.subscription.api.user.SubscriptionSpecifier;
import org.killbill.billing.subscription.events.SubscriptionBaseEvent;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.TenantContext;
@@ -47,7 +47,7 @@ public interface SubscriptionBaseApiService {
CallContext context)
throws SubscriptionBaseApiException;
- public List<DefaultSubscriptionBase> createPlans(Iterable<SubscriptionSpecifier> subscriptions, CallContext context)
+ public List<DefaultSubscriptionBaseWithAddOns> createPlansWithAddOns(UUID accountId, Iterable<SubscriptionAndAddOnsSpecifier> subscriptionsAndAddOns, CallContext context)
throws SubscriptionBaseApiException;
public boolean cancel(DefaultSubscriptionBase subscription, CallContext context)
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 843e114..9ccf2a8 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,6 +48,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.ProductCategory;
+import org.killbill.billing.entitlement.api.BaseEntitlementWithAddOnsSpecifier;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
import org.killbill.billing.entitlement.api.EntitlementAOStatusDryRun;
import org.killbill.billing.entitlement.api.EntitlementAOStatusDryRun.DryRunChangeReason;
@@ -58,11 +59,14 @@ import org.killbill.billing.subscription.api.SubscriptionApiBase;
import org.killbill.billing.subscription.api.SubscriptionBase;
import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
+import org.killbill.billing.subscription.api.SubscriptionBaseWithAddOns;
import org.killbill.billing.subscription.api.user.DefaultEffectiveSubscriptionEvent;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseApiService;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
+import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseWithAddOns;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionStatusDryRun;
+import org.killbill.billing.subscription.api.user.SubscriptionAndAddOnsSpecifier;
import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
import org.killbill.billing.subscription.api.user.SubscriptionBaseTransition;
@@ -195,82 +199,112 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
}
}
- @Override
- public List<SubscriptionBase> createBaseSubscriptionWithAddOns(final UUID bundleId, final Iterable<EntitlementSpecifier> entitlements, final DateTime requestedDateWithMs, final boolean isMigrated, final InternalCallContext context) throws SubscriptionBaseApiException {
-
- final DateTime now = clock.getUTCNow();
- final DateTime effectiveDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
+ private List<SubscriptionSpecifier> verifyAndBuildSubscriptionSpecifiers(final UUID bundleId, final Iterable<EntitlementSpecifier> entitlements, final boolean isMigrated, final InternalCallContext context, final DateTime now, final DateTime effectiveDate, final Catalog catalog, final CallContext callContext) throws SubscriptionBaseApiException, CatalogApiException {
+ final List<SubscriptionSpecifier> subscriptions = new ArrayList<SubscriptionSpecifier>();
+ boolean first = true;
+ final List<SubscriptionBase> subscriptionsForBundle = getSubscriptionsForBundle(bundleId, null, context);
- try {
- final List<SubscriptionSpecifier> subscriptions = new ArrayList<SubscriptionSpecifier>();
- final Catalog catalog = catalogService.getFullCatalog(true, true, context);
- final CallContext callContext = internalCallContextFactory.createCallContext(context);
-
- final SubscriptionBaseBundle bundle = dao.getSubscriptionBundleFromId(bundleId, context);
- if (bundle == null) {
- throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_NO_BUNDLE, bundleId);
- }
-
- boolean first = true;
- final List<SubscriptionBase> subscriptionsForBundle = getSubscriptionsForBundle(bundleId, null, context);
+ for (EntitlementSpecifier entitlement : entitlements) {
- for (EntitlementSpecifier entitlement : entitlements) {
+ final PlanPhaseSpecifier spec = entitlement.getPlanPhaseSpecifier();
- final PlanPhaseSpecifier spec = entitlement.getPlanPhaseSpecifier();
+ final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(entitlement.getOverrides(), callContext);
- final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(entitlement.getOverrides(), callContext);
+ 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(), plan.getPriceListName()));
+ }
- 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(), plan.getPriceListName()));
+ if (first) {
+ first = false;
+ if (plan.getProduct().getCategory() != ProductCategory.BASE) {
+ throw new SubscriptionBaseApiException(new IllegalArgumentException(), ErrorCode.SUB_CREATE_NO_BP.getCode(), "Missing Base Subscription.");
}
+ }
- if (first) {
- first = false;
- if (plan.getProduct().getCategory() != ProductCategory.BASE) {
- throw new SubscriptionBaseApiException(new IllegalArgumentException(), ErrorCode.SUB_CREATE_NO_BP.getCode(), "Missing Base Subscription.");
+ // verify the number of subscriptions (of the same kind) allowed per bundle and the existing ones
+ if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(plan.getProduct().getCategory().toString())) {
+ if (plan.getPlansAllowedInBundle() != -1 && plan.getPlansAllowedInBundle() > 0) {
+ int existingAddOnsWithSamePlanName = addonUtils.countExistingAddOnsWithSamePlanName(subscriptionsForBundle, plan.getName());
+ int currentAddOnsWithSamePlanName = countCurrentAddOnsWithSamePlanName(entitlements, catalog, plan.getName(), effectiveDate, callContext);
+ if ((existingAddOnsWithSamePlanName + currentAddOnsWithSamePlanName) > plan.getPlansAllowedInBundle()) {
+ // a new ADD_ON subscription of the same plan can't be added because it has reached its limit by bundle
+ throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE, plan.getName());
}
}
+ }
- // verify the number of subscriptions (of the same kind) allowed per bundle and the existing ones
- if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(plan.getProduct().getCategory().toString())) {
- if (plan.getPlansAllowedInBundle() != -1 && plan.getPlansAllowedInBundle() > 0) {
- int existingAddOnsWithSamePlanName = addonUtils.countExistingAddOnsWithSamePlanName(subscriptionsForBundle, plan.getName());
- int currentAddOnsWithSamePlanName = countCurrentAddOnsWithSamePlanName(entitlements, catalog, plan.getName(), effectiveDate, callContext);
- if ((existingAddOnsWithSamePlanName + currentAddOnsWithSamePlanName) > plan.getPlansAllowedInBundle()) {
- // a new ADD_ON subscription of the same plan can't be added because it has reached its limit by bundle
- throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE, plan.getName());
- }
- }
- }
+ SubscriptionSpecifier subscription = new SubscriptionSpecifier();
+ subscription.setRealPriceList(plan.getPriceListName());
+ subscription.setEffectiveDate(effectiveDate);
+ subscription.setProcessedDate(now);
+ subscription.setPlan(plan);
+ subscription.setInitialPhase(spec.getPhaseType());
+ subscription.setBuilder(new SubscriptionBuilder()
+ .setId(UUIDs.randomUUID())
+ .setBundleId(bundleId)
+ .setCategory(plan.getProduct().getCategory())
+ .setBundleStartDate(effectiveDate)
+ .setAlignStartDate(effectiveDate)
+ .setMigrated(isMigrated));
+
+ subscriptions.add(subscription);
+ }
+ return subscriptions;
+ }
- SubscriptionSpecifier subscription = new SubscriptionSpecifier();
- subscription.setRealPriceList(plan.getPriceListName());
- subscription.setEffectiveDate(effectiveDate);
- subscription.setProcessedDate(now);
- subscription.setPlan(plan);
- subscription.setInitialPhase(spec.getPhaseType());
- subscription.setBuilder(new SubscriptionBuilder()
- .setId(UUIDs.randomUUID())
- .setBundleId(bundleId)
- .setCategory(plan.getProduct().getCategory())
- .setBundleStartDate(effectiveDate)
- .setAlignStartDate(effectiveDate)
- .setMigrated(isMigrated));
-
- subscriptions.add(subscription);
+ @Override
+ public List<SubscriptionBaseWithAddOns> createBaseSubscriptionsWithAddOns(final UUID accountId, final Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifier, final InternalCallContext context) throws SubscriptionBaseApiException {
+ try {
+ final Catalog catalog = catalogService.getFullCatalog(true, true, context);
+ final CallContext callContext = internalCallContextFactory.createCallContext(context);
+ final DateTime now = clock.getUTCNow();
+
+ final List<SubscriptionAndAddOnsSpecifier> subscriptionAndAddOns = new ArrayList<SubscriptionAndAddOnsSpecifier>();
+ for (BaseEntitlementWithAddOnsSpecifier entitlementWithAddOnsSpecifier : baseEntitlementWithAddOnsSpecifier) {
+ final DateTime effectiveDate = (entitlementWithAddOnsSpecifier.getBillingEffectiveDate() != null) ?
+ DefaultClock.truncateMs(entitlementWithAddOnsSpecifier.getBillingEffectiveDate().toDateTimeAtStartOfDay()) : now;
+
+ final SubscriptionBaseBundle bundle = createBundleForAccount(accountId, entitlementWithAddOnsSpecifier.getExternalKey(), context);
+
+ SubscriptionAndAddOnsSpecifier subscriptionAndAddOnsSpecifier = new SubscriptionAndAddOnsSpecifier(
+ bundle.getId(),
+ effectiveDate,
+ verifyAndBuildSubscriptionSpecifiers(bundle.getId(),
+ entitlementWithAddOnsSpecifier.getEntitlementSpecifier(),
+ entitlementWithAddOnsSpecifier.isMigrated(),
+ context,
+ now,
+ effectiveDate,
+ catalog,
+ callContext)
+ );
+ subscriptionAndAddOns.add(subscriptionAndAddOnsSpecifier);
}
- final List<DefaultSubscriptionBase> result = apiService.createPlans(subscriptions, callContext);
- return ImmutableList.copyOf(Iterables.transform(result, new Function<DefaultSubscriptionBase, SubscriptionBase>() {
- @Override
- public SubscriptionBase apply(final DefaultSubscriptionBase input) {
- return (SubscriptionBase) input;
- }
- }));
- } catch (final CatalogApiException e) {
+ final List<DefaultSubscriptionBaseWithAddOns> defaultSubscriptionBaseWithAddOnsList = apiService.createPlansWithAddOns(accountId, subscriptionAndAddOns, callContext);
+ List<SubscriptionBaseWithAddOns> subscriptionBaseWithAddOnsList = new ArrayList<SubscriptionBaseWithAddOns>();
+ for (final DefaultSubscriptionBaseWithAddOns cur : defaultSubscriptionBaseWithAddOnsList) {
+ SubscriptionBaseWithAddOns subscriptionBaseWithAddOns = new SubscriptionBaseWithAddOns() {
+ @Override
+ public UUID getBundleId() {
+ return cur.getBundleId();
+ }
+ @Override
+ public List<SubscriptionBase> getSubscriptionBaseList() {
+ return cur.getSubscriptionBaseList();
+ }
+ @Override
+ public DateTime getEffectiveDate() {
+ return cur.getEffectiveDate();
+ }
+ };
+ subscriptionBaseWithAddOnsList.add(subscriptionBaseWithAddOns);
+ }
+ return subscriptionBaseWithAddOnsList;
+ } catch (CatalogApiException e) {
throw new SubscriptionBaseApiException(e);
}
}
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 0fee918..0cd9ce2 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
@@ -34,7 +34,6 @@ import org.killbill.billing.ObjectType;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingActionPolicy;
-import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Catalog;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.CatalogService;
@@ -71,6 +70,7 @@ import org.killbill.billing.util.callcontext.TenantContext;
import org.killbill.clock.Clock;
import org.killbill.clock.DefaultClock;
+import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -118,12 +118,41 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
}
@Override
- public List<DefaultSubscriptionBase> createPlans(final Iterable<SubscriptionSpecifier> subscriptions, final CallContext context) throws SubscriptionBaseApiException {
-
+ public List<DefaultSubscriptionBaseWithAddOns> createPlansWithAddOns(final UUID accountId, final Iterable<SubscriptionAndAddOnsSpecifier> subscriptionsAndAddOns, final CallContext context) throws SubscriptionBaseApiException {
Map<UUID, List<SubscriptionBaseEvent>> eventsMap = new HashMap<UUID, List<SubscriptionBaseEvent>>();
- List<DefaultSubscriptionBase> subscriptionBaseList = new ArrayList<DefaultSubscriptionBase>();
- for (SubscriptionSpecifier subscription : subscriptions) {
+ List<List<DefaultSubscriptionBase>> subscriptionBaseAndAddOnsList = new ArrayList<List<DefaultSubscriptionBase>>();
+ List<DefaultSubscriptionBaseWithAddOns> allSubscriptions = new ArrayList<DefaultSubscriptionBaseWithAddOns>();
+
+ for (SubscriptionAndAddOnsSpecifier subscriptionAndAddOns : subscriptionsAndAddOns) {
+ List<DefaultSubscriptionBase> subscriptionBaseList = new ArrayList<DefaultSubscriptionBase>();
+ createEvents(subscriptionAndAddOns.getSubscriptionSpecifiers(), context, eventsMap, subscriptionBaseList);
+
+ subscriptionBaseAndAddOnsList.add(subscriptionBaseList);
+
+ DefaultSubscriptionBaseWithAddOns defaultSubscriptionBaseWithAddOns = new DefaultSubscriptionBaseWithAddOns(
+ subscriptionAndAddOns.getBundleId(),
+ ImmutableList.copyOf(Iterables.transform(subscriptionBaseList, new Function<DefaultSubscriptionBase, SubscriptionBase>() {
+ @Override
+ public SubscriptionBase apply(final DefaultSubscriptionBase input) {
+ return input;
+ }
+ })),
+ subscriptionAndAddOns.getEffectiveDate());
+ allSubscriptions.add(defaultSubscriptionBaseWithAddOns);
+ }
+
+ final InternalCallContext internalCallContext = createCallContextFromAccountId(accountId, context);
+ dao.createSubscriptionsWithAddOns(allSubscriptions, eventsMap, internalCallContext);
+
+ for (List<DefaultSubscriptionBase> subscriptions : subscriptionBaseAndAddOnsList) {
+ final DefaultSubscriptionBase baseSubscription = findBaseSubscription(subscriptions);
+ rebuildTransitions(internalCallContext, subscriptions, baseSubscription);
+ }
+ return allSubscriptions;
+ }
+ private void createEvents(final Iterable<SubscriptionSpecifier> subscriptions, final CallContext context, final Map<UUID, List<SubscriptionBaseEvent>> eventsMap, final List<DefaultSubscriptionBase> subscriptionBaseList) throws SubscriptionBaseApiException {
+ for (SubscriptionSpecifier subscription : subscriptions) {
try {
final DefaultSubscriptionBase subscriptionBase = new DefaultSubscriptionBase(subscription.getBuilder(), this, clock);
final InternalCallContext internalCallContext = createCallContextFromBundleId(subscriptionBase.getBundleId(), context);
@@ -138,16 +167,14 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
throw new SubscriptionBaseApiException(e);
}
}
+ }
- final InternalCallContext internalCallContext = createCallContextFromBundleId(subscriptionBaseList.get(0).getBundleId(), context);
- dao.createSubscriptionWithAddOns(subscriptionBaseList, eventsMap, internalCallContext);
-
- final DefaultSubscriptionBase baseSubscription = findBaseSubscription(subscriptionBaseList);
+ private void rebuildTransitions(final InternalCallContext internalCallContext, final List<DefaultSubscriptionBase> subscriptions, final DefaultSubscriptionBase baseSubscription) throws SubscriptionBaseApiException {
try {
baseSubscription.rebuildTransitions(dao.getEventsForSubscription(baseSubscription.getId(), internalCallContext),
catalogService.getFullCatalog(true, true, internalCallContext));
- for (final DefaultSubscriptionBase input : subscriptionBaseList) {
+ for (final DefaultSubscriptionBase input : subscriptions) {
if (input.getId().equals(baseSubscription.getId())) {
continue;
}
@@ -158,13 +185,12 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
} catch (CatalogApiException e) {
throw new SubscriptionBaseApiException(e);
}
- return subscriptionBaseList;
}
private DefaultSubscriptionBase findBaseSubscription(final List<DefaultSubscriptionBase> subscriptionBaseList) {
- return Iterables.tryFind(subscriptionBaseList, new Predicate<DefaultSubscriptionBase>() {
+ return Iterables.tryFind(subscriptionBaseList, new Predicate<SubscriptionBase>() {
@Override
- public boolean apply(final DefaultSubscriptionBase subscription) {
+ public boolean apply(final SubscriptionBase subscription) {
return ProductCategory.BASE.equals(subscription.getCategory());
}
}).orNull();
@@ -592,6 +618,10 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
return internalCallContextFactory.createInternalCallContext(bundleId, ObjectType.BUNDLE, context);
}
+ private InternalCallContext createCallContextFromAccountId(final UUID accountId, final CallContext context) {
+ return internalCallContextFactory.createInternalCallContext(accountId, ObjectType.ACCOUNT, context);
+ }
+
private InternalTenantContext createTenantContextFromBundleId(final UUID bundleId, final TenantContext context) {
return internalCallContextFactory.createInternalTenantContext(bundleId, ObjectType.BUNDLE, context);
}
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseWithAddOns.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseWithAddOns.java
new file mode 100644
index 0000000..0050afd
--- /dev/null
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseWithAddOns.java
@@ -0,0 +1,55 @@
+/*
+ * 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.subscription.api.user;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.killbill.billing.subscription.api.SubscriptionBase;
+import org.killbill.billing.subscription.api.SubscriptionBaseWithAddOns;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DefaultSubscriptionBaseWithAddOns implements SubscriptionBaseWithAddOns {
+
+ private static final Logger log = LoggerFactory.getLogger(DefaultSubscriptionBaseWithAddOns.class);
+
+ private final UUID bundleId;
+ private final List<SubscriptionBase> subscriptionBaseList;
+ private final DateTime effectiveDate;
+
+ public DefaultSubscriptionBaseWithAddOns(final UUID bundleId, final List<SubscriptionBase> subscriptionBaseList, final DateTime effectiveDate) {
+ this.bundleId = bundleId;
+ this.subscriptionBaseList = subscriptionBaseList;
+ this.effectiveDate = effectiveDate;
+ }
+
+ @Override
+ public UUID getBundleId() {
+ return bundleId;
+ }
+
+ @Override
+ public List<SubscriptionBase> getSubscriptionBaseList() {
+ return subscriptionBaseList;
+ }
+
+ public DateTime getEffectiveDate() {
+ return effectiveDate;
+ }
+}
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionAndAddOnsSpecifier.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionAndAddOnsSpecifier.java
new file mode 100644
index 0000000..549335e
--- /dev/null
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionAndAddOnsSpecifier.java
@@ -0,0 +1,55 @@
+/*
+ * 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.subscription.api.user;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+public class SubscriptionAndAddOnsSpecifier {
+
+ private UUID bundleId;
+ private DateTime effectiveDate;
+ private List<SubscriptionSpecifier> subscriptionSpecifiers;
+
+ public SubscriptionAndAddOnsSpecifier() {
+ }
+
+ public SubscriptionAndAddOnsSpecifier(final UUID bundleId, final DateTime effectiveDate,
+ final List<SubscriptionSpecifier> subscriptionSpecifiers) {
+ this.bundleId = bundleId;
+ this.effectiveDate = effectiveDate;
+ this.subscriptionSpecifiers = subscriptionSpecifiers;
+ }
+
+ public UUID getBundleId() {
+ return bundleId;
+ }
+
+ public DateTime getEffectiveDate() {
+ return effectiveDate;
+ }
+
+ public List<SubscriptionSpecifier> getSubscriptionSpecifiers() {
+ return subscriptionSpecifiers;
+ }
+
+ public void setSubscriptionSpecifiers(final List<SubscriptionSpecifier> subscriptionSpecifiers) {
+ this.subscriptionSpecifiers = subscriptionSpecifiers;
+ }
+}
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
index 8899098..81df1b3 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
@@ -54,6 +54,7 @@ import org.killbill.billing.subscription.api.user.DefaultEffectiveSubscriptionEv
import org.killbill.billing.subscription.api.user.DefaultRequestedSubscriptionEvent;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
+import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseWithAddOns;
import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
import org.killbill.billing.subscription.api.user.SubscriptionBaseTransitionData;
import org.killbill.billing.subscription.api.user.SubscriptionBuilder;
@@ -513,27 +514,34 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
}
@Override
- public void createSubscriptionWithAddOns(final List<DefaultSubscriptionBase> subscriptions, final Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap, final InternalCallContext context) {
+ public void createSubscriptionsWithAddOns(final List<DefaultSubscriptionBaseWithAddOns> subscriptions, final Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap, final InternalCallContext context) {
transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
@Override
public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
final SubscriptionSqlDao transactional = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class);
final SubscriptionEventSqlDao eventsDaoFromSameTransaction = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class);
+ for (DefaultSubscriptionBaseWithAddOns subscription : subscriptions) {
+ List<DefaultSubscriptionBase> currentSubscriptionBaseList = ImmutableList.copyOf(Iterables.transform(subscription.getSubscriptionBaseList(), new Function<SubscriptionBase, DefaultSubscriptionBase>() {
+ @Override
+ public DefaultSubscriptionBase apply(final SubscriptionBase input) {
+ return (DefaultSubscriptionBase) input;
+ }
+ }));
+ for (DefaultSubscriptionBase subscriptionBase : currentSubscriptionBaseList) {
+ transactional.create(new SubscriptionModelDao(subscriptionBase), context);
- for (DefaultSubscriptionBase subscription : subscriptions) {
- transactional.create(new SubscriptionModelDao(subscription), context);
-
- final List<SubscriptionBaseEvent> initialEvents = initialEventsMap.get(subscription.getId());
- for (final SubscriptionBaseEvent cur : initialEvents) {
- eventsDaoFromSameTransaction.create(new SubscriptionEventModelDao(cur), context);
+ final List<SubscriptionBaseEvent> initialEvents = initialEventsMap.get(subscriptionBase.getId());
+ for (final SubscriptionBaseEvent cur : initialEvents) {
+ eventsDaoFromSameTransaction.create(new SubscriptionEventModelDao(cur), context);
- final boolean isBusEvent = cur.getEffectiveDate().compareTo(clock.getUTCNow()) <= 0 && (cur.getType() == EventType.API_USER);
- recordBusOrFutureNotificationFromTransaction(subscription, cur, entitySqlDaoWrapperFactory, isBusEvent, 0, context);
+ final boolean isBusEvent = cur.getEffectiveDate().compareTo(clock.getUTCNow()) <= 0 && (cur.getType() == EventType.API_USER);
+ recordBusOrFutureNotificationFromTransaction(subscriptionBase, cur, entitySqlDaoWrapperFactory, isBusEvent, 0, context);
- }
- // Notify the Bus of the latest requested change, if needed
- if (initialEvents.size() > 0) {
- notifyBusOfRequestedChange(entitySqlDaoWrapperFactory, subscription, initialEvents.get(initialEvents.size() - 1), SubscriptionBaseTransitionType.CREATE, context);
+ }
+ // Notify the Bus of the latest requested change, if needed
+ if (initialEvents.size() > 0) {
+ notifyBusOfRequestedChange(entitySqlDaoWrapperFactory, subscriptionBase, initialEvents.get(initialEvents.size() - 1), SubscriptionBaseTransitionType.CREATE, context);
+ }
}
}
return null;
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
index 846be18..7c5743d 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
@@ -29,6 +29,7 @@ import org.killbill.billing.subscription.api.transfer.BundleTransferData;
import org.killbill.billing.subscription.api.transfer.TransferCancelData;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
+import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseWithAddOns;
import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
import org.killbill.billing.subscription.engine.dao.model.SubscriptionBundleModelDao;
import org.killbill.billing.subscription.events.SubscriptionBaseEvent;
@@ -81,7 +82,7 @@ public interface SubscriptionDao extends EntityDao<SubscriptionBundleModelDao, S
// SubscriptionBase creation, cancellation, changePlanWithRequestedDate apis
public void createSubscription(DefaultSubscriptionBase subscription, List<SubscriptionBaseEvent> initialEvents, InternalCallContext context);
- public void createSubscriptionWithAddOns(List<DefaultSubscriptionBase> subscriptions, Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap, InternalCallContext context);
+ public void createSubscriptionsWithAddOns(List<DefaultSubscriptionBaseWithAddOns> subscriptions, Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap, InternalCallContext context);
public void cancelSubscriptionsOnBasePlanEvent(DefaultSubscriptionBase subscription, SubscriptionBaseEvent event, List<DefaultSubscriptionBase> subscriptions, List<SubscriptionBaseEvent> cancelEvents, InternalCallContext context);
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
index b3bde6d..d2306f1 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
@@ -43,6 +43,7 @@ import org.killbill.billing.subscription.api.transfer.TransferCancelData;
import org.killbill.billing.subscription.api.user.DefaultEffectiveSubscriptionEvent;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
+import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseWithAddOns;
import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
import org.killbill.billing.subscription.api.user.SubscriptionBaseTransitionData;
import org.killbill.billing.subscription.api.user.SubscriptionBuilder;
@@ -68,6 +69,9 @@ import org.killbill.notificationq.api.NotificationQueueService.NoSuchNotificatio
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
import com.google.inject.Inject;
public class MockSubscriptionDaoMemory extends MockEntityDaoBase<SubscriptionBundleModelDao, SubscriptionBaseBundle, SubscriptionApiException> implements SubscriptionDao {
@@ -220,20 +224,27 @@ public class MockSubscriptionDaoMemory extends MockEntityDaoBase<SubscriptionBun
mockNonEntityDao.addTenantRecordIdMapping(updatedSubscription.getId(), context);
}
- @Override
- public void createSubscriptionWithAddOns(final List<DefaultSubscriptionBase> subscriptions,
- final Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap,
- final InternalCallContext context) {
+ public void createSubscriptionsWithAddOns(final List<DefaultSubscriptionBaseWithAddOns> subscriptions,
+ final Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap,
+ final InternalCallContext context) {
synchronized (events) {
- for (DefaultSubscriptionBase subscription : subscriptions) {
- final List<SubscriptionBaseEvent> initialEvents = initialEventsMap.get(subscription.getId());
- events.addAll(initialEvents);
- for (final SubscriptionBaseEvent cur : initialEvents) {
- recordFutureNotificationFromTransaction(null, cur.getEffectiveDate(), new SubscriptionNotificationKey(cur.getId()), context);
+ for (DefaultSubscriptionBaseWithAddOns subscription : subscriptions) {
+ List<DefaultSubscriptionBase> currentSubscriptionBaseList = ImmutableList.copyOf(Iterables.transform(subscription.getSubscriptionBaseList(), new Function<SubscriptionBase, DefaultSubscriptionBase>() {
+ @Override
+ public DefaultSubscriptionBase apply(final SubscriptionBase input) {
+ return (DefaultSubscriptionBase) input;
+ }
+ }));
+ for (DefaultSubscriptionBase subscriptionBase : currentSubscriptionBaseList) {
+ final List<SubscriptionBaseEvent> initialEvents = initialEventsMap.get(subscriptionBase.getId());
+ events.addAll(initialEvents);
+ for (final SubscriptionBaseEvent cur : initialEvents) {
+ recordFutureNotificationFromTransaction(null, cur.getEffectiveDate(), new SubscriptionNotificationKey(cur.getId()), context);
+ }
+ final SubscriptionBase updatedSubscription = buildSubscription(subscriptionBase, context);
+ this.subscriptions.add(updatedSubscription);
+ mockNonEntityDao.addTenantRecordIdMapping(updatedSubscription.getId(), context);
}
- final SubscriptionBase updatedSubscription = buildSubscription(subscription, context);
- this.subscriptions.add(updatedSubscription);
- mockNonEntityDao.addTenantRecordIdMapping(updatedSubscription.getId(), context);
}
}
}