Search in sources :

Example 56 with SubscriptionBaseEvent

use of org.killbill.billing.subscription.events.SubscriptionBaseEvent in project killbill by killbill.

the class DefaultSubscriptionBaseApiService method getEventsOnCreation.

@Override
public List<SubscriptionBaseEvent> getEventsOnCreation(final UUID subscriptionId, final DateTime alignStartDate, final DateTime bundleStartDate, final Plan plan, final PhaseType initialPhase, final String realPriceList, final DateTime effectiveDate, final Integer bcd, final SubscriptionCatalog catalog, final InternalTenantContext internalTenantContext) throws CatalogApiException, SubscriptionBaseApiException {
    final TimedPhase[] curAndNextPhases = planAligner.getCurrentAndNextTimedPhaseOnCreate(alignStartDate, bundleStartDate, plan, initialPhase, realPriceList, effectiveDate, catalog, internalTenantContext);
    final ApiEventBuilder createBuilder = new ApiEventBuilder().setSubscriptionId(subscriptionId).setEventPlan(plan.getName()).setEventPlanPhase(curAndNextPhases[0].getPhase().getName()).setEventPriceList(realPriceList).setEffectiveDate(effectiveDate).setFromDisk(true);
    final SubscriptionBaseEvent creationEvent = new ApiEventCreate(createBuilder);
    final TimedPhase nextTimedPhase = curAndNextPhases[1];
    final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ? PhaseEventData.createNextPhaseEvent(subscriptionId, nextTimedPhase.getPhase().getName(), nextTimedPhase.getStartPhase()) : null;
    final List<SubscriptionBaseEvent> events = new ArrayList<SubscriptionBaseEvent>();
    events.add(creationEvent);
    if (bcd != null) {
        final SubscriptionBaseEvent bcdEvent = new BCDEventData(new BCDEventBuilder().setSubscriptionId(subscriptionId).setEffectiveDate(effectiveDate).setActive(true).setBillCycleDayLocal(bcd));
        events.add(bcdEvent);
    }
    if (nextPhaseEvent != null) {
        events.add(nextPhaseEvent);
    }
    return events;
}
Also used : ApiEventCreate(org.killbill.billing.subscription.events.user.ApiEventCreate) BCDEventData(org.killbill.billing.subscription.events.bcd.BCDEventData) 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) BCDEventBuilder(org.killbill.billing.subscription.events.bcd.BCDEventBuilder) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent)

Example 57 with SubscriptionBaseEvent

use of org.killbill.billing.subscription.events.SubscriptionBaseEvent in project killbill by killbill.

the class DefaultSubscriptionBaseApiService method doChangePlan.

