killbill-aplcache

invoice: fix invoice tracking auditing Signed-off-by:

2/12/2019 7:59:42 AM

Details

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 b0fe792..f419f2d 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
@@ -1219,7 +1219,17 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                 // Deactivate any usage trackingIds if necessary
                 } else if (InvoiceStatus.VOID.equals(newStatus)) {
                     final InvoiceTrackingSqlDao trackingSqlDao = entitySqlDaoWrapperFactory.become(InvoiceTrackingSqlDao.class);
-                    trackingSqlDao.deactivateForInvoice(invoiceId.toString(), context);
+                    final List<InvoiceTrackingModelDao> invoiceTrackingModelDaos = trackingSqlDao.getTrackingsForInvoice(invoiceId.toString(), context);
+                    if (!invoiceTrackingModelDaos.isEmpty()) {
+                        final Collection<String> invoiceTrackingIdsToDeactivate = Collections2.<InvoiceTrackingModelDao, String>transform(invoiceTrackingModelDaos,
+                                                                                                                                          new Function<InvoiceTrackingModelDao, String>() {
+                                                                                                                                              @Override
+                                                                                                                                              public String apply(final InvoiceTrackingModelDao input) {
+                                                                                                                                                  return input.getId().toString();
+                                                                                                                                              }
+                                                                                                                                          });
+                        trackingSqlDao.deactivateByIds(invoiceTrackingIdsToDeactivate, context);
+                    }
                 }
                 return null;
             }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceTrackingSqlDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceTrackingSqlDao.java
index 49e8b8e..f1eeab5 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceTrackingSqlDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceTrackingSqlDao.java
@@ -17,6 +17,7 @@
 
 package org.killbill.billing.invoice.dao;
 
