Search in sources :

Example 1 with EntitlementState

use of org.killbill.billing.entitlement.api.Entitlement.EntitlementState in project killbill by killbill.

the class DefaultSubscriptionBase method rebuildTransitions.

public void rebuildTransitions(final List<SubscriptionBaseEvent> inputEvents, final SubscriptionCatalog catalog) throws CatalogApiException {
    if (inputEvents == null) {
        return;
    }
    this.events = inputEvents;
    Collections.sort(inputEvents, new Comparator<SubscriptionBaseEvent>() {

        @Override
        public int compare(final SubscriptionBaseEvent o1, final SubscriptionBaseEvent o2) {
            final int res = o1.getEffectiveDate().compareTo(o2.getEffectiveDate());
            if (res != 0) {
                return res;
            }
            // In-memory events have a total order of 0, make sure they are after on disk event
            if (o1.getTotalOrdering() == 0 && o2.getTotalOrdering() > 0) {
                return 1;
            } else if (o1.getTotalOrdering() > 0 && o2.getTotalOrdering() == 0) {
                return -1;
            } else if (o1.getTotalOrdering() == o2.getTotalOrdering()) {
                return 0;
            } else {
                return o1.getTotalOrdering() < (o2.getTotalOrdering()) ? -1 : 1;
            }
        }
    });
    removeEverythingPastCancelEvent(events);
    final UUID nextUserToken = null;
    UUID nextEventId;
    DateTime nextCreatedDate;
    EntitlementState nextState = null;
    String nextPlanName = null;
    String nextPhaseName = null;
    Integer nextBillingCycleDayLocal = null;
    UUID prevEventId = null;
    DateTime prevCreatedDate = null;
    EntitlementState previousState = null;
    PriceList previousPriceList = null;
    Plan previousPlan = null;
    PlanPhase previousPhase = null;
    Integer previousBillingCycleDayLocal = null;
    transitions = new LinkedList<SubscriptionBaseTransition>();
    // Track each time we change Plan to fetch the Plan from the right catalog version
    DateTime lastPlanChangeTime = null;
    for (final SubscriptionBaseEvent cur : inputEvents) {
        if (!cur.isActive()) {
            continue;
        }
        ApiEventType apiEventType = null;
        boolean isFromDisk = true;
        nextEventId = cur.getId();
        nextCreatedDate = cur.getCreatedDate();
        switch(cur.getType()) {
            case PHASE:
                final PhaseEvent phaseEV = (PhaseEvent) cur;
                nextPhaseName = phaseEV.getPhase();
                break;
            case BCD_UPDATE:
                final BCDEvent bcdEvent = (BCDEvent) cur;
                nextBillingCycleDayLocal = bcdEvent.getBillCycleDayLocal();
                break;
            case API_USER:
                final ApiEvent userEV = (ApiEvent) cur;
                apiEventType = userEV.getApiEventType();
                isFromDisk = userEV.isFromDisk();
                switch(apiEventType) {
                    case TRANSFER:
                    case CREATE:
                        prevEventId = null;
                        prevCreatedDate = null;
                        previousState = null;
                        previousPlan = null;
                        previousPhase = null;
                        previousPriceList = null;
                        nextState = EntitlementState.ACTIVE;
                        nextPlanName = userEV.getEventPlan();
                        nextPhaseName = userEV.getEventPlanPhase();
                        lastPlanChangeTime = cur.getEffectiveDate();
                        break;
                    case CHANGE:
                        nextPlanName = userEV.getEventPlan();
                        nextPhaseName = userEV.getEventPlanPhase();
                        lastPlanChangeTime = cur.getEffectiveDate();
                        break;
                    case CANCEL:
                        nextState = EntitlementState.CANCELLED;
                        nextPlanName = null;
                        nextPhaseName = null;
                        break;
                    case UNCANCEL:
                    case UNDO_CHANGE:
                    default:
                        throw new SubscriptionBaseError(String.format("Unexpected UserEvent type = %s", userEV.getApiEventType().toString()));
                }
                break;
            default:
                throw new SubscriptionBaseError(String.format("Unexpected Event type = %s", cur.getType()));
        }
        final Plan nextPlan = (nextPlanName != null) ? catalog.findPlan(nextPlanName, cur.getEffectiveDate(), lastPlanChangeTime) : null;
        final PlanPhase nextPhase = (nextPlan != null && nextPhaseName != null) ? nextPlan.findPhase(nextPhaseName) : null;
        final PriceList nextPriceList = (nextPlan != null) ? nextPlan.getPriceList() : null;
        final SubscriptionBaseTransitionData transition = new SubscriptionBaseTransitionData(cur.getId(), id, bundleId, bundleExternalKey, cur.getType(), apiEventType, cur.getEffectiveDate(), prevEventId, prevCreatedDate, previousState, previousPlan, previousPhase, previousPriceList, previousBillingCycleDayLocal, nextEventId, nextCreatedDate, nextState, nextPlan, nextPhase, nextPriceList, nextBillingCycleDayLocal, cur.getTotalOrdering(), cur.getCreatedDate(), nextUserToken, isFromDisk);
        transitions.add(transition);
        previousState = nextState;
        previousPlan = nextPlan;
        previousPhase = nextPhase;
        previousPriceList = nextPriceList;
        prevEventId = nextEventId;
        prevCreatedDate = nextCreatedDate;
        previousBillingCycleDayLocal = nextBillingCycleDayLocal;
    }
}
Also used : ApiEventType(org.killbill.billing.subscription.events.user.ApiEventType) PhaseEvent(org.killbill.billing.subscription.events.phase.PhaseEvent) BCDEvent(org.killbill.billing.subscription.events.bcd.BCDEvent) Plan(org.killbill.billing.catalog.api.Plan) DateTime(org.joda.time.DateTime) EntitlementState(org.killbill.billing.entitlement.api.Entitlement.EntitlementState) SubscriptionBaseError(org.killbill.billing.subscription.exceptions.SubscriptionBaseError) ApiEvent(org.killbill.billing.subscription.events.user.ApiEvent) PlanPhase(org.killbill.billing.catalog.api.PlanPhase) UUID(java.util.UUID) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) PriceList(org.killbill.billing.catalog.api.PriceList)

Example 2 with EntitlementState

use of org.killbill.billing.entitlement.api.Entitlement.EntitlementState in project killbill by killbill.

the class DefaultSubscriptionBase method rebuildTransitions.

public void rebuildTransitions(final List<SubscriptionBaseEvent> inputEvents, final Catalog catalog) throws CatalogApiException {
    if (inputEvents == null) {
        return;
    }
    this.events = inputEvents;
    filterOutDuplicateCancelEvents(events);
    UUID nextUserToken = null;
    UUID nextEventId = null;
    DateTime nextCreatedDate = null;
    EntitlementState nextState = null;
    String nextPlanName = null;
    String nextPhaseName = null;
    Integer nextBillingCycleDayLocal = null;
    UUID prevEventId = null;
    DateTime prevCreatedDate = null;
    EntitlementState previousState = null;
    PriceList previousPriceList = null;
    Plan previousPlan = null;
    PlanPhase previousPhase = null;
    Integer previousBillingCycleDayLocal = null;
    transitions = new LinkedList<SubscriptionBaseTransition>();
    for (final SubscriptionBaseEvent cur : inputEvents) {
        if (!cur.isActive()) {
            continue;
        }
        ApiEventType apiEventType = null;
        boolean isFromDisk = true;
        nextEventId = cur.getId();
        nextCreatedDate = cur.getCreatedDate();
        switch(cur.getType()) {
            case PHASE:
                final PhaseEvent phaseEV = (PhaseEvent) cur;
                nextPhaseName = phaseEV.getPhase();
                break;
            case BCD_UPDATE:
                final BCDEvent bcdEvent = (BCDEvent) cur;
                nextBillingCycleDayLocal = bcdEvent.getBillCycleDayLocal();
                break;
            case API_USER:
                final ApiEvent userEV = (ApiEvent) cur;
                apiEventType = userEV.getApiEventType();
                isFromDisk = userEV.isFromDisk();
                switch(apiEventType) {
                    case TRANSFER:
                    case CREATE:
                        prevEventId = null;
                        prevCreatedDate = null;
                        previousState = null;
                        previousPlan = null;
                        previousPhase = null;
                        previousPriceList = null;
                        nextState = EntitlementState.ACTIVE;
                        nextPlanName = userEV.getEventPlan();
                        nextPhaseName = userEV.getEventPlanPhase();
                        break;
                    case CHANGE:
                        nextPlanName = userEV.getEventPlan();
                        nextPhaseName = userEV.getEventPlanPhase();
                        break;
                    case CANCEL:
                        nextState = EntitlementState.CANCELLED;
                        nextPlanName = null;
                        nextPhaseName = null;
                        break;
                    case UNCANCEL:
                    default:
                        throw new SubscriptionBaseError(String.format("Unexpected UserEvent type = %s", userEV.getApiEventType().toString()));
                }
                break;
            default:
                throw new SubscriptionBaseError(String.format("Unexpected Event type = %s", cur.getType()));
        }
        Plan nextPlan = null;
        PlanPhase nextPhase = null;
        PriceList nextPriceList = null;
        nextPlan = (nextPlanName != null) ? catalog.findPlan(nextPlanName, cur.getEffectiveDate(), getAlignStartDate()) : null;
        nextPhase = (nextPhaseName != null) ? catalog.findPhase(nextPhaseName, cur.getEffectiveDate(), getAlignStartDate()) : null;
        nextPriceList = (nextPlan != null) ? catalog.findPriceListForPlan(nextPlanName, cur.getEffectiveDate(), getAlignStartDate()) : null;
        final SubscriptionBaseTransitionData transition = new SubscriptionBaseTransitionData(cur.getId(), id, bundleId, bundleExternalKey, cur.getType(), apiEventType, cur.getEffectiveDate(), prevEventId, prevCreatedDate, previousState, previousPlan, previousPhase, previousPriceList, previousBillingCycleDayLocal, nextEventId, nextCreatedDate, nextState, nextPlan, nextPhase, nextPriceList, nextBillingCycleDayLocal, cur.getTotalOrdering(), cur.getCreatedDate(), nextUserToken, isFromDisk);
        transitions.add(transition);
        previousState = nextState;
        previousPlan = nextPlan;
        previousPhase = nextPhase;
        previousPriceList = nextPriceList;
        prevEventId = nextEventId;
        prevCreatedDate = nextCreatedDate;
        previousBillingCycleDayLocal = nextBillingCycleDayLocal;
    }
}
Also used : ApiEventType(org.killbill.billing.subscription.events.user.ApiEventType) PhaseEvent(org.killbill.billing.subscription.events.phase.PhaseEvent) BCDEvent(org.killbill.billing.subscription.events.bcd.BCDEvent) Plan(org.killbill.billing.catalog.api.Plan) DateTime(org.joda.time.DateTime) EntitlementState(org.killbill.billing.entitlement.api.Entitlement.EntitlementState) SubscriptionBaseError(org.killbill.billing.subscription.exceptions.SubscriptionBaseError) ApiEvent(org.killbill.billing.subscription.events.user.ApiEvent) PlanPhase(org.killbill.billing.catalog.api.PlanPhase) UUID(java.util.UUID) PriceList(org.killbill.billing.catalog.api.PriceList) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent)

Example 3 with EntitlementState

use of org.killbill.billing.entitlement.api.Entitlement.EntitlementState in project killbill by killbill.

the class DefaultSubscriptionBaseApiService method cancelWithPolicy.

@Override
public boolean cancelWithPolicy(final DefaultSubscriptionBase subscription, final BillingActionPolicy policy, final DateTimeZone accountTimeZone, int accountBillCycleDayLocal, final CallContext context) throws SubscriptionBaseApiException {
    final EntitlementState currentState = subscription.getState();
    if (currentState == EntitlementState.CANCELLED) {
        throw new SubscriptionBaseApiException(ErrorCode.SUB_CANCEL_BAD_STATE, subscription.getId(), currentState);
    }
    final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
    return cancelWithPolicyNoValidation(ImmutableList.<DefaultSubscriptionBase>of(subscription), policy, accountTimeZone, accountBillCycleDayLocal, internalCallContext);
}
Also used : InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) EntitlementState(org.killbill.billing.entitlement.api.Entitlement.EntitlementState) PlanPhasePriceOverride(org.killbill.billing.catalog.api.PlanPhasePriceOverride)

Example 4 with EntitlementState

use of org.killbill.billing.entitlement.api.Entitlement.EntitlementState in project killbill by killbill.

the class DefaultSubscriptionBaseApiService method doCancelPlan.

private boolean doCancelPlan(final Map<DefaultSubscriptionBase, DateTime> subscriptions, final SubscriptionCatalog catalog, final InternalCallContext internalCallContext) throws SubscriptionBaseApiException {
    final List<DefaultSubscriptionBase> subscriptionsToBeCancelled = new LinkedList<DefaultSubscriptionBase>();
    final List<SubscriptionBaseEvent> cancelEvents = new LinkedList<SubscriptionBaseEvent>();
    try {
        for (final DefaultSubscriptionBase subscription : subscriptions.keySet()) {
            final EntitlementState currentState = subscription.getState();
            if (currentState == EntitlementState.CANCELLED) {
                throw new SubscriptionBaseApiException(ErrorCode.SUB_CANCEL_BAD_STATE, subscription.getId(), currentState);
            }
            final DateTime effectiveDate = subscriptions.get(subscription);
            // If subscription was future cancelled at an earlier date we disallow the operation -- i.e,
            // user should first uncancel prior trying to cancel again.
            // However, note that in case a future cancellation already exists with a greater or equal effectiveDate,
            // the operation is allowed, but such existing cancellation would become invalidated (is_active=0)
            final SubscriptionBaseTransition pendingTransition = subscription.getPendingTransition();
            if (pendingTransition != null && pendingTransition.getTransitionType() == SubscriptionBaseTransitionType.CANCEL && pendingTransition.getEffectiveTransitionTime().compareTo(effectiveDate) < 0) {
                throw new SubscriptionBaseApiException(ErrorCode.SUB_CANCEL_BAD_STATE, subscription.getId(), "PENDING CANCELLED");
            }
            validateEffectiveDate(subscription, effectiveDate);
            subscriptionsToBeCancelled.add(subscription);
            cancelEvents.addAll(getEventsOnCancelPlan(subscription, effectiveDate, false, catalog, internalCallContext));
            if (subscription.getCategory() == ProductCategory.BASE) {
                subscriptionsToBeCancelled.addAll(computeAddOnsToCancel(cancelEvents, null, subscription.getBundleId(), effectiveDate, catalog, internalCallContext));
            }
        }
        dao.cancelSubscriptions(subscriptionsToBeCancelled, cancelEvents, catalog, internalCallContext);
        boolean allSubscriptionsCancelled = true;
        for (final DefaultSubscriptionBase subscription : subscriptions.keySet()) {
            subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalog);
            allSubscriptionsCancelled = allSubscriptionsCancelled && (subscription.getState() == EntitlementState.CANCELLED);
        }
        return allSubscriptionsCancelled;
    } catch (final CatalogApiException e) {
        throw new SubscriptionBaseApiException(e);
    }
}
Also used : CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) LinkedList(java.util.LinkedList) EntitlementState(org.killbill.billing.entitlement.api.Entitlement.EntitlementState) DateTime(org.joda.time.DateTime)

Aggregations

EntitlementState (org.killbill.billing.entitlement.api.Entitlement.EntitlementState)4 DateTime (org.joda.time.DateTime)3 SubscriptionBaseEvent (org.killbill.billing.subscription.events.SubscriptionBaseEvent)3 UUID (java.util.UUID)2 Plan (org.killbill.billing.catalog.api.Plan)2 PlanPhase (org.killbill.billing.catalog.api.PlanPhase)2 PriceList (org.killbill.billing.catalog.api.PriceList)2 BCDEvent (org.killbill.billing.subscription.events.bcd.BCDEvent)2 PhaseEvent (org.killbill.billing.subscription.events.phase.PhaseEvent)2 ApiEvent (org.killbill.billing.subscription.events.user.ApiEvent)2 ApiEventType (org.killbill.billing.subscription.events.user.ApiEventType)2 SubscriptionBaseError (org.killbill.billing.subscription.exceptions.SubscriptionBaseError)2 LinkedList (java.util.LinkedList)1 InternalCallContext (org.killbill.billing.callcontext.InternalCallContext)1 CatalogApiException (org.killbill.billing.catalog.api.CatalogApiException)1 PlanPhasePriceOverride (org.killbill.billing.catalog.api.PlanPhasePriceOverride)1