killbill-memoizeit
Changes
beatrix/pom.xml 6(+3 -3)
invoice/src/test/java/com/ning/billing/invoice/generator/TestBillingIntervalDetail.java 106(+106 -0)
osgi-bundles/bundles/logger/pom.xml 2(+1 -1)
Details
beatrix/pom.xml 6(+3 -3)
diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index f71aa5c..fae6f5e 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -240,9 +240,9 @@
</goals>
<configuration>
<tasks>
- <copy file="${basedir}/../osgi-bundles/tests/beatrix/target/killbill-osgi-bundles-test-beatrix-${project.version}-jar-with-dependencies.jar" tofile="${basedir}/src/test/resources/killbill-osgi-bundles-test-beatrix-${project.version}-jar-with-dependencies.jar" />
- <copy file="${basedir}/../osgi-bundles/tests/payment/target/killbill-osgi-bundles-test-payment-${project.version}-jar-with-dependencies.jar" tofile="${basedir}/src/test/resources/killbill-osgi-bundles-test-payment-${project.version}-jar-with-dependencies.jar" />
- <copy file="${basedir}/../osgi-bundles/bundles/jruby/target/killbill-osgi-bundles-jruby-${project.version}.jar" tofile="${basedir}/src/test/resources/killbill-osgi-bundles-jruby-${project.version}.jar" />
+ <copy file="${basedir}/../osgi-bundles/tests/beatrix/target/killbill-osgi-bundles-test-beatrix-${project.version}-jar-with-dependencies.jar" tofile="${basedir}/src/test/resources/killbill-osgi-bundles-test-beatrix-${project.version}-jar-with-dependencies.jar"></copy>
+ <copy file="${basedir}/../osgi-bundles/tests/payment/target/killbill-osgi-bundles-test-payment-${project.version}-jar-with-dependencies.jar" tofile="${basedir}/src/test/resources/killbill-osgi-bundles-test-payment-${project.version}-jar-with-dependencies.jar"></copy>
+ <copy file="${basedir}/../osgi-bundles/bundles/jruby/target/killbill-osgi-bundles-jruby-${project.version}.jar" tofile="${basedir}/src/test/resources/killbill-osgi-bundles-jruby-${project.version}.jar"></copy>
</tasks>
</configuration>
</execution>
diff --git a/invoice/src/main/java/com/ning/billing/invoice/generator/BillingIntervalDetail.java b/invoice/src/main/java/com/ning/billing/invoice/generator/BillingIntervalDetail.java
new file mode 100644
index 0000000..c54a084
--- /dev/null
+++ b/invoice/src/main/java/com/ning/billing/invoice/generator/BillingIntervalDetail.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.invoice.generator;
+
+import org.joda.time.LocalDate;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+
+public class BillingIntervalDetail {
+
+
+ private final boolean shouldUsePatch = true;
+
+ private final LocalDate startDate;
+ private final LocalDate endDate;
+ private final LocalDate targetDate;
+ private final int billingCycleDay;
+ private final BillingPeriod billingPeriod;
+
+ private LocalDate firstBillingCycleDate;
+ private LocalDate effectiveEndDate;
+ private LocalDate lastBillingCycleDate;
+
+ public BillingIntervalDetail(final LocalDate startDate, final LocalDate endDate, final LocalDate targetDate, final int billingCycleDay, final BillingPeriod billingPeriod) {
+ this.startDate = startDate;
+ this.endDate = endDate;
+ this.targetDate = targetDate;
+ this.billingCycleDay = billingCycleDay;
+ this.billingPeriod = billingPeriod;
+ computeAll();
+ }
+
+ public LocalDate getFirstBillingCycleDate() {
+ return firstBillingCycleDate;
+ }
+
+ public LocalDate getEffectiveEndDate() {
+ return effectiveEndDate;
+ }
+
+ public LocalDate getFutureBillingDateFor(int nbPeriod) {
+ final int numberOfMonthsPerBillingPeriod = billingPeriod.getNumberOfMonths();
+ LocalDate proposedDate = firstBillingCycleDate.plusMonths((nbPeriod) * numberOfMonthsPerBillingPeriod);
+ return alignProposedBillCycleDate(proposedDate);
+ }
+
+ public LocalDate getLastBillingCycleDate() {
+ return lastBillingCycleDate;
+ }
+
+ private void computeAll() {
+ calculateFirstBillingCycleDate();
+ calculateEffectiveEndDate();
+ calculateLastBillingCycleDate();
+ }
+
+ private void calculateFirstBillingCycleDate() {
+
+ final int lastDayOfMonth = startDate.dayOfMonth().getMaximumValue();
+ final LocalDate billingCycleDate;
+ if (billingCycleDay > lastDayOfMonth) {
+ billingCycleDate = new LocalDate(startDate.getYear(), startDate.getMonthOfYear(), lastDayOfMonth, startDate.getChronology());
+ } else {
+ billingCycleDate = new LocalDate(startDate.getYear(), startDate.getMonthOfYear(), billingCycleDay, startDate.getChronology());
+ }
+
+ LocalDate proposedDate = billingCycleDate;
+ while (proposedDate.isBefore(startDate)) {
+ proposedDate = proposedDate.plusMonths(1);
+ }
+ firstBillingCycleDate = proposedDate;
+ }
+
+ private void calculateEffectiveEndDate() {
+
+ // We have an endDate and the targetDate is greater or equal to our endDate => return it
+ if (endDate != null && !targetDate.isBefore(endDate)) {
+ effectiveEndDate = endDate;
+ return;
+ }
+
+ if (targetDate.isBefore(firstBillingCycleDate)) {
+ effectiveEndDate = firstBillingCycleDate;
+ return;
+ }
+
+ final int numberOfMonthsInPeriod = billingPeriod.getNumberOfMonths();
+ int numberOfPeriods = 0;
+ LocalDate proposedDate = firstBillingCycleDate;
+
+ while (!proposedDate.isAfter(targetDate)) {
+ proposedDate = firstBillingCycleDate.plusMonths(numberOfPeriods * numberOfMonthsInPeriod);
+ numberOfPeriods += 1;
+ }
+ proposedDate = alignProposedBillCycleDate(proposedDate);
+
+ // The proposedDate is greater to our endDate => return it
+ if (endDate != null && endDate.isBefore(proposedDate)) {
+ effectiveEndDate = endDate;
+ } else {
+ effectiveEndDate = proposedDate;
+ }
+ }
+
+
+ private void calculateLastBillingCycleDate() {
+
+ // Start from firstBillingCycleDate and billingPeriod until we pass the effectiveEndDate
+ LocalDate proposedDate = firstBillingCycleDate;
+ int numberOfPeriods = 0;
+ while (!proposedDate.isAfter(effectiveEndDate)) {
+ proposedDate = firstBillingCycleDate.plusMonths(numberOfPeriods * billingPeriod.getNumberOfMonths());
+ numberOfPeriods += 1;
+ }
+
+ // Our proposed date is billingCycleDate prior to the effectiveEndDate
+ proposedDate = proposedDate.plusMonths(-billingPeriod.getNumberOfMonths());
+ proposedDate = alignProposedBillCycleDate(proposedDate);
+
+ if (proposedDate.isBefore(firstBillingCycleDate)) {
+ // Make sure not to go too far in the past
+ lastBillingCycleDate = firstBillingCycleDate;
+ } else {
+ lastBillingCycleDate = proposedDate;
+ }
+ }
+
+
+ //
+ // We start from a billCycleDate
+ //
+ private LocalDate alignProposedBillCycleDate(final LocalDate proposedDate) {
+ if (!shouldUsePatch) {
+ return proposedDate;
+ }
+ final int lastDayOfMonth = proposedDate.dayOfMonth().getMaximumValue();
+
+ int proposedBillCycleDate = proposedDate.getDayOfMonth();
+ if (proposedBillCycleDate < billingCycleDay && billingCycleDay <= lastDayOfMonth) {
+ proposedBillCycleDate = billingCycleDay;
+ }
+ return new LocalDate(proposedDate.getYear(), proposedDate.getMonthOfYear(), proposedBillCycleDate, proposedDate.getChronology());
+ }
+}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/InAdvanceBillingMode.java b/invoice/src/main/java/com/ning/billing/invoice/model/InAdvanceBillingMode.java
index 5ad6d44..9fd7784 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/InAdvanceBillingMode.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/InAdvanceBillingMode.java
@@ -27,10 +27,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.invoice.generator.BillingIntervalDetail;
-import static com.ning.billing.invoice.generator.InvoiceDateUtils.calculateBillingCycleDateOnOrAfter;
-import static com.ning.billing.invoice.generator.InvoiceDateUtils.calculateEffectiveEndDate;
-import static com.ning.billing.invoice.generator.InvoiceDateUtils.calculateLastBillingCycleDateBefore;
import static com.ning.billing.invoice.generator.InvoiceDateUtils.calculateNumberOfWholeBillingPeriods;
import static com.ning.billing.invoice.generator.InvoiceDateUtils.calculateProRationAfterLastBillingCycleDate;
import static com.ning.billing.invoice.generator.InvoiceDateUtils.calculateProRationBeforeFirstBillingPeriod;
@@ -52,7 +50,7 @@ public class InAdvanceBillingMode implements BillingMode {
final List<RecurringInvoiceItemData> results = new ArrayList<RecurringInvoiceItemData>();
- final LocalDate firstBillingCycleDate = calculateBillingCycleDateOnOrAfter(startDate, billingCycleDayLocal);
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(startDate, endDate, targetDate, billingCycleDayLocal, billingPeriod);
// We are not billing for less than a day (we could...)
if (endDate != null && endDate.equals(startDate)) {
@@ -62,7 +60,7 @@ public class InAdvanceBillingMode implements BillingMode {
// If there is an endDate and that endDate is before our first coming firstBillingCycleDate, all we have to do
// is to charge for that period
//
- if (endDate != null && !endDate.isAfter(firstBillingCycleDate)) {
+ if (endDate != null && !endDate.isAfter(billingIntervalDetail.getFirstBillingCycleDate())) {
final BigDecimal leadingProRationPeriods = calculateProRationBeforeFirstBillingPeriod(startDate, endDate, billingPeriod);
final RecurringInvoiceItemData itemData = new RecurringInvoiceItemData(startDate, endDate, leadingProRationPeriods);
results.add(itemData);
@@ -74,11 +72,11 @@ public class InAdvanceBillingMode implements BillingMode {
// i) The first firstBillingCycleDate is strictly after our start date AND
// ii) The endDate is is not null and is strictly after our firstBillingCycleDate (previous check)
//
- if (firstBillingCycleDate.isAfter(startDate)) {
- final BigDecimal leadingProRationPeriods = calculateProRationBeforeFirstBillingPeriod(startDate, firstBillingCycleDate, billingPeriod);
+ if (billingIntervalDetail.getFirstBillingCycleDate().isAfter(startDate)) {
+ final BigDecimal leadingProRationPeriods = calculateProRationBeforeFirstBillingPeriod(startDate, billingIntervalDetail.getFirstBillingCycleDate(), billingPeriod);
if (leadingProRationPeriods != null && leadingProRationPeriods.compareTo(BigDecimal.ZERO) > 0) {
// Not common - add info in the logs for debugging purposes
- final RecurringInvoiceItemData itemData = new RecurringInvoiceItemData(startDate, firstBillingCycleDate, leadingProRationPeriods);
+ final RecurringInvoiceItemData itemData = new RecurringInvoiceItemData(startDate, billingIntervalDetail.getFirstBillingCycleDate(), leadingProRationPeriods);
log.info("Adding pro-ration: {}", itemData);
results.add(itemData);
}
@@ -89,19 +87,13 @@ public class InAdvanceBillingMode implements BillingMode {
// - If endDate != null and targetDate is after endDate => this is the endDate and will lead to a trailing pro-ration
// - If not, this is the last billingCycleDate calculation right after the targetDate
//
- final LocalDate effectiveEndDate;
- if (endDate != null) {
- effectiveEndDate = calculateEffectiveEndDate(firstBillingCycleDate, targetDate, endDate, billingPeriod);
- } else {
- effectiveEndDate = calculateEffectiveEndDate(firstBillingCycleDate, targetDate, billingPeriod);
- }
+ final LocalDate effectiveEndDate = billingIntervalDetail.getEffectiveEndDate();
//
// Based on what we calculated previously, code recompute one more time the numberOfWholeBillingPeriods
//
- final LocalDate lastBillingCycleDate = calculateLastBillingCycleDateBefore(effectiveEndDate, firstBillingCycleDate, billingCycleDayLocal, billingPeriod);
- final int numberOfWholeBillingPeriods = calculateNumberOfWholeBillingPeriods(firstBillingCycleDate, lastBillingCycleDate, billingPeriod);
- final int numberOfMonthsPerBillingPeriod = billingPeriod.getNumberOfMonths();
+ final LocalDate lastBillingCycleDate = billingIntervalDetail.getLastBillingCycleDate();
+ final int numberOfWholeBillingPeriods = calculateNumberOfWholeBillingPeriods(billingIntervalDetail.getFirstBillingCycleDate(), lastBillingCycleDate, billingPeriod);
for (int i = 0; i < numberOfWholeBillingPeriods; i++) {
final LocalDate servicePeriodStartDate;
@@ -116,8 +108,7 @@ public class InAdvanceBillingMode implements BillingMode {
}
// Make sure to align the end date with the BCD
- final LocalDate servicePeriodEndDate = firstBillingCycleDate.plusMonths((i + 1) * numberOfMonthsPerBillingPeriod);
-
+ final LocalDate servicePeriodEndDate = billingIntervalDetail.getFutureBillingDateFor(i + 1);
results.add(new RecurringInvoiceItemData(servicePeriodStartDate, servicePeriodEndDate, BigDecimal.ONE));
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/generator/TestBillingIntervalDetail.java b/invoice/src/test/java/com/ning/billing/invoice/generator/TestBillingIntervalDetail.java
new file mode 100644
index 0000000..65c692f
--- /dev/null
+++ b/invoice/src/test/java/com/ning/billing/invoice/generator/TestBillingIntervalDetail.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.invoice.generator;
+
+import org.joda.time.LocalDate;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.invoice.InvoiceTestSuiteNoDB;
+
+public class TestBillingIntervalDetail extends InvoiceTestSuiteNoDB {
+
+
+ @Test(groups = "fast")
+ public void testNextBCDShouldNotBeInThePast() throws Exception {
+ final LocalDate from = new LocalDate("2012-07-16");
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(from, null, new LocalDate(), 15, BillingPeriod.MONTHLY);
+ final LocalDate to = billingIntervalDetail.getFirstBillingCycleDate();
+ Assert.assertEquals(to, new LocalDate("2012-08-15"));
+ }
+
+ @Test(groups = "fast")
+ public void testBeforeBCDWithOnOrAfter() throws Exception {
+ final LocalDate from = new LocalDate("2012-03-02");
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(from, null, new LocalDate(), 3, BillingPeriod.MONTHLY);
+ final LocalDate to = billingIntervalDetail.getFirstBillingCycleDate();
+ Assert.assertEquals(to, new LocalDate("2012-03-03"));
+ }
+
+ @Test(groups = "fast")
+ public void testEqualBCDWithOnOrAfter() throws Exception {
+ final LocalDate from = new LocalDate("2012-03-03");
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(from, null, new LocalDate(), 3, BillingPeriod.MONTHLY);
+ final LocalDate to = billingIntervalDetail.getFirstBillingCycleDate();
+ Assert.assertEquals(to, new LocalDate("2012-03-03"));
+ }
+
+ @Test(groups = "fast")
+ public void testAfterBCDWithOnOrAfter() throws Exception {
+ final LocalDate from = new LocalDate("2012-03-04");
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(from, null, new LocalDate(), 3, BillingPeriod.MONTHLY);
+ final LocalDate to = billingIntervalDetail.getFirstBillingCycleDate();
+ Assert.assertEquals(to, new LocalDate("2012-04-03"));
+ }
+
+ @Test(groups = "fast")
+ public void testEffectiveEndDate() throws Exception {
+ final LocalDate firstBCD = new LocalDate(2012, 7, 16);
+ final LocalDate targetDate = new LocalDate(2012, 8, 16);
+ final BillingPeriod billingPeriod = BillingPeriod.MONTHLY;
+
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(firstBCD, null, targetDate, 16, billingPeriod);
+ final LocalDate effectiveEndDate = billingIntervalDetail.getEffectiveEndDate();
+ Assert.assertEquals(effectiveEndDate, new LocalDate(2012, 9, 16));
+ }
+
+ @Test(groups = "fast")
+ public void testLastBCD() throws Exception {
+ final LocalDate start = new LocalDate(2012, 7, 16);
+ final LocalDate endDate = new LocalDate(2012, 9, 15); // so we get effectiveEndDate on 9/15
+ final LocalDate targetDate = new LocalDate(2012, 8, 16);
+
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(start, endDate, targetDate, 16, BillingPeriod.MONTHLY);
+ final LocalDate lastBCD = billingIntervalDetail.getLastBillingCycleDate();
+ Assert.assertEquals(lastBCD, new LocalDate(2012, 8, 16));
+ }
+
+ @Test(groups = "fast")
+ public void testLastBCDShouldNotBeBeforePreviousBCD() throws Exception {
+ final LocalDate start = new LocalDate("2012-07-16");
+ final int bcdLocal = 15;
+
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(start, null, start, bcdLocal, BillingPeriod.MONTHLY);
+ final LocalDate lastBCD = billingIntervalDetail.getLastBillingCycleDate();
+ Assert.assertEquals(lastBCD, new LocalDate("2012-08-15"));
+ }
+
+ @Test(groups = "fast")
+ public void testBCD31StartingWith30DayMonth() throws Exception {
+ final LocalDate start = new LocalDate("2012-04-30");
+ final LocalDate targetDate = new LocalDate("2012-04-30");
+ final LocalDate end = null;
+ final int bcdLocal = 31;
+
+ final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(start, end, targetDate, bcdLocal, BillingPeriod.MONTHLY);
+ final LocalDate effectiveEndDate = billingIntervalDetail.getEffectiveEndDate();
+ Assert.assertEquals(effectiveEndDate, new LocalDate("2012-05-31"));
+ }
+
+
+}
osgi-bundles/bundles/logger/pom.xml 2(+1 -1)
diff --git a/osgi-bundles/bundles/logger/pom.xml b/osgi-bundles/bundles/logger/pom.xml
index bc85013..f5fc4b1 100644
--- a/osgi-bundles/bundles/logger/pom.xml
+++ b/osgi-bundles/bundles/logger/pom.xml
@@ -56,7 +56,7 @@
<configuration>
<instructions>
<Bundle-Activator>com.ning.billing.osgi.bundles.logger.Activator</Bundle-Activator>
- <Export-Package />
+ <Export-Package></Export-Package>
<Private-Package>com.ning.billing.osgi.bundles.logger.*</Private-Package>
<!-- Optional resolution because exported by the Felix system bundle -->
<Import-Package>*;resolution:=optional</Import-Package>