killbill-memoizeit
Changes
beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java 171(+143 -28)
Details
diff --git a/api/src/main/java/com/ning/billing/overdue/config/api/OverdueStateSet.java b/api/src/main/java/com/ning/billing/overdue/config/api/OverdueStateSet.java
index 693fa8f..2c043d6 100644
--- a/api/src/main/java/com/ning/billing/overdue/config/api/OverdueStateSet.java
+++ b/api/src/main/java/com/ning/billing/overdue/config/api/OverdueStateSet.java
@@ -24,7 +24,7 @@ import com.ning.billing.overdue.OverdueState;
public interface OverdueStateSet<T extends Blockable> {
- public abstract OverdueState<T> findClearState() throws OverdueApiException;
+ public abstract OverdueState<T> getClearState() throws OverdueApiException;
public abstract OverdueState<T> findState(String stateName) throws OverdueApiException;
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
index 3c937a7..0eaae76 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
@@ -30,6 +30,7 @@ import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.ning.billing.account.glue.AccountModule;
+import com.ning.billing.beatrix.integration.overdue.IntegrationTestOverdueModule;
import com.ning.billing.beatrix.lifecycle.DefaultLifecycle;
import com.ning.billing.beatrix.lifecycle.Lifecycle;
import com.ning.billing.catalog.api.CatalogService;
@@ -44,6 +45,7 @@ import com.ning.billing.invoice.api.InvoiceService;
import com.ning.billing.invoice.glue.DefaultInvoiceModule;
import com.ning.billing.junction.glue.DefaultJunctionModule;
import com.ning.billing.lifecycle.KillbillService;
+import com.ning.billing.overdue.OverdueService;
import com.ning.billing.payment.api.PaymentService;
import com.ning.billing.payment.provider.MockPaymentProviderPluginModule;
import com.ning.billing.payment.setup.PaymentModule;
@@ -99,6 +101,7 @@ public class MockModule extends AbstractModule {
install(new TemplateModule());
install(new PaymentMockModule());
install(new DefaultJunctionModule());
+ install(new IntegrationTestOverdueModule());
}
private static final class PaymentMockModule extends PaymentModule {
@@ -133,6 +136,7 @@ public class MockModule extends AbstractModule {
.add(injector.getInstance(EntitlementService.class))
.add(injector.getInstance(InvoiceService.class))
.add(injector.getInstance(PaymentService.class))
+ .add(injector.getInstance(OverdueService.class))
.build();
return services;
}
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 edc9ec1..0242954 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
@@ -16,10 +16,17 @@
package com.ning.billing.beatrix.integration.overdue;
+import static com.jayway.awaitility.Awaitility.await;
+import static java.util.concurrent.TimeUnit.SECONDS;
import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
import org.joda.time.DateTime;
import org.testng.Assert;
@@ -29,7 +36,9 @@ import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import com.google.inject.Inject;
+import com.google.inject.name.Named;
import com.ning.billing.account.api.Account;
+import com.ning.billing.api.TestApiListener.NextEvent;
import com.ning.billing.beatrix.integration.MockModule;
import com.ning.billing.beatrix.integration.TestIntegrationBase;
import com.ning.billing.catalog.api.BillingPeriod;
@@ -38,10 +47,18 @@ import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceUserApi;
import com.ning.billing.junction.api.BlockingApi;
-import com.ning.billing.junction.api.BlockingState;
+import com.ning.billing.overdue.OverdueUserApi;
import com.ning.billing.overdue.config.OverdueConfig;
+import com.ning.billing.overdue.wrapper.MockOverdueWrapperFactory;
+import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
+import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
+import com.ning.billing.payment.api.PaymentAttempt;
import com.ning.billing.payment.provider.MockPaymentProviderPlugin;
+import com.ning.billing.util.callcontext.DefaultCallContext;
import com.ning.billing.util.clock.ClockMock;
import com.ning.billing.util.config.XMLLoader;
@@ -51,50 +68,83 @@ public class TestOverdueIntegration extends TestIntegrationBase {
private final String configXml =
"<overdueConfig>" +
" <bundleOverdueStates>" +
- " <state name=\"OD1\">" +
+ " <state name=\"OD3\">" +
" <condition>" +
" <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
- " <unit>MONTHS</unit><number>1</number>" +
+ " <unit>DAYS</unit><number>50</number>" +
" </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
" </condition>" +
- " <externalMessage>Reached OD1</externalMessage>" +
+ " <externalMessage>Reached OD3</externalMessage>" +
" <blockChanges>true</blockChanges>" +
- " <disableEntitlementAndChangesBlocked>false</disableEntitlementAndChangesBlocked>" +
+ " <disableEntitlementAndChangesBlocked>true</disableEntitlementAndChangesBlocked>" +
+ " <autoReevaluationInterval>" +
+ " <unit>DAYS</unit><number>5</number>" +
+ " </autoReevaluationInterval>" +
" </state>" +
" <state name=\"OD2\">" +
" <condition>" +
" <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
- " <unit>MONTHS</unit><number>2</number>" +
+ " <unit>DAYS</unit><number>40</number>" +
" </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
" </condition>" +
- " <externalMessage>Reached OD1</externalMessage>" +
+ " <externalMessage>Reached OD2</externalMessage>" +
" <blockChanges>true</blockChanges>" +
" <disableEntitlementAndChangesBlocked>true</disableEntitlementAndChangesBlocked>" +
+ " <autoReevaluationInterval>" +
+ " <unit>DAYS</unit><number>5</number>" +
+ " </autoReevaluationInterval>" +
+ " </state>" +
+ " <state name=\"OD1\">" +
+ " <condition>" +
+ " <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+ " <unit>DAYS</unit><number>30</number>" +
+ " </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+ " </condition>" +
+ " <externalMessage>Reached OD1</externalMessage>" +
+ " <blockChanges>true</blockChanges>" +
+ " <disableEntitlementAndChangesBlocked>false</disableEntitlementAndChangesBlocked>" +
+ " <autoReevaluationInterval>" +
+ " <unit>DAYS</unit><number>100</number>" + // this number is intentionally too high
+ " </autoReevaluationInterval>" +
" </state>" +
" </bundleOverdueStates>" +
"</overdueConfig>";
private OverdueConfig config;
-
+
@Inject
private ClockMock clock;
+
+ @Inject
+ private @Named("yoyo") MockPaymentProviderPlugin paymentPlugin;
+
+ @Inject
+ private BlockingApi blockingApi;
@Inject
- private MockPaymentProviderPlugin paymentPlugin;
+ private OverdueWrapperFactory overdueWrapperFactory;
@Inject
- private BlockingApi blockingApi;
+ private OverdueUserApi overdueApi;
+
+ @Inject
+ private PaymentApi paymentApi;
+ @Inject
+ private InvoiceUserApi invoiceApi;
+
private Account account;
private SubscriptionBundle bundle;
private String productName;
private BillingPeriod term;
private String planSetName;
-
+
@BeforeMethod(groups = {"slow"})
public void setupOverdue() throws Exception {
InputStream is = new ByteArrayInputStream(configXml.getBytes());
config = XMLLoader.getObjectFromStreamNoValidation(is, OverdueConfig.class);
- Account account = accountUserApi.createAccount(getAccountData(25), null, null, context);
+ ((MockOverdueWrapperFactory)overdueWrapperFactory).setOverdueConfig(config);
+
+ account = accountUserApi.createAccount(getAccountData(25), null, null, context);
assertNotNull(account);
bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever", context);
@@ -102,41 +152,106 @@ public class TestOverdueIntegration extends TestIntegrationBase {
productName = "Shotgun";
term = BillingPeriod.MONTHLY;
planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
-
+
// create account
// set mock payments to fail
// reset clock
// configure basic OD state rules for 2 states OD1 1-2month, OD2 2-3 month
}
-
+
@AfterMethod
public void cleanup(){
// Clear databases
}
-
+
@Test(groups={"slow"}, enabled = true)
public void testBasicOverdueState() throws Exception {
clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
-
+ paymentPlugin.makeAllInvoicesFail(true);
+
// set next invoice to fail and create network
- paymentPlugin.makeNextInvoiceFail();
+ busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.INVOICE);
SubscriptionData baseSubscription = subscriptionDataFromSubscription(entitlementUserApi.createSubscription(bundle.getId(),
new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null), null, context));
assertNotNull(baseSubscription);
+ assertTrue(busHandler.isCompleted(DELAY));
+
+ busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR);
+ clock.addDays(30); // DAY 30 have to get out of trial before first payment
+ assertTrue(busHandler.isCompleted(DELAY));
+
+ // should still be in clear state
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ clock.addDays(15); // DAY 45 - 15 days after invoice
+ assertTrue(busHandler.isCompleted(DELAY));
+ overdueApi.refreshOverdueStateFor(bundle); // trigger a refresh because there are no events to do it for us
+ //should still be in clear state
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT_ERROR);
+ clock.addDays(20); // DAY 65 - 35 days after invoice
+ assertTrue(busHandler.isCompleted(DELAY));
+
+ //Now we should be in OD1
+ checkODState("OD1");
+
+ clock.addDays(2); //DAY 67 - 37 days after invoice
+ assertTrue(busHandler.isCompleted(DELAY));
+ overdueApi.refreshOverdueStateFor(bundle); // trigger a refresh because there are no events to do it for us
+ // should still be in OD1
+ checkODState("OD1");
- // advance time 2weeks
- clock.addWeeks(2);
+ //busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT_ERROR);
+ clock.addDays(8); //DAY 75 - 45 days after invoice
+ assertTrue(busHandler.isCompleted(DELAY));
+ overdueApi.refreshOverdueStateFor(bundle); // trigger a refresh because there are no events to do it for us
+ // should still be in OD1
+ checkODState("OD2");
- // should still be in clear state
- BlockingState state = blockingApi.getBlockingStateFor(bundle);
- Assert.assertEquals(state.getStateName(), BlockingApi.CLEAR_STATE_NAME);
- // set next invoice to fail and advance time 1 month
- clock.addWeeks(4);
+ busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT_ERROR);
+ clock.addDays(10); //DAY 85 - 55 days after invoice
+ assertTrue(busHandler.isCompleted(DELAY));
+ // should now be in OD2 state once the update is processed
+ checkODState("OD3");
+
+ paymentPlugin.makeAllInvoicesFail(false);
+ Collection<Invoice> invoices = invoiceApi.getUnpaidInvoicesByAccountId(account.getId(), clock.getUTCNow());
+ List<String> invoiceIds = new ArrayList<String>();
+ List<PaymentAttempt> paymentAttempts = new ArrayList<PaymentAttempt>();
+ for(Invoice invoice : invoices) {
+// paymentAttempts.addAll(paymentApi.getPaymentAttemptsForInvoiceId(invoice.getId().toString()));
+// for(PaymentAttempt pa : paymentAttempts) {
+// busHandler.pushExpectedEvent(NextEvent.PAYMENT);
+// try {
+// paymentApi.createPaymentForPaymentAttempt(pa.getPaymentAttemptId(), new DefaultCallContext("test", null, null, clock));
+// } catch(PaymentApiException e) {
+// log.info("",e);
+// }
+// }
+ invoiceIds.add(invoice.getId().toString());
+
+ }
+ paymentApi.createPayment(account, invoiceIds, new DefaultCallContext("test", null, null, clock));
- // should now be in OD1 state
- // set next invoice to fail and advance time 1 month
- // should now be in OD2 state
- clock.addWeeks(4);
+ assertTrue(busHandler.isCompleted(DELAY));
+
+ overdueApi.refreshOverdueStateFor(bundle);
+ checkODState(BlockingApi.CLEAR_STATE_NAME);
+
+ }
+
+ private void checkODState(final String expected) {
+ try {
+ await().atMost(10, SECONDS).until(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return expected.equals(blockingApi.getBlockingStateFor(bundle).getStateName()) ;
+ }
+ });
+ } catch (Exception e) {
+ Assert.assertEquals(blockingApi.getBlockingStateFor(bundle).getStateName(), expected);
+ }
}
}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
index 7996141..c936a52 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
@@ -127,7 +127,7 @@ public class TestIntegration extends TestIntegrationBase {
busHandler.pushExpectedEvent(NextEvent.CREATE);
busHandler.pushExpectedEvent(NextEvent.INVOICE);
busHandler.pushExpectedEvent(NextEvent.PAYMENT);
- SubscriptionData aoSubscription = subscriptionDataFromSubscription(entitlementUserApi.createSubscription(bundle.getId(),
+ subscriptionDataFromSubscription(entitlementUserApi.createSubscription(bundle.getId(),
new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null), null, context));
assertTrue(busHandler.isCompleted(DELAY));
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
index b83dc82..27f8dff 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
@@ -94,6 +94,7 @@ getUnpaidInvoicesByAccountId() ::= <<
WHERE i.account_id = :accountId AND NOT (i.target_date > :upToDate) AND migrated = 'FALSE'
GROUP BY i.id, i.account_id, i.invoice_date, i.target_date, i.currency
HAVING (SUM(iis.amount_invoiced) > SUM(ips.total_paid)) OR (SUM(ips.total_paid) IS NULL)
+ AND SUM(iis.amount_invoiced) > 0
ORDER BY i.target_date ASC;
>>
diff --git a/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java b/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
index 83487ea..e71a2fd 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
@@ -17,11 +17,12 @@
package com.ning.billing.overdue.api;
import org.apache.commons.lang.NotImplementedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import com.ning.billing.ErrorCode;
import com.ning.billing.catalog.api.CatalogService;
-import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.junction.api.Blockable;
import com.ning.billing.junction.api.BlockingApi;
@@ -32,22 +33,21 @@ import com.ning.billing.overdue.config.OverdueConfig;
import com.ning.billing.overdue.config.api.BillingState;
import com.ning.billing.overdue.config.api.OverdueError;
import com.ning.billing.overdue.config.api.OverdueStateSet;
-import com.ning.billing.overdue.service.ExtendedOverdueService;
import com.ning.billing.overdue.wrapper.OverdueWrapper;
import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
public class DefaultOverdueUserApi implements OverdueUserApi {
-
+ Logger log = LoggerFactory.getLogger(DefaultOverdueUserApi.class);
private final OverdueWrapperFactory factory;
private final BlockingApi accessApi;
private final OverdueConfig overdueConfig;
@Inject
- public DefaultOverdueUserApi(OverdueWrapperFactory factory,BlockingApi accessApi, ExtendedOverdueService service, CatalogService catalogService) {
+ public DefaultOverdueUserApi(OverdueWrapperFactory factory,BlockingApi accessApi, OverdueConfig config, CatalogService catalogService) {
this.factory = factory;
this.accessApi = accessApi;
- this.overdueConfig = service.getOverdueConfig();
+ this.overdueConfig = config;
}
@SuppressWarnings("unchecked")
@@ -63,8 +63,9 @@ public class DefaultOverdueUserApi implements OverdueUserApi {
}
@Override
- public <T extends Blockable> OverdueState<T> refreshOverdueStateFor(T overdueable) throws OverdueError, OverdueApiException {
- OverdueWrapper<T> wrapper = factory.createOverdueWrapperFor(overdueable);
+ public <T extends Blockable> OverdueState<T> refreshOverdueStateFor(T blockable) throws OverdueError, OverdueApiException {
+ log.info(String.format("Refresh of %s requested", blockable.getId()));
+ OverdueWrapper<T> wrapper = factory.createOverdueWrapperFor(blockable);
return wrapper.refresh();
}
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 abd4e0a..139357b 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
@@ -46,8 +46,8 @@ public class OverdueStateApplicator<T extends Blockable>{
this.poster = poster;
}
- public void apply(T overdueable, OverdueState<T> previousOverdueState, OverdueState<T> nextOverdueState) throws OverdueError {
- if(previousOverdueState.getName().equals(nextOverdueState.getName())) {
+ public void apply(T overdueable, String previousOverdueStateName, OverdueState<T> nextOverdueState) throws OverdueError {
+ if(previousOverdueStateName.equals(nextOverdueState.getName())) {
return; // nothing to do
}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java
index d47f3f3..ccabe19 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java
@@ -20,6 +20,7 @@ import java.math.BigDecimal;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
+import java.util.NoSuchElementException;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
@@ -60,7 +61,11 @@ public abstract class BillingStateCalculator<T extends Blockable> {
public abstract BillingState<T> calculateBillingState(T overdueable) throws EntitlementUserApiException;
protected DateTime earliest(SortedSet<Invoice> unpaidInvoices) {
- return unpaidInvoices.first().getInvoiceDate();
+ try {
+ return unpaidInvoices.first().getInvoiceDate();
+ } catch (NoSuchElementException e) {
+ return null;
+ }
}
protected BigDecimal sumBalance(SortedSet<Invoice> unpaidInvoices) {
diff --git a/overdue/src/main/java/com/ning/billing/overdue/config/Condition.java b/overdue/src/main/java/com/ning/billing/overdue/config/Condition.java
index 6fc8564..490c5f0 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/config/Condition.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/config/Condition.java
@@ -25,6 +25,6 @@ import com.ning.billing.overdue.config.api.BillingState;
public interface Condition<T extends Blockable> {
- public boolean evaluate(BillingState state, DateTime now);
+ public boolean evaluate(BillingState<T> state, DateTime now);
}
\ No newline at end of file
diff --git a/overdue/src/main/java/com/ning/billing/overdue/config/DefaultCondition.java b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultCondition.java
index 44f6c99..36343f8 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/config/DefaultCondition.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultCondition.java
@@ -59,11 +59,17 @@ public class DefaultCondition<T extends Blockable> extends ValidatingConfig<Over
* @see com.ning.billing.catalog.overdue.Condition#evaluate(com.ning.billing.catalog.api.overdue.BillingState, org.joda.time.DateTime)
*/
@Override
- public boolean evaluate(BillingState state, DateTime now) {
+ public boolean evaluate(BillingState<T> state, DateTime now) {
+ DateTime unpaidInvoiceTriggerDate = null;
+ if( timeSinceEarliestUnpaidInvoiceEqualsOrExceeds != null && state.getDateOfEarliestUnpaidInvoice() != null) { // no date => no unpaid invoices
+ unpaidInvoiceTriggerDate = state.getDateOfEarliestUnpaidInvoice().plus(timeSinceEarliestUnpaidInvoiceEqualsOrExceeds.toJodaPeriod());
+ }
+
return
(numberOfUnpaidInvoicesEqualsOrExceeds == null || state.getNumberOfUnpaidInvoices() >= numberOfUnpaidInvoicesEqualsOrExceeds.intValue() ) &&
(totalUnpaidInvoiceBalanceEqualsOrExceeds == null || totalUnpaidInvoiceBalanceEqualsOrExceeds.compareTo(state.getBalanceOfUnpaidInvoices()) <= 0) &&
- (timeSinceEarliestUnpaidInvoiceEqualsOrExceeds == null || !timeSinceEarliestUnpaidInvoiceEqualsOrExceeds.addToDateTime(state.getDateOfEarliestUnpaidInvoice()).isAfter(now)) &&
+ (unpaidInvoiceTriggerDate == null ||
+ (state.getDateOfEarliestUnpaidInvoice() != null && !unpaidInvoiceTriggerDate.isAfter(now))) &&
(responseForLastFailedPayment == null || responseIsIn(state.getResponseForLastFailedPayment(), responseForLastFailedPayment)) &&
(controlTag == null || isTagIn(controlTag, state.getTags()));
}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueState.java b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueState.java
index 690d717..4206e45 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueState.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueState.java
@@ -121,6 +121,10 @@ public class DefaultOverdueState<T extends Blockable> extends ValidatingConfig<O
return this;
}
+ protected DefaultOverdueState<T> setClearState(boolean isClearState) {
+ this.isClearState = isClearState;
+ return this;
+ }
protected DefaultOverdueState<T> setExternalMessage(String externalMessage) {
this.externalMessage = externalMessage;
return this;
diff --git a/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueStateSet.java b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueStateSet.java
index 277fb1b..59a82bf 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueStateSet.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueStateSet.java
@@ -26,6 +26,8 @@ import org.joda.time.Period;
import com.ning.billing.ErrorCode;
import com.ning.billing.catalog.api.Duration;
import com.ning.billing.junction.api.Blockable;
+import com.ning.billing.junction.api.BlockingApi;
+import com.ning.billing.junction.api.BlockingState;
import com.ning.billing.overdue.OverdueApiException;
import com.ning.billing.overdue.OverdueState;
import com.ning.billing.overdue.config.api.BillingState;
@@ -36,21 +38,15 @@ import com.ning.billing.util.config.ValidationErrors;
@XmlAccessorType(XmlAccessType.NONE)
public abstract class DefaultOverdueStateSet<T extends Blockable> extends ValidatingConfig<OverdueConfig> implements OverdueStateSet<T> {
private static final Period ZERO_PERIOD = new Period();
- private DefaultOverdueState<T> clearState;
+ private DefaultOverdueState<T> clearState = new DefaultOverdueState<T>().setName(BlockingApi.CLEAR_STATE_NAME).setClearState(true);
protected abstract DefaultOverdueState<T>[] getStates();
- private DefaultOverdueState<T> getClearState() throws OverdueApiException {
- for(DefaultOverdueState<T> overdueState : getStates()) {
- if(overdueState.isClearState()) {
- return overdueState;
- }
- }
- throw new OverdueApiException(ErrorCode.CAT_MISSING_CLEAR_STATE);
- }
-
@Override
public OverdueState<T> findState(String stateName) throws OverdueApiException {
+ if(stateName.equals( BlockingApi.CLEAR_STATE_NAME)) {
+ return clearState;
+ }
for(DefaultOverdueState<T> state: getStates()) {
if(state.getName().equals(stateName) ) { return state; }
}
@@ -62,11 +58,8 @@ public abstract class DefaultOverdueStateSet<T extends Blockable> extends Valida
* @see com.ning.billing.catalog.overdue.OverdueBillingState#findClearState()
*/
@Override
- public DefaultOverdueState<T> findClearState() throws OverdueApiException {
- if (clearState != null) {
- clearState = getClearState();
- }
- return clearState;
+ public DefaultOverdueState<T> getClearState() throws OverdueApiException {
+ return clearState;
}
/* (non-Javadoc)
@@ -79,7 +72,7 @@ public abstract class DefaultOverdueStateSet<T extends Blockable> extends Valida
return overdueState;
}
}
- return findClearState();
+ return getClearState();
}
@Override
diff --git a/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueDispatcher.java b/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueDispatcher.java
index 8f2d03f..f7b247e 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueDispatcher.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueDispatcher.java
@@ -16,15 +16,13 @@
package com.ning.billing.overdue.listener;
+import java.util.List;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
-import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.AccountApiException;
-import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
@@ -36,29 +34,25 @@ import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
public class OverdueDispatcher {
Logger log = LoggerFactory.getLogger(OverdueDispatcher.class);
-
+
private final EntitlementUserApi entitlementUserApi;
- private final AccountUserApi accountUserApi;
private final OverdueWrapperFactory factory;
-
+
@Inject
- public OverdueDispatcher(AccountUserApi accountUserApi,
+ public OverdueDispatcher(
EntitlementUserApi entitlementUserApi,
OverdueWrapperFactory factory) {
- this.accountUserApi = accountUserApi;
this.entitlementUserApi = entitlementUserApi;
this.factory = factory;
}
-
+
public void processOverdueForAccount(UUID accountId) {
- try {
- Account account = accountUserApi.getAccountById(accountId);
- processOverdue(account);
- } catch (AccountApiException e) {
- log.error("Error processing Overdue for Account with id: " + accountId.toString(), e);
+ List<SubscriptionBundle> bundles = entitlementUserApi.getBundlesForAccount(accountId);
+ for(SubscriptionBundle bundle : bundles) {
+ processOverdue(bundle);
}
}
-
+
public void processOverdueForBundle(UUID bundleId) {
try {
SubscriptionBundle bundle = entitlementUserApi.getBundleFromId(bundleId);
@@ -68,20 +62,24 @@ public class OverdueDispatcher {
}
}
- public void processOverdue(Blockable bloackable) {
+ public void processOverdue(Blockable blockable) {
try {
- OverdueWrapper<?> wrapper = factory.createOverdueWrapperFor(bloackable);
- wrapper.refresh();
+ factory.createOverdueWrapperFor(blockable).refresh();
} catch (OverdueError e) {
- log.error("Error processing Overdue for Blockable with id: " + bloackable.getId().toString(), e);
+ log.error("Error processing Overdue for Blockable with id: " + blockable.getId().toString(), e);
} catch (OverdueApiException e) {
- log.error("Error processing Overdue for Blockable with id: " + bloackable.getId().toString(), e);
+ log.error("Error processing Overdue for Blockable with id: " + blockable.getId().toString(), e);
}
}
public void processOverdue(UUID blockableId) {
-
-
+ try {
+ factory.createOverdueWrapperFor(blockableId).refresh();
+ } catch (OverdueError e) {
+ log.error("Error processing Overdue for Blockable with id: " + blockableId.toString(), e);
+ } catch (OverdueApiException e) {
+ log.error("Error processing Overdue for Blockable with id: " + blockableId.toString(), e);
+ }
}
}
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 2c193b4..f208813 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
@@ -24,17 +24,14 @@ import org.slf4j.LoggerFactory;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Inject;
import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentAttempt;
import com.ning.billing.payment.api.PaymentErrorEvent;
import com.ning.billing.payment.api.PaymentInfoEvent;
public class OverdueListener {
OverdueDispatcher dispatcher;
-
- //
- //TODO disabled overdue for prod deployment - comments should be removed
- //
-
+
private final static Logger log = LoggerFactory.getLogger(OverdueListener.class);
private final PaymentApi paymentApi;
@@ -46,21 +43,28 @@ public class OverdueListener {
@Subscribe
public void handlePaymentInfoEvent(final PaymentInfoEvent event) {
-// String paymentId = event.getPaymentId();
-// PaymentAttempt attempt = paymentApi.getPaymentAttemptForPaymentId(paymentId);
-// UUID accountId = attempt.getAccountId();
-// dispatcher.processOverdueForAccount(accountId);
+ log.info(String.format("Received PaymentInfo event %s", event.toString()));
+ try {
+ String paymentId = event.getPaymentId();
+ PaymentAttempt attempt = paymentApi.getPaymentAttemptForPaymentId(paymentId);
+ UUID accountId = attempt.getAccountId();
+ dispatcher.processOverdueForAccount(accountId);
+ } catch (PaymentApiException e) {
+ log.error("Payment exception encountered when trying process Overdue against payement: " + event.getPaymentId(), e);
+ }
}
-
+
@Subscribe
public void handlePaymentErrorEvent(final PaymentErrorEvent event) {
-// UUID accountId = event.getAccountId();
-// dispatcher.processOverdueForAccount(accountId);
+ log.info(String.format("Received PaymentError event %s", event.toString()));
+ UUID accountId = event.getAccountId();
+ dispatcher.processOverdueForAccount(accountId);
}
public void handleNextOverdueCheck(UUID overdueableId) {
-// dispatcher.processOverdue(overdueableId);
+ log.info(String.format("Received OD checkup notification for %s", overdueableId));
+ dispatcher.processOverdue(overdueableId);
}
-
-
+
+
}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java b/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java
index 3153f0e..17f4be1 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java
@@ -18,28 +18,48 @@ package com.ning.billing.overdue.service;
import java.net.URI;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.google.inject.Inject;
import com.ning.billing.lifecycle.LifecycleHandlerType;
import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
+import com.ning.billing.ovedue.notification.OverdueCheckNotifier;
import com.ning.billing.overdue.OverdueProperties;
import com.ning.billing.overdue.OverdueUserApi;
import com.ning.billing.overdue.config.OverdueConfig;
+import com.ning.billing.overdue.listener.OverdueListener;
+import com.ning.billing.util.bus.Bus.EventBusException;
+import com.ning.billing.util.bus.BusService;
import com.ning.billing.util.config.XMLLoader;
public class DefaultOverdueService implements ExtendedOverdueService {
+ private static final Logger log = LoggerFactory.getLogger(DefaultOverdueService.class);
+
public static final String OVERDUE_SERVICE_NAME = "overdue-service";
private OverdueUserApi userApi;
private OverdueConfig overdueConfig;
private OverdueProperties properties;
+ private OverdueCheckNotifier notifier;
+ private BusService busService;
+ OverdueListener listener;
private boolean isInitialized;
@Inject
- public DefaultOverdueService(OverdueUserApi userApi, OverdueProperties properties){
+ public DefaultOverdueService(
+ OverdueUserApi userApi,
+ OverdueProperties properties,
+ OverdueCheckNotifier notifier,
+ BusService busService,
+ OverdueListener listener){
this.userApi = userApi;
this.properties = properties;
+ this.notifier = notifier;
+ this.busService = busService;
+ this.listener = listener;
}
-
+
@Override
public String getName() {
return OVERDUE_SERVICE_NAME;
@@ -51,7 +71,7 @@ public class DefaultOverdueService implements ExtendedOverdueService {
}
@Override
- public OverdueConfig getOverdueConfig() {
+ public OverdueConfig getOverdueConfig() {
return overdueConfig;
}
@@ -70,4 +90,36 @@ public class DefaultOverdueService implements ExtendedOverdueService {
}
}
+ @LifecycleHandlerType(LifecycleHandlerType.LifecycleLevel.INIT_SERVICE)
+ public void initialize() {
+ notifier.initialize();
+ }
+
+ @LifecycleHandlerType(LifecycleLevel.START_SERVICE)
+ public void start() {
+ notifier.start();
+ }
+
+ @LifecycleHandlerType(LifecycleHandlerType.LifecycleLevel.REGISTER_EVENTS)
+ public void registerForBus() {
+ try {
+ busService.getBus().register(listener);
+ } catch (EventBusException e) {
+ log.error("Problem encountered registering OverdueListener on the Event Bus", e);
+ }
+ }
+
+ @LifecycleHandlerType(LifecycleHandlerType.LifecycleLevel.UNREGISTER_EVENTS)
+ public void unregisterForBus() {
+ try {
+ busService.getBus().unregister(listener);
+ } catch (EventBusException e) {
+ log.error("Problem encountered registering OverdueListener on the Event Bus", e);
+ }
+ }
+
+ @LifecycleHandlerType(LifecycleLevel.STOP_SERVICE)
+ public void stop() {
+ notifier.stop();
+ }
}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java
index 97220d5..cb693e4 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java
@@ -56,8 +56,8 @@ public class OverdueWrapper<T extends Blockable> {
String previousOverdueStateName = api.getBlockingStateFor(overdueable).getStateName();
nextOverdueState = overdueStateSet.calculateOverdueState(billingState, clock.getUTCNow());
- if(!previousOverdueStateName.equals(nextOverdueState.getName())) {
- overdueStateApplicator.apply(overdueable, nextOverdueState, nextOverdueState);
+ if(nextOverdueState != null && !previousOverdueStateName.equals(nextOverdueState.getName())) {
+ overdueStateApplicator.apply(overdueable, previousOverdueStateName, nextOverdueState);
}
return nextOverdueState;
diff --git a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java
index 0fd6854..17e2817 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java
@@ -39,7 +39,7 @@ import com.ning.billing.util.clock.Clock;
public class OverdueWrapperFactory {
private static final Logger log = LoggerFactory.getLogger(OverdueWrapperFactory.class);
- private final OverdueConfig overdueConfig;
+ protected OverdueConfig overdueConfig; //protected and not final so it can be set in testing
private final EntitlementUserApi entitlementApi;
private final BillingStateCalculatorBundle billingStateCalcuatorBundle;
private final OverdueStateApplicator<SubscriptionBundle> overdueStateApplicatorBundle;
@@ -47,14 +47,14 @@ public class OverdueWrapperFactory {
private final Clock clock;
@Inject
- public OverdueWrapperFactory(BlockingApi api, ExtendedOverdueService service, Clock clock,
+ public OverdueWrapperFactory(BlockingApi api, OverdueConfig config, Clock clock,
BillingStateCalculatorBundle billingStateCalcuatorBundle,
OverdueStateApplicator<SubscriptionBundle> overdueStateApplicatorBundle,
EntitlementUserApi entitlementApi) {
this.billingStateCalcuatorBundle = billingStateCalcuatorBundle;
this.overdueStateApplicatorBundle = overdueStateApplicatorBundle;
this.entitlementApi = entitlementApi;
- this.overdueConfig = service.getOverdueConfig();
+ this.overdueConfig = config;
this.api = api;
this.clock = clock;
}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
index bb7ece3..5d2061b 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
@@ -135,7 +135,48 @@ public class TestBillingStateCalculatorBundle extends TestBillingStateCalculator
}
-
+ @Test(groups = {"fast"}, enabled=true)
+ public void testcalculateBillingStateForBundleNoOverdueInvoices() throws Exception {
+
+ UUID thisBundleId = new UUID(0L,0L);
+ UUID thatBundleId = new UUID(0L,1L);
+
+ now = new DateTime();
+ List<Invoice> invoices = new ArrayList<Invoice>(5);
+
+ Clock clock = new ClockMock();
+ InvoiceUserApi invoiceApi = BrainDeadProxyFactory.createBrainDeadProxyFor(InvoiceUserApi.class);
+ ((ZombieControl)invoiceApi).addResult("getUnpaidInvoicesByAccountId", invoices);
+
+ SubscriptionBundle bundle = BrainDeadProxyFactory.createBrainDeadProxyFor(SubscriptionBundle.class);
+ ((ZombieControl)bundle).addResult("getId", thisBundleId);
+ ((ZombieControl)bundle).addResult("getAccountId", UUID.randomUUID());
+
+ EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+ Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
+ ((ZombieControl)entitlementApi).addResult("getBaseSubscription",subscription);
+
+ Plan plan = MockPlan.createBicycleNoTrialEvergreen1USD();
+ PriceList pricelist = new MockPriceList();
+ ((ZombieControl)subscription).addResult("getCurrentPlan", plan);
+ ((ZombieControl)subscription).addResult("getCurrentPriceList", pricelist);
+ ((ZombieControl)subscription).addResult("getCurrentPhase", plan.getFinalPhase());
+
+ BillingStateCalculatorBundle calc = new BillingStateCalculatorBundle(entitlementApi, invoiceApi, clock);
+
+ BillingStateBundle state = calc.calculateBillingState(bundle);
+
+ Assert.assertEquals(state.getNumberOfUnpaidInvoices(),0);
+ Assert.assertEquals(state.getBalanceOfUnpaidInvoices().intValue(), 0);
+ Assert.assertEquals(state.getDateOfEarliestUnpaidInvoice(), null);
+ Assert.assertEquals(state.getResponseForLastFailedPayment(),PaymentResponse.INSUFFICIENT_FUNDS); //TODO needs more when implemented
+ Assert.assertEquals(state.getTags().length,0);//TODO needs more when implemented
+ Assert.assertEquals(state.getBasePlanBillingPeriod(), plan.getBillingPeriod());
+ Assert.assertEquals(state.getBasePlanPhaseType(), plan.getFinalPhase().getPhaseType());
+ Assert.assertEquals(state.getBasePlanPriceList(), pricelist);
+ Assert.assertEquals(state.getBasePlanProduct(), plan.getProduct());
+
+ }
diff --git a/overdue/src/test/java/com/ning/billing/overdue/config/TestCondition.java b/overdue/src/test/java/com/ning/billing/overdue/config/TestCondition.java
index 1e5f1e0..e697f29 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/config/TestCondition.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/TestCondition.java
@@ -89,7 +89,7 @@ public class TestCondition {
DateTime now = new DateTime();
- BillingState<Blockable> state0 = new BillingState<Blockable>(new UUID(0L,1L), 0, BigDecimal.ZERO, now, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+ BillingState<Blockable> state0 = new BillingState<Blockable>(new UUID(0L,1L), 0, BigDecimal.ZERO, null, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
BillingState<Blockable> state1 = new BillingState<Blockable>(new UUID(0L,1L), 1, new BigDecimal("100.00"), now.minusDays(10), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
BillingState<Blockable> state2 = new BillingState<Blockable>(new UUID(0L,1L), 1, new BigDecimal("200.00"), now.minusDays(20), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
diff --git a/overdue/src/test/java/com/ning/billing/overdue/config/TestOverdueConfig.java b/overdue/src/test/java/com/ning/billing/overdue/config/TestOverdueConfig.java
index df4f4c3..4cffcdc 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/config/TestOverdueConfig.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/TestOverdueConfig.java
@@ -36,6 +36,9 @@ public class TestOverdueConfig {
" <externalMessage>Reached OD1</externalMessage>" +
" <blockChanges>true</blockChanges>" +
" <disableEntitlementAndChangesBlocked>false</disableEntitlementAndChangesBlocked>" +
+ " <autoReevaluationInterval>" +
+ " <unit>DAYS</unit><number>15</number>" +
+ " </autoReevaluationInterval>" +
" </state>" +
" <state name=\"OD2\">" +
" <condition>" +
@@ -46,6 +49,9 @@ public class TestOverdueConfig {
" <externalMessage>Reached OD1</externalMessage>" +
" <blockChanges>true</blockChanges>" +
" <disableEntitlementAndChangesBlocked>true</disableEntitlementAndChangesBlocked>" +
+ " <autoReevaluationInterval>" +
+ " <unit>DAYS</unit><number>15</number>" +
+ " </autoReevaluationInterval>" +
" </state>" +
" </bundleOverdueStates>" +
"</overdueConfig>";
diff --git a/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java b/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java
index 7f48dda..a4d0fa1 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java
@@ -53,7 +53,7 @@ import com.ning.billing.ovedue.notification.DefaultOverdueCheckNotifier;
import com.ning.billing.ovedue.notification.DefaultOverdueCheckPoster;
import com.ning.billing.ovedue.notification.OverdueCheckPoster;
import com.ning.billing.overdue.OverdueProperties;
-import com.ning.billing.overdue.glue.OverdueModule;
+import com.ning.billing.overdue.glue.DefaultOverdueModule;
import com.ning.billing.overdue.listener.OverdueListener;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.bus.InMemoryBus;
@@ -108,7 +108,7 @@ public class TestOverdueCheckNotifier {
@BeforeClass(groups={"slow"})
public void setup() throws ServiceException, IOException, ClassNotFoundException, SQLException {
//TestApiBase.loadSystemPropertiesFromClasspath("/entitlement.properties");
- final Injector g = Guice.createInjector(Stage.PRODUCTION, new OverdueModule() {
+ final Injector g = Guice.createInjector(Stage.PRODUCTION, new DefaultOverdueModule() {
protected void configure() {
super.configure();
diff --git a/overdue/src/test/resources/OverdueConfigSchema.xsd b/overdue/src/test/resources/OverdueConfigSchema.xsd
index 256da08..bf57ece 100644
--- a/overdue/src/test/resources/OverdueConfigSchema.xsd
+++ b/overdue/src/test/resources/OverdueConfigSchema.xsd
@@ -35,10 +35,11 @@
<xs:sequence>
<xs:element minOccurs="0" name="condition" type="defaultCondition"/>
<xs:element minOccurs="0" name="externalMessage" type="xs:string"/>
-<xs:element minOccurs="0" name="disableEntitlementAndChangesBlocked" type="xs:boolean"/>
<xs:element minOccurs="0" name="blockChanges" type="xs:boolean"/>
+<xs:element minOccurs="0" name="disableEntitlementAndChangesBlocked" type="xs:boolean"/>
<xs:element minOccurs="0" name="daysBetweenPaymentRetries" type="xs:int"/>
<xs:element minOccurs="0" name="isClearState" type="xs:boolean"/>
+<xs:element minOccurs="0" name="autoReevaluationInterval" type="defaultDuration"/>
</xs:sequence>
<xs:attribute name="name" type="xs:ID" use="required"/>
</xs:extension>
diff --git a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
index 2077c5e..c90d859 100644
--- a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
@@ -23,7 +23,6 @@ import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Inject;
import com.ning.billing.account.api.Account;
@@ -31,7 +30,6 @@ import com.ning.billing.account.api.AccountApiException;
import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.invoice.api.InvoiceCreationEvent;
import com.ning.billing.payment.api.DefaultPaymentErrorEvent;
-import com.ning.billing.payment.api.Either;
import com.ning.billing.payment.api.PaymentApi;
import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentErrorEvent;
@@ -39,7 +37,6 @@ import com.ning.billing.payment.api.PaymentInfoEvent;
import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.bus.Bus.EventBusException;
-import com.ning.billing.util.bus.BusEvent.BusEventType;
import com.ning.billing.util.bus.BusEvent;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallOrigin;
@@ -67,7 +64,7 @@ public class RequestProcessor {
this.paymentApi = paymentApi;
this.eventBus = eventBus;
}
-
+
private void postPaymentEvent(BusEvent ev, UUID accountId) {
if (ev == null) {
return;
@@ -94,14 +91,14 @@ public class RequestProcessor {
postPaymentEvent(infoEvent, account.getId());
return;
} else {
- errorEvent = new DefaultPaymentErrorEvent(null, "Failed to retrieve account", event.getAccountId(), null, null);
+ errorEvent = new DefaultPaymentErrorEvent(null, "Failed to retrieve account", event.getAccountId(), event.getInvoiceId(), event.getUserToken());
}
} catch(AccountApiException e) {
log.error("Failed to process invoice payment", e);
- errorEvent = new DefaultPaymentErrorEvent(null, e.getMessage(), event.getAccountId(), null, null);
+ errorEvent = new DefaultPaymentErrorEvent(null, e.getMessage(), event.getAccountId(), event.getInvoiceId(), event.getUserToken());
} catch (PaymentApiException e) {
- log.error("Failed to process invoice payment", e);
- errorEvent = new DefaultPaymentErrorEvent(null, e.getMessage(), event.getAccountId(), null, null);
+ log.info("Failed to process invoice payment for account: " + event.getAccountId()); // Removed stack trace log here and changed to info - this an expected flow
+ errorEvent = new DefaultPaymentErrorEvent(null, e.getMessage(), event.getAccountId(), event.getInvoiceId(), event.getUserToken());
}
postPaymentEvent(errorEvent, event.getAccountId());
}
diff --git a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
index 492bf30..f1176f7 100644
--- a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
+++ b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
@@ -44,6 +44,7 @@ import com.ning.billing.util.clock.Clock;
public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
private final AtomicBoolean makeNextInvoiceFail = new AtomicBoolean(false);
+ private final AtomicBoolean makeAllInvoicesFail = new AtomicBoolean(false);
private final Map<String, PaymentInfoEvent> payments = new ConcurrentHashMap<String, PaymentInfoEvent>();
private final Map<String, PaymentProviderAccount> accounts = new ConcurrentHashMap<String, PaymentProviderAccount>();
private final Map<String, PaymentMethodInfo> paymentMethods = new ConcurrentHashMap<String, PaymentMethodInfo>();
@@ -58,9 +59,13 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
makeNextInvoiceFail.set(true);
}
+ public void makeAllInvoicesFail(boolean failure) {
+ makeAllInvoicesFail.set(failure);
+ }
+
@Override
public Either<PaymentErrorEvent, PaymentInfoEvent> processInvoice(Account account, Invoice invoice) {
- if (makeNextInvoiceFail.getAndSet(false)) {
+ if (makeNextInvoiceFail.getAndSet(false) || makeAllInvoicesFail.get()) {
return Either.left((PaymentErrorEvent) new DefaultPaymentErrorEvent("unknown", "test error", account.getId(), invoice.getId(), null));
}
else {
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 351affc..9eddf7b 100644
--- a/util/src/test/java/com/ning/billing/api/TestApiListener.java
+++ b/util/src/test/java/com/ning/billing/api/TestApiListener.java
@@ -139,7 +139,8 @@ public class TestApiListener {
@Subscribe
public void handlePaymentErrorEvents(PaymentErrorEvent event) {
log.info(String.format("TestApiListener Got PaymentError event %s", event.toString()));
- }
+ assertEqualsNicely(NextEvent.PAYMENT_ERROR);
+ notifyIfStackEmpty(); }
public void reset() {
synchronized(this) {
@@ -149,6 +150,12 @@ public class TestApiListener {
}
}
+ public void pushExpectedEvents(NextEvent ... events) {
+ for(NextEvent event : events) {
+ pushExpectedEvent(event);
+ }
+ }
+
public void pushExpectedEvent(NextEvent next) {
synchronized (this) {
Joiner joiner = Joiner.on(" ");