private void doChangePlan(final DefaultSubscriptionBase subscription, final EntitlementSpecifier spec, final DateTime effectiveDate, final CallContext context) throws SubscriptionBaseApiException, CatalogApiException { final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context); final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(spec.getOverrides(), context); final Catalog fullCatalog = catalogInternalApi.getFullCatalog(true, true, internalCallContext); final PlanPhaseSpecifier planPhaseSpecifier = spec.getPlanPhaseSpecifier(); final Plan newPlan = fullCatalog.createOrFindPlan(planPhaseSpecifier, overridesWithContext, effectiveDate, subscription.getStartDate()); final PhaseType initialPhaseType = planPhaseSpecifier.getPhaseType(); if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(newPlan.getProduct().getCategory().toString())) { if (newPlan.getPlansAllowedInBundle() != -1 && newPlan.getPlansAllowedInBundle() > 0 && addonUtils.countExistingAddOnsWithSamePlanName(dao.getSubscriptions(subscription.getBundleId(), null, fullCatalog, internalCallContext), newPlan.getName()) >= newPlan.getPlansAllowedInBundle()) { // the plan can be changed to the new value, because it has reached its limit by bundle throw new SubscriptionBaseApiException(ErrorCode.SUB_CHANGE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE, newPlan.getName()); } } if (newPlan.getProduct().getCategory() != subscription.getCategory()) { throw new SubscriptionBaseApiException(ErrorCode.SUB_CHANGE_INVALID, subscription.getId()); } final List<DefaultSubscriptionBase> addOnSubscriptionsToBeCancelled = new ArrayList<DefaultSubscriptionBase>(); final List<SubscriptionBaseEvent> addOnCancelEvents = new ArrayList<SubscriptionBaseEvent>(); final List<SubscriptionBaseEvent> changeEvents = getEventsOnChangePlan(subscription, newPlan, newPlan.getPriceListName(), effectiveDate, true, addOnSubscriptionsToBeCancelled, addOnCancelEvents, initialPhaseType, spec.getBillCycleDay(), fullCatalog, internalCallContext); dao.changePlan(subscription, changeEvents, addOnSubscriptionsToBeCancelled, addOnCancelEvents, fullCatalog, internalCallContext); subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), fullCatalog); }
@Override public Collection<Plan> findPlans(final Product product, final BillingPeriod period) { final List<Plan> result = new ArrayList<Plan>(plans.size()); for (final Plan cur : getPlans()) { if (cur.getProduct().equals(product) && (cur.getRecurringBillingPeriod() != null && cur.getRecurringBillingPeriod().equals(period))) { result.add(cur); } } return result; }
@Override public PlanPhase findPhase(final String phaseName, final DateTime requestedDate, final DateTime subscriptionStartDate) throws CatalogApiException { final String planName = DefaultPlanPhase.planName(phaseName); final Plan plan = findPlan(planName, requestedDate, subscriptionStartDate); return plan.findPhase(phaseName); }
public DefaultPlanPhase setPlan(final Plan plan) { this.planName = plan.getName(); this.product = plan.getProduct(); return this; }
private Plan toDefaultPlan(final StaticCatalog staticCatalog, final Plan input) { if (tmpDefaultPlans != null) { final Plan existingPlan = tmpDefaultPlans.get(input.getName()); if (existingPlan == null) throw new IllegalStateException("Unknown plan " + input.getName()); return existingPlan; } final DefaultPlan result = new DefaultPlan(); result.setName(input.getName()); result.setPrettyName(input.getPrettyName()); result.setRecurringBillingMode(input.getRecurringBillingMode()); result.setEffectiveDateForExistingSubscriptions(input.getEffectiveDateForExistingSubscriptions()); result.setFinalPhase(toDefaultPlanPhase(input.getFinalPhase())); result.setInitialPhases(toDefaultPlanPhases(ImmutableList.copyOf(input.getInitialPhases()))); result.setPlansAllowedInBundle(input.getPlansAllowedInBundle()); result.setProduct(toDefaultProduct(input.getProduct())); result.setPriceListName(input.getPriceListName()); return result; }
final PlanPhasePriceOverride phase1 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[0].getName(), Currency.USD, BigDecimal.ONE, null, null); overrides.add(phase1); final PlanPhasePriceOverride phase3 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[2].getName(), Currency.USD, null, new BigDecimal("142.41"), null); overrides.add(phase3); assertEquals(m.group(1), plan.getName()); assertEquals(overriddenPlan.getProduct().getName(), plan.getProduct().getName()); assertEquals(overriddenPlan.getRecurringBillingPeriod(), plan.getRecurringBillingPeriod()); if (plan.getEffectiveDateForExistingSubscriptions() != null) { assertEquals(overriddenPlan.getEffectiveDateForExistingSubscriptions().compareTo(plan.getEffectiveDateForExistingSubscriptions()), 0); assertNotEquals(overriddenPlan.getFinalPhase().getName(), plan.getFinalPhase().getName()); assertEquals(overriddenPlan.getPlansAllowedInBundle(), plan.getPlansAllowedInBundle()); final DefaultPlanPhase initialPhase = (DefaultPlanPhase) plan.getAllPhases()[i]; final DefaultPlanPhase newPhase = (DefaultPlanPhase) overriddenPlan.getAllPhases()[i];
usagePriceOverrides.add(new DefaultUsagePriceOverride("chocolate-monthly-videos", UsageType.CONSUMABLE, tierPriceOverrides)); final PlanPhasePriceOverride phase = new DefaultPlanPhasePriceOverride(plan.getFinalPhase().getName(), Currency.USD, null, null, usagePriceOverrides); overrides.add(phase); assertEquals(m.group(1), plan.getName()); assertEquals(overriddenPlan.getProduct().getName(), plan.getProduct().getName()); assertEquals(overriddenPlan.getRecurringBillingPeriod(), plan.getRecurringBillingPeriod()); if (plan.getEffectiveDateForExistingSubscriptions() != null) { assertEquals(overriddenPlan.getEffectiveDateForExistingSubscriptions().compareTo(plan.getEffectiveDateForExistingSubscriptions()), 0); assertNotEquals(overriddenPlan.getFinalPhase().getName(), plan.getFinalPhase().getName()); final DefaultUsage initialUsage = (DefaultUsage) plan.getFinalPhase().getUsages()[i]; final DefaultUsage newUsage = (DefaultUsage) overriddenPlan.getFinalPhase().getUsages()[i];
assertEquals(plan.getName(), "dynamic-monthly"); assertEquals(plan.getPriceListName(), DefaultPriceListSet.DEFAULT_PRICELIST_NAME); assertEquals(plan.getProduct().getName(), "Dynamic"); assertEquals(plan.getProduct().getCategory(), ProductCategory.BASE); assertEquals(plan.getInitialPhases().length, 1); assertEquals(plan.getInitialPhases()[0].getName(), "dynamic-monthly-trial"); assertEquals(plan.getInitialPhases()[0].getPhaseType(), PhaseType.TRIAL); assertEquals(plan.getInitialPhases()[0].getFixed().getPrice().getPrices().length, 1); assertEquals(plan.getInitialPhases()[0].getFixed().getPrice().getPrices()[0].getCurrency(), Currency.USD); assertEquals(plan.getInitialPhases()[0].getFixed().getPrice().getPrices()[0].getValue(), BigDecimal.ZERO); assertEquals(plan.getFinalPhase().getName(), "dynamic-monthly-evergreen"); assertEquals(plan.getFinalPhase().getPhaseType(), PhaseType.EVERGREEN); assertEquals(plan.getFinalPhase().getRecurring().getBillingPeriod(), BillingPeriod.MONTHLY); assertEquals(plan.getFinalPhase().getRecurring().getRecurringPrice().getPrices().length, 1); assertEquals(plan.getFinalPhase().getRecurring().getRecurringPrice().getPrices()[0].getCurrency(), Currency.USD); assertEquals(plan.getFinalPhase().getRecurring().getRecurringPrice().getPrices()[0].getValue(), BigDecimal.TEN);
private Iterable<Plan> toDefaultPlans(final StaticCatalog staticCatalog, final Iterable<Plan> input) { if (tmpDefaultPlans == null) { final Map<String, Plan> map = new HashMap<String, Plan>(); for (final Plan plan : input) map.put(plan.getName(), toDefaultPlan(staticCatalog, plan)); tmpDefaultPlans = map; } return tmpDefaultPlans.values(); }
@Test(groups = "fast") public void testAddExistingPlanWithNewCurrency() throws Exception { final StandaloneCatalog originalCatalog = XMLLoader.getObjectFromString(Resources.getResource("SpyCarBasic.xml").toExternalForm(), StandaloneCatalog.class); assertEquals(originalCatalog.getPriceLists().getAllPriceLists().size(), 1); assertEquals(originalCatalog.getPriceLists().getAllPriceLists().get(0).getName(), new PriceListDefault().getName()); assertEquals(originalCatalog.getPriceLists().getAllPriceLists().get(0).getPlans().size(), 3); final CatalogUpdater catalogUpdater = new CatalogUpdater(originalCatalog); final SimplePlanDescriptor desc = new DefaultSimplePlanDescriptor("standard-monthly", "Standard", ProductCategory.BASE, Currency.EUR, BigDecimal.TEN, BillingPeriod.MONTHLY, 30, TimeUnit.DAYS, ImmutableList.<String>of()); catalogUpdater.addSimplePlanDescriptor(desc); final StandaloneCatalog catalog = catalogUpdater.getCatalog(); final Plan plan = catalog.findCurrentPlan("standard-monthly"); assertEquals(plan.getName(), "standard-monthly"); assertEquals(plan.getInitialPhases().length, 1); assertEquals(plan.getInitialPhases()[0].getPhaseType(), PhaseType.TRIAL); assertEquals(plan.getInitialPhases()[0].getFixed().getPrice().getPrices().length, 0); assertEquals(plan.getInitialPhases()[0].getFixed().getPrice().getPrice(Currency.EUR), BigDecimal.ZERO); assertEquals(plan.getInitialPhases()[0].getName(), "standard-monthly-trial"); assertEquals(plan.getFinalPhase().getPhaseType(), PhaseType.EVERGREEN); assertNull(plan.getFinalPhase().getFixed()); assertEquals(plan.getFinalPhase().getName(), "standard-monthly-evergreen"); assertEquals(plan.getFinalPhase().getRecurring().getBillingPeriod(), BillingPeriod.MONTHLY); assertEquals(plan.getFinalPhase().getRecurring().getRecurringPrice().getPrices().length, 3); assertEquals(plan.getFinalPhase().getRecurring().getRecurringPrice().getPrice(Currency.EUR), BigDecimal.TEN); }
planPhaseName = phaseEV.getPhase(); phaseType = prevPlan != null ? prevPlan.findPhase(phaseEV.getPhase()).getPhaseType() : null; plan = prevPlan; productName = prevProductName; planPhaseName = userEV.getEventPlanPhase(); plan = (userEV.getEventPlan() != null) ? catalog.findPlan(userEV.getEventPlan(), cur.getEffectiveDate(), startDate) : null; phaseType = (plan != null && userEV.getEventPlanPhase() != null) ? plan.findPhase(userEV.getEventPlanPhase()).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; final String planNameWithClosure = plan != null ? plan.getName() : null; final String planPhaseNameWithClosure = planPhaseName; final Integer billCycleDayLocalWithClosure = billCycleDayLocal;
@Override public DateTime getDryRunChangePlanEffectiveDate(final SubscriptionBase subscription, final EntitlementSpecifier spec, final DateTime requestedDateWithMs, final BillingActionPolicy requestedPolicy, final InternalCallContext context) throws SubscriptionBaseApiException, CatalogApiException { final TenantContext tenantContext = internalCallContextFactory.createTenantContext(context); final CallContext callContext = internalCallContextFactory.createCallContext(context); // verify the number of subscriptions (of the same kind) allowed per bundle final Catalog catalog = catalogInternalApi.getFullCatalog(true, true, context); final DateTime effectiveDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : null; final DateTime effectiveCatalogDate = effectiveDate != null ? effectiveDate : context.getCreatedDate(); final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(spec.getOverrides(), callContext); final Plan plan = catalog.createOrFindPlan(spec.getPlanPhaseSpecifier(), overridesWithContext, effectiveCatalogDate, subscription.getStartDate()); if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(plan.getProduct().getCategory().toString())) { if (plan.getPlansAllowedInBundle() != -1 && plan.getPlansAllowedInBundle() > 0 && addonUtils.countExistingAddOnsWithSamePlanName(getSubscriptionsForBundle(subscription.getBundleId(), null, catalog, addonUtils, callContext, context), plan.getName()) >= plan.getPlansAllowedInBundle()) { // the plan can be changed to the new value, because it has reached its limit by bundle throw new SubscriptionBaseApiException(ErrorCode.SUB_CHANGE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE, plan.getName()); } } return apiService.dryRunChangePlan((DefaultSubscriptionBase) subscription, spec, effectiveDate, requestedPolicy, tenantContext); }
private boolean isStandaloneSpecifier(final Plan inputPlan) { return inputPlan.getProduct().getCategory() == ProductCategory.STANDALONE; }
DateTime curPhaseStart = (initialPhase == null) ? initialPhaseStartDate : null; DateTime nextPhaseStart; for (final PlanPhase cur : plan.getAllPhases()) { if (nextPhaseStart == null) { throw new SubscriptionBaseError(String.format("Unexpected non ending UNLIMITED phase for plan %s", plan.getName()));
if (from.getPlanName() != null) { final Plan plan = catalog.findCurrentPlan(from.getPlanName()); inFromProduct = plan.getProduct(); inFromBillingPeriod = plan.getRecurringBillingPeriod(); inFromProductCategory = plan.getProduct().getCategory(); inFromPriceList = catalog.findCurrentPricelist(plan.getPriceListName()); } else { inFromProduct = catalog.findCurrentProduct(from.getProductName()); if (to.getPlanName() != null) { final Plan plan = catalog.findCurrentPlan(to.getPlanName()); inToProduct = plan.getProduct(); inToBillingPeriod = plan.getRecurringBillingPeriod(); inToProductCategory = plan.getProduct().getCategory(); inToPriceList = catalog.findCurrentPricelist(plan.getPriceListName()); } else { inToProduct = catalog.findCurrentProduct(to.getProductName());
public PlanJson(final Plan plan) throws CurrencyValueNull { final List<PhaseJson> phases = new LinkedList<PhaseJson>(); for (final PlanPhase phase : plan.getAllPhases()) { final PhaseJson phaseJson = new PhaseJson(phase); phases.add(phaseJson); } this.name = plan.getName(); this.prettyName = plan.getPrettyName(); this.billingPeriod = plan.getRecurringBillingPeriod(); this.phases = phases; }
@Test(groups = "slow") public void testOverrideLastPhase() throws Exception { final StandaloneCatalog catalog = XMLLoader.getObjectFromString(Resources.getResource("SpyCarBasic.xml").toExternalForm(), StandaloneCatalog.class); final Plan plan = catalog.findCurrentPlan("standard-monthly"); final PlanPhasePriceOverride[] resolvedOverrides = new PlanPhasePriceOverride[plan.getAllPhases().length]; resolvedOverrides[0] = null; resolvedOverrides[1] = new DefaultPlanPhasePriceOverride(plan.getFinalPhase().getName(), Currency.USD, null, new BigDecimal("128.76"), null); final CatalogOverridePlanDefinitionModelDao newPlan = catalogOverrideDao.getOrCreateOverridePlanDefinition(plan, new DateTime(catalog.getEffectiveDate()), resolvedOverrides, internalCallContext); assertEquals(newPlan.getParentPlanName(), "standard-monthly"); assertTrue(newPlan.getIsActive()); }
final Plan plan = catalog.findPlan(planName, createdDate); if (plan != null) { prettyPlanName = plan.getPrettyName(); Preconditions.checkState(plan.getProduct().getName().equals(productName)); prettyProductName = plan.getProduct().getPrettyName(); final PlanPhase planPhase = plan.findPhase(phaseName); if (planPhase != null) { prettyPlanPhaseName = planPhase.getPrettyName();
private PlanPhaseSpecifier getPlanPhaseSpecifierFromTransition(final Catalog catalog, final SubscriptionInternalEvent transition) throws CatalogApiException { final Plan prevPlan = (transition.getPreviousPlan() != null) ? catalog.findPlan(transition.getPreviousPlan(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null; final Plan nextPlan = (transition.getNextPlan() != null) ? catalog.findPlan(transition.getNextPlan(), transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null; final Plan plan = (transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ? nextPlan : prevPlan; final PlanPhase prevPhase = prevPlan != null && transition.getPreviousPhase() != null ? prevPlan.findPhase(transition.getPreviousPhase()) : null; final PlanPhase nextPhase = nextPlan != null && transition.getNextPhase() != null ? nextPlan.findPhase(transition.getNextPhase()) : null; final PlanPhase phase = (transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ? nextPhase : prevPhase; return new PlanPhaseSpecifier(plan.getName(), phase.getPhaseType()); }
@Override public BillingPeriod getLastActiveBillingPeriod() { if (getState() == EntitlementState.CANCELLED) { final SubscriptionBaseTransition data = getPreviousTransition(); return data.getPreviousPlan().getRecurringBillingPeriod(); } else if (getState() == EntitlementState.PENDING) { final SubscriptionBaseTransition data = getPendingTransition(); return data.getNextPlan().getRecurringBillingPeriod(); } else { final Plan currentPlan = getCurrentPlan(); // currentPlan can be null when playing with the clock (subscription created in the future) return currentPlan.getRecurringBillingPeriod(); } }