private void doChangePlan(final DefaultSubscriptionBase subscription, final EntitlementSpecifier spec, final DateTime effectiveDate, final CallContext context) throws SubscriptionBaseApiException, CatalogApiException {
    final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
    final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(spec.getOverrides(), context);
    final SubscriptionCatalog catalog = subscriptionCatalogApi.getFullCatalog(internalCallContext);
    final PlanPhaseSpecifier planPhaseSpecifier = spec.getPlanPhaseSpecifier();
    final StaticCatalog versionCatalog = catalog.versionForDate(effectiveDate);
    final Plan newPlan = versionCatalog.createOrFindPlan(planPhaseSpecifier, overridesWithContext);
    final PhaseType initialPhaseType = planPhaseSpecifier.getPhaseType();
    if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(newPlan.getProduct().getCategory().toString())) {
        if (newPlan.getPlansAllowedInBundle() != -1 && newPlan.getPlansAllowedInBundle() > 0 && addonUtils.countExistingAddOnsWithSamePlanName(dao.getSubscriptions(subscription.getBundleId(), null, catalog, internalCallContext), newPlan.getName()) >= newPlan.getPlansAllowedInBundle()) {
            // the plan can be changed to the new value, because it has reached its limit by bundle
            throw new SubscriptionBaseApiException(ErrorCode.SUB_CHANGE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE, newPlan.getName());
        }
    }
    if (newPlan.getProduct().getCategory() != subscription.getCategory()) {
        throw new SubscriptionBaseApiException(ErrorCode.SUB_CHANGE_INVALID, subscription.getId());
    }
    final List<DefaultSubscriptionBase> addOnSubscriptionsToBeCancelled = new ArrayList<DefaultSubscriptionBase>();
    final List<SubscriptionBaseEvent> addOnCancelEvents = new ArrayList<SubscriptionBaseEvent>();
    final List<SubscriptionBaseEvent> changeEvents = getEventsOnChangePlan(subscription, newPlan, newPlan.getPriceList().getName(), effectiveDate, true, addOnSubscriptionsToBeCancelled, addOnCancelEvents, initialPhaseType, spec.getBillCycleDay(), catalog, internalCallContext);
    dao.changePlan(subscription, changeEvents, addOnSubscriptionsToBeCancelled, addOnCancelEvents, catalog, internalCallContext);
    subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalog);
}
Also used : PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) ArrayList(java.util.ArrayList) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) Plan(org.killbill.billing.catalog.api.Plan) SubscriptionCatalog(org.killbill.billing.subscription.catalog.SubscriptionCatalog) StaticCatalog(org.killbill.billing.catalog.api.StaticCatalog) DefaultPlanPhasePriceOverridesWithCallContext(org.killbill.billing.subscription.api.svcs.DefaultPlanPhasePriceOverridesWithCallContext) PlanPhasePriceOverridesWithCallContext(org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext) DefaultPlanPhasePriceOverridesWithCallContext(org.killbill.billing.subscription.api.svcs.DefaultPlanPhasePriceOverridesWithCallContext) PhaseType(org.killbill.billing.catalog.api.PhaseType) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent)

Example 58 with SubscriptionBaseEvent

use of org.killbill.billing.subscription.events.SubscriptionBaseEvent in project killbill by killbill.

the class DefaultSubscriptionBaseTimeline method toExistingEvents.

