killbill-memoizeit

Details

diff --git a/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java b/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java
index 43a1d70..c1e3140 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java
@@ -18,6 +18,7 @@ package com.ning.billing.invoice.generator;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -56,6 +57,9 @@ import com.ning.billing.invoice.model.RepairAdjInvoiceItem;
 import com.ning.billing.junction.api.BillingEventSet;
 import com.ning.billing.util.clock.Clock;
 
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
 import com.google.inject.Inject;
 
 public class DefaultInvoiceGenerator implements InvoiceGenerator {
@@ -78,9 +82,9 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
      */
     @Override
     public Invoice generateInvoice(final UUID accountId, @Nullable final BillingEventSet events,
-                                   @Nullable final List<Invoice> existingInvoices,
-                                   final LocalDate targetDate, final DateTimeZone accountTimeZone,
-                                   final Currency targetCurrency) throws InvoiceApiException {
+            @Nullable final List<Invoice> existingInvoices,
+            final LocalDate targetDate, final DateTimeZone accountTimeZone,
+            final Currency targetCurrency) throws InvoiceApiException {
         if ((events == null) || (events.size() == 0) || events.isAccountAutoInvoiceOff()) {
             return null;
         }
@@ -94,8 +98,8 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
             for (final Invoice invoice : existingInvoices) {
                 for (final InvoiceItem item : invoice.getInvoiceItems()) {
                     if (item.getSubscriptionId() == null || // Always include migration invoices, credits, external charges etc.
-                        !events.getSubscriptionIdsWithAutoInvoiceOff()
-                               .contains(item.getSubscriptionId())) { //don't add items with auto_invoice_off tag
+                            !events.getSubscriptionIdsWithAutoInvoiceOff()
+                            .contains(item.getSubscriptionId())) { //don't add items with auto_invoice_off tag
                         existingItems.add(item);
                     }
                 }
@@ -127,7 +131,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
     }
 
     void generateCBAForExistingInvoices(final UUID accountId, final List<Invoice> existingInvoices,
-                                        final List<InvoiceItem> proposedItems, final Currency currency) {
+            final List<InvoiceItem> proposedItems, final Currency currency) {
         // Determine most accurate invoice balances up to this point
         final Map<UUID, BigDecimal> amountOwedByInvoice = new HashMap<UUID, BigDecimal>();
 
@@ -159,16 +163,48 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
     void addRepairedItems(final List<InvoiceItem> existingItems, final List<InvoiceItem> proposedItems) {
         for (final InvoiceItem existingItem : existingItems) {
             if (existingItem.getInvoiceItemType() == InvoiceItemType.RECURRING ||
-                existingItem.getInvoiceItemType() == InvoiceItemType.FIXED) {
-                final BigDecimal amountNegated = existingItem.getAmount() == null ? null : existingItem.getAmount().negate();
-                final RepairAdjInvoiceItem repairItem = new RepairAdjInvoiceItem(existingItem.getInvoiceId(), existingItem.getAccountId(), existingItem.getStartDate(), existingItem.getEndDate(), amountNegated, existingItem.getCurrency(), existingItem.getId());
-                proposedItems.add(repairItem);
+                    existingItem.getInvoiceItemType() == InvoiceItemType.FIXED) {
+                final BigDecimal existingAdjustedPositiveAmount = getAdjustedPositiveAmount(existingItems, existingItem.getId());
+                final BigDecimal amountNegated = existingItem.getAmount() == null ? null : existingItem.getAmount().subtract(existingAdjustedPositiveAmount).negate();
+                if (amountNegated.compareTo(BigDecimal.ZERO) < 0) {
+                    final RepairAdjInvoiceItem repairItem = new RepairAdjInvoiceItem(existingItem.getInvoiceId(), existingItem.getAccountId(), existingItem.getStartDate(), existingItem.getEndDate(), amountNegated, existingItem.getCurrency(), existingItem.getId());
+                    proposedItems.add(repairItem);
+                }
             }
         }
+
+    }
+
+
+    // We check to see if there are any adjustments that point to the item we are trying to repair
+    // If we did any CREDIT_ADJ or REFUND_ADJ, then we unfortunately we can't know what is the intent
+    // was as it applies to the full Invoice, so we ignore it. That might result in an extra positive CBA
+    // that would have to be corrected manually. This is the best we can do, and administrators should always
+    // use ITEM_ADJUSTEMNT rather than CREDIT_ADJ or REFUND_ADJ when possible.
+    //
+    BigDecimal getAdjustedPositiveAmount(final List<InvoiceItem> existingItems, final UUID linkedItemId) {
+        BigDecimal totalAdjustedOnItem = BigDecimal.ZERO;
+        final Collection<InvoiceItem> c = Collections2.filter(existingItems, new Predicate<InvoiceItem>() {
+            @Override
+            public boolean apply(InvoiceItem item) {
+                if (item.getInvoiceItemType() == InvoiceItemType.ITEM_ADJ &&
+                        item.getLinkedItemId() != null && item.getLinkedItemId().equals(linkedItemId)) {
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+        });
+
+        final Iterator<InvoiceItem> it = c.iterator();
+        while (it.hasNext()) {
+            totalAdjustedOnItem = totalAdjustedOnItem.add(it.next().getAmount());
+        }
+        return totalAdjustedOnItem.negate();
     }
 
     void consumeExistingCredit(final UUID invoiceId, final UUID accountId, final List<InvoiceItem> existingItems,
-                               final List<InvoiceItem> proposedItems, final Currency targetCurrency) {
+            final List<InvoiceItem> proposedItems, final Currency targetCurrency) {
         BigDecimal totalUnusedCreditAmount = BigDecimal.ZERO;
         BigDecimal totalAmountOwed = BigDecimal.ZERO;
 
@@ -230,7 +266,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
      * Removes all matching items from both submitted collections
      */
     void removeDuplicatedInvoiceItems(final List<InvoiceItem> proposedItems,
-                                      final List<InvoiceItem> existingInvoiceItems) {
+            final List<InvoiceItem> existingInvoiceItems) {
         // We can't just use sets here as order matters (we want to keep duplicated in existingInvoiceItems)
         final Iterator<InvoiceItem> proposedItemIterator = proposedItems.iterator();
         while (proposedItemIterator.hasNext()) {
@@ -269,7 +305,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
     }
 
     private List<InvoiceItem> generateInvoiceItems(final UUID invoiceId, final UUID accountId, final BillingEventSet events,
-                                                   final LocalDate targetDate, final DateTimeZone accountTimeZone, final Currency currency) throws InvoiceApiException {
+            final LocalDate targetDate, final DateTimeZone accountTimeZone, final Currency currency) throws InvoiceApiException {
         final List<InvoiceItem> items = new ArrayList<InvoiceItem>();
 
         if (events.size() == 0) {
@@ -307,7 +343,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
 
     // Turn a set of events into a list of invoice items. Note that the dates on the invoice items will be rounded (granularity of a day)
     private List<InvoiceItem> processEvents(final UUID invoiceId, final UUID accountId, final BillingEvent thisEvent, @Nullable final BillingEvent nextEvent,
-                                            final LocalDate targetDate, final DateTimeZone accountTimeZone, final Currency currency) throws InvoiceApiException {
+            final LocalDate targetDate, final DateTimeZone accountTimeZone, final Currency currency) throws InvoiceApiException {
         final List<InvoiceItem> items = new ArrayList<InvoiceItem>();
 
         // Handle fixed price items
@@ -341,13 +377,13 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
                         final BigDecimal amount = itemDatum.getNumberOfCycles().multiply(rate).setScale(NUMBER_OF_DECIMALS, ROUNDING_MODE);
 
                         final RecurringInvoiceItem recurringItem = new RecurringInvoiceItem(invoiceId,
-                                                                                            accountId,
-                                                                                            thisEvent.getSubscription().getBundleId(),
-                                                                                            thisEvent.getSubscription().getId(),
-                                                                                            thisEvent.getPlan().getName(),
-                                                                                            thisEvent.getPlanPhase().getName(),
-                                                                                            itemDatum.getStartDate(), itemDatum.getEndDate(),
-                                                                                            amount, rate, currency);
+                                accountId,
+                                thisEvent.getSubscription().getBundleId(),
+                                thisEvent.getSubscription().getId(),
+                                thisEvent.getPlan().getName(),
+                                thisEvent.getPlanPhase().getName(),
+                                itemDatum.getStartDate(), itemDatum.getEndDate(),
+                                amount, rate, currency);
                         items.add(recurringItem);
                     }
                 }
@@ -360,15 +396,15 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
 
     private BillingMode instantiateBillingMode(final BillingModeType billingMode) {
         switch (billingMode) {
-            case IN_ADVANCE:
-                return new InAdvanceBillingMode();
-            default:
-                throw new UnsupportedOperationException();
+        case IN_ADVANCE:
+            return new InAdvanceBillingMode();
+        default:
+            throw new UnsupportedOperationException();
         }
     }
 
     InvoiceItem generateFixedPriceItem(final UUID invoiceId, final UUID accountId, final BillingEvent thisEvent,
-                                       final LocalDate targetDate, final Currency currency) {
+            final LocalDate targetDate, final Currency currency) {
         final LocalDate roundedStartDate = new LocalDate(thisEvent.getEffectiveDate(), thisEvent.getTimeZone());
 
         if (roundedStartDate.isAfter(targetDate)) {
@@ -378,9 +414,9 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
 
             if (fixedPrice != null) {
                 return new FixedPriceInvoiceItem(invoiceId, accountId, thisEvent.getSubscription().getBundleId(),
-                                                 thisEvent.getSubscription().getId(),
-                                                 thisEvent.getPlan().getName(), thisEvent.getPlanPhase().getName(),
-                                                 roundedStartDate, fixedPrice, currency);
+                        thisEvent.getSubscription().getId(),
+                        thisEvent.getPlan().getName(), thisEvent.getPlanPhase().getName(),
+                        roundedStartDate, fixedPrice, currency);
             } else {
                 return null;
             }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
index 55a2e61..ee27de3 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
@@ -16,9 +16,15 @@
 
 package com.ning.billing.invoice.dao;
 
+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 java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
@@ -29,6 +35,7 @@ import org.joda.time.LocalDate;
 import org.mockito.Mockito;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.ImmutableMap;
 import com.ning.billing.catalog.DefaultPrice;
 import com.ning.billing.catalog.MockInternationalPrice;
 import com.ning.billing.catalog.MockPlan;
@@ -59,19 +66,13 @@ import com.ning.billing.invoice.model.RecurringInvoiceItem;
 import com.ning.billing.invoice.model.RepairAdjInvoiceItem;
 import com.ning.billing.junction.api.BillingEventSet;
 import com.ning.billing.util.api.TagApiException;
+import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.ControlTagType;
 import com.ning.billing.util.tag.Tag;
 import com.ning.billing.util.tag.dao.AuditedTagDao;
 import com.ning.billing.util.tag.dao.TagDao;
 
-import com.google.common.collect.ImmutableMap;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
-
 public class TestInvoiceDao extends InvoiceDaoTestBase {
 
     @Test(groups = "slow")
@@ -103,7 +104,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         final LocalDate startDate = new LocalDate(2010, 1, 1);
         final LocalDate endDate = new LocalDate(2010, 4, 1);
         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, invoice.getTargetDate().getDayOfMonth(), true, context);
@@ -159,19 +160,19 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         LocalDate 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)
@@ -184,15 +185,15 @@ public class TestInvoiceDao 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
@@ -235,19 +236,19 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         LocalDate endDate = startDate.plusMonths(1);
 
         final FixedPriceInvoiceItem item1 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId1, "test plan", "test A", startDate,
-                                                                      rate1, Currency.USD);
+                rate1, Currency.USD);
         invoiceItemSqlDao.create(item1, context);
 
         final FixedPriceInvoiceItem item2 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId2, "test plan", "test B", startDate,
-                                                                      rate2, Currency.USD);
+                rate2, Currency.USD);
         invoiceItemSqlDao.create(item2, context);
 
         final FixedPriceInvoiceItem item3 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId3, "test plan", "test C", startDate,
-                                                                      rate3, Currency.USD);
+                rate3, Currency.USD);
         invoiceItemSqlDao.create(item3, context);
 
         final FixedPriceInvoiceItem item4 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId4, "test plan", "test D", startDate,
-                                                                      rate4, Currency.USD);
+                rate4, Currency.USD);
         invoiceItemSqlDao.create(item4, context);
 
         // create invoice 2 (subscriptions 1-3)
