use of org.killbill.billing.entitlement.api.Entitlement.EntitlementState in project killbill by killbill.
the class DefaultSubscriptionBase method rebuildTransitions.
public void rebuildTransitions(final List<SubscriptionBaseEvent> inputEvents, final SubscriptionCatalog catalog) throws CatalogApiException {
if (inputEvents == null) {
return;
}
this.events = inputEvents;
Collections.sort(inputEvents, new Comparator<SubscriptionBaseEvent>() {
@Override
public int compare(final SubscriptionBaseEvent o1, final SubscriptionBaseEvent o2) {
final int res = o1.getEffectiveDate().compareTo(o2.getEffectiveDate());
if (res != 0) {
return res;
}
// In-memory events have a total order of 0, make sure they are after on disk event
if (o1.getTotalOrdering() == 0 && o2.getTotalOrdering() > 0) {
return 1;
} else if (o1.getTotalOrdering() > 0 && o2.getTotalOrdering() == 0) {
return -1;
} else if (o1.getTotalOrdering() == o2.getTotalOrdering()) {
return 0;
} else {
return o1.getTotalOrdering() < (o2.getTotalOrdering()) ? -1 : 1;
}
}
});
removeEverythingPastCancelEvent(events);
final UUID nextUserToken = null;
UUID nextEventId;
DateTime nextCreatedDate;
EntitlementState nextState = null;
String nextPlanName = null;
String nextPhaseName = null;
Integer nextBillingCycleDayLocal = null;
UUID prevEventId = null;
DateTime prevCreatedDate = null;
EntitlementState previousState = null;
PriceList previousPriceList = null;
Plan previousPlan = null;
PlanPhase previousPhase = null;
Integer previousBillingCycleDayLocal = null;
transitions = new LinkedList<SubscriptionBaseTransition>();
// Track each time we change Plan to fetch the Plan from the right catalog version
DateTime lastPlanChangeTime = null;
for (final SubscriptionBaseEvent cur : inputEvents) {
if (!cur.isActive()) {
continue;
}
ApiEventType apiEventType = null;
boolean isFromDisk = true;
nextEventId = cur.getId();
nextCreatedDate = cur.getCreatedDate();
switch(cur.getType()) {
case PHASE:
final PhaseEvent phaseEV = (PhaseEvent) cur;
nextPhaseName = phaseEV.getPhase();
break;
case BCD_UPDATE:
final BCDEvent bcdEvent = (BCDEvent) cur;
nextBillingCycleDayLocal = bcdEvent.getBillCycleDayLocal();
break;
case API_USER:
final ApiEvent userEV = (ApiEvent) cur;
apiEventType = userEV.getApiEventType();
isFromDisk = userEV.isFromDisk();
switch(apiEventType) {
case TRANSFER:
case CREATE:
prevEventId = null;
prevCreatedDate = null;
previousState = null;
previousPlan = null;
previousPhase = null;
previousPriceList = null;
nextState = EntitlementState.ACTIVE;
nextPlanName = userEV.getEventPlan();
nextPhaseName = userEV.getEventPlanPhase();
lastPlanChangeTime = cur.getEffectiveDate();
break;
case CHANGE:
nextPlanName = userEV.getEventPlan();
nextPhaseName = userEV.getEventPlanPhase();
lastPlanChangeTime = cur.getEffectiveDate();
break;
case CANCEL:
nextState = EntitlementState.CANCELLED;
nextPlanName = null;
nextPhaseName = null;
break;
case UNCANCEL:
case UNDO_CHANGE:
default:
throw new SubscriptionBaseError(String.format("Unexpected UserEvent type = %s", userEV.getApiEventType().toString()));
}
break;
default:
throw new SubscriptionBaseError(String.format("Unexpected Event type = %s", cur.getType()));
}
final Plan nextPlan = (nextPlanName != null) ? catalog.findPlan(nextPlanName, cur.getEffectiveDate(), lastPlanChangeTime) : null;
final PlanPhase nextPhase = (nextPlan != null && nextPhaseName != null) ? nextPlan.findPhase(nextPhaseName) : null;
final PriceList nextPriceList = (nextPlan != null) ? nextPlan.getPriceList() : null;
final SubscriptionBaseTransitionData transition = new SubscriptionBaseTransitionData(cur.getId(), id, bundleId, bundleExternalKey, cur.getType(), apiEventType, cur.getEffectiveDate(), prevEventId, prevCreatedDate, previousState, previousPlan, previousPhase, previousPriceList, previousBillingCycleDayLocal, nextEventId, nextCreatedDate, nextState, nextPlan, nextPhase, nextPriceList, nextBillingCycleDayLocal, cur.getTotalOrdering(), cur.getCreatedDate(), nextUserToken, isFromDisk);
transitions.add(transition);
previousState = nextState;
previousPlan = nextPlan;
previousPhase = nextPhase;
previousPriceList = nextPriceList;
prevEventId = nextEventId;
prevCreatedDate = nextCreatedDate;
previousBillingCycleDayLocal = nextBillingCycleDayLocal;
}
}
use of org.killbill.billing.entitlement.api.Entitlement.EntitlementState in project killbill by killbill.
the class DefaultSubscriptionBase method rebuildTransitions.
public void rebuildTransitions(final List<SubscriptionBaseEvent> inputEvents, final Catalog catalog) throws CatalogApiException {
if (inputEvents == null) {
return;
}
this.events = inputEvents;
filterOutDuplicateCancelEvents(events);
UUID nextUserToken = null;
UUID nextEventId = null;
DateTime nextCreatedDate = null;
EntitlementState nextState = null;
String nextPlanName = null;
String nextPhaseName = null;
Integer nextBillingCycleDayLocal = null;
UUID prevEventId = null;
DateTime prevCreatedDate = null;
EntitlementState previousState = null;
PriceList previousPriceList = null;
Plan previousPlan = null;
PlanPhase previousPhase = null;
Integer previousBillingCycleDayLocal = null;
transitions = new LinkedList<SubscriptionBaseTransition>();
for (final SubscriptionBaseEvent cur : inputEvents) {
if (!cur.isActive()) {
continue;
}
ApiEventType apiEventType = null;
boolean isFromDisk = true;
nextEventId = cur.getId();
nextCreatedDate = cur.getCreatedDate();
switch(cur.getType()) {
case PHASE:
final PhaseEvent phaseEV = (PhaseEvent) cur;
nextPhaseName = phaseEV.getPhase();
break;
case BCD_UPDATE:
final BCDEvent bcdEvent = (BCDEvent) cur;
nextBillingCycleDayLocal = bcdEvent.getBillCycleDayLocal();
break;
case API_USER:
final ApiEvent userEV = (ApiEvent) cur;
apiEventType = userEV.getApiEventType();
isFromDisk = userEV.isFromDisk();
switch(apiEventType) {
case TRANSFER:
case CREATE:
prevEventId = null;
prevCreatedDate = null;
previousState = null;
previousPlan = null;
previousPhase = null;
previousPriceList = null;
nextState = EntitlementState.ACTIVE;
nextPlanName = userEV.getEventPlan();
nextPhaseName = userEV.getEventPlanPhase();
break;
case CHANGE:
nextPlanName = userEV.getEventPlan();
nextPhaseName = userEV.getEventPlanPhase();
break;
case CANCEL:
nextState = EntitlementState.CANCELLED;
nextPlanName = null;
nextPhaseName = null;
break;
case UNCANCEL:
default:
throw new SubscriptionBaseError(String.format("Unexpected UserEvent type = %s", userEV.getApiEventType().toString()));
}
break;
default:
throw new SubscriptionBaseError(String.format("Unexpected Event type = %s", cur.getType()));
}
Plan nextPlan = null;
PlanPhase nextPhase = null;
PriceList nextPriceList = null;
nextPlan = (nextPlanName != null) ? catalog.findPlan(nextPlanName, cur.getEffectiveDate(), getAlignStartDate()) : null;
nextPhase = (nextPhaseName != null) ? catalog.findPhase(nextPhaseName, cur.getEffectiveDate(), getAlignStartDate()) : null;
nextPriceList = (nextPlan != null) ? catalog.findPriceListForPlan(nextPlanName, cur.getEffectiveDate(), getAlignStartDate()) : null;
final SubscriptionBaseTransitionData transition = new SubscriptionBaseTransitionData(cur.getId(), id, bundleId, bundleExternalKey, cur.getType(), apiEventType, cur.getEffectiveDate(), prevEventId, prevCreatedDate, previousState, previousPlan, previousPhase, previousPriceList, previousBillingCycleDayLocal, nextEventId, nextCreatedDate, nextState, nextPlan, nextPhase, nextPriceList, nextBillingCycleDayLocal, cur.getTotalOrdering(), cur.getCreatedDate(), nextUserToken, isFromDisk);
transitions.add(transition);
previousState = nextState;
previousPlan = nextPlan;
previousPhase = nextPhase;
previousPriceList = nextPriceList;
prevEventId = nextEventId;
prevCreatedDate = nextCreatedDate;
previousBillingCycleDayLocal = nextBillingCycleDayLocal;
}
}
use of org.killbill.billing.entitlement.api.Entitlement.EntitlementState in project killbill by killbill.
the class DefaultSubscriptionBaseApiService method cancelWithPolicy.
@Override
public boolean cancelWithPolicy(final DefaultSubscriptionBase subscription, final BillingActionPolicy policy, final DateTimeZone accountTimeZone, int accountBillCycleDayLocal, final CallContext context) throws SubscriptionBaseApiException {
final EntitlementState currentState = subscription.getState();
if (currentState == EntitlementState.CANCELLED) {
throw new SubscriptionBaseApiException(ErrorCode.SUB_CANCEL_BAD_STATE, subscription.getId(), currentState);
}
final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
return cancelWithPolicyNoValidation(ImmutableList.<DefaultSubscriptionBase>of(subscription), policy, accountTimeZone, accountBillCycleDayLocal, internalCallContext);
}
use of org.killbill.billing.entitlement.api.Entitlement.EntitlementState in project killbill by killbill.
the class DefaultSubscriptionBaseApiService method doCancelPlan.
private boolean doCancelPlan(final Map<DefaultSubscriptionBase, DateTime> subscriptions, final SubscriptionCatalog catalog, final InternalCallContext internalCallContext) throws SubscriptionBaseApiException {
final List<DefaultSubscriptionBase> subscriptionsToBeCancelled = new LinkedList<DefaultSubscriptionBase>();
final List<SubscriptionBaseEvent> cancelEvents = new LinkedList<SubscriptionBaseEvent>();
try {
for (final DefaultSubscriptionBase subscription : subscriptions.keySet()) {
final EntitlementState currentState = subscription.getState();
if (currentState == EntitlementState.CANCELLED) {
throw new SubscriptionBaseApiException(ErrorCode.SUB_CANCEL_BAD_STATE, subscription.getId(), currentState);
}
final DateTime effectiveDate = subscriptions.get(subscription);
// If subscription was future cancelled at an earlier date we disallow the operation -- i.e,
// user should first uncancel prior trying to cancel again.
// However, note that in case a future cancellation already exists with a greater or equal effectiveDate,
// the operation is allowed, but such existing cancellation would become invalidated (is_active=0)
final SubscriptionBaseTransition pendingTransition = subscription.getPendingTransition();
if (pendingTransition != null && pendingTransition.getTransitionType() == SubscriptionBaseTransitionType.CANCEL && pendingTransition.getEffectiveTransitionTime().compareTo(effectiveDate) < 0) {
throw new SubscriptionBaseApiException(ErrorCode.SUB_CANCEL_BAD_STATE, subscription.getId(), "PENDING CANCELLED");
}
validateEffectiveDate(subscription, effectiveDate);
subscriptionsToBeCancelled.add(subscription);
cancelEvents.addAll(getEventsOnCancelPlan(subscription, effectiveDate, false, catalog, internalCallContext));
if (subscription.getCategory() == ProductCategory.BASE) {
subscriptionsToBeCancelled.addAll(computeAddOnsToCancel(cancelEvents, null, subscription.getBundleId(), effectiveDate, catalog, internalCallContext));
}
}
dao.cancelSubscriptions(subscriptionsToBeCancelled, cancelEvents, catalog, internalCallContext);
boolean allSubscriptionsCancelled = true;
for (final DefaultSubscriptionBase subscription : subscriptions.keySet()) {
subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalog);
allSubscriptionsCancelled = allSubscriptionsCancelled && (subscription.getState() == EntitlementState.CANCELLED);
}
return allSubscriptionsCancelled;
} catch (final CatalogApiException e) {
throw new SubscriptionBaseApiException(e);
}
}
Aggregations