killbill-uncached
Changes
entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java 40(+31 -9)
entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionApi.java 14(+14 -0)
entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java 214(+211 -3)
NEWS 11(+11 -0)
subscription/src/main/java/com/ning/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java 17(+3 -14)
subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBase.java 8(+0 -8)
subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBuilder.java 16(+3 -13)
subscription/src/main/java/com/ning/billing/subscription/engine/dao/DefaultSubscriptionDao.java 48(+42 -6)
subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionModelDao.java 20(+2 -18)
subscription/src/main/java/com/ning/billing/subscription/engine/dao/RepairSubscriptionDao.java 5(+5 -0)
subscription/src/main/resources/com/ning/billing/subscription/engine/dao/SubscriptionSqlDao.sql.stg 2(+0 -2)
Details
diff --git a/api/src/main/java/com/ning/billing/subscription/api/SubscriptionBase.java b/api/src/main/java/com/ning/billing/subscription/api/SubscriptionBase.java
index 09fabfc..7675239 100644
--- a/api/src/main/java/com/ning/billing/subscription/api/SubscriptionBase.java
+++ b/api/src/main/java/com/ning/billing/subscription/api/SubscriptionBase.java
@@ -25,7 +25,6 @@ import com.ning.billing.catalog.api.BillingActionPolicy;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
-import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.PriceList;
import com.ning.billing.catalog.api.Product;
import com.ning.billing.catalog.api.ProductCategory;
@@ -34,13 +33,11 @@ import com.ning.billing.entitlement.api.Entitlement.EntitlementSourceType;
import com.ning.billing.entitlement.api.Entitlement.EntitlementState;
import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
import com.ning.billing.subscription.api.user.SubscriptionBaseTransition;
-import com.ning.billing.entitlement.api.Entitlement.EntitlementState;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.entity.Entity;
public interface SubscriptionBase extends Entity, Blockable {
-
public boolean cancel(final CallContext context)
throws SubscriptionBaseApiException;
@@ -98,8 +95,6 @@ public interface SubscriptionBase extends Entity, Blockable {
public DateTime getChargedThroughDate();
- public DateTime getPaidThroughDate();
-
public ProductCategory getCategory();
public SubscriptionBaseTransition getPendingTransition();
diff --git a/api/src/main/java/com/ning/billing/subscription/api/SubscriptionBaseInternalApi.java b/api/src/main/java/com/ning/billing/subscription/api/SubscriptionBaseInternalApi.java
index b8de4a1..02a1bd9 100644
--- a/api/src/main/java/com/ning/billing/subscription/api/SubscriptionBaseInternalApi.java
+++ b/api/src/main/java/com/ning/billing/subscription/api/SubscriptionBaseInternalApi.java
@@ -49,7 +49,7 @@ public interface SubscriptionBaseInternalApi {
public List<SubscriptionBaseBundle> getBundlesForKey(final String bundleKey, final InternalTenantContext context);
- public SubscriptionBaseBundle getActiveBundleForKey(final String bundleKey, final InternalTenantContext context) throws SubscriptionBaseApiException;
+ public Iterable<UUID> getNonAOSubscriptionIdsForKey(final String bundleKey, final InternalTenantContext context);
public List<SubscriptionBase> getSubscriptionsForBundle(final UUID bundleId, final InternalTenantContext context);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlementApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlementApi.java
index a1b3deb..4481d3a 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlementApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlementApi.java
@@ -44,6 +44,7 @@ import com.ning.billing.entitlement.DefaultEntitlementService;
import com.ning.billing.entitlement.EntitlementService;
import com.ning.billing.entitlement.EntitlementTransitionType;
import com.ning.billing.entitlement.EventsStream;
+import com.ning.billing.entitlement.api.Entitlement.EntitlementState;
import com.ning.billing.entitlement.block.BlockingChecker;
import com.ning.billing.entitlement.dao.BlockingStateDao;
import com.ning.billing.entitlement.engine.core.EntitlementNotificationKey;
@@ -79,8 +80,8 @@ public class DefaultEntitlementApi implements EntitlementApi {
public static final String ENT_STATE_CLEAR = "ENT_CLEAR";
public static final String ENT_STATE_CANCELLED = "ENT_CANCELLED";
- private final SubscriptionBaseInternalApi subscriptionInternalApi;
- private final SubscriptionBaseTransferApi subscriptionTransferApi;
+ private final SubscriptionBaseInternalApi subscriptionBaseInternalApi;
+ private final SubscriptionBaseTransferApi subscriptionBaseTransferApi;
private final AccountInternalApi accountApi;
private final Clock clock;
private final InternalCallContextFactory internalCallContextFactory;
@@ -100,8 +101,8 @@ public class DefaultEntitlementApi implements EntitlementApi {
final EventsStreamBuilder eventsStreamBuilder, final EntitlementUtils entitlementUtils) {
this.eventBus = eventBus;
this.internalCallContextFactory = internalCallContextFactory;
- this.subscriptionInternalApi = subscriptionInternalApi;
- this.subscriptionTransferApi = subscriptionTransferApi;
+ this.subscriptionBaseInternalApi = subscriptionInternalApi;
+ this.subscriptionBaseTransferApi = subscriptionTransferApi;
this.accountApi = accountApi;
this.clock = clock;
this.checker = checker;
@@ -116,14 +117,19 @@ public class DefaultEntitlementApi implements EntitlementApi {
public Entitlement createBaseEntitlement(final UUID accountId, final PlanPhaseSpecifier planPhaseSpecifier, final String externalKey, final LocalDate effectiveDate, final CallContext callContext) throws EntitlementApiException {
final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(accountId, callContext);
try {
- final SubscriptionBaseBundle bundle = subscriptionInternalApi.createBundleForAccount(accountId, externalKey, contextWithValidAccountRecordId);
+
+ if (entitlementUtils.getFirstActiveSubscriptionIdForKeyOrNull(externalKey, contextWithValidAccountRecordId) != null) {
+ throw new EntitlementApiException(new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS, externalKey));
+ }
+
+ final SubscriptionBaseBundle bundle = subscriptionBaseInternalApi.createBundleForAccount(accountId, externalKey, contextWithValidAccountRecordId);
final DateTime referenceTime = clock.getUTCNow();
final DateTime requestedDate = dateHelper.fromLocalDateAndReferenceTime(effectiveDate, referenceTime, contextWithValidAccountRecordId);
- final SubscriptionBase subscription = subscriptionInternalApi.createSubscription(bundle.getId(), planPhaseSpecifier, requestedDate, contextWithValidAccountRecordId);
+ final SubscriptionBase subscription = subscriptionBaseInternalApi.createSubscription(bundle.getId(), planPhaseSpecifier, requestedDate, contextWithValidAccountRecordId);
return new DefaultEntitlement(subscription.getId(), eventsStreamBuilder, this,
- blockingStateDao, subscriptionInternalApi, checker, notificationQueueService,
+ blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
entitlementUtils, dateHelper, clock, internalCallContextFactory, callContext);
} catch (SubscriptionBaseApiException e) {
throw new EntitlementApiException(e);
@@ -148,10 +154,10 @@ public class DefaultEntitlementApi implements EntitlementApi {
try {
final InternalCallContext context = internalCallContextFactory.createInternalCallContext(callContext);
- final SubscriptionBase subscription = subscriptionInternalApi.createSubscription(bundleId, planPhaseSpecifier, requestedDate, context);
+ final SubscriptionBase subscription = subscriptionBaseInternalApi.createSubscription(bundleId, planPhaseSpecifier, requestedDate, context);
return new DefaultEntitlement(subscription.getId(), eventsStreamBuilder, this,
- blockingStateDao, subscriptionInternalApi, checker, notificationQueueService,
+ blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
entitlementUtils, dateHelper, clock, internalCallContextFactory, callContext);
} catch (SubscriptionBaseApiException e) {
throw new EntitlementApiException(e);
@@ -162,12 +168,12 @@ public class DefaultEntitlementApi implements EntitlementApi {
public List<EntitlementAOStatusDryRun> getDryRunStatusForChange(final UUID bundleId, final String targetProductName, final LocalDate effectiveDate, final TenantContext context) throws EntitlementApiException {
final InternalTenantContext internalContext = internalCallContextFactory.createInternalTenantContext(context);
try {
- final SubscriptionBaseBundle bundle = subscriptionInternalApi.getBundleFromId(bundleId, internalContext);
- final SubscriptionBase baseSubscription = subscriptionInternalApi.getBaseSubscription(bundleId, internalContext);
+ final SubscriptionBaseBundle bundle = subscriptionBaseInternalApi.getBundleFromId(bundleId, internalContext);
+ final SubscriptionBase baseSubscription = subscriptionBaseInternalApi.getBaseSubscription(bundleId, internalContext);
final InternalTenantContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalTenantContext(bundle.getAccountId(), context);
final DateTime requestedDate = dateHelper.fromLocalDateAndReferenceTime(effectiveDate, baseSubscription.getStartDate(), contextWithValidAccountRecordId);
- return subscriptionInternalApi.getDryRunChangePlanStatus(baseSubscription.getId(), targetProductName, requestedDate, contextWithValidAccountRecordId);
+ return subscriptionBaseInternalApi.getDryRunChangePlanStatus(baseSubscription.getId(), targetProductName, requestedDate, contextWithValidAccountRecordId);
} catch (SubscriptionBaseApiException e) {
throw new EntitlementApiException(e);
}
@@ -177,7 +183,7 @@ public class DefaultEntitlementApi implements EntitlementApi {
public Entitlement getEntitlementForId(final UUID uuid, final TenantContext tenantContext) throws EntitlementApiException {
final EventsStream eventsStream = eventsStreamBuilder.buildForEntitlement(uuid, tenantContext);
return new DefaultEntitlement(eventsStream, eventsStreamBuilder, this,
- blockingStateDao, subscriptionInternalApi, checker, notificationQueueService,
+ blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
entitlementUtils, dateHelper, clock, internalCallContextFactory);
}
@@ -186,7 +192,7 @@ public class DefaultEntitlementApi implements EntitlementApi {
final InternalTenantContext internalContext = internalCallContextFactory.createInternalTenantContext(tenantContext);
final UUID accountId;
try {
- accountId = subscriptionInternalApi.getBundleFromId(bundleId, internalContext).getAccountId();
+ accountId = subscriptionBaseInternalApi.getBundleFromId(bundleId, internalContext).getAccountId();
} catch (SubscriptionBaseApiException e) {
throw new EntitlementApiException(e);
}
@@ -224,7 +230,7 @@ public class DefaultEntitlementApi implements EntitlementApi {
@Override
public Entitlement apply(final EventsStream eventsStream) {
return new DefaultEntitlement(eventsStream, eventsStreamBuilder, entitlementApi,
- blockingStateDao, subscriptionInternalApi, checker, notificationQueueService,
+ blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
entitlementUtils, dateHelper, clock, internalCallContextFactory);
}
});
@@ -239,9 +245,9 @@ public class DefaultEntitlementApi implements EntitlementApi {
throw new EntitlementApiException(ErrorCode.ENT_ALREADY_BLOCKED, bundleId);
}
- final SubscriptionBaseBundle bundle = subscriptionInternalApi.getBundleFromId(bundleId, contextWithValidAccountRecordId);
+ final SubscriptionBaseBundle bundle = subscriptionBaseInternalApi.getBundleFromId(bundleId, contextWithValidAccountRecordId);
final Account account = accountApi.getAccountById(bundle.getAccountId(), contextWithValidAccountRecordId);
- final SubscriptionBase baseSubscription = subscriptionInternalApi.getBaseSubscription(bundleId, contextWithValidAccountRecordId);
+ final SubscriptionBase baseSubscription = subscriptionBaseInternalApi.getBaseSubscription(bundleId, contextWithValidAccountRecordId);
final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(localEffectiveDate, baseSubscription.getStartDate(), contextWithValidAccountRecordId);
if (!dateHelper.isBeforeOrEqualsToday(effectiveDate, account.getTimeZone())) {
@@ -276,9 +282,9 @@ public class DefaultEntitlementApi implements EntitlementApi {
public void resume(final UUID bundleId, final LocalDate localEffectiveDate, final CallContext context) throws EntitlementApiException {
try {
final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(bundleId, ObjectType.BUNDLE, context);
- final SubscriptionBaseBundle bundle = subscriptionInternalApi.getBundleFromId(bundleId, contextWithValidAccountRecordId);
+ final SubscriptionBaseBundle bundle = subscriptionBaseInternalApi.getBundleFromId(bundleId, contextWithValidAccountRecordId);
final Account account = accountApi.getAccountById(bundle.getAccountId(), contextWithValidAccountRecordId);
- final SubscriptionBase baseSubscription = subscriptionInternalApi.getBaseSubscription(bundleId, contextWithValidAccountRecordId);
+ final SubscriptionBase baseSubscription = subscriptionBaseInternalApi.getBaseSubscription(bundleId, contextWithValidAccountRecordId);
final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(localEffectiveDate, baseSubscription.getStartDate(), contextWithValidAccountRecordId);
@@ -338,18 +344,23 @@ public class DefaultEntitlementApi implements EntitlementApi {
final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(sourceAccountId, context);
try {
- final SubscriptionBaseBundle bundle = subscriptionInternalApi.getActiveBundleForKey(externalKey, contextWithValidAccountRecordId);
- if (!bundle.getAccountId().equals(sourceAccountId)) {
+
+ final UUID activeSubscriptionIdForKey = entitlementUtils.getFirstActiveSubscriptionIdForKeyOrNull(externalKey, contextWithValidAccountRecordId);
+ final SubscriptionBase baseSubscription = activeSubscriptionIdForKey != null ?
+ subscriptionBaseInternalApi.getSubscriptionFromId(activeSubscriptionIdForKey, contextWithValidAccountRecordId) : null;
+ final SubscriptionBaseBundle baseBundle = baseSubscription != null ?
+ subscriptionBaseInternalApi.getBundleFromId(baseSubscription.getBundleId(), contextWithValidAccountRecordId) : null;
+
+ if (baseBundle == null || ! baseBundle.getAccountId().equals(sourceAccountId)) {
throw new EntitlementApiException(new SubscriptionBaseApiException(ErrorCode.SUB_GET_INVALID_BUNDLE_KEY, externalKey));
}
- final SubscriptionBase baseSubscription = subscriptionInternalApi.getBaseSubscription(bundle.getId(), contextWithValidAccountRecordId);
final DateTime requestedDate = dateHelper.fromLocalDateAndReferenceTime(effectiveDate, baseSubscription.getStartDate(), contextWithValidAccountRecordId);
- final SubscriptionBaseBundle newBundle = subscriptionTransferApi.transferBundle(sourceAccountId, destAccountId, externalKey, requestedDate, true, cancelImm, context);
+ final SubscriptionBaseBundle newBundle = subscriptionBaseTransferApi.transferBundle(sourceAccountId, destAccountId, externalKey, requestedDate, true, cancelImm, context);
// Block all associated subscriptions - TODO Do we want to block the bundle as well (this will add an extra STOP_ENTITLEMENT event in the bundle timeline stream)?
// Note that there is no un-transfer at the moment, so we effectively add a blocking state on disk for all subscriptions
- for (final SubscriptionBase subscriptionBase : subscriptionInternalApi.getSubscriptionsForBundle(bundle.getId(), contextWithValidAccountRecordId)) {
+ for (final SubscriptionBase subscriptionBase : subscriptionBaseInternalApi.getSubscriptionsForBundle(baseBundle.getId(), contextWithValidAccountRecordId)) {
final BlockingState blockingState = new DefaultBlockingState(subscriptionBase.getId(), BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_CANCELLED, EntitlementService.ENTITLEMENT_SERVICE_NAME, true, true, false, requestedDate);
entitlementUtils.setBlockingStateAndPostBlockingTransitionEvent(blockingState, contextWithValidAccountRecordId);
}
@@ -378,4 +389,5 @@ public class DefaultEntitlementApi implements EntitlementApi {
throw new EntitlementApiException(e, ErrorCode.__UNKNOWN_ERROR_CODE);
}
}
+
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionApi.java
index 253525e..928930a 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionApi.java
@@ -33,6 +33,10 @@ import com.ning.billing.ObjectType;
import com.ning.billing.callcontext.InternalTenantContext;
import com.ning.billing.entitlement.AccountEntitlements;
import com.ning.billing.entitlement.EntitlementInternalApi;
+import com.ning.billing.entitlement.EventsStream;
+import com.ning.billing.entitlement.api.svcs.DefaultEntitlementInternalApi;
+import com.ning.billing.entitlement.engine.core.EntitlementUtils;
+import com.ning.billing.subscription.api.SubscriptionBase;
import com.ning.billing.subscription.api.SubscriptionBaseInternalApi;
import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
@@ -70,18 +74,20 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
};
private final EntitlementInternalApi entitlementInternalApi;
- private final SubscriptionBaseInternalApi subscriptionInternalApi;
+ private final SubscriptionBaseInternalApi subscriptionBaseInternalApi;
private final InternalCallContextFactory internalCallContextFactory;
private final NonEntityDao nonEntityDao;
private final CacheControllerDispatcher cacheControllerDispatcher;
+ private final EntitlementUtils entitlementUtils;
@Inject
public DefaultSubscriptionApi(final EntitlementInternalApi entitlementInternalApi, final SubscriptionBaseInternalApi subscriptionInternalApi,
- final InternalCallContextFactory internalCallContextFactory, final NonEntityDao nonEntityDao, final CacheControllerDispatcher cacheControllerDispatcher) {
+ final InternalCallContextFactory internalCallContextFactory, final EntitlementUtils entitlementUtils, final NonEntityDao nonEntityDao, final CacheControllerDispatcher cacheControllerDispatcher) {
this.entitlementInternalApi = entitlementInternalApi;
- this.subscriptionInternalApi = subscriptionInternalApi;
+ this.subscriptionBaseInternalApi = subscriptionInternalApi;
this.internalCallContextFactory = internalCallContextFactory;
this.nonEntityDao = nonEntityDao;
+ this.entitlementUtils = entitlementUtils;
this.cacheControllerDispatcher = cacheControllerDispatcher;
}
@@ -144,8 +150,12 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
public SubscriptionBundle getActiveSubscriptionBundleForExternalKey(final String externalKey, final TenantContext context) throws SubscriptionApiException {
final InternalTenantContext internalContext = internalCallContextFactory.createInternalTenantContext(context);
try {
- final SubscriptionBaseBundle baseBundle = subscriptionInternalApi.getActiveBundleForKey(externalKey, internalContext);
- return getSubscriptionBundle(baseBundle.getId(), context);
+ final UUID activeSubscriptionIdForKey = entitlementUtils.getFirstActiveSubscriptionIdForKeyOrNull(externalKey, internalContext);
+ if (activeSubscriptionIdForKey == null) {
+ throw new SubscriptionApiException(new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS, externalKey));
+ }
+ final SubscriptionBase subscriptionBase = subscriptionBaseInternalApi.getSubscriptionFromId(activeSubscriptionIdForKey, internalContext);
+ return getSubscriptionBundle(subscriptionBase.getBundleId(), context);
} catch (SubscriptionBaseApiException e) {
throw new SubscriptionApiException(e);
}
@@ -154,7 +164,7 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
@Override
public List<SubscriptionBundle> getSubscriptionBundlesForExternalKey(final String externalKey, final TenantContext context) throws SubscriptionApiException {
final InternalTenantContext internalContext = internalCallContextFactory.createInternalTenantContext(context);
- final List<SubscriptionBaseBundle> baseBundles = subscriptionInternalApi.getBundlesForKey(externalKey, internalContext);
+ final List<SubscriptionBaseBundle> baseBundles = subscriptionBaseInternalApi.getBundlesForKey(externalKey, internalContext);
final List<SubscriptionBundle> result = new ArrayList<SubscriptionBundle>(baseBundles.size());
for (final SubscriptionBaseBundle cur : baseBundles) {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java
index 99af794..255f8e9 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java
@@ -334,6 +334,9 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
break;
case PAUSE_BILLING:
case PAUSE_ENTITLEMENT:
+ case RESUME_ENTITLEMENT:
+ case RESUME_BILLING:
+ case SERVICE_STATE_CHANGE:
curTargetState.addEntitlementEvent(cur);
break;
case STOP_BILLING:
@@ -507,12 +510,7 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
}
// See https://github.com/killbill/killbill/issues/135
- final String serviceName;
- if (DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME.equals(in.getService())) {
- serviceName = getServiceName(eventType);
- } else {
- serviceName = in.getService();
- }
+ final String serviceName = getRealServiceNameForEntitlementOrExternalServiceName(in.getService(), eventType);
return new DefaultSubscriptionEvent(in.getId(),
entitlementId,
@@ -537,6 +535,16 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
accountTimeZone);
}
+ private static String getRealServiceNameForEntitlementOrExternalServiceName(final String originalServiceName, final SubscriptionEventType eventType) {
+ final String serviceName;
+ if (DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME.equals(originalServiceName)) {
+ serviceName = getServiceName(eventType);
+ } else {
+ serviceName = originalServiceName;
+ }
+ return serviceName;
+ }
+
private SubscriptionEvent toSubscriptionEvent(final SubscriptionBaseTransition in, final SubscriptionEventType eventType, final DateTimeZone accountTimeZone) {
return new DefaultSubscriptionEvent(in.getId(),
in.getSubscriptionId(),
@@ -663,8 +671,22 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
}
public void addEntitlementEvent(final SubscriptionEvent e) {
- final BlockingState converted = new DefaultBlockingState(e.getEntitlementId(), BlockingStateType.SUBSCRIPTION,
- e.getServiceStateName(), e.getServiceName(), false, e.isBlockedEntitlement(), e.isBlockedBilling(),
+ final String serviceName = getRealServiceNameForEntitlementOrExternalServiceName(e.getServiceName(), e.getSubscriptionEventType());
+ final BlockingState lastBlockingStateForService = perServiceBlockingState.get(serviceName);
+
+ // Assume the event has no impact on changes - TODO this is wrong for SERVICE_STATE_CHANGE
+ final boolean blockChange = lastBlockingStateForService != null && lastBlockingStateForService.isBlockChange();
+ // For block entitlement or billing, override the previous state
+ final boolean blockedEntitlement = e.isBlockedEntitlement();
+ final boolean blockedBilling = e.isBlockedBilling();
+
+ final BlockingState converted = new DefaultBlockingState(e.getEntitlementId(),
+ BlockingStateType.SUBSCRIPTION,
+ e.getServiceStateName(),
+ serviceName,
+ blockChange,
+ blockedEntitlement,
+ blockedBilling,
((DefaultSubscriptionEvent) e).getEffectiveDateTime());
perServiceBlockingState.put(converted.getService(), converted);
}
@@ -724,7 +746,7 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
result.add(SubscriptionEventType.PAUSE_BILLING);
}
- if (!shouldResumeEntitlement && !shouldBlockEntitlement && !shouldBlockEntitlement && !shouldBlockBilling && !fixedBlockingState.getService().equals(DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME)) {
+ if (!shouldResumeEntitlement && !shouldResumeBilling && !shouldBlockEntitlement && !shouldBlockBilling && !fixedBlockingState.getService().equals(DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME)) {
result.add(SubscriptionEventType.SERVICE_STATE_CHANGE);
}
return result;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EntitlementUtils.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EntitlementUtils.java
index c595673..113447c 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EntitlementUtils.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/EntitlementUtils.java
@@ -17,8 +17,10 @@
package com.ning.billing.entitlement.engine.core;
import java.io.IOException;
+import java.util.List;
import java.util.UUID;
+import javax.annotation.Nullable;
import javax.inject.Inject;
import org.joda.time.DateTime;
@@ -29,12 +31,17 @@ import com.ning.billing.bus.api.BusEvent;
import com.ning.billing.bus.api.PersistentBus;
import com.ning.billing.bus.api.PersistentBus.EventBusException;
import com.ning.billing.callcontext.InternalCallContext;
+import com.ning.billing.callcontext.InternalTenantContext;
import com.ning.billing.clock.Clock;
import com.ning.billing.entitlement.DefaultEntitlementService;
+import com.ning.billing.entitlement.EventsStream;
import com.ning.billing.entitlement.api.BlockingApiException;
import com.ning.billing.entitlement.api.BlockingState;
import com.ning.billing.entitlement.api.BlockingStateType;
import com.ning.billing.entitlement.api.DefaultBlockingTransitionInternalEvent;
+import com.ning.billing.entitlement.api.DefaultEntitlementApi;
+import com.ning.billing.entitlement.api.Entitlement.EntitlementState;
+import com.ning.billing.entitlement.api.EntitlementApiException;
import com.ning.billing.entitlement.block.BlockingChecker;
import com.ning.billing.entitlement.block.BlockingChecker.BlockingAggregator;
import com.ning.billing.entitlement.dao.BlockingStateDao;
@@ -42,6 +49,13 @@ import com.ning.billing.notificationq.api.NotificationEvent;
import com.ning.billing.notificationq.api.NotificationQueue;
import com.ning.billing.notificationq.api.NotificationQueueService;
import com.ning.billing.notificationq.api.NotificationQueueService.NoSuchNotificationQueue;
+import com.ning.billing.subscription.api.SubscriptionBaseInternalApi;
+import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.TenantContext;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
public class EntitlementUtils {
@@ -49,6 +63,7 @@ public class EntitlementUtils {
private final BlockingStateDao dao;
private final BlockingChecker blockingChecker;
+ private final SubscriptionBaseInternalApi subscriptionBaseInternalApi;
private final PersistentBus eventBus;
private final Clock clock;
protected final NotificationQueueService notificationQueueService;
@@ -56,11 +71,13 @@ public class EntitlementUtils {
@Inject
public EntitlementUtils(final BlockingStateDao dao, final BlockingChecker blockingChecker,
final PersistentBus eventBus, final Clock clock,
+ final SubscriptionBaseInternalApi subscriptionBaseInternalApi,
final NotificationQueueService notificationQueueService) {
this.dao = dao;
this.blockingChecker = blockingChecker;
this.eventBus = eventBus;
this.clock = clock;
+ this.subscriptionBaseInternalApi = subscriptionBaseInternalApi;
this.notificationQueueService = notificationQueueService;
}
@@ -81,6 +98,25 @@ public class EntitlementUtils {
}
}
+ /**
+ *
+ * @param externalKey the bundle externalKey
+ * @param tenantContext the context
+ * @return the id of the first subscription (BASE or STANDALONE) that is still active for that key
+ */
+ public UUID getFirstActiveSubscriptionIdForKeyOrNull(final String externalKey, final InternalTenantContext tenantContext) {
+
+ final Iterable<UUID> nonAddonUUIDs = subscriptionBaseInternalApi.getNonAOSubscriptionIdsForKey(externalKey, tenantContext);
+ return Iterables.tryFind(nonAddonUUIDs, new Predicate<UUID>() {
+ @Override
+ public boolean apply(final UUID input) {
+ final BlockingState state = dao.getBlockingStateForService(input, BlockingStateType.SUBSCRIPTION, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME, tenantContext);
+ return (state == null || !state.getStateName().equals(DefaultEntitlementApi.ENT_STATE_CANCELLED));
+ }
+ }).orNull();
+ }
+
+
private BlockingAggregator getBlockingStateFor(final UUID blockableId, final BlockingStateType type, final InternalCallContext context) {
try {
return blockingChecker.getBlockedStatus(blockableId, type, context);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionApi.java
index bcfd0f1..6856ec9 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionApi.java
@@ -23,6 +23,7 @@ import org.joda.time.LocalDate;
import org.testng.Assert;
import org.testng.annotations.Test;
+import com.ning.billing.ErrorCode;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.AccountApiException;
import com.ning.billing.api.TestApiListener.NextEvent;
@@ -37,6 +38,8 @@ import com.ning.billing.util.audit.AuditLog;
import com.ning.billing.util.audit.ChangeType;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbeddedDB {
@@ -106,12 +109,23 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
final List<SubscriptionBundle> bundles = subscriptionApi.getSubscriptionBundlesForExternalKey(externalKey, callContext);
assertEquals(bundles.size(), 1);
+ final SubscriptionBundle activeBundle = subscriptionApi.getActiveSubscriptionBundleForExternalKey(externalKey, callContext);
+ assertEquals(activeBundle.getId(), entitlement.getBundleId());
+
// Cancel entitlement
clock.addDays(3);
testListener.pushExpectedEvents(NextEvent.CANCEL, NextEvent.BLOCK);
entitlement.cancelEntitlementWithDate(new LocalDate(clock.getUTCNow(), account.getTimeZone()), true, callContext);
assertListenerStatus();
+ try {
+ subscriptionApi.getActiveSubscriptionBundleForExternalKey(externalKey, callContext);
+ Assert.fail("Expected getActiveSubscriptionBundleForExternalKey to fail after cancellation");
+ } catch (SubscriptionApiException e) {
+ assertEquals(e.getCode(), ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS.getCode());
+
+ }
+
clock.addDays(1);
// Re-create a new bundle with same externalKey
final PlanPhaseSpecifier spec2 = new PlanPhaseSpecifier("Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
index 9932e3f..3ebebb8 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
@@ -326,6 +326,77 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
assertNull(events.get(3).getNextPhase());
}
+ @Test(groups = "fast")
+ public void testCancelBundleBeforeSubscription() throws CatalogApiException {
+ clock.setDay(new LocalDate(2013, 1, 1));
+
+ final DateTimeZone accountTimeZone = DateTimeZone.UTC;
+ final UUID accountId = UUID.randomUUID();
+ final UUID bundleId = UUID.randomUUID();
+ final String externalKey = "foo";
+
+ final UUID entitlementId = UUID.randomUUID();
+
+ final List<SubscriptionBaseTransition> allTransitions = new ArrayList<SubscriptionBaseTransition>();
+ final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
+
+ final DateTime requestedDate = new DateTime();
+ DateTime effectiveDate = new DateTime(2013, 1, 1, 15, 43, 25, 0, DateTimeZone.UTC);
+ final SubscriptionBaseTransition tr1 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CREATE, requestedDate, effectiveDate, clock.getUTCNow(), null, "trial");
+ allTransitions.add(tr1);
+
+ // Block the bundle before the subscription
+ effectiveDate = effectiveDate.plusDays(15);
+ clock.addDays(15);
+ final BlockingState bs1 = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE,
+ DefaultEntitlementApi.ENT_STATE_CANCELLED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
+ true, true, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow());
+
+ blockingStates.add(bs1);
+
+ effectiveDate = effectiveDate.plusDays(15);
+ clock.addDays(15);
+ final SubscriptionBaseTransition tr2 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CANCEL, requestedDate, effectiveDate, clock.getUTCNow(), "trial", null);
+ allTransitions.add(tr2);
+
+ final List<Entitlement> entitlements = new ArrayList<Entitlement>();
+ final Entitlement entitlement = createEntitlement(entitlementId, allTransitions);
+ entitlements.add(entitlement);
+
+ final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlements, blockingStates);
+
+ assertEquals(timeline.getAccountId(), accountId);
+ assertEquals(timeline.getBundleId(), bundleId);
+ assertEquals(timeline.getExternalKey(), externalKey);
+
+ final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
+ assertEquals(events.size(), 4);
+
+ assertEquals(events.get(0).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
+ assertEquals(events.get(1).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
+ assertEquals(events.get(2).getEffectiveDate().compareTo(new LocalDate(bs1.getEffectiveDate(), accountTimeZone)), 0);
+ assertEquals(events.get(3).getEffectiveDate().compareTo(new LocalDate(tr2.getEffectiveTransitionTime(), accountTimeZone)), 0);
+
+ assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+ assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+ assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.STOP_ENTITLEMENT);
+ assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.STOP_BILLING);
+
+ assertEquals(events.get(0).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
+ assertEquals(events.get(1).getServiceName(), DefaultSubscriptionBundleTimeline.BILLING_SERVICE_NAME);
+ assertEquals(events.get(2).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
+ assertEquals(events.get(3).getServiceName(), DefaultSubscriptionBundleTimeline.BILLING_SERVICE_NAME);
+
+ assertNull(events.get(0).getPrevPhase());
+ assertEquals(events.get(0).getNextPhase().getName(), "trial");
+ assertNull(events.get(1).getPrevPhase());
+ assertEquals(events.get(1).getNextPhase().getName(), "trial");
+ assertEquals(events.get(2).getPrevPhase().getName(), "trial");
+ assertNull(events.get(2).getNextPhase());
+ assertEquals(events.get(3).getPrevPhase().getName(), "trial");
+ assertNull(events.get(3).getNextPhase());
+ }
+
@Test(groups = "fast", description = "Test for https://github.com/killbill/killbill/issues/135")
public void testOneEntitlementWithPauseResume() throws CatalogApiException {
clock.setDay(new LocalDate(2013, 1, 1));
@@ -368,7 +439,7 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
effectiveDate = effectiveDate.plusDays(15);
clock.addDays(15);
- final String service = "boo";
+ final String service = "boo-service-which-will-pause-billing";
final BlockingState bs3 = new DefaultBlockingState(UUID.randomUUID(), entitlementId, BlockingStateType.SUBSCRIPTION,
"NothingUseful3", service,
false, false, true, effectiveDate, clock.getUTCNow(), clock.getUTCNow());
@@ -416,8 +487,8 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
assertEquals(events.get(5).getSubscriptionEventType(), SubscriptionEventType.RESUME_ENTITLEMENT);
assertEquals(events.get(6).getSubscriptionEventType(), SubscriptionEventType.RESUME_BILLING);
- assertEquals(events.get(7).getSubscriptionEventType(), SubscriptionEventType.SERVICE_STATE_CHANGE);
- assertEquals(events.get(8).getSubscriptionEventType(), SubscriptionEventType.SERVICE_STATE_CHANGE);
+ assertEquals(events.get(7).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
+ assertEquals(events.get(8).getSubscriptionEventType(), SubscriptionEventType.RESUME_BILLING);
assertEquals(events.get(0).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
assertEquals(events.get(1).getServiceName(), DefaultSubscriptionBundleTimeline.BILLING_SERVICE_NAME);
@@ -1081,6 +1152,143 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
assertNull(events.get(3).getNextPhase());
}
+ @Test(groups = "fast", description = "Test for https://github.com/killbill/killbill/issues/149")
+ public void testVariousBlockingStatesAtTheSameEffectiveDate() throws CatalogApiException {
+ clock.setDay(new LocalDate(2013, 1, 1));
+
+ final DateTimeZone accountTimeZone = DateTimeZone.UTC;
+ final UUID accountId = UUID.randomUUID();
+ final UUID bundleId = UUID.randomUUID();
+ final String externalKey = "foo";
+
+ final UUID entitlementId = UUID.randomUUID();
+
+ final List<SubscriptionBaseTransition> allTransitions = new ArrayList<SubscriptionBaseTransition>();
+ final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
+
+ final DateTime requestedDate = new DateTime();
+ DateTime effectiveDate = new DateTime(2013, 1, 1, 15, 43, 25, 0, DateTimeZone.UTC);
+ final SubscriptionBaseTransition tr1 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CREATE, requestedDate, effectiveDate, clock.getUTCNow(), null, "trial");
+ allTransitions.add(tr1);
+
+ // 2013-02-10
+ effectiveDate = effectiveDate.plusDays(40);
+ clock.addDays(40);
+ final BlockingState bs1 = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE,
+ DefaultEntitlementApi.ENT_STATE_BLOCKED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
+ true, true, true, effectiveDate, clock.getUTCNow(), clock.getUTCNow());
+ blockingStates.add(bs1);
+ // Same timestamp on purpose
+ final BlockingState bs2 = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE,
+ DefaultEntitlementApi.ENT_STATE_CLEAR, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
+ false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow());
+ blockingStates.add(bs2);
+
+ // 2013-02-20
+ effectiveDate = effectiveDate.plusDays(10);
+ clock.addDays(10);
+ final BlockingState bs3 = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE,
+ DefaultEntitlementApi.ENT_STATE_BLOCKED, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
+ true, true, true, effectiveDate, clock.getUTCNow(), clock.getUTCNow());
+ blockingStates.add(bs3);
+
+ // 2013-03-02
+ effectiveDate = effectiveDate.plusDays(10);
+ clock.addDays(10);
+ final BlockingState bs4 = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE,
+ DefaultEntitlementApi.ENT_STATE_CLEAR, DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME,
+ false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow());
+ blockingStates.add(bs4);
+
+ final String overdueService = "overdue-service";
+ // 2013-03-04
+ effectiveDate = effectiveDate.plusDays(2);
+ clock.addDays(2);
+ final BlockingState bs5 = new DefaultBlockingState(UUID.randomUUID(), accountId, BlockingStateType.ACCOUNT,
+ "OD1", overdueService,
+ false, false, false, effectiveDate, clock.getUTCNow(), clock.getUTCNow());
+ blockingStates.add(bs5);
+
+ final List<Entitlement> entitlements = new ArrayList<Entitlement>();
+ final Entitlement entitlement = createEntitlement(entitlementId, allTransitions);
+ entitlements.add(entitlement);
+
+ final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlements, blockingStates);
+
+ final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
+ assertEquals(events.size(), 11);
+
+ assertEquals(events.get(0).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
+ assertEquals(events.get(1).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
+
+ assertEquals(events.get(2).getEffectiveDate().compareTo(new LocalDate(bs1.getEffectiveDate(), accountTimeZone)), 0);
+ assertEquals(events.get(3).getEffectiveDate().compareTo(new LocalDate(bs1.getEffectiveDate(), accountTimeZone)), 0);
+ assertEquals(events.get(4).getEffectiveDate().compareTo(new LocalDate(bs2.getEffectiveDate(), accountTimeZone)), 0);
+ assertEquals(events.get(5).getEffectiveDate().compareTo(new LocalDate(bs2.getEffectiveDate(), accountTimeZone)), 0);
+ assertEquals(events.get(6).getEffectiveDate().compareTo(new LocalDate(bs3.getEffectiveDate(), accountTimeZone)), 0);
+ assertEquals(events.get(7).getEffectiveDate().compareTo(new LocalDate(bs3.getEffectiveDate(), accountTimeZone)), 0);
+ assertEquals(events.get(8).getEffectiveDate().compareTo(new LocalDate(bs4.getEffectiveDate(), accountTimeZone)), 0);
+ assertEquals(events.get(9).getEffectiveDate().compareTo(new LocalDate(bs4.getEffectiveDate(), accountTimeZone)), 0);
+
+ assertEquals(events.get(10).getEffectiveDate().compareTo(new LocalDate(bs5.getEffectiveDate(), accountTimeZone)), 0);
+
+ assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+ assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+
+ assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+ assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
+ assertEquals(events.get(4).getSubscriptionEventType(), SubscriptionEventType.RESUME_ENTITLEMENT);
+ assertEquals(events.get(5).getSubscriptionEventType(), SubscriptionEventType.RESUME_BILLING);
+
+ assertEquals(events.get(6).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+ assertEquals(events.get(7).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
+ assertEquals(events.get(8).getSubscriptionEventType(), SubscriptionEventType.RESUME_ENTITLEMENT);
+ assertEquals(events.get(9).getSubscriptionEventType(), SubscriptionEventType.RESUME_BILLING);
+
+ assertEquals(events.get(10).getSubscriptionEventType(), SubscriptionEventType.SERVICE_STATE_CHANGE);
+
+ assertEquals(events.get(0).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
+ assertEquals(events.get(1).getServiceName(), DefaultSubscriptionBundleTimeline.BILLING_SERVICE_NAME);
+
+ assertEquals(events.get(2).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
+ assertEquals(events.get(3).getServiceName(), DefaultSubscriptionBundleTimeline.BILLING_SERVICE_NAME);
+ assertEquals(events.get(4).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
+ assertEquals(events.get(5).getServiceName(), DefaultSubscriptionBundleTimeline.BILLING_SERVICE_NAME);
+
+ assertEquals(events.get(6).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
+ assertEquals(events.get(7).getServiceName(), DefaultSubscriptionBundleTimeline.BILLING_SERVICE_NAME);
+ assertEquals(events.get(8).getServiceName(), DefaultEntitlementService.ENTITLEMENT_SERVICE_NAME);
+ assertEquals(events.get(9).getServiceName(), DefaultSubscriptionBundleTimeline.BILLING_SERVICE_NAME);
+
+ assertEquals(events.get(10).getServiceName(), overdueService);
+
+ assertNull(events.get(0).getPrevPhase());
+ assertEquals(events.get(0).getNextPhase().getName(), "trial");
+ assertNull(events.get(1).getPrevPhase());
+ assertEquals(events.get(1).getNextPhase().getName(), "trial");
+
+ assertEquals(events.get(2).getPrevPhase().getName(), "trial");
+ assertEquals(events.get(2).getNextPhase().getName(), "trial");
+ assertEquals(events.get(3).getPrevPhase().getName(), "trial");
+ assertEquals(events.get(3).getNextPhase().getName(), "trial");
+ assertEquals(events.get(4).getPrevPhase().getName(), "trial");
+ assertEquals(events.get(4).getNextPhase().getName(), "trial");
+ assertEquals(events.get(5).getPrevPhase().getName(), "trial");
+ assertEquals(events.get(5).getNextPhase().getName(), "trial");
+
+ assertEquals(events.get(6).getPrevPhase().getName(), "trial");
+ assertEquals(events.get(6).getNextPhase().getName(), "trial");
+ assertEquals(events.get(7).getPrevPhase().getName(), "trial");
+ assertEquals(events.get(7).getNextPhase().getName(), "trial");
+ assertEquals(events.get(8).getPrevPhase().getName(), "trial");
+ assertEquals(events.get(8).getNextPhase().getName(), "trial");
+ assertEquals(events.get(9).getPrevPhase().getName(), "trial");
+ assertEquals(events.get(9).getNextPhase().getName(), "trial");
+
+ assertEquals(events.get(10).getPrevPhase().getName(), "trial");
+ assertEquals(events.get(10).getNextPhase().getName(), "trial");
+ }
+
private Entitlement createEntitlement(final UUID entitlementId, final List<SubscriptionBaseTransition> allTransitions) {
final DefaultEntitlement result = Mockito.mock(DefaultEntitlement.class);
Mockito.when(result.getId()).thenReturn(entitlementId);
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
index 764872a..91dcf0e 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
@@ -40,6 +40,7 @@ import org.joda.time.LocalDate;
import com.ning.billing.ObjectType;
import com.ning.billing.account.api.AccountApiException;
import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.catalog.api.BillingActionPolicy;
import com.ning.billing.clock.Clock;
import com.ning.billing.entitlement.api.EntitlementApi;
import com.ning.billing.entitlement.api.EntitlementApiException;
@@ -197,21 +198,22 @@ public class BundleResource extends JaxRsResourceBase {
public Response transferBundle(final BundleJson json,
@PathParam(ID_PARAM_NAME) final String id,
@QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
- @QueryParam(QUERY_BUNDLE_TRANSFER_ADDON) @DefaultValue("true") final Boolean transferAddOn,
- @QueryParam(QUERY_BUNDLE_TRANSFER_CANCEL_IMM) @DefaultValue("false") final Boolean cancelImmediatley,
+ @QueryParam(QUERY_BILLING_POLICY) @DefaultValue("END_OF_TERM") final String policyString,
@HeaderParam(HDR_CREATED_BY) final String createdBy,
@HeaderParam(HDR_REASON) final String reason,
@HeaderParam(HDR_COMMENT) final String comment,
@javax.ws.rs.core.Context final UriInfo uriInfo,
@javax.ws.rs.core.Context final HttpServletRequest request) throws EntitlementApiException, SubscriptionApiException, AccountApiException {
+ final BillingActionPolicy policy = BillingActionPolicy.valueOf(policyString.toUpperCase());
+
final CallContext callContext = context.createContext(createdBy, reason, comment, request);
final UUID bundleId = UUID.fromString(id);
final SubscriptionBundle bundle = subscriptionApi.getSubscriptionBundle(bundleId, callContext);
final LocalDate inputLocalDate = toLocalDate(bundle.getAccountId(), requestedDate, callContext);
- final UUID newBundleId = entitlementApi.transferEntitlements(bundle.getAccountId(), UUID.fromString(json.getAccountId()), bundle.getExternalKey(), inputLocalDate, callContext);
+ final UUID newBundleId = entitlementApi.transferEntitlementsOverrideBillingPolicy(bundle.getAccountId(), UUID.fromString(json.getAccountId()), bundle.getExternalKey(), inputLocalDate, policy, callContext);
return uriBuilder.buildResponse(BundleResource.class, "getBundle", newBundleId, uriInfo.getBaseUri().toString());
}
NEWS 11(+11 -0)
diff --git a/NEWS b/NEWS
index 3a050f2..06a5585 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,14 @@
+0.8.7
+ DDL: remove unused paid_through_date column
+
+0.8.6
+ Partial fix for https://github.com/killbill/killbill/issues/141
+ https://github.com/killbill/killbill/issues/143
+ https://github.com/killbill/killbill/issues/145
+ https://github.com/killbill/killbill/issues/147
+ https://github.com/killbill/killbill/issues/148
+ DDL: remove unused billing_cycle_day_utc column
+
0.8.5
https://github.com/killbill/killbill/issues/134
https://github.com/killbill/killbill/issues/135
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java b/subscription/src/main/java/com/ning/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
index bde3dfd..25336b3 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
@@ -163,10 +163,6 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
public SubscriptionBaseBundle createBundleForAccount(final UUID accountId, final String bundleKey, final InternalCallContext context) throws SubscriptionBaseApiException {
final List<SubscriptionBaseBundle> existingBundles = dao.getSubscriptionBundlesForKey(bundleKey, context);
- final SubscriptionBaseBundle result = getActiveBundleForKeyNotException(existingBundles, dao, clock, context);
- if (result != null) {
- throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS, bundleKey);
- }
final DateTime now = clock.getUTCNow();
final DateTime originalCreatedDate = existingBundles.size() > 0 ? existingBundles.get(0).getCreatedDate() : now;
final DefaultSubscriptionBaseBundle bundle = new DefaultSubscriptionBaseBundle(bundleKey, accountId, now, originalCreatedDate, now, now);
@@ -191,14 +187,8 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
}
@Override
- public SubscriptionBaseBundle getActiveBundleForKey(final String bundleKey, final InternalTenantContext context) throws SubscriptionBaseApiException {
- final List<SubscriptionBaseBundle> existingBundles = dao.getSubscriptionBundlesForKey(bundleKey, context);
-
- final SubscriptionBaseBundle result = getActiveBundleForKeyNotException(existingBundles, dao, clock, context);
- if (result == null) {
- throw new SubscriptionBaseApiException(ErrorCode.SUB_GET_INVALID_BUNDLE_KEY, bundleKey);
- }
- return result;
+ public Iterable<UUID> getNonAOSubscriptionIdsForKey(final String bundleKey, final InternalTenantContext context) {
+ return dao.getNonAOSubscriptionIdsForKey(bundleKey, context);
}
public static SubscriptionBaseBundle getActiveBundleForKeyNotException(final List<SubscriptionBaseBundle> existingBundles, final SubscriptionDao dao, final Clock clock, final InternalTenantContext context) {
@@ -273,8 +263,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
DateTime chargedThruDate, InternalCallContext context) {
final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) dao.getSubscriptionFromId(subscriptionId, context);
final SubscriptionBuilder builder = new SubscriptionBuilder(subscription)
- .setChargedThroughDate(chargedThruDate)
- .setPaidThroughDate(subscription.getPaidThroughDate());
+ .setChargedThroughDate(chargedThruDate);
dao.updateChargedThroughDate(new DefaultSubscriptionBase(builder), context);
}
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBase.java b/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBase.java
index 4faf2f2..bb191d5 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBase.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/user/DefaultSubscriptionBase.java
@@ -78,7 +78,6 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
//
private final long activeVersion;
private final DateTime chargedThroughDate;
- private final DateTime paidThroughDate;
//
// User APIs (create, change, cancelWithRequestedDate,...) will recompute those each time,
@@ -110,7 +109,6 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
this.category = builder.getCategory();
this.activeVersion = builder.getActiveVersion();
this.chargedThroughDate = builder.getChargedThroughDate();
- this.paidThroughDate = builder.getPaidThroughDate();
}
// Used for API to make sure we have a clock and an apiService set before we return the object
@@ -124,7 +122,6 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
this.category = internalSubscription.getCategory();
this.activeVersion = internalSubscription.getActiveVersion();
this.chargedThroughDate = internalSubscription.getChargedThroughDate();
- this.paidThroughDate = internalSubscription.getPaidThroughDate();
this.transitions = new LinkedList<SubscriptionBaseTransition>(internalSubscription.getAllTransitions());
this.events = internalSubscription.getEvents();
}
@@ -349,11 +346,6 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
}
@Override
- public DateTime getPaidThroughDate() {
- return paidThroughDate;
- }
-
- @Override
public List<SubscriptionBaseTransition> getAllTransitions() {
if (transitions == null) {
return Collections.emptyList();
diff --git a/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBuilder.java b/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBuilder.java
index 94f23f7..2347887 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBuilder.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/api/user/SubscriptionBuilder.java
@@ -25,6 +25,7 @@ import com.ning.billing.catalog.api.ProductCategory;
import com.ning.billing.subscription.exceptions.SubscriptionBaseError;
public class SubscriptionBuilder {
+
private UUID id;
private UUID bundleId;
private DateTime createdDate;
@@ -34,7 +35,6 @@ public class SubscriptionBuilder {
private Long activeVersion;
private ProductCategory category;
private DateTime chargedThroughDate;
- private DateTime paidThroughDate;
public SubscriptionBuilder() {
this.activeVersion = SubscriptionEvents.INITIAL_VERSION;
@@ -48,7 +48,6 @@ public class SubscriptionBuilder {
this.category = original.getCategory();
this.activeVersion = original.getActiveVersion();
this.chargedThroughDate = original.getChargedThroughDate();
- this.paidThroughDate = original.getPaidThroughDate();
}
public SubscriptionBuilder setId(final UUID id) {
@@ -91,11 +90,6 @@ public class SubscriptionBuilder {
return this;
}
- public SubscriptionBuilder setPaidThroughDate(final DateTime paidThroughDate) {
- this.paidThroughDate = paidThroughDate;
- return this;
- }
-
public SubscriptionBuilder setCategory(final ProductCategory category) {
this.category = category;
return this;
@@ -137,21 +131,17 @@ public class SubscriptionBuilder {
return chargedThroughDate;
}
- public DateTime getPaidThroughDate() {
- return paidThroughDate;
- }
-
private void checkAllFieldsSet() {
for (final Field cur : SubscriptionBuilder.class.getDeclaredFields()) {
try {
final Object value = cur.get(this);
if (value == null) {
throw new SubscriptionBaseError(String.format("Field %s has not been set for SubscriptionBase",
- cur.getName()));
+ cur.getName()));
}
} catch (IllegalAccessException e) {
throw new SubscriptionBaseError(String.format("Failed to access value for field %s for SubscriptionBase",
- cur.getName()), e);
+ cur.getName()), e);
}
}
}
diff --git a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/DefaultSubscriptionDao.java b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/DefaultSubscriptionDao.java
index 21edeeb..07096eb 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/DefaultSubscriptionDao.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/DefaultSubscriptionDao.java
@@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -93,8 +94,9 @@ import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Collections2;
-import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
public class DefaultSubscriptionDao implements SubscriptionDao {
@@ -181,6 +183,43 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
}
@Override
+ public Iterable<UUID> getNonAOSubscriptionIdsForKey(final String bundleKey, final InternalTenantContext context) {
+ return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Iterable<UUID>>() {
+ @Override
+ public Iterable<UUID> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+
+ final BundleSqlDao bundleSqlDao = entitySqlDaoWrapperFactory.become(BundleSqlDao.class);
+
+ final List<SubscriptionBundleModelDao> bundles = bundleSqlDao.getBundlesForKey(bundleKey, context);
+
+ final SubscriptionSqlDao subscriptionSqlDao = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class);
+ return Iterables.concat(Iterables.transform(bundles, new Function<SubscriptionBundleModelDao, Iterable<UUID>>() {
+
+ @Override
+ public Iterable<UUID> apply(final SubscriptionBundleModelDao cur) {
+
+ final List<SubscriptionModelDao> subscriptions = subscriptionSqlDao.getSubscriptionsFromBundleId(cur.getId().toString(), context);
+
+ final Iterable<SubscriptionModelDao> nonAddonSubscriptions = Iterables.filter(subscriptions, new Predicate<SubscriptionModelDao>() {
+ @Override
+ public boolean apply(final SubscriptionModelDao input) {
+ return input.getCategory() != ProductCategory.ADD_ON;
+ }
+ });
+
+ return Iterables.transform(nonAddonSubscriptions, new Function<SubscriptionModelDao, UUID>() {
+ @Override
+ public UUID apply(final SubscriptionModelDao input) {
+ return input.getId();
+ }
+ });
+ }
+ }));
+ }
+ });
+ }
+
+ @Override
public SubscriptionBaseBundle createSubscriptionBundle(final DefaultSubscriptionBaseBundle bundle, final InternalCallContext context) {
return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<SubscriptionBaseBundle>() {
@Override
@@ -259,7 +298,6 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
});
}
-
@Override
public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(final InternalTenantContext context) {
final Map<UUID, List<SubscriptionBase>> subscriptionsFromAccountId = getSubscriptionsFromAccountId(context);
@@ -279,7 +317,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
final Multimap<UUID, SubscriptionBaseEvent> eventsForSubscriptions = ArrayListMultimap.create();
for (final SubscriptionBase cur : subscriptionsForBundle) {
- final Collection<SubscriptionBaseEvent> events= Collections2.filter(eventsForAccount, new Predicate<SubscriptionBaseEvent>() {
+ final Collection<SubscriptionBaseEvent> events = Collections2.filter(eventsForAccount, new Predicate<SubscriptionBaseEvent>() {
@Override
public boolean apply(final SubscriptionBaseEvent input) {
return input.getSubscriptionId().equals(cur.getId());
@@ -289,7 +327,7 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
eventsForSubscriptions.putAll(cur.getId(), ImmutableList.copyOf(events));
}
- result.put(bundleId, buildBundleSubscriptions(subscriptionsForBundle, eventsForSubscriptions,context));
+ result.put(bundleId, buildBundleSubscriptions(subscriptionsForBundle, eventsForSubscriptions, context));
}
return result;
}
@@ -379,7 +417,6 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
});
}
-
@Override
public Map<UUID, List<SubscriptionBaseEvent>> getEventsForBundle(final UUID bundleId, final InternalTenantContext context) {
return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Map<UUID, List<SubscriptionBaseEvent>>>() {
@@ -800,7 +837,6 @@ public class DefaultSubscriptionDao implements SubscriptionDao {
final List<SubscriptionBase> result = new ArrayList<SubscriptionBase>(input.size());
for (final SubscriptionBase cur : input) {
-
final List<SubscriptionBaseEvent> events = eventsForSubscription != null ?
(List<SubscriptionBaseEvent>) eventsForSubscription.get(cur.getId()) :
getEventsForSubscription(cur.getId(), context);
diff --git a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionModelDao.java b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionModelDao.java
index bd181c6..9defa26 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionModelDao.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/model/SubscriptionModelDao.java
@@ -36,12 +36,11 @@ public class SubscriptionModelDao extends EntityBase implements EntityModelDao<S
private DateTime bundleStartDate;
private long activeVersion;
private DateTime chargedThroughDate;
- private DateTime paidThroughDate;
public SubscriptionModelDao() { /* For the DAO mapper */ }
public SubscriptionModelDao(final UUID id, final UUID bundleId, final ProductCategory category, final DateTime startDate, final DateTime bundleStartDate,
- final long activeVersion, final DateTime chargedThroughDate, final DateTime paidThroughDate, final DateTime createdDate, final DateTime updateDate) {
+ final long activeVersion, final DateTime chargedThroughDate, final DateTime createdDate, final DateTime updateDate) {
super(id, createdDate, updateDate);
this.bundleId = bundleId;
this.category = category;
@@ -49,12 +48,11 @@ public class SubscriptionModelDao extends EntityBase implements EntityModelDao<S
this.bundleStartDate = bundleStartDate;
this.activeVersion = activeVersion;
this.chargedThroughDate = chargedThroughDate;
- this.paidThroughDate = paidThroughDate;
}
public SubscriptionModelDao(final DefaultSubscriptionBase src) {
this(src.getId(), src.getBundleId(), src.getCategory(), src.getAlignStartDate(), src.getBundleStartDate(), src.getActiveVersion(),
- src.getChargedThroughDate(), src.getPaidThroughDate(), src.getCreatedDate(), src.getUpdatedDate());
+ src.getChargedThroughDate(), src.getCreatedDate(), src.getUpdatedDate());
}
public UUID getBundleId() {
@@ -81,10 +79,6 @@ public class SubscriptionModelDao extends EntityBase implements EntityModelDao<S
return chargedThroughDate;
}
- public DateTime getPaidThroughDate() {
- return paidThroughDate;
- }
-
public void setBundleId(final UUID bundleId) {
this.bundleId = bundleId;
}
@@ -109,10 +103,6 @@ public class SubscriptionModelDao extends EntityBase implements EntityModelDao<S
this.chargedThroughDate = chargedThroughDate;
}
- public void setPaidThroughDate(final DateTime paidThroughDate) {
- this.paidThroughDate = paidThroughDate;
- }
-
public static SubscriptionBase toSubscription(final SubscriptionModelDao src) {
if (src == null) {
return null;
@@ -127,7 +117,6 @@ public class SubscriptionModelDao extends EntityBase implements EntityModelDao<S
.setAlignStartDate(src.getStartDate())
.setActiveVersion(src.getActiveVersion())
.setChargedThroughDate(src.getChargedThroughDate())
- .setPaidThroughDate(src.getPaidThroughDate())
.setCreatedDate(src.getCreatedDate())
.setUpdatedDate(src.getUpdatedDate()));
}
@@ -142,7 +131,6 @@ public class SubscriptionModelDao extends EntityBase implements EntityModelDao<S
sb.append(", bundleStartDate=").append(bundleStartDate);
sb.append(", activeVersion=").append(activeVersion);
sb.append(", chargedThroughDate=").append(chargedThroughDate);
- sb.append(", paidThroughDate=").append(paidThroughDate);
sb.append('}');
return sb.toString();
}
@@ -176,9 +164,6 @@ public class SubscriptionModelDao extends EntityBase implements EntityModelDao<S
if (chargedThroughDate != null ? !chargedThroughDate.equals(that.chargedThroughDate) : that.chargedThroughDate != null) {
return false;
}
- if (paidThroughDate != null ? !paidThroughDate.equals(that.paidThroughDate) : that.paidThroughDate != null) {
- return false;
- }
if (startDate != null ? !startDate.equals(that.startDate) : that.startDate != null) {
return false;
}
@@ -195,7 +180,6 @@ public class SubscriptionModelDao extends EntityBase implements EntityModelDao<S
result = 31 * result + (bundleStartDate != null ? bundleStartDate.hashCode() : 0);
result = 31 * result + (int) (activeVersion ^ (activeVersion >>> 32));
result = 31 * result + (chargedThroughDate != null ? chargedThroughDate.hashCode() : 0);
- result = 31 * result + (paidThroughDate != null ? paidThroughDate.hashCode() : 0);
return result;
}
diff --git a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/RepairSubscriptionDao.java b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/RepairSubscriptionDao.java
index b05e650..fe12bc3 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/RepairSubscriptionDao.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/RepairSubscriptionDao.java
@@ -306,6 +306,11 @@ public class RepairSubscriptionDao implements SubscriptionDao, RepairSubscriptio
}
@Override
+ public List<UUID> getNonAOSubscriptionIdsForKey(final String bundleKey, final InternalTenantContext context) {
+ throw new SubscriptionBaseError(NOT_IMPLEMENTED);
+ }
+
+ @Override
public List<SubscriptionBaseBundle> getSubscriptionBundlesForAccountAndKey(final UUID accountId, final String bundleKey, final InternalTenantContext context) {
throw new SubscriptionBaseError(NOT_IMPLEMENTED);
}
diff --git a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/SubscriptionDao.java b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/SubscriptionDao.java
index b7cffc0..77229e4 100644
--- a/subscription/src/main/java/com/ning/billing/subscription/engine/dao/SubscriptionDao.java
+++ b/subscription/src/main/java/com/ning/billing/subscription/engine/dao/SubscriptionDao.java
@@ -39,6 +39,8 @@ public interface SubscriptionDao {
public List<SubscriptionBaseBundle> getSubscriptionBundlesForKey(String bundleKey, InternalTenantContext context);
+ public Iterable<UUID> getNonAOSubscriptionIdsForKey(final String bundleKey, final InternalTenantContext context);
+
public List<SubscriptionBaseBundle> getSubscriptionBundlesForAccountAndKey(UUID accountId, String bundleKey, InternalTenantContext context);
public SubscriptionBaseBundle getSubscriptionBundleFromId(UUID bundleId, InternalTenantContext context);
diff --git a/subscription/src/main/resources/com/ning/billing/subscription/engine/dao/SubscriptionSqlDao.sql.stg b/subscription/src/main/resources/com/ning/billing/subscription/engine/dao/SubscriptionSqlDao.sql.stg
index ad122a2..55b2cdb 100644
--- a/subscription/src/main/resources/com/ning/billing/subscription/engine/dao/SubscriptionSqlDao.sql.stg
+++ b/subscription/src/main/resources/com/ning/billing/subscription/engine/dao/SubscriptionSqlDao.sql.stg
@@ -9,7 +9,6 @@ tableFields(prefix) ::= <<
, <prefix>bundle_start_date
, <prefix>active_version
, <prefix>charged_through_date
-, <prefix>paid_through_date
, <prefix>created_by
, <prefix>created_date
, <prefix>updated_by
@@ -23,7 +22,6 @@ tableValues() ::= <<
, :bundleStartDate
, :activeVersion
, :chargedThroughDate
-, :paidThroughDate
, :createdBy
, :createdDate
, :updatedBy
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/transfer/TestTransfer.java b/subscription/src/test/java/com/ning/billing/subscription/api/transfer/TestTransfer.java
index 62cf563..8b5af59 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/transfer/TestTransfer.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/transfer/TestTransfer.java
@@ -99,10 +99,6 @@ public class TestTransfer extends SubscriptionTestSuiteWithEmbeddedDB {
// The MIGRATE_BILLING event should have been invalidated
assertEquals(subscriptionInternalApi.getBillingTransitions(oldBaseSubscription, internalCallContext).size(), 0);
//assertEquals(subscriptionInternalApi.getBillingTransitions(oldBaseSubscription, internalCallContext).get(0).getTransitionType(), SubscriptionBaseTransitionType.CANCEL);
-
- final SubscriptionBaseBundle newBundle = subscriptionInternalApi.getActiveBundleForKey(bundle.getExternalKey(), internalCallContext);
- assertNotEquals(newBundle.getId(), bundle.getId());
- assertEquals(newBundle.getOriginalCreatedDate().compareTo(bundleCreatedDate), 0);
}
@Test(groups = "slow")
diff --git a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiCreate.java b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiCreate.java
index de6eef8..ebb176c 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiCreate.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/api/user/TestUserApiCreate.java
@@ -57,14 +57,6 @@ public class TestUserApiCreate extends SubscriptionTestSuiteWithEmbeddedDB {
assertListenerStatus();
assertNotNull(subscription);
- try {
- final SubscriptionBaseBundle newBundle = subscriptionInternalApi.createBundleForAccount(bundle.getAccountId(), DefaultSubscriptionTestInitializer.DEFAULT_BUNDLE_KEY, internalCallContext);
-
- Assert.fail("Unexpected success to create a bundle");
- } catch (SubscriptionBaseApiException e) {
- Assert.assertEquals(e.getCode(), ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS.getCode());
- }
-
testListener.pushExpectedEvent(NextEvent.CANCEL);
subscription.cancelWithDate(clock.getUTCNow(), callContext);
assertListenerStatus();
diff --git a/subscription/src/test/java/com/ning/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java b/subscription/src/test/java/com/ning/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
index 77ce836..4d23fd3 100644
--- a/subscription/src/test/java/com/ning/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
+++ b/subscription/src/test/java/com/ning/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
@@ -114,6 +114,11 @@ public class MockSubscriptionDaoMemory implements SubscriptionDao {
}
@Override
+ public List<UUID> getNonAOSubscriptionIdsForKey(final String bundleKey, final InternalTenantContext context) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public SubscriptionBaseBundle getSubscriptionBundleFromId(final UUID bundleId, final InternalTenantContext context) {
for (final SubscriptionBaseBundle cur : bundles) {
if (cur.getId().equals(bundleId)) {
diff --git a/util/src/test/java/com/ning/billing/mock/MockSubscription.java b/util/src/test/java/com/ning/billing/mock/MockSubscription.java
index a663791..f32ce7a 100644
--- a/util/src/test/java/com/ning/billing/mock/MockSubscription.java
+++ b/util/src/test/java/com/ning/billing/mock/MockSubscription.java
@@ -166,11 +166,6 @@ public class MockSubscription implements SubscriptionBase {
}
@Override
- public DateTime getPaidThroughDate() {
- return sub.getPaidThroughDate();
- }
-
- @Override
public ProductCategory getCategory() {
return sub.getCategory();
}