killbill-aplcache
Changes
invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java 100(+59 -41)
invoice/src/main/java/org/killbill/billing/invoice/model/RecurringInvoiceItemDataWithNextBillingCycleDate.java 45(+45 -0)
invoice/src/test/java/org/killbill/billing/invoice/generator/TestInAdvanceBillingIntervalDetail.java 2(+1 -1)
Details
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/BillingIntervalDetail.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/BillingIntervalDetail.java
index 513cd87..51f2845 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/BillingIntervalDetail.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/BillingIntervalDetail.java
@@ -30,7 +30,9 @@ public class BillingIntervalDetail {
private final int billingCycleDay;
private final BillingPeriod billingPeriod;
private final BillingMode billingMode;
+ // First date after the startDate aligned with the BCD
private LocalDate firstBillingCycleDate;
+ // Date up to which we should bill
private LocalDate effectiveEndDate;
private LocalDate lastBillingCycleDate;
@@ -67,6 +69,14 @@ public class BillingIntervalDetail {
return lastBillingCycleDate;
}
+ public LocalDate getNextBillingCycleDate() {
+ final int numberOfMonthsInPeriod = billingPeriod.getNumberOfMonths();
+ final LocalDate proposedDate = lastBillingCycleDate != null ? lastBillingCycleDate.plusMonths(numberOfMonthsInPeriod) : firstBillingCycleDate;
+ final LocalDate nextBillingCycleDate = alignProposedBillCycleDate(proposedDate, billingCycleDay);
+ return nextBillingCycleDate;
+ }
+
+
public boolean hasSomethingToBill() {
return effectiveEndDate != null /* IN_ARREAR mode prior we have reached our firstBillingCycleDate */ &&
(endDate == null || endDate.isAfter(startDate)); /* When there is an endDate, it should be > startDate since we don't bill for less than a day */
@@ -171,8 +181,9 @@ public class BillingIntervalDetail {
private void calculateLastBillingCycleDate() {
- if (effectiveEndDate == null) {
- lastBillingCycleDate = firstBillingCycleDate;
+ // IN_ARREAR cases
+ if (effectiveEndDate == null || effectiveEndDate.compareTo(firstBillingCycleDate) < 0 ) {
+ lastBillingCycleDate = null;
return;
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
index 070348d..3d8fecc 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
@@ -52,6 +52,7 @@ import org.killbill.billing.invoice.model.FixedPriceInvoiceItem;
import org.killbill.billing.invoice.model.InvalidDateSequenceException;
import org.killbill.billing.invoice.model.RecurringInvoiceItem;
import org.killbill.billing.invoice.model.RecurringInvoiceItemData;
+import org.killbill.billing.invoice.model.RecurringInvoiceItemDataWithNextBillingCycleDate;
import org.killbill.billing.invoice.tree.AccountItemTree;
import org.killbill.billing.invoice.usage.RawUsageOptimizer;
import org.killbill.billing.invoice.usage.RawUsageOptimizer.RawUsageOptimizerResult;
@@ -65,6 +66,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -123,8 +126,6 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates,
final InternalCallContext internalCallContext) throws InvoiceApiException {
- final Map<String, LocalDate> perSubscriptionUsage = new HashMap<String, LocalDate>();
-
final Map<UUID, List<InvoiceItem>> perSubscriptionConsumableInArrearUsageItems = extractPerSubscriptionExistingConsumableInArrearUsageItems(eventSet.getUsages(), existingInvoices);
try {
final List<InvoiceItem> items = Lists.newArrayList();
@@ -163,10 +164,9 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
final SubscriptionConsumableInArrear subscriptionConsumableInArrear = new SubscriptionConsumableInArrear(invoiceId, curEvents, rawUsageOptimizerResult.getRawUsage(), targetDate, rawUsageOptimizerResult.getRawUsageStartDate());
final List<InvoiceItem> consumableInUsageArrearItems = perSubscriptionConsumableInArrearUsageItems.get(curSubscriptionId);
- final List<InvoiceItem> newProposedItems = subscriptionConsumableInArrear.computeMissingUsageInvoiceItems(consumableInUsageArrearItems != null ? consumableInUsageArrearItems : ImmutableList.<InvoiceItem>of());
- items.addAll(newProposedItems);
- updatePerSubscriptionNextNotificationUsageDate(curSubscriptionId, newProposedItems, perSubscriptionFutureNotificationDates);
-
+ final List<InvoiceItem> newInArrearUsageItems = subscriptionConsumableInArrear.computeMissingUsageInvoiceItems(consumableInUsageArrearItems != null ? consumableInUsageArrearItems : ImmutableList.<InvoiceItem>of());
+ items.addAll(newInArrearUsageItems);
+ updatePerSubscriptionNextNotificationUsageDate(curSubscriptionId, newInArrearUsageItems, BillingMode.IN_ARREAR, perSubscriptionFutureNotificationDates);
curEvents = Lists.newArrayList();
}
curSubscriptionId = subscriptionId;
@@ -176,9 +176,9 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
final SubscriptionConsumableInArrear subscriptionConsumableInArrear = new SubscriptionConsumableInArrear(invoiceId, curEvents, rawUsageOptimizerResult.getRawUsage(), targetDate, rawUsageOptimizerResult.getRawUsageStartDate());
final List<InvoiceItem> consumableInUsageArrearItems = perSubscriptionConsumableInArrearUsageItems.get(curSubscriptionId);
- final List<InvoiceItem> newProposedItems = subscriptionConsumableInArrear.computeMissingUsageInvoiceItems(consumableInUsageArrearItems != null ? consumableInUsageArrearItems : ImmutableList.<InvoiceItem>of());
- items.addAll(newProposedItems);
- updatePerSubscriptionNextNotificationUsageDate(curSubscriptionId, newProposedItems, perSubscriptionFutureNotificationDates);
+ final List<InvoiceItem> newInArrearUsageItems = subscriptionConsumableInArrear.computeMissingUsageInvoiceItems(consumableInUsageArrearItems != null ? consumableInUsageArrearItems : ImmutableList.<InvoiceItem>of());
+ items.addAll(newInArrearUsageItems);
+ updatePerSubscriptionNextNotificationUsageDate(curSubscriptionId, newInArrearUsageItems, BillingMode.IN_ARREAR, perSubscriptionFutureNotificationDates);
}
return items;
@@ -188,14 +188,14 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
}
- private void updatePerSubscriptionNextNotificationUsageDate(final UUID subscriptionId, final List<InvoiceItem> newProposedItems, Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates) {
- for (final InvoiceItem item : newProposedItems) {
+ private void updatePerSubscriptionNextNotificationUsageDate(final UUID subscriptionId, final List<InvoiceItem> newInArrearUsageItems, final BillingMode usageBillingMode, final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates) {
+ for (final InvoiceItem item : newInArrearUsageItems) {
SubscriptionFutureNotificationDates subscriptionFutureNotificationDates = perSubscriptionFutureNotificationDates.get(subscriptionId);
if (subscriptionFutureNotificationDates == null) {
- subscriptionFutureNotificationDates = new SubscriptionFutureNotificationDates();
+ subscriptionFutureNotificationDates = new SubscriptionFutureNotificationDates(null);
perSubscriptionFutureNotificationDates.put(subscriptionId, subscriptionFutureNotificationDates);
}
- subscriptionFutureNotificationDates.updateNextUsageDateIfRequired(item.getUsageName(), item.getEndDate());
+ subscriptionFutureNotificationDates.updateNextUsageDateIfRequired(item.getUsageName(), usageBillingMode, item.getEndDate());
}
}
@@ -285,7 +285,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
private List<InvoiceItem> processRecurringBillingEvents(final UUID invoiceId, final UUID accountId, final BillingEventSet events,
final LocalDate targetDate, final Currency currency, final List<InvoiceItem> proposedItems,
- Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate) throws InvoiceApiException {
+ final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate) throws InvoiceApiException {
if (events.size() == 0) {
return proposedItems;
@@ -305,37 +305,18 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
if (!events.getSubscriptionIdsWithAutoInvoiceOff().
contains(thisEvent.getSubscription().getId())) { // don't consider events for subscriptions that have auto_invoice_off
final BillingEvent adjustedNextEvent = (thisEvent.getSubscription().getId() == nextEvent.getSubscription().getId()) ? nextEvent : null;
- final List<InvoiceItem> newProposedItems = processRecurringEvent(invoiceId, accountId, thisEvent, adjustedNextEvent, targetDate, currency, logStringBuilder, events.getRecurringBillingMode());
+ final List<InvoiceItem> newProposedItems = processRecurringEvent(invoiceId, accountId, thisEvent, adjustedNextEvent, targetDate, currency, logStringBuilder, events.getRecurringBillingMode(), perSubscriptionFutureNotificationDate);
proposedItems.addAll(newProposedItems);
- updatePerSubscriptionNextNotificationDate(thisEvent.getSubscription().getId(), newProposedItems, perSubscriptionFutureNotificationDate);
}
}
- final List<InvoiceItem> newProposedItems = processRecurringEvent(invoiceId, accountId, nextEvent, null, targetDate, currency, logStringBuilder, events.getRecurringBillingMode());
+ final List<InvoiceItem> newProposedItems = processRecurringEvent(invoiceId, accountId, nextEvent, null, targetDate, currency, logStringBuilder, events.getRecurringBillingMode(), perSubscriptionFutureNotificationDate);
proposedItems.addAll(newProposedItems);
- updatePerSubscriptionNextNotificationDate(nextEvent.getSubscription().getId(), newProposedItems, perSubscriptionFutureNotificationDate);
log.info(logStringBuilder.toString());
return proposedItems;
}
- private void updatePerSubscriptionNextNotificationDate(final UUID subscriptionId, final List<InvoiceItem> newProposedItems, Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates) {
- for (final InvoiceItem item : newProposedItems) {
- if ((item.getEndDate() != null) &&
- (item.getAmount() == null ||
- item.getAmount().compareTo(BigDecimal.ZERO) >= 0)) {
- SubscriptionFutureNotificationDates subscriptionFutureNotificationDates = perSubscriptionFutureNotificationDates.get(subscriptionId);
- if (subscriptionFutureNotificationDates == null) {
- subscriptionFutureNotificationDates = new SubscriptionFutureNotificationDates();
- perSubscriptionFutureNotificationDates.put(subscriptionId, subscriptionFutureNotificationDates);
- }
- subscriptionFutureNotificationDates.updateNextRecurringDateIfRequired(item.getEndDate());
- }
- }
- }
-
-
-
private List<InvoiceItem> processFixedBillingEvents(final UUID invoiceId, final UUID accountId, final BillingEventSet events, final LocalDate targetDate, final Currency currency, final List<InvoiceItem> proposedItems) {
final Iterator<BillingEvent> eventIt = events.iterator();
@@ -353,7 +334,8 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
// Turn a set of events into a list of invoice items. Note that the dates on the invoice items will be rounded (granularity of a day)
private List<InvoiceItem> processRecurringEvent(final UUID invoiceId, final UUID accountId, final BillingEvent thisEvent, @Nullable final BillingEvent nextEvent,
final LocalDate targetDate, final Currency currency,
- final StringBuilder logStringBuilder, final BillingMode billingMode) throws InvoiceApiException {
+ final StringBuilder logStringBuilder, final BillingMode billingMode,
+ final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate) throws InvoiceApiException {
final List<InvoiceItem> items = new ArrayList<InvoiceItem>();
// Handle recurring items
@@ -366,14 +348,14 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
final int billCycleDayLocal = thisEvent.getBillCycleDayLocal();
- final List<RecurringInvoiceItemData> itemData;
+ final RecurringInvoiceItemDataWithNextBillingCycleDate itemDataWithNextBillingCycleDate;
try {
- itemData = billingModeGenerator.generateInvoiceItemData(startDate, endDate, targetDate, billCycleDayLocal, billingPeriod, billingMode);
+ itemDataWithNextBillingCycleDate = billingModeGenerator.generateInvoiceItemData(startDate, endDate, targetDate, billCycleDayLocal, billingPeriod, billingMode);
} catch (InvalidDateSequenceException e) {
throw new InvoiceApiException(ErrorCode.INVOICE_INVALID_DATE_SEQUENCE, startDate, endDate, targetDate);
}
- for (final RecurringInvoiceItemData itemDatum : itemData) {
+ for (final RecurringInvoiceItemData itemDatum : itemDataWithNextBillingCycleDate.getItemData()) {
final BigDecimal rate = thisEvent.getRecurringPrice();
if (rate != null) {
@@ -390,6 +372,8 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
items.add(recurringItem);
}
}
+ updatePerSubscriptionNextNotificationDate(thisEvent.getSubscription().getId(), itemDataWithNextBillingCycleDate.getNextBillingCycleDate(), items, thisEvent.getBillingMode(), perSubscriptionFutureNotificationDate);
+
}
}
@@ -400,11 +384,45 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
logStringBuilder.append("\n\t")
.append(item);
}
-
return items;
}
- InvoiceItem generateFixedPriceItem(final UUID invoiceId, final UUID accountId, final BillingEvent thisEvent,
+ private void updatePerSubscriptionNextNotificationDate(final UUID subscriptionId, final LocalDate nextBillingCycleDate, final List<InvoiceItem> newProposedItems, final BillingMode billingMode, final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates) {
+
+ LocalDate nextNotificationDate = null;
+ switch(billingMode) {
+ case IN_ADVANCE:
+ for (final InvoiceItem item : newProposedItems) {
+ if ((item.getEndDate() != null) &&
+ (item.getAmount() == null ||
+ item.getAmount().compareTo(BigDecimal.ZERO) >= 0)) {
+ if (nextNotificationDate == null) {
+ nextNotificationDate = item.getEndDate();
+ } else {
+ nextNotificationDate = nextNotificationDate.compareTo(item.getEndDate()) > 0 ? nextNotificationDate : item.getEndDate();
+ }
+ }
+ }
+ break;
+ case IN_ARREAR:
+ nextNotificationDate = nextBillingCycleDate;
+ break;
+ default:
+ throw new IllegalStateException("Unrecognized billing mode " + billingMode);
+ }
+ if (nextNotificationDate != null) {
+ SubscriptionFutureNotificationDates subscriptionFutureNotificationDates = perSubscriptionFutureNotificationDates.get(subscriptionId);
+ if (subscriptionFutureNotificationDates == null) {
+ subscriptionFutureNotificationDates = new SubscriptionFutureNotificationDates(billingMode);
+ perSubscriptionFutureNotificationDates.put(subscriptionId, subscriptionFutureNotificationDates);
+ }
+ subscriptionFutureNotificationDates.updateNextRecurringDateIfRequired(nextNotificationDate);
+
+ }
+ }
+
+
+ private InvoiceItem generateFixedPriceItem(final UUID invoiceId, final UUID accountId, final BillingEvent thisEvent,
final LocalDate targetDate, final Currency currency) {
final LocalDate roundedStartDate = new LocalDate(thisEvent.getEffectiveDate(), thisEvent.getTimeZone());
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceWithMetadata.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceWithMetadata.java
index a319245..0e0f30e 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceWithMetadata.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceWithMetadata.java
@@ -18,25 +18,80 @@
package org.killbill.billing.invoice.generator;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import javax.annotation.Nullable;
import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.BillingMode;
import org.killbill.billing.invoice.api.Invoice;
+import org.killbill.billing.invoice.api.InvoiceItem;
+import org.killbill.billing.invoice.api.InvoiceItemType;
+import org.killbill.billing.invoice.generator.InvoiceWithMetadata.SubscriptionFutureNotificationDates.UsageDef;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
public class InvoiceWithMetadata {
private final Invoice invoice;
private final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates;
+
+ public InvoiceWithMetadata(final Invoice invoice, final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates) {
+ this.invoice = invoice;
+ this.perSubscriptionFutureNotificationDates = perSubscriptionFutureNotificationDates;
+ build();
+ }
+
+ public Invoice getInvoice() {
+ return invoice;
+ }
+
+ public Map<UUID, SubscriptionFutureNotificationDates> getPerSubscriptionFutureNotificationDates() {
+ return perSubscriptionFutureNotificationDates;
+ }
+
+ // Remove all the IN_ADVANCE items for which we have no invoice items
+ private void build() {
+ for (final UUID subscriptionId : perSubscriptionFutureNotificationDates.keySet()) {
+ final SubscriptionFutureNotificationDates tmp = perSubscriptionFutureNotificationDates.get(subscriptionId);
+ if (tmp.getRecurringBillingMode() == BillingMode.IN_ADVANCE && !hasItemsForSubscription(subscriptionId, InvoiceItemType.RECURRING)) {
+ tmp.resetNextRecurringDate();
+ }
+ if (tmp.getNextUsageDates() != null) {
+ final Iterator<UsageDef> it = tmp.getNextUsageDates().keySet().iterator();
+ while (it.hasNext()) {
+ final UsageDef usageDef = it.next();
+ if (usageDef.getBillingMode() == BillingMode.IN_ADVANCE && !hasItemsForSubscription(subscriptionId, InvoiceItemType.USAGE)) {
+ it.remove();
+ }
+ }
+ }
+ }
+ }
+
+ private boolean hasItemsForSubscription(final UUID subscriptionId, final InvoiceItemType invoiceItemType) {
+ return invoice != null && Iterables.any(invoice.getInvoiceItems(), new Predicate<InvoiceItem>() {
+ @Override
+ public boolean apply(final InvoiceItem input) {
+ return input.getInvoiceItemType() == invoiceItemType &&
+ input.getSubscriptionId().equals(subscriptionId);
+ }
+ });
+ }
+
public static class SubscriptionFutureNotificationDates {
+ private final BillingMode recurringBillingMode;
+
private LocalDate nextRecurringDate;
- private Map<String, LocalDate> nextUsageDates;
+ private Map<UsageDef, LocalDate> nextUsageDates;
- public SubscriptionFutureNotificationDates() {
+ public SubscriptionFutureNotificationDates(final BillingMode recurringBillingMode) {
+ this.recurringBillingMode = recurringBillingMode;
this.nextRecurringDate = null;
this.nextUsageDates = null;
}
@@ -45,22 +100,32 @@ public class InvoiceWithMetadata {
nextRecurringDate = getMaxDate(nextRecurringDate, nextRecurringDateCandidate);
}
- public void updateNextUsageDateIfRequired(final String usageName, final LocalDate nextUsageDateCandidate) {
+ public void updateNextUsageDateIfRequired(final String usageName, final BillingMode billingMode, final LocalDate nextUsageDateCandidate) {
if (nextUsageDates == null) {
- nextUsageDates = new HashMap<String, LocalDate>();
+ nextUsageDates = new HashMap<UsageDef, LocalDate>();
}
- final LocalDate nextUsageDate = getMaxDate(nextUsageDates.get(usageName), nextUsageDateCandidate);
- nextUsageDates.put(usageName, nextUsageDate);
+ final UsageDef usageDef = new UsageDef(usageName, billingMode);
+ final LocalDate nextUsageDate = getMaxDate(nextUsageDates.get(usageDef), nextUsageDateCandidate);
+ nextUsageDates.put(usageDef, nextUsageDate);
}
public LocalDate getNextRecurringDate() {
return nextRecurringDate;
}
- public Map<String, LocalDate> getNextUsageDates() {
+ public Map<UsageDef, LocalDate> getNextUsageDates() {
return nextUsageDates;
}
+ public BillingMode getRecurringBillingMode() {
+ return recurringBillingMode;
+ }
+
+ public void resetNextRecurringDate() {
+ nextRecurringDate = null;
+ }
+
+
private static LocalDate getMaxDate(@Nullable final LocalDate existingDate, final LocalDate nextDateCandidate) {
if (existingDate == null) {
return nextDateCandidate;
@@ -69,19 +134,49 @@ public class InvoiceWithMetadata {
}
}
- }
- public InvoiceWithMetadata(final Invoice invoice, final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates) {
- this.invoice = invoice;
- this.perSubscriptionFutureNotificationDates = perSubscriptionFutureNotificationDates;
- }
+ public static class UsageDef {
- public Invoice getInvoice() {
- return invoice;
- }
+ private final String usageName;
+ private final BillingMode billingMode;
- public Map<UUID, SubscriptionFutureNotificationDates> getPerSubscriptionFutureNotificationDates() {
- return perSubscriptionFutureNotificationDates;
- }
+ public UsageDef(final String usageName, final BillingMode billingMode) {
+ this.usageName = usageName;
+ this.billingMode = billingMode;
+ }
+
+ public String getUsageName() {
+ return usageName;
+ }
+
+ public BillingMode getBillingMode() {
+ return billingMode;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof UsageDef)) {
+ return false;
+ }
+
+ final UsageDef usageDef = (UsageDef) o;
+ if (usageName != null ? !usageName.equals(usageDef.usageName) : usageDef.usageName != null) {
+ return false;
+ }
+ return billingMode == usageDef.billingMode;
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = usageName != null ? usageName.hashCode() : 0;
+ result = 31 * result + (billingMode != null ? billingMode.hashCode() : 0);
+ return result;
+ }
+ }
+ }
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
index 6f4b247..58194a6 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -70,6 +70,7 @@ import org.killbill.billing.invoice.generator.BillingIntervalDetail;
import org.killbill.billing.invoice.generator.InvoiceGenerator;
import org.killbill.billing.invoice.generator.InvoiceWithMetadata;
import org.killbill.billing.invoice.generator.InvoiceWithMetadata.SubscriptionFutureNotificationDates;
+import org.killbill.billing.invoice.generator.InvoiceWithMetadata.SubscriptionFutureNotificationDates.UsageDef;
import org.killbill.billing.invoice.model.DefaultInvoice;
import org.killbill.billing.invoice.model.FixedPriceInvoiceItem;
import org.killbill.billing.invoice.model.InvoiceItemFactory;
@@ -101,7 +102,6 @@ import org.killbill.notificationq.api.NotificationQueueService.NoSuchNotificatio
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
@@ -118,7 +118,7 @@ public class InvoiceDispatcher {
private static final int NB_LOCK_TRY = 5;
private static final Ordering<DateTime> UPCOMING_NOTIFICATION_DATE_ORDERING = Ordering.natural();
-
+ private final static Joiner JOINER_COMMA = Joiner.on(",");
private static final NullDryRunArguments NULL_DRY_RUN_ARGUMENTS = new NullDryRunArguments();
private final InvoiceGenerator generator;
@@ -358,9 +358,9 @@ public class InvoiceDispatcher {
}
// Add next usage dates if any
if (subscriptionFutureNotificationDates.getNextUsageDates() != null) {
- for (String usageName : subscriptionFutureNotificationDates.getNextUsageDates().keySet()) {
- final LocalDate nextNotificationDateForUsage = subscriptionFutureNotificationDates.getNextUsageDates().get(usageName);
- final DateTime subscriptionUsageCallbackDate = getNextUsageBillingDate(subscriptionId, usageName, nextNotificationDateForUsage, dateAndTimeZoneContext, billingEvents);
+ for (UsageDef usageDef : subscriptionFutureNotificationDates.getNextUsageDates().keySet()) {
+ final LocalDate nextNotificationDateForUsage = subscriptionFutureNotificationDates.getNextUsageDates().get(usageDef);
+ final DateTime subscriptionUsageCallbackDate = getNextUsageBillingDate(subscriptionId, usageDef.getUsageName(), nextNotificationDateForUsage, dateAndTimeZoneContext, billingEvents);
perSubscriptionNotifications.add(new SubscriptionNotification(subscriptionUsageCallbackDate, true));
}
}
@@ -409,14 +409,18 @@ public class InvoiceDispatcher {
}
private void logInvoiceWithItems(final Account account, final Invoice invoice, final LocalDate targetDate, final Set<UUID> adjustedUniqueOtherInvoiceId, final boolean isRealInvoiceWithItems) {
+ final StringBuilder tmp = new StringBuilder();
if (isRealInvoiceWithItems) {
- log.info("Generated invoice {} with {} items for accountId {} and targetDate {}", new Object[]{invoice.getId(), invoice.getNumberOfItems(), account.getId(), targetDate});
+ tmp.append(String.format("Generated invoice %s with %d items for accountId %s and targetDate %s:\n", invoice.getId(), invoice.getNumberOfItems(), account.getId(), targetDate));
} else {
- final Joiner joiner = Joiner.on(",");
- final String adjustedInvoices = joiner.join(adjustedUniqueOtherInvoiceId.toArray(new UUID[adjustedUniqueOtherInvoiceId.size()]));
- log.info("Adjusting existing invoices {} with {} items for accountId {} and targetDate {})", new Object[]{adjustedInvoices, invoice.getNumberOfItems(),
- account.getId(), targetDate});
+ final String adjustedInvoices = JOINER_COMMA.join(adjustedUniqueOtherInvoiceId.toArray(new UUID[adjustedUniqueOtherInvoiceId.size()]));
+ tmp.append(String.format("Adjusting existing invoices %s with %d items for accountId %s and targetDate %s:\n",
+ adjustedInvoices, invoice.getNumberOfItems(), account.getId(), targetDate));
+ }
+ for (InvoiceItem item : invoice.getInvoiceItems()) {
+ tmp.append(String.format("\t item = %s\n", item));
}
+ log.info(tmp.toString());
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/BillingModeGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/model/BillingModeGenerator.java
index 26fbfd9..19a8496 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/model/BillingModeGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/BillingModeGenerator.java
@@ -16,18 +16,14 @@
package org.killbill.billing.invoice.model;
-import java.util.List;
-
import javax.annotation.Nullable;
-import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
-
import org.killbill.billing.catalog.api.BillingMode;
import org.killbill.billing.catalog.api.BillingPeriod;
public interface BillingModeGenerator {
- List<RecurringInvoiceItemData> generateInvoiceItemData(LocalDate startDate, @Nullable LocalDate endDate, LocalDate targetDate,
- int billingCycleDay, BillingPeriod billingPeriod, BillingMode billingMode) throws InvalidDateSequenceException;
+ RecurringInvoiceItemDataWithNextBillingCycleDate generateInvoiceItemData(LocalDate startDate, @Nullable LocalDate endDate, LocalDate targetDate,
+ int billingCycleDay, BillingPeriod billingPeriod, BillingMode billingMode) throws InvalidDateSequenceException;
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultBillingModeGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultBillingModeGenerator.java
index 29bcc1f..2da9169 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultBillingModeGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultBillingModeGenerator.java
@@ -38,7 +38,7 @@ public class DefaultBillingModeGenerator implements BillingModeGenerator {
private static final Logger log = LoggerFactory.getLogger(DefaultBillingModeGenerator.class);
@Override
- public List<RecurringInvoiceItemData> generateInvoiceItemData(final LocalDate startDate, @Nullable final LocalDate endDate,
+ public RecurringInvoiceItemDataWithNextBillingCycleDate generateInvoiceItemData(final LocalDate startDate, @Nullable final LocalDate endDate,
final LocalDate targetDate,
final int billingCycleDayLocal,
final BillingPeriod billingPeriod,
@@ -56,7 +56,7 @@ public class DefaultBillingModeGenerator implements BillingModeGenerator {
// We are not billing for less than a day
if (!billingIntervalDetail.hasSomethingToBill()) {
- return results;
+ return new RecurringInvoiceItemDataWithNextBillingCycleDate(results, billingIntervalDetail, billingMode);
}
//
// If there is an endDate and that endDate is before our first coming firstBillingCycleDate, all we have to do
@@ -66,7 +66,7 @@ public class DefaultBillingModeGenerator implements BillingModeGenerator {
final BigDecimal leadingProRationPeriods = calculateProRationBeforeFirstBillingPeriod(startDate, endDate, billingPeriod);
final RecurringInvoiceItemData itemData = new RecurringInvoiceItemData(startDate, endDate, leadingProRationPeriods);
results.add(itemData);
- return results;
+ return new RecurringInvoiceItemDataWithNextBillingCycleDate(results, billingIntervalDetail, billingMode);
}
//
@@ -126,6 +126,6 @@ public class DefaultBillingModeGenerator implements BillingModeGenerator {
results.add(itemData);
}
}
- return results;
+ return new RecurringInvoiceItemDataWithNextBillingCycleDate(results, billingIntervalDetail, billingMode);
}
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/RecurringInvoiceItemDataWithNextBillingCycleDate.java b/invoice/src/main/java/org/killbill/billing/invoice/model/RecurringInvoiceItemDataWithNextBillingCycleDate.java
new file mode 100644
index 0000000..3533240
--- /dev/null
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/RecurringInvoiceItemDataWithNextBillingCycleDate.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.invoice.model;
+
+import java.util.List;
+
+import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.BillingMode;
+import org.killbill.billing.invoice.generator.BillingIntervalDetail;
+
+public class RecurringInvoiceItemDataWithNextBillingCycleDate {
+
+ private final List<RecurringInvoiceItemData> itemData;
+ private final BillingIntervalDetail billingIntervalDetail;
+ private final BillingMode billingMode;
+
+ public RecurringInvoiceItemDataWithNextBillingCycleDate(final List<RecurringInvoiceItemData> itemData, final BillingIntervalDetail billingIntervalDetail,final BillingMode billingMode) {
+ this.itemData = itemData;
+ this.billingIntervalDetail = billingIntervalDetail;
+ this.billingMode = billingMode;
+ }
+
+ public List<RecurringInvoiceItemData> getItemData() {
+ return itemData;
+ }
+
+ public LocalDate getNextBillingCycleDate() {
+ return billingIntervalDetail.getNextBillingCycleDate();
+ }
+}
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestInArrearBillingIntervalDetail.java b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestInArrearBillingIntervalDetail.java
new file mode 100644
index 0000000..009ee8c
--- /dev/null
+++ b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestInArrearBillingIntervalDetail.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.invoice.generator;
+
+import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.BillingMode;
+import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.invoice.InvoiceTestSuiteNoDB;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class TestInArrearBillingIntervalDetail extends InvoiceTestSuiteNoDB {
+
+
+ /*
+ * TD
+ * BCD Start
+ * |---------|-----------------
+ *
+ */
+ @Test(groups = "fast")
+ public void testScenarioBCDBeforeStart1() throws Exception {
+ final LocalDate start = new LocalDate("2012-01-16");
+ final LocalDate targetDate = new LocalDate("2012-01-16");
+ final int bcd = 13;
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(start, null, targetDate, bcd, BillingPeriod.MONTHLY, BillingMode.IN_ARREAR);
+
+ Assert.assertFalse(billingIntervalDetail.hasSomethingToBill());
+ Assert.assertEquals(billingIntervalDetail.getFirstBillingCycleDate(), new LocalDate("2012-02-13"));
+ Assert.assertNull(billingIntervalDetail.getEffectiveEndDate());
+ Assert.assertEquals(billingIntervalDetail.getNextBillingCycleDate(), new LocalDate("2012-02-13"));
+ }
+
+ /*
+ *
+ * BCD Start TD = (next BCD)
+ * |---------|----------|-------
+ *
+ */
+ @Test(groups = "fast")
+ public void testScenarioBCDBeforeStart2() throws Exception {
+ final LocalDate start = new LocalDate("2012-01-16");
+ final LocalDate targetDate = new LocalDate("2012-02-13");
+ final int bcd = 13;
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(start, null, targetDate, bcd, BillingPeriod.MONTHLY, BillingMode.IN_ARREAR);
+
+ Assert.assertTrue(billingIntervalDetail.hasSomethingToBill());
+ Assert.assertEquals(billingIntervalDetail.getFirstBillingCycleDate(), new LocalDate("2012-02-13"));
+ Assert.assertEquals(billingIntervalDetail.getEffectiveEndDate(), new LocalDate("2012-02-13"));
+ Assert.assertEquals(billingIntervalDetail.getNextBillingCycleDate(), new LocalDate("2012-03-13"));
+ }
+
+
+ /*
+ * BCD
+ * Start TD
+ * |---------|-----------------
+ *
+ */
+ @Test(groups = "fast")
+ public void testScenarioBCDAEqualsStart1() throws Exception {
+ final LocalDate start = new LocalDate("2012-01-16");
+ final LocalDate targetDate = new LocalDate("2012-01-19");
+ final int bcd = 16;
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(start, null, targetDate, bcd, BillingPeriod.MONTHLY, BillingMode.IN_ARREAR);
+
+ Assert.assertTrue(billingIntervalDetail.hasSomethingToBill());
+ Assert.assertEquals(billingIntervalDetail.getFirstBillingCycleDate(), new LocalDate("2012-01-16"));
+ Assert.assertEquals(billingIntervalDetail.getEffectiveEndDate(), new LocalDate("2012-01-16"));
+ Assert.assertEquals(billingIntervalDetail.getNextBillingCycleDate(), new LocalDate("2012-02-16"));
+ }
+
+
+ /*
+ *
+ * Start TD BCD
+ * |---------|----------|-------
+ *
+ */
+ @Test(groups = "fast")
+ public void testScenarioBCDAfterStart1() throws Exception {
+ final LocalDate start = new LocalDate("2012-01-16");
+ final LocalDate targetDate = new LocalDate("2012-01-19");
+ final int bcd = 25;
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(start, null, targetDate, bcd, BillingPeriod.MONTHLY, BillingMode.IN_ARREAR);
+
+ Assert.assertFalse(billingIntervalDetail.hasSomethingToBill());
+ Assert.assertEquals(billingIntervalDetail.getFirstBillingCycleDate(), new LocalDate("2012-01-25"));
+ Assert.assertNull(billingIntervalDetail.getEffectiveEndDate());
+ Assert.assertEquals(billingIntervalDetail.getNextBillingCycleDate(), new LocalDate("2012-01-25"));
+ }
+
+
+ /*
+ * TD
+ * Start End BCD
+ * |---------|------------|-------
+ *
+ */
+ @Test(groups = "fast")
+ public void testScenarioBCDAfterStart2() throws Exception {
+ final LocalDate start = new LocalDate("2012-01-16");
+ final LocalDate end = new LocalDate("2012-01-19");
+ final LocalDate targetDate = new LocalDate("2012-01-25");
+ final int bcd = 25;
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(start, end, targetDate, bcd, BillingPeriod.MONTHLY, BillingMode.IN_ARREAR);
+
+ Assert.assertTrue(billingIntervalDetail.hasSomethingToBill());
+ Assert.assertEquals(billingIntervalDetail.getFirstBillingCycleDate(), new LocalDate("2012-01-25"));
+ Assert.assertEquals(billingIntervalDetail.getEffectiveEndDate(), end);
+ // STEPH maybe we should change because we actually don't want a notification
+ Assert.assertEquals(billingIntervalDetail.getNextBillingCycleDate(), new LocalDate("2012-01-25"));
+ }
+
+
+ /*
+ * TD
+ * Start BCD
+ * |--------------------|-------
+ *
+ */
+ @Test(groups = "fast")
+ public void testScenarioBCDAfterStart3() throws Exception {
+ final LocalDate start = new LocalDate("2012-01-16");
+ final LocalDate targetDate = new LocalDate("2012-01-25");
+ final int bcd = 25;
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(start, null, targetDate, bcd, BillingPeriod.MONTHLY, BillingMode.IN_ARREAR);
+
+ Assert.assertTrue(billingIntervalDetail.hasSomethingToBill());
+ Assert.assertEquals(billingIntervalDetail.getFirstBillingCycleDate(), new LocalDate("2012-01-25"));
+ Assert.assertEquals(billingIntervalDetail.getEffectiveEndDate(), new LocalDate("2012-01-25"));
+ Assert.assertEquals(billingIntervalDetail.getNextBillingCycleDate(), new LocalDate("2012-02-25"));
+ }
+
+
+ /*
+ *
+ * Start BCD end TD next BCD
+ * |-------|------|----|------|---
+ *
+ */
+ @Test(groups = "fast")
+ public void testScenarioEndDateBetweenPeriod1() throws Exception {
+ final LocalDate start = new LocalDate("2012-01-16");
+ final LocalDate end = new LocalDate("2012-01-20");
+ final LocalDate targetDate = new LocalDate("2012-01-25");
+ final int bcd = 18;
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(start, end, targetDate, bcd, BillingPeriod.MONTHLY, BillingMode.IN_ARREAR);
+
+ Assert.assertTrue(billingIntervalDetail.hasSomethingToBill());
+ Assert.assertEquals(billingIntervalDetail.getFirstBillingCycleDate(), new LocalDate("2012-01-18"));
+ Assert.assertEquals(billingIntervalDetail.getEffectiveEndDate(), new LocalDate("2012-01-18"));
+ Assert.assertEquals(billingIntervalDetail.getNextBillingCycleDate(), new LocalDate("2012-02-18"));
+ }
+
+ /*
+ *
+ * Start BCD TD next BCD
+ * |-------|----------|------|---
+ *
+ */
+ @Test(groups = "fast")
+ public void testScenarioEndDateBetweenPeriod2() throws Exception {
+ final LocalDate start = new LocalDate("2012-01-16");
+ final LocalDate targetDate = new LocalDate("2012-01-25");
+ final int bcd = 18;
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(start, null, targetDate, bcd, BillingPeriod.MONTHLY, BillingMode.IN_ARREAR);
+
+ Assert.assertTrue(billingIntervalDetail.hasSomethingToBill());
+ Assert.assertEquals(billingIntervalDetail.getFirstBillingCycleDate(), new LocalDate("2012-01-18"));
+ Assert.assertEquals(billingIntervalDetail.getEffectiveEndDate(), new LocalDate("2012-01-18"));
+ Assert.assertEquals(billingIntervalDetail.getNextBillingCycleDate(), new LocalDate("2012-02-18"));
+ }
+
+ /*
+ *
+ * Start BCD TD end next BCD
+ * |-------|----------|----|------|---
+ *
+ */
+ @Test(groups = "fast")
+ public void testScenarioEndDateBetweenPeriod3() throws Exception {
+ final LocalDate start = new LocalDate("2012-01-16");
+ final LocalDate end = new LocalDate("2012-01-28");
+ final LocalDate targetDate = new LocalDate("2012-01-25");
+ final int bcd = 18;
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(start, end, targetDate, bcd, BillingPeriod.MONTHLY, BillingMode.IN_ARREAR);
+
+ Assert.assertTrue(billingIntervalDetail.hasSomethingToBill());
+ Assert.assertEquals(billingIntervalDetail.getFirstBillingCycleDate(), new LocalDate("2012-01-18"));
+ Assert.assertEquals(billingIntervalDetail.getEffectiveEndDate(), new LocalDate("2012-01-18"));
+ Assert.assertEquals(billingIntervalDetail.getNextBillingCycleDate(), new LocalDate("2012-02-18"));
+ }
+
+ /*
+ * TD
+ * Start BCD next BCD
+ * |-------|--------------------|---
+ *
+ */
+ @Test(groups = "fast")
+ public void testScenarioTargetDateOnNextBCD1() throws Exception {
+ final LocalDate start = new LocalDate("2012-01-16");
+ final LocalDate targetDate = new LocalDate("2012-02-18");
+ final int bcd = 18;
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(start, null, targetDate, bcd, BillingPeriod.MONTHLY, BillingMode.IN_ARREAR);
+
+ Assert.assertTrue(billingIntervalDetail.hasSomethingToBill());
+ Assert.assertEquals(billingIntervalDetail.getFirstBillingCycleDate(), new LocalDate("2012-01-18"));
+ Assert.assertEquals(billingIntervalDetail.getEffectiveEndDate(), new LocalDate("2012-02-18"));
+ Assert.assertEquals(billingIntervalDetail.getNextBillingCycleDate(), new LocalDate("2012-03-18"));
+ }
+
+ /*
+ * TD
+ * Start BCD end next BCD
+ * |-------|-------------|-------|---
+ *
+ */
+ @Test(groups = "fast")
+ public void testScenarioTargetDateOnNextBCD2() throws Exception {
+ final LocalDate start = new LocalDate("2012-01-16");
+ final LocalDate end = new LocalDate("2012-02-16");
+ final LocalDate targetDate = new LocalDate("2012-02-18");
+ final int bcd = 18;
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(start, end, targetDate, bcd, BillingPeriod.MONTHLY, BillingMode.IN_ARREAR);
+
+ Assert.assertTrue(billingIntervalDetail.hasSomethingToBill());
+ Assert.assertEquals(billingIntervalDetail.getFirstBillingCycleDate(), new LocalDate("2012-01-18"));
+ Assert.assertEquals(billingIntervalDetail.getEffectiveEndDate(), new LocalDate("2012-02-16"));
+ Assert.assertEquals(billingIntervalDetail.getNextBillingCycleDate(), new LocalDate("2012-02-18"));
+ }
+}
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/model/TestInAdvanceBillingMode.java b/invoice/src/test/java/org/killbill/billing/invoice/model/TestInAdvanceBillingMode.java
index db121f6..5766409 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/model/TestInAdvanceBillingMode.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/model/TestInAdvanceBillingMode.java
@@ -151,8 +151,8 @@ public class TestInAdvanceBillingMode extends InvoiceTestSuiteNoDB {
final LinkedHashMap<LocalDate, LocalDate> expectedDates) throws InvalidDateSequenceException {
final DefaultBillingModeGenerator billingMode = new DefaultBillingModeGenerator();
- final List<RecurringInvoiceItemData> invoiceItems = billingMode.generateInvoiceItemData(startDate, endDate, targetDate, billingCycleDayLocal, billingPeriod, BillingMode.IN_ADVANCE);
-
+ final RecurringInvoiceItemDataWithNextBillingCycleDate invoiceItemsWithDates = billingMode.generateInvoiceItemData(startDate, endDate, targetDate, billingCycleDayLocal, billingPeriod, BillingMode.IN_ADVANCE);
+ final List<RecurringInvoiceItemData> invoiceItems = invoiceItemsWithDates.getItemData();
int i = 0;
for (final LocalDate periodStartDate : expectedDates.keySet()) {
Assert.assertEquals(invoiceItems.get(i).getStartDate(), periodStartDate);
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/model/TestInArrearBillingMode.java b/invoice/src/test/java/org/killbill/billing/invoice/model/TestInArrearBillingMode.java
index aa4733e..69a72aa 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/model/TestInArrearBillingMode.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/model/TestInArrearBillingMode.java
@@ -153,7 +153,8 @@ public class TestInArrearBillingMode extends InvoiceTestSuiteNoDB {
final LinkedHashMap<LocalDate, LocalDate> expectedDates) throws InvalidDateSequenceException {
final DefaultBillingModeGenerator billingMode = new DefaultBillingModeGenerator();
- final List<RecurringInvoiceItemData> invoiceItems = billingMode.generateInvoiceItemData(startDate, endDate, targetDate, billingCycleDayLocal, billingPeriod, BillingMode.IN_ARREAR);
+ final RecurringInvoiceItemDataWithNextBillingCycleDate invoiceItemsWithDates = billingMode.generateInvoiceItemData(startDate, endDate, targetDate, billingCycleDayLocal, billingPeriod, BillingMode.IN_ARREAR);
+ final List<RecurringInvoiceItemData> invoiceItems = invoiceItemsWithDates.getItemData();
int i = 0;
for (final LocalDate periodStartDate : expectedDates.keySet()) {
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/proRations/ProRationTestBase.java b/invoice/src/test/java/org/killbill/billing/invoice/proRations/ProRationTestBase.java
index 82e110a..2a31e14 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/proRations/ProRationTestBase.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/proRations/ProRationTestBase.java
@@ -30,6 +30,7 @@ import org.killbill.billing.invoice.model.BillingModeGenerator;
import org.killbill.billing.invoice.model.DefaultBillingModeGenerator;
import org.killbill.billing.invoice.model.InvalidDateSequenceException;
import org.killbill.billing.invoice.model.RecurringInvoiceItemData;
+import org.killbill.billing.invoice.model.RecurringInvoiceItemDataWithNextBillingCycleDate;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;
@@ -72,10 +73,10 @@ public abstract class ProRationTestBase extends InvoiceTestSuiteNoDB {
}
protected BigDecimal calculateNumberOfBillingCycles(final LocalDate startDate, final LocalDate endDate, final LocalDate targetDate, final int billingCycleDay) throws InvalidDateSequenceException {
- final List<RecurringInvoiceItemData> items = getBillingModeGenerator().generateInvoiceItemData(startDate, endDate, targetDate, billingCycleDay, getBillingPeriod(), getBillingMode());
+ final RecurringInvoiceItemDataWithNextBillingCycleDate items = getBillingModeGenerator().generateInvoiceItemData(startDate, endDate, targetDate, billingCycleDay, getBillingPeriod(), getBillingMode());
BigDecimal numberOfBillingCycles = ZERO;
- for (final RecurringInvoiceItemData item : items) {
+ for (final RecurringInvoiceItemData item : items.getItemData()) {
numberOfBillingCycles = numberOfBillingCycles.add(item.getNumberOfCycles());
}
@@ -83,10 +84,10 @@ public abstract class ProRationTestBase extends InvoiceTestSuiteNoDB {
}
protected BigDecimal calculateNumberOfBillingCycles(final LocalDate startDate, final LocalDate targetDate, final int billingCycleDay) throws InvalidDateSequenceException {
- final List<RecurringInvoiceItemData> items = getBillingModeGenerator().generateInvoiceItemData(startDate, null, targetDate, billingCycleDay, getBillingPeriod(), getBillingMode());
+ final RecurringInvoiceItemDataWithNextBillingCycleDate items = getBillingModeGenerator().generateInvoiceItemData(startDate, null, targetDate, billingCycleDay, getBillingPeriod(), getBillingMode());
BigDecimal numberOfBillingCycles = ZERO;
- for (final RecurringInvoiceItemData item : items) {
+ for (final RecurringInvoiceItemData item : items.getItemData()) {
numberOfBillingCycles = numberOfBillingCycles.add(item.getNumberOfCycles());
}