use of org.killbill.billing.entitlement.api.Entitlement 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);
}
use of org.killbill.billing.entitlement.api.Entitlement in project killbill by killbill.
the class UsageResource method recordUsage.
@TimedResource
@POST
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Record usage for a subscription")
@ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully recorded usage data change"), @ApiResponse(code = 400, message = "Invalid subscription (e.g. inactive)") })
public Response recordUsage(final SubscriptionUsageRecordJson json, @HeaderParam(HDR_CREATED_BY) final String createdBy, @HeaderParam(HDR_REASON) final String reason, @HeaderParam(HDR_COMMENT) final String comment, @javax.ws.rs.core.Context final HttpServletRequest request, @javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementApiException, AccountApiException, UsageApiException {
verifyNonNullOrEmpty(json, "SubscriptionUsageRecordJson body should be specified");
verifyNonNullOrEmpty(json.getSubscriptionId(), "SubscriptionUsageRecordJson subscriptionId needs to be set", json.getUnitUsageRecords(), "SubscriptionUsageRecordJson unitUsageRecords needs to be set");
Preconditions.checkArgument(!json.getUnitUsageRecords().isEmpty());
for (final UnitUsageRecordJson unitUsageRecordJson : json.getUnitUsageRecords()) {
verifyNonNullOrEmpty(unitUsageRecordJson.getUnitType(), "UnitUsageRecordJson unitType need to be set");
Preconditions.checkArgument(Iterables.size(unitUsageRecordJson.getUsageRecords()) > 0, "UnitUsageRecordJson usageRecords must have at least one element.");
for (final UsageRecordJson usageRecordJson : unitUsageRecordJson.getUsageRecords()) {
verifyNonNull(usageRecordJson.getAmount(), "UsageRecordJson amount needs to be set");
verifyNonNull(usageRecordJson.getRecordDate(), "UsageRecordJson recordDate needs to be set");
}
}
final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
// Verify subscription exists..
final Entitlement entitlement = entitlementApi.getEntitlementForId(json.getSubscriptionId(), callContext);
if (entitlement.getEffectiveEndDate() != null) {
final LocalDate highestRecordDate = getHighestRecordDate(json.getUnitUsageRecords());
if (entitlement.getEffectiveEndDate().compareTo(highestRecordDate) < 0) {
return Response.status(Status.BAD_REQUEST).build();
}
}
final SubscriptionUsageRecord record = json.toSubscriptionUsageRecord();
usageUserApi.recordRolledUpUsage(record, callContext);
return Response.status(Status.CREATED).build();
}
use of org.killbill.billing.entitlement.api.Entitlement in project killbill by killbill.
the class TestInArrearWithCatalogVersions method testWithChangeWithinCatalog.
@Test(groups = "slow")
public void testWithChangeWithinCatalog() throws Exception {
// 30 days month
clock.setDay(new LocalDate(2016, 4, 1));
final AccountData accountData = getAccountData(1);
final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
accountChecker.checkAccount(account.getId(), accountData, callContext);
final PlanPhaseSpecifier spec1 = new PlanPhaseSpecifier("electricity-monthly");
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.NULL_INVOICE);
final UUID entitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec1), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
recordUsageData(entitlementId, "t1", "kilowatt-hour", new LocalDate(2016, 4, 1), 143L, callContext);
recordUsageData(entitlementId, "t2", "kilowatt-hour", new LocalDate(2016, 4, 18), 57L, callContext);
busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
clock.addMonths(1);
assertListenerStatus();
Invoice curInvoice = invoiceChecker.checkInvoice(account.getId(), 1, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2016, 4, 1), new LocalDate(2016, 5, 1), InvoiceItemType.USAGE, new BigDecimal("300.00")));
invoiceChecker.checkTrackingIds(curInvoice, ImmutableSet.of("t1", "t2"), internalCallContext);
// -> Uses v1 : $150
recordUsageData(entitlementId, "t3", "kilowatt-hour", new LocalDate(2016, 5, 2), 100L, callContext);
final Entitlement bp = entitlementApi.getEntitlementForId(entitlementId, callContext);
final PlanPhaseSpecifier spec2 = new PlanPhaseSpecifier("electricity-monthly-special");
bp.changePlanWithDate(new DefaultEntitlementSpecifier(spec2), new LocalDate("2016-05-07"), null, callContext);
assertListenerStatus();
busHandler.pushExpectedEvents(NextEvent.CHANGE, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
clock.addDays(8);
assertListenerStatus();
curInvoice = invoiceChecker.checkInvoice(account.getId(), 2, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2016, 5, 1), new LocalDate(2016, 5, 7), InvoiceItemType.USAGE, new BigDecimal("150.00")));
invoiceChecker.checkTrackingIds(curInvoice, ImmutableSet.of("t3"), internalCallContext);
// -> Uses special plan : $100
recordUsageData(entitlementId, "t4", "kilowatt-hour", new LocalDate(2016, 5, 10), 100L, callContext);
busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
clock.addDays(23);
assertListenerStatus();
curInvoice = invoiceChecker.checkInvoice(account.getId(), 3, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2016, 5, 7), new LocalDate(2016, 6, 1), InvoiceItemType.USAGE, new BigDecimal("100.00")));
invoiceChecker.checkTrackingIds(curInvoice, ImmutableSet.of("t4"), internalCallContext);
// Check item catalogEffectiveDate correctly reflects the first catalog where such plan is available
final VersionedCatalog catalog = catalogUserApi.getCatalog("foo", callContext);
assertEquals(curInvoice.getInvoiceItems().get(0).getCatalogEffectiveDate().toDate().compareTo(catalog.getVersions().get(0).getEffectiveDate()), 0);
}
use of org.killbill.billing.entitlement.api.Entitlement in project killbill by killbill.
the class TestInArrearWithCatalogVersions method testWithSubscriptionBCD.
@Test(groups = "slow")
public void testWithSubscriptionBCD() throws Exception {
// 30 days month
clock.setDay(new LocalDate(2016, 4, 1));
final VersionedCatalog catalog = catalogUserApi.getCatalog("foo", callContext);
final AccountData accountData = getAccountData(1);
final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
accountChecker.checkAccount(account.getId(), accountData, callContext);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("electricity-monthly");
busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.NULL_INVOICE);
final UUID entitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), null, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
assertListenerStatus();
recordUsageData(entitlementId, "t1", "kilowatt-hour", new LocalDate(2016, 4, 5), 1L, callContext);
recordUsageData(entitlementId, "t2", "kilowatt-hour", new LocalDate(2016, 4, 5), 99L, callContext);
busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
clock.addMonths(1);
assertListenerStatus();
Invoice curInvoice = invoiceChecker.checkInvoice(account.getId(), 1, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2016, 4, 1), new LocalDate(2016, 5, 1), InvoiceItemType.USAGE, new BigDecimal("150.00")));
invoiceChecker.checkTrackingIds(curInvoice, ImmutableSet.of("t1", "t2"), internalCallContext);
final Entitlement bp = entitlementApi.getEntitlementForId(entitlementId, callContext);
recordUsageData(entitlementId, "t3", "kilowatt-hour", new LocalDate(2016, 5, 2), 100L, callContext);
// Update subscription BCD
bp.updateBCD(9, new LocalDate(2016, 5, 9), callContext);
recordUsageData(entitlementId, "t4", "kilowatt-hour", new LocalDate(2016, 5, 10), 10L, callContext);
busHandler.pushExpectedEvents(NextEvent.BCD_CHANGE, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
clock.addDays(9);
assertListenerStatus();
curInvoice = invoiceChecker.checkInvoice(account.getId(), 2, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2016, 5, 1), new LocalDate(2016, 5, 8), InvoiceItemType.USAGE, new BigDecimal("150.00")), // Reach the catalog version change date for this subscription
new ExpectedInvoiceItemCheck(new LocalDate(2016, 5, 8), new LocalDate(2016, 5, 9), InvoiceItemType.USAGE, new BigDecimal("0.00")));
invoiceChecker.checkTrackingIds(curInvoice, ImmutableSet.of("t3"), internalCallContext);
// Check items catalogEffectiveDate are correctly marked against each version
assertEquals(curInvoice.getInvoiceItems().get(0).getCatalogEffectiveDate().toDate().compareTo(catalog.getVersions().get(0).getEffectiveDate()), 0);
assertEquals(curInvoice.getInvoiceItems().get(1).getCatalogEffectiveDate().toDate().compareTo(catalog.getVersions().get(1).getEffectiveDate()), 0);
// Original notification before we change BCD
busHandler.pushExpectedEvents(NextEvent.NULL_INVOICE);
clock.addDays(23);
assertListenerStatus();
busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
clock.addDays(8);
assertListenerStatus();
// NOTE: Is using the new version of the catalog Utility-v2 (effectiveDateForExistingSubscriptions = 2016-05-08T00:00:00+00:00) what we want or is this a bug?
curInvoice = invoiceChecker.checkInvoice(account.getId(), 3, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2016, 5, 9), new LocalDate(2016, 6, 9), InvoiceItemType.USAGE, new BigDecimal("25.00")));
invoiceChecker.checkTrackingIds(curInvoice, ImmutableSet.of("t4"), internalCallContext);
// Check items catalogEffectiveDate is correctly set against last version
assertEquals(curInvoice.getInvoiceItems().get(0).getCatalogEffectiveDate().toDate().compareTo(catalog.getVersions().get(1).getEffectiveDate()), 0);
}
use of org.killbill.billing.entitlement.api.Entitlement in project killbill by killbill.
the class TestDefaultInternalBillingApi method testUnblockThenBlockBlockingStatesWithSimilarEffectiveDate.
private void testUnblockThenBlockBlockingStatesWithSimilarEffectiveDate(final ReadablePeriod delay) throws Exception {
final LocalDate initialDate = new LocalDate(2013, 8, 7);
clock.setDay(initialDate);
final Account account = createAccount(getAccountData(7));
testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
final UUID entitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), account.getExternalKey(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
final Entitlement entitlement = entitlementApi.getEntitlementForId(entitlementId, callContext);
final SubscriptionBase subscription = subscriptionInternalApi.getSubscriptionFromId(entitlement.getId(), internalCallContext);
assertListenerStatus();
final DateTime block1Date = subscription.getStartDate().plus(delay);
// Make sure to update the clock here, because we don't disable for periods less than a day
clock.setTime(block1Date);
testListener.pushExpectedEvents(NextEvent.BLOCK);
final DefaultBlockingState state1 = new DefaultBlockingState(account.getId(), BlockingStateType.ACCOUNT, DefaultEntitlementApi.ENT_STATE_BLOCKED, KILLBILL_SERVICES.ENTITLEMENT_SERVICE.getServiceName(), true, true, true, block1Date);
blockingInternalApi.setBlockingState(state1, internalCallContext);
assertListenerStatus();
clock.addDays(1);
final DateTime block2Date = clock.getUTCNow();
testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.BLOCK);
final DefaultBlockingState state2 = new DefaultBlockingState(account.getId(), BlockingStateType.ACCOUNT, DefaultEntitlementApi.ENT_STATE_CLEAR, KILLBILL_SERVICES.ENTITLEMENT_SERVICE.getServiceName(), false, false, false, block2Date);
blockingInternalApi.setBlockingState(state2, internalCallContext);
// Same date
final DefaultBlockingState state3 = new DefaultBlockingState(account.getId(), BlockingStateType.ACCOUNT, DefaultEntitlementApi.ENT_STATE_BLOCKED, KILLBILL_SERVICES.ENTITLEMENT_SERVICE.getServiceName(), true, true, true, block2Date);
blockingInternalApi.setBlockingState(state3, internalCallContext);
assertListenerStatus();
// Nothing should happen
clock.addDays(3);
assertListenerStatus();
final List<BillingEvent> events = ImmutableList.<BillingEvent>copyOf(billingInternalApi.getBillingEventsForAccountAndUpdateAccountBCD(account.getId(), null, null, internalCallContext));
if (delay.toPeriod().toStandardDuration().compareTo(Period.ZERO.toStandardDuration()) == 0) {
Assert.assertEquals(events.size(), 0);
} else {
// Expected blocking duration:
// * 2013-08-07 to now [2013-08-07 to 2013-08-08 then 2013-08-08 to now]
Assert.assertEquals(events.size(), 2);
Assert.assertEquals(events.get(0).getTransitionType(), SubscriptionBaseTransitionType.CREATE);
Assert.assertEquals(events.get(0).getEffectiveDate(), subscription.getStartDate());
Assert.assertEquals(events.get(1).getTransitionType(), SubscriptionBaseTransitionType.START_BILLING_DISABLED);
Assert.assertEquals(events.get(1).getEffectiveDate(), block1Date);
}
}
Aggregations