use of org.killbill.billing.subscription.events.user.ApiEventBuilder 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;
}
use of org.killbill.billing.subscription.events.user.ApiEventBuilder 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 SubscriptionCatalog catalog = subscriptionCatalogApi.getFullCatalog(fromInternalCallContext);
final DateTime effectiveTransferDate = transferDate == null ? context.getCreatedDate() : transferDate;
if (effectiveTransferDate.isAfter(context.getCreatedDate())) {
// (subscription always expects the first event to be in the past)
throw new SubscriptionBaseTransferApiException(ErrorCode.SUB_TRANSFER_INVALID_EFF_DATE, effectiveTransferDate);
}
final SubscriptionBaseBundle bundle = subscriptionBaseInternalApi.getActiveBundleForKey(catalog.getCatalog(), bundleKey, 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(), context.getCreatedDate(), context.getCreatedDate());
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(), catalog, 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(), catalog, fromInternalCallContext);
final List<SubscriptionBaseEvent> events = toEvents(existingEvents, defaultSubscriptionBase, effectiveTransferDate, fromInternalCallContext);
final SubscriptionTransferData curData = new SubscriptionTransferData(defaultSubscriptionBase, events, null);
subscriptionTransferDataList.add(curData);
}
final 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, catalog, 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.events.user.ApiEventBuilder in project killbill by killbill.
the class TestSubscriptionDao method createSubscription.
private List<SubscriptionBaseEvent> createSubscription(final SubscriptionBaseBundle bundle, final String externalKey, final DateTime startDate, final DateTime cancelDate) {
final SubscriptionBuilder builder = new SubscriptionBuilder().setId(UUIDs.randomUUID()).setBundleId(bundle.getId()).setBundleExternalKey(bundle.getExternalKey()).setCategory(ProductCategory.BASE).setBundleStartDate(startDate).setAlignStartDate(startDate).setExternalKey(externalKey).setMigrated(false);
final ApiEventBuilder createBuilder = new ApiEventBuilder().setSubscriptionId(builder.getId()).setEventPlan("shotgun-monthly").setEventPlanPhase("shotgun-monthly-trial").setEventPriceList(DefaultPriceListSet.DEFAULT_PRICELIST_NAME).setEffectiveDate(startDate).setFromDisk(true);
final SubscriptionBaseEvent creationEvent = new ApiEventCreate(createBuilder);
final ApiEventBuilder cancelBuilder = cancelDate != null ? new ApiEventBuilder().setSubscriptionId(builder.getId()).setEffectiveDate(cancelDate).setFromDisk(true) : null;
final SubscriptionBaseEvent cancelEvent = cancelBuilder != null ? new ApiEventCancel(cancelBuilder) : null;
final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(builder);
final SubscriptionBaseWithAddOns subscriptionBaseWithAddOns = new DefaultSubscriptionBaseWithAddOns(bundle, ImmutableList.<SubscriptionBase>of(subscription));
testListener.pushExpectedEvents(NextEvent.CREATE);
final ImmutableList<SubscriptionBaseEvent> events = cancelEvent != null ? ImmutableList.<SubscriptionBaseEvent>of(creationEvent, cancelEvent) : ImmutableList.<SubscriptionBaseEvent>of(creationEvent);
final List<SubscriptionBaseEvent> result = dao.createSubscriptionsWithAddOns(ImmutableList.<SubscriptionBaseWithAddOns>of(subscriptionBaseWithAddOns), ImmutableMap.<UUID, List<SubscriptionBaseEvent>>of(subscription.getId(), events), catalog, internalCallContext);
assertListenerStatus();
return result;
}
use of org.killbill.billing.subscription.events.user.ApiEventBuilder in project killbill by killbill.
the class TestSubscriptionDao method testWithAuditAndHistory.
@Test(groups = "slow")
public void testWithAuditAndHistory() throws SubscriptionBaseApiException {
final String bundleExternalKey = "54341455sttfs1";
final DateTime startDate = clock.getUTCNow();
final DefaultSubscriptionBaseBundle bundleDef = new DefaultSubscriptionBaseBundle(bundleExternalKey, accountId, startDate, startDate, startDate, startDate);
final SubscriptionBaseBundle bundle = dao.createSubscriptionBundle(bundleDef, catalog, true, internalCallContext);
final List<AuditLogWithHistory> bundleHistory1 = dao.getSubscriptionBundleAuditLogsWithHistoryForId(bundle.getId(), AuditLevel.FULL, internalCallContext);
assertEquals(bundleHistory1.size(), 1);
final AuditLogWithHistory bundleHistoryRow1 = bundleHistory1.get(0);
assertEquals(bundleHistoryRow1.getChangeType(), ChangeType.INSERT);
final SubscriptionBundleModelDao historyRow1 = (SubscriptionBundleModelDao) bundleHistoryRow1.getEntity();
assertEquals(historyRow1.getExternalKey(), bundle.getExternalKey());
assertEquals(historyRow1.getAccountId(), bundle.getAccountId());
dao.updateBundleExternalKey(bundle.getId(), "you changed me!", internalCallContext);
final List<AuditLogWithHistory> bundleHistory2 = dao.getSubscriptionBundleAuditLogsWithHistoryForId(bundle.getId(), AuditLevel.FULL, internalCallContext);
assertEquals(bundleHistory2.size(), 2);
final AuditLogWithHistory bundleHistoryRow2 = bundleHistory2.get(1);
assertEquals(bundleHistoryRow2.getChangeType(), ChangeType.UPDATE);
final SubscriptionBundleModelDao historyRow2 = (SubscriptionBundleModelDao) bundleHistoryRow2.getEntity();
assertEquals(historyRow2.getExternalKey(), "you changed me!");
assertEquals(historyRow2.getAccountId(), bundle.getAccountId());
final SubscriptionBuilder builder = new SubscriptionBuilder().setId(UUIDs.randomUUID()).setBundleId(bundle.getId()).setBundleExternalKey(bundle.getExternalKey()).setCategory(ProductCategory.BASE).setBundleStartDate(startDate).setAlignStartDate(startDate).setMigrated(false);
final ApiEventBuilder createBuilder = new ApiEventBuilder().setSubscriptionId(builder.getId()).setEventPlan("shotgun-monthly").setEventPlanPhase("shotgun-monthly-trial").setEventPriceList(DefaultPriceListSet.DEFAULT_PRICELIST_NAME).setEffectiveDate(startDate).setFromDisk(true);
final SubscriptionBaseEvent creationEvent = new ApiEventCreate(createBuilder);
final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(builder);
testListener.pushExpectedEvents(NextEvent.CREATE);
final SubscriptionBaseWithAddOns subscriptionBaseWithAddOns = new DefaultSubscriptionBaseWithAddOns(bundle, ImmutableList.<SubscriptionBase>of(subscription));
final List<SubscriptionBaseEvent> resultSubscriptions = dao.createSubscriptionsWithAddOns(ImmutableList.<SubscriptionBaseWithAddOns>of(subscriptionBaseWithAddOns), ImmutableMap.<UUID, List<SubscriptionBaseEvent>>of(subscription.getId(), ImmutableList.<SubscriptionBaseEvent>of(creationEvent)), catalog, internalCallContext);
assertListenerStatus();
assertEquals(resultSubscriptions.size(), 1);
final SubscriptionBaseEvent subscriptionBaseEvent = resultSubscriptions.get(0);
final List<AuditLogWithHistory> subscriptionHistory = dao.getSubscriptionAuditLogsWithHistoryForId(subscriptionBaseEvent.getSubscriptionId(), AuditLevel.FULL, internalCallContext);
assertEquals(subscriptionHistory.size(), 1);
final AuditLogWithHistory subscriptionHistoryRow1 = subscriptionHistory.get(0);
assertEquals(subscriptionHistoryRow1.getChangeType(), ChangeType.INSERT);
final SubscriptionModelDao subHistoryRow1 = (SubscriptionModelDao) subscriptionHistoryRow1.getEntity();
assertEquals(subHistoryRow1.getBundleId(), bundle.getId());
assertEquals(subHistoryRow1.getCategory(), ProductCategory.BASE);
final List<AuditLogWithHistory> subscriptionEventHistory = dao.getSubscriptionEventAuditLogsWithHistoryForId(subscriptionBaseEvent.getId(), AuditLevel.FULL, internalCallContext);
final AuditLogWithHistory subscriptionEventHistoryRow1 = subscriptionEventHistory.get(0);
assertEquals(subscriptionEventHistoryRow1.getChangeType(), ChangeType.INSERT);
final SubscriptionEventModelDao subEventHistoryRow1 = (SubscriptionEventModelDao) subscriptionEventHistoryRow1.getEntity();
assertEquals(subEventHistoryRow1.getSubscriptionId(), subscriptionBaseEvent.getSubscriptionId());
assertEquals(subEventHistoryRow1.getEventType(), EventType.API_USER);
assertEquals(subEventHistoryRow1.getUserType(), ApiEventType.CREATE);
assertEquals(subEventHistoryRow1.getPlanName(), "shotgun-monthly");
assertEquals(subEventHistoryRow1.getIsActive(), true);
}
use of org.killbill.billing.subscription.events.user.ApiEventBuilder in project killbill by killbill.
the class TestDefaultSubscriptionBase method testCancelSOT.
@Test(groups = "fast")
public void testCancelSOT() throws Exception {
final DateTime startDate = new DateTime(2012, 5, 1, 0, 0, DateTimeZone.UTC);
final DefaultSubscriptionBase subscriptionBase = new DefaultSubscriptionBase(new SubscriptionBuilder().setAlignStartDate(startDate));
final UUID subscriptionId = UUID.randomUUID();
final List<SubscriptionBaseEvent> inputEvents = new LinkedList<SubscriptionBaseEvent>();
inputEvents.add(new ApiEventCreate(new ApiEventBuilder().setApiEventType(CREATE).setEventPlan("laser-scope-monthly").setEventPlanPhase("laser-scope-monthly-discount").setEventPriceList("DEFAULT").setFromDisk(true).setUuid(UUID.randomUUID()).setSubscriptionId(subscriptionId).setCreatedDate(startDate).setUpdatedDate(startDate).setEffectiveDate(startDate).setTotalOrdering(3).setActive(true)));
inputEvents.add(new ApiEventCancel(new ApiEventBuilder().setApiEventType(ApiEventType.CANCEL).setEventPlan(null).setEventPlanPhase(null).setEventPriceList(null).setFromDisk(false).setUuid(UUID.randomUUID()).setSubscriptionId(subscriptionId).setCreatedDate(startDate).setUpdatedDate(null).setEffectiveDate(startDate).setTotalOrdering(// In-memory event
0).setActive(true)));
subscriptionBase.rebuildTransitions(inputEvents, catalog);
Assert.assertEquals(subscriptionBase.getAllTransitions().size(), 2);
Assert.assertNull(subscriptionBase.getAllTransitions().get(0).getPreviousState());
Assert.assertEquals(subscriptionBase.getAllTransitions().get(0).getNextState(), EntitlementState.ACTIVE);
Assert.assertEquals(subscriptionBase.getAllTransitions().get(0).getEffectiveTransitionTime(), startDate);
Assert.assertEquals(subscriptionBase.getAllTransitions().get(1).getPreviousState(), EntitlementState.ACTIVE);
Assert.assertEquals(subscriptionBase.getAllTransitions().get(1).getNextState(), EntitlementState.CANCELLED);
Assert.assertEquals(subscriptionBase.getAllTransitions().get(1).getEffectiveTransitionTime(), startDate);
}
Aggregations