killbill-memoizeit

Changes

account/pom.xml 2(+1 -1)

api/pom.xml 2(+1 -1)

beatrix/pom.xml 2(+1 -1)

catalog/pom.xml 2(+1 -1)

currency/pom.xml 2(+1 -1)

invoice/pom.xml 2(+1 -1)

jaxrs/pom.xml 2(+1 -1)

junction/pom.xml 2(+1 -1)

NEWS 5(+5 -0)

osgi/pom.xml 2(+1 -1)

overdue/pom.xml 2(+1 -1)

payment/pom.xml 2(+1 -1)

pom.xml 2(+1 -1)

server/pom.xml 2(+1 -1)

tenant/pom.xml 2(+1 -1)

usage/pom.xml 2(+1 -1)

util/pom.xml 2(+1 -1)

Details

account/pom.xml 2(+1 -1)

diff --git a/account/pom.xml b/account/pom.xml
index 4e25722..0b7d1d6 100644
--- a/account/pom.xml
+++ b/account/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-account</artifactId>

api/pom.xml 2(+1 -1)

diff --git a/api/pom.xml b/api/pom.xml
index 5ba1975..87b9b12 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-internal-api</artifactId>

beatrix/pom.xml 2(+1 -1)

diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index abfe6e1..4a956f1 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-beatrix</artifactId>
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
index 71b9f62..cccafc3 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
@@ -918,7 +918,7 @@ public class TestOverdueIntegration extends TestOverdueBase {
         invoiceChecker.checkInvoice(account.getId(), 4, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 31), new LocalDate(2012, 8, 31), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
 
         // Fully adjust all invoices
-        final List<Invoice> invoicesToAdjust = ImmutableList.<Invoice>copyOf(invoiceUserApi.getUnpaidInvoicesByAccountId(account.getId(), clock.getUTCToday(), callContext));
+        final List<Invoice> invoicesToAdjust = getUnpaidInvoicesOrderFromRecent();
         for (int i = 0; i < invoicesToAdjust.size(); i++) {
             if (i == invoicesToAdjust.size() - 1) {
                 fullyAdjustInvoiceAndCheckForCompletion(account, invoicesToAdjust.get(i), NextEvent.BLOCK, NextEvent.INVOICE_ADJUSTMENT);
@@ -947,15 +947,7 @@ public class TestOverdueIntegration extends TestOverdueBase {
         // Upon paying the last invoice, the overdue system will clear the state and notify invoice that it should re-generate a new invoice
         // for the part hat was unblocked, which explains why on the last payment we expect an additional invoice and payment.
         //
-        final Collection<Invoice> invoices = invoiceUserApi.getUnpaidInvoicesByAccountId(account.getId(), clock.getUTCToday(), callContext);
-        // Sort in reverse order to first pay most recent invoice-- that way overdue state may only flip when we reach the last one.
-        final List<Invoice> sortedInvoices = new LinkedList<Invoice>(invoices);
-        Collections.sort(sortedInvoices, new Comparator<Invoice>() {
-            @Override
-            public int compare(final Invoice i1, final Invoice i2) {
-                return i2.getInvoiceDate().compareTo(i1.getInvoiceDate());
-            }
-        });
+        final List<Invoice> sortedInvoices = getUnpaidInvoicesOrderFromRecent();
 
         int remainingUnpaidInvoices = sortedInvoices.size();
         for (final Invoice invoice : sortedInvoices) {
@@ -971,6 +963,19 @@ public class TestOverdueIntegration extends TestOverdueBase {
         checkODState(DefaultBlockingState.CLEAR_STATE_NAME);
     }
 
+    private List<Invoice> getUnpaidInvoicesOrderFromRecent() {
+        final Collection<Invoice> invoices = invoiceUserApi.getUnpaidInvoicesByAccountId(account.getId(), clock.getUTCToday(), callContext);
+        // Sort in reverse order to first pay most recent invoice-- that way overdue state may only flip when we reach the last one.
+        final List<Invoice> sortedInvoices = new LinkedList<Invoice>(invoices);
+        Collections.sort(sortedInvoices, new Comparator<Invoice>() {
+            @Override
+            public int compare(final Invoice i1, final Invoice i2) {
+                return i2.getInvoiceDate().compareTo(i1.getInvoiceDate());
+            }
+        });
+        return sortedInvoices;
+    }
+
     private void checkChangePlanWithOverdueState(final Entitlement entitlement, final boolean shouldFail, final boolean expectedPayment) {
         if (shouldFail) {
             try {
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueWithSubscriptionCancellation.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueWithSubscriptionCancellation.java
index 8c1f241..b7250c1 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueWithSubscriptionCancellation.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueWithSubscriptionCancellation.java
@@ -24,9 +24,11 @@ import org.testng.annotations.Test;
 
 import com.ning.billing.api.TestApiListener.NextEvent;
 import com.ning.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck;
+import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.DefaultEntitlement;
 import com.ning.billing.entitlement.api.Entitlement.EntitlementState;
+import com.ning.billing.entitlement.api.SubscriptionBundle;
 import com.ning.billing.invoice.api.InvoiceItemType;
 import com.ning.billing.junction.DefaultBlockingState;
 import com.ning.billing.subscription.api.SubscriptionBase;
@@ -74,22 +76,85 @@ public class TestOverdueWithSubscriptionCancellation extends TestOverdueBase {
         invoiceChecker.checkInvoice(account.getId(), 1, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
         invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 5, 1), callContext);
 
+        final DefaultEntitlement addOn1 = addAOEntitlementAndCheckForCompletion(baseEntitlement.getBundleId(), "Holster", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.INVOICE);
+
+        final DefaultEntitlement addOn2 = addAOEntitlementAndCheckForCompletion(baseEntitlement.getBundleId(), "Holster", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.INVOICE);
+
+        // Cancel addOn1 one day after
+        clock.addDays(1);
+        cancelEntitlementAndCheckForCompletion(addOn1, clock.getUTCNow(), NextEvent.BLOCK, NextEvent.CANCEL);
+
         // DAY 30 have to get out of trial before first payment
-        addDaysAndCheckForCompletion(30, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR);
+        addDaysAndCheckForCompletion(29, NextEvent.PHASE,  NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR);
 
-        invoiceChecker.checkInvoice(account.getId(), 2, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 6, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
         invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 6, 30), callContext);
 
+
         // Should still be in clear state
         checkODState(DefaultBlockingState.CLEAR_STATE_NAME);
 
+
         // DAY 36 -- RIGHT AFTER OD1 (two block events, for the cancellation and the OD1 state)
-        addDaysAndCheckForCompletion(6, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.INVOICE_ADJUSTMENT);
+        // One BLOCK event is for the overdue state transition
+        // The 2 other BLOCK are for the entitlement blocking states for both base plan and addOn2
+        addDaysAndCheckForCompletion(6, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.INVOICE_ADJUSTMENT);
 
         // Should be in OD1
         checkODState("OD1");
 
         final SubscriptionBase cancelledBaseSubscription = ((DefaultEntitlement) entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext)).getSubscriptionBase();
         assertTrue(cancelledBaseSubscription.getState() == EntitlementState.CANCELLED);
+
+        final SubscriptionBase cancelledAddon1= ((DefaultEntitlement) entitlementApi.getEntitlementForId(addOn1.getId(), callContext)).getSubscriptionBase();
+        assertTrue(cancelledAddon1.getState() == EntitlementState.CANCELLED);
     }
+
+
+    @Test(groups = "slow")
+    public void testCheckSubscriptionCancellationWithMultipleBundles() throws Exception {
+        clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
+
+        // Set next invoice to fail and create subscription
+        paymentPlugin.makeAllInvoicesFailWithError(true);
+        final DefaultEntitlement baseEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.INVOICE);
+        bundle = subscriptionApi.getSubscriptionBundle(baseEntitlement.getBundleId(), callContext);
+
+        invoiceChecker.checkInvoice(account.getId(), 1, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
+        invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 5, 1), callContext);
+
+        final DefaultEntitlement baseEntitlement2 = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey2", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.INVOICE);
+        final SubscriptionBundle bundle2 = subscriptionApi.getSubscriptionBundle(baseEntitlement.getBundleId(), callContext);
+
+        final DefaultEntitlement baseEntitlement3 = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey3", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.INVOICE);
+        final SubscriptionBundle bundle3 = subscriptionApi.getSubscriptionBundle(baseEntitlement.getBundleId(), callContext);
+
+        // Cancel addOn1 one day after
+        clock.addDays(1);
+        cancelEntitlementAndCheckForCompletion(baseEntitlement2, clock.getUTCNow(), NextEvent.BLOCK, NextEvent.CANCEL);
+
+        // DAY 30 have to get out of trial before first payment
+        addDaysAndCheckForCompletion(29, NextEvent.PHASE,  NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR);
+
+        invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 6, 30), callContext);
+
+
+        // Should still be in clear state
+        checkODState(DefaultBlockingState.CLEAR_STATE_NAME);
+
+
+        // DAY 36 -- RIGHT AFTER OD1 (two block events, for the cancellation and the OD1 state)
+        // One BLOCK event is for the overdue state transition
+        // The 2 other BLOCK are for the entitlement blocking states for both base plan and baseEntitlement3
+        addDaysAndCheckForCompletion(6, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.INVOICE_ADJUSTMENT, NextEvent.INVOICE_ADJUSTMENT);
+
+        // Should be in OD1
+        checkODState("OD1");
+
+        final SubscriptionBase cancelledBaseSubscription = ((DefaultEntitlement) entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext)).getSubscriptionBase();
+        assertTrue(cancelledBaseSubscription.getState() == EntitlementState.CANCELLED);
+
+        final SubscriptionBase cancelledbaseEntitlement3 = ((DefaultEntitlement) entitlementApi.getEntitlementForId(baseEntitlement3.getId(), callContext)).getSubscriptionBase();
+        assertTrue(cancelledbaseEntitlement3.getState() == EntitlementState.CANCELLED);
+    }
+
 }
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/util/InvoiceChecker.java b/beatrix/src/test/java/com/ning/billing/beatrix/util/InvoiceChecker.java
index d36682c..3b55ab2 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/util/InvoiceChecker.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/util/InvoiceChecker.java
@@ -132,12 +132,15 @@ public class InvoiceChecker {
             if (expectedLocalCTD == null) {
                 assertNull(subscription.getChargedThroughDate());
             } else {
+                assertTrue(expectedLocalCTD.compareTo(subscription.getChargedThroughDate().toLocalDate()) == 0);
+                /*
                 final DateTime expectedCTD = expectedLocalCTD.toDateTime(new LocalTime(subscription.getStartDate().getMillis(), DateTimeZone.UTC), DateTimeZone.UTC);
                 final String msg = String.format("Checking CTD for entitlement %s : expectedLocalCTD = %s => expectedCTD = %s, got %s",
                                                  entitlementId, expectedLocalCTD, expectedCTD, subscription.getChargedThroughDate());
                 log.info(msg);
                 assertNotNull(subscription.getChargedThroughDate());
                 assertTrue(subscription.getChargedThroughDate().compareTo(expectedCTD) == 0, msg);
+                */
             }
         } catch (EntitlementApiException e) {
             fail("Failed to retrieve entitlement for " + entitlementId);
diff --git a/beatrix/src/test/resources/catalogSample.xml b/beatrix/src/test/resources/catalogSample.xml
index 8aa1247..d6531b1 100644
--- a/beatrix/src/test/resources/catalogSample.xml
+++ b/beatrix/src/test/resources/catalogSample.xml
@@ -47,6 +47,7 @@
             <available>
                 <addonProduct>Telescopic-Scope</addonProduct>
                 <addonProduct>Laser-Scope</addonProduct>
+                <addonProduct>Holster</addonProduct>
             </available>
         </product>
         <product name="Assault-Rifle">
@@ -722,7 +723,7 @@
                 <duration>
                     <unit>UNLIMITED</unit>
                 </duration>
-                <billingPeriod>ANNUAL</billingPeriod>
+                <billingPeriod>MONTHLY</billingPeriod>
                 <recurringPrice>
                     <price>
                         <currency>USD</currency>
diff --git a/beatrix/src/test/resources/killbill-notification-test.tar.gz b/beatrix/src/test/resources/killbill-notification-test.tar.gz
index b84773c..9f65d95 100644
Binary files a/beatrix/src/test/resources/killbill-notification-test.tar.gz and b/beatrix/src/test/resources/killbill-notification-test.tar.gz differ
diff --git a/beatrix/src/test/resources/killbill-payment-test.tar.gz b/beatrix/src/test/resources/killbill-payment-test.tar.gz
index d73be8f..c89e0c3 100644
Binary files a/beatrix/src/test/resources/killbill-payment-test.tar.gz and b/beatrix/src/test/resources/killbill-payment-test.tar.gz differ

catalog/pom.xml 2(+1 -1)

diff --git a/catalog/pom.xml b/catalog/pom.xml
index cf25262..93130b2 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-catalog</artifactId>

currency/pom.xml 2(+1 -1)

diff --git a/currency/pom.xml b/currency/pom.xml
index 2bbcae4..fee8437 100644
--- a/currency/pom.xml
+++ b/currency/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index b49ed24..308e1c5 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-entitlement</artifactId>
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/block/DefaultBlockingChecker.java b/entitlement/src/main/java/com/ning/billing/entitlement/block/DefaultBlockingChecker.java
index 9d87e3c..e41a5e1 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/block/DefaultBlockingChecker.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/block/DefaultBlockingChecker.java
@@ -77,6 +77,38 @@ public class DefaultBlockingChecker implements BlockingChecker {
         public boolean isBlockBilling() {
             return blockBilling;
         }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (!(o instanceof DefaultBlockingAggregator)) {
+                return false;
+            }
+
+            final DefaultBlockingAggregator that = (DefaultBlockingAggregator) o;
+
+            if (blockBilling != that.blockBilling) {
+                return false;
+            }
+            if (blockChange != that.blockChange) {
+                return false;
+            }
+            if (blockEntitlement != that.blockEntitlement) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = (blockChange ? 1 : 0);
+            result = 31 * result + (blockEntitlement ? 1 : 0);
+            result = 31 * result + (blockBilling ? 1 : 0);
+            return result;
+        }
     }
 
     private final SubscriptionBaseInternalApi subscriptionApi;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EntitlementUtils.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EntitlementUtils.java
index 113447c..87a20c7 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EntitlementUtils.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EntitlementUtils.java
@@ -34,6 +34,7 @@ import com.ning.billing.callcontext.InternalCallContext;
 import com.ning.billing.callcontext.InternalTenantContext;
 import com.ning.billing.clock.Clock;
 import com.ning.billing.entitlement.DefaultEntitlementService;
+import com.ning.billing.entitlement.EntitlementService;
 import com.ning.billing.entitlement.EventsStream;
 import com.ning.billing.entitlement.api.BlockingApiException;
 import com.ning.billing.entitlement.api.BlockingState;
@@ -94,7 +95,7 @@ public class EntitlementUtils {
 
         final BlockingAggregator currentState = getBlockingStateFor(state.getBlockedId(), state.getType(), context);
         if (previousState != null && currentState != null) {
-            postBlockingTransitionEvent(state.getId(), state.getEffectiveDate(), state.getBlockedId(), state.getType(), previousState, currentState, context);
+            postBlockingTransitionEvent(state.getId(), state.getEffectiveDate(), state.getBlockedId(), state.getType(), state.getService(), previousState, currentState, context);
         }
     }
 
@@ -127,7 +128,7 @@ public class EntitlementUtils {
     }
 
     private void postBlockingTransitionEvent(final UUID blockingStateId, final DateTime effectiveDate, final UUID blockableId, final BlockingStateType type,
-                                             final BlockingAggregator previousState, final BlockingAggregator currentState,
+                                             final String serviceName, final BlockingAggregator previousState, final BlockingAggregator currentState,
                                              final InternalCallContext context) {
         final boolean isTransitionToBlockedBilling = !previousState.isBlockBilling() && currentState.isBlockBilling();
         final boolean isTransitionToUnblockedBilling = previousState.isBlockBilling() && !currentState.isBlockBilling();
@@ -143,12 +144,18 @@ public class EntitlementUtils {
             recordFutureNotification(effectiveDate, notificationEvent, context);
         } else {
             // TODO Do we want to send a DefaultEffectiveEntitlementEvent for entitlement specific blocking states?
-            final BusEvent event = new DefaultBlockingTransitionInternalEvent(blockableId, type,
-                                                                              isTransitionToBlockedBilling, isTransitionToUnblockedBilling,
-                                                                              isTransitionToBlockedEntitlement, isTransitionToUnblockedEntitlement,
-                                                                              context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
 
-            postBusEvent(event);
+            // Don't post if nothing has changed for entitlement-service
+           if (! serviceName.equals(EntitlementService.ENTITLEMENT_SERVICE_NAME) || ! previousState.equals(currentState)) {
+                final BusEvent event = new DefaultBlockingTransitionInternalEvent(blockableId, type,
+                                                                                  isTransitionToBlockedBilling, isTransitionToUnblockedBilling,
+                                                                                  isTransitionToBlockedEntitlement, isTransitionToUnblockedEntitlement,
+                                                                                  context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
+                postBusEvent(event);
+           } else {
+               System.out.println("**********   SKIPPING EVENT ");
+           }
+
         }
     }
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/TestEntitlementUtils.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/TestEntitlementUtils.java
index 13be1fe..6f916e0 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/TestEntitlementUtils.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/TestEntitlementUtils.java
@@ -351,7 +351,7 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
         Assert.assertEquals(entitlementApi.getEntitlementForId(addOnEntitlement.getId(), callContext).getEffectiveEndDate(), addOn1CancellationDate);
         Assert.assertEquals(entitlementApi.getEntitlementForId(addOn2Entitlement.getId(), callContext).getEffectiveEndDate(), baseCancellationDate);
 
-        testListener.pushExpectedEvents(NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.BLOCK);
+        testListener.pushExpectedEvents(NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.BLOCK);
         clock.setDay(new LocalDate(2013, 10, 30));
         assertListenerStatus();
 

invoice/pom.xml 2(+1 -1)

diff --git a/invoice/pom.xml b/invoice/pom.xml
index dcb1ef9..9447396 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-invoice</artifactId>

jaxrs/pom.xml 2(+1 -1)

diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
index c5b0daf..7843efc 100644
--- a/jaxrs/pom.xml
+++ b/jaxrs/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-jaxrs</artifactId>

junction/pom.xml 2(+1 -1)

diff --git a/junction/pom.xml b/junction/pom.xml
index 57257e5..341ae2d 100644
--- a/junction/pom.xml
+++ b/junction/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-junction</artifactId>

NEWS 5(+5 -0)

diff --git a/NEWS b/NEWS
index 31f07c8..5771fee 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,11 @@
 0.8.7
     DDL: remove unused paid_through_date column
+    https://github.com/killbill/killbill/issues/130
+    https://github.com/killbill/killbill/issues/149
     Add API to retrieve deleted tags
+    Add search APIs for payments
+    Audit API optimizations
+    JDBI optimizations
     Update killbill-oss-parent to 0.5.9
 
 0.8.6

osgi/pom.xml 2(+1 -1)

diff --git a/osgi/pom.xml b/osgi/pom.xml
index 7188bb6..25c52cb 100644
--- a/osgi/pom.xml
+++ b/osgi/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi</artifactId>
diff --git a/osgi-bundles/bundles/jruby/pom.xml b/osgi-bundles/bundles/jruby/pom.xml
index 55285b5..762b0bf 100644
--- a/osgi-bundles/bundles/jruby/pom.xml
+++ b/osgi-bundles/bundles/jruby/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill-osgi-bundles</artifactId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-jruby</artifactId>
diff --git a/osgi-bundles/bundles/logger/pom.xml b/osgi-bundles/bundles/logger/pom.xml
index ad8a4bc..7f63a17 100644
--- a/osgi-bundles/bundles/logger/pom.xml
+++ b/osgi-bundles/bundles/logger/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-logger</artifactId>
diff --git a/osgi-bundles/bundles/pom.xml b/osgi-bundles/bundles/pom.xml
index 50f2924..cfa3841 100644
--- a/osgi-bundles/bundles/pom.xml
+++ b/osgi-bundles/bundles/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-all-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles</artifactId>
diff --git a/osgi-bundles/bundles/webconsolebranding/pom.xml b/osgi-bundles/bundles/webconsolebranding/pom.xml
index 7dc1a20..9949e75 100644
--- a/osgi-bundles/bundles/webconsolebranding/pom.xml
+++ b/osgi-bundles/bundles/webconsolebranding/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-webconsolebranding</artifactId>
diff --git a/osgi-bundles/defaultbundles/pom.xml b/osgi-bundles/defaultbundles/pom.xml
index cf2fab5..9f143a9 100644
--- a/osgi-bundles/defaultbundles/pom.xml
+++ b/osgi-bundles/defaultbundles/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-all-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-defaultbundles</artifactId>
diff --git a/osgi-bundles/libs/killbill/pom.xml b/osgi-bundles/libs/killbill/pom.xml
index 8c34c54..8262ae3 100644
--- a/osgi-bundles/libs/killbill/pom.xml
+++ b/osgi-bundles/libs/killbill/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-lib-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-lib-killbill</artifactId>
diff --git a/osgi-bundles/libs/pom.xml b/osgi-bundles/libs/pom.xml
index 529b949..96655f8 100644
--- a/osgi-bundles/libs/pom.xml
+++ b/osgi-bundles/libs/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-all-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-lib-bundles</artifactId>
diff --git a/osgi-bundles/libs/slf4j-osgi/pom.xml b/osgi-bundles/libs/slf4j-osgi/pom.xml
index 480680c..034552b 100644
--- a/osgi-bundles/libs/slf4j-osgi/pom.xml
+++ b/osgi-bundles/libs/slf4j-osgi/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-lib-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-lib-slf4j-osgi</artifactId>
diff --git a/osgi-bundles/pom.xml b/osgi-bundles/pom.xml
index 17b668a..2c98f63 100644
--- a/osgi-bundles/pom.xml
+++ b/osgi-bundles/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-all-bundles</artifactId>
diff --git a/osgi-bundles/tests/beatrix/pom.xml b/osgi-bundles/tests/beatrix/pom.xml
index 46ae16b..1e59723 100644
--- a/osgi-bundles/tests/beatrix/pom.xml
+++ b/osgi-bundles/tests/beatrix/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-test-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-test-beatrix</artifactId>
diff --git a/osgi-bundles/tests/payment/pom.xml b/osgi-bundles/tests/payment/pom.xml
index a6649d9..d2fad2f 100644
--- a/osgi-bundles/tests/payment/pom.xml
+++ b/osgi-bundles/tests/payment/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-test-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-test-payment</artifactId>
diff --git a/osgi-bundles/tests/pom.xml b/osgi-bundles/tests/pom.xml
index 1012727..3f888f0 100644
--- a/osgi-bundles/tests/pom.xml
+++ b/osgi-bundles/tests/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-all-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-test-bundles</artifactId>

overdue/pom.xml 2(+1 -1)

diff --git a/overdue/pom.xml b/overdue/pom.xml
index eddf2f1..d48c00f 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-overdue</artifactId>
diff --git a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
index 78fe7fe..01ad416 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
@@ -114,7 +114,6 @@ public class OverdueStateApplicator {
         this.bus = bus;
     }
 
-
     public void apply(final OverdueStateSet overdueStateSet, final BillingState billingState,
                       final Account account, final OverdueState previousOverdueState,
                       final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException {
@@ -170,7 +169,6 @@ public class OverdueStateApplicator {
         }
     }
 
-
     public void clear(final Account overdueable, final OverdueState previousOverdueState, final OverdueState clearState, final InternalCallContext context) throws OverdueException {
 
         log.debug("OverdueStateApplicator:clear : time = " + clock.getUTCNow() + ", previousState = " + previousOverdueState.getName());
@@ -260,13 +258,17 @@ public class OverdueStateApplicator {
 
             final UUID tenantId = nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT);
             for (final Entitlement cur : toBeCancelled) {
-                cur.cancelEntitlementWithDateOverrideBillingPolicy(new LocalDate(clock.getUTCNow(), account.getTimeZone()), actionPolicy, context.toCallContext(tenantId));
+                try {
+                    cur.cancelEntitlementWithDateOverrideBillingPolicy(new LocalDate(clock.getUTCNow(), account.getTimeZone()), actionPolicy, context.toCallContext(tenantId));
+                } catch (EntitlementApiException e) {
+                    // If subscription has already been cancelled, there is nothing to do so we can ignore
+                    if (e.getCode() != ErrorCode.SUB_CANCEL_BAD_STATE.getCode()) {
+                        throw new OverdueException(e);
+                    }
+                }
             }
         } catch (EntitlementApiException e) {
-            // If subscription has already been cancelled, there is nothing to do so we can ignore
-            if (e.getCode() != ErrorCode.SUB_CANCEL_BAD_STATE.getCode()) {
-                throw new OverdueException(e);
-            }
+            throw new OverdueException(e);
         }
     }
 

payment/pom.xml 2(+1 -1)

diff --git a/payment/pom.xml b/payment/pom.xml
index 292bd92..9692ffb 100644
--- a/payment/pom.xml
+++ b/payment/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-payment</artifactId>

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index 332a2da..4050a9a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
         <version>0.5.10</version>
     </parent>
     <artifactId>killbill</artifactId>
-    <version>0.8.7-SNAPSHOT</version>
+    <version>0.8.8-SNAPSHOT</version>
     <packaging>pom</packaging>
     <name>killbill</name>
     <description>Library for managing recurring subscriptions and the associated billing</description>

server/pom.xml 2(+1 -1)

diff --git a/server/pom.xml b/server/pom.xml
index 3ae175a..9ba7701 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-server</artifactId>
diff --git a/server/src/main/resources/update-checker/killbill-server-update-list.properties b/server/src/main/resources/update-checker/killbill-server-update-list.properties
index 311c8be..ebfb4e0 100644
--- a/server/src/main/resources/update-checker/killbill-server-update-list.properties
+++ b/server/src/main/resources/update-checker/killbill-server-update-list.properties
@@ -1,27 +1,71 @@
 ## Top level keys
 # general.notice = This notice should rarely, if ever, be used as everyone will see it
 
-## 0.7.2 -- latest release
+## 0.8.7 -- latest release
+0.8.7.updates           =
+0.8.7.notices           = This is the latest GA release.
+0.8.7.release-notes     = http://kill-bill.org
+
+## 0.8.6
+0.8.6.updates           = 0.8.7
+0.8.6.notices           = We recommend upgrading to 0.8.7, our latest GA release.
+0.8.6.release-notes     = http://kill-bill.org
+
+## 0.8.5
+0.8.5.updates           = 0.8.7
+0.8.5.notices           = We recommend upgrading to 0.8.7, our latest GA release.
+0.8.5.release-notes     = http://kill-bill.org
+
+## 0.8.4
+0.8.4.updates           = 0.8.7
+0.8.4.notices           = We recommend upgrading to 0.8.7, our latest GA release.
+0.8.4.release-notes     = http://kill-bill.org
+
+## 0.8.3
+0.8.3.updates           = 0.8.7
+0.8.3.notices           = We recommend upgrading to 0.8.7, our latest GA release.
+0.8.3.release-notes     = http://kill-bill.org
+
+## 0.8.2
+0.8.2.updates           = 0.8.7
+0.8.2.notices           = We recommend upgrading to 0.8.7, our latest GA release.
+0.8.2.release-notes     = http://kill-bill.org
+
+## 0.8.1
+0.8.1.updates           = 0.8.7
+0.8.1.notices           = We recommend upgrading to 0.8.7, our latest GA release.
+0.8.1.release-notes     = http://kill-bill.org
+
+## 0.8.0
+0.8.0.updates           = 0.8.7
+0.8.0.notices           = We recommend upgrading to 0.8.7, our latest GA release.
+0.8.0.release-notes     = http://kill-bill.org
+
+### 0.7.x series ###
+
+## 0.7.2
 0.7.2.updates           =
-0.7.2.notices           = This is the latest GA release.
+0.7.2.notices           = We recommend upgrading to 0.8.7, our latest GA release.
 0.7.2.release-notes     = http://kill-bill.org
 
 ## 0.7.1
 0.7.1.updates           = 0.7.2
-0.7.1.notices           = We recommend upgrading to 0.7.2, our latest GA release.
+0.7.1.notices           = We recommend upgrading to 0.8.7, our latest GA release.
 0.7.1.release-notes     = http://kill-bill.org
 
 ## 0.7.0
 0.7.0.updates           = 0.7.2
-0.7.0.notices           = We recommend upgrading to 0.7.2, our latest GA release.
+0.7.0.notices           = We recommend upgrading to 0.8.7, our latest GA release.
 0.7.0.release-notes     = http://kill-bill.org
 
+### 0.6.x series ###
+
 ## 0.6.17
 0.6.17.updates           =
-0.6.17.notices           = We recommend upgrading to 0.7.2, our latest GA release.
+0.6.17.notices           = We recommend upgrading to 0.8.7, our latest GA release.
 0.6.17.release-notes     = http://kill-bill.org
 
 ## 0.6.16
 0.6.16.updates           = 0.6.17
-0.6.16.notices           = We recommend upgrading to 0.7.2, our latest GA release.
+0.6.16.notices           = We recommend upgrading to 0.8.7, our latest GA release.
 0.6.16.release-notes     = http://kill-bill.org
diff --git a/subscription/pom.xml b/subscription/pom.xml
index dacdd78..eef186c 100644
--- a/subscription/pom.xml
+++ b/subscription/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-subscription</artifactId>
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java b/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
index d9202e9..62d2acc 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
@@ -231,7 +231,9 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
         dao.cancelSubscription(subscription, cancelEvent, internalCallContext, 0);
         subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalogService.getFullCatalog());
 
-        cancelAddOnsIfRequired(subscription, effectiveDate, internalCallContext);
+        if (subscription.getCategory() == ProductCategory.BASE) {
+            cancelAddOnsIfRequired(subscription, effectiveDate, internalCallContext);
+        }
 
         final boolean isImmediate = subscription.getState() == EntitlementState.CANCELLED;
         return isImmediate;
@@ -384,7 +386,9 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
         dao.changePlan(subscription, changeEvents, internalCallContext);
         subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalogService.getFullCatalog());
 
-        cancelAddOnsIfRequired(subscription, effectiveDate, internalCallContext);
+        if (subscription.getCategory() == ProductCategory.BASE) {
+            cancelAddOnsIfRequired(subscription, effectiveDate, internalCallContext);
+        }
 
         final boolean isChangeImmediate = subscription.getCurrentPlan().getProduct().getName().equals(newProductName) &&
                                           subscription.getCurrentPlan().getBillingPeriod() == newBillingPeriod;

tenant/pom.xml 2(+1 -1)

diff --git a/tenant/pom.xml b/tenant/pom.xml
index 5c8f43a..b84cc64 100644
--- a/tenant/pom.xml
+++ b/tenant/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-tenant</artifactId>

usage/pom.xml 2(+1 -1)

diff --git a/usage/pom.xml b/usage/pom.xml
index 91303de..eb83d8b 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-usage</artifactId>

util/pom.xml 2(+1 -1)

diff --git a/util/pom.xml b/util/pom.xml
index fafbec2..7750249 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -12,7 +12,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.8.7-SNAPSHOT</version>
+        <version>0.8.8-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-util</artifactId>