use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.
the class DefaultEntitlementApiBase method resume.
public void resume(final UUID bundleId, @Nullable final LocalDate localEffectiveDate, final Iterable<PluginProperty> properties, final InternalCallContext internalCallContext) throws EntitlementApiException {
final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(bundleId, null, null, localEffectiveDate, localEffectiveDate, false);
final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
baseEntitlementWithAddOnsSpecifierList.add(baseEntitlementWithAddOnsSpecifier);
final EntitlementContext pluginContext = new DefaultEntitlementContext(OperationType.RESUME_BUNDLE, null, null, baseEntitlementWithAddOnsSpecifierList, null, properties, internalCallContextFactory.createCallContext(internalCallContext));
final WithEntitlementPlugin<Void> resumeWithPlugin = new WithEntitlementPlugin<Void>() {
@Override
public Void doCall(final EntitlementApi entitlementApi, final DefaultEntitlementContext updatedPluginContext) throws EntitlementApiException {
try {
final SubscriptionBase baseSubscription = subscriptionInternalApi.getBaseSubscription(bundleId, internalCallContext);
blockUnblockBundle(bundleId, DefaultEntitlementApi.ENT_STATE_CLEAR, KILLBILL_SERVICES.ENTITLEMENT_SERVICE.getServiceName(), localEffectiveDate, false, false, false, baseSubscription, internalCallContext);
} catch (SubscriptionBaseApiException e) {
throw new EntitlementApiException(e);
}
return null;
}
};
pluginExecution.executeWithPlugin(resumeWithPlugin, pluginContext);
}
use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.
the class SubscriptionEventOrdering method computeSubscriptionBaseEvents.
// Compute the initial stream of events based on the subscription base events
private LinkedList<SubscriptionEvent> computeSubscriptionBaseEvents(final Iterable<Entitlement> entitlements, final InternalTenantContext internalTenantContext) {
final LinkedList<SubscriptionEvent> result = new LinkedList<SubscriptionEvent>();
for (final Entitlement cur : entitlements) {
Preconditions.checkState(cur instanceof DefaultEntitlement, "Entitlement %s is not a DefaultEntitlement", cur);
final SubscriptionBase base = ((DefaultEntitlement) cur).getSubscriptionBase();
final List<SubscriptionBaseTransition> baseTransitions = base.getAllTransitions();
for (final SubscriptionBaseTransition tr : baseTransitions) {
final List<SubscriptionEventType> eventTypes = toEventTypes(tr.getTransitionType());
for (final SubscriptionEventType eventType : eventTypes) {
final SubscriptionEvent event = toSubscriptionEvent(tr, eventType, internalTenantContext);
insertSubscriptionEvent(event, result);
}
}
}
return result;
}
use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.
the class DefaultEntitlementApi method getDryRunStatusForChange.
@Override
public List<EntitlementAOStatusDryRun> getDryRunStatusForChange(final UUID bundleId, final String targetProductName, @Nullable final LocalDate effectiveDate, final TenantContext context) throws EntitlementApiException {
final InternalTenantContext internalContext = internalCallContextFactory.createInternalTenantContext(bundleId, ObjectType.BUNDLE, context);
try {
final SubscriptionBase baseSubscription = subscriptionBaseInternalApi.getBaseSubscription(bundleId, internalContext);
final UUID accountId = subscriptionBaseInternalApi.getAccountIdFromBundleId(bundleId, internalContext);
final InternalTenantContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalTenantContext(accountId, context);
final DateTime now = clock.getUTCNow();
final DateTime requestedDate = dateHelper.fromLocalDateAndReferenceTime(effectiveDate, now, contextWithValidAccountRecordId);
return subscriptionBaseInternalApi.getDryRunChangePlanStatus(baseSubscription.getId(), targetProductName, requestedDate, contextWithValidAccountRecordId);
} catch (final SubscriptionBaseApiException e) {
throw new EntitlementApiException(e);
}
}
use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.
the class DefaultInternalBillingApi method addBillingEventsForBundles.
private void addBillingEventsForBundles(final ImmutableAccountData account, final DryRunArguments dryRunArguments, final InternalCallContext context, final DefaultBillingEventSet result, final Set<UUID> skipSubscriptionsSet, final Map<UUID, List<SubscriptionBase>> subscriptionsForAccount, final VersionedCatalog catalog, final List<Tag> tagsForAccount, final int currentAccountBCD) throws AccountApiException, CatalogApiException, SubscriptionBaseApiException {
// want to tap into subscriptionBase logic, so we make up a bundleId
if (dryRunArguments != null && dryRunArguments.getAction() == SubscriptionEventType.START_BILLING && dryRunArguments.getBundleId() == null) {
final UUID fakeBundleId = UUIDs.randomUUID();
final List<SubscriptionBase> subscriptions = subscriptionApi.getSubscriptionsForBundle(fakeBundleId, dryRunArguments, context);
addBillingEventsForSubscription(account, subscriptions, null, currentAccountBCD, context, result, skipSubscriptionsSet, catalog);
}
for (final UUID bundleId : subscriptionsForAccount.keySet()) {
final DryRunArguments dryRunArgumentsForBundle = (dryRunArguments != null && dryRunArguments.getBundleId() != null && dryRunArguments.getBundleId().equals(bundleId)) ? dryRunArguments : null;
final List<SubscriptionBase> subscriptions;
// In dryRun mode, optimization is intentionally left as is, since is not a common path.
if (dryRunArgumentsForBundle == null || dryRunArgumentsForBundle.getAction() == null) {
subscriptions = getSubscriptionsForAccountByBundleId(subscriptionsForAccount, bundleId);
} else {
subscriptions = subscriptionApi.getSubscriptionsForBundle(bundleId, dryRunArgumentsForBundle, context);
}
// Check if billing is off for the bundle
final List<Tag> bundleTags = getTagsForObjectType(ObjectType.BUNDLE, tagsForAccount, bundleId);
final boolean found_AUTO_INVOICING_OFF = is_AUTO_INVOICING_OFF(bundleTags);
if (found_AUTO_INVOICING_OFF) {
for (final SubscriptionBase subscription : subscriptions) {
// billing is off so list sub ids in set to be excluded
result.getSubscriptionIdsWithAutoInvoiceOff().add(subscription.getId());
}
} else {
// billing is not off
final SubscriptionBase baseSubscription = subscriptions != null && !subscriptions.isEmpty() ? subscriptions.get(0) : null;
addBillingEventsForSubscription(account, subscriptions, baseSubscription, currentAccountBCD, context, result, skipSubscriptionsSet, catalog);
}
}
// If dryRun is specified, we don't want to update the account BCD value, so we initialize the flag updatedAccountBCD to true
if (currentAccountBCD == 0) {
final Integer accountBCDCandidate = computeAccountBCD(result);
if (accountBCDCandidate == null) {
return;
}
// Because we now have computed the real BCD, we need to re-compute the BillingEvents BCD for ACCOUNT alignments (see BillCycleDayCalculator#calculateBcdForAlignment).
// The code could maybe be optimized (no need to re-run the full function?), but since it's run once per account, it's probably not worth it.
result.clear();
addBillingEventsForBundles(account, dryRunArguments, context, result, skipSubscriptionsSet, subscriptionsForAccount, catalog, tagsForAccount, accountBCDCandidate);
final boolean dryRunMode = dryRunArguments != null;
if (!dryRunMode) {
log.info("Setting account BCD='{}', accountId='{}'", accountBCDCandidate, account.getId());
accountApi.updateBCD(account.getExternalKey(), accountBCDCandidate, context);
}
}
}
use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.
the class DefaultInternalBillingApi method addBillingEventsForSubscription.
private void addBillingEventsForSubscription(final ImmutableAccountData account, @Nullable final List<SubscriptionBase> subscriptions, final SubscriptionBase baseSubscription, final int currentAccountBCD, final InternalCallContext context, final DefaultBillingEventSet result, final Set<UUID> skipSubscriptionsSet, final VersionedCatalog catalog) throws SubscriptionBaseApiException, CatalogApiException {
if (subscriptions == null) {
return;
}
final Map<UUID, Integer> bcdCache = new HashMap<UUID, Integer>();
for (final SubscriptionBase subscription : subscriptions) {
// TODO Can we batch those ?
final List<SubscriptionBillingEvent> billingTransitions = subscriptionApi.getSubscriptionBillingEvents(catalog, subscription, context);
if (billingTransitions.isEmpty() || (billingTransitions.get(0).getType() != SubscriptionBaseTransitionType.CREATE && billingTransitions.get(0).getType() != SubscriptionBaseTransitionType.TRANSFER)) {
log.warn("Skipping billing events for subscription " + subscription.getId() + ": Does not start with a valid CREATE transition");
skipSubscriptionsSet.add(subscription.getId());
return;
}
Integer overridenBCD = null;
int bcdLocal = 0;
BillingAlignment alignment = null;
for (final SubscriptionBillingEvent transition : billingTransitions) {
if (transition.getType() != SubscriptionBaseTransitionType.CANCEL) {
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(transition.getPlan().getName(), transition.getPlanPhase().getPhaseType());
alignment = subscription.getBillingAlignment(spec, transition.getEffectiveDate(), catalog);
//
// A BCD_CHANGE transition defines a new billCycleDayLocal for the subscription and this overrides whatever computation
// occurs below (which is based on billing alignment policy). Also multiple of those BCD_CHANGE transitions could occur,
// to define different intervals with different billing cycle days.
//
overridenBCD = transition.getBcdLocal() != null ? transition.getBcdLocal() : overridenBCD;
bcdLocal = overridenBCD != null ? overridenBCD : calculateBcdForTransition(alignment, bcdCache, baseSubscription, subscription, currentAccountBCD, context);
}
final BillingEvent event = new DefaultBillingEvent(transition, subscription, bcdLocal, alignment, account.getCurrency());
result.add(event);
}
}
}
Aggregations