killbill-memoizeit

invoice: Allow invoice plugins to modify existing items. This

6/5/2018 9:12:52 PM

Details

diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithInvoicePlugin.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithInvoicePlugin.java
index db8c664..e1e9460 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithInvoicePlugin.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithInvoicePlugin.java
@@ -190,6 +190,48 @@ public class TestWithInvoicePlugin extends TestIntegrationBase {
         assertEquals(externalCharge.getId(), pluginInvoiceItemId);
         // verify the ID is the one passed by the plugin #887
         assertEquals(externalCharge.getLinkedItemId(), pluginLinkedItemId);
+
+
+        // On next invoice we will update the amount and the description of the previously inserted EXTERNAL_CHARGE item
+        testInvoicePluginApi.additionalInvoiceItem = new ExternalChargeInvoiceItem(pluginInvoiceItemId,
+                                                                                   clock.getUTCNow(),
+                                                                                   invoices.get(0).getId(),
+                                                                                   account.getId(),
+                                                                                   null,
+                                                                                   null,
+                                                                                   null,
+                                                                                   null,
+                                                                                   null,
+                                                                                   null,
+                                                                                   null,
+                                                                                   null,
+                                                                                   "Update Description",
+                                                                                   clock.getUTCToday(),
+                                                                                   null,
+                                                                                   BigDecimal.ONE,
+                                                                                   null,
+                                                                                   Currency.USD,
+                                                                                   pluginLinkedItemId,
+                                                                                   null);
+
+        busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
+        clock.addDays(30);
+        assertListenerStatus();
+        invoiceChecker.checkInvoice(account.getId(), 2, callContext,
+                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 6, 1), InvoiceItemType.RECURRING, new BigDecimal("29.95")));
+
+
+        final List<Invoice> invoices2 = invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext);
+        final List<InvoiceItem> invoiceItems2 = invoices2.get(0).getInvoiceItems();
+        final InvoiceItem externalCharge2 = Iterables.tryFind(invoiceItems2, new Predicate<InvoiceItem>() {
+            @Override
+            public boolean apply(final InvoiceItem input) {
+                return input.getInvoiceItemType() == InvoiceItemType.EXTERNAL_CHARGE;
+            }
+        }).orNull();
+        assertNotNull(externalCharge2);
+
+        assertEquals(externalCharge2.getAmount().compareTo(BigDecimal.ONE), 0);
     }
 
     @Test(groups = "slow")
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
index 5cd89af..f928ba5 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
@@ -84,6 +84,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Function;
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
@@ -357,7 +358,12 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                                    (invoiceItemModelDao.getAmount().compareTo(existingInvoiceItem.getAmount()) != 0)) {
                             checkAgainstExistingInvoiceItemState(existingInvoiceItem, invoiceItemModelDao);
 
-                            transInvoiceItemSqlDao.updateAmount(invoiceItemModelDao.getId().toString(), invoiceItemModelDao.getAmount(), context);
+                            // We allow plugins to override these 3 fields
+                            final BigDecimal updatedAmount = invoiceItemModelDao.getAmount() != null ? invoiceItemModelDao.getAmount() :  existingInvoiceItem.getAmount();
+                            final String updatedDescription = invoiceItemModelDao.getDescription() != null ? invoiceItemModelDao.getDescription() : existingInvoiceItem.getDescription();
+                            final String updatedItemDetails = invoiceItemModelDao.getItemDetails() != null ? invoiceItemModelDao.getItemDetails() : existingInvoiceItem.getItemDetails();
+
+                            transInvoiceItemSqlDao.updateItemFields(invoiceItemModelDao.getId().toString(), updatedAmount, updatedDescription, updatedItemDetails, context);
                         }
                     }
 
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.java
index 7a864d9..cb7c841 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.java
@@ -27,9 +27,9 @@ import org.killbill.billing.invoice.api.InvoiceItem;
 import org.killbill.billing.util.audit.ChangeType;
 import org.killbill.billing.util.entity.dao.Audited;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
-import org.killbill.commons.jdbi.binder.SmartBindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 
@@ -39,7 +39,6 @@ public interface InvoiceItemSqlDao extends EntitySqlDao<InvoiceItemModelDao, Inv
     @SqlQuery
     List<InvoiceItemModelDao> getInvoiceItemsByInvoice(@Bind("invoiceId") final String invoiceId,
                                                        @SmartBindBean final InternalTenantContext context);
