use of org.killbill.billing.subscription.events.user.ApiEventBuilder 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);
}
}
use of org.killbill.billing.subscription.events.user.ApiEventBuilder 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);
}
}
use of org.killbill.billing.subscription.events.user.ApiEventBuilder 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;
}
use of org.killbill.billing.subscription.events.user.ApiEventBuilder in project killbill by killbill.
the class TestSubscriptionDao method afterMethod.
// to ignore events
@Override
@AfterMethod(groups = "slow")
public void afterMethod() throws Exception {
if (hasFailed()) {
final String externalKey = "12345";
final DateTime startDate = clock.getUTCNow();
final DateTime createdDate = startDate.plusSeconds(10);
final DefaultSubscriptionBaseBundle bundleDef = new DefaultSubscriptionBaseBundle(externalKey, accountId, startDate, startDate, createdDate, createdDate);
final SubscriptionBaseBundle bundle = dao.createSubscriptionBundle(bundleDef, catalog, true, internalCallContext);
final List<SubscriptionBaseBundle> result = dao.getSubscriptionBundlesForKey(externalKey, internalCallContext);
assertEquals(result.size(), 1);
assertEquals(result.get(0).getExternalKey(), bundle.getExternalKey());
// Operation succeeds but nothing new got created because bundle is empty
dao.createSubscriptionBundle(bundleDef, catalog, true, internalCallContext);
final List<SubscriptionBaseBundle> result2 = dao.getSubscriptionBundlesForKey(externalKey, internalCallContext);
assertEquals(result2.size(), 1);
// Create a subscription and this time operation should fail
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));
dao.createSubscriptionsWithAddOns(ImmutableList.<SubscriptionBaseWithAddOns>of(subscriptionBaseWithAddOns), ImmutableMap.<UUID, List<SubscriptionBaseEvent>>of(subscription.getId(), ImmutableList.<SubscriptionBaseEvent>of(creationEvent)), catalog, internalCallContext);
assertListenerStatus();
// Operation Should now fail
try {
dao.createSubscriptionBundle(bundleDef, catalog, true, internalCallContext);
Assert.fail("Should fail to create new subscription bundle with existing key");
} catch (SubscriptionBaseApiException e) {
assertEquals(ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS.getCode(), e.getCode());
}
return;
}
subscriptionTestInitializer.stopTestFramework(testListener, busService, subscriptionBaseService);
}
use of org.killbill.billing.subscription.events.user.ApiEventBuilder in project killbill by killbill.
the class TestSubscriptionBillingEvents method testWithChange_After_EffSubDtV3.
@Test(groups = "fast")
public void testWithChange_After_EffSubDtV3() throws Exception {
final DateTime createDate = new DateTime(2011, 1, 2, 0, 0, DateTimeZone.UTC);
final DefaultSubscriptionBase subscriptionBase = new DefaultSubscriptionBase(new SubscriptionBuilder().setAlignStartDate(createDate));
final UUID subscriptionId = UUID.randomUUID();
final List<SubscriptionBaseEvent> inputEvents = new LinkedList<SubscriptionBaseEvent>();
inputEvents.add(new ApiEventCreate(new ApiEventBuilder().setApiEventType(CREATE).setEventPlan("gold-monthly").setEventPlanPhase("gold-monthly-trial").setEventPriceList("DEFAULT").setFromDisk(true).setUuid(UUID.randomUUID()).setSubscriptionId(subscriptionId).setCreatedDate(createDate).setUpdatedDate(createDate).setEffectiveDate(createDate).setTotalOrdering(1).setActive(true)));
final DateTime evergreenPhaseDate = createDate.plusDays(30);
inputEvents.add(new PhaseEventData(new PhaseEventBuilder().setPhaseName("gold-monthly-evergreen").setUuid(UUID.randomUUID()).setSubscriptionId(subscriptionId).setCreatedDate(evergreenPhaseDate).setUpdatedDate(evergreenPhaseDate).setEffectiveDate(evergreenPhaseDate).setTotalOrdering(2).setActive(true)));
final DateTime changeDate = new DateTime(2011, 2, 15, 0, 0, DateTimeZone.UTC);
inputEvents.add(new ApiEventChange(new ApiEventBuilder().setApiEventType(ApiEventType.CHANGE).setEventPlan("silver-monthly").setEventPlanPhase("silver-monthly-evergreen").setEventPriceList("DEFAULT").setFromDisk(true).setUuid(UUID.randomUUID()).setSubscriptionId(subscriptionId).setCreatedDate(changeDate).setUpdatedDate(null).setEffectiveDate(changeDate).setTotalOrdering(3).setActive(true)));
subscriptionBase.rebuildTransitions(inputEvents, catalog);
final List<SubscriptionBillingEvent> result = subscriptionBase.getSubscriptionBillingEvents(catalog.getCatalog());
Assert.assertEquals(result.size(), 5);
Assert.assertEquals(result.get(0).getType(), SubscriptionBaseTransitionType.CREATE);
Assert.assertEquals(result.get(0).getEffectiveDate().compareTo(createDate), 0);
Assert.assertEquals(result.get(0).getPlan().getName().compareTo("gold-monthly"), 0);
Assert.assertEquals(toDateTime(result.get(0).getPlan().getCatalog().getEffectiveDate()).compareTo(EFF_V1), 0);
Assert.assertEquals(result.get(1).getType(), SubscriptionBaseTransitionType.PHASE);
Assert.assertEquals(result.get(1).getEffectiveDate().compareTo(evergreenPhaseDate), 0);
Assert.assertEquals(result.get(1).getPlan().getName().compareTo("gold-monthly"), 0);
Assert.assertEquals(toDateTime(result.get(1).getPlan().getCatalog().getEffectiveDate()).compareTo(EFF_V1), 0);
// Catalog change event for EFF_SUB_DT_V2
Assert.assertEquals(result.get(2).getType(), SubscriptionBaseTransitionType.CHANGE);
Assert.assertEquals(result.get(2).getEffectiveDate().compareTo(EFF_SUB_DT_V2), 0);
Assert.assertEquals(result.get(2).getPlan().getName().compareTo("gold-monthly"), 0);
Assert.assertEquals(toDateTime(result.get(2).getPlan().getCatalog().getEffectiveDate()).compareTo(EFF_V2), 0);
// Catalog change event for EFF_SUB_DT_V3
Assert.assertEquals(result.get(3).getType(), SubscriptionBaseTransitionType.CHANGE);
Assert.assertEquals(result.get(3).getEffectiveDate().compareTo(EFF_SUB_DT_V3), 0);
Assert.assertEquals(result.get(3).getPlan().getName().compareTo("gold-monthly"), 0);
Assert.assertEquals(toDateTime(result.get(3).getPlan().getCatalog().getEffectiveDate()).compareTo(EFF_V3), 0);
// User CHANGE event
Assert.assertEquals(result.get(4).getType(), SubscriptionBaseTransitionType.CHANGE);
Assert.assertEquals(result.get(4).getEffectiveDate().compareTo(changeDate), 0);
Assert.assertEquals(result.get(4).getPlan().getName().compareTo("silver-monthly"), 0);
Assert.assertEquals(toDateTime(result.get(4).getPlan().getCatalog().getEffectiveDate()).compareTo(EFF_V3), 0);
// We should not see any more catalog CHANGE events
}
Aggregations