use of org.killbill.billing.entitlement.api.Entitlement in project killbill by killbill.
the class TestIntegrationDryRunInvoice method testDryRunWithPendingSubscription.
@Test(groups = "slow")
public void testDryRunWithPendingSubscription() throws Exception {
final LocalDate initialDate = new LocalDate(2017, 4, 1);
clock.setDay(initialDate);
// Create account with no BCD
final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(null));
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
final LocalDate futureDate = new LocalDate(2017, 5, 1);
// No CREATE event as this is set in the future
final UUID createdEntitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), account.getExternalKey(), futureDate, futureDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
final Entitlement createdEntitlement = entitlementApi.getEntitlementForId(createdEntitlementId, callContext);
assertEquals(createdEntitlement.getState(), Entitlement.EntitlementState.PENDING);
assertEquals(createdEntitlement.getEffectiveStartDate().compareTo(futureDate), 0);
assertEquals(createdEntitlement.getEffectiveEndDate(), null);
assertListenerStatus();
// Generate a dryRun invoice on the billing startDate
final Invoice dryRunInvoice1 = invoiceUserApi.triggerDryRunInvoiceGeneration(createdEntitlement.getAccountId(), futureDate, DRY_RUN_TARGET_DATE_ARG, callContext);
assertEquals(dryRunInvoice1.getInvoiceItems().size(), 1);
assertEquals(dryRunInvoice1.getInvoiceItems().get(0).getInvoiceItemType(), InvoiceItemType.FIXED);
assertEquals(dryRunInvoice1.getInvoiceItems().get(0).getAmount().compareTo(BigDecimal.ZERO), 0);
assertEquals(dryRunInvoice1.getInvoiceItems().get(0).getStartDate(), futureDate);
assertEquals(dryRunInvoice1.getInvoiceItems().get(0).getPlanName(), "shotgun-annual");
// Generate a dryRun invoice with a plan change
final DryRunArguments dryRunSubscriptionActionArg = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null, SubscriptionEventType.CHANGE, createdEntitlement.getId(), createdEntitlement.getBundleId(), futureDate, BillingActionPolicy.IMMEDIATE);
// First one day prior subscription starts
try {
invoiceUserApi.triggerDryRunInvoiceGeneration(createdEntitlement.getAccountId(), futureDate.minusDays(1), dryRunSubscriptionActionArg, callContext);
fail("Should fail to trigger dryRun invoice prior subscription starts");
} catch (final InvoiceApiException e) {
assertEquals(e.getCode(), INVOICE_NOTHING_TO_DO.getCode());
}
// Second, on the startDate
final Invoice dryRunInvoice2 = invoiceUserApi.triggerDryRunInvoiceGeneration(createdEntitlement.getAccountId(), futureDate, dryRunSubscriptionActionArg, callContext);
assertEquals(dryRunInvoice2.getInvoiceItems().size(), 1);
assertEquals(dryRunInvoice2.getInvoiceItems().get(0).getInvoiceItemType(), InvoiceItemType.FIXED);
assertEquals(dryRunInvoice2.getInvoiceItems().get(0).getAmount().compareTo(BigDecimal.ZERO), 0);
assertEquals(dryRunInvoice2.getInvoiceItems().get(0).getStartDate(), futureDate);
assertEquals(dryRunInvoice2.getInvoiceItems().get(0).getPlanName(), "pistol-monthly");
// Check BCD is not yet set
final Account refreshedAccount1 = accountUserApi.getAccountById(account.getId(), callContext);
assertEquals(refreshedAccount1.getBillCycleDayLocal(), new Integer(0));
busHandler.pushExpectedEvents(NextEvent.INVOICE);
final Invoice realInvoice = invoiceUserApi.triggerInvoiceGeneration(createdEntitlement.getAccountId(), futureDate, callContext);
assertListenerStatus();
assertEquals(realInvoice.getInvoiceItems().size(), 1);
assertEquals(realInvoice.getInvoiceItems().get(0).getInvoiceItemType(), InvoiceItemType.FIXED);
assertEquals(realInvoice.getInvoiceItems().get(0).getAmount().compareTo(BigDecimal.ZERO), 0);
assertEquals(realInvoice.getInvoiceItems().get(0).getStartDate(), futureDate);
assertEquals(realInvoice.getInvoiceItems().get(0).getPlanName(), "shotgun-annual");
// Check BCD is still not set (SUBSCRIPTION alignment)
final Account refreshedAccount2 = accountUserApi.getAccountById(account.getId(), callContext);
assertEquals(refreshedAccount2.getBillCycleDayLocal(), new Integer(0));
// Move clock past startDate to check nothing happens
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.NULL_INVOICE);
clock.addDays(31);
assertListenerStatus();
// Move clock after PHASE event
busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
clock.addMonths(12);
assertListenerStatus();
}
use of org.killbill.billing.entitlement.api.Entitlement in project killbill by killbill.
the class TestIntegrationDryRunInvoice method testForIssue_1505.
//
// Basic test with one subscription that verifies the behavior of using invoice dryRun api with no date
//
@Test(groups = "slow", description = "https://github.com/killbill/killbill/issues/1505")
public void testForIssue_1505() throws Exception {
clock.setTime(new DateTime("2021-09-20T3:56:02"));
final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(10));
assertNotNull(account);
// Start subscription in the past on 2021-08-10
final LocalDate billingStartDate = new LocalDate(2021, 8, 10);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT, NextEvent.INVOICE_PAYMENT);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", BillingPeriod.MONTHLY, "notrial", null);
final UUID entitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), "Something", billingStartDate, billingStartDate, false, true, ImmutableList.<PluginProperty>of(), callContext);
final Entitlement bp = entitlementApi.getEntitlementForId(entitlementId, callContext);
assertListenerStatus();
final Invoice firstInvoice = invoiceChecker.checkInvoice(account.getId(), 1, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2021, 8, 10), new LocalDate(2021, 9, 10), InvoiceItemType.RECURRING, new BigDecimal("29.95")));
final Invoice secondInvoice = invoiceChecker.checkInvoice(account.getId(), 2, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2021, 9, 10), new LocalDate(2021, 10, 10), InvoiceItemType.RECURRING, new BigDecimal("29.95")));
final InvoiceItem recurringItem = Iterables.tryFind(secondInvoice.getInvoiceItems(), new Predicate<InvoiceItem>() {
@Override
public boolean apply(final InvoiceItem input) {
return input.getInvoiceItemType() == InvoiceItemType.RECURRING;
}
}).orNull();
Assert.assertNotNull(recurringItem);
// Full item adjustment for the RECURRING from second invoice
busHandler.pushExpectedEvents(NextEvent.INVOICE_ADJUSTMENT);
invoiceUserApi.insertInvoiceItemAdjustment(account.getId(), secondInvoice.getId(), recurringItem.getId(), clock.getUTCToday(), "", "", null, callContext);
assertListenerStatus();
// Cancel Subscription on 2021-09-20
busHandler.pushExpectedEvents(NextEvent.CANCEL, NextEvent.BLOCK, NextEvent.INVOICE);
bp.cancelEntitlementWithDate(new LocalDate(2021, 9, 10), true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
// We see a third Invoice generated with a $0 REPAIR_ADJ item
final Invoice thirdInvoice = invoiceChecker.checkInvoice(account.getId(), 3, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2021, 9, 10), new LocalDate(2021, 10, 10), InvoiceItemType.REPAIR_ADJ, BigDecimal.ZERO));
busHandler.pushExpectedEvents(NextEvent.NULL_INVOICE);
try {
invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), callContext);
Assert.fail("Should not generate an invoice");
} catch (final InvoiceApiException e) {
assertEquals(e.getCode(), INVOICE_NOTHING_TO_DO.getCode());
} finally {
assertListenerStatus();
}
}
use of org.killbill.billing.entitlement.api.Entitlement in project killbill by killbill.
the class TestIntegrationDryRunInvoice method testForIssue_1503.
@Test(groups = "slow", description = "https://github.com/killbill/killbill/issues/1503")
public void testForIssue_1503() throws Exception {
clock.setTime(new DateTime("2021-04-01T3:56:02"));
final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
assertNotNull(account);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", BillingPeriod.MONTHLY, "notrial", null);
final UUID entitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), "Something", null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
final Entitlement bp = entitlementApi.getEntitlementForId(entitlementId, callContext);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 1, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2021, 4, 1), new LocalDate(2021, 5, 1), InvoiceItemType.RECURRING, new BigDecimal("29.95")));
bp.cancelEntitlementWithDate(new LocalDate(2021, 6, 1), true, ImmutableList.<PluginProperty>of(), callContext);
// We see one recurring from 2021-5-1 -> 2021-6-1
final Invoice dryRunInvoice1 = invoiceUserApi.triggerDryRunInvoiceGeneration(bp.getAccountId(), new LocalDate(2021, 5, 1), DRY_RUN_TARGET_DATE_ARG, callContext);
invoiceChecker.checkInvoiceNoAudits(dryRunInvoice1, ImmutableList.of(new ExpectedInvoiceItemCheck(new LocalDate(2021, 5, 1), new LocalDate(2021, 6, 1), InvoiceItemType.RECURRING, new BigDecimal("29.95"))));
// From any date > 2021-5-1, we should see nothing
Set<LocalDate> nextDates = ImmutableSet.of(new LocalDate(2021, 6, 1), /* cancelation date */
new LocalDate(2021, 6, 3), new LocalDate(2021, 7, 1));
for (LocalDate targetDate : nextDates) {
try {
invoiceUserApi.triggerDryRunInvoiceGeneration(bp.getAccountId(), targetDate, DRY_RUN_TARGET_DATE_ARG, callContext);
Assert.fail(String.format("Should not have received an invoice for date %s", targetDate));
} catch (final InvoiceApiException e) {
assertEquals(e.getCode(), ErrorCode.INVOICE_NOTHING_TO_DO.getCode());
}
}
}
use of org.killbill.billing.entitlement.api.Entitlement in project killbill by killbill.
the class TestCatalogPlanAligner method testUncancel.
@Test(groups = "slow")
public void testUncancel() throws Exception {
// Catalog effDt = 2020-09-16T10:34:25
uploadCatalog("WeaponsHireSmall-v1.xml");
assertListenerStatus();
// 2020-09-17T12:56:02
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("pistol-monthly", null);
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
final UUID subId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec, null, null, null), UUID.randomUUID().toString(), null, null, false, true, ImmutableList.<PluginProperty>of(), testCallContext);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 1, testCallContext, new ExpectedInvoiceItemCheck(new LocalDate(2020, 9, 17), null, InvoiceItemType.FIXED, new BigDecimal("0.00")));
// Catalog effDt = 2020-09-18T11:19:01
uploadCatalog("WeaponsHireSmall-v2.xml");
assertListenerStatus();
final Entitlement entitlement = entitlementApi.getEntitlementForId(subId, testCallContext);
// 2020-09-18T12:56:02 (WeaponsHireSmall-v2 is active)
clock.addDays(1);
// pistol-discount-monthly is only available on WeaponsHireSmall-v2
// pistol-discount-monthly has a 3 months discount period
final PlanPhaseSpecifier spec2 = new PlanPhaseSpecifier("pistol-discount-monthly", null);
busHandler.pushExpectedEvents(NextEvent.CHANGE, NextEvent.INVOICE);
entitlement.changePlanWithDate(new DefaultEntitlementSpecifier(spec2), clock.getUTCToday(), ImmutableList.<PluginProperty>of(), testCallContext);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 2, testCallContext, new ExpectedInvoiceItemCheck(new LocalDate(2020, 9, 18), null, InvoiceItemType.FIXED, new BigDecimal("0.00")));
// Catalog effDt = 2020-09-19T11:19:01 (we remove the plan pistol-discount-monthly)
uploadCatalog("WeaponsHireSmall-v3.xml");
assertListenerStatus();
// 2020-09-19T12:56:02
clock.addDays(1);
// Cancel way far in the future after the pending RECURRING phase
entitlement.cancelEntitlementWithDate(new LocalDate("2020-12-20"), true, ImmutableList.<PluginProperty>of(), testCallContext);
assertListenerStatus();
// 2020-09-20T12:56:02
clock.addDays(1);
// We should see the pending RECURRING phase in the future
busHandler.pushExpectedEvents(NextEvent.UNCANCEL);
entitlement.uncancelEntitlement(ImmutableList.<PluginProperty>of(), testCallContext);
assertListenerStatus();
// 2020-10-20T12:56:02 Move after TRIAL
busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
clock.addMonths(1);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 3, testCallContext, new ExpectedInvoiceItemCheck(new LocalDate(2020, 10, 17), new LocalDate(2020, 11, 17), InvoiceItemType.RECURRING, new BigDecimal("49.95")));
busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
clock.addMonths(1);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 4, testCallContext, new ExpectedInvoiceItemCheck(new LocalDate(2020, 11, 17), new LocalDate(2020, 12, 17), InvoiceItemType.RECURRING, new BigDecimal("49.95")));
busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
clock.addMonths(1);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 5, testCallContext, new ExpectedInvoiceItemCheck(new LocalDate(2020, 12, 17), new LocalDate(2021, 1, 17), InvoiceItemType.RECURRING, new BigDecimal("49.95")));
// 2021-01-20T12:56:02 Move after DISCOUNT
busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
clock.addMonths(1);
assertListenerStatus();
invoiceChecker.checkInvoice(account.getId(), 6, testCallContext, new ExpectedInvoiceItemCheck(new LocalDate(2021, 1, 17), new LocalDate(2021, 2, 17), InvoiceItemType.RECURRING, new BigDecimal("89.95")));
checkNoMoreInvoiceToGenerate(account.getId(), testCallContext);
}
use of org.killbill.billing.entitlement.api.Entitlement 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);
}
Aggregations