Search in sources :

Example 91 with BillingPeriod

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

the class TestCatalogRetireElements method testChangePlanTwiceWithNewPlan.

@Test(groups = "slow", description = "See https://github.com/killbill/killbill/issues/1110")
public void testChangePlanTwiceWithNewPlan() throws Exception {
    // Catalog v1 starts in 2011-01-01
    // Catalog v2 starts in 2015-12-01
    // -> Start on catalog V1
    final LocalDate today = new LocalDate(2015, 11, 5);
    // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
    clock.setDay(today);
    final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(null));
    final String productName = "Shotgun";
    final BillingPeriod term = BillingPeriod.MONTHLY;
    final PlanPhaseSpecifier spec1 = new PlanPhaseSpecifier(productName, term, "DEFAULT", null);
    busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
    final UUID bpEntitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec1), "externalKey", null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
    assertListenerStatus();
    Entitlement bpEntitlement = entitlementApi.getEntitlementForId(bpEntitlementId, callContext);
    // Move out a month. Date > catalog V2
    busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addMonths(1);
    assertListenerStatus();
    // Current date is > catalog V2
    // Change to a plan that exists in V2 but not in V1
    final PlanPhaseSpecifier spec2 = new PlanPhaseSpecifier("bazooka-monthly", null);
    busHandler.pushExpectedEvents(NextEvent.CHANGE, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
    bpEntitlement = bpEntitlement.changePlanWithDate(new DefaultEntitlementSpecifier(spec2), clock.getUTCToday(), ImmutableList.<PluginProperty>of(), callContext);
    assertListenerStatus();
    // Change back to original plan: The code (subscription) chooses the latest version of the catalog when making the change and therefore the call succeeds
    busHandler.pushExpectedEvents(NextEvent.CHANGE, NextEvent.INVOICE);
    bpEntitlement.changePlanWithDate(new DefaultEntitlementSpecifier(spec1), clock.getUTCToday(), ImmutableList.<PluginProperty>of(), callContext);
    assertListenerStatus();
    // 
    // The code normally goes through the grandfathering logic to find the version but specifies the transitionTime of the latest CHANGE (and not the subscriptionStartDate)
    // and therefore correctly find the latest catalog version, invoicing at the new price 295.95
    // 
    Invoice curInvoice = invoiceChecker.checkInvoice(account.getId(), 4, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2015, 12, 5), new LocalDate(2016, 1, 5), InvoiceItemType.RECURRING, new BigDecimal("295.95")), new ExpectedInvoiceItemCheck(new LocalDate(2015, 12, 5), new LocalDate(2016, 1, 5), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-500.00")), new ExpectedInvoiceItemCheck(new LocalDate(2015, 12, 5), new LocalDate(2015, 12, 5), InvoiceItemType.CBA_ADJ, new BigDecimal("204.05")));
    final VersionedCatalog catalog = catalogUserApi.getCatalog("foo", callContext);
    // RECURRING should be set against V2
    Assert.assertEquals(curInvoice.getInvoiceItems().get(0).getCatalogEffectiveDate().toDate().compareTo(catalog.getVersions().get(1).getEffectiveDate()), 0);
    Assert.assertNull(curInvoice.getInvoiceItems().get(1).getCatalogEffectiveDate());
    Assert.assertNull(curInvoice.getInvoiceItems().get(2).getCatalogEffectiveDate());
    final Subscription bpSubscription = subscriptionApi.getSubscriptionForEntitlementId(bpEntitlementId, callContext);
    final List<SubscriptionEvent> events = bpSubscription.getSubscriptionEvents();
    // We are seeing START_ENTITLEMENT, START_BILLING, and the **last CHANGE**
    // Note that the PHASE and intermediate CHANGE are not being returned (is_active = '0') because all coincided on the same date. This is debatable
    // whether this is a good semantics. See #1030
    assertEquals(events.size(), 3);
    // Verify what we return is the price from the correct catalog version. See #1120
    assertEquals(events.get(2).getNextPhase().getRecurring().getRecurringPrice().getPrice(account.getCurrency()).compareTo(new BigDecimal("295.95")), 0);
}
Also used : PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) SubscriptionEvent(org.killbill.billing.entitlement.api.SubscriptionEvent) Account(org.killbill.billing.account.api.Account) Invoice(org.killbill.billing.invoice.api.Invoice) BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) LocalDate(org.joda.time.LocalDate) ExpectedInvoiceItemCheck(org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck) BigDecimal(java.math.BigDecimal) DefaultEntitlementSpecifier(org.killbill.billing.entitlement.api.DefaultEntitlementSpecifier) PluginProperty(org.killbill.billing.payment.api.PluginProperty) VersionedCatalog(org.killbill.billing.catalog.api.VersionedCatalog) UUID(java.util.UUID) DefaultEntitlement(org.killbill.billing.entitlement.api.DefaultEntitlement) Entitlement(org.killbill.billing.entitlement.api.Entitlement) Subscription(org.killbill.billing.entitlement.api.Subscription) Test(org.testng.annotations.Test)

