killbill-memoizeit
Changes
analytics/pom.xml 1(+0 -1)
analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java 224(+165 -59)
analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldMapper.java 6(+5 -1)
analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldSqlDao.java 3(+2 -1)
analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.java 12(+11 -1)
analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagMapper.java 5(+4 -1)
analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagSqlDao.java 2(+1 -1)
analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransition.java 31(+16 -15)
analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionField.java 29(+20 -9)
analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionTag.java 23(+17 -6)
analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessOverdueStatusSqlDao.sql.stg 5(+4 -1)
analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldSqlDao.sql.stg 5(+4 -1)
analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg 85(+85 -0)
analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagSqlDao.sql.stg 5(+4 -1)
analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessOverdueStatusSqlDao.java 9(+5 -4)
analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessSubscriptionTransitionFieldSqlDao.java 8(+5 -3)
analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessSubscriptionTransitionTagSqlDao.java 8(+5 -3)
analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java 52(+52 -0)
analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionEvent.java 5(+2 -3)
analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransition.java 7(+2 -5)
analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransitionField.java 6(+5 -1)
analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransitionTag.java 10(+8 -2)
analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransitionRecorder.java 41(+16 -25)
entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java 3(+2 -1)
entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java 2(+1 -1)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultRequestedSubscriptionEvent.java 6(+6 -0)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java 8(+4 -4)
entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java 141(+119 -22)
entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java 61(+54 -7)
entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java 15(+8 -7)
entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java 20(+10 -10)
entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java 5(+3 -2)
invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java 35(+23 -12)
invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java 25(+12 -13)
Details
analytics/pom.xml 1(+0 -1)
diff --git a/analytics/pom.xml b/analytics/pom.xml
index ecd27bf..c95818d 100644
--- a/analytics/pom.xml
+++ b/analytics/pom.xml
@@ -117,7 +117,6 @@
<dependency>
<groupId>com.ning.billing</groupId>
<artifactId>killbill-util</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>com.ning.billing</groupId>
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 87a7060..bcddd64 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/AnalyticsListener.java
@@ -24,6 +24,7 @@ import com.ning.billing.account.api.AccountCreationEvent;
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.invoice.api.EmptyInvoiceEvent;
import com.ning.billing.invoice.api.InvoiceCreationEvent;
import com.ning.billing.payment.api.PaymentErrorEvent;
@@ -55,32 +56,19 @@ 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 {
+ bstRecorder.rebuildTransitionsForBundle(eventEffective.getBundleId());
+ }
+
+ @Subscribe
+ public void handleRequestedSubscriptionTransitionChange(final RequestedSubscriptionEvent eventRequested) throws AccountApiException, EntitlementUserApiException {
+ bstRecorder.rebuildTransitionsForBundle(eventRequested.getBundleId());
+ }
+
+ @Subscribe
+ public void handleRepairEntitlement(final RepairEntitlementEvent event) {
+ // In case of repair, just rebuild all transitions
+ bstRecorder.rebuildTransitionsForBundle(event.getBundleId());
}
@Subscribe
@@ -99,6 +87,7 @@ public class AnalyticsListener {
@Subscribe
public void handleInvoiceCreation(final InvoiceCreationEvent event) {
+ // TODO - follow same logic as entitlements to support repair
invoiceRecorder.invoiceCreated(event.getInvoiceId());
}
@@ -156,9 +145,4 @@ public class AnalyticsListener {
public void handleUserTagDefinitionDeletion(final UserTagDefinitionDeletionEvent event) {
// Ignored for now
}
-
- @Subscribe
- public void handleRepairEntitlement(final RepairEntitlementEvent event) {
- // Ignored for now
- }
}
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 49d6a9d..a4c9ff3 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
@@ -16,9 +16,13 @@
package com.ning.billing.analytics;
+import java.util.ArrayList;
import java.util.List;
+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;
@@ -32,10 +36,14 @@ 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.SubscriptionTransitionType;
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.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionEvent;
+import com.ning.billing.util.clock.Clock;
public class BusinessSubscriptionTransitionRecorder {
private static final Logger log = LoggerFactory.getLogger(BusinessSubscriptionTransitionRecorder.class);
@@ -44,94 +52,194 @@ public class BusinessSubscriptionTransitionRecorder {
private final EntitlementUserApi entitlementApi;
private final AccountUserApi accountApi;
private final CatalogService catalogService;
+ private final Clock clock;
@Inject
- public BusinessSubscriptionTransitionRecorder(final BusinessSubscriptionTransitionSqlDao sqlDao, final CatalogService catalogService, final EntitlementUserApi entitlementApi, final AccountUserApi accountApi) {
+ public BusinessSubscriptionTransitionRecorder(final BusinessSubscriptionTransitionSqlDao sqlDao,
+ final CatalogService catalogService,
+ final EntitlementUserApi entitlementApi,
+ final AccountUserApi accountApi,
+ final Clock clock) {
this.sqlDao = sqlDao;
this.catalogService = catalogService;
this.entitlementApi = entitlementApi;
this.accountApi = accountApi;
+ this.clock = clock;
}
+ public void rebuildTransitionsForBundle(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 List<Subscription> subscriptions = entitlementApi.getSubscriptionsForBundle(bundleId);
+
+ final String externalKey = bundle.getKey();
+ final String accountKey = account.getExternalKey();
+ final Currency currency = account.getCurrency();
+
+ sqlDao.inTransaction(new Transaction<Void, BusinessSubscriptionTransitionSqlDao>() {
+ @Override
+ public Void inTransaction(final BusinessSubscriptionTransitionSqlDao transactional, final TransactionStatus status) throws Exception {
+ log.info("Started rebuilding transitions for bundle {}", externalKey);
+ transactional.deleteTransitionsForBundle(externalKey);
+
+ final ArrayList<BusinessSubscriptionTransition> transitions = new ArrayList<BusinessSubscriptionTransition>();
+ for (final Subscription subscription : subscriptions) {
+ for (final EffectiveSubscriptionEvent event : subscription.getAllTransitions()) {
+ final BusinessSubscriptionEvent businessEvent = getBusinessSubscriptionFromEvent(event);
+ if (businessEvent == null) {
+ continue;
+ }
+
+ final BusinessSubscription prevSubscription = createPreviousBusinessSubscription(event, businessEvent, transitions, currency);
+ final BusinessSubscription nextSubscription = createNextBusinessSubscription(event, businessEvent, currency);
+ final BusinessSubscriptionTransition transition = new BusinessSubscriptionTransition(
+ event.getTotalOrdering(),
+ externalKey,
+ accountKey,
+ event.getRequestedTransitionTime(),
+ businessEvent,
+ prevSubscription,
+ nextSubscription
+ );
- public void subscriptionCreated(final EffectiveSubscriptionEvent created) throws AccountApiException, EntitlementUserApiException {
- final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionCreated(created.getNextPlan(), catalogService.getFullCatalog(), created.getEffectiveTransitionTime(), created.getSubscriptionStartDate());
- recordTransition(event, created);
+ transactional.createTransition(transition);
+ transitions.add(transition);
+ log.info("Adding transition {}", transition);
+
+ // We need to manually add the system cancel event
+ if (SubscriptionTransitionType.CANCEL.equals(event.getTransitionType()) &&
+ clock.getUTCNow().isAfter(event.getEffectiveTransitionTime())) {
+ final BusinessSubscriptionTransition systemCancelTransition = new BusinessSubscriptionTransition(
+ event.getTotalOrdering(),
+ externalKey,
+ accountKey,
+ event.getRequestedTransitionTime(),
+ new BusinessSubscriptionEvent(BusinessSubscriptionEvent.EventType.SYSTEM_CANCEL, businessEvent.getCategory()),
+ prevSubscription,
+ nextSubscription
+ );
+ transactional.createTransition(systemCancelTransition);
+ transitions.add(systemCancelTransition);
+ log.info("Adding transition {}", systemCancelTransition);
+ }
+ }
+ }
+
+ log.info("Finished rebuilding transitions for bundle {}", externalKey);
+ return null;
+ }
+ });
}
+ private BusinessSubscriptionEvent getBusinessSubscriptionFromEvent(final SubscriptionEvent event) throws AccountApiException, EntitlementUserApiException {
+ switch (event.getTransitionType()) {
+ // A subscription enters either through migration or as newly created subscription
+ case MIGRATE_ENTITLEMENT:
+ case CREATE:
+ return subscriptionCreated(event);
+ case RE_CREATE:
+ return subscriptionRecreated(event);
+ case CANCEL:
+ return subscriptionCancelled(event);
+ case CHANGE:
+ return subscriptionChanged(event);
+ case PHASE:
+ return subscriptionPhaseChanged(event);
+ // TODO - should we really ignore these?
+ case MIGRATE_BILLING:
+ case UNCANCEL:
+ return null;
+ default:
+ log.warn("Unexpected event type " + event.getTransitionType());
+ return null;
+ }
+ }
- public void subscriptionRecreated(final EffectiveSubscriptionEvent recreated) throws AccountApiException, EntitlementUserApiException {
- final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionRecreated(recreated.getNextPlan(), catalogService.getFullCatalog(), recreated.getEffectiveTransitionTime(), recreated.getSubscriptionStartDate());
- recordTransition(event, recreated);
+ private BusinessSubscriptionEvent subscriptionCreated(final SubscriptionEvent created) throws AccountApiException, EntitlementUserApiException {
+ return BusinessSubscriptionEvent.subscriptionCreated(created.getNextPlan(), catalogService.getFullCatalog(), created.getEffectiveTransitionTime(), created.getSubscriptionStartDate());
}
+ private BusinessSubscriptionEvent subscriptionRecreated(final SubscriptionEvent recreated) throws AccountApiException, EntitlementUserApiException {
+ return BusinessSubscriptionEvent.subscriptionRecreated(recreated.getNextPlan(), catalogService.getFullCatalog(), recreated.getEffectiveTransitionTime(), recreated.getSubscriptionStartDate());
+ }
- public void subscriptionCancelled(final EffectiveSubscriptionEvent cancelled) throws AccountApiException, EntitlementUserApiException {
+ private BusinessSubscriptionEvent 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);
+ return BusinessSubscriptionEvent.subscriptionCancelled(cancelled.getPreviousPlan(), catalogService.getFullCatalog(), cancelled.getEffectiveTransitionTime(), cancelled.getSubscriptionStartDate());
}
+ private BusinessSubscriptionEvent subscriptionChanged(final SubscriptionEvent changed) throws AccountApiException, EntitlementUserApiException {
+ return BusinessSubscriptionEvent.subscriptionChanged(changed.getNextPlan(), catalogService.getFullCatalog(), changed.getEffectiveTransitionTime(), changed.getSubscriptionStartDate());
+ }
- 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);
+ private BusinessSubscriptionEvent subscriptionPhaseChanged(final SubscriptionEvent phaseChanged) throws AccountApiException, EntitlementUserApiException {
+ return BusinessSubscriptionEvent.subscriptionPhaseChanged(phaseChanged.getNextPlan(), phaseChanged.getNextState(), catalogService.getFullCatalog(), phaseChanged.getEffectiveTransitionTime(), phaseChanged.getSubscriptionStartDate());
}
- public void subscriptionPhaseChanged(final EffectiveSubscriptionEvent phaseChanged) throws AccountApiException, EntitlementUserApiException {
- final BusinessSubscriptionEvent event = BusinessSubscriptionEvent.subscriptionPhaseChanged(phaseChanged.getNextPlan(), phaseChanged.getNextState(), catalogService.getFullCatalog(), phaseChanged.getEffectiveTransitionTime(), phaseChanged.getSubscriptionStartDate());
- recordTransition(event, phaseChanged);
+ private BusinessSubscription createNextBusinessSubscription(final EffectiveSubscriptionEvent event, final BusinessSubscriptionEvent businessEvent, final Currency currency) {
+ final BusinessSubscription nextSubscription;
+ if (BusinessSubscriptionEvent.EventType.CANCEL.equals(businessEvent.getEventType()) ||
+ BusinessSubscriptionEvent.EventType.SYSTEM_CANCEL.equals(businessEvent.getEventType())) {
+ nextSubscription = null;
+ } else {
+ nextSubscription = new BusinessSubscription(event.getNextPriceList(), event.getNextPlan(), event.getNextPhase(),
+ currency, event.getEffectiveTransitionTime(), event.getNextState(),
+ event.getSubscriptionId(), event.getBundleId(), catalogService.getFullCatalog());
+ }
+
+ return nextSubscription;
}
- void recordTransition(final BusinessSubscriptionEvent event, final EffectiveSubscriptionEvent transition)
- throws AccountApiException, EntitlementUserApiException {
- Currency currency = null;
- String externalKey = null;
- String accountKey = null;
-
- // Retrieve key and currency via the bundle
- final SubscriptionBundle bundle = entitlementApi.getBundleFromId(transition.getBundleId());
- if (bundle != null) {
- externalKey = bundle.getKey();
-
- final Account account = accountApi.getAccountById(bundle.getAccountId());
- if (account != null) {
- accountKey = account.getExternalKey();
- currency = account.getCurrency();
- }
+ private BusinessSubscription createPreviousBusinessSubscription(final EffectiveSubscriptionEvent event,
+ final BusinessSubscriptionEvent businessEvent,
+ final ArrayList<BusinessSubscriptionTransition> transitions,
+ final Currency currency) {
+ if (BusinessSubscriptionEvent.EventType.ADD.equals(businessEvent.getEventType()) ||
+ BusinessSubscriptionEvent.EventType.RE_ADD.equals(businessEvent.getEventType())) {
+ return null;
}
- // The ISubscriptionTransition interface gives us all the prev/next information we need but the start date
- // of the previous plan. We need to retrieve it from our own transitions table
- DateTime previousEffectiveTransitionTime = null;
- // For creation events, the prev subscription will always be null
- 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();
- }
+ final BusinessSubscriptionTransition prevTransition = getPreviousBusinessSubscriptionTransitionForEvent(event, transitions);
+ return new BusinessSubscription(event.getPreviousPriceList(), event.getPreviousPlan(), event.getPreviousPhase(),
+ currency, prevTransition.getNextSubscription().getStartDate(), event.getPreviousState(),
+ event.getSubscriptionId(), event.getBundleId(), catalogService.getFullCatalog());
+ }
+
+ private BusinessSubscriptionTransition getPreviousBusinessSubscriptionTransitionForEvent(final EffectiveSubscriptionEvent event,
+ final ArrayList<BusinessSubscriptionTransition> transitions) {
+ BusinessSubscriptionTransition transition = null;
+ for (final BusinessSubscriptionTransition candidate : transitions) {
+ final BusinessSubscription nextSubscription = candidate.getNextSubscription();
+ if (nextSubscription == null || !nextSubscription.getStartDate().isBefore(event.getEffectiveTransitionTime())) {
+ continue;
}
- }
- // TODO Support currency changes
- final BusinessSubscription prevSubscription;
- if (previousEffectiveTransitionTime == null) {
- prevSubscription = null;
- } else {
- prevSubscription = new BusinessSubscription(transition.getPreviousPriceList(), transition.getPreviousPlan(), transition.getPreviousPhase(), currency, previousEffectiveTransitionTime, transition.getPreviousState(), transition.getSubscriptionId(), transition.getBundleId(), catalogService.getFullCatalog());
+ if (nextSubscription.getSubscriptionId().equals(event.getSubscriptionId())) {
+ transition = candidate;
+ }
}
- final BusinessSubscription nextSubscription;
- // next plan is null for CANCEL events
- if (transition.getNextPlan() == null) {
- nextSubscription = null;
- } else {
- nextSubscription = new BusinessSubscription(transition.getNextPriceList(), transition.getNextPlan(), transition.getNextPhase(), currency, transition.getEffectiveTransitionTime(), transition.getNextState(), transition.getSubscriptionId(), transition.getBundleId(), catalogService.getFullCatalog());
+ if (transition == null) {
+ log.error("Unable to retrieve the previous transition - THIS SHOULD NEVER HAPPEN");
+ // Fall back to the latest one?
+ transition = transitions.get(transitions.size() - 1);
}
- record(transition.getTotalOrdering(), externalKey, accountKey, transition.getRequestedTransitionTime(), event, prevSubscription, nextSubscription);
+ return transition;
}
// Public for internal reasons
@@ -145,8 +253,6 @@ public class BusinessSubscriptionTransitionRecorder {
prevSubscription,
nextSubscription
);
-
- log.info(transition.getEvent() + " " + transition);
sqlDao.createTransition(transition);
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessTagRecorder.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessTagRecorder.java
index 8aa4343..49c4b2b 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessTagRecorder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessTagRecorder.java
@@ -122,13 +122,22 @@ public class BusinessTagRecorder {
return;
}
+ final Account account;
+ try {
+ account = accountApi.getAccountById(bundle.getAccountId());
+ } catch (AccountApiException e) {
+ log.warn("Ignoring tag addition of {} for bundle id {} and account id {} (account does not exist)", new Object[]{name, objectId.toString(), bundle.getAccountId()});
+ return;
+ }
+
/*
* Note: we store tags associated to bundles, not to subscriptions.
* Subscriptions are in the core of killbill and not exposed in Analytics to avoid a hard dependency
* (i.e. dashboards should not rely on killbill ids).
*/
+ final String accountKey = account.getExternalKey();
final String externalKey = bundle.getKey();
- subscriptionTransitionTagSqlDao.addTag(externalKey, name);
+ subscriptionTransitionTagSqlDao.addTag(accountKey, externalKey, name);
}
private void tagRemovedForBundle(final UUID objectId, final String name) {
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessOverdueStatusBinder.java b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessOverdueStatusBinder.java
index eb1bd9d..1e0575e 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessOverdueStatusBinder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessOverdueStatusBinder.java
@@ -38,6 +38,7 @@ public @interface BusinessOverdueStatusBinder {
public Binder build(final Annotation annotation) {
return new Binder<BusinessOverdueStatusBinder, BusinessOverdueStatus>() {
public void bind(final SQLStatement q, final BusinessOverdueStatusBinder bind, final BusinessOverdueStatus overdueStatus) {
+ q.bind("account_key", overdueStatus.getAccountKey());
q.bind("external_key", overdueStatus.getExternalKey());
q.bind("status", overdueStatus.getStatus());
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessOverdueStatusMapper.java b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessOverdueStatusMapper.java
index dcd6bf2..819c9ab 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessOverdueStatusMapper.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessOverdueStatusMapper.java
@@ -30,10 +30,11 @@ public class BusinessOverdueStatusMapper implements ResultSetMapper<BusinessOver
@Override
public BusinessOverdueStatus map(final int index, final ResultSet r, final StatementContext ctx) throws SQLException {
final String externalKey = r.getString(1);
- final String status = r.getString(2);
- final DateTime startDate = new DateTime(r.getLong(3), DateTimeZone.UTC);
- final DateTime endDate = new DateTime(r.getLong(4), DateTimeZone.UTC);
+ final String accountKey = r.getString(2);
+ final String status = r.getString(3);
+ final DateTime startDate = new DateTime(r.getLong(4), DateTimeZone.UTC);
+ final DateTime endDate = new DateTime(r.getLong(5), DateTimeZone.UTC);
- return new BusinessOverdueStatus(endDate, externalKey, startDate, status);
+ return new BusinessOverdueStatus(accountKey, endDate, externalKey, startDate, status);
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldMapper.java b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldMapper.java
index 68ef0e2..53cfef7 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldMapper.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldMapper.java
@@ -27,6 +27,10 @@ import com.ning.billing.analytics.model.BusinessSubscriptionTransitionField;
public class BusinessSubscriptionTransitionFieldMapper implements ResultSetMapper<BusinessSubscriptionTransitionField> {
@Override
public BusinessSubscriptionTransitionField map(final int index, final ResultSet r, final StatementContext ctx) throws SQLException {
- return new BusinessSubscriptionTransitionField(r.getString(1), r.getString(2), r.getString(3));
+ final String externalKey = r.getString(1);
+ final String accountKey = r.getString(2);
+ final String name = r.getString(3);
+ final String value = r.getString(4);
+ return new BusinessSubscriptionTransitionField(accountKey, externalKey, name, value);
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldSqlDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldSqlDao.java
index d22076e..a316939 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldSqlDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldSqlDao.java
@@ -33,7 +33,8 @@ public interface BusinessSubscriptionTransitionFieldSqlDao {
List<BusinessSubscriptionTransitionField> getFieldsForBusinessSubscriptionTransition(@Bind("external_key") final String externalKey);
@SqlUpdate
- int addField(@Bind("external_key") final String externalKey, @Bind("name") final String name, @Bind("value") final String value);
+ int addField(@Bind("account_key") final String accountKey, @Bind("external_key") final String externalKey,
+ @Bind("name") final String name, @Bind("value") final String value);
@SqlUpdate
int removeField(@Bind("external_key") final String externalKey, @Bind("name") final String name);
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 fe90321..2092d47 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,19 +22,29 @@ 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);
+ @SqlQuery
+ List<BusinessSubscriptionTransition> getTransitionForSubscription(@Bind("subscription_id") final String subscriptionId);
+
@SqlUpdate
int createTransition(@BusinessSubscriptionTransitionBinder final BusinessSubscriptionTransition transition);
@SqlUpdate
+ void updateTransition(@Bind("total_ordering") long totalOrdering, @BusinessSubscriptionTransitionBinder BusinessSubscriptionTransition updatedFirstTransition);
+
+ @SqlUpdate
+ void deleteTransitionsForBundle(@Bind("external_key") final String externalKey);
+
+ @SqlUpdate
void test();
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagMapper.java b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagMapper.java
index 36f7631..47a7be9 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagMapper.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagMapper.java
@@ -27,6 +27,9 @@ import com.ning.billing.analytics.model.BusinessSubscriptionTransitionTag;
public class BusinessSubscriptionTransitionTagMapper implements ResultSetMapper<BusinessSubscriptionTransitionTag> {
@Override
public BusinessSubscriptionTransitionTag map(final int index, final ResultSet r, final StatementContext ctx) throws SQLException {
- return new BusinessSubscriptionTransitionTag(r.getString(1), r.getString(2));
+ final String externalKey = r.getString(1);
+ final String accountKey = r.getString(2);
+ final String name = r.getString(3);
+ return new BusinessSubscriptionTransitionTag(accountKey, externalKey, name);
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagSqlDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagSqlDao.java
index c073a53..094af9a 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagSqlDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagSqlDao.java
@@ -33,7 +33,7 @@ public interface BusinessSubscriptionTransitionTagSqlDao {
List<BusinessSubscriptionTransitionTag> getTagsForBusinessSubscriptionTransition(@Bind("external_key") final String externalKey);
@SqlUpdate
- int addTag(@Bind("external_key") final String externalKey, @Bind("name") final String name);
+ int addTag(@Bind("account_key") final String accountKey, @Bind("external_key") final String externalKey, @Bind("name") final String name);
@SqlUpdate
int removeTag(@Bind("external_key") final String externalKey, @Bind("name") final String name);
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountField.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountField.java
index b990125..3d9df23 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountField.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountField.java
@@ -33,8 +33,8 @@ public class BusinessAccountField extends BusinessField {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessAccountField");
sb.append("{accountKey='").append(accountKey).append('\'');
- sb.append(", name='").append(name).append('\'');
- sb.append(", value='").append(value).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
+ sb.append(", value='").append(getValue()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -53,10 +53,10 @@ public class BusinessAccountField extends BusinessField {
if (accountKey != null ? !accountKey.equals(that.accountKey) : that.accountKey != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
- if (value != null ? !value.equals(that.value) : that.value != null) {
+ if (getValue() != null ? !getValue().equals(that.getValue()) : that.getValue() != null) {
return false;
}
@@ -66,8 +66,8 @@ public class BusinessAccountField extends BusinessField {
@Override
public int hashCode() {
int result = accountKey != null ? accountKey.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
- result = 31 * result + (value != null ? value.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+ result = 31 * result + (getValue() != null ? getValue().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountTag.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountTag.java
index 3a8de99..1461c6d 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountTag.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessAccountTag.java
@@ -33,7 +33,7 @@ public class BusinessAccountTag extends BusinessTag {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessAccountTag");
sb.append("{accountKey='").append(accountKey).append('\'');
- sb.append(", name='").append(name).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -52,7 +52,7 @@ public class BusinessAccountTag extends BusinessTag {
if (accountKey != null ? !accountKey.equals(that.accountKey) : that.accountKey != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
@@ -62,7 +62,7 @@ public class BusinessAccountTag extends BusinessTag {
@Override
public int hashCode() {
int result = accountKey != null ? accountKey.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessField.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessField.java
index 68552d0..5d5e727 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessField.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessField.java
@@ -17,8 +17,8 @@
package com.ning.billing.analytics.model;
public abstract class BusinessField {
- protected final String name;
- protected final String value;
+ private final String name;
+ private final String value;
public BusinessField(final String name, final String value) {
this.name = name;
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceField.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceField.java
index cf69497..d4597f4 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceField.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceField.java
@@ -35,8 +35,8 @@ public class BusinessInvoiceField extends BusinessField {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessInvoiceField");
sb.append("{invoiceId='").append(invoiceId).append('\'');
- sb.append(", name='").append(name).append('\'');
- sb.append(", value='").append(value).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
+ sb.append(", value='").append(getValue()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -55,10 +55,10 @@ public class BusinessInvoiceField extends BusinessField {
if (invoiceId != null ? !invoiceId.equals(that.invoiceId) : that.invoiceId != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
- if (value != null ? !value.equals(that.value) : that.value != null) {
+ if (getValue() != null ? !getValue().equals(that.getValue()) : that.getValue() != null) {
return false;
}
@@ -68,8 +68,8 @@ public class BusinessInvoiceField extends BusinessField {
@Override
public int hashCode() {
int result = invoiceId != null ? invoiceId.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
- result = 31 * result + (value != null ? value.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+ result = 31 * result + (getValue() != null ? getValue().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentField.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentField.java
index bcfc85b..c79b2b1 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentField.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentField.java
@@ -35,8 +35,8 @@ public class BusinessInvoicePaymentField extends BusinessField {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessPaymentField");
sb.append("{paymentId='").append(paymentId).append('\'');
- sb.append(", name='").append(name).append('\'');
- sb.append(", value='").append(value).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
+ sb.append(", value='").append(getValue()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -55,10 +55,10 @@ public class BusinessInvoicePaymentField extends BusinessField {
if (paymentId != null ? !paymentId.equals(that.paymentId) : that.paymentId != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
- if (value != null ? !value.equals(that.value) : that.value != null) {
+ if (getValue() != null ? !getValue().equals(that.getValue()) : that.getValue() != null) {
return false;
}
@@ -68,8 +68,8 @@ public class BusinessInvoicePaymentField extends BusinessField {
@Override
public int hashCode() {
int result = paymentId != null ? paymentId.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
- result = 31 * result + (value != null ? value.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+ result = 31 * result + (getValue() != null ? getValue().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentTag.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentTag.java
index fd48b1c..e1cbbd5 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentTag.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoicePaymentTag.java
@@ -35,7 +35,7 @@ public class BusinessInvoicePaymentTag extends BusinessTag {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessPaymentTag");
sb.append("{paymentId='").append(paymentId).append('\'');
- sb.append(", name='").append(name).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -54,7 +54,7 @@ public class BusinessInvoicePaymentTag extends BusinessTag {
if (paymentId != null ? !paymentId.equals(that.paymentId) : that.paymentId != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
@@ -64,7 +64,7 @@ public class BusinessInvoicePaymentTag extends BusinessTag {
@Override
public int hashCode() {
int result = paymentId != null ? paymentId.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceTag.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceTag.java
index e9efe5a..41b7d27 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceTag.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessInvoiceTag.java
@@ -35,7 +35,7 @@ public class BusinessInvoiceTag extends BusinessTag {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessInvoiceTag");
sb.append("{paymentId='").append(invoiceId).append('\'');
- sb.append(", name='").append(name).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -54,7 +54,7 @@ public class BusinessInvoiceTag extends BusinessTag {
if (invoiceId != null ? !invoiceId.equals(that.invoiceId) : that.invoiceId != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
@@ -64,7 +64,7 @@ public class BusinessInvoiceTag extends BusinessTag {
@Override
public int hashCode() {
int result = invoiceId != null ? invoiceId.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessOverdueStatus.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessOverdueStatus.java
index dd8a310..e76a02e 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessOverdueStatus.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessOverdueStatus.java
@@ -19,18 +19,25 @@ package com.ning.billing.analytics.model;
import org.joda.time.DateTime;
public class BusinessOverdueStatus {
+ private final String accountKey;
private final String externalKey;
private final String status;
private final DateTime startDate;
private final DateTime endDate;
- public BusinessOverdueStatus(final DateTime endDate, final String externalKey, final DateTime startDate, final String status) {
+ public BusinessOverdueStatus(final String accountKey, final DateTime endDate, final String externalKey,
+ final DateTime startDate, final String status) {
+ this.accountKey = accountKey;
this.endDate = endDate;
this.externalKey = externalKey;
this.startDate = startDate;
this.status = status;
}
+ public String getAccountKey() {
+ return accountKey;
+ }
+
public DateTime getEndDate() {
return endDate;
}
@@ -51,7 +58,8 @@ public class BusinessOverdueStatus {
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessOverdueStatus");
- sb.append("{endDate=").append(endDate);
+ sb.append("{accountKey=").append(accountKey);
+ sb.append(", endDate='").append(endDate).append('\'');
sb.append(", externalKey='").append(externalKey).append('\'');
sb.append(", status='").append(status).append('\'');
sb.append(", startDate=").append(startDate);
@@ -70,6 +78,9 @@ public class BusinessOverdueStatus {
final BusinessOverdueStatus that = (BusinessOverdueStatus) o;
+ if (accountKey != null ? !accountKey.equals(that.accountKey) : that.accountKey != null) {
+ return false;
+ }
if (endDate != null ? !endDate.equals(that.endDate) : that.endDate != null) {
return false;
}
@@ -88,7 +99,8 @@ public class BusinessOverdueStatus {
@Override
public int hashCode() {
- int result = externalKey != null ? externalKey.hashCode() : 0;
+ int result = accountKey != null ? accountKey.hashCode() : 0;
+ result = 31 * result + (externalKey != null ? externalKey.hashCode() : 0);
result = 31 * result + (status != null ? status.hashCode() : 0);
result = 31 * result + (startDate != null ? startDate.hashCode() : 0);
result = 31 * result + (endDate != null ? endDate.hashCode() : 0);
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/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionField.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionField.java
index bab1259..f54e39e 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionField.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionField.java
@@ -17,13 +17,19 @@
package com.ning.billing.analytics.model;
public class BusinessSubscriptionTransitionField extends BusinessField {
+ private final String accountKey;
private final String externalKey;
- public BusinessSubscriptionTransitionField(final String externalKey, final String name, final String value) {
+ public BusinessSubscriptionTransitionField(final String accountKey, final String externalKey, final String name, final String value) {
super(name, value);
+ this.accountKey = accountKey;
this.externalKey = externalKey;
}
+ public String getAccountKey() {
+ return accountKey;
+ }
+
public String getExternalKey() {
return externalKey;
}
@@ -32,9 +38,10 @@ public class BusinessSubscriptionTransitionField extends BusinessField {
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessSubscriptionTransitionField");
- sb.append("{externalKey='").append(externalKey).append('\'');
- sb.append(", name='").append(name).append('\'');
- sb.append(", value='").append(value).append('\'');
+ sb.append("{accountKey='").append(accountKey).append('\'');
+ sb.append(", externalKey='").append(externalKey).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
+ sb.append(", value='").append(getValue()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -50,13 +57,16 @@ public class BusinessSubscriptionTransitionField extends BusinessField {
final BusinessSubscriptionTransitionField that = (BusinessSubscriptionTransitionField) o;
+ if (accountKey != null ? !accountKey.equals(that.accountKey) : that.accountKey != null) {
+ return false;
+ }
if (externalKey != null ? !externalKey.equals(that.externalKey) : that.externalKey != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
- if (value != null ? !value.equals(that.value) : that.value != null) {
+ if (getValue() != null ? !getValue().equals(that.getValue()) : that.getValue() != null) {
return false;
}
@@ -65,9 +75,10 @@ public class BusinessSubscriptionTransitionField extends BusinessField {
@Override
public int hashCode() {
- int result = externalKey != null ? externalKey.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
- result = 31 * result + (value != null ? value.hashCode() : 0);
+ int result = accountKey != null ? accountKey.hashCode() : 0;
+ result = 31 * result + (externalKey != null ? externalKey.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+ result = 31 * result + (getValue() != null ? getValue().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionTag.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionTag.java
index 522194a..0539461 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionTag.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionTransitionTag.java
@@ -17,13 +17,19 @@
package com.ning.billing.analytics.model;
public class BusinessSubscriptionTransitionTag extends BusinessTag {
+ private final String accountKey;
private final String externalKey;
- public BusinessSubscriptionTransitionTag(final String externalKey, final String name) {
+ public BusinessSubscriptionTransitionTag(final String accountKey, final String externalKey, final String name) {
super(name);
+ this.accountKey = accountKey;
this.externalKey = externalKey;
}
+ public String getAccountKey() {
+ return accountKey;
+ }
+
public String getExternalKey() {
return externalKey;
}
@@ -32,8 +38,9 @@ public class BusinessSubscriptionTransitionTag extends BusinessTag {
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("BusinessSubscriptionTransitionTag");
- sb.append("{externalKey='").append(externalKey).append('\'');
- sb.append(", name='").append(name).append('\'');
+ sb.append("{accountKey='").append(accountKey).append('\'');
+ sb.append(", externalKey='").append(externalKey).append('\'');
+ sb.append(", name='").append(getName()).append('\'');
sb.append('}');
return sb.toString();
}
@@ -49,10 +56,13 @@ public class BusinessSubscriptionTransitionTag extends BusinessTag {
final BusinessSubscriptionTransitionTag that = (BusinessSubscriptionTransitionTag) o;
+ if (accountKey != null ? !accountKey.equals(that.accountKey) : that.accountKey != null) {
+ return false;
+ }
if (externalKey != null ? !externalKey.equals(that.externalKey) : that.externalKey != null) {
return false;
}
- if (name != null ? !name.equals(that.name) : that.name != null) {
+ if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
@@ -61,8 +71,9 @@ public class BusinessSubscriptionTransitionTag extends BusinessTag {
@Override
public int hashCode() {
- int result = externalKey != null ? externalKey.hashCode() : 0;
- result = 31 * result + (name != null ? name.hashCode() : 0);
+ int result = accountKey != null ? accountKey.hashCode() : 0;
+ result = 31 * result + (externalKey != null ? externalKey.hashCode() : 0);
+ result = 31 * result + (getName() != null ? getName().hashCode() : 0);
return result;
}
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessTag.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessTag.java
index 80343e1..64ddaa9 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessTag.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessTag.java
@@ -17,7 +17,7 @@
package com.ning.billing.analytics.model;
public abstract class BusinessTag {
- protected final String name;
+ private final String name;
public BusinessTag(final String name) {
this.name = name;
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 d412125..c1c7140 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
@@ -3,6 +3,7 @@ group BusinessOverdueStatus;
getOverdueStatusesForBundle(external_key) ::= <<
select
external_key
+, account_key
, status
, start_date
, end_date
@@ -15,11 +16,13 @@ order by start_date asc
createOverdueStatus() ::= <<
insert into bos (
external_key
+, account_key
, status
, start_date
, end_date
) values (
:external_key
+, :account_key
, :status
, :start_date
, :end_date
@@ -28,4 +31,4 @@ insert into bos (
test() ::= <<
select 1 from bos;
->>
\ No newline at end of file
+>>
diff --git a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldSqlDao.sql.stg b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldSqlDao.sql.stg
index 522e6d7..0330ac0 100644
--- a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldSqlDao.sql.stg
+++ b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionFieldSqlDao.sql.stg
@@ -3,6 +3,7 @@ group BusinessSubscriptionTransitionField;
getFieldsForBusinessSubscriptionTransition(external_key) ::=<<
select
external_key
+, account_key
, name
, value
from bst_fields
@@ -13,10 +14,12 @@ where external_key = :external_key
addField(external_key, name, value) ::=<<
insert into bst_fields (
external_key
+, account_key
, name
, value
) values (
:external_key
+, :account_key
, :name
, :value
);
@@ -28,4 +31,4 @@ delete from bst_fields where external_key = :external_key and name = :name;
test() ::= <<
select 1 from bst_fields;
->>
\ No newline at end of file
+>>
diff --git a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg
index c80b6b5..7192e5f 100644
--- a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg
+++ b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionSqlDao.sql.stg
@@ -41,6 +41,47 @@ getTransitions(external_key) ::= <<
;
>>
+getTransitionForSubscription(subscription_id) ::= <<
+ select
+ total_ordering
+ , external_key
+ , account_key
+ , requested_timestamp
+ , event
+ , prev_product_name
+ , prev_product_type
+ , prev_product_category
+ , prev_slug
+ , prev_phase
+ , prev_billing_period
+ , prev_price
+ , prev_price_list
+ , prev_mrr
+ , prev_currency
+ , prev_start_date
+ , prev_state
+ , prev_subscription_id
+ , prev_bundle_id
+ , next_product_name
+ , next_product_type
+ , next_product_category
+ , next_slug
+ , next_phase
+ , next_billing_period
+ , next_price
+ , next_price_list
+ , next_mrr
+ , next_currency
+ , next_start_date
+ , next_state
+ , next_subscription_id
+ , next_bundle_id
+ from bst
+ where prev_subscription_id = :subscription_id or next_subscription_id = :subscription_id
+ order by requested_timestamp asc
+ ;
+>>
+
createTransition() ::= <<
insert ignore into bst(
total_ordering
@@ -113,6 +154,50 @@ createTransition() ::= <<
);
>>
+updateTransition() ::= <<
+ update bst set
+ total_ordering = :total_ordering
+ , external_key = :external_key
+ , account_key = :account_key
+ , requested_timestamp = :requested_timestamp
+ , event = :event
+ , prev_product_name = :prev_product_name
+ , prev_product_type = :prev_product_type
+ , prev_product_category = :prev_product_category
+ , prev_slug = :prev_slug
+ , prev_phase = :prev_phase
+ , prev_billing_period = :prev_billing_period
+ , prev_price = :prev_price
+ , prev_price_list = :prev_price_list
+ , prev_mrr = :prev_mrr
+ , prev_currency = :prev_currency
+ , prev_start_date = :prev_start_date
+ , prev_state = :prev_state
+ , prev_subscription_id = :prev_subscription_id
+ , prev_bundle_id = :prev_bundle_id
+ , next_product_name = :next_product_name
+ , next_product_type = :next_product_type
+ , next_product_category = :next_product_category
+ , next_slug = :next_slug
+ , next_phase = :next_phase
+ , next_billing_period = :next_billing_period
+ , next_price = :next_price
+ , next_price_list = :next_price_list
+ , next_mrr = :next_mrr
+ , next_currency = :next_currency
+ , next_start_date = :next_start_date
+ , next_state = :next_state
+ , next_subscription_id = :next_subscription_id
+ , next_bundle_id = :next_bundle_id
+ where total_ordering = :total_ordering
+>>
+
+deleteTransitionsForBundle(external_key) ::= <<
+ delete from bst
+ where external_key=:external_key
+ ;
+>>
+
test() ::= <<
select 1 from bst;
>>
diff --git a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagSqlDao.sql.stg b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagSqlDao.sql.stg
index 3d2255f..dcd99aa 100644
--- a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagSqlDao.sql.stg
+++ b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionTagSqlDao.sql.stg
@@ -3,6 +3,7 @@ group BusinessSubscriptionTransitionTag;
getTagsForBusinessSubscriptionTransition(external_key) ::=<<
select
external_key
+, account_key
, name
from bst_tags
where external_key = :external_key
@@ -12,9 +13,11 @@ where external_key = :external_key
addTag(external_key, name) ::=<<
insert into bst_tags (
external_key
+, account_key
, name
) values (
:external_key
+, :account_key
, :name
);
>>
@@ -25,4 +28,4 @@ delete from bst_tags where external_key = :external_key and name = :name;
test() ::= <<
select 1 from bst_tags;
->>
\ No newline at end of file
+>>
diff --git a/analytics/src/main/resources/com/ning/billing/analytics/ddl.sql b/analytics/src/main/resources/com/ning/billing/analytics/ddl.sql
index 43aaad8..c7f9d1b 100644
--- a/analytics/src/main/resources/com/ning/billing/analytics/ddl.sql
+++ b/analytics/src/main/resources/com/ning/billing/analytics/ddl.sql
@@ -1,6 +1,7 @@
drop table if exists bst;
create table bst (
- total_ordering bigint default 0
+ record_id int(11) unsigned not null auto_increment
+, total_ordering bigint default 0
, external_key varchar(50) not null comment 'Bundle external key'
, account_key varchar(50) not null comment 'Account external key'
, requested_timestamp bigint not null
@@ -33,13 +34,14 @@ create table bst (
, next_state varchar(32) default null
, next_subscription_id varchar(100) default null
, next_bundle_id varchar(100) default null
-, primary key(total_ordering)
+, primary key(record_id)
) engine=innodb comment 'Business Subscription Transitions, track bundles lifecycle';
create index bst_key_index on bst (external_key, requested_timestamp asc);
drop table if exists bac;
create table bac (
- account_key varchar(50) not null
+ record_id int(11) unsigned not null auto_increment
+, account_key varchar(50) not null
, name varchar(100) not null
, created_date bigint not null
, updated_date bigint not null
@@ -51,12 +53,14 @@ create table bac (
, credit_card_type varchar(32) default null
, billing_address_country varchar(100) default null
, currency char(3) default null
+, primary key(record_id)
) engine=innodb comment 'Business ACcounts, keep a record of all accounts';
create unique index bac_key_index on bac (account_key);
drop table if exists bin;
create table bin (
- invoice_id char(36) not null
+ record_id int(11) unsigned not null auto_increment
+, invoice_id char(36) not null
, created_date bigint not null
, updated_date bigint not null
, account_key varchar(50) not null
@@ -67,12 +71,14 @@ create table bin (
, amount_paid numeric(10, 4) default 0 comment 'Sums of the successful payments made for this invoice minus the refunds associated with this invoice'
, amount_charged numeric(10, 4) default 0 comment 'Sums of the invoice items amount'
, amount_credited numeric(10, 4) default 0 comment 'Sums of the credit items'
+, primary key(record_id)
) engine=innodb comment 'Business INvoices, keep a record of generated invoices';
create unique index bin_key_index on bin (invoice_id);
drop table if exists bii;
create table bii (
- item_id char(36) not null
+ record_id int(11) unsigned not null auto_increment
+, item_id char(36) not null
, created_date bigint not null
, updated_date bigint not null
, invoice_id char(36) not null
@@ -88,12 +94,14 @@ create table bii (
, end_date bigint default null
, amount numeric(10, 4) default 0
, currency char(3) default null
+, primary key(record_id)
) engine=innodb comment 'Business Invoice Items, keep a record of all invoice items';
create unique index bii_key_index on bii (item_id);
drop table if exists bip;
create table bip (
- payment_id char(36) not null
+ record_id int(11) unsigned not null auto_increment
+, payment_id char(36) not null
, created_date bigint not null
, updated_date bigint not null
, attempt_id char(36) not null
@@ -110,66 +118,88 @@ create table bip (
, payment_method varchar(20) default null
, card_type varchar(20) default null
, card_country varchar(20) default null
+, primary key(record_id)
) engine=innodb comment 'Business Invoice Payments, track all payment attempts';
create unique index bip_key_index on bip (attempt_id);
drop table if exists bos;
create table bos (
- external_key varchar(50) not null comment 'Bundle external key'
+ record_id int(11) unsigned not null auto_increment
+, external_key varchar(50) not null comment 'Bundle external key'
+, account_key varchar(50) not null comment 'Account external key'
, status varchar(50) not null
, start_date bigint default null
, end_date bigint default null
+, primary key(record_id)
) engine=innodb comment 'Business Overdue Status, historical bundles overdue status';
create unique index bos_key_index on bos (external_key, status);
drop table if exists bac_tags;
create table bac_tags (
- account_key varchar(50) not null comment 'Account external key'
+ record_id int(11) unsigned not null auto_increment
+, account_key varchar(50) not null comment 'Account external key'
, name varchar(20) not null
+, primary key(record_id)
) engine=innodb comment 'Tags associated to accounts';
drop table if exists bac_fields;
create table bac_fields (
- account_key varchar(50) not null comment 'Account external key'
+ record_id int(11) unsigned not null auto_increment
+, account_key varchar(50) not null comment 'Account external key'
, name varchar(30) not null
, value varchar(255) default null
+, primary key(record_id)
) engine=innodb comment 'Custom fields associated to accounts';
drop table if exists bst_tags;
create table bst_tags (
- external_key varchar(50) not null comment 'Bundle external key'
+ record_id int(11) unsigned not null auto_increment
+, external_key varchar(50) not null comment 'Bundle external key'
+, account_key varchar(50) not null comment 'Account external key'
, name varchar(20) not null
+, primary key(record_id)
) engine=innodb comment 'Tags associated to bundles';
drop table if exists bst_fields;
create table bst_fields (
- external_key varchar(50) not null comment 'Bundle external key'
+ record_id int(11) unsigned not null auto_increment
+, external_key varchar(50) not null comment 'Bundle external key'
+, account_key varchar(50) not null comment 'Account external key'
, name varchar(30) not null
, value varchar(255) default null
+, primary key(record_id)
) engine=innodb comment 'Custom fields associated to bundles';
drop table if exists bin_tags;
create table bin_tags (
- invoice_id char(36) not null
+ record_id int(11) unsigned not null auto_increment
+, invoice_id char(36) not null
, name varchar(20) not null
+, primary key(record_id)
) engine=innodb comment 'Tags associated to invoices';
drop table if exists bin_fields;
create table bin_fields (
- invoice_id char(36) not null
+ record_id int(11) unsigned not null auto_increment
+, invoice_id char(36) not null
, name varchar(30) not null
, value varchar(255) default null
+, primary key(record_id)
) engine=innodb comment 'Custom fields associated to invoices';
drop table if exists bip_tags;
create table bip_tags (
- payment_id char(36) not null
+ record_id int(11) unsigned not null auto_increment
+, payment_id char(36) not null
, name varchar(20) not null
+, primary key(record_id)
) engine=innodb comment 'Tags associated to payments';
drop table if exists bip_fields;
create table bip_fields (
- payment_id char(36) not null
+ record_id int(11) unsigned not null auto_increment
+, payment_id char(36) not null
, name varchar(30) not null
, value varchar(255) default null
+, primary key(record_id)
) engine=innodb comment 'Custom fields associated to payments';
diff --git a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
index ad54c53..e82b61c 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
@@ -38,7 +38,6 @@ import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
import com.ning.billing.analytics.AnalyticsTestModule;
import com.ning.billing.analytics.MockDuration;
import com.ning.billing.analytics.MockPhase;
-import com.ning.billing.analytics.MockPlan;
import com.ning.billing.analytics.MockProduct;
import com.ning.billing.analytics.TestWithEmbeddedDB;
import com.ning.billing.analytics.dao.BusinessAccountSqlDao;
@@ -73,6 +72,7 @@ import com.ning.billing.invoice.dao.InvoiceDao;
import com.ning.billing.invoice.model.DefaultInvoice;
import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
import com.ning.billing.mock.MockAccountBuilder;
+import com.ning.billing.mock.MockPlan;
import com.ning.billing.payment.api.DefaultPaymentInfoEvent;
import com.ning.billing.payment.api.PaymentInfoEvent;
import com.ning.billing.payment.api.PaymentStatus;
@@ -180,7 +180,6 @@ public class TestAnalyticsService extends TestWithEmbeddedDB {
final DateTime requestedTransitionTime = clock.getUTCNow();
final PriceList priceList = new MockPriceList().setName("something");
-
transition = new DefaultEffectiveSubscriptionEvent(new SubscriptionTransitionData(
UUID.randomUUID(),
subscriptionId,
diff --git a/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java b/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
index 5d6b3a6..a953ed2 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
@@ -36,7 +36,6 @@ import com.ning.billing.analytics.model.BusinessSubscriptionEvent;
import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
import com.ning.billing.analytics.MockDuration;
import com.ning.billing.analytics.MockPhase;
-import com.ning.billing.analytics.MockPlan;
import com.ning.billing.analytics.MockProduct;
import com.ning.billing.analytics.TestWithEmbeddedDB;
import com.ning.billing.analytics.utils.Rounder;
@@ -50,6 +49,7 @@ import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.Product;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.mock.MockPlan;
public class TestAnalyticsDao extends TestWithEmbeddedDB {
private static final Long TOTAL_ORDERING = 1L;
@@ -113,45 +113,6 @@ public class TestAnalyticsDao extends TestWithEmbeddedDB {
}
@Test(groups = "slow")
- public void testHandleDuplicatedEvents() {
- final BusinessSubscriptionTransition transitionWithNullPrev = new BusinessSubscriptionTransition(
- transition.getTotalOrdering(),
- transition.getExternalKey(),
- transition.getAccountKey(),
- transition.getRequestedTimestamp(),
- transition.getEvent(),
- null,
- transition.getNextSubscription()
- );
-
- businessSubscriptionTransitionSqlDao.createTransition(transitionWithNullPrev);
- List<BusinessSubscriptionTransition> transitions = businessSubscriptionTransitionSqlDao.getTransitions(EXTERNAL_KEY);
- Assert.assertEquals(transitions.size(), 1);
- Assert.assertEquals(transitions.get(0), transitionWithNullPrev);
- // Try to add the same transition, with the same UUID - we should only store one though
- businessSubscriptionTransitionSqlDao.createTransition(transitionWithNullPrev);
- transitions = businessSubscriptionTransitionSqlDao.getTransitions(EXTERNAL_KEY);
- Assert.assertEquals(transitions.size(), 1);
- Assert.assertEquals(transitions.get(0), transitionWithNullPrev);
-
- // Try now to store a look-alike transition (same fields except UUID) - we should store it this time
- final BusinessSubscriptionTransition secondTransitionWithNullPrev = new BusinessSubscriptionTransition(
- 12L,
- transition.getExternalKey(),
- transition.getAccountKey(),
- transition.getRequestedTimestamp(),
- transition.getEvent(),
- null,
- transition.getNextSubscription()
- );
- businessSubscriptionTransitionSqlDao.createTransition(secondTransitionWithNullPrev);
- transitions = businessSubscriptionTransitionSqlDao.getTransitions(EXTERNAL_KEY);
- Assert.assertEquals(transitions.size(), 2);
- Assert.assertTrue(transitions.contains(transitionWithNullPrev));
- Assert.assertTrue(transitions.contains(secondTransitionWithNullPrev));
- }
-
- @Test(groups = "slow")
public void testTransitionsWithNullPrevSubscription() {
final BusinessSubscriptionTransition transitionWithNullPrev = new BusinessSubscriptionTransition(
transition.getTotalOrdering(),
diff --git a/analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessOverdueStatusSqlDao.java b/analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessOverdueStatusSqlDao.java
index c16ab3c..f21d3af 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessOverdueStatusSqlDao.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessOverdueStatusSqlDao.java
@@ -39,8 +39,9 @@ public class TestBusinessOverdueStatusSqlDao extends TestWithEmbeddedDB {
@Test(groups = "slow")
public void testCreate() throws Exception {
+ final String accountKey = UUID.randomUUID().toString();
final String externalKey = UUID.randomUUID().toString();
- final BusinessOverdueStatus firstOverdueStatus = createOverdueStatus(externalKey);
+ final BusinessOverdueStatus firstOverdueStatus = createOverdueStatus(accountKey, externalKey);
// Verify initial state
Assert.assertEquals(overdueStatusSqlDao.getOverdueStatusesForBundle(externalKey).size(), 0);
@@ -53,7 +54,7 @@ public class TestBusinessOverdueStatusSqlDao extends TestWithEmbeddedDB {
Assert.assertEquals(overdueStatusSqlDao.getOverdueStatusesForBundle(externalKey).get(0), firstOverdueStatus);
// Add a second one
- final BusinessOverdueStatus secondOverdueStatus = createOverdueStatus(externalKey);
+ final BusinessOverdueStatus secondOverdueStatus = createOverdueStatus(accountKey, externalKey);
Assert.assertEquals(overdueStatusSqlDao.createOverdueStatus(secondOverdueStatus), 1);
// Retrieve both
@@ -72,11 +73,11 @@ public class TestBusinessOverdueStatusSqlDao extends TestWithEmbeddedDB {
}
}
- private BusinessOverdueStatus createOverdueStatus(final String externalKey) {
+ private BusinessOverdueStatus createOverdueStatus(final String accountKey, final String externalKey) {
final DateTime endDate = new DateTime(DateTimeZone.UTC);
final DateTime startDate = new DateTime(DateTimeZone.UTC);
final String status = UUID.randomUUID().toString();
- return new BusinessOverdueStatus(endDate, externalKey, startDate, status);
+ return new BusinessOverdueStatus(accountKey, endDate, externalKey, startDate, status);
}
}
diff --git a/analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessSubscriptionTransitionFieldSqlDao.java b/analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessSubscriptionTransitionFieldSqlDao.java
index 5233229..eb0d374 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessSubscriptionTransitionFieldSqlDao.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessSubscriptionTransitionFieldSqlDao.java
@@ -38,6 +38,7 @@ public class TestBusinessSubscriptionTransitionFieldSqlDao extends TestWithEmbed
@Test(groups = "slow")
public void testCRUD() throws Exception {
+ final String accountKey = UUID.randomUUID().toString();
final String externalKey = UUID.randomUUID().toString();
final String name = UUID.randomUUID().toString().substring(0, 30);
final String value = UUID.randomUUID().toString();
@@ -47,7 +48,7 @@ public class TestBusinessSubscriptionTransitionFieldSqlDao extends TestWithEmbed
Assert.assertEquals(subscriptionTransitionFieldSqlDao.removeField(externalKey, name), 0);
// Add an entry
- Assert.assertEquals(subscriptionTransitionFieldSqlDao.addField(externalKey, name, value), 1);
+ Assert.assertEquals(subscriptionTransitionFieldSqlDao.addField(accountKey, externalKey, name, value), 1);
final List<BusinessSubscriptionTransitionField> fieldsForBusinessSubscriptionTransition = subscriptionTransitionFieldSqlDao.getFieldsForBusinessSubscriptionTransition(externalKey);
Assert.assertEquals(fieldsForBusinessSubscriptionTransition.size(), 1);
@@ -64,14 +65,15 @@ public class TestBusinessSubscriptionTransitionFieldSqlDao extends TestWithEmbed
@Test(groups = "slow")
public void testSegmentation() throws Exception {
+ final String accountKey = UUID.randomUUID().toString();
final String externalKey1 = UUID.randomUUID().toString();
final String name1 = UUID.randomUUID().toString().substring(0, 30);
final String externalKey2 = UUID.randomUUID().toString();
final String name2 = UUID.randomUUID().toString().substring(0, 30);
// Add a field to both transitions
- Assert.assertEquals(subscriptionTransitionFieldSqlDao.addField(externalKey1, name1, UUID.randomUUID().toString()), 1);
- Assert.assertEquals(subscriptionTransitionFieldSqlDao.addField(externalKey2, name2, UUID.randomUUID().toString()), 1);
+ Assert.assertEquals(subscriptionTransitionFieldSqlDao.addField(accountKey, externalKey1, name1, UUID.randomUUID().toString()), 1);
+ Assert.assertEquals(subscriptionTransitionFieldSqlDao.addField(accountKey, externalKey2, name2, UUID.randomUUID().toString()), 1);
Assert.assertEquals(subscriptionTransitionFieldSqlDao.getFieldsForBusinessSubscriptionTransition(externalKey1).size(), 1);
Assert.assertEquals(subscriptionTransitionFieldSqlDao.getFieldsForBusinessSubscriptionTransition(externalKey2).size(), 1);
diff --git a/analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessSubscriptionTransitionTagSqlDao.java b/analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessSubscriptionTransitionTagSqlDao.java
index 8b4740f..7b8f1db 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessSubscriptionTransitionTagSqlDao.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/dao/TestBusinessSubscriptionTransitionTagSqlDao.java
@@ -38,6 +38,7 @@ public class TestBusinessSubscriptionTransitionTagSqlDao extends TestWithEmbedde
@Test(groups = "slow")
public void testCRUD() throws Exception {
+ final String accountKey = UUID.randomUUID().toString();
final String externalKey = UUID.randomUUID().toString();
final String name = UUID.randomUUID().toString().substring(0, 20);
@@ -46,7 +47,7 @@ public class TestBusinessSubscriptionTransitionTagSqlDao extends TestWithEmbedde
Assert.assertEquals(subscriptionTransitionTagSqlDao.removeTag(externalKey, name), 0);
// Add an entry
- Assert.assertEquals(subscriptionTransitionTagSqlDao.addTag(externalKey, name), 1);
+ Assert.assertEquals(subscriptionTransitionTagSqlDao.addTag(accountKey, externalKey, name), 1);
final List<BusinessSubscriptionTransitionTag> tagsForBusinessSubscriptionTransition = subscriptionTransitionTagSqlDao.getTagsForBusinessSubscriptionTransition(externalKey);
Assert.assertEquals(tagsForBusinessSubscriptionTransition.size(), 1);
@@ -62,14 +63,15 @@ public class TestBusinessSubscriptionTransitionTagSqlDao extends TestWithEmbedde
@Test(groups = "slow")
public void testSegmentation() throws Exception {
+ final String accountKey = UUID.randomUUID().toString();
final String externalKey1 = UUID.randomUUID().toString();
final String name1 = UUID.randomUUID().toString().substring(0, 20);
final String externalKey2 = UUID.randomUUID().toString();
final String name2 = UUID.randomUUID().toString().substring(0, 20);
// Add a tag to both transitions
- Assert.assertEquals(subscriptionTransitionTagSqlDao.addTag(externalKey1, name1), 1);
- Assert.assertEquals(subscriptionTransitionTagSqlDao.addTag(externalKey2, name2), 1);
+ Assert.assertEquals(subscriptionTransitionTagSqlDao.addTag(accountKey, externalKey1, name1), 1);
+ Assert.assertEquals(subscriptionTransitionTagSqlDao.addTag(accountKey, externalKey2, name2), 1);
Assert.assertEquals(subscriptionTransitionTagSqlDao.getTagsForBusinessSubscriptionTransition(externalKey1).size(), 1);
Assert.assertEquals(subscriptionTransitionTagSqlDao.getTagsForBusinessSubscriptionTransition(externalKey2).size(), 1);
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 a442f2a..b54d7ce 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockBusinessSubscriptionTransitionSqlDao.java
@@ -21,8 +21,11 @@ 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 org.testng.Assert;
+import com.google.common.collect.ImmutableList;
import com.ning.billing.analytics.dao.BusinessSubscriptionTransitionBinder;
import com.ning.billing.analytics.dao.BusinessSubscriptionTransitionSqlDao;
import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
@@ -36,6 +39,11 @@ public class MockBusinessSubscriptionTransitionSqlDao implements BusinessSubscri
}
@Override
+ public List<BusinessSubscriptionTransition> getTransitionForSubscription(@Bind("subscription_id") final String subscriptionId) {
+ return ImmutableList.<BusinessSubscriptionTransition>of();
+ }
+
+ @Override
public int createTransition(@BusinessSubscriptionTransitionBinder final BusinessSubscriptionTransition transition) {
if (content.get(transition.getExternalKey()) == null) {
content.put(transition.getExternalKey(), new ArrayList<BusinessSubscriptionTransition>());
@@ -45,6 +53,50 @@ public class MockBusinessSubscriptionTransitionSqlDao implements BusinessSubscri
}
@Override
+ public void updateTransition(@Bind("total_ordering") final long totalOrdering, @BusinessSubscriptionTransitionBinder final BusinessSubscriptionTransition updatedFirstTransition) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void deleteTransitionsForBundle(@Bind("external_key") final String externalKey) {
+ content.put(externalKey, new ArrayList<BusinessSubscriptionTransition>());
+ }
+
+ @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) {
+ try {
+ return func.inTransaction(this, null);
+ } catch (Exception e) {
+ Assert.fail(e.toString());
+ return null;
+ }
+ }
}
diff --git a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessOverdueStatus.java b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessOverdueStatus.java
index b92ee12..6edcbf9 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessOverdueStatus.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessOverdueStatus.java
@@ -28,21 +28,26 @@ import com.ning.billing.analytics.AnalyticsTestSuite;
public class TestBusinessOverdueStatus extends AnalyticsTestSuite {
@Test(groups = "fast")
public void testEquals() throws Exception {
+ final String accountKey = UUID.randomUUID().toString();
final DateTime endDate = new DateTime(DateTimeZone.UTC);
final String externalKey = UUID.randomUUID().toString();
final DateTime startDate = new DateTime(DateTimeZone.UTC);
final String status = UUID.randomUUID().toString();
- final BusinessOverdueStatus overdueStatus = new BusinessOverdueStatus(endDate, externalKey, startDate, status);
+ final BusinessOverdueStatus overdueStatus = new BusinessOverdueStatus(accountKey, endDate, externalKey, startDate, status);
Assert.assertSame(overdueStatus, overdueStatus);
Assert.assertEquals(overdueStatus, overdueStatus);
Assert.assertTrue(overdueStatus.equals(overdueStatus));
+ Assert.assertEquals(overdueStatus.getAccountKey(), accountKey);
Assert.assertEquals(overdueStatus.getEndDate(), endDate);
Assert.assertEquals(overdueStatus.getExternalKey(), externalKey);
Assert.assertEquals(overdueStatus.getStartDate(), startDate);
Assert.assertEquals(overdueStatus.getStatus(), status);
- final BusinessOverdueStatus otherOverdueStatus = new BusinessOverdueStatus(new DateTime(DateTimeZone.UTC), UUID.randomUUID().toString(),
- new DateTime(DateTimeZone.UTC), UUID.randomUUID().toString());
+ final BusinessOverdueStatus otherOverdueStatus = new BusinessOverdueStatus(UUID.randomUUID().toString(),
+ new DateTime(DateTimeZone.UTC),
+ UUID.randomUUID().toString(),
+ new DateTime(DateTimeZone.UTC),
+ UUID.randomUUID().toString());
Assert.assertFalse(overdueStatus.equals(otherOverdueStatus));
}
}
diff --git a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscription.java b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscription.java
index c102d35..7a2cbd7 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscription.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscription.java
@@ -27,10 +27,7 @@ import org.testng.annotations.Test;
import com.ning.billing.analytics.AnalyticsTestSuite;
import com.ning.billing.analytics.MockDuration;
import com.ning.billing.analytics.MockPhase;
-import com.ning.billing.analytics.MockPlan;
import com.ning.billing.analytics.MockProduct;
-import com.ning.billing.analytics.MockSubscription;
-import com.ning.billing.analytics.model.BusinessSubscription;
import com.ning.billing.catalog.api.Catalog;
import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.catalog.api.Duration;
@@ -40,6 +37,8 @@ import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.Product;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.mock.MockPlan;
+import com.ning.billing.mock.MockSubscription;
import static com.ning.billing.catalog.api.Currency.USD;
diff --git a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionEvent.java b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionEvent.java
index 11c6215..de713a8 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionEvent.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionEvent.java
@@ -25,10 +25,7 @@ import org.testng.annotations.Test;
import com.ning.billing.analytics.AnalyticsTestSuite;
import com.ning.billing.analytics.MockDuration;
import com.ning.billing.analytics.MockPhase;
-import com.ning.billing.analytics.MockPlan;
import com.ning.billing.analytics.MockProduct;
-import com.ning.billing.analytics.MockSubscription;
-import com.ning.billing.analytics.model.BusinessSubscriptionEvent;
import com.ning.billing.catalog.api.Catalog;
import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.catalog.api.PhaseType;
@@ -37,6 +34,8 @@ import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.Product;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.mock.MockPlan;
+import com.ning.billing.mock.MockSubscription;
public class TestBusinessSubscriptionEvent extends AnalyticsTestSuite {
private Product product;
diff --git a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransition.java b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransition.java
index 4c401a6..1e10acf 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransition.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransition.java
@@ -26,12 +26,7 @@ import org.testng.annotations.Test;
import com.ning.billing.analytics.AnalyticsTestSuite;
import com.ning.billing.analytics.MockDuration;
import com.ning.billing.analytics.MockPhase;
-import com.ning.billing.analytics.MockPlan;
import com.ning.billing.analytics.MockProduct;
-import com.ning.billing.analytics.MockSubscription;
-import com.ning.billing.analytics.model.BusinessSubscription;
-import com.ning.billing.analytics.model.BusinessSubscriptionEvent;
-import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
import com.ning.billing.catalog.api.Catalog;
import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.catalog.api.PhaseType;
@@ -40,6 +35,8 @@ import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.catalog.api.Product;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.mock.MockPlan;
+import com.ning.billing.mock.MockSubscription;
import static com.ning.billing.catalog.api.Currency.USD;
diff --git a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransitionField.java b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransitionField.java
index 5a1e31b..af9122e 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransitionField.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransitionField.java
@@ -26,21 +26,25 @@ import com.ning.billing.analytics.AnalyticsTestSuite;
public class TestBusinessSubscriptionTransitionField extends AnalyticsTestSuite {
@Test(groups = "fast")
public void testEquals() throws Exception {
+ final String accountKey = UUID.randomUUID().toString();
final String externalKey = UUID.randomUUID().toString();
final String name = UUID.randomUUID().toString();
final String value = UUID.randomUUID().toString();
- final BusinessSubscriptionTransitionField subscriptionTransitionField = new BusinessSubscriptionTransitionField(externalKey,
+ final BusinessSubscriptionTransitionField subscriptionTransitionField = new BusinessSubscriptionTransitionField(accountKey,
+ externalKey,
name,
value);
Assert.assertSame(subscriptionTransitionField, subscriptionTransitionField);
Assert.assertEquals(subscriptionTransitionField, subscriptionTransitionField);
Assert.assertTrue(subscriptionTransitionField.equals(subscriptionTransitionField));
+ Assert.assertEquals(subscriptionTransitionField.getAccountKey(), accountKey);
Assert.assertEquals(subscriptionTransitionField.getExternalKey(), externalKey);
Assert.assertEquals(subscriptionTransitionField.getName(), name);
Assert.assertEquals(subscriptionTransitionField.getValue(), value);
final BusinessSubscriptionTransitionField otherSubscriptionField = new BusinessSubscriptionTransitionField(UUID.randomUUID().toString(),
UUID.randomUUID().toString(),
+ UUID.randomUUID().toString(),
UUID.randomUUID().toString());
Assert.assertFalse(subscriptionTransitionField.equals(otherSubscriptionField));
}
diff --git a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransitionTag.java b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransitionTag.java
index b5a40d1..9d079b4 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransitionTag.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/model/TestBusinessSubscriptionTransitionTag.java
@@ -26,16 +26,22 @@ import com.ning.billing.analytics.AnalyticsTestSuite;
public class TestBusinessSubscriptionTransitionTag extends AnalyticsTestSuite {
@Test(groups = "fast")
public void testEquals() throws Exception {
+ final String accountKey = UUID.randomUUID().toString();
final String externalKey = UUID.randomUUID().toString();
final String name = UUID.randomUUID().toString();
- final BusinessSubscriptionTransitionTag subscriptionTransitionTag = new BusinessSubscriptionTransitionTag(externalKey, name);
+ final BusinessSubscriptionTransitionTag subscriptionTransitionTag = new BusinessSubscriptionTransitionTag(accountKey,
+ externalKey,
+ name);
Assert.assertSame(subscriptionTransitionTag, subscriptionTransitionTag);
Assert.assertEquals(subscriptionTransitionTag, subscriptionTransitionTag);
Assert.assertTrue(subscriptionTransitionTag.equals(subscriptionTransitionTag));
+ Assert.assertEquals(subscriptionTransitionTag.getAccountKey(), accountKey);
Assert.assertEquals(subscriptionTransitionTag.getExternalKey(), externalKey);
Assert.assertEquals(subscriptionTransitionTag.getName(), name);
- final BusinessSubscriptionTransitionTag otherTransitionTag = new BusinessSubscriptionTransitionTag(UUID.randomUUID().toString(), UUID.randomUUID().toString());
+ final BusinessSubscriptionTransitionTag otherTransitionTag = new BusinessSubscriptionTransitionTag(UUID.randomUUID().toString(),
+ UUID.randomUUID().toString(),
+ UUID.randomUUID().toString());
Assert.assertFalse(subscriptionTransitionTag.equals(otherTransitionTag));
}
}
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransitionRecorder.java b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransitionRecorder.java
index 75c3ebc..48cefb4 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransitionRecorder.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransitionRecorder.java
@@ -24,23 +24,24 @@ import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.Test;
+import com.google.common.collect.ImmutableList;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.analytics.dao.BusinessSubscriptionTransitionSqlDao;
-import com.ning.billing.analytics.model.BusinessSubscription;
-import com.ning.billing.analytics.model.BusinessSubscriptionEvent;
import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
import com.ning.billing.catalog.api.Catalog;
import com.ning.billing.catalog.api.CatalogService;
-import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.entitlement.api.SubscriptionTransitionType;
import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
import com.ning.billing.entitlement.api.user.EntitlementUserApi;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.util.clock.DefaultClock;
public class TestBusinessSubscriptionTransitionRecorder extends AnalyticsTestSuite {
@Test(groups = "fast")
public void testCreateAddOn() throws Exception {
+ final UUID bundleId = UUID.randomUUID();
final UUID externalKey = UUID.randomUUID();
// Setup the catalog
@@ -49,26 +50,10 @@ public class TestBusinessSubscriptionTransitionRecorder extends AnalyticsTestSui
// Setup the dao
final BusinessSubscriptionTransitionSqlDao sqlDao = new MockBusinessSubscriptionTransitionSqlDao();
- // Add a previous subscription to make sure it doesn't impact the addon
- final BusinessSubscription nextPrevSubscription = new BusinessSubscription(UUID.randomUUID().toString(),
- UUID.randomUUID().toString(),
- UUID.randomUUID().toString(),
- Currency.USD,
- new DateTime(DateTimeZone.UTC),
- Subscription.SubscriptionState.ACTIVE,
- UUID.randomUUID(),
- UUID.randomUUID(),
- catalogService.getFullCatalog());
- sqlDao.createTransition(new BusinessSubscriptionTransition(10L,
- externalKey.toString(),
- UUID.randomUUID().toString(),
- new DateTime(DateTimeZone.UTC),
- BusinessSubscriptionEvent.valueOf("ADD_MISC"),
- null,
- nextPrevSubscription));
// Setup the entitlement API
final SubscriptionBundle bundle = Mockito.mock(SubscriptionBundle.class);
+ Mockito.when(bundle.getId()).thenReturn(bundleId);
Mockito.when(bundle.getKey()).thenReturn(externalKey.toString());
final EntitlementUserApi entitlementApi = Mockito.mock(EntitlementUserApi.class);
Mockito.when(entitlementApi.getBundleFromId(Mockito.<UUID>any())).thenReturn(bundle);
@@ -79,19 +64,25 @@ public class TestBusinessSubscriptionTransitionRecorder extends AnalyticsTestSui
final AccountUserApi accountApi = Mockito.mock(AccountUserApi.class);
Mockito.when(accountApi.getAccountById(bundle.getAccountId())).thenReturn(account);
- final BusinessSubscriptionTransitionRecorder recorder = new BusinessSubscriptionTransitionRecorder(sqlDao, catalogService, entitlementApi, accountApi);
-
// Create an new subscription event
final EffectiveSubscriptionEvent eventEffective = Mockito.mock(EffectiveSubscriptionEvent.class);
Mockito.when(eventEffective.getId()).thenReturn(UUID.randomUUID());
+ Mockito.when(eventEffective.getTransitionType()).thenReturn(SubscriptionTransitionType.CREATE);
+ Mockito.when(eventEffective.getSubscriptionId()).thenReturn(UUID.randomUUID());
Mockito.when(eventEffective.getRequestedTransitionTime()).thenReturn(new DateTime(DateTimeZone.UTC));
Mockito.when(eventEffective.getNextPlan()).thenReturn(UUID.randomUUID().toString());
Mockito.when(eventEffective.getEffectiveTransitionTime()).thenReturn(new DateTime(DateTimeZone.UTC));
Mockito.when(eventEffective.getSubscriptionStartDate()).thenReturn(new DateTime(DateTimeZone.UTC));
- recorder.subscriptionCreated(eventEffective);
- Assert.assertEquals(sqlDao.getTransitions(externalKey.toString()).size(), 2);
- final BusinessSubscriptionTransition transition = sqlDao.getTransitions(externalKey.toString()).get(1);
+ final Subscription subscription = Mockito.mock(Subscription.class);
+ Mockito.when(subscription.getAllTransitions()).thenReturn(ImmutableList.<EffectiveSubscriptionEvent>of(eventEffective));
+ Mockito.when(entitlementApi.getSubscriptionsForBundle(Mockito.<UUID>any())).thenReturn(ImmutableList.<Subscription>of(subscription));
+
+ final BusinessSubscriptionTransitionRecorder recorder = new BusinessSubscriptionTransitionRecorder(sqlDao, catalogService, entitlementApi, accountApi, new DefaultClock());
+ recorder.rebuildTransitionsForBundle(bundle.getId());
+
+ Assert.assertEquals(sqlDao.getTransitions(externalKey.toString()).size(), 1);
+ final BusinessSubscriptionTransition transition = sqlDao.getTransitions(externalKey.toString()).get(0);
Assert.assertEquals(transition.getTotalOrdering(), (long) eventEffective.getTotalOrdering());
Assert.assertEquals(transition.getAccountKey(), externalKey.toString());
// Make sure all the prev_ columns are null
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
index 6f18739..79e762f 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessTagRecorder.java
@@ -85,7 +85,7 @@ public class TestBusinessTagRecorder extends TestWithEmbeddedDB {
final CatalogService catalogService = new DefaultCatalogService(Mockito.mock(CatalogConfig.class), Mockito.mock(VersionedCatalogLoader.class));
final AddonUtils addonUtils = new AddonUtils(catalogService);
final DefaultNotificationQueueService notificationQueueService = new DefaultNotificationQueueService(dbi, clock);
- final EntitlementDao entitlementDao = new AuditedEntitlementDao(dbi, clock, addonUtils, notificationQueueService, eventBus);
+ final EntitlementDao entitlementDao = new AuditedEntitlementDao(dbi, clock, addonUtils, notificationQueueService, eventBus, catalogService);
final PlanAligner planAligner = new PlanAligner(catalogService);
final DefaultSubscriptionApiService apiService = new DefaultSubscriptionApiService(clock, entitlementDao, catalogService, planAligner);
final DefaultSubscriptionFactory subscriptionFactory = new DefaultSubscriptionFactory(apiService, clock, catalogService);
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java b/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
index ac17237..e75ea1b 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
@@ -31,7 +31,6 @@ import com.ning.billing.junction.api.Blockable;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.entity.Entity;
-
public interface Subscription extends Entity, Blockable {
public boolean cancel(DateTime requestedDate, boolean eot, CallContext context)
@@ -40,7 +39,7 @@ public interface Subscription extends Entity, Blockable {
public boolean uncancel(CallContext context)
throws EntitlementUserApiException;
- public boolean changePlan(String productName, BillingPeriod term, String planSet, DateTime requestedDate, CallContext context)
+ public boolean changePlan(String productName, BillingPeriod term, String priceList, DateTime requestedDate, CallContext context)
throws EntitlementUserApiException;
public boolean recreate(PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
@@ -76,4 +75,6 @@ public interface Subscription extends Entity, Blockable {
public EffectiveSubscriptionEvent getPreviousTransition();
public List<EffectiveSubscriptionEvent> getBillingTransitions();
+
+ public List<EffectiveSubscriptionEvent> getAllTransitions();
}
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index bc20699..c3b55a1 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -244,6 +244,9 @@ public enum ErrorCode {
PAYMENT_NO_SUCH_PAYMENT(7020, "Payment %s does not exist"),
PAYMENT_NO_DEFAULT_PAYMENT_METHOD(7021, "Account %s does not have a default payment method set"),
PAYMENT_DEL_DEFAULT_PAYMENT_METHOD(7022, "Cannot delete default payment method for account %s"),
+ PAYMENT_NO_SUCH_REFUND(7023, "Refund %s does not exist"),
+ PAYMENT_NO_SUCH_SUCCESS_PAYMENT(7024, "Payment %s did not succeed"),
+ PAYMENT_REFUND_AMOUNT_TOO_LARGE(7025, "Refund amount if larger than payment"),
PAYMENT_PLUGIN_TIMEOUT(7100, "Plugin timeout for account %s and invoice %s"),
PAYMENT_PLUGIN_ACCOUNT_INIT(7101, "Account initialization for account %s and plugin % s failed: %s"),
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java b/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java
index 880fc2b..102eb64 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java
@@ -39,6 +39,8 @@ public interface InvoicePayment extends Entity {
UUID getLinkedInvoicePaymentId();
+ UUID getPaymentCookieId();
+
public enum InvoicePaymentType {
ATTEMPT,
CHARGED_BACK,
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java b/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java
index a71783a..54e03bf 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java
@@ -42,7 +42,7 @@ public interface InvoicePaymentApi {
public void notifyOfPaymentAttempt(UUID invoiceId, BigDecimal amountOutstanding, Currency currency, UUID paymentAttemptId, DateTime paymentAttemptDate, CallContext context);
- public InvoicePayment createRefund(UUID paymentAttemptId, BigDecimal amount, boolean isInvoiceAdjusted, CallContext context) throws InvoiceApiException;
+ public InvoicePayment createRefund(UUID paymentAttemptId, BigDecimal amount, boolean isInvoiceAdjusted, UUID paymentCookieId, CallContext context) throws InvoiceApiException;
public InvoicePayment createChargeback(UUID invoicePaymentId, BigDecimal amount, CallContext context) throws InvoiceApiException;
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
index c8f9b2f..479966a 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
@@ -31,8 +31,17 @@ public interface PaymentApi {
public Payment createPayment(final Account account, final UUID invoiceId, final BigDecimal amount, final CallContext context)
throws PaymentApiException;
- public Refund createRefund(final Account account, final UUID paymentId, final CallContext context)
- throws PaymentApiException;
+ public Refund getRefund(final UUID refundId)
+ throws PaymentApiException;
+
+ public Refund createRefund(final Account account, final UUID paymentId, final BigDecimal refundAmount, final boolean isAdjusted, final CallContext context)
+ throws PaymentApiException;
+
+ public List<Refund> getAccountRefunds(final Account account)
+ throws PaymentApiException;
+
+ public List<Refund> getPaymentRefunds(final UUID paymentId)
+ throws PaymentApiException;
public List<Payment> getInvoicePayments(final UUID invoiceId)
throws PaymentApiException;
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentApiException.java b/api/src/main/java/com/ning/billing/payment/api/PaymentApiException.java
index 2ef846d..aa69bd0 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentApiException.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentApiException.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
@@ -18,11 +18,16 @@ package com.ning.billing.payment.api;
import com.ning.billing.BillingExceptionBase;
import com.ning.billing.ErrorCode;
import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.invoice.api.InvoiceApiException;
public class PaymentApiException extends BillingExceptionBase {
private static final long serialVersionUID = 39445033L;
+ public PaymentApiException(final InvoiceApiException e) {
+ super(e, e.getCode(), e.getMessage());
+ }
+
public PaymentApiException(final AccountApiException e) {
super(e, e.getCode(), e.getMessage());
}
diff --git a/api/src/main/java/com/ning/billing/payment/api/Refund.java b/api/src/main/java/com/ning/billing/payment/api/Refund.java
index e769e54..ed2e15c 100644
--- a/api/src/main/java/com/ning/billing/payment/api/Refund.java
+++ b/api/src/main/java/com/ning/billing/payment/api/Refund.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
@@ -15,6 +15,15 @@
*/
package com.ning.billing.payment.api;
-public interface Refund {
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import com.ning.billing.catalog.api.Currency;
+public interface Refund {
+ public UUID getId();
+ public UUID getPaymentId();
+ public boolean isAdjusted();
+ public BigDecimal getRefundAmount();
+ public Currency getCurrency();
}
diff --git a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApi.java b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApi.java
index 10b329e..5f8fe2d 100644
--- a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApi.java
+++ b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApi.java
@@ -33,8 +33,11 @@ public interface PaymentPluginApi {
public PaymentInfoPlugin getPaymentInfo(UUID paymentId)
throws PaymentPluginApiException;
- public List<PaymentInfoPlugin> processRefund(Account account)
- throws PaymentPluginApiException;
+ public void processRefund(Account account, UUID paymentId, BigDecimal refundAmout)
+ throws PaymentPluginApiException;
+
+ public int getNbRefundForPaymentAmount(final Account account, final UUID paymentId, final BigDecimal refundAmount)
+ throws PaymentPluginApiException;
public String createPaymentProviderAccount(Account account)
throws PaymentPluginApiException;
diff --git a/api/src/main/java/com/ning/billing/util/dao/ObjectType.java b/api/src/main/java/com/ning/billing/util/dao/ObjectType.java
index a158e77..b67e847 100644
--- a/api/src/main/java/com/ning/billing/util/dao/ObjectType.java
+++ b/api/src/main/java/com/ning/billing/util/dao/ObjectType.java
@@ -22,9 +22,10 @@ public enum ObjectType {
BUNDLE("subscription bundle"),
INVOICE("invoice"),
PAYMENT("payment"),
- RECURRING_INVOICE_ITEM("recurring_invoice_item"),
+ INVOICE_ITEM("invoice item"),
SUBSCRIPTION("subscription"),
- PAYMENT_METHOD("payment method");
+ PAYMENT_METHOD("payment method"),
+ REFUND("refund");
private final String objectName;
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 9dadb9e..0c7eeec 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;
@@ -52,8 +55,12 @@ import com.ning.billing.util.api.TagDefinitionApiException;
import com.ning.billing.util.dao.ObjectType;
import com.ning.billing.util.tag.TagDefinition;
+import static org.testng.Assert.assertTrue;
+
@Guice(modules = BeatrixModule.class)
public class TestAnalytics extends TestIntegrationBase {
+ private Plan subscriptionPlan;
+
@BeforeMethod(groups = "slow")
public void setUpAnalyticsHandler() throws Exception {
busService.getBus().register(analyticsListener);
@@ -65,7 +72,46 @@ public class TestAnalytics extends TestIntegrationBase {
}
@Test(groups = "slow")
- public void testAnalyticsEvents() throws Exception {
+ public void testCreateAndCancelSubscription() throws Exception {
+ // Create an account
+ final Account account = verifyAccountCreation();
+
+ // Create a bundle
+ final SubscriptionBundle bundle = verifyFirstBundle(account);
+
+ // Add a subscription
+ 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);
+
+ // Cancel end of term - refetch the subscription to have the CTD set
+ // (otherwise, cancellation would be immediate)
+ subscription = entitlementUserApi.getSubscriptionFromId(subscription.getId());
+ subscription.cancel(clock.getUTCNow(), true, context);
+
+ waitALittle();
+
+ verifyBSTWithTrialAndEvergreenPhasesAndCancellation(account, bundle, subscription);
+
+ // Move after cancel date
+ clock.addDeltaFromReality(AT_LEAST_ONE_MONTH_MS + 100);
+ assertTrue(busHandler.isCompleted(DELAY));
+ waitALittle();
+
+ // Check BST received the system cancel event
+ verifyBSTWithTrialAndEvergreenPhasesAndCancellationAndSystemCancellation(account, bundle, subscription);
+ }
+
+ @Test(groups = "slow")
+ public void testCreateAndUpdateSubscription() throws Exception {
// Create an account
final Account account = verifyAccountCreation();
@@ -192,35 +238,12 @@ public class TestAnalytics extends TestIntegrationBase {
final String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
final PlanPhaseSpecifier phaseSpecifier = new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null);
final Subscription subscription = entitlementUserApi.createSubscription(bundle.getId(), phaseSpecifier, null, context);
+ subscriptionPlan = subscription.getCurrentPlan();
waitALittle();
- // BST should have one transition
- final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
- Assert.assertEquals(transitions.size(), 1);
- final BusinessSubscriptionTransition transition = transitions.get(0);
- Assert.assertEquals(transition.getExternalKey(), bundle.getKey());
- Assert.assertEquals(transition.getAccountKey(), account.getExternalKey());
- Assert.assertEquals(transition.getEvent().getCategory(), phaseSpecifier.getProductCategory());
- Assert.assertEquals(transition.getEvent().getEventType(), BusinessSubscriptionEvent.EventType.ADD);
-
- // This is the first transition
- Assert.assertNull(transition.getPreviousSubscription());
-
- Assert.assertEquals(transition.getNextSubscription().getBillingPeriod(), subscription.getCurrentPhase().getBillingPeriod().toString());
- Assert.assertEquals(transition.getNextSubscription().getBundleId(), subscription.getBundleId());
- Assert.assertEquals(transition.getNextSubscription().getCurrency(), account.getCurrency().toString());
- Assert.assertEquals(transition.getNextSubscription().getPhase(), subscription.getCurrentPhase().getPhaseType().toString());
- // Trial: fixed price of zero
- Assert.assertEquals(transition.getNextSubscription().getPrice().doubleValue(), subscription.getCurrentPhase().getFixedPrice().getPrice(account.getCurrency()).doubleValue());
- Assert.assertEquals(transition.getNextSubscription().getPriceList(), subscription.getCurrentPriceList().getName());
- Assert.assertEquals(transition.getNextSubscription().getProductCategory(), subscription.getCurrentPlan().getProduct().getCategory());
- Assert.assertEquals(transition.getNextSubscription().getProductName(), subscription.getCurrentPlan().getProduct().getName());
- Assert.assertEquals(transition.getNextSubscription().getProductType(), subscription.getCurrentPlan().getProduct().getCatalogName());
- Assert.assertEquals(transition.getNextSubscription().getSlug(), subscription.getCurrentPhase().getName());
- Assert.assertEquals(transition.getNextSubscription().getStartDate(), subscription.getStartDate());
- Assert.assertEquals(transition.getNextSubscription().getState(), subscription.getState());
- Assert.assertEquals(transition.getNextSubscription().getSubscriptionId(), subscription.getId());
+ // Verify BST
+ verifyBSTWithTrialAndEvergreenPhases(account, bundle, subscription);
// Make sure the account balance is still zero
final BusinessAccount businessAccount = analyticsUserApi.getAccountByKey(account.getExternalKey());
@@ -260,6 +283,118 @@ public class TestAnalytics extends TestIntegrationBase {
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);
+
+ verifyTrialAndEvergreenPhases(account, bundle, subscription);
+ }
+
+ private void verifyBSTWithTrialAndEvergreenPhasesAndCancellation(final Account account, final SubscriptionBundle bundle, final Subscription subscription) throws CatalogApiException {
+ // BST should have three transitions
+ final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
+ Assert.assertEquals(transitions.size(), 3);
+
+ verifyTrialAndEvergreenPhases(account, bundle, subscription);
+ verifyCancellationTransition(account, bundle);
+ }
+
+ private void verifyBSTWithTrialAndEvergreenPhasesAndCancellationAndSystemCancellation(final Account account, final SubscriptionBundle bundle, final Subscription subscription) throws CatalogApiException {
+ // BST should have four transitions
+ final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
+ Assert.assertEquals(transitions.size(), 4);
+
+ verifyTrialAndEvergreenPhases(account, bundle, subscription);
+ verifyCancellationTransition(account, bundle);
+ verifySystemCancellationTransition(account, bundle);
+ }
+
+ private void verifyTrialAndEvergreenPhases(final Account account, final SubscriptionBundle bundle, final Subscription subscription) throws CatalogApiException {
+ final Product currentProduct = subscriptionPlan.getProduct();
+ final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
+
+ // 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(), currentProduct.getCategory());
+ Assert.assertEquals(initialTransition.getEvent().getEventType(), BusinessSubscriptionEvent.EventType.ADD);
+
+ // This is the first transition
+ Assert.assertNull(initialTransition.getPreviousSubscription());
+
+ 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(), PhaseType.TRIAL.toString());
+ // Trial: fixed price of zero
+ Assert.assertEquals(initialTransition.getNextSubscription().getPrice().doubleValue(), (double) 0);
+ Assert.assertEquals(initialTransition.getNextSubscription().getPriceList(), subscription.getCurrentPriceList().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.SubscriptionState.ACTIVE);
+ Assert.assertEquals(initialTransition.getNextSubscription().getSubscriptionId(), subscription.getId());
+
+ // Check the second transition (from trial to evergreen)
+ final BusinessSubscriptionTransition futureTransition = transitions.get(1);
+ Assert.assertEquals(futureTransition.getExternalKey(), bundle.getKey());
+ Assert.assertEquals(futureTransition.getAccountKey(), account.getExternalKey());
+ Assert.assertEquals(futureTransition.getEvent().getCategory(), currentProduct.getCategory());
+ Assert.assertEquals(futureTransition.getEvent().getEventType(), BusinessSubscriptionEvent.EventType.SYSTEM_CHANGE);
+
+ Assert.assertEquals(futureTransition.getPreviousSubscription(), initialTransition.getNextSubscription());
+
+ // 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(), 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.SubscriptionState.ACTIVE);
+ Assert.assertEquals(futureTransition.getNextSubscription().getSubscriptionId(), subscription.getId());
+ }
+
+ private void verifyCancellationTransition(final Account account, final SubscriptionBundle bundle) throws CatalogApiException {
+ final Product currentProduct = subscriptionPlan.getProduct();
+ final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
+
+ final BusinessSubscriptionTransition cancellationRequest = transitions.get(2);
+ Assert.assertEquals(cancellationRequest.getExternalKey(), bundle.getKey());
+ Assert.assertEquals(cancellationRequest.getAccountKey(), account.getExternalKey());
+ Assert.assertEquals(cancellationRequest.getEvent().getCategory(), currentProduct.getCategory());
+ Assert.assertEquals(cancellationRequest.getEvent().getEventType(), BusinessSubscriptionEvent.EventType.CANCEL);
+
+ Assert.assertNull(cancellationRequest.getNextSubscription());
+ // The actual content has already been checked in verifyTrialAndEvergreenPhases
+ Assert.assertEquals(cancellationRequest.getPreviousSubscription(), transitions.get(1).getNextSubscription());
+ }
+
+ private void verifySystemCancellationTransition(final Account account, final SubscriptionBundle bundle) throws CatalogApiException {
+ final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
+
+ final BusinessSubscriptionTransition systemCancellation = transitions.get(3);
+ Assert.assertEquals(systemCancellation.getExternalKey(), bundle.getKey());
+ Assert.assertEquals(systemCancellation.getAccountKey(), account.getExternalKey());
+ Assert.assertEquals(systemCancellation.getEvent().getCategory(), ProductCategory.BASE);
+ Assert.assertEquals(systemCancellation.getEvent().getEventType(), BusinessSubscriptionEvent.EventType.SYSTEM_CANCEL);
+
+ Assert.assertNull(systemCancellation.getNextSubscription());
+ // The actual content has already been checked in verifyTrialAndEvergreenPhases
+ Assert.assertEquals(systemCancellation.getPreviousSubscription(), transitions.get(1).getNextSubscription());
+ }
+
private void verifyChangePlan(final Account account, final SubscriptionBundle bundle, final Subscription subscription) throws EntitlementUserApiException, InterruptedException {
final String newProductName = "Assault-Rifle";
final BillingPeriod newTerm = BillingPeriod.MONTHLY;
@@ -269,9 +404,9 @@ public class TestAnalytics extends TestIntegrationBase {
waitALittle();
- // BST should have two transitions
+ // BST should have three transitions (a ADD_BASE, CHANGE_BASE and SYSTEM_CHANGE_BASE)
final List<BusinessSubscriptionTransition> transitions = analyticsUserApi.getTransitionsForBundle(bundle.getKey());
- Assert.assertEquals(transitions.size(), 2);
+ Assert.assertEquals(transitions.size(), 3);
final BusinessSubscriptionTransition previousTransition = transitions.get(0);
final BusinessSubscriptionTransition transition = transitions.get(1);
Assert.assertEquals(transition.getExternalKey(), bundle.getKey());
@@ -317,6 +452,6 @@ public class TestAnalytics extends TestIntegrationBase {
private void waitALittle() throws InterruptedException {
// We especially need to wait for entitlement events
- Thread.sleep(2000);
+ Thread.sleep(4000);
}
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
index 368dbb5..220c2ad 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
@@ -37,6 +37,7 @@ import com.ning.billing.entitlement.api.SubscriptionFactory;
import com.ning.billing.entitlement.api.SubscriptionTransitionType;
import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.NewEvent;
import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.entitlement.api.user.SubscriptionBundleData;
@@ -323,7 +324,7 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
if (nbDeleted != deletedEvents.size()) {
for (final SubscriptionTimeline.DeletedEvent d : deletedEvents) {
boolean found = false;
- for (final SubscriptionTransitionData cur : data.getAllTransitions()) {
+ for (final EffectiveSubscriptionEvent cur : data.getAllTransitions()) {
if (cur.getId().equals(d.getEventId())) {
found = true;
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java
index cdc6797..66cf27c 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java
@@ -165,7 +165,7 @@ public class SubscriptionDataRepair extends SubscriptionData {
.setRequestedDate(now)
.setUserToken(context.getUserToken())
.setFromDisk(true));
- repairDao.cancelSubscription(cur.getId(), cancelEvent, context, 0);
+ repairDao.cancelSubscription(cur, cancelEvent, context, 0);
cur.rebuildTransitions(repairDao.getEventsForSubscription(cur.getId()), catalogService.getFullCatalog());
}
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultRequestedSubscriptionEvent.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultRequestedSubscriptionEvent.java
index f03ba35..38b6b98 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultRequestedSubscriptionEvent.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultRequestedSubscriptionEvent.java
@@ -23,6 +23,7 @@ import org.joda.time.DateTime;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ning.billing.entitlement.api.SubscriptionTransitionType;
+import com.ning.billing.entitlement.events.EntitlementEvent;
public class DefaultRequestedSubscriptionEvent extends DefaultSubscriptionEvent implements RequestedSubscriptionEvent {
public DefaultRequestedSubscriptionEvent(final SubscriptionTransitionData in, final DateTime startDate) {
@@ -52,4 +53,9 @@ public class DefaultRequestedSubscriptionEvent extends DefaultSubscriptionEvent
previousPhase, previousPriceList, nextState, nextPlan, nextPhase, nextPriceList, totalOrdering, userToken,
transitionType, remainingEventsForUserOperation, startDate);
}
+
+ public DefaultRequestedSubscriptionEvent(final SubscriptionData subscription, final EntitlementEvent nextEvent) {
+ this(nextEvent.getId(), nextEvent.getSubscriptionId(), subscription.getBundleId(), nextEvent.getRequestedDate(), nextEvent.getEffectiveDate(),
+ null, null, null, null, null, null, null, null, nextEvent.getTotalOrdering(), null, null, 0, null);
+ }
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
index 4469661..99e3e58 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
@@ -139,7 +139,7 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
events.add(nextPhaseEvent);
}
if (reCreate) {
- dao.recreateSubscription(subscription.getId(), events, context);
+ dao.recreateSubscription(subscription, events, context);
} else {
dao.createSubscription(subscription, events, context);
}
@@ -179,7 +179,7 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
.setUserToken(context.getUserToken())
.setFromDisk(true));
- dao.cancelSubscription(subscription.getId(), cancelEvent, context, 0);
+ dao.cancelSubscription(subscription, cancelEvent, context, 0);
subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
return (policy == ActionPolicy.IMMEDIATE);
} catch (CatalogApiException e) {
@@ -213,7 +213,7 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
uncancelEvents.add(nextPhaseEvent);
}
- dao.uncancelSubscription(subscription.getId(), uncancelEvents, context);
+ dao.uncancelSubscription(subscription, uncancelEvents, context);
subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
return true;
@@ -285,7 +285,7 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
changeEvents.add(nextPhaseEvent);
}
changeEvents.add(changeEvent);
- dao.changePlan(subscription.getId(), changeEvents, context);
+ dao.changePlan(subscription, changeEvents, context);
subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
return (policy == ActionPolicy.IMMEDIATE);
} catch (CatalogApiException e) {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
index 409bc8d..d5586e9 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
@@ -303,8 +303,19 @@ public class SubscriptionData extends EntityBase implements Subscription {
return activeVersion;
}
- public List<SubscriptionTransitionData> getAllTransitions() {
- return transitions;
+ @Override
+ public List<EffectiveSubscriptionEvent> getAllTransitions() {
+ if (transitions == null) {
+ return Collections.emptyList();
+ }
+
+ final List<EffectiveSubscriptionEvent> result = new ArrayList<EffectiveSubscriptionEvent>();
+ final SubscriptionTransitionDataIterator it = new SubscriptionTransitionDataIterator(clock, transitions, Order.ASC_FROM_PAST, Kind.ALL, Visibility.ALL, TimeLimit.ALL);
+ while (it.hasNext()) {
+ result.add(new DefaultEffectiveSubscriptionEvent(it.next(), startDate));
+ }
+
+ return result;
}
public SubscriptionTransitionData getInitialTransitionForCurrentPlan() {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
index ac54ea3..d3707fa 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
@@ -30,8 +30,6 @@ import com.ning.billing.entitlement.events.user.ApiEventType;
import com.ning.billing.entitlement.exceptions.EntitlementError;
public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
-
-
private final Long totalOrdering;
private final UUID subscriptionId;
private final UUID bundleId;
@@ -52,7 +50,6 @@ public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
private final Integer remainingEventsForUserOperation;
private final UUID userToken;
-
public SubscriptionTransitionData(final UUID eventId,
final UUID subscriptionId,
final UUID bundleId,
@@ -71,7 +68,6 @@ public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
final Long totalOrdering,
final UUID userToken,
final Boolean isFromDisk) {
- super();
this.eventId = eventId;
this.subscriptionId = subscriptionId;
this.bundleId = bundleId;
@@ -116,7 +112,6 @@ public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
this.remainingEventsForUserOperation = remainingEventsForUserOperation;
}
-
public UUID getId() {
return eventId;
}
@@ -153,7 +148,6 @@ public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
return nextState;
}
-
public PriceList getPreviousPriceList() {
return previousPriceList;
}
@@ -170,7 +164,6 @@ public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
return remainingEventsForUserOperation;
}
-
public SubscriptionTransitionType getTransitionType() {
return toSubscriptionTransitionType(eventType, apiEventType);
}
@@ -194,7 +187,6 @@ public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
return effectiveTransitionTime;
}
-
public Long getTotalOrdering() {
return totalOrdering;
}
@@ -211,21 +203,126 @@ public class SubscriptionTransitionData /* implements SubscriptionEvent */ {
return eventType;
}
-
@Override
public String toString() {
- return "SubscriptionTransition [eventId=" + eventId
- + ", subscriptionId=" + subscriptionId
- + ", eventType=" + eventType + ", apiEventType="
- + apiEventType + ", requestedTransitionTime=" + requestedTransitionTime
- + ", effectiveTransitionTime=" + effectiveTransitionTime
- + ", previousState=" + previousState + ", previousPlan="
- + ((previousPlan != null) ? previousPlan.getName() : null)
- + ", previousPhase=" + ((previousPhase != null) ? previousPhase.getName() : null)
- + ", previousPriceList " + previousPriceList
- + ", nextState=" + nextState
- + ", nextPlan=" + ((nextPlan != null) ? nextPlan.getName() : null)
- + ", nextPriceList " + nextPriceList
- + ", nextPhase=" + ((nextPhase != null) ? nextPhase.getName() : null) + "]";
+ final StringBuilder sb = new StringBuilder();
+ sb.append("SubscriptionTransitionData");
+ sb.append("{apiEventType=").append(apiEventType);
+ sb.append(", totalOrdering=").append(totalOrdering);
+ sb.append(", subscriptionId=").append(subscriptionId);
+ sb.append(", bundleId=").append(bundleId);
+ sb.append(", eventId=").append(eventId);
+ sb.append(", eventType=").append(eventType);
+ sb.append(", requestedTransitionTime=").append(requestedTransitionTime);
+ sb.append(", effectiveTransitionTime=").append(effectiveTransitionTime);
+ sb.append(", previousState=").append(previousState);
+ sb.append(", previousPriceList=").append(previousPriceList);
+ sb.append(", previousPlan=").append(previousPlan);
+ sb.append(", previousPhase=").append(previousPhase);
+ sb.append(", nextState=").append(nextState);
+ sb.append(", nextPriceList=").append(nextPriceList);
+ sb.append(", nextPlan=").append(nextPlan);
+ sb.append(", nextPhase=").append(nextPhase);
+ sb.append(", isFromDisk=").append(isFromDisk);
+ sb.append(", remainingEventsForUserOperation=").append(remainingEventsForUserOperation);
+ sb.append(", userToken=").append(userToken);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final SubscriptionTransitionData that = (SubscriptionTransitionData) o;
+
+ if (apiEventType != that.apiEventType) {
+ return false;
+ }
+ if (bundleId != null ? !bundleId.equals(that.bundleId) : that.bundleId != null) {
+ return false;
+ }
+ if (effectiveTransitionTime != null ? effectiveTransitionTime.compareTo(that.effectiveTransitionTime) != 0 : that.effectiveTransitionTime != null) {
+ return false;
+ }
+ if (eventId != null ? !eventId.equals(that.eventId) : that.eventId != null) {
+ return false;
+ }
+ if (eventType != that.eventType) {
+ return false;
+ }
+ if (isFromDisk != null ? !isFromDisk.equals(that.isFromDisk) : that.isFromDisk != null) {
+ return false;
+ }
+ if (nextPhase != null ? !nextPhase.equals(that.nextPhase) : that.nextPhase != null) {
+ return false;
+ }
+ if (nextPlan != null ? !nextPlan.equals(that.nextPlan) : that.nextPlan != null) {
+ return false;
+ }
+ if (nextPriceList != null ? !nextPriceList.equals(that.nextPriceList) : that.nextPriceList != null) {
+ return false;
+ }
+ if (nextState != that.nextState) {
+ return false;
+ }
+ if (previousPhase != null ? !previousPhase.equals(that.previousPhase) : that.previousPhase != null) {
+ return false;
+ }
+ if (previousPlan != null ? !previousPlan.equals(that.previousPlan) : that.previousPlan != null) {
+ return false;
+ }
+ if (previousPriceList != null ? !previousPriceList.equals(that.previousPriceList) : that.previousPriceList != null) {
+ return false;
+ }
+ if (previousState != that.previousState) {
+ return false;
+ }
+ if (remainingEventsForUserOperation != null ? !remainingEventsForUserOperation.equals(that.remainingEventsForUserOperation) : that.remainingEventsForUserOperation != null) {
+ return false;
+ }
+ if (requestedTransitionTime != null ? requestedTransitionTime.compareTo(that.requestedTransitionTime) != 0 : that.requestedTransitionTime != null) {
+ return false;
+ }
+ if (subscriptionId != null ? !subscriptionId.equals(that.subscriptionId) : that.subscriptionId != null) {
+ return false;
+ }
+ if (totalOrdering != null ? !totalOrdering.equals(that.totalOrdering) : that.totalOrdering != null) {
+ return false;
+ }
+ if (userToken != null ? !userToken.equals(that.userToken) : that.userToken != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = totalOrdering != null ? totalOrdering.hashCode() : 0;
+ result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0);
+ result = 31 * result + (bundleId != null ? bundleId.hashCode() : 0);
+ result = 31 * result + (eventId != null ? eventId.hashCode() : 0);
+ result = 31 * result + (eventType != null ? eventType.hashCode() : 0);
+ result = 31 * result + (apiEventType != null ? apiEventType.hashCode() : 0);
+ result = 31 * result + (requestedTransitionTime != null ? requestedTransitionTime.hashCode() : 0);
+ result = 31 * result + (effectiveTransitionTime != null ? effectiveTransitionTime.hashCode() : 0);
+ result = 31 * result + (previousState != null ? previousState.hashCode() : 0);
+ result = 31 * result + (previousPriceList != null ? previousPriceList.hashCode() : 0);
+ result = 31 * result + (previousPlan != null ? previousPlan.hashCode() : 0);
+ result = 31 * result + (previousPhase != null ? previousPhase.hashCode() : 0);
+ result = 31 * result + (nextState != null ? nextState.hashCode() : 0);
+ result = 31 * result + (nextPriceList != null ? nextPriceList.hashCode() : 0);
+ result = 31 * result + (nextPlan != null ? nextPlan.hashCode() : 0);
+ result = 31 * result + (nextPhase != null ? nextPhase.hashCode() : 0);
+ result = 31 * result + (isFromDisk != null ? isFromDisk.hashCode() : 0);
+ result = 31 * result + (remainingEventsForUserOperation != null ? remainingEventsForUserOperation.hashCode() : 0);
+ result = 31 * result + (userToken != null ? userToken.hashCode() : 0);
+ return result;
}
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
index a4a926e..57b21d3 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
@@ -16,15 +16,11 @@
package com.ning.billing.entitlement.engine.core;
-
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
-import javax.swing.text.html.HTMLDocument.HTMLReader.IsindexAction;
-
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -69,8 +65,6 @@ import com.ning.billing.util.notificationq.NotificationQueueService.Notification
import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
public class Engine implements EventListener, EntitlementService {
-
-
public static final String NOTIFICATION_QUEUE_NAME = "subscription-events";
public static final String ENTITLEMENT_SERVICE_NAME = "entitlement-service";
@@ -81,21 +75,20 @@ public class Engine implements EventListener, EntitlementService {
private final PlanAligner planAligner;
private final AddonUtils addonUtils;
private final Bus eventBus;
-
private final EntitlementConfig config;
private final NotificationQueueService notificationQueueService;
private final CallContextFactory factory;
private final SubscriptionFactory subscriptionFactory;
+
private NotificationQueue subscriptionEventQueue;
@Inject
public Engine(final Clock clock, final EntitlementDao dao, final PlanAligner planAligner,
- final EntitlementConfig config,
- final AddonUtils addonUtils, final Bus eventBus,
- final NotificationQueueService notificationQueueService,
- final SubscriptionFactory subscriptionFactory,
- final CallContextFactory factory) {
- super();
+ final EntitlementConfig config,
+ final AddonUtils addonUtils, final Bus eventBus,
+ final NotificationQueueService notificationQueueService,
+ final SubscriptionFactory subscriptionFactory,
+ final CallContextFactory factory) {
this.clock = clock;
this.dao = dao;
this.planAligner = planAligner;
@@ -114,32 +107,29 @@ public class Engine implements EventListener, EntitlementService {
@LifecycleHandlerType(LifecycleLevel.INIT_SERVICE)
public void initialize() {
-
try {
- subscriptionEventQueue = notificationQueueService.createNotificationQueue(ENTITLEMENT_SERVICE_NAME,
- NOTIFICATION_QUEUE_NAME,
- new NotificationQueueHandler() {
+ final NotificationQueueHandler queueHandler = new NotificationQueueHandler() {
@Override
public void handleReadyNotification(final NotificationKey inputKey, final DateTime eventDateTime) {
-
- if (! (inputKey instanceof EntitlementNotificationKey)) {
+ if (!(inputKey instanceof EntitlementNotificationKey)) {
log.error("Entitlement service received an unexpected event type {}" + inputKey.getClass().getName());
return;
}
- EntitlementNotificationKey key = (EntitlementNotificationKey) inputKey;
-
- final EntitlementEvent event = dao.getEventById(key.getEventId());
+
+ final EntitlementNotificationKey key = (EntitlementNotificationKey) inputKey;
+ final EntitlementEvent event = dao.getEventById(key.getEventId());
if (event == null) {
log.warn("Failed to extract event for notification key {}", inputKey);
return;
}
+
final UUID userToken = (event.getType() == EventType.API_USER) ? ((ApiEvent) event).getUserToken() : null;
final CallContext context = factory.createCallContext("SubscriptionEventQueue", CallOrigin.INTERNAL, UserType.SYSTEM, userToken);
processEventReady(event, key.getSeqId(), context);
}
- },
- new NotificationConfig() {
+ };
+ final NotificationConfig notificationConfig = new NotificationConfig() {
@Override
public long getSleepTimeMs() {
return config.getSleepTimeMs();
@@ -149,8 +139,12 @@ public class Engine implements EventListener, EntitlementService {
public boolean isNotificationProcessingOff() {
return config.isNotificationProcessingOff();
}
- }
- );
+ };
+
+ subscriptionEventQueue = notificationQueueService.createNotificationQueue(ENTITLEMENT_SERVICE_NAME,
+ NOTIFICATION_QUEUE_NAME,
+ queueHandler,
+ notificationConfig);
} catch (NotificationQueueAlreadyExists e) {
throw new RuntimeException(e);
}
@@ -169,12 +163,12 @@ public class Engine implements EventListener, EntitlementService {
}
}
-
@Override
public void processEventReady(final EntitlementEvent event, final int seqId, final CallContext context) {
if (!event.isActive()) {
return;
}
+
final SubscriptionData subscription = (SubscriptionData) dao.getSubscriptionFromId(subscriptionFactory, event.getSubscriptionId());
if (subscription == null) {
log.warn("Failed to retrieve subscription for id %s", event.getSubscriptionId());
@@ -192,10 +186,10 @@ public class Engine implements EventListener, EntitlementService {
int theRealSeqId = seqId;
if (event.getType() == EventType.PHASE) {
onPhaseEvent(subscription, context);
- } else if (event.getType() == EventType.API_USER &&
- subscription.getCategory() == ProductCategory.BASE) {
+ } else if (event.getType() == EventType.API_USER && subscription.getCategory() == ProductCategory.BASE) {
theRealSeqId = onBasePlanEvent(subscription, (ApiEvent) event, context);
}
+
try {
eventBus.post(subscription.getTransitionFromEvent(event, theRealSeqId));
} catch (EventBusException e) {
@@ -203,41 +197,36 @@ public class Engine implements EventListener, EntitlementService {
}
}
-
private void onPhaseEvent(final SubscriptionData subscription, final CallContext context) {
try {
final DateTime now = clock.getUTCNow();
final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, now, now);
final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
PhaseEventData.createNextPhaseEvent(nextTimedPhase.getPhase().getName(), subscription, now, nextTimedPhase.getStartPhase()) :
- null;
- if (nextPhaseEvent != null) {
- dao.createNextPhaseEvent(subscription.getId(), nextPhaseEvent, context);
- }
+ null;
+ if (nextPhaseEvent != null) {
+ dao.createNextPhaseEvent(subscription, nextPhaseEvent, context);
+ }
} catch (EntitlementError e) {
log.error(String.format("Failed to insert next phase for subscription %s", subscription.getId()), e);
}
}
private int onBasePlanEvent(final SubscriptionData baseSubscription, final ApiEvent event, final CallContext context) {
-
final DateTime now = clock.getUTCNow();
-
- final Product baseProduct = (baseSubscription.getState() == SubscriptionState.CANCELLED) ?
- null : baseSubscription.getCurrentPlan().getProduct();
+ final Product baseProduct = (baseSubscription.getState() == SubscriptionState.CANCELLED) ? null : baseSubscription.getCurrentPlan().getProduct();
final List<Subscription> subscriptions = dao.getSubscriptions(subscriptionFactory, baseSubscription.getBundleId());
-
final Map<UUID, EntitlementEvent> addOnCancellations = new HashMap<UUID, EntitlementEvent>();
-
- final Iterator<Subscription> it = subscriptions.iterator();
- while (it.hasNext()) {
- final SubscriptionData cur = (SubscriptionData) it.next();
+ final Map<UUID, SubscriptionData> addOnCancellationSubscriptions = new HashMap<UUID, SubscriptionData>();
+ for (final Subscription subscription : subscriptions) {
+ final SubscriptionData cur = (SubscriptionData) subscription;
if (cur.getState() == SubscriptionState.CANCELLED ||
cur.getCategory() != ProductCategory.ADD_ON) {
continue;
}
+
final Plan addonCurrentPlan = cur.getCurrentPlan();
if (baseProduct == null ||
addonUtils.isAddonIncluded(baseProduct, addonCurrentPlan) ||
@@ -246,23 +235,26 @@ public class Engine implements EventListener, EntitlementService {
// Perform AO cancellation using the effectiveDate of the BP
//
final EntitlementEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder()
- .setSubscriptionId(cur.getId())
- .setActiveVersion(cur.getActiveVersion())
- .setProcessedDate(now)
- .setEffectiveDate(event.getEffectiveDate())
- .setRequestedDate(now)
- .setUserToken(context.getUserToken())
- .setFromDisk(true));
+ .setSubscriptionId(cur.getId())
+ .setActiveVersion(cur.getActiveVersion())
+ .setProcessedDate(now)
+ .setEffectiveDate(event.getEffectiveDate())
+ .setRequestedDate(now)
+ .setUserToken(context.getUserToken())
+ .setFromDisk(true));
addOnCancellations.put(cur.getId(), cancelEvent);
+ addOnCancellationSubscriptions.put(cur.getId(), cur);
}
}
+
final int addOnSize = addOnCancellations.size();
int cancelSeq = addOnSize - 1;
for (final UUID key : addOnCancellations.keySet()) {
- dao.cancelSubscription(key, addOnCancellations.get(key), context, cancelSeq);
+ dao.cancelSubscription(addOnCancellationSubscriptions.get(key), addOnCancellations.get(key), context, cancelSeq);
cancelSeq--;
}
+
return addOnSize;
}
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java
index 2d7f212..24c7cca 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/AuditedEntitlementDao.java
@@ -40,6 +40,7 @@ import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.inject.Inject;
import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.entitlement.api.SubscriptionFactory;
@@ -49,6 +50,7 @@ import com.ning.billing.entitlement.api.migration.AccountMigrationData.Subscript
import com.ning.billing.entitlement.api.timeline.DefaultRepairEntitlementEvent;
import com.ning.billing.entitlement.api.timeline.RepairEntitlementEvent;
import com.ning.billing.entitlement.api.timeline.SubscriptionDataRepair;
+import com.ning.billing.entitlement.api.user.DefaultRequestedSubscriptionEvent;
import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.entitlement.api.user.SubscriptionBundle;
@@ -87,10 +89,11 @@ public class AuditedEntitlementDao implements EntitlementDao {
private final NotificationQueueService notificationQueueService;
private final AddonUtils addonUtils;
private final Bus eventBus;
+ private final CatalogService catalogService;
@Inject
public AuditedEntitlementDao(final IDBI dbi, final Clock clock, final AddonUtils addonUtils,
- final NotificationQueueService notificationQueueService, final Bus eventBus) {
+ final NotificationQueueService notificationQueueService, final Bus eventBus, final CatalogService catalogService) {
this.clock = clock;
this.subscriptionsDao = dbi.onDemand(SubscriptionSqlDao.class);
this.eventsDao = dbi.onDemand(EntitlementEventSqlDao.class);
@@ -98,6 +101,7 @@ public class AuditedEntitlementDao implements EntitlementDao {
this.notificationQueueService = notificationQueueService;
this.addonUtils = addonUtils;
this.eventBus = eventBus;
+ this.catalogService = catalogService;
}
@Override
@@ -206,10 +210,11 @@ public class AuditedEntitlementDao implements EntitlementDao {
}
@Override
- public void createNextPhaseEvent(final UUID subscriptionId, final EntitlementEvent nextPhase, final CallContext context) {
+ public void createNextPhaseEvent(final SubscriptionData subscription, final EntitlementEvent nextPhase, final CallContext context) {
eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
@Override
public Void inTransaction(final EntitlementEventSqlDao transactional, final TransactionStatus status) throws Exception {
+ final UUID subscriptionId = subscription.getId();
cancelNextPhaseEventFromTransaction(subscriptionId, transactional, context);
transactional.insertEvent(nextPhase, context);
@@ -221,6 +226,9 @@ public class AuditedEntitlementDao implements EntitlementDao {
nextPhase.getEffectiveDate(),
new EntitlementNotificationKey(nextPhase.getId()));
+ // Notify the Bus of the requested change
+ notifyBusOfRequestedChange(transactional, subscription, nextPhase);
+
return null;
}
});
@@ -290,13 +298,19 @@ public class AuditedEntitlementDao implements EntitlementDao {
}
eventsDaoFromSameTransaction.insertAuditFromTransaction(audits, context);
+
+ // Notify the Bus of the latest requested change, if needed
+ if (initialEvents.size() > 0) {
+ notifyBusOfRequestedChange(eventsDaoFromSameTransaction, subscription, initialEvents.get(initialEvents.size() - 1));
+ }
+
return null;
}
});
}
@Override
- public void recreateSubscription(final UUID subscriptionId, final List<EntitlementEvent> recreateEvents, final CallContext context) {
+ public void recreateSubscription(final SubscriptionData subscription, final List<EntitlementEvent> recreateEvents, final CallContext context) {
eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
@Override
public Void inTransaction(final EntitlementEventSqlDao transactional,
@@ -313,16 +327,21 @@ public class AuditedEntitlementDao implements EntitlementDao {
}
transactional.insertAuditFromTransaction(audits, context);
+
+ // Notify the Bus of the latest requested change
+ notifyBusOfRequestedChange(transactional, subscription, recreateEvents.get(recreateEvents.size() - 1));
+
return null;
}
});
}
@Override
- public void cancelSubscription(final UUID subscriptionId, final EntitlementEvent cancelEvent, final CallContext context, final int seqId) {
+ public void cancelSubscription(final SubscriptionData subscription, final EntitlementEvent cancelEvent, final CallContext context, final int seqId) {
eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
@Override
public Void inTransaction(final EntitlementEventSqlDao transactional, final TransactionStatus status) throws Exception {
+ final UUID subscriptionId = subscription.getId();
cancelNextCancelEventFromTransaction(subscriptionId, transactional, context);
cancelNextChangeEventFromTransaction(subscriptionId, transactional, context);
cancelNextPhaseEventFromTransaction(subscriptionId, transactional, context);
@@ -336,16 +355,21 @@ public class AuditedEntitlementDao implements EntitlementDao {
recordFutureNotificationFromTransaction(transactional,
cancelEvent.getEffectiveDate(),
new EntitlementNotificationKey(cancelEvent.getId(), seqId));
+
+ // Notify the Bus of the requested change
+ notifyBusOfRequestedChange(transactional, subscription, cancelEvent);
+
return null;
}
});
}
@Override
- public void uncancelSubscription(final UUID subscriptionId, final List<EntitlementEvent> uncancelEvents, final CallContext context) {
+ public void uncancelSubscription(final SubscriptionData subscription, final List<EntitlementEvent> uncancelEvents, final CallContext context) {
eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
@Override
public Void inTransaction(final EntitlementEventSqlDao transactional, final TransactionStatus status) throws Exception {
+ final UUID subscriptionId = subscription.getId();
EntitlementEvent cancelledEvent = null;
final Date now = clock.getUTCNow().toDate();
final List<EntitlementEvent> events = transactional.getFutureActiveEventForSubscription(subscriptionId.toString(), now);
@@ -377,17 +401,22 @@ public class AuditedEntitlementDao implements EntitlementDao {
}
transactional.insertAuditFromTransaction(eventAudits, context);
+
+ // Notify the Bus of the latest requested change
+ notifyBusOfRequestedChange(transactional, subscription, uncancelEvents.get(uncancelEvents.size() - 1));
}
+
return null;
}
});
}
@Override
- public void changePlan(final UUID subscriptionId, final List<EntitlementEvent> changeEvents, final CallContext context) {
+ public void changePlan(final SubscriptionData subscription, final List<EntitlementEvent> changeEvents, final CallContext context) {
eventsDao.inTransaction(new Transaction<Void, EntitlementEventSqlDao>() {
@Override
public Void inTransaction(final EntitlementEventSqlDao transactional, final TransactionStatus status) throws Exception {
+ final UUID subscriptionId = subscription.getId();
cancelNextChangeEventFromTransaction(subscriptionId, transactional, context);
cancelNextPhaseEventFromTransaction(subscriptionId, transactional, context);
@@ -403,6 +432,11 @@ public class AuditedEntitlementDao implements EntitlementDao {
}
transactional.insertAuditFromTransaction(eventAudits, context);
+
+ // Notify the Bus of the latest requested change
+ final EntitlementEvent finalEvent = changeEvents.get(changeEvents.size() - 1);
+ notifyBusOfRequestedChange(transactional, subscription, finalEvent);
+
return null;
}
});
@@ -559,7 +593,6 @@ public class AuditedEntitlementDao implements EntitlementDao {
final SubscriptionBundleData bundleData = curBundle.getData();
for (final SubscriptionMigrationData curSubscription : curBundle.getSubscriptions()) {
-
final SubscriptionData subData = curSubscription.getData();
for (final EntitlementEvent curEvent : curSubscription.getInitialEvents()) {
transactional.insertEvent(curEvent, context);
@@ -573,7 +606,12 @@ public class AuditedEntitlementDao implements EntitlementDao {
transSubDao.insertSubscription(subData, context);
recordId = transSubDao.getRecordId(subData.getId().toString());
audits.add(new EntityAudit(TableName.SUBSCRIPTIONS, recordId, ChangeType.INSERT));
+
+ // Notify the Bus of the latest requested change
+ final EntitlementEvent finalEvent = curSubscription.getInitialEvents().get(curSubscription.getInitialEvents().size() - 1);
+ notifyBusOfRequestedChange(transactional, subData, finalEvent);
}
+
transBundleDao.insertBundle(bundleData, context);
recordId = transBundleDao.getRecordId(bundleData.getId().toString());
audits.add(new EntityAudit(TableName.BUNDLES, recordId, ChangeType.INSERT));
@@ -608,6 +646,7 @@ public class AuditedEntitlementDao implements EntitlementDao {
}
try {
+ // Note: we don't send a requested change event here, but a repair event
final RepairEntitlementEvent busEvent = new DefaultRepairEntitlementEvent(context.getUserToken(), accountId, bundleId, clock.getUTCNow());
eventBus.postFromTransaction(busEvent, transactional);
} catch (EventBusException e) {
@@ -641,4 +680,12 @@ public class AuditedEntitlementDao implements EntitlementDao {
throw new RuntimeException(e);
}
}
+
+ private void notifyBusOfRequestedChange(final EntitlementEventSqlDao transactional, final SubscriptionData subscription, final EntitlementEvent nextEvent) {
+ try {
+ eventBus.postFromTransaction(new DefaultRequestedSubscriptionEvent(subscription, nextEvent), transactional);
+ } catch (EventBusException e) {
+ log.warn("Failed to post requested change event for subscription " + subscription.getId(), e);
+ }
+ }
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
index 710391b..b85a47a 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
@@ -56,7 +56,7 @@ public interface EntitlementDao {
public void updateChargedThroughDate(final SubscriptionData subscription, final CallContext context);
// Event apis
- public void createNextPhaseEvent(final UUID subscriptionId, final EntitlementEvent nextPhase, final CallContext context);
+ public void createNextPhaseEvent(final SubscriptionData subscription, final EntitlementEvent nextPhase, final CallContext context);
public EntitlementEvent getEventById(final UUID eventId);
@@ -69,13 +69,13 @@ public interface EntitlementDao {
// Subscription creation, cancellation, changePlan apis
public void createSubscription(final SubscriptionData subscription, final List<EntitlementEvent> initialEvents, final CallContext context);
- public void recreateSubscription(final UUID subscriptionId, final List<EntitlementEvent> recreateEvents, final CallContext context);
+ public void recreateSubscription(final SubscriptionData subscription, final List<EntitlementEvent> recreateEvents, final CallContext context);
- public void cancelSubscription(final UUID subscriptionId, final EntitlementEvent cancelEvent, final CallContext context, final int cancelSeq);
+ public void cancelSubscription(final SubscriptionData subscription, final EntitlementEvent cancelEvent, final CallContext context, final int cancelSeq);
- public void uncancelSubscription(final UUID subscriptionId, final List<EntitlementEvent> uncancelEvents, final CallContext context);
+ public void uncancelSubscription(final SubscriptionData subscription, final List<EntitlementEvent> uncancelEvents, final CallContext context);
- public void changePlan(final UUID subscriptionId, final List<EntitlementEvent> changeEvents, final CallContext context);
+ public void changePlan(final SubscriptionData subscription, final List<EntitlementEvent> changeEvents, final CallContext context);
public void migrate(final UUID accountId, final AccountMigrationData data, final CallContext context);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
index 653e1ca..ed9cf13 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
@@ -92,14 +92,15 @@ public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLi
}
@Override
- public void recreateSubscription(final UUID subscriptionId,
+ public void recreateSubscription(final SubscriptionData subscription,
final List<EntitlementEvent> recreateEvents, final CallContext context) {
- addEvents(subscriptionId, recreateEvents);
+ addEvents(subscription.getId(), recreateEvents);
}
@Override
- public void cancelSubscription(final UUID subscriptionId,
+ public void cancelSubscription(final SubscriptionData subscription,
final EntitlementEvent cancelEvent, final CallContext context, final int cancelSeq) {
+ final UUID subscriptionId = subscription.getId();
final long activeVersion = cancelEvent.getActiveVersion();
addEvents(subscriptionId, Collections.singletonList(cancelEvent));
final SubscriptionRepairEvent target = getRepairSubscriptionEvents(subscriptionId);
@@ -114,9 +115,9 @@ public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLi
}
@Override
- public void changePlan(final UUID subscriptionId,
+ public void changePlan(final SubscriptionData subscription,
final List<EntitlementEvent> changeEvents, final CallContext context) {
- addEvents(subscriptionId, changeEvents);
+ addEvents(subscription.getId(), changeEvents);
}
@Override
@@ -142,7 +143,7 @@ public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLi
}
@Override
- public void uncancelSubscription(final UUID subscriptionId,
+ public void uncancelSubscription(final SubscriptionData subscription,
final List<EntitlementEvent> uncancelEvents, final CallContext context) {
throw new EntitlementError(NOT_IMPLEMENTED);
}
@@ -204,7 +205,7 @@ public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLi
}
@Override
- public void createNextPhaseEvent(final UUID subscriptionId,
+ public void createNextPhaseEvent(final SubscriptionData subscription,
final EntitlementEvent nextPhase, final CallContext context) {
throw new EntitlementError(NOT_IMPLEMENTED);
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestPlanAligner.java b/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestPlanAligner.java
index 400da99..6579baa 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestPlanAligner.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/alignment/TestPlanAligner.java
@@ -36,6 +36,7 @@ import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.io.VersionedCatalogLoader;
import com.ning.billing.config.CatalogConfig;
import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory;
+import com.ning.billing.entitlement.api.user.EffectiveSubscriptionEvent;
import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
import com.ning.billing.entitlement.api.user.SubscriptionData;
import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
@@ -201,7 +202,7 @@ public class TestPlanAligner {
subscriptionData.rebuildTransitions(ImmutableList.<EntitlementEvent>of(previousEvent, event), catalogService.getFullCatalog());
- final List<SubscriptionTransitionData> newTransitions = subscriptionData.getAllTransitions();
+ final List<EffectiveSubscriptionEvent> newTransitions = subscriptionData.getAllTransitions();
Assert.assertEquals(newTransitions.size(), 2);
Assert.assertNull(newTransitions.get(0).getPreviousPhase());
Assert.assertEquals(newTransitions.get(0).getNextPhase(), newTransitions.get(1).getPreviousPhase());
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
index ec5c17e..06032f7 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
@@ -169,7 +169,7 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
}
@Override
- public void recreateSubscription(final UUID subscriptionId,
+ public void recreateSubscription(final SubscriptionData subscription,
final List<EntitlementEvent> recreateEvents, final CallContext context) {
synchronized (events) {
@@ -233,9 +233,9 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
}
@Override
- public void createNextPhaseEvent(final UUID subscriptionId, final EntitlementEvent nextPhase,
+ public void createNextPhaseEvent(final SubscriptionData subscription, final EntitlementEvent nextPhase,
final CallContext context) {
- cancelNextPhaseEvent(subscriptionId);
+ cancelNextPhaseEvent(subscription.getId());
insertEvent(nextPhase);
}
@@ -271,20 +271,20 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
}
@Override
- public void cancelSubscription(final UUID subscriptionId, final EntitlementEvent cancelEvent,
+ public void cancelSubscription(final SubscriptionData subscription, final EntitlementEvent cancelEvent,
final CallContext context, final int seqId) {
synchronized (events) {
- cancelNextPhaseEvent(subscriptionId);
+ cancelNextPhaseEvent(subscription.getId());
insertEvent(cancelEvent);
}
}
@Override
- public void changePlan(final UUID subscriptionId, final List<EntitlementEvent> changeEvents,
+ public void changePlan(final SubscriptionData subscription, final List<EntitlementEvent> changeEvents,
final CallContext context) {
synchronized (events) {
- cancelNextChangeEvent(subscriptionId);
- cancelNextPhaseEvent(subscriptionId);
+ cancelNextChangeEvent(subscription.getId());
+ cancelNextPhaseEvent(subscription.getId());
events.addAll(changeEvents);
for (final EntitlementEvent cur : changeEvents) {
recordFutureNotificationFromTransaction(null, cur.getEffectiveDate(), new EntitlementNotificationKey(cur.getId()));
@@ -348,7 +348,7 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
}
@Override
- public void uncancelSubscription(final UUID subscriptionId, final List<EntitlementEvent> uncancelEvents,
+ public void uncancelSubscription(final SubscriptionData subscription, final List<EntitlementEvent> uncancelEvents,
final CallContext context) {
synchronized (events) {
@@ -356,7 +356,7 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
final Iterator<EntitlementEvent> it = events.descendingIterator();
while (it.hasNext()) {
final EntitlementEvent cur = it.next();
- if (cur.getSubscriptionId() != subscriptionId) {
+ if (cur.getSubscriptionId() != subscription.getId()) {
continue;
}
if (cur.getType() == EventType.API_USER &&
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
index 929f03d..6a93d3c 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
@@ -24,6 +24,7 @@ import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
import com.google.inject.Inject;
+import com.ning.billing.catalog.api.CatalogService;
import com.ning.billing.entitlement.engine.addon.AddonUtils;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.clock.Clock;
@@ -35,8 +36,8 @@ public class MockEntitlementDaoSql extends AuditedEntitlementDao implements Mock
@Inject
public MockEntitlementDaoSql(final IDBI dbi, final Clock clock, final AddonUtils addonUtils, final NotificationQueueService notificationQueueService,
- final Bus eventBus) {
- super(dbi, clock, addonUtils, notificationQueueService, eventBus);
+ final Bus eventBus, final CatalogService catalogService) {
+ super(dbi, clock, addonUtils, notificationQueueService, eventBus, catalogService);
this.resetDao = dbi.onDemand(ResetSqlDao.class);
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java b/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java
index a73fab7..be8aa79 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java
@@ -111,8 +111,8 @@ public class DefaultInvoicePaymentApi implements InvoicePaymentApi {
@Override
public InvoicePayment createRefund(UUID paymentAttemptId,
- BigDecimal amount, boolean isInvoiceAdjusted, CallContext context)
+ BigDecimal amount, boolean isInvoiceAdjusted, UUID paymentCookieId, CallContext context)
throws InvoiceApiException {
- return dao.createRefund(paymentAttemptId, amount, isInvoiceAdjusted, context);
+ return dao.createRefund(paymentAttemptId, amount, isInvoiceAdjusted, paymentCookieId, context);
}
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index c0539a9..b09e347 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -298,12 +298,13 @@ public class DefaultInvoiceDao implements InvoiceDao {
@Override
public InvoicePayment createRefund(final UUID paymentAttemptId,
- final BigDecimal amount, final boolean isInvoiceAdjusted, final CallContext context)
+ final BigDecimal amount, final boolean isInvoiceAdjusted, final UUID paymentCookieId, final CallContext context)
throws InvoiceApiException {
return invoicePaymentSqlDao.inTransaction(new Transaction<InvoicePayment, InvoicePaymentSqlDao>() {
@Override
public InvoicePayment inTransaction(final InvoicePaymentSqlDao transactional, final TransactionStatus status) throws Exception {
+
final InvoicePayment payment = transactional.getByPaymentAttemptId(paymentAttemptId.toString());
if (payment == null) {
throw new InvoiceApiException(ErrorCode.INVOICE_PAYMENT_BY_ATTEMPT_NOT_FOUND, paymentAttemptId);
@@ -322,7 +323,7 @@ public class DefaultInvoiceDao implements InvoiceDao {
final InvoicePayment refund = new DefaultInvoicePayment(UUID.randomUUID(), InvoicePaymentType.REFUND, paymentAttemptId,
- payment.getInvoiceId(), context.getCreatedDate(), requestedPositiveAmount.negate(), payment.getCurrency(), payment.getId());
+ payment.getInvoiceId(), context.getCreatedDate(), requestedPositiveAmount.negate(), payment.getCurrency(), paymentCookieId, payment.getId());
transactional.create(refund, context);
// Retrieve invoice after the Refund
@@ -382,7 +383,7 @@ public class DefaultInvoiceDao implements InvoiceDao {
throw new InvoiceApiException(ErrorCode.INVOICE_PAYMENT_NOT_FOUND, invoicePaymentId.toString());
} else {
final InvoicePayment chargeBack = new DefaultInvoicePayment(UUID.randomUUID(), InvoicePaymentType.CHARGED_BACK, null,
- payment.getInvoiceId(), context.getCreatedDate(), requestedChargedBackAmout.negate(), payment.getCurrency(), payment.getId());
+ payment.getInvoiceId(), context.getCreatedDate(), requestedChargedBackAmout.negate(), payment.getCurrency(), null, payment.getId());
invoicePaymentSqlDao.create(chargeBack, context);
return chargeBack;
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
index 209285b..443f07a 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
@@ -67,7 +67,7 @@ public interface InvoiceDao {
InvoicePayment postChargeback(final UUID invoicePaymentId, final BigDecimal amount, final CallContext context) throws InvoiceApiException;
InvoicePayment createRefund(UUID paymentAttemptId,
- BigDecimal amount, boolean isInvoiceAdjusted, CallContext context) throws InvoiceApiException;
+ BigDecimal amount, boolean isInvoiceAdjusted, UUID paymentCookieId, CallContext context) throws InvoiceApiException;
BigDecimal getRemainingAmountPaid(final UUID invoicePaymentId);
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
index ed5b2c3..6ca968d 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
@@ -111,10 +111,11 @@ public interface InvoicePaymentSqlDao extends EntitySqlDao<InvoicePayment>, Tran
final BigDecimal amount = result.getBigDecimal("amount");
final String currencyString = result.getString("currency");
final Currency currency = (currencyString == null) ? null : Currency.valueOf(currencyString);
+ final UUID paymentCookieId = getUUID(result, "payment_cookie_id");
final UUID linkedInvoicePaymentId = getUUID(result, "linked_invoice_payment_id");
return new DefaultInvoicePayment(id, type, paymentAttemptId, invoiceId, paymentAttemptDate,
- amount, currency, linkedInvoicePaymentId);
+ amount, currency, paymentCookieId, linkedInvoicePaymentId);
}
}
@@ -136,6 +137,7 @@ public interface InvoicePaymentSqlDao extends EntitySqlDao<InvoicePayment>, Tran
q.bind("amount", payment.getAmount());
final Currency currency = payment.getCurrency();
q.bind("currency", (currency == null) ? null : currency.toString());
+ q.bind("paymentCookieId", uuidToString(payment.getPaymentCookieId()));
q.bind("linkedInvoicePaymentId", uuidToString(payment.getLinkedInvoicePaymentId()));
}
};
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java
index 08371ed..6145f07 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java
@@ -33,16 +33,17 @@ public class DefaultInvoicePayment extends EntityBase implements InvoicePayment
private final DateTime paymentDate;
private final BigDecimal amount;
private final Currency currency;
- private final UUID reversedInvoicePaymentId;
+ private final UUID paymentCookieId;
+ private final UUID linkedInvoicePaymentId;
public DefaultInvoicePayment(final InvoicePaymentType type, final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate,
final BigDecimal amount, final Currency currency) {
- this(UUID.randomUUID(), type, paymentAttemptId, invoiceId, paymentDate, amount, currency, null);
+ this(UUID.randomUUID(), type, paymentAttemptId, invoiceId, paymentDate, amount, currency, null, null);
}
public DefaultInvoicePayment(final UUID id, final InvoicePaymentType type, final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate,
- @Nullable final BigDecimal amount, @Nullable final Currency currency,
- @Nullable final UUID reversedInvoicePaymentId) {
+ @Nullable final BigDecimal amount, @Nullable final Currency currency, final UUID paymentCookieId,
+ @Nullable final UUID linkedInvoicePaymentId) {
super(id);
this.type = type;
this.paymentAttemptId = paymentAttemptId;
@@ -50,7 +51,8 @@ public class DefaultInvoicePayment extends EntityBase implements InvoicePayment
this.invoiceId = invoiceId;
this.paymentDate = paymentDate;
this.currency = currency;
- this.reversedInvoicePaymentId = reversedInvoicePaymentId;
+ this.paymentCookieId = paymentCookieId;
+ this.linkedInvoicePaymentId = linkedInvoicePaymentId;
}
@Override
@@ -85,6 +87,12 @@ public class DefaultInvoicePayment extends EntityBase implements InvoicePayment
@Override
public UUID getLinkedInvoicePaymentId() {
- return reversedInvoicePaymentId;
+ return linkedInvoicePaymentId;
}
+
+ @Override
+ public UUID getPaymentCookieId() {
+ return paymentCookieId;
+ }
+
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
index 55a2e8f..9499378 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
@@ -29,6 +29,7 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
+
package com.ning.billing.invoice.template.formatters;
import java.math.BigDecimal;
@@ -41,6 +42,9 @@ import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
+import com.google.common.base.Objects;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceItem;
@@ -48,6 +52,9 @@ import com.ning.billing.invoice.api.InvoicePayment;
import com.ning.billing.invoice.api.formatters.InvoiceFormatter;
import com.ning.billing.util.template.translation.TranslatorConfig;
+/**
+ * Format invoice fields. Note that the Mustache engine won't accept null values.
+ */
public class DefaultInvoiceFormatter implements InvoiceFormatter {
private final TranslatorConfig config;
private final Invoice invoice;
@@ -63,7 +70,7 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
@Override
public Integer getInvoiceNumber() {
- return invoice.getInvoiceNumber();
+ return Objects.firstNonNull(invoice.getInvoiceNumber(), 0);
}
@Override
@@ -87,7 +94,7 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
@Override
public <T extends InvoiceItem> List<InvoiceItem> getInvoiceItems(final Class<T> clazz) {
- return invoice.getInvoiceItems(clazz);
+ return Objects.firstNonNull(invoice.getInvoiceItems(clazz), ImmutableList.<InvoiceItem>of());
}
@Override
@@ -107,7 +114,7 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
@Override
public List<InvoicePayment> getPayments() {
- return invoice.getPayments();
+ return Objects.firstNonNull(invoice.getPayments(), ImmutableList.<InvoicePayment>of());
}
@Override
@@ -122,18 +129,17 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
@Override
public BigDecimal getChargedAmount() {
- return invoice.getChargedAmount();
+ return Objects.firstNonNull(invoice.getChargedAmount(), BigDecimal.ZERO);
}
@Override
public BigDecimal getCBAAmount() {
- return invoice.getCBAAmount();
+ return Objects.firstNonNull(invoice.getCBAAmount(), BigDecimal.ZERO);
}
-
@Override
public BigDecimal getBalance() {
- return invoice.getBalance();
+ return Objects.firstNonNull(invoice.getBalance(), BigDecimal.ZERO);
}
@Override
@@ -168,12 +174,17 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
@Override
public BigDecimal getPaidAmount() {
- return invoice.getPaidAmount();
+ return Objects.firstNonNull(invoice.getPaidAmount(), BigDecimal.ZERO);
}
@Override
public String getFormattedInvoiceDate() {
- return invoice.getInvoiceDate().toString(dateFormatter);
+ final DateTime invoiceDate = invoice.getInvoiceDate();
+ if (invoiceDate == null) {
+ return "";
+ } else {
+ return Strings.nullToEmpty(invoiceDate.toString(dateFormatter));
+ }
}
@Override
@@ -201,16 +212,16 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
@Override
public BigDecimal getTotalAdjAmount() {
- return invoice.getTotalAdjAmount();
+ return Objects.firstNonNull(invoice.getTotalAdjAmount(), BigDecimal.ZERO);
}
@Override
public BigDecimal getCreditAdjAmount() {
- return invoice.getCreditAdjAmount();
+ return Objects.firstNonNull(invoice.getCreditAdjAmount(), BigDecimal.ZERO);
}
@Override
public BigDecimal getRefundAdjAmount() {
- return invoice.getRefundAdjAmount();
+ return Objects.firstNonNull(invoice.getRefundAdjAmount(), BigDecimal.ZERO);
}
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
index 3f4ff92..86be83b 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
@@ -23,6 +23,8 @@ import java.util.UUID;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
+import com.google.common.base.Objects;
+import com.google.common.base.Strings;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.InvoiceItem;
import com.ning.billing.invoice.api.InvoiceItemType;
@@ -31,6 +33,9 @@ import com.ning.billing.util.template.translation.DefaultCatalogTranslator;
import com.ning.billing.util.template.translation.Translator;
import com.ning.billing.util.template.translation.TranslatorConfig;
+/**
+ * Format invoice item fields. Note that the Mustache engine won't accept null values.
+ */
public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
private final Translator translator;
@@ -48,7 +53,7 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
@Override
public BigDecimal getAmount() {
- return item.getAmount();
+ return Objects.firstNonNull(item.getAmount(), BigDecimal.ZERO);
}
@Override
@@ -60,16 +65,10 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
public InvoiceItemType getInvoiceItemType() {
return item.getInvoiceItemType();
}
-/*
- @Override
- public InvoiceItem asReversingItem() {
- return item.asReversingItem();
- }
- */
@Override
public String getDescription() {
- return item.getDescription();
+ return Strings.nullToEmpty(item.getDescription());
}
@Override
@@ -84,12 +83,12 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
@Override
public String getFormattedStartDate() {
- return item.getStartDate().toString(dateFormatter);
+ return Strings.nullToEmpty(item.getStartDate().toString(dateFormatter));
}
@Override
public String getFormattedEndDate() {
- return item.getEndDate().toString(dateFormatter);
+ return Strings.nullToEmpty(item.getEndDate().toString(dateFormatter));
}
@Override
@@ -114,12 +113,12 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
@Override
public String getPlanName() {
- return translator.getTranslation(locale, item.getPlanName());
+ return Strings.nullToEmpty(translator.getTranslation(locale, item.getPlanName()));
}
@Override
public String getPhaseName() {
- return translator.getTranslation(locale, item.getPhaseName());
+ return Strings.nullToEmpty(translator.getTranslation(locale, item.getPhaseName()));
}
@Override
@@ -134,7 +133,7 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
@Override
public BigDecimal getRate() {
- return null;
+ return BigDecimal.ZERO;
}
@Override
diff --git a/invoice/src/main/java/com/ning/billing/invoice/template/HtmlInvoiceGenerator.java b/invoice/src/main/java/com/ning/billing/invoice/template/HtmlInvoiceGenerator.java
index f27bce7..04c5075 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/template/HtmlInvoiceGenerator.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/template/HtmlInvoiceGenerator.java
@@ -16,6 +16,7 @@
package com.ning.billing.invoice.template;
+import javax.annotation.Nullable;
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
@@ -42,7 +43,12 @@ public class HtmlInvoiceGenerator {
this.config = config;
}
- public String generateInvoice(final Account account, final Invoice invoice) throws IOException {
+ public String generateInvoice(final Account account, @Nullable final Invoice invoice) throws IOException {
+ // Don't do anything if the invoice is null
+ if (invoice == null) {
+ return null;
+ }
+
final Map<String, Object> data = new HashMap<String, Object>();
final DefaultInvoiceTranslator invoiceTranslator = new DefaultInvoiceTranslator(config);
final Locale locale = new Locale(account.getLocale());
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
index f201331..a028cf6 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
@@ -8,6 +8,7 @@ invoicePaymentFields(prefix) ::= <<
<prefix>payment_attempt_date,
<prefix>amount,
<prefix>currency,
+ <prefix>payment_cookie_id,
<prefix>linked_invoice_payment_id,
<prefix>created_by,
<prefix>created_date
@@ -16,13 +17,13 @@ invoicePaymentFields(prefix) ::= <<
create() ::= <<
INSERT INTO invoice_payments(<invoicePaymentFields()>)
VALUES(:id, :type, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency,
- :linkedInvoicePaymentId, :userName, :createdDate);
+ :paymentCookieId, :linkedInvoicePaymentId, :userName, :createdDate);
>>
batchCreateFromTransaction() ::= <<
INSERT INTO invoice_payments(<invoicePaymentFields()>)
VALUES(:id, :type, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency,
- :linkedInvoicePaymentId, :userName, :createdDate);
+ :paymentCookieId, :linkedInvoicePaymentId, :userName, :createdDate);
>>
getByPaymentAttemptId() ::= <<
@@ -51,7 +52,7 @@ getPaymentsForInvoice() ::= <<
notifyOfPaymentAttempt() ::= <<
INSERT INTO invoice_payments(<invoicePaymentFields()>)
VALUES(:id, :type, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency,
- :linkedInvoicePaymentId, :userName, :createdDate);
+ :paymentCookieId, :linkedInvoicePaymentId, :userName, :createdDate);
>>
getInvoicePayment() ::= <<
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
index a408d3c..b6bd51f 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
+++ b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
@@ -52,6 +52,7 @@ CREATE TABLE invoice_payments (
payment_attempt_date datetime NOT NULL,
amount numeric(10,4) NOT NULL,
currency char(3) NOT NULL,
+ payment_cookie_id char(36) DEFAULT NULL,
linked_invoice_payment_id char(36) DEFAULT NULL,
created_by varchar(50) NOT NULL,
created_date datetime NOT NULL,
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java
index af2c854..a049bcf 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java
@@ -108,7 +108,7 @@ public class MockInvoicePaymentApi implements InvoicePaymentApi {
if (existingPayment != null) {
invoicePayments.add(new DefaultInvoicePayment(UUID.randomUUID(), InvoicePaymentType.CHARGED_BACK, null, null, DateTime.now(DateTimeZone.UTC), amount,
- Currency.USD, existingPayment.getId()));
+ Currency.USD, null, existingPayment.getId()));
}
return existingPayment;
@@ -168,7 +168,7 @@ public class MockInvoicePaymentApi implements InvoicePaymentApi {
@Override
public InvoicePayment createRefund(UUID paymentAttemptId,
- BigDecimal amount, boolean isInvoiceAdjusted, CallContext context)
+ BigDecimal amount, boolean isInvoiceAdjusted, UUID paymentCookieId, CallContext context)
throws InvoiceApiException {
// TODO Auto-generated method stub
return null;
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
index a2e8a34..da91371 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
@@ -260,7 +260,7 @@ public class MockInvoiceDao implements InvoiceDao {
@Override
public InvoicePayment createRefund(UUID paymentAttemptId,
- BigDecimal amount, boolean isInvoiceAdjusted, CallContext context)
+ BigDecimal amount, boolean isInvoiceAdjusted, UUID paymentCookieId, CallContext context)
throws InvoiceApiException {
// TODO Auto-generated method stub
return null;
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
index 160038e..bf8c4a4 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
@@ -584,7 +584,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
balance = invoiceDao.getAccountBalance(accountId);
assertEquals(balance.compareTo(new BigDecimal("0.00")), 0);
- invoiceDao.createRefund(paymentAttemptId, refund1, withAdjustment, context);
+ invoiceDao.createRefund(paymentAttemptId, refund1, withAdjustment, null, context);
balance = invoiceDao.getAccountBalance(accountId);
if (withAdjustment) {
assertEquals(balance.compareTo(BigDecimal.ZERO), 0);
@@ -678,7 +678,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
assertEquals(cba.compareTo(new BigDecimal("10.00")), 0);
// PARTIAL REFUND on the payment
- invoiceDao.createRefund(paymentAttemptId, refundAmount, withAdjustment, context);
+ invoiceDao.createRefund(paymentAttemptId, refundAmount, withAdjustment, null, context);
balance = invoiceDao.getAccountBalance(accountId);
assertEquals(balance.compareTo(expectedFinalBalance), 0);
@@ -745,7 +745,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
assertEquals(cba.compareTo(new BigDecimal("10.00")), 0);
// partial REFUND on the payment (along with CBA generated by the system)
- final InvoicePayment refund = new DefaultInvoicePayment(UUID.randomUUID(), InvoicePaymentType.ATTEMPT, UUID.randomUUID(), invoice1.getId(), new DateTime(), rate2.negate(), Currency.USD, payment.getId());
+ final InvoicePayment refund = new DefaultInvoicePayment(UUID.randomUUID(), InvoicePaymentType.ATTEMPT, UUID.randomUUID(), invoice1.getId(), new DateTime(), rate2.negate(), Currency.USD, null, payment.getId());
invoicePaymentDao.create(refund, context);
final CreditBalanceAdjInvoiceItem cbaItem2 = new CreditBalanceAdjInvoiceItem(invoice1.getId(), accountId, new DateTime(), rate2.negate(), Currency.USD);
invoiceItemSqlDao.create(cbaItem2, context);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/TestHtmlInvoiceGenerator.java b/invoice/src/test/java/com/ning/billing/invoice/TestHtmlInvoiceGenerator.java
index 2847e0b..8c9ace4 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/TestHtmlInvoiceGenerator.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/TestHtmlInvoiceGenerator.java
@@ -22,7 +22,9 @@ import java.util.List;
import java.util.Locale;
import org.joda.time.DateTime;
+import org.mockito.Mockito;
import org.skife.config.ConfigurationObjectFactory;
+import org.testng.Assert;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;
@@ -39,12 +41,10 @@ import com.ning.billing.util.email.templates.MustacheTemplateEngine;
import com.ning.billing.util.email.templates.TemplateEngine;
import com.ning.billing.util.template.translation.TranslatorConfig;
-import static org.testng.Assert.assertNotNull;
-
public class TestHtmlInvoiceGenerator {
private HtmlInvoiceGenerator g;
- @BeforeSuite(groups = {"fast"})
+ @BeforeSuite(groups = "fast")
public void setup() {
final TranslatorConfig config = new ConfigurationObjectFactory(System.getProperties()).build(TranslatorConfig.class);
final TemplateEngine templateEngine = new MustacheTemplateEngine();
@@ -52,11 +52,23 @@ public class TestHtmlInvoiceGenerator {
g = new HtmlInvoiceGenerator(factory, templateEngine, config);
}
- @Test(groups = {"fast"})
+ @Test(groups = "fast")
public void testGenerateInvoice() throws Exception {
final String output = g.generateInvoice(createAccount(), createInvoice());
- assertNotNull(output);
- System.out.print(output);
+ Assert.assertNotNull(output);
+ }
+
+ @Test(groups = "fast")
+ public void testGenerateEmptyInvoice() throws Exception {
+ final Invoice invoice = Mockito.mock(Invoice.class);
+ final String output = g.generateInvoice(createAccount(), invoice);
+ Assert.assertNotNull(output);
+ }
+
+ @Test(groups = "fast")
+ public void testGenerateNullInvoice() throws Exception {
+ final String output = g.generateInvoice(createAccount(), null);
+ Assert.assertNull(output);
}
private Account createAccount() {
@@ -110,7 +122,6 @@ public class TestHtmlInvoiceGenerator {
zombie.addResult("getPlanName", planName);
zombie.addResult("getDescription", networkName);
-
return item;
}
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/TestChargeBacks.java b/invoice/src/test/java/com/ning/billing/invoice/tests/TestChargeBacks.java
index a9b2627..114fa8d 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/TestChargeBacks.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/TestChargeBacks.java
@@ -259,7 +259,7 @@ public class TestChargeBacks {
zombie.addResult("getAmount", amount);
zombie.addResult("getCurrency", CURRENCY);
zombie.addResult("getLinkedInvoicePaymentId", BrainDeadProxyFactory.ZOMBIE_VOID);
-
+ zombie.addResult("getPaymentCookieId", BrainDeadProxyFactory.ZOMBIE_VOID);
invoicePaymentApi.notifyOfPaymentAttempt(payment, context);
return payment;
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/RefundJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/RefundJson.java
new file mode 100644
index 0000000..8c4b812
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/RefundJson.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.math.BigDecimal;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ning.billing.payment.api.Refund;
+
+
+public class RefundJson {
+
+ private final String paymentId;
+ private final BigDecimal refundAmount;
+ private final Boolean isAdjusted;
+
+ public RefundJson(Refund input) {
+ this(input.getPaymentId().toString(), input.getRefundAmount(), input.isAdjusted());
+ }
+
+ @JsonCreator
+ public RefundJson(@JsonProperty("paymentId") String paymentId,
+ @JsonProperty("refundAmount") BigDecimal refundAmount,
+ @JsonProperty("isAdjusted") final Boolean isAdjusted) {
+ super();
+ this.paymentId = paymentId;
+ this.refundAmount = refundAmount;
+ this.isAdjusted = isAdjusted;
+ }
+
+ public RefundJson() {
+ this(null, null, null);
+ }
+
+ public String getPaymentId() {
+ return paymentId;
+ }
+
+ public BigDecimal getRefundAmount() {
+ return refundAmount;
+ }
+
+ public boolean isAdjusted() {
+ return isAdjusted;
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
index d96edd4..0dec7e0 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
@@ -68,6 +68,7 @@ import com.ning.billing.jaxrs.json.CustomFieldJson;
import com.ning.billing.jaxrs.json.InvoiceEmailJson;
import com.ning.billing.jaxrs.json.PaymentJsonSimple;
import com.ning.billing.jaxrs.json.PaymentMethodJson;
+import com.ning.billing.jaxrs.json.RefundJson;
import com.ning.billing.jaxrs.util.Context;
import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
import com.ning.billing.jaxrs.util.TagHelper;
@@ -75,6 +76,7 @@ import com.ning.billing.payment.api.Payment;
import com.ning.billing.payment.api.PaymentApi;
import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentMethod;
+import com.ning.billing.payment.api.Refund;
import com.ning.billing.util.api.CustomFieldUserApi;
import com.ning.billing.util.api.TagUserApi;
import com.ning.billing.util.dao.ObjectType;
@@ -126,7 +128,11 @@ public class AccountResource extends JaxRsResourceBase {
final AccountJson json = new AccountJson(account);
return Response.status(Status.OK).entity(json).build();
} catch (AccountApiException e) {
- return Response.status(Status.NO_CONTENT).build();
+ if (e.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID.getCode()) {
+ return Response.status(Status.NO_CONTENT).build();
+ } else {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
}
}
@@ -148,7 +154,11 @@ public class AccountResource extends JaxRsResourceBase {
});
return Response.status(Status.OK).entity(result).build();
} catch (AccountApiException e) {
- return Response.status(Status.NO_CONTENT).build();
+ if (e.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID.getCode()) {
+ return Response.status(Status.NO_CONTENT).build();
+ } else {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
}
}
@@ -166,7 +176,11 @@ public class AccountResource extends JaxRsResourceBase {
final AccountJson json = new AccountJson(account);
return Response.status(Status.OK).entity(json).build();
} catch (AccountApiException e) {
- return Response.status(Status.NO_CONTENT).build();
+ if (e.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY.getCode()) {
+ return Response.status(Status.NO_CONTENT).build();
+ } else {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
}
}
@@ -253,7 +267,11 @@ public class AccountResource extends JaxRsResourceBase {
final AccountTimelineJson json = new AccountTimelineJson(account, invoices, payments, bundlesTimeline);
return Response.status(Status.OK).entity(json).build();
} catch (AccountApiException e) {
- return Response.status(Status.NO_CONTENT).build();
+ if (e.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID.getCode()) {
+ return Response.status(Status.NO_CONTENT).build();
+ } else {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
} catch (PaymentApiException e) {
log.error(e.getMessage());
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
@@ -277,7 +295,11 @@ public class AccountResource extends JaxRsResourceBase {
return Response.status(Status.OK).entity(invoiceEmailJson).build();
} catch (AccountApiException e) {
- return Response.status(Status.NOT_FOUND).build();
+ if (e.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID.getCode()) {
+ return Response.status(Status.NO_CONTENT).build();
+ } else {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
}
}
@@ -300,7 +322,11 @@ public class AccountResource extends JaxRsResourceBase {
return Response.status(Status.OK).build();
} catch (AccountApiException e) {
- return Response.status(Status.NOT_FOUND).build();
+ if (e.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID.getCode()) {
+ return Response.status(Status.NO_CONTENT).build();
+ } else {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
}
}
@@ -322,7 +348,7 @@ public class AccountResource extends JaxRsResourceBase {
}
return Response.status(Status.OK).entity(result).build();
} catch (PaymentApiException e) {
- return Response.status(Status.NOT_FOUND).build();
+ return Response.status(Status.BAD_REQUEST).build();
}
}
@@ -343,9 +369,11 @@ public class AccountResource extends JaxRsResourceBase {
final UUID paymentMethodId = paymentApi.addPaymentMethod(data.getPluginName(), account, isDefault, data.getPluginDetail(), context.createContext(createdBy, reason, comment));
return uriBuilder.buildResponse(PaymentMethodResource.class, "getPaymentMethod", paymentMethodId, uriInfo.getBaseUri().toString());
} catch (AccountApiException e) {
- final String error = String.format("Failed to create account %s", json);
- log.info(error, e);
- return Response.status(Status.BAD_REQUEST).entity(error).build();
+ if (e.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID.getCode()) {
+ return Response.status(Status.NO_CONTENT).build();
+ } else {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
} catch (PaymentApiException e) {
final String error = String.format("Failed to create payment Method %s", json);
log.info(error, e);
@@ -377,7 +405,11 @@ public class AccountResource extends JaxRsResourceBase {
} catch (PaymentApiException e) {
return Response.status(Status.NOT_FOUND).build();
} catch (AccountApiException e) {
- return Response.status(Status.NOT_FOUND).build();
+ if (e.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID.getCode()) {
+ return Response.status(Status.NO_CONTENT).build();
+ } else {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
}
}
@@ -395,7 +427,11 @@ public class AccountResource extends JaxRsResourceBase {
paymentApi.setDefaultPaymentMethod(account, UUID.fromString(paymentMethodId), context.createContext(createdBy, reason, comment));
return Response.status(Status.OK).build();
} catch (AccountApiException e) {
- return Response.status(Status.BAD_REQUEST).build();
+ if (e.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID.getCode()) {
+ return Response.status(Status.NO_CONTENT).build();
+ } else {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
} catch (PaymentApiException e) {
return Response.status(Status.NOT_FOUND).build();
} catch (IllegalArgumentException e) {
@@ -403,6 +439,38 @@ public class AccountResource extends JaxRsResourceBase {
}
}
+
+ /*
+ * ************************** REFUNDS ********************************
+ */
+ @GET
+ @Path("/{accountId:" + UUID_PATTERN + "}/" + REFUNDS)
+ @Produces(APPLICATION_JSON)
+ public Response getRefunds(@PathParam("accountId") final String accountId) {
+
+ try {
+ final Account account = accountApi.getAccountById(UUID.fromString(accountId));
+ List<Refund> refunds = paymentApi.getAccountRefunds(account);
+ List<RefundJson> result = new ArrayList<RefundJson>(Collections2.transform(refunds, new Function<Refund, RefundJson>() {
+ @Override
+ public RefundJson apply(Refund input) {
+ return new RefundJson(input);
+ }
+ }));
+ return Response.status(Status.OK).entity(result).build();
+ } catch (AccountApiException e) {
+ if (e.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID.getCode()) {
+ return Response.status(Status.NO_CONTENT).build();
+ } else {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
+ } catch (PaymentApiException e) {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
+ }
+
+
+
/*
* ************************* CUSTOM FIELDS *****************************
*/
@@ -518,7 +586,11 @@ public class AccountResource extends JaxRsResourceBase {
} catch (RuntimeException e) {
return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();
} catch (AccountApiException e) {
- return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();
+ if (e.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID.getCode()) {
+ return Response.status(Status.NO_CONTENT).build();
+ } else {
+ return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();
+ }
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/ChargebackResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/ChargebackResource.java
index 2ce2493..c08c01a 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/ChargebackResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/ChargebackResource.java
@@ -159,6 +159,7 @@ public class ChargebackResource implements JaxrsResource {
return Response.status(Response.Status.NO_CONTENT).entity(error).build();
}
+ // STEPH that does not seem to work, we need to find the correct attempt
final UUID paymentAttemptId = attempts.iterator().next().getId();
final InvoicePayment invoicePayment = invoicePaymentApi.getInvoicePayment(paymentAttemptId);
if (invoicePayment == null) {
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
index 16c6bc5..984f633 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
@@ -79,6 +79,9 @@ public interface JaxrsResource {
public static final String PAYMENTS = "payments";
public static final String PAYMENTS_PATH = PREFIX + "/" + PAYMENTS;
+ public static final String REFUNDS = "refunds";
+ public static final String REFUNDS_PATH = PREFIX + "/" + "refunds";
+
public static final String PAYMENT_METHODS = "paymentMethods";
public static final String PAYMENT_METHODS_PATH = PREFIX + "/" + PAYMENT_METHODS;
public static final String PAYMENT_METHODS_DEFAULT_PATH_POSTFIX = "setDefault";
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java
index bdff8e8..8dc98a9 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java
@@ -42,10 +42,11 @@ import com.ning.billing.util.tag.Tag;
import com.ning.billing.util.tag.TagDefinition;
public abstract class JaxRsResourceBase implements JaxrsResource {
- private final JaxrsUriBuilder uriBuilder;
- private final TagUserApi tagUserApi;
- private final TagHelper tagHelper;
- private final CustomFieldUserApi customFieldUserApi;
+
+ protected final JaxrsUriBuilder uriBuilder;
+ protected final TagUserApi tagUserApi;
+ protected final TagHelper tagHelper;
+ protected final CustomFieldUserApi customFieldUserApi;
protected abstract ObjectType getObjectType();
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
index 5f53ab3..264c620 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
@@ -26,14 +26,30 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.account.api.AccountData;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.jaxrs.json.AccountJson;
import com.ning.billing.jaxrs.json.CustomFieldJson;
+import com.ning.billing.jaxrs.json.RefundJson;
import com.ning.billing.jaxrs.util.Context;
import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
import com.ning.billing.jaxrs.util.TagHelper;
+import com.ning.billing.payment.api.Payment;
+import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
+import com.ning.billing.payment.api.Refund;
import com.ning.billing.util.api.CustomFieldUserApi;
import com.ning.billing.util.api.TagUserApi;
import com.ning.billing.util.dao.ObjectType;
@@ -48,13 +64,70 @@ public class PaymentResource extends JaxRsResourceBase {
private static final String TAG_URI = JaxrsResource.TAGS + "/{" + ID_PARAM_NAME + ":" + UUID_PATTERN + "}";
private final Context context;
+ private final PaymentApi paymentApi;
+ private final AccountUserApi accountApi;
@Inject
- public PaymentResource(final JaxrsUriBuilder uriBuilder, final TagUserApi tagUserApi,
- final TagHelper tagHelper, final CustomFieldUserApi customFieldUserApi,
- final Context context) {
+ public PaymentResource(final JaxrsUriBuilder uriBuilder,
+ final AccountUserApi accountApi,
+ final PaymentApi paymentApi,
+ final TagUserApi tagUserApi,
+ final TagHelper tagHelper,
+ final CustomFieldUserApi customFieldUserApi,
+ final Context context) {
super(uriBuilder, tagUserApi, tagHelper, customFieldUserApi);
this.context = context;
+ this.paymentApi = paymentApi;
+ this.accountApi = accountApi;
+ }
+
+
+ @GET
+ @Path("/{paymentId:" + UUID_PATTERN + "}/" + REFUNDS)
+ @Produces(APPLICATION_JSON)
+ public Response getRefunds(@PathParam("paymentId") final String paymentId) {
+
+ try {
+ List<Refund> refunds = paymentApi.getPaymentRefunds(UUID.fromString(paymentId));
+ List<RefundJson> result = new ArrayList<RefundJson>(Collections2.transform(refunds, new Function<Refund, RefundJson>() {
+ @Override
+ public RefundJson apply(Refund input) {
+ return new RefundJson(input);
+ }
+ }));
+ return Response.status(Status.OK).entity(result).build();
+ } catch (PaymentApiException e) {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
+ }
+
+ @POST
+ @Path("/{paymentId:" + UUID_PATTERN + "}/" + REFUNDS)
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Response createRefund(final RefundJson json,
+ @PathParam("paymentId") final String paymentId,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
+
+ try {
+ final UUID paymentUuid = UUID.fromString(paymentId);
+ final Payment payment = paymentApi.getPayment(paymentUuid);
+
+ final Account account = accountApi.getAccountById(payment.getAccountId());
+
+ Refund result = paymentApi.createRefund(account, paymentUuid, json.getRefundAmount(), json.isAdjusted(), context.createContext(createdBy, reason, comment));
+ return uriBuilder.buildResponse(RefundResource.class, "getRefund", result.getId());
+ } catch (AccountApiException e) {
+ if (e.getCode() == ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID.getCode()) {
+ return Response.status(Status.NO_CONTENT).build();
+ } else {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
+ } catch (PaymentApiException e) {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
}
@GET
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/RefundResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/RefundResource.java
index 05acf58..63e72c0 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/RefundResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/RefundResource.java
@@ -16,6 +16,68 @@
package com.ning.billing.jaxrs.resources;
-public class RefundResource {
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.ning.billing.jaxrs.json.RefundJson;
+import com.ning.billing.jaxrs.util.Context;
+import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
+import com.ning.billing.jaxrs.util.TagHelper;
+import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
+import com.ning.billing.payment.api.Refund;
+import com.ning.billing.util.api.CustomFieldUserApi;
+import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.dao.ObjectType;
+
+
+@Path(JaxrsResource.REFUNDS_PATH)
+public class RefundResource extends JaxRsResourceBase {
+
+ private static final Logger log = LoggerFactory.getLogger(RefundResource.class);
+
+ private final PaymentApi paymentApi;
+
+ @Inject
+ public RefundResource(final JaxrsUriBuilder uriBuilder,
+ final PaymentApi paymentApi,
+ final TagUserApi tagUserApi,
+ final TagHelper tagHelper,
+ final CustomFieldUserApi customFieldUserApi,
+ final Context context) {
+ super(uriBuilder, tagUserApi, tagHelper, customFieldUserApi);
+ this.paymentApi = paymentApi;
+ }
+
+ @GET
+ @Path("/{refundId:" + UUID_PATTERN + "}")
+ @Produces(APPLICATION_JSON)
+ public Response getRefund(@PathParam("refundId") final String refundId) {
+ try {
+ Refund refund = paymentApi.getRefund(UUID.fromString(refundId));
+ return Response.status(Status.OK).entity(new RefundJson(refund)).build();
+ } catch (PaymentApiException e) {
+ // STEPH NO_CONTENT if oes not exist
+ return Response.status(Status.BAD_REQUEST).build();
+ }
+ }
+
+ @Override
+ protected ObjectType getObjectType() {
+ return ObjectType.REFUND;
+ }
}
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java
index aa03560..fb41a88 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java
@@ -128,6 +128,11 @@ public class BlockingSubscription implements Subscription {
return subscription.getBillingTransitions();
}
+ @Override
+ public List<EffectiveSubscriptionEvent> getAllTransitions() {
+ return subscription.getAllTransitions();
+ }
+
public BlockingState getBlockingState() {
if (blockingState == null) {
blockingState = blockingApi.getBlockingStateFor(this);
@@ -138,6 +143,4 @@ public class BlockingSubscription implements Subscription {
public Subscription getDelegateSubscription() {
return subscription;
}
-
-
}
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java
index ee83777..2a31a6e 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java
@@ -16,7 +16,6 @@
package com.ning.billing.junction.plumbing.billing;
-
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
@@ -67,6 +66,8 @@ import com.ning.billing.junction.api.DefaultBlockingState;
import com.ning.billing.lifecycle.KillbillService.ServiceException;
import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.mock.MockEffectiveSubscriptionEvent;
+import com.ning.billing.mock.MockSubscription;
import com.ning.billing.util.api.TagUserApi;
import com.ning.billing.util.callcontext.CallContextFactory;
import com.ning.billing.util.callcontext.DefaultCallContextFactory;
@@ -141,7 +142,6 @@ public class TestBillingApi {
};
-
private Clock clock;
private Subscription subscription;
private DateTime subscriptionStartDate;
@@ -163,39 +163,11 @@ public class TestBillingApi {
//new SubscriptionBundleData( eventId,"TestKey", subId, clock.getUTCNow().minusDays(4), null);
bundles.add(bundle);
-
effectiveSubscriptionTransitions = new LinkedList<EffectiveSubscriptionEvent>();
final List<Subscription> subscriptions = new LinkedList<Subscription>();
subscriptionStartDate = clock.getUTCNow().minusDays(3);
- subscription = new MockSubscription() {
- @Override
- public List<EffectiveSubscriptionEvent> getBillingTransitions() {
- return effectiveSubscriptionTransitions;
- }
-
- @Override
- public Plan getCurrentPlan() {
- return subscriptionPlan;
- }
-
- @Override
- public UUID getId() {
- return subId;
- }
-
- @Override
- public UUID getBundleId() {
- return bunId;
- }
-
- @Override
- public DateTime getStartDate() {
- return subscriptionStartDate;
- }
-
-
- };
+ subscription = new MockSubscription(subId, bunId, subscriptionPlan, subscriptionStartDate, effectiveSubscriptionTransitions);
subscriptions.add(subscription);
@@ -308,7 +280,6 @@ public class TestBillingApi {
nextPriceList.getName(), 1L, null,
SubscriptionTransitionType.CREATE, 0, null);
-
effectiveSubscriptionTransitions.add(t);
final AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
@@ -376,7 +347,6 @@ public class TestBillingApi {
final PlanPhase nextPhase = nextPlan.getAllPhases()[1];
final PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
-
final EffectiveSubscriptionEvent t = new MockEffectiveSubscriptionEvent(
eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE,
nextPlan.getName(), nextPhase.getName(),
@@ -457,7 +427,6 @@ public class TestBillingApi {
nextPriceList.getName(), 1L, null,
SubscriptionTransitionType.CREATE, 0, null);
-
effectiveSubscriptionTransitions.add(t);
final AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
@@ -486,7 +455,6 @@ public class TestBillingApi {
assertEquals(events.size(), 0);
}
-
@Test(enabled = true, groups = "fast")
public void testBillingEventsAutoInvoicingOffBundle() throws CatalogApiException {
final DateTime now = clock.getUTCNow();
@@ -501,7 +469,6 @@ public class TestBillingApi {
nextPriceList.getName(), 1L, null,
SubscriptionTransitionType.CREATE, 0, null);
-
effectiveSubscriptionTransitions.add(t);
final AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
index ad55ff9..a43b1b5 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
@@ -78,13 +78,35 @@ public class DefaultPaymentApi implements PaymentApi {
}
+
+ @Override
+ public Refund getRefund(UUID refundId) throws PaymentApiException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
@Override
- public Refund createRefund(final Account account, final UUID paymentId, final CallContext context)
+ public Refund createRefund(Account account, UUID paymentId,
+ BigDecimal refundAmount, boolean isAdjusted, CallContext context)
throws PaymentApiException {
- return refundProcessor.createRefund(account, paymentId, context);
+ return refundProcessor.createRefund(account, paymentId, refundAmount, isAdjusted, context);
+
}
@Override
+ public List<Refund> getAccountRefunds(Account account)
+ throws PaymentApiException {
+ return refundProcessor.getAccountRefunds(account);
+ }
+
+ @Override
+ public List<Refund> getPaymentRefunds(UUID paymentId)
+ throws PaymentApiException {
+ return refundProcessor.getPaymentRefunds(paymentId);
+ }
+
+
+ @Override
public Set<String> getAvailablePlugins() {
return methodProcessor.getAvailablePlugins();
}
@@ -118,6 +140,7 @@ public class DefaultPaymentApi implements PaymentApi {
return methodProcessor.getPaymentMethods(account, withPluginDetail);
}
+ @Override
public PaymentMethod getPaymentMethodById(final UUID paymentMethodId)
throws PaymentApiException {
return methodProcessor.getPaymentMethodById(paymentMethodId);
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultRefund.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultRefund.java
new file mode 100644
index 0000000..729e701
--- /dev/null
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultRefund.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package com.ning.billing.payment.api;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.util.entity.EntityBase;
+
+public class DefaultRefund extends EntityBase implements Refund {
+
+ private final UUID paymentId;
+ private final BigDecimal amount;
+ private final Currency currency;
+ private final boolean isAdjusted;
+
+ public DefaultRefund(final UUID id, final UUID paymentId, final BigDecimal amount,
+ final Currency currency, final boolean isAdjusted) {
+ super(id);
+ this.paymentId = paymentId;
+ this.amount = amount;
+ this.currency = currency;
+ this.isAdjusted = isAdjusted;
+ }
+
+ @Override
+ public UUID getPaymentId() {
+ return paymentId;
+ }
+
+ @Override
+ public BigDecimal getRefundAmount() {
+ return amount;
+ }
+
+ @Override
+ public Currency getCurrency() {
+ return currency;
+ }
+
+ @Override
+ public boolean isAdjusted() {
+ return isAdjusted;
+ }
+}
diff --git a/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
index 4f21a9b..54fbeb9 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
@@ -16,52 +16,217 @@
package com.ning.billing.payment.core;
import javax.inject.Inject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
import com.google.inject.name.Named;
+import com.ning.billing.ErrorCode;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.invoice.api.InvoiceApiException;
+import com.ning.billing.invoice.api.InvoicePaymentApi;
+import com.ning.billing.payment.api.DefaultRefund;
import com.ning.billing.payment.api.PaymentApiException;
+import com.ning.billing.payment.api.PaymentStatus;
import com.ning.billing.payment.api.Refund;
+import com.ning.billing.payment.core.ProcessorBase.WithAccountLock;
+import com.ning.billing.payment.core.ProcessorBase.WithAccountLockCallback;
+import com.ning.billing.payment.dao.PaymentAttemptModelDao;
import com.ning.billing.payment.dao.PaymentDao;
+import com.ning.billing.payment.dao.RefundModelDao;
+import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
+import com.ning.billing.payment.plugin.api.PaymentPluginApi;
+import com.ning.billing.payment.plugin.api.PaymentPluginApiException;
import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallContextFactory;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.UserType;
import com.ning.billing.util.globallocker.GlobalLocker;
import static com.ning.billing.payment.glue.PaymentModule.PLUGIN_EXECUTOR_NAMED;
public class RefundProcessor extends ProcessorBase {
+ private final static Logger log = LoggerFactory.getLogger(RefundProcessor.class);
+
+ private final InvoicePaymentApi invoicePaymentApi;
+ private final CallContextFactory factory;
+
@Inject
public RefundProcessor(final PaymentProviderPluginRegistry pluginRegistry,
- final AccountUserApi accountUserApi,
- final Bus eventBus,
- final PaymentDao paymentDao,
- final GlobalLocker locker,
- @Named(PLUGIN_EXECUTOR_NAMED) final ExecutorService executor) {
+ final AccountUserApi accountUserApi,
+ final InvoicePaymentApi invoicePaymentApi,
+ final Bus eventBus,
+ final CallContextFactory factory,
+ final PaymentDao paymentDao,
+ final GlobalLocker locker,
+ @Named(PLUGIN_EXECUTOR_NAMED) final ExecutorService executor) {
super(pluginRegistry, accountUserApi, eventBus, paymentDao, locker, executor);
+ this.invoicePaymentApi = invoicePaymentApi;
+ this.factory = factory;
}
- public Refund createRefund(final Account account, final UUID paymentId, final CallContext context)
- throws PaymentApiException {
- /*
+
+ public Refund createRefund(final Account account, final UUID paymentId, final BigDecimal refundAmount, final boolean isAdjusted, final CallContext context)
+ throws PaymentApiException {
+
+ return new WithAccountLock<Refund>().processAccountWithLock(locker, account.getExternalKey(), new WithAccountLockCallback<Refund>() {
+
+ @Override
+ public Refund doOperation() throws PaymentApiException {
+ try {
+
+
+ final PaymentAttemptModelDao successfulAttempt = getPaymentAttempt(paymentId);
+ if (successfulAttempt == null) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_SUCCESS_PAYMENT, paymentId);
+ }
+ if (successfulAttempt.getRequestedAmount().compareTo(refundAmount) < 0) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_REFUND_AMOUNT_TOO_LARGE);
+ }
+
+ // Look for that refund entry and count any 'similar' refund left in CREATED state (same amount, same paymentId)
+ int foundPluginCompletedRefunds = 0;
+ RefundModelDao refundInfo = null;
+ List<RefundModelDao> existingRefunds = paymentDao.getRefundsForPayment(paymentId);
+ for (RefundModelDao cur : existingRefunds) {
+ if (cur.getAmount().compareTo(refundAmount) == 0) {
+ if (cur.getRefundStatus() == RefundStatus.CREATED) {
+ if (refundInfo == null) {
+ refundInfo = cur;
+ }
+ } else {
+ foundPluginCompletedRefunds++;
+ }
+ }
+ }
+ if (refundInfo == null) {
+ refundInfo = new RefundModelDao(account.getId(), paymentId, refundAmount, account.getCurrency(), isAdjusted);
+ paymentDao.insertRefund(refundInfo, context);
+ }
+
+ final PaymentPluginApi plugin = getPaymentProviderPlugin(account);
+ int nbExistingRefunds = plugin.getNbRefundForPaymentAmount(account, paymentId, refundAmount);
+ if (nbExistingRefunds > foundPluginCompletedRefunds) {
+ log.info("Found existing plugin refund for paymentId {}, skip plugin", paymentId);
+ } else {
+ // If there is no such exitng refund we create it
+ plugin.processRefund(account, paymentId, refundAmount);
+ }
+ paymentDao.updateRefundStatus(refundInfo.getId(), RefundStatus.PLUGIN_COMPLETED, context);
+
+ invoicePaymentApi.createRefund(successfulAttempt.getId(), refundAmount, isAdjusted, refundInfo.getId(), context);
+
+ paymentDao.updateRefundStatus(refundInfo.getId(), RefundStatus.COMPLETED, context);
+
+ return new DefaultRefund(refundInfo.getId(), paymentId, refundInfo.getAmount(), account.getCurrency(), isAdjusted);
+ } catch (PaymentPluginApiException e) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_REFUND, account.getId(), e.getMessage());
+ } catch (InvoiceApiException e) {
+ throw new PaymentApiException(e);
+ }
+ }
+ });
+ }
+
+
+ public Refund getRefund(final UUID refundId)
+ throws PaymentApiException {
+ RefundModelDao result = paymentDao.getRefund(refundId);
+ if (result == null) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_REFUND, refundId);
+ }
+ List<RefundModelDao> filteredInput = filterUncompletedPluginRefund(Collections.singletonList(result));
+ if (filteredInput.size() == 0) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_REFUND, refundId);
+ }
+ if (completePluginCompletedRefund(filteredInput)) {
+ result = paymentDao.getRefund(refundId);
+ }
+ return new DefaultRefund(result.getId(), result.getPaymentId(), result.getAmount(), result.getCurrency(), result.isAdjsuted());
+ }
+
+
+ public List<Refund> getAccountRefunds(final Account account)
+ throws PaymentApiException {
+ List<RefundModelDao> result = paymentDao.getRefundsForAccount(account.getId());
+ if (completePluginCompletedRefund(result)) {
+ result = paymentDao.getRefundsForAccount(account.getId());
+ }
+ List<RefundModelDao> filteredInput = filterUncompletedPluginRefund(result);
+ return toRefunds(filteredInput);
+ }
+
+ public List<Refund> getPaymentRefunds(final UUID paymentId)
+ throws PaymentApiException {
+ List<RefundModelDao> result = paymentDao.getRefundsForPayment(paymentId);
+ if (completePluginCompletedRefund(result)) {
+ result = paymentDao.getRefundsForPayment(paymentId);
+ }
+ List<RefundModelDao> filteredInput = filterUncompletedPluginRefund(result);
+ return toRefunds(filteredInput);
+ }
+
+ public List<Refund> toRefunds(final List<RefundModelDao> in) {
+ return new ArrayList<Refund>(Collections2.transform(in, new Function<RefundModelDao, Refund>() {
+ @Override
+ public Refund apply(RefundModelDao cur) {
+ return new DefaultRefund(cur.getId(), cur.getPaymentId(), cur.getAmount(), cur.getCurrency(), cur.isAdjsuted());
+ }
+ }));
+ }
+
+ private List<RefundModelDao> filterUncompletedPluginRefund(final List<RefundModelDao> input) {
+ return new ArrayList<RefundModelDao>(Collections2.filter(input, new Predicate<RefundModelDao>() {
+ @Override
+ public boolean apply(RefundModelDao in) {
+ return in.getRefundStatus() != RefundStatus.CREATED;
+ }
+ }));
+ }
+
+ private boolean completePluginCompletedRefund(final List<RefundModelDao> refunds) throws PaymentApiException {
+
+ boolean fixedTheWorld = false;
try {
-
- final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
- List<PaymentInfoPlugin> result = plugin.processRefund(account);
- List<PaymentInfoEvent> info = new LinkedList<PaymentInfoEvent>();
- int i = 0;
- for (PaymentInfoPlugin cur : result) {
- // STEPH
- //info.add(new DefaultPaymentInfoEvent(cur, account.getId(), invoiceIds.get(i)));
+ final CallContext context = factory.createCallContext("RefundProcessor", CallOrigin.INTERNAL, UserType.SYSTEM);
+ for (RefundModelDao cur : refunds) {
+ if (cur.getRefundStatus() == RefundStatus.PLUGIN_COMPLETED) {
+ final PaymentAttemptModelDao successfulAttempt = getPaymentAttempt(cur.getPaymentId());
+ if (successfulAttempt != null) {
+ invoicePaymentApi.createRefund(successfulAttempt.getId(), cur.getAmount(), cur.isAdjsuted(), cur.getId(), context);
+ paymentDao.updateRefundStatus(cur.getId(), RefundStatus.COMPLETED, context);
+ fixedTheWorld = true;
+ }
+ }
+ }
+ } catch (InvoiceApiException e) {
+ throw new PaymentApiException(e);
}
- return info;
- } catch (PaymentPluginApiException e) {
- throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_REFUND, account.getId(), e.getMessage());
+ return fixedTheWorld;
+ }
+
+ private PaymentAttemptModelDao getPaymentAttempt(final UUID paymentId) {
+ List<PaymentAttemptModelDao> attempts = paymentDao.getAttemptsForPayment(paymentId);
+ for (PaymentAttemptModelDao cur : attempts) {
+ if (cur.getPaymentStatus() == PaymentStatus.SUCCESS) {
+ return cur;
+ }
}
- */
return null;
}
+
}
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
index 5dad606..3c39f60 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
@@ -25,6 +25,7 @@ import org.skife.jdbi.v2.TransactionStatus;
import com.google.inject.Inject;
import com.ning.billing.payment.api.PaymentStatus;
+import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
import com.ning.billing.payment.retry.PluginFailureRetryService.PluginFailureRetryServiceScheduler;
import com.ning.billing.util.ChangeType;
import com.ning.billing.util.callcontext.CallContext;
@@ -34,9 +35,11 @@ import com.ning.billing.util.dao.TableName;
public class AuditedPaymentDao implements PaymentDao {
+
private final PaymentSqlDao paymentSqlDao;
private final PaymentAttemptSqlDao paymentAttemptSqlDao;
private final PaymentMethodSqlDao paymentMethodSqlDao;
+ private final RefundSqlDao refundSqlDao;
//private final TimedoutPaymentRetryServiceScheduler timedoutSchduler;
@Inject
@@ -44,6 +47,7 @@ public class AuditedPaymentDao implements PaymentDao {
this.paymentSqlDao = dbi.onDemand(PaymentSqlDao.class);
this.paymentAttemptSqlDao = dbi.onDemand(PaymentAttemptSqlDao.class);
this.paymentMethodSqlDao = dbi.onDemand(PaymentMethodSqlDao.class);
+ this.refundSqlDao = dbi.onDemand(RefundSqlDao.class);
// this.timedoutSchduler = timedoutSchduler;
}
@@ -92,10 +96,10 @@ public class AuditedPaymentDao implements PaymentDao {
}).size();
}
-
+
private void scheduleTimeoutRetryFromTransaction(final UUID paymentId, final PaymentAttemptSqlDao transactional, final boolean scheduleTimeoutRetry) {
- if (scheduleTimeoutRetry) {
+ if (scheduleTimeoutRetry) {
int retryAttempt = getNbTimedoutAttemptsFromTransaction(paymentId, transactional) + 1;
timedoutSchduler.scheduleRetryFromTransaction(paymentId, retryAttempt, transactional);
}
@@ -225,6 +229,74 @@ public class AuditedPaymentDao implements PaymentDao {
}
@Override
+ public RefundModelDao insertRefund(final RefundModelDao refundInfo, final CallContext context) {
+ return refundSqlDao.inTransaction(new Transaction<RefundModelDao, RefundSqlDao>() {
+
+ @Override
+ public RefundModelDao inTransaction(RefundSqlDao transactional,
+ TransactionStatus status) throws Exception {
+ transactional.insertRefund(refundInfo, context);
+ return refundInfo;
+ }
+ });
+ }
+
+
+ @Override
+ public void updateRefundStatus(final UUID refundId,
+ final RefundStatus status, final CallContext context) {
+ refundSqlDao.inTransaction(new Transaction<Void, RefundSqlDao>() {
+
+ @Override
+ public Void inTransaction(RefundSqlDao transactional,
+ TransactionStatus status) throws Exception {
+ transactional.updateStatus(refundId.toString(), status.toString());
+ return null;
+ }
+ });
+ }
+
+ @Override
+ public RefundModelDao getRefund(final UUID refundId) {
+ return refundSqlDao.inTransaction(new Transaction<RefundModelDao, RefundSqlDao>() {
+
+ @Override
+ public RefundModelDao inTransaction(RefundSqlDao transactional,
+ TransactionStatus status) throws Exception {
+ return transactional.getById(refundId.toString());
+ }
+ });
+ }
+
+
+ @Override
+ public List<RefundModelDao> getRefundsForPayment(final UUID paymentId) {
+ return refundSqlDao.inTransaction(new Transaction<List<RefundModelDao>, RefundSqlDao>() {
+
+ @Override
+ public List<RefundModelDao> inTransaction(RefundSqlDao transactional,
+ TransactionStatus status) throws Exception {
+ return transactional.getRefundsForPayment(paymentId.toString());
+ }
+ });
+ }
+
+
+ @Override
+ public List<RefundModelDao> getRefundsForAccount(final UUID accountId) {
+ return refundSqlDao.inTransaction(new Transaction<List<RefundModelDao>, RefundSqlDao>() {
+
+ @Override
+ public List<RefundModelDao> inTransaction(RefundSqlDao transactional,
+ TransactionStatus status) throws Exception {
+ return transactional.getRefundsForAccount(accountId.toString());
+ }
+ });
+ }
+
+
+
+ @Override
public PaymentMethodModelDao getPaymentMethod(final UUID paymentMethodId) {
return paymentMethodSqlDao.inTransaction(new Transaction<PaymentMethodModelDao, PaymentMethodSqlDao>() {
@Override
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
index 6580217..65254fb 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
@@ -18,8 +18,14 @@ package com.ning.billing.payment.dao;
import java.util.List;
import java.util.UUID;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+
import com.ning.billing.payment.api.PaymentStatus;
+import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
+import com.ning.billing.payment.dao.RefundSqlDao.RefundModelDaoBinder;
import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallContextBinder;
public interface PaymentDao {
@@ -43,6 +49,16 @@ public interface PaymentDao {
public List<PaymentAttemptModelDao> getAttemptsForPayment(final UUID paymentId);
+ public RefundModelDao insertRefund(RefundModelDao refundInfo, final CallContext context);
+
+ public void updateRefundStatus(UUID refundId, RefundStatus status, final CallContext context);
+
+ public RefundModelDao getRefund(UUID refundId);
+
+ public List<RefundModelDao> getRefundsForPayment(final UUID paymentId);
+
+ public List<RefundModelDao> getRefundsForAccount(final UUID accountId);
+
public PaymentMethodModelDao insertPaymentMethod(final PaymentMethodModelDao paymentMethod, final CallContext context);
public PaymentMethodModelDao getPaymentMethod(final UUID paymentMethodId);
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentModelDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentModelDao.java
index 6ee7ea1..ab1fecc 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentModelDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentModelDao.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
index 4173ac2..f637976 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/RefundModelDao.java b/payment/src/main/java/com/ning/billing/payment/dao/RefundModelDao.java
new file mode 100644
index 0000000..286fe51
--- /dev/null
+++ b/payment/src/main/java/com/ning/billing/payment/dao/RefundModelDao.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package com.ning.billing.payment.dao;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.util.entity.EntityBase;
+
+
+public class RefundModelDao extends EntityBase {
+
+ private final UUID accountId;
+ private final UUID paymentId;
+ private final BigDecimal amount;
+ private final Currency currency;
+ private final boolean isAdjusted;
+ private final RefundStatus refundStatus;
+
+ public RefundModelDao(final UUID accountId, final UUID paymentId,
+ final BigDecimal amount, final Currency currency, final boolean isAdjusted) {
+ this(UUID.randomUUID(), accountId, paymentId, amount, currency, isAdjusted, RefundStatus.CREATED);
+ }
+
+ public RefundModelDao(final UUID id, final UUID accountId, final UUID paymentId,
+ final BigDecimal amount, final Currency currency, final boolean isAdjusted, final RefundStatus refundStatus) {
+ super(id);
+ this.accountId = accountId;
+ this.paymentId = paymentId;
+ this.amount = amount;
+ this.currency = currency;
+ this.refundStatus = refundStatus;
+ this.isAdjusted = isAdjusted;
+ }
+
+ public UUID getAccountId() {
+ return accountId;
+ }
+
+ public UUID getPaymentId() {
+ return paymentId;
+ }
+
+ public BigDecimal getAmount() {
+ return amount;
+ }
+
+ public Currency getCurrency() {
+ return currency;
+ }
+
+ public RefundStatus getRefundStatus() {
+ return refundStatus;
+ }
+
+ public boolean isAdjsuted() {
+ return isAdjusted;
+ }
+
+ public enum RefundStatus {
+ CREATED,
+ PLUGIN_COMPLETED,
+ COMPLETED,
+ }
+}
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/RefundSqlDao.java b/payment/src/main/java/com/ning/billing/payment/dao/RefundSqlDao.java
new file mode 100644
index 0000000..c29c6ed
--- /dev/null
+++ b/payment/src/main/java/com/ning/billing/payment/dao/RefundSqlDao.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package com.ning.billing.payment.dao;
+
+import java.math.BigDecimal;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.UUID;
+
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.Binder;
+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.CloseMe;
+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 org.skife.jdbi.v2.tweak.ResultSetMapper;
+
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallContextBinder;
+import com.ning.billing.util.dao.BinderBase;
+import com.ning.billing.util.dao.MapperBase;
+import com.ning.billing.util.entity.dao.UpdatableEntitySqlDao;
+
+
+@ExternalizedSqlViaStringTemplate3()
+@RegisterMapper(RefundSqlDao.RefundModelDaoMapper.class)
+public interface RefundSqlDao extends Transactional<RefundSqlDao>, UpdatableEntitySqlDao<RefundModelDao>, Transmogrifier, CloseMe {
+
+
+ @SqlUpdate
+ void insertRefund(@Bind(binder = RefundModelDaoBinder.class) final RefundModelDao refundInfo,
+ @CallContextBinder final CallContext context);
+
+ @SqlUpdate
+ void updateStatus(@Bind("id") final String refundId, @Bind("refund_status") final String status);
+
+ @SqlQuery
+ RefundModelDao getRefund(@Bind("id") final String refundId);
+
+ @SqlQuery
+ List<RefundModelDao> getRefundsForPayment(@Bind("paymentId") final String paymentId);
+
+ @SqlQuery
+ List<RefundModelDao> getRefundsForAccount(@Bind("accountId") final String accountId);
+
+
+ public static final class RefundModelDaoBinder extends BinderBase implements Binder<Bind, RefundModelDao> {
+ @Override
+ public void bind(@SuppressWarnings("rawtypes") final SQLStatement stmt, final Bind bind, final RefundModelDao refund) {
+ stmt.bind("id", refund.getId().toString());
+ stmt.bind("accountId", refund.getAccountId().toString());
+ stmt.bind("paymentId", refund.getPaymentId().toString());
+ stmt.bind("amount", refund.getAmount());
+ stmt.bind("currency", refund.getCurrency().toString());
+ stmt.bind("is_adjusted", refund.isAdjsuted());
+ stmt.bind("refund_status", refund.getRefundStatus().toString());
+ }
+ }
+
+ public static class RefundModelDaoMapper extends MapperBase implements ResultSetMapper<RefundModelDao> {
+
+ @Override
+ public RefundModelDao map(final int index, final ResultSet rs, final StatementContext ctx)
+ throws SQLException {
+ final UUID id = getUUID(rs, "id");
+ final UUID accountId = getUUID(rs, "account_id");
+ final UUID paymentId = getUUID(rs, "payment_id");
+ final BigDecimal amount = rs.getBigDecimal("amount");
+ final boolean isAdjusted = rs.getBoolean("is_adjusted");
+ final Currency currency = Currency.valueOf(rs.getString("currency"));
+ final RefundStatus refundStatus = RefundStatus.valueOf(rs.getString("refund_status"));
+ return new RefundModelDao(id, accountId, paymentId, amount, currency, isAdjusted, refundStatus);
+ }
+ }
+}
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java b/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java
index 5591937..cf23c59 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java
@@ -192,8 +192,15 @@ public class DefaultNoOpPaymentProviderPlugin implements NoOpPaymentPluginApi {
}
@Override
- public List<PaymentInfoPlugin> processRefund(final Account account)
- throws PaymentPluginApiException {
- return null;
+ public void processRefund(Account account, UUID paymentId,
+ BigDecimal refundAmout) throws PaymentPluginApiException {
+ }
+
+ @Override
+ public int getNbRefundForPaymentAmount(Account account, UUID paymentId,
+ BigDecimal refundAmount) throws PaymentPluginApiException {
+ // TODO Auto-generated method stub
+ return 0;
}
+
}
diff --git a/payment/src/main/resources/com/ning/billing/payment/ddl.sql b/payment/src/main/resources/com/ning/billing/payment/ddl.sql
index b8fa010..69db6a2 100644
--- a/payment/src/main/resources/com/ning/billing/payment/ddl.sql
+++ b/payment/src/main/resources/com/ning/billing/payment/ddl.sql
@@ -1,4 +1,24 @@
+DROP TABLE IF EXISTS refunds;
+CREATE TABLE refunds (
+ record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+ id char(36) NOT NULL,
+ account_id char(36) COLLATE utf8_bin NOT NULL,
+ payment_id char(36) COLLATE utf8_bin NOT NULL,
+ amount decimal(8,2),
+ currency char(3),
+ is_adjusted tinyint(1),
+ refund_status varchar(50),
+ created_by varchar(50) NOT NULL,
+ created_date datetime NOT NULL,
+ updated_by varchar(50) NOT NULL,
+ updated_date datetime NOT NULL,
+ PRIMARY KEY (record_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+CREATE UNIQUE INDEX refunds_id ON refunds(id);
+CREATE INDEX refunds_pay ON refunds(payment_id);
+CREATE INDEX refunds_accnt ON refunds(account_id);
+
DROP TABLE IF EXISTS payments;
CREATE TABLE payments (
record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
index fb6a281..ce1a17c 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
@@ -24,6 +24,7 @@ import java.util.Map;
import java.util.UUID;
import com.ning.billing.payment.api.PaymentStatus;
+import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
import com.ning.billing.util.callcontext.CallContext;
public class MockPaymentDao implements PaymentDao {
@@ -167,4 +168,36 @@ public class MockPaymentDao implements PaymentDao {
}
}
}
+
+ @Override
+ public RefundModelDao insertRefund(RefundModelDao refundInfo,
+ CallContext context) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void updateRefundStatus(UUID refundId, RefundStatus status,
+ CallContext context) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public RefundModelDao getRefund(UUID refundId) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<RefundModelDao> getRefundsForPayment(UUID paymentId) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<RefundModelDao> getRefundsForAccount(UUID accountId) {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
diff --git a/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java b/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java
index b315e79..c5e5375 100644
--- a/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java
+++ b/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java
@@ -171,7 +171,7 @@ public class PersistentBus extends PersistentQueueBase implements Bus {
final BusEventEntry entry = new BusEventEntry(hostname, event.getClass().getName(), json);
transactional.insertBusEvent(entry);
} catch (Exception e) {
- log.error("Failed to post BusEvent " + event.toString(), e);
+ log.error("Failed to post BusEvent " + event, e);
}
}
}
diff --git a/util/src/test/java/com/ning/billing/mock/api/MockEntitlementUserApi.java b/util/src/test/java/com/ning/billing/mock/api/MockEntitlementUserApi.java
index 60da96b..0fdeeb1 100644
--- a/util/src/test/java/com/ning/billing/mock/api/MockEntitlementUserApi.java
+++ b/util/src/test/java/com/ning/billing/mock/api/MockEntitlementUserApi.java
@@ -36,6 +36,7 @@ import com.ning.billing.util.callcontext.CallContext;
public class MockEntitlementUserApi implements EntitlementUserApi {
private final Map<UUID, String> subscriptionBundles = new HashMap<UUID, String>();
private final Map<UUID, UUID> accountForBundle = new HashMap<UUID, UUID>();
+ private final Map<UUID, Subscription> subscriptionsById = new HashMap<UUID, Subscription>();
public synchronized void addBundle(final UUID bundleUUID, final String externalKey, final UUID accountId) {
subscriptionBundles.put(bundleUUID, externalKey);
diff --git a/util/src/test/java/com/ning/billing/mock/MockPriceList.java b/util/src/test/java/com/ning/billing/mock/MockPriceList.java
new file mode 100644
index 0000000..8903a3c
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/mock/MockPriceList.java
@@ -0,0 +1,59 @@
+/*
+ * 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.mock;
+
+import java.util.UUID;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PriceList;
+import com.ning.billing.catalog.api.Product;
+
+public class MockPriceList implements PriceList {
+ private final String name;
+ private final Boolean isRetired;
+ private final Plan plan;
+
+ public MockPriceList() {
+ this(false, UUID.randomUUID().toString(), new MockPlan());
+ }
+
+ public MockPriceList(final Boolean retired, final String name, final Plan plan) {
+ isRetired = retired;
+ this.name = name;
+ this.plan = plan;
+ }
+
+ @Override
+ public boolean isRetired() {
+ return isRetired;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public Plan findPlan(final Product product, final BillingPeriod period) {
+ return plan;
+ }
+
+ public Plan getPlan() {
+ return plan;
+ }
+}
diff --git a/util/src/test/java/com/ning/billing/mock/MockProduct.java b/util/src/test/java/com/ning/billing/mock/MockProduct.java
new file mode 100644
index 0000000..ea341b0
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/mock/MockProduct.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2010-2011 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.mock;
+
+import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
+
+public class MockProduct implements Product {
+ private final String name;
+ private final ProductCategory category;
+ private final String catalogName;
+
+ public MockProduct() {
+ name = "TestProduct";
+ category = ProductCategory.BASE;
+ catalogName = "Vehicules";
+ }
+
+ public MockProduct(final String name, final ProductCategory category, final String catalogName) {
+ this.name = name;
+ this.category = category;
+ this.catalogName = catalogName;
+ }
+
+ @Override
+ public String getCatalogName() {
+ return catalogName;
+ }
+
+ @Override
+ public ProductCategory getCategory() {
+ return category;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isRetired() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Product[] getAvailable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Product[] getIncluded() {
+ throw new UnsupportedOperationException();
+ }
+
+ public static MockProduct createBicycle() {
+ return new MockProduct("Bicycle", ProductCategory.BASE, "Vehcles");
+ }
+
+ public static MockProduct createPickup() {
+ return new MockProduct("Pickup", ProductCategory.BASE, "Vehcles");
+ }
+
+ public static MockProduct createSportsCar() {
+ return new MockProduct("SportsCar", ProductCategory.BASE, "Vehcles");
+ }
+
+ public static MockProduct createJet() {
+ return new MockProduct("Jet", ProductCategory.BASE, "Vehcles");
+ }
+
+ public static MockProduct createHorn() {
+ return new MockProduct("Horn", ProductCategory.ADD_ON, "Vehcles");
+ }
+
+ public static MockProduct createSpotlight() {
+ return new MockProduct("spotlight", ProductCategory.ADD_ON, "Vehcles");
+ }
+
+ public static MockProduct createRedPaintJob() {
+ return new MockProduct("RedPaintJob", ProductCategory.ADD_ON, "Vehcles");
+ }
+
+ public static Product[] createAll() {
+ return new MockProduct[]{
+ createBicycle(),
+ createPickup(),
+ createSportsCar(),
+ createJet(),
+ createHorn(),
+ createRedPaintJob()
+ };
+ }
+}
diff --git a/util/src/test/java/com/ning/billing/util/tag/dao/TestAuditedTagDao.java b/util/src/test/java/com/ning/billing/util/tag/dao/TestAuditedTagDao.java
index 2bb6a37..c21cf14 100644
--- a/util/src/test/java/com/ning/billing/util/tag/dao/TestAuditedTagDao.java
+++ b/util/src/test/java/com/ning/billing/util/tag/dao/TestAuditedTagDao.java
@@ -95,7 +95,7 @@ public class TestAuditedTagDao {
final String definitionName = UUID.randomUUID().toString().substring(0, 5);
final String description = UUID.randomUUID().toString().substring(0, 5);
final UUID objectId = UUID.randomUUID();
- final ObjectType objectType = ObjectType.RECURRING_INVOICE_ITEM;
+ final ObjectType objectType = ObjectType.INVOICE_ITEM;
// Verify the initial state
Assert.assertEquals(eventsListener.getEvents().size(), 0);