Search in sources :

Example 61 with SubscriptionBaseEvent

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

the class DefaultSubscriptionBaseApiService method uncancel.

@Override
public boolean uncancel(final DefaultSubscriptionBase subscription, final CallContext context) throws SubscriptionBaseApiException {
    if (!subscription.isFutureCancelled()) {
        throw new SubscriptionBaseApiException(ErrorCode.SUB_UNCANCEL_BAD_STATE, subscription.getId().toString());
    }
    try {
        final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
        final SubscriptionCatalog catalog = subscriptionCatalogApi.getFullCatalog(internalCallContext);
        final SubscriptionBaseEvent uncancelEvent = new ApiEventUncancel(new ApiEventBuilder().setSubscriptionId(subscription.getId()).setEffectiveDate(context.getCreatedDate()).setFromDisk(true));
        final List<SubscriptionBaseEvent> uncancelEvents = new ArrayList<SubscriptionBaseEvent>();
        uncancelEvents.add(uncancelEvent);
        // 
        // Used to compute effective for next phase (which was set unactive during cancellation).
        // In case of a pending subscription we don't want to pass an effective date prior the CREATE event as we would end up with the wrong
        // transition in PlanAligner (next transition would be CREATE instead of potential next PHASE)
        // 
        final DateTime planAlignerEffectiveDate = subscription.getState() == EntitlementState.PENDING ? subscription.getStartDate() : context.getCreatedDate();
        final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, planAlignerEffectiveDate, catalog, internalCallContext);
        final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ? PhaseEventData.createNextPhaseEvent(subscription.getId(), nextTimedPhase.getPhase().getName(), nextTimedPhase.getStartPhase()) : null;
        if (nextPhaseEvent != null) {
            uncancelEvents.add(nextPhaseEvent);
        }
        dao.uncancelSubscription(subscription, uncancelEvents, internalCallContext);
        subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalog);
        return true;
    } catch (final CatalogApiException e) {
        throw new SubscriptionBaseApiException(e);
    }
}
Also used : PhaseEvent(org.killbill.billing.subscription.events.phase.PhaseEvent) ApiEventBuilder(org.killbill.billing.subscription.events.user.ApiEventBuilder) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) ArrayList(java.util.ArrayList) TimedPhase(org.killbill.billing.subscription.alignment.TimedPhase) ApiEventUncancel(org.killbill.billing.subscription.events.user.ApiEventUncancel) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) SubscriptionCatalog(org.killbill.billing.subscription.catalog.SubscriptionCatalog) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) DateTime(org.joda.time.DateTime)

Example 62 with SubscriptionBaseEvent

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

the class DefaultSubscriptionBaseApiService method undoChangePlan.

