Search in sources :

Example 1 with ExistingEvent

use of org.killbill.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent in project killbill by killbill.

the class DefaultSubscriptionBaseTransferApi method transferBundle.

@Override
public SubscriptionBaseBundle transferBundle(final UUID sourceAccountId, final UUID destAccountId, final String bundleKey, final DateTime transferDate, final boolean transferAddOn, final boolean cancelImmediately, final CallContext context) throws SubscriptionBaseTransferApiException {
    final InternalCallContext fromInternalCallContext = internalCallContextFactory.createInternalCallContext(sourceAccountId, context);
    final InternalCallContext toInternalCallContext = internalCallContextFactory.createInternalCallContext(destAccountId, context);
    try {
        final DateTime effectiveTransferDate = transferDate == null ? clock.getUTCNow() : transferDate;
        if (effectiveTransferDate.isAfter(clock.getUTCNow())) {
            // (subscription always expects the first event to be in the past)
            throw new SubscriptionBaseTransferApiException(ErrorCode.SUB_TRANSFER_INVALID_EFF_DATE, effectiveTransferDate);
        }
        final List<SubscriptionBaseBundle> bundlesForAccountAndKey = dao.getSubscriptionBundlesForAccountAndKey(sourceAccountId, bundleKey, fromInternalCallContext);
        final SubscriptionBaseBundle bundle = DefaultSubscriptionInternalApi.getActiveBundleForKeyNotException(bundlesForAccountAndKey, dao, clock, fromInternalCallContext);
        if (bundle == null) {
            throw new SubscriptionBaseTransferApiException(ErrorCode.SUB_CREATE_NO_BUNDLE, bundleKey);
        }
        // Get the bundle timeline for the old account
        final BundleBaseTimeline bundleBaseTimeline = timelineApi.getBundleTimeline(bundle, context);
        final DefaultSubscriptionBaseBundle subscriptionBundleData = new DefaultSubscriptionBaseBundle(bundleKey, destAccountId, effectiveTransferDate, bundle.getOriginalCreatedDate(), clock.getUTCNow(), clock.getUTCNow());
        final List<SubscriptionTransferData> subscriptionTransferDataList = new LinkedList<SubscriptionTransferData>();
        final List<TransferCancelData> transferCancelDataList = new LinkedList<TransferCancelData>();
        DateTime bundleStartdate = null;
        for (final SubscriptionBaseTimeline cur : bundleBaseTimeline.getSubscriptions()) {
            final DefaultSubscriptionBase oldSubscription = (DefaultSubscriptionBase) dao.getSubscriptionFromId(cur.getId(), fromInternalCallContext);
            // Skip already cancelled subscriptions
            if (oldSubscription.getState() == EntitlementState.CANCELLED) {
                continue;
            }
            final List<ExistingEvent> existingEvents = cur.getExistingEvents();
            final ProductCategory productCategory = existingEvents.get(0).getProductCategory();
            // on base plan cancellations, even though we don't support un-transfer today)
            if (productCategory != ProductCategory.ADD_ON || cancelImmediately) {
                // Create the cancelWithRequestedDate event on effectiveCancelDate
                final DateTime effectiveCancelDate = !cancelImmediately && oldSubscription.getChargedThroughDate() != null && effectiveTransferDate.isBefore(oldSubscription.getChargedThroughDate()) ? oldSubscription.getChargedThroughDate() : effectiveTransferDate;
                final SubscriptionBaseEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder().setSubscriptionId(cur.getId()).setEffectiveDate(effectiveCancelDate).setFromDisk(true));
                final TransferCancelData cancelData = new TransferCancelData(oldSubscription, cancelEvent);
                transferCancelDataList.add(cancelData);
            }
            if (productCategory == ProductCategory.ADD_ON && !transferAddOn) {
                continue;
            }
            // We Align with the original subscription
            final DateTime subscriptionAlignStartDate = oldSubscription.getAlignStartDate();
            if (bundleStartdate == null) {
                bundleStartdate = oldSubscription.getStartDate();
            }
            // Create the new subscription for the new bundle on the new account
            final DefaultSubscriptionBase defaultSubscriptionBase = createSubscriptionForApiUse(new SubscriptionBuilder().setId(UUIDs.randomUUID()).setBundleId(subscriptionBundleData.getId()).setBundleExternalKey(subscriptionBundleData.getExternalKey()).setCategory(productCategory).setBundleStartDate(effectiveTransferDate).setAlignStartDate(subscriptionAlignStartDate), ImmutableList.<SubscriptionBaseEvent>of(), fromInternalCallContext);
            final List<SubscriptionBaseEvent> events = toEvents(existingEvents, defaultSubscriptionBase, effectiveTransferDate, fromInternalCallContext);
            final SubscriptionTransferData curData = new SubscriptionTransferData(defaultSubscriptionBase, events, null);
            subscriptionTransferDataList.add(curData);
        }
        BundleTransferData bundleTransferData = new BundleTransferData(subscriptionBundleData, subscriptionTransferDataList);
        // Atomically cancelWithRequestedDate all subscription on old account and create new bundle, subscriptions, events for new account
        dao.transfer(sourceAccountId, destAccountId, bundleTransferData, transferCancelDataList, fromInternalCallContext, toInternalCallContext);
        return bundleTransferData.getData();
    } catch (SubscriptionBaseRepairException e) {
        throw new SubscriptionBaseTransferApiException(e);
    } catch (CatalogApiException e) {
        throw new SubscriptionBaseTransferApiException(e);
    }
}
Also used : InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) SubscriptionBaseTimeline(org.killbill.billing.subscription.api.timeline.SubscriptionBaseTimeline) DateTime(org.joda.time.DateTime) ApiEventBuilder(org.killbill.billing.subscription.events.user.ApiEventBuilder) SubscriptionBaseBundle(org.killbill.billing.subscription.api.user.SubscriptionBaseBundle) DefaultSubscriptionBaseBundle(org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) ExistingEvent(org.killbill.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent) BundleBaseTimeline(org.killbill.billing.subscription.api.timeline.BundleBaseTimeline) SubscriptionBaseRepairException(org.killbill.billing.subscription.api.timeline.SubscriptionBaseRepairException) DefaultSubscriptionBaseBundle(org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle) ApiEventCancel(org.killbill.billing.subscription.events.user.ApiEventCancel) SubscriptionBuilder(org.killbill.billing.subscription.api.user.SubscriptionBuilder) LinkedList(java.util.LinkedList) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) ProductCategory(org.killbill.billing.catalog.api.ProductCategory) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent)

