killbill-memoizeit

Fix credit endpoint

6/29/2012 8:51:53 PM

Details

diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java b/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java
index d95f56d..a3ef34c 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java
@@ -51,7 +51,10 @@ public interface InvoiceUserApi {
     public InvoiceItem getCreditById(UUID creditId) throws InvoiceApiException;
 
     public InvoiceItem insertCredit(UUID accountId, BigDecimal amount, DateTime effectiveDate,
-                                    Currency currency, CallContext context) throws InvoiceApiException;
+            Currency currency, CallContext context) throws InvoiceApiException;
+
+    public InvoiceItem insertCreditForInvoice(UUID accountId, UUID invoiceId, BigDecimal amount, DateTime effectiveDate,
+            Currency currency, CallContext context) throws InvoiceApiException;
 
     public String getInvoiceAsHTML(UUID invoiceId) throws AccountApiException, IOException, InvoiceApiException;
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java b/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java
index 4245ba8..88d67fd 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java
@@ -115,10 +115,18 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
     @Override
     public InvoiceItem insertCredit(final UUID accountId, final BigDecimal amount, final DateTime effectiveDate,
                                     final Currency currency, final CallContext context) throws InvoiceApiException {
-        return dao.insertCredit(accountId, amount, effectiveDate, currency, context);
+        return dao.insertCredit(accountId, null, amount, effectiveDate, currency, context);
     }
 
     @Override
+    public InvoiceItem insertCreditForInvoice(UUID accountId, UUID invoiceId,
+            BigDecimal amount, DateTime effectiveDate, Currency currency,
+            CallContext context) throws InvoiceApiException {
+        return dao.insertCredit(accountId, invoiceId, amount, effectiveDate, currency, context);
+    }
+
+
+    @Override
     public String getInvoiceAsHTML(final UUID invoiceId) throws AccountApiException, IOException, InvoiceApiException {
         final Invoice invoice = getInvoice(invoiceId);
         if (invoice == null) {
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index 8af5a92..dea44c3 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -39,6 +39,7 @@ import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoiceItemType;
 import com.ning.billing.invoice.api.InvoicePayment;
+import com.ning.billing.invoice.model.CreditAdjInvoiceItem;
 import com.ning.billing.invoice.model.CreditBalanceAdjInvoiceItem;
 import com.ning.billing.invoice.model.DefaultInvoice;
 import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
@@ -211,21 +212,32 @@ public class DefaultInvoiceDao implements InvoiceDao {
 
                 BigDecimal accountBalance = BigDecimal.ZERO;
                 List<Invoice> invoices = getAllInvoicesByAccountFromTransaction(accountId, transactional);
-                List<InvoiceItem> creditBalanceItems = new LinkedList<InvoiceItem>();
                 for (Invoice cur : invoices) {
                     accountBalance = accountBalance.add(cur.getBalance());
-                    creditBalanceItems.addAll(cur.getInvoiceItems(CreditBalanceAdjInvoiceItem.class));
                 }
-                BigDecimal cbaTotal = BigDecimal.ZERO;
-                for (InvoiceItem cur : creditBalanceItems) {
-                    cbaTotal = cbaTotal.add(cur.getAmount());
+                return accountBalance;
+            }
+        });
+    }
+
+    @Override
+    public BigDecimal getAccountCBA(final UUID accountId) {
+        return invoiceSqlDao.inTransaction(new Transaction<BigDecimal, InvoiceSqlDao>() {
+            @Override
+            public BigDecimal inTransaction(final InvoiceSqlDao transactional, final TransactionStatus status) throws Exception {
+
+                BigDecimal cba = BigDecimal.ZERO;
+                List<Invoice> invoices = getAllInvoicesByAccountFromTransaction(accountId, transactional);
+                for (Invoice cur : invoices) {
+                    cba = cba.add(cur.getCBAAmount());
                 }
-                return accountBalance.add(cbaTotal.negate());
+                return cba;
             }
         });
     }
 
 