@Override
public boolean undoChangePlan(final DefaultSubscriptionBase subscription, final CallContext context) throws SubscriptionBaseApiException {
    if (!subscription.isPendingChangePlan()) {
        throw new SubscriptionBaseApiException(ErrorCode.SUB_UNDO_CHANGE_BAD_STATE, subscription.getId().toString());
    }
    try {
        final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
        final SubscriptionCatalog catalog = subscriptionCatalogApi.getFullCatalog(internalCallContext);
        final SubscriptionBaseEvent undoChangePlanEvent = new ApiEventUndoChange(new ApiEventBuilder().setSubscriptionId(subscription.getId()).setEffectiveDate(context.getCreatedDate()).setFromDisk(true));
        final List<SubscriptionBaseEvent> undoChangePlanEvents = new ArrayList<SubscriptionBaseEvent>();
        undoChangePlanEvents.add(undoChangePlanEvent);
        // 
        // Used to compute effective for next phase (which was set unactive during cancellation).
        // In case of a pending subscription we don't want to pass an effective date prior the CREATE event as we would end up with the wrong
        // transition in PlanAligner (next transition would be CREATE instead of potential next PHASE)
        // 
        final DateTime planAlignerEffectiveDate = subscription.getState() == EntitlementState.PENDING ? subscription.getStartDate() : context.getCreatedDate();
        final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, planAlignerEffectiveDate, catalog, internalCallContext);
        final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ? PhaseEventData.createNextPhaseEvent(subscription.getId(), nextTimedPhase.getPhase().getName(), nextTimedPhase.getStartPhase()) : null;
        if (nextPhaseEvent != null) {
            undoChangePlanEvents.add(nextPhaseEvent);
        }
        dao.undoChangePlan(subscription, undoChangePlanEvents, internalCallContext);
        subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalog);
        return true;
    } catch (final CatalogApiException e) {
        throw new SubscriptionBaseApiException(e);
    }
}
Also used : ApiEventUndoChange(org.killbill.billing.subscription.events.user.ApiEventUndoChange) PhaseEvent(org.killbill.billing.subscription.events.phase.PhaseEvent) ApiEventBuilder(org.killbill.billing.subscription.events.user.ApiEventBuilder) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) ArrayList(java.util.ArrayList) TimedPhase(org.killbill.billing.subscription.alignment.TimedPhase) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) SubscriptionCatalog(org.killbill.billing.subscription.catalog.SubscriptionCatalog) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) DateTime(org.joda.time.DateTime)

Example 63 with SubscriptionBaseEvent

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

the class DefaultSubscriptionDao method cancelSubscriptionFromTransaction.

private void cancelSubscriptionFromTransaction(final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent cancelEvent, final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final SubscriptionCatalog catalog, final InternalCallContext context, final int seqId) throws EntityPersistenceException {
    final UUID subscriptionId = subscription.getId();
    cancelFutureEventsFromTransaction(subscriptionId, cancelEvent.getEffectiveDate(), entitySqlDaoWrapperFactory, true, context);
    final SubscriptionEventSqlDao subscriptionEventSqlDao = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class);
    final SubscriptionEventModelDao cancelEventWithUpdatedTotalOrdering = createAndRefresh(subscriptionEventSqlDao, new SubscriptionEventModelDao(cancelEvent), context);
    final SubscriptionBaseEvent refreshedSubscriptionEvent = SubscriptionEventModelDao.toSubscriptionEvent(cancelEventWithUpdatedTotalOrdering);
    final boolean isBusEvent = refreshedSubscriptionEvent.getEffectiveDate().compareTo(context.getCreatedDate()) <= 0;
    recordBusOrFutureNotificationFromTransaction(subscription, refreshedSubscriptionEvent, entitySqlDaoWrapperFactory, isBusEvent, seqId, catalog, context);
    // Notify the Bus of the requested change
    notifyBusOfRequestedChange(entitySqlDaoWrapperFactory, subscription, refreshedSubscriptionEvent, SubscriptionBaseTransitionType.CANCEL, 0, context);
}
Also used : UUID(java.util.UUID) SubscriptionEventModelDao(org.killbill.billing.subscription.engine.dao.model.SubscriptionEventModelDao) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent)

Example 64 with SubscriptionBaseEvent

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

the class DefaultSubscriptionDao method buildBundleSubscriptions.

