Search in sources :

Example 1 with PhaseType

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

the class PhasePriceOverrideJson method toPlanPhasePriceOverrides.

public static List<PlanPhasePriceOverride> toPlanPhasePriceOverrides(final List<PhasePriceOverrideJson> priceOverrides, final PlanSpecifier spec, final Currency currency) {
    if (priceOverrides == null || priceOverrides.isEmpty()) {
        return ImmutableList.<PlanPhasePriceOverride>of();
    }
    return ImmutableList.copyOf(Iterables.transform(priceOverrides, new Function<PhasePriceOverrideJson, PlanPhasePriceOverride>() {

        @Nullable
        @Override
        public PlanPhasePriceOverride apply(@Nullable final PhasePriceOverrideJson input) {
            if (input.getPhaseName() != null) {
                return new DefaultPlanPhasePriceOverride(input.getPhaseName(), currency, input.getFixedPrice(), input.getRecurringPrice());
            } else {
                final PhaseType phaseType = input.getPhaseType() != null ? PhaseType.valueOf(input.getPhaseType()) : null;
                final PlanPhaseSpecifier planPhaseSpecifier = spec.getPlanName() != null ? new PlanPhaseSpecifier(spec.getPlanName(), phaseType) : new PlanPhaseSpecifier(spec.getProductName(), spec.getBillingPeriod(), spec.getPriceListName(), phaseType);
                final Currency resolvedCurrency = input.getFixedPrice() != null || input.getRecurringPrice() != null ? currency : null;
                return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, resolvedCurrency, input.getFixedPrice(), input.getRecurringPrice());
            }
        }
    }));
}
Also used : PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) Function(com.google.common.base.Function) DefaultPlanPhasePriceOverride(org.killbill.billing.catalog.DefaultPlanPhasePriceOverride) Currency(org.killbill.billing.catalog.api.Currency) PhaseType(org.killbill.billing.catalog.api.PhaseType) Nullable(javax.annotation.Nullable) DefaultPlanPhasePriceOverride(org.killbill.billing.catalog.DefaultPlanPhasePriceOverride) PlanPhasePriceOverride(org.killbill.billing.catalog.api.PlanPhasePriceOverride)

Example 2 with PhaseType

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

the class SubscriptionResource method createEntitlement.

@TimedResource
@POST
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Create an entitlement")
@ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid entitlement supplied") })
public Response createEntitlement(final SubscriptionJson entitlement, @QueryParam(QUERY_REQUESTED_DT) final String requestedDate, /* This is deprecated, only used for backward compatibility */
@QueryParam(QUERY_ENTITLEMENT_REQUESTED_DT) final String entitlementDate, @QueryParam(QUERY_BILLING_REQUESTED_DT) final String billingDate, @QueryParam(QUERY_MIGRATED) @DefaultValue("false") final Boolean isMigrated, @QueryParam(QUERY_BCD) final Integer newBCD, @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion, @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec, @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString, @HeaderParam(HDR_CREATED_BY) final String createdBy, @HeaderParam(HDR_REASON) final String reason, @HeaderParam(HDR_COMMENT) final String comment, @javax.ws.rs.core.Context final HttpServletRequest request, @javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementApiException, AccountApiException, SubscriptionApiException {
    verifyNonNullOrEmpty(entitlement, "SubscriptionJson body should be specified");
    if (entitlement.getPlanName() == null) {
        verifyNonNullOrEmpty(entitlement.getProductName(), "SubscriptionJson productName needs to be set", entitlement.getProductCategory(), "SubscriptionJson productCategory needs to be set", entitlement.getBillingPeriod(), "SubscriptionJson billingPeriod needs to be set", entitlement.getPriceList(), "SubscriptionJson priceList needs to be set");
    }
    logDeprecationParameterWarningIfNeeded(QUERY_REQUESTED_DT, QUERY_ENTITLEMENT_REQUESTED_DT, QUERY_BILLING_REQUESTED_DT);
    // For ADD_ON we can provide externalKey or the bundleId
    final boolean createAddOnEntitlement = ProductCategory.ADD_ON.toString().equals(entitlement.getProductCategory());
    if (createAddOnEntitlement) {
        Preconditions.checkArgument(entitlement.getExternalKey() != null || entitlement.getBundleId() != null, "SubscriptionJson bundleId or externalKey should be specified for ADD_ON");
    }
    final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
    final CallContext callContext = context.createContext(createdBy, reason, comment, request);
    final EntitlementCallCompletionCallback<Entitlement> callback = new EntitlementCallCompletionCallback<Entitlement>() {

        @Override
        public Entitlement doOperation(final CallContext ctx) throws InterruptedException, TimeoutException, EntitlementApiException, SubscriptionApiException, AccountApiException {
            final Account account = getAccountFromSubscriptionJson(entitlement, callContext);
            final PhaseType phaseType = entitlement.getPhaseType() != null ? PhaseType.valueOf(entitlement.getPhaseType()) : null;
            final PlanPhaseSpecifier spec = entitlement.getPlanName() != null ? new PlanPhaseSpecifier(entitlement.getPlanName(), phaseType) : new PlanPhaseSpecifier(entitlement.getProductName(), BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList(), phaseType);
            final LocalDate resolvedEntitlementDate = requestedDate != null ? toLocalDate(requestedDate) : toLocalDate(entitlementDate);
            final LocalDate resolvedBillingDate = requestedDate != null ? toLocalDate(requestedDate) : toLocalDate(billingDate);
            final List<PlanPhasePriceOverride> overrides = PhasePriceOverrideJson.toPlanPhasePriceOverrides(entitlement.getPriceOverrides(), spec, account.getCurrency());
            final Entitlement result = createAddOnEntitlement ? entitlementApi.addEntitlement(getBundleIdForAddOnCreation(entitlement), spec, overrides, resolvedEntitlementDate, resolvedBillingDate, isMigrated, pluginProperties, callContext) : entitlementApi.createBaseEntitlement(account.getId(), spec, entitlement.getExternalKey(), overrides, resolvedEntitlementDate, resolvedBillingDate, isMigrated, pluginProperties, callContext);
            if (newBCD != null) {
                result.updateBCD(newBCD, null, callContext);
            }
            return result;
        }

        private UUID getBundleIdForAddOnCreation(final SubscriptionJson entitlement) throws SubscriptionApiException {
            if (entitlement.getBundleId() != null) {
                return UUID.fromString(entitlement.getBundleId());
            }
            // If user only specified the externalKey we need to fech the bundle (expensive operation) to extract the bundleId
            final SubscriptionBundle bundle = subscriptionApi.getActiveSubscriptionBundleForExternalKey(entitlement.getExternalKey(), callContext);
            return bundle.getId();
        }

        @Override
        public boolean isImmOperation() {
            return true;
        }

        @Override
        public Response doResponseOk(final Entitlement createdEntitlement) {
            return uriBuilder.buildResponse(uriInfo, SubscriptionResource.class, "getEntitlement", createdEntitlement.getId(), request);
        }
    };
    final EntitlementCallCompletion<Entitlement> callCompletionCreation = new EntitlementCallCompletion<Entitlement>();
    return callCompletionCreation.withSynchronization(callback, timeoutSec, callCompletion, callContext);
}
Also used : PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) Account(org.killbill.billing.account.api.Account) SubscriptionJson(org.killbill.billing.jaxrs.json.SubscriptionJson) CallContext(org.killbill.billing.util.callcontext.CallContext) LocalDate(org.joda.time.LocalDate) PluginProperty(org.killbill.billing.payment.api.PluginProperty) SubscriptionBundle(org.killbill.billing.entitlement.api.SubscriptionBundle) PhaseType(org.killbill.billing.catalog.api.PhaseType) Entitlement(org.killbill.billing.entitlement.api.Entitlement) PlanPhasePriceOverride(org.killbill.billing.catalog.api.PlanPhasePriceOverride) TimedResource(org.killbill.commons.metrics.TimedResource) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces) ApiOperation(io.swagger.annotations.ApiOperation) ApiResponses(io.swagger.annotations.ApiResponses)

Example 3 with PhaseType

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

the class DefaultSubscriptionBaseTimeline method toExistingEvents.

private List<ExistingEvent> toExistingEvents(final Catalog catalog, final ProductCategory category, final List<SubscriptionBaseEvent> events) throws CatalogApiException {
    final List<ExistingEvent> result = new LinkedList<SubscriptionBaseTimeline.ExistingEvent>();
    String prevPlanName = null;
    String prevProductName = null;
    BillingPeriod prevBillingPeriod = null;
    String prevPriceListName = null;
    PhaseType prevPhaseType = null;
    DateTime startDate = null;
    for (final SubscriptionBaseEvent cur : events) {
        if (!cur.isActive()) {
            continue;
        }
        startDate = (startDate == null) ? cur.getEffectiveDate() : startDate;
        String productName = null;
        BillingPeriod billingPeriod = null;
        String priceListName = null;
        PhaseType phaseType = null;
        String planName = null;
        String planPhaseName = null;
        Integer billCycleDayLocal = null;
        ApiEventType apiType = null;
        switch(cur.getType()) {
            case PHASE:
                final PhaseEvent phaseEV = (PhaseEvent) cur;
                planPhaseName = phaseEV.getPhase();
                phaseType = catalog.findPhase(phaseEV.getPhase(), cur.getEffectiveDate(), startDate).getPhaseType();
                // A PHASE event always occurs within the same plan (and is never the first event)
                planName = prevPlanName;
                productName = prevProductName;
                billingPeriod = getBillingPeriod(catalog, phaseEV.getPhase(), cur.getEffectiveDate(), startDate);
                priceListName = prevPriceListName;
                break;
            case BCD_UPDATE:
                final BCDEvent bcdEvent = (BCDEvent) cur;
                billCycleDayLocal = bcdEvent.getBillCycleDayLocal();
                break;
            case API_USER:
                final ApiEvent userEV = (ApiEvent) cur;
                apiType = userEV.getApiEventType();
                planName = userEV.getEventPlan();
                planPhaseName = userEV.getEventPlanPhase();
                final Plan plan = (userEV.getEventPlan() != null) ? catalog.findPlan(userEV.getEventPlan(), cur.getEffectiveDate(), startDate) : null;
                phaseType = (userEV.getEventPlanPhase() != null) ? catalog.findPhase(userEV.getEventPlanPhase(), cur.getEffectiveDate(), startDate).getPhaseType() : prevPhaseType;
                productName = (plan != null) ? plan.getProduct().getName() : prevProductName;
                billingPeriod = (userEV.getEventPlanPhase() != null) ? getBillingPeriod(catalog, userEV.getEventPlanPhase(), cur.getEffectiveDate(), startDate) : prevBillingPeriod;
                priceListName = (userEV.getPriceList() != null) ? userEV.getPriceList() : prevPriceListName;
                break;
        }
        final SubscriptionBaseTransitionType transitionType = SubscriptionBaseTransitionData.toSubscriptionTransitionType(cur.getType(), apiType);
        final String planNameWithClosure = planName;
        final String planPhaseNameWithClosure = planPhaseName;
        final Integer billCycleDayLocalWithClosure = billCycleDayLocal;
        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(planName, phaseType);
        result.add(new ExistingEvent() {

            @Override
            public SubscriptionBaseTransitionType getSubscriptionTransitionType() {
                return transitionType;
            }

            @Override
            public ProductCategory getProductCategory() {
                return category;
            }

            @Override
            public PlanPhaseSpecifier getPlanPhaseSpecifier() {
                return spec;
            }

            @Override
            public UUID getEventId() {
                return cur.getId();
            }

            @Override
            public DateTime getEffectiveDate() {
                return cur.getEffectiveDate();
            }

            @Override
            public String getPlanName() {
                return planNameWithClosure;
            }

            @Override
            public String getPlanPhaseName() {
                return planPhaseNameWithClosure;
            }

            @Override
            public Integer getBillCycleDayLocal() {
                return billCycleDayLocalWithClosure;
            }
        });
        prevPlanName = planName;
        prevProductName = productName;
        prevBillingPeriod = billingPeriod;
        prevPriceListName = priceListName;
        prevPhaseType = phaseType;
    }
    sortExistingEvent(result);
    return result;
}
Also used : ApiEventType(org.killbill.billing.subscription.events.user.ApiEventType) PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) PhaseEvent(org.killbill.billing.subscription.events.phase.PhaseEvent) BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) SubscriptionBaseTransitionType(org.killbill.billing.subscription.api.SubscriptionBaseTransitionType) BCDEvent(org.killbill.billing.subscription.events.bcd.BCDEvent) Plan(org.killbill.billing.catalog.api.Plan) LinkedList(java.util.LinkedList) DateTime(org.joda.time.DateTime) ApiEvent(org.killbill.billing.subscription.events.user.ApiEvent) PhaseType(org.killbill.billing.catalog.api.PhaseType) ProductCategory(org.killbill.billing.catalog.api.ProductCategory) UUID(java.util.UUID) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent)

Example 4 with PhaseType

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

the class TestPlanAligner method testCreationSubscriptionAlignment.

@Test(groups = "fast")
public void testCreationSubscriptionAlignment() throws Exception {
    final String productName = "laser-scope-monthly";
    final PhaseType initialPhase = PhaseType.DISCOUNT;
    final DateTime now = clock.getUTCNow();
    final DateTime bundleStartDate = now.minusHours(10);
    final DateTime alignStartDate = bundleStartDate.plusHours(5);
    final DefaultSubscriptionBase defaultSubscriptionBase = createSubscription(bundleStartDate, alignStartDate, productName, initialPhase);
    // Look now, after the bundle and the subscription started
    final DateTime effectiveDate = clock.getUTCNow();
    final TimedPhase[] phases = getTimedPhasesOnCreate(productName, initialPhase, defaultSubscriptionBase, effectiveDate);
    // Laser-Scope is START_OF_SUBSCRIPTION aligned on creation
    Assert.assertEquals(phases[0].getStartPhase(), defaultSubscriptionBase.getStartDate());
    Assert.assertEquals(phases[1].getStartPhase(), defaultSubscriptionBase.getStartDate().plusMonths(1));
    // Verify the next phase via the other API
    final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDate, catalog, internalCallContext);
    Assert.assertEquals(nextTimePhase.getStartPhase(), defaultSubscriptionBase.getStartDate().plusMonths(1));
    // Now look at the past, before the subscription started
    final DateTime effectiveDateInThePast = defaultSubscriptionBase.getStartDate().minusHours(10);
    final TimedPhase[] phasesInThePast = getTimedPhasesOnCreate(productName, initialPhase, defaultSubscriptionBase, effectiveDateInThePast);
    Assert.assertNull(phasesInThePast[0]);
    Assert.assertEquals(phasesInThePast[1].getStartPhase(), defaultSubscriptionBase.getStartDate());
    // Try a change plan (simulate END_OF_TERM policy)
    final String newProductName = "telescopic-scope-monthly";
    final DateTime effectiveChangeDate = defaultSubscriptionBase.getStartDate().plusMonths(1);
    changeSubscription(effectiveChangeDate, defaultSubscriptionBase, productName, newProductName, initialPhase);
    // All non rescue plans are START_OF_SUBSCRIPTION aligned on change. Since we're END_OF_TERM here, we'll
    // never see the discount phase of telescopic-scope-monthly and jump right into evergreen.
    // But in this test, since we didn't create the future change event from discount to evergreen (see changeSubscription,
    // the subscription has only two transitions), we'll see null
    final TimedPhase newPhase = getNextTimedPhaseOnChange(defaultSubscriptionBase, newProductName, effectiveChangeDate);
    Assert.assertNull(newPhase);
}
Also used : PhaseType(org.killbill.billing.catalog.api.PhaseType) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Example 5 with PhaseType

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

the class TestPlanAligner method testCreationBundleAlignment.

@Test(groups = "fast")
public void testCreationBundleAlignment() throws Exception {
    final String productName = "pistol-monthly";
    final PhaseType initialPhase = PhaseType.TRIAL;
    final DateTime now = clock.getUTCNow();
    final DateTime bundleStartDate = now.minusHours(10);
    final DateTime alignStartDate = bundleStartDate.plusHours(5);
    final DefaultSubscriptionBase defaultSubscriptionBase = createSubscription(bundleStartDate, alignStartDate, productName, initialPhase);
    // Make the creation effective now, after the bundle and the subscription started
    final DateTime effectiveDate = clock.getUTCNow();
    final TimedPhase[] phases = getTimedPhasesOnCreate(productName, initialPhase, defaultSubscriptionBase, effectiveDate);
    // All plans but Laser-Scope are START_OF_BUNDLE aligned on creation
    Assert.assertEquals(phases[0].getStartPhase(), defaultSubscriptionBase.getBundleStartDate());
    Assert.assertEquals(phases[1].getStartPhase(), defaultSubscriptionBase.getBundleStartDate().plusDays(30));
    // Verify the next phase via the other API
    final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDate, catalog, internalCallContext);
    Assert.assertEquals(nextTimePhase.getStartPhase(), defaultSubscriptionBase.getBundleStartDate().plusDays(30));
    // Now look at the past, before the bundle started
    final DateTime effectiveDateInThePast = defaultSubscriptionBase.getBundleStartDate().minusHours(10);
    final TimedPhase[] phasesInThePast = getTimedPhasesOnCreate(productName, initialPhase, defaultSubscriptionBase, effectiveDateInThePast);
    Assert.assertNull(phasesInThePast[0]);
    Assert.assertEquals(phasesInThePast[1].getStartPhase(), defaultSubscriptionBase.getBundleStartDate());
    // Try a change plan now (simulate an IMMEDIATE policy)
    final String newProductName = "shotgun-monthly";
    final DateTime effectiveChangeDate = clock.getUTCNow();
    changeSubscription(effectiveChangeDate, defaultSubscriptionBase, productName, newProductName, initialPhase);
    // All non rescue plans are START_OF_SUBSCRIPTION aligned on change
    final TimedPhase newPhase = getNextTimedPhaseOnChange(defaultSubscriptionBase, newProductName, effectiveChangeDate);
    Assert.assertEquals(newPhase.getStartPhase(), defaultSubscriptionBase.getStartDate().plusDays(30), String.format("Start phase: %s, but bundle start date: %s and subscription start date: %s", newPhase.getStartPhase(), defaultSubscriptionBase.getBundleStartDate(), defaultSubscriptionBase.getStartDate()));
}
Also used : PhaseType(org.killbill.billing.catalog.api.PhaseType) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Aggregations

PhaseType (org.killbill.billing.catalog.api.PhaseType)13 PlanPhaseSpecifier (org.killbill.billing.catalog.api.PlanPhaseSpecifier)9 DateTime (org.joda.time.DateTime)6 Plan (org.killbill.billing.catalog.api.Plan)5 SubscriptionBaseEvent (org.killbill.billing.subscription.events.SubscriptionBaseEvent)4 PlanPhasePriceOverride (org.killbill.billing.catalog.api.PlanPhasePriceOverride)3 ArrayList (java.util.ArrayList)2 LinkedList (java.util.LinkedList)2 UUID (java.util.UUID)2 InternalCallContext (org.killbill.billing.callcontext.InternalCallContext)2 Catalog (org.killbill.billing.catalog.api.Catalog)2 Currency (org.killbill.billing.catalog.api.Currency)2 PlanAlignmentChange (org.killbill.billing.catalog.api.PlanAlignmentChange)2 PlanPhasePriceOverridesWithCallContext (org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext)2 PlanSpecifier (org.killbill.billing.catalog.api.PlanSpecifier)2 ProductCategory (org.killbill.billing.catalog.api.ProductCategory)2 SubscriptionBaseTransitionType (org.killbill.billing.subscription.api.SubscriptionBaseTransitionType)2 DefaultPlanPhasePriceOverridesWithCallContext (org.killbill.billing.subscription.api.svcs.DefaultPlanPhasePriceOverridesWithCallContext)2 DefaultSubscriptionBase (org.killbill.billing.subscription.api.user.DefaultSubscriptionBase)2 BCDEvent (org.killbill.billing.subscription.events.bcd.BCDEvent)2