+
     @Override
     public void notifyOfPaymentAttempt(final InvoicePayment invoicePayment, final CallContext context) {
         invoicePaymentSqlDao.inTransaction(new Transaction<Void, InvoicePaymentSqlDao>() {
@@ -344,18 +356,26 @@ public class DefaultInvoiceDao implements InvoiceDao {
         return invoiceItemSqlDao.getById(creditId.toString());
     }
 
-    // TODO: make this transactional
     @Override
-    public InvoiceItem insertCredit(final UUID accountId, final BigDecimal amount,
-                                    final DateTime effectiveDate, final Currency currency,
-                                    final CallContext context) {
-        final Invoice invoice = new DefaultInvoice(accountId, effectiveDate, effectiveDate, currency);
-        invoiceSqlDao.create(invoice, context);
-
-        final InvoiceItem credit = new CreditBalanceAdjInvoiceItem(invoice.getId(), accountId, effectiveDate, amount, currency);
-        invoiceItemSqlDao.create(credit, context);
+    public InvoiceItem insertCredit(final UUID accountId, final UUID invoiceId, final BigDecimal amount,
+            final DateTime effectiveDate, final Currency currency,
+            final CallContext context) {
 
-        return credit;
+        return invoiceSqlDao.inTransaction(new Transaction<InvoiceItem, InvoiceSqlDao>() {
+            @Override
+            public InvoiceItem inTransaction(final InvoiceSqlDao transactional, final TransactionStatus status) throws Exception {
+                UUID invoiceIdForRefund = invoiceId;
+                if (invoiceIdForRefund == null) {
+                    final Invoice invoiceForRefund = new DefaultInvoice(accountId, effectiveDate, effectiveDate, currency);
+                    transactional.create(invoiceForRefund, context);
+                    invoiceIdForRefund = invoiceForRefund.getId();
+                }
+                final InvoiceItem credit = new CreditAdjInvoiceItem(invoiceIdForRefund, accountId, effectiveDate, amount, currency);
+                InvoiceItemSqlDao transInvoiceItemDao = transactional.become(InvoiceItemSqlDao.class);
+                transInvoiceItemDao.create(credit, context);
+                return credit;
+            }
+        });
     }
 
     @Override
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
index 888295a..8d3c1a8 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
@@ -31,6 +31,7 @@ import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.callcontext.CallContext;
 
 public interface InvoiceDao {
+
     void create(Invoice invoice, CallContext context);
 
     Invoice getById(final UUID id);
@@ -51,6 +52,8 @@ public interface InvoiceDao {
 
     BigDecimal getAccountBalance(final UUID accountId);
 
+    public BigDecimal getAccountCBA(final UUID accountId);
+
     List<Invoice> getUnpaidInvoicesByAccountId(final UUID accountId, final DateTime upToDate);
 
     void test();
@@ -75,7 +78,8 @@ public interface InvoiceDao {
 
     InvoiceItem getCreditById(final UUID creditId) throws InvoiceApiException;
 
-    InvoiceItem insertCredit(final UUID accountId, final BigDecimal amount,
+    InvoiceItem insertCredit(final UUID accountId, final UUID invoiceId, final BigDecimal amount,
                              final DateTime effectiveDate, final Currency currency,
                              final CallContext context);
+
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
index 6fd4af2..bb25497 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
@@ -198,7 +198,7 @@ public class DefaultInvoice extends EntityBase implements Invoice {
     }
     @Override
     public BigDecimal getBalance() {
-        final BigDecimal balance = getChargedAmount().add(getTotalAdjAmount()).subtract(getPaidAmount()).subtract(getCBAAmount());
+        final BigDecimal balance = getChargedAmount().add(getTotalAdjAmount()).subtract(getPaidAmount());;
         return balance;
     }
 
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 a5bca99..36d42fd 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
@@ -45,10 +45,14 @@ import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoicePayment;
+import com.ning.billing.invoice.model.CreditAdjInvoiceItem;
+import com.ning.billing.invoice.model.CreditBalanceAdjInvoiceItem;
 import com.ning.billing.invoice.model.DefaultInvoice;
 import com.ning.billing.invoice.model.DefaultInvoicePayment;
 import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
 import com.ning.billing.invoice.model.RecurringInvoiceItem;
+import com.ning.billing.invoice.model.RefundAdjInvoiceItem;
+import com.ning.billing.invoice.model.RepairAdjInvoiceItem;
 import com.ning.billing.junction.api.BillingEventSet;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
@@ -95,7 +99,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         final DateTime startDate = new DateTime(2010, 1, 1, 0, 0, 0, 0);
         final DateTime endDate = new DateTime(2010, 4, 1, 0, 0, 0, 0);
         final InvoiceItem invoiceItem = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, "test plan", "test phase", startDate, endDate,
-                                                                 new BigDecimal("21.00"), new BigDecimal("7.00"), Currency.USD);
+                new BigDecimal("21.00"), new BigDecimal("7.00"), Currency.USD);
 
         invoice.addInvoiceItem(invoiceItem);
         invoiceDao.create(invoice, context);
@@ -185,19 +189,19 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         DateTime endDate = startDate.plusMonths(1);
 
         final RecurringInvoiceItem item1 = new RecurringInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId1, "test plan", "test A", startDate, endDate,
-                                                                    rate1, rate1, Currency.USD);
+                rate1, rate1, Currency.USD);
         invoiceItemSqlDao.create(item1, context);
 
         final RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId2, "test plan", "test B", startDate, endDate,
-                                                                    rate2, rate2, Currency.USD);
+                rate2, rate2, Currency.USD);
         invoiceItemSqlDao.create(item2, context);
 
         final RecurringInvoiceItem item3 = new RecurringInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId3, "test plan", "test C", startDate, endDate,
-                                                                    rate3, rate3, Currency.USD);
+                rate3, rate3, Currency.USD);
         invoiceItemSqlDao.create(item3, context);
 
         final RecurringInvoiceItem item4 = new RecurringInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId4, "test plan", "test D", startDate, endDate,
