Search in sources :

Example 41 with PlanPhase

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

the class TestUserApiCancel method testCancelSubscriptionWithInvalidRequestedDate.

@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);
}
Also used : BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) PlanPhase(org.killbill.billing.catalog.api.PlanPhase) DateTime(org.joda.time.DateTime) Interval(org.joda.time.Interval) Test(org.testng.annotations.Test)

Example 42 with PlanPhase

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

the class TestUserApiCancel method testWithMultipleCancellationEvent.

@Test(groups = "slow")
public void testWithMultipleCancellationEvent() throws SubscriptionBillingApiException, SubscriptionBaseApiException {
    final String prod = "Shotgun";
    final BillingPeriod term = BillingPeriod.MONTHLY;
    final String planSet = PriceListSet.DEFAULT_PRICELIST_NAME;
    // CREATE
    DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, prod, term, planSet);
    PlanPhase trialPhase = subscription.getCurrentPhase();
    assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
    // NEXT PHASE
    final DateTime expectedPhaseTrialChange = TestSubscriptionHelper.addDuration(subscription.getStartDate(), trialPhase.getDuration());
    testUtil.checkNextPhaseChange(subscription, 1, expectedPhaseTrialChange);
    // MOVE TO NEXT PHASE
    testListener.pushExpectedEvent(NextEvent.PHASE);
    Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
    clock.addDeltaFromReality(it.toDurationMillis());
    assertListenerStatus();
    trialPhase = subscription.getCurrentPhase();
    assertEquals(trialPhase.getPhaseType(), PhaseType.EVERGREEN);
    // SET CTD + RE READ SUBSCRIPTION + CHANGE PLAN
    final Duration ctd = testUtil.getDurationMonth(1);
    final DateTime newChargedThroughDate = TestSubscriptionHelper.addDuration(expectedPhaseTrialChange, ctd);
    subscriptionInternalApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, internalCallContext);
    subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
    assertEquals(subscription.getLastActiveProduct().getName(), prod);
    assertEquals(subscription.getLastActivePriceList().getName(), planSet);
    assertEquals(subscription.getLastActiveBillingPeriod(), term);
    assertEquals(subscription.getLastActiveCategory(), ProductCategory.BASE);
    // CANCEL
    subscription.cancel(callContext);
    assertListenerStatus();
    subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
    Assert.assertEquals(subscription.getAllTransitions().size(), 3);
    // Manually add a CANCEL event on the same EOT date as the previous one to verify the code is resilient enough to ignore it
    final SubscriptionBaseEvent cancelEvent = subscription.getEvents().get(subscription.getEvents().size() - 1);
    final SubscriptionEventModelDao newCancelEvent = new SubscriptionEventModelDao(cancelEvent);
    newCancelEvent.setId(UUID.randomUUID());
    final Handle handle = dbi.open();
    final SubscriptionEventSqlDao sqlDao = handle.attach(SubscriptionEventSqlDao.class);
    try {
        sqlDao.create(newCancelEvent, internalCallContext);
    } catch (EntityPersistenceException e) {
        Assert.fail(e.getMessage());
    }
    subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
    // The extra cancel event is being ignored
    Assert.assertEquals(subscription.getEvents().size(), 3);
    Assert.assertEquals(subscription.getAllTransitions().size(), 3);
    // We expect only one CANCEL event, this other one is skipped
    testListener.pushExpectedEvents(NextEvent.CANCEL);
    it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
    clock.addDeltaFromReality(it.toDurationMillis());
    assertListenerStatus();
    // Our previous transition should be a CANCEL with a valid previous plan
    final SubscriptionBaseTransition previousTransition = subscription.getPreviousTransition();
    Assert.assertEquals(previousTransition.getPreviousState(), EntitlementState.ACTIVE);
    Assert.assertNotNull(previousTransition.getPreviousPlan());
}
Also used : BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) Duration(org.killbill.billing.catalog.api.Duration) SubscriptionEventModelDao(org.killbill.billing.subscription.engine.dao.model.SubscriptionEventModelDao) DateTime(org.joda.time.DateTime) Handle(org.skife.jdbi.v2.Handle) SubscriptionEventSqlDao(org.killbill.billing.subscription.engine.dao.SubscriptionEventSqlDao) PlanPhase(org.killbill.billing.catalog.api.PlanPhase) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) EntityPersistenceException(org.killbill.billing.entity.EntityPersistenceException) Interval(org.joda.time.Interval) Test(org.testng.annotations.Test)