@@ -260,15 +261,15 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         endDate = startDate.plusMonths(1);
 
         final FixedPriceInvoiceItem item5 = new FixedPriceInvoiceItem(invoiceId2, accountId, bundleId, subscriptionId1, "test plan", "test phase A", startDate,
-                                                                      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,
-                                                                      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,
-                                                                      rate3, Currency.USD);
+                rate3, Currency.USD);
         invoiceItemSqlDao.create(item7, context);
 
         // check that each subscription returns the correct number of invoices
@@ -311,35 +312,35 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         LocalDate 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,
-                                                                           rate1, Currency.USD);
+                rate1, Currency.USD);
         invoiceItemSqlDao.create(fixedItem1, context);
 
         final FixedPriceInvoiceItem fixedItem2 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId2, "test plan", "test B", startDate,
-                                                                           rate2, Currency.USD);
+                rate2, Currency.USD);
         invoiceItemSqlDao.create(fixedItem2, context);
 
         final FixedPriceInvoiceItem fixedItem3 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId3, "test plan", "test C", startDate,
-                                                                           rate3, Currency.USD);
+                rate3, Currency.USD);
         invoiceItemSqlDao.create(fixedItem3, context);
 
         final FixedPriceInvoiceItem fixedItem4 = new FixedPriceInvoiceItem(invoiceId1, accountId, bundleId, subscriptionId4, "test plan", "test D", startDate,
-                                                                           rate4, Currency.USD);
+                rate4, Currency.USD);
         invoiceItemSqlDao.create(fixedItem4, context);
 
         // create invoice 2 (subscriptions 1-3)