Example 92 with BillingPeriod

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

the class TestCatalogRetireElements method testRetireProduct.

@Test(groups = "slow")
public void testRetireProduct() throws Exception {
    // Catalog v1 starts in 2011-01-01
    // Catalog v3 starts in 2016-01-01
    final LocalDate today = new LocalDate(2015, 11, 5);
    // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
    clock.setDay(today);
    final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
    // accountUserApi.createAccount(getAccountData(1), callContext);
    final String productName = "Pistol";
    final BillingPeriod term = BillingPeriod.MONTHLY;
    final DefaultEntitlement bpEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
    assertNotNull(bpEntitlement);
    assertEquals(invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext).size(), 1);
    assertEquals(bpEntitlement.getSubscriptionBase().getCurrentPlan().getRecurringBillingPeriod(), BillingPeriod.MONTHLY);
    // Move out a month.
    busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addMonths(1);
    assertListenerStatus();
    // Move out a month.
    busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addMonths(1);
    assertListenerStatus();
    // Catalog v3 should start now.
    final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, term, PriceListSet.DEFAULT_PRICELIST_NAME, null);
    try {
        entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), "externalKey2", null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
        // force to fail is there is not an exception
        fail();
    } catch (final EntitlementApiException e) {
        assertTrue(e.getLocalizedMessage().startsWith("Could not find any product named 'Pistol'"));
    }
    // Move out a month and verify 'Pistol' plan continue working as expected.
    busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addMonths(1);
    assertListenerStatus();
    final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext);
    assertEquals(invoices.size(), 4);
    for (final Invoice invoice : invoices) {
        assertEquals(invoice.getInvoiceItems().get(0).getPlanName(), "pistol-monthly");
    }
}
Also used : PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) DefaultEntitlementSpecifier(org.killbill.billing.entitlement.api.DefaultEntitlementSpecifier) Account(org.killbill.billing.account.api.Account) Invoice(org.killbill.billing.invoice.api.Invoice) BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) DefaultEntitlement(org.killbill.billing.entitlement.api.DefaultEntitlement) EntitlementApiException(org.killbill.billing.entitlement.api.EntitlementApiException) LocalDate(org.joda.time.LocalDate) Test(org.testng.annotations.Test)

Example 93 with BillingPeriod

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

the class TestCatalogRetireElements method testRetirePlan.