-                                                                    rate4, rate4, Currency.USD);
+                rate4, rate4, Currency.USD);
         invoiceItemSqlDao.create(item4, context);
 
         // Create invoice 2 (subscriptions 1-3)
@@ -210,15 +214,15 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         endDate = startDate.plusMonths(1);
 
         final RecurringInvoiceItem item5 = new RecurringInvoiceItem(invoiceId2, accountId, bundleId, subscriptionId1, "test plan", "test phase A", startDate, endDate,
-                                                                    rate1, rate1, Currency.USD);
+                rate1, rate1, Currency.USD);
         invoiceItemSqlDao.create(item5, context);
 
         final RecurringInvoiceItem item6 = new RecurringInvoiceItem(invoiceId2, accountId, bundleId, subscriptionId2, "test plan", "test phase B", startDate, endDate,
-                                                                    rate2, rate2, Currency.USD);
+                rate2, rate2, Currency.USD);
         invoiceItemSqlDao.create(item6, context);
 
         final RecurringInvoiceItem item7 = new RecurringInvoiceItem(invoiceId2, accountId, bundleId, subscriptionId3, "test plan", "test phase C", startDate, endDate,
-                                                                    rate3, rate3, Currency.USD);
+                rate3, rate3, Currency.USD);
         invoiceItemSqlDao.create(item7, context);
 
         // Check that each subscription returns the correct number of invoices
@@ -261,19 +265,19 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         DateTime endDate = startDate.plusMonths(1);
 
         final FixedPriceInvoiceItem item1 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId1, "test plan", "test A", startDate, endDate,
-                                                                      rate1, Currency.USD);
+                rate1, Currency.USD);
         invoiceItemSqlDao.create(item1, context);
 
         final FixedPriceInvoiceItem item2 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId2, "test plan", "test B", startDate, endDate,
-                                                                      rate2, Currency.USD);
+                rate2, Currency.USD);
         invoiceItemSqlDao.create(item2, context);
 
         final FixedPriceInvoiceItem item3 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId3, "test plan", "test C", startDate, endDate,
-                                                                      rate3, Currency.USD);
+                rate3, Currency.USD);
         invoiceItemSqlDao.create(item3, context);
 
         final FixedPriceInvoiceItem item4 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId4, "test plan", "test D", startDate, endDate,
-                                                                      rate4, Currency.USD);
+                rate4, Currency.USD);
         invoiceItemSqlDao.create(item4, context);
 
         // create invoice 2 (subscriptions 1-3)