@@ -352,26 +353,26 @@ public class TestInvoiceDao 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,
-                                                                           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,
-                                                                           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,
-                                                                           rate3, Currency.USD);
+                rate3, Currency.USD);
         invoiceItemSqlDao.create(fixedItem7, context);
 
         // check that each subscription returns the correct number of invoices
@@ -431,11 +432,11 @@ public class TestInvoiceDao 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");
@@ -460,7 +461,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         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);
+                endDate, rate1, rate1, Currency.USD);
         invoiceItemSqlDao.create(item1, context);
 
         final CreditAdjInvoiceItem creditItem = new CreditAdjInvoiceItem(invoice1.getId(), accountId, new LocalDate(), rate1.negate(), Currency.USD);
@@ -485,11 +486,11 @@ public class TestInvoiceDao 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);
@@ -538,7 +539,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
 
         // Recurring item
         final RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase B", startDate,
-                                                                    endDate, rate1, rate1, Currency.USD);
+                endDate, rate1, rate1, Currency.USD);
         invoiceItemSqlDao.create(item2, context);
         BigDecimal balance = invoiceDao.getAccountBalance(accountId);
         assertEquals(balance.compareTo(new BigDecimal("20.00")), 0);
@@ -604,7 +605,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
 
         // Fixed Item
         final FixedPriceInvoiceItem item1 = new FixedPriceInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase A", startDate,
