@Override public boolean apply(final SubscriptionBase input) { return ProductCategory.BASE.equals(input.getCategory()); } });
@Override public ProductCategory getCategory() { return sub.getCategory(); }
final InternalTenantContext context) throws EntitlementApiException { if (!ProductCategory.ADD_ON.equals(subscription.getCategory())) {
@Override public boolean apply(final SubscriptionBase subscription) { return ProductCategory.ADD_ON.equals(subscription.getCategory()) && // Check the entitlement for that add-on hasn't been cancelled yet getEntitlementCancellationEvent(subscription.getId()) == null && ( // Base subscription cancelled baseTransitionTriggerNextProduct == null || ( // Change plan - check which add-ons to cancel includedAddonsForProduct.contains(subscription.getLastActivePlan().getProduct().getName()) || !availableAddonsForProduct.contains(subscription.getLastActivePlan().getProduct().getName()) ) ); } });
@Override public Collection<BlockingState> computeAddonsBlockingStatesForFutureSubscriptionBaseEvents() { if (!ProductCategory.BASE.equals(subscription.getCategory())) { // Only base subscriptions have add-ons return ImmutableList.of(); } // We need to find the first "trigger" transition, from which we will create the add-ons cancellation events. // This can either be a future entitlement cancel... if (isEntitlementFutureCancelled()) { // Note that in theory we could always only look subscription base as we assume entitlement cancel means subscription base cancel // but we want to use the effective date of the entitlement cancel event to create the add-on cancel event final BlockingState futureEntitlementCancelEvent = getEntitlementCancellationEvent(subscription.getId()); return computeAddonsBlockingStatesForNextSubscriptionBaseEvent(futureEntitlementCancelEvent.getEffectiveDate(), false); } else if (isEntitlementFutureChanged()) { // ...or a subscription change (i.e. a change plan where the new plan has an impact on the existing add-on). // We need to go back to subscription base as entitlement doesn't know about these return computeAddonsBlockingStatesForNextSubscriptionBaseEvent(utcNow, true); } else { return ImmutableList.of(); } }
public void blockAddOnsIfRequired(final DateTime effectiveDate, final TenantContext context, final InternalCallContext internalCallContext) throws EntitlementApiException { // Optimization - bail early if (!ProductCategory.BASE.equals(getSubscriptionBase().getCategory())) { // Only base subscriptions have add-ons return; } // Get the latest state from disk (we just got cancelled or changed plan) refresh(context); // If cancellation/change occurs in the future, do nothing for now but add a notification entry. // This is to distinguish whether a future cancellation was requested by the user, or was a side effect // (e.g. base plan cancellation): future entitlement cancellations for add-ons on disk always reflect // an explicit cancellation. This trick lets us determine what to do when un-cancelling. // This mirror the behavior in subscription base (see DefaultSubscriptionBaseApiService). final DateTime now = clock.getUTCNow(); if (effectiveDate.compareTo(now) > 0) { // Note that usually we record the notification from the DAO. We cannot do it here because not all calls // go through the DAO (e.g. change) final boolean isBaseEntitlementCancelled = eventsStream.isEntitlementCancelled(); final NotificationEvent notificationEvent = new EntitlementNotificationKey(getId(), getBundleId(), isBaseEntitlementCancelled ? EntitlementNotificationKeyAction.CANCEL : EntitlementNotificationKeyAction.CHANGE, effectiveDate); recordFutureNotification(effectiveDate, notificationEvent, internalCallContext); return; } final Collection<BlockingState> addOnsBlockingStates = eventsStream.computeAddonsBlockingStatesForNextSubscriptionBaseEvent(effectiveDate); for (final BlockingState addOnBlockingState : addOnsBlockingStates) { entitlementUtils.setBlockingStateAndPostBlockingTransitionEvent(addOnBlockingState, internalCallContext); } }