use of org.killbill.billing.entitlement.api.SubscriptionBundle in project killbill by killbill.
the class TestOverdueWithSubscriptionCancellation method testCheckSubscriptionCancellationWithMultipleBundles.
@Test(groups = "slow")
public void testCheckSubscriptionCancellationWithMultipleBundles() throws Exception {
// 2012-05-01T00:03:53.000Z
clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
setupAccount();
// Set next invoice to fail and create subscription
paymentPlugin.makeAllInvoicesFailWithError(true);
final DefaultEntitlement baseEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
bundle = subscriptionApi.getSubscriptionBundle(baseEntitlement.getBundleId(), callContext);
invoiceChecker.checkInvoice(account.getId(), 1, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 5, 1), callContext);
final DefaultEntitlement baseEntitlement2 = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey2", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
final SubscriptionBundle bundle2 = subscriptionApi.getSubscriptionBundle(baseEntitlement.getBundleId(), callContext);
invoiceChecker.checkInvoice(account.getId(), 2, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
invoiceChecker.checkChargedThroughDate(baseEntitlement2.getId(), new LocalDate(2012, 5, 1), callContext);
final DefaultEntitlement baseEntitlement3 = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey3", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
final SubscriptionBundle bundle3 = subscriptionApi.getSubscriptionBundle(baseEntitlement.getBundleId(), callContext);
invoiceChecker.checkInvoice(account.getId(), 3, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
invoiceChecker.checkChargedThroughDate(baseEntitlement2.getId(), new LocalDate(2012, 5, 1), callContext);
// Cancel bundle 2 one day after (2012-05-02)
clock.addDays(1);
cancelEntitlementAndCheckForCompletion(baseEntitlement2, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.NULL_INVOICE);
final SubscriptionBase cancelledBaseSubscription2 = ((DefaultEntitlement) entitlementApi.getEntitlementForId(baseEntitlement2.getId(), callContext)).getSubscriptionBase();
assertTrue(cancelledBaseSubscription2.getState() == EntitlementState.CANCELLED);
// DAY 30 have to get out of trial before first payment (2012-05-31)
addDaysAndCheckForCompletion(29, NextEvent.PHASE, NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR, NextEvent.INVOICE_PAYMENT_ERROR);
invoiceChecker.checkInvoice(account.getId(), 4, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 6, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")), new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 6, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 6, 30), callContext);
// Should still be in clear state
checkODState(OverdueWrapper.CLEAR_STATE_NAME);
// DAY 36 (2012-06-06)-- RIGHT AFTER OD1 (two block events, for the cancellation and the OD1 state)
// One BLOCK event is for the overdue state transition
// The 2 other BLOCK are for the entitlement blocking states for both baseEntitlement and baseEntitlement3
addDaysAndCheckForCompletion(6, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.INVOICE);
// Should be in OD1
checkODState("OD1");
final SubscriptionBase cancelledBaseSubscription = ((DefaultEntitlement) entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext)).getSubscriptionBase();
assertTrue(cancelledBaseSubscription.getState() == EntitlementState.CANCELLED);
final SubscriptionBase cancelledBaseEntitlement3 = ((DefaultEntitlement) entitlementApi.getEntitlementForId(baseEntitlement3.getId(), callContext)).getSubscriptionBase();
assertTrue(cancelledBaseEntitlement3.getState() == EntitlementState.CANCELLED);
}
use of org.killbill.billing.entitlement.api.SubscriptionBundle in project killbill by killbill.
the class AccountResource method getAccountBundles.
@TimedResource
@GET
@Path("/{accountId:" + UUID_PATTERN + "}/" + BUNDLES)
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Retrieve bundles for account", response = BundleJson.class, responseContainer = "List")
@ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid account id supplied"), @ApiResponse(code = 404, message = "Account not found") })
public Response getAccountBundles(@PathParam("accountId") final String accountId, @QueryParam(QUERY_EXTERNAL_KEY) final String externalKey, @QueryParam(QUERY_BUNDLES_FILTER) final String bundlesFilter, @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode, @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, SubscriptionApiException {
final TenantContext tenantContext = context.createContext(request);
final UUID uuid = UUID.fromString(accountId);
final Account account = accountUserApi.getAccountById(uuid, tenantContext);
final List<SubscriptionBundle> bundles = (externalKey != null) ? subscriptionApi.getSubscriptionBundlesForAccountIdAndExternalKey(uuid, externalKey, tenantContext) : subscriptionApi.getSubscriptionBundlesForAccountId(uuid, tenantContext);
final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(account.getId(), auditMode.getLevel(), tenantContext);
boolean filter = (null != bundlesFilter && !bundlesFilter.isEmpty());
final Collection<BundleJson> result = Collections2.transform((filter) ? filterBundles(bundles, Arrays.asList(bundlesFilter.split(","))) : bundles, new Function<SubscriptionBundle, BundleJson>() {
@Override
public BundleJson apply(final SubscriptionBundle input) {
try {
return new BundleJson(input, account.getCurrency(), accountAuditLogs);
} catch (final CatalogApiException e) {
// Not the cleanest thing, but guava Api don't allow throw..
throw new RuntimeException(e);
}
}
});
return Response.status(Status.OK).entity(result).build();
}
use of org.killbill.billing.entitlement.api.SubscriptionBundle in project killbill by killbill.
the class AccountResource method getAccountTimeline.
@TimedResource
@GET
@Path("/{accountId:" + UUID_PATTERN + "}/" + TIMELINE)
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Retrieve account timeline", response = AccountTimelineJson.class)
@ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid account id supplied"), @ApiResponse(code = 404, message = "Account not found") })
public Response getAccountTimeline(@PathParam("accountId") final String accountIdString, @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode, @QueryParam(QUERY_PARALLEL) @DefaultValue("false") final Boolean parallel, @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, PaymentApiException, SubscriptionApiException, InvoiceApiException, CatalogApiException {
final TenantContext tenantContext = context.createContext(request);
final UUID accountId = UUID.fromString(accountIdString);
final Account account = accountUserApi.getAccountById(accountId, tenantContext);
final Callable<List<SubscriptionBundle>> bundlesCallable = new Callable<List<SubscriptionBundle>>() {
@Override
public List<SubscriptionBundle> call() throws Exception {
return subscriptionApi.getSubscriptionBundlesForAccountId(accountId, tenantContext);
}
};
final Callable<List<Invoice>> invoicesCallable = new Callable<List<Invoice>>() {
@Override
public List<Invoice> call() throws Exception {
return invoiceApi.getInvoicesByAccount(accountId, false, tenantContext);
}
};
final Callable<List<InvoicePayment>> invoicePaymentsCallable = new Callable<List<InvoicePayment>>() {
@Override
public List<InvoicePayment> call() throws Exception {
return invoicePaymentApi.getInvoicePaymentsByAccount(accountId, tenantContext);
}
};
final Callable<List<Payment>> paymentsCallable = new Callable<List<Payment>>() {
@Override
public List<Payment> call() throws Exception {
return paymentApi.getAccountPayments(accountId, false, false, ImmutableList.<PluginProperty>of(), tenantContext);
}
};
final Callable<AccountAuditLogs> auditsCallable = new Callable<AccountAuditLogs>() {
@Override
public AccountAuditLogs call() throws Exception {
return auditUserApi.getAccountAuditLogs(accountId, auditMode.getLevel(), tenantContext);
}
};
final AccountTimelineJson json;
List<Invoice> invoices = null;
List<SubscriptionBundle> bundles = null;
List<InvoicePayment> invoicePayments = null;
List<Payment> payments = null;
AccountAuditLogs accountAuditLogs = null;
if (parallel) {
final ExecutorService executor = jaxrsExecutors.getJaxrsExecutorService();
final Future<List<SubscriptionBundle>> futureBundlesCallable = executor.submit(bundlesCallable);
final Future<List<Invoice>> futureInvoicesCallable = executor.submit(invoicesCallable);
final Future<List<InvoicePayment>> futureInvoicePaymentsCallable = executor.submit(invoicePaymentsCallable);
final Future<List<Payment>> futurePaymentsCallable = executor.submit(paymentsCallable);
final Future<AccountAuditLogs> futureAuditsCallable = executor.submit(auditsCallable);
final ImmutableList<Future> toBeCancelled = ImmutableList.<Future>of(futureBundlesCallable, futureInvoicesCallable, futureInvoicePaymentsCallable, futurePaymentsCallable, futureAuditsCallable);
final int timeoutMsec = 100;
final long ini = System.currentTimeMillis();
do {
bundles = (bundles == null) ? waitOnFutureAndHandleTimeout("bundles", futureBundlesCallable, timeoutMsec, toBeCancelled) : bundles;
invoices = (invoices == null) ? waitOnFutureAndHandleTimeout("invoices", futureInvoicesCallable, timeoutMsec, toBeCancelled) : invoices;
invoicePayments = (invoicePayments == null) ? waitOnFutureAndHandleTimeout("invoicePayments", futureInvoicePaymentsCallable, timeoutMsec, toBeCancelled) : invoicePayments;
payments = (payments == null) ? waitOnFutureAndHandleTimeout("payments", futurePaymentsCallable, timeoutMsec, toBeCancelled) : payments;
accountAuditLogs = (accountAuditLogs == null) ? waitOnFutureAndHandleTimeout("accountAuditLogs", futureAuditsCallable, timeoutMsec, toBeCancelled) : accountAuditLogs;
} while ((System.currentTimeMillis() - ini < jaxrsConfig.getJaxrsTimeout().getMillis()) && (bundles == null || invoices == null || invoicePayments == null || payments == null || accountAuditLogs == null));
if (bundles == null || invoices == null || invoicePayments == null || payments == null || accountAuditLogs == null) {
Response.status(Status.SERVICE_UNAVAILABLE).build();
}
} else {
invoices = runCallable("invoices", invoicesCallable);
payments = runCallable("payments", paymentsCallable);
bundles = runCallable("bundles", bundlesCallable);
accountAuditLogs = runCallable("accountAuditLogs", auditsCallable);
invoicePayments = runCallable("invoicePayments", invoicePaymentsCallable);
}
json = new AccountTimelineJson(account, invoices, payments, invoicePayments, bundles, accountAuditLogs);
return Response.status(Status.OK).entity(json).build();
}
use of org.killbill.billing.entitlement.api.SubscriptionBundle in project killbill by killbill.
the class BundleResource method searchBundles.
@TimedResource
@GET
@Path("/" + SEARCH + "/{searchKey:" + ANYTHING_PATTERN + "}")
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Search bundles", response = BundleJson.class, responseContainer = "List")
@ApiResponses(value = {})
public Response searchBundles(@PathParam("searchKey") final String searchKey, @QueryParam(QUERY_SEARCH_OFFSET) @DefaultValue("0") final Long offset, @QueryParam(QUERY_SEARCH_LIMIT) @DefaultValue("100") final Long limit, @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode, @javax.ws.rs.core.Context final HttpServletRequest request) throws SubscriptionApiException {
final TenantContext tenantContext = context.createContext(request);
final Pagination<SubscriptionBundle> bundles = subscriptionApi.searchSubscriptionBundles(searchKey, offset, limit, tenantContext);
final URI nextPageUri = uriBuilder.nextPage(BundleResource.class, "searchBundles", bundles.getNextOffset(), limit, ImmutableMap.<String, String>of("searchKey", searchKey, QUERY_AUDIT, auditMode.getLevel().toString()));
final AtomicReference<Map<UUID, AccountAuditLogs>> accountsAuditLogs = new AtomicReference<Map<UUID, AccountAuditLogs>>(new HashMap<UUID, AccountAuditLogs>());
return buildStreamingPaginationResponse(bundles, new Function<SubscriptionBundle, BundleJson>() {
@Override
public BundleJson apply(final SubscriptionBundle bundle) {
// Cache audit logs per account
if (accountsAuditLogs.get().get(bundle.getAccountId()) == null) {
accountsAuditLogs.get().put(bundle.getAccountId(), auditUserApi.getAccountAuditLogs(bundle.getAccountId(), auditMode.getLevel(), tenantContext));
}
try {
return new BundleJson(bundle, null, accountsAuditLogs.get().get(bundle.getAccountId()));
} catch (final CatalogApiException unused) {
// Does not happen because we pass a null Currency
throw new RuntimeException(unused);
}
}
}, nextPageUri);
}
use of org.killbill.billing.entitlement.api.SubscriptionBundle in project killbill by killbill.
the class BundleResource method getBundle.
@TimedResource
@GET
@Path("/{bundleId:" + UUID_PATTERN + "}")
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Retrieve a bundle by id", response = BundleJson.class)
@ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid bundle id supplied"), @ApiResponse(code = 404, message = "Bundle not found") })
public Response getBundle(@PathParam("bundleId") final String bundleId, @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode, @javax.ws.rs.core.Context final HttpServletRequest request) throws SubscriptionApiException, AccountApiException, CatalogApiException {
final UUID id = UUID.fromString(bundleId);
final TenantContext tenantContext = this.context.createContext(request);
final SubscriptionBundle bundle = subscriptionApi.getSubscriptionBundle(id, tenantContext);
final Account account = accountUserApi.getAccountById(bundle.getAccountId(), tenantContext);
final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(bundle.getAccountId(), auditMode.getLevel(), tenantContext);
final BundleJson json = new BundleJson(bundle, account.getCurrency(), accountAuditLogs);
return Response.status(Status.OK).entity(json).build();
}
Aggregations