Example 2 with ExistingEvent

use of org.killbill.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent in project killbill by killbill.

the class DefaultSubscriptionBaseTransferApi method toEvents.

@VisibleForTesting
List<SubscriptionBaseEvent> toEvents(final List<ExistingEvent> existingEvents, final DefaultSubscriptionBase subscription, final DateTime transferDate, final InternalTenantContext context) throws SubscriptionBaseTransferApiException {
    try {
        final List<SubscriptionBaseEvent> result = new LinkedList<SubscriptionBaseEvent>();
        SubscriptionBaseEvent event = null;
        ExistingEvent prevEvent = null;
        boolean firstEvent = true;
        for (ExistingEvent cur : existingEvents) {
            // Skip all events prior to the transferDate
            if (cur.getEffectiveDate().isBefore(transferDate)) {
                prevEvent = cur;
                continue;
            }
            // Add previous event the first time if needed
            if (prevEvent != null) {
                event = createEvent(firstEvent, prevEvent, subscription, transferDate, context);
                if (event != null) {
                    result.add(event);
                    firstEvent = false;
                }
                prevEvent = null;
            }
            event = createEvent(firstEvent, cur, subscription, transferDate, context);
            if (event != null) {
                result.add(event);
                firstEvent = false;
            }
        }
        // Previous loop did not get anything because transferDate is greater than effectiveDate of last event
        if (prevEvent != null) {
            event = createEvent(firstEvent, prevEvent, subscription, transferDate, context);
            if (event != null) {
                result.add(event);
            }
            prevEvent = null;
        }
        return result;
    } catch (CatalogApiException e) {
        throw new SubscriptionBaseTransferApiException(e);
    }
}
Also used : CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) ExistingEvent(org.killbill.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) LinkedList(java.util.LinkedList) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 3 with ExistingEvent

use of org.killbill.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent in project killbill by killbill.

the class TestDefaultSubscriptionTransferApi method testEventsForCancelledSubscriptionBeforeTransfer.