-                                                                      amount1, Currency.USD);
+                amount1, Currency.USD);
         invoiceItemSqlDao.create(item1, context);
 
         BigDecimal balance = invoiceDao.getAccountBalance(accountId);
@@ -612,7 +613,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
 
         // Recurring item
         final RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase B", startDate,
-                                                                    endDate, rate1, rate1, Currency.USD);
+                endDate, rate1, rate1, Currency.USD);
         invoiceItemSqlDao.create(item2, context);
         balance = invoiceDao.getAccountBalance(accountId);
         assertEquals(balance.compareTo(new BigDecimal("25.00")), 0);
@@ -628,7 +629,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         // 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);
+                endDate, rate2, rate2, Currency.USD);
         invoiceItemSqlDao.create(item2Repair, context);
         invoiceItemSqlDao.create(item2Replace, context);
         balance = invoiceDao.getAccountBalance(accountId);
@@ -671,7 +672,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
 
         // Fixed Item
         final FixedPriceInvoiceItem item1 = new FixedPriceInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase A", startDate,
-                                                                      amount1, Currency.USD);
+                amount1, Currency.USD);
         invoiceItemSqlDao.create(item1, context);
 
         BigDecimal balance = invoiceDao.getAccountBalance(accountId);
@@ -679,7 +680,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
 
         // Recurring item
         final RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase B", startDate,
