Search in sources :

Example 1 with ApiEventChange

use of org.killbill.billing.subscription.events.user.ApiEventChange in project killbill by killbill.

the class DefaultSubscriptionDao method buildBundleSubscriptions.

private List<SubscriptionBase> buildBundleSubscriptions(final List<SubscriptionBase> input, @Nullable final Multimap<UUID, SubscriptionBaseEvent> eventsForSubscription, @Nullable final Collection<SubscriptionBaseEvent> dryRunEvents, final InternalTenantContext context) throws CatalogApiException {
    if (input == null || input.isEmpty()) {
        return Collections.emptyList();
    }
    // Make sure BasePlan -- if exists-- is first
    Collections.sort(input, DefaultSubscriptionInternalApi.SUBSCRIPTIONS_COMPARATOR);
    final Collection<ApiEventChange> baseChangeEvents = new LinkedList<ApiEventChange>();
    ApiEventCancel baseCancellationEvent = null;
    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);
        mergeDryRunEvents(cur.getId(), events, dryRunEvents);
        SubscriptionBase reloaded = createSubscriptionForInternalUse(cur, events, context);
        switch(cur.getCategory()) {
            case BASE:
                for (final SubscriptionBaseEvent event : events) {
                    if (!event.isActive()) {
                        continue;
                    } else if (event instanceof ApiEventCancel) {
                        baseCancellationEvent = (ApiEventCancel) event;
                        break;
                    } else if (event instanceof ApiEventChange) {
                        // Need to track all changes, see https://github.com/killbill/killbill/issues/268
                        baseChangeEvents.add((ApiEventChange) event);
                    }
                }
                break;
            case ADD_ON:
                final Plan targetAddOnPlan = reloaded.getCurrentPlan();
                if (targetAddOnPlan == null || reloaded.getFutureEndDate() != null) {
                    // triggers another cancellation before?
                    break;
                }
                SubscriptionBaseEvent baseTriggerEventForAddOnCancellation = baseCancellationEvent;
                for (final ApiEventChange baseChangeEvent : baseChangeEvents) {
                    final String baseProductName = baseChangeEvent.getEventPlan();
                    if ((!addonUtils.isAddonAvailableFromPlanName(baseProductName, targetAddOnPlan, baseChangeEvent.getEffectiveDate(), context)) || (addonUtils.isAddonIncludedFromPlanName(baseProductName, targetAddOnPlan, baseChangeEvent.getEffectiveDate(), context))) {
                        if (baseTriggerEventForAddOnCancellation != null) {
                            if (baseTriggerEventForAddOnCancellation.getEffectiveDate().isAfter(baseChangeEvent.getEffectiveDate())) {
                                baseTriggerEventForAddOnCancellation = baseChangeEvent;
                            }
                        } else {
                            baseTriggerEventForAddOnCancellation = baseChangeEvent;
                        }
                    }
                }
                if (baseTriggerEventForAddOnCancellation != null) {
                    final DateTime now = clock.getUTCNow();
                    final SubscriptionBaseEvent addOnCancelEvent = new ApiEventCancel(new ApiEventBuilder().setSubscriptionId(reloaded.getId()).setEffectiveDate(baseTriggerEventForAddOnCancellation.getEffectiveDate()).setCreatedDate(baseTriggerEventForAddOnCancellation.getCreatedDate()).setFromDisk(false));
                    events.add(addOnCancelEvent);
                    // Finally reload subscription with full set of events
                    reloaded = createSubscriptionForInternalUse(cur, events, context);
                }
                break;
            default:
                break;
        }
        result.add(reloaded);
    }
    return result;
}
Also used : ArrayList(java.util.ArrayList) ApiEventCancel(org.killbill.billing.subscription.events.user.ApiEventCancel) Plan(org.killbill.billing.catalog.api.Plan) LinkedList(java.util.LinkedList) DateTime(org.joda.time.DateTime) SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) ApiEventBuilder(org.killbill.billing.subscription.events.user.ApiEventBuilder) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) ApiEventChange(org.killbill.billing.subscription.events.user.ApiEventChange)

Example 2 with ApiEventChange

use of org.killbill.billing.subscription.events.user.ApiEventChange in project killbill by killbill.

the class DefaultSubscriptionBaseTransferApi method createEvent.

private SubscriptionBaseEvent createEvent(final boolean firstEvent, final ExistingEvent existingEvent, final DefaultSubscriptionBase subscription, final DateTime transferDate, final InternalTenantContext context) throws CatalogApiException {
    SubscriptionBaseEvent newEvent = null;
    final Catalog catalog = catalogService.getFullCatalog(true, true, context);
    final DateTime effectiveDate = existingEvent.getEffectiveDate().isBefore(transferDate) ? transferDate : existingEvent.getEffectiveDate();
    final PlanPhaseSpecifier spec = existingEvent.getPlanPhaseSpecifier();
    final PlanPhase currentPhase = existingEvent.getPlanPhaseName() != null ? catalog.findPhase(existingEvent.getPlanPhaseName(), effectiveDate, subscription.getAlignStartDate()) : null;
    if (spec == null || currentPhase == null) {
        // Ignore cancellations - we assume that transferred subscriptions should always be active
        return null;
    }
    final ApiEventBuilder apiBuilder = new ApiEventBuilder().setSubscriptionId(subscription.getId()).setEventPlan(existingEvent.getPlanName()).setEventPlanPhase(currentPhase.getName()).setEventPriceList(spec.getPriceListName()).setEffectiveDate(effectiveDate).setFromDisk(true);
    switch(existingEvent.getSubscriptionTransitionType()) {
        case TRANSFER:
        case CREATE:
            newEvent = new ApiEventTransfer(apiBuilder);
            break;
        // Should we even keep future change events; product question really
        case CHANGE:
            newEvent = firstEvent ? new ApiEventTransfer(apiBuilder) : new ApiEventChange(apiBuilder);
            break;
        case PHASE:
            newEvent = firstEvent ? new ApiEventTransfer(apiBuilder) : PhaseEventData.createNextPhaseEvent(subscription.getId(), currentPhase.getName(), effectiveDate);
            break;
        case CANCEL:
            break;
        default:
            throw new SubscriptionBaseError(String.format("Unexpected transitionType %s", existingEvent.getSubscriptionTransitionType()));
    }
    return newEvent;
}
Also used : PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) ApiEventBuilder(org.killbill.billing.subscription.events.user.ApiEventBuilder) SubscriptionBaseError(org.killbill.billing.subscription.exceptions.SubscriptionBaseError) PlanPhase(org.killbill.billing.catalog.api.PlanPhase) ApiEventTransfer(org.killbill.billing.subscription.events.user.ApiEventTransfer) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) Catalog(org.killbill.billing.catalog.api.Catalog) DateTime(org.joda.time.DateTime) ApiEventChange(org.killbill.billing.subscription.events.user.ApiEventChange)

Example 3 with ApiEventChange

use of org.killbill.billing.subscription.events.user.ApiEventChange in project killbill by killbill.

the class DefaultSubscriptionBaseApiService method getEventsOnChangePlan.

private List<SubscriptionBaseEvent> getEventsOnChangePlan(final DefaultSubscriptionBase subscription, final Plan newPlan, final String newPriceList, final DateTime effectiveDate, final boolean addCancellationAddOnForEventsIfRequired, final Collection<DefaultSubscriptionBase> addOnSubscriptionsToBeCancelled, final Collection<SubscriptionBaseEvent> addOnCancelEvents, final PhaseType initialPhaseType, final InternalTenantContext internalTenantContext) throws CatalogApiException, SubscriptionBaseApiException {
    final TimedPhase currentTimedPhase = planAligner.getCurrentTimedPhaseOnChange(subscription, newPlan, effectiveDate, initialPhaseType, internalTenantContext);
    final SubscriptionBaseEvent changeEvent = new ApiEventChange(new ApiEventBuilder().setSubscriptionId(subscription.getId()).setEventPlan(newPlan.getName()).setEventPlanPhase(currentTimedPhase.getPhase().getName()).setEventPriceList(newPriceList).setEffectiveDate(effectiveDate).setFromDisk(true));
    final TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(subscription, newPlan, effectiveDate, initialPhaseType, internalTenantContext);
    final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ? PhaseEventData.createNextPhaseEvent(subscription.getId(), nextTimedPhase.getPhase().getName(), nextTimedPhase.getStartPhase()) : null;
    final List<SubscriptionBaseEvent> changeEvents = new ArrayList<SubscriptionBaseEvent>();
    // Only add the PHASE if it does not coincide with the CHANGE, if not this is 'just' a CHANGE.
    changeEvents.add(changeEvent);
    if (nextPhaseEvent != null && !nextPhaseEvent.getEffectiveDate().equals(changeEvent.getEffectiveDate())) {
        changeEvents.add(nextPhaseEvent);
    }
    if (subscription.getCategory() == ProductCategory.BASE && addCancellationAddOnForEventsIfRequired) {
        final Product currentBaseProduct = changeEvent.getEffectiveDate().compareTo(clock.getUTCNow()) <= 0 ? newPlan.getProduct() : subscription.getCurrentPlan().getProduct();
        addOnSubscriptionsToBeCancelled.addAll(addCancellationAddOnForEventsIfRequired(addOnCancelEvents, currentBaseProduct, subscription.getBundleId(), effectiveDate, internalTenantContext));
    }
    return changeEvents;
}
Also used : PhaseEvent(org.killbill.billing.subscription.events.phase.PhaseEvent) ApiEventBuilder(org.killbill.billing.subscription.events.user.ApiEventBuilder) TimedPhase(org.killbill.billing.subscription.alignment.TimedPhase) ArrayList(java.util.ArrayList) Product(org.killbill.billing.catalog.api.Product) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) ApiEventChange(org.killbill.billing.subscription.events.user.ApiEventChange)

Aggregations

SubscriptionBaseEvent (org.killbill.billing.subscription.events.SubscriptionBaseEvent)3 ApiEventBuilder (org.killbill.billing.subscription.events.user.ApiEventBuilder)3 ApiEventChange (org.killbill.billing.subscription.events.user.ApiEventChange)3 ArrayList (java.util.ArrayList)2 DateTime (org.joda.time.DateTime)2 LinkedList (java.util.LinkedList)1 Catalog (org.killbill.billing.catalog.api.Catalog)1 Plan (org.killbill.billing.catalog.api.Plan)1 PlanPhase (org.killbill.billing.catalog.api.PlanPhase)1 PlanPhaseSpecifier (org.killbill.billing.catalog.api.PlanPhaseSpecifier)1 Product (org.killbill.billing.catalog.api.Product)1 TimedPhase (org.killbill.billing.subscription.alignment.TimedPhase)1 SubscriptionBase (org.killbill.billing.subscription.api.SubscriptionBase)1 DefaultSubscriptionBase (org.killbill.billing.subscription.api.user.DefaultSubscriptionBase)1 PhaseEvent (org.killbill.billing.subscription.events.phase.PhaseEvent)1 ApiEventCancel (org.killbill.billing.subscription.events.user.ApiEventCancel)1 ApiEventTransfer (org.killbill.billing.subscription.events.user.ApiEventTransfer)1 SubscriptionBaseError (org.killbill.billing.subscription.exceptions.SubscriptionBaseError)1