private void computeEntitlementsToCancel(final ImmutableAccountData account, final List<Entitlement> result, final CallContext context) throws EntitlementApiException { final List<Entitlement> allEntitlementsForAccountId = entitlementApi.getAllEntitlementsForAccountId(account.getId(), context); // Entitlement is smart enough and will cancel the associated add-ons. See also discussion in https://github.com/killbill/killbill/issues/94 final Collection<Entitlement> allEntitlementsButAddonsForAccountId = Collections2.<Entitlement>filter(allEntitlementsForAccountId, new Predicate<Entitlement>() { @Override public boolean apply(final Entitlement entitlement) { // Note: this would miss add-ons created in the future. We should expose a new API to do something similar to EventsStreamBuilder#findBaseSubscription return !ProductCategory.ADD_ON.equals(entitlement.getLastActiveProductCategory()); } }); result.addAll(allEntitlementsButAddonsForAccountId); }
@Override public Entitlement apply(@Nullable final Void dontcare) { try { final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, billingPeriod, priceList, null); final UUID entitlementId = entitlementApi.createBaseEntitlement(accountId, new DefaultEntitlementSpecifier(spec, null, overrides), bundleExternalKey, null, billingEffectiveDate, false, true, ImmutableList.<PluginProperty>of(), callContext); assertNotNull(entitlementId); return entitlementApi.getEntitlementForId(entitlementId, callContext); } catch (final EntitlementApiException e) { fail("Unable to create entitlement", e); return null; } } }, events);
final UUID baseEntitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), account.getExternalKey(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); final Entitlement baseEntitlement = entitlementApi.getEntitlementForId(baseEntitlementId, callContext); final UUID telescopicEntitlementId = entitlementApi.addEntitlement(baseEntitlement.getBundleId(), new DefaultEntitlementSpecifier(spec1), initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); final Entitlement telescopicEntitlement = entitlementApi.getEntitlementForId(telescopicEntitlementId, callContext); assertEquals(telescopicEntitlement.getLastActiveProductCategory(), ProductCategory.ADD_ON); List<Entitlement> bundleEntitlements = entitlementApi.getAllEntitlementsForBundle(telescopicEntitlement.getBundleId(), callContext); assertEquals(bundleEntitlements.size(), 2); bundleEntitlements = entitlementApi.getAllEntitlementsForAccountIdAndExternalKey(account.getId(), account.getExternalKey(), callContext); assertEquals(bundleEntitlements.size(), 2);
@Test(groups = "slow") public void testAddOnCreationTiming() throws AccountApiException, EntitlementApiException { final LocalDate initialDate = new LocalDate(2013, 8, 7); clock.setDay(initialDate); final Account account = createAccount(getAccountData(7)); // Reference time of 2013-08-07T00:00:00.000 Assert.assertEquals(account.getReferenceTime().compareTo(new DateTime(2013, 8, 7, 0, 0, 0, DateTimeZone.UTC)), 0); // Add 5 seconds clock.addDeltaFromReality(5000); // Create base entitlement (null LocalDate will map to now(), i.e. 2013-08-07T00:00:05.000Z) testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK); final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null); final UUID baseEntitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(baseSpec), account.getExternalKey(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); final DefaultEntitlement baseEntitlement = (DefaultEntitlement) entitlementApi.getEntitlementForId(baseEntitlementId, callContext); Assert.assertEquals(baseEntitlement.getSubscriptionBase().getStartDate().compareTo(account.getReferenceTime().plusSeconds(5)), 0); // Add ADD_ON (verify date passed, i.e. initialDate, won't map to 2013-08-07T00:00:00.000Z) testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK); final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null); final UUID addOnEntitlementId = entitlementApi.addEntitlement(baseEntitlement.getBundleId(), new DefaultEntitlementSpecifier(addOnSpec), initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); final DefaultEntitlement addOnEntitlement = (DefaultEntitlement) entitlementApi.getEntitlementForId(addOnEntitlementId, callContext); Assert.assertEquals(addOnEntitlement.getSubscriptionBase().getStartDate().compareTo(baseEntitlement.getSubscriptionBase().getStartDate()), 0); }
final UUID baseEntitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), account.getExternalKey(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); final Entitlement baseEntitlement = entitlementApi.getEntitlementForId(baseEntitlementId, callContext); final PlanPhaseSpecifier spec1 = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null); testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK); final UUID telescopicEntitlementId = entitlementApi.addEntitlement(baseEntitlement.getBundleId(), new DefaultEntitlementSpecifier(spec1), effectiveDateSpec1, effectiveDateSpec1, false, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); final Entitlement telescopicEntitlement = entitlementApi.getEntitlementForId(telescopicEntitlementId, callContext); entitlementApi.pause(baseEntitlement.getBundleId(), blockingStateDate, ImmutableList .<PluginProperty>of(), callContext); assertListenerStatus(); final Entitlement baseEntitlement2 = entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext); assertEquals(baseEntitlement2.getState(), EntitlementState.BLOCKED); final Entitlement telescopicEntitlement2 = entitlementApi.getEntitlementForId(telescopicEntitlement.getId(), callContext); assertEquals(telescopicEntitlement2.getState(), EntitlementState.BLOCKED); final List<Entitlement> bundleEntitlements2 = entitlementApi.getAllEntitlementsForBundle(telescopicEntitlement2.getBundleId(), callContext); assertEquals(bundleEntitlements2.size(), 2); for (final Entitlement cur : bundleEntitlements2) { entitlementApi.addEntitlement(baseEntitlement.getBundleId(), new DefaultEntitlementSpecifier(spec3), blockingStateDate, effectiveDateSpec1, false, ImmutableList.<PluginProperty>of(), callContext); fail("Should not be able to create ADD-ON because BP is paused"); } catch (EntitlementApiException e) { entitlementApi.resume(baseEntitlement.getBundleId(), new LocalDate(clock.getUTCNow()), ImmutableList.<PluginProperty>of(), callContext);
final UUID baseEntitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), account.getExternalKey(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); final Entitlement baseEntitlement = entitlementApi.getEntitlementForId(baseEntitlementId, callContext); entitlementApi.pause(baseEntitlement.getBundleId(), pauseDate, ImmutableList.<PluginProperty>of(), callContext); final Entitlement refreshedAfterFuturePause = entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext); assertEquals(refreshedAfterFuturePause.getState(), EntitlementState.ACTIVE); entitlementApi.resume(baseEntitlement.getBundleId(), resumeDate, ImmutableList.<PluginProperty>of(), callContext); final Entitlement baseEntitlementPaused = entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext); assertEquals(baseEntitlementPaused.getState(), EntitlementState.BLOCKED); final Entitlement baseEntitlementUnpaused = entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext); assertEquals(baseEntitlementUnpaused.getState(), EntitlementState.ACTIVE);
DefaultEntitlement entitlement = (DefaultEntitlement) entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext); busHandler.pushExpectedEvents(NextEvent.BLOCK, NextEvent.INVOICE); entitlementApi.pause(entitlement.getBundleId(), clock.getUTCNow().toLocalDate(), ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); new ExpectedInvoiceItemCheck(new LocalDate(2012, 3, 4), new LocalDate(2012, 3, 4), InvoiceItemType.CBA_ADJ, new BigDecimal("233.82"))); entitlement = (DefaultEntitlement) entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext); Assert.assertEquals(entitlement.getState(), EntitlementState.BLOCKED); entitlementApi.resume(entitlement.getBundleId(), clock.getUTCNow().toLocalDate(), ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus();
@TimedResource @POST @Path("/{subscriptionId:" + UUID_PATTERN + "}/" + BLOCK) @Consumes(APPLICATION_JSON) @ApiOperation(value = "Block a subscription", response = BlockingStateJson.class, responseContainer = "List") @ApiResponses(value = {@ApiResponse(code = 201, message = "Blocking state created successfully"), @ApiResponse(code = 400, message = "Invalid subscription id supplied"), @ApiResponse(code = 404, message = "Subscription not found")}) public Response addSubscriptionBlockingState(@PathParam(ID_PARAM_NAME) final UUID id, final BlockingStateJson json, @QueryParam(QUERY_REQUESTED_DT) final String requestedDate, @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString, @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 SubscriptionApiException, EntitlementApiException, AccountApiException { final TenantContext tenantContext = context.createTenantContextNoAccountId(request); final Entitlement entitlement = entitlementApi.getEntitlementForId(id, tenantContext); return addBlockingState(json, entitlement.getAccountId(), id, BlockingStateType.SUBSCRIPTION, requestedDate, pluginPropertiesString, createdBy, reason, comment, request, uriInfo); }
NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT ); final List<UUID> allEntitlements = entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), entitlementWithAddOnsSpecifierList, true, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); checkNoMoreInvoiceToGenerate(account); assertEquals(allEntitlements.size(), 6); final Entitlement baseEntitlement = entitlementApi.getEntitlementForId(allEntitlements.get(0), callContext); final Entitlement addOnEntitlement1 = entitlementApi.getEntitlementForId(allEntitlements.get(1), callContext); final Entitlement addOnEntitlement2 = entitlementApi.getEntitlementForId(allEntitlements.get(2), callContext);
final UUID entitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), account.getExternalKey(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); final Entitlement entitlement = entitlementApi.getEntitlementForId(entitlementId, callContext); assertEquals(entitlement.getAccountId(), account.getId()); assertEquals(entitlement.getExternalKey(), account.getExternalKey()); final Entitlement entitlement2 = entitlementApi.getEntitlementForId(entitlement.getId(), callContext); final List<Entitlement> accountEntitlements = entitlementApi.getAllEntitlementsForAccountId(account.getId(), callContext); assertEquals(accountEntitlements.size(), 1);
@Override public Entitlement apply(@Nullable final Void dontcare) { try { final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, null); final UUID entitlementId = entitlementApi.addEntitlement(bundleId, new DefaultEntitlementSpecifier(spec), effectiveDate, effectiveDate, false, ImmutableList.<PluginProperty>of(), callContext); assertNotNull(entitlementId); return entitlementApi.getEntitlementForId(entitlementId, callContext); } catch (final EntitlementApiException e) { fail(e.getMessage()); return null; } } }, events);
final UUID baseEntitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), account.getExternalKey(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); final Entitlement baseEntitlement = entitlementApi.getEntitlementForId(baseEntitlementId, callContext); assertListenerStatus(); List<Entitlement> bundleEntitlements = entitlementApi.getAllEntitlementsForBundle(baseEntitlement.getBundleId(), callContext); assertEquals(bundleEntitlements.size(), 1); assertEquals(bundleEntitlements.get(0).getState(), EntitlementState.BLOCKED); assertListenerStatus(); bundleEntitlements = entitlementApi.getAllEntitlementsForBundle(baseEntitlement.getBundleId(), callContext); assertEquals(bundleEntitlements.size(), 1); assertEquals(bundleEntitlements.get(0).getState(), EntitlementState.BLOCKED); bundleEntitlements = entitlementApi.getAllEntitlementsForBundle(baseEntitlement.getBundleId(), callContext); assertEquals(bundleEntitlements.size(), 1); assertEquals(bundleEntitlements.get(0).getState(), EntitlementState.ACTIVE); bundleEntitlements = entitlementApi.getAllEntitlementsForBundle(baseEntitlement.getBundleId(), callContext); assertEquals(bundleEntitlements.size(), 1); assertEquals(bundleEntitlements.get(0).getState(), EntitlementState.BLOCKED); bundleEntitlements = entitlementApi.getAllEntitlementsForBundle(baseEntitlement.getBundleId(), callContext); assertEquals(bundleEntitlements.size(), 1); assertEquals(bundleEntitlements.get(0).getState(), EntitlementState.ACTIVE);
final UUID entitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), externalKey, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); final Entitlement entitlement = entitlementApi.getEntitlementForId(entitlementId, callContext); assertEquals(entitlement.getAccountId(), account.getId()); assertEquals(entitlement.getExternalKey(), externalKey); final UUID entitlement2Id = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec2), externalKey, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); final Entitlement entitlement2 = entitlementApi.getEntitlementForId(entitlement2Id, callContext); assertEquals(entitlement2.getAccountId(), account.getId()); assertEquals(entitlement2.getExternalKey(), externalKey); entitlementApi.transferEntitlements(account.getId(), account2.getId(), externalKey, new LocalDate(clock.getUTCNow(), account.getTimeZone()), ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus();
final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null); testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE); entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), bundleKey2, null, null, false, true, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); final List<UUID> entitlementIds = entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), baseEntitlementWithAddOnsSpecifiers, true, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); final List<Entitlement> entitlementsForBundle1 = entitlementApi.getAllEntitlementsForAccountIdAndExternalKey(account.getId(), bundleKey1, callContext); Assert.assertEquals(entitlementsForBundle1.size(), 2); final List<Entitlement> entitlementsForBundle2 = entitlementApi.getAllEntitlementsForAccountIdAndExternalKey(account.getId(), bundleKey2, callContext); Assert.assertEquals(entitlementsForBundle2.size(), 2);
@Override public List<UUID> doOperation(final CallContext ctx) throws EntitlementApiException { return entitlementApi.createBaseEntitlementsWithAddOns(account.getId(), baseEntitlementWithAddOnsSpecifierList, renameKeyIfExistsAndUnused, pluginProperties, callContext); }
@Test(groups = "slow") public void testError_CAT_MULTIPLE_MATCHING_PLANS_FOR_PRICELIST() throws Exception { // Create a per-tenant catalog with one plan final SimplePlanDescriptor desc1 = new DefaultSimplePlanDescriptor("zoe-monthly", "Zoe", ProductCategory.BASE, account.getCurrency(), BigDecimal.TEN, BillingPeriod.MONTHLY, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()); catalogUserApi.addSimplePlan(desc1, init, testCallContext); StaticCatalog catalog = catalogUserApi.getCurrentCatalog("dummy", testCallContext); assertEquals(catalog.getCurrentPlans().size(), 1); final SimplePlanDescriptor desc2 = new DefaultSimplePlanDescriptor("zoe-14-monthly", "Zoe", ProductCategory.BASE, account.getCurrency(), BigDecimal.TEN, BillingPeriod.MONTHLY, 14, TimeUnit.DAYS, ImmutableList.<String>of()); catalogUserApi.addSimplePlan(desc2, init, testCallContext); catalog = catalogUserApi.getCurrentCatalog("dummy", testCallContext); assertEquals(catalog.getCurrentPlans().size(), 2); try { final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Zoe", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null); entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), UUID.randomUUID().toString(), null, null, false, true, ImmutableList.<PluginProperty>of(), testCallContext); fail("Creating entitlement should fail"); } catch (final EntitlementApiException e) { assertEquals(e.getCode(), ErrorCode.CAT_MULTIPLE_MATCHING_PLANS_FOR_PRICELIST.getCode()); } }
final UUID newBundleId = entitlementApi.transferEntitlements(account.getId(), newAccount.getId(), bundleExternalKey, transferDay, ImmutableList.<PluginProperty>of(), callContext); assertListenerStatus(); final List<Entitlement> oldEntitlements = entitlementApi.getAllEntitlementsForBundle(bpEntitlement.getBundleId(), callContext); Assert.assertEquals(oldEntitlements.size(), 2); for (final Entitlement entitlement : oldEntitlements) { final List<Entitlement> newEntitlements = entitlementApi.getAllEntitlementsForBundle(newBundleId, callContext); Assert.assertEquals(newEntitlements.size(), 2); for (final Entitlement entitlement : newEntitlements) {
@TimedResource @PUT @Path("/{bundleId:" + UUID_PATTERN + "}/" + RESUME) @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @ApiOperation(value = "Resume a bundle") @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"), @ApiResponse(code = 400, message = "Invalid bundle id supplied"), @ApiResponse(code = 404, message = "Bundle not found")}) public Response resumeBundle(@PathParam(ID_PARAM_NAME) final UUID bundleId, @QueryParam(QUERY_REQUESTED_DT) final String requestedDate, @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString, @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) throws SubscriptionApiException, EntitlementApiException, AccountApiException { final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString); final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request); final LocalDate inputLocalDate = toLocalDate(requestedDate); entitlementApi.resume(bundleId, inputLocalDate, pluginProperties, callContext); return Response.status(Status.NO_CONTENT).build(); }
@TimedResource @PUT @Path("/{bundleId:" + UUID_PATTERN + "}/" + PAUSE) @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @ApiOperation(value = "Pause a bundle") @ApiResponses(value = {@ApiResponse(code = 204, message = "Successful operation"), @ApiResponse(code = 400, message = "Invalid bundle id supplied"), @ApiResponse(code = 404, message = "Bundle not found")}) public Response pauseBundle(@PathParam(ID_PARAM_NAME) final UUID bundleId, @QueryParam(QUERY_REQUESTED_DT) final String requestedDate, @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString, @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) throws SubscriptionApiException, EntitlementApiException, AccountApiException { final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString); final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request); final LocalDate inputLocalDate = toLocalDate(requestedDate); entitlementApi.pause(bundleId, inputLocalDate, pluginProperties, callContext); return Response.status(Status.NO_CONTENT).build(); }