use of org.killbill.billing.catalog.api.PlanPhase in project killbill by killbill.
the class DefaultSubscriptionInternalApi method verifyAndBuildSubscriptionSpecifiers.
private List<SubscriptionSpecifier> verifyAndBuildSubscriptionSpecifiers(final UUID bundleId, final String externalKey, final Iterable<EntitlementSpecifier> entitlements, final boolean isMigrated, final InternalCallContext context, final DateTime now, final DateTime effectiveDate, final Catalog catalog, final CallContext callContext) throws SubscriptionBaseApiException, CatalogApiException {
final List<SubscriptionSpecifier> subscriptions = new ArrayList<SubscriptionSpecifier>();
boolean first = true;
final List<SubscriptionBase> subscriptionsForBundle = getSubscriptionsForBundle(bundleId, null, context);
for (final EntitlementSpecifier entitlement : entitlements) {
final PlanPhaseSpecifier spec = entitlement.getPlanPhaseSpecifier();
final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(entitlement.getOverrides(), 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()));
}
if (first) {
first = false;
if (plan.getProduct().getCategory() != ProductCategory.BASE) {
throw new SubscriptionBaseApiException(new IllegalArgumentException(), ErrorCode.SUB_CREATE_NO_BP.getCode(), "Missing Base Subscription.");
}
}
// verify the number of subscriptions (of the same kind) allowed per bundle and the existing ones
if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(plan.getProduct().getCategory().toString())) {
if (plan.getPlansAllowedInBundle() != -1 && plan.getPlansAllowedInBundle() > 0) {
final int existingAddOnsWithSamePlanName = addonUtils.countExistingAddOnsWithSamePlanName(subscriptionsForBundle, plan.getName());
final int currentAddOnsWithSamePlanName = countCurrentAddOnsWithSamePlanName(entitlements, catalog, plan.getName(), effectiveDate, callContext);
if ((existingAddOnsWithSamePlanName + currentAddOnsWithSamePlanName) > 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 SubscriptionSpecifier subscription = new SubscriptionSpecifier();
subscription.setRealPriceList(plan.getPriceListName());
subscription.setEffectiveDate(effectiveDate);
subscription.setProcessedDate(now);
subscription.setPlan(plan);
subscription.setInitialPhase(spec.getPhaseType());
subscription.setBuilder(new SubscriptionBuilder().setId(UUIDs.randomUUID()).setBundleId(bundleId).setBundleExternalKey(externalKey).setCategory(plan.getProduct().getCategory()).setBundleStartDate(effectiveDate).setAlignStartDate(effectiveDate).setMigrated(isMigrated));
subscriptions.add(subscription);
}
return subscriptions;
}
use of org.killbill.billing.catalog.api.PlanPhase in project killbill by killbill.
the class TestUserApiChangePlan method testChangePlanBundleAlignEOTWithChargeThroughDate.
private void testChangePlanBundleAlignEOTWithChargeThroughDate(final String fromProd, final BillingPeriod fromTerm, final String fromPlanSet, final String toProd, final BillingPeriod toTerm, final String toPlanSet) throws SubscriptionBillingApiException, SubscriptionBaseApiException {
// CREATE
DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, fromProd, fromTerm, fromPlanSet);
final PlanPhase trialPhase = subscription.getCurrentPhase();
final DateTime expectedPhaseTrialChange = TestSubscriptionHelper.addDuration(subscription.getStartDate(), trialPhase.getDuration());
assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
// MOVE TO NEXT PHASE
testListener.pushExpectedEvent(NextEvent.PHASE);
Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
clock.addDeltaFromReality(it.toDurationMillis());
assertListenerStatus();
PlanPhase currentPhase = subscription.getCurrentPhase();
assertEquals(currentPhase.getPhaseType(), PhaseType.DISCOUNT);
// SET CTD
final Duration ctd = testUtil.getDurationMonth(1);
final DateTime newChargedThroughDate = TestSubscriptionHelper.addDuration(expectedPhaseTrialChange, ctd);
subscriptionInternalApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, internalCallContext);
// RE READ SUBSCRIPTION + CHANGE PLAN
subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
subscription.changePlan(new PlanSpecifier(toProd, toTerm, toPlanSet), null, callContext);
assertListenerStatus();
// CHECK CHANGE PLAN
currentPhase = subscription.getCurrentPhase();
checkChangePlan(subscription, fromProd, ProductCategory.BASE, fromTerm, PhaseType.DISCOUNT);
// NEXT PHASE
final DateTime nextExpectedPhaseChange = TestSubscriptionHelper.addDuration(expectedPhaseTrialChange, currentPhase.getDuration());
testUtil.checkNextPhaseChange(subscription, 2, nextExpectedPhaseChange);
// ALSO VERIFY PENDING CHANGE EVENT
final List<SubscriptionBaseEvent> events = dao.getPendingEventsForSubscription(subscription.getId(), internalCallContext);
assertTrue(events.get(0) instanceof ApiEvent);
// MOVE TO EOT
testListener.pushExpectedEvent(NextEvent.CHANGE);
it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
clock.addDeltaFromReality(it.toDurationMillis());
assertListenerStatus();
subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
currentPhase = subscription.getCurrentPhase();
checkChangePlan(subscription, toProd, ProductCategory.BASE, toTerm, PhaseType.DISCOUNT);
assertListenerStatus();
}
use of org.killbill.billing.catalog.api.PlanPhase in project killbill by killbill.
the class TestUserApiChangePlan method tChangePlanChangePlanAlignEOTWithChargeThroughDate.
private void tChangePlanChangePlanAlignEOTWithChargeThroughDate(final String fromProd, final BillingPeriod fromTerm, final String fromPlanSet, final String toProd, final BillingPeriod toTerm, final String toPlanSet) throws SubscriptionBillingApiException, SubscriptionBaseApiException {
DateTime currentTime = clock.getUTCNow();
DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, fromProd, fromTerm, fromPlanSet);
final PlanPhase trialPhase = subscription.getCurrentPhase();
final DateTime expectedPhaseTrialChange = TestSubscriptionHelper.addDuration(subscription.getStartDate(), trialPhase.getDuration());
assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
// MOVE TO NEXT PHASE
testListener.pushExpectedEvent(NextEvent.PHASE);
currentTime = clock.getUTCNow();
Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
clock.addDeltaFromReality(it.toDurationMillis());
currentTime = clock.getUTCNow();
assertListenerStatus();
// SET CTD
final Duration ctd = testUtil.getDurationMonth(1);
final DateTime newChargedThroughDate = TestSubscriptionHelper.addDuration(expectedPhaseTrialChange, ctd);
subscriptionInternalApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, internalCallContext);
// RE READ SUBSCRIPTION + CHECK CURRENT PHASE
subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
PlanPhase currentPhase = subscription.getCurrentPhase();
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
// CHANGE PLAN
currentTime = clock.getUTCNow();
subscription.changePlan(new PlanSpecifier(toProd, toTerm, toPlanSet), null, callContext);
checkChangePlan(subscription, fromProd, ProductCategory.BASE, fromTerm, PhaseType.EVERGREEN);
// CHECK CHANGE DID NOT KICK IN YET
assertListenerStatus();
// MOVE TO AFTER CTD
testListener.pushExpectedEvent(NextEvent.CHANGE);
it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
clock.addDeltaFromReality(it.toDurationMillis());
currentTime = clock.getUTCNow();
assertListenerStatus();
// CHECK CORRECT PRODUCT, PHASE, PLAN SET
final String currentProduct = subscription.getCurrentPlan().getProduct().getName();
assertNotNull(currentProduct);
assertEquals(currentProduct, toProd);
currentPhase = subscription.getCurrentPhase();
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.DISCOUNT);
// MOVE TIME ABOUT ONE MONTH BEFORE NEXT EXPECTED PHASE CHANGE
it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(11));
clock.addDeltaFromReality(it.toDurationMillis());
currentTime = clock.getUTCNow();
assertListenerStatus();
final DateTime nextExpectedPhaseChange = TestSubscriptionHelper.addDuration(newChargedThroughDate, currentPhase.getDuration());
testUtil.checkNextPhaseChange(subscription, 1, nextExpectedPhaseChange);
// MOVE TIME RIGHT AFTER NEXT EXPECTED PHASE CHANGE
testListener.pushExpectedEvent(NextEvent.PHASE);
it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
clock.addDeltaFromReality(it.toDurationMillis());
currentTime = clock.getUTCNow();
assertListenerStatus();
assertListenerStatus();
}
use of org.killbill.billing.catalog.api.PlanPhase in project killbill by killbill.
the class TestUserApiCreate method testSimpleCreateSubscription.
@Test(groups = "slow")
public void testSimpleCreateSubscription() throws SubscriptionBaseApiException {
final DateTime init = clock.getUTCNow();
final String productName = "Shotgun";
final BillingPeriod term = BillingPeriod.MONTHLY;
final String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
testListener.pushExpectedEvent(NextEvent.CREATE);
final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) subscriptionInternalApi.createSubscription(bundle.getId(), testUtil.getProductSpecifier(productName, planSetName, term, null), null, clock.getUTCNow(), false, internalCallContext);
assertNotNull(subscription);
assertEquals(subscription.getBundleId(), bundle.getId());
testUtil.assertDateWithin(subscription.getStartDate(), init, clock.getUTCNow());
testUtil.assertDateWithin(subscription.getBundleStartDate(), init, clock.getUTCNow());
final Plan currentPlan = subscription.getCurrentPlan();
assertNotNull(currentPlan);
assertEquals(currentPlan.getProduct().getName(), productName);
assertEquals(currentPlan.getProduct().getCategory(), ProductCategory.BASE);
assertEquals(currentPlan.getRecurringBillingPeriod(), BillingPeriod.MONTHLY);
final PlanPhase currentPhase = subscription.getCurrentPhase();
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.TRIAL);
assertListenerStatus();
final List<SubscriptionBaseEvent> events = dao.getPendingEventsForSubscription(subscription.getId(), internalCallContext);
assertNotNull(events);
testUtil.printEvents(events);
assertTrue(events.size() == 1);
assertTrue(events.get(0) instanceof PhaseEvent);
final DateTime nextPhaseChange = ((PhaseEvent) events.get(0)).getEffectiveDate();
final DateTime nextExpectedPhaseChange = TestSubscriptionHelper.addDuration(subscription.getStartDate(), currentPhase.getDuration());
assertEquals(nextPhaseChange, nextExpectedPhaseChange);
testListener.pushExpectedEvent(NextEvent.PHASE);
final Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
clock.addDeltaFromReality(it.toDurationMillis());
final DateTime futureNow = clock.getUTCNow();
assertTrue(futureNow.isAfter(nextPhaseChange));
assertListenerStatus();
}
use of org.killbill.billing.catalog.api.PlanPhase in project killbill by killbill.
the class TestUserApiCreate method testCreateWithInitialPhase.
@Test(groups = "slow")
public void testCreateWithInitialPhase() throws SubscriptionBaseApiException {
final DateTime init = clock.getUTCNow();
final String productName = "Shotgun";
final BillingPeriod term = BillingPeriod.MONTHLY;
final String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
testListener.pushExpectedEvent(NextEvent.CREATE);
final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) subscriptionInternalApi.createSubscription(bundle.getId(), testUtil.getProductSpecifier(productName, planSetName, term, PhaseType.EVERGREEN), null, clock.getUTCNow(), false, internalCallContext);
assertNotNull(subscription);
assertEquals(subscription.getBundleId(), bundle.getId());
testUtil.assertDateWithin(subscription.getStartDate(), init, clock.getUTCNow());
testUtil.assertDateWithin(subscription.getBundleStartDate(), init, clock.getUTCNow());
final Plan currentPlan = subscription.getCurrentPlan();
assertNotNull(currentPlan);
assertEquals(currentPlan.getProduct().getName(), productName);
assertEquals(currentPlan.getProduct().getCategory(), ProductCategory.BASE);
assertEquals(currentPlan.getRecurringBillingPeriod(), BillingPeriod.MONTHLY);
final PlanPhase currentPhase = subscription.getCurrentPhase();
assertNotNull(currentPhase);
assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
assertListenerStatus();
}
Aggregations