-                                                                    endDate, rate1, rate1, Currency.USD);
+                endDate, rate1, rate1, Currency.USD);
         invoiceItemSqlDao.create(item2, context);
         balance = invoiceDao.getAccountBalance(accountId);
         assertEquals(balance.compareTo(new BigDecimal("25.00")), 0);
@@ -694,7 +695,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         // 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);
+                endDate, rate2, rate2, Currency.USD);
         invoiceItemSqlDao.create(item2Repair, context);
         invoiceItemSqlDao.create(item2Replace, context);
         balance = invoiceDao.getAccountBalance(accountId);
@@ -725,7 +726,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         invoiceDao.create(invoice2, invoice2.getTargetDate().getDayOfMonth(), true, 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);
+                endDate.plusMonths(1), rate2, rate2, Currency.USD);
         invoiceItemSqlDao.create(nextItem, context);
         balance = invoiceDao.getAccountBalance(accountId);
         assertEquals(balance.compareTo(new BigDecimal("10.00")), 0);
@@ -818,7 +819,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
 
         // Fixed Item
         final FixedPriceInvoiceItem item1 = new FixedPriceInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase A", startDate,
-                                                                      amount1, Currency.USD);
+                amount1, Currency.USD);
         invoiceItemSqlDao.create(item1, context);
 
         // Create the credit item
@@ -862,11 +863,11 @@ public class TestInvoiceDao 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);
 
         LocalDate upToDate;
@@ -890,7 +891,7 @@ public class TestInvoiceDao 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 LocalDate(2011, 1, 1);
@@ -924,8 +925,8 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
 
         final DateTime effectiveDate1 = new DateTime(2011, 2, 1, 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);
@@ -942,8 +943,8 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
 
         final DateTime effectiveDate2 = new DateTime(2011, 2, 15, 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
@@ -974,8 +975,8 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         final DateTime effectiveDate = buildDate(2011, 1, 1).toDateTimeAtStartOfDay();
 
         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);
 
@@ -1013,8 +1014,8 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         final DateTime effectiveDate1 = buildDate(2011, 1, 1).toDateTimeAtStartOfDay();
 
         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);
 
@@ -1031,8 +1032,8 @@ public class TestInvoiceDao 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, new LocalDate(effectiveDate2), DateTimeZone.UTC, Currency.USD);
@@ -1078,16 +1079,16 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         final DateTime effectiveDate1 = buildDate(2011, 1, 1).toDateTimeAtStartOfDay();
 
         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, new LocalDate(effectiveDate2), DateTimeZone.UTC, Currency.USD);
@@ -1103,6 +1104,81 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         assertEquals(savedInvoice.getBalance().compareTo(cheapAmount), 0);
     }
 
