killbill-memoizeit

junction: Refactor BillCycleDayCalculator (make it a static

6/10/2016 7:39:04 PM

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);
     }
 }