@@ -286,15 +290,15 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         endDate = startDate.plusMonths(1);
 
         final FixedPriceInvoiceItem item5 = new FixedPriceInvoiceItem(invoiceId2, accountId, bundleId, subscriptionId1, "test plan", "test phase A", startDate, endDate,
-                                                                      rate1, Currency.USD);
+                rate1, Currency.USD);
         invoiceItemSqlDao.create(item5, context);
 
         final FixedPriceInvoiceItem item6 = new FixedPriceInvoiceItem(invoiceId2, accountId, bundleId, subscriptionId2, "test plan", "test phase B", startDate, endDate,
-                                                                      rate2, Currency.USD);
+                rate2, Currency.USD);
         invoiceItemSqlDao.create(item6, context);
 
         final FixedPriceInvoiceItem item7 = new FixedPriceInvoiceItem(invoiceId2, accountId, bundleId, subscriptionId3, "test plan", "test phase C", startDate, endDate,
-                                                                      rate3, Currency.USD);
+                rate3, Currency.USD);
         invoiceItemSqlDao.create(item7, context);
 
         // check that each subscription returns the correct number of invoices
@@ -337,35 +341,35 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         DateTime endDate = startDate.plusMonths(1);
 
         final RecurringInvoiceItem recurringItem1 = new RecurringInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId1, "test plan", "test A", startDate, endDate,
-                                                                             rate1, rate1, Currency.USD);
+                rate1, rate1, Currency.USD);
         invoiceItemSqlDao.create(recurringItem1, context);
 
         final RecurringInvoiceItem recurringItem2 = new RecurringInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId2, "test plan", "test B", startDate, endDate,
-                                                                             rate2, rate2, Currency.USD);
+                rate2, rate2, Currency.USD);
         invoiceItemSqlDao.create(recurringItem2, context);
 
         final RecurringInvoiceItem recurringItem3 = new RecurringInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId3, "test plan", "test C", startDate, endDate,
-                                                                             rate3, rate3, Currency.USD);
+                rate3, rate3, Currency.USD);
         invoiceItemSqlDao.create(recurringItem3, context);
 
         final RecurringInvoiceItem recurringItem4 = new RecurringInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId4, "test plan", "test D", startDate, endDate,
-                                                                             rate4, rate4, Currency.USD);
+                rate4, rate4, Currency.USD);
         invoiceItemSqlDao.create(recurringItem4, context);
 
         final FixedPriceInvoiceItem fixedItem1 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId1, "test plan", "test A", startDate, endDate,
-                                                                           rate1, Currency.USD);
+                rate1, Currency.USD);
         invoiceItemSqlDao.create(fixedItem1, context);
 
         final FixedPriceInvoiceItem fixedItem2 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId2, "test plan", "test B", startDate, endDate,
-                                                                           rate2, Currency.USD);
+                rate2, Currency.USD);
         invoiceItemSqlDao.create(fixedItem2, context);
 
         final FixedPriceInvoiceItem fixedItem3 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId3, "test plan", "test C", startDate, endDate,
-                                                                           rate3, Currency.USD);
+                rate3, Currency.USD);
         invoiceItemSqlDao.create(fixedItem3, context);
 
         final FixedPriceInvoiceItem fixedItem4 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId4, "test plan", "test D", startDate, endDate,
-                                                                           rate4, Currency.USD);
+                rate4, Currency.USD);
         invoiceItemSqlDao.create(fixedItem4, context);
 
         // create invoice 2 (subscriptions 1-3)
@@ -378,26 +382,26 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         endDate = startDate.plusMonths(1);
 
         final RecurringInvoiceItem recurringItem5 = new RecurringInvoiceItem(invoiceId2, accountId, bundleId, subscriptionId1, "test plan", "test phase A", startDate, endDate,
-                                                                             rate1, rate1, Currency.USD);
+                rate1, rate1, Currency.USD);
         invoiceItemSqlDao.create(recurringItem5, context);
 
         final RecurringInvoiceItem recurringItem6 = new RecurringInvoiceItem(invoiceId2, accountId, bundleId, subscriptionId2, "test plan", "test phase B", startDate, endDate,
-                                                                             rate2, rate2, Currency.USD);
+                rate2, rate2, Currency.USD);
         invoiceItemSqlDao.create(recurringItem6, context);
 
         final RecurringInvoiceItem recurringItem7 = new RecurringInvoiceItem(invoiceId2, accountId, bundleId, subscriptionId3, "test plan", "test phase C", startDate, endDate,
-                                                                             rate3, rate3, Currency.USD);
+                rate3, rate3, Currency.USD);
         invoiceItemSqlDao.create(recurringItem7, context);
         final FixedPriceInvoiceItem fixedItem5 = new FixedPriceInvoiceItem(invoiceId2, accountId, bundleId, subscriptionId1, "test plan", "test phase A", startDate, endDate,
-                                                                           rate1, Currency.USD);
+                rate1, Currency.USD);
         invoiceItemSqlDao.create(fixedItem5, context);
 
         final FixedPriceInvoiceItem fixedItem6 = new FixedPriceInvoiceItem(invoiceId2, accountId, bundleId, subscriptionId2, "test plan", "test phase B", startDate, endDate,
-                                                                           rate2, Currency.USD);
+                rate2, Currency.USD);
         invoiceItemSqlDao.create(fixedItem6, context);
 
         final FixedPriceInvoiceItem fixedItem7 = new FixedPriceInvoiceItem(invoiceId2, accountId, bundleId, subscriptionId3, "test plan", "test phase C", startDate, endDate,
-                                                                           rate3, Currency.USD);
+                rate3, Currency.USD);
         invoiceItemSqlDao.create(fixedItem7, context);
 
         // check that each subscription returns the correct number of invoices