-
     @SqlQuery
     List<InvoiceItemModelDao> getInvoiceItemsBySubscription(@Bind("subscriptionId") final String subscriptionId,
                                                             @SmartBindBean final InternalTenantContext context);
@@ -55,6 +54,14 @@ public interface InvoiceItemSqlDao extends EntitySqlDao<InvoiceItemModelDao, Inv
                       @Bind("amount")BigDecimal amount,
                       @SmartBindBean final InternalCallContext context);
 
+    @SqlUpdate
+    @Audited(ChangeType.UPDATE)
+    void updateItemFields(@Bind("id") String invoiceItemId,
+                          @Bind("amount") BigDecimal amount,
+                          @Bind("description") String description,
+                          @Bind("itemDetails") String itemDetails,
+                          @SmartBindBean final InternalCallContext context);
+
     @SqlQuery
     List<InvoiceItemModelDao> getInvoiceItemsByParentInvoice(@Bind("parentInvoiceId") final String parentInvoiceId,
                                                              @SmartBindBean final InternalTenantContext context);
diff --git a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
index 72c9c9e..b4fe07f 100644
--- a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
@@ -83,6 +83,17 @@ updateAmount() ::= <<
     <AND_CHECK_TENANT("")>;
 >>
 
+
+updateItemFields() ::= <<
+    UPDATE <tableName()>
+    SET amount = coalesce(:amount, amount),
+        description = coalesce(:description, description),
+        item_details = coalesce(:itemDetails, item_details)
+    WHERE id = :id
+    <AND_CHECK_TENANT("")>;
+>>
+
+
 getInvoiceItemsByParentInvoice() ::= <<
   SELECT <allTableFields(("items."))>
   FROM <tableName()> items
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceItemSqlDao.java b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceItemSqlDao.java
new file mode 100644
index 0000000..e39f7df
--- /dev/null
+++ b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceItemSqlDao.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.invoice.dao;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.invoice.api.InvoiceItemType;
+import org.killbill.billing.util.UtilTestSuiteWithEmbeddedDB;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class TestInvoiceItemSqlDao extends UtilTestSuiteWithEmbeddedDB {
+
+    @Test(groups = "slow")
+    public void testUpdateItemFields() throws Exception {
+        final InvoiceItemSqlDao dao = dbi.onDemand(InvoiceItemSqlDao.class);
+
+        final UUID invoiceItemId = UUID.randomUUID();
+
+        dao.create(new InvoiceItemModelDao(invoiceItemId, null, InvoiceItemType.FIXED, UUID.randomUUID(), UUID.randomUUID(), null, null, null, "description",
+                                                                                                  null, null, null, null, new LocalDate(), null, BigDecimal.ONE, null, Currency.USD, null), internalCallContext);
+
+        // Update all fields
+        dao.updateItemFields(invoiceItemId.toString(), new BigDecimal("2.00"), "new description", "new items", internalCallContext);
+
+        InvoiceItemModelDao UpdatedItem = dao.getById(invoiceItemId.toString(), internalCallContext);
+        Assert.assertTrue(UpdatedItem.getAmount().compareTo(new BigDecimal("2.00")) == 0);
+        Assert.assertEquals(UpdatedItem.getDescription(), "new description");
+        Assert.assertEquals(UpdatedItem.getItemDetails(), "new items");
+
+        // Update just amount
+        dao.updateItemFields(invoiceItemId.toString(), new BigDecimal("3.00"), null, null, internalCallContext);
+        UpdatedItem = dao.getById(invoiceItemId.toString(), internalCallContext);
+        Assert.assertTrue(UpdatedItem.getAmount().compareTo(new BigDecimal("3.00")) == 0);
+        Assert.assertEquals(UpdatedItem.getDescription(), "new description");
+        Assert.assertEquals(UpdatedItem.getItemDetails(), "new items");
+
+
+        // Update just description
+        dao.updateItemFields(invoiceItemId.toString(), null, "newer description", null, internalCallContext);
+        UpdatedItem = dao.getById(invoiceItemId.toString(), internalCallContext);
+        Assert.assertTrue(UpdatedItem.getAmount().compareTo(new BigDecimal("3.00")) == 0);
+        Assert.assertEquals(UpdatedItem.getDescription(), "newer description");
+        Assert.assertEquals(UpdatedItem.getItemDetails(), "new items");
+
+
+
+    }
+}