@Override public boolean apply(final PlanPhase input) { return input.getPhaseType() == phaseType; } });
public DefaultRecurring setPhase(final PlanPhase phase) { this.phaseType = phase.getPhaseType(); return this; }
@Override public DateTime getDateOfFirstRecurringNonZeroCharge() { final Plan initialPlan = !transitions.isEmpty() ? transitions.get(0).getNextPlan() : null; final PlanPhase initialPhase = !transitions.isEmpty() ? transitions.get(0).getNextPhase() : null; final PhaseType initialPhaseType = initialPhase != null ? initialPhase.getPhaseType() : null; return initialPlan.dateOfFirstRecurringNonZeroCharge(getStartDate(), initialPhaseType); }
@Override public boolean apply(final PlanPhasePriceOverride input) { if (input.getPhaseName() != null) { return input.getPhaseName().equals(curPhase.getName()); } // If the phaseName was not passed, we infer by matching the phaseType. This obviously would not work in a case where // a plan is defined with multiple phases of the same type. final PlanPhaseSpecifier curPlanPhaseSpecifier = input.getPlanPhaseSpecifier(); if (curPlanPhaseSpecifier.getPhaseType().equals(curPhase.getPhaseType())) { return true; } return false; } }).orNull();
private void checkChangePlan(final DefaultSubscriptionBase subscription, final String expProduct, final ProductCategory expCategory, final BillingPeriod expBillingPeriod, final PhaseType expPhase) { final Plan currentPlan = subscription.getCurrentPlan(); assertNotNull(currentPlan); assertEquals(currentPlan.getProduct().getName(), expProduct); assertEquals(currentPlan.getProduct().getCategory(), expCategory); assertEquals(currentPlan.getRecurringBillingPeriod(), expBillingPeriod); final PlanPhase currentPhase = subscription.getCurrentPhase(); assertNotNull(currentPhase); assertEquals(currentPhase.getPhaseType(), expPhase); }
private enum WhichPhase { CURRENT, NEXT }
@Test(groups = "fast") public void testChangeWithTargetPhaseType1() throws Exception { final String productName = "pistol-monthly"; final DateTime now = clock.getUTCNow(); final DateTime bundleStartDate = now; final DateTime alignStartDate = bundleStartDate; final Plan plan = catalogService.getFullCatalog(true, true, internalCallContext).findPlan(productName, clock.getUTCNow()); final TimedPhase[] phases = planAligner.getCurrentAndNextTimedPhaseOnCreate(alignStartDate, bundleStartDate, plan, null, PriceListSet.DEFAULT_PRICELIST_NAME, now, catalog, internalCallContext); Assert.assertEquals(phases.length, 2); Assert.assertEquals(phases[0].getPhase().getPhaseType(), PhaseType.TRIAL); Assert.assertEquals(phases[0].getStartPhase(), now); Assert.assertEquals(phases[1].getPhase().getPhaseType(), PhaseType.EVERGREEN); Assert.assertEquals(phases[1].getStartPhase(), now.plusDays(30)); final DefaultSubscriptionBase defaultSubscriptionBase = createSubscription(bundleStartDate, alignStartDate, productName, PhaseType.TRIAL); final String newProductName = "pistol-annual-gunclub-discount"; final Plan newPlan = catalogService.getFullCatalog(true, true, internalCallContext).findPlan(newProductName, clock.getUTCNow()); final DateTime effectiveChangeDate = defaultSubscriptionBase.getStartDate().plusDays(5); final TimedPhase currentPhase = planAligner.getCurrentTimedPhaseOnChange(defaultSubscriptionBase, newPlan, effectiveChangeDate, PhaseType.DISCOUNT, catalog, internalCallContext); // We end up straight on DISCOUNT but because we are using START_OF_SUBSCRIPTION alignment, such Phase starts with beginning of subscription Assert.assertEquals(currentPhase.getStartPhase(), alignStartDate); Assert.assertEquals(currentPhase.getPhase().getPhaseType(), PhaseType.DISCOUNT); final TimedPhase nextPhase = planAligner.getNextTimedPhaseOnChange(defaultSubscriptionBase, newPlan, effectiveChangeDate, PhaseType.DISCOUNT, catalog, internalCallContext); Assert.assertEquals(nextPhase.getStartPhase(), alignStartDate.plusMonths(6)); Assert.assertEquals(nextPhase.getPhase().getPhaseType(), PhaseType.EVERGREEN); }
@Override public boolean cancelWithPolicyNoValidationAndCatalog(final Iterable<DefaultSubscriptionBase> subscriptions, final BillingActionPolicy policy, final Catalog catalog, final InternalCallContext context) throws SubscriptionBaseApiException { final Map<DefaultSubscriptionBase, DateTime> subscriptionsWithEffectiveDate = new HashMap<DefaultSubscriptionBase, DateTime>(); try { for (final DefaultSubscriptionBase subscription : subscriptions) { final BillingAlignment billingAlignment = (subscription.getState() == EntitlementState.PENDING ? null : catalog.billingAlignment(new PlanPhaseSpecifier(subscription.getLastActivePlan().getName(), subscription.getLastActivePhase().getPhaseType()), clock.getUTCNow(), subscription.getStartDate())); final Integer accountBillCycleDayLocal = accountInternalApi.getBCD(context); final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy, billingAlignment, accountBillCycleDayLocal, context); subscriptionsWithEffectiveDate.put(subscription, effectiveDate); } return doCancelPlan(subscriptionsWithEffectiveDate, catalog, context); } catch (final CatalogApiException e) { throw new SubscriptionBaseApiException(e); } catch (final AccountApiException e) { throw new SubscriptionBaseApiException(e); } }
@Test(groups = "slow", expectedExceptions = SubscriptionBaseApiException.class) public void testCancelSubscriptionWithInvalidRequestedDate() throws SubscriptionBaseApiException { final String prod = "Shotgun"; final BillingPeriod term = BillingPeriod.MONTHLY; final String planSet = PriceListSet.DEFAULT_PRICELIST_NAME; // CREATE final DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, prod, term, planSet); PlanPhase currentPhase = subscription.getCurrentPhase(); assertEquals(currentPhase.getPhaseType(), PhaseType.TRIAL); // MOVE TO NEXT PHASE testListener.pushExpectedEvent(NextEvent.PHASE); final Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31)); clock.addDeltaFromReality(it.toDurationMillis()); assertListenerStatus(); currentPhase = subscription.getCurrentPhase(); assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN); final DateTime invalidDate = subscription.getBundleStartDate().minusDays(3); // CANCEL in EVERGREEN period with an invalid Date (prior to the Creation Date) subscription.cancelWithDate(invalidDate, callContext); }
@Test(groups = "fast") public void testCreateWithTargetPhaseType1() throws Exception { final String productName = "pistol-monthly"; final DateTime now = clock.getUTCNow(); final DateTime bundleStartDate = now; final DateTime alignStartDate = bundleStartDate; final Plan plan = catalogService.getFullCatalog(true, true, internalCallContext).findPlan(productName, clock.getUTCNow()); final TimedPhase[] phases = planAligner.getCurrentAndNextTimedPhaseOnCreate(alignStartDate, bundleStartDate, plan, PhaseType.EVERGREEN, PriceListSet.DEFAULT_PRICELIST_NAME, now, catalog, internalCallContext); Assert.assertEquals(phases.length, 2); Assert.assertEquals(phases[0].getPhase().getPhaseType(), PhaseType.EVERGREEN); Assert.assertEquals(phases[0].getStartPhase(), now); Assert.assertNull(phases[1]); final DefaultSubscriptionBase defaultSubscriptionBase = createSubscription(bundleStartDate, alignStartDate, productName, PhaseType.EVERGREEN); final String newProductName = "pistol-monthly-notrial"; final Plan newPlan = catalogService.getFullCatalog(true, true, internalCallContext).findPlan(newProductName, clock.getUTCNow()); final DateTime effectiveChangeDate = defaultSubscriptionBase.getStartDate().plusMonths(15); final TimedPhase currentPhase = planAligner.getCurrentTimedPhaseOnChange(defaultSubscriptionBase, newPlan, effectiveChangeDate, null, catalog, internalCallContext); Assert.assertEquals(currentPhase.getStartPhase(), alignStartDate); Assert.assertEquals(currentPhase.getPhase().getPhaseType(), PhaseType.EVERGREEN); }
@Test(groups = "fast") public void testCreateWithTargetPhaseType2() throws Exception { final String productName = "pistol-monthly"; final DateTime now = clock.getUTCNow(); final DateTime bundleStartDate = now; final DateTime alignStartDate = bundleStartDate; final Plan plan = catalogService.getFullCatalog(true, true, internalCallContext).findPlan(productName, clock.getUTCNow()); final TimedPhase[] phases = planAligner.getCurrentAndNextTimedPhaseOnCreate(alignStartDate, bundleStartDate, plan, PhaseType.EVERGREEN, PriceListSet.DEFAULT_PRICELIST_NAME, now, catalog, internalCallContext); Assert.assertEquals(phases.length, 2); Assert.assertEquals(phases[0].getPhase().getPhaseType(), PhaseType.EVERGREEN); Assert.assertEquals(phases[0].getStartPhase(), now); Assert.assertNull(phases[1]); final DefaultSubscriptionBase defaultSubscriptionBase = createSubscription(bundleStartDate, alignStartDate, productName, PhaseType.EVERGREEN); final String newProductName = "shotgun-monthly"; final Plan newPlan = catalogService.getFullCatalog(true, true, internalCallContext).findPlan(newProductName, clock.getUTCNow()); final DateTime effectiveChangeDate = defaultSubscriptionBase.getStartDate().plusMonths(15); final TimedPhase currentPhase = planAligner.getCurrentTimedPhaseOnChange(defaultSubscriptionBase, newPlan, effectiveChangeDate, null, catalog, internalCallContext); Assert.assertEquals(currentPhase.getStartPhase(), alignStartDate); Assert.assertEquals(currentPhase.getPhase().getPhaseType(), PhaseType.EVERGREEN); }
@Test(groups = "fast") public void testCreateWithTargetPhaseType3() throws Exception { final String productName = "pistol-monthly"; final DateTime now = clock.getUTCNow(); final DateTime bundleStartDate = now; final DateTime alignStartDate = bundleStartDate; final Plan plan = catalogService.getFullCatalog(true, true, internalCallContext).findPlan(productName, clock.getUTCNow()); final TimedPhase[] phases = planAligner.getCurrentAndNextTimedPhaseOnCreate(alignStartDate, bundleStartDate, plan, PhaseType.EVERGREEN, PriceListSet.DEFAULT_PRICELIST_NAME, now, catalog, internalCallContext); Assert.assertEquals(phases.length, 2); Assert.assertEquals(phases[0].getPhase().getPhaseType(), PhaseType.EVERGREEN); Assert.assertEquals(phases[0].getStartPhase(), now); Assert.assertNull(phases[1]); final DefaultSubscriptionBase defaultSubscriptionBase = createSubscription(bundleStartDate, alignStartDate, productName, PhaseType.EVERGREEN); final String newProductName = "assault-rifle-annual-gunclub-discount"; final Plan newPlan = catalogService.getFullCatalog(true, true, internalCallContext).findPlan(newProductName, clock.getUTCNow()); final DateTime effectiveChangeDate = defaultSubscriptionBase.getStartDate().plusMonths(15); // Because new Plan has an EVERGREEN PhaseType we end up directly on that PhaseType final TimedPhase currentPhase = planAligner.getCurrentTimedPhaseOnChange(defaultSubscriptionBase, newPlan, effectiveChangeDate, null, catalog, internalCallContext); Assert.assertEquals(currentPhase.getStartPhase(), alignStartDate); Assert.assertEquals(currentPhase.getPhase().getPhaseType(), PhaseType.EVERGREEN); }
@Test(groups = "fast") public void testCreateWithTargetPhaseType4() throws Exception { final String productName = "pistol-monthly"; final DateTime now = clock.getUTCNow(); final DateTime bundleStartDate = now; final DateTime alignStartDate = bundleStartDate; final Plan plan = catalogService.getFullCatalog(true, true, internalCallContext).findPlan(productName, clock.getUTCNow()); final TimedPhase[] phases = planAligner.getCurrentAndNextTimedPhaseOnCreate(alignStartDate, bundleStartDate, plan, PhaseType.EVERGREEN, PriceListSet.DEFAULT_PRICELIST_NAME, now, catalog, internalCallContext); Assert.assertEquals(phases.length, 2); Assert.assertEquals(phases[0].getPhase().getPhaseType(), PhaseType.EVERGREEN); Assert.assertEquals(phases[0].getStartPhase(), now); Assert.assertNull(phases[1]); final DefaultSubscriptionBase defaultSubscriptionBase = createSubscription(bundleStartDate, alignStartDate, productName, PhaseType.EVERGREEN); final String newProductName = "pistol-annual-gunclub-discount-notrial"; final Plan newPlan = catalogService.getFullCatalog(true, true, internalCallContext).findPlan(newProductName, clock.getUTCNow()); final DateTime effectiveChangeDate = defaultSubscriptionBase.getStartDate().plusMonths(15); // Because new Plan has an EVERGREEN PhaseType we end up directly on that PhaseType final TimedPhase currentPhase = planAligner.getCurrentTimedPhaseOnChange(defaultSubscriptionBase, newPlan, effectiveChangeDate, null, catalog, internalCallContext); Assert.assertEquals(currentPhase.getStartPhase(), alignStartDate); Assert.assertEquals(currentPhase.getPhase().getPhaseType(), PhaseType.EVERGREEN); }
@Override public PlanChangeResult getPlanChangeResult(final DefaultSubscriptionBase subscription, final PlanSpecifier toPlanPhase, final DateTime effectiveDate, final TenantContext context) throws SubscriptionBaseApiException { final PlanChangeResult planChangeResult; try { final InternalTenantContext internalCallContext = createTenantContextFromBundleId(subscription.getBundleId(), context); final Plan currentPlan = subscription.getCurrentOrPendingPlan(); final PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getName(), subscription.getCurrentOrPendingPhase().getPhaseType()); planChangeResult = catalogInternalApi.getFullCatalog(true, true, internalCallContext).planChange(fromPlanPhase, toPlanPhase, effectiveDate, subscription.getStartDate()); } catch (final CatalogApiException e) { throw new SubscriptionBaseApiException(e); } return planChangeResult; }
private DefaultPlanPhase toDefaultPlanPhase(final PlanPhase input) { final DefaultPlanPhase result = new DefaultPlanPhase(); result.setDuration(toDefaultDuration(input.getDuration())); result.setFixed(toDefaultFixed(input.getFixed())); result.setPhaseType(input.getPhaseType()); result.setRecurring(toDefaultRecurring(input.getRecurring())); if (input.getUsages() != null && input.getUsages().length > 0) { result.setUsages(toDefaultUsages(Arrays.asList(input.getUsages()))); } return result; }
@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; final DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, productName, term, planSetName, PhaseType.EVERGREEN, null); assertNotNull(subscription); assertEquals(subscription.getBundleExternalKey(), bundle.getExternalKey()); 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(); }
@Override public DateTime dateOfFirstRecurringNonZeroCharge(final DateTime subscriptionStartDate, final PhaseType initialPhaseType) { DateTime result = subscriptionStartDate; boolean skipPhase = initialPhaseType != null; for (final PlanPhase phase : getAllPhases()) { if (skipPhase) { if (phase.getPhaseType() != initialPhaseType) { continue; } else { skipPhase = false; } } final Recurring recurring = phase.getRecurring(); if (phase.getDuration().getUnit() != TimeUnit.UNLIMITED && (recurring == null || recurring.getRecurringPrice() == null || recurring.getRecurringPrice().isZero())) { try { result = phase.getDuration().addToDateTime(result); } catch (final CatalogApiException ignored) { } } else { break; } } return result; }
@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); }
@Test(groups = "fast") public void testAddPlanOnExistingCatalog() 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-annual", "Standard", ProductCategory.BASE, Currency.USD, BigDecimal.TEN, BillingPeriod.MONTHLY, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()); catalogUpdater.addSimplePlanDescriptor(desc); final StandaloneCatalog catalog = catalogUpdater.getCatalog(); final Plan plan = catalog.findCurrentPlan("standard-annual"); assertEquals(plan.getName(), "standard-annual"); assertEquals(plan.getInitialPhases().length, 0); assertEquals(plan.getFinalPhase().getPhaseType(), PhaseType.EVERGREEN); assertNull(plan.getFinalPhase().getFixed()); assertEquals(plan.getFinalPhase().getName(), "standard-annual-evergreen"); assertEquals(plan.getFinalPhase().getRecurring().getBillingPeriod(), BillingPeriod.MONTHLY); assertEquals(plan.getFinalPhase().getRecurring().getRecurringPrice().getPrices().length, 1); assertEquals(plan.getFinalPhase().getRecurring().getRecurringPrice().getPrices()[0].getValue(), BigDecimal.TEN); assertEquals(plan.getFinalPhase().getRecurring().getRecurringPrice().getPrices()[0].getCurrency(), Currency.USD); assertEquals(catalog.getPriceLists().getAllPriceLists().size(), 1); final PriceList priceList = catalog.getPriceLists().getAllPriceLists().get(0); assertEquals(priceList.getName(), new PriceListDefault().getName()); assertEquals(priceList.getPlans().size(), 4); }
@Test(groups = "fast") public void testOverriding() throws CatalogApiException { final DefaultProduct foo = new DefaultProduct("Foo", ProductCategory.BASE); final DefaultProduct bar = new DefaultProduct("Bar", ProductCategory.BASE); final DefaultPlan[] defaultPlans = new DefaultPlan[]{ new MockPlan().setName("plan-foo-monthly").setProduct(foo).setFinalPhase(new MockPlanPhase().setRecurring(new MockRecurring(MONTHLY, null)).setPhaseType(EVERGREEN)), new MockPlan().setName("plan-bar-monthly").setProduct(bar).setFinalPhase(new MockPlanPhase().setRecurring(new MockRecurring(MONTHLY, null)).setPhaseType(EVERGREEN)), new MockPlan().setName("plan-foo-annual").setProduct(foo).setFinalPhase(new MockPlanPhase().setRecurring(new MockRecurring(ANNUAL, null)).setPhaseType(EVERGREEN)), new MockPlan().setName("plan-bar-annual").setProduct(bar).setFinalPhase(new MockPlanPhase().setRecurring(new MockRecurring(ANNUAL, null)).setPhaseType(EVERGREEN)) }; final DefaultPlan[] childPlans = new DefaultPlan[]{ new MockPlan().setName("plan-foo").setProduct(foo).setFinalPhase(new MockPlanPhase().setRecurring(new MockRecurring(ANNUAL, null)).setPhaseType(DISCOUNT)), new MockPlan().setName("plan-bar").setProduct(bar).setFinalPhase(new MockPlanPhase().setRecurring(new MockRecurring(ANNUAL, null)).setPhaseType(DISCOUNT)) }; final PriceListDefault defaultPriceList = new PriceListDefault(defaultPlans); final DefaultPriceList[] childPriceLists = new DefaultPriceList[]{ new DefaultPriceList(childPlans, "child") }; final DefaultPriceListSet set = new DefaultPriceListSet(defaultPriceList, childPriceLists); Assert.assertEquals(set.getPlanFrom(foo, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN); Assert.assertEquals(set.getPlanFrom(foo, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN); Assert.assertEquals(set.getPlanFrom(foo, BillingPeriod.ANNUAL, "child").getFinalPhase().getPhaseType(), PhaseType.DISCOUNT); Assert.assertEquals(set.getPlanFrom(foo, BillingPeriod.MONTHLY, "child").getFinalPhase().getPhaseType(), PhaseType.EVERGREEN); }