@@ -458,11 +462,11 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         final BigDecimal rate2 = new BigDecimal("42.0");
 
         final RecurringInvoiceItem item1 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase A", startDate,
-                                                                    endDate, rate1, rate1, Currency.USD);
+                endDate, rate1, rate1, Currency.USD);
         invoiceItemSqlDao.create(item1, context);
 
         final RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase B", startDate,
-                                                                    endDate, rate2, rate2, Currency.USD);
+                endDate, rate2, rate2, Currency.USD);
         invoiceItemSqlDao.create(item2, context);
 
         final BigDecimal payment1 = new BigDecimal("48.0");
@@ -473,6 +477,32 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         assertEquals(balance.compareTo(rate1.add(rate2).subtract(payment1)), 0);
     }
 
+
+    @Test
+    public void testAccountBalanceWithCredit() {
+        final UUID accountId = UUID.randomUUID();
+        final UUID bundleId = UUID.randomUUID();
+        final DateTime targetDate1 = new DateTime(2011, 10, 6, 0, 0, 0, 0);
+        final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCNow(), targetDate1, Currency.USD);
+        invoiceDao.create(invoice1, context);
+
+        final DateTime startDate = new DateTime(2011, 3, 1, 0, 0, 0, 0);
+        final DateTime endDate = startDate.plusMonths(1);
+
+        final BigDecimal rate1 = new BigDecimal("17.0");
+
+
+        final RecurringInvoiceItem item1 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase A", startDate,
+                endDate, rate1, rate1, Currency.USD);
+        invoiceItemSqlDao.create(item1, context);
+
+        final CreditAdjInvoiceItem creditItem = new CreditAdjInvoiceItem(invoice1.getId(), accountId, new DateTime(), rate1.negate(), Currency.USD);
+        invoiceItemSqlDao.create(creditItem, context);
+
+        final BigDecimal balance = invoiceDao.getAccountBalance(accountId);
+        assertEquals(balance.compareTo(BigDecimal.ZERO), 0);
+    }
+
     @Test
     public void testAccountBalanceWithNoPayments() {
         final UUID accountId = UUID.randomUUID();
@@ -488,11 +518,11 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         final BigDecimal rate2 = new BigDecimal("42.0");
 
         final RecurringInvoiceItem item1 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase A", startDate, endDate,
-                                                                    rate1, rate1, Currency.USD);
+                rate1, rate1, Currency.USD);
         invoiceItemSqlDao.create(item1, context);
 
         final RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase B", startDate, endDate,
-                                                                    rate2, rate2, Currency.USD);
+                rate2, rate2, Currency.USD);
         invoiceItemSqlDao.create(item2, context);
 
         final BigDecimal balance = invoiceDao.getAccountBalance(accountId);
@@ -515,6 +545,99 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
     }
 
     @Test
