use of org.killbill.billing.entitlement.api.BlockingState in project killbill by killbill.
the class TestOverdueHelper method checkStateApplied.
public void checkStateApplied(final OverdueState state) {
final BlockingState result = ((ApplicatorBlockingApi) blockingInternalApi).getBlockingState();
checkStateApplied(result, state);
}
use of org.killbill.billing.entitlement.api.BlockingState in project killbill by killbill.
the class DefaultEntitlementApiBase method blockUnblockBundle.
private UUID blockUnblockBundle(final UUID bundleId, final String stateName, final String serviceName, @Nullable final LocalDate localEffectiveDate, boolean blockBilling, boolean blockEntitlement, boolean blockChange, @Nullable final SubscriptionBase inputBaseSubscription, final InternalCallContext internalCallContext) throws EntitlementApiException {
final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(localEffectiveDate, internalCallContext);
final BlockingState state = new DefaultBlockingState(bundleId, BlockingStateType.SUBSCRIPTION_BUNDLE, stateName, serviceName, blockChange, blockEntitlement, blockBilling, effectiveDate);
entitlementUtils.setBlockingStatesAndPostBlockingTransitionEvent(ImmutableList.<BlockingState>of(state), bundleId, internalCallContext);
return state.getId();
}
use of org.killbill.billing.entitlement.api.BlockingState in project killbill by killbill.
the class DefaultEntitlementInternalApi method cancel.
@Override
public void cancel(final Iterable<Entitlement> entitlements, @Nullable final LocalDate effectiveDate, final BillingActionPolicy billingPolicy, final Iterable<PluginProperty> properties, final InternalCallContext internalCallContext) throws EntitlementApiException {
if (!entitlements.iterator().hasNext()) {
return;
}
int bcd = 0;
DateTimeZone accountTimeZone = null;
try {
bcd = accountApi.getBCD(entitlements.iterator().next().getAccountId(), internalCallContext);
accountTimeZone = accountApi.getImmutableAccountDataByRecordId(internalCallContext.getAccountRecordId(), internalCallContext).getTimeZone();
} catch (final AccountApiException e) {
throw new EntitlementApiException(e);
}
Preconditions.checkState(bcd > 0 && accountTimeZone != null, "Unexpected condition where account info could not be retrieved");
final CallContext callContext = internalCallContextFactory.createCallContext(internalCallContext);
final ImmutableMap.Builder<BlockingState, Optional<UUID>> blockingStates = new ImmutableMap.Builder<BlockingState, Optional<UUID>>();
final Map<DateTime, Collection<NotificationEvent>> notificationEvents = new HashMap<DateTime, Collection<NotificationEvent>>();
final Collection<EntitlementContext> pluginContexts = new LinkedList<EntitlementContext>();
final List<WithEntitlementPlugin> callbacks = new LinkedList<WithEntitlementPlugin>();
final List<SubscriptionBase> subscriptions = new LinkedList<SubscriptionBase>();
for (final Entitlement entitlement : entitlements) {
if (entitlement.getState() == EntitlementState.CANCELLED) {
// If subscription has already been cancelled, we ignore and carry on
continue;
}
final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(entitlement.getBundleId(), entitlement.getExternalKey(), null, effectiveDate, null, false);
final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.CANCEL_SUBSCRIPTION, entitlement.getAccountId(), null, baseEntitlementWithAddOnsSpecifierList, billingPolicy, properties, callContext);
pluginContexts.add(pluginContext);
final WithEntitlementPlugin<Entitlement> cancelEntitlementWithPlugin = new WithDateOverrideBillingPolicyEntitlementCanceler((DefaultEntitlement) entitlement, blockingStates, notificationEvents, callContext, internalCallContext);
callbacks.add(cancelEntitlementWithPlugin);
subscriptions.add(((DefaultEntitlement) entitlement).getSubscriptionBase());
}
final Callable<Void> preCallbacksCallback = new BulkSubscriptionBaseCancellation(subscriptions, billingPolicy, accountTimeZone, bcd, internalCallContext);
pluginExecution.executeWithPlugin(preCallbacksCallback, callbacks, pluginContexts);
// Record the new states first, then insert the notifications to avoid race conditions
blockingStateDao.setBlockingStatesAndPostBlockingTransitionEvent(blockingStates.build(), internalCallContext);
for (final DateTime effectiveDateForNotification : notificationEvents.keySet()) {
for (final NotificationEvent notificationEvent : notificationEvents.get(effectiveDateForNotification)) {
recordFutureNotification(effectiveDateForNotification, notificationEvent, internalCallContext);
}
}
}
use of org.killbill.billing.entitlement.api.BlockingState in project killbill by killbill.
the class ProxyBlockingStateDao method sortedCopy.
// Ordering is critical here, especially for Junction
public static List<BlockingState> sortedCopy(final Iterable<BlockingState> blockingStates) {
final List<BlockingState> blockingStatesSomewhatSorted = Ordering.<BlockingState>natural().immutableSortedCopy(blockingStates);
final List<BlockingState> result = new LinkedList<BlockingState>();
// Make sure same-day transitions are always returned in the same order depending on their attributes
final Iterator<BlockingState> iterator = blockingStatesSomewhatSorted.iterator();
BlockingState prev = null;
while (iterator.hasNext()) {
final BlockingState current = iterator.next();
if (iterator.hasNext()) {
final BlockingState next = iterator.next();
if (prev != null && current.getEffectiveDate().equals(next.getEffectiveDate()) && current.getBlockedId().equals(next.getBlockedId()) && !current.getService().equals(next.getService())) {
// Same date, same blockable id, different services (for same-service events, trust the total ordering)
// Make sure block billing transitions are respected first
BlockingState prevCandidate = insertTiedBlockingStatesInTheRightOrder(result, current, next, prev.isBlockBilling(), current.isBlockBilling(), next.isBlockBilling());
if (prevCandidate == null) {
// Then respect block entitlement transitions
prevCandidate = insertTiedBlockingStatesInTheRightOrder(result, current, next, prev.isBlockEntitlement(), current.isBlockEntitlement(), next.isBlockEntitlement());
if (prevCandidate == null) {
// And finally block changes transitions
prevCandidate = insertTiedBlockingStatesInTheRightOrder(result, current, next, prev.isBlockChange(), current.isBlockChange(), next.isBlockChange());
if (prevCandidate == null) {
// Trust the current sorting
result.add(current);
result.add(next);
prev = next;
} else {
prev = prevCandidate;
}
} else {
prev = prevCandidate;
}
} else {
prev = prevCandidate;
}
} else {
result.add(current);
result.add(next);
prev = next;
}
} else {
// End of the list
result.add(current);
}
}
return result;
}
use of org.killbill.billing.entitlement.api.BlockingState in project killbill by killbill.
the class ProxyBlockingStateDao method addBlockingStatesNotOnDisk.
// Special signature for OptimizedProxyBlockingStateDao
protected List<BlockingState> addBlockingStatesNotOnDisk(@Nullable final UUID blockableId, @Nullable final BlockingStateType blockingStateType, final Collection<BlockingState> blockingStatesOnDiskCopy, final Iterable<SubscriptionBase> baseSubscriptionsToConsider, final Iterable<EventsStream> eventsStreams) {
// Compute the blocking states not on disk for all base subscriptions
final DateTime now = clock.getUTCNow();
for (final SubscriptionBase baseSubscription : baseSubscriptionsToConsider) {
final EventsStream eventsStream = Iterables.<EventsStream>find(eventsStreams, new Predicate<EventsStream>() {
@Override
public boolean apply(final EventsStream input) {
return input.getSubscriptionBase().getId().equals(baseSubscription.getId());
}
});
// First, check to see if the base entitlement is cancelled
final Collection<BlockingState> blockingStatesNotOnDisk = eventsStream.computeAddonsBlockingStatesForFutureSubscriptionBaseEvents();
// Inject the extra blocking states into the stream if needed
for (final BlockingState blockingState : blockingStatesNotOnDisk) {
// If this entitlement is actually already cancelled, add the cancellation event we computed
// only if it's prior to the blocking state on disk (e.g. add-on future cancelled but base plan cancelled earlier).
BlockingState cancellationBlockingStateOnDisk = null;
boolean overrideCancellationBlockingStateOnDisk = false;
if (isEntitlementCancellationBlockingState(blockingState)) {
cancellationBlockingStateOnDisk = findEntitlementCancellationBlockingState(blockingState.getBlockedId(), blockingStatesOnDiskCopy);
overrideCancellationBlockingStateOnDisk = cancellationBlockingStateOnDisk != null && blockingState.getEffectiveDate().isBefore(cancellationBlockingStateOnDisk.getEffectiveDate());
}
if ((blockingStateType == null || // blocking states for other add-ons on that base subscription
(BlockingStateType.SUBSCRIPTION.equals(blockingStateType) && blockingState.getBlockedId().equals(blockableId))) && (cancellationBlockingStateOnDisk == null || overrideCancellationBlockingStateOnDisk)) {
final BlockingStateModelDao blockingStateModelDao = new BlockingStateModelDao(blockingState, now, now);
blockingStatesOnDiskCopy.add(BlockingStateModelDao.toBlockingState(blockingStateModelDao));
if (overrideCancellationBlockingStateOnDisk) {
blockingStatesOnDiskCopy.remove(cancellationBlockingStateOnDisk);
}
}
}
}
// Return the sorted list
return sortedCopy(blockingStatesOnDiskCopy);
}
Aggregations