Example 43 with PlanPhase

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

the class TestUserApiCancel method testCancelSubscriptionEOTWithNoChargeThroughDate.

@Test(groups = "slow")
public void testCancelSubscriptionEOTWithNoChargeThroughDate() 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 trialPhase = subscription.getCurrentPhase();
    assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
    // NEXT PHASE
    final DateTime expectedPhaseTrialChange = TestSubscriptionHelper.addDuration(subscription.getStartDate(), trialPhase.getDuration());
    testUtil.checkNextPhaseChange(subscription, 1, expectedPhaseTrialChange);
    // MOVE TO NEXT PHASE
    testListener.pushExpectedEvent(NextEvent.PHASE);
    final Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
    clock.addDeltaFromReality(it.toDurationMillis());
    assertListenerStatus();
    trialPhase = subscription.getCurrentPhase();
    assertEquals(trialPhase.getPhaseType(), PhaseType.EVERGREEN);
    testListener.pushExpectedEvent(NextEvent.CANCEL);
    // CANCEL
    subscription.cancel(callContext);
    assertListenerStatus();
    final PlanPhase currentPhase = subscription.getCurrentPhase();
    assertNull(currentPhase);
    testUtil.checkNextPhaseChange(subscription, 0, null);
    assertListenerStatus();
}
Also used : BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) PlanPhase(org.killbill.billing.catalog.api.PlanPhase) DateTime(org.joda.time.DateTime) Interval(org.joda.time.Interval) Test(org.testng.annotations.Test)

Example 44 with PlanPhase

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

the class TestUserApiChangePlan method tChangePlanBundleAlignEOTWithNoChargeThroughDate.

private void tChangePlanBundleAlignEOTWithNoChargeThroughDate(final String fromProd, final BillingPeriod fromTerm, final String fromPlanSet, final String toProd, final BillingPeriod toTerm, final String toPlanSet) {
    try {
        // CREATE
        final DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, fromProd, fromTerm, fromPlanSet);
        // MOVE TO NEXT PHASE
        PlanPhase currentPhase = subscription.getCurrentPhase();
        testListener.pushExpectedEvent(NextEvent.PHASE);
        final Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(31));
        clock.addDeltaFromReality(it.toDurationMillis());
        final DateTime futureNow = clock.getUTCNow();
        final DateTime nextExpectedPhaseChange = TestSubscriptionHelper.addDuration(subscription.getStartDate(), currentPhase.getDuration());
        assertTrue(futureNow.isAfter(nextExpectedPhaseChange));
        assertListenerStatus();
        // CHANGE PLAN
        testListener.pushExpectedEvent(NextEvent.CHANGE);
        subscription.changePlan(new PlanSpecifier(toProd, toTerm, toPlanSet), null, callContext);
        assertListenerStatus();
        // CHECK CHANGE PLAN
        currentPhase = subscription.getCurrentPhase();
        checkChangePlan(subscription, toProd, ProductCategory.BASE, toTerm, PhaseType.EVERGREEN);
        assertListenerStatus();
    } catch (SubscriptionBaseApiException e) {
        Assert.fail(e.getMessage());
    }
}
Also used : PlanPhase(org.killbill.billing.catalog.api.PlanPhase) DateTime(org.joda.time.DateTime) Interval(org.joda.time.Interval) PlanSpecifier(org.killbill.billing.catalog.api.PlanSpecifier)

Example 45 with PlanPhase

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

the class TestInvoiceDispatcher method testWithParking.

