use of org.killbill.billing.invoice.model.RecurringInvoiceItem in project killbill by killbill.
the class TestDefaultInvoiceItemFormatter method testNonNullEndDate.
@Test(groups = "fast")
public void testNonNullEndDate() throws Exception {
final LocalDate startDate = new LocalDate(2012, 12, 1);
final LocalDate endDate = new LocalDate(2012, 12, 31);
final RecurringInvoiceItem recurringItem = new RecurringInvoiceItem(UUID.randomUUID(), UUID.randomUUID(), null, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), UUID.randomUUID().toString(), null, startDate, endDate, BigDecimal.TEN, BigDecimal.TEN, Currency.USD);
checkOutput(recurringItem, "{{#invoiceItem}}<td>{{formattedStartDate}}{{#formattedEndDate}} - {{formattedEndDate}}{{/formattedEndDate}}</td>{{/invoiceItem}}", "<td>Dec 1, 2012 - Dec 31, 2012</td>");
}
use of org.killbill.billing.invoice.model.RecurringInvoiceItem in project killbill by killbill.
the class FixedAndRecurringInvoiceItemGenerator method processRecurringEvent.
// 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 InvoiceItemGeneratorLogger invoiceItemGeneratorLogger, final BillingMode billingMode, final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate, final InternalCallContext internalCallContext) throws InvoiceApiException {
try {
final List<InvoiceItem> items = new ArrayList<InvoiceItem>();
// For FIXEDTERM phases we need to stop when the specified duration has been reached
final LocalDate maxEndDate = thisEvent.getPlanPhase().getPhaseType() == PhaseType.FIXEDTERM ? thisEvent.getPlanPhase().getDuration().addToLocalDate(internalCallContext.toLocalDate(thisEvent.getEffectiveDate())) : null;
// Handle recurring items
final BillingPeriod billingPeriod = thisEvent.getBillingPeriod();
if (billingPeriod != BillingPeriod.NO_BILLING_PERIOD) {
final LocalDate startDate = internalCallContext.toLocalDate(thisEvent.getEffectiveDate());
if (!startDate.isAfter(targetDate)) {
final LocalDate endDate = (nextEvent == null) ? null : internalCallContext.toLocalDate(nextEvent.getEffectiveDate());
final int billCycleDayLocal = thisEvent.getBillCycleDayLocal();
final RecurringInvoiceItemDataWithNextBillingCycleDate itemDataWithNextBillingCycleDate;
try {
itemDataWithNextBillingCycleDate = generateInvoiceItemData(startDate, endDate, targetDate, billCycleDayLocal, billingPeriod, billingMode);
} catch (final InvalidDateSequenceException e) {
throw new InvoiceApiException(ErrorCode.INVOICE_INVALID_DATE_SEQUENCE, startDate, endDate, targetDate);
}
for (final RecurringInvoiceItemData itemDatum : itemDataWithNextBillingCycleDate.getItemData()) {
// Stop if there a maxEndDate and we have reached it
if (maxEndDate != null && maxEndDate.compareTo(itemDatum.getEndDate()) < 0) {
break;
}
final BigDecimal rate = thisEvent.getRecurringPrice(internalCallContext.toUTCDateTime(itemDatum.getStartDate()));
if (rate != null) {
final BigDecimal amount = KillBillMoney.of(itemDatum.getNumberOfCycles().multiply(rate), currency);
final RecurringInvoiceItem recurringItem = new RecurringInvoiceItem(invoiceId, accountId, thisEvent.getSubscription().getBundleId(), thisEvent.getSubscription().getId(), thisEvent.getPlan().getName(), thisEvent.getPlanPhase().getName(), itemDatum.getStartDate(), itemDatum.getEndDate(), amount, rate, currency);
items.add(recurringItem);
}
}
updatePerSubscriptionNextNotificationDate(thisEvent.getSubscription().getId(), itemDataWithNextBillingCycleDate.getNextBillingCycleDate(), items, billingMode, perSubscriptionFutureNotificationDate);
}
}
// For debugging purposes
invoiceItemGeneratorLogger.append(thisEvent, items);
return items;
} catch (final CatalogApiException e) {
throw new InvoiceApiException(e);
}
}
use of org.killbill.billing.invoice.model.RecurringInvoiceItem in project killbill by killbill.
the class TestSubscriptionItemTree method testWithWrongInitialItemInLoop.
@Test(groups = "fast")
public void testWithWrongInitialItemInLoop() {
final LocalDate wrongStartDate = new LocalDate(2016, 9, 9);
final LocalDate correctStartDate = new LocalDate(2016, 9, 8);
final LocalDate endDate = new LocalDate(2016, 10, 8);
final BigDecimal rate1 = new BigDecimal("12.00");
final BigDecimal amount1 = rate1;
final List<InvoiceItem> existingItems = new ArrayList<InvoiceItem>();
final List<InvoiceItem> proposedItems = new ArrayList<InvoiceItem>();
final InvoiceItem wrongInitialItem = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, wrongStartDate, endDate, amount1, rate1, currency);
proposedItems.add(wrongInitialItem);
int previousExistingSize = existingItems.size();
int iteration = 0;
do {
SubscriptionItemTree tree = new SubscriptionItemTree(subscriptionId, invoiceId);
for (InvoiceItem e : existingItems) {
tree.addItem(e);
}
tree.build();
tree.flatten(true);
for (InvoiceItem p : proposedItems) {
tree.mergeProposedItem(p);
}
tree.buildForMerge();
existingItems.addAll(tree.getView());
if (iteration == 0) {
final InvoiceItem itemAdj = new ItemAdjInvoiceItem(wrongInitialItem, new LocalDate(2016, 10, 2), amount1.negate(), currency);
existingItems.add(itemAdj);
}
previousExistingSize = existingItems.size();
proposedItems.clear();
final InvoiceItem correctInitialItem = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, correctStartDate, endDate, amount1, rate1, currency);
proposedItems.add(correctInitialItem);
iteration++;
} while (iteration < 10);
// We have repaired wrongInitialItem and generated the correctInitialItem and stopped
Assert.assertEquals(previousExistingSize, 3);
}
use of org.killbill.billing.invoice.model.RecurringInvoiceItem in project killbill by killbill.
the class TestSubscriptionItemTree method testOverlappingRepair.
// The test that first repair (repair1) and new Item (newItem1) end up being ignored.
@Test(groups = "fast")
public void testOverlappingRepair() {
final LocalDate startDate = new LocalDate(2012, 5, 1);
final LocalDate endDate = new LocalDate(2013, 5, 1);
final LocalDate changeDate = new LocalDate(2012, 5, 11);
final LocalDate monthlyAlignmentDate = new LocalDate(2012, 6, 1);
final BigDecimal rate1 = new BigDecimal("2400.00");
final BigDecimal amount1 = rate1;
final BigDecimal rate2 = new BigDecimal("300.00");
final BigDecimal amount2 = rate2;
// Start with a ANNUAL plan (high rate, rate1)
final InvoiceItem initial = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount1, rate1, currency);
// Change to MONTHLY plan 10 days later (low rate, rate2)
final InvoiceItem repair1 = new RepairAdjInvoiceItem(invoiceId, accountId, changeDate, endDate, amount1.negate(), currency, initial.getId());
final InvoiceItem newItem1 = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, "someelse", "someelse", changeDate, monthlyAlignmentDate, amount2, rate2, currency);
// On the same day, now revert back to ANNUAL
final InvoiceItem repair2 = new RepairAdjInvoiceItem(invoiceId, accountId, changeDate, monthlyAlignmentDate, amount2.negate(), currency, newItem1.getId());
final InvoiceItem newItem2 = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, changeDate, endDate, amount1, rate1, currency);
final SubscriptionItemTree tree = new SubscriptionItemTree(subscriptionId, invoiceId);
tree.addItem(initial);
tree.addItem(newItem1);
tree.addItem(repair1);
tree.addItem(newItem2);
tree.addItem(repair2);
final List<InvoiceItem> expectedResult = Lists.newLinkedList();
final InvoiceItem expected1 = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, changeDate, new BigDecimal("65.75"), rate1, currency);
expectedResult.add(expected1);
expectedResult.add(newItem2);
tree.build();
verifyResult(tree.getView(), expectedResult);
}
use of org.killbill.billing.invoice.model.RecurringInvoiceItem in project killbill by killbill.
the class TestSubscriptionItemTree method testInvalidRepairCausingOverlappingRecurringV2.
@Test(groups = "fast")
public void testInvalidRepairCausingOverlappingRecurringV2() {
final LocalDate startDate = new LocalDate(2014, 1, 1);
final LocalDate endDate = new LocalDate(2014, 2, 1);
final LocalDate repairDate1 = new LocalDate(2014, 1, 23);
final LocalDate repairDate2 = new LocalDate(2014, 1, 26);
final BigDecimal rate1 = new BigDecimal("12.00");
final BigDecimal amount1 = rate1;
final BigDecimal rate2 = new BigDecimal("14.85");
final BigDecimal amount2 = rate2;
final InvoiceItem initial = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount1, rate1, currency);
final InvoiceItem newItem1 = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, repairDate1, endDate, amount2, rate2, currency);
final InvoiceItem repair1 = new RepairAdjInvoiceItem(invoiceId, accountId, repairDate2, endDate, amount1.negate(), currency, initial.getId());
// Out-of-order insertion to show ordering doesn't matter
final SubscriptionItemTree tree = new SubscriptionItemTree(subscriptionId, invoiceId);
tree.addItem(repair1);
tree.addItem(initial);
tree.addItem(newItem1);
try {
tree.build();
fail();
} catch (final IllegalStateException e) {
}
}
Aggregations