Details
diff --git a/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java b/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
index 1a2585b..af8c7c6 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
@@ -27,6 +27,7 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.RequestedSubscriptionEvent;
import com.ning.billing.invoice.api.EmptyInvoiceEvent;
import com.ning.billing.invoice.api.InvoiceCreationEvent;
+import com.ning.billing.overdue.OverdueChangeEvent;
import com.ning.billing.payment.api.PaymentErrorEvent;
import com.ning.billing.payment.api.PaymentInfoEvent;
import com.ning.billing.util.tag.api.ControlTagCreationEvent;
@@ -42,16 +43,19 @@ public class AnalyticsListener {
private final BusinessSubscriptionTransitionRecorder bstRecorder;
private final BusinessAccountRecorder bacRecorder;
private final BusinessInvoiceRecorder invoiceRecorder;
+ private final BusinessOverdueStatusRecorder bosRecorder;
private final BusinessTagRecorder tagRecorder;
@Inject
public AnalyticsListener(final BusinessSubscriptionTransitionRecorder bstRecorder,
final BusinessAccountRecorder bacRecorder,
final BusinessInvoiceRecorder invoiceRecorder,
+ final BusinessOverdueStatusRecorder bosRecorder,
final BusinessTagRecorder tagRecorder) {
this.bstRecorder = bstRecorder;
this.bacRecorder = bacRecorder;
this.invoiceRecorder = invoiceRecorder;
+ this.bosRecorder = bosRecorder;
this.tagRecorder = tagRecorder;
}
@@ -109,6 +113,11 @@ public class AnalyticsListener {
}
@Subscribe
+ public void handleOverdueChange(final OverdueChangeEvent changeEvent) {
+ bosRecorder.overdueStatusChanged(changeEvent.getOverdueObjectType(), changeEvent.getOverdueObjectId());
+ }
+
+ @Subscribe
public void handleControlTagCreation(final ControlTagCreationEvent event) {
tagRecorder.tagAdded(event.getObjectType(), event.getObjectId(), event.getTagDefinition().getName());
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java b/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java
index 424e1c2..102fb95 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java
@@ -25,6 +25,7 @@ import com.ning.billing.analytics.model.BusinessAccount;
import com.ning.billing.analytics.model.BusinessAccountTag;
import com.ning.billing.analytics.model.BusinessInvoice;
import com.ning.billing.analytics.model.BusinessInvoiceItem;
+import com.ning.billing.analytics.model.BusinessOverdueStatus;
import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
// Note: not exposed in api yet
@@ -52,6 +53,10 @@ public class DefaultAnalyticsUserApi {
return analyticsDao.getTagsForAccount(accountKey);
}
+ public List<BusinessOverdueStatus> getOverdueStatusesForBundle(final String externalKey) {
+ return analyticsDao.getOverdueStatusesForBundleByKey(externalKey);
+ }
+
public List<BusinessInvoiceItem> getInvoiceItemsForInvoice(final UUID invoiceId) {
return analyticsDao.getInvoiceItemsForInvoice(invoiceId.toString());
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessOverdueStatusRecorder.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessOverdueStatusRecorder.java
new file mode 100644
index 0000000..8ec98d4
--- /dev/null
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessOverdueStatusRecorder.java
@@ -0,0 +1,116 @@
+/*
+ * 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.analytics;
+
+import javax.inject.Inject;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.Transaction;
+import org.skife.jdbi.v2.TransactionStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+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.analytics.dao.BusinessOverdueStatusSqlDao;
+import com.ning.billing.analytics.model.BusinessOverdueStatus;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+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;
+import com.ning.billing.junction.api.BlockingState;
+
+public class BusinessOverdueStatusRecorder {
+ private static final Logger log = LoggerFactory.getLogger(BusinessOverdueStatusRecorder.class);
+
+ private final BusinessOverdueStatusSqlDao overdueStatusSqlDao;
+ private final AccountUserApi accountApi;
+ private final EntitlementUserApi entitlementApi;
+ private final BlockingApi blockingApi;
+
+ @Inject
+ public BusinessOverdueStatusRecorder(final BusinessOverdueStatusSqlDao overdueStatusSqlDao, final AccountUserApi accountApi,
+ final EntitlementUserApi entitlementApi, final BlockingApi blockingApi) {
+ this.overdueStatusSqlDao = overdueStatusSqlDao;
+ this.accountApi = accountApi;
+ this.entitlementApi = entitlementApi;
+ this.blockingApi = blockingApi;
+ }
+
+ public void overdueStatusChanged(final Blockable.Type objectType, final UUID objectId) {
+ if (Blockable.Type.SUBSCRIPTION_BUNDLE.equals(objectType)) {
+ overdueStatusChangedForBundle(objectId);
+ } else {
+ log.info("Ignoring overdue status change for object id {} (type {})", objectId.toString(), objectType.toString());
+ }
+ }
+
+ private void overdueStatusChangedForBundle(final UUID bundleId) {
+ final SubscriptionBundle bundle;
+ try {
+ bundle = entitlementApi.getBundleFromId(bundleId);
+ } catch (EntitlementUserApiException e) {
+ log.warn("Ignoring update for bundle {}: bundle does not exist", bundleId);
+ return;
+ }
+
+ final Account account;
+ try {
+ account = accountApi.getAccountById(bundle.getAccountId());
+ } catch (AccountApiException e) {
+ log.warn("Ignoring update for bundle {}: account {} does not exist", bundleId, bundle.getAccountId());
+ return;
+ }
+
+ final String accountKey = account.getExternalKey();
+ final String externalKey = bundle.getKey();
+
+ overdueStatusSqlDao.inTransaction(new Transaction<Void, BusinessOverdueStatusSqlDao>() {
+ @Override
+ public Void inTransaction(final BusinessOverdueStatusSqlDao transactional, final TransactionStatus status) throws Exception {
+ log.info("Started rebuilding overdue statuses for bundle id {}", bundleId);
+ transactional.deleteOverdueStatusesForBundle(bundleId.toString());
+
+ final SortedSet<BlockingState> blockingHistory = blockingApi.getBlockingHistory(bundleId);
+ if (blockingHistory != null && blockingHistory.size() > 0) {
+ final List<BlockingState> overdueStates = ImmutableList.<BlockingState>copyOf(blockingHistory);
+ final List<BlockingState> overdueStatesReversed = Lists.reverse(overdueStates);
+
+ DateTime previousStartDate = null;
+ for (final BlockingState state : overdueStatesReversed) {
+ final BusinessOverdueStatus overdueStatus = new BusinessOverdueStatus(accountKey, bundleId, previousStartDate,
+ externalKey, state.getTimestamp(), state.getStateName());
+ log.info("Adding overdue state {}", overdueStatus);
+ overdueStatusSqlDao.createOverdueStatus(overdueStatus);
+
+ previousStartDate = state.getTimestamp();
+ }
+ }
+
+ log.info("Finished rebuilding overdue statuses for bundle id {}", bundleId);
+ return null;
+ }
+ });
+ }
+}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java
index 2f0b6db..97d72f2 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java
@@ -22,6 +22,7 @@ import com.ning.billing.analytics.model.BusinessAccount;
import com.ning.billing.analytics.model.BusinessAccountTag;
import com.ning.billing.analytics.model.BusinessInvoice;
import com.ning.billing.analytics.model.BusinessInvoiceItem;
+import com.ning.billing.analytics.model.BusinessOverdueStatus;
import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
public interface AnalyticsDao {
@@ -34,4 +35,6 @@ public interface AnalyticsDao {
List<BusinessAccountTag> getTagsForAccount(final String accountKey);
List<BusinessInvoiceItem> getInvoiceItemsForInvoice(final String invoiceId);
+
+ List<BusinessOverdueStatus> getOverdueStatusesForBundleByKey(final String externalKey);
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessOverdueStatusSqlDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessOverdueStatusSqlDao.java
index 44668d0..b910919 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessOverdueStatusSqlDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessOverdueStatusSqlDao.java
@@ -22,13 +22,15 @@ import org.skife.jdbi.v2.sqlobject.Bind;
import org.skife.jdbi.v2.sqlobject.SqlQuery;
import org.skife.jdbi.v2.sqlobject.SqlUpdate;
import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
import com.ning.billing.analytics.model.BusinessOverdueStatus;
@ExternalizedSqlViaStringTemplate3()
@RegisterMapper(BusinessOverdueStatusMapper.class)
-public interface BusinessOverdueStatusSqlDao {
+public interface BusinessOverdueStatusSqlDao extends Transactional<BusinessOverdueStatusSqlDao>, Transmogrifier {
@SqlQuery
List<BusinessOverdueStatus> getOverdueStatusesForBundle(@Bind("external_key") final String externalKey);
@@ -36,5 +38,8 @@ public interface BusinessOverdueStatusSqlDao {
int createOverdueStatus(@BusinessOverdueStatusBinder final BusinessOverdueStatus status);
@SqlUpdate
+ void deleteOverdueStatusesForBundle(@Bind("bundle_id") final String bundleId);
+
+ @SqlUpdate
void test();
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java
index edbf529..5ab5dbb 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java
@@ -23,6 +23,7 @@ import com.ning.billing.analytics.model.BusinessAccount;
import com.ning.billing.analytics.model.BusinessAccountTag;
import com.ning.billing.analytics.model.BusinessInvoice;
import com.ning.billing.analytics.model.BusinessInvoiceItem;
+import com.ning.billing.analytics.model.BusinessOverdueStatus;
import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
public class DefaultAnalyticsDao implements AnalyticsDao {
@@ -31,18 +32,21 @@ public class DefaultAnalyticsDao implements AnalyticsDao {
private final BusinessInvoiceSqlDao invoiceSqlDao;
private final BusinessInvoiceItemSqlDao invoiceItemSqlDao;
private final BusinessAccountTagSqlDao accountTagSqlDao;
+ private final BusinessOverdueStatusSqlDao overdueStatusSqlDao;
@Inject
public DefaultAnalyticsDao(final BusinessAccountSqlDao accountSqlDao,
final BusinessSubscriptionTransitionSqlDao subscriptionTransitionSqlDao,
final BusinessInvoiceSqlDao invoiceSqlDao,
final BusinessInvoiceItemSqlDao invoiceItemSqlDao,
- final BusinessAccountTagSqlDao accountTagSqlDao) {
+ final BusinessAccountTagSqlDao accountTagSqlDao,
+ final BusinessOverdueStatusSqlDao overdueStatusSqlDao) {
this.accountSqlDao = accountSqlDao;
this.subscriptionTransitionSqlDao = subscriptionTransitionSqlDao;
this.invoiceSqlDao = invoiceSqlDao;
this.invoiceItemSqlDao = invoiceItemSqlDao;
this.accountTagSqlDao = accountTagSqlDao;
+ this.overdueStatusSqlDao = overdueStatusSqlDao;
}
@Override
@@ -69,4 +73,9 @@ public class DefaultAnalyticsDao implements AnalyticsDao {
public List<BusinessInvoiceItem> getInvoiceItemsForInvoice(final String invoiceId) {
return invoiceItemSqlDao.getInvoiceItemsForInvoice(invoiceId);
}
+
+ @Override
+ public List<BusinessOverdueStatus> getOverdueStatusesForBundleByKey(final String externalKey) {
+ return overdueStatusSqlDao.getOverdueStatusesForBundle(externalKey);
+ }
}
diff --git a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessOverdueStatusSqlDao.sql.stg b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessOverdueStatusSqlDao.sql.stg
index a785959..fddafdb 100644
--- a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessOverdueStatusSqlDao.sql.stg
+++ b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessOverdueStatusSqlDao.sql.stg
@@ -32,6 +32,10 @@ insert into bos (
);
>>
+deleteOverdueStatusesForBundle(bundle_id) ::= <<
+delete from bos where bundle_id = :bundle_id;
+>>
+
test() ::= <<
select 1 from bos;
>>
diff --git a/api/src/main/java/com/ning/billing/overdue/OverdueChangeEvent.java b/api/src/main/java/com/ning/billing/overdue/OverdueChangeEvent.java
index 5b6aa57..daa731d 100644
--- a/api/src/main/java/com/ning/billing/overdue/OverdueChangeEvent.java
+++ b/api/src/main/java/com/ning/billing/overdue/OverdueChangeEvent.java
@@ -22,12 +22,11 @@ import com.ning.billing.junction.api.Blockable;
import com.ning.billing.util.bus.BusEvent;
public interface OverdueChangeEvent extends BusEvent {
-
UUID getOverdueObjectId();
-
+
Blockable.Type getOverdueObjectType();
-
+
String getPreviousOverdueStateName();
-
+
String getNextOverdueStateName();
}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java
index 9d4b29a..a9b9e76 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestAnalytics.java
@@ -16,6 +16,8 @@
package com.ning.billing.beatrix.integration;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;
@@ -50,8 +52,10 @@ import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.overdue.config.OverdueConfig;
import com.ning.billing.util.api.TagApiException;
import com.ning.billing.util.api.TagDefinitionApiException;
+import com.ning.billing.util.config.XMLLoader;
import com.ning.billing.util.dao.ObjectType;
import com.ning.billing.util.tag.TagDefinition;
@@ -63,6 +67,53 @@ public class TestAnalytics extends TestIntegrationBase {
@BeforeMethod(groups = "slow")
public void setUpAnalyticsHandler() throws Exception {
+ final String configXml = "<overdueConfig>" +
+ " <bundleOverdueStates>" +
+ " <state name=\"OD3\">" +
+ " <condition>" +
+ " <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+ " <unit>DAYS</unit><number>50</number>" +
+ " </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+ " </condition>" +
+ " <externalMessage>Reached OD3</externalMessage>" +
+ " <blockChanges>true</blockChanges>" +
+ " <disableEntitlementAndChangesBlocked>true</disableEntitlementAndChangesBlocked>" +
+ " <autoReevaluationInterval>" +
+ " <unit>DAYS</unit><number>5</number>" +
+ " </autoReevaluationInterval>" +
+ " </state>" +
+ " <state name=\"OD2\">" +
+ " <condition>" +
+ " <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+ " <unit>DAYS</unit><number>40</number>" +
+ " </timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+ " </condition>" +
+ " <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>";
+ final InputStream is = new ByteArrayInputStream(configXml.getBytes());
+ final OverdueConfig config = XMLLoader.getObjectFromStreamNoValidation(is, OverdueConfig.class);
+ overdueWrapperFactory.setOverdueConfig(config);
+
busService.getBus().register(analyticsListener);
}
@@ -131,6 +182,105 @@ public class TestAnalytics extends TestIntegrationBase {
verifyChangePlan(account, bundle, subscription);
}
+ @Test(groups = "slow")
+ public void testOverdue() throws Exception {
+ paymentPlugin.makeAllInvoicesFailWithError(true);
+
+ // Create an account
+ final Account account = verifyAccountCreation();
+
+ // Create a bundle
+ final SubscriptionBundle bundle = verifyFirstBundle(account);
+
+ // Add a subscription
+ busHandler.pushExpectedEvents(TestApiListener.NextEvent.CREATE, TestApiListener.NextEvent.INVOICE);
+ final Subscription subscription = verifyFirstSubscription(account, bundle);
+ assertTrue(busHandler.isCompleted(DELAY));
+
+ // Verify the initial overdue status
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).size(), 0);
+
+ // Move after trial
+ busHandler.pushExpectedEvents(TestApiListener.NextEvent.PHASE, TestApiListener.NextEvent.INVOICE, TestApiListener.NextEvent.PAYMENT_ERROR);
+ clock.addDays(30); // DAY 30 have to get out of trial before first payment
+ Assert.assertTrue(busHandler.isCompleted(DELAY));
+
+ // Check BST - nothing should have changed
+ verifyBSTWithTrialAndEvergreenPhases(account, bundle, subscription);
+
+ // Verify overdue status - we should still be in clear state
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).size(), 0);
+
+ clock.addDays(15); // DAY 45 - 15 days after invoice
+ assertTrue(busHandler.isCompleted(DELAY));
+
+ // Check BST - nothing should have changed
+ verifyBSTWithTrialAndEvergreenPhases(account, bundle, subscription);
+
+ // Verify overdue status - we should still be in clear state
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).size(), 0);
+
+ busHandler.pushExpectedEvents(TestApiListener.NextEvent.INVOICE, TestApiListener.NextEvent.PAYMENT_ERROR);
+ clock.addDays(20); // DAY 65 - 35 days after invoice
+ assertTrue(busHandler.isCompleted(DELAY));
+ waitALittle();
+
+ // Verify overdue status - we should be in OD1
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).size(), 1);
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getStatus(), "OD1");
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getBundleId(), bundle.getId());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getExternalKey(), bundle.getKey());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getAccountKey(), account.getExternalKey());
+
+ clock.addDays(2); // DAY 67 - 37 days after invoice
+ assertTrue(busHandler.isCompleted(DELAY));
+ waitALittle();
+ // Verify overdue status - we should still be in OD1
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).size(), 1);
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getStatus(), "OD1");
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getBundleId(), bundle.getId());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getExternalKey(), bundle.getKey());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getAccountKey(), account.getExternalKey());
+
+ clock.addDays(8); // DAY 75 - 45 days after invoice
+ assertTrue(busHandler.isCompleted(DELAY));
+ waitALittle();
+ // Verify overdue status - we should be in OD2
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).size(), 2);
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getStatus(), "OD1");
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(1).getStatus(), "OD2");
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getEndDate(),
+ analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(1).getStartDate());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getBundleId(), bundle.getId());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getExternalKey(), bundle.getKey());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getAccountKey(), account.getExternalKey());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(1).getBundleId(), bundle.getId());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(1).getExternalKey(), bundle.getKey());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(1).getAccountKey(), account.getExternalKey());
+
+ clock.addDays(10); // DAY 85 - 55 days after invoice
+ assertTrue(busHandler.isCompleted(DELAY));
+ waitALittle();
+ // Verify overdue status - we should be in OD3
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).size(), 3);
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getStatus(), "OD1");
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(1).getStatus(), "OD2");
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(2).getStatus(), "OD3");
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getEndDate(),
+ analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(1).getStartDate());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(1).getEndDate(),
+ analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(2).getStartDate());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getBundleId(), bundle.getId());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getExternalKey(), bundle.getKey());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(0).getAccountKey(), account.getExternalKey());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(1).getBundleId(), bundle.getId());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(1).getExternalKey(), bundle.getKey());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(1).getAccountKey(), account.getExternalKey());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(2).getBundleId(), bundle.getId());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(2).getExternalKey(), bundle.getKey());
+ Assert.assertEquals(analyticsUserApi.getOverdueStatusesForBundle(bundle.getKey()).get(2).getAccountKey(), account.getExternalKey());
+ }
+
private Account verifyAccountCreation() throws Exception {
final AccountData accountData = getAccountData(1);
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 fbf4a68..7aeaa80 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
@@ -33,6 +33,7 @@ import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import com.google.inject.Inject;
+import com.google.inject.name.Named;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountData;
import com.ning.billing.account.api.AccountService;
@@ -56,8 +57,10 @@ import com.ning.billing.invoice.api.InvoiceService;
import com.ning.billing.invoice.api.InvoiceUserApi;
import com.ning.billing.invoice.model.InvoicingConfiguration;
import com.ning.billing.junction.plumbing.api.BlockingSubscription;
+import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
import com.ning.billing.payment.api.PaymentApi;
import com.ning.billing.payment.api.PaymentMethodPlugin;
+import com.ning.billing.payment.provider.MockPaymentProviderPlugin;
import com.ning.billing.util.api.TagUserApi;
import com.ning.billing.util.bus.BusService;
import com.ning.billing.util.callcontext.CallContext;
@@ -124,6 +127,13 @@ public class TestIntegrationBase implements TestListenerStatus {
@Inject
protected PaymentApi paymentApi;
+ @Named(BeatrixModule.PLUGIN_NAME)
+ @Inject
+ protected MockPaymentProviderPlugin paymentPlugin;
+
+ @Inject
+ protected OverdueWrapperFactory overdueWrapperFactory;
+
@Inject
protected AccountUserApi accountUserApi;