@Test(groups = "slow")
public void testWithParking() throws InvoiceApiException, AccountApiException, CatalogApiException, SubscriptionBaseApiException, TagDefinitionApiException {
    final UUID accountId = account.getId();
    final BillingEventSet events = new MockBillingEventSet();
    final Plan plan = MockPlan.createBicycleNoTrialEvergreen1USD();
    final PlanPhase planPhase = MockPlanPhase.create1USDMonthlyEvergreen();
    final DateTime effectiveDate = clock.getUTCNow().minusDays(1);
    final Currency currency = Currency.USD;
    final BigDecimal fixedPrice = null;
    events.add(invoiceUtil.createMockBillingEvent(account, subscription, effectiveDate, plan, planPhase, fixedPrice, BigDecimal.ONE, currency, BillingPeriod.MONTHLY, 1, BillingMode.IN_ADVANCE, "", 1L, SubscriptionBaseTransitionType.CREATE));
    Mockito.when(billingApi.getBillingEventsForAccountAndUpdateAccountBCD(Mockito.<UUID>any(), Mockito.<DryRunArguments>any(), Mockito.<InternalCallContext>any())).thenReturn(events);
    final LocalDate target = internalCallContext.toLocalDate(effectiveDate);
    final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
    final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi, invoiceDao, internalCallContextFactory, invoiceNotifier, invoicePluginDispatcher, locker, busService.getBus(), null, invoiceConfig, clock, parkedAccountsManager);
    // Verify initial tags state for account
    Assert.assertTrue(tagUserApi.getTagsForAccount(accountId, true, callContext).isEmpty());
    // Create chaos on disk
    final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(accountId, target, target, currency, false);
    final InvoiceItemModelDao invoiceItemModelDao1 = new InvoiceItemModelDao(clock.getUTCNow(), InvoiceItemType.RECURRING, invoiceModelDao.getId(), accountId, subscription.getBundleId(), subscription.getId(), "Bad data", plan.getName(), planPhase.getName(), null, effectiveDate.toLocalDate(), effectiveDate.plusMonths(1).toLocalDate(), BigDecimal.TEN, BigDecimal.ONE, currency, null);
    final InvoiceItemModelDao invoiceItemModelDao2 = new InvoiceItemModelDao(clock.getUTCNow(), InvoiceItemType.RECURRING, invoiceModelDao.getId(), accountId, subscription.getBundleId(), subscription.getId(), "Bad data", plan.getName(), planPhase.getName(), null, effectiveDate.plusDays(1).toLocalDate(), effectiveDate.plusMonths(1).toLocalDate(), BigDecimal.TEN, BigDecimal.ONE, currency, null);
    invoiceModelDao.addInvoiceItem(invoiceItemModelDao1);
    invoiceModelDao.addInvoiceItem(invoiceItemModelDao2);
    invoiceDao.createInvoices(ImmutableList.<InvoiceModelDao>of(invoiceModelDao), context);
    try {
        dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, new DryRunFutureDateArguments(), context);
        Assert.fail();
    } catch (final InvoiceApiException e) {
        Assert.assertEquals(e.getCode(), ErrorCode.UNEXPECTED_ERROR.getCode());
        Assert.assertTrue(e.getCause().getMessage().startsWith("Double billing detected"));
    }
    // Dry-run: no side effect on disk
    Assert.assertEquals(invoiceDao.getInvoicesByAccount(context).size(), 1);
    Assert.assertTrue(tagUserApi.getTagsForAccount(accountId, true, callContext).isEmpty());
    try {
        dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, null, context);
        Assert.fail();
    } catch (final InvoiceApiException e) {
        Assert.assertEquals(e.getCode(), ErrorCode.UNEXPECTED_ERROR.getCode());
        Assert.assertTrue(e.getCause().getMessage().startsWith("Double billing detected"));
    }
    Assert.assertEquals(invoiceDao.getInvoicesByAccount(context).size(), 1);
    // No dry-run: account is parked
    final List<Tag> tags = tagUserApi.getTagsForAccount(accountId, false, callContext);
    Assert.assertEquals(tags.size(), 1);
    Assert.assertEquals(tags.get(0).getTagDefinitionId(), SystemTags.PARK_TAG_DEFINITION_ID);
    // isApiCall=false
    final Invoice nullInvoice1 = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, null, context);
    Assert.assertNull(nullInvoice1);
    // No dry-run and isApiCall=true
    try {
        dispatcher.processAccount(true, accountId, target, null, context);
        Assert.fail();
    } catch (final InvoiceApiException e) {
        Assert.assertEquals(e.getCode(), ErrorCode.UNEXPECTED_ERROR.getCode());
        Assert.assertTrue(e.getCause().getMessage().startsWith("Double billing detected"));
    }
    // Idempotency
    Assert.assertEquals(invoiceDao.getInvoicesByAccount(context).size(), 1);
    Assert.assertEquals(tagUserApi.getTagsForAccount(accountId, false, callContext), tags);
    // Fix state
    dbi.withHandle(new HandleCallback<Void>() {

        @Override
        public Void withHandle(final Handle handle) throws Exception {
            handle.execute("delete from invoices");
            handle.execute("delete from invoice_items");
            return null;
        }
    });
    // Dry-run and isApiCall=false: still parked
    final Invoice nullInvoice2 = dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, new DryRunFutureDateArguments(), context);
    Assert.assertNull(nullInvoice2);
    // Dry-run and isApiCall=true: call goes through
    final Invoice invoice1 = dispatcher.processAccount(true, accountId, target, new DryRunFutureDateArguments(), context);
    Assert.assertNotNull(invoice1);
    Assert.assertEquals(invoiceDao.getInvoicesByAccount(context).size(), 0);
    // Dry-run: still parked
    Assert.assertEquals(tagUserApi.getTagsForAccount(accountId, false, callContext).size(), 1);
    // No dry-run and isApiCall=true: call goes through
    final Invoice invoice2 = dispatcher.processAccount(true, accountId, target, null, context);
    Assert.assertNotNull(invoice2);
    Assert.assertEquals(invoiceDao.getInvoicesByAccount(context).size(), 1);
    // No dry-run: now unparked
    Assert.assertEquals(tagUserApi.getTagsForAccount(accountId, false, callContext).size(), 0);
    Assert.assertEquals(tagUserApi.getTagsForAccount(accountId, true, callContext).size(), 1);
}
Also used : Invoice(org.killbill.billing.invoice.api.Invoice) NullInvoiceNotifier(org.killbill.billing.invoice.notification.NullInvoiceNotifier) InvoiceNotifier(org.killbill.billing.invoice.api.InvoiceNotifier) InvoiceModelDao(org.killbill.billing.invoice.dao.InvoiceModelDao) MockPlan(org.killbill.billing.catalog.MockPlan) Plan(org.killbill.billing.catalog.api.Plan) LocalDate(org.joda.time.LocalDate) DateTime(org.joda.time.DateTime) BigDecimal(java.math.BigDecimal) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) AccountApiException(org.killbill.billing.account.api.AccountApiException) InvoiceApiException(org.killbill.billing.invoice.api.InvoiceApiException) TagDefinitionApiException(org.killbill.billing.util.api.TagDefinitionApiException) SubscriptionBaseApiException(org.killbill.billing.subscription.api.user.SubscriptionBaseApiException) Handle(org.skife.jdbi.v2.Handle) InvoiceApiException(org.killbill.billing.invoice.api.InvoiceApiException) NullInvoiceNotifier(org.killbill.billing.invoice.notification.NullInvoiceNotifier) InvoiceItemModelDao(org.killbill.billing.invoice.dao.InvoiceItemModelDao) BillingEventSet(org.killbill.billing.junction.BillingEventSet) Currency(org.killbill.billing.catalog.api.Currency) DryRunFutureDateArguments(org.killbill.billing.invoice.TestInvoiceHelper.DryRunFutureDateArguments) PlanPhase(org.killbill.billing.catalog.api.PlanPhase) MockPlanPhase(org.killbill.billing.catalog.MockPlanPhase) Tag(org.killbill.billing.util.tag.Tag) UUID(java.util.UUID) Test(org.testng.annotations.Test)