@Test(groups = "slow")
public void testRetirePlan() throws Exception {
    // Catalog v1 starts in 2011-01-01
    // Catalog v2 starts in 2015-12-01
    final LocalDate today = new LocalDate(2015, 11, 5);
    // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
    clock.setDay(today);
    final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
    // accountUserApi.createAccount(getAccountData(1), callContext);
    final String productName = "Pistol";
    final BillingPeriod term = BillingPeriod.MONTHLY;
    final DefaultEntitlement bpEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
    assertNotNull(bpEntitlement);
    assertEquals(invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext).size(), 1);
    assertEquals(bpEntitlement.getSubscriptionBase().getCurrentPlan().getRecurringBillingPeriod(), BillingPeriod.MONTHLY);
    // Move out a month.
    busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addMonths(1);
    assertListenerStatus();
    // Catalog v2 should start now.
    final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, term, PriceListSet.DEFAULT_PRICELIST_NAME, null);
    try {
        entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), "externalKey2", null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
        // force to fail is there is not an exception
        fail();
    } catch (final EntitlementApiException e) {
        assertEquals(e.getCode(), ErrorCode.CAT_PLAN_NOT_FOUND.getCode());
    }
    final DefaultEntitlement bpEntitlement2 = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey2", "Bazooka", ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    assertNotNull(bpEntitlement2);
    // Move out a month and verify 'Pistol' plan continue working as expected.
    busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addMonths(1);
    assertListenerStatus();
    List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext);
    assertEquals(invoices.size(), 4);
    // One more invoice to generate an item whose effectiveDate is past our original V1 version
    // and verify we still know how to compute the pretty name by finding the right initial
    // catalog version -- as pistol-monthly was retired on V1
    busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addMonths(1);
    assertListenerStatus();
    invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext);
    assertEquals(invoices.size(), 5);
    final Invoice fifthInvoice = invoices.get(4);
    assertEquals(fifthInvoice.getInvoiceItems().size(), 2);
    final InvoiceItem pistolInvoiceItem = Iterables.find(fifthInvoice.getInvoiceItems(), new Predicate<InvoiceItem>() {

        @Override
        public boolean apply(final InvoiceItem input) {
            return "pistol-monthly".equals(input.getPlanName());
        }
    });
    assertEquals(pistolInvoiceItem.getPrettyPlanName(), "Beretta");
}
Also used : PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) Account(org.killbill.billing.account.api.Account) Invoice(org.killbill.billing.invoice.api.Invoice) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) EntitlementApiException(org.killbill.billing.entitlement.api.EntitlementApiException) LocalDate(org.joda.time.LocalDate) DefaultEntitlementSpecifier(org.killbill.billing.entitlement.api.DefaultEntitlementSpecifier) DefaultEntitlement(org.killbill.billing.entitlement.api.DefaultEntitlement) Test(org.testng.annotations.Test)

Example 94 with BillingPeriod

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

the class TestCatalogRetireElements method testRetirePlanAfterChange.