+
+    @Test(groups = "slow")
+    public void testRefundedInvoiceWithInvoiceItemAdjustmentWithRepair() throws InvoiceApiException  {
+
+        final UUID accountId = UUID.randomUUID();
+        final UUID subscriptionId = UUID.randomUUID();
+        final UUID bundleId = UUID.randomUUID();
+        final LocalDate startDate = new LocalDate(2010, 1, 1);
+
+        ((ClockMock) clock).setDay(startDate);
+
+        final LocalDate recuringStartDate = clock.getUTCNow().plusDays(30).toLocalDate();
+        final LocalDate recuringEndDate = clock.getUTCNow().plusDays(30).toLocalDate();
+        final LocalDate targetDate = recuringStartDate.plusDays(1);
+
+
+        // FIRST CREATE INITIAL INVOICE WITH ONE RECURRING ITEM
+        final Invoice invoice = new DefaultInvoice(accountId, targetDate, targetDate, Currency.USD);
+        final UUID invoiceId = invoice.getId();
+
+        final InvoiceItem invoiceItem = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, "test-plan", "test-phase-rec",
+                recuringStartDate, recuringEndDate, new BigDecimal("239.00"), new BigDecimal("239.00"), Currency.USD);
+
+
+        invoice.addInvoiceItem(invoiceItem);
+        invoiceDao.create(invoice, invoice.getTargetDate().getDayOfMonth(), true, context);
+
+
+        ((ClockMock) clock).addDays(1);
+
+        // SECOND CREATE THE PAYMENT
+        final BigDecimal paymentAmount = new BigDecimal("239.00");
+        final UUID paymentId = UUID.randomUUID();
+        invoiceDao.notifyOfPayment(new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, paymentId, invoiceId, clock.getUTCNow(), paymentAmount, Currency.USD), context);
+
+        // AND THEN THIRD THE REFUND
+        Map<UUID, BigDecimal> invoiceItemMap = new HashMap<UUID, BigDecimal>();
+        invoiceItemMap.put(invoiceItem.getId(), new BigDecimal("239.00"));
+        invoiceDao.createRefund(paymentId, paymentAmount, true, invoiceItemMap, UUID.randomUUID(), context);
+
+        final Invoice savedInvoice = invoiceDao.getById(invoiceId);
+        assertNotNull(savedInvoice);
+        assertEquals(savedInvoice.getInvoiceItems().size(), 2);
+
+        final List<Invoice> invoices = new ArrayList<Invoice>();
+        invoices.add(savedInvoice);
+
+
+        // NOW COMPUTE A DIFFERENT ITEM TO TRIGGER REPAIR
+        final BillingEventSet events = new MockBillingEventSet();
+        final Subscription subscription = getZombieSubscription();
+
+        final Plan plan = Mockito.mock(Plan.class);
+        Mockito.when(plan.getName()).thenReturn("plan");
+
+        final PlanPhase phase1 = Mockito.mock(PlanPhase.class);
+        Mockito.when(phase1.getName()).thenReturn("plan-phase1");
+
+        final PlanPhase phase2 = Mockito.mock(PlanPhase.class);
+        Mockito.when(phase2.getName()).thenReturn("plan-phase2");
+
+        final BillingEvent event1 = createMockBillingEvent(null, subscription, recuringStartDate.toDateTimeAtStartOfDay(), plan, phase1, null,
+                TEN, Currency.USD,
+                BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
+                "new-event", 1L, SubscriptionTransitionType.CREATE);
+        events.add(event1);
+        Invoice newInvoice = generator.generateInvoice(UUID.randomUUID(), events, invoices, targetDate, DateTimeZone.UTC, Currency.USD);
+        invoiceDao.create(newInvoice, newInvoice.getTargetDate().getDayOfMonth(), true, context);
+
+        // VERIFY THAT WE STILL HAVE ONLY 2 ITEMS, MENAING THERE WERE NO REPAIR AND NO CBA GENERATED
+        final Invoice firstInvoice = invoiceDao.getById(invoiceId);
+        assertNotNull(firstInvoice);
+        assertEquals(firstInvoice.getInvoiceItems().size(), 2);
+    }
+
     @Test(groups = "slow")
     public void testInvoiceNumber() throws InvoiceApiException {
         final Currency currency = Currency.USD;
@@ -1124,9 +1200,9 @@ public class TestInvoiceDao 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, new LocalDate(targetDate1), DateTimeZone.UTC, Currency.USD);
@@ -1136,9 +1212,9 @@ public class TestInvoiceDao 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, new LocalDate(targetDate2), DateTimeZone.UTC, Currency.USD);
         invoiceDao.create(invoice2, invoice2.getTargetDate().getDayOfMonth(), true, context);
@@ -1161,9 +1237,9 @@ public class TestInvoiceDao 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);
 
@@ -1192,9 +1268,9 @@ public class TestInvoiceDao 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/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
index 73f981f..aafebdb 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
@@ -143,7 +143,7 @@ public class InvoiceResource extends JaxRsResourceBase {
                                @QueryParam(QUERY_INVOICE_WITH_ITEMS) @DefaultValue("false") final boolean withItems) throws InvoiceApiException {
         final Invoice invoice = invoiceApi.getInvoice(UUID.fromString(invoiceId));
         if (invoice == null) {
-            throw new InvoiceApiException(ErrorCode.INVOICE_NOT_FOUND);
+            throw new InvoiceApiException(ErrorCode.INVOICE_NOT_FOUND, invoiceId);
         } else {
             final InvoiceJsonSimple json = withItems ? new InvoiceJsonWithItems(invoice) : new InvoiceJsonSimple(invoice);
             return Response.status(Status.OK).entity(json).build();