killbill-memoizeit
Changes
junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java 81(+9 -72)
Details
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
index ec2fee4..e2ba736 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
@@ -18,108 +18,45 @@
package org.killbill.billing.junction.plumbing.billing;
-import java.util.UUID;
-
import org.joda.time.DateTime;
-import org.killbill.billing.ErrorCode;
-import org.killbill.billing.account.api.AccountApiException;
-import org.killbill.billing.account.api.ImmutableAccountData;
-import org.killbill.billing.callcontext.InternalCallContext;
+import org.joda.time.DateTimeZone;
import org.killbill.billing.catalog.api.BillingAlignment;
-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;
-import org.killbill.billing.catalog.api.Plan;
-import org.killbill.billing.catalog.api.PlanPhase;
-import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
-import org.killbill.billing.catalog.api.PriceList;
-import org.killbill.billing.catalog.api.Product;
-import org.killbill.billing.events.EffectiveSubscriptionInternalEvent;
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.user.SubscriptionBaseApiException;
import org.killbill.clock.ClockUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
-import com.google.inject.Inject;
public class BillCycleDayCalculator {
private static final Logger log = LoggerFactory.getLogger(BillCycleDayCalculator.class);
- private final CatalogService catalogService;
- private final SubscriptionBaseInternalApi subscriptionApi;
-
- @Inject
- public BillCycleDayCalculator(final CatalogService catalogService, final SubscriptionBaseInternalApi subscriptionApi) {
- this.catalogService = catalogService;
- this.subscriptionApi = subscriptionApi;
- }
-
- protected int calculateBcd(final ImmutableAccountData account, final int accountBillCycleDayLocal, final UUID bundleId, final SubscriptionBase subscription, final EffectiveSubscriptionInternalEvent transition, final InternalCallContext context)
- throws CatalogApiException, AccountApiException, SubscriptionBaseApiException {
-
- final Catalog catalog = catalogService.getFullCatalog(context);
-
- final Plan prevPlan = (transition.getPreviousPlan() != null) ? catalog.findPlan(transition.getPreviousPlan(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
- final Plan nextPlan = (transition.getNextPlan() != null) ? catalog.findPlan(transition.getNextPlan(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
-
- final Plan plan = (transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ? nextPlan : prevPlan;
- final Product product = plan.getProduct();
-
- final PlanPhase prevPhase = (transition.getPreviousPhase() != null) ? catalog.findPhase(transition.getPreviousPhase(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
- final PlanPhase nextPhase = (transition.getNextPhase() != null) ? catalog.findPhase(transition.getNextPhase(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
-
- final PlanPhase phase = (transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ? nextPhase : prevPhase;
-
- final BillingPeriod billingPeriod = phase.getRecurring() != null ? phase.getRecurring().getBillingPeriod() : BillingPeriod.NO_BILLING_PERIOD;
- final BillingAlignment alignment = catalog.billingAlignment(
- new PlanPhaseSpecifier(product.getName(),
- product.getCategory(),
- billingPeriod,
- transition.getNextPriceList(),
- phase.getPhaseType()),
- transition.getRequestedTransitionTime());
-
- return calculateBcdForAlignment(account, accountBillCycleDayLocal, subscription, alignment, bundleId, context);
+ public BillCycleDayCalculator() {
}
- @VisibleForTesting
- int calculateBcdForAlignment(final ImmutableAccountData account, final int accountBillCycleDayLocal, final SubscriptionBase subscription, final BillingAlignment alignment, final UUID bundleId,
- final InternalCallContext context) throws AccountApiException, SubscriptionBaseApiException, CatalogApiException {
+ public static int calculateBcdForAlignment(final SubscriptionBase subscription, final SubscriptionBase baseSubscription, final BillingAlignment alignment, final DateTimeZone accountTimeZone, final int accountBillCycleDayLocal) {
int result = 0;
switch (alignment) {
case ACCOUNT:
- result = accountBillCycleDayLocal != 0 ? accountBillCycleDayLocal : calculateBcdFromSubscription(subscription, account);
+ result = accountBillCycleDayLocal != 0 ? accountBillCycleDayLocal : calculateBcdFromSubscription(subscription, accountTimeZone);
break;
case BUNDLE:
- final SubscriptionBase baseSub = subscriptionApi.getBaseSubscription(bundleId, context);
- result = calculateBcdFromSubscription(baseSub, account);
+ result = calculateBcdFromSubscription(baseSubscription, accountTimeZone);
break;
case SUBSCRIPTION:
- result = calculateBcdFromSubscription(subscription, account);
+ result = calculateBcdFromSubscription(subscription, accountTimeZone);
break;
}
-
- if (result == 0) {
- throw new CatalogApiException(ErrorCode.CAT_INVALID_BILLING_ALIGNMENT, alignment.toString());
- }
-
return result;
}
@VisibleForTesting
- int calculateBcdFromSubscription(final SubscriptionBase subscription, final ImmutableAccountData account)
- throws AccountApiException, CatalogApiException {
-
+ static int calculateBcdFromSubscription(final SubscriptionBase subscription, final DateTimeZone accountTimeZone) {
final DateTime date = subscription.getDateOfFirstRecurringNonZeroCharge();
- final int bcdLocal = ClockUtil.toDateTime(date, account.getTimeZone()).getDayOfMonth();
+ final int bcdLocal = ClockUtil.toDateTime(date, accountTimeZone).getDayOfMonth();
log.info("Calculated BCD: subscriptionId='{}', subscriptionStartDate='{}', accountTimeZone='{}', bcd='{}'",
- subscription.getId(), date.toDateTimeISO(), account.getTimeZone(), bcdLocal);
+ subscription.getId(), date.toDateTimeISO(), accountTimeZone, bcdLocal);
return bcdLocal;
}
}
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
index cb91c31..d6ca0c4 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
@@ -26,13 +26,21 @@ import java.util.UUID;
import javax.annotation.Nullable;
+import org.joda.time.DateTime;
import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountInternalApi;
import org.killbill.billing.account.api.ImmutableAccountData;
import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.catalog.api.BillingAlignment;
+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;
+import org.killbill.billing.catalog.api.Plan;
+import org.killbill.billing.catalog.api.PlanPhase;
+import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.Product;
import org.killbill.billing.catalog.api.StaticCatalog;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
import org.killbill.billing.entitlement.api.SubscriptionEventType;
@@ -140,7 +148,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
final UUID fakeBundleId = UUIDs.randomUUID();
final List<SubscriptionBase> subscriptions = subscriptionApi.getSubscriptionsForBundle(fakeBundleId, dryRunArguments, context);
- addBillingEventsForSubscription(account, subscriptions, fakeBundleId, dryRunMode, context, result, skipSubscriptionsSet);
+ addBillingEventsForSubscription(account, subscriptions, null, dryRunMode, context, result, skipSubscriptionsSet);
}
@@ -159,7 +167,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
result.getSubscriptionIdsWithAutoInvoiceOff().add(subscription.getId());
}
} else { // billing is not off
- addBillingEventsForSubscription(account, subscriptions, bundle.getId(), dryRunMode, context, result, skipSubscriptionsSet);
+ addBillingEventsForSubscription(account, subscriptions, subscriptions.get(0), dryRunMode, context, result, skipSubscriptionsSet);
}
}
}
@@ -167,7 +175,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
private void addBillingEventsForSubscription(final ImmutableAccountData account,
final List<SubscriptionBase> subscriptions,
- final UUID bundleId,
+ final SubscriptionBase baseSubscription,
final boolean dryRunMode,
final InternalCallContext context,
final DefaultBillingEventSet result,
@@ -206,7 +214,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
overridenBCD = transition.getNextBillCycleDayLocal() != null ? transition.getNextBillCycleDayLocal() : overridenBCD;
final int bcdLocal = overridenBCD != null ?
overridenBCD :
- bcdCalculator.calculateBcd(account, currentAccountBCD, bundleId, subscription, transition, context);
+ calculateBcd(account, currentAccountBCD, baseSubscription, subscription, transition, context);
if (currentAccountBCD == 0 && !updatedAccountBCD) {
accountApi.updateBCD(account.getExternalKey(), bcdLocal, context);
@@ -228,6 +236,37 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
}
}
+ protected int calculateBcd(final ImmutableAccountData account, final int accountBillCycleDayLocal, final SubscriptionBase baseSubscription, final SubscriptionBase subscription, final EffectiveSubscriptionInternalEvent transition, final InternalCallContext context)
+ throws CatalogApiException, AccountApiException, SubscriptionBaseApiException {
+ final Catalog catalog = catalogService.getFullCatalog(context);
+ final BillingAlignment alignment = catalog.billingAlignment(getPlanPhaseSpecifierFromTransition(transition, context), transition.getEffectiveTransitionTime());
+ return bcdCalculator.calculateBcdForAlignment(subscription, baseSubscription, alignment, account.getTimeZone(), accountBillCycleDayLocal);
+ }
+
+
+ private PlanPhaseSpecifier getPlanPhaseSpecifierFromTransition(final EffectiveSubscriptionInternalEvent transition, final InternalCallContext context) throws CatalogApiException {
+
+ final Catalog catalog = catalogService.getFullCatalog(context);
+ final Plan prevPlan = (transition.getPreviousPlan() != null) ? catalog.findPlan(transition.getPreviousPlan(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
+ final Plan nextPlan = (transition.getNextPlan() != null) ? catalog.findPlan(transition.getNextPlan(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
+
+ final Plan plan = (transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ? nextPlan : prevPlan;
+ final Product product = plan.getProduct();
+
+ final PlanPhase prevPhase = (transition.getPreviousPhase() != null) ? catalog.findPhase(transition.getPreviousPhase(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
+ final PlanPhase nextPhase = (transition.getNextPhase() != null) ? catalog.findPhase(transition.getNextPhase(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
+
+ final PlanPhase phase = (transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ? nextPhase : prevPhase;
+
+ final BillingPeriod billingPeriod = phase.getRecurring() != null ? phase.getRecurring().getBillingPeriod() : BillingPeriod.NO_BILLING_PERIOD;
+
+ return new PlanPhaseSpecifier(product.getName(),
+ product.getCategory(),
+ billingPeriod,
+ transition.getNextPriceList(),
+ phase.getPhaseType());
+ }
+
private final boolean is_AUTO_INVOICING_OFF(final List<Tag> tags) {
return ControlTagType.isAutoInvoicingOff(Collections2.transform(tags, new Function<Tag, UUID>() {
@Nullable
diff --git a/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteNoDB.java b/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteNoDB.java
index f13d01e..4a84424 100644
--- a/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteNoDB.java
+++ b/junction/src/test/java/org/killbill/billing/junction/JunctionTestSuiteNoDB.java
@@ -16,21 +16,19 @@
package org.killbill.billing.junction;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeMethod;
-
import org.killbill.billing.GuicyKillbillTestSuiteNoDB;
-import org.killbill.bus.api.PersistentBus;
+import org.killbill.billing.account.api.AccountInternalApi;
import org.killbill.billing.catalog.api.CatalogService;
import org.killbill.billing.entitlement.dao.BlockingStateDao;
import org.killbill.billing.junction.glue.TestJunctionModuleNoDB;
-import org.killbill.billing.junction.plumbing.billing.BillCycleDayCalculator;
import org.killbill.billing.junction.plumbing.billing.BlockingCalculator;
-import org.killbill.billing.account.api.AccountInternalApi;
import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
import org.killbill.billing.tag.TagInternalApi;
import org.killbill.billing.util.tag.dao.TagDao;
+import org.killbill.bus.api.PersistentBus;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
import com.google.inject.Guice;
import com.google.inject.Inject;
@@ -41,8 +39,6 @@ public abstract class JunctionTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
@Inject
protected AccountInternalApi accountInternalApi;
@Inject
- protected BillCycleDayCalculator billCycleDayCalculator;
- @Inject
protected BillingInternalApi billingInternalApi;
@Inject
protected BlockingCalculator blockingCalculator;
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillCycleDayCalculator.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillCycleDayCalculator.java
index 2a7cf5d..4bc06af 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillCycleDayCalculator.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillCycleDayCalculator.java
@@ -20,22 +20,19 @@ import java.util.UUID;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
-import org.killbill.billing.account.api.ImmutableAccountData;
-import org.mockito.Mockito;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
import org.killbill.billing.account.api.AccountApiException;
+import org.killbill.billing.account.api.ImmutableAccountData;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingAlignment;
import org.killbill.billing.catalog.api.Catalog;
import org.killbill.billing.catalog.api.CatalogApiException;
-import org.killbill.billing.catalog.api.CatalogService;
import org.killbill.billing.catalog.api.Plan;
+import org.killbill.billing.junction.JunctionTestSuiteNoDB;
import org.killbill.billing.subscription.api.SubscriptionBase;
import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
-import org.killbill.billing.junction.JunctionTestSuiteNoDB;
-import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
+import org.mockito.Mockito;
+import org.testng.Assert;
+import org.testng.annotations.Test;
public class TestBillCycleDayCalculator extends JunctionTestSuiteNoDB {
@@ -62,8 +59,7 @@ public class TestBillCycleDayCalculator extends JunctionTestSuiteNoDB {
final ImmutableAccountData account = Mockito.mock(ImmutableAccountData.class);
Mockito.when(account.getTimeZone()).thenReturn(accountTimeZone);
- final Integer billCycleDayLocal = billCycleDayCalculator.calculateBcdForAlignment(account, 0, subscription, BillingAlignment.BUNDLE, bundle.getId(),
- internalCallContext);
+ final Integer billCycleDayLocal = BillCycleDayCalculator.calculateBcdForAlignment(subscription, subscription, BillingAlignment.BUNDLE, account.getTimeZone(), 0);
Assert.assertEquals(billCycleDayLocal, (Integer) expectedBCDUTC);
}
@@ -124,8 +120,6 @@ public class TestBillCycleDayCalculator extends JunctionTestSuiteNoDB {
}
private void verifyBCDCalculation(final DateTimeZone accountTimeZone, final DateTime startDateUTC, final int bcdLocal) throws AccountApiException, CatalogApiException {
- final BillCycleDayCalculator billCycleDayCalculator = new BillCycleDayCalculator(Mockito.mock(CatalogService.class), Mockito.mock(SubscriptionBaseInternalApi.class));
-
final SubscriptionBase subscription = Mockito.mock(SubscriptionBase.class);
Mockito.when(subscription.getStartDate()).thenReturn(startDateUTC);
Mockito.when(subscription.getDateOfFirstRecurringNonZeroCharge()).thenReturn(startDateUTC);
@@ -133,7 +127,7 @@ public class TestBillCycleDayCalculator extends JunctionTestSuiteNoDB {
final ImmutableAccountData account = Mockito.mock(ImmutableAccountData.class);
Mockito.when(account.getTimeZone()).thenReturn(accountTimeZone);
- final Integer bcd = billCycleDayCalculator.calculateBcdFromSubscription(subscription, account);
+ final Integer bcd = BillCycleDayCalculator.calculateBcdForAlignment(subscription, subscription, BillingAlignment.SUBSCRIPTION, account.getTimeZone(), 0);
Assert.assertEquals(bcd, (Integer) bcdLocal);
}
}