Search in sources :

Example 1 with SubscriptionBaseEvent

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

the class DefaultSubscriptionDao method getSubscriptionsForAccount.

@Override
public Map<UUID, List<SubscriptionBase>> getSubscriptionsForAccount(final InternalTenantContext context) throws CatalogApiException {
    final Map<UUID, List<SubscriptionBase>> subscriptionsFromAccountId = getSubscriptionsFromAccountId(context);
    final List<SubscriptionBaseEvent> eventsForAccount = getEventsForAccountId(context);
    final Map<UUID, List<SubscriptionBase>> result = new HashMap<UUID, List<SubscriptionBase>>();
    for (final UUID bundleId : subscriptionsFromAccountId.keySet()) {
        final List<SubscriptionBase> subscriptionsForBundle = subscriptionsFromAccountId.get(bundleId);
        final Multimap<UUID, SubscriptionBaseEvent> eventsForSubscriptions = ArrayListMultimap.create();
        for (final SubscriptionBase cur : subscriptionsForBundle) {
            final Collection<SubscriptionBaseEvent> events = Collections2.filter(eventsForAccount, new Predicate<SubscriptionBaseEvent>() {

                @Override
                public boolean apply(final SubscriptionBaseEvent input) {
                    return input.getSubscriptionId().equals(cur.getId());
                }
            });
            eventsForSubscriptions.putAll(cur.getId(), ImmutableList.copyOf(events));
        }
        result.put(bundleId, buildBundleSubscriptions(subscriptionsForBundle, eventsForSubscriptions, null, context));
    }
    return result;
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) HashMap(java.util.HashMap) List(java.util.List) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) LinkedList(java.util.LinkedList) UUID(java.util.UUID) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent)

Example 2 with SubscriptionBaseEvent

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

the class DefaultSubscriptionDao method uncancelSubscription.

@Override
public void uncancelSubscription(final DefaultSubscriptionBase subscription, final List<SubscriptionBaseEvent> uncancelEvents, final InternalCallContext context) {
    final InternalCallContext contextWithUpdatedDate = contextWithUpdatedDate(context);
    transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {

        @Override
        public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
            final SubscriptionEventSqlDao transactional = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class);
            final UUID subscriptionId = subscription.getId();
            SubscriptionEventModelDao cancelledEvent = null;
            final Date now = clock.getUTCNow().toDate();
            final List<SubscriptionEventModelDao> eventModels = transactional.getFutureActiveEventForSubscription(subscriptionId.toString(), now, contextWithUpdatedDate);
            for (final SubscriptionEventModelDao cur : eventModels) {
                if (cur.getUserType() == ApiEventType.CANCEL) {
                    if (cancelledEvent != null) {
                        throw new SubscriptionBaseError(String.format("Found multiple cancelWithRequestedDate active events for subscriptions %s", subscriptionId.toString()));
                    }
                    cancelledEvent = cur;
                }
            }
            if (cancelledEvent != null) {
                final String cancelledEventId = cancelledEvent.getId().toString();
                transactional.unactiveEvent(cancelledEventId, contextWithUpdatedDate);
                for (final SubscriptionBaseEvent cur : uncancelEvents) {
                    transactional.create(new SubscriptionEventModelDao(cur), contextWithUpdatedDate);
                    recordFutureNotificationFromTransaction(entitySqlDaoWrapperFactory, cur.getEffectiveDate(), new SubscriptionNotificationKey(cur.getId()), contextWithUpdatedDate);
                }
                // Notify the Bus of the latest requested change
                notifyBusOfRequestedChange(entitySqlDaoWrapperFactory, subscription, uncancelEvents.get(uncancelEvents.size() - 1), SubscriptionBaseTransitionType.UNCANCEL, contextWithUpdatedDate);
            }
            return null;
        }
    });
}
Also used : InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) SubscriptionEventModelDao(org.killbill.billing.subscription.engine.dao.model.SubscriptionEventModelDao) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) SubscriptionApiException(org.killbill.billing.entitlement.api.SubscriptionApiException) IOException(java.io.IOException) EventBusException(org.killbill.bus.api.PersistentBus.EventBusException) EntityPersistenceException(org.killbill.billing.entity.EntityPersistenceException) Date(java.util.Date) SubscriptionNotificationKey(org.killbill.billing.subscription.engine.core.SubscriptionNotificationKey) SubscriptionBaseError(org.killbill.billing.subscription.exceptions.SubscriptionBaseError) EntitySqlDaoWrapperFactory(org.killbill.billing.util.entity.dao.EntitySqlDaoWrapperFactory) List(java.util.List) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) LinkedList(java.util.LinkedList) UUID(java.util.UUID) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent)