+    public void testAccountBalanceWithAllSortsOfThings() {
+        final UUID accountId = UUID.randomUUID();
+        final UUID bundleId = UUID.randomUUID();
+        final DateTime targetDate1 = new DateTime(2011, 10, 6, 0, 0, 0, 0);
+        final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCNow(), targetDate1, Currency.USD);
+        invoiceDao.create(invoice1, context);
+
+        final DateTime startDate = new DateTime(2011, 3, 1, 0, 0, 0, 0);
+        final DateTime endDate = startDate.plusMonths(1);
+
+        final BigDecimal amount1 = new BigDecimal("5.0");
+        final BigDecimal rate1 = new BigDecimal("20.0");
+        final BigDecimal rate2 = new BigDecimal("10.0");
+
+
+        // Fixed Item
+        final FixedPriceInvoiceItem item1 = new FixedPriceInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase A", startDate,
+                endDate, amount1, Currency.USD);
+        invoiceItemSqlDao.create(item1, context);
+
+        BigDecimal balance = invoiceDao.getAccountBalance(accountId);
+        assertEquals(balance.compareTo(new BigDecimal("5.00")), 0);
+
+        // Recurring item
+        final RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase B", startDate,
+                endDate, rate1, rate1, Currency.USD);
+        invoiceItemSqlDao.create(item2, context);
+        balance = invoiceDao.getAccountBalance(accountId);
+        assertEquals(balance.compareTo(new BigDecimal("25.00")), 0);
+
+        // Pay the whole thing
+        final BigDecimal payment1 = amount1.add(rate1);
+        final InvoicePayment payment = new DefaultInvoicePayment(UUID.randomUUID(), invoice1.getId(), new DateTime(), payment1, Currency.USD);
+        invoicePaymentDao.create(payment, context);
+        balance = invoiceDao.getAccountBalance(accountId);
+        assertEquals(balance.compareTo(new BigDecimal("0.00")), 0);
+
+        // Repair previous item with rate 2
+        final RepairAdjInvoiceItem item2Repair = new RepairAdjInvoiceItem(invoice1.getId(), accountId, startDate, endDate, rate1.negate(), Currency.USD, item2.getId());
+        final RecurringInvoiceItem item2Replace = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase B", startDate,
+                endDate, rate2, rate2, Currency.USD);
+        invoiceItemSqlDao.create(item2Repair, context);
+        invoiceItemSqlDao.create(item2Replace, context);
+        balance = invoiceDao.getAccountBalance(accountId);
+        assertEquals(balance.compareTo(new BigDecimal("-10.00")), 0);
+
+        // CBA
+        final CreditBalanceAdjInvoiceItem cbaItem = new CreditBalanceAdjInvoiceItem(invoice1.getId(), accountId, new DateTime(), balance.negate(), Currency.USD);
+        invoiceItemSqlDao.create(cbaItem, context);
+        balance = invoiceDao.getAccountBalance(accountId);
+        assertEquals(balance.compareTo(new BigDecimal("-10.00")), 0);
+        BigDecimal cba =  invoiceDao.getAccountCBA(accountId);
+        assertEquals(cba.compareTo(new BigDecimal("10.00")), 0);
+
+        // partial REFUND on the payment (along with CBA generated by the system)
+        final InvoicePayment refund = new DefaultInvoicePayment(UUID.randomUUID(), UUID.randomUUID(), invoice1.getId(), new DateTime(), rate2.negate(), Currency.USD, payment.getId());
+        invoicePaymentDao.create(refund, context);
+        final CreditBalanceAdjInvoiceItem cbaItem2 = new CreditBalanceAdjInvoiceItem(invoice1.getId(), accountId, new DateTime(), rate2.negate(), Currency.USD);
+        invoiceItemSqlDao.create(cbaItem2, context);
+
+        balance = invoiceDao.getAccountBalance(accountId);
+        assertEquals(balance.compareTo(BigDecimal.ZERO), 0);
+        cba =  invoiceDao.getAccountCBA(accountId);
+        assertEquals(cba.compareTo(BigDecimal.ZERO), 0);
+
+
+
+        // NEXT RECURRING on invoice 2
+
+        final Invoice invoice2 = new DefaultInvoice(accountId, clock.getUTCNow(), targetDate1.plusMonths(1), Currency.USD);
+        invoiceDao.create(invoice2, context);
+
+
+        final RecurringInvoiceItem nextItem = new RecurringInvoiceItem(invoice2.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test bla", startDate.plusMonths(1),
+                endDate.plusMonths(1), rate2, rate2, Currency.USD);
+        invoiceItemSqlDao.create(nextItem, context);
+        balance = invoiceDao.getAccountBalance(accountId);
+        assertEquals(balance.compareTo(new BigDecimal("10.00")), 0);
+        cba =  invoiceDao.getAccountCBA(accountId);
+        assertEquals(cba.compareTo(new BigDecimal("0.00")), 0);
+
+
+        // FINALLY ISSUE A CREDIT ADJ
+        final CreditAdjInvoiceItem creditItem =  new CreditAdjInvoiceItem(invoice2.getId(), accountId, new DateTime(), rate2.negate(), Currency.USD);
+        invoiceItemSqlDao.create(creditItem, context);
+        balance = invoiceDao.getAccountBalance(accountId);
+        assertEquals(balance.compareTo(new BigDecimal("0.00")), 0);
+        cba =  invoiceDao.getAccountCBA(accountId);
+        assertEquals(cba.compareTo(new BigDecimal("0.00")), 0);
+
+    }
+
+    @Test
     public void testGetUnpaidInvoicesByAccountId() {
         final UUID accountId = UUID.randomUUID();
         final UUID bundleId = UUID.randomUUID();
@@ -530,11 +653,11 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
 
 
         final RecurringInvoiceItem item1 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase A", startDate, endDate,
-                                                                    rate1, rate1, Currency.USD);
+                rate1, rate1, Currency.USD);
         invoiceItemSqlDao.create(item1, context);
 
         final RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase B", startDate, endDate,
