protected void clearFutureNotification(final ImmutableAccountData account, final InternalCallContext context) { // Need to clear the override table here too (when we add it) checkPoster.clearOverdueCheckNotifications(account.getId(), OverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE, OverdueCheckNotificationKey.class, context); }
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); }
protected void createFutureNotification(final ImmutableAccountData account, final DateTime timeOfNextCheck, final InternalCallContext context) { final OverdueCheckNotificationKey notificationKey = new OverdueCheckNotificationKey(account.getId()); checkPoster.insertOverdueNotification(account.getId(), timeOfNextCheck, OverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE, notificationKey, context); }
private void avoid_extra_credit_by_toggling_AUTO_INVOICE_OFF(final ImmutableAccountData account, final OverdueState previousOverdueState, final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueApiException { if (isBlockBillingTransition(previousOverdueState, nextOverdueState)) { set_AUTO_INVOICE_OFF_on_blockedBilling(account.getId(), context); } else if (isUnblockBillingTransition(previousOverdueState, nextOverdueState)) { remove_AUTO_INVOICE_OFF_on_clear(account.getId(), context); } }
public BillingState calculateBillingState(final ImmutableAccountData account, final InternalCallContext context) throws OverdueException { final SortedSet<Invoice> unpaidInvoices = unpaidInvoicesForAccount(account.getId(), context); final int numberOfUnpaidInvoices = unpaidInvoices.size(); final BigDecimal unpaidInvoiceBalance = sumBalance(unpaidInvoices); LocalDate dateOfEarliestUnpaidInvoice = null; UUID idOfEarliestUnpaidInvoice = null; final Invoice invoice = earliest(unpaidInvoices); if (invoice != null) { dateOfEarliestUnpaidInvoice = invoice.getInvoiceDate(); idOfEarliestUnpaidInvoice = invoice.getId(); } final PaymentResponse responseForLastFailedPayment = PaymentResponse.INSUFFICIENT_FUNDS; //TODO MDW final List<Tag> accountTags = tagApi.getTags(account.getId(), ObjectType.ACCOUNT, context); final Tag[] tags = accountTags.toArray(new Tag[accountTags.size()]); return new BillingState(account.getId(), numberOfUnpaidInvoices, unpaidInvoiceBalance, dateOfEarliestUnpaidInvoice, idOfEarliestUnpaidInvoice, responseForLastFailedPayment, tags); }
protected void storeNewState(final DateTime effectiveDate, final ImmutableAccountData blockable, final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException { try { blockingApi.setBlockingState(new DefaultBlockingState(blockable.getId(), BlockingStateType.ACCOUNT, nextOverdueState.getName(), OverdueService.OVERDUE_SERVICE_NAME, blockChanges(nextOverdueState), blockEntitlement(nextOverdueState), blockBilling(nextOverdueState), effectiveDate), context); } catch (final Exception e) { throw new OverdueException(e, ErrorCode.OVERDUE_CAT_ERROR_ENCOUNTERED, blockable.getId(), blockable.getClass().getName()); } }
@Override public int getBCD(final InternalTenantContext context) throws AccountApiException { final CacheLoaderArgument arg = createBCDCacheLoaderArgument(context); Preconditions.checkNotNull(context.getAccountRecordId(), "Context missing accountRecordId"); final ImmutableAccountData account = immutableAccountInternalApi.getImmutableAccountDataByRecordId(context.getAccountRecordId(), context); final Integer result = bcdCacheController.get(account.getId(), arg); return result != null ? result : DefaultMutableAccountData.DEFAULT_BILLING_CYCLE_DAY_LOCAL; }
private OverdueChangeInternalEvent createOverdueEvent(final ImmutableAccountData overdueable, final String previousOverdueStateName, final String nextOverdueStateName, final boolean isBlockedBilling, final boolean isUnblockedBilling, final InternalCallContext context) throws BlockingApiException { return new DefaultOverdueChangeEvent(overdueable.getId(), previousOverdueStateName, nextOverdueStateName, isBlockedBilling, isUnblockedBilling, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()); }
log.debug("OverdueStateApplicator <notificationQ>: missing InitialReevaluationInterval from config, NOT inserting notification for account {}", account.getId()); } else { log.debug("OverdueStateApplicator <notificationQ>: inserting notification for account={}, time={}", account.getId(), effectiveDate.plus(reevaluationInterval)); createFutureNotification(account, effectiveDate.plus(reevaluationInterval), context); isUnblockBillingTransition(previousOverdueState, nextOverdueState), context); } catch (final BlockingApiException e) { log.warn("Failed to create OverdueChangeInternalEvent for accountId='{}'", account.getId(), e); return;
public void clear(final DateTime effectiveDate, final ImmutableAccountData account, final OverdueState previousOverdueState, final OverdueState clearState, final InternalCallContext context) throws OverdueException { log.debug("OverdueStateApplicator:clear : time = " + effectiveDate + ", previousState = " + previousOverdueState.getName()); storeNewState(effectiveDate, account, clearState, context); clearFutureNotification(account, context); try { avoid_extra_credit_by_toggling_AUTO_INVOICE_OFF(account, previousOverdueState, clearState, context); } catch (final OverdueApiException e) { throw new OverdueException(e); } final OverdueChangeInternalEvent event; try { event = createOverdueEvent(account, previousOverdueState.getName(), clearState.getName(), isBlockBillingTransition(previousOverdueState, clearState), isUnblockBillingTransition(previousOverdueState, clearState), context); } catch (final BlockingApiException e) { log.warn("Failed to create OverdueChangeInternalEvent for accountId='{}'", account.getId(), e); return; } try { bus.post(event); } catch (final Exception e) { log.warn("Failed to post event {}", event, e); } }
@Test(groups = "slow") public void testApplicator() throws Exception { final InputStream is = new ByteArrayInputStream(testOverdueHelper.getConfigXml().getBytes()); final DefaultOverdueConfig config = XMLLoader.getObjectFromStreamNoValidation(is, DefaultOverdueConfig.class); final ImmutableAccountData account = Mockito.mock(ImmutableAccountData.class); Mockito.when(account.getId()).thenReturn(UUID.randomUUID()); final OverdueStateSet overdueStateSet = config.getOverdueStatesAccount(); final OverdueState clearState = config.getOverdueStatesAccount().findState(OverdueWrapper.CLEAR_STATE_NAME); OverdueState state; state = config.getOverdueStatesAccount().findState("OD1"); applicator.apply(clock.getUTCNow(), overdueStateSet, null, account, clearState, state, internalCallContext); testOverdueHelper.checkStateApplied(state); checkBussEvent("OD1"); state = config.getOverdueStatesAccount().findState("OD2"); applicator.apply(clock.getUTCNow(), overdueStateSet, null, account, clearState, state, internalCallContext); testOverdueHelper.checkStateApplied(state); checkBussEvent("OD2"); state = config.getOverdueStatesAccount().findState("OD3"); applicator.apply(clock.getUTCNow(), overdueStateSet, null, account, clearState, state, internalCallContext); testOverdueHelper.checkStateApplied(state); checkBussEvent("OD3"); }
protected void clearFutureNotification(final ImmutableAccountData account, final InternalCallContext context) { // Need to clear the override table here too (when we add it) checkPoster.clearOverdueCheckNotifications(account.getId(), OverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE, OverdueCheckNotificationKey.class, context); }
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); }
protected void createFutureNotification(final ImmutableAccountData account, final DateTime timeOfNextCheck, final InternalCallContext context) { final OverdueCheckNotificationKey notificationKey = new OverdueCheckNotificationKey(account.getId()); checkPoster.insertOverdueNotification(account.getId(), timeOfNextCheck, OverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE, notificationKey, context); }
private void logInvoiceWithItems(final ImmutableAccountData account, final Invoice invoice, final LocalDate targetDate, final Set<UUID> adjustedUniqueOtherInvoiceId, final boolean isRealInvoiceWithItems) { final StringBuilder tmp = new StringBuilder(); if (isRealInvoiceWithItems) { tmp.append(String.format("Generated invoiceId='%s', numberOfItems='%d', accountId='%s', targetDate='%s':", invoice.getId(), invoice.getNumberOfItems(), account.getId(), targetDate)); } else { final String adjustedInvoices = JOINER_COMMA.join(adjustedUniqueOtherInvoiceId.toArray(new UUID[adjustedUniqueOtherInvoiceId.size()])); tmp.append(String.format("Adjusting existing invoiceId='%s', numberOfItems='%d', accountId='%s', targetDate='%s':\n", adjustedInvoices, invoice.getNumberOfItems(), account.getId(), targetDate)); } for (final InvoiceItem item : invoice.getInvoiceItems()) { tmp.append(String.format("\n\t item = %s", item)); } log.info(tmp.toString()); }
private void avoid_extra_credit_by_toggling_AUTO_INVOICE_OFF(final ImmutableAccountData account, final OverdueState previousOverdueState, final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueApiException { if (isBlockBillingTransition(previousOverdueState, nextOverdueState)) { set_AUTO_INVOICE_OFF_on_blockedBilling(account.getId(), context); } else if (isUnblockBillingTransition(previousOverdueState, nextOverdueState)) { remove_AUTO_INVOICE_OFF_on_clear(account.getId(), context); } }
private void commitInvoiceAndSetFutureNotifications(final ImmutableAccountData account, @Nullable final InvoiceModelDao invoiceModelDao, final Set<InvoiceTrackingModelDao> trackingIds, final FutureAccountNotifications futureAccountNotifications, final InternalCallContext context) { final boolean isThereAnyItemsLeft = invoiceModelDao != null && !invoiceModelDao.getInvoiceItems().isEmpty(); if (isThereAnyItemsLeft) { invoiceDao.createInvoice(invoiceModelDao, trackingIds, futureAccountNotifications, context); } else { invoiceDao.setFutureAccountNotificationsForEmptyInvoice(account.getId(), futureAccountNotifications, context); } }
protected void storeNewState(final DateTime effectiveDate, final ImmutableAccountData blockable, final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException { try { blockingApi.setBlockingState(new DefaultBlockingState(blockable.getId(), BlockingStateType.ACCOUNT, nextOverdueState.getName(), OverdueService.OVERDUE_SERVICE_NAME, blockChanges(nextOverdueState), blockEntitlement(nextOverdueState), blockBilling(nextOverdueState), effectiveDate), context); } catch (final Exception e) { throw new OverdueException(e, ErrorCode.OVERDUE_CAT_ERROR_ENCOUNTERED, blockable.getId(), blockable.getClass().getName()); } }
@Override public int getBCD(final InternalTenantContext context) throws AccountApiException { final CacheLoaderArgument arg = createBCDCacheLoaderArgument(context); Preconditions.checkNotNull(context.getAccountRecordId(), "Context missing accountRecordId"); final ImmutableAccountData account = immutableAccountInternalApi.getImmutableAccountDataByRecordId(context.getAccountRecordId(), context); final Integer result = bcdCacheController.get(account.getId(), arg); return result != null ? result : DefaultMutableAccountData.DEFAULT_BILLING_CYCLE_DAY_LOCAL; }
private OverdueChangeInternalEvent createOverdueEvent(final ImmutableAccountData overdueable, final String previousOverdueStateName, final String nextOverdueStateName, final boolean isBlockedBilling, final boolean isUnblockedBilling, final InternalCallContext context) throws BlockingApiException { return new DefaultOverdueChangeEvent(overdueable.getId(), previousOverdueStateName, nextOverdueStateName, isBlockedBilling, isUnblockedBilling, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()); }