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);
}
}
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);
}
}
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);
}
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);
}
Aggregations