diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
index e3e1f08..e3efac7 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
@@ -21,6 +21,7 @@ import java.util.List;
import java.util.UUID;
import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
import org.joda.time.Interval;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
@@ -46,28 +47,28 @@ public class TestIntegration extends TestIntegrationBase {
@Test(groups = "slow", enabled = true)
public void testBasePlanCompleteWithBillingDayInPast() throws Exception {
log.info("Starting testBasePlanCompleteWithBillingDayInPast");
- final DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
+ final DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
testBasePlanComplete(startDate, 31, false);
}
@Test(groups = "slow", enabled = true)
public void testBasePlanCompleteWithBillingDayPresent() throws Exception {
log.info("Starting testBasePlanCompleteWithBillingDayPresent");
- final DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
+ final DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
testBasePlanComplete(startDate, 1, false);
}
@Test(groups = "slow", enabled = true)
public void testBasePlanCompleteWithBillingDayAlignedWithTrial() throws Exception {
log.info("Starting testBasePlanCompleteWithBillingDayAlignedWithTrial");
- final DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
+ final DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
testBasePlanComplete(startDate, 2, false);
}
@Test(groups = "slow", enabled = true)
public void testBasePlanCompleteWithBillingDayInFuture() throws Exception {
log.info("Starting testBasePlanCompleteWithBillingDayInFuture");
- final DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
+ final DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
testBasePlanComplete(startDate, 3, true);
}
@@ -114,7 +115,7 @@ public class TestIntegration extends TestIntegrationBase {
log.info("Starting testRepairChangeBPWithAddonIncluded");
- final DateTime initialDate = new DateTime(2012, 4, 25, 0, 13, 42, 0);
+ final DateTime initialDate = new DateTime(2012, 4, 25, 0, 13, 42, 0, testTimeZone);
clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
final Account account = createAccountWithPaymentMethod(getAccountData(25));
@@ -204,7 +205,7 @@ public class TestIntegration extends TestIntegrationBase {
final UUID accountId = account.getId();
assertNotNull(account);
- final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
+ final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0, testTimeZone);
clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
final SubscriptionBundle bundle = entitlementUserApi.createBundleForAccount(account.getId(), "someBundle", context);
@@ -232,7 +233,7 @@ public class TestIntegration extends TestIntegrationBase {
log.info("Starting testWithRecreatePlan");
- final DateTime initialDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
+ final DateTime initialDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
final int billingDay = 2;
log.info("Beginning test with BCD of " + billingDay);
@@ -303,7 +304,6 @@ public class TestIntegration extends TestIntegrationBase {
private void testBasePlanComplete(final DateTime initialCreationDate, final int billingDay,
final boolean proRationExpected) throws Exception {
-
log.info("Beginning test with BCD of " + billingDay);
final Account account = createAccountWithPaymentMethod(getAccountData(billingDay));
final UUID accountId = account.getId();
@@ -506,7 +506,7 @@ public class TestIntegration extends TestIntegrationBase {
log.info("Starting testForMultipleRecurringPhases");
- final DateTime initialCreationDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
+ final DateTime initialCreationDate = new DateTime(2012, 2, 1, 0, 3, 42, 0, testTimeZone);
clock.setDeltaFromReality(initialCreationDate.getMillis() - clock.getUTCNow().getMillis());
final Account account = createAccountWithPaymentMethod(getAccountData(2));
diff --git a/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java b/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java
index 69a8ac4..7d34da2 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java
@@ -297,44 +297,38 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
return items;
}
-
- private DateTime roundDateTimeToDate(final DateTime input, final DateTimeZone timeZone) {
- if (input == null) {
- return null;
- }
- final DateTime tzAdjustedStartDate = input.toDateTime(timeZone);
- final DateTime roundedStartDate = new DateTime(tzAdjustedStartDate.getYear(), tzAdjustedStartDate.getMonthOfYear(), tzAdjustedStartDate.getDayOfMonth(), 0, 0, timeZone);
- return roundedStartDate;
- }
-
+ // 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)
List<InvoiceItem> processEvents(final UUID invoiceId, final UUID accountId, final BillingEvent thisEvent, @Nullable final BillingEvent nextEvent,
final DateTime targetDate, final Currency currency) throws InvoiceApiException {
final List<InvoiceItem> items = new ArrayList<InvoiceItem>();
- final InvoiceItem fixedPriceInvoiceItem = generateFixedPriceItem(invoiceId, accountId, thisEvent, targetDate, currency);
+
+ final DateTime roundedTargetDate = InvoiceDateUtils.roundDateTimeToDate(targetDate, thisEvent.getTimeZone());
+
+ // Handle fixed price items
+ final InvoiceItem fixedPriceInvoiceItem = generateFixedPriceItem(invoiceId, accountId, thisEvent, roundedTargetDate, currency);
if (fixedPriceInvoiceItem != null) {
items.add(fixedPriceInvoiceItem);
}
+ // Handle recurring items
final BillingPeriod billingPeriod = thisEvent.getBillingPeriod();
if (billingPeriod != BillingPeriod.NO_BILLING_PERIOD) {
final BillingMode billingMode = instantiateBillingMode(thisEvent.getBillingMode());
// Invoice granularity is day; (if not some comparison might fail)
final DateTime startDate = thisEvent.getEffectiveDate();
- final DateTime roundedStartDate = roundDateTimeToDate(startDate, thisEvent.getTimeZone());
- final DateTime roundedTargetDate = roundDateTimeToDate(targetDate, thisEvent.getTimeZone());
+ final DateTime roundedStartDate = InvoiceDateUtils.roundDateTimeToDate(startDate, thisEvent.getTimeZone());
- log.info(String.format("start = %s, rounded = %s, target = %s, in = %s", startDate, roundedStartDate, targetDate, (!roundedStartDate.isAfter(targetDate)) ? "in" : "out"));
- if (!roundedStartDate.isAfter(targetDate)) {
+ if (!roundedStartDate.isAfter(roundedTargetDate)) {
final DateTime endDate = (nextEvent == null) ? null : nextEvent.getEffectiveDate();
- final DateTime roundedEndDate = roundDateTimeToDate(endDate, thisEvent.getTimeZone());
+ final DateTime roundedEndDate = InvoiceDateUtils.roundDateTimeToDate(endDate, thisEvent.getTimeZone());
final int billCycleDay = thisEvent.getBillCycleDay();
final List<RecurringInvoiceItemData> itemData;
try {
itemData = billingMode.calculateInvoiceItemData(roundedStartDate, roundedEndDate, roundedTargetDate, billCycleDay, billingPeriod);
} catch (InvalidDateSequenceException e) {
- throw new InvoiceApiException(ErrorCode.INVOICE_INVALID_DATE_SEQUENCE, startDate, endDate, targetDate);
+ throw new InvoiceApiException(ErrorCode.INVOICE_INVALID_DATE_SEQUENCE, startDate, endDate, roundedTargetDate);
}
for (final RecurringInvoiceItemData itemDatum : itemData) {
@@ -370,20 +364,23 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
}
InvoiceItem generateFixedPriceItem(final UUID invoiceId, final UUID accountId, final BillingEvent thisEvent,
- final DateTime targetDate, final Currency currency) {
- if (thisEvent.getEffectiveDate().isAfter(targetDate)) {
+ final DateTime roundedTargetDate, final Currency currency) {
+ final DateTime roundedStartDate = InvoiceDateUtils.roundDateTimeToDate(thisEvent.getEffectiveDate(), thisEvent.getTimeZone());
+
+ if (roundedStartDate.isAfter(roundedTargetDate)) {
return null;
} else {
final BigDecimal fixedPrice = thisEvent.getFixedPrice();
if (fixedPrice != null) {
final Duration duration = thisEvent.getPlanPhase().getDuration();
- final DateTime endDate = duration.addToDateTime(thisEvent.getEffectiveDate());
+ final DateTime endDate = InvoiceDateUtils.roundDateTimeToDate(duration.addToDateTime(roundedStartDate), thisEvent.getTimeZone());
return new FixedPriceInvoiceItem(invoiceId, accountId, thisEvent.getSubscription().getBundleId(),
- thisEvent.getSubscription().getId(),
- thisEvent.getPlan().getName(), thisEvent.getPlanPhase().getName(),
- thisEvent.getEffectiveDate(), endDate, fixedPrice, currency);
+ thisEvent.getSubscription().getId(),
+ thisEvent.getPlan().getName(), thisEvent.getPlanPhase().getName(),
+ roundedStartDate, endDate,
+ fixedPrice, currency);
} else {
return null;
}