-                                                                    rate2, rate2, Currency.USD);
+                rate2, rate2, Currency.USD);
         invoiceItemSqlDao.create(item2, context);
 
         DateTime upToDate;
@@ -558,7 +681,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         final BigDecimal rate3 = new BigDecimal("21.0");
 
         final RecurringInvoiceItem item3 = new RecurringInvoiceItem(invoice2.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase C", startDate2, endDate2,
-                                                                    rate3, rate3, Currency.USD);
+                rate3, rate3, Currency.USD);
         invoiceItemSqlDao.create(item3, context);
 
         upToDate = new DateTime(2011, 1, 1, 0, 0, 0, 0);
@@ -592,8 +715,8 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
 
         final DateTime effectiveDate1 = new DateTime(2011, 2, 1, 0, 0, 0, 0);
         final BillingEvent event1 = createMockBillingEvent(null, subscription, effectiveDate1, plan1, phase1, null,
-                                                           recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
-                                                           "testEvent1", 1L, SubscriptionTransitionType.CREATE);
+                recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
+                "testEvent1", 1L, SubscriptionTransitionType.CREATE);
 
         final BillingEventSet events = new MockBillingEventSet();
         events.add(event1);
@@ -610,8 +733,8 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
 
         final DateTime effectiveDate2 = new DateTime(2011, 2, 15, 0, 0, 0, 0);
         final BillingEvent event2 = createMockBillingEvent(null, subscription, effectiveDate2, plan2, phase2, null,
-                                                           recurringPrice2.getPrice(currency), currency, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
-                                                           "testEvent2", 2L, SubscriptionTransitionType.CREATE);
+                recurringPrice2.getPrice(currency), currency, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
+                "testEvent2", 2L, SubscriptionTransitionType.CREATE);
         events.add(event2);
 
         // second invoice should be for one half (14/28 days) the difference between the rate plans
@@ -642,8 +765,8 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         final DateTime effectiveDate = buildDateTime(2011, 1, 1);
 
         final BillingEvent event = createMockBillingEvent(null, subscription, effectiveDate, plan, phase, null,
-                                                          recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 15, BillingModeType.IN_ADVANCE,
-                                                          "testEvent", 1L, SubscriptionTransitionType.CREATE);
+                recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 15, BillingModeType.IN_ADVANCE,
+                "testEvent", 1L, SubscriptionTransitionType.CREATE);
         final BillingEventSet events = new MockBillingEventSet();
         events.add(event);
 
@@ -681,8 +804,8 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         final DateTime effectiveDate1 = buildDateTime(2011, 1, 1);
 
         final BillingEvent event1 = createMockBillingEvent(null, subscription, effectiveDate1, plan, phase1, fixedPrice.getPrice(currency),
-                                                           null, currency, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
-                                                           "testEvent1", 1L, SubscriptionTransitionType.CREATE);
+                null, currency, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
+                "testEvent1", 1L, SubscriptionTransitionType.CREATE);
         final BillingEventSet events = new MockBillingEventSet();
         events.add(event1);
 
