@VisibleForTesting DateTime getEffectiveDateForNewBCD(final int bcd, @Nullable final LocalDate effectiveFromDate, final InternalCallContext internalCallContext) { if (internalCallContext.getAccountRecordId() == null) { throw new IllegalStateException("Need to have a valid context with accountRecordId"); } // Today as seen by this account final LocalDate startDate = effectiveFromDate != null ? effectiveFromDate : internalCallContext.toLocalDate(internalCallContext.getCreatedDate()); // We want to compute a LocalDate in account TZ which maps to the provided 'bcd' and then compute an effectiveDate for when that BCD_CHANGE event needs to be triggered // // There is a bit of complexity to make sure the date we chose exists (e.g: a BCD of 31 in a february month would not make sense). final int currentDay = startDate.getDayOfMonth(); final int lastDayOfMonth = startDate.dayOfMonth().getMaximumValue(); final LocalDate requestedDate; if (bcd < currentDay) { final LocalDate startDatePlusOneMonth = startDate.plusMonths(1); final int lastDayOfNextMonth = startDatePlusOneMonth.dayOfMonth().getMaximumValue(); final int originalBCDORLastDayOfMonth = bcd <= lastDayOfNextMonth ? bcd : lastDayOfNextMonth; requestedDate = new LocalDate(startDatePlusOneMonth.getYear(), startDatePlusOneMonth.getMonthOfYear(), originalBCDORLastDayOfMonth); } else if (bcd == currentDay && effectiveFromDate == null) { // will default to immediate event requestedDate = null; } else if (bcd <= lastDayOfMonth) { requestedDate = new LocalDate(startDate.getYear(), startDate.getMonthOfYear(), bcd); } else /* bcd > lastDayOfMonth && bcd > currentDay */ { requestedDate = new LocalDate(startDate.getYear(), startDate.getMonthOfYear(), lastDayOfMonth); } return requestedDate == null ? internalCallContext.getCreatedDate() : internalCallContext.toUTCDateTime(requestedDate); }
context.toUTCDateTime(subscriptionBaseWithAddOnsSpecifier.getBillingEffectiveDate()) : context.getCreatedDate();
private void populateNextFutureDryRunNotificationDate(final BillingEventSet billingEvents, final FutureAccountNotificationsBuilder notificationsBuilder, final InternalCallContext context) { final Map<LocalDate, Set<UUID>> notificationListForTrigger = notificationsBuilder.getNotificationListForTrigger(); final long dryRunNotificationTime = invoiceConfig.getDryRunNotificationSchedule(context).getMillis(); final boolean isInvoiceNotificationEnabled = dryRunNotificationTime > 0; final Map<LocalDate, Set<UUID>> notificationListForDryRun = isInvoiceNotificationEnabled ? new HashMap<LocalDate, Set<UUID>>() : ImmutableMap.<LocalDate, Set<UUID>>of(); if (isInvoiceNotificationEnabled) { for (final LocalDate curDate : notificationListForTrigger.keySet()) { final LocalDate curDryRunDate = context.toLocalDate(context.toUTCDateTime(curDate).minus(dryRunNotificationTime)); Set<UUID> subscriptionsForDryRunDates = notificationListForDryRun.get(curDryRunDate); if (subscriptionsForDryRunDates == null) { subscriptionsForDryRunDates = new HashSet<UUID>(); notificationListForDryRun.put(curDryRunDate, subscriptionsForDryRunDates); } subscriptionsForDryRunDates.addAll(notificationListForTrigger.get(curDate)); } final Map<UUID, DateTime> upcomingTransitionsForSubscriptions = isInvoiceNotificationEnabled ? getNextTransitionsForSubscriptions(billingEvents) : ImmutableMap.<UUID, DateTime>of(); for (UUID curId : upcomingTransitionsForSubscriptions.keySet()) { final LocalDate curDryRunDate = context.toLocalDate(upcomingTransitionsForSubscriptions.get(curId).minus(dryRunNotificationTime)); Set<UUID> subscriptionsForDryRunDates = notificationListForDryRun.get(curDryRunDate); if (subscriptionsForDryRunDates == null) { subscriptionsForDryRunDates = new HashSet<UUID>(); notificationListForDryRun.put(curDryRunDate, subscriptionsForDryRunDates); } subscriptionsForDryRunDates.add(curId); } } notificationsBuilder.setNotificationListForDryRun(notificationListForDryRun); }
private void notifyOfFutureBillingEvents(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final UUID accountId, final FutureAccountNotifications callbackDateTimePerSubscriptions, final InternalCallContext internalCallContext) { for (final LocalDate notificationDate : callbackDateTimePerSubscriptions.getNotificationsForTrigger().keySet()) { final DateTime notificationDateTime = internalCallContext.toUTCDateTime(notificationDate); final Set<UUID> subscriptionIds = callbackDateTimePerSubscriptions.getNotificationsForTrigger().get(notificationDate); nextBillingDatePoster.insertNextBillingNotificationFromTransaction(entitySqlDaoWrapperFactory, accountId, subscriptionIds, notificationDateTime, callbackDateTimePerSubscriptions.isRescheduled(), internalCallContext); } final long dryRunNotificationTime = invoiceConfig.getDryRunNotificationSchedule(internalCallContext).getMillis(); if (dryRunNotificationTime > 0) { for (final LocalDate notificationDate : callbackDateTimePerSubscriptions.getNotificationsForDryRun().keySet()) { final DateTime notificationDateTime = internalCallContext.toUTCDateTime(notificationDate); if (notificationDateTime.compareTo(internalCallContext.getCreatedDate()) > 0) { final Set<UUID> subscriptionIds = callbackDateTimePerSubscriptions.getNotificationsForDryRun().get(notificationDate); nextBillingDatePoster.insertNextBillingDryRunNotificationFromTransaction(entitySqlDaoWrapperFactory, accountId, subscriptionIds, notificationDateTime, notificationDateTime.plusMillis((int) dryRunNotificationTime), internalCallContext); } } } }
public void processSubscriptionForInvoiceNotification(final UUID subscriptionId, final LocalDate targetDate, final InternalCallContext context) throws InvoiceApiException { final Invoice dryRunInvoice = processSubscriptionInternal(subscriptionId, targetDate, true, false, context); if (dryRunInvoice != null && dryRunInvoice.getBalance().compareTo(BigDecimal.ZERO) > 0) { final InvoiceNotificationInternalEvent event = new DefaultInvoiceNotificationInternalEvent(dryRunInvoice.getAccountId(), dryRunInvoice.getBalance(), dryRunInvoice.getCurrency(), context.toUTCDateTime(targetDate), context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()); try { eventBus.post(event); } catch (EventBusException e) { log.warn("Failed to post event {}", event, e); } } }
@VisibleForTesting DateTime getEffectiveDateForNewBCD(final int bcd, @Nullable final LocalDate effectiveFromDate, final InternalCallContext internalCallContext) { if (internalCallContext.getAccountRecordId() == null) { throw new IllegalStateException("Need to have a valid context with accountRecordId"); } // Today as seen by this account final LocalDate startDate = effectiveFromDate != null ? effectiveFromDate : internalCallContext.toLocalDate(internalCallContext.getCreatedDate()); // We want to compute a LocalDate in account TZ which maps to the provided 'bcd' and then compute an effectiveDate for when that BCD_CHANGE event needs to be triggered // // There is a bit of complexity to make sure the date we chose exists (e.g: a BCD of 31 in a february month would not make sense). final int currentDay = startDate.getDayOfMonth(); final int lastDayOfMonth = startDate.dayOfMonth().getMaximumValue(); final LocalDate requestedDate; if (bcd < currentDay) { final LocalDate startDatePlusOneMonth = startDate.plusMonths(1); final int lastDayOfNextMonth = startDatePlusOneMonth.dayOfMonth().getMaximumValue(); final int originalBCDORLastDayOfMonth = bcd <= lastDayOfNextMonth ? bcd : lastDayOfNextMonth; requestedDate = new LocalDate(startDatePlusOneMonth.getYear(), startDatePlusOneMonth.getMonthOfYear(), originalBCDORLastDayOfMonth); } else if (bcd == currentDay && effectiveFromDate == null) { // will default to immediate event requestedDate = null; } else if (bcd <= lastDayOfMonth) { requestedDate = new LocalDate(startDate.getYear(), startDate.getMonthOfYear(), bcd); } else /* bcd > lastDayOfMonth && bcd > currentDay */ { requestedDate = new LocalDate(startDate.getYear(), startDate.getMonthOfYear(), lastDayOfMonth); } return requestedDate == null ? internalCallContext.getCreatedDate() : internalCallContext.toUTCDateTime(requestedDate); }
context.toUTCDateTime(subscriptionBaseWithAddOnsSpecifier.getBillingEffectiveDate()) : context.getCreatedDate();
break; final BigDecimal rate = thisEvent.getRecurringPrice(internalCallContext.toUTCDateTime(itemDatum.getStartDate())); if (rate != null) { final BigDecimal amount = KillBillMoney.of(itemDatum.getNumberOfCycles().multiply(rate), currency);