private List<DefaultSubscriptionBase> buildBundleSubscriptions(final List<DefaultSubscriptionBase> input, @Nullable final Multimap<UUID, SubscriptionBaseEvent> eventsForSubscription, @Nullable final Collection<SubscriptionBaseEvent> dryRunEvents, final SubscriptionCatalog catalog, 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<DefaultSubscriptionBase> result = new ArrayList<DefaultSubscriptionBase>(input.size());
    for (final DefaultSubscriptionBase cur : input) {
        final List<SubscriptionBaseEvent> events = eventsForSubscription != null ? (List<SubscriptionBaseEvent>) eventsForSubscription.get(cur.getId()) : getEventsForSubscription(cur.getId(), context);
        mergeDryRunEvents(cur.getId(), events, dryRunEvents);
        DefaultSubscriptionBase reloaded = createSubscriptionForInternalUse(cur, events, catalog, 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 Plan basePlan = catalog.findPlan(baseChangeEvent.getEventPlan(), baseChangeEvent.getEffectiveDate(), cur.getAlignStartDate());
                    final Product baseProduct = basePlan.getProduct();
                    if ((!addonUtils.isAddonAvailable(baseProduct, targetAddOnPlan)) || (addonUtils.isAddonIncluded(baseProduct, targetAddOnPlan))) {
                        if (baseTriggerEventForAddOnCancellation != null) {
                            if (baseTriggerEventForAddOnCancellation.getEffectiveDate().isAfter(baseChangeEvent.getEffectiveDate())) {
                                baseTriggerEventForAddOnCancellation = baseChangeEvent;
                            }
                        } else {
                            baseTriggerEventForAddOnCancellation = baseChangeEvent;
                        }
                    }
                }
                if (baseTriggerEventForAddOnCancellation != null) {
                    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, catalog, context);
                }
                break;
            default:
                break;
        }
        result.add(reloaded);
    }
    return result;
}
Also used : ApiEventBuilder(org.killbill.billing.subscription.events.user.ApiEventBuilder) ArrayList(java.util.ArrayList) Product(org.killbill.billing.catalog.api.Product) ApiEventCancel(org.killbill.billing.subscription.events.user.ApiEventCancel) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) Plan(org.killbill.billing.catalog.api.Plan) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) ApiEventChange(org.killbill.billing.subscription.events.user.ApiEventChange) LinkedList(java.util.LinkedList)

Example 65 with SubscriptionBaseEvent

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

the class DefaultSubscriptionBaseService method initialize.

@LifecycleHandlerType(LifecycleLevel.INIT_SERVICE)
public void initialize() {
    try {
        final NotificationQueueHandler queueHandler = new NotificationQueueHandler() {

            @Override
            public void handleReadyNotification(final NotificationEvent inputKey, final DateTime eventDateTime, final UUID fromNotificationQueueUserToken, final Long accountRecordId, final Long tenantRecordId) {
                if (!(inputKey instanceof SubscriptionNotificationKey)) {
                    log.error("SubscriptionBase service received an unexpected event className='{}'", inputKey.getClass().getName());
                    return;
                }
                final SubscriptionNotificationKey key = (SubscriptionNotificationKey) inputKey;
                final SubscriptionBaseEvent event = dao.getEventById(key.getEventId(), internalCallContextFactory.createInternalTenantContext(tenantRecordId, accountRecordId));
                if (event == null) {
                    // This can be expected if the event is soft deleted (is_active = '0')
                    log.debug("Failed to extract event for notification key {}", inputKey);
                    return;
                }
                final InternalCallContext context = internalCallContextFactory.createInternalCallContext(tenantRecordId, accountRecordId, "SubscriptionEventQueue", CallOrigin.INTERNAL, UserType.SYSTEM, fromNotificationQueueUserToken);
                processEventReady(event, key.getSeqId(), context);
            }
        };
        subscriptionEventQueue = notificationQueueService.createNotificationQueue(KILLBILL_SERVICES.SUBSCRIPTION_BASE_SERVICE.getServiceName(), NOTIFICATION_QUEUE_NAME, queueHandler);
    } catch (final NotificationQueueAlreadyExists e) {
        throw new RuntimeException(e);
    }
}
Also used : NotificationEvent(org.killbill.notificationq.api.NotificationEvent) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) UUID(java.util.UUID) NotificationQueueAlreadyExists(org.killbill.notificationq.api.NotificationQueueService.NotificationQueueAlreadyExists) NotificationQueueHandler(org.killbill.notificationq.api.NotificationQueueService.NotificationQueueHandler) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) DateTime(org.joda.time.DateTime) LifecycleHandlerType(org.killbill.billing.platform.api.LifecycleHandlerType)

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