killbill-memoizeit
Changes
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsListener.java 13(+5 -8)
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/api/user/AnalyticsUserApi.java 13(+5 -8)
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoiceAndInvoicePaymentDao.java 173(+173 -0)
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoiceDao.java 393(+259 -134)
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoicePaymentDao.java 115(+49 -66)
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceAdjustmentModelDao.java 5(+5 -0)
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemAdjustmentModelDao.java 5(+5 -0)
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemBaseModelDao.java 48(+27 -21)
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemCreditModelDao.java 5(+5 -0)
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemModelDao.java 5(+5 -0)
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceModelDao.java 40(+31 -9)
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoicePaymentBaseModelDao.java 38(+21 -17)
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/utils/BusinessInvoiceUtils.java 155(+155 -0)
osgi-bundles/bundles/analytics/src/main/resources/com/ning/billing/osgi/bundles/analytics/dao/BusinessAnalyticsSqlDao.sql.stg 16(+16 -0)
osgi-bundles/bundles/analytics/src/main/resources/com/ning/billing/osgi/bundles/analytics/ddl.sql 8(+8 -0)
osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/AnalyticsTestSuiteNoDB.java 79(+77 -2)
osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/api/TestBusinessInvoice.java 9(+9 -0)
osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/api/TestBusinessSnapshot.java 3(+3 -0)
osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoiceItemModelDao.java 11(+6 -5)
osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoiceModelDao.java 22(+17 -5)
osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoicePaymentModelDao.java 11(+6 -5)
osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/TestBusinessAnalyticsSqlDao.java 3(+3 -0)
Details
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsListener.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsListener.java
index 2ded659..3a18bb0 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsListener.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsListener.java
@@ -29,8 +29,7 @@ import com.ning.billing.commons.locker.GlobalLocker;
import com.ning.billing.commons.locker.mysql.MySqlGlobalLocker;
import com.ning.billing.osgi.bundles.analytics.dao.BusinessAccountDao;
import com.ning.billing.osgi.bundles.analytics.dao.BusinessFieldDao;
-import com.ning.billing.osgi.bundles.analytics.dao.BusinessInvoiceDao;
-import com.ning.billing.osgi.bundles.analytics.dao.BusinessInvoicePaymentDao;
+import com.ning.billing.osgi.bundles.analytics.dao.BusinessInvoiceAndInvoicePaymentDao;
import com.ning.billing.osgi.bundles.analytics.dao.BusinessOverdueStatusDao;
import com.ning.billing.osgi.bundles.analytics.dao.BusinessSubscriptionTransitionDao;
import com.ning.billing.osgi.bundles.analytics.dao.BusinessTagDao;
@@ -50,8 +49,7 @@ public class AnalyticsListener implements OSGIKillbillEventHandler {
private final LogService logService;
private final BusinessAccountDao bacDao;
private final BusinessSubscriptionTransitionDao bstDao;
- private final BusinessInvoiceDao binDao;
- private final BusinessInvoicePaymentDao bipDao;
+ private final BusinessInvoiceAndInvoicePaymentDao binAndBipDao;
private final BusinessOverdueStatusDao bosDao;
private final BusinessFieldDao bFieldDao;
private final BusinessTagDao bTagDao;
@@ -64,8 +62,7 @@ public class AnalyticsListener implements OSGIKillbillEventHandler {
this.bacDao = new BusinessAccountDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
this.bstDao = new BusinessSubscriptionTransitionDao(logService, osgiKillbillAPI, osgiKillbillDataSource, bacDao);
- this.binDao = new BusinessInvoiceDao(logService, osgiKillbillAPI, osgiKillbillDataSource, bacDao);
- this.bipDao = new BusinessInvoicePaymentDao(logService, osgiKillbillAPI, osgiKillbillDataSource, bacDao, binDao);
+ this.binAndBipDao = new BusinessInvoiceAndInvoicePaymentDao(logService, osgiKillbillAPI, osgiKillbillDataSource, bacDao);
this.bosDao = new BusinessOverdueStatusDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
this.bFieldDao = new BusinessFieldDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
this.bTagDao = new BusinessTagDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
@@ -135,7 +132,7 @@ public class AnalyticsListener implements OSGIKillbillEventHandler {
updateWithAccountLock(killbillEvent, new Callable<Void>() {
@Override
public Void call() throws Exception {
- binDao.update(killbillEvent.getAccountId(), callContext);
+ binAndBipDao.update(killbillEvent.getAccountId(), callContext);
return null;
}
});
@@ -145,7 +142,7 @@ public class AnalyticsListener implements OSGIKillbillEventHandler {
updateWithAccountLock(killbillEvent, new Callable<Void>() {
@Override
public Void call() throws Exception {
- bipDao.update(killbillEvent.getAccountId(), callContext);
+ binAndBipDao.update(killbillEvent.getAccountId(), callContext);
return null;
}
});
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/api/user/AnalyticsUserApi.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/api/user/AnalyticsUserApi.java
index f3d573c..8826361 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/api/user/AnalyticsUserApi.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/api/user/AnalyticsUserApi.java
@@ -35,8 +35,7 @@ import com.ning.billing.osgi.bundles.analytics.api.BusinessTag;
import com.ning.billing.osgi.bundles.analytics.dao.AnalyticsDao;
import com.ning.billing.osgi.bundles.analytics.dao.BusinessAccountDao;
import com.ning.billing.osgi.bundles.analytics.dao.BusinessFieldDao;
-import com.ning.billing.osgi.bundles.analytics.dao.BusinessInvoiceDao;
-import com.ning.billing.osgi.bundles.analytics.dao.BusinessInvoicePaymentDao;
+import com.ning.billing.osgi.bundles.analytics.dao.BusinessInvoiceAndInvoicePaymentDao;
import com.ning.billing.osgi.bundles.analytics.dao.BusinessOverdueStatusDao;
import com.ning.billing.osgi.bundles.analytics.dao.BusinessSubscriptionTransitionDao;
import com.ning.billing.osgi.bundles.analytics.dao.BusinessTagDao;
@@ -51,8 +50,7 @@ public class AnalyticsUserApi extends BusinessAnalyticsBase {
private final AnalyticsDao analyticsDao;
private final BusinessAccountDao bacDao;
private final BusinessSubscriptionTransitionDao bstDao;
- private final BusinessInvoiceDao binDao;
- private final BusinessInvoicePaymentDao bipDao;
+ private final BusinessInvoiceAndInvoicePaymentDao binAndBipDao;
private final BusinessOverdueStatusDao bosDao;
private final BusinessFieldDao bFieldDao;
private final BusinessTagDao bTagDao;
@@ -64,8 +62,7 @@ public class AnalyticsUserApi extends BusinessAnalyticsBase {
this.analyticsDao = new AnalyticsDao(osgiKillbillAPI, osgiKillbillDataSource);
this.bacDao = new BusinessAccountDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
this.bstDao = new BusinessSubscriptionTransitionDao(logService, osgiKillbillAPI, osgiKillbillDataSource, bacDao);
- this.binDao = new BusinessInvoiceDao(logService, osgiKillbillAPI, osgiKillbillDataSource, bacDao);
- this.bipDao = new BusinessInvoicePaymentDao(logService, osgiKillbillAPI, osgiKillbillDataSource, bacDao, binDao);
+ this.binAndBipDao = new BusinessInvoiceAndInvoicePaymentDao(logService, osgiKillbillAPI, osgiKillbillDataSource, bacDao);
this.bosDao = new BusinessOverdueStatusDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
this.bFieldDao = new BusinessFieldDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
this.bTagDao = new BusinessTagDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
@@ -103,8 +100,8 @@ public class AnalyticsUserApi extends BusinessAnalyticsBase {
public void rebuildAnalyticsForAccount(final UUID accountId, final CallContext context) throws AnalyticsRefreshException {
logService.log(LogService.LOG_INFO, "Starting rebuild of Analytics for account " + accountId);
- // Refresh payments. This will automatically trigger a refresh of invoices and account
- bipDao.update(accountId, context);
+ // Refresh invoices and payments. This will automatically trigger a refresh of account
+ binAndBipDao.update(accountId, context);
// Refresh BST
bstDao.update(accountId, context);
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoiceAndInvoicePaymentDao.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoiceAndInvoicePaymentDao.java
new file mode 100644
index 0000000..d41d613
--- /dev/null
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoiceAndInvoicePaymentDao.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.osgi.bundles.analytics.dao;
+
+import java.math.BigDecimal;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.UUID;
+
+import org.skife.jdbi.v2.Transaction;
+import org.skife.jdbi.v2.TransactionStatus;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.osgi.bundles.analytics.AnalyticsRefreshException;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessAccountModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceItemBaseModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoicePaymentBaseModelDao;
+import com.ning.billing.osgi.bundles.analytics.utils.BusinessInvoiceUtils;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.killbill.osgi.libs.killbill.OSGIKillbillAPI;
+import com.ning.killbill.osgi.libs.killbill.OSGIKillbillDataSource;
+import com.ning.killbill.osgi.libs.killbill.OSGIKillbillLogService;
+
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * Wrapper around BusinessInvoiceDao and BusinessInvoicePaymentDao.
+ * <p/>
+ * These two should always be updated together as invoice and payment information is denormalized across tables.
+ */
+public class BusinessInvoiceAndInvoicePaymentDao extends BusinessAnalyticsDaoBase {
+
+ private final BusinessAccountDao businessAccountDao;
+ private final BusinessInvoiceDao businessInvoiceDao;
+ private final BusinessInvoicePaymentDao businessInvoicePaymentDao;
+
+ public BusinessInvoiceAndInvoicePaymentDao(final OSGIKillbillLogService logService,
+ final OSGIKillbillAPI osgiKillbillAPI,
+ final OSGIKillbillDataSource osgiKillbillDataSource,
+ final BusinessAccountDao businessAccountDao) {
+ super(logService, osgiKillbillAPI, osgiKillbillDataSource);
+ this.businessAccountDao = businessAccountDao;
+ this.businessInvoiceDao = new BusinessInvoiceDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
+ this.businessInvoicePaymentDao = new BusinessInvoicePaymentDao(logService, osgiKillbillAPI, osgiKillbillDataSource);
+ }
+
+ public void update(final UUID accountId, final CallContext context) throws AnalyticsRefreshException {
+ final Account account = getAccount(accountId, context);
+
+ // Recompute the account record
+ final BusinessAccountModelDao bac = businessAccountDao.createBusinessAccount(account, context);
+
+ final Map<UUID, BusinessInvoiceModelDao> invoices = new HashMap<UUID, BusinessInvoiceModelDao>();
+ final Map<UUID, Collection<BusinessInvoiceItemBaseModelDao>> invoiceItems = new HashMap<UUID, Collection<BusinessInvoiceItemBaseModelDao>>();
+ final Map<UUID, Collection<BusinessInvoicePaymentBaseModelDao>> invoicePayments = new HashMap<UUID, Collection<BusinessInvoicePaymentBaseModelDao>>();
+ createBusinessPojos(account, invoices, invoiceItems, invoicePayments, context);
+
+ // Delete and recreate invoice and invoice items in the transaction
+ sqlDao.inTransaction(new Transaction<Void, BusinessAnalyticsSqlDao>() {
+ @Override
+ public Void inTransaction(final BusinessAnalyticsSqlDao transactional, final TransactionStatus status) throws Exception {
+ updateInTransaction(bac, invoices, invoiceItems, invoicePayments, transactional, context);
+ return null;
+ }
+ });
+ }
+
+ @VisibleForTesting
+ void createBusinessPojos(final Account account,
+ final Map<UUID, BusinessInvoiceModelDao> invoices,
+ final Map<UUID, Collection<BusinessInvoiceItemBaseModelDao>> invoiceItems,
+ final Map<UUID, Collection<BusinessInvoicePaymentBaseModelDao>> invoicePayments,
+ final CallContext context) throws AnalyticsRefreshException {
+ // Recompute all invoices and invoice items. Invoices will have their denormalized payment fields missing,
+ // and items won't have neither invoice nor payment denormalized fields populated
+ final Map<BusinessInvoiceModelDao, Collection<BusinessInvoiceItemBaseModelDao>> businessInvoices = businessInvoiceDao.createBusinessInvoicesAndInvoiceItems(account, context);
+
+ // Recompute all invoice payments (without denormalized payment fields populated)
+ final Collection<BusinessInvoicePaymentBaseModelDao> businessInvoicePayments = businessInvoicePaymentDao.createBusinessInvoicePayments(account, businessInvoices, context);
+
+ // Transform the results
+ for (final BusinessInvoiceModelDao businessInvoice : businessInvoices.keySet()) {
+ invoices.put(businessInvoice.getInvoiceId(), businessInvoice);
+ for (final BusinessInvoiceItemBaseModelDao businessInvoiceItem : businessInvoices.get(businessInvoice)) {
+ if (invoiceItems.get(businessInvoice.getInvoiceId()) == null) {
+ invoiceItems.put(businessInvoice.getInvoiceId(), new LinkedList<BusinessInvoiceItemBaseModelDao>());
+ }
+ invoiceItems.get(businessInvoice.getInvoiceId()).add(businessInvoiceItem);
+ }
+ }
+ for (final BusinessInvoicePaymentBaseModelDao businessInvoicePayment : businessInvoicePayments) {
+ if (invoicePayments.get(businessInvoicePayment.getInvoiceId()) == null) {
+ invoicePayments.put(businessInvoicePayment.getInvoiceId(), new LinkedList<BusinessInvoicePaymentBaseModelDao>());
+ }
+ invoicePayments.get(businessInvoicePayment.getInvoiceId()).add(businessInvoicePayment);
+ }
+
+ // Populate missing fields
+ populatedMissingDenormalizedFields(invoices, invoiceItems, invoicePayments);
+ }
+
+ private void populatedMissingDenormalizedFields(final Map<UUID, BusinessInvoiceModelDao> businessInvoices,
+ final Map<UUID, Collection<BusinessInvoiceItemBaseModelDao>> businessInvoiceItems,
+ final Map<UUID, Collection<BusinessInvoicePaymentBaseModelDao>> businessInvoicePayments) {
+ // First, populated missing payment fields in invoice
+ for (final BusinessInvoiceModelDao businessInvoice : businessInvoices.values()) {
+ final BigDecimal balance = BusinessInvoiceUtils.computeInvoiceBalance(businessInvoiceItems.get(businessInvoice.getInvoiceId()),
+ businessInvoicePayments.get(businessInvoice.getInvoiceId()));
+ businessInvoice.setBalance(balance);
+
+ final BigDecimal amountPaid = BusinessInvoiceUtils.computeInvoiceAmountPaid(businessInvoicePayments.get(businessInvoice.getInvoiceId()));
+ businessInvoice.setAmountPaid(amountPaid);
+
+ final BigDecimal amountRefunded = BusinessInvoiceUtils.computeInvoiceAmountRefunded(businessInvoicePayments.get(businessInvoice.getInvoiceId()));
+ businessInvoice.setAmountRefunded(amountRefunded);
+ }
+
+ // At this point, all of the invoice objects are fully populated. Use them to update the invoice items and payment objects
+ for (final UUID invoiceId : businessInvoices.keySet()) {
+ final Collection<BusinessInvoiceItemBaseModelDao> invoiceItemsForInvoice = businessInvoiceItems.get(invoiceId);
+ if (invoiceItemsForInvoice != null) {
+ for (final BusinessInvoiceItemBaseModelDao businessInvoiceItem : invoiceItemsForInvoice) {
+ businessInvoiceItem.populateDenormalizedInvoiceFields(businessInvoices.get(invoiceId));
+ }
+ }
+
+ final Collection<BusinessInvoicePaymentBaseModelDao> invoicePaymentsForInvoice = businessInvoicePayments.get(invoiceId);
+ if (invoicePaymentsForInvoice != null) {
+ for (final BusinessInvoicePaymentBaseModelDao businessInvoicePayment : invoicePaymentsForInvoice) {
+ businessInvoicePayment.populateDenormalizedInvoiceFields(businessInvoices.get(invoiceId));
+ }
+ }
+ }
+ }
+
+ private void updateInTransaction(final BusinessAccountModelDao bac,
+ final Map<UUID, BusinessInvoiceModelDao> invoices,
+ final Map<UUID, Collection<BusinessInvoiceItemBaseModelDao>> invoiceItems,
+ final Map<UUID, Collection<BusinessInvoicePaymentBaseModelDao>> invoicePayments,
+ final BusinessAnalyticsSqlDao transactional,
+ final CallContext context) throws AnalyticsRefreshException {
+ // Update invoice tables
+ businessInvoiceDao.updateInTransaction(bac, invoices, invoiceItems, transactional, context);
+
+ // Update invoice payment tables
+ // TODO flatten function?
+ final Collection<BusinessInvoicePaymentBaseModelDao> flattenedInvoicePayments = new LinkedList<BusinessInvoicePaymentBaseModelDao>();
+ for (final UUID invoiceId : invoicePayments.keySet()) {
+ flattenedInvoicePayments.addAll(invoicePayments.get(invoiceId));
+ }
+ businessInvoicePaymentDao.updateInTransaction(bac, flattenedInvoicePayments, transactional, context);
+
+ // Update invoice and payment details in BAC
+ businessAccountDao.updateInTransaction(bac, transactional, context);
+ }
+}
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoiceDao.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoiceDao.java
index 3654cc8..ee396ab 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoiceDao.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoiceDao.java
@@ -19,9 +19,11 @@ package com.ning.billing.osgi.bundles.analytics.dao;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
+import java.util.Set;
import java.util.UUID;
import javax.annotation.Nullable;
@@ -29,8 +31,6 @@ import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.osgi.service.log.LogService;
-import org.skife.jdbi.v2.Transaction;
-import org.skife.jdbi.v2.TransactionStatus;
import com.ning.billing.account.api.Account;
import com.ning.billing.catalog.api.Currency;
@@ -46,6 +46,7 @@ import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceItemBase
import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceItemBaseModelDao.BusinessInvoiceItemType;
import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceModelDao;
import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessModelDaoBase.ReportGroup;
+import com.ning.billing.osgi.bundles.analytics.utils.BusinessInvoiceUtils;
import com.ning.billing.util.audit.AuditLog;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.TenantContext;
@@ -58,88 +59,102 @@ import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.Collections2;
-public class BusinessInvoiceDao extends BusinessAnalyticsDaoBase {
+import static com.ning.billing.osgi.bundles.analytics.utils.BusinessInvoiceUtils.isAccountCreditItem;
+import static com.ning.billing.osgi.bundles.analytics.utils.BusinessInvoiceUtils.isCharge;
+import static com.ning.billing.osgi.bundles.analytics.utils.BusinessInvoiceUtils.isInvoiceAdjustmentItem;
+import static com.ning.billing.osgi.bundles.analytics.utils.BusinessInvoiceUtils.isInvoiceItemAdjustmentItem;
+import static com.ning.billing.osgi.bundles.analytics.utils.BusinessInvoiceUtils.isRevenueRecognizable;
- private final BusinessAccountDao businessAccountDao;
+public class BusinessInvoiceDao extends BusinessAnalyticsDaoBase {
public BusinessInvoiceDao(final OSGIKillbillLogService logService,
final OSGIKillbillAPI osgiKillbillAPI,
- final OSGIKillbillDataSource osgiKillbillDataSource,
- final BusinessAccountDao businessAccountDao) {
+ final OSGIKillbillDataSource osgiKillbillDataSource) {
super(logService, osgiKillbillAPI, osgiKillbillDataSource);
- this.businessAccountDao = businessAccountDao;
}
- public void update(final UUID accountId, final CallContext context) throws AnalyticsRefreshException {
- final Account account = getAccount(accountId, context);
-
- // Recompute the account record
- final BusinessAccountModelDao bac = businessAccountDao.createBusinessAccount(account, context);
+ public void updateInTransaction(final BusinessAccountModelDao bac,
+ final Map<UUID, BusinessInvoiceModelDao> businessInvoices,
+ final Map<UUID, Collection<BusinessInvoiceItemBaseModelDao>> businessInvoiceItems,
+ final BusinessAnalyticsSqlDao transactional,
+ final CallContext context) throws AnalyticsRefreshException {
+ rebuildInvoicesForAccountInTransaction(bac, businessInvoices, businessInvoiceItems, transactional, context);
+ // Invoice and payment details in BAC will be updated by BusinessInvoiceAndInvoicePaymentDao
+ }
- // Recompute all invoices and invoice items
- final Map<BusinessInvoiceModelDao, Collection<BusinessInvoiceItemBaseModelDao>> businessInvoices = createBusinessInvoicesAndInvoiceItems(account, context);
+ private void rebuildInvoicesForAccountInTransaction(final BusinessAccountModelDao account,
+ final Map<UUID, BusinessInvoiceModelDao> businessInvoices,
+ final Map<UUID, Collection<BusinessInvoiceItemBaseModelDao>> businessInvoiceItems,
+ final BusinessAnalyticsSqlDao transactional,
+ final CallContext context) {
+ deleteInvoicesAndInvoiceItemsForAccountInTransaction(transactional, account.getAccountRecordId(), account.getTenantRecordId(), context);
- // Delete and recreate invoice and invoice items in the transaction
- sqlDao.inTransaction(new Transaction<Void, BusinessAnalyticsSqlDao>() {
- @Override
- public Void inTransaction(final BusinessAnalyticsSqlDao transactional, final TransactionStatus status) throws Exception {
- updateInTransaction(bac, businessInvoices, transactional, context);
- return null;
+ for (final BusinessInvoiceModelDao businessInvoice : businessInvoices.values()) {
+ final Collection<BusinessInvoiceItemBaseModelDao> invoiceItems = businessInvoiceItems.get(businessInvoice.getInvoiceId());
+ if (invoiceItems != null) {
+ createInvoiceInTransaction(transactional, businessInvoice, invoiceItems, context);
}
- });
+ }
}
- public void updateInTransaction(final BusinessAccountModelDao bac,
- final Map<BusinessInvoiceModelDao, Collection<BusinessInvoiceItemBaseModelDao>> businessInvoices,
- final BusinessAnalyticsSqlDao transactional,
- final CallContext context) throws AnalyticsRefreshException {
- rebuildInvoicesForAccountInTransaction(bac, businessInvoices, transactional, context);
+ private void deleteInvoicesAndInvoiceItemsForAccountInTransaction(final BusinessAnalyticsSqlDao transactional,
+ final Long accountRecordId,
+ final Long tenantRecordId,
+ final CallContext context) {
+ // Delete all invoice items
+ for (final String tableName : BusinessInvoiceItemBaseModelDao.ALL_INVOICE_ITEMS_TABLE_NAMES) {
+ transactional.deleteByAccountRecordId(tableName, accountRecordId, tenantRecordId, context);
+ }
- // Update invoice and payment details in BAC
- businessAccountDao.updateInTransaction(bac, transactional, context);
+ // Delete all invoices
+ transactional.deleteByAccountRecordId(BusinessInvoiceModelDao.INVOICES_TABLE_NAME, accountRecordId, tenantRecordId, context);
}
+ private void createInvoiceInTransaction(final BusinessAnalyticsSqlDao transactional,
+ final BusinessInvoiceModelDao invoice,
+ final Iterable<BusinessInvoiceItemBaseModelDao> invoiceItems,
+ final CallContext context) {
+ // Create the invoice
+ transactional.create(invoice.getTableName(), invoice, context);
+
+ // Add associated invoice items
+ for (final BusinessInvoiceItemBaseModelDao invoiceItem : invoiceItems) {
+ transactional.create(invoiceItem.getTableName(), invoiceItem, context);
+ }
+ }
+
+ /**
+ * Create business invoices and invoice items to record. Note that these POJOs are incomplete
+ * (denormalized payment fields have not yet been populated)
+ *
+ * @param account current account refreshed
+ * @param context call context
+ * @return all business invoice and invoice items to create
+ * @throws AnalyticsRefreshException
+ */
public Map<BusinessInvoiceModelDao, Collection<BusinessInvoiceItemBaseModelDao>> createBusinessInvoicesAndInvoiceItems(final Account account,
final CallContext context) throws AnalyticsRefreshException {
final Long accountRecordId = getAccountRecordId(account.getId(), context);
final Long tenantRecordId = getTenantRecordId(context);
final ReportGroup reportGroup = getReportGroup(account.getId(), context);
- final Map<UUID, BusinessInvoiceModelDao> businessInvoices = new HashMap<UUID, BusinessInvoiceModelDao>();
- final Map<UUID, Collection<BusinessInvoiceItemBaseModelDao>> businessInvoiceItems = new HashMap<UUID, Collection<BusinessInvoiceItemBaseModelDao>>();
-
- // All invoice items across all invoices for that account
- // We need to be able to reference items across multiple invoices
- final Collection<InvoiceItem> allInvoiceItems = new LinkedList<InvoiceItem>();
-
// Lookup the invoices for that account
final Collection<Invoice> invoices = getInvoicesByAccountId(account.getId(), context);
- // Create a convenient mapping invoice_id -> invoice
+ // All invoice items across all invoices for that accounr (we need to be able to reference items across multiple invoices)
+ final Collection<InvoiceItem> allInvoiceItems = new LinkedList<InvoiceItem>();
+ // Convenient mapping invoice_id -> invoice
final Map<UUID, Invoice> invoiceIdToInvoiceMappings = new LinkedHashMap<UUID, Invoice>();
-
- // Create the business invoices
for (final Invoice invoice : invoices) {
invoiceIdToInvoiceMappings.put(invoice.getId(), invoice);
allInvoiceItems.addAll(invoice.getInvoiceItems());
-
- final Long invoiceRecordId = getInvoiceRecordId(invoice.getId(), context);
- final AuditLog creationAuditLog = getInvoiceCreationAuditLog(invoice.getId(), context);
- final BusinessInvoiceModelDao businessInvoice = new BusinessInvoiceModelDao(account,
- accountRecordId,
- invoice,
- invoiceRecordId,
- creationAuditLog,
- tenantRecordId,
- reportGroup);
-
- businessInvoices.put(invoice.getId(), businessInvoice);
}
// Sanitize (cherry-pick, merge) the items
final Collection<InvoiceItem> sanitizedInvoiceItems = sanitizeInvoiceItems(allInvoiceItems);
- // Create the business invoice items
+ // Create the business invoice items. These are incomplete (the denormalized invoice fields haven't been computed yet)
+ final Map<UUID, Collection<BusinessInvoiceItemBaseModelDao>> businessInvoiceItemsForInvoiceId = new HashMap<UUID, Collection<BusinessInvoiceItemBaseModelDao>>();
for (final InvoiceItem invoiceItem : sanitizedInvoiceItems) {
final Invoice invoice = invoiceIdToInvoiceMappings.get(invoiceItem.getInvoiceId());
final BusinessInvoiceItemBaseModelDao businessInvoiceItem = createBusinessInvoiceItem(account,
@@ -157,59 +172,52 @@ public class BusinessInvoiceDao extends BusinessAnalyticsDaoBase {
reportGroup,
context);
if (businessInvoiceItem != null) {
- if (businessInvoiceItems.get(invoice.getId()) == null) {
- businessInvoiceItems.put(invoice.getId(), new LinkedList<BusinessInvoiceItemBaseModelDao>());
+ if (businessInvoiceItemsForInvoiceId.get(invoice.getId()) == null) {
+ businessInvoiceItemsForInvoiceId.put(invoice.getId(), new LinkedList<BusinessInvoiceItemBaseModelDao>());
}
- businessInvoiceItems.get(invoice.getId()).add(businessInvoiceItem);
+ businessInvoiceItemsForInvoiceId.get(invoice.getId()).add(businessInvoiceItem);
}
}
+ // Now, create the business invoices
final Map<BusinessInvoiceModelDao, Collection<BusinessInvoiceItemBaseModelDao>> businessRecords = new HashMap<BusinessInvoiceModelDao, Collection<BusinessInvoiceItemBaseModelDao>>();
- for (final BusinessInvoiceModelDao businessInvoiceModelDao : businessInvoices.values()) {
- businessRecords.put(businessInvoiceModelDao, businessInvoiceItems.get(businessInvoiceModelDao.getInvoiceId()));
- }
-
- return businessRecords;
- }
-
- private void rebuildInvoicesForAccountInTransaction(final BusinessAccountModelDao account,
- final Map<BusinessInvoiceModelDao, Collection<BusinessInvoiceItemBaseModelDao>> businessInvoices,
- final BusinessAnalyticsSqlDao transactional,
- final CallContext context) {
- deleteInvoicesAndInvoiceItemsForAccountInTransaction(transactional, account.getAccountRecordId(), account.getTenantRecordId(), context);
-
- for (final BusinessInvoiceModelDao businessInvoice : businessInvoices.keySet()) {
- final Collection<BusinessInvoiceItemBaseModelDao> invoiceItems = businessInvoices.get(businessInvoice);
- if (invoiceItems != null) {
- createInvoiceInTransaction(transactional, businessInvoice, invoiceItems, context);
+ for (final Invoice invoice : invoices) {
+ final Collection<BusinessInvoiceItemBaseModelDao> businessInvoiceItems = businessInvoiceItemsForInvoiceId.get(invoice.getId());
+ if (businessInvoiceItems == null) {
+ continue;
}
- }
- }
- private void deleteInvoicesAndInvoiceItemsForAccountInTransaction(final BusinessAnalyticsSqlDao transactional,
- final Long accountRecordId,
- final Long tenantRecordId,
- final CallContext context) {
- // Delete all invoice items
- for (final String tableName : BusinessInvoiceItemBaseModelDao.ALL_INVOICE_ITEMS_TABLE_NAMES) {
- transactional.deleteByAccountRecordId(tableName, accountRecordId, tenantRecordId, context);
+ final BusinessInvoiceModelDao businessInvoice = createBusinessInvoice(account, invoice, businessInvoiceItems, accountRecordId, tenantRecordId, reportGroup, context);
+ businessRecords.put(businessInvoice, businessInvoiceItems);
}
- // Delete all invoices
- transactional.deleteByAccountRecordId(BusinessInvoiceModelDao.INVOICES_TABLE_NAME, accountRecordId, tenantRecordId, context);
+ return businessRecords;
}
- private void createInvoiceInTransaction(final BusinessAnalyticsSqlDao transactional,
- final BusinessInvoiceModelDao invoice,
- final Iterable<BusinessInvoiceItemBaseModelDao> invoiceItems,
- final CallContext context) {
- // Create the invoice
- transactional.create(invoice.getTableName(), invoice, context);
-
- // Add associated invoice items
- for (final BusinessInvoiceItemBaseModelDao invoiceItem : invoiceItems) {
- transactional.create(invoiceItem.getTableName(), invoiceItem, context);
- }
+ private BusinessInvoiceModelDao createBusinessInvoice(final Account account,
+ final Invoice invoice,
+ final Collection<BusinessInvoiceItemBaseModelDao> businessInvoiceItems,
+ final Long accountRecordId,
+ final Long tenantRecordId,
+ @Nullable final ReportGroup reportGroup,
+ final CallContext context) throws AnalyticsRefreshException {
+ final Long invoiceRecordId = getInvoiceRecordId(invoice.getId(), context);
+ final AuditLog creationAuditLog = getInvoiceCreationAuditLog(invoice.getId(), context);
+
+ final BigDecimal amountCharged = BusinessInvoiceUtils.computeInvoiceAmountCharged(businessInvoiceItems);
+ final BigDecimal originalAmountCharged = BusinessInvoiceUtils.computeInvoiceOriginalAmountCharged(businessInvoiceItems);
+ final BigDecimal amountCredited = BusinessInvoiceUtils.computeInvoiceAmountCredited(businessInvoiceItems);
+
+ return new BusinessInvoiceModelDao(account,
+ accountRecordId,
+ invoice,
+ amountCharged,
+ originalAmountCharged,
+ amountCredited,
+ invoiceRecordId,
+ creationAuditLog,
+ tenantRecordId,
+ reportGroup);
}
private BusinessInvoiceItemBaseModelDao createBusinessInvoiceItem(final Account account,
@@ -307,46 +315,13 @@ public class BusinessInvoiceDao extends BusinessAnalyticsDaoBase {
reportGroup);
}
- private Boolean isRevenueRecognizable(final InvoiceItem invoiceItem, final Collection<InvoiceItem> otherInvoiceItems) {
- // All items are recognizable except user generated credit (CBA_ADJ and CREDIT_ADJ on their own invoice)
- return !(InvoiceItemType.CBA_ADJ.equals(invoiceItem.getInvoiceItemType()) &&
- (otherInvoiceItems.size() == 1 &&
- InvoiceItemType.CREDIT_ADJ.equals(otherInvoiceItems.iterator().next().getInvoiceItemType()) &&
- otherInvoiceItems.iterator().next().getInvoiceId().equals(invoiceItem.getInvoiceId()) &&
- otherInvoiceItems.iterator().next().getAmount().compareTo(invoiceItem.getAmount().negate()) == 0));
- }
-
- // Invoice adjustments
- @VisibleForTesting
- boolean isInvoiceAdjustmentItem(final InvoiceItem invoiceItem, final Collection<InvoiceItem> otherInvoiceItems) {
- // Either REFUND_ADJ
- return InvoiceItemType.REFUND_ADJ.equals(invoiceItem.getInvoiceItemType()) ||
- // Or invoice level credit, i.e. credit adj, but NOT on its on own invoice
- // Note: the negative credit adj items (internal generation of account level credits) doesn't figure in analytics
- (InvoiceItemType.CREDIT_ADJ.equals(invoiceItem.getInvoiceItemType()) &&
- !(otherInvoiceItems.size() == 1 &&
- InvoiceItemType.CBA_ADJ.equals(otherInvoiceItems.iterator().next().getInvoiceItemType()) &&
- otherInvoiceItems.iterator().next().getInvoiceId().equals(invoiceItem.getInvoiceId()) &&
- otherInvoiceItems.iterator().next().getAmount().compareTo(invoiceItem.getAmount().negate()) == 0));
- }
-
- // Item adjustments
- private boolean isInvoiceItemAdjustmentItem(final InvoiceItem invoiceItem) {
- return InvoiceItemType.ITEM_ADJ.equals(invoiceItem.getInvoiceItemType());
- }
-
- // Account credits, gained or consumed
- private boolean isAccountCreditItem(final InvoiceItem invoiceItem) {
- return InvoiceItemType.CBA_ADJ.equals(invoiceItem.getInvoiceItemType());
- }
-
- // Regular line item (charges)
- private boolean isCharge(final InvoiceItem invoiceItem) {
- return InvoiceItemType.EXTERNAL_CHARGE.equals(invoiceItem.getInvoiceItemType()) ||
- InvoiceItemType.FIXED.equals(invoiceItem.getInvoiceItemType()) ||
- InvoiceItemType.RECURRING.equals(invoiceItem.getInvoiceItemType());
- }
-
+ /**
+ * Filter and transform the original invoice items for Analytics purposes. We mainly
+ * merge REPAIR_ADJ items with reparation items (reparees) to create item adjustments.
+ *
+ * @param allInvoiceItems all items for the current account
+ * @return invoice items interesting for Analytics purposes
+ */
@VisibleForTesting
Collection<InvoiceItem> sanitizeInvoiceItems(final Collection<InvoiceItem> allInvoiceItems) {
// Build a convenience mapping between items -> repair_adj items (inverse of linkedItemId)
@@ -390,10 +365,50 @@ public class BusinessInvoiceDao extends BusinessAnalyticsDaoBase {
}
}
+ // We now need to adjust the CBA_ADJ for the repair items
+ final Set<UUID> cbasToIgnore = new HashSet<UUID>();
+ final Collection<AdjustedCBAInvoiceItem> newCbasToAdd = new LinkedList<AdjustedCBAInvoiceItem>();
+ for (final InvoiceItem cbaInvoiceItem : allInvoiceItems) {
+ if (!InvoiceItemType.CBA_ADJ.equals(cbaInvoiceItem.getInvoiceItemType())) {
+ continue;
+ }
+
+ for (final InvoiceItem invoiceItem : allInvoiceItems) {
+ if (reparationInvoiceItemIdToRepairItemMappings.keySet().contains(invoiceItem.getId())) {
+ final InvoiceItem repairInvoiceItem = reparationInvoiceItemIdToRepairItemMappings.get(invoiceItem.getId());
+ final InvoiceItem reparationInvoiceItem = invoiceItem;
+ // Au petit bonheur la chance... There is nothing else against to compare
+ if (repairInvoiceItem.getAmount().negate().compareTo(cbaInvoiceItem.getAmount()) == 0) {
+ cbasToIgnore.add(cbaInvoiceItem.getId());
+ newCbasToAdd.add(new AdjustedCBAInvoiceItem(cbaInvoiceItem, cbaInvoiceItem.getAmount().add(reparationInvoiceItem.getAmount().negate()), reparationInvoiceItem.getId()));
+
+ // Now, fiddle with the CBA used on the reparation invoice
+ for (final InvoiceItem cbaUsedOnNextInvoiceItem : allInvoiceItems) {
+ if (!InvoiceItemType.CBA_ADJ.equals(cbaUsedOnNextInvoiceItem.getInvoiceItemType()) ||
+ !cbaUsedOnNextInvoiceItem.getInvoiceId().equals(reparationInvoiceItem.getInvoiceId())) {
+ continue;
+ }
+
+ // Au petit bonheur la chance... There is nothing else against to compare. Take the first one again?
+ cbasToIgnore.add(cbaUsedOnNextInvoiceItem.getId());
+ newCbasToAdd.add(new AdjustedCBAInvoiceItem(cbaUsedOnNextInvoiceItem, cbaUsedOnNextInvoiceItem.getAmount().add(reparationInvoiceItem.getAmount()), reparationInvoiceItem.getId()));
+ break;
+ }
+
+ // Break from the inner loop only
+ break;
+ }
+ }
+ }
+ }
+
+
// Filter the invoice items for analytics
final Collection<InvoiceItem> invoiceItemsForAnalytics = new LinkedList<InvoiceItem>();
for (final InvoiceItem invoiceItem : allInvoiceItems) {
- if (InvoiceItemType.REPAIR_ADJ.equals(invoiceItem.getInvoiceItemType())) {
+ if (cbasToIgnore.contains(invoiceItem.getId())) {
+ // We don't care
+ } else if (InvoiceItemType.REPAIR_ADJ.equals(invoiceItem.getInvoiceItemType())) {
// We don't care, we'll create a special item for it below
} else if (reparationInvoiceItemIdToRepairItemMappings.keySet().contains(invoiceItem.getId())) {
// We do care - this is a reparation item. Create an item adjustment for it
@@ -404,10 +419,120 @@ public class BusinessInvoiceDao extends BusinessAnalyticsDaoBase {
invoiceItemsForAnalytics.add(invoiceItem);
}
}
+ invoiceItemsForAnalytics.addAll(newCbasToAdd);
return invoiceItemsForAnalytics;
}
+ private class AdjustedCBAInvoiceItem implements InvoiceItem {
+
+ private final InvoiceItem cbaInvoiceItem;
+ private final BigDecimal amount;
+ private final UUID reparationItemId;
+
+ private AdjustedCBAInvoiceItem(final InvoiceItem cbaInvoiceItem,
+ final BigDecimal amount,
+ final UUID reparationItemId) {
+ this.cbaInvoiceItem = cbaInvoiceItem;
+ this.amount = amount;
+ this.reparationItemId = reparationItemId;
+ }
+
+ @Override
+ public InvoiceItemType getInvoiceItemType() {
+ return InvoiceItemType.CBA_ADJ;
+ }
+
+ @Override
+ public UUID getInvoiceId() {
+ return cbaInvoiceItem.getInvoiceId();
+ }
+
+ @Override
+ public UUID getAccountId() {
+ return cbaInvoiceItem.getAccountId();
+ }
+
+ @Override
+ public LocalDate getStartDate() {
+ return cbaInvoiceItem.getStartDate();
+ }
+
+ @Override
+ public LocalDate getEndDate() {
+ return cbaInvoiceItem.getStartDate();
+ }
+
+ @Override
+ public BigDecimal getAmount() {
+ return amount;
+ }
+
+ @Override
+ public Currency getCurrency() {
+ return cbaInvoiceItem.getCurrency();
+ }
+
+ @Override
+ public String getDescription() {
+ return cbaInvoiceItem.getDescription();
+ }
+
+ @Override
+ public UUID getBundleId() {
+ return cbaInvoiceItem.getBundleId();
+ }
+
+ @Override
+ public UUID getSubscriptionId() {
+ return cbaInvoiceItem.getSubscriptionId();
+ }
+
+ @Override
+ public String getPlanName() {
+ return cbaInvoiceItem.getPlanName();
+ }
+
+ @Override
+ public String getPhaseName() {
+ return cbaInvoiceItem.getPhaseName();
+ }
+
+ @Override
+ public BigDecimal getRate() {
+ return cbaInvoiceItem.getRate();
+ }
+
+ @Override
+ public UUID getLinkedItemId() {
+ return cbaInvoiceItem.getLinkedItemId();
+ }
+
+ @Override
+ public boolean matches(final Object other) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public UUID getId() {
+ return cbaInvoiceItem.getId();
+ }
+
+ public UUID getSecondId() {
+ return reparationItemId;
+ }
+
+ @Override
+ public DateTime getCreatedDate() {
+ return cbaInvoiceItem.getCreatedDate();
+ }
+
+ @Override
+ public DateTime getUpdatedDate() {
+ return cbaInvoiceItem.getUpdatedDate();
+ }
+ }
+
private class AdjustmentInvoiceItemForRepair implements InvoiceItem {
private final InvoiceItem repairInvoiceItem;
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoicePaymentDao.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoicePaymentDao.java
index 5116b3b..423024c 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoicePaymentDao.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoicePaymentDao.java
@@ -19,10 +19,8 @@ package com.ning.billing.osgi.bundles.analytics.dao;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Map;
-import java.util.UUID;
-import org.skife.jdbi.v2.Transaction;
-import org.skife.jdbi.v2.TransactionStatus;
+import javax.annotation.Nullable;
import com.ning.billing.account.api.Account;
import com.ning.billing.invoice.api.Invoice;
@@ -44,50 +42,18 @@ import com.ning.killbill.osgi.libs.killbill.OSGIKillbillLogService;
public class BusinessInvoicePaymentDao extends BusinessAnalyticsDaoBase {
- private final BusinessAccountDao businessAccountDao;
- private final BusinessInvoiceDao businessInvoiceDao;
-
public BusinessInvoicePaymentDao(final OSGIKillbillLogService logService,
final OSGIKillbillAPI osgiKillbillAPI,
- final OSGIKillbillDataSource osgiKillbillDataSource,
- final BusinessAccountDao businessAccountDao,
- final BusinessInvoiceDao businessInvoiceDao) {
+ final OSGIKillbillDataSource osgiKillbillDataSource) {
super(logService, osgiKillbillAPI, osgiKillbillDataSource);
- this.businessAccountDao = businessAccountDao;
- this.businessInvoiceDao = businessInvoiceDao;
- }
-
- public void update(final UUID accountId, final CallContext context) throws AnalyticsRefreshException {
- final Account account = getAccount(accountId, context);
-
- // Recompute the account record
- final BusinessAccountModelDao bac = businessAccountDao.createBusinessAccount(account, context);
-
- // Recompute all invoice payments
- final Collection<BusinessInvoicePaymentBaseModelDao> businessInvoicePayments = createBusinessInvoicePayments(account, context);
-
- // Recompute all invoice and invoice items
- final Map<BusinessInvoiceModelDao, Collection<BusinessInvoiceItemBaseModelDao>> businessInvoices = businessInvoiceDao.createBusinessInvoicesAndInvoiceItems(account, context);
-
- sqlDao.inTransaction(new Transaction<Void, BusinessAnalyticsSqlDao>() {
- @Override
- public Void inTransaction(final BusinessAnalyticsSqlDao transactional, final TransactionStatus status) throws Exception {
- updateInTransaction(bac, businessInvoices, businessInvoicePayments, transactional, context);
- return null;
- }
- });
}
- private void updateInTransaction(final BusinessAccountModelDao bac,
- final Map<BusinessInvoiceModelDao, Collection<BusinessInvoiceItemBaseModelDao>> businessInvoices,
- final Collection<BusinessInvoicePaymentBaseModelDao> businessInvoicePayments,
- final BusinessAnalyticsSqlDao transactional,
- final CallContext context) throws AnalyticsRefreshException {
+ public void updateInTransaction(final BusinessAccountModelDao bac,
+ final Collection<BusinessInvoicePaymentBaseModelDao> businessInvoicePayments,
+ final BusinessAnalyticsSqlDao transactional,
+ final CallContext context) throws AnalyticsRefreshException {
rebuildInvoicePaymentsForAccountInTransaction(bac, businessInvoicePayments, transactional, context);
-
- // Update invoice balance details in BIN
- // Note: no need to explicitly update BAC as well, since BusinessInvoiceDao will take care of it
- businessInvoiceDao.updateInTransaction(bac, businessInvoices, transactional, context);
+ // Invoice and payment details in BAC will be updated by BusinessInvoiceAndInvoicePaymentDao
}
private void rebuildInvoicePaymentsForAccountInTransaction(final BusinessAccountModelDao bac,
@@ -103,8 +69,9 @@ public class BusinessInvoicePaymentDao extends BusinessAnalyticsDaoBase {
}
}
- private Collection<BusinessInvoicePaymentBaseModelDao> createBusinessInvoicePayments(final Account account,
- final CallContext context) throws AnalyticsRefreshException {
+ public Collection<BusinessInvoicePaymentBaseModelDao> createBusinessInvoicePayments(final Account account,
+ final Map<BusinessInvoiceModelDao, Collection<BusinessInvoiceItemBaseModelDao>> businessInvoices,
+ final CallContext context) throws AnalyticsRefreshException {
final Collection<BusinessInvoicePaymentBaseModelDao> businessInvoicePayments = new LinkedList<BusinessInvoicePaymentBaseModelDao>();
final Long accountRecordId = getAccountRecordId(account.getId(), context);
@@ -113,29 +80,13 @@ public class BusinessInvoicePaymentDao extends BusinessAnalyticsDaoBase {
final Collection<InvoicePayment> invoicePayments = getAccountInvoicePayments(account.getId(), context);
for (final InvoicePayment invoicePayment : invoicePayments) {
- final Long invoicePaymentRecordId = getInvoicePaymentRecordId(invoicePayment.getId(), context);
-
- final Invoice invoice = getInvoice(invoicePayment.getInvoiceId(), context);
- final Payment payment = getPaymentWithPluginInfo(invoicePayment.getPaymentId(), context);
- Refund refund = null;
- if (invoicePayment.getPaymentCookieId() != null) {
- refund = getRefundWithPluginInfo(invoicePayment.getPaymentCookieId(), context);
- }
-
- final PaymentMethod paymentMethod = getPaymentMethod(payment.getPaymentMethodId(), context);
- final AuditLog creationAuditLog = getInvoicePaymentCreationAuditLog(invoicePayment.getId(), context);
-
- final BusinessInvoicePaymentBaseModelDao businessInvoicePayment = BusinessInvoicePaymentBaseModelDao.create(account,
- accountRecordId,
- invoice,
- invoicePayment,
- invoicePaymentRecordId,
- payment,
- refund,
- paymentMethod,
- creationAuditLog,
- tenantRecordId,
- reportGroup);
+ final BusinessInvoicePaymentBaseModelDao businessInvoicePayment = createBusinessInvoicePayment(account,
+ invoicePayment,
+ businessInvoices,
+ accountRecordId,
+ tenantRecordId,
+ reportGroup,
+ context);
if (businessInvoicePayment != null) {
businessInvoicePayments.add(businessInvoicePayment);
}
@@ -143,4 +94,36 @@ public class BusinessInvoicePaymentDao extends BusinessAnalyticsDaoBase {
return businessInvoicePayments;
}
+
+ private BusinessInvoicePaymentBaseModelDao createBusinessInvoicePayment(final Account account,
+ final InvoicePayment invoicePayment,
+ final Map<BusinessInvoiceModelDao, Collection<BusinessInvoiceItemBaseModelDao>> businessInvoices,
+ final Long accountRecordId,
+ final Long tenantRecordId,
+ @Nullable final ReportGroup reportGroup,
+ final CallContext context) throws AnalyticsRefreshException {
+ final Long invoicePaymentRecordId = getInvoicePaymentRecordId(invoicePayment.getId(), context);
+
+ final Payment payment = getPaymentWithPluginInfo(invoicePayment.getPaymentId(), context);
+ Refund refund = null;
+ if (invoicePayment.getPaymentCookieId() != null) {
+ refund = getRefundWithPluginInfo(invoicePayment.getPaymentCookieId(), context);
+ }
+
+ final Invoice invoice = getInvoice(invoicePayment.getInvoiceId(), context);
+ final PaymentMethod paymentMethod = getPaymentMethod(payment.getPaymentMethodId(), context);
+ final AuditLog creationAuditLog = getInvoicePaymentCreationAuditLog(invoicePayment.getId(), context);
+
+ return BusinessInvoicePaymentBaseModelDao.create(account,
+ accountRecordId,
+ invoice,
+ invoicePayment,
+ invoicePaymentRecordId,
+ payment,
+ refund,
+ paymentMethod,
+ creationAuditLog,
+ tenantRecordId,
+ reportGroup);
+ }
}
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceAdjustmentModelDao.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceAdjustmentModelDao.java
index 8c64231..94d3063 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceAdjustmentModelDao.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceAdjustmentModelDao.java
@@ -62,4 +62,9 @@ public class BusinessInvoiceAdjustmentModelDao extends BusinessInvoiceItemBaseMo
public String getTableName() {
return INVOICE_ADJUSTMENTS_TABLE_NAME;
}
+
+ @Override
+ public BusinessInvoiceItemType getBusinessInvoiceItemType() {
+ return BusinessInvoiceItemType.INVOICE_ADJUSTMENT;
+ }
}
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemAdjustmentModelDao.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemAdjustmentModelDao.java
index fca1e6a..4a0e3f9 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemAdjustmentModelDao.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemAdjustmentModelDao.java
@@ -62,4 +62,9 @@ public class BusinessInvoiceItemAdjustmentModelDao extends BusinessInvoiceItemBa
public String getTableName() {
return INVOICE_ITEM_ADJUSTMENTS_TABLE_NAME;
}
+
+ @Override
+ public BusinessInvoiceItemType getBusinessInvoiceItemType() {
+ return BusinessInvoiceItemType.INVOICE_ITEM_ADJUSTMENT;
+ }
}
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemBaseModelDao.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemBaseModelDao.java
index f0fcef2..75e5643 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemBaseModelDao.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemBaseModelDao.java
@@ -55,6 +55,7 @@ public abstract class BusinessInvoiceItemBaseModelDao extends BusinessModelDaoBa
private BigDecimal invoiceAmountCharged;
private BigDecimal invoiceOriginalAmountCharged;
private BigDecimal invoiceAmountCredited;
+ private BigDecimal invoiceAmountRefunded;
private String itemType;
private Boolean revenueRecognizable;
private String bundleExternalKey;
@@ -77,6 +78,8 @@ public abstract class BusinessInvoiceItemBaseModelDao extends BusinessModelDaoBa
CHARGE
}
+ public abstract BusinessInvoiceItemType getBusinessInvoiceItemType();
+
public static BusinessInvoiceItemBaseModelDao create(final Account account,
final Long accountRecordId,
final Invoice invoice,
@@ -164,11 +167,6 @@ public abstract class BusinessInvoiceItemBaseModelDao extends BusinessModelDaoBa
final LocalDate invoiceDate,
final LocalDate invoiceTargetDate,
final String invoiceCurrency,
- final BigDecimal invoiceBalance,
- final BigDecimal invoiceAmountPaid,
- final BigDecimal invoiceAmountCharged,
- final BigDecimal invoiceOriginalAmountCharged,
- final BigDecimal invoiceAmountCredited,
final String itemType,
final Boolean revenueRecognizable,
final String bundleExternalKey,
@@ -212,11 +210,6 @@ public abstract class BusinessInvoiceItemBaseModelDao extends BusinessModelDaoBa
this.invoiceDate = invoiceDate;
this.invoiceTargetDate = invoiceTargetDate;
this.invoiceCurrency = invoiceCurrency;
- this.invoiceBalance = invoiceBalance;
- this.invoiceAmountPaid = invoiceAmountPaid;
- this.invoiceAmountCharged = invoiceAmountCharged;
- this.invoiceOriginalAmountCharged = invoiceOriginalAmountCharged;
- this.invoiceAmountCredited = invoiceAmountCredited;
this.itemType = itemType;
this.revenueRecognizable = revenueRecognizable;
this.bundleExternalKey = bundleExternalKey;
@@ -255,23 +248,18 @@ public abstract class BusinessInvoiceItemBaseModelDao extends BusinessModelDaoBa
invoice.getInvoiceDate(),
invoice.getTargetDate(),
invoice.getCurrency() == null ? null : invoice.getCurrency().toString(),
- invoice.getBalance(),
- invoice.getPaidAmount(),
- invoice.getChargedAmount(),
- invoice.getOriginalChargedAmount(),
- invoice.getCreditAdjAmount(),
invoiceItem.getInvoiceItemType().toString(),
revenueRecognizable,
bundle == null ? null : bundle.getExternalKey(),
- plan != null ? plan.getProduct().getName() : null,
- plan != null ? plan.getProduct().getCatalogName() : null,
- plan != null ? plan.getProduct().getCategory().toString() : null,
+ (plan != null && plan.getProduct() != null) ? plan.getProduct().getName() : null,
+ (plan != null && plan.getProduct() != null) ? plan.getProduct().getCatalogName() : null,
+ (plan != null && plan.getProduct().getCategory() != null) ? plan.getProduct().getCategory().toString() : null,
planPhase != null ? planPhase.getName() : null,
- planPhase != null ? planPhase.getPhaseType().toString() : null,
- planPhase != null ? planPhase.getBillingPeriod().toString() : null,
+ (planPhase != null && planPhase.getPhaseType() != null) ? planPhase.getPhaseType().toString() : null,
+ (planPhase != null && planPhase.getBillingPeriod() != null) ? planPhase.getBillingPeriod().toString() : null,
invoiceItem.getStartDate(),
/* Populate end date for fixed items for convenience (null in invoice_items table) */
- (invoiceItem.getEndDate() == null && planPhase != null) ? invoiceItem.getStartDate().plus(planPhase.getDuration().toJodaPeriod()) : invoiceItem.getEndDate(),
+ (invoiceItem.getEndDate() == null && planPhase != null && planPhase.getDuration() != null) ? invoiceItem.getStartDate().plus(planPhase.getDuration().toJodaPeriod()) : invoiceItem.getEndDate(),
invoiceItem.getAmount(),
invoiceItem.getCurrency() == null ? null : invoiceItem.getCurrency().toString(),
invoiceItem.getLinkedItemId(),
@@ -287,6 +275,15 @@ public abstract class BusinessInvoiceItemBaseModelDao extends BusinessModelDaoBa
reportGroup);
}
+ public void populateDenormalizedInvoiceFields(final BusinessInvoiceModelDao businessInvoice) {
+ invoiceBalance = businessInvoice.getBalance();
+ invoiceAmountPaid = businessInvoice.getAmountPaid();
+ invoiceAmountCharged = businessInvoice.getAmountCharged();
+ invoiceOriginalAmountCharged = businessInvoice.getOriginalAmountCharged();
+ invoiceAmountCredited = businessInvoice.getAmountCredited();
+ invoiceAmountRefunded = businessInvoice.getAmountRefunded();
+ }
+
public Long getInvoiceItemRecordId() {
return invoiceItemRecordId;
}
@@ -343,6 +340,10 @@ public abstract class BusinessInvoiceItemBaseModelDao extends BusinessModelDaoBa
return invoiceAmountCredited;
}
+ public BigDecimal getInvoiceAmountRefunded() {
+ return invoiceAmountRefunded;
+ }
+
public String getItemType() {
return itemType;
}
@@ -417,6 +418,7 @@ public abstract class BusinessInvoiceItemBaseModelDao extends BusinessModelDaoBa
sb.append(", invoiceAmountCharged=").append(invoiceAmountCharged);
sb.append(", invoiceOriginalAmountCharged=").append(invoiceOriginalAmountCharged);
sb.append(", invoiceAmountCredited=").append(invoiceAmountCredited);
+ sb.append(", invoiceAmountRefunded=").append(invoiceAmountRefunded);
sb.append(", itemType='").append(itemType).append('\'');
sb.append(", revenueRecognizable=").append(revenueRecognizable);
sb.append(", bundleExternalKey='").append(bundleExternalKey).append('\'');
@@ -473,6 +475,9 @@ public abstract class BusinessInvoiceItemBaseModelDao extends BusinessModelDaoBa
if (invoiceAmountPaid != null ? (invoiceAmountPaid.compareTo(that.invoiceAmountPaid) != 0) : that.invoiceAmountPaid != null) {
return false;
}
+ if (invoiceAmountRefunded != null ? (invoiceAmountRefunded.compareTo(that.invoiceAmountRefunded) != 0) : that.invoiceAmountRefunded != null) {
+ return false;
+ }
if (invoiceBalance != null ? (invoiceBalance.compareTo(that.invoiceBalance) != 0) : that.invoiceBalance != null) {
return false;
}
@@ -554,6 +559,7 @@ public abstract class BusinessInvoiceItemBaseModelDao extends BusinessModelDaoBa
result = 31 * result + (invoiceAmountCharged != null ? invoiceAmountCharged.hashCode() : 0);
result = 31 * result + (invoiceOriginalAmountCharged != null ? invoiceOriginalAmountCharged.hashCode() : 0);
result = 31 * result + (invoiceAmountCredited != null ? invoiceAmountCredited.hashCode() : 0);
+ result = 31 * result + (invoiceAmountRefunded != null ? invoiceAmountRefunded.hashCode() : 0);
result = 31 * result + (itemType != null ? itemType.hashCode() : 0);
result = 31 * result + (revenueRecognizable != null ? revenueRecognizable.hashCode() : 0);
result = 31 * result + (bundleExternalKey != null ? bundleExternalKey.hashCode() : 0);
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemCreditModelDao.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemCreditModelDao.java
index f9557d2..b299b30 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemCreditModelDao.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemCreditModelDao.java
@@ -62,4 +62,9 @@ public class BusinessInvoiceItemCreditModelDao extends BusinessInvoiceItemBaseMo
public String getTableName() {
return ACCOUNT_CREDITS_TABLE_NAME;
}
+
+ @Override
+ public BusinessInvoiceItemType getBusinessInvoiceItemType() {
+ return BusinessInvoiceItemType.ACCOUNT_CREDIT;
+ }
}
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemModelDao.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemModelDao.java
index bd7832c..753f979 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemModelDao.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceItemModelDao.java
@@ -62,4 +62,9 @@ public class BusinessInvoiceItemModelDao extends BusinessInvoiceItemBaseModelDao
public String getTableName() {
return INVOICE_ITEMS_TABLE_NAME;
}
+
+ @Override
+ public BusinessInvoiceItemType getBusinessInvoiceItemType() {
+ return BusinessInvoiceItemType.CHARGE;
+ }
}
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceModelDao.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceModelDao.java
index 650a86c..6aa8a9f 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceModelDao.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoiceModelDao.java
@@ -43,6 +43,7 @@ public class BusinessInvoiceModelDao extends BusinessModelDaoBase {
private BigDecimal amountCharged;
private BigDecimal originalAmountCharged;
private BigDecimal amountCredited;
+ private BigDecimal amountRefunded;
public BusinessInvoiceModelDao() { /* When reading from the database */ }
@@ -52,8 +53,6 @@ public class BusinessInvoiceModelDao extends BusinessModelDaoBase {
final LocalDate invoiceDate,
final LocalDate targetDate,
final String currency,
- final BigDecimal balance,
- final BigDecimal amountPaid,
final BigDecimal amountCharged,
final BigDecimal originalAmountCharged,
final BigDecimal amountCredited,
@@ -83,8 +82,6 @@ public class BusinessInvoiceModelDao extends BusinessModelDaoBase {
this.invoiceDate = invoiceDate;
this.targetDate = targetDate;
this.currency = currency;
- this.balance = balance;
- this.amountPaid = amountPaid;
this.amountCharged = amountCharged;
this.originalAmountCharged = originalAmountCharged;
this.amountCredited = amountCredited;
@@ -93,6 +90,9 @@ public class BusinessInvoiceModelDao extends BusinessModelDaoBase {
public BusinessInvoiceModelDao(final Account account,
final Long accountRecordId,
final Invoice invoice,
+ final BigDecimal amountCharged,
+ final BigDecimal originalAmountCharged,
+ final BigDecimal amountCredited,
final Long invoiceRecordId,
@Nullable final AuditLog creationAuditLog,
final Long tenantRecordId,
@@ -103,11 +103,9 @@ public class BusinessInvoiceModelDao extends BusinessModelDaoBase {
invoice.getInvoiceDate(),
invoice.getTargetDate(),
invoice.getCurrency() == null ? null : invoice.getCurrency().toString(),
- invoice.getBalance(),
- invoice.getPaidAmount(),
- invoice.getChargedAmount(),
- invoice.getOriginalChargedAmount(),
- invoice.getCreditAdjAmount(),
+ amountCharged,
+ originalAmountCharged,
+ amountCredited,
invoice.getCreatedDate(),
creationAuditLog != null ? creationAuditLog.getUserName() : null,
creationAuditLog != null ? creationAuditLog.getReasonCode() : null,
@@ -120,6 +118,21 @@ public class BusinessInvoiceModelDao extends BusinessModelDaoBase {
reportGroup);
}
+ // Denormalized payment field
+ public void setBalance(final BigDecimal balance) {
+ this.balance = balance;
+ }
+
+ // Denormalized payment field
+ public void setAmountPaid(final BigDecimal amountPaid) {
+ this.amountPaid = amountPaid;
+ }
+
+ // Denormalized payment field
+ public void setAmountRefunded(final BigDecimal amountRefunded) {
+ this.amountRefunded = amountRefunded;
+ }
+
@Override
public String getTableName() {
return INVOICES_TABLE_NAME;
@@ -169,6 +182,10 @@ public class BusinessInvoiceModelDao extends BusinessModelDaoBase {
return amountCredited;
}
+ public BigDecimal getAmountRefunded() {
+ return amountRefunded;
+ }
+
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
@@ -184,6 +201,7 @@ public class BusinessInvoiceModelDao extends BusinessModelDaoBase {
sb.append(", amountCharged=").append(amountCharged);
sb.append(", originalAmountCharged=").append(originalAmountCharged);
sb.append(", amountCredited=").append(amountCredited);
+ sb.append(", amountRefunded=").append(amountRefunded);
sb.append('}');
return sb.toString();
}
@@ -211,6 +229,9 @@ public class BusinessInvoiceModelDao extends BusinessModelDaoBase {
if (amountPaid != null ? (amountPaid.compareTo(that.amountPaid) != 0) : that.amountPaid != null) {
return false;
}
+ if (amountRefunded != null ? (amountRefunded.compareTo(that.amountRefunded) != 0) : that.amountRefunded != null) {
+ return false;
+ }
if (balance != null ? (balance.compareTo(that.balance) != 0) : that.balance != null) {
return false;
}
@@ -253,6 +274,7 @@ public class BusinessInvoiceModelDao extends BusinessModelDaoBase {
result = 31 * result + (amountCharged != null ? amountCharged.hashCode() : 0);
result = 31 * result + (originalAmountCharged != null ? originalAmountCharged.hashCode() : 0);
result = 31 * result + (amountCredited != null ? amountCredited.hashCode() : 0);
+ result = 31 * result + (amountRefunded != null ? amountRefunded.hashCode() : 0);
return result;
}
}
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoicePaymentBaseModelDao.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoicePaymentBaseModelDao.java
index 402c98d..b542755 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoicePaymentBaseModelDao.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/model/BusinessInvoicePaymentBaseModelDao.java
@@ -59,6 +59,7 @@ public abstract class BusinessInvoicePaymentBaseModelDao extends BusinessModelDa
private BigDecimal invoiceAmountCharged;
private BigDecimal invoiceOriginalAmountCharged;
private BigDecimal invoiceAmountCredited;
+ private BigDecimal invoiceAmountRefunded;
private String invoicePaymentType;
private UUID paymentId;
private UUID refundId;
@@ -149,11 +150,6 @@ public abstract class BusinessInvoicePaymentBaseModelDao extends BusinessModelDa
final LocalDate invoiceDate,
final LocalDate invoiceTargetDate,
final String invoiceCurrency,
- final BigDecimal invoiceBalance,
- final BigDecimal invoiceAmountPaid,
- final BigDecimal invoiceAmountCharged,
- final BigDecimal invoiceOriginalAmountCharged,
- final BigDecimal invoiceAmountCredited,
final String invoicePaymentType,
final UUID paymentId,
final UUID refundId,
@@ -211,11 +207,6 @@ public abstract class BusinessInvoicePaymentBaseModelDao extends BusinessModelDa
this.invoiceDate = invoiceDate;
this.invoiceTargetDate = invoiceTargetDate;
this.invoiceCurrency = invoiceCurrency;
- this.invoiceBalance = invoiceBalance;
- this.invoiceAmountPaid = invoiceAmountPaid;
- this.invoiceAmountCharged = invoiceAmountCharged;
- this.invoiceOriginalAmountCharged = invoiceOriginalAmountCharged;
- this.invoiceAmountCredited = invoiceAmountCredited;
this.invoicePaymentType = invoicePaymentType;
this.paymentId = paymentId;
this.refundId = refundId;
@@ -266,12 +257,7 @@ public abstract class BusinessInvoicePaymentBaseModelDao extends BusinessModelDa
invoice.getInvoiceDate(),
invoice.getTargetDate(),
invoice.getCurrency() == null ? null : invoice.getCurrency().toString(),
- invoice.getBalance(),
- invoice.getPaidAmount(),
- invoice.getChargedAmount(),
- invoice.getOriginalChargedAmount(),
- invoice.getCreditAdjAmount(),
- invoicePayment.getType().toString(),
+ invoicePayment.getType() == null ? null : invoicePayment.getType().toString(),
payment.getId(),
refund != null ? refund.getId() : null,
payment.getPaymentNumber() == null ? null : payment.getPaymentNumber().longValue(),
@@ -281,7 +267,7 @@ public abstract class BusinessInvoicePaymentBaseModelDao extends BusinessModelDa
paymentMethod != null ? paymentMethod.getPluginName() : DEFAULT_PLUGIN_NAME,
refund != null ? (refund.getPluginDetail() != null ? refund.getPluginDetail().getCreatedDate() : null) : (payment.getPaymentInfoPlugin() != null ? payment.getPaymentInfoPlugin().getCreatedDate() : null),
refund != null ? (refund.getPluginDetail() != null ? refund.getPluginDetail().getEffectiveDate() : null) : (payment.getPaymentInfoPlugin() != null ? payment.getPaymentInfoPlugin().getEffectiveDate() : null),
- refund != null ? (refund.getPluginDetail() != null ? refund.getPluginDetail().getStatus().toString() : null) : (payment.getPaymentInfoPlugin() != null ? payment.getPaymentInfoPlugin().getStatus().toString() : null),
+ refund != null ? (refund.getPluginDetail() != null && refund.getPluginDetail().getStatus() != null ? refund.getPluginDetail().getStatus().toString() : null) : (payment.getPaymentInfoPlugin() != null && payment.getPaymentInfoPlugin().getStatus() != null ? payment.getPaymentInfoPlugin().getStatus().toString() : null),
refund != null ? (refund.getPluginDetail() != null ? refund.getPluginDetail().getGatewayError() : null) : (payment.getPaymentInfoPlugin() != null ? payment.getPaymentInfoPlugin().getGatewayError() : null),
refund != null ? (refund.getPluginDetail() != null ? refund.getPluginDetail().getGatewayErrorCode() : null) : (payment.getPaymentInfoPlugin() != null ? payment.getPaymentInfoPlugin().getGatewayErrorCode() : null),
refund != null ? (refund.getPluginDetail() != null ? refund.getPluginDetail().getReferenceId() : null) : (payment.getPaymentInfoPlugin() != null ? payment.getPaymentInfoPlugin().getFirstPaymentReferenceId() : null),
@@ -312,6 +298,15 @@ public abstract class BusinessInvoicePaymentBaseModelDao extends BusinessModelDa
reportGroup);
}
+ public void populateDenormalizedInvoiceFields(final BusinessInvoiceModelDao businessInvoice) {
+ invoiceBalance = businessInvoice.getBalance();
+ invoiceAmountPaid = businessInvoice.getAmountPaid();
+ invoiceAmountCharged = businessInvoice.getAmountCharged();
+ invoiceOriginalAmountCharged = businessInvoice.getOriginalAmountCharged();
+ invoiceAmountCredited = businessInvoice.getAmountCredited();
+ invoiceAmountRefunded = businessInvoice.getAmountRefunded();
+ }
+
public Long getInvoicePaymentRecordId() {
return invoicePaymentRecordId;
}
@@ -364,6 +359,10 @@ public abstract class BusinessInvoicePaymentBaseModelDao extends BusinessModelDa
return invoiceAmountCredited;
}
+ public BigDecimal getInvoiceAmountRefunded() {
+ return invoiceAmountRefunded;
+ }
+
public String getInvoicePaymentType() {
return invoicePaymentType;
}
@@ -496,6 +495,7 @@ public abstract class BusinessInvoicePaymentBaseModelDao extends BusinessModelDa
sb.append(", invoiceAmountCharged=").append(invoiceAmountCharged);
sb.append(", invoiceOriginalAmountCharged=").append(invoiceOriginalAmountCharged);
sb.append(", invoiceAmountCredited=").append(invoiceAmountCredited);
+ sb.append(", invoiceAmountRefunded=").append(invoiceAmountRefunded);
sb.append(", invoicePaymentType='").append(invoicePaymentType).append('\'');
sb.append(", paymentId=").append(paymentId);
sb.append(", refundId=").append(refundId);
@@ -558,6 +558,9 @@ public abstract class BusinessInvoicePaymentBaseModelDao extends BusinessModelDa
if (invoiceAmountPaid != null ? (invoiceAmountPaid.compareTo(that.invoiceAmountPaid) != 0) : that.invoiceAmountPaid != null) {
return false;
}
+ if (invoiceAmountRefunded != null ? (invoiceAmountRefunded.compareTo(that.invoiceAmountRefunded) != 0) : that.invoiceAmountRefunded != null) {
+ return false;
+ }
if (invoiceBalance != null ? (invoiceBalance.compareTo(that.invoiceBalance) != 0) : that.invoiceBalance != null) {
return false;
}
@@ -689,6 +692,7 @@ public abstract class BusinessInvoicePaymentBaseModelDao extends BusinessModelDa
result = 31 * result + (invoiceAmountCharged != null ? invoiceAmountCharged.hashCode() : 0);
result = 31 * result + (invoiceOriginalAmountCharged != null ? invoiceOriginalAmountCharged.hashCode() : 0);
result = 31 * result + (invoiceAmountCredited != null ? invoiceAmountCredited.hashCode() : 0);
+ result = 31 * result + (invoiceAmountRefunded != null ? invoiceAmountRefunded.hashCode() : 0);
result = 31 * result + (invoicePaymentType != null ? invoicePaymentType.hashCode() : 0);
result = 31 * result + (paymentId != null ? paymentId.hashCode() : 0);
result = 31 * result + (refundId != null ? refundId.hashCode() : 0);
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/utils/BusinessInvoiceUtils.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/utils/BusinessInvoiceUtils.java
new file mode 100644
index 0000000..40ef30b
--- /dev/null
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/utils/BusinessInvoiceUtils.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.osgi.bundles.analytics.utils;
+
+import java.math.BigDecimal;
+import java.util.Collection;
+
+import javax.annotation.Nullable;
+
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoiceItemType;
+import com.ning.billing.invoice.api.InvoicePayment.InvoicePaymentType;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceItemBaseModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceItemBaseModelDao.BusinessInvoiceItemType;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoicePaymentBaseModelDao;
+
+public class BusinessInvoiceUtils {
+
+ public static Boolean isRevenueRecognizable(final InvoiceItem invoiceItem, final Collection<InvoiceItem> otherInvoiceItems) {
+ // All items are recognizable except user generated credit (CBA_ADJ and CREDIT_ADJ on their own invoice)
+ return !(InvoiceItemType.CBA_ADJ.equals(invoiceItem.getInvoiceItemType()) &&
+ (otherInvoiceItems.size() == 1 &&
+ InvoiceItemType.CREDIT_ADJ.equals(otherInvoiceItems.iterator().next().getInvoiceItemType()) &&
+ otherInvoiceItems.iterator().next().getInvoiceId().equals(invoiceItem.getInvoiceId()) &&
+ otherInvoiceItems.iterator().next().getAmount().compareTo(invoiceItem.getAmount().negate()) == 0));
+ }
+
+ // Invoice adjustments
+ public static boolean isInvoiceAdjustmentItem(final InvoiceItem invoiceItem, final Collection<InvoiceItem> otherInvoiceItems) {
+ // Either REFUND_ADJ
+ return InvoiceItemType.REFUND_ADJ.equals(invoiceItem.getInvoiceItemType()) ||
+ // Or invoice level credit, i.e. credit adj, but NOT on its on own invoice
+ // Note: the negative credit adj items (internal generation of account level credits) doesn't figure in analytics
+ (InvoiceItemType.CREDIT_ADJ.equals(invoiceItem.getInvoiceItemType()) &&
+ !(otherInvoiceItems.size() == 1 &&
+ InvoiceItemType.CBA_ADJ.equals(otherInvoiceItems.iterator().next().getInvoiceItemType()) &&
+ otherInvoiceItems.iterator().next().getInvoiceId().equals(invoiceItem.getInvoiceId()) &&
+ otherInvoiceItems.iterator().next().getAmount().compareTo(invoiceItem.getAmount().negate()) == 0));
+ }
+
+ // Item adjustments
+ public static boolean isInvoiceItemAdjustmentItem(final InvoiceItem invoiceItem) {
+ return InvoiceItemType.ITEM_ADJ.equals(invoiceItem.getInvoiceItemType());
+ }
+
+ // Account credits, gained or consumed
+ public static boolean isAccountCreditItem(final InvoiceItem invoiceItem) {
+ return InvoiceItemType.CBA_ADJ.equals(invoiceItem.getInvoiceItemType());
+ }
+
+ // Regular line item (charges)
+ public static boolean isCharge(final InvoiceItem invoiceItem) {
+ return InvoiceItemType.EXTERNAL_CHARGE.equals(invoiceItem.getInvoiceItemType()) ||
+ InvoiceItemType.FIXED.equals(invoiceItem.getInvoiceItemType()) ||
+ InvoiceItemType.RECURRING.equals(invoiceItem.getInvoiceItemType());
+ }
+
+ public static BigDecimal computeInvoiceBalance(@Nullable final Collection<BusinessInvoiceItemBaseModelDao> businessInvoiceItems,
+ @Nullable final Collection<BusinessInvoicePaymentBaseModelDao> businessInvoicePayments) {
+ return computeInvoiceAmountCharged(businessInvoiceItems)
+ .add(computeInvoiceAmountCredited(businessInvoiceItems))
+ .add(
+ computeInvoiceAmountPaid(businessInvoicePayments).negate()
+ .add(computeInvoiceAmountRefunded(businessInvoicePayments).negate())
+ );
+ }
+
+ public static BigDecimal computeInvoiceAmountCharged(@Nullable final Collection<BusinessInvoiceItemBaseModelDao> businessInvoiceItems) {
+ BigDecimal amountCharged = BigDecimal.ZERO;
+ if (businessInvoiceItems == null) {
+ return amountCharged;
+ }
+
+ for (final BusinessInvoiceItemBaseModelDao businessInvoiceItem : businessInvoiceItems) {
+ if (BusinessInvoiceItemType.CHARGE.equals(businessInvoiceItem.getBusinessInvoiceItemType()) ||
+ BusinessInvoiceItemType.INVOICE_ADJUSTMENT.equals(businessInvoiceItem.getBusinessInvoiceItemType()) ||
+ BusinessInvoiceItemType.INVOICE_ITEM_ADJUSTMENT.equals(businessInvoiceItem.getBusinessInvoiceItemType())) {
+ amountCharged = amountCharged.add(businessInvoiceItem.getAmount());
+ }
+ }
+ return amountCharged;
+ }
+
+ public static BigDecimal computeInvoiceOriginalAmountCharged(@Nullable final Collection<BusinessInvoiceItemBaseModelDao> businessInvoiceItems) {
+ BigDecimal amountCharged = BigDecimal.ZERO;
+ if (businessInvoiceItems == null) {
+ return amountCharged;
+ }
+
+ for (final BusinessInvoiceItemBaseModelDao businessInvoiceItem : businessInvoiceItems) {
+ if (BusinessInvoiceItemType.CHARGE.equals(businessInvoiceItem.getBusinessInvoiceItemType()) &&
+ businessInvoiceItem.getCreatedDate().equals(businessInvoiceItem.getInvoiceCreatedDate())) {
+ amountCharged = amountCharged.add(businessInvoiceItem.getAmount());
+ }
+ }
+ return amountCharged;
+ }
+
+ public static BigDecimal computeInvoiceAmountCredited(@Nullable final Collection<BusinessInvoiceItemBaseModelDao> businessInvoiceItems) {
+ BigDecimal amountCredited = BigDecimal.ZERO;
+ if (businessInvoiceItems == null) {
+ return amountCredited;
+ }
+
+ for (final BusinessInvoiceItemBaseModelDao businessInvoiceItem : businessInvoiceItems) {
+ if (BusinessInvoiceItemType.ACCOUNT_CREDIT.equals(businessInvoiceItem.getBusinessInvoiceItemType())) {
+ amountCredited = amountCredited.add(businessInvoiceItem.getAmount());
+ }
+ }
+ return amountCredited;
+ }
+
+ public static BigDecimal computeInvoiceAmountPaid(@Nullable final Collection<BusinessInvoicePaymentBaseModelDao> businessInvoicePayments) {
+ BigDecimal amountPaid = BigDecimal.ZERO;
+ if (businessInvoicePayments == null) {
+ return amountPaid;
+ }
+
+ for (final BusinessInvoicePaymentBaseModelDao businessInvoicePayment : businessInvoicePayments) {
+ if (InvoicePaymentType.ATTEMPT.toString().equals(businessInvoicePayment.getInvoicePaymentType())) {
+ amountPaid = amountPaid.add(businessInvoicePayment.getAmount());
+ }
+ }
+ return amountPaid;
+ }
+
+ public static BigDecimal computeInvoiceAmountRefunded(@Nullable final Collection<BusinessInvoicePaymentBaseModelDao> businessInvoicePayments) {
+ BigDecimal amountRefunded = BigDecimal.ZERO;
+ if (businessInvoicePayments == null) {
+ return amountRefunded;
+ }
+
+ for (final BusinessInvoicePaymentBaseModelDao businessInvoicePayment : businessInvoicePayments) {
+ if (InvoicePaymentType.REFUND.toString().equals(businessInvoicePayment.getInvoicePaymentType()) ||
+ InvoicePaymentType.CHARGED_BACK.toString().equals(businessInvoicePayment.getInvoicePaymentType())) {
+ amountRefunded = amountRefunded.add(businessInvoicePayment.getAmount());
+ }
+ }
+ return amountRefunded;
+ }
+}
diff --git a/osgi-bundles/bundles/analytics/src/main/resources/com/ning/billing/osgi/bundles/analytics/dao/BusinessAnalyticsSqlDao.sql.stg b/osgi-bundles/bundles/analytics/src/main/resources/com/ning/billing/osgi/bundles/analytics/dao/BusinessAnalyticsSqlDao.sql.stg
index 4dc7879..11fa694 100644
--- a/osgi-bundles/bundles/analytics/src/main/resources/com/ning/billing/osgi/bundles/analytics/dao/BusinessAnalyticsSqlDao.sql.stg
+++ b/osgi-bundles/bundles/analytics/src/main/resources/com/ning/billing/osgi/bundles/analytics/dao/BusinessAnalyticsSqlDao.sql.stg
@@ -241,6 +241,7 @@ insert into bin (
, amount_charged
, original_amount_charged
, amount_credited
+, amount_refunded
, created_date
, created_by
, created_reason_code
@@ -263,6 +264,7 @@ insert into bin (
, :amountCharged
, :originalAmountCharged
, :amountCredited
+, :amountRefunded
, :createdDate
, :createdBy
, :createdReasonCode
@@ -292,6 +294,7 @@ insert into bia (
, invoice_amount_charged
, invoice_original_amount_charged
, invoice_amount_credited
+, invoice_amount_refunded
, item_type
, revenue_recognizable
, bundle_external_key
@@ -331,6 +334,7 @@ insert into bia (
, :invoiceAmountCharged
, :invoiceOriginalAmountCharged
, :invoiceAmountCredited
+, :invoiceAmountRefunded
, :itemType
, :revenueRecognizable
, :bundleExternalKey
@@ -374,6 +378,7 @@ insert into bii (
, invoice_amount_charged
, invoice_original_amount_charged
, invoice_amount_credited
+, invoice_amount_refunded
, item_type
, revenue_recognizable
, bundle_external_key
@@ -413,6 +418,7 @@ insert into bii (
, :invoiceAmountCharged
, :invoiceOriginalAmountCharged
, :invoiceAmountCredited
+, :invoiceAmountRefunded
, :itemType
, :revenueRecognizable
, :bundleExternalKey
@@ -456,6 +462,7 @@ insert into biia (
, invoice_amount_charged
, invoice_original_amount_charged
, invoice_amount_credited
+, invoice_amount_refunded
, item_type
, revenue_recognizable
, bundle_external_key
@@ -495,6 +502,7 @@ insert into biia (
, :invoiceAmountCharged
, :invoiceOriginalAmountCharged
, :invoiceAmountCredited
+, :invoiceAmountRefunded
, :itemType
, :revenueRecognizable
, :bundleExternalKey
@@ -538,6 +546,7 @@ insert into biic (
, invoice_amount_charged
, invoice_original_amount_charged
, invoice_amount_credited
+, invoice_amount_refunded
, item_type
, revenue_recognizable
, bundle_external_key
@@ -577,6 +586,7 @@ insert into biic (
, :invoiceAmountCharged
, :invoiceOriginalAmountCharged
, :invoiceAmountCredited
+, :invoiceAmountRefunded
, :itemType
, :revenueRecognizable
, :bundleExternalKey
@@ -619,6 +629,7 @@ insert into bip (
, invoice_amount_charged
, invoice_original_amount_charged
, invoice_amount_credited
+, invoice_amount_refunded
, invoice_payment_type
, payment_id
, payment_number
@@ -671,6 +682,7 @@ insert into bip (
, :invoiceAmountCharged
, :invoiceOriginalAmountCharged
, :invoiceAmountCredited
+, :invoiceAmountRefunded
, :invoicePaymentType
, :paymentId
, :paymentNumber
@@ -727,6 +739,7 @@ insert into bipr (
, invoice_amount_charged
, invoice_original_amount_charged
, invoice_amount_credited
+, invoice_amount_refunded
, invoice_payment_type
, payment_id
, refund_id
@@ -780,6 +793,7 @@ insert into bipr (
, :invoiceAmountCharged
, :invoiceOriginalAmountCharged
, :invoiceAmountCredited
+, :invoiceAmountRefunded
, :invoicePaymentType
, :paymentId
, :refundId
@@ -837,6 +851,7 @@ insert into bipc (
, invoice_amount_charged
, invoice_original_amount_charged
, invoice_amount_credited
+, invoice_amount_refunded
, invoice_payment_type
, payment_id
, payment_number
@@ -889,6 +904,7 @@ insert into bipc (
, :invoiceAmountCharged
, :invoiceOriginalAmountCharged
, :invoiceAmountCredited
+, :invoiceAmountRefunded
, :invoicePaymentType
, :paymentId
, :paymentNumber
diff --git a/osgi-bundles/bundles/analytics/src/main/resources/com/ning/billing/osgi/bundles/analytics/ddl.sql b/osgi-bundles/bundles/analytics/src/main/resources/com/ning/billing/osgi/bundles/analytics/ddl.sql
index 7eca803..5a57ac6 100644
--- a/osgi-bundles/bundles/analytics/src/main/resources/com/ning/billing/osgi/bundles/analytics/ddl.sql
+++ b/osgi-bundles/bundles/analytics/src/main/resources/com/ning/billing/osgi/bundles/analytics/ddl.sql
@@ -154,6 +154,7 @@ create table bin (
, amount_charged numeric(10, 4) default 0
, original_amount_charged numeric(10, 4) default 0
, amount_credited numeric(10, 4) default 0
+, amount_refunded numeric(10, 4) default 0
, created_date datetime default null
, created_by varchar(50) default null
, created_reason_code varchar(255) default null
@@ -190,6 +191,7 @@ create table bia (
, invoice_amount_charged numeric(10, 4) default 0
, invoice_original_amount_charged numeric(10, 4) default 0
, invoice_amount_credited numeric(10, 4) default 0
+, invoice_amount_refunded numeric(10, 4) default 0
, item_type char(50) default null
, revenue_recognizable bool default true
, bundle_external_key varchar(50) default null
@@ -240,6 +242,7 @@ create table bii (
, invoice_amount_charged numeric(10, 4) default 0
, invoice_original_amount_charged numeric(10, 4) default 0
, invoice_amount_credited numeric(10, 4) default 0
+, invoice_amount_refunded numeric(10, 4) default 0
, item_type char(50) default null
, revenue_recognizable bool default true
, bundle_external_key varchar(50) default null
@@ -290,6 +293,7 @@ create table biia (
, invoice_amount_charged numeric(10, 4) default 0
, invoice_original_amount_charged numeric(10, 4) default 0
, invoice_amount_credited numeric(10, 4) default 0
+, invoice_amount_refunded numeric(10, 4) default 0
, item_type char(50) default null
, revenue_recognizable bool default true
, bundle_external_key varchar(50) default null
@@ -340,6 +344,7 @@ create table biic (
, invoice_amount_charged numeric(10, 4) default 0
, invoice_original_amount_charged numeric(10, 4) default 0
, invoice_amount_credited numeric(10, 4) default 0
+, invoice_amount_refunded numeric(10, 4) default 0
, item_type char(50) default null
, revenue_recognizable bool default true
, bundle_external_key varchar(50) default null
@@ -389,6 +394,7 @@ create table bip (
, invoice_amount_charged numeric(10, 4) default 0
, invoice_original_amount_charged numeric(10, 4) default 0
, invoice_amount_credited numeric(10, 4) default 0
+, invoice_amount_refunded numeric(10, 4) default 0
, invoice_payment_type varchar(50) default null
, payment_id char(36) default null
, payment_number bigint default null
@@ -452,6 +458,7 @@ create table bipr (
, invoice_amount_charged numeric(10, 4) default 0
, invoice_original_amount_charged numeric(10, 4) default 0
, invoice_amount_credited numeric(10, 4) default 0
+, invoice_amount_refunded numeric(10, 4) default 0
, invoice_payment_type varchar(50) default null
, payment_id char(36) default null
, refund_id char(36) default null
@@ -516,6 +523,7 @@ create table bipc (
, invoice_amount_charged numeric(10, 4) default 0
, invoice_original_amount_charged numeric(10, 4) default 0
, invoice_amount_credited numeric(10, 4) default 0
+, invoice_amount_refunded numeric(10, 4) default 0
, invoice_payment_type varchar(50) default null
, payment_id char(36) default null
, payment_number bigint default null
diff --git a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/AnalyticsTestSuiteNoDB.java b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/AnalyticsTestSuiteNoDB.java
index 3b336e4..9e079bd 100644
--- a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/AnalyticsTestSuiteNoDB.java
+++ b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/AnalyticsTestSuiteNoDB.java
@@ -17,8 +17,11 @@
package com.ning.billing.osgi.bundles.analytics;
import java.math.BigDecimal;
+import java.util.List;
import java.util.UUID;
+import javax.annotation.Nullable;
+
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
@@ -75,6 +78,7 @@ import com.google.common.collect.ImmutableList;
public abstract class AnalyticsTestSuiteNoDB {
+ private static final DateTime INVOICE_CREATED_DATE = new DateTime(2016, 1, 22, 10, 56, 53, DateTimeZone.UTC);
protected final Logger logger = LoggerFactory.getLogger(AnalyticsTestSuiteNoDB.class);
protected final Long accountRecordId = 1L;
@@ -140,6 +144,77 @@ public abstract class AnalyticsTestSuiteNoDB {
Assert.assertEquals(businessModelDaoBase.getReportGroup(), reportGroup.toString());
}
+ protected Invoice createInvoice(final UUID invoiceId, final Integer invoiceNumber, final List<InvoiceItem> items) {
+ final Invoice invoice = Mockito.mock(Invoice.class);
+
+ Mockito.when(invoice.getId()).thenReturn(invoiceId);
+ Mockito.when(invoice.getNumberOfItems()).thenReturn(items.size());
+ Mockito.when(invoice.getInvoiceItems()).thenReturn(items);
+ Mockito.when(invoice.getNumberOfPayments()).thenReturn(0);
+ Mockito.when(invoice.getAccountId()).thenReturn(UUID.randomUUID());
+ Mockito.when(invoice.getInvoiceNumber()).thenReturn(invoiceNumber);
+ Mockito.when(invoice.getInvoiceDate()).thenReturn(new LocalDate(1954, 12, 1));
+ Mockito.when(invoice.getTargetDate()).thenReturn(new LocalDate(2017, 3, 4));
+ Mockito.when(invoice.getCurrency()).thenReturn(Currency.AUD);
+ Mockito.when(invoice.getPaidAmount()).thenReturn(BigDecimal.ZERO);
+ Mockito.when(invoice.getOriginalChargedAmount()).thenReturn(new BigDecimal("1922"));
+ Mockito.when(invoice.getChargedAmount()).thenReturn(new BigDecimal("100293"));
+ Mockito.when(invoice.getCBAAmount()).thenReturn(BigDecimal.TEN);
+ Mockito.when(invoice.getTotalAdjAmount()).thenReturn(new BigDecimal("192"));
+ Mockito.when(invoice.getCreditAdjAmount()).thenReturn(new BigDecimal("283"));
+ Mockito.when(invoice.getRefundAdjAmount()).thenReturn(new BigDecimal("384"));
+ Mockito.when(invoice.getBalance()).thenReturn(new BigDecimal("18376"));
+ Mockito.when(invoice.isMigrationInvoice()).thenReturn(false);
+ Mockito.when(invoice.getCreatedDate()).thenReturn(INVOICE_CREATED_DATE);
+
+ return invoice;
+ }
+
+ protected InvoiceItem createInvoiceItem(final UUID invoiceId, final InvoiceItemType type) {
+ return createInvoiceItem(invoiceId, type, BigDecimal.TEN);
+ }
+
+ protected InvoiceItem createInvoiceItem(final UUID invoiceId, final InvoiceItemType type, final BigDecimal amount) {
+ return createInvoiceItem(invoiceId, type, UUID.randomUUID(), new LocalDate(2013, 1, 2), new LocalDate(2013, 2, 5), amount, null);
+ }
+
+ protected InvoiceItem createInvoiceItem(final UUID invoiceId,
+ final InvoiceItemType invoiceItemType,
+ final BigDecimal amount,
+ final UUID linkedItemId) {
+ return createInvoiceItem(invoiceId, invoiceItemType, UUID.randomUUID(), new LocalDate(2013, 1, 2), new LocalDate(2013, 2, 5), amount, linkedItemId);
+ }
+
+ protected InvoiceItem createInvoiceItem(final UUID invoiceId,
+ final InvoiceItemType invoiceItemType,
+ final UUID subscriptionId,
+ final LocalDate startDate,
+ final LocalDate endDate,
+ final BigDecimal amount,
+ @Nullable final UUID linkedItemId) {
+ final UUID invoiceItemId = UUID.randomUUID();
+
+ final InvoiceItem invoiceItem = Mockito.mock(InvoiceItem.class);
+ Mockito.when(invoiceItem.getId()).thenReturn(invoiceItemId);
+ Mockito.when(invoiceItem.getInvoiceItemType()).thenReturn(invoiceItemType);
+ Mockito.when(invoiceItem.getInvoiceId()).thenReturn(invoiceId);
+ Mockito.when(invoiceItem.getAccountId()).thenReturn(UUID.randomUUID());
+ Mockito.when(invoiceItem.getStartDate()).thenReturn(startDate);
+ Mockito.when(invoiceItem.getEndDate()).thenReturn(endDate);
+ Mockito.when(invoiceItem.getAmount()).thenReturn(amount);
+ Mockito.when(invoiceItem.getCurrency()).thenReturn(Currency.EUR);
+ Mockito.when(invoiceItem.getDescription()).thenReturn(UUID.randomUUID().toString());
+ Mockito.when(invoiceItem.getBundleId()).thenReturn(UUID.randomUUID());
+ Mockito.when(invoiceItem.getSubscriptionId()).thenReturn(subscriptionId);
+ Mockito.when(invoiceItem.getPlanName()).thenReturn(UUID.randomUUID().toString());
+ Mockito.when(invoiceItem.getPhaseName()).thenReturn(UUID.randomUUID().toString());
+ Mockito.when(invoiceItem.getRate()).thenReturn(new BigDecimal("1203"));
+ Mockito.when(invoiceItem.getLinkedItemId()).thenReturn(linkedItemId);
+ Mockito.when(invoiceItem.getCreatedDate()).thenReturn(INVOICE_CREATED_DATE);
+
+ return invoiceItem;
+ }
+
@BeforeMethod(groups = "fast")
public void setUp() throws Exception {
account = Mockito.mock(Account.class);
@@ -261,7 +336,7 @@ public abstract class AnalyticsTestSuiteNoDB {
Mockito.when(invoicePayment.getCurrency()).thenReturn(Currency.MXN);
Mockito.when(invoicePayment.getLinkedInvoicePaymentId()).thenReturn(UUID.randomUUID());
Mockito.when(invoicePayment.getPaymentCookieId()).thenReturn(UUID.randomUUID());
- Mockito.when(invoicePayment.getCreatedDate()).thenReturn(new DateTime(2016, 1, 22, 10, 56, 53, DateTimeZone.UTC));
+ Mockito.when(invoicePayment.getCreatedDate()).thenReturn(INVOICE_CREATED_DATE);
final UUID invoicePaymentId = invoicePayment.getId();
invoice = Mockito.mock(Invoice.class);
@@ -284,7 +359,7 @@ public abstract class AnalyticsTestSuiteNoDB {
Mockito.when(invoice.getRefundAdjAmount()).thenReturn(new BigDecimal("384"));
Mockito.when(invoice.getBalance()).thenReturn(new BigDecimal("18376"));
Mockito.when(invoice.isMigrationInvoice()).thenReturn(false);
- Mockito.when(invoice.getCreatedDate()).thenReturn(new DateTime(2016, 1, 22, 10, 56, 53, DateTimeZone.UTC));
+ Mockito.when(invoice.getCreatedDate()).thenReturn(INVOICE_CREATED_DATE);
paymentAttempt = Mockito.mock(PaymentAttempt.class);
Mockito.when(paymentAttempt.getId()).thenReturn(UUID.randomUUID());
diff --git a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/api/TestBusinessInvoice.java b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/api/TestBusinessInvoice.java
index 51fdbb1..39d0020 100644
--- a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/api/TestBusinessInvoice.java
+++ b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/api/TestBusinessInvoice.java
@@ -16,6 +16,8 @@
package com.ning.billing.osgi.bundles.analytics.api;
+import java.math.BigDecimal;
+
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -29,9 +31,16 @@ public class TestBusinessInvoice extends AnalyticsTestSuiteNoDB {
@Test(groups = "fast")
public void testConstructor() throws Exception {
+ final BigDecimal balance = BigDecimal.ONE;
+ final BigDecimal amountPaid = BigDecimal.TEN;
+ final BigDecimal amountCharged = BigDecimal.ZERO;
+ final BigDecimal originalAmountCharged = BigDecimal.ONE;
final BusinessInvoiceModelDao invoiceModelDao = new BusinessInvoiceModelDao(account,
accountRecordId,
invoice,
+ amountPaid,
+ amountCharged,
+ originalAmountCharged,
invoiceRecordId,
auditLog,
tenantRecordId,
diff --git a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/api/TestBusinessSnapshot.java b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/api/TestBusinessSnapshot.java
index 1634b9d..349a3d0 100644
--- a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/api/TestBusinessSnapshot.java
+++ b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/api/TestBusinessSnapshot.java
@@ -71,6 +71,9 @@ public class TestBusinessSnapshot extends AnalyticsTestSuiteNoDB {
final BusinessInvoiceModelDao invoiceModelDao = new BusinessInvoiceModelDao(account,
accountRecordId,
invoice,
+ BigDecimal.ONE,
+ BigDecimal.ONE,
+ BigDecimal.ONE,
invoiceRecordId,
auditLog,
tenantRecordId,
diff --git a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoiceItemModelDao.java b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoiceItemModelDao.java
index 1d867e8..cd2a065 100644
--- a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoiceItemModelDao.java
+++ b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoiceItemModelDao.java
@@ -85,11 +85,12 @@ public class TestBusinessInvoiceItemModelDao extends AnalyticsTestSuiteNoDB {
Assert.assertEquals(invoiceItemModelDao.getInvoiceDate(), invoice.getInvoiceDate());
Assert.assertEquals(invoiceItemModelDao.getInvoiceTargetDate(), invoice.getTargetDate());
Assert.assertEquals(invoiceItemModelDao.getInvoiceCurrency(), invoice.getCurrency().toString());
- Assert.assertEquals(invoiceItemModelDao.getInvoiceBalance(), invoice.getBalance());
- Assert.assertEquals(invoiceItemModelDao.getInvoiceAmountPaid(), invoice.getPaidAmount());
- Assert.assertEquals(invoiceItemModelDao.getInvoiceAmountCharged(), invoice.getChargedAmount());
- Assert.assertEquals(invoiceItemModelDao.getInvoiceOriginalAmountCharged(), invoice.getOriginalChargedAmount());
- Assert.assertEquals(invoiceItemModelDao.getInvoiceAmountCredited(), invoice.getCreditAdjAmount());
+ Assert.assertNull(invoiceItemModelDao.getInvoiceBalance());
+ Assert.assertNull(invoiceItemModelDao.getInvoiceAmountPaid());
+ Assert.assertNull(invoiceItemModelDao.getInvoiceAmountCharged());
+ Assert.assertNull(invoiceItemModelDao.getInvoiceOriginalAmountCharged());
+ Assert.assertNull(invoiceItemModelDao.getInvoiceAmountCredited());
+ Assert.assertNull(invoiceItemModelDao.getInvoiceAmountRefunded());
Assert.assertEquals(invoiceItemModelDao.getItemType(), invoiceItem.getInvoiceItemType().toString());
//Assert.assertEquals(invoiceItemModelDao.getRevenueRecognizable(), /* TODO */);
Assert.assertEquals(invoiceItemModelDao.getStartDate(), invoiceItem.getStartDate());
diff --git a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoiceModelDao.java b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoiceModelDao.java
index 31bab62..906db0e 100644
--- a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoiceModelDao.java
+++ b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoiceModelDao.java
@@ -16,6 +16,8 @@
package com.ning.billing.osgi.bundles.analytics.dao.model;
+import java.math.BigDecimal;
+
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -25,13 +27,22 @@ public class TestBusinessInvoiceModelDao extends AnalyticsTestSuiteNoDB {
@Test(groups = "fast")
public void testConstructor() throws Exception {
+ final BigDecimal balance = BigDecimal.ONE;
+ final BigDecimal amountCharged = BigDecimal.ZERO;
+ final BigDecimal originalAmountCharged = BigDecimal.ONE;
+ final BigDecimal amountCredited = BigDecimal.TEN;
+
final BusinessInvoiceModelDao invoiceModelDao = new BusinessInvoiceModelDao(account,
accountRecordId,
invoice,
+ amountCharged,
+ originalAmountCharged,
+ amountCredited,
invoiceRecordId,
auditLog,
tenantRecordId,
reportGroup);
+
verifyBusinessModelDaoBase(invoiceModelDao, accountRecordId, tenantRecordId);
Assert.assertEquals(invoiceModelDao.getCreatedDate(), invoice.getCreatedDate());
Assert.assertEquals(invoiceModelDao.getInvoiceRecordId(), invoiceRecordId);
@@ -40,10 +51,11 @@ public class TestBusinessInvoiceModelDao extends AnalyticsTestSuiteNoDB {
Assert.assertEquals(invoiceModelDao.getInvoiceDate(), invoice.getInvoiceDate());
Assert.assertEquals(invoiceModelDao.getTargetDate(), invoice.getTargetDate());
Assert.assertEquals(invoiceModelDao.getCurrency(), invoice.getCurrency().toString());
- Assert.assertEquals(invoiceModelDao.getBalance(), invoice.getBalance());
- Assert.assertEquals(invoiceModelDao.getAmountPaid(), invoice.getPaidAmount());
- Assert.assertEquals(invoiceModelDao.getAmountCharged(), invoice.getChargedAmount());
- Assert.assertEquals(invoiceModelDao.getOriginalAmountCharged(), invoice.getOriginalChargedAmount());
- Assert.assertEquals(invoiceModelDao.getAmountCredited(), invoice.getCreditAdjAmount());
+ Assert.assertEquals(invoiceModelDao.getAmountCharged(), amountCharged);
+ Assert.assertEquals(invoiceModelDao.getOriginalAmountCharged(), originalAmountCharged);
+ Assert.assertEquals(invoiceModelDao.getAmountCredited(), amountCredited);
+ Assert.assertNull(invoiceModelDao.getBalance());
+ Assert.assertNull(invoiceModelDao.getAmountPaid());
+ Assert.assertNull(invoiceModelDao.getAmountRefunded());
}
}
diff --git a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoicePaymentModelDao.java b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoicePaymentModelDao.java
index 51118ca..bcdac82 100644
--- a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoicePaymentModelDao.java
+++ b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/model/TestBusinessInvoicePaymentModelDao.java
@@ -104,11 +104,12 @@ public class TestBusinessInvoicePaymentModelDao extends AnalyticsTestSuiteNoDB {
Assert.assertEquals(invoicePaymentModelDao.getInvoiceDate(), invoice.getInvoiceDate());
Assert.assertEquals(invoicePaymentModelDao.getInvoiceTargetDate(), invoice.getTargetDate());
Assert.assertEquals(invoicePaymentModelDao.getInvoiceCurrency(), invoice.getCurrency().toString());
- Assert.assertEquals(invoicePaymentModelDao.getInvoiceBalance(), invoice.getBalance());
- Assert.assertEquals(invoicePaymentModelDao.getInvoiceAmountPaid(), invoice.getPaidAmount());
- Assert.assertEquals(invoicePaymentModelDao.getInvoiceAmountCharged(), invoice.getChargedAmount());
- Assert.assertEquals(invoicePaymentModelDao.getInvoiceOriginalAmountCharged(), invoice.getOriginalChargedAmount());
- Assert.assertEquals(invoicePaymentModelDao.getInvoiceAmountCredited(), invoice.getCreditAdjAmount());
+ Assert.assertNull(invoicePaymentModelDao.getInvoiceBalance());
+ Assert.assertNull(invoicePaymentModelDao.getInvoiceAmountPaid());
+ Assert.assertNull(invoicePaymentModelDao.getInvoiceAmountCharged());
+ Assert.assertNull(invoicePaymentModelDao.getInvoiceOriginalAmountCharged());
+ Assert.assertNull(invoicePaymentModelDao.getInvoiceAmountCredited());
+ Assert.assertNull(invoicePaymentModelDao.getInvoiceAmountRefunded());
Assert.assertEquals(invoicePaymentModelDao.getInvoicePaymentType(), invoicePayment.getType().toString());
Assert.assertEquals(invoicePaymentModelDao.getPaymentNumber(), (Long) payment.getPaymentNumber().longValue());
Assert.assertEquals(invoicePaymentModelDao.getLinkedInvoicePaymentId(), invoicePayment.getLinkedInvoicePaymentId());
diff --git a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/TestBusinessAnalyticsSqlDao.java b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/TestBusinessAnalyticsSqlDao.java
index abd47c7..32d2f67 100644
--- a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/TestBusinessAnalyticsSqlDao.java
+++ b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/TestBusinessAnalyticsSqlDao.java
@@ -153,6 +153,9 @@ public class TestBusinessAnalyticsSqlDao extends AnalyticsTestSuiteWithEmbeddedD
final BusinessInvoiceModelDao businessInvoiceModelDao = new BusinessInvoiceModelDao(account,
accountRecordId,
invoice,
+ BigDecimal.ONE,
+ BigDecimal.ONE,
+ BigDecimal.ONE,
invoiceRecordId,
auditLog,
tenantRecordId,
diff --git a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/TestBusinessInvoiceAndInvoicePaymentDao.java b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/TestBusinessInvoiceAndInvoicePaymentDao.java
new file mode 100644
index 0000000..60f46e9
--- /dev/null
+++ b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/TestBusinessInvoiceAndInvoicePaymentDao.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.osgi.bundles.analytics.dao;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.ning.billing.invoice.api.Invoice;
+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.osgi.bundles.analytics.AnalyticsTestSuiteNoDB;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceItemBaseModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceModelDao;
+import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoicePaymentBaseModelDao;
+import com.ning.billing.payment.api.Payment;
+import com.ning.killbill.osgi.libs.killbill.OSGIKillbillAPI;
+import com.ning.killbill.osgi.libs.killbill.OSGIKillbillDataSource;
+import com.ning.killbill.osgi.libs.killbill.OSGIKillbillLogService;
+
+import com.google.common.collect.ImmutableList;
+
+public class TestBusinessInvoiceAndInvoicePaymentDao extends AnalyticsTestSuiteNoDB {
+
+ private BusinessInvoiceAndInvoicePaymentDao dao;
+ private OSGIKillbillAPI osgiKillbillApi;
+
+ @Override
+ @BeforeMethod(groups = "fast")
+ public void setUp() throws Exception {
+ super.setUp();
+
+ final OSGIKillbillDataSource osgiKillbillDataSource = Mockito.mock(OSGIKillbillDataSource.class);
+
+ final DataSource dataSource = Mockito.mock(DataSource.class);
+ Mockito.when(osgiKillbillDataSource.getDataSource()).thenReturn(dataSource);
+
+ final OSGIKillbillLogService osgiKillbillLogService = Mockito.mock(OSGIKillbillLogService.class);
+ Mockito.doAnswer(new Answer() {
+ @Override
+ public Object answer(final InvocationOnMock invocation) throws Throwable {
+ logger.info(Arrays.toString(invocation.getArguments()));
+ return null;
+ }
+ }).when(osgiKillbillLogService).log(Mockito.anyInt(), Mockito.anyString());
+
+ osgiKillbillApi = Mockito.mock(OSGIKillbillAPI.class, Mockito.RETURNS_DEEP_STUBS);
+
+ final BusinessAccountDao businessAccountDao = new BusinessAccountDao(osgiKillbillLogService, osgiKillbillApi, osgiKillbillDataSource);
+ dao = new BusinessInvoiceAndInvoicePaymentDao(osgiKillbillLogService, osgiKillbillApi, osgiKillbillDataSource, businessAccountDao);
+ }
+
+ @Test(groups = "fast")
+ public void testVerifyDenormalizationFillUp() throws Exception {
+ /*
+ * Invoice 349:
+ * +588 (recurring1)
+ * -588 (repair)
+ * +588 (cba)
+ */
+ final UUID invoice349Id = UUID.randomUUID();
+ final InvoiceItem invoiceItem349Recurring1 = createInvoiceItem(invoice349Id, InvoiceItemType.RECURRING, new BigDecimal("588"));
+ final InvoiceItem invoiceItem349Repair = createInvoiceItem(invoice349Id, InvoiceItemType.REPAIR_ADJ, new BigDecimal("-588"), invoiceItem349Recurring1.getId());
+ final InvoiceItem invoiceItem349Cba = createInvoiceItem(invoice349Id, InvoiceItemType.CBA_ADJ, new BigDecimal("588"));
+ final Invoice invoice349 = createInvoice(invoice349Id, 349, ImmutableList.<InvoiceItem>of(invoiceItem349Recurring1, invoiceItem349Repair, invoiceItem349Cba));
+
+ final BigDecimal balance349 = BigDecimal.ZERO;
+ final BigDecimal amountPaid349 = new BigDecimal("588");
+ final BigDecimal amountCharged349 = new BigDecimal("27.40");
+ final BigDecimal originalAmountCharged349 = new BigDecimal("588");
+ final BigDecimal amountCredited349 = new BigDecimal("560.60");
+ final BigDecimal amountRefunded349 = BigDecimal.ZERO;
+
+ /*
+ * Invoice 570:
+ * +27.40 (recurring1 proration)
+ * +42.29 (recurring2)
+ * -69.69 (cba use)
+ */
+ final UUID invoice570Id = UUID.randomUUID();
+ final InvoiceItem invoiceItem570Recurring1Proration = createInvoiceItem(invoice570Id,
+ InvoiceItemType.RECURRING,
+ invoiceItem349Recurring1.getSubscriptionId(),
+ invoiceItem349Recurring1.getStartDate(),
+ invoiceItem349Recurring1.getEndDate().minusDays(1),
+ new BigDecimal("27.40"),
+ null);
+ final InvoiceItem invoiceItem570Recurring2 = createInvoiceItem(invoice570Id, InvoiceItemType.RECURRING, new BigDecimal("42.29"));
+ final InvoiceItem invoiceItem570Cba = createInvoiceItem(invoice570Id, InvoiceItemType.CBA_ADJ, new BigDecimal("-69.69"));
+ final Invoice invoice570 = createInvoice(invoice570Id, 570, ImmutableList.<InvoiceItem>of(invoiceItem570Recurring1Proration, invoiceItem570Recurring2, invoiceItem570Cba));
+
+ final BigDecimal balance570 = BigDecimal.ZERO;
+ final BigDecimal amountPaid570 = BigDecimal.ZERO;
+ final BigDecimal amountCharged570 = new BigDecimal("42.29");
+ final BigDecimal originalAmountCharged570 = new BigDecimal("42.29");
+ final BigDecimal amountCredited570 = new BigDecimal("-42.29");
+ final BigDecimal amountRefunded570 = BigDecimal.ZERO;
+
+ // Setup the mocks
+ // TODO this is really fragile - we need to extract a mock library for testing Kill Bill
+ Mockito.when(osgiKillbillApi.getInvoiceUserApi().getInvoicesByAccount(account.getId(), callContext)).thenReturn(ImmutableList.<Invoice>of(invoice349, invoice570));
+ Mockito.when(osgiKillbillApi.getInvoiceUserApi().getInvoice(invoice349Id, callContext)).thenReturn(invoice349);
+ Mockito.when(osgiKillbillApi.getInvoiceUserApi().getInvoice(invoice570Id, callContext)).thenReturn(invoice570);
+
+ Mockito.when(payment.getAmount()).thenReturn(amountPaid349);
+ Mockito.when(osgiKillbillApi.getPaymentApi().getAccountPayments(account.getId(), callContext)).thenReturn(ImmutableList.<Payment>of(payment));
+
+ Mockito.when(invoicePayment.getInvoiceId()).thenReturn(invoice349Id);
+ Mockito.when(invoicePayment.getAmount()).thenReturn(amountPaid349);
+ Mockito.when(osgiKillbillApi.getInvoicePaymentApi().getInvoicePayments(payment.getId(), callContext)).thenReturn(ImmutableList.<InvoicePayment>of(invoicePayment));
+
+ // Compute the pojos
+ final Map<UUID, BusinessInvoiceModelDao> invoices = new HashMap<UUID, BusinessInvoiceModelDao>();
+ final Map<UUID, Collection<BusinessInvoiceItemBaseModelDao>> invoiceItems = new HashMap<UUID, Collection<BusinessInvoiceItemBaseModelDao>>();
+ final Map<UUID, Collection<BusinessInvoicePaymentBaseModelDao>> invoicePayments = new HashMap<UUID, Collection<BusinessInvoicePaymentBaseModelDao>>();
+ dao.createBusinessPojos(account, invoices, invoiceItems, invoicePayments, callContext);
+
+ /*
+ * Expected Business invoice 349:
+ * BII : +588 (recurring1)
+ * BIIA : -560.60
+ * BIIC: +560.60
+ *
+ * Expected Business invoice 570:
+ * BII : +42.29 (recurring2)
+ * BIIC: -42.29
+ */
+ Assert.assertEquals(invoices.keySet().size(), 2);
+
+ Assert.assertEquals(invoices.get(invoice349Id).getBalance().compareTo(balance349), 0);
+ Assert.assertEquals(invoices.get(invoice349Id).getAmountPaid().compareTo(amountPaid349), 0);
+ Assert.assertEquals(invoices.get(invoice349Id).getAmountCharged().compareTo(amountCharged349), 0);
+ Assert.assertEquals(invoices.get(invoice349Id).getOriginalAmountCharged().compareTo(originalAmountCharged349), 0);
+ Assert.assertEquals(invoices.get(invoice349Id).getAmountCredited().compareTo(amountCredited349), 0);
+ Assert.assertEquals(invoices.get(invoice349Id).getAmountRefunded().compareTo(amountRefunded349), 0);
+
+ Assert.assertEquals(invoices.get(invoice570Id).getBalance().compareTo(balance570), 0);
+ Assert.assertEquals(invoices.get(invoice570Id).getAmountPaid().compareTo(amountPaid570), 0);
+ Assert.assertEquals(invoices.get(invoice570Id).getAmountCharged().compareTo(amountCharged570), 0);
+ Assert.assertEquals(invoices.get(invoice570Id).getOriginalAmountCharged().compareTo(originalAmountCharged570), 0);
+ Assert.assertEquals(invoices.get(invoice570Id).getAmountCredited().compareTo(amountCredited570), 0);
+ Assert.assertEquals(invoices.get(invoice570Id).getAmountRefunded().compareTo(amountRefunded570), 0);
+
+ Assert.assertEquals(invoiceItems.get(invoice349Id).size(), 3);
+ for (final BusinessInvoiceItemBaseModelDao invoiceItem : invoiceItems.get(invoice349Id)) {
+ if (InvoiceItemType.RECURRING.toString().equals(invoiceItem.getItemType())) {
+ Assert.assertEquals(invoiceItem.getAmount().compareTo(new BigDecimal("588")), 0, String.format("RECURRING item is %s, not 588", invoiceItem.getAmount()));
+ } else if (InvoiceItemType.ITEM_ADJ.toString().equals(invoiceItem.getItemType())) {
+ Assert.assertEquals(invoiceItem.getAmount().compareTo(new BigDecimal("-560.60")), 0, String.format("ITEM_ADJ item is %s, not -560.60", invoiceItem.getAmount()));
+ } else if (InvoiceItemType.CBA_ADJ.toString().equals(invoiceItem.getItemType())) {
+ Assert.assertEquals(invoiceItem.getAmount().compareTo(new BigDecimal("560.60")), 0, String.format("CBA item is %s, not 560.60", invoiceItem.getAmount()));
+ } else {
+ Assert.fail();
+ }
+ }
+
+ Assert.assertEquals(invoiceItems.get(invoice570Id).size(), 2);
+ for (final BusinessInvoiceItemBaseModelDao invoiceItem : invoiceItems.get(invoice570Id)) {
+ if (InvoiceItemType.RECURRING.toString().equals(invoiceItem.getItemType())) {
+ Assert.assertEquals(invoiceItem.getAmount().compareTo(new BigDecimal("42.29")), 0, String.format("RECURRING item is %s, not 42.29", invoiceItem.getAmount()));
+ } else if (InvoiceItemType.CBA_ADJ.toString().equals(invoiceItem.getItemType())) {
+ Assert.assertEquals(invoiceItem.getAmount().compareTo(new BigDecimal("-42.29")), 0, String.format("CBA item is %s, not -42.29", invoiceItem.getAmount()));
+ } else {
+ Assert.fail();
+ }
+ }
+ }
+}
diff --git a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/TestBusinessInvoiceDao.java b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/TestBusinessInvoiceDao.java
index c063011..1f1e381 100644
--- a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/TestBusinessInvoiceDao.java
+++ b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/dao/TestBusinessInvoiceDao.java
@@ -21,11 +21,8 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.UUID;
-import javax.annotation.Nullable;
import javax.sql.DataSource;
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
@@ -34,11 +31,11 @@ import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.InvoiceItem;
import com.ning.billing.invoice.api.InvoiceItemType;
import com.ning.billing.osgi.bundles.analytics.AnalyticsTestSuiteNoDB;
import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessInvoiceItemBaseModelDao;
+import com.ning.billing.osgi.bundles.analytics.utils.BusinessInvoiceUtils;
import com.ning.killbill.osgi.libs.killbill.OSGIKillbillDataSource;
import com.ning.killbill.osgi.libs.killbill.OSGIKillbillLogService;
@@ -46,9 +43,6 @@ import com.google.common.collect.ImmutableList;
public class TestBusinessInvoiceDao extends AnalyticsTestSuiteNoDB {
- private final UUID accountId = UUID.randomUUID();
- private final UUID bundleId = UUID.randomUUID();
-
private BusinessInvoiceDao invoiceDao;
@Override
@@ -70,7 +64,7 @@ public class TestBusinessInvoiceDao extends AnalyticsTestSuiteNoDB {
}
}).when(osgiKillbillLogService).log(Mockito.anyInt(), Mockito.anyString());
- invoiceDao = new BusinessInvoiceDao(osgiKillbillLogService, null, osgiKillbillDataSource, null);
+ invoiceDao = new BusinessInvoiceDao(osgiKillbillLogService, null, osgiKillbillDataSource);
}
@Test(groups = "fast")
@@ -196,22 +190,22 @@ public class TestBusinessInvoiceDao extends AnalyticsTestSuiteNoDB {
public void testInvoiceAdjustment() throws Exception {
final UUID invoiceId = UUID.randomUUID();
- Assert.assertFalse(invoiceDao.isInvoiceAdjustmentItem(createInvoiceItem(invoiceId, InvoiceItemType.RECURRING),
- ImmutableList.<InvoiceItem>of()));
- Assert.assertTrue(invoiceDao.isInvoiceAdjustmentItem(createInvoiceItem(invoiceId, InvoiceItemType.REFUND_ADJ),
- ImmutableList.<InvoiceItem>of()));
+ Assert.assertFalse(BusinessInvoiceUtils.isInvoiceAdjustmentItem(createInvoiceItem(invoiceId, InvoiceItemType.RECURRING),
+ ImmutableList.<InvoiceItem>of()));
+ Assert.assertTrue(BusinessInvoiceUtils.isInvoiceAdjustmentItem(createInvoiceItem(invoiceId, InvoiceItemType.REFUND_ADJ),
+ ImmutableList.<InvoiceItem>of()));
final InvoiceItem creditAdj = createInvoiceItem(invoiceId, InvoiceItemType.CREDIT_ADJ);
// Account credit
- Assert.assertFalse(invoiceDao.isInvoiceAdjustmentItem(creditAdj,
- ImmutableList.<InvoiceItem>of(createInvoiceItem(invoiceId, InvoiceItemType.CBA_ADJ, creditAdj.getAmount().negate()))));
-
- Assert.assertTrue(invoiceDao.isInvoiceAdjustmentItem(creditAdj,
- ImmutableList.<InvoiceItem>of(createInvoiceItem(invoiceId, InvoiceItemType.CBA_ADJ, creditAdj.getAmount().negate().add(BigDecimal.ONE)))));
- Assert.assertTrue(invoiceDao.isInvoiceAdjustmentItem(creditAdj,
- ImmutableList.<InvoiceItem>of(createInvoiceItem(invoiceId, InvoiceItemType.RECURRING),
- createInvoiceItem(invoiceId, InvoiceItemType.CBA_ADJ, creditAdj.getAmount().negate()))));
+ Assert.assertFalse(BusinessInvoiceUtils.isInvoiceAdjustmentItem(creditAdj,
+ ImmutableList.<InvoiceItem>of(createInvoiceItem(invoiceId, InvoiceItemType.CBA_ADJ, creditAdj.getAmount().negate()))));
+
+ Assert.assertTrue(BusinessInvoiceUtils.isInvoiceAdjustmentItem(creditAdj,
+ ImmutableList.<InvoiceItem>of(createInvoiceItem(invoiceId, InvoiceItemType.CBA_ADJ, creditAdj.getAmount().negate().add(BigDecimal.ONE)))));
+ Assert.assertTrue(BusinessInvoiceUtils.isInvoiceAdjustmentItem(creditAdj,
+ ImmutableList.<InvoiceItem>of(createInvoiceItem(invoiceId, InvoiceItemType.RECURRING),
+ createInvoiceItem(invoiceId, InvoiceItemType.CBA_ADJ, creditAdj.getAmount().negate()))));
}
@Test(groups = "fast")
@@ -276,42 +270,4 @@ public class TestBusinessInvoiceDao extends AnalyticsTestSuiteNoDB {
}
}
}
-
- private InvoiceItem createInvoiceItem(final UUID invoiceId, final InvoiceItemType type) {
- return createInvoiceItem(invoiceId, type, BigDecimal.TEN);
- }
-
- private InvoiceItem createInvoiceItem(final UUID invoiceId, final InvoiceItemType type, final BigDecimal amount) {
- return createInvoiceItem(invoiceId, type, UUID.randomUUID(), new LocalDate(2013, 1, 2), new LocalDate(2013, 2, 5), amount, null);
- }
-
- private InvoiceItem createInvoiceItem(final UUID invoiceId,
- final InvoiceItemType invoiceItemType,
- final UUID subscriptionId,
- final LocalDate startDate,
- final LocalDate endDate,
- final BigDecimal amount,
- @Nullable final UUID linkedItemId) {
- final UUID invoiceItemId = UUID.randomUUID();
-
- final InvoiceItem invoiceItem = Mockito.mock(InvoiceItem.class);
- Mockito.when(invoiceItem.getId()).thenReturn(invoiceItemId);
- Mockito.when(invoiceItem.getInvoiceItemType()).thenReturn(invoiceItemType);
- Mockito.when(invoiceItem.getInvoiceId()).thenReturn(invoiceId);
- Mockito.when(invoiceItem.getAccountId()).thenReturn(accountId);
- Mockito.when(invoiceItem.getStartDate()).thenReturn(startDate);
- Mockito.when(invoiceItem.getEndDate()).thenReturn(endDate);
- Mockito.when(invoiceItem.getAmount()).thenReturn(amount);
- Mockito.when(invoiceItem.getCurrency()).thenReturn(Currency.EUR);
- Mockito.when(invoiceItem.getDescription()).thenReturn(UUID.randomUUID().toString());
- Mockito.when(invoiceItem.getBundleId()).thenReturn(bundleId);
- Mockito.when(invoiceItem.getSubscriptionId()).thenReturn(subscriptionId);
- Mockito.when(invoiceItem.getPlanName()).thenReturn(UUID.randomUUID().toString());
- Mockito.when(invoiceItem.getPhaseName()).thenReturn(UUID.randomUUID().toString());
- Mockito.when(invoiceItem.getRate()).thenReturn(new BigDecimal("1203"));
- Mockito.when(invoiceItem.getLinkedItemId()).thenReturn(linkedItemId);
- Mockito.when(invoiceItem.getCreatedDate()).thenReturn(new DateTime(2016, 1, 22, 10, 56, 51, DateTimeZone.UTC));
-
- return invoiceItem;
- }
}