Search in sources :

Example 11 with Catalog

use of org.killbill.billing.catalog.api.Catalog in project killbill by killbill.

the class DefaultSubscriptionInternalApi method createSubscription.

@Override
public SubscriptionBase createSubscription(final UUID bundleId, final PlanPhaseSpecifier spec, final List<PlanPhasePriceOverride> overrides, final DateTime requestedDateWithMs, final boolean isMigrated, final InternalCallContext context) throws SubscriptionBaseApiException {
    try {
        final DateTime now = clock.getUTCNow();
        final DateTime effectiveDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
        /*
            if (requestedDate.isAfter(now)) {
                throw new SubscriptionBaseApiException(ErrorCode.SUB_INVALID_REQUESTED_DATE, now.toString(), requestedDate.toString());
            }
            */
        final CallContext callContext = internalCallContextFactory.createCallContext(context);
        final Catalog catalog = catalogService.getFullCatalog(true, true, context);
        final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(overrides, callContext);
        final Plan plan = catalog.createOrFindPlan(spec, overridesWithContext, effectiveDate);
        final PlanPhase phase = plan.getAllPhases()[0];
        if (phase == null) {
            throw new SubscriptionBaseError(String.format("No initial PlanPhase for Product %s, term %s and set %s does not exist in the catalog", spec.getProductName(), spec.getBillingPeriod().toString(), plan.getPriceListName()));
        }
        final SubscriptionBaseBundle bundle = dao.getSubscriptionBundleFromId(bundleId, context);
        if (bundle == null) {
            throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_NO_BUNDLE, bundleId);
        }
        final DefaultSubscriptionBase baseSubscription = (DefaultSubscriptionBase) dao.getBaseSubscription(bundleId, context);
        // verify the number of subscriptions (of the same kind) allowed per bundle
        if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(plan.getProduct().getCategory().toString())) {
            if (plan.getPlansAllowedInBundle() != -1 && plan.getPlansAllowedInBundle() > 0 && addonUtils.countExistingAddOnsWithSamePlanName(getSubscriptionsForBundle(bundleId, null, context), plan.getName()) >= plan.getPlansAllowedInBundle()) {
                // a new ADD_ON subscription of the same plan can't be added because it has reached its limit by bundle
                throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE, plan.getName());
            }
        }
        final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, effectiveDate, context);
        return apiService.createPlan(new SubscriptionBuilder().setId(UUIDs.randomUUID()).setBundleId(bundleId).setBundleExternalKey(bundle.getExternalKey()).setCategory(plan.getProduct().getCategory()).setBundleStartDate(bundleStartDate).setAlignStartDate(effectiveDate).setMigrated(isMigrated), plan, spec.getPhaseType(), plan.getPriceListName(), effectiveDate, now, callContext);
    } catch (final CatalogApiException e) {
        throw new SubscriptionBaseApiException(e);
    }
}
Also used : SubscriptionBuilder(org.killbill.billing.subscription.api.user.SubscriptionBuilder) Plan(org.killbill.billing.catalog.api.Plan) PlanPhasePriceOverridesWithCallContext(org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext) CallContext(org.killbill.billing.util.callcontext.CallContext) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) DateTime(org.joda.time.DateTime) Catalog(org.killbill.billing.catalog.api.Catalog) PlanPhasePriceOverridesWithCallContext(org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext) SubscriptionBaseError(org.killbill.billing.subscription.exceptions.SubscriptionBaseError) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) PlanPhase(org.killbill.billing.catalog.api.PlanPhase) SubscriptionBaseBundle(org.killbill.billing.subscription.api.user.SubscriptionBaseBundle) DefaultSubscriptionBaseBundle(org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) SubscriptionBaseApiException(org.killbill.billing.subscription.api.user.SubscriptionBaseApiException) PlanPhasePriceOverride(org.killbill.billing.catalog.api.PlanPhasePriceOverride)

Example 12 with Catalog

use of org.killbill.billing.catalog.api.Catalog in project killbill by killbill.

the class DefaultSubscriptionInternalApi method populateDryRunEvents.

private void populateDryRunEvents(@Nullable final UUID bundleId, @Nullable final DryRunArguments dryRunArguments, final Collection<SubscriptionBaseEvent> outputDryRunEvents, final Collection<SubscriptionBase> outputSubscriptions, final InternalTenantContext context) throws SubscriptionBaseApiException {
    if (dryRunArguments == null || dryRunArguments.getAction() == null) {
        return;
    }
    final DateTime utcNow = clock.getUTCNow();
    List<SubscriptionBaseEvent> dryRunEvents = null;
    try {
        final PlanPhaseSpecifier inputSpec = dryRunArguments.getPlanPhaseSpecifier();
        final boolean isInputSpecNullOrEmpty = inputSpec == null || (inputSpec.getPlanName() == null && inputSpec.getProductName() == null && inputSpec.getBillingPeriod() == null);
        final Catalog catalog = catalogService.getFullCatalog(true, true, context);
        // Create an overridesWithContext with a null context to indicate this is dryRun and no price overriden plan should be created.
        final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(dryRunArguments.getPlanPhasePriceOverrides(), null);
        final Plan plan = isInputSpecNullOrEmpty ? null : catalog.createOrFindPlan(inputSpec, overridesWithContext, utcNow);
        final TenantContext tenantContext = internalCallContextFactory.createTenantContext(context);
        switch(dryRunArguments.getAction()) {
            case START_BILLING:
                final DefaultSubscriptionBase baseSubscription = (DefaultSubscriptionBase) dao.getBaseSubscription(bundleId, context);
                final DateTime startEffectiveDate = dryRunArguments.getEffectiveDate() != null ? context.toUTCDateTime(dryRunArguments.getEffectiveDate()) : utcNow;
                final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, startEffectiveDate, context);
                final UUID subscriptionId = UUIDs.randomUUID();
                dryRunEvents = apiService.getEventsOnCreation(bundleId, subscriptionId, startEffectiveDate, bundleStartDate, plan, inputSpec.getPhaseType(), plan.getPriceListName(), startEffectiveDate, utcNow, context);
                final SubscriptionBuilder builder = new SubscriptionBuilder().setId(subscriptionId).setBundleId(bundleId).setBundleExternalKey(null).setCategory(plan.getProduct().getCategory()).setBundleStartDate(bundleStartDate).setAlignStartDate(startEffectiveDate);
                final DefaultSubscriptionBase newSubscription = new DefaultSubscriptionBase(builder, apiService, clock);
                newSubscription.rebuildTransitions(dryRunEvents, catalog);
                outputSubscriptions.add(newSubscription);
                break;
            case CHANGE:
                final DefaultSubscriptionBase subscriptionForChange = (DefaultSubscriptionBase) dao.getSubscriptionFromId(dryRunArguments.getSubscriptionId(), context);
                DateTime changeEffectiveDate = dryRunArguments.getEffectiveDate() != null ? context.toUTCDateTime(dryRunArguments.getEffectiveDate()) : null;
                if (changeEffectiveDate == null) {
                    BillingActionPolicy policy = dryRunArguments.getBillingActionPolicy();
                    if (policy == null) {
                        final PlanChangeResult planChangeResult = apiService.getPlanChangeResult(subscriptionForChange, inputSpec, utcNow, tenantContext);
                        policy = planChangeResult.getPolicy();
                    }
                    // We pass null for billingAlignment, accountTimezone, account BCD because this is not available which means that dryRun with START_OF_TERM BillingPolicy will fail
                    changeEffectiveDate = subscriptionForChange.getPlanChangeEffectiveDate(policy, null, null, -1, context);
                }
                dryRunEvents = apiService.getEventsOnChangePlan(subscriptionForChange, plan, plan.getPriceListName(), changeEffectiveDate, utcNow, true, context);
                break;
            case STOP_BILLING:
                final DefaultSubscriptionBase subscriptionForCancellation = (DefaultSubscriptionBase) dao.getSubscriptionFromId(dryRunArguments.getSubscriptionId(), context);
                DateTime cancelEffectiveDate = dryRunArguments.getEffectiveDate() != null ? context.toUTCDateTime(dryRunArguments.getEffectiveDate()) : null;
                if (dryRunArguments.getEffectiveDate() == null) {
                    BillingActionPolicy policy = dryRunArguments.getBillingActionPolicy();
                    if (policy == null) {
                        final Plan currentPlan = subscriptionForCancellation.getCurrentPlan();
                        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(currentPlan.getName(), subscriptionForCancellation.getCurrentPhase().getPhaseType());
                        policy = catalogService.getFullCatalog(true, true, context).planCancelPolicy(spec, utcNow);
                    }
                    // We pass null for billingAlignment, accountTimezone, account BCD because this is not available which means that dryRun with START_OF_TERM BillingPolicy will fail
                    cancelEffectiveDate = subscriptionForCancellation.getPlanChangeEffectiveDate(policy, null, null, -1, context);
                }
                dryRunEvents = apiService.getEventsOnCancelPlan(subscriptionForCancellation, cancelEffectiveDate, utcNow, true, context);
                break;
            default:
                throw new IllegalArgumentException("Unexpected dryRunArguments action " + dryRunArguments.getAction());
        }
    } catch (final CatalogApiException e) {
        throw new SubscriptionBaseApiException(e);
    }
    if (dryRunEvents != null && !dryRunEvents.isEmpty()) {
        outputDryRunEvents.addAll(dryRunEvents);
    }
}
Also used : PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) BillingActionPolicy(org.killbill.billing.catalog.api.BillingActionPolicy) InternalTenantContext(org.killbill.billing.callcontext.InternalTenantContext) TenantContext(org.killbill.billing.util.callcontext.TenantContext) PlanChangeResult(org.killbill.billing.catalog.api.PlanChangeResult) SubscriptionBuilder(org.killbill.billing.subscription.api.user.SubscriptionBuilder) Plan(org.killbill.billing.catalog.api.Plan) DateTime(org.joda.time.DateTime) Catalog(org.killbill.billing.catalog.api.Catalog) PlanPhasePriceOverridesWithCallContext(org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) UUID(java.util.UUID) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) SubscriptionBaseApiException(org.killbill.billing.subscription.api.user.SubscriptionBaseApiException)

Example 13 with Catalog

use of org.killbill.billing.catalog.api.Catalog in project killbill by killbill.

the class BlockingCalculator method createNewEvents.

protected SortedSet<BillingEvent> createNewEvents(final List<DisabledDuration> disabledDuration, final SortedSet<BillingEvent> billingEvents, final SubscriptionBase subscription, final InternalTenantContext context) throws CatalogApiException {
    final SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
    final Catalog catalog = catalogService.getFullCatalog(true, true, context);
    for (final DisabledDuration duration : disabledDuration) {
        // The first one before the blocked duration
        final BillingEvent precedingInitialEvent = precedingBillingEventForSubscription(duration.getStart(), billingEvents, subscription);
        // The last one during of before the duration
        final BillingEvent precedingFinalEvent = precedingBillingEventForSubscription(duration.getEnd(), billingEvents, subscription);
        if (precedingInitialEvent != null) {
            // there is a preceding billing event
            result.add(createNewDisableEvent(duration.getStart(), precedingInitialEvent, catalog, context));
            if (duration.getEnd() != null) {
                // no second event in the pair means they are still disabled (no re-enable)
                result.add(createNewReenableEvent(duration.getEnd(), precedingFinalEvent, catalog, context));
            }
        } else if (precedingFinalEvent != null) {
            // can happen - e.g. phase event
            result.add(createNewReenableEvent(duration.getEnd(), precedingFinalEvent, catalog, context));
        }
    // N.B. if there's no precedingInitial and no precedingFinal then there's nothing to do
    }
    return result;
}
Also used : TreeSet(java.util.TreeSet) BillingEvent(org.killbill.billing.junction.BillingEvent) Catalog(org.killbill.billing.catalog.api.Catalog)

Example 14 with Catalog

use of org.killbill.billing.catalog.api.Catalog in project killbill by killbill.

the class EntitlementTestSuiteWithEmbeddedDB method initCatalog.

private Catalog initCatalog(final CatalogService catalogService) throws Exception {
    ((DefaultCatalogService) catalogService).loadCatalog();
    final Catalog catalog = catalogService.getFullCatalog(true, true, internalCallContext);
    assertNotNull(catalog);
    return catalog;
}
Also used : DefaultCatalogService(org.killbill.billing.catalog.DefaultCatalogService) Catalog(org.killbill.billing.catalog.api.Catalog)

Example 15 with Catalog

use of org.killbill.billing.catalog.api.Catalog in project killbill by killbill.

the class TestBillCycleDayCalculator method testCalculateBCDForAOWithBPCancelledBundleAligned.

@Test(groups = "fast")
public void testCalculateBCDForAOWithBPCancelledBundleAligned() throws Exception {
    final DateTimeZone accountTimeZone = DateTimeZone.UTC;
    final DateTime bpStartDateUTC = new DateTime(2012, 7, 16, 21, 0, 0, DateTimeZone.UTC);
    final int expectedBCDUTC = 16;
    // Create a Bundle associated with a subscription
    final SubscriptionBaseBundle bundle = Mockito.mock(SubscriptionBaseBundle.class);
    final SubscriptionBase subscription = Mockito.mock(SubscriptionBase.class);
    Mockito.when(subscription.getStartDate()).thenReturn(bpStartDateUTC);
    // Create a the base plan associated with that subscription
    final Plan plan = Mockito.mock(Plan.class);
    final Catalog catalog = Mockito.mock(Catalog.class);
    Mockito.when(catalog.findPlan(Mockito.anyString(), Mockito.<DateTime>any(), Mockito.<DateTime>any())).thenReturn(plan);
    Mockito.when(subscription.getLastActivePlan()).thenReturn(plan);
    Mockito.when(subscription.getDateOfFirstRecurringNonZeroCharge()).thenReturn(bpStartDateUTC);
    final ImmutableAccountData account = Mockito.mock(ImmutableAccountData.class);
    Mockito.when(account.getTimeZone()).thenReturn(accountTimeZone);
    final Integer billCycleDayLocal = BillCycleDayCalculator.calculateBcdForAlignment(new HashMap<UUID, Integer>(), subscription, subscription, BillingAlignment.BUNDLE, account.getTimeZone(), 0);
    Assert.assertEquals(billCycleDayLocal, (Integer) expectedBCDUTC);
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) ImmutableAccountData(org.killbill.billing.account.api.ImmutableAccountData) SubscriptionBaseBundle(org.killbill.billing.subscription.api.user.SubscriptionBaseBundle) Plan(org.killbill.billing.catalog.api.Plan) UUID(java.util.UUID) DateTimeZone(org.joda.time.DateTimeZone) DateTime(org.joda.time.DateTime) Catalog(org.killbill.billing.catalog.api.Catalog) Test(org.testng.annotations.Test)

Aggregations

Catalog (org.killbill.billing.catalog.api.Catalog)19 DateTime (org.joda.time.DateTime)10 CatalogApiException (org.killbill.billing.catalog.api.CatalogApiException)7 InternalCallContext (org.killbill.billing.callcontext.InternalCallContext)6 Plan (org.killbill.billing.catalog.api.Plan)5 PlanPhasePriceOverride (org.killbill.billing.catalog.api.PlanPhasePriceOverride)5 PlanPhasePriceOverridesWithCallContext (org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext)5 SubscriptionBaseApiException (org.killbill.billing.subscription.api.user.SubscriptionBaseApiException)5 SubscriptionBaseEvent (org.killbill.billing.subscription.events.SubscriptionBaseEvent)5 SubscriptionBaseError (org.killbill.billing.subscription.exceptions.SubscriptionBaseError)4 ArrayList (java.util.ArrayList)3 UUID (java.util.UUID)3 DefaultCatalogService (org.killbill.billing.catalog.DefaultCatalogService)3 PlanPhaseSpecifier (org.killbill.billing.catalog.api.PlanPhaseSpecifier)3 DefaultSubscriptionBase (org.killbill.billing.subscription.api.user.DefaultSubscriptionBase)3 SubscriptionBaseBundle (org.killbill.billing.subscription.api.user.SubscriptionBaseBundle)3 SubscriptionBuilder (org.killbill.billing.subscription.api.user.SubscriptionBuilder)3 CallContext (org.killbill.billing.util.callcontext.CallContext)3 InternalTenantContext (org.killbill.billing.callcontext.InternalTenantContext)2 PhaseType (org.killbill.billing.catalog.api.PhaseType)2