Example 3 with SubscriptionBaseEvent

use of org.killbill.billing.subscription.events.SubscriptionBaseEvent 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 4 with SubscriptionBaseEvent

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

the class DefaultSubscriptionDao method createSubscriptionWithNewEvent.

//
// Creates a copy of the existing subscriptions whose 'transitions' will reflect the new event
//
private DefaultSubscriptionBase createSubscriptionWithNewEvent(final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent newEvent, final InternalTenantContext context) throws CatalogApiException {
    final DefaultSubscriptionBase subscriptionWithNewEvent = new DefaultSubscriptionBase(subscription, null, clock);
    final List<SubscriptionBaseEvent> allEvents = new LinkedList<SubscriptionBaseEvent>();
    if (subscriptionWithNewEvent.getEvents() != null) {
        allEvents.addAll(subscriptionWithNewEvent.getEvents());
    }
    allEvents.add(newEvent);
    subscriptionWithNewEvent.rebuildTransitions(allEvents, catalogService.getFullCatalog(true, true, context));
    return subscriptionWithNewEvent;
}
Also used : DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) LinkedList(java.util.LinkedList)

Example 5 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 Catalog catalog, final ProductCategory category, final List<SubscriptionBaseEvent> events) throws CatalogApiException {
    final List<ExistingEvent> result = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
    String prevPlanName = null;
    String prevProductName = null;
    BillingPeriod prevBillingPeriod = 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;
        BillingPeriod billingPeriod = null;
        String priceListName = null;
        PhaseType phaseType = null;
        String planName = null;
        String planPhaseName = null;
        Integer billCycleDayLocal = null;
        ApiEventType apiType = null;
        switch(cur.getType()) {
            case PHASE:
                final PhaseEvent phaseEV = (PhaseEvent) cur;
                planPhaseName = phaseEV.getPhase();
                phaseType = catalog.findPhase(phaseEV.getPhase(), cur.getEffectiveDate(), startDate).getPhaseType();
                // A PHASE event always occurs within the same plan (and is never the first event)
                planName = prevPlanName;
                productName = prevProductName;
                billingPeriod = getBillingPeriod(catalog, phaseEV.getPhase(), cur.getEffectiveDate(), startDate);
                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();
                planName = userEV.getEventPlan();
                planPhaseName = userEV.getEventPlanPhase();
                final Plan plan = (userEV.getEventPlan() != null) ? catalog.findPlan(userEV.getEventPlan(), cur.getEffectiveDate(), startDate) : null;
                phaseType = (userEV.getEventPlanPhase() != null) ? catalog.findPhase(userEV.getEventPlanPhase(), cur.getEffectiveDate(), startDate).getPhaseType() : prevPhaseType;
                productName = (plan != null) ? plan.getProduct().getName() : prevProductName;
                billingPeriod = (userEV.getEventPlanPhase() != null) ? getBillingPeriod(catalog, userEV.getEventPlanPhase(), cur.getEffectiveDate(), startDate) : prevBillingPeriod;
                priceListName = (userEV.getPriceList() != null) ? userEV.getPriceList() : prevPriceListName;
                break;
        }
        final SubscriptionBaseTransitionType transitionType = SubscriptionBaseTransitionData.toSubscriptionTransitionType(cur.getType(), apiType);
        final String planNameWithClosure = planName;
        final String planPhaseNameWithClosure = planPhaseName;
        final Integer billCycleDayLocalWithClosure = billCycleDayLocal;
        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(planName, 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;
            }
        });
        prevPlanName = planName;
        prevProductName = productName;
        prevBillingPeriod = billingPeriod;
        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) BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) 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)

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