killbill-memoizeit

Implement a fix for migration code to avoid having a MIGRATE_BILLING

10/24/2012 2:17:02 AM

Details

diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index c081e57..b62ab79 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -60,7 +60,7 @@ public enum ErrorCode {
     ENT_GET_INVALID_BUNDLE_ID(1081, "Could not find a bundle matching id %s"),
     ENT_INVALID_SUBSCRIPTION_ID(1082, "Unknown subscription %s"),
     ENT_GET_INVALID_BUNDLE_KEY(1083, "Could not find a bundle matching key %s"),
-    ENT_GET_NO_SUCH_BASE_SUBSCRIPTION(1084, "Could not base subscription for bundle %s"),
+    ENT_GET_NO_SUCH_BASE_SUBSCRIPTION(1084, "Could not find base subscription for bundle %s"),
 
     /* Repair */
     ENT_REPAIR_INVALID_DELETE_SET(1091, "Event %s is not deleted for subscription %s but prior events were"),
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java
index f08e351..e836d59 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java
@@ -170,10 +170,13 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
     private List<EntitlementEvent> toEvents(final SubscriptionData subscriptionData, final DateTime now, final DateTime ctd, final TimedMigration[] migrationEvents, final CallContext context) {
         ApiEventMigrateEntitlement creationEvent = null;
         final List<EntitlementEvent> events = new ArrayList<EntitlementEvent>(migrationEvents.length);
-        DateTime subsciptionCancelledDate = null;
+
+        // The first event date after the MIGRATE_ENTITLEMENT event
+        DateTime nextEventDate = null;
         for (final TimedMigration cur : migrationEvents) {
 
             if (cur.getEventType() == EventType.PHASE) {
+                nextEventDate = nextEventDate != null && nextEventDate.compareTo(cur.getEventTime()) < 0 ? nextEventDate : cur.getEventTime();
                 final PhaseEvent nextPhaseEvent = PhaseEventData.createNextPhaseEvent(cur.getPhase().getName(), subscriptionData, now, cur.getEventTime());
                 events.add(nextPhaseEvent);
 
@@ -198,10 +201,11 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
                         break;
 
                     case CHANGE:
+                        nextEventDate = nextEventDate != null && nextEventDate.compareTo(cur.getEventTime()) < 0 ? nextEventDate : cur.getEventTime();
                         events.add(new ApiEventChange(builder));
                         break;
                     case CANCEL:
-                        subsciptionCancelledDate = cur.getEventTime();
+                        nextEventDate = nextEventDate != null && nextEventDate.compareTo(cur.getEventTime()) < 0 ? nextEventDate : cur.getEventTime();
                         events.add(new ApiEventCancel(builder));
                         break;
                     default:
@@ -214,7 +218,8 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
         if (creationEvent == null || ctd == null) {
             throw new EntitlementError(String.format("Could not create migration billing event ctd = %s", ctd));
         }
-        if (subsciptionCancelledDate == null || subsciptionCancelledDate.isAfter(ctd)) {
+        // Only add the MIGRATE_BILLING event if there is no event prior to that that will trigger the first invoice.
+        if (nextEventDate == null || nextEventDate.isAfter(ctd)) {
             events.add(new ApiEventMigrateBilling(creationEvent, ctd));
         }
         Collections.sort(events, new Comparator<EntitlementEvent>() {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
index ccdc80a..aefdfbe 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
@@ -192,7 +192,6 @@ public abstract class TestMigration extends TestApiBase {
             assertEquals(subscription.getCurrentPlan().getName(), "assault-rifle-monthly");
             assertEquals(subscription.getChargedThroughDate(), trialDate.plusDays(30));
 
-            testListener.pushExpectedEvent(NextEvent.MIGRATE_BILLING);
             testListener.pushExpectedEvent(NextEvent.PHASE);
 
             final Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(30));
diff --git a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
index 4934889..226ef40 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
@@ -24,6 +24,7 @@ import java.util.UUID;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 
+import com.ning.billing.ErrorCode;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.catalog.api.BillingPeriod;
@@ -60,13 +61,14 @@ public class BillingStateCalculatorBundle extends BillingStateCalculator<Subscri
         this.accountApi = accountApi;
     }
 
+
     @Override
     public BillingStateBundle calculateBillingState(final SubscriptionBundle bundle, final InternalTenantContext context) throws OverdueException {
         try {
             final Account account = accountApi.getAccountById(bundle.getAccountId(), context);
             final SortedSet<Invoice> unpaidInvoices = unpaidInvoicesForBundle(bundle.getId(), bundle.getAccountId(), account.getTimeZone(), context);
 
-            final Subscription basePlan = entitlementApi.getBaseSubscription(bundle.getId(), context);
+            final Subscription basePlan = getBasePlanIfExist(bundle.getId(), context);
 
             final UUID id = bundle.getId();
             final int numberOfUnpaidInvoices = unpaidInvoices.size();
@@ -131,6 +133,19 @@ public class BillingStateCalculatorBundle extends BillingStateCalculator<Subscri
         return result;
     }
 
+    private Subscription getBasePlanIfExist(UUID bundleId, final InternalTenantContext context) throws EntitlementUserApiException {
+        try {
+            final Subscription basePlan = entitlementApi.getBaseSubscription(bundleId, context);
+            return basePlan;
+        } catch (EntitlementUserApiException e) {
+            if (e.getCode() == ErrorCode.ENT_GET_NO_SUCH_BASE_SUBSCRIPTION.getCode()) {
+                // No base plan probably a STANDALONE subscription in a bundle
+                return null;
+            }
+            throw e;
+        }
+    }
+
     private boolean invoiceHasAnItemFromBundle(final Invoice invoice, final UUID bundleId) {
         for (final InvoiceItem item : invoice.getInvoiceItems()) {
             if (item.getBundleId() != null && item.getBundleId().equals(bundleId)) {
@@ -139,6 +154,4 @@ public class BillingStateCalculatorBundle extends BillingStateCalculator<Subscri
         }
         return false;
     }
-
-
 }