@Test(groups = "fast")
public void testEventsForCancelledSubscriptionBeforeTransfer() throws Exception {
    final DateTime subscriptionStartTime = clock.getUTCNow();
    final DateTime subscriptionCancelTime = subscriptionStartTime.plusDays(1);
    final ImmutableList<ExistingEvent> existingEvents = ImmutableList.<ExistingEvent>of(createEvent(subscriptionStartTime, SubscriptionBaseTransitionType.CREATE), createEvent(subscriptionCancelTime, SubscriptionBaseTransitionType.CANCEL));
    final SubscriptionBuilder subscriptionBuilder = new SubscriptionBuilder();
    final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(subscriptionBuilder);
    final DateTime transferDate = subscriptionStartTime.plusDays(10);
    final List<SubscriptionBaseEvent> events = transferApi.toEvents(existingEvents, subscription, transferDate, internalCallContext);
    Assert.assertEquals(events.size(), 0);
}
Also used : SubscriptionBuilder(org.killbill.billing.subscription.api.user.SubscriptionBuilder) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) ExistingEvent(org.killbill.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Example 4 with ExistingEvent

use of org.killbill.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent in project killbill by killbill.

the class TestDefaultSubscriptionTransferApi method testEventsForCancelledSubscriptionAfterTransfer.

@Test(groups = "fast")
public void testEventsForCancelledSubscriptionAfterTransfer() throws Exception {
    final DateTime subscriptionStartTime = clock.getUTCNow();
    final DateTime subscriptionCancelTime = subscriptionStartTime.plusDays(1);
    final ImmutableList<ExistingEvent> existingEvents = ImmutableList.<ExistingEvent>of(createEvent(subscriptionStartTime, SubscriptionBaseTransitionType.CREATE), createEvent(subscriptionCancelTime, SubscriptionBaseTransitionType.CANCEL));
    final SubscriptionBuilder subscriptionBuilder = new SubscriptionBuilder();
    final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(subscriptionBuilder);
    final DateTime transferDate = subscriptionStartTime.plusHours(1);
    final List<SubscriptionBaseEvent> events = transferApi.toEvents(existingEvents, subscription, transferDate, internalCallContext);
    Assert.assertEquals(events.size(), 1);
    Assert.assertEquals(events.get(0).getType(), EventType.API_USER);
    Assert.assertEquals(events.get(0).getEffectiveDate(), transferDate);
    Assert.assertEquals(((ApiEventTransfer) events.get(0)).getApiEventType(), ApiEventType.TRANSFER);
}
Also used : SubscriptionBuilder(org.killbill.billing.subscription.api.user.SubscriptionBuilder) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) ExistingEvent(org.killbill.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Aggregations

ExistingEvent (org.killbill.billing.subscription.api.timeline.SubscriptionBaseTimeline.ExistingEvent)4 SubscriptionBaseEvent (org.killbill.billing.subscription.events.SubscriptionBaseEvent)4 DateTime (org.joda.time.DateTime)3 DefaultSubscriptionBase (org.killbill.billing.subscription.api.user.DefaultSubscriptionBase)3 SubscriptionBuilder (org.killbill.billing.subscription.api.user.SubscriptionBuilder)3 LinkedList (java.util.LinkedList)2 CatalogApiException (org.killbill.billing.catalog.api.CatalogApiException)2 Test (org.testng.annotations.Test)2 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 InternalCallContext (org.killbill.billing.callcontext.InternalCallContext)1 ProductCategory (org.killbill.billing.catalog.api.ProductCategory)1 BundleBaseTimeline (org.killbill.billing.subscription.api.timeline.BundleBaseTimeline)1 SubscriptionBaseRepairException (org.killbill.billing.subscription.api.timeline.SubscriptionBaseRepairException)1 SubscriptionBaseTimeline (org.killbill.billing.subscription.api.timeline.SubscriptionBaseTimeline)1 DefaultSubscriptionBaseBundle (org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle)1 SubscriptionBaseBundle (org.killbill.billing.subscription.api.user.SubscriptionBaseBundle)1 ApiEventBuilder (org.killbill.billing.subscription.events.user.ApiEventBuilder)1 ApiEventCancel (org.killbill.billing.subscription.events.user.ApiEventCancel)1