+import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 
@@ -31,14 +32,15 @@ import org.killbill.commons.jdbi.template.KillBillSqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.unstable.BindIn;
 
 @KillBillSqlDaoStringTemplate
 public interface InvoiceTrackingSqlDao extends EntitySqlDao<InvoiceTrackingModelDao, Entity> {
 
     @SqlUpdate
     @Audited(ChangeType.DELETE)
-    public void deactivateForInvoice(@Bind("invoiceId") String invoiceId,
-                                     @SmartBindBean final InternalCallContext context);
+    public void deactivateByIds(@BindIn("ids") final Collection<String> ids,
+                                @SmartBindBean final InternalCallContext context);
 
     @SqlQuery
     List<InvoiceTrackingModelDao> getTrackingsByDateRange(@Bind("startDate") final Date startDate,
diff --git a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceTrackingSqlDao.sql.stg b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceTrackingSqlDao.sql.stg
index 9add3fe..b20293a 100644
--- a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceTrackingSqlDao.sql.stg
+++ b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceTrackingSqlDao.sql.stg
@@ -28,14 +28,13 @@ tableValues() ::= <<
 , :updatedDate
 >>
 
-deactivateForInvoice() ::= <<
+deactivateByIds() ::= <<
 update <tableName()>
 set
-is_active = false
+  is_active = false
 , updated_by = :createdBy
 , updated_date = :updatedDate
-where
-invoice_id = :invoiceId
+where <idField("")> in (<ids>)
 <AND_CHECK_TENANT("")>
 ;
 >>
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceTrackingSqlDao.java b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceTrackingSqlDao.java
index 0072f3d..8c42ce5 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceTrackingSqlDao.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceTrackingSqlDao.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2018 Groupon, Inc
- * Copyright 2014-2018 The Billing Project, LLC
+ * Copyright 2014-2019 Groupon, Inc
+ * Copyright 2014-2019 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
@@ -24,15 +24,33 @@ import java.util.UUID;
 import org.joda.time.LocalDate;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.invoice.InvoiceTestSuiteWithEmbeddedDB;
+import org.killbill.billing.util.audit.ChangeType;
+import org.killbill.billing.util.audit.dao.AuditLogModelDao;
+import org.killbill.billing.util.cache.CacheControllerDispatcher;
+import org.killbill.billing.util.dao.TableName;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
 import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.ImmutableList;
+
 public class TestInvoiceTrackingSqlDao extends InvoiceTestSuiteWithEmbeddedDB {
 
+    private EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
+
+    @BeforeMethod(groups = "slow")
+    public void setUp() {
+        if (hasFailed()) {
+            return;
+        }
+        transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, roDbi, clock, new CacheControllerDispatcher(), nonEntityDao, internalCallContextFactory);
+    }
+
     @Test(groups = "slow")
     public void testBasicTrackingIds() {
-        final InvoiceTrackingSqlDao dao = dbi.onDemand(InvoiceTrackingSqlDao.class);
-
         LocalDate startRange = new LocalDate(2018, 8, 1);
         LocalDate endRange = new LocalDate(2018, 11, 23);
 
@@ -57,32 +75,39 @@ public class TestInvoiceTrackingSqlDao extends InvoiceTestSuiteWithEmbeddedDB {
         inputs.add(input3);
         inputs.add(input4);
 
-        dao.create(inputs, internalCallContext);
+        transactionalSqlDao.execute(false,
+                                    new EntitySqlDaoTransactionWrapper<Void>() {
+                                        @Override
+                                        public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
+                                            final InvoiceTrackingSqlDao dao = entitySqlDaoWrapperFactory.become(InvoiceTrackingSqlDao.class);
+
+                                            dao.create(inputs, internalCallContext);
 
-        final List<InvoiceTrackingModelDao> result = dao.getTrackingsByDateRange(startRange.toDate(), endRange.toDate(), internalCallContext);
-        Assert.assertEquals(result.size(), 3);
+                                            final List<InvoiceTrackingModelDao> result = dao.getTrackingsByDateRange(startRange.toDate(), endRange.toDate(), internalCallContext);
+                                            Assert.assertEquals(result.size(), 3);
 
-        Assert.assertEquals(result.get(0).getTrackingId(), "trackingId1");
-        Assert.assertEquals(result.get(0).getInvoiceId(), invoiceId1);
-        Assert.assertEquals(result.get(0).getRecordDate(), startRange);
-        Assert.assertEquals(result.get(0).getSubscriptionId(), subscriptionId);
+                                            Assert.assertEquals(result.get(0).getTrackingId(), "trackingId1");
+                                            Assert.assertEquals(result.get(0).getInvoiceId(), invoiceId1);
+                                            Assert.assertEquals(result.get(0).getRecordDate(), startRange);
+                                            Assert.assertEquals(result.get(0).getSubscriptionId(), subscriptionId);
 
-        Assert.assertEquals(result.get(1).getTrackingId(), "trackingId2");
-        Assert.assertEquals(result.get(1).getInvoiceId(), invoiceId1);
-        Assert.assertEquals(result.get(1).getRecordDate(), new LocalDate(2018, 8, 5));
-        Assert.assertEquals(result.get(1).getSubscriptionId(), subscriptionId);
+                                            Assert.assertEquals(result.get(1).getTrackingId(), "trackingId2");
+                                            Assert.assertEquals(result.get(1).getInvoiceId(), invoiceId1);
+                                            Assert.assertEquals(result.get(1).getRecordDate(), new LocalDate(2018, 8, 5));
+                                            Assert.assertEquals(result.get(1).getSubscriptionId(), subscriptionId);
 
-        Assert.assertEquals(result.get(2).getTrackingId(), "trackingId3");
-        Assert.assertEquals(result.get(2).getInvoiceId(), invoiceId2);
-        Assert.assertEquals(result.get(2).getRecordDate(), new LocalDate(2018, 9, 1));
-        Assert.assertEquals(result.get(2).getSubscriptionId(), subscriptionId);
+                                            Assert.assertEquals(result.get(2).getTrackingId(), "trackingId3");
+                                            Assert.assertEquals(result.get(2).getInvoiceId(), invoiceId2);
+                                            Assert.assertEquals(result.get(2).getRecordDate(), new LocalDate(2018, 9, 1));
+                                            Assert.assertEquals(result.get(2).getSubscriptionId(), subscriptionId);
 
+                                            return null;
+                                        }
+                                    });
     }
 
     @Test(groups = "slow")
     public void testInvalidation() {
-        final InvoiceTrackingSqlDao dao = dbi.onDemand(InvoiceTrackingSqlDao.class);
-
         LocalDate startRange = new LocalDate(2019, 1, 1);
         LocalDate endRange = new LocalDate(2019, 1, 31);
 
@@ -104,29 +129,56 @@ public class TestInvoiceTrackingSqlDao extends InvoiceTestSuiteWithEmbeddedDB {
         inputs.add(input3);
         inputs.add(input4);
 
-        dao.create(inputs, internalCallContext);
-
-        final List<InvoiceTrackingModelDao> result = dao.getTrackingsByDateRange(startRange.toDate(), endRange.toDate(), internalCallContext);
-        Assert.assertEquals(result.size(), 4);
-
-        clock.addDays(1);
-        final InternalCallContext updatedContext = new InternalCallContext(internalCallContext.getTenantRecordId(),
-                                                                           internalCallContext.getAccountRecordId(),
-                                                                           internalCallContext.getFixedOffsetTimeZone(),
-                                                                           clock.getUTCNow(),
-                                                                           internalCallContext.getUserToken(),
-                                                                           "invalidation-user",
-                                                                           internalCallContext.getCallOrigin(),
-                                                                           internalCallContext.getContextUserType(),
-                                                                           internalCallContext.getReasonCode(),
-                                                                           internalCallContext.getComments(),
-                                                                           internalCallContext.getCreatedDate(),
-                                                                           clock.getUTCNow());
-
-        dao.deactivateForInvoice(invoiceId1.toString(), updatedContext);
-
-        final List<InvoiceTrackingModelDao> result2 = dao.getTrackingsByDateRange(startRange.toDate(), endRange.toDate(), internalCallContext);
-        Assert.assertEquals(result2.size(), 1);
-
+        transactionalSqlDao.execute(false,
+                                    new EntitySqlDaoTransactionWrapper<Void>() {
+                                        @Override
+                                        public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
+                                            final InvoiceTrackingSqlDao dao = entitySqlDaoWrapperFactory.become(InvoiceTrackingSqlDao.class);
+
+                                            dao.create(inputs, internalCallContext);
+
+                                            final List<InvoiceTrackingModelDao> result = dao.getTrackingsByDateRange(startRange.toDate(), endRange.toDate(), internalCallContext);
+                                            Assert.assertEquals(result.size(), 4);
+
+                                            final List<AuditLogModelDao> auditLogsPostCreate = ImmutableList.<AuditLogModelDao>copyOf(dao.getAuditLogsForTableNameAndAccountRecordId(TableName.INVOICE_TRACKING_IDS.toString(), internalCallContext));
+                                            Assert.assertEquals(auditLogsPostCreate.size(), 4);
+                                            for (int i = 0; i < 4; i++) {
+                                                Assert.assertEquals(auditLogsPostCreate.get(i).getChangeType(), ChangeType.INSERT);
+                                                Assert.assertEquals(auditLogsPostCreate.get(i).getTargetRecordId(), result.get(i).getRecordId());
+                                            }
+
+                                            clock.addDays(1);
+                                            final InternalCallContext updatedContext = new InternalCallContext(internalCallContext.getTenantRecordId(),
+                                                                                                               internalCallContext.getAccountRecordId(),
+                                                                                                               internalCallContext.getFixedOffsetTimeZone(),
+                                                                                                               clock.getUTCNow(),
+                                                                                                               internalCallContext.getUserToken(),
+                                                                                                               "invalidation-user",
+                                                                                                               internalCallContext.getCallOrigin(),
+                                                                                                               internalCallContext.getContextUserType(),
+                                                                                                               internalCallContext.getReasonCode(),
+                                                                                                               internalCallContext.getComments(),
+                                                                                                               internalCallContext.getCreatedDate(),
+                                                                                                               clock.getUTCNow());
+
+                                            dao.deactivateByIds(ImmutableList.<String>of(input1.getId().toString(), input2.getId().toString(), input3.getId().toString()), updatedContext);
+
+                                            final List<InvoiceTrackingModelDao> result2 = dao.getTrackingsByDateRange(startRange.toDate(), endRange.toDate(), internalCallContext);
+                                            Assert.assertEquals(result2.size(), 1);
+
+                                            final List<AuditLogModelDao> auditLogsPostDelete = ImmutableList.<AuditLogModelDao>copyOf(dao.getAuditLogsForTableNameAndAccountRecordId(TableName.INVOICE_TRACKING_IDS.toString(), internalCallContext));
+                                            Assert.assertEquals(auditLogsPostDelete.size(), 7);
+                                            for (int i = 0; i < 4; i++) {
+                                                Assert.assertEquals(auditLogsPostDelete.get(i).getChangeType(), ChangeType.INSERT);
+                                                Assert.assertEquals(auditLogsPostDelete.get(i).getTargetRecordId(), result.get(i).getRecordId());
+                                            }
+                                            for (int i = 4; i < 7; i++) {
+                                                Assert.assertEquals(auditLogsPostDelete.get(i).getChangeType(), ChangeType.DELETE);
+                                                Assert.assertEquals(auditLogsPostDelete.get(i).getTargetRecordId(), result.get(i - 4).getRecordId());
+                                            }
+
+                                            return null;
+                                        }
+                                    });
     }
 }
diff --git a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
index 0378027..2471a95 100644
--- a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
+++ b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
@@ -221,13 +221,10 @@ public class EntitySqlDaoWrapperInvocationHandler<S extends EntitySqlDao<M, E>, 
         // Get the current state before deletion for the history tables
         final Map<Long, M> deletedAndUpdatedEntities = new HashMap<Long, M>();
         if (changeType == ChangeType.DELETE) {
-            // TODO FIXME: this shouldn't happen (auditing for InvoiceTrackingSqlDao is broken)
-            if (!entityIds.isEmpty()) {
-                final List<M> entitiesToBeDeleted = sqlDao.getByIds(entityIds, contextMaybeWithoutAccountRecordId);
-                printSQLWarnings();
-                for (final M entityToBeDeleted : entitiesToBeDeleted) {
-                    deletedAndUpdatedEntities.put(entityToBeDeleted.getRecordId(), entityToBeDeleted);
-                }
+            final List<M> entitiesToBeDeleted = sqlDao.getByIds(entityIds, contextMaybeWithoutAccountRecordId);
+            printSQLWarnings();
+            for (final M entityToBeDeleted : entitiesToBeDeleted) {
+                deletedAndUpdatedEntities.put(entityToBeDeleted.getRecordId(), entityToBeDeleted);
             }
         }