Search in sources :

Example 96 with BillingPeriod

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

the class DefaultSubscriptionBase method getEffectiveDateForPolicy.

public DateTime getEffectiveDateForPolicy(final BillingActionPolicy policy, @Nullable final BillingAlignment alignment, @Nullable final Integer accountBillCycleDayLocal, final InternalTenantContext context) {
    final DateTime candidateResult;
    switch(policy) {
        case IMMEDIATE:
            candidateResult = clock.getUTCNow();
            break;
        case START_OF_TERM:
            if (chargedThroughDate == null) {
                candidateResult = getStartDate();
            // Will take care of billing IN_ARREAR or subscriptions that are not invoiced up to date
            } else if (!chargedThroughDate.isAfter(clock.getUTCNow())) {
                candidateResult = chargedThroughDate;
            } else {
                // In certain path (dryRun, or default catalog START_OF_TERM policy), the info is not easily available and as a result, such policy is not implemented
                Preconditions.checkState(alignment != null && context != null && accountBillCycleDayLocal != null, "START_OF_TERM not implemented in dryRun use case");
                Preconditions.checkState(alignment != BillingAlignment.BUNDLE || category != ProductCategory.ADD_ON, "START_OF_TERM not implemented for AO configured with a BUNDLE billing alignment");
                // If BCD was overriden at the subscription level, we take its latest value (it should also be reflected in the chargedThroughDate) but still required for
                // alignment purpose
                Integer bcd = getBillCycleDayLocal();
                if (bcd == null) {
                    bcd = BillCycleDayCalculator.calculateBcdForAlignment(null, this, this, alignment, context, accountBillCycleDayLocal);
                }
                final BillingPeriod billingPeriod = getLastActivePlan().getRecurringBillingPeriod();
                DateTime proposedDate = chargedThroughDate;
                while (proposedDate.isAfter(clock.getUTCNow())) {
                    proposedDate = proposedDate.minus(billingPeriod.getPeriod());
                }
                final LocalDate resultingLocalDate = BillCycleDayCalculator.alignProposedBillCycleDate(proposedDate, bcd, billingPeriod, context);
                candidateResult = context.toUTCDateTime(resultingLocalDate);
            }
            break;
        case END_OF_TERM:
            // 
            // If we have a chargedThroughDate that is 'up to date' we use it, if not default to now
            // chargedThroughDate could exist and be less than now if:
            // 1. account is not being invoiced, for e.g AUTO_INVOICING_OFF nis set
            // 2. In the case if FIXED item CTD is set using startDate of the service period
            // 
            candidateResult = (chargedThroughDate != null && chargedThroughDate.isAfter(clock.getUTCNow())) ? chargedThroughDate : clock.getUTCNow();
            break;
        default:
            throw new SubscriptionBaseError(String.format("Unexpected policy type %s", policy.toString()));
    }
    // Finally we verify we won't cancel prior the beginning of our current PHASE  -- mostly as a sanity or for test stability
    final DateTime lastTransitionTime = getCurrentPhaseStart();
    return (candidateResult.compareTo(lastTransitionTime) < 0) ? lastTransitionTime : candidateResult;
}
Also used : BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) SubscriptionBaseError(org.killbill.billing.subscription.exceptions.SubscriptionBaseError) LocalDate(org.joda.time.LocalDate) DateTime(org.joda.time.DateTime)

Example 97 with BillingPeriod

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

the class TestTransfer method testTransferBPNoTrialWithCTD.

