Search in sources :

Example 6 with SubscriptionBundle

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);
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) SubscriptionBundle(org.killbill.billing.entitlement.api.SubscriptionBundle) DefaultEntitlement(org.killbill.billing.entitlement.api.DefaultEntitlement) ExpectedInvoiceItemCheck(org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck) LocalDate(org.joda.time.LocalDate) DateTime(org.joda.time.DateTime) BigDecimal(java.math.BigDecimal) Test(org.testng.annotations.Test)

Example 7 with SubscriptionBundle

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();
}
Also used : Account(org.killbill.billing.account.api.Account) TenantContext(org.killbill.billing.util.callcontext.TenantContext) BundleJson(org.killbill.billing.jaxrs.json.BundleJson) SubscriptionBundle(org.killbill.billing.entitlement.api.SubscriptionBundle) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) UUID(java.util.UUID) AccountAuditLogs(org.killbill.billing.util.audit.AccountAuditLogs) Path(javax.ws.rs.Path) TimedResource(org.killbill.commons.metrics.TimedResource) Produces(javax.ws.rs.Produces) GET(javax.ws.rs.GET) ApiOperation(io.swagger.annotations.ApiOperation) ApiResponses(io.swagger.annotations.ApiResponses)

Example 8 with SubscriptionBundle

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();
}
Also used : Account(org.killbill.billing.account.api.Account) Invoice(org.killbill.billing.invoice.api.Invoice) TenantContext(org.killbill.billing.util.callcontext.TenantContext) Callable(java.util.concurrent.Callable) SubscriptionBundle(org.killbill.billing.entitlement.api.SubscriptionBundle) ArrayList(java.util.ArrayList) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList) LinkedList(java.util.LinkedList) UUID(java.util.UUID) InvoicePayment(org.killbill.billing.invoice.api.InvoicePayment) InvoicePayment(org.killbill.billing.invoice.api.InvoicePayment) Payment(org.killbill.billing.payment.api.Payment) AccountTimelineJson(org.killbill.billing.jaxrs.json.AccountTimelineJson) ExecutorService(java.util.concurrent.ExecutorService) Future(java.util.concurrent.Future) AccountAuditLogs(org.killbill.billing.util.audit.AccountAuditLogs) Path(javax.ws.rs.Path) TimedResource(org.killbill.commons.metrics.TimedResource) Produces(javax.ws.rs.Produces) GET(javax.ws.rs.GET) ApiOperation(io.swagger.annotations.ApiOperation) ApiResponses(io.swagger.annotations.ApiResponses)

Example 9 with SubscriptionBundle

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);
}
Also used : TenantContext(org.killbill.billing.util.callcontext.TenantContext) AtomicReference(java.util.concurrent.atomic.AtomicReference) URI(java.net.URI) BundleJson(org.killbill.billing.jaxrs.json.BundleJson) SubscriptionBundle(org.killbill.billing.entitlement.api.SubscriptionBundle) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) UUID(java.util.UUID) AccountAuditLogs(org.killbill.billing.util.audit.AccountAuditLogs) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) HashMap(java.util.HashMap) Path(javax.ws.rs.Path) TimedResource(org.killbill.commons.metrics.TimedResource) Produces(javax.ws.rs.Produces) GET(javax.ws.rs.GET) ApiOperation(io.swagger.annotations.ApiOperation) ApiResponses(io.swagger.annotations.ApiResponses)

Example 10 with SubscriptionBundle

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();
}
Also used : Account(org.killbill.billing.account.api.Account) SubscriptionBundle(org.killbill.billing.entitlement.api.SubscriptionBundle) TenantContext(org.killbill.billing.util.callcontext.TenantContext) UUID(java.util.UUID) AccountAuditLogs(org.killbill.billing.util.audit.AccountAuditLogs) BundleJson(org.killbill.billing.jaxrs.json.BundleJson) Path(javax.ws.rs.Path) TimedResource(org.killbill.commons.metrics.TimedResource) Produces(javax.ws.rs.Produces) GET(javax.ws.rs.GET) ApiOperation(io.swagger.annotations.ApiOperation) ApiResponses(io.swagger.annotations.ApiResponses)

Aggregations

SubscriptionBundle (org.killbill.billing.entitlement.api.SubscriptionBundle)12 ApiOperation (io.swagger.annotations.ApiOperation)9 ApiResponses (io.swagger.annotations.ApiResponses)9 Produces (javax.ws.rs.Produces)9 TimedResource (org.killbill.commons.metrics.TimedResource)9 UUID (java.util.UUID)8 GET (javax.ws.rs.GET)7 Path (javax.ws.rs.Path)7 TenantContext (org.killbill.billing.util.callcontext.TenantContext)7 Account (org.killbill.billing.account.api.Account)6 AccountAuditLogs (org.killbill.billing.util.audit.AccountAuditLogs)6 BundleJson (org.killbill.billing.jaxrs.json.BundleJson)5 LocalDate (org.joda.time.LocalDate)3 CatalogApiException (org.killbill.billing.catalog.api.CatalogApiException)3 ImmutableMap (com.google.common.collect.ImmutableMap)2 URI (java.net.URI)2 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 Map (java.util.Map)2 AtomicReference (java.util.concurrent.atomic.AtomicReference)2