@Test(groups = "slow")
public void testRetirePlanAfterChange() throws Exception {
    // Catalog v1 starts in 2011-01-01
    // Catalog v3 starts in 2016-01-01
    final LocalDate today = new LocalDate(2015, 7, 5);
    // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
    clock.setDay(today);
    final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(null));
    final String productName = "Pistol";
    final BillingPeriod term = BillingPeriod.MONTHLY;
    final PlanPhaseSpecifier spec1 = new PlanPhaseSpecifier(productName, term, "DEFAULT", null);
    busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
    final UUID bpEntitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec1), "externalKey", null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
    assertListenerStatus();
    Entitlement bpEntitlement = entitlementApi.getEntitlementForId(bpEntitlementId, callContext);
    assertNotNull(bpEntitlement);
    assertEquals(bpEntitlement.getLastActivePhase().getPhaseType(), PhaseType.TRIAL);
    assertEquals(invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext).size(), 1);
    // Move out after trial (2015-08-04)
    busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addDays(30);
    assertListenerStatus();
    assertEquals(entitlementApi.getEntitlementForId(bpEntitlement.getId(), callContext).getLastActivePhase().getPhaseType(), PhaseType.EVERGREEN);
    assertEquals(invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext).size(), 2);
    // 2015-08-05
    clock.addDays(1);
    assertListenerStatus();
    // Change to discount phase in SpecialDiscount pricelist (CBA generated, no payment)
    // Note that we need to trigger a CHANGE outside a TRIAL phase to generate a CHANGE event (otherwise, a CREATE is generated)
    final PlanPhaseSpecifier spec2 = new PlanPhaseSpecifier(productName, term, "SpecialDiscount", null);
    busHandler.pushExpectedEvents(NextEvent.CHANGE, NextEvent.INVOICE);
    bpEntitlement = bpEntitlement.changePlanWithDate(new DefaultEntitlementSpecifier(spec2), clock.getUTCToday(), ImmutableList.<PluginProperty>of(), callContext);
    assertListenerStatus();
    assertEquals(entitlementApi.getEntitlementForId(bpEntitlement.getId(), callContext).getLastActivePhase().getPhaseType(), PhaseType.DISCOUNT);
    assertEquals(invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext).size(), 3);
    // Move out after discount phase (happens on 2015-11-04)
    busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    // 2015-09-05
    clock.addMonths(1);
    assertListenerStatus();
    busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    // 2015-10-05
    clock.addMonths(1);
    assertListenerStatus();
    busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    // 2015-11-05
    clock.addMonths(1);
    // This verifies the PlanAligner.getNextTimedPhase codepath with a CHANGE transition type
    assertListenerStatus();
    assertEquals(entitlementApi.getEntitlementForId(bpEntitlement.getId(), callContext).getLastActivePhase().getPhaseType(), PhaseType.EVERGREEN);
    // Move out a month (2015-12-05)
    busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addMonths(1);
    assertListenerStatus();
    // Move out a month (2016-01-01)
    busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addMonths(1);
    assertListenerStatus();
    try {
        entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec2), "externalKey2", null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
        // force to fail is there is not an exception
        fail();
    } catch (final EntitlementApiException e) {
        assertEquals(e.getCode(), ErrorCode.CAT_NO_SUCH_PRODUCT.getCode());
    }
    // Move out a month and verify 'Pistol' discounted plan continues working as expected.
    busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addMonths(1);
    assertListenerStatus();
    final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext);
    assertEquals(invoices.size(), 9);
}
Also used : PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) DefaultEntitlementSpecifier(org.killbill.billing.entitlement.api.DefaultEntitlementSpecifier) Account(org.killbill.billing.account.api.Account) PluginProperty(org.killbill.billing.payment.api.PluginProperty) Invoice(org.killbill.billing.invoice.api.Invoice) BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) EntitlementApiException(org.killbill.billing.entitlement.api.EntitlementApiException) UUID(java.util.UUID) DefaultEntitlement(org.killbill.billing.entitlement.api.DefaultEntitlement) Entitlement(org.killbill.billing.entitlement.api.Entitlement) LocalDate(org.joda.time.LocalDate) Test(org.testng.annotations.Test)

Example 95 with BillingPeriod

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

the class TestPlanDetailJson method testJson.

@Test(groups = "fast")
public void testJson() throws Exception {
    final String productName = UUID.randomUUID().toString();
    final String planName = UUID.randomUUID().toString();
    final BillingPeriod billingPeriod = BillingPeriod.ANNUAL;
    final String priceListName = UUID.randomUUID().toString();
    final PlanDetailJson planDetailJason = new PlanDetailJson(productName, planName, billingPeriod, priceListName, null);
    Assert.assertEquals(planDetailJason.getProduct(), productName);
    Assert.assertEquals(planDetailJason.getPlan(), planName);
    Assert.assertEquals(planDetailJason.getFinalPhaseBillingPeriod(), billingPeriod);
    Assert.assertEquals(planDetailJason.getPriceList(), priceListName);
    Assert.assertEquals(planDetailJason.getFinalPhaseRecurringPrice(), null);
    final String asJson = mapper.writeValueAsString(planDetailJason);
    Assert.assertEquals(asJson, "{\"product\":\"" + planDetailJason.getProduct() + "\"," + "\"plan\":\"" + planDetailJason.getPlan() + "\"," + "\"priceList\":\"" + planDetailJason.getPriceList() + "\"," + "\"finalPhaseBillingPeriod\":\"" + planDetailJason.getFinalPhaseBillingPeriod().toString() + "\"," + "\"finalPhaseRecurringPrice\":null}");
    final PlanDetailJson fromJson = mapper.readValue(asJson, PlanDetailJson.class);
    Assert.assertEquals(fromJson, planDetailJason);
}
Also used : BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) Test(org.testng.annotations.Test)

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