killbill-memoizeit
Changes
analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java 54(+37 -17)
analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java 3(+2 -1)
analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransition.java 31(+16 -15)
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 4daeb39..247a438 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
@@ -25,6 +25,7 @@ import com.ning.billing.entitlement.api.timeline.RepairEntitlementEvent;
import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.RequestedSubscriptionEvent;
+import com.ning.billing.entitlement.api.user.SubscriptionEvent;
import com.ning.billing.invoice.api.EmptyInvoiceEvent;
import com.ning.billing.invoice.api.InvoiceCreationEvent;
import com.ning.billing.payment.api.PaymentErrorEvent;
@@ -56,38 +57,14 @@ public class AnalyticsListener {
}
@Subscribe
- public void handleSubscriptionTransitionChange(final EffectiveSubscriptionEvent eventEffective) throws AccountApiException, EntitlementUserApiException {
- switch (eventEffective.getTransitionType()) {
- // A subscription enters either through migration or as newly created subscription
- case MIGRATE_ENTITLEMENT:
- case CREATE:
- bstRecorder.subscriptionCreated(eventEffective);
- break;
- case RE_CREATE:
- bstRecorder.subscriptionRecreated(eventEffective);
- break;
- case MIGRATE_BILLING:
- break;
- case CANCEL:
- bstRecorder.subscriptionCancelled(eventEffective);
- break;
- case CHANGE:
- bstRecorder.subscriptionChanged(eventEffective);
- break;
- case UNCANCEL:
- break;
- case PHASE:
- bstRecorder.subscriptionPhaseChanged(eventEffective);
- break;
- default:
- throw new RuntimeException("Unexpected event type " + eventEffective.getTransitionType());
- }
+ public void handleEffectiveSubscriptionTransitionChange(final EffectiveSubscriptionEvent eventEffective) throws AccountApiException, EntitlementUserApiException {
+ handleSubscriptionTransitionChange(eventEffective);
}
@Subscribe
- public void handleFutureSubscriptionTransitionChange(final RequestedSubscriptionEvent eventRequested) throws AccountApiException, EntitlementUserApiException {
+ public void handleRequestedSubscriptionTransitionChange(final RequestedSubscriptionEvent eventRequested) throws AccountApiException, EntitlementUserApiException {
if (eventRequested.getEffectiveTransitionTime().isAfter(eventRequested.getRequestedTransitionTime())) {
- bstRecorder.subscriptionChanged(eventRequested);
+ handleSubscriptionTransitionChange(eventRequested);
}
}
@@ -169,4 +146,32 @@ public class AnalyticsListener {
public void handleRepairEntitlement(final RepairEntitlementEvent event) {
// Ignored for now
}
+
+ private void handleSubscriptionTransitionChange(final SubscriptionEvent eventEffective) throws AccountApiException, EntitlementUserApiException {
+ switch (eventEffective.getTransitionType()) {
+ // A subscription enters either through migration or as newly created subscription
+ case MIGRATE_ENTITLEMENT:
+ case CREATE:
+ bstRecorder.subscriptionCreated(eventEffective);
+ break;
+ case RE_CREATE:
+ bstRecorder.subscriptionRecreated(eventEffective);
+ break;
+ case MIGRATE_BILLING:
+ break;
+ case CANCEL:
+ bstRecorder.subscriptionCancelled(eventEffective);
+ break;
+ case CHANGE:
+ bstRecorder.subscriptionChanged(eventEffective);
+ break;
+ case UNCANCEL:
+ break;
+ case PHASE:
+ bstRecorder.subscriptionPhaseChanged(eventEffective);
+ break;
+ default:
+ throw new RuntimeException("Unexpected event type " + eventEffective.getTransitionType());
+ }
+ }
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
index b5a1b68..b27c056 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
@@ -19,6 +19,8 @@ package com.ning.billing.analytics;
import java.util.List;
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;
@@ -32,10 +34,8 @@ import com.ning.billing.analytics.model.BusinessSubscriptionEvent;
import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
-import com.ning.billing.entitlement.api.user.RequestedSubscriptionEvent;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.entitlement.api.user.SubscriptionEvent;
@@ -55,34 +55,28 @@ public class BusinessSubscriptionTransitionRecorder {
this.accountApi = accountApi;
}
- public void subscriptionCreated(final EffectiveSubscriptionEvent created) throws AccountApiException, EntitlementUserApiException {
+ public void subscriptionCreated(final SubscriptionEvent created) throws AccountApiException, EntitlementUserApiException {
final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionCreated(created.getNextPlan(), catalogService.getFullCatalog(), created.getEffectiveTransitionTime(), created.getSubscriptionStartDate());
recordTransition(event, created);
}
- public void subscriptionRecreated(final EffectiveSubscriptionEvent recreated) throws AccountApiException, EntitlementUserApiException {
+ public void subscriptionRecreated(final SubscriptionEvent recreated) throws AccountApiException, EntitlementUserApiException {
final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionRecreated(recreated.getNextPlan(), catalogService.getFullCatalog(), recreated.getEffectiveTransitionTime(), recreated.getSubscriptionStartDate());
recordTransition(event, recreated);
}
- public void subscriptionCancelled(final EffectiveSubscriptionEvent cancelled) throws AccountApiException, EntitlementUserApiException {
+ public void subscriptionCancelled(final SubscriptionEvent cancelled) throws AccountApiException, EntitlementUserApiException {
// cancelled.getNextPlan() is null here - need to look at the previous one to create the correct event name
final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionCancelled(cancelled.getPreviousPlan(), catalogService.getFullCatalog(), cancelled.getEffectiveTransitionTime(), cancelled.getSubscriptionStartDate());
recordTransition(event, cancelled);
}
- public void subscriptionChanged(final RequestedSubscriptionEvent changed) throws EntitlementUserApiException, AccountApiException {
- // Future change
+ public void subscriptionChanged(final SubscriptionEvent changed) throws AccountApiException, EntitlementUserApiException {
final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionChanged(changed.getNextPlan(), catalogService.getFullCatalog(), changed.getEffectiveTransitionTime(), changed.getSubscriptionStartDate());
recordTransition(event, changed);
}
- public void subscriptionChanged(final EffectiveSubscriptionEvent changed) throws AccountApiException, EntitlementUserApiException {
- final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionChanged(changed.getNextPlan(), catalogService.getFullCatalog(), changed.getEffectiveTransitionTime(), changed.getSubscriptionStartDate());
- recordTransition(event, changed);
- }
-
- public void subscriptionPhaseChanged(final EffectiveSubscriptionEvent phaseChanged) throws AccountApiException, EntitlementUserApiException {
+ public void subscriptionPhaseChanged(final SubscriptionEvent phaseChanged) throws AccountApiException, EntitlementUserApiException {
final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionPhaseChanged(phaseChanged.getNextPlan(), phaseChanged.getNextState(), catalogService.getFullCatalog(), phaseChanged.getEffectiveTransitionTime(), phaseChanged.getSubscriptionStartDate());
recordTransition(event, phaseChanged);
}
@@ -111,9 +105,10 @@ public class BusinessSubscriptionTransitionRecorder {
if (event.getEventType() != BusinessSubscriptionEvent.EventType.ADD) {
final List<BusinessSubscriptionTransition> transitions = sqlDao.getTransitions(externalKey);
if (transitions != null && transitions.size() > 0) {
- final BusinessSubscriptionTransition lastTransition = transitions.get(transitions.size() - 1);
- if (lastTransition != null && lastTransition.getNextSubscription() != null) {
- previousEffectiveTransitionTime = lastTransition.getNextSubscription().getStartDate();
+ for (final BusinessSubscriptionTransition candidate : transitions) {
+ if (candidate != null && candidate.getNextSubscription() != null && candidate.getNextSubscription().getStartDate().isBefore(transition.getEffectiveTransitionTime())) {
+ previousEffectiveTransitionTime = candidate.getNextSubscription().getStartDate();
+ }
}
}
}
@@ -178,6 +173,31 @@ public class BusinessSubscriptionTransitionRecorder {
);
log.info(transition.getEvent() + " " + transition);
- sqlDao.createTransition(transition);
+ sqlDao.inTransaction(new Transaction<Void, BusinessSubscriptionTransitionSqlDao>() {
+ @Override
+ public Void inTransaction(final BusinessSubscriptionTransitionSqlDao transactional, final TransactionStatus status) throws Exception {
+ final String subscriptionId;
+ if (nextSubscription.getSubscriptionId() != null) {
+ subscriptionId = nextSubscription.getSubscriptionId().toString();
+ } else {
+ subscriptionId = prevSubscription.getSubscriptionId().toString();
+ }
+
+ // Ignore duplicates: for e.g. phase events, we may already have recorded the transition when the change
+ // was requested. In that case, ignore it
+ final List<BusinessSubscriptionTransition> currentTransitions = transactional.getTransitionForSubscription(subscriptionId);
+ if (currentTransitions != null && currentTransitions.size() > 0) {
+ for (final BusinessSubscriptionTransition currentTransition : currentTransitions) {
+ if (currentTransition.isDuplicateOf(transition)) {
+ return null;
+ }
+ }
+ }
+
+ transactional.createTransition(transition);
+
+ return null;
+ }
+ });
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java
index 9e35630..5b2838c 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java
@@ -22,13 +22,14 @@ 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.stringtemplate.ExternalizedSqlViaStringTemplate3;
import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
@ExternalizedSqlViaStringTemplate3()
@RegisterMapper(BusinessSubscriptionTransitionMapper.class)
-public interface BusinessSubscriptionTransitionSqlDao {
+public interface BusinessSubscriptionTransitionSqlDao extends Transactional<BusinessSubscriptionTransitionSqlDao> {
@SqlQuery
List<BusinessSubscriptionTransition> getTransitions(@Bind("external_key") final String externalKey);
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransition.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransition.java
index 3618b7d..2e2a6ce 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransition.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransition.java
@@ -112,15 +112,28 @@ public class BusinessSubscriptionTransition {
final BusinessSubscriptionTransition that = (BusinessSubscriptionTransition) o;
+ return totalOrdering == that.totalOrdering && isDuplicateOf(that);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) (totalOrdering ^ (totalOrdering >>> 32));
+ result = 31 * result + (externalKey != null ? externalKey.hashCode() : 0);
+ result = 31 * result + (accountKey != null ? accountKey.hashCode() : 0);
+ result = 31 * result + (requestedTimestamp != null ? requestedTimestamp.hashCode() : 0);
+ result = 31 * result + (event != null ? event.hashCode() : 0);
+ result = 31 * result + (previousSubscription != null ? previousSubscription.hashCode() : 0);
+ result = 31 * result + (nextSubscription != null ? nextSubscription.hashCode() : 0);
+ return result;
+ }
+
+ public boolean isDuplicateOf(final BusinessSubscriptionTransition that) {
if (accountKey != null ? !accountKey.equals(that.accountKey) : that.accountKey != null) {
return false;
}
if (event != null ? !event.equals(that.event) : that.event != null) {
return false;
}
- if (totalOrdering != that.totalOrdering) {
- return false;
- }
if (externalKey != null ? !externalKey.equals(that.externalKey) : that.externalKey != null) {
return false;
}
@@ -136,16 +149,4 @@ public class BusinessSubscriptionTransition {
return true;
}
-
- @Override
- public int hashCode() {
- int result = (int) (totalOrdering ^ (totalOrdering >>> 32));
- result = 31 * result + (externalKey != null ? externalKey.hashCode() : 0);
- result = 31 * result + (accountKey != null ? accountKey.hashCode() : 0);
- result = 31 * result + (requestedTimestamp != null ? requestedTimestamp.hashCode() : 0);
- result = 31 * result + (event != null ? event.hashCode() : 0);
- result = 31 * result + (previousSubscription != null ? previousSubscription.hashCode() : 0);
- result = 31 * result + (nextSubscription != null ? nextSubscription.hashCode() : 0);
- return result;
- }
}
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java b/analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java
index 056d28f..d05fa9b 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java
@@ -21,6 +21,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.skife.jdbi.v2.Transaction;
import org.skife.jdbi.v2.sqlobject.Bind;
import com.google.common.collect.ImmutableList;
@@ -58,4 +59,33 @@ public class MockBusinessSubscriptionTransitionSqlDao implements BusinessSubscri
@Override
public void test() {
}
+
+ @Override
+ public void begin() {
+ }
+
+ @Override
+ public void commit() {
+ }
+
+ @Override
+ public void rollback() {
+ }
+
+ @Override
+ public void checkpoint(final String name) {
+ }
+
+ @Override
+ public void release(final String name) {
+ }
+
+ @Override
+ public void rollback(final String name) {
+ }
+
+ @Override
+ public <ReturnType> ReturnType inTransaction(final Transaction<ReturnType, BusinessSubscriptionTransitionSqlDao> func) {
+ return null;
+ }
}
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java b/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
index d43e0dc..e6334fe 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
@@ -98,7 +98,7 @@ public class TestAnalyticsListener extends AnalyticsTestSuite {
final DateTime requestedTransitionTime = effectiveTransitionTime;
final SubscriptionTransitionData firstTransition = createFirstSubscriptionTransition(requestedTransitionTime, effectiveTransitionTime);
final BusinessSubscriptionTransition firstBST = createExpectedFirstBST(firstTransition.getTotalOrdering(), requestedTransitionTime, effectiveTransitionTime);
- listener.handleSubscriptionTransitionChange(new DefaultEffectiveSubscriptionEvent(firstTransition, effectiveTransitionTime));
+ listener.handleEffectiveSubscriptionTransitionChange(new DefaultEffectiveSubscriptionEvent(firstTransition, effectiveTransitionTime));
Assert.assertEquals(dao.getTransitions(EXTERNAL_KEY).size(), 1);
Assert.assertEquals(dao.getTransitions(EXTERNAL_KEY).get(0), firstBST);
@@ -107,7 +107,7 @@ public class TestAnalyticsListener extends AnalyticsTestSuite {
final DateTime requestedCancelTransitionTime = effectiveCancelTransitionTime;
final SubscriptionTransitionData cancelledSubscriptionTransition = createCancelSubscriptionTransition(requestedCancelTransitionTime, effectiveCancelTransitionTime, firstTransition.getNextState());
final BusinessSubscriptionTransition cancelledBST = createExpectedCancelledBST(cancelledSubscriptionTransition.getTotalOrdering(), requestedCancelTransitionTime, effectiveCancelTransitionTime, firstBST.getNextSubscription());
- listener.handleSubscriptionTransitionChange(new DefaultEffectiveSubscriptionEvent(cancelledSubscriptionTransition, effectiveTransitionTime));
+ listener.handleEffectiveSubscriptionTransitionChange(new DefaultEffectiveSubscriptionEvent(cancelledSubscriptionTransition, effectiveTransitionTime));
Assert.assertEquals(dao.getTransitions(EXTERNAL_KEY).size(), 2);
Assert.assertEquals(dao.getTransitions(EXTERNAL_KEY).get(1), cancelledBST);
@@ -116,7 +116,7 @@ public class TestAnalyticsListener extends AnalyticsTestSuite {
final DateTime requestedRecreatedTransitionTime = effectiveRecreatedTransitionTime;
final SubscriptionTransitionData recreatedSubscriptionTransition = createRecreatedSubscriptionTransition(requestedRecreatedTransitionTime, effectiveRecreatedTransitionTime, cancelledSubscriptionTransition.getNextState());
final BusinessSubscriptionTransition recreatedBST = createExpectedRecreatedBST(recreatedSubscriptionTransition.getTotalOrdering(), requestedRecreatedTransitionTime, effectiveRecreatedTransitionTime, cancelledBST.getNextSubscription());
- listener.handleSubscriptionTransitionChange(new DefaultEffectiveSubscriptionEvent(recreatedSubscriptionTransition, effectiveTransitionTime));
+ listener.handleEffectiveSubscriptionTransitionChange(new DefaultEffectiveSubscriptionEvent(recreatedSubscriptionTransition, effectiveTransitionTime));
Assert.assertEquals(dao.getTransitions(EXTERNAL_KEY).size(), 3);
Assert.assertEquals(dao.getTransitions(EXTERNAL_KEY).get(2), recreatedBST);
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 4c33fba..4aa125a 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
@@ -38,11 +38,14 @@ import com.ning.billing.analytics.model.BusinessInvoiceItem;
import com.ning.billing.analytics.model.BusinessSubscriptionEvent;
import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
import com.ning.billing.analytics.utils.Rounder;
+import com.ning.billing.api.TestApiListener;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.catalog.api.Product;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.Subscription;
@@ -74,6 +77,16 @@ public class TestAnalytics extends TestIntegrationBase {
// Add a subscription
final Subscription subscription = verifyFirstSubscription(account, bundle);
+
+ // Move after trial
+ clock.addDeltaFromReality(AT_LEAST_ONE_MONTH_MS);
+ busHandler.pushExpectedEvent(TestApiListener.NextEvent.PHASE);
+ busHandler.pushExpectedEvent(TestApiListener.NextEvent.INVOICE);
+ busHandler.pushExpectedEvent(TestApiListener.NextEvent.PAYMENT);
+ Assert.assertTrue(busHandler.isCompleted(DELAY));
+
+ // Check BST - nothing should have changed
+ verifyBSTWithTrialAndEvergreenPhases(account, bundle, subscription);
}
@Test(groups = "slow")
@@ -207,31 +220,76 @@ public class TestAnalytics extends TestIntegrationBase {
waitALittle();
+ // Verify BST
+ verifyBSTWithTrialAndEvergreenPhases(account, bundle, subscription);
+
+ // Make sure the account balance is still zero
+ final BusinessAccount businessAccount = analyticsUserApi.getAccountByKey(account.getExternalKey());
+ Assert.assertEquals(businessAccount.getBalance().doubleValue(), Rounder.round(BigDecimal.ZERO));
+ Assert.assertEquals(businessAccount.getTotalInvoiceBalance().doubleValue(), Rounder.round(BigDecimal.ZERO));
+
+ // The account should have one invoice for the trial phase
+ final List<BusinessInvoice> invoices = analyticsUserApi.getInvoicesForAccount(account.getExternalKey());
+ Assert.assertEquals(invoices.size(), 1);
+ final BusinessInvoice invoice = invoices.get(0);
+ Assert.assertEquals(invoice.getBalance().doubleValue(), 0.0);
+ Assert.assertEquals(invoice.getAmountCharged().doubleValue(), 0.0);
+ Assert.assertEquals(invoice.getAmountCredited().doubleValue(), 0.0);
+ Assert.assertEquals(invoice.getAmountPaid().doubleValue(), 0.0);
+ Assert.assertEquals(invoice.getCurrency(), account.getCurrency());
+
+ // The invoice should have a single item associated to it
+ final List<BusinessInvoiceItem> invoiceItems = analyticsUserApi.getInvoiceItemsForInvoice(invoice.getInvoiceId());
+ Assert.assertEquals(invoiceItems.size(), 1);
+ final BusinessInvoiceItem invoiceItem = invoiceItems.get(0);
+ Assert.assertEquals(invoiceItem.getAmount().doubleValue(), 0.0);
+ // No billing period for the trial item
+ Assert.assertEquals(invoiceItem.getBillingPeriod(), subscription.getCurrentPhase().getBillingPeriod().toString());
+ Assert.assertEquals(invoiceItem.getCurrency(), account.getCurrency());
+ // The subscription end date is null (evergreen)
+ Assert.assertEquals(invoiceItem.getEndDate(), subscription.getStartDate().plus(subscription.getCurrentPhase().getDuration().toJodaPeriod()));
+ Assert.assertEquals(invoiceItem.getExternalKey(), bundle.getKey());
+ Assert.assertEquals(invoiceItem.getInvoiceId(), invoice.getInvoiceId());
+ Assert.assertEquals(invoiceItem.getItemType(), "FIXED");
+ Assert.assertEquals(invoiceItem.getPhase(), subscription.getCurrentPhase().getPhaseType().toString());
+ Assert.assertEquals(invoiceItem.getProductCategory(), subscription.getCurrentPlan().getProduct().getCategory().toString());
+ Assert.assertEquals(invoiceItem.getProductName(), subscription.getCurrentPlan().getProduct().getName());
+ Assert.assertEquals(invoiceItem.getProductType(), subscription.getCurrentPlan().getProduct().getCatalogName());
+ Assert.assertEquals(invoiceItem.getSlug(), subscription.getCurrentPhase().getName());
+ Assert.assertEquals(invoiceItem.getStartDate(), subscription.getStartDate());
+
+ return subscription;
+ }
+
+ private void verifyBSTWithTrialAndEvergreenPhases(final Account account, final SubscriptionBundle bundle, final Subscription subscription) throws CatalogApiException {
// BST should have two transitions
final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
Assert.assertEquals(transitions.size(), 2);
+ final Plan currentPlan = subscription.getCurrentPlan();
+ final Product currentProduct = currentPlan.getProduct();
+
// Check the first transition (into trial phase)
final BusinessSubscriptionTransition initialTransition = transitions.get(0);
Assert.assertEquals(initialTransition.getExternalKey(), bundle.getKey());
Assert.assertEquals(initialTransition.getAccountKey(), account.getExternalKey());
- Assert.assertEquals(initialTransition.getEvent().getCategory(), phaseSpecifier.getProductCategory());
+ Assert.assertEquals(initialTransition.getEvent().getCategory(), currentProduct.getCategory());
Assert.assertEquals(initialTransition.getEvent().getEventType(), BusinessSubscriptionEvent.EventType.ADD);
// This is the first transition
Assert.assertNull(initialTransition.getPreviousSubscription());
- Assert.assertEquals(initialTransition.getNextSubscription().getBillingPeriod(), subscription.getCurrentPhase().getBillingPeriod().toString());
+ Assert.assertEquals(initialTransition.getNextSubscription().getBillingPeriod(), BillingPeriod.NO_BILLING_PERIOD.toString());
Assert.assertEquals(initialTransition.getNextSubscription().getBundleId(), subscription.getBundleId());
Assert.assertEquals(initialTransition.getNextSubscription().getCurrency(), account.getCurrency().toString());
- Assert.assertEquals(initialTransition.getNextSubscription().getPhase(), subscription.getCurrentPhase().getPhaseType().toString());
+ Assert.assertEquals(initialTransition.getNextSubscription().getPhase(), PhaseType.TRIAL.toString());
// Trial: fixed price of zero
- Assert.assertEquals(initialTransition.getNextSubscription().getPrice().doubleValue(), subscription.getCurrentPhase().getFixedPrice().getPrice(account.getCurrency()).doubleValue());
+ Assert.assertEquals(initialTransition.getNextSubscription().getPrice().doubleValue(), (double) 0);
Assert.assertEquals(initialTransition.getNextSubscription().getPriceList(), subscription.getCurrentPriceList().getName());
- Assert.assertEquals(initialTransition.getNextSubscription().getProductCategory(), subscription.getCurrentPlan().getProduct().getCategory());
- Assert.assertEquals(initialTransition.getNextSubscription().getProductName(), subscription.getCurrentPlan().getProduct().getName());
- Assert.assertEquals(initialTransition.getNextSubscription().getProductType(), subscription.getCurrentPlan().getProduct().getCatalogName());
- Assert.assertEquals(initialTransition.getNextSubscription().getSlug(), subscription.getCurrentPhase().getName());
+ Assert.assertEquals(initialTransition.getNextSubscription().getProductCategory(), currentProduct.getCategory());
+ Assert.assertEquals(initialTransition.getNextSubscription().getProductName(), currentProduct.getName());
+ Assert.assertEquals(initialTransition.getNextSubscription().getProductType(), currentProduct.getCatalogName());
+ Assert.assertEquals(initialTransition.getNextSubscription().getSlug(), currentProduct.getName().toLowerCase() + "-monthly-trial");
Assert.assertEquals(initialTransition.getNextSubscription().getStartDate(), subscription.getStartDate());
Assert.assertEquals(initialTransition.getNextSubscription().getState(), subscription.getState());
Assert.assertEquals(initialTransition.getNextSubscription().getSubscriptionId(), subscription.getId());
@@ -240,63 +298,27 @@ public class TestAnalytics extends TestIntegrationBase {
final BusinessSubscriptionTransition futureTransition = transitions.get(1);
Assert.assertEquals(futureTransition.getExternalKey(), bundle.getKey());
Assert.assertEquals(futureTransition.getAccountKey(), account.getExternalKey());
- Assert.assertEquals(futureTransition.getEvent().getCategory(), phaseSpecifier.getProductCategory());
- Assert.assertEquals(futureTransition.getEvent().getEventType(), BusinessSubscriptionEvent.EventType.CHANGE);
+ Assert.assertEquals(futureTransition.getEvent().getCategory(), currentProduct.getCategory());
+ Assert.assertEquals(futureTransition.getEvent().getEventType(), BusinessSubscriptionEvent.EventType.SYSTEM_CHANGE);
Assert.assertEquals(futureTransition.getPreviousSubscription(), initialTransition.getNextSubscription());
- Assert.assertEquals(futureTransition.getNextSubscription().getBillingPeriod(), term.toString());
+ // The billing period should have changed (NO_BILLING_PERIOD for the trial period)
+ Assert.assertEquals(futureTransition.getNextSubscription().getBillingPeriod(), BillingPeriod.MONTHLY.toString());
Assert.assertEquals(futureTransition.getNextSubscription().getBundleId(), subscription.getBundleId());
Assert.assertEquals(initialTransition.getNextSubscription().getCurrency(), account.getCurrency().toString());
// From trial to evergreen
Assert.assertEquals(futureTransition.getNextSubscription().getPhase(), PhaseType.EVERGREEN.toString());
Assert.assertTrue(futureTransition.getNextSubscription().getPrice().doubleValue() > 0);
Assert.assertEquals(futureTransition.getNextSubscription().getPriceList(), subscription.getCurrentPriceList().getName());
- Assert.assertEquals(futureTransition.getNextSubscription().getProductCategory(), subscription.getCurrentPlan().getProduct().getCategory());
- Assert.assertEquals(futureTransition.getNextSubscription().getProductName(), subscription.getCurrentPlan().getProduct().getName());
- Assert.assertEquals(futureTransition.getNextSubscription().getProductType(), subscription.getCurrentPlan().getProduct().getCatalogName());
- Assert.assertEquals(futureTransition.getNextSubscription().getSlug(), subscription.getCurrentPhase().getName().replace("-trial", "-evergreen"));
+ Assert.assertEquals(futureTransition.getNextSubscription().getProductCategory(), currentProduct.getCategory());
+ Assert.assertEquals(futureTransition.getNextSubscription().getProductName(), currentProduct.getName());
+ Assert.assertEquals(futureTransition.getNextSubscription().getProductType(), currentProduct.getCatalogName());
+ Assert.assertEquals(futureTransition.getNextSubscription().getSlug(), currentProduct.getName().toLowerCase() + "-monthly-evergreen");
// 30 days trial
Assert.assertEquals(futureTransition.getNextSubscription().getStartDate(), subscription.getStartDate().plusDays(30));
Assert.assertEquals(futureTransition.getNextSubscription().getState(), subscription.getState());
Assert.assertEquals(futureTransition.getNextSubscription().getSubscriptionId(), subscription.getId());
-
- // Make sure the account balance is still zero
- final BusinessAccount businessAccount = analyticsUserApi.getAccountByKey(account.getExternalKey());
- Assert.assertEquals(businessAccount.getBalance().doubleValue(), Rounder.round(BigDecimal.ZERO));
- Assert.assertEquals(businessAccount.getTotalInvoiceBalance().doubleValue(), Rounder.round(BigDecimal.ZERO));
-
- // The account should have one invoice for the trial phase
- final List<BusinessInvoice> invoices = analyticsUserApi.getInvoicesForAccount(account.getExternalKey());
- Assert.assertEquals(invoices.size(), 1);
- final BusinessInvoice invoice = invoices.get(0);
- Assert.assertEquals(invoice.getBalance().doubleValue(), 0.0);
- Assert.assertEquals(invoice.getAmountCharged().doubleValue(), 0.0);
- Assert.assertEquals(invoice.getAmountCredited().doubleValue(), 0.0);
- Assert.assertEquals(invoice.getAmountPaid().doubleValue(), 0.0);
- Assert.assertEquals(invoice.getCurrency(), account.getCurrency());
-
- // The invoice should have a single item associated to it
- final List<BusinessInvoiceItem> invoiceItems = analyticsUserApi.getInvoiceItemsForInvoice(invoice.getInvoiceId());
- Assert.assertEquals(invoiceItems.size(), 1);
- final BusinessInvoiceItem invoiceItem = invoiceItems.get(0);
- Assert.assertEquals(invoiceItem.getAmount().doubleValue(), 0.0);
- // No billing period for the trial item
- Assert.assertEquals(invoiceItem.getBillingPeriod(), subscription.getCurrentPhase().getBillingPeriod().toString());
- Assert.assertEquals(invoiceItem.getCurrency(), account.getCurrency());
- // The subscription end date is null (evergreen)
- Assert.assertEquals(invoiceItem.getEndDate(), subscription.getStartDate().plus(subscription.getCurrentPhase().getDuration().toJodaPeriod()));
- Assert.assertEquals(invoiceItem.getExternalKey(), bundle.getKey());
- Assert.assertEquals(invoiceItem.getInvoiceId(), invoice.getInvoiceId());
- Assert.assertEquals(invoiceItem.getItemType(), "FIXED");
- Assert.assertEquals(invoiceItem.getPhase(), subscription.getCurrentPhase().getPhaseType().toString());
- Assert.assertEquals(invoiceItem.getProductCategory(), subscription.getCurrentPlan().getProduct().getCategory().toString());
- Assert.assertEquals(invoiceItem.getProductName(), subscription.getCurrentPlan().getProduct().getName());
- Assert.assertEquals(invoiceItem.getProductType(), subscription.getCurrentPlan().getProduct().getCatalogName());
- Assert.assertEquals(invoiceItem.getSlug(), subscription.getCurrentPhase().getName());
- Assert.assertEquals(invoiceItem.getStartDate(), subscription.getStartDate());
-
- return subscription;
}
private void verifyChangePlan(final Account account, final SubscriptionBundle bundle, final Subscription subscription) throws EntitlementUserApiException, InterruptedException {