Details
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java
index 5223992..899b4a5 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java
@@ -59,6 +59,10 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
private InvoiceItemList reconcileInvoiceItems(final UUID invoiceId, final InvoiceItemList currentInvoiceItems,
final InvoiceItemList existingInvoiceItems) {
+ if (existingInvoiceItems == null) {
+ return currentInvoiceItems;
+ }
+
InvoiceItemList currentItems = new InvoiceItemList();
for (final InvoiceItem item : currentInvoiceItems) {
currentItems.add(new DefaultInvoiceItem(item, invoiceId));
@@ -80,7 +84,6 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
}
}
}
-
existingItems.removeAll(existingItemsToRemove);
// remove cancelling pairs of invoice items
@@ -88,7 +91,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
// add existing items that aren't covered by current items as credit items
for (final InvoiceItem existingItem : existingItems) {
- currentItems.add(existingItem.asCredit(invoiceId));
+ currentItems.add(existingItem.asCredit(existingItem.getInvoiceId()));
}
return currentItems;
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
index ce7a429..f483773 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
@@ -91,15 +91,6 @@ getUnpaidInvoicesByAccountId() ::= <<
ORDER BY i.target_date ASC;
>>
-getAccountBalance() ::= <<
- SELECT SUM(iis.total_amount) AS amount_invoiced, SUM(ips.total_paid) AS amount_paid
- FROM invoices i
- LEFT JOIN invoice_payment_summary ips ON i.id = ips.invoice_id
- LEFT JOIN invoice_item_summary iis ON i.id = iis.invoice_id
- WHERE i.account_id = :accountId
- GROUP BY i.account_id;
->>
-
test() ::= <<
SELECT 1
FROM invoices;
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
index 2dd88cc..4779495 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
@@ -21,6 +21,7 @@ import static org.testng.Assert.fail;
import java.io.IOException;
+import com.ning.billing.invoice.tests.InvoicingTestBase;
import org.apache.commons.io.IOUtils;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
@@ -32,7 +33,7 @@ import com.ning.billing.invoice.glue.InvoiceModuleWithEmbeddedDb;
import com.ning.billing.util.bus.BusService;
import com.ning.billing.util.bus.DefaultBusService;
-public abstract class InvoiceDaoTestBase {
+public abstract class InvoiceDaoTestBase extends InvoicingTestBase {
protected InvoiceDao invoiceDao;
protected InvoiceItemSqlDao invoiceItemDao;
protected InvoicePaymentSqlDao invoicePaymentDao;
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
index 8ce7a26..66ad993 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
@@ -16,13 +16,31 @@
package com.ning.billing.invoice.dao;
+import com.ning.billing.catalog.DefaultPrice;
+import com.ning.billing.catalog.MockInternationalPrice;
+import com.ning.billing.catalog.MockPlan;
+import com.ning.billing.catalog.MockPlanPhase;
+import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.entitlement.api.billing.BillingEvent;
+import com.ning.billing.entitlement.api.billing.BillingModeType;
+import com.ning.billing.entitlement.api.billing.DefaultBillingEvent;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionTransition;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceItem;
import com.ning.billing.invoice.api.InvoicePayment;
+import com.ning.billing.invoice.model.BillingEventSet;
import com.ning.billing.invoice.model.DefaultInvoice;
+import com.ning.billing.invoice.model.DefaultInvoiceGenerator;
import com.ning.billing.invoice.model.DefaultInvoiceItem;
import com.ning.billing.invoice.model.DefaultInvoicePayment;
+import com.ning.billing.invoice.model.InvoiceGenerator;
+import com.ning.billing.invoice.model.InvoiceItemList;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.DefaultClock;
import org.joda.time.DateTime;
@@ -35,6 +53,7 @@ import java.util.List;
import java.util.UUID;
import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
@Test(groups = {"invoicing", "invoicing-invoiceDao"})
public class InvoiceDaoTests extends InvoiceDaoTestBase {
@@ -448,4 +467,189 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
invoices = invoiceDao.getUnpaidInvoicesByAccountId(accountId, upToDate);
assertEquals(invoices.size(), 2);
}
+
+ /*
+ *
+ * this test verifies that immediate changes give the correct results
+ *
+ */
+ @Test
+ public void testInvoiceGenerationForImmediateChanges() {
+ InvoiceGenerator generator = new DefaultInvoiceGenerator();
+
+ UUID accountId = UUID.randomUUID();
+ InvoiceItemList invoiceItemList = new InvoiceItemList();
+ DateTime targetDate = new DateTime(2011, 2, 16, 0, 0, 0, 0);
+
+ // generate first invoice
+ DefaultPrice price1 = new DefaultPrice(TEN, Currency.USD);
+ MockInternationalPrice recurringPrice = new MockInternationalPrice(price1);
+ MockPlanPhase phase1 = new MockPlanPhase(recurringPrice, null, BillingPeriod.MONTHLY, PhaseType.TRIAL);
+ MockPlan plan1 = new MockPlan(phase1);
+
+ Subscription subscription = new MockSubscription();
+ DateTime effectiveDate1 = new DateTime(2011, 2, 1, 0, 0, 0, 0);
+ BillingEvent event1 = new DefaultBillingEvent(subscription, effectiveDate1, plan1, phase1, null,
+ recurringPrice, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
+ "testEvent1");
+
+ BillingEventSet events = new BillingEventSet();
+ events.add(event1);
+
+ Invoice invoice1 = generator.generateInvoice(accountId, events, invoiceItemList, targetDate, Currency.USD);
+ assertEquals(invoice1.getBalance(), TEN);
+ invoiceItemList.addAll(invoice1.getInvoiceItems());
+
+ // generate second invoice
+ DefaultPrice price2 = new DefaultPrice(TWENTY, Currency.USD);
+ MockInternationalPrice recurringPrice2 = new MockInternationalPrice(price2);
+ MockPlanPhase phase2 = new MockPlanPhase(recurringPrice, null, BillingPeriod.MONTHLY, PhaseType.TRIAL);
+ MockPlan plan2 = new MockPlan(phase2);
+
+ DateTime effectiveDate2 = new DateTime(2011, 2, 15, 0, 0, 0, 0);
+ BillingEvent event2 = new DefaultBillingEvent(subscription, effectiveDate2, plan2, phase2, null,
+ recurringPrice2, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
+ "testEvent2");
+ events.add(event2);
+
+ // second invoice should be for one half (14/28 days) the difference between the rate plans
+ // this is a temporary state, since it actually contains an adjusting item that properly belong to invoice 1
+ Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceItemList, targetDate, Currency.USD);
+ assertEquals(invoice2.getBalance(), FIVE);
+ invoiceItemList.addAll(invoice2.getInvoiceItems());
+
+ invoiceDao.create(invoice1);
+ invoiceDao.create(invoice2);
+
+ Invoice savedInvoice1 = invoiceDao.getById(invoice1.getId());
+ assertEquals(savedInvoice1.getTotalAmount(), ZERO);
+
+ Invoice savedInvoice2 = invoiceDao.getById(invoice2.getId());
+ assertEquals(savedInvoice2.getTotalAmount(), FIFTEEN);
+ }
+
+ @Test
+ public void testInvoiceForFreeTrial() {
+ DefaultPrice price = new DefaultPrice(BigDecimal.ZERO, Currency.USD);
+ MockInternationalPrice recurringPrice = new MockInternationalPrice(price);
+ MockPlanPhase phase = new MockPlanPhase(recurringPrice, null);
+ MockPlan plan = new MockPlan(phase);
+
+ Subscription subscription = new MockSubscription();
+ DateTime effectiveDate = buildDateTime(2011, 1, 1);
+
+ BillingEvent event = new DefaultBillingEvent(subscription, effectiveDate, plan, phase, null,
+ recurringPrice, BillingPeriod.MONTHLY, 15, BillingModeType.IN_ADVANCE,
+ "testEvent");
+ BillingEventSet events = new BillingEventSet();
+ events.add(event);
+
+ DateTime targetDate = buildDateTime(2011, 1, 15);
+ InvoiceGenerator generator = new DefaultInvoiceGenerator();
+ Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD);
+ assertEquals(invoice.getNumberOfItems(), 1);
+ assertEquals(invoice.getTotalAmount().compareTo(ZERO), 0);
+ }
+
+ @Test
+ public void testInvoiceForEmptyEventSet() {
+ InvoiceGenerator generator = new DefaultInvoiceGenerator();
+ BillingEventSet events = new BillingEventSet();
+ Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, new DateTime(), Currency.USD);
+ assertNull(invoice);
+ }
+
+ private class MockSubscription implements Subscription {
+ private UUID subscriptionId = UUID.randomUUID();
+
+ @Override
+ public void cancel(DateTime requestedDate, boolean eot) throws EntitlementUserApiException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void uncancel() throws EntitlementUserApiException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void changePlan(String productName, BillingPeriod term, String planSet, DateTime requestedDate) throws EntitlementUserApiException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void pause() throws EntitlementUserApiException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void resume() throws EntitlementUserApiException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public UUID getId() {
+ return subscriptionId;
+ }
+
+ @Override
+ public UUID getBundleId() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SubscriptionState getState() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DateTime getStartDate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DateTime getEndDate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Plan getCurrentPlan() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getCurrentPriceList() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public PlanPhase getCurrentPhase() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DateTime getChargedThroughDate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DateTime getPaidThroughDate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<SubscriptionTransition> getActiveTransitions() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<SubscriptionTransition> getAllTransitions() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SubscriptionTransition getPendingTransition() {
+ throw new UnsupportedOperationException();
+ }
+ }
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
index c64ae04..11c3b1d 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
@@ -16,24 +16,17 @@
package com.ning.billing.invoice.tests;
-import com.ning.billing.catalog.DefaultPrice;
import com.ning.billing.catalog.MockCatalog;
-import com.ning.billing.catalog.MockInternationalPrice;
-import com.ning.billing.catalog.MockPlan;
-import com.ning.billing.catalog.MockPlanPhase;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.entitlement.api.billing.BillingEvent;
import com.ning.billing.entitlement.api.billing.BillingModeType;
import com.ning.billing.entitlement.api.billing.DefaultBillingEvent;
-import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionData;
import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceItem;
import com.ning.billing.invoice.model.BillingEventSet;
@@ -45,14 +38,11 @@ import org.joda.time.DateTime;
import org.testng.annotations.Test;
import java.math.BigDecimal;
-import java.util.List;
import java.util.UUID;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
@Test(groups = {"fast", "invoicing", "invoiceGenerator"})
public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
@@ -437,82 +427,6 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
testInvoiceGeneration(events, invoiceItems, buildDateTime(2011, 10, 10), 1, expectedAmount);
}
- /*
- *
- * this test verifies that immediate changes give the correct results
- *
- */
- @Test
- public void testInvoiceGenerationForImmediateChanges() {
- UUID accountId = UUID.randomUUID();
- InvoiceItemList invoiceItemList = new InvoiceItemList();
- DateTime targetDate = new DateTime(2011, 2, 16, 0, 0, 0, 0);
-
- // generate first invoice
- DefaultPrice price1 = new DefaultPrice(TEN, Currency.USD);
- MockInternationalPrice recurringPrice = new MockInternationalPrice(price1);
- MockPlanPhase phase1 = new MockPlanPhase(recurringPrice, null, BillingPeriod.MONTHLY, PhaseType.TRIAL);
- MockPlan plan1 = new MockPlan(phase1);
-
- Subscription subscription = new MockSubscription();
- DateTime effectiveDate1 = new DateTime(2011, 2, 1, 0, 0, 0, 0);
- BillingEvent event1 = new DefaultBillingEvent(subscription, effectiveDate1, plan1, phase1, null,
- recurringPrice, BillingPeriod.MONTHLY, 15, BillingModeType.IN_ADVANCE,
- "testEvent");
-
- BillingEventSet events = new BillingEventSet();
- events.add(event1);
-
- Invoice invoice1 = generator.generateInvoice(accountId, events, invoiceItemList, targetDate, Currency.USD);
- assertEquals(invoice1.getBalance(), TEN);
- invoiceItemList.addAll(invoice1.getInvoiceItems());
-
- // generate second invoice
- DefaultPrice price2 = new DefaultPrice(TWENTY, Currency.USD);
- MockInternationalPrice recurringPrice2 = new MockInternationalPrice(price2);
- MockPlanPhase phase2 = new MockPlanPhase(recurringPrice, null, BillingPeriod.MONTHLY, PhaseType.TRIAL);
- MockPlan plan2 = new MockPlan(phase2);
-
- DateTime effectiveDate2 = new DateTime(2011, 2, 15, 0, 0, 0, 0);
- BillingEvent event2 = new DefaultBillingEvent(subscription, effectiveDate2, plan2, phase2, null,
- recurringPrice, BillingPeriod.MONTHLY, 15, BillingModeType.IN_ADVANCE,
- "testEvent");
- events.add(event2);
-
- Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceItemList, targetDate, Currency.USD);
- assertEquals(invoice1.getBalance(), FIFTEEN);
- invoiceItemList.addAll(invoice2.getInvoiceItems());
-
- fail();
- }
-
- @Test
- public void testInvoiceForFreeTrial() {
- DefaultPrice price = new DefaultPrice(BigDecimal.ZERO, Currency.USD);
- MockInternationalPrice recurringPrice = new MockInternationalPrice(price);
- MockPlanPhase phase = new MockPlanPhase(recurringPrice, null);
- MockPlan plan = new MockPlan(phase);
-
- Subscription subscription = new MockSubscription();
- DateTime effectiveDate = new DateTime(2011, 1, 1, 0, 0, 0, 0);
-
- BillingEvent event = new DefaultBillingEvent(subscription, effectiveDate, plan, phase, null,
- recurringPrice, BillingPeriod.MONTHLY, 15, BillingModeType.IN_ADVANCE,
- "testEvent");
-
- fail();
- }
-
- @Test
- public void testInvoiceForNoCurrentItems() {
- fail();
- }
-
- @Test
- public void testInvoiceForEmptyEventSet() {
- fail();
- }
-
private DefaultBillingEvent createBillingEvent(final UUID subscriptionId, final DateTime startDate,
final Plan plan, final PlanPhase planPhase,
final BigDecimal rate, final int billCycleDay) {
@@ -545,100 +459,6 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
existingInvoiceItems.addAll(invoice.getInvoiceItems());
assertEquals(invoice.getTotalAmount(), expectedAmount);
- }
-
- private class MockSubscription implements Subscription {
- private UUID subscriptionId = UUID.randomUUID();
-
- @Override
- public void cancel(DateTime requestedDate, boolean eot) throws EntitlementUserApiException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void uncancel() throws EntitlementUserApiException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void changePlan(String productName, BillingPeriod term, String planSet, DateTime requestedDate) throws EntitlementUserApiException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void pause() throws EntitlementUserApiException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void resume() throws EntitlementUserApiException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public UUID getId() {
- return subscriptionId;
- }
-
- @Override
- public UUID getBundleId() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public SubscriptionState getState() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public DateTime getStartDate() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public DateTime getEndDate() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Plan getCurrentPlan() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getCurrentPriceList() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public PlanPhase getCurrentPhase() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public DateTime getChargedThroughDate() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public DateTime getPaidThroughDate() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public List<SubscriptionTransition> getActiveTransitions() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public List<SubscriptionTransition> getAllTransitions() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public SubscriptionTransition getPendingTransition() {
- throw new UnsupportedOperationException();
- }
}
// TODO: Jeff C -- how do we ensure that an annual add-on is properly aligned *at the end* with the base plan?
}
\ No newline at end of file