@@ -699,8 +822,8 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
 
         final DateTime effectiveDate2 = effectiveDate1.plusDays(30);
         final BillingEvent event2 = createMockBillingEvent(null, subscription, effectiveDate2, plan, phase2, null,
-                                                           recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
-                                                           "testEvent2", 2L, SubscriptionTransitionType.PHASE);
+                recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
+                "testEvent2", 2L, SubscriptionTransitionType.PHASE);
         events.add(event2);
 
         final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, effectiveDate2, Currency.USD);
@@ -746,16 +869,16 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         final DateTime effectiveDate1 = buildDateTime(2011, 1, 1);
 
         final BillingEvent event1 = createMockBillingEvent(null, subscription, effectiveDate1, plan, phase1,
-                                                           fixedPrice.getPrice(currency), null, currency,
-                                                           BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
-                                                           "testEvent1", 1L, SubscriptionTransitionType.CREATE);
+                fixedPrice.getPrice(currency), null, currency,
+                BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
+                "testEvent1", 1L, SubscriptionTransitionType.CREATE);
         final BillingEventSet events = new MockBillingEventSet();
         events.add(event1);
 
         final DateTime effectiveDate2 = effectiveDate1.plusDays(30);
         final BillingEvent event2 = createMockBillingEvent(null, subscription, effectiveDate2, plan, phase2, null,
-                                                           recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
-                                                           "testEvent2", 2L, SubscriptionTransitionType.CHANGE);
+                recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
+                "testEvent2", 2L, SubscriptionTransitionType.CHANGE);
         events.add(event2);
 
         final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, effectiveDate2, Currency.USD);
@@ -792,9 +915,9 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         final List<Invoice> invoices = new ArrayList<Invoice>();
 
         final BillingEvent event1 = createMockBillingEvent(null, subscription, targetDate1, plan, phase1, null,
-                                                           TEN, currency,
-                                                           BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
-                                                           "testEvent1", 1L, SubscriptionTransitionType.CHANGE);
+                TEN, currency,
+                BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
+                "testEvent1", 1L, SubscriptionTransitionType.CHANGE);
         events.add(event1);
 
         Invoice invoice1 = generator.generateInvoice(UUID.randomUUID(), events, invoices, targetDate1, Currency.USD);
@@ -804,9 +927,9 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         assertNotNull(invoice1.getInvoiceNumber());
 
         final BillingEvent event2 = createMockBillingEvent(null, subscription, targetDate1, plan, phase2, null,
-                                                           TWENTY, currency,
-                                                           BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
-                                                           "testEvent2", 2L, SubscriptionTransitionType.CHANGE);
+                TWENTY, currency,
+                BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
+                "testEvent2", 2L, SubscriptionTransitionType.CHANGE);
         events.add(event2);
         Invoice invoice2 = generator.generateInvoice(UUID.randomUUID(), events, invoices, targetDate2, Currency.USD);
         invoiceDao.create(invoice2, context);
@@ -829,9 +952,9 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
 
         // create pseudo-random invoice
         final BillingEvent event1 = createMockBillingEvent(null, subscription, targetDate1, plan, phase1, null,
-                                                           TEN, currency,
-                                                           BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
-                                                           "testEvent1", 1L, SubscriptionTransitionType.CHANGE);
+                TEN, currency,
+                BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
+                "testEvent1", 1L, SubscriptionTransitionType.CHANGE);
         final BillingEventSet events = new MockBillingEventSet();
         events.add(event1);
 
@@ -860,9 +983,9 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
 
         // create pseudo-random invoice
         final BillingEvent event1 = createMockBillingEvent(null, subscription, targetDate1, plan, phase1, null,
-                                                           TEN, currency,
-                                                           BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
-                                                           "testEvent1", 1L, SubscriptionTransitionType.CHANGE);
+                TEN, currency,
+                BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
+                "testEvent1", 1L, SubscriptionTransitionType.CHANGE);
         final BillingEventSet events = new MockBillingEventSet();
         events.add(event1);
 
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
index 0564bd0..984d819 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
@@ -248,7 +248,14 @@ public class MockInvoiceDao implements InvoiceDao {
     }
 
     @Override
-    public InvoiceItem insertCredit(final UUID accountId, final BigDecimal amount, final DateTime effectiveDate, final Currency currency, final CallContext context) {
+    public InvoiceItem insertCredit(final UUID accountId, final UUID invoiceId, final BigDecimal amount, final DateTime effectiveDate, final Currency currency, final CallContext context) {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public BigDecimal getAccountCBA(UUID accountId) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
 }