private boolean responseIsIn(final PaymentResponse actualResponse, final PaymentResponse[] responseForLastFailedPayment) { for (final PaymentResponse response : responseForLastFailedPayment) { if (response.equals(actualResponse)) { return true; } } return false; }
public OverdueState refresh(final InternalCallContext context) throws OverdueException, OverdueApiException { if (overdueStateSet.size() < 1) { // No configuration available return overdueStateSet.getClearState(); } final BillingState billingState = billingState(context); final String previousOverdueStateName = api.getBlockingStateForService(overdueable.getId(), BlockingStateType.ACCOUNT, OverdueService.OVERDUE_SERVICE_NAME, context).getStateName(); final OverdueState currentOverdueState = overdueStateSet.findState(previousOverdueStateName); final OverdueState nextOverdueState = overdueStateSet.calculateOverdueState(billingState, clock.getToday(billingState.getAccountTimeZone())); overdueStateApplicator.apply(overdueStateSet, billingState, overdueable, currentOverdueState, nextOverdueState, context); return nextOverdueState; }
@Override public boolean evaluate(final BillingState state, final LocalDate date) { LocalDate unpaidInvoiceTriggerDate = null; if (timeSinceEarliestUnpaidInvoiceEqualsOrExceeds != null && state.getDateOfEarliestUnpaidInvoice() != null) { // no date => no unpaid invoices unpaidInvoiceTriggerDate = state.getDateOfEarliestUnpaidInvoice().plus(timeSinceEarliestUnpaidInvoiceEqualsOrExceeds.toJodaPeriod()); } return (numberOfUnpaidInvoicesEqualsOrExceeds == null || state.getNumberOfUnpaidInvoices() >= numberOfUnpaidInvoicesEqualsOrExceeds) && (totalUnpaidInvoiceBalanceEqualsOrExceeds == null || totalUnpaidInvoiceBalanceEqualsOrExceeds.compareTo(state.getBalanceOfUnpaidInvoices()) <= 0) && (timeSinceEarliestUnpaidInvoiceEqualsOrExceeds == null || (unpaidInvoiceTriggerDate != null && !unpaidInvoiceTriggerDate.isAfter(date))) && (responseForLastFailedPayment == null || responseIsIn(state.getResponseForLastFailedPayment(), responseForLastFailedPayment)) && (controlTag == null || isTagIn(controlTag, state.getTags())); }
@Test(groups = "fast") public void testBalanceFormatting() throws Exception { final BillingState billingState = new BillingState(UUID.randomUUID(), 2, BigDecimal.TEN, new LocalDate(), DateTimeZone.UTC, UUID.randomUUID(), null, null); final DefaultBillingStateFormatter formatter = new DefaultBillingStateFormatter(billingState); Assert.assertEquals(formatter.getFormattedBalanceOfUnpaidInvoices(), "10.00"); } }
final OverdueState firstOverdueState = overdueStateSet.getFirstState(); final boolean conditionForNextNotfication = !nextOverdueState.isClearState() || (firstOverdueState != null && billingState != null && billingState.getDateOfEarliestUnpaidInvoice() != null); final Period reevaluationInterval = nextOverdueState.isClearState() ? overdueStateSet.getInitialReevaluationInterval() : nextOverdueState.getReevaluationInterval(); throw new OverdueException(e);
@SuppressWarnings("unchecked") public OverdueWrapper createOverdueWrapperFor(final UUID id, final InternalTenantContext context) throws OverdueException { try { Account account = accountApi.getAccountById(id, context); return new OverdueWrapper(account, api, getOverdueStateSet(), clock, billingStateCalculator, overdueStateApplicator); } catch (AccountApiException e) { throw new OverdueException(e); } }
@SuppressWarnings("unchecked") @Override public OverdueState getOverdueStateFor(final Account overdueable, final TenantContext context) throws OverdueException { try { final String stateName = accessApi.getBlockingStateForService(overdueable.getId(), BlockingStateType.ACCOUNT, OverdueService.OVERDUE_SERVICE_NAME, internalCallContextFactory.createInternalTenantContext(context)).getStateName(); final OverdueStateSet states = overdueConfig.getStateSet(); return states.findState(stateName); } catch (OverdueApiException e) { throw new OverdueException(e, ErrorCode.OVERDUE_CAT_ERROR_ENCOUNTERED, overdueable.getId(), overdueable.getClass().getSimpleName()); } }
public void clear(final InternalCallContext context) throws OverdueException, OverdueApiException { final String previousOverdueStateName = api.getBlockingStateForService(overdueable.getId(), BlockingStateType.ACCOUNT, OverdueService.OVERDUE_SERVICE_NAME, context).getStateName(); final OverdueState previousOverdueState = overdueStateSet.findState(previousOverdueStateName); overdueStateApplicator.clear(overdueable, previousOverdueState, overdueStateSet.getClearState(), context); }
@Test(groups = "fast") public void testNumberOfUnpaidInvoicesEqualsOrExceeds() throws Exception { final String xml = "<condition>" + " <numberOfUnpaidInvoicesEqualsOrExceeds>1</numberOfUnpaidInvoicesEqualsOrExceeds>" + "</condition>"; final InputStream is = new ByteArrayInputStream(xml.getBytes()); final MockCondition c = XMLLoader.getObjectFromStreamNoValidation(is, MockCondition.class); final UUID unpaidInvoiceId = UUID.randomUUID(); final BillingState state0 = new BillingState(new UUID(0L, 1L), 0, BigDecimal.ZERO, new LocalDate(), DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}); final BillingState state1 = new BillingState(new UUID(0L, 1L), 1, BigDecimal.ZERO, new LocalDate(), DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}); final BillingState state2 = new BillingState(new UUID(0L, 1L), 2, BigDecimal.ZERO, new LocalDate(), DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}); Assert.assertTrue(!c.evaluate(state0, new LocalDate())); Assert.assertTrue(c.evaluate(state1, new LocalDate())); Assert.assertTrue(c.evaluate(state2, new LocalDate())); }
private boolean isAccountTaggedWith_OVERDUE_ENFORCEMENT_OFF(final InternalCallContext context) throws OverdueException { try { final UUID accountId = accountApi.getByRecordId(context.getAccountRecordId(), context); final List<Tag> accountTags = tagApi.getTags(accountId, ObjectType.ACCOUNT, context); for (Tag cur : accountTags) { if (cur.getTagDefinitionId().equals(ControlTagType.OVERDUE_ENFORCEMENT_OFF.getId())) { return true; } } return false; } catch (AccountApiException e) { throw new OverdueException(e); } } }
@Test(groups = "fast") public void testTotalUnpaidInvoiceBalanceEqualsOrExceeds() throws Exception { final String xml = "<condition>" + " <totalUnpaidInvoiceBalanceEqualsOrExceeds>100.00</totalUnpaidInvoiceBalanceEqualsOrExceeds>" + "</condition>"; final InputStream is = new ByteArrayInputStream(xml.getBytes()); final MockCondition c = XMLLoader.getObjectFromStreamNoValidation(is, MockCondition.class); final UUID unpaidInvoiceId = UUID.randomUUID(); final BillingState state0 = new BillingState(new UUID(0L, 1L), 0, BigDecimal.ZERO, new LocalDate(), DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}); final BillingState state1 = new BillingState(new UUID(0L, 1L), 1, new BigDecimal("100.00"), new LocalDate(), DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}); final BillingState state2 = new BillingState(new UUID(0L, 1L), 1, new BigDecimal("200.00"), new LocalDate(), DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}); Assert.assertTrue(!c.evaluate(state0, new LocalDate())); Assert.assertTrue(c.evaluate(state1, new LocalDate())); Assert.assertTrue(c.evaluate(state2, new LocalDate())); }
public void clear(final Account account, final OverdueState previousOverdueState, final OverdueState clearState, final InternalCallContext context) throws OverdueException { log.debug("OverdueStateApplicator:clear : time = " + clock.getUTCNow() + ", previousState = " + previousOverdueState.getName()); storeNewState(account, clearState, context); clearFutureNotification(account, context); try { avoid_extra_credit_by_toggling_AUTO_INVOICE_OFF(account, previousOverdueState, clearState, context); } catch (OverdueApiException e) { throw new OverdueException(e); } try { bus.post(createOverdueEvent(account, previousOverdueState.getName(), clearState.getName(), isBlockBillingTransition(previousOverdueState, clearState), isUnblockBillingTransition(previousOverdueState, clearState), context)); } catch (Exception e) { log.error("Error posting overdue change event to bus", e); } }
public BillingState calculateBillingState(final Account account, final InternalTenantContext context) throws OverdueException { final SortedSet<Invoice> unpaidInvoices = unpaidInvoicesForAccount(account.getId(), account.getTimeZone(), 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 Tag[] tags = new Tag[]{}; //TODO MDW return new BillingState(account.getId(), numberOfUnpaidInvoices, unpaidInvoiceBalance, dateOfEarliestUnpaidInvoice, account.getTimeZone(), idOfEarliestUnpaidInvoice, responseForLastFailedPayment, tags); }
protected void storeNewState(final Account 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), clock.getUTCNow()), context); } catch (Exception e) { throw new OverdueException(e, ErrorCode.OVERDUE_CAT_ERROR_ENCOUNTERED, blockable.getId(), blockable.getClass().getName()); } }
@Test(groups = "fast") public void testResponseForLastFailedPaymentIn() throws Exception { final String xml = "<condition>" + " <responseForLastFailedPaymentIn><response>INSUFFICIENT_FUNDS</response><response>DO_NOT_HONOR</response></responseForLastFailedPaymentIn>" + "</condition>"; final InputStream is = new ByteArrayInputStream(xml.getBytes()); final MockCondition c = XMLLoader.getObjectFromStreamNoValidation(is, MockCondition.class); final UUID unpaidInvoiceId = UUID.randomUUID(); final LocalDate now = new LocalDate(); final BillingState state0 = new BillingState(new UUID(0L, 1L), 0, BigDecimal.ZERO, null, DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.LOST_OR_STOLEN_CARD, new Tag[]{}); final BillingState state1 = new BillingState(new UUID(0L, 1L), 1, new BigDecimal("100.00"), now.minusDays(10), DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}); final BillingState state2 = new BillingState(new UUID(0L, 1L), 1, new BigDecimal("200.00"), now.minusDays(20), DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.DO_NOT_HONOR, new Tag[]{}); Assert.assertTrue(!c.evaluate(state0, now)); Assert.assertTrue(c.evaluate(state1, now)); Assert.assertTrue(c.evaluate(state2, now)); }
throw new OverdueException(e); throw new OverdueException(e);
@Test(groups = "fast") public void testTimeSinceEarliestUnpaidInvoiceEqualsOrExceeds() throws Exception { final String xml = "<condition>" + " <timeSinceEarliestUnpaidInvoiceEqualsOrExceeds><unit>DAYS</unit><number>10</number></timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" + "</condition>"; final InputStream is = new ByteArrayInputStream(xml.getBytes()); final MockCondition c = XMLLoader.getObjectFromStreamNoValidation(is, MockCondition.class); final UUID unpaidInvoiceId = UUID.randomUUID(); final LocalDate now = new LocalDate(); final BillingState state0 = new BillingState(new UUID(0L, 1L), 0, BigDecimal.ZERO, null, DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}); final BillingState state1 = new BillingState(new UUID(0L, 1L), 1, new BigDecimal("100.00"), now.minusDays(10), DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}); final BillingState state2 = new BillingState(new UUID(0L, 1L), 1, new BigDecimal("200.00"), now.minusDays(20), DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{}); Assert.assertTrue(!c.evaluate(state0, now)); Assert.assertTrue(c.evaluate(state1, now)); Assert.assertTrue(c.evaluate(state2, now)); }
final BillingState state0 = new BillingState(objectId, 0, BigDecimal.ZERO, null, DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.LOST_OR_STOLEN_CARD, new Tag[]{new DefaultControlTag(ControlTagType.AUTO_INVOICING_OFF, objectType, objectId, clock.getUTCNow()), new DescriptiveTag(UUID.randomUUID(), objectType, objectId, clock.getUTCNow())}); final BillingState state1 = new BillingState(objectId, 1, new BigDecimal("100.00"), now.minusDays(10), DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{new DefaultControlTag(ControlTagType.OVERDUE_ENFORCEMENT_OFF, objectType, objectId, clock.getUTCNow())}); final BillingState state2 = new BillingState(objectId, 1, new BigDecimal("200.00"), now.minusDays(20), DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.DO_NOT_HONOR,