Aggregations

PlanPhase (org.killbill.billing.catalog.api.PlanPhase)98 Plan (org.killbill.billing.catalog.api.Plan)77 Test (org.testng.annotations.Test)71 MockPlan (org.killbill.billing.catalog.MockPlan)50 MockPlanPhase (org.killbill.billing.catalog.MockPlanPhase)49 LocalDate (org.joda.time.LocalDate)47 DateTime (org.joda.time.DateTime)43 BillingEventSet (org.killbill.billing.junction.BillingEventSet)43 BigDecimal (java.math.BigDecimal)42 BillingEvent (org.killbill.billing.junction.BillingEvent)41 MockBillingEventSet (org.killbill.billing.invoice.MockBillingEventSet)40 Invoice (org.killbill.billing.invoice.api.Invoice)39 DefaultInvoice (org.killbill.billing.invoice.model.DefaultInvoice)36 UUID (java.util.UUID)34 DefaultPrice (org.killbill.billing.catalog.DefaultPrice)22 MockInternationalPrice (org.killbill.billing.catalog.MockInternationalPrice)22 RecurringInvoiceItem (org.killbill.billing.invoice.model.RecurringInvoiceItem)22 SubscriptionBase (org.killbill.billing.subscription.api.SubscriptionBase)22 InvoiceItem (org.killbill.billing.invoice.api.InvoiceItem)21 FixedPriceInvoiceItem (org.killbill.billing.invoice.model.FixedPriceInvoiceItem)21