killbill-memoizeit
Details
.gitignore 1(+1 -0)
diff --git a/.gitignore b/.gitignore
index 395361e..9e14eea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.idea/workspace.xml
+.idea/libraries
*.ipr
*.iws
*.DS_Store
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
index eb26739..65848da 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
@@ -19,6 +19,7 @@ package com.ning.billing.jaxrs.resources;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
@@ -433,6 +434,7 @@ public class AccountResource extends JaxRsResourceBase {
public Response createPaymentMethod(final PaymentMethodJson json,
@PathParam("accountId") final String accountId,
@QueryParam(QUERY_PAYMENT_METHOD_IS_DEFAULT) @DefaultValue("false") final Boolean isDefault,
+ @QueryParam(QUERY_PAY_ALL_UNPAID_INVOICES) @DefaultValue("false") final Boolean payAllUnpaidInvoices,
@HeaderParam(HDR_CREATED_BY) final String createdBy,
@HeaderParam(HDR_REASON) final String reason,
@HeaderParam(HDR_COMMENT) final String comment,
@@ -443,7 +445,19 @@ public class AccountResource extends JaxRsResourceBase {
final PaymentMethod data = json.toPaymentMethod(accountId);
final Account account = accountUserApi.getAccountById(data.getAccountId(), callContext);
+ final boolean hasDefaultPaymentMethod = account.getPaymentMethodId() != null || isDefault;
+ final Collection<Invoice> unpaidInvoices = payAllUnpaidInvoices ? invoiceApi.getUnpaidInvoicesByAccountId(account.getId(), clock.getUTCToday(), callContext) :
+ Collections.<Invoice>emptyList();
+ if (payAllUnpaidInvoices && unpaidInvoices.size() > 0 && !hasDefaultPaymentMethod) {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
+
final UUID paymentMethodId = paymentApi.addPaymentMethod(data.getPluginName(), account, isDefault, data.getPluginDetail(), callContext);
+ if (payAllUnpaidInvoices && unpaidInvoices.size() > 0) {
+ for (final Invoice invoice : unpaidInvoices) {
+ paymentApi.createPayment(account, invoice.getId(), invoice.getBalance(), callContext);
+ }
+ }
return uriBuilder.buildResponse(PaymentMethodResource.class, "getPaymentMethod", paymentMethodId, uriInfo.getBaseUri().toString());
}
@@ -473,6 +487,7 @@ public class AccountResource extends JaxRsResourceBase {
@Path("/{accountId:" + UUID_PATTERN + "}/" + PAYMENT_METHODS + "/{paymentMethodId:" + UUID_PATTERN + "}/" + PAYMENT_METHODS_DEFAULT_PATH_POSTFIX)
public Response setDefaultPaymentMethod(@PathParam("accountId") final String accountId,
@PathParam("paymentMethodId") final String paymentMethodId,
+ @QueryParam(QUERY_PAY_ALL_UNPAID_INVOICES) @DefaultValue("false") final Boolean payAllUnpaidInvoices,
@HeaderParam(HDR_CREATED_BY) final String createdBy,
@HeaderParam(HDR_REASON) final String reason,
@HeaderParam(HDR_COMMENT) final String comment,
@@ -481,6 +496,13 @@ public class AccountResource extends JaxRsResourceBase {
final Account account = accountUserApi.getAccountById(UUID.fromString(accountId), callContext);
paymentApi.setDefaultPaymentMethod(account, UUID.fromString(paymentMethodId), callContext);
+
+ if (payAllUnpaidInvoices) {
+ final Collection<Invoice> unpaidInvoices = invoiceApi.getUnpaidInvoicesByAccountId(account.getId(), clock.getUTCToday(), callContext);
+ for (final Invoice invoice : unpaidInvoices) {
+ paymentApi.createPayment(account, invoice.getId(), invoice.getBalance(), callContext);
+ }
+ }
return Response.status(Status.OK).build();
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
index 9c595e1..6f43c9a 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
@@ -253,15 +253,18 @@ public class InvoiceResource extends JaxRsResourceBase {
@Path("/" +CHARGES)
public Response createExternalCharge(final InvoiceItemJson externalChargeJson,
@QueryParam(QUERY_REQUESTED_DT) final String requestedDateTimeString,
+ @QueryParam(QUERY_PAY_INVOICE) @DefaultValue("false") final Boolean payInvoice,
@HeaderParam(HDR_CREATED_BY) final String createdBy,
@HeaderParam(HDR_REASON) final String reason,
@HeaderParam(HDR_COMMENT) final String comment,
@javax.ws.rs.core.Context final UriInfo uriInfo,
- @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, InvoiceApiException {
+ @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, InvoiceApiException, PaymentApiException {
final CallContext callContext = context.createContext(createdBy, reason, comment, request);
final Account account = accountUserApi.getAccountById(UUID.fromString(externalChargeJson.getAccountId()), callContext);
-
+ if (payInvoice && account.getPaymentMethodId() == null) {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
// Get the effective date of the external charge, in the account timezone
final LocalDate requestedDate = toLocalDate(account, requestedDateTimeString, callContext);
@@ -277,6 +280,10 @@ public class InvoiceResource extends JaxRsResourceBase {
currency, callContext);
}
+ if (payInvoice) {
+ final Invoice invoice = invoiceApi.getInvoice(externalCharge.getInvoiceId(), callContext);
+ paymentApi.createPayment(account, invoice.getId(), invoice.getBalance(), callContext);
+ }
return uriBuilder.buildResponse(InvoiceResource.class, "getInvoice", externalCharge.getInvoiceId(), uriInfo.getBaseUri().toString());
}
@@ -287,14 +294,18 @@ public class InvoiceResource extends JaxRsResourceBase {
public Response createExternalChargeForInvoice(final InvoiceItemJson externalChargeJson,
@PathParam("invoiceId") final String invoiceIdString,
@QueryParam(QUERY_REQUESTED_DT) final String requestedDateTimeString,
+ @QueryParam(QUERY_PAY_INVOICE) @DefaultValue("false") final Boolean payInvoice,
@HeaderParam(HDR_CREATED_BY) final String createdBy,
@HeaderParam(HDR_REASON) final String reason,
@HeaderParam(HDR_COMMENT) final String comment,
@javax.ws.rs.core.Context final UriInfo uriInfo,
- @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, InvoiceApiException {
+ @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, InvoiceApiException, PaymentApiException {
final CallContext callContext = context.createContext(createdBy, reason, comment, request);
final Account account = accountUserApi.getAccountById(UUID.fromString(externalChargeJson.getAccountId()), callContext);
+ if (payInvoice && account.getPaymentMethodId() == null) {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
// Get the effective date of the external charge, in the account timezone
final LocalDate requestedDate = toLocalDate(account, requestedDateTimeString, callContext);
@@ -312,6 +323,11 @@ public class InvoiceResource extends JaxRsResourceBase {
requestedDate, currency, callContext);
}
+ if (payInvoice) {
+ final Invoice invoice = invoiceApi.getInvoice(externalCharge.getInvoiceId(), callContext);
+ paymentApi.createPayment(account, invoice.getId(), invoice.getBalance(), callContext);
+ }
+
return uriBuilder.buildResponse(InvoiceResource.class, "getInvoice", externalCharge.getInvoiceId(), uriInfo.getBaseUri().toString());
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
index bf2915a..0f1e2d1 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
@@ -80,6 +80,9 @@ public interface JaxrsResource {
public static final String QUERY_PAYMENT_METHOD_PLUGIN_INFO = "withPluginInfo";
public static final String QUERY_PAYMENT_METHOD_IS_DEFAULT = "isDefault";
+ public static final String QUERY_PAY_ALL_UNPAID_INVOICES = "payAllUnpaidInvoices";
+ public static final String QUERY_PAY_INVOICE = "payInvoice";
+
public static final String QUERY_BUNDLE_TRANSFER_ADDON = "transferAddOn";
public static final String QUERY_BUNDLE_TRANSFER_CANCEL_IMM = "cancelImmediately";
diff --git a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
index 2d4bb21..ee412f3 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
@@ -118,6 +118,8 @@ public class OverdueStateApplicator {
createFutureNotification(overdueable, clock.getUTCNow().plus(reevaluationInterval), context);
log.debug("OverdueStateApplicator <notificationQ> : inserting notification for time = " + clock.getUTCNow().plus(reevaluationInterval));
+ } else if (nextOverdueState.isClearState()) {
+ clearFutureNotification(overdueable, context);
}
if (previousOverdueStateName.equals(nextOverdueState.getName())) {
@@ -136,9 +138,6 @@ public class OverdueStateApplicator {
}
}
- if (nextOverdueState.isClearState()) {
- clearFutureNotification(overdueable, context);
- }
try {
bus.post(createOverdueEvent(overdueable, previousOverdueStateName, nextOverdueState.getName(), context));
diff --git a/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
index b7d1296..bfc5550 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
@@ -75,6 +75,8 @@ import static com.ning.billing.payment.glue.PaymentModule.PLUGIN_EXECUTOR_NAMED;
public class PaymentProcessor extends ProcessorBase {
+ private static final UUID MISSING_PAYMENT_METHOD_ID = UUID.fromString("99999999-dead-beef-babe-999999999999");
+
private final PaymentMethodProcessor paymentMethodProcessor;
private final FailedPaymentRetryServiceScheduler failedPaymentRetryService;
private final PluginFailureRetryServiceScheduler pluginFailureRetryService;
@@ -258,6 +260,10 @@ public class PaymentProcessor extends ProcessorBase {
paymentMethodId = account.getPaymentMethodId();
}
} catch (PaymentApiException e) {
+
+ // Insert a payment entry with one attempt in a terminal state to keep a record of the failure
+ processNewPaymentForMissingDefaultPaymentMethodWithAccountLocked(account, invoice, requestedAmount, context);
+
// This event will be caught by overdue to refresh the overdue state, if needed.
// Note that at this point, we don't know the exact invoice balance (see getAndValidatePaymentAmount() below).
// This means that events will be posted for null and zero dollar invoices (e.g. trials).
@@ -438,6 +444,20 @@ public class PaymentProcessor extends ProcessorBase {
return fromPaymentModelDao(paymentInfo, null, context);
}
+
+ private Payment processNewPaymentForMissingDefaultPaymentMethodWithAccountLocked(final Account account, final Invoice invoice,
+ final BigDecimal requestedAmount, final InternalCallContext context)
+ throws PaymentApiException {
+ final PaymentStatus paymentStatus = PaymentStatus.PAYMENT_FAILURE_ABORTED ;
+
+ final PaymentModelDao paymentInfo = new PaymentModelDao(account.getId(), invoice.getId(), MISSING_PAYMENT_METHOD_ID, requestedAmount, invoice.getCurrency(), clock.getUTCNow(), paymentStatus);
+ final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), paymentInfo.getId(), MISSING_PAYMENT_METHOD_ID, paymentStatus, clock.getUTCNow(), requestedAmount);
+
+ paymentDao.insertPaymentWithFirstAttempt(paymentInfo, attempt, context);
+ return fromPaymentModelDao(paymentInfo, null, context);
+ }
+
+
private Payment processNewPaymentWithAccountLocked(final UUID paymentMethodId, final PaymentPluginApi plugin, final Account account, final Invoice invoice,
final BigDecimal requestedAmount, final boolean isInstantPayment, final InternalCallContext context) throws PaymentApiException {
final PaymentModelDao payment = new PaymentModelDao(account.getId(), invoice.getId(), paymentMethodId, requestedAmount.setScale(2, RoundingMode.HALF_UP), invoice.getCurrency(), clock.getUTCNow());
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
index 7193cb9..1587ee6 100644
--- a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
@@ -17,93 +17,45 @@
package com.ning.billing.payment.api;
import java.math.BigDecimal;
-import java.math.RoundingMode;
import java.util.List;
import java.util.UUID;
import org.joda.time.LocalDate;
-import org.mockito.Mockito;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.testng.Assert;
import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.ning.billing.ErrorCode;
import com.ning.billing.account.api.Account;
+import com.ning.billing.bus.api.PersistentBus.EventBusException;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceApiException;
import com.ning.billing.payment.MockRecurringInvoiceItem;
-import com.ning.billing.payment.PaymentTestSuiteNoDB;
-import com.ning.billing.payment.provider.DefaultNoOpPaymentMethodPlugin;
-import com.ning.billing.payment.provider.MockPaymentProviderPlugin;
+import com.ning.billing.payment.PaymentTestSuiteWithEmbeddedDB;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
+public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
-public class TestPaymentApi extends PaymentTestSuiteNoDB {
-
- private static final Logger log = LoggerFactory.getLogger(TestPaymentApi.class);
private Account account;
- @BeforeClass(groups = "fast")
+ @BeforeClass(groups = "slow")
public void beforeClass() throws Exception {
super.beforeClass();
- account = testHelper.createTestAccount("yoyo.yahoo.com", false);
- }
-
- @BeforeMethod(groups = "fast")
- public void beforeMethod() throws Exception {
- super.beforeMethod();
- final PaymentMethodPlugin paymentMethodInfo = new DefaultNoOpPaymentMethodPlugin(UUID.randomUUID().toString(), true, null);
- testHelper.addTestPaymentMethod(account, paymentMethodInfo);
- }
-
- @Test(groups = "fast")
- public void testSimplePaymentWithNoAmount() throws Exception {
- final BigDecimal invoiceAmount = new BigDecimal("10.0011");
- final BigDecimal requestedAmount = null;
- final BigDecimal expectedAmount = invoiceAmount;
-
- testSimplePayment(invoiceAmount, requestedAmount, expectedAmount);
+ account = testHelper.createTestAccount("bobo@gmail.com", false);
}
- @Test(groups = "fast")
- public void testSimplePaymentWithInvoiceAmount() throws Exception {
- final BigDecimal invoiceAmount = new BigDecimal("10.0011");
- final BigDecimal requestedAmount = invoiceAmount;
- final BigDecimal expectedAmount = invoiceAmount;
- testSimplePayment(invoiceAmount, requestedAmount, expectedAmount);
- }
-
- @Test(groups = "fast")
- public void testSimplePaymentWithLowerAmount() throws Exception {
- final BigDecimal invoiceAmount = new BigDecimal("10.0011");
- final BigDecimal requestedAmount = new BigDecimal("8.0091");
- final BigDecimal expectedAmount = requestedAmount;
-
- testSimplePayment(invoiceAmount, requestedAmount, expectedAmount);
- }
-
- @Test(groups = "fast")
- public void testSimplePaymentWithInvalidAmount() throws Exception {
- final BigDecimal invoiceAmount = new BigDecimal("10.0011");
- final BigDecimal requestedAmount = new BigDecimal("80.0091");
- final BigDecimal expectedAmount = null;
+ @Test(groups = "slow")
+ public void testCreatePaymentWithNoDefaultPaymentMethod() throws InvoiceApiException, EventBusException, PaymentApiException {
- testSimplePayment(invoiceAmount, requestedAmount, expectedAmount);
- }
- private void testSimplePayment(final BigDecimal invoiceAmount, final BigDecimal requestedAmount, final BigDecimal expectedAmount) throws Exception {
final LocalDate now = clock.getUTCToday();
final Invoice invoice = testHelper.createTestInvoice(account, now, Currency.USD, callContext);
final UUID subscriptionId = UUID.randomUUID();
final UUID bundleId = UUID.randomUUID();
+ final BigDecimal requestedAmount = BigDecimal.TEN;
invoice.addInvoiceItem(new MockRecurringInvoiceItem(invoice.getId(), account.getId(),
subscriptionId,
@@ -111,69 +63,20 @@ public class TestPaymentApi extends PaymentTestSuiteNoDB {
"test plan", "test phase",
now,
now.plusMonths(1),
- invoiceAmount,
+ requestedAmount,
new BigDecimal("1.0"),
Currency.USD));
try {
- final Payment paymentInfo = paymentApi.createPayment(account, invoice.getId(), requestedAmount, callContext);
- if (expectedAmount == null) {
- fail("Expected to fail because requested amount > invoice amount");
- }
- assertNotNull(paymentInfo.getId());
- assertTrue(paymentInfo.getAmount().compareTo(expectedAmount.setScale(2, RoundingMode.HALF_EVEN)) == 0);
- assertNotNull(paymentInfo.getPaymentNumber());
- assertEquals(paymentInfo.getPaymentStatus(), PaymentStatus.SUCCESS);
- assertEquals(paymentInfo.getAttempts().size(), 1);
- assertEquals(paymentInfo.getInvoiceId(), invoice.getId());
- assertEquals(paymentInfo.getCurrency(), Currency.USD);
-
- final PaymentAttempt paymentAttempt = paymentInfo.getAttempts().get(0);
- assertNotNull(paymentAttempt);
- assertNotNull(paymentAttempt.getId());
+ paymentApi.createPayment(account, invoice.getId(), requestedAmount, callContext);
} catch (PaymentApiException e) {
- if (expectedAmount != null) {
- fail("Failed to create payment", e);
- } else {
- log.info(e.getMessage());
- assertEquals(e.getCode(), ErrorCode.PAYMENT_AMOUNT_DENIED.getCode());
- }
+ Assert.assertEquals(e.getCode(), ErrorCode.PAYMENT_NO_DEFAULT_PAYMENT_METHOD.getCode());
}
- }
-
- @Test(groups = "fast")
- public void testPaymentMethods() throws Exception {
- List<PaymentMethod> methods = paymentApi.getPaymentMethods(account, false, callContext);
- assertEquals(methods.size(), 1);
-
- final PaymentMethod initDefaultMethod = methods.get(0);
- assertEquals(initDefaultMethod.getId(), account.getPaymentMethodId());
-
- final PaymentMethodPlugin newPaymenrMethod = new DefaultNoOpPaymentMethodPlugin(UUID.randomUUID().toString(), true, null);
- final UUID newPaymentMethodId = paymentApi.addPaymentMethod(MockPaymentProviderPlugin.PLUGIN_NAME, account, true, newPaymenrMethod, callContext);
- Mockito.when(account.getPaymentMethodId()).thenReturn(newPaymentMethodId);
-
- methods = paymentApi.getPaymentMethods(account, false, callContext);
- assertEquals(methods.size(), 2);
-
- assertEquals(newPaymentMethodId, account.getPaymentMethodId());
-
- boolean failed = false;
- try {
- paymentApi.deletedPaymentMethod(account, newPaymentMethodId, false, callContext);
- } catch (PaymentApiException e) {
- failed = true;
- }
- assertTrue(failed);
-
- paymentApi.deletedPaymentMethod(account, initDefaultMethod.getId(), true, callContext);
- methods = paymentApi.getPaymentMethods(account, false, callContext);
- assertEquals(methods.size(), 1);
- // NOW retry with default payment method with special flag
- paymentApi.deletedPaymentMethod(account, newPaymentMethodId, true, callContext);
+ final List<Payment> payments = paymentApi.getAccountPayments(account.getId(), callContext);
+ Assert.assertEquals(payments.size(), 1);
- methods = paymentApi.getPaymentMethods(account, false, callContext);
- assertEquals(methods.size(), 0);
+ final Payment payment = payments.get(0);
+ Assert.assertEquals(payment.getPaymentStatus(), PaymentStatus.PAYMENT_FAILURE_ABORTED);
}
}
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApiNoDB.java b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApiNoDB.java
new file mode 100644
index 0000000..32938da
--- /dev/null
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApiNoDB.java
@@ -0,0 +1,179 @@
+/*
+ * 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.payment.api;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.LocalDate;
+import org.mockito.Mockito;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.ning.billing.ErrorCode;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.payment.MockRecurringInvoiceItem;
+import com.ning.billing.payment.PaymentTestSuiteNoDB;
+import com.ning.billing.payment.provider.DefaultNoOpPaymentMethodPlugin;
+import com.ning.billing.payment.provider.MockPaymentProviderPlugin;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+public class TestPaymentApiNoDB extends PaymentTestSuiteNoDB {
+
+ private static final Logger log = LoggerFactory.getLogger(TestPaymentApiNoDB.class);
+
+ private Account account;
+
+ @BeforeClass(groups = "fast")
+ public void beforeClass() throws Exception {
+ super.beforeClass();
+ account = testHelper.createTestAccount("yoyo.yahoo.com", false);
+ }
+
+ @BeforeMethod(groups = "fast")
+ public void beforeMethod() throws Exception {
+ super.beforeMethod();
+ final PaymentMethodPlugin paymentMethodInfo = new DefaultNoOpPaymentMethodPlugin(UUID.randomUUID().toString(), true, null);
+ testHelper.addTestPaymentMethod(account, paymentMethodInfo);
+ }
+
+ @Test(groups = "fast")
+ public void testSimplePaymentWithNoAmount() throws Exception {
+ final BigDecimal invoiceAmount = new BigDecimal("10.0011");
+ final BigDecimal requestedAmount = null;
+ final BigDecimal expectedAmount = invoiceAmount;
+
+ testSimplePayment(invoiceAmount, requestedAmount, expectedAmount);
+ }
+
+ @Test(groups = "fast")
+ public void testSimplePaymentWithInvoiceAmount() throws Exception {
+ final BigDecimal invoiceAmount = new BigDecimal("10.0011");
+ final BigDecimal requestedAmount = invoiceAmount;
+ final BigDecimal expectedAmount = invoiceAmount;
+
+ testSimplePayment(invoiceAmount, requestedAmount, expectedAmount);
+ }
+
+ @Test(groups = "fast")
+ public void testSimplePaymentWithLowerAmount() throws Exception {
+ final BigDecimal invoiceAmount = new BigDecimal("10.0011");
+ final BigDecimal requestedAmount = new BigDecimal("8.0091");
+ final BigDecimal expectedAmount = requestedAmount;
+
+ testSimplePayment(invoiceAmount, requestedAmount, expectedAmount);
+ }
+
+ @Test(groups = "fast")
+ public void testSimplePaymentWithInvalidAmount() throws Exception {
+ final BigDecimal invoiceAmount = new BigDecimal("10.0011");
+ final BigDecimal requestedAmount = new BigDecimal("80.0091");
+ final BigDecimal expectedAmount = null;
+
+ testSimplePayment(invoiceAmount, requestedAmount, expectedAmount);
+ }
+
+ private void testSimplePayment(final BigDecimal invoiceAmount, final BigDecimal requestedAmount, final BigDecimal expectedAmount) throws Exception {
+ final LocalDate now = clock.getUTCToday();
+ final Invoice invoice = testHelper.createTestInvoice(account, now, Currency.USD, callContext);
+
+ final UUID subscriptionId = UUID.randomUUID();
+ final UUID bundleId = UUID.randomUUID();
+
+ invoice.addInvoiceItem(new MockRecurringInvoiceItem(invoice.getId(), account.getId(),
+ subscriptionId,
+ bundleId,
+ "test plan", "test phase",
+ now,
+ now.plusMonths(1),
+ invoiceAmount,
+ new BigDecimal("1.0"),
+ Currency.USD));
+
+ try {
+ final Payment paymentInfo = paymentApi.createPayment(account, invoice.getId(), requestedAmount, callContext);
+ if (expectedAmount == null) {
+ fail("Expected to fail because requested amount > invoice amount");
+ }
+ assertNotNull(paymentInfo.getId());
+ assertTrue(paymentInfo.getAmount().compareTo(expectedAmount.setScale(2, RoundingMode.HALF_EVEN)) == 0);
+ assertNotNull(paymentInfo.getPaymentNumber());
+ assertEquals(paymentInfo.getPaymentStatus(), PaymentStatus.SUCCESS);
+ assertEquals(paymentInfo.getAttempts().size(), 1);
+ assertEquals(paymentInfo.getInvoiceId(), invoice.getId());
+ assertEquals(paymentInfo.getCurrency(), Currency.USD);
+
+ final PaymentAttempt paymentAttempt = paymentInfo.getAttempts().get(0);
+ assertNotNull(paymentAttempt);
+ assertNotNull(paymentAttempt.getId());
+ } catch (PaymentApiException e) {
+ if (expectedAmount != null) {
+ fail("Failed to create payment", e);
+ } else {
+ log.info(e.getMessage());
+ assertEquals(e.getCode(), ErrorCode.PAYMENT_AMOUNT_DENIED.getCode());
+ }
+ }
+ }
+
+ @Test(groups = "fast")
+ public void testPaymentMethods() throws Exception {
+ List<PaymentMethod> methods = paymentApi.getPaymentMethods(account, false, callContext);
+ assertEquals(methods.size(), 1);
+
+ final PaymentMethod initDefaultMethod = methods.get(0);
+ assertEquals(initDefaultMethod.getId(), account.getPaymentMethodId());
+
+ final PaymentMethodPlugin newPaymenrMethod = new DefaultNoOpPaymentMethodPlugin(UUID.randomUUID().toString(), true, null);
+ final UUID newPaymentMethodId = paymentApi.addPaymentMethod(MockPaymentProviderPlugin.PLUGIN_NAME, account, true, newPaymenrMethod, callContext);
+ Mockito.when(account.getPaymentMethodId()).thenReturn(newPaymentMethodId);
+
+ methods = paymentApi.getPaymentMethods(account, false, callContext);
+ assertEquals(methods.size(), 2);
+
+ assertEquals(newPaymentMethodId, account.getPaymentMethodId());
+
+ boolean failed = false;
+ try {
+ paymentApi.deletedPaymentMethod(account, newPaymentMethodId, false, callContext);
+ } catch (PaymentApiException e) {
+ failed = true;
+ }
+ assertTrue(failed);
+
+ paymentApi.deletedPaymentMethod(account, initDefaultMethod.getId(), true, callContext);
+ methods = paymentApi.getPaymentMethods(account, false, callContext);
+ assertEquals(methods.size(), 1);
+
+ // NOW retry with default payment method with special flag
+ paymentApi.deletedPaymentMethod(account, newPaymentMethodId, true, callContext);
+
+ methods = paymentApi.getPaymentMethods(account, false, callContext);
+ assertEquals(methods.size(), 0);
+ }
+}
diff --git a/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java b/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
index d56eba2..193dbb1 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
@@ -549,22 +549,25 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
}
protected InvoiceJson createExternalCharge(final String accountId, final BigDecimal amount, @Nullable final String bundleId,
- @Nullable final Currency currency, @Nullable final DateTime requestedDate) throws Exception {
- return doCreateExternalCharge(accountId, null, bundleId, amount, currency, requestedDate, JaxrsResource.CHARGES_PATH);
+ @Nullable final Currency currency, @Nullable final DateTime requestedDate, final Boolean autoPay) throws Exception {
+ return doCreateExternalCharge(accountId, null, bundleId, amount, currency, requestedDate, autoPay, JaxrsResource.CHARGES_PATH);
}
protected InvoiceJson createExternalChargeForInvoice(final String accountId, final String invoiceId, @Nullable final String bundleId, final BigDecimal amount,
- @Nullable final Currency currency, @Nullable final DateTime requestedDate) throws Exception {
+ @Nullable final Currency currency, @Nullable final DateTime requestedDate, final Boolean autoPay) throws Exception {
final String uri = JaxrsResource.INVOICES_PATH + "/" + invoiceId + "/" + JaxrsResource.CHARGES;
- return doCreateExternalCharge(accountId, invoiceId, bundleId, amount, currency, requestedDate, uri);
+ return doCreateExternalCharge(accountId, invoiceId, bundleId, amount, currency, requestedDate, autoPay, uri);
}
private InvoiceJson doCreateExternalCharge(final String accountId, @Nullable final String invoiceId, @Nullable final String bundleId, @Nullable final BigDecimal amount,
- @Nullable final Currency currency, final DateTime requestedDate, final String uri) throws IOException {
+ @Nullable final Currency currency, final DateTime requestedDate, final Boolean autoPay, final String uri) throws IOException {
final Map<String, String> queryParams = new HashMap<String, String>();
if (requestedDate != null) {
queryParams.put(JaxrsResource.QUERY_REQUESTED_DT, requestedDate.toDateTimeISO().toString());
}
+ if (autoPay) {
+ queryParams.put(JaxrsResource.QUERY_PAY_INVOICE, "true");
+ }
final InvoiceItemJson externalCharge = new InvoiceItemJson(null, invoiceId, null, accountId, bundleId, null, null, null,
null, null, null, null, amount, currency, null);
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java b/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
index 6b6721f..34a661e 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
@@ -35,6 +35,7 @@ import com.ning.billing.payment.provider.ExternalPaymentProviderPlugin;
import com.ning.billing.util.api.AuditLevel;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
public class TestInvoice extends TestJaxrsBase {
@@ -109,7 +110,7 @@ public class TestInvoice extends TestJaxrsBase {
final AccountJson accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
// Check there was no payment made
- assertEquals(getPaymentsForAccount(accountJson.getAccountId()).size(), 0);
+ assertEquals(getPaymentsForAccount(accountJson.getAccountId()).size(), 1);
// Get the invoices
final List<InvoiceJson> invoices = getInvoicesForAccount(accountJson.getAccountId());
@@ -122,7 +123,7 @@ public class TestInvoice extends TestJaxrsBase {
for (final InvoiceJson invoice : getInvoicesForAccount(accountJson.getAccountId())) {
assertEquals(invoice.getBalance().compareTo(BigDecimal.ZERO), 0);
}
- assertEquals(getPaymentsForAccount(accountJson.getAccountId()).size(), 1);
+ assertEquals(getPaymentsForAccount(accountJson.getAccountId()).size(), 2);
}
@Test(groups = "slow")
@@ -154,7 +155,8 @@ public class TestInvoice extends TestJaxrsBase {
// Verify we didn't get any payment
final List<PaymentJson> noPaymentsFromJson = getPaymentsForAccount(accountJson.getAccountId());
- assertEquals(noPaymentsFromJson.size(), 0);
+ assertEquals(noPaymentsFromJson.size(), 1);
+ final String initialPaymentId = noPaymentsFromJson.get(0).getPaymentId();
// Get the invoices
final List<InvoiceJson> invoices = getInvoicesForAccount(accountJson.getAccountId());
@@ -168,11 +170,20 @@ public class TestInvoice extends TestJaxrsBase {
// Verify we indeed got the payment
final List<PaymentJson> paymentsFromJson = getPaymentsForAccount(accountJson.getAccountId());
- assertEquals(paymentsFromJson.size(), 1);
- assertEquals(paymentsFromJson.get(0).getPaidAmount().compareTo(paidAmount), 0);
+ assertEquals(paymentsFromJson.size(), 2);
+ PaymentJson secondPayment = null;
+ for (PaymentJson cur : paymentsFromJson) {
+ if (! cur.getPaymentId().equals(initialPaymentId)) {
+ secondPayment = cur;
+ break;
+ }
+ }
+ assertNotNull(secondPayment);
+
+ assertEquals(secondPayment.getPaidAmount().compareTo(paidAmount), 0);
// Check the PaymentMethod from paymentMethodId returned in the Payment object
- final String paymentMethodId = paymentsFromJson.get(0).getPaymentMethodId();
+ final String paymentMethodId = secondPayment.getPaymentMethodId();
final PaymentMethodJson paymentMethodJson = getPaymentMethod(paymentMethodId);
assertEquals(paymentMethodJson.getPaymentMethodId(), paymentMethodId);
assertEquals(paymentMethodJson.getAccountId(), accountJson.getAccountId());
@@ -271,7 +282,7 @@ public class TestInvoice extends TestJaxrsBase {
// Post an external charge
final BigDecimal chargeAmount = BigDecimal.TEN;
- final InvoiceJson invoiceWithItems = createExternalCharge(accountJson.getAccountId(), chargeAmount, null, null, null);
+ final InvoiceJson invoiceWithItems = createExternalCharge(accountJson.getAccountId(), chargeAmount, null, null, null, false);
assertEquals(invoiceWithItems.getBalance().compareTo(chargeAmount), 0);
assertEquals(invoiceWithItems.getItems().size(), 1);
assertNull(invoiceWithItems.getItems().get(0).getBundleId());
@@ -280,6 +291,26 @@ public class TestInvoice extends TestJaxrsBase {
assertEquals(getInvoicesForAccount(accountJson.getAccountId()).size(), 3);
}
+
+ @Test(groups = "slow")
+ public void testExternalChargeOnNewInvoiceWithAutomaticPayment() throws Exception {
+ final AccountJson accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
+
+ // Get the invoices
+ assertEquals(getInvoicesForAccount(accountJson.getAccountId()).size(), 2);
+
+ // Post an external charge
+ final BigDecimal chargeAmount = BigDecimal.TEN;
+ final InvoiceJson invoiceWithItems = createExternalCharge(accountJson.getAccountId(), chargeAmount, null, null, null, true);
+ assertEquals(invoiceWithItems.getBalance().compareTo(BigDecimal.ZERO), 0);
+ assertEquals(invoiceWithItems.getItems().size(), 1);
+ assertNull(invoiceWithItems.getItems().get(0).getBundleId());
+
+ // Verify the total number of invoices
+ assertEquals(getInvoicesForAccount(accountJson.getAccountId()).size(), 3);
+
+ }
+
@Test(groups = "slow")
public void testExternalChargeForBundleOnNewInvoice() throws Exception {
final AccountJson accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
@@ -290,7 +321,7 @@ public class TestInvoice extends TestJaxrsBase {
// Post an external charge
final BigDecimal chargeAmount = BigDecimal.TEN;
final String bundleId = UUID.randomUUID().toString();
- final InvoiceJson invoiceWithItems = createExternalCharge(accountJson.getAccountId(), chargeAmount, bundleId, null, null);
+ final InvoiceJson invoiceWithItems = createExternalCharge(accountJson.getAccountId(), chargeAmount, bundleId, null, null, false);
assertEquals(invoiceWithItems.getBalance().compareTo(chargeAmount), 0);
assertEquals(invoiceWithItems.getItems().size(), 1);
assertEquals(invoiceWithItems.getItems().get(0).getBundleId(), bundleId);
@@ -314,7 +345,7 @@ public class TestInvoice extends TestJaxrsBase {
// Post an external charge
final BigDecimal chargeAmount = BigDecimal.TEN;
final InvoiceJson invoiceWithItems = createExternalChargeForInvoice(accountJson.getAccountId(), invoiceId,
- null, chargeAmount, null, null);
+ null, chargeAmount, null, null, false);
assertEquals(invoiceWithItems.getItems().size(), originalNumberOfItemsForInvoice + 1);
assertNull(invoiceWithItems.getItems().get(originalNumberOfItemsForInvoice).getBundleId());
@@ -325,6 +356,31 @@ public class TestInvoice extends TestJaxrsBase {
}
@Test(groups = "slow")
+ public void testExternalChargeOnExistingInvoiceWithAutomaticPayment() throws Exception {
+ final AccountJson accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
+
+ // Get the invoices
+ final List<InvoiceJson> invoices = getInvoicesWithItemsForAccount(accountJson.getAccountId());
+ // 2 invoices but look for the non zero dollar one
+ assertEquals(invoices.size(), 2);
+ final String invoiceId = invoices.get(1).getInvoiceId();
+ final BigDecimal originalInvoiceAmount = invoices.get(1).getAmount();
+ final int originalNumberOfItemsForInvoice = invoices.get(1).getItems().size();
+
+ // Post an external charge
+ final BigDecimal chargeAmount = BigDecimal.TEN;
+ final InvoiceJson invoiceWithItems = createExternalChargeForInvoice(accountJson.getAccountId(), invoiceId,
+ null, chargeAmount, null, null, true);
+ assertEquals(invoiceWithItems.getItems().size(), originalNumberOfItemsForInvoice + 1);
+ assertNull(invoiceWithItems.getItems().get(originalNumberOfItemsForInvoice).getBundleId());
+
+ // Verify the new invoice balance
+ final InvoiceJson adjustedInvoice = getInvoice(invoiceId);
+ assertEquals(adjustedInvoice.getBalance().compareTo(BigDecimal.ZERO), 0);
+ }
+
+
+ @Test(groups = "slow")
public void testExternalChargeForBundleOnExistingInvoice() throws Exception {
final AccountJson accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
@@ -340,7 +396,7 @@ public class TestInvoice extends TestJaxrsBase {
final BigDecimal chargeAmount = BigDecimal.TEN;
final String bundleId = UUID.randomUUID().toString();
final InvoiceJson invoiceWithItems = createExternalChargeForInvoice(accountJson.getAccountId(), invoiceId,
- bundleId, chargeAmount, null, null);
+ bundleId, chargeAmount, null, null, false);
assertEquals(invoiceWithItems.getItems().size(), originalNumberOfItemsForInvoice + 1);
assertEquals(invoiceWithItems.getItems().get(originalNumberOfItemsForInvoice).getBundleId(), bundleId);
util/src/main/resources/accountRecordIdSanity.sql 667(+667 -0)
diff --git a/util/src/main/resources/accountRecordIdSanity.sql b/util/src/main/resources/accountRecordIdSanity.sql
new file mode 100644
index 0000000..02f8029
--- /dev/null
+++ b/util/src/main/resources/accountRecordIdSanity.sql
@@ -0,0 +1,667 @@
+select
+ 'AUDIT_LOG' as table_name
+, sum(count) count
+from (
+ select
+ 'ACCOUNT_EMAIL_HISTORY' table_name
+ , count(1) count
+ from audit_log al
+ join account_email_history t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'ACCOUNT_EMAIL_HISTORY'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'ACCOUNT_HISTORY' table_name
+ , count(1) count
+ from audit_log al
+ join account_history t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'ACCOUNT_HISTORY'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'BLOCKING_STATES' table_name
+ , count(1) count
+ from audit_log al
+ join blocking_states t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'BLOCKING_STATES'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'BUNDLES' table_name
+ , count(1) count
+ from audit_log al
+ join bundles t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'BUNDLES'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'CUSTOM_FIELD_HISTORY' table_name
+ , count(1) count
+ from audit_log al
+ join custom_field_history t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'CUSTOM_FIELD_HISTORY'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'INVOICES' table_name
+ , count(1) count
+ from audit_log al
+ join invoices t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'INVOICES'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'INVOICE_ITEMS' table_name
+ , count(1) count
+ from audit_log al
+ join invoice_items t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'INVOICE_ITEMS'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'INVOICE_PAYMENTS' table_name
+ , count(1) count
+ from audit_log al
+ join invoice_payments t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'INVOICE_PAYMENTS'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'PAYMENTS' table_name
+ , count(1) count
+ from audit_log al
+ join payments t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'PAYMENTS'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'PAYMENT_ATTEMPTS' table_name
+ , count(1) count
+ from audit_log al
+ join payment_attempts t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'PAYMENT_ATTEMPTS'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'PAYMENT_ATTEMPT_HISTORY' table_name
+ , count(1) count
+ from audit_log al
+ join payment_attempt_history t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'PAYMENT_ATTEMPT_HISTORY'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'PAYMENT_HISTORY' table_name
+ , count(1) count
+ from audit_log al
+ join payment_history t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'PAYMENT_HISTORY'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'PAYMENT_METHODS' table_name
+ , count(1) count
+ from audit_log al
+ join payment_methods t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'PAYMENT_METHODS'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'PAYMENT_METHOD_HISTORY' table_name
+ , count(1) count
+ from audit_log al
+ join payment_method_history t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'PAYMENT_METHOD_HISTORY'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'REFUNDS' table_name
+ , count(1) count
+ from audit_log al
+ join refunds t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'REFUNDS'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'REFUND_HISTORY' table_name
+ , count(1) count
+ from audit_log al
+ join refund_history t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'REFUND_HISTORY'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'SUBSCRIPTIONS' table_name
+ , count(1) count
+ from audit_log al
+ join subscriptions t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'SUBSCRIPTIONS'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'SUBSCRIPTION_EVENTS' table_name
+ , count(1) count
+ from audit_log al
+ join subscription_events t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'SUBSCRIPTION_EVENTS'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+ union
+ select
+ 'TAG_HISTORY' table_name
+ , count(1) count
+ from audit_log al
+ join tag_history t on al.target_record_id = t.record_id
+ where 1 = 1
+ and al.table_name = 'TAG_HISTORY'
+ and (
+ al.account_record_id != t.account_record_id
+ or al.account_record_id is null
+ )
+) audit
+union
+select
+ 'ACCOUNT_EMAILS' as table_name
+, count(1) count
+from account_emails ae
+left outer join accounts a on ae.account_id = a.id
+where 1 = 1
+and (
+ ae.account_record_id != a.record_id
+ or ae.account_record_id is null
+)
+union
+select
+ 'ACCOUNT_EMAIL_HISTORY' as table_name
+, count(1) count
+from account_email_history aeh
+left outer join accounts a on aeh.account_id = a.id
+where 1 = 1
+and (
+ aeh.account_record_id != a.record_id
+ or aeh.account_record_id is null
+)
+union
+select
+ 'ACCOUNT_HISTORY' as table_name
+, count(1) count
+from account_history ah
+left outer join accounts a on ah.id = a.id
+where 1 = 1
+and (
+ ah.target_record_id != a.record_id
+ or ah.target_record_id is null
+)
+union
+select
+ 'BLOCKING_STATES' as table_name
+, count(1) count
+from blocking_states bs
+left outer join bundles b on bs.blockable_id = b.id and bs.type = 'SUBSCRIPTION_BUNDLE'
+left outer join accounts a on b.account_id = a.id
+where 1 = 1
+and (
+ bs.account_record_id != a.record_id
+ or bs.account_record_id is null
+)
+union
+select
+ 'BUNDLES' as table_name
+, count(1) count
+from bundles b
+left outer join accounts a on b.account_id = a.id
+where 1 = 1
+and (
+ b.account_record_id != a.record_id
+ or b.account_record_id is null
+)
+union
+select
+ 'BUS_EVENTS' as table_name
+, ifnull(sum(count), 0) count
+from (
+ select
+ class_name
+ , count(1) count
+ from (
+ select
+ substr(event_json, position('accountId' in event_json) + 12, 36) id
+ , search_key1 account_record_id
+ , class_name
+ from bus_events
+ where 1 = 1
+ and class_name in ('com.ning.billing.account.api.user.DefaultAccountChangeEvent', 'com.ning.billing.invoice.api.user.DefaultNullInvoiceEvent', 'com.ning.billing.payment.api.DefaultPaymentInfoEvent', 'com.ning.billing.invoice.api.user.DefaultInvoiceAdjustmentEvent', 'com.ning.billing.payment.api.DefaultPaymentErrorEvent')
+ union all
+ select
+ substr(event_json,position('objectId' in event_json) + 11, 36) id
+ , search_key1 account_record_id
+ , class_name
+ from bus_events
+ where 1 = 1
+ and class_name in ('com.ning.billing.util.tag.api.user.DefaultUserTagCreationEvent', 'com.ning.billing.util.tag.api.user.DefaultControlTagCreationEvent', 'com.ning.billing.util.tag.api.user.DefaultControlTagDeletionEvent', 'com.ning.billing.util.tag.api.user.DefaultUserTagDeletionEvent')
+ ) be
+ left outer join accounts a using (id)
+ where 1 = 1
+ and (
+ be.account_record_id is null
+ or be.account_record_id != a.record_id
+ )
+ group by class_name
+ union all
+ select
+ class_name
+ , count(1) count
+ from (
+ select
+ substr(event_json, position('subscriptionId' in event_json) + 17, 36) id
+ , search_key1 account_record_id
+ , class_name
+ from bus_events
+ where 1 = 1
+ and class_name in ('com.ning.billing.entitlement.api.user.DefaultRequestedSubscriptionEvent', 'com.ning.billing.entitlement.api.user.DefaultEffectiveSubscriptionEvent')
+ ) be
+ left outer join subscriptions s using (id)
+ where 1 = 1
+ and (
+ be.account_record_id is null
+ or be.account_record_id != s.account_record_id
+ )
+ group by class_name
+ union all
+ select
+ class_name
+ , count(1) count
+ from (
+ select
+ substr(event_json, position('invoiceId' in event_json) + 12, 36) id
+ , search_key1 account_record_id
+ , class_name
+ from bus_events
+ where 1 = 1
+ and class_name in ('com.ning.billing.invoice.api.user.DefaultInvoiceCreationEvent')
+ ) be
+ left outer join invoices i using (id)
+ where 1 = 1
+ and (
+ be.account_record_id is null
+ or be.account_record_id != i.account_record_id
+ )
+ group by class_name
+ union all
+ select
+ class_name
+ , count(1) count
+ from (
+ select
+ substr(event_json, position('overdueObjectId' in event_json) + 18, 36) id
+ , search_key1 account_record_id
+ , class_name
+ from bus_events
+ where 1 = 1
+ and class_name in ('com.ning.billing.overdue.applicator.DefaultOverdueChangeEvent')
+ ) be
+ left outer join bundles b using (id)
+ where 1 = 1
+ and (
+ be.account_record_id is null
+ or be.account_record_id != b.account_record_id
+ )
+ group by class_name
+) bus
+union
+select
+ 'CUSTOM_FIELD_HISTORY' as table_name
+, count(1) count
+from custom_field_history cfh
+left outer join accounts a on cfh.object_id = a.id and cfh.object_type = 'ACCOUNT'
+where 1 = 1
+and (
+ cfh.account_record_id != a.record_id
+ or cfh.account_record_id is null
+)
+union
+select
+ 'CUSTOM_FIELDS' as table_name
+, count(1) count
+from custom_fields cf
+left outer join accounts a on cf.object_id = a.id and cf.object_type = 'ACCOUNT'
+where 1 = 1
+and (
+ cf.account_record_id != a.record_id
+ or cf.account_record_id is null
+)
+union
+select
+ 'INVOICE_ITEMS' as table_name
+, count(1) count
+from invoice_items it
+left outer join invoices i on it.invoice_id = i.id
+left outer join accounts a on i.account_id = a.id
+where 1 = 1
+and (
+ it.account_record_id != a.record_id
+ or it.account_record_id is null
+)
+union
+select
+ 'INVOICE_PAYMENTS' as table_name
+, count(1) count
+from invoice_payments ip
+left outer join invoices i on ip.invoice_id = i.id
+left outer join accounts a on i.account_id = a.id
+where 1 = 1
+and (
+ ip.account_record_id != a.record_id
+ or ip.account_record_id is null
+)
+union
+select
+ 'INVOICES' as table_name
+, count(1) count
+from invoices i
+left outer join accounts a on i.account_id = a.id
+where 1 = 1
+and (
+ i.account_record_id != a.record_id
+ or i.account_record_id is null
+)
+union
+select
+ 'NOTIFICATIONS' as table_name
+, ifnull(sum(count), 0) count
+from (
+ select
+ class_name
+ , count(1) count
+ from (
+ select
+ substr(event_json, 13, 36) id
+ , search_key1 account_record_id
+ , class_name
+ from notifications
+ where 1 = 1
+ and class_name = 'com.ning.billing.invoice.notification.NextBillingDateNotificationKey'
+ ) n
+ left outer join subscriptions s using (id)
+ where 1 = 1
+ and (
+ n.account_record_id is null
+ or n.account_record_id != s.account_record_id
+ )
+ group by class_name
+ union all
+ select
+ class_name
+ , count(1) count
+ from (
+ select
+ substr(event_json, 13, 36) id
+ , search_key1 account_record_id
+ , class_name
+ from notifications
+ where 1 = 1
+ and class_name in ('com.ning.billing.ovedue.notification.OverdueCheckNotificationKey', 'com.ning.billing.irs.callbacks.CallbackNotificationKey')
+ ) n
+ left outer join bundles b using (id)
+ where 1 = 1
+ and (
+ n.account_record_id is null
+ or n.account_record_id != b.account_record_id
+ )
+ group by class_name
+ union all
+ select
+ class_name
+ , count(1) count
+ from (
+ select
+ substr(event_json, 13, 36) id
+ , search_key1 account_record_id
+ , class_name
+ from notifications
+ where 1 = 1
+ and class_name = 'com.ning.billing.payment.retry.PaymentRetryNotificationKey'
+ ) n
+ left outer join payments p using (id)
+ where 1 = 1
+ and (
+ n.account_record_id is null
+ or n.account_record_id != p.account_record_id
+ )
+ group by class_name
+ union all
+ select
+ class_name
+ , count(1) count
+ from (
+ select
+ substr(event_json, 13, 36) id
+ , search_key1 account_record_id
+ , class_name
+ from notifications
+ where 1 = 1
+ and class_name = 'com.ning.billing.entitlement.engine.core.EntitlementNotificationKey'
+ ) n
+ left outer join subscription_events se using (id)
+ where 1 = 1
+ and (
+ n.account_record_id is null
+ or n.account_record_id != se.account_record_id
+ )
+ group by class_name
+) notifications
+union
+select
+ 'PAYMENT_ATTEMPTS' as table_name
+, count(1) count
+from payment_attempts pa
+left outer join payments p on pa.payment_id = p.id
+left outer join accounts a on p.account_id = a.id
+where 1 = 1
+and (
+ pa.account_record_id != a.record_id
+ or pa.account_record_id is null
+)
+union
+select
+ 'PAYMENT_ATTEMPT_HISTORY' as table_name
+, count(1) from payment_attempt_history pah
+left outer join payment_attempts pa on pah.target_record_id = pa.record_id
+left outer join payments p on pa.payment_id = p.id
+left outer join accounts a on p.account_id = a.id
+where 1 = 1
+and (
+ pah.account_record_id != a.record_id
+ or pah.account_record_id is null
+)
+union
+select
+ 'PAYMENT_METHODS' as table_name
+, sum(count) count
+from (
+ select
+ count(1) count
+ from payment_methods pm
+ left outer join accounts a on pm.account_id = a.id
+ where 1 = 1
+ and (
+ pm.account_record_id != a.record_id
+ or pm.account_record_id is null
+ )
+ and pm.is_active = 0
+ union all
+ select
+ count(1) count
+ from payment_methods pm
+ left outer join accounts a on pm.account_id = a.id
+ where 1 = 1
+ and (
+ pm.account_record_id != a.record_id
+ or pm.account_record_id is null
+ )
+ and pm.is_active = 1
+) pms
+union
+select
+ 'PAYMENTS' as table_name
+, count(1) count
+from payments p
+left outer join accounts a on p.account_id = a.id
+where 1 = 1
+and (
+ p.account_record_id != a.record_id
+ or p.account_record_id is null
+)
+union
+select
+ 'PAYMENT_HISTORY' as table_name
+, count(1) count
+from payment_history ph
+left outer join payments p on ph.target_record_id = p.record_id
+where 1 = 1
+and (
+ ph.account_record_id != p.account_record_id
+ or ph.account_record_id is null
+)
+union
+select
+ 'REFUND_HISTORY' as table_name
+, count(1) count
+from refund_history rh
+left outer join refunds r on rh.target_record_id = r.record_id
+left outer join accounts a on r.account_id = a.id
+where 1 = 1
+and (
+ rh.account_record_id != a.record_id
+ or rh.account_record_id is null
+)
+union
+select
+ 'REFUNDS' as table_name
+, count(1) count
+from refunds r
+left outer join accounts a on r.account_id = a.id
+where 1 = 1
+and (
+ r.account_record_id != a.record_id
+ or r.account_record_id is null
+)
+union
+select
+ 'SUBSCRIPTIONS' as table_name
+, count(1) count
+from subscriptions s
+left outer join bundles b on s.bundle_id = b.id
+left outer join accounts a on b.account_id = a.id
+where 1 = 1
+and (
+ s.account_record_id != a.record_id
+ or s.account_record_id is null
+)
+union
+select
+ 'SUBSCRIPTION_EVENTS' as table_name
+, count(1) count
+from subscription_events e
+left outer join subscriptions s on e.subscription_id = s.id
+left outer join bundles b on s.bundle_id = b.id
+left outer join accounts a on b.account_id = a.id
+where 1 = 1
+and (
+ e.account_record_id != a.record_id
+ or e.account_record_id is null
+)
+union
+select
+ 'TAG_HISTORY' as table_name
+, count(1) count
+from tag_history th
+left outer join accounts a on th.object_id = a.id and th.object_type = 'ACCOUNT'
+where 1 = 1
+and (
+ th.account_record_id != a.record_id
+ or th.account_record_id is null
+)
+union
+select
+ 'TAGS' as table_name
+, count(1) count
+from tags t
+left outer join accounts a on t.object_id = a.id and t.object_type = 'ACCOUNT'
+where 1 = 1
+and (
+ t.account_record_id != a.record_id
+ or t.account_record_id is null
+)
+;
\ No newline at end of file