Details
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/tree/Item.java b/invoice/src/main/java/org/killbill/billing/invoice/tree/Item.java
index 4899f0c..f67b24d 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/tree/Item.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/tree/Item.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2014 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
*
@@ -184,7 +186,9 @@ public class Item {
final InvoiceItem otherItem = other.toInvoiceItem();
- return !id.equals(otherItem.getId()) &&
+ // See https://github.com/killbill/killbill/issues/286
+ return otherItem != null &&
+ !id.equals(otherItem.getId()) &&
// Finally, for the tricky part... In case of complete repairs, the new invoiceItem will always meet all of the
// following conditions: same type, subscription, start date. Depending on the catalog configuration, the end
// date check could also match (e.g. repair from annual to monthly). For that scenario, we need to default
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/tree/ItemsInterval.java b/invoice/src/main/java/org/killbill/billing/invoice/tree/ItemsInterval.java
index 8047cd5..eeeeba7 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/tree/ItemsInterval.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/tree/ItemsInterval.java
@@ -1,7 +1,9 @@
/*
* Copyright 2010-2014 Ning, Inc.
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * 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:
*
@@ -27,6 +29,7 @@ import java.util.Map;
import java.util.UUID;
import org.joda.time.LocalDate;
+import org.killbill.billing.invoice.api.InvoiceItem;
import org.killbill.billing.invoice.tree.Item.ItemAction;
import com.google.common.base.Preconditions;
@@ -227,15 +230,20 @@ public class ItemsInterval {
* @param mergeMode mode to consider.
* @return
*/
- private Item createNewItem(LocalDate startDate, LocalDate endDate, final boolean mergeMode) {
+ private Item createNewItem(final LocalDate startDate, final LocalDate endDate, final boolean mergeMode) {
final Item item = getResultingItem(mergeMode);
if (item == null) {
return null;
}
- final Item result = new Item(item.toProratedInvoiceItem(startDate, endDate), targetInvoiceId, item.getAction());
- if (item.getAction() == ItemAction.CANCEL && result != null) {
+ final InvoiceItem proratedInvoiceItem = item.toProratedInvoiceItem(startDate, endDate);
+ if (proratedInvoiceItem == null) {
+ return null;
+ }
+
+ final Item result = new Item(proratedInvoiceItem, targetInvoiceId, item.getAction());
+ if (item.getAction() == ItemAction.CANCEL) {
item.incrementCurrentRepairedAmount(result.getAmount());
}
return result;
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/tree/TestSubscriptionItemTree.java b/invoice/src/test/java/org/killbill/billing/invoice/tree/TestSubscriptionItemTree.java
index f81e093..f9a86d1 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/tree/TestSubscriptionItemTree.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/tree/TestSubscriptionItemTree.java
@@ -855,6 +855,32 @@ public class TestSubscriptionItemTree extends InvoiceTestSuiteNoDB {
}
}
+ @Test(groups = "fast", description = "https://github.com/killbill/killbill/issues/286")
+ public void testMaxedOutProRation() {
+ final LocalDate startDate = new LocalDate(2014, 1, 1);
+ final LocalDate cancelDate = new LocalDate(2014, 1, 25);
+ final LocalDate endDate = new LocalDate(2014, 2, 1);
+
+ final BigDecimal monthlyRate1 = new BigDecimal("12.00");
+ final BigDecimal monthlyAmount1 = monthlyRate1;
+
+ final SubscriptionItemTree tree = new SubscriptionItemTree(subscriptionId, invoiceId);
+
+ final InvoiceItem existing1 = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, monthlyAmount1, monthlyRate1, currency);
+ tree.addItem(existing1);
+ // Fully item adjust the recurring item
+ final InvoiceItem existingItemAdj1 = new ItemAdjInvoiceItem(existing1, startDate, monthlyRate1.negate(), currency);
+ tree.addItem(existingItemAdj1);
+ tree.flatten(true);
+
+ final InvoiceItem proposed1 = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, cancelDate, monthlyAmount1, monthlyRate1, currency);
+ tree.mergeProposedItem(proposed1);
+ tree.buildForMerge();
+
+ final List<InvoiceItem> expectedResult = Lists.newLinkedList();
+ verifyResult(tree.getView(), expectedResult);
+ }
+
private void verifyResult(final List<InvoiceItem> result, final List<InvoiceItem> expectedResult) {
assertEquals(result.size(), expectedResult.size());
for (int i = 0; i < expectedResult.size(); i++) {