killbill-memoizeit
Changes
beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java 267(+266 -1)
invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceAdjustmentEvent.java 105(+105 -0)
Details
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoiceAdjustmentEvent.java b/api/src/main/java/com/ning/billing/invoice/api/InvoiceAdjustmentEvent.java
new file mode 100644
index 0000000..c59105c
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoiceAdjustmentEvent.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2010-2012 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.invoice.api;
+
+import java.util.UUID;
+
+public interface InvoiceAdjustmentEvent extends InvoiceEvent {
+
+ public UUID getInvoiceId();
+}
diff --git a/api/src/main/java/com/ning/billing/util/bus/BusEvent.java b/api/src/main/java/com/ning/billing/util/bus/BusEvent.java
index 919924e..c1636e0 100644
--- a/api/src/main/java/com/ning/billing/util/bus/BusEvent.java
+++ b/api/src/main/java/com/ning/billing/util/bus/BusEvent.java
@@ -26,6 +26,7 @@ public interface BusEvent {
BUNDLE_REPAIR,
INVOICE_EMPTY,
INVOICE_CREATION,
+ INVOICE_ADJUSTMENT,
PAYMENT_INFO,
PAYMENT_ERROR,
CONTROL_TAG_CREATION,
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
index 41afabf..380b287 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
@@ -37,6 +37,7 @@ import com.ning.billing.beatrix.integration.BeatrixModule;
import com.ning.billing.beatrix.integration.TestIntegrationBase;
import com.ning.billing.beatrix.util.InvoiceChecker.ExpectedItemCheck;
import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.Currency;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
@@ -44,12 +45,15 @@ import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceItemType;
+import com.ning.billing.invoice.api.InvoicePayment;
import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.junction.api.Blockable;
import com.ning.billing.junction.api.BlockingApi;
import com.ning.billing.junction.api.BlockingApiException;
import com.ning.billing.overdue.OverdueUserApi;
import com.ning.billing.overdue.config.OverdueConfig;
import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
+import com.ning.billing.payment.api.Payment;
import com.ning.billing.payment.api.PaymentApi;
import com.ning.billing.payment.api.PaymentMethodPlugin;
import com.ning.billing.payment.provider.MockPaymentProviderPlugin;
@@ -189,9 +193,9 @@ public class TestOverdueIntegration extends TestIntegrationBase {
@Test(groups = "slow")
public void testBasicOverdueState() throws Exception {
clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
- paymentPlugin.makeAllInvoicesFailWithError(true);
// Set next invoice to fail and create subscription
+ paymentPlugin.makeAllInvoicesFailWithError(true);
final Subscription baseSubscription = createSubscriptionAndCheckForCompletion(bundle.getId(), productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.INVOICE);
invoiceChecker.checkInvoice(account.getId(), 1, new ExpectedItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
@@ -371,6 +375,267 @@ public class TestOverdueIntegration extends TestIntegrationBase {
assertEquals(invoiceUserApi.getAccountBalance(account.getId()).compareTo(new BigDecimal("-8.88")), 0);
}
+ @Test(groups = "slow")
+ public void testShouldBeInOverdueAfterExternalCharge() throws Exception {
+ clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
+
+ // Create a subscription without failing payments
+ final Subscription baseSubscription = createSubscriptionAndCheckForCompletion(bundle.getId(), productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.INVOICE);
+
+ invoiceChecker.checkInvoice(account.getId(), 1, new ExpectedItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 5, 1));
+
+ // Create an external charge on a new invoice
+ addDaysAndCheckForCompletion(5);
+ busHandler.pushExpectedEvents(NextEvent.INVOICE_ADJUSTMENT);
+ invoiceApi.insertExternalChargeForBundle(account.getId(), bundle.getId(), BigDecimal.TEN, "For overdue", new LocalDate(2012, 5, 6), Currency.USD, context);
+ assertTrue(busHandler.isCompleted(DELAY));
+ assertListenerStatus();
+ invoiceChecker.checkInvoice(account.getId(), 2, new ExpectedItemCheck(new LocalDate(2012, 5, 6), null, InvoiceItemType.EXTERNAL_CHARGE, BigDecimal.TEN));
+
+ // DAY 30 have to get out of trial before first payment
+ addDaysAndCheckForCompletion(25, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT);
+
+ invoiceChecker.checkInvoice(account.getId(), 3, new ExpectedItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 6, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 6, 30));
+
+ // Should still be in clear state - the invoice for the bundle has been paid, but not the invoice with the external charge
+ // We refresh overdue just to be safe, see below
+ overdueApi.refreshOverdueStateFor(bundle);
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ // Past 30 days since the external charge
+ addDaysAndCheckForCompletion(6);
+ // Note! We need to explicitly refresh here because overdue won't get notified to refresh up until the next
+ // payment (when the next invoice is generated)
+ // TODO - we should fix this
+ overdueApi.refreshOverdueStateFor(bundle);
+ // We should now be in OD1
+ checkODState("OD1");
+
+ // Pay the invoice
+ final Invoice externalChargeInvoice = invoiceApi.getUnpaidInvoicesByAccountId(account.getId(), clock.getUTCToday()).iterator().next();
+ createExternalPaymentAndCheckForCompletion(account, externalChargeInvoice, NextEvent.PAYMENT);
+ // We should be clear now
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+ }
+
+ @Test(groups = "slow")
+ public void testShouldBeInOverdueAfterRefundWithoutAdjustment() throws Exception {
+ clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
+
+ // Create subscription and don't fail payments
+ final Subscription baseSubscription = createSubscriptionAndCheckForCompletion(bundle.getId(), productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.INVOICE);
+
+ invoiceChecker.checkInvoice(account.getId(), 1, new ExpectedItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 5, 1));
+
+ // DAY 30 have to get out of trial before first payment
+ addDaysAndCheckForCompletion(30, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT);
+
+ invoiceChecker.checkInvoice(account.getId(), 2, new ExpectedItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 6, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 6, 30));
+
+ // Should still be in clear state
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ // DAY 45 - 15 days after invoice
+ addDaysAndCheckForCompletion(15);
+
+ // Should still be in clear state
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ // DAY 65 - 35 days after invoice
+ addDaysAndCheckForCompletion(20, NextEvent.INVOICE, NextEvent.PAYMENT);
+
+ invoiceChecker.checkInvoice(account.getId(), 3, new ExpectedItemCheck(new LocalDate(2012, 6, 30), new LocalDate(2012, 7, 31), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 7, 31));
+
+ // Should still be in clear state
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ // Now, refund the second (first non-zero dollar) invoice
+ final Payment payment = paymentApi.getPayment(invoiceApi.getInvoicesByAccount(account.getId()).get(1).getPayments().get(0).getPaymentId());
+ refundPaymentAndCheckForCompletion(account, payment, NextEvent.INVOICE_ADJUSTMENT);
+ // We should now be in OD1
+ checkODState("OD1");
+ checkChangePlanWithOverdueState(baseSubscription, true);
+ }
+
+ @Test(groups = "slow")
+ public void testShouldBeInOverdueAfterChargeback() throws Exception {
+ clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
+
+ // Create subscription and don't fail payments
+ final Subscription baseSubscription = createSubscriptionAndCheckForCompletion(bundle.getId(), productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.INVOICE);
+
+ invoiceChecker.checkInvoice(account.getId(), 1, new ExpectedItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 5, 1));
+
+ // DAY 30 have to get out of trial before first payment
+ addDaysAndCheckForCompletion(30, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT);
+
+ invoiceChecker.checkInvoice(account.getId(), 2, new ExpectedItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 6, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 6, 30));
+
+ // Should still be in clear state
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ // DAY 45 - 15 days after invoice
+ addDaysAndCheckForCompletion(15);
+
+ // Should still be in clear state
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ // DAY 65 - 35 days after invoice
+ addDaysAndCheckForCompletion(20, NextEvent.INVOICE, NextEvent.PAYMENT);
+
+ invoiceChecker.checkInvoice(account.getId(), 3, new ExpectedItemCheck(new LocalDate(2012, 6, 30), new LocalDate(2012, 7, 31), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 7, 31));
+
+ // Should still be in clear state
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ // Now, create a chargeback for the second (first non-zero dollar) invoice
+ final InvoicePayment payment = invoicePaymentApi.getInvoicePayments(invoiceApi.getInvoicesByAccount(account.getId()).get(1).getPayments().get(0).getPaymentId()).get(0);
+ createChargeBackAndCheckForCompletion(payment, NextEvent.INVOICE_ADJUSTMENT);
+ // We should now be in OD1
+ checkODState("OD1");
+ checkChangePlanWithOverdueState(baseSubscription, true);
+ }
+
+ @Test(groups = "slow")
+ public void testOverdueStateShouldClearAfterExternalPayment() throws Exception {
+ clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
+
+ // Set next invoice to fail and create subscription
+ paymentPlugin.makeAllInvoicesFailWithError(true);
+ final Subscription baseSubscription = createSubscriptionAndCheckForCompletion(bundle.getId(), productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.INVOICE);
+
+ invoiceChecker.checkInvoice(account.getId(), 1, new ExpectedItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 5, 1));
+
+ // DAY 30 have to get out of trial before first payment
+ addDaysAndCheckForCompletion(30, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR);
+
+ invoiceChecker.checkInvoice(account.getId(), 2, new ExpectedItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 6, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 6, 30));
+
+ // Should still be in clear state
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ // DAY 45 - 15 days after invoice
+ addDaysAndCheckForCompletion(15, NextEvent.PAYMENT_ERROR);
+
+ // Should still be in clear state
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ // DAY 65 - 35 days after invoice
+ addDaysAndCheckForCompletion(20, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR, NextEvent.PAYMENT_ERROR);
+
+ invoiceChecker.checkInvoice(account.getId(), 3, new ExpectedItemCheck(new LocalDate(2012, 6, 30), new LocalDate(2012, 7, 31), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 7, 31));
+
+ // Now we should be in OD1
+ checkODState("OD1");
+ checkChangePlanWithOverdueState(baseSubscription, true);
+
+ // We have two unpaid non-zero dollar invoices at this point
+ // Pay the first one via an external payment - we should then be 5 days apart from the second invoice
+ // (which is the earliest unpaid one) and hence come back to a clear state (see configuration)
+ final Invoice firstNonZeroInvoice = invoiceApi.getUnpaidInvoicesByAccountId(account.getId(), clock.getUTCToday()).iterator().next();
+ createExternalPaymentAndCheckForCompletion(account, firstNonZeroInvoice, NextEvent.PAYMENT);
+ // We should be clear now
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+ }
+
+ @Test(groups = "slow", enabled = false)
+ public void testOverdueStateAndWRITTEN_OFFTag() throws Exception {
+ // TODO add/remove tag to invoice
+ }
+
+ @Test(groups = "slow")
+ public void testOverdueStateShouldClearAfterCreditOrInvoiceItemAdjustment() throws Exception {
+ clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
+
+ // Set next invoice to fail and create subscription
+ paymentPlugin.makeAllInvoicesFailWithError(true);
+ final Subscription baseSubscription = createSubscriptionAndCheckForCompletion(bundle.getId(), productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.INVOICE);
+
+ invoiceChecker.checkInvoice(account.getId(), 1, new ExpectedItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 5, 1));
+
+ // DAY 30 have to get out of trial before first payment
+ addDaysAndCheckForCompletion(30, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR);
+
+ invoiceChecker.checkInvoice(account.getId(), 2, new ExpectedItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 6, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 6, 30));
+
+ // Should still be in clear state
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ // DAY 45 - 15 days after invoice
+ addDaysAndCheckForCompletion(15, NextEvent.PAYMENT_ERROR);
+
+ // Should still be in clear state
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ // DAY 65 - 35 days after invoice
+ addDaysAndCheckForCompletion(20, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR, NextEvent.PAYMENT_ERROR);
+
+ invoiceChecker.checkInvoice(account.getId(), 3, new ExpectedItemCheck(new LocalDate(2012, 6, 30), new LocalDate(2012, 7, 31), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 7, 31));
+
+ // Now we should be in OD1
+ checkODState("OD1");
+ checkChangePlanWithOverdueState(baseSubscription, true);
+
+ // We have two unpaid non-zero dollar invoices at this point
+ // Adjust the first (and only) item of the first invoice - we should then be 5 days apart from the second invoice
+ // (which is the earliest unpaid one) and hence come back to a clear state (see configuration)
+ final Invoice firstNonZeroInvoice = invoiceApi.getUnpaidInvoicesByAccountId(account.getId(), clock.getUTCToday()).iterator().next();
+ fullyAdjustInvoiceItemAndCheckForCompletion(account, firstNonZeroInvoice, 1, NextEvent.INVOICE_ADJUSTMENT);
+ // We should be clear now
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ invoiceChecker.checkRepairedInvoice(account.getId(), 2,
+ new ExpectedItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 6, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")),
+ new ExpectedItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 5, 31), InvoiceItemType.ITEM_ADJ, new BigDecimal("-249.95")));
+ invoiceChecker.checkChargedThroughDate(baseSubscription.getId(), new LocalDate(2012, 7, 31));
+
+ // DAY 70 - 10 days after second invoice
+ addDaysAndCheckForCompletion(5);
+
+ // We should still be clear
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ // DAY 80 - 20 days after second invoice
+ addDaysAndCheckForCompletion(10, NextEvent.PAYMENT_ERROR);
+
+ // We should still be clear
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ // DAY 95 - 35 days after second invoice
+ addDaysAndCheckForCompletion(15, NextEvent.PAYMENT_ERROR, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR);
+
+ // We should now be in OD1
+ checkODState("OD1");
+ checkChangePlanWithOverdueState(baseSubscription, true);
+
+ invoiceChecker.checkInvoice(account.getId(), 4, new ExpectedItemCheck(new LocalDate(2012, 7, 31), new LocalDate(2012, 8, 31), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+
+ // Fully adjust all invoices
+ final Collection<Invoice> invoices = invoiceApi.getUnpaidInvoicesByAccountId(account.getId(), clock.getUTCToday());
+ for (final Invoice invoice : invoices) {
+ if (invoice.getBalance().compareTo(BigDecimal.ZERO) > 0) {
+ fullyAdjustInvoiceAndCheckForCompletion(account, invoice, NextEvent.INVOICE_ADJUSTMENT);
+ }
+ }
+
+ // We should be cleared again
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+ }
+
private void checkChangePlanWithOverdueState(final Subscription subscription, final boolean shouldFail) {
if (shouldFail) {
try {
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
index 150a971..e9c42b0 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
@@ -62,7 +62,10 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionData;
import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceApiException;
import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoicePayment;
+import com.ning.billing.invoice.api.InvoicePaymentApi;
import com.ning.billing.invoice.api.InvoiceService;
import com.ning.billing.invoice.api.InvoiceUserApi;
import com.ning.billing.invoice.model.InvoicingConfiguration;
@@ -70,6 +73,7 @@ import com.ning.billing.junction.plumbing.api.BlockingSubscription;
import com.ning.billing.mock.MockAccountBuilder;
import com.ning.billing.mock.api.MockBillCycleDay;
import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
+import com.ning.billing.payment.api.Payment;
import com.ning.billing.payment.api.PaymentApi;
import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentMethodPlugin;
@@ -149,6 +153,9 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
protected InvoiceUserApi invoiceUserApi;
@Inject
+ protected InvoicePaymentApi invoicePaymentApi;
+
+ @Inject
protected PaymentApi paymentApi;
@Named(BeatrixModule.PLUGIN_NAME)
@@ -371,6 +378,48 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
}, events);
}
+ protected void createExternalPaymentAndCheckForCompletion(final Account account, final Invoice invoice, final NextEvent... events) {
+ doCallAndCheckForCompletion(new Function<Void, Void>() {
+ @Override
+ public Void apply(@Nullable final Void input) {
+ try {
+ paymentApi.createExternalPayment(account, invoice.getId(), invoice.getBalance(), new DefaultCallContext("test", null, null, clock));
+ } catch (PaymentApiException e) {
+ fail(e.toString());
+ }
+ return null;
+ }
+ }, events);
+ }
+
+ protected void refundPaymentAndCheckForCompletion(final Account account, final Payment payment, final NextEvent... events) {
+ doCallAndCheckForCompletion(new Function<Void, Void>() {
+ @Override
+ public Void apply(@Nullable final Void input) {
+ try {
+ paymentApi.createRefund(account, payment.getId(), payment.getPaidAmount(), new DefaultCallContext("test", null, null, clock));
+ } catch (PaymentApiException e) {
+ fail(e.toString());
+ }
+ return null;
+ }
+ }, events);
+ }
+
+ protected void createChargeBackAndCheckForCompletion(final InvoicePayment payment, final NextEvent... events) {
+ doCallAndCheckForCompletion(new Function<Void, Void>() {
+ @Override
+ public Void apply(@Nullable final Void input) {
+ try {
+ invoicePaymentApi.createChargeback(payment.getId(), payment.getAmount(), new DefaultCallContext("test", null, null, clock));
+ } catch (InvoiceApiException e) {
+ fail(e.toString());
+ }
+ return null;
+ }
+ }, events);
+ }
+
protected Subscription createSubscriptionAndCheckForCompletion(final UUID bundleId,
final String productName,
final ProductCategory productCategory,
@@ -433,6 +482,36 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
}, events);
}
+ protected void fullyAdjustInvoiceAndCheckForCompletion(final Account account, final Invoice invoice, final NextEvent... events) {
+ doCallAndCheckForCompletion(new Function<Void, Void>() {
+ @Override
+ public Void apply(@Nullable final Void input) {
+ try {
+ invoiceUserApi.insertCreditForInvoice(account.getId(), invoice.getId(), invoice.getBalance(), invoice.getInvoiceDate(),
+ account.getCurrency(), new DefaultCallContext("test", null, null, clock));
+ } catch (InvoiceApiException e) {
+ fail(e.toString());
+ }
+ return null;
+ }
+ }, events);
+ }
+
+ protected void fullyAdjustInvoiceItemAndCheckForCompletion(final Account account, final Invoice invoice, final int itemNb, final NextEvent... events) {
+ doCallAndCheckForCompletion(new Function<Void, Void>() {
+ @Override
+ public Void apply(@Nullable final Void input) {
+ try {
+ invoiceUserApi.insertInvoiceItemAdjustment(account.getId(), invoice.getId(), invoice.getInvoiceItems().get(itemNb - 1).getId(),
+ invoice.getInvoiceDate(), new DefaultCallContext("test", null, null, clock));
+ } catch (InvoiceApiException e) {
+ fail(e.toString());
+ }
+ return null;
+ }
+ }, events);
+ }
+
private <T> T doCallAndCheckForCompletion(Function<Void, T> f, final NextEvent... events) {
Joiner joiner = Joiner.on(", ");
diff --git a/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceAdjustmentEvent.java b/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceAdjustmentEvent.java
new file mode 100644
index 0000000..d4e6170
--- /dev/null
+++ b/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceAdjustmentEvent.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2010-2012 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.invoice.api.user;
+
+import java.util.UUID;
+
+import com.ning.billing.invoice.api.InvoiceAdjustmentEvent;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class DefaultInvoiceAdjustmentEvent implements InvoiceAdjustmentEvent {
+
+ private final UUID invoiceId;
+ private final UUID accountId;
+ private final UUID userToken;
+
+ @JsonCreator
+ public DefaultInvoiceAdjustmentEvent(@JsonProperty("invoiceId") final UUID invoiceId,
+ @JsonProperty("accountId") final UUID accountId,
+ @JsonProperty("userToken") final UUID userToken) {
+ this.invoiceId = invoiceId;
+ this.accountId = accountId;
+ this.userToken = userToken;
+ }
+
+ @Override
+ public UUID getInvoiceId() {
+ return invoiceId;
+ }
+
+ @Override
+ public UUID getAccountId() {
+ return accountId;
+ }
+
+ @JsonIgnore
+ @Override
+ public BusEventType getBusEventType() {
+ return BusEventType.INVOICE_ADJUSTMENT;
+ }
+
+ @Override
+ public UUID getUserToken() {
+ return userToken;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("DefaultInvoiceAdjustmentEvent");
+ sb.append("{invoiceId=").append(invoiceId);
+ sb.append(", accountId=").append(accountId);
+ sb.append(", userToken=").append(userToken);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final DefaultInvoiceAdjustmentEvent that = (DefaultInvoiceAdjustmentEvent) o;
+
+ if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) {
+ return false;
+ }
+ if (invoiceId != null ? !invoiceId.equals(that.invoiceId) : that.invoiceId != null) {
+ return false;
+ }
+ if (userToken != null ? !userToken.equals(that.userToken) : that.userToken != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = invoiceId != null ? invoiceId.hashCode() : 0;
+ result = 31 * result + (accountId != null ? accountId.hashCode() : 0);
+ result = 31 * result + (userToken != null ? userToken.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/AuditedInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/AuditedInvoiceDao.java
index 1abfe3d..ba3ec0c 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/AuditedInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/AuditedInvoiceDao.java
@@ -30,6 +30,9 @@ import org.joda.time.LocalDate;
import org.skife.jdbi.v2.IDBI;
import org.skife.jdbi.v2.Transaction;
import org.skife.jdbi.v2.TransactionStatus;
+import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.ning.billing.ErrorCode;
import com.ning.billing.catalog.api.Currency;
@@ -39,6 +42,7 @@ 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.invoice.api.InvoicePayment.InvoicePaymentType;
+import com.ning.billing.invoice.api.user.DefaultInvoiceAdjustmentEvent;
import com.ning.billing.invoice.generator.InvoiceDateUtils;
import com.ning.billing.invoice.model.CreditAdjInvoiceItem;
import com.ning.billing.invoice.model.CreditBalanceAdjInvoiceItem;
@@ -52,6 +56,8 @@ import com.ning.billing.invoice.notification.NextBillingDatePoster;
import com.ning.billing.util.ChangeType;
import com.ning.billing.util.api.TagApiException;
import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.bus.Bus;
+import com.ning.billing.util.bus.Bus.EventBusException;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.dao.EntityAudit;
@@ -68,24 +74,29 @@ import com.google.inject.Inject;
public class AuditedInvoiceDao implements InvoiceDao {
+ private static final Logger log = LoggerFactory.getLogger(AuditedInvoiceDao.class);
+
private final InvoiceSqlDao invoiceSqlDao;
private final InvoicePaymentSqlDao invoicePaymentSqlDao;
private final TagUserApi tagUserApi;
private final NextBillingDatePoster nextBillingDatePoster;
private final InvoiceItemSqlDao invoiceItemSqlDao;
private final Clock clock;
+ private final Bus eventBus;
@Inject
public AuditedInvoiceDao(final IDBI dbi,
final NextBillingDatePoster nextBillingDatePoster,
final TagUserApi tagUserApi,
- final Clock clock) {
+ final Clock clock,
+ final Bus eventBus) {
this.invoiceSqlDao = dbi.onDemand(InvoiceSqlDao.class);
this.invoicePaymentSqlDao = dbi.onDemand(InvoicePaymentSqlDao.class);
this.invoiceItemSqlDao = dbi.onDemand(InvoiceItemSqlDao.class);
this.nextBillingDatePoster = nextBillingDatePoster;
this.tagUserApi = tagUserApi;
this.clock = clock;
+ this.eventBus = eventBus;
}
@Override
@@ -301,12 +312,32 @@ public class AuditedInvoiceDao implements InvoiceDao {
@Override
public void setWrittenOff(final UUID invoiceId, final CallContext context) throws TagApiException {
- tagUserApi.addTag(invoiceId, ObjectType.INVOICE, ControlTagType.WRITTEN_OFF.getId(), context);
+ invoiceSqlDao.inTransaction(new Transaction<Void, InvoiceSqlDao>() {
+ @Override
+ public Void inTransaction(final InvoiceSqlDao transactional, final TransactionStatus status) throws Exception {
+ tagUserApi.addTag(invoiceId, ObjectType.INVOICE, ControlTagType.WRITTEN_OFF.getId(), context);
+
+ final Invoice invoice = transactional.getById(invoiceId.toString());
+ notifyBusOfInvoiceAdjustment(transactional, invoiceId, invoice.getAccountId(), context.getUserToken());
+
+ return null;
+ }
+ });
}
@Override
public void removeWrittenOff(final UUID invoiceId, final CallContext context) throws TagApiException {
- tagUserApi.removeTag(invoiceId, ObjectType.INVOICE, ControlTagType.WRITTEN_OFF.getId(), context);
+ invoiceSqlDao.inTransaction(new Transaction<Void, InvoiceSqlDao>() {
+ @Override
+ public Void inTransaction(final InvoiceSqlDao transactional, final TransactionStatus status) throws Exception {
+ tagUserApi.removeTag(invoiceId, ObjectType.INVOICE, ControlTagType.WRITTEN_OFF.getId(), context);
+
+ final Invoice invoice = transactional.getById(invoiceId.toString());
+ notifyBusOfInvoiceAdjustment(transactional, invoiceId, invoice.getAccountId(), context.getUserToken());
+
+ return null;
+ }
+ });
}
@Override
@@ -387,6 +418,9 @@ public class AuditedInvoiceDao implements InvoiceDao {
}
}
+ // Notify the bus since the balance of the invoice changed
+ notifyBusOfInvoiceAdjustment(transactional, invoice.getId(), invoice.getAccountId(), context.getUserToken());
+
return refund;
}
});
@@ -483,12 +517,16 @@ public class AuditedInvoiceDao implements InvoiceDao {
} else {
final InvoicePayment chargeBack = new DefaultInvoicePayment(UUID.randomUUID(), InvoicePaymentType.CHARGED_BACK, payment.getPaymentId(),
payment.getInvoiceId(), context.getCreatedDate(), requestedChargedBackAmout.negate(), payment.getCurrency(), null, payment.getId());
- invoicePaymentSqlDao.create(chargeBack, context);
+ transactional.create(chargeBack, context);
// Add audit
- final Long recordId = invoicePaymentSqlDao.getRecordId(chargeBack.getId().toString());
+ final Long recordId = transactional.getRecordId(chargeBack.getId().toString());
final EntityAudit audit = new EntityAudit(TableName.INVOICE_PAYMENTS, recordId, ChangeType.INSERT);
- invoicePaymentSqlDao.insertAuditFromTransaction(audit, context);
+ transactional.insertAuditFromTransaction(audit, context);
+
+ // Notify the bus since the balance of the invoice changed
+ final UUID accountId = transactional.getAccountIdFromInvoicePaymentId(chargeBack.getId().toString());
+ notifyBusOfInvoiceAdjustment(transactional, payment.getInvoiceId(), accountId, context.getUserToken());
return chargeBack;
}
@@ -557,6 +595,9 @@ public class AuditedInvoiceDao implements InvoiceDao {
final InvoiceItemSqlDao transInvoiceItemDao = transactional.become(InvoiceItemSqlDao.class);
transInvoiceItemDao.create(externalCharge, context);
+ // Notify the bus since the balance of the invoice changed
+ notifyBusOfInvoiceAdjustment(transactional, invoiceId, accountId, context.getUserToken());
+
return externalCharge;
}
});
@@ -589,6 +630,9 @@ public class AuditedInvoiceDao implements InvoiceDao {
final EntityAudit audit = new EntityAudit(TableName.INVOICE_ITEMS, recordId, ChangeType.INSERT);
transactional.insertAuditFromTransaction(audit, context);
+ // Notify the bus since the balance of the invoice changed
+ notifyBusOfInvoiceAdjustment(transactional, invoiceId, accountId, context.getUserToken());
+
return credit;
}
});
@@ -604,6 +648,9 @@ public class AuditedInvoiceDao implements InvoiceDao {
final InvoiceItem invoiceItemAdjustment = createAdjustmentItem(transactional, invoiceId, invoiceItemId, positiveAdjAmount,
currency, effectiveDate);
insertItemAndAddCBAIfNeeded(transactional, invoiceItemAdjustment, context);
+
+ notifyBusOfInvoiceAdjustment(transactional, invoiceId, accountId, context.getUserToken());
+
return invoiceItemAdjustment;
}
});
@@ -773,4 +820,12 @@ public class AuditedInvoiceDao implements InvoiceDao {
nextBillingDatePoster.insertNextBillingNotification(dao, accountId, subscriptionForNextNotification, nextNotificationDateTime);
}
}
+
+ private void notifyBusOfInvoiceAdjustment(final Transmogrifier transactional, final UUID invoiceId, final UUID accountId, final UUID userToken) {
+ try {
+ eventBus.postFromTransaction(new DefaultInvoiceAdjustmentEvent(invoiceId, accountId, userToken), transactional);
+ } catch (EventBusException e) {
+ log.warn("Failed to post adjustment event for invoice " + invoiceId, e);
+ }
+ }
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/invoice/TestDefaultInvoicePaymentApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/invoice/TestDefaultInvoicePaymentApi.java
index 864c4b4..32f52e4 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/invoice/TestDefaultInvoicePaymentApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/invoice/TestDefaultInvoicePaymentApi.java
@@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
+import org.mockito.Mockito;
import org.skife.jdbi.v2.IDBI;
import org.testng.Assert;
import org.testng.annotations.BeforeSuite;
@@ -44,6 +45,7 @@ import com.ning.billing.invoice.dao.InvoiceSqlDao;
import com.ning.billing.invoice.notification.MockNextBillingDatePoster;
import com.ning.billing.invoice.notification.NextBillingDatePoster;
import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.TestCallContext;
import com.ning.billing.util.clock.Clock;
@@ -87,7 +89,7 @@ public class TestDefaultInvoicePaymentApi extends InvoiceTestSuiteWithEmbeddedDB
final TagDefinitionDao tagDefinitionDao = new MockTagDefinitionDao();
final TagDao tagDao = new MockTagDao();
final TagUserApi tagUserApi = new DefaultTagUserApi(tagDefinitionDao, tagDao);
- final InvoiceDao invoiceDao = new AuditedInvoiceDao(dbi, nextBillingDatePoster, tagUserApi, clock);
+ final InvoiceDao invoiceDao = new AuditedInvoiceDao(dbi, nextBillingDatePoster, tagUserApi, clock, Mockito.mock(Bus.class));
invoicePaymentApi = new DefaultInvoicePaymentApi(invoiceDao);
context = new TestCallContext("Invoice payment tests");
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
index 1b42c4e..902591b 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
@@ -110,7 +110,7 @@ public class InvoiceDaoTestBase extends InvoicingTestBase {
final TagDefinitionDao tagDefinitionDao = new MockTagDefinitionDao();
final TagDao tagDao = new AuditedTagDao(dbi, tagEventBuilder, bus);
final TagUserApi tagUserApi = new DefaultTagUserApi(tagDefinitionDao, tagDao);
- invoiceDao = new AuditedInvoiceDao(dbi, nextBillingDatePoster, tagUserApi, clock);
+ invoiceDao = new AuditedInvoiceDao(dbi, nextBillingDatePoster, tagUserApi, clock, bus);
invoiceDao.test();
invoiceItemSqlDao = dbi.onDemand(InvoiceItemSqlDao.class);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/TestDefaultInvoiceDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/TestDefaultInvoiceDao.java
index 3724b9f..c5510d6 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/TestDefaultInvoiceDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/TestDefaultInvoiceDao.java
@@ -33,6 +33,7 @@ import com.ning.billing.invoice.api.InvoiceApiException;
import com.ning.billing.invoice.api.InvoicePayment;
import com.ning.billing.invoice.notification.NextBillingDatePoster;
import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.dao.ObjectType;
@@ -45,6 +46,7 @@ import com.ning.billing.util.tag.dao.TagDao;
import com.ning.billing.util.tag.dao.TagDefinitionDao;
import com.google.common.collect.ImmutableMap;
+import com.google.common.eventbus.EventBus;
public class TestDefaultInvoiceDao extends InvoiceTestSuite {
@@ -62,7 +64,7 @@ public class TestDefaultInvoiceDao extends InvoiceTestSuite {
final TagDefinitionDao tagDefinitionDao = new MockTagDefinitionDao();
final TagDao tagDao = new MockTagDao();
tagUserApi = new DefaultTagUserApi(tagDefinitionDao, tagDao);
- dao = new AuditedInvoiceDao(idbi, poster, tagUserApi, Mockito.mock(Clock.class));
+ dao = new AuditedInvoiceDao(idbi, poster, tagUserApi, Mockito.mock(Clock.class), Mockito.mock(Bus.class));
}
@Test(groups = "fast")
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/TestChargeBacks.java b/invoice/src/test/java/com/ning/billing/invoice/tests/TestChargeBacks.java
index e9842eb..928b727 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/TestChargeBacks.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/TestChargeBacks.java
@@ -22,6 +22,7 @@ import java.net.URL;
import java.util.List;
import java.util.UUID;
+import org.mockito.Mockito;
import org.skife.jdbi.v2.IDBI;
import org.skife.jdbi.v2.exceptions.TransactionFailedException;
import org.testng.annotations.BeforeSuite;
@@ -44,6 +45,7 @@ import com.ning.billing.invoice.glue.InvoiceModuleWithEmbeddedDb;
import com.ning.billing.invoice.notification.MockNextBillingDatePoster;
import com.ning.billing.invoice.notification.NextBillingDatePoster;
import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.TestCallContext;
import com.ning.billing.util.clock.Clock;
@@ -89,7 +91,7 @@ public class TestChargeBacks extends InvoiceTestSuiteWithEmbeddedDB {
final TagDefinitionDao tagDefinitionDao = new MockTagDefinitionDao();
final TagDao tagDao = new MockTagDao();
final TagUserApi tagUserApi = new DefaultTagUserApi(tagDefinitionDao, tagDao);
- final InvoiceDao invoiceDao = new AuditedInvoiceDao(dbi, nextBillingDatePoster, tagUserApi, clock);
+ final InvoiceDao invoiceDao = new AuditedInvoiceDao(dbi, nextBillingDatePoster, tagUserApi, clock, Mockito.mock(Bus.class));
invoicePaymentApi = new DefaultInvoicePaymentApi(invoiceDao);
context = new TestCallContext("Charge back tests");
diff --git a/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java b/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java
index 1ab250a..b4688b5 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java
@@ -21,13 +21,16 @@ import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.eventbus.Subscribe;
-import com.google.inject.Inject;
+import com.ning.billing.invoice.api.InvoiceAdjustmentEvent;
import com.ning.billing.payment.api.PaymentErrorEvent;
import com.ning.billing.payment.api.PaymentInfoEvent;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+
public class OverdueListener {
- OverdueDispatcher dispatcher;
+
+ private final OverdueDispatcher dispatcher;
private static final Logger log = LoggerFactory.getLogger(OverdueListener.class);
@@ -49,10 +52,15 @@ public class OverdueListener {
dispatcher.processOverdueForAccount(accountId);
}
+ @Subscribe
+ public void handleInvoiceAdjustmentEvent(final InvoiceAdjustmentEvent event) {
+ log.info(String.format("Received InvoiceAdjustment event %s", event.toString()));
+ final UUID accountId = event.getAccountId();
+ dispatcher.processOverdueForAccount(accountId);
+ }
+
public void handleNextOverdueCheck(final UUID overdueableId) {
log.info(String.format("Received OD checkup notification for %s", overdueableId));
dispatcher.processOverdue(overdueableId);
}
-
-
}
diff --git a/util/src/test/java/com/ning/billing/api/TestApiListener.java b/util/src/test/java/com/ning/billing/api/TestApiListener.java
index 841cffb..b752c19 100644
--- a/util/src/test/java/com/ning/billing/api/TestApiListener.java
+++ b/util/src/test/java/com/ning/billing/api/TestApiListener.java
@@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
import com.ning.billing.entitlement.api.timeline.RepairEntitlementEvent;
import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
+import com.ning.billing.invoice.api.InvoiceAdjustmentEvent;
import com.ning.billing.invoice.api.InvoiceCreationEvent;
import com.ning.billing.payment.api.PaymentErrorEvent;
import com.ning.billing.payment.api.PaymentInfoEvent;
@@ -65,6 +66,7 @@ public class TestApiListener {
RESUME,
PHASE,
INVOICE,
+ INVOICE_ADJUSTMENT,
PAYMENT,
PAYMENT_ERROR,
REPAIR_BUNDLE
@@ -136,6 +138,13 @@ public class TestApiListener {
}
@Subscribe
+ public void handleInvoiceAdjustmentEvents(final InvoiceAdjustmentEvent event) {
+ log.info(String.format("Got Invoice adjustment event %s", event.toString()));
+ assertEqualsNicely(NextEvent.INVOICE_ADJUSTMENT);
+ notifyIfStackEmpty();
+ }
+
+ @Subscribe
public void handlePaymentEvents(final PaymentInfoEvent event) {
log.info(String.format("Got PaymentInfo event %s", event.toString()));
assertEqualsNicely(NextEvent.PAYMENT);