private List<ExistingEvent> toExistingEvents(final SubscriptionCatalog catalog, final ProductCategory category, final List<SubscriptionBaseEvent> events) throws CatalogApiException {
    final List<ExistingEvent> result = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
    Plan prevPlan = null;
    String prevProductName = null;
    String prevPriceListName = null;
    PhaseType prevPhaseType = null;
    DateTime startDate = null;
    for (final SubscriptionBaseEvent cur : events) {
        if (!cur.isActive()) {
            continue;
        }
        startDate = (startDate == null) ? cur.getEffectiveDate() : startDate;
        String productName = null;
        String priceListName = null;
        PhaseType phaseType = null;
        Plan plan = null;
        String planPhaseName = null;
        Integer billCycleDayLocal = null;
        ApiEventType apiType = null;
        switch(cur.getType()) {
            case PHASE:
                final PhaseEvent phaseEV = (PhaseEvent) cur;
                planPhaseName = phaseEV.getPhase();
                // A PHASE event always occurs within the same plan (and is never the first event)
                phaseType = prevPlan != null ? prevPlan.findPhase(phaseEV.getPhase()).getPhaseType() : null;
                plan = prevPlan;
                productName = prevProductName;
                priceListName = prevPriceListName;
                break;
            case BCD_UPDATE:
                final BCDEvent bcdEvent = (BCDEvent) cur;
                billCycleDayLocal = bcdEvent.getBillCycleDayLocal();
                break;
            case API_USER:
                final ApiEvent userEV = (ApiEvent) cur;
                apiType = userEV.getApiEventType();
                planPhaseName = userEV.getEventPlanPhase();
                plan = (userEV.getEventPlan() != null) ? catalog.findPlan(userEV.getEventPlan(), cur.getEffectiveDate(), startDate) : null;
                phaseType = (plan != null && userEV.getEventPlanPhase() != null) ? plan.findPhase(userEV.getEventPlanPhase()).getPhaseType() : prevPhaseType;
                productName = (plan != null) ? plan.getProduct().getName() : prevProductName;
                priceListName = (userEV.getPriceList() != null) ? userEV.getPriceList() : prevPriceListName;
                break;
        }
        final SubscriptionBaseTransitionType transitionType = SubscriptionBaseTransitionData.toSubscriptionTransitionType(cur.getType(), apiType);
        final String planNameWithClosure = plan != null ? plan.getName() : null;
        final String planPhaseNameWithClosure = planPhaseName;
        final Integer billCycleDayLocalWithClosure = billCycleDayLocal;
        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(planNameWithClosure, phaseType);
        result.add(new ExistingEvent() {

            @Override
            public SubscriptionBaseTransitionType getSubscriptionTransitionType() {
                return transitionType;
            }

            @Override
            public ProductCategory getProductCategory() {
                return category;
            }

            @Override
            public PlanPhaseSpecifier getPlanPhaseSpecifier() {
                return spec;
            }

            @Override
            public UUID getEventId() {
                return cur.getId();
            }

            @Override
            public DateTime getEffectiveDate() {
                return cur.getEffectiveDate();
            }

            @Override
            public String getPlanName() {
                return planNameWithClosure;
            }

            @Override
            public String getPlanPhaseName() {
                return planPhaseNameWithClosure;
            }

            @Override
            public Integer getBillCycleDayLocal() {
                return billCycleDayLocalWithClosure;
            }
        });
        prevPlan = plan;
        prevProductName = productName;
        prevPriceListName = priceListName;
        prevPhaseType = phaseType;
    }
    sortExistingEvent(result);
    return result;
}
Also used : ApiEventType(org.killbill.billing.subscription.events.user.ApiEventType) PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) PhaseEvent(org.killbill.billing.subscription.events.phase.PhaseEvent) SubscriptionBaseTransitionType(org.killbill.billing.subscription.api.SubscriptionBaseTransitionType) BCDEvent(org.killbill.billing.subscription.events.bcd.BCDEvent) Plan(org.killbill.billing.catalog.api.Plan) LinkedList(java.util.LinkedList) DateTime(org.joda.time.DateTime) ApiEvent(org.killbill.billing.subscription.events.user.ApiEvent) PhaseType(org.killbill.billing.catalog.api.PhaseType) ProductCategory(org.killbill.billing.catalog.api.ProductCategory) UUID(java.util.UUID) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent)

Example 59 with SubscriptionBaseEvent

use of org.killbill.billing.subscription.events.SubscriptionBaseEvent in project killbill by killbill.

the class DefaultSubscriptionBase method removeEverythingPastCancelEvent.

// Skip any event after a CANCEL event:
// 
// * DefaultSubscriptionDao#buildBundleSubscriptions may have added an out-of-order cancellation event (https://github.com/killbill/killbill/issues/897)
// * Hardening against data integrity issues where we have multiple active CANCEL (https://github.com/killbill/killbill/issues/619)
// 
private void removeEverythingPastCancelEvent(final List<SubscriptionBaseEvent> inputEvents) {
    final SubscriptionBaseEvent cancellationEvent = Iterables.tryFind(inputEvents, new Predicate<SubscriptionBaseEvent>() {

        @Override
        public boolean apply(final SubscriptionBaseEvent input) {
            return input.getType() == EventType.API_USER && ((ApiEvent) input).getApiEventType() == ApiEventType.CANCEL;
        }
    }).orNull();
    if (cancellationEvent == null) {
        return;
    }
    final Iterator<SubscriptionBaseEvent> it = inputEvents.iterator();
    while (it.hasNext()) {
        final SubscriptionBaseEvent input = it.next();
        if (!input.isActive()) {
            continue;
        }
        if (input.getId().compareTo(cancellationEvent.getId()) == 0) {
        // Keep the cancellation event
        } else if (input.getType() == EventType.API_USER && (((ApiEvent) input).getApiEventType() == ApiEventType.TRANSFER || ((ApiEvent) input).getApiEventType() == ApiEventType.CREATE)) {
        // Keep the initial event (SOT use-case)
        } else if (input.getEffectiveDate().compareTo(cancellationEvent.getEffectiveDate()) >= 0) {
            // Event to ignore past cancellation date
            it.remove();
        }
    }
}
Also used : ApiEvent(org.killbill.billing.subscription.events.user.ApiEvent) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) Predicate(com.google.common.base.Predicate)

Example 60 with SubscriptionBaseEvent

use of org.killbill.billing.subscription.events.SubscriptionBaseEvent in project killbill by killbill.

the class DefaultSubscriptionBaseApiService method addCancellationAddOnForEventsIfRequired.

private List<DefaultSubscriptionBase> addCancellationAddOnForEventsIfRequired(final Collection<SubscriptionBaseEvent> events, final Product baseProduct, final UUID bundleId, final DateTime effectiveDate, final SubscriptionCatalog catalog, final InternalTenantContext internalTenantContext) throws CatalogApiException {
    final List<DefaultSubscriptionBase> subscriptionsToBeCancelled = new ArrayList<DefaultSubscriptionBase>();
    final List<DefaultSubscriptionBase> subscriptions = dao.getSubscriptions(bundleId, ImmutableList.<SubscriptionBaseEvent>of(), catalog, internalTenantContext);
    for (final SubscriptionBase subscription : subscriptions) {
        final DefaultSubscriptionBase cur = (DefaultSubscriptionBase) subscription;
        if (cur.getState() == EntitlementState.CANCELLED || cur.getCategory() != ProductCategory.ADD_ON) {
            continue;
        }
        final Plan addonCurrentPlan = cur.getCurrentPlan();
        if (baseProduct == null || addonUtils.isAddonIncluded(baseProduct, addonCurrentPlan) || !addonUtils.isAddonAvailable(baseProduct, addonCurrentPlan)) {
            // 
            // Perform AO cancellation using the effectiveDate of the BP
            // 
            final SubscriptionBaseEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder().setSubscriptionId(cur.getId()).setEffectiveDate(effectiveDate).setFromDisk(true));
            subscriptionsToBeCancelled.add(cur);
            events.add(cancelEvent);
        }
    }
    return subscriptionsToBeCancelled;
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) ApiEventBuilder(org.killbill.billing.subscription.events.user.ApiEventBuilder) ArrayList(java.util.ArrayList) ApiEventCancel(org.killbill.billing.subscription.events.user.ApiEventCancel) Plan(org.killbill.billing.catalog.api.Plan) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent)

Aggregations

SubscriptionBaseEvent (org.killbill.billing.subscription.events.SubscriptionBaseEvent)75 DateTime (org.joda.time.DateTime)31 ApiEventBuilder (org.killbill.billing.subscription.events.user.ApiEventBuilder)26 LinkedList (java.util.LinkedList)25 ArrayList (java.util.ArrayList)23 UUID (java.util.UUID)22 DefaultSubscriptionBase (org.killbill.billing.subscription.api.user.DefaultSubscriptionBase)21 InternalCallContext (org.killbill.billing.callcontext.InternalCallContext)16 CatalogApiException (org.killbill.billing.catalog.api.CatalogApiException)14 Test (org.testng.annotations.Test)14 Plan (org.killbill.billing.catalog.api.Plan)13 PhaseEvent (org.killbill.billing.subscription.events.phase.PhaseEvent)13 ApiEvent (org.killbill.billing.subscription.events.user.ApiEvent)13 ApiEventCancel (org.killbill.billing.subscription.events.user.ApiEventCancel)12 ApiEventCreate (org.killbill.billing.subscription.events.user.ApiEventCreate)11 SubscriptionBase (org.killbill.billing.subscription.api.SubscriptionBase)10 SubscriptionBuilder (org.killbill.billing.subscription.api.user.SubscriptionBuilder)9 SubscriptionNotificationKey (org.killbill.billing.subscription.engine.core.SubscriptionNotificationKey)8 ApiEventChange (org.killbill.billing.subscription.events.user.ApiEventChange)8 ImmutableList (com.google.common.collect.ImmutableList)7