@Test(groups = "slow")
public void testTransferBPNoTrialWithCTD() throws Exception {
    final String baseProduct = "Shotgun";
    final BillingPeriod baseTerm = BillingPeriod.MONTHLY;
    final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
    // CREATE BP
    final SubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
    // MOVE AFTER TRIAL
    testListener.pushExpectedEvent(NextEvent.PHASE);
    clock.addDays(40);
    assertListenerStatus();
    // SET CTD
    final DateTime ctd = baseSubscription.getStartDate().plusDays(30).plusMonths(1);
    setChargedThroughDate(baseSubscription.getId(), ctd, internalCallContext);
    final DateTime transferRequestedDate = clock.getUTCNow();
    testListener.pushExpectedEvent(NextEvent.TRANSFER);
    transferApi.transferBundle(bundle.getAccountId(), newAccountId, bundle.getExternalKey(), transferRequestedDate, false, false, callContext);
    assertListenerStatus();
    // CHECK OLD BASE IS CANCEL AT THE TRANSFER DATE
    final SubscriptionBase oldBaseSubscription = subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
    assertNotNull(oldBaseSubscription.getFutureEndDate());
    assertTrue(oldBaseSubscription.getFutureEndDate().compareTo(ctd) == 0);
    // CHECK NEW BUNDLE EXIST, WITH ONE SUBSCRIPTION STARTING ON TRANSFER_DATE
    final List<SubscriptionBaseBundle> bundlesForAccountAndKey = subscriptionInternalApi.getBundlesForAccountAndKey(newAccountId, bundle.getExternalKey(), internalCallContext);
    assertEquals(bundlesForAccountAndKey.size(), 1);
    final SubscriptionBaseBundle newBundle = bundlesForAccountAndKey.get(0);
    final List<SubscriptionBase> subscriptions = subscriptionInternalApi.getSubscriptionsForBundle(newBundle.getId(), null, internalCallContext);
    assertEquals(subscriptions.size(), 1);
    final SubscriptionBase newBaseSubscription = subscriptions.get(0);
    assertTrue(((DefaultSubscriptionBase) newBaseSubscription).getAlignStartDate().compareTo(((DefaultSubscriptionBase) baseSubscription).getAlignStartDate()) == 0);
    // CHECK ONLY ONE PHASE EXISTS
    assertEquals(subscriptionInternalApi.getAllTransitions(newBaseSubscription, internalCallContext).size(), 1);
    Plan newPlan = newBaseSubscription.getCurrentPlan();
    assertEquals(newPlan.getProduct().getName(), baseProduct);
    assertEquals(newBaseSubscription.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
    // MAKE A PLAN CHANGE IMM
    clock.addDays(5);
    final String newBaseProduct1 = "Assault-Rifle";
    final BillingPeriod newBaseTerm1 = BillingPeriod.ANNUAL;
    testListener.pushExpectedEvent(NextEvent.CHANGE);
    final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier(newBaseProduct1, newBaseTerm1, basePriceList);
    newBaseSubscription.changePlan(new DefaultEntitlementSpecifier(planPhaseSpecifier, null, null, null), callContext);
    assertListenerStatus();
    newPlan = newBaseSubscription.getCurrentPlan();
    assertEquals(newPlan.getProduct().getName(), newBaseProduct1);
    assertEquals(newBaseSubscription.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
    // SET CTD AND MAKE CHANGE EOT
    clock.addDays(2);
    final DateTime newCtd = newBaseSubscription.getStartDate().plusYears(1);
    setChargedThroughDate(newBaseSubscription.getId(), newCtd, internalCallContext);
    final SubscriptionBase newBaseSubscriptionWithCtd = subscriptionInternalApi.getSubscriptionFromId(newBaseSubscription.getId(), internalCallContext);
    final String newBaseProduct2 = "Pistol";
    final BillingPeriod newBaseTerm2 = BillingPeriod.ANNUAL;
    final PlanPhaseSpecifier planPhaseSpecifier1 = new PlanPhaseSpecifier(newBaseProduct2, newBaseTerm2, basePriceList);
    newBaseSubscriptionWithCtd.changePlan(new DefaultEntitlementSpecifier(planPhaseSpecifier1, null, null, null), callContext);
    newPlan = newBaseSubscriptionWithCtd.getCurrentPlan();
    assertEquals(newPlan.getProduct().getName(), newBaseProduct1);
    assertEquals(newBaseSubscriptionWithCtd.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
    assertNotNull(newBaseSubscriptionWithCtd.getPendingTransition());
    assertEquals(newBaseSubscriptionWithCtd.getPendingTransition().getEffectiveTransitionTime(), newCtd);
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) DefaultEntitlementSpecifier(org.killbill.billing.entitlement.api.DefaultEntitlementSpecifier) BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) SubscriptionBaseBundle(org.killbill.billing.subscription.api.user.SubscriptionBaseBundle) Plan(org.killbill.billing.catalog.api.Plan) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Example 98 with BillingPeriod

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

the class TestTransfer method testTransferWithUncancel.

@Test(groups = "slow")
public void testTransferWithUncancel() throws Exception {
    final String baseProduct = "Shotgun";
    final BillingPeriod baseTerm = BillingPeriod.MONTHLY;
    final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
    // CREATE BP
    SubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
    testListener.pushExpectedEvent(NextEvent.PHASE);
    clock.addDays(30);
    assertListenerStatus();
    // SET CTD TO TRIGGER CANCELLATION EOT
    final DateTime ctd = baseSubscription.getStartDate().plusDays(30).plusMonths(1);
    setChargedThroughDate(baseSubscription.getId(), ctd, internalCallContext);
    // CANCEL BP
    baseSubscription = subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
    baseSubscription.cancel(callContext);
    // MOVE CLOCK one day AHEAD AND UNCANCEL BP
    clock.addDays(1);
    testListener.pushExpectedEvent(NextEvent.UNCANCEL);
    baseSubscription.uncancel(callContext);
    assertListenerStatus();
    // MOVE CLOCK one day AHEAD AND UNCANCEL BP
    clock.addDays(1);
    final DateTime transferRequestedDate = clock.getUTCNow();
    testListener.pushExpectedEvent(NextEvent.TRANSFER);
    transferApi.transferBundle(bundle.getAccountId(), newAccountId, bundle.getExternalKey(), transferRequestedDate, true, false, callContext);
    assertListenerStatus();
    final List<SubscriptionBaseBundle> bundlesForAccountAndKey = subscriptionInternalApi.getBundlesForAccountAndKey(newAccountId, bundle.getExternalKey(), internalCallContext);
    assertEquals(bundlesForAccountAndKey.size(), 1);
    final SubscriptionBaseBundle newBundle = bundlesForAccountAndKey.get(0);
    final List<SubscriptionBase> subscriptions = subscriptionInternalApi.getSubscriptionsForBundle(newBundle.getId(), null, internalCallContext);
    assertEquals(subscriptions.size(), 1);
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) SubscriptionBaseBundle(org.killbill.billing.subscription.api.user.SubscriptionBaseBundle) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Example 99 with BillingPeriod

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

the class TestTransfer method testTransferBPInTrialWithNoCTD.

@Test(groups = "slow")
public void testTransferBPInTrialWithNoCTD() throws Exception {
    final String baseProduct = "Shotgun";
    final BillingPeriod baseTerm = BillingPeriod.MONTHLY;
    final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
    // CREATE BP
    final SubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
    final DateTime evergreenPhaseDate = ((DefaultSubscriptionBase) baseSubscription).getPendingTransition().getEffectiveTransitionTime();
    // MOVE A LITTLE, STILL IN TRIAL
    clock.addDays(20);
    final DateTime beforeTransferDate = clock.getUTCNow();
    final DateTime transferRequestedDate = clock.getUTCNow();
    testListener.pushExpectedEvent(NextEvent.TRANSFER);
    testListener.pushExpectedEvent(NextEvent.CANCEL);
    transferApi.transferBundle(bundle.getAccountId(), newAccountId, bundle.getExternalKey(), transferRequestedDate, false, false, callContext);
    assertListenerStatus();
    final DateTime afterTransferDate = clock.getUTCNow();
    // CHECK OLD BASE IS CANCEL AT THE TRANSFER DATE
    final SubscriptionBase oldBaseSubscription = subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
    assertNotNull(oldBaseSubscription.getEndDate());
    testUtil.assertDateWithin(oldBaseSubscription.getEndDate(), beforeTransferDate, afterTransferDate);
    assertTrue(oldBaseSubscription.getEndDate().compareTo(transferRequestedDate) == 0);
    // CHECK NEW BUNDLE EXIST, WITH ONE SUBSCRIPTION STARTING ON TRANSFER_DATE
    final List<SubscriptionBaseBundle> bundlesForAccountAndKey = subscriptionInternalApi.getBundlesForAccountAndKey(newAccountId, bundle.getExternalKey(), internalCallContext);
    assertEquals(bundlesForAccountAndKey.size(), 1);
    final SubscriptionBaseBundle newBundle = bundlesForAccountAndKey.get(0);
    final List<SubscriptionBase> subscriptions = subscriptionInternalApi.getSubscriptionsForBundle(newBundle.getId(), null, internalCallContext);
    assertEquals(subscriptions.size(), 1);
    final SubscriptionBase newBaseSubscription = subscriptions.get(0);
    assertTrue(((DefaultSubscriptionBase) newBaseSubscription).getAlignStartDate().compareTo(((DefaultSubscriptionBase) oldBaseSubscription).getAlignStartDate()) == 0);
    // CHECK NEXT PENDING PHASE IS ALIGNED WITH OLD SUBSCRIPTION START DATE
    assertEquals(subscriptionInternalApi.getAllTransitions(newBaseSubscription, internalCallContext).size(), 2);
    assertTrue(subscriptionInternalApi.getAllTransitions(newBaseSubscription, internalCallContext).get(1).getEffectiveTransitionTime().compareTo(evergreenPhaseDate) == 0);
    final Plan newPlan = newBaseSubscription.getCurrentPlan();
    assertEquals(newPlan.getProduct().getName(), baseProduct);
    assertEquals(newBaseSubscription.getCurrentPhase().getPhaseType(), PhaseType.TRIAL);
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) SubscriptionBaseBundle(org.killbill.billing.subscription.api.user.SubscriptionBaseBundle) Plan(org.killbill.billing.catalog.api.Plan) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Example 100 with BillingPeriod

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

the class TestUserApiAddOn method testAddonCreateInternal.

private void testAddonCreateInternal(final String aoProduct, final BillingPeriod aoTerm, final String aoPriceList, final PlanAlignmentCreate expAlignement) throws SubscriptionBaseApiException {
    final String baseProduct = "Shotgun";
    final BillingPeriod baseTerm = BillingPeriod.MONTHLY;
    final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
    // CREATE BP
    final DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
    // MOVE CLOCK 14 DAYS LATER
    Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(14));
    clock.addDeltaFromReality(it.toDurationMillis());
    // CREATE ADDON
    final DateTime beforeAOCreation = clock.getUTCNow();
    DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
    final DateTime afterAOCreation = clock.getUTCNow();
    // CHECK EVERYTHING
    Plan aoCurrentPlan = aoSubscription.getCurrentPlan();
    assertNotNull(aoCurrentPlan);
    assertEquals(aoCurrentPlan.getProduct().getName(), aoProduct);
    assertEquals(aoCurrentPlan.getProduct().getCategory(), ProductCategory.ADD_ON);
    assertEquals(aoCurrentPlan.getRecurringBillingPeriod(), aoTerm);
    PlanPhase aoCurrentPhase = aoSubscription.getCurrentPhase();
    assertNotNull(aoCurrentPhase);
    assertEquals(aoCurrentPhase.getPhaseType(), PhaseType.DISCOUNT);
    testUtil.assertDateWithin(aoSubscription.getStartDate(), beforeAOCreation, afterAOCreation);
    assertEquals(aoSubscription.getBundleStartDate().compareTo(baseSubscription.getBundleStartDate()), 0);
    // CHECK next AO PHASE EVENT IS INDEED A MONTH AFTER BP STARTED => BUNDLE ALIGNMENT
    SubscriptionBaseTransition aoPendingTranstion = aoSubscription.getPendingTransition();
    if (expAlignement == PlanAlignmentCreate.START_OF_BUNDLE) {
        assertEquals(aoPendingTranstion.getEffectiveTransitionTime(), baseSubscription.getStartDate().plusMonths(1));
    } else {
        assertEquals(aoPendingTranstion.getEffectiveTransitionTime(), aoSubscription.getStartDate().plusMonths(1));
    }
    // ADD TWO PHASE EVENTS (BP + AO)
    testListener.pushExpectedEvent(NextEvent.PHASE);
    testListener.pushExpectedEvent(NextEvent.PHASE);
    // MOVE THROUGH TIME TO GO INTO EVERGREEN
    it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(33));
    clock.addDeltaFromReality(it.toDurationMillis());
    assertListenerStatus();
    // CHECK EVERYTHING AGAIN
    aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
    aoCurrentPlan = aoSubscription.getCurrentPlan();
    assertNotNull(aoCurrentPlan);
    assertEquals(aoCurrentPlan.getProduct().getName(), aoProduct);
    assertEquals(aoCurrentPlan.getProduct().getCategory(), ProductCategory.ADD_ON);
    assertEquals(aoCurrentPlan.getRecurringBillingPeriod(), aoTerm);
    aoCurrentPhase = aoSubscription.getCurrentPhase();
    assertNotNull(aoCurrentPhase);
    assertEquals(aoCurrentPhase.getPhaseType(), PhaseType.EVERGREEN);
    aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
    aoPendingTranstion = aoSubscription.getPendingTransition();
    assertNull(aoPendingTranstion);
    assertListenerStatus();
}
Also used : BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) PlanPhase(org.killbill.billing.catalog.api.PlanPhase) Plan(org.killbill.billing.catalog.api.Plan) DateTime(org.joda.time.DateTime) Interval(org.joda.time.Interval)

Aggregations

BillingPeriod (org.killbill.billing.catalog.api.BillingPeriod)111 Test (org.testng.annotations.Test)91 LocalDate (org.joda.time.LocalDate)61 DateTime (org.joda.time.DateTime)59 DefaultEntitlement (org.killbill.billing.entitlement.api.DefaultEntitlement)45 BigDecimal (java.math.BigDecimal)44 Account (org.killbill.billing.account.api.Account)44 Invoice (org.killbill.billing.invoice.api.Invoice)40 ExpectedInvoiceItemCheck (org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck)31 Plan (org.killbill.billing.catalog.api.Plan)20 PlanPhase (org.killbill.billing.catalog.api.PlanPhase)20 Interval (org.joda.time.Interval)17 PlanPhaseSpecifier (org.killbill.billing.catalog.api.PlanPhaseSpecifier)17 UUID (java.util.UUID)15 DefaultEntitlementSpecifier (org.killbill.billing.entitlement.api.DefaultEntitlementSpecifier)15 ArrayList (java.util.ArrayList)14 Duration (org.killbill.billing.catalog.api.Duration)10 Entitlement (org.killbill.billing.entitlement.api.Entitlement)10 SubscriptionBase (org.killbill.billing.subscription.api.SubscriptionBase)10 HashMap (java.util.HashMap)9