killbill-aplcache
Changes
.travis.yml 5(+5 -0)
beatrix/pom.xml 1(+1 -0)
beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java 5(+1 -4)
beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java 175(+175 -0)
beatrix/src/test/resources/log4j.xml 4(+4 -0)
invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java 9(+7 -2)
invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java 6(+6 -0)
invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java 9(+4 -5)
invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java 228(+166 -62)
junction/pom.xml 19(+12 -7)
junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java 106(+75 -31)
junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEventSet.java 12(+12 -0)
junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java 2(+1 -1)
overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java 6(+6 -0)
overdue/src/test/java/com/ning/billing/overdue/applicator/ApplicatorMockJunctionModule.java 8(+1 -7)
payment/src/main/java/com/ning/billing/payment/provider/DefaultPaymentProviderPluginRegistry.java 1(+1 -0)
pom.xml 20(+13 -7)
Details
.travis.yml 5(+5 -0)
diff --git a/.travis.yml b/.travis.yml
index 93b1a6e..3f1b576 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,3 +4,8 @@ script: mvn clean install -Ptravis
notifications:
email:
- ri-dev@ning.com
+
+jdk:
+ - openjdk6
+ - openjdk7
+ - oraclejdk7
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
index eb68910..acd4d8f 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
@@ -193,7 +193,6 @@ public class BusinessAccountRecorder {
}
}
}
-
bac.setLastPaymentStatus(lastPaymentStatus);
bac.setPaymentMethod(paymentMethod);
diff --git a/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java b/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java
index 17ea132..0b2ef57 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java
@@ -17,6 +17,7 @@
package com.ning.billing.catalog.api;
import java.util.Date;
+import java.util.List;
public interface StaticCatalog {
@@ -76,4 +77,6 @@ public interface StaticCatalog {
public abstract boolean canCreatePlan(PlanSpecifier specifier) throws CatalogApiException;
+ public abstract List<Listing> getAvailableAddonListings(String baseProductName) throws CatalogApiException;
+
}
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index 1ff2610..7816bee 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -17,9 +17,6 @@
package com.ning.billing;
public enum ErrorCode {
-
-
-
/*
* Range 0 : COMMON EXCEPTIONS
*/
@@ -185,7 +182,17 @@ public enum ErrorCode {
INVOICE_NO_ACCOUNT_ID_FOR_SUBSCRIPTION_ID(4003, "No account id was retrieved for subscription id %s"),
INVOICE_INVALID_DATE_SEQUENCE(4004, "Date sequence was invalid. Start Date: %s; End Date: %s; Target Date: %s"),
INVOICE_TARGET_DATE_TOO_FAR_IN_THE_FUTURE(4005, "The target date was too far in the future. Target Date: %s"),
-
+
+ /*
+ *
+ * Range 4900: Invoice payment
+ *
+ */
+ INVOICE_PAYMENT_NOT_FOUND(4900, "No invoice payment could be found for id %s."),
+ CHARGE_BACK_AMOUNT_TOO_HIGH(4901, "Tried to charge back %s of a %s payment."),
+ CHARGE_BACK_AMOUNT_IS_NEGATIVE(4902, "Charge backs for negative amounts are not permitted"),
+ CHARGE_BACK_COULD_NOT_FIND_ACCOUNT_ID(4093, "Could not find chargeback for id %s."),
+ CHARGE_BACK_DOES_NOT_EXIST(4093, "Could not find chargeback for id %s."),
/*
*
* Range 5000: Overdue system
@@ -228,9 +235,11 @@ public enum ErrorCode {
PAYMENT_NULL_INVOICE(7017, "Invoice %s has a balance <= 0 "),
PAYMENT_AMOUNT_DENIED(7018, "Payment amount requested for invoice %s is greater than invoice balance [%f/%f]"),
PAYMENT_INTERNAL_ERROR(7019, "Internal payment error : %s"),
+ PAYMENT_NO_SUCH_PAYMENT(7020, "Payment %s does not exist"),
PAYMENT_PLUGIN_TIMEOUT(7100, "Plugin timeout for account %s and invoice %s"),
PAYMENT_PLUGIN_ACCOUNT_INIT(7101, "Account initialization for account %s and plugin % s failed: %s"),
+
/*
*
diff --git a/api/src/main/java/com/ning/billing/invoice/api/Invoice.java b/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
index 9f21b11..bf7fd7b 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
@@ -57,7 +57,9 @@ public interface Invoice extends Entity {
BigDecimal getAmountPaid();
- BigDecimal getTotalAmount();
+ BigDecimal getAmountCharged();
+
+ BigDecimal getAmountCredited();
BigDecimal getBalance();
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java b/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java
index cd7decd..9f898c7 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java
@@ -46,5 +46,7 @@ public interface InvoiceItem extends Entity, Comparable<InvoiceItem> {
Currency getCurrency();
+ InvoiceItemType getInvoiceItemType();
+
InvoiceItem asReversingItem();
}
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoiceItemType.java b/api/src/main/java/com/ning/billing/invoice/api/InvoiceItemType.java
index ce066a4..aaae9df 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoiceItemType.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoiceItemType.java
@@ -23,6 +23,5 @@ public enum InvoiceItemType {
MIGRATION,
REFUND,
CHARGE_BACK,
- ADD_CREDIT,
- USE_CREDIT
+ CREDIT
}
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java b/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java
index 29f175b..4ba42c1 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java
@@ -32,4 +32,11 @@ public interface InvoicePayment extends Entity {
BigDecimal getAmount();
Currency getCurrency();
+
+ UUID getReversedInvoicePaymentId();
+
+ /*
+ * @param chargeBackAmount BigDecimal pass the amount as a positive number
+ */
+ InvoicePayment asChargeBack(BigDecimal chargeBackAmount, DateTime chargeBackDate) throws InvoiceApiException;
}
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java b/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java
index 0a34604..ecc477b 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java
@@ -26,7 +26,6 @@ import org.joda.time.DateTime;
import com.ning.billing.catalog.api.Currency;
public interface InvoicePaymentApi {
-
/**
* @param accountId
* @return All invoices, including migrated invoices
@@ -45,4 +44,17 @@ public interface InvoicePaymentApi {
public void notifyOfPaymentAttempt(UUID invoiceId, UUID paymentAttemptId, DateTime paymentAttemptDate, CallContext context);
+ public void processChargeback(UUID invoicePaymentId, BigDecimal amount, CallContext context) throws InvoiceApiException;
+
+ public void processChargeback(UUID invoicePaymentId, CallContext context) throws InvoiceApiException;
+
+ public BigDecimal getRemainingAmountPaid(UUID invoicePaymentId);
+
+ public List<InvoicePayment> getChargebacksByAccountId(UUID accountId);
+
+ public UUID getAccountIdFromInvoicePaymentId(UUID uuid) throws InvoiceApiException;
+
+ public List<InvoicePayment> getChargebacksByPaymentAttemptId(UUID paymentAttemptId);
+
+ public InvoicePayment getChargebackById(UUID chargebackId) throws InvoiceApiException;
}
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java b/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java
index 66016df..56ee93f 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java
@@ -16,6 +16,7 @@
package com.ning.billing.invoice.api;
+import com.ning.billing.catalog.api.Currency;
import com.ning.billing.util.callcontext.CallContext;
import org.joda.time.DateTime;
@@ -41,5 +42,10 @@ public interface InvoiceUserApi {
public void tagInvoiceAsWrittenOff(UUID invoiceId, CallContext context);
- public void tagInvoiceAsNotWrittenOff(UUID invoiceId, CallContext context);
+ public void tagInvoiceAsNotWrittenOff(UUID invoiceId, CallContext context) throws InvoiceApiException;
+
+ public InvoiceItem getCreditById(UUID creditId) throws InvoiceApiException;
+
+ public InvoiceItem insertCredit( UUID accountId, BigDecimal amount, DateTime effectiveDate,
+ Currency currency, CallContext context) throws InvoiceApiException;
}
diff --git a/api/src/main/java/com/ning/billing/junction/api/BillingApi.java b/api/src/main/java/com/ning/billing/junction/api/BillingApi.java
index cff8ee7..bb38e8d 100644
--- a/api/src/main/java/com/ning/billing/junction/api/BillingApi.java
+++ b/api/src/main/java/com/ning/billing/junction/api/BillingApi.java
@@ -16,10 +16,8 @@
package com.ning.billing.junction.api;
-import java.util.SortedSet;
import java.util.UUID;
-import com.ning.billing.entitlement.api.billing.BillingEvent;
import com.ning.billing.entitlement.api.billing.ChargeThruApi;
public interface BillingApi extends ChargeThruApi {
@@ -29,5 +27,5 @@ public interface BillingApi extends ChargeThruApi {
* @return an ordered list of billing event for the given accounts
*
*/
- public SortedSet<BillingEvent> getBillingEventsForAccountAndUpdateAccountBCD(UUID accountId);
+ public BillingEventSet getBillingEventsForAccountAndUpdateAccountBCD(UUID accountId);
}
diff --git a/api/src/main/java/com/ning/billing/junction/api/BillingEventSet.java b/api/src/main/java/com/ning/billing/junction/api/BillingEventSet.java
index 3a7b66d..aed5c6a 100644
--- a/api/src/main/java/com/ning/billing/junction/api/BillingEventSet.java
+++ b/api/src/main/java/com/ning/billing/junction/api/BillingEventSet.java
@@ -27,5 +27,7 @@ public interface BillingEventSet extends SortedSet<BillingEvent> {
public abstract boolean isAccountAutoInvoiceOff();
public abstract List<UUID> getSubscriptionIdsWithAutoInvoiceOff();
+
+ public boolean isLast(BillingEvent event);
}
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
index d2661f3..03954eb 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
@@ -42,6 +42,8 @@ public interface PaymentApi {
public List<Payment> getAccountPayments(final UUID accountId)
throws PaymentApiException;
+ public Payment getPayment(final UUID paymentId)
+ throws PaymentApiException;
/*
* Payment method Apis
@@ -71,6 +73,5 @@ public interface PaymentApi {
public void setDefaultPaymentMethod(final Account account, final UUID paymentMethodId, final CallContext context)
throws PaymentApiException;
-
-
+
}
diff --git a/api/src/main/java/com/ning/billing/util/api/TagUserApi.java b/api/src/main/java/com/ning/billing/util/api/TagUserApi.java
index 16b8a30..fed7517 100644
--- a/api/src/main/java/com/ning/billing/util/api/TagUserApi.java
+++ b/api/src/main/java/com/ning/billing/util/api/TagUserApi.java
@@ -20,6 +20,7 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
+import com.ning.billing.invoice.api.InvoiceApiException;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.dao.ObjectType;
diff --git a/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java b/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
index c122766..65d32c7 100644
--- a/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
+++ b/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
@@ -48,7 +48,9 @@ public enum ControlTagType {
public TagDefinition toTagDefinition() {
return new TagDefinition() {
- @Override public String getName() {return this.toString();}
+ @Override public String getName() {
+ return name();
+ }
@Override public String getDescription() {return description;}
beatrix/pom.xml 1(+1 -0)
diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index a81c264..547db04 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -111,6 +111,7 @@
<artifactId>jdbi</artifactId>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
index dcdc17b..1d48692 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
@@ -187,7 +187,6 @@ public class TestOverdueIntegration extends TestIntegrationBase {
clock.addDays(15); // DAY 45 - 15 days after invoice
assertTrue(busHandler.isCompleted(DELAY));
- overdueApi.refreshOverdueStateFor(bundle); // trigger a refresh because there are no events to do it for us
//should still be in clear state
checkODState(BlockingApi.CLEAR_STATE_NAME);
@@ -200,14 +199,12 @@ public class TestOverdueIntegration extends TestIntegrationBase {
clock.addDays(2); //DAY 67 - 37 days after invoice
assertTrue(busHandler.isCompleted(DELAY));
- overdueApi.refreshOverdueStateFor(bundle); // trigger a refresh because there are no events to do it for us
// should still be in OD1
checkODState("OD1");
//busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT_ERROR);
clock.addDays(8); //DAY 75 - 45 days after invoice
assertTrue(busHandler.isCompleted(DELAY));
- overdueApi.refreshOverdueStateFor(bundle); // trigger a refresh because there are no events to do it for us
// should still be in OD1
checkODState("OD2");
@@ -229,7 +226,6 @@ public class TestOverdueIntegration extends TestIntegrationBase {
}
}
- overdueApi.refreshOverdueStateFor(bundle);
checkODState(BlockingApi.CLEAR_STATE_NAME);
}
@@ -240,6 +236,7 @@ public class TestOverdueIntegration extends TestIntegrationBase {
await().atMost(10, SECONDS).until(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
+ overdueApi.refreshOverdueStateFor(bundle);
return expected.equals(blockingApi.getBlockingStateFor(bundle).getStateName()) ;
}
});
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java
new file mode 100644
index 0000000..bc4f5a9
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationWithAutoInvoiceOffTag.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2010-2011 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.beatrix.integration;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import com.google.inject.Inject;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.api.TestApiListener.NextEvent;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.util.api.TagDefinitionApiException;
+import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.tag.ControlTagType;
+import com.ning.billing.util.tag.Tag;
+import com.ning.billing.util.tag.TagDefinition;
+
+@Guice(modules = {BeatrixModule.class})
+public class TestIntegrationWithAutoInvoiceOffTag extends TestIntegrationBase {
+
+ @Inject
+ private InvoiceUserApi invoiceApi;
+
+ @Inject
+ private TagUserApi tagApi;
+
+ private Account account;
+ private SubscriptionBundle bundle;
+ private String productName;
+ private BillingPeriod term;
+ private String planSetName;
+
+ @BeforeMethod(groups = {"slow"})
+ public void setupOverdue() throws Exception {
+
+ account = accountUserApi.createAccount(getAccountData(25), null, null, context);
+ assertNotNull(account);
+
+ bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever", context);
+
+ productName = "Shotgun";
+ term = BillingPeriod.MONTHLY;
+ planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
+ }
+
+ @Test(groups={"slow"}, enabled = true)
+ public void testAutoInvoiceOffAccount() throws Exception {
+ clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
+ addTag(account.getId(), ObjectType.ACCOUNT);
+
+ // set next invoice to fail and create network
+ busHandler.pushExpectedEvents(NextEvent.CREATE);
+ SubscriptionData baseSubscription = subscriptionDataFromSubscription(entitlementUserApi.createSubscription(bundle.getId(),
+ new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null), null, context));
+ assertNotNull(baseSubscription);
+ assertTrue(busHandler.isCompleted(DELAY));
+
+
+ Collection<Invoice> invoices = invoiceApi.getInvoicesByAccount(account.getId());
+ assertEquals(invoices.size(), 0);
+
+ clock.addDays(10); // DAY 10 still in trial
+ assertTrue(busHandler.isCompleted(DELAY));
+
+ invoices = invoiceApi.getInvoicesByAccount(account.getId());
+ assertEquals(invoices.size(), 0);
+
+ busHandler.pushExpectedEvents(NextEvent.PHASE);
+ clock.addDays(30); // DAY 40 out of trial
+ assertTrue(busHandler.isCompleted(DELAY));
+
+ invoices = invoiceApi.getInvoicesByAccount(account.getId());
+ assertEquals(invoices.size(), 0);
+
+ }
+
+ @Test(groups={"slow"}, enabled = true)
+ public void testAutoInvoiceOffSingleSubscription() throws Exception {
+ clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
+
+ // set next invoice to fail and create network
+ busHandler.pushExpectedEvents(NextEvent.CREATE,NextEvent.INVOICE);
+ SubscriptionData baseSubscription = subscriptionDataFromSubscription(entitlementUserApi.createSubscription(bundle.getId(),
+ new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null), null, context));
+ assertNotNull(baseSubscription);
+ assertTrue(busHandler.isCompleted(DELAY));
+
+ Collection<Invoice> invoices = invoiceApi.getInvoicesByAccount(account.getId());
+ assertEquals(invoices.size(), 1); // first invoice is generated immediately after creation can't reliably stop it
+
+
+ addTag(baseSubscription.getBundleId(), ObjectType.BUNDLE);
+
+ busHandler.pushExpectedEvents(NextEvent.PHASE);
+ clock.addDays(40); // DAY 40 out of trial
+ assertTrue(busHandler.isCompleted(DELAY));
+
+ invoices = invoiceApi.getInvoicesByAccount(account.getId());
+ assertEquals(invoices.size(), 1); //No additional invoices generated
+
+ }
+
+
+ @Test(groups={"slow"}, enabled = true)
+ public void testAutoInvoiceOffMultipleSubscriptions() throws Exception {
+ clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
+
+ // set next invoice to fail and create network
+ busHandler.pushExpectedEvents(NextEvent.CREATE,NextEvent.INVOICE);
+ SubscriptionData baseSubscription = subscriptionDataFromSubscription(entitlementUserApi.createSubscription(bundle.getId(),
+ new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null), null, context));
+ assertNotNull(baseSubscription);
+ assertTrue(busHandler.isCompleted(DELAY));
+
+ SubscriptionBundle bundle2 = entitlementUserApi.createBundleForAccount(account.getId(), "whatever", context);
+
+ busHandler.pushExpectedEvents(NextEvent.CREATE,NextEvent.INVOICE);
+ SubscriptionData baseSubscription2 = subscriptionDataFromSubscription(entitlementUserApi.createSubscription(bundle2.getId(),
+ new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null), null, context));
+ assertNotNull(baseSubscription2);
+ assertTrue(busHandler.isCompleted(DELAY));
+
+ Collection<Invoice> invoices = invoiceApi.getInvoicesByAccount(account.getId());
+ assertEquals(invoices.size(), 2); // first invoice is generated immediately after creation can't reliably stop it
+
+ addTag(baseSubscription.getBundleId(), ObjectType.BUNDLE);
+
+ busHandler.pushExpectedEvents(NextEvent.PHASE,NextEvent.PHASE,NextEvent.INVOICE);
+ clock.addDays(40); // DAY 40 out of trial
+ assertTrue(busHandler.isCompleted(DELAY));
+
+ invoices = invoiceApi.getInvoicesByAccount(account.getId());
+ assertEquals(invoices.size(), 3); // Only one additional invoice generated
+ }
+
+
+ private void addTag(UUID id, ObjectType type) throws TagDefinitionApiException {
+ TagDefinition def = tagApi.getTagDefinition(ControlTagType.AUTO_INVOICING_OFF.name());
+ tagApi.addTag(id, type, def, context);
+ Map<String,Tag> tags = tagApi.getTags(id, type);
+ assertNotNull(tags.get(ControlTagType.AUTO_INVOICING_OFF.name()));
+ }
+}
beatrix/src/test/resources/log4j.xml 4(+4 -0)
diff --git a/beatrix/src/test/resources/log4j.xml b/beatrix/src/test/resources/log4j.xml
index ac530a1..79e0ec2 100644
--- a/beatrix/src/test/resources/log4j.xml
+++ b/beatrix/src/test/resources/log4j.xml
@@ -33,6 +33,10 @@
<level value="info"/>
</logger>
+ <logger name="com.ning.billing.junction">
+ <level value="debug"/>
+ </logger>
+
<root>
<priority value="info"/>
<appender-ref ref="stdout"/>
diff --git a/catalog/src/main/java/com/ning/billing/catalog/DefaultDuration.java b/catalog/src/main/java/com/ning/billing/catalog/DefaultDuration.java
index 71bfe50..34860be 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/DefaultDuration.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/DefaultDuration.java
@@ -16,16 +16,18 @@
package com.ning.billing.catalog;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
+import org.joda.time.DateTime;
+import org.joda.time.Period;
+
import com.ning.billing.catalog.api.Duration;
import com.ning.billing.catalog.api.TimeUnit;
import com.ning.billing.util.config.ValidatingConfig;
+import com.ning.billing.util.config.ValidationError;
import com.ning.billing.util.config.ValidationErrors;
-import org.joda.time.DateTime;
-import org.joda.time.Period;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
@XmlAccessorType(XmlAccessType.NONE)
public class DefaultDuration extends ValidatingConfig<StandaloneCatalog> implements Duration {
@@ -71,6 +73,12 @@ public class DefaultDuration extends ValidatingConfig<StandaloneCatalog> impleme
@Override
public ValidationErrors validate(StandaloneCatalog catalog, ValidationErrors errors) {
+ //Validation: TimeUnit UNLIMITED iff number == -1
+ if((unit == TimeUnit.UNLIMITED && number != -1)) {
+ errors.add(new ValidationError("Duration can only have 'UNLIMITED' unit if the number is omitted.",
+ catalog.getCatalogURI(), DefaultPlanPhase.class, ""));
+ }
+
//TODO MDW - Validation TimeUnit UNLIMITED iff number == -1
return errors;
}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/DefaultPlanPhase.java b/catalog/src/main/java/com/ning/billing/catalog/DefaultPlanPhase.java
index 0f021c3..8feff37 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/DefaultPlanPhase.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/DefaultPlanPhase.java
@@ -144,20 +144,26 @@ public class DefaultPlanPhase extends ValidatingConfig<StandaloneCatalog> implem
catalog.getCatalogURI(), DefaultPlanPhase.class, type.toString()));
}
- //Validation: if there is no recurring price there should be no billing period
- if((recurringPrice == null) && billingPeriod != BillingPeriod.NO_BILLING_PERIOD) {
- errors.add(new ValidationError(String.format("Phase %s of plan %s has no recurring price but does have a billing period. The billing period should be set to '%s'",
- type.toString(), plan.getName(), BillingPeriod.NO_BILLING_PERIOD),
- catalog.getCatalogURI(), DefaultPlanPhase.class, type.toString()));
- }
-
+ //Validation: if there is no recurring price there should be no billing period
+ if((recurringPrice == null) && billingPeriod != BillingPeriod.NO_BILLING_PERIOD) {
+ errors.add(new ValidationError(String.format("Phase %s of plan %s has no recurring price but does have a billing period. The billing period should be set to '%s'",
+ type.toString(), plan.getName(), BillingPeriod.NO_BILLING_PERIOD),
+ catalog.getCatalogURI(), DefaultPlanPhase.class, type.toString()));
+ }
+
+ //Validation: if there BP is set to NO_BILLING_PERIOD there must be a fixed price
+ if((billingPeriod == BillingPeriod.NO_BILLING_PERIOD && fixedPrice == null)) {
+ errors.add(new ValidationError(String.format("Phase %s of plan %s has no billing period. It must have a fixed price set.",
+ type.toString(), plan.getName()),
+ catalog.getCatalogURI(), DefaultPlanPhase.class, type.toString()));
+ }
+
//Validation: there must be at least one of recurringPrice or fixedPrice
if((recurringPrice == null) && fixedPrice == null) {
errors.add(new ValidationError(String.format("Phase %s of plan %s has neither a recurring price or a fixed price.",
type.toString(), plan.getName()),
catalog.getCatalogURI(), DefaultPlanPhase.class, type.toString()));
}
- //TODO : if there BP is set to NO_BILLING_PERIOD there must be a recurring price
return errors;
}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceListSet.java b/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceListSet.java
index 83d810b..b8a8695 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceListSet.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceListSet.java
@@ -16,6 +16,9 @@
package com.ning.billing.catalog;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
@@ -23,6 +26,7 @@ import javax.xml.bind.annotation.XmlElement;
import com.ning.billing.ErrorCode;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.PriceList;
import com.ning.billing.catalog.api.PriceListSet;
import com.ning.billing.catalog.api.Product;
import com.ning.billing.util.config.ValidatingConfig;
@@ -99,6 +103,15 @@ public class DefaultPriceListSet extends ValidatingConfig<StandaloneCatalog> {
return childPriceLists;
}
+ public List<PriceList> getAllPriceLists() {
+ List<PriceList> result = new ArrayList<PriceList> (childPriceLists.length + 1);
+ result.add(getDefaultPricelist());
+ for(PriceList list : getChildPriceLists()) {
+ result.add(list);
+ }
+ return result;
+ }
+
}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java b/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java
index a63645c..32324f9 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java
@@ -17,8 +17,10 @@
package com.ning.billing.catalog;
import java.net.URI;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
+import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
@@ -32,6 +34,7 @@ import com.ning.billing.catalog.api.BillingAlignment;
import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.Listing;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanAlignmentChange;
import com.ning.billing.catalog.api.PlanAlignmentCreate;
@@ -303,15 +306,41 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
return this;
}
- @Override
- public boolean canCreatePlan(PlanSpecifier specifier) throws CatalogApiException {
- Product product = findCurrentProduct(specifier.getProductName());
- Plan plan = findCurrentPlan(specifier.getProductName(), specifier.getBillingPeriod(), specifier.getPriceListName());
- DefaultPriceList priceList = findCurrentPriceList(specifier.getPriceListName());
-
- return (!product.isRetired()) &&
- (!plan.isRetired()) &&
- (!priceList.isRetired());
- }
+ @Override
+ public boolean canCreatePlan(PlanSpecifier specifier) throws CatalogApiException {
+ Product product = findCurrentProduct(specifier.getProductName());
+ Plan plan = findCurrentPlan(specifier.getProductName(), specifier.getBillingPeriod(), specifier.getPriceListName());
+ DefaultPriceList priceList = findCurrentPriceList(specifier.getPriceListName());
+
+ return (!product.isRetired()) &&
+ (!plan.isRetired()) &&
+ (!priceList.isRetired());
+ }
+
+ @Override
+ public List<Listing> getAvailableAddonListings(String baseProductName) {
+ List<Listing> availAddons = new ArrayList<Listing>();
+
+ try {
+ Product product = findCurrentProduct(baseProductName);
+ if ( product != null ) {
+ for ( Product availAddon : product.getAvailable() ) {
+ for ( Plan plan : getCurrentPlans()) {
+ if( plan.getProduct().equals(availAddon)) {
+ for( PriceList priceList : getPriceLists().getAllPriceLists()) {
+ if ( priceList.findPlan(availAddon, plan.getBillingPeriod()) != null &&
+ priceList.findPlan(product, plan.getBillingPeriod()).equals(plan)) {
+ availAddons.add(new DefaultListing(plan, priceList));
+ }
+ }
+ }
+ }
+ }
+ }
+ } catch (CatalogApiException e) {
+ // No such product - just return an empty list
+ }
+
+ return availAddons; }
}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java b/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
index 215b142..3bd370a 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
@@ -39,6 +39,7 @@ import com.ning.billing.catalog.api.BillingPeriod;
import com.ning.billing.catalog.api.Catalog;
import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.Listing;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanAlignmentChange;
import com.ning.billing.catalog.api.PlanAlignmentCreate;
@@ -445,4 +446,9 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
return versionForDate(clock.getUTCNow()).canCreatePlan(specifier);
}
+ @Override
+ public List<Listing> getAvailableAddonListings(String baseProductName) throws CatalogApiException {
+ return versionForDate(clock.getUTCNow()).getAvailableAddonListings(baseProductName);
+ }
+
}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java b/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
index 40dc146..ac090de 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
@@ -184,20 +184,17 @@ public class MockCatalog extends StandaloneCatalog implements Catalog {
@Override
public ActionPolicy planChangePolicy(PlanPhaseSpecifier from, PlanSpecifier to) throws CatalogApiException {
- // TODO Auto-generated method stub
return super.planChangePolicy(from, to);
}
@Override
public PlanAlignmentChange planChangeAlignment(PlanPhaseSpecifier from, PlanSpecifier to)
throws CatalogApiException {
- // TODO Auto-generated method stub
return super.planChangeAlignment(from, to);
}
@Override
public ActionPolicy planCancelPolicy(PlanPhaseSpecifier planPhase) throws CatalogApiException {
- // TODO Auto-generated method stub
return super.planCancelPolicy(planPhase);
}
@@ -208,13 +205,11 @@ public class MockCatalog extends StandaloneCatalog implements Catalog {
@Override
public BillingAlignment billingAlignment(PlanPhaseSpecifier planPhase) throws CatalogApiException {
- // TODO Auto-generated method stub
return billingAlignment;
}
@Override
public PlanChangeResult planChange(PlanPhaseSpecifier from, PlanSpecifier to) throws CatalogApiException {
- // TODO Auto-generated method stub
return planChange;
}
diff --git a/catalog/src/test/java/com/ning/billing/mock/catalog/MockPlan.java b/catalog/src/test/java/com/ning/billing/mock/catalog/MockPlan.java
index 0657fd4..2199eb9 100644
--- a/catalog/src/test/java/com/ning/billing/mock/catalog/MockPlan.java
+++ b/catalog/src/test/java/com/ning/billing/mock/catalog/MockPlan.java
@@ -46,57 +46,48 @@ public class MockPlan implements Plan {
@Override
public boolean isRetired() {
- // TODO Auto-generated method stub
- return false;
+ return false;
}
@Override
public Iterator<PlanPhase> getInitialPhaseIterator() {
- // TODO Auto-generated method stub
- return null;
+ return null;
}
@Override
public PlanPhase getFinalPhase() {
- // TODO Auto-generated method stub
- return null;
+ return null;
}
@Override
public BillingPeriod getBillingPeriod() {
- // TODO Auto-generated method stub
- return null;
+ return null;
}
@Override
public int getPlansAllowedInBundle() {
- // TODO Auto-generated method stub
- return 0;
+ return 0;
}
@Override
public PlanPhase[] getAllPhases() {
- // TODO Auto-generated method stub
- return null;
+ return null;
}
@Override
public Date getEffectiveDateForExistingSubscriptons() {
- // TODO Auto-generated method stub
- return null;
+ return null;
}
@Override
public PlanPhase findPhase(String name) throws CatalogApiException {
- // TODO Auto-generated method stub
- return null;
+ return null;
}
@Override
public DateTime dateOfFirstRecurringNonZeroCharge(
DateTime subscriptionStartDate) {
- // TODO Auto-generated method stub
- return null;
+ return null;
}
}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
index 7990084..9aede3c 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
@@ -324,7 +324,6 @@ public class TestUserApiAddOn extends TestApiBase {
}
}
- //TODO MDW - debugging reenable if you find this
@Test(enabled=true, groups={"slow"})
public void testAddonCreateWithSubscriptionAlign() {
diff --git a/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java b/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java
index 11712d2..2283a39 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java
@@ -21,6 +21,7 @@ import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;
+import com.ning.billing.invoice.api.InvoiceApiException;
import com.ning.billing.util.callcontext.CallContext;
import org.joda.time.DateTime;
@@ -78,5 +79,41 @@ public class DefaultInvoicePaymentApi implements InvoicePaymentApi {
dao.notifyOfPaymentAttempt(invoicePayment, context);
}
+ @Override
+ public void processChargeback(UUID invoicePaymentId, BigDecimal amount, CallContext context) throws InvoiceApiException {
+ dao.postChargeback(invoicePaymentId, amount, context);
+ }
+
+ @Override
+ public void processChargeback(UUID invoicePaymentId, CallContext context) throws InvoiceApiException {
+ // use the invoicePaymentId to get the amount remaining on the payment
+ // (preventing charge backs totalling more than the payment)
+ BigDecimal amount = dao.getRemainingAmountPaid(invoicePaymentId);
+ processChargeback(invoicePaymentId, amount, context);
+ }
+ @Override
+ public BigDecimal getRemainingAmountPaid(UUID invoicePaymentId) {
+ return dao.getRemainingAmountPaid(invoicePaymentId);
+ }
+
+ @Override
+ public List<InvoicePayment> getChargebacksByAccountId(UUID accountId) {
+ return dao.getChargebacksByAccountId(accountId);
+ }
+
+ @Override
+ public List<InvoicePayment> getChargebacksByPaymentAttemptId(UUID paymentAttemptId) {
+ return dao.getChargebacksByPaymentAttemptId(paymentAttemptId);
+ }
+
+ @Override
+ public InvoicePayment getChargebackById(UUID chargebackId) throws InvoiceApiException {
+ return dao.getChargebackById(chargebackId);
+ }
+
+ @Override
+ public UUID getAccountIdFromInvoicePaymentId(UUID invoicePaymentId) throws InvoiceApiException {
+ return dao.getAccountIdFromInvoicePaymentId(invoicePaymentId);
+ }
}
\ No newline at end of file
diff --git a/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java b/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java
index 1e45646..7f2ced3 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java
@@ -20,6 +20,8 @@ import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.InvoiceItem;
import com.ning.billing.util.callcontext.CallContext;
import org.joda.time.DateTime;
@@ -85,7 +87,18 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
}
@Override
- public void tagInvoiceAsNotWrittenOff(final UUID invoiceId, final CallContext context) {
+ public void tagInvoiceAsNotWrittenOff(final UUID invoiceId, final CallContext context) throws InvoiceApiException {
dao.removeWrittenOff(invoiceId, context);
}
+
+ @Override
+ public InvoiceItem getCreditById(final UUID creditId) throws InvoiceApiException {
+ return dao.getCreditById(creditId);
+ }
+
+ @Override
+ public InvoiceItem insertCredit(final UUID accountId, final BigDecimal amount, final DateTime effectiveDate,
+ final Currency currency, final CallContext context) throws InvoiceApiException {
+ return dao.insertCredit(accountId, amount, effectiveDate, currency, context);
+ }
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/CreditInvoiceItemSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/CreditInvoiceItemSqlDao.java
new file mode 100644
index 0000000..d60e813
--- /dev/null
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/CreditInvoiceItemSqlDao.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2010-2011 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.dao;
+
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.model.CreditInvoiceItem;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallContextBinder;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+import org.skife.jdbi.v2.sqlobject.SqlBatch;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
+import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.math.BigDecimal;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.UUID;
+
+@ExternalizedSqlViaStringTemplate3
+@RegisterMapper(CreditInvoiceItemSqlDao.CreditInvoiceItemMapper.class)
+public interface CreditInvoiceItemSqlDao extends EntitySqlDao<InvoiceItem> {
+ @SqlQuery
+ List<Long> getRecordIds(@Bind("invoiceId") final String invoiceId);
+
+ @SqlQuery
+ List<InvoiceItem> getInvoiceItemsByInvoice(@Bind("invoiceId") final String invoiceId);
+
+ @SqlQuery
+ List<InvoiceItem> getInvoiceItemsByAccount(@Bind("accountId") final String accountId);
+
+ @Override
+ @SqlUpdate
+ void create(@CreditInvoiceItemBinder final InvoiceItem invoiceItem, @CallContextBinder final CallContext context);
+
+ @SqlBatch
+ void create(@CreditInvoiceItemBinder final List<InvoiceItem> items, @CallContextBinder final CallContext context);
+
+ @SqlBatch(transactional=false)
+ void batchCreateFromTransaction(@CreditInvoiceItemBinder final List<InvoiceItem> items, @CallContextBinder final CallContext context);
+
+ @BindingAnnotation(CreditInvoiceItemBinder.CreditInvoiceItemBinderFactory.class)
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.PARAMETER})
+ public @interface CreditInvoiceItemBinder {
+ public static class CreditInvoiceItemBinderFactory implements BinderFactory {
+ public Binder build(Annotation annotation) {
+ return new Binder<CreditInvoiceItemBinder, CreditInvoiceItem>() {
+ public void bind(SQLStatement q, CreditInvoiceItemBinder bind, CreditInvoiceItem item) {
+ q.bind("id", item.getId().toString());
+ q.bind("invoiceId", item.getInvoiceId().toString());
+ q.bind("accountId", item.getAccountId().toString());
+ q.bind("creditDate", item.getStartDate().toDate());
+ q.bind("amount", item.getAmount());
+ q.bind("currency", item.getCurrency().toString());
+ }
+ };
+ }
+ }
+ }
+ public class CreditInvoiceItemMapper implements ResultSetMapper<InvoiceItem> {
+ @Override
+ public InvoiceItem map(int index, ResultSet result, StatementContext ctx) throws SQLException {
+ UUID id = UUID.fromString(result.getString("id"));
+ UUID invoiceId = UUID.fromString(result.getString("invoice_id"));
+ UUID accountId = UUID.fromString(result.getString("account_id"));
+ DateTime creditDate = new DateTime(result.getTimestamp("credit_date"));
+ BigDecimal amount = result.getBigDecimal("amount");
+ Currency currency = Currency.valueOf(result.getString("currency"));
+ return new CreditInvoiceItem(id, invoiceId, accountId, creditDate, amount, currency);
+ }
+ }
+}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index 4b262db..779a359 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -21,6 +21,11 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.InvoiceApiException;
+import com.ning.billing.invoice.model.CreditInvoiceItem;
+import com.ning.billing.invoice.model.DefaultInvoice;
import org.joda.time.DateTime;
import org.skife.jdbi.v2.IDBI;
import org.skife.jdbi.v2.Transaction;
@@ -44,6 +49,7 @@ import com.ning.billing.util.tag.dao.TagDao;
public class DefaultInvoiceDao implements InvoiceDao {
private final InvoiceSqlDao invoiceSqlDao;
private final InvoicePaymentSqlDao invoicePaymentSqlDao;
+ private final CreditInvoiceItemSqlDao creditInvoiceItemSqlDao;
private final TagDao tagDao;
private final NextBillingDatePoster nextBillingDatePoster;
@@ -54,6 +60,7 @@ public class DefaultInvoiceDao implements InvoiceDao {
final TagDao tagDao) {
this.invoiceSqlDao = dbi.onDemand(InvoiceSqlDao.class);
this.invoicePaymentSqlDao = dbi.onDemand(InvoicePaymentSqlDao.class);
+ this.creditInvoiceItemSqlDao = dbi.onDemand(CreditInvoiceItemSqlDao.class);
this.nextBillingDatePoster = nextBillingDatePoster;
this.tagDao = tagDao;
}
@@ -117,16 +124,16 @@ public class DefaultInvoiceDao implements InvoiceDao {
@Override
public Invoice getById(final UUID invoiceId) {
return invoiceSqlDao.inTransaction(new Transaction<Invoice, InvoiceSqlDao>() {
- @Override
- public Invoice inTransaction(final InvoiceSqlDao invoiceDao, final TransactionStatus status) throws Exception {
- Invoice invoice = invoiceDao.getById(invoiceId.toString());
+ @Override
+ public Invoice inTransaction(final InvoiceSqlDao invoiceDao, final TransactionStatus status) throws Exception {
+ Invoice invoice = invoiceDao.getById(invoiceId.toString());
- if (invoice != null) {
- populateChildren(invoice, invoiceDao);
- }
+ if (invoice != null) {
+ populateChildren(invoice, invoiceDao);
+ }
- return invoice;
- }
+ return invoice;
+ }
});
}
@@ -163,6 +170,12 @@ public class DefaultInvoiceDao implements InvoiceDao {
recordIdList = fixedPriceInvoiceItemDao.getRecordIds(invoice.getId().toString());
audits.addAll(createAudits(TableName.FIXED_INVOICE_ITEMS, recordIdList));
+ List<InvoiceItem> creditInvoiceItems = invoice.getInvoiceItems(CreditInvoiceItem.class);
+ CreditInvoiceItemSqlDao creditInvoiceItemSqlDao = transactional.become(CreditInvoiceItemSqlDao.class);
+ creditInvoiceItemSqlDao.batchCreateFromTransaction(creditInvoiceItems, context);
+ recordIdList = creditInvoiceItemSqlDao.getRecordIds(invoice.getId().toString());
+ audits.addAll(createAudits(TableName.CREDIT_INVOICE_ITEMS, recordIdList));
+
List<InvoicePayment> invoicePayments = invoice.getPayments();
InvoicePaymentSqlDao invoicePaymentSqlDao = transactional.become(InvoicePaymentSqlDao.class);
invoicePaymentSqlDao.batchCreateFromTransaction(invoicePayments, context);
@@ -177,7 +190,7 @@ public class DefaultInvoiceDao implements InvoiceDao {
});
}
- private List<EntityAudit> createAudits(TableName tableName, List<Long> recordIdList) {
+ private List<EntityAudit> createAudits(final TableName tableName, final List<Long> recordIdList) {
List<EntityAudit> entityAuditList = new ArrayList<EntityAudit>();
for (Long recordId : recordIdList) {
entityAuditList.add(new EntityAudit(tableName, recordId, ChangeType.INSERT));
@@ -237,26 +250,96 @@ public class DefaultInvoiceDao implements InvoiceDao {
}
@Override
- public UUID getInvoiceIdByPaymentAttemptId(UUID paymentAttemptId) {
+ public UUID getInvoiceIdByPaymentAttemptId(final UUID paymentAttemptId) {
return invoiceSqlDao.getInvoiceIdByPaymentAttemptId(paymentAttemptId.toString());
}
@Override
- public InvoicePayment getInvoicePayment(UUID paymentAttemptId) {
+ public InvoicePayment getInvoicePayment(final UUID paymentAttemptId) {
return invoicePaymentSqlDao.getInvoicePayment(paymentAttemptId);
}
@Override
- public void setWrittenOff(UUID invoiceId, CallContext context) {
+ public void setWrittenOff(final UUID invoiceId, final CallContext context) {
tagDao.insertTag(invoiceId, ObjectType.INVOICE, ControlTagType.WRITTEN_OFF.toTagDefinition(), context);
}
@Override
- public void removeWrittenOff(UUID invoiceId, CallContext context) {
+ public void removeWrittenOff(final UUID invoiceId, final CallContext context) throws InvoiceApiException {
tagDao.deleteTag(invoiceId, ObjectType.INVOICE, ControlTagType.WRITTEN_OFF.toTagDefinition(), context);
}
@Override
+ public void postChargeback(final UUID invoicePaymentId, final BigDecimal amount, final CallContext context) throws InvoiceApiException {
+ InvoicePayment payment = invoicePaymentSqlDao.getById(invoicePaymentId.toString());
+ if (payment == null) {
+ throw new InvoiceApiException(ErrorCode.INVOICE_PAYMENT_NOT_FOUND, invoicePaymentId.toString());
+ } else {
+ if (amount.compareTo(BigDecimal.ZERO) < 0) {
+ throw new InvoiceApiException(ErrorCode.CHARGE_BACK_AMOUNT_IS_NEGATIVE);
+ }
+
+ InvoicePayment chargeBack = payment.asChargeBack(amount, context.getCreatedDate());
+ invoicePaymentSqlDao.create(chargeBack, context);
+ }
+ }
+
+ @Override
+ public BigDecimal getRemainingAmountPaid(UUID invoicePaymentId) {
+ BigDecimal amount = invoicePaymentSqlDao.getRemainingAmountPaid(invoicePaymentId.toString());
+ return amount == null ? BigDecimal.ZERO : amount;
+ }
+
+ @Override
+ public UUID getAccountIdFromInvoicePaymentId(UUID invoicePaymentId) throws InvoiceApiException {
+ UUID accountId = invoicePaymentSqlDao.getAccountIdFromInvoicePaymentId(invoicePaymentId.toString());
+ if (accountId == null) {
+ throw new InvoiceApiException(ErrorCode.CHARGE_BACK_COULD_NOT_FIND_ACCOUNT_ID, invoicePaymentId);
+ } else {
+ return accountId;
+ }
+ }
+
+ @Override
+ public List<InvoicePayment> getChargebacksByAccountId(UUID accountId) {
+ return invoicePaymentSqlDao.getChargeBacksByAccountId(accountId.toString());
+ }
+
+ @Override
+ public List<InvoicePayment> getChargebacksByPaymentAttemptId(final UUID paymentAttemptId) {
+ return invoicePaymentSqlDao.getChargebacksByAttemptPaymentId(paymentAttemptId.toString());
+ }
+
+ @Override
+ public InvoicePayment getChargebackById(UUID chargebackId) throws InvoiceApiException {
+ InvoicePayment chargeback = invoicePaymentSqlDao.getById(chargebackId.toString());
+ if (chargeback == null) {
+ throw new InvoiceApiException(ErrorCode.CHARGE_BACK_DOES_NOT_EXIST, chargebackId);
+ } else {
+ return chargeback;
+ }
+ }
+
+ @Override
+ public InvoiceItem getCreditById(final UUID creditId) throws InvoiceApiException {
+ return creditInvoiceItemSqlDao.getById(creditId.toString());
+ }
+
+ // TODO: make this transactional
+ @Override
+ public InvoiceItem insertCredit(final UUID accountId, final BigDecimal amount,
+ final DateTime effectiveDate, final Currency currency,
+ final CallContext context) {
+ Invoice invoice = new DefaultInvoice(accountId, effectiveDate, effectiveDate, currency);
+ invoiceSqlDao.create(invoice, context);
+
+ InvoiceItem credit = new CreditInvoiceItem(invoice.getId(), accountId, effectiveDate, amount, currency);
+ creditInvoiceItemSqlDao.create(credit, context);
+
+ return credit;
+ }
+
+ @Override
public void test() {
invoiceSqlDao.test();
}
@@ -278,13 +361,19 @@ public class DefaultInvoiceDao implements InvoiceDao {
}
private void getInvoiceItemsWithinTransaction(final Invoice invoice, final InvoiceSqlDao invoiceDao) {
+ String invoiceId = invoice.getId().toString();
+
RecurringInvoiceItemSqlDao recurringInvoiceItemDao = invoiceDao.become(RecurringInvoiceItemSqlDao.class);
- List<InvoiceItem> recurringInvoiceItems = recurringInvoiceItemDao.getInvoiceItemsByInvoice(invoice.getId().toString());
+ List<InvoiceItem> recurringInvoiceItems = recurringInvoiceItemDao.getInvoiceItemsByInvoice(invoiceId);
invoice.addInvoiceItems(recurringInvoiceItems);
FixedPriceInvoiceItemSqlDao fixedPriceInvoiceItemDao = invoiceDao.become(FixedPriceInvoiceItemSqlDao.class);
- List<InvoiceItem> fixedPriceInvoiceItems = fixedPriceInvoiceItemDao.getInvoiceItemsByInvoice(invoice.getId().toString());
+ List<InvoiceItem> fixedPriceInvoiceItems = fixedPriceInvoiceItemDao.getInvoiceItemsByInvoice(invoiceId);
invoice.addInvoiceItems(fixedPriceInvoiceItems);
+
+ CreditInvoiceItemSqlDao creditInvoiceItemSqlDao = invoiceDao.become(CreditInvoiceItemSqlDao.class);
+ List<InvoiceItem> creditInvoiceItems = creditInvoiceItemSqlDao.getInvoiceItemsByInvoice(invoiceId);
+ invoice.addInvoiceItems(creditInvoiceItems);
}
private void getInvoicePaymentsWithinTransaction(final List<Invoice> invoices, final InvoiceSqlDao invoiceDao) {
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
index 17006d3..c7e520b 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
@@ -16,7 +16,10 @@
package com.ning.billing.invoice.dao;
+import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceApiException;
+import com.ning.billing.invoice.api.InvoiceItem;
import com.ning.billing.invoice.api.InvoicePayment;
import com.ning.billing.util.callcontext.CallContext;
import org.joda.time.DateTime;
@@ -52,8 +55,25 @@ public interface InvoiceDao {
List<Invoice> getAllInvoicesByAccount(final UUID accountId);
- void setWrittenOff(UUID invoiceId, CallContext context);
+ void setWrittenOff(final UUID invoiceId, final CallContext context);
- void removeWrittenOff(UUID invoiceId, CallContext context);
+ void removeWrittenOff(final UUID invoiceId, final CallContext context) throws InvoiceApiException;
+ void postChargeback(final UUID invoicePaymentId, final BigDecimal amount, final CallContext context) throws InvoiceApiException;
+
+ BigDecimal getRemainingAmountPaid(final UUID invoicePaymentId);
+
+ UUID getAccountIdFromInvoicePaymentId(final UUID invoicePaymentId) throws InvoiceApiException;
+
+ List<InvoicePayment> getChargebacksByAccountId(final UUID accountId);
+
+ List<InvoicePayment> getChargebacksByPaymentAttemptId(final UUID paymentAttemptId);
+
+ InvoicePayment getChargebackById(final UUID chargebackId) throws InvoiceApiException;
+
+ InvoiceItem getCreditById(final UUID creditId) throws InvoiceApiException;
+
+ InvoiceItem insertCredit(final UUID accountId, final BigDecimal amount,
+ final DateTime effectiveDate, final Currency currency,
+ final CallContext context);
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
index a11c8e0..69c4c2a 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
@@ -28,10 +28,13 @@ import java.util.List;
import java.util.UUID;
import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.model.DefaultInvoicePayment;
import com.ning.billing.util.dao.AuditSqlDao;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallContextBinder;
+import com.ning.billing.util.dao.BinderBase;
import com.ning.billing.util.dao.MapperBase;
+import com.ning.billing.util.dao.UuidMapper;
import com.ning.billing.util.entity.dao.EntitySqlDao;
import org.joda.time.DateTime;
import org.skife.jdbi.v2.SQLStatement;
@@ -81,7 +84,18 @@ public interface InvoicePaymentSqlDao extends EntitySqlDao<InvoicePayment>, Tran
void notifyOfPaymentAttempt(@InvoicePaymentBinder final InvoicePayment invoicePayment,
@CallContextBinder final CallContext context);
+ @SqlQuery
+ BigDecimal getRemainingAmountPaid(@Bind("invoicePaymentId") final String invoicePaymentId);
+
+ @SqlQuery
+ @RegisterMapper(UuidMapper.class)
+ UUID getAccountIdFromInvoicePaymentId(@Bind("invoicePaymentId") final String invoicePaymentId);
+ @SqlQuery
+ List<InvoicePayment> getChargeBacksByAccountId(@Bind("accountId") final String accountId);
+
+ @SqlQuery
+ List<InvoicePayment> getChargebacksByAttemptPaymentId(@Bind("paymentAttemptId") final String paymentAttemptId);
public static class InvoicePaymentMapper extends MapperBase implements ResultSetMapper<InvoicePayment> {
@Override
@@ -93,33 +107,10 @@ public interface InvoicePaymentSqlDao extends EntitySqlDao<InvoicePayment>, Tran
final BigDecimal amount = result.getBigDecimal("amount");
final String currencyString = result.getString("currency");
final Currency currency = (currencyString == null) ? null : Currency.valueOf(currencyString);
+ final UUID reversedInvoicePaymentId = getUUID(result, "reversed_invoice_Payment_id");
- return new InvoicePayment() {
- @Override
- public UUID getId() {
- return id;
- }
- @Override
- public UUID getPaymentAttemptId() {
- return paymentAttemptId;
- }
- @Override
- public UUID getInvoiceId() {
- return invoiceId;
- }
- @Override
- public DateTime getPaymentAttemptDate() {
- return paymentAttemptDate;
- }
- @Override
- public BigDecimal getAmount() {
- return amount;
- }
- @Override
- public Currency getCurrency() {
- return currency;
- }
- };
+ return new DefaultInvoicePayment(id, paymentAttemptId, invoiceId, paymentAttemptDate,
+ amount, currency, reversedInvoicePaymentId);
}
}
@@ -127,7 +118,7 @@ public interface InvoicePaymentSqlDao extends EntitySqlDao<InvoicePayment>, Tran
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface InvoicePaymentBinder {
- public static class InvoicePaymentBinderFactory implements BinderFactory {
+ public static class InvoicePaymentBinderFactory extends BinderBase implements BinderFactory {
@Override
public Binder build(Annotation annotation) {
return new Binder<InvoicePaymentBinder, InvoicePayment>() {
@@ -135,11 +126,12 @@ public interface InvoicePaymentSqlDao extends EntitySqlDao<InvoicePayment>, Tran
public void bind(SQLStatement q, InvoicePaymentBinder bind, InvoicePayment payment) {
q.bind("id", payment.getId().toString());
q.bind("invoiceId", payment.getInvoiceId().toString());
- q.bind("paymentAttemptId", payment.getPaymentAttemptId().toString());
+ q.bind("paymentAttemptId", uuidToString(payment.getPaymentAttemptId()));
q.bind("paymentAttemptDate", payment.getPaymentAttemptDate().toDate());
q.bind("amount", payment.getAmount());
Currency currency = payment.getCurrency();
q.bind("currency", (currency == null) ? null : currency.toString());
+ q.bind("reversedInvoicePaymentId", uuidToString(payment.getReversedInvoicePaymentId()));
}
};
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
index af611bc..04b3fce 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
@@ -83,8 +83,6 @@ public interface InvoiceSqlDao extends EntitySqlDao<Invoice>, AuditSqlDao, Trans
@SqlQuery
List<Invoice> getUnpaidInvoicesByAccountId(@Bind("accountId") final String accountId,
@Bind("upToDate") final Date upToDate);
-
-
@BindingAnnotation(InvoiceBinder.InvoiceBinderFactory.class)
@Retention(RetentionPolicy.RUNTIME)
diff --git a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
index 32d444d..b982a3f 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
@@ -16,11 +16,11 @@
package com.ning.billing.invoice;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.SortedSet;
import java.util.UUID;
import org.joda.time.DateTime;
@@ -37,18 +37,18 @@ import com.ning.billing.entitlement.api.billing.BillingEvent;
import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
import com.ning.billing.entitlement.api.user.SubscriptionEvent;
import com.ning.billing.invoice.api.Invoice;
-import com.ning.billing.invoice.api.InvoiceCreationEvent;
-import com.ning.billing.invoice.api.InvoiceNotifier;
import com.ning.billing.invoice.api.InvoiceApiException;
+import com.ning.billing.invoice.api.InvoiceCreationEvent;
import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoiceNotifier;
import com.ning.billing.invoice.api.user.DefaultEmptyInvoiceEvent;
import com.ning.billing.invoice.api.user.DefaultInvoiceCreationEvent;
import com.ning.billing.invoice.dao.InvoiceDao;
-import com.ning.billing.invoice.model.BillingEventSet;
import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
import com.ning.billing.invoice.model.InvoiceGenerator;
import com.ning.billing.invoice.model.RecurringInvoiceItem;
import com.ning.billing.junction.api.BillingApi;
+import com.ning.billing.junction.api.BillingEventSet;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.bus.Bus.EventBusException;
import com.ning.billing.util.bus.BusEvent;
@@ -145,17 +145,21 @@ public class InvoiceDispatcher {
final boolean dryRun, final CallContext context) throws InvoiceApiException {
try {
Account account = accountUserApi.getAccountById(accountId);
- SortedSet<BillingEvent> events = billingApi.getBillingEventsForAccountAndUpdateAccountBCD(accountId);
- BillingEventSet billingEvents = new BillingEventSet(events);
+ BillingEventSet billingEvents = billingApi.getBillingEventsForAccountAndUpdateAccountBCD(accountId);
+
+ List<Invoice> invoices = new ArrayList<Invoice>();
+ if (!billingEvents.isAccountAutoInvoiceOff()) {
+ invoices = invoiceDao.getInvoicesByAccount(accountId); //no need to fetch, invoicing is off on this account
+ }
Currency targetCurrency = account.getCurrency();
- List<Invoice> invoices = invoiceDao.getInvoicesByAccount(accountId);
+
Invoice invoice = generator.generateInvoice(accountId, billingEvents, invoices, targetDate, targetCurrency);
if (invoice == null) {
log.info("Generated null invoice.");
- outputDebugData(events, invoices);
+ outputDebugData(billingEvents, invoices);
if (!dryRun) {
BusEvent event = new DefaultEmptyInvoiceEvent(accountId, clock.getUTCNow(), context.getUserToken());
postEvent(event, accountId);
@@ -168,7 +172,7 @@ public class InvoiceDispatcher {
log.info(item.toString());
}
}
- outputDebugData(events, invoices);
+ outputDebugData(billingEvents, invoices);
if (!dryRun) {
invoiceDao.create(invoice, context);
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/CreditInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/CreditInvoiceItem.java
index ac800a7..651a717 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/CreditInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/CreditInvoiceItem.java
@@ -18,6 +18,7 @@ package com.ning.billing.invoice.model;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoiceItemType;
import org.joda.time.DateTime;
import java.math.BigDecimal;
@@ -29,7 +30,7 @@ public class CreditInvoiceItem extends InvoiceItemBase {
}
public CreditInvoiceItem(UUID id, UUID invoiceId, UUID accountId, DateTime date, BigDecimal amount, Currency currency) {
- super(id, invoiceId, accountId, null, null, null, null, date, date, amount, currency);
+ super(id, invoiceId, accountId, null, null, null, null, date, date, amount, currency, InvoiceItemType.CREDIT);
}
@Override
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
index 0de9aa4..952ff60 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
@@ -173,18 +173,24 @@ public class DefaultInvoice extends EntityBase implements Invoice {
}
@Override
- public BigDecimal getTotalAmount() {
- return invoiceItems.getTotalAmount();
+ public BigDecimal getAmountCharged() {
+ return invoiceItems.getAmountCharged();
+ }
+
+ @Override
+ public BigDecimal getAmountCredited() {
+ return invoiceItems.getAmountCredited();
}
@Override
public BigDecimal getBalance() {
- return getTotalAmount().subtract(getAmountPaid());
+ // credits offset payments
+ return getAmountCharged().subtract(getAmountPaid().subtract(getAmountCredited()));
}
@Override
public boolean isDueForPayment(final DateTime targetDate, final int numberOfDays) {
- if (getTotalAmount().compareTo(BigDecimal.ZERO) == 0) {
+ if (getBalance().compareTo(BigDecimal.ZERO) == 0) {
return false;
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java
index c24215c..08e19c0 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java
@@ -41,6 +41,7 @@ import com.ning.billing.entitlement.api.billing.BillingModeType;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceApiException;
import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.junction.api.BillingEventSet;
import com.ning.billing.util.clock.Clock;
public class DefaultInvoiceGenerator implements InvoiceGenerator {
@@ -64,18 +65,24 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
@Nullable final List<Invoice> existingInvoices,
DateTime targetDate,
final Currency targetCurrency) throws InvoiceApiException {
- if ((events == null) || (events.size() == 0)) {
+ if ((events == null) || (events.size() == 0) || events.isAccountAutoInvoiceOff()) {
return null;
}
validateTargetDate(targetDate);
-
- Collections.sort(events);
+ //TODO MDW can use subscription Id - not bundle
+ //TODO MDW worry about null sub id
List<InvoiceItem> existingItems = new ArrayList<InvoiceItem>();
if (existingInvoices != null) {
for (Invoice invoice : existingInvoices) {
- existingItems.addAll(invoice.getInvoiceItems());
+ for(InvoiceItem item : invoice.getInvoiceItems()) {
+ if(item.getSubscriptionId() == null || // Always include migration invoices, credits etc.
+ !events.getSubscriptionIdsWithAutoInvoiceOff()
+ .contains(item.getSubscriptionId())) { //don't add items with auto_invoice_off tag
+ existingItems.add(item);
+ }
+ }
}
Collections.sort(existingItems);
@@ -83,21 +90,16 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
targetDate = adjustTargetDate(existingInvoices, targetDate);
- DefaultInvoice invoice = new DefaultInvoice(accountId, clock.getUTCNow(), targetDate, targetCurrency);
+ Invoice invoice = new DefaultInvoice(accountId, clock.getUTCNow(), targetDate, targetCurrency);
UUID invoiceId = invoice.getId();
List<InvoiceItem> proposedItems = generateInvoiceItems(invoiceId, accountId, events, targetDate, targetCurrency);
removeCancellingInvoiceItems(existingItems);
removeDuplicatedInvoiceItems(proposedItems, existingItems);
- for (InvoiceItem existingItem : existingItems) {
- if (existingItem instanceof RecurringInvoiceItem) {
- RecurringInvoiceItem recurringItem = (RecurringInvoiceItem) existingItem;
- proposedItems.add(recurringItem.asReversingItem());
- }
- }
-
- //addCreditItems(accountId, proposedItems, existingInvoices, targetCurrency);
+ addReversingItems(existingItems, proposedItems);
+ generateCreditsForPastRepairedInvoices(accountId, existingInvoices, proposedItems, targetCurrency);
+ consumeExistingCredit(invoiceId, accountId, existingItems, proposedItems, targetCurrency);
if (proposedItems == null || proposedItems.size() == 0) {
return null;
@@ -108,75 +110,75 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
}
}
- /*
- * ensures that the balance of all invoices are zero or positive, adding an adjusting credit item if needed
- */
- private void addCreditItems(UUID accountId, List<InvoiceItem> invoiceItems, List<Invoice> invoices, Currency currency) {
- Map<UUID, BigDecimal> invoiceBalances = new HashMap<UUID, BigDecimal>();
-
- updateInvoiceBalance(invoiceItems, invoiceBalances);
+ private void generateCreditsForPastRepairedInvoices(UUID accountId, List<Invoice> existingInvoices, List<InvoiceItem> proposedItems, Currency currency) {
+ // determine most accurate invoice balances up to this point
+ Map<UUID, BigDecimal> amountOwedByInvoice = new HashMap<UUID, BigDecimal>();
- // add all existing items and payments
- if (invoices != null) {
- for (Invoice invoice : invoices) {
- updateInvoiceBalance(invoice.getInvoiceItems(), invoiceBalances);
- }
-
- for (Invoice invoice : invoices) {
- UUID invoiceId = invoice.getId();
- invoiceBalances.put(invoiceId, invoiceBalances.get(invoiceId).subtract(invoice.getAmountPaid()));
+ if (existingInvoices != null) {
+ for (Invoice invoice : existingInvoices) {
+ amountOwedByInvoice.put(invoice.getId(), invoice.getBalance());
}
}
- BigDecimal creditTotal = BigDecimal.ZERO;
-
- for (UUID invoiceId : invoiceBalances.keySet()) {
- BigDecimal balance = invoiceBalances.get(invoiceId);
- if (balance.compareTo(BigDecimal.ZERO) < 0) {
- creditTotal = creditTotal.add(balance.negate());
- invoiceItems.add(new CreditInvoiceItem(invoiceId, accountId, clock.getUTCNow(), balance, currency));
+ for (InvoiceItem item : proposedItems) {
+ UUID invoiceId = item.getInvoiceId();
+ if (amountOwedByInvoice.containsKey(invoiceId)) {
+ amountOwedByInvoice.put(invoiceId, amountOwedByInvoice.get(invoiceId).add(item.getAmount()));
+ } else {
+ amountOwedByInvoice.put(invoiceId, item.getAmount());
}
}
- if (creditTotal.compareTo(BigDecimal.ZERO) != 0) {
- // create a single credit item to cover all credits
- //invoiceItems.add(new CreditInvoiceItem());
+ for (UUID invoiceId : amountOwedByInvoice.keySet()) {
+ BigDecimal invoiceBalance = amountOwedByInvoice.get(invoiceId);
+ if (invoiceBalance.compareTo(BigDecimal.ZERO) < 0) {
+ proposedItems.add(new CreditInvoiceItem(invoiceId, accountId, clock.getUTCNow(), invoiceBalance.negate(), currency));
+ }
}
}
- private void updateInvoiceBalance(List<InvoiceItem> items, Map<UUID, BigDecimal> invoiceBalances) {
- for (InvoiceItem item : items) {
- UUID invoiceId = item.getInvoiceId();
-
- if (!invoiceBalances.containsKey(invoiceId)) {
- invoiceBalances.put(invoiceId, BigDecimal.ZERO);
+ private void addReversingItems(List<InvoiceItem> existingItems, List<InvoiceItem> proposedItems) {
+ for (InvoiceItem existingItem : existingItems) {
+ if (existingItem instanceof RecurringInvoiceItem) {
+ RecurringInvoiceItem recurringItem = (RecurringInvoiceItem) existingItem;
+ proposedItems.add(recurringItem.asReversingItem());
}
-
- invoiceBalances.put(invoiceId, invoiceBalances.get(invoiceId).add(item.getAmount()));
}
}
- @Override
- public void distributeItems(List<Invoice> invoices) {
- Map<UUID, Invoice> invoiceMap = new HashMap<UUID, Invoice>();
+ private void consumeExistingCredit(UUID invoiceId, UUID accountId, List<InvoiceItem> existingItems,
+ List<InvoiceItem> proposedItems, Currency targetCurrency) {
+ BigDecimal totalUnusedCreditAmount = BigDecimal.ZERO;
+ BigDecimal totalAmountOwed = BigDecimal.ZERO;
- for (Invoice invoice : invoices) {
- invoiceMap.put(invoice.getId(), invoice);
+ for (InvoiceItem item : existingItems) {
+ if (item instanceof CreditInvoiceItem) {
+ totalUnusedCreditAmount = totalUnusedCreditAmount.add(item.getAmount());
+ }
}
- for (final Invoice invoice: invoices) {
- Iterator<InvoiceItem> itemIterator = invoice.getInvoiceItems().iterator();
- final UUID invoiceId = invoice.getId();
-
- while (itemIterator.hasNext()) {
- InvoiceItem item = itemIterator.next();
+ for (InvoiceItem item : proposedItems) {
+ if (item instanceof CreditInvoiceItem) {
+ totalUnusedCreditAmount = totalUnusedCreditAmount.add(item.getAmount());
+ } else {
+ totalAmountOwed = totalAmountOwed.add(item.getAmount());
+ }
+ }
- if (!item.getInvoiceId().equals(invoiceId)) {
- invoiceMap.get(item.getInvoiceId()).addInvoiceItem(item);
- itemIterator.remove();
- }
+ // credits are positive when they reduce the amount owed (since they offset payment)
+ // the credit balance should never be negative
+ BigDecimal creditAmount = BigDecimal.ZERO;
+ if (totalUnusedCreditAmount.compareTo(BigDecimal.ZERO) > 0) {
+ if (totalAmountOwed.abs().compareTo(totalUnusedCreditAmount.abs()) > 0) {
+ creditAmount = totalUnusedCreditAmount.negate();
+ } else {
+ creditAmount = totalAmountOwed;
}
}
+
+ if (creditAmount.compareTo(BigDecimal.ZERO) < 0) {
+ proposedItems.add(new CreditInvoiceItem(invoiceId, accountId, clock.getUTCNow(), creditAmount, targetCurrency));
+ }
}
private void validateTargetDate(DateTime targetDate) throws InvoiceApiException {
@@ -246,16 +248,36 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
private List<InvoiceItem> generateInvoiceItems(final UUID invoiceId, final UUID accountId, final BillingEventSet events,
final DateTime targetDate, final Currency currency) throws InvoiceApiException {
List<InvoiceItem> items = new ArrayList<InvoiceItem>();
+
+ if(events.size() == 0) {
+ return items;
+ }
- for (int i = 0; i < events.size(); i++) {
- BillingEvent thisEvent = events.get(i);
- BillingEvent nextEvent = events.isLast(thisEvent) ? null : events.get(i + 1);
- if (nextEvent != null) {
- nextEvent = (thisEvent.getSubscription().getId() == nextEvent.getSubscription().getId()) ? nextEvent : null;
- }
+ Iterator<BillingEvent> eventIt = events.iterator();
- items.addAll(processEvents(invoiceId, accountId, thisEvent, nextEvent, targetDate, currency));
+ BillingEvent nextEvent = eventIt.next();
+ while(eventIt.hasNext()) {
+ BillingEvent thisEvent = nextEvent;
+ nextEvent = eventIt.next();
+ if(!events.getSubscriptionIdsWithAutoInvoiceOff().
+ contains(thisEvent.getSubscription().getId())) { // don't consider events for subscriptions that have auto_invoice_off
+ BillingEvent adjustedNextEvent = (thisEvent.getSubscription().getId() == nextEvent.getSubscription().getId()) ? nextEvent : null;
+ items.addAll(processEvents(invoiceId, accountId, thisEvent, adjustedNextEvent, targetDate, currency));
+ }
}
+ items.addAll(processEvents(invoiceId, accountId, nextEvent, null, targetDate, currency));
+
+// The above should reproduce the semantics of the code below using iterator instead of list.
+//
+// for (int i = 0; i < events.size(); i++) {
+// BillingEvent thisEvent = events.get(i);
+// BillingEvent nextEvent = events.isLast(thisEvent) ? null : events.get(i + 1);
+// if (nextEvent != null) {
+// nextEvent = (thisEvent.getSubscription().getId() == nextEvent.getSubscription().getId()) ? nextEvent : null;
+// }
+//
+// items.addAll(processEvents(invoiceId, accountId, thisEvent, nextEvent, targetDate, currency));
+// }
return items;
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java
index ba02039..1be9662 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java
@@ -16,7 +16,9 @@
package com.ning.billing.invoice.model;
+import com.ning.billing.ErrorCode;
import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.InvoiceApiException;
import com.ning.billing.invoice.api.InvoicePayment;
import com.ning.billing.util.entity.EntityBase;
import org.joda.time.DateTime;
@@ -31,24 +33,27 @@ public class DefaultInvoicePayment extends EntityBase implements InvoicePayment
private final DateTime paymentDate;
private final BigDecimal amount;
private final Currency currency;
+ private final UUID reversedInvoicePaymentId;
public DefaultInvoicePayment(final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate) {
- this(UUID.randomUUID(), paymentAttemptId, invoiceId, paymentDate, null, null);
+ this(UUID.randomUUID(), paymentAttemptId, invoiceId, paymentDate, null, null, null);
}
public DefaultInvoicePayment(final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate,
final BigDecimal amount, final Currency currency) {
- this(UUID.randomUUID(), paymentAttemptId, invoiceId, paymentDate, amount, currency);
+ this(UUID.randomUUID(), paymentAttemptId, invoiceId, paymentDate, amount, currency, null);
}
public DefaultInvoicePayment(final UUID id, final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate,
- @Nullable final BigDecimal amount, @Nullable final Currency currency) {
+ @Nullable final BigDecimal amount, @Nullable final Currency currency,
+ @Nullable final UUID reversedInvoicePaymentId) {
super(id);
this.paymentAttemptId = paymentAttemptId;
this.amount = amount;
this.invoiceId = invoiceId;
this.paymentDate = paymentDate;
this.currency = currency;
+ this.reversedInvoicePaymentId = reversedInvoicePaymentId;
}
@Override
@@ -75,4 +80,18 @@ public class DefaultInvoicePayment extends EntityBase implements InvoicePayment
public Currency getCurrency() {
return currency;
}
+
+ @Override
+ public UUID getReversedInvoicePaymentId() {
+ return reversedInvoicePaymentId;
+ }
+
+ @Override
+ public InvoicePayment asChargeBack(BigDecimal chargeBackAmount, DateTime chargeBackDate) throws InvoiceApiException {
+ if (chargeBackAmount.compareTo(amount) > 0) {
+ throw new InvoiceApiException(ErrorCode.CHARGE_BACK_AMOUNT_TOO_HIGH, chargeBackAmount, amount);
+ }
+
+ return new DefaultInvoicePayment(UUID.randomUUID(), null, invoiceId, chargeBackDate, chargeBackAmount.negate(), currency, id);
+ }
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
index b5a79ab..60a39a6 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
@@ -19,6 +19,7 @@ package com.ning.billing.invoice.model;
import java.math.BigDecimal;
import java.util.UUID;
+import com.ning.billing.invoice.api.InvoiceItemType;
import org.joda.time.DateTime;
import com.ning.billing.catalog.api.Currency;
@@ -28,12 +29,12 @@ public class FixedPriceInvoiceItem extends InvoiceItemBase {
public FixedPriceInvoiceItem(UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency) {
- super(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency);
+ super(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, InvoiceItemType.FIXED);
}
public FixedPriceInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency) {
- super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency);
+ super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, InvoiceItemType.FIXED);
}
@Override
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceGenerator.java b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceGenerator.java
index f903087..0b47099 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceGenerator.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceGenerator.java
@@ -16,19 +16,19 @@
package com.ning.billing.invoice.model;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceApiException;
-import com.ning.billing.invoice.api.InvoiceItem;
-import org.joda.time.DateTime;
-
-import javax.annotation.Nullable;
-import java.util.List;
-import java.util.UUID;
+import com.ning.billing.junction.api.BillingEventSet;
public interface InvoiceGenerator {
public Invoice generateInvoice(UUID accountId, @Nullable BillingEventSet events, @Nullable List<Invoice> existingInvoices,
DateTime targetDate, Currency targetCurrency) throws InvoiceApiException;
-
- public void distributeItems(List<Invoice> invoices);
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
index 5ccaa8c..016184d 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
@@ -18,6 +18,7 @@ package com.ning.billing.invoice.model;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoiceItemType;
import com.ning.billing.util.entity.EntityBase;
import org.joda.time.DateTime;
@@ -36,16 +37,18 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem
protected final DateTime endDate;
protected final BigDecimal amount;
protected final Currency currency;
+ protected InvoiceItemType invoiceItemType;
public InvoiceItemBase(UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
- DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency) {
+ DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency, InvoiceItemType invoiceItemType) {
this(UUID.randomUUID(), invoiceId, accountId, bundleId, subscriptionId, planName, phaseName,
- startDate, endDate, amount, currency);
+ startDate, endDate, amount, currency, invoiceItemType);
}
public InvoiceItemBase(UUID id, UUID invoiceId, UUID accountId, @Nullable UUID bundleId,
@Nullable UUID subscriptionId, String planName, String phaseName,
- DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency) {
+ DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency,
+ InvoiceItemType invoiceItemType) {
super(id);
this.invoiceId = invoiceId;
this.accountId = accountId;
@@ -57,6 +60,7 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem
this.endDate = endDate;
this.amount = amount;
this.currency = currency;
+ this.invoiceItemType = invoiceItemType;
}
@Override
@@ -109,6 +113,11 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem
}
@Override
+ public InvoiceItemType getInvoiceItemType() {
+ return invoiceItemType;
+ }
+
+ @Override
public abstract InvoiceItem asReversingItem();
@Override
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemList.java b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemList.java
index 683bbaf..357c7a8 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemList.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemList.java
@@ -34,55 +34,33 @@ public class InvoiceItemList extends ArrayList<InvoiceItem> {
this.addAll(invoiceItems);
}
- public BigDecimal getTotalAmount() {
+ public BigDecimal getAmountCharged() {
// naive implementation, assumes all invoice items share the same currency
BigDecimal total = BigDecimal.ZERO.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
for (final InvoiceItem item : this) {
- if (item.getAmount() != null) {
- total = total.add(item.getAmount());
+ if (!(item instanceof CreditInvoiceItem)) {
+ if (item.getAmount() != null) {
+ total = total.add(item.getAmount());
+ }
}
}
return total.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
}
-// public void removeCancellingPairs() {
-// List<InvoiceItem> itemsToRemove = new ArrayList<InvoiceItem>();
-//
-// for (int firstItemIndex = 0; firstItemIndex < this.size(); firstItemIndex++) {
-// for (int secondItemIndex = firstItemIndex + 1; secondItemIndex < this.size(); secondItemIndex++) {
-// InvoiceItem firstItem = this.get(firstItemIndex);
-// InvoiceItem secondItem = this.get(secondItemIndex);
-// if (firstItem.cancels(secondItem)) {
-// itemsToRemove.add(firstItem);
-// itemsToRemove.add(secondItem);
-// }
-// }
-// }
-//
-// this.removeAll(itemsToRemove);
-// }
+ public BigDecimal getAmountCredited() {
+ // naive implementation, assumes all invoice items share the same currency
+ BigDecimal total = BigDecimal.ZERO.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+
+ for (final InvoiceItem item : this) {
+ if (item instanceof CreditInvoiceItem) {
+ if (item.getAmount() != null) {
+ total = total.add(item.getAmount());
+ }
+ }
+ }
-// /*
-// * removes recurring items from the list that have a recurring amount of zero, but a recurring rate that is not zero
-// */
-// public void cleanupDuplicatedItems() {
-// Iterator<InvoiceItem> iterator = this.iterator();
-// while (iterator.hasNext()) {
-// InvoiceItem item = iterator.next();
-//
-// if (item instanceof RecurringInvoiceItem) {
-// RecurringInvoiceItem that = (RecurringInvoiceItem) item;
-// boolean recurringRateNull = (that.getRate() == null);
-// boolean recurringAmountZero = (that.getAmount() !=null) && (that.getAmount().compareTo(BigDecimal.ZERO) == 0);
-//
-// if (recurringRateNull || recurringAmountZero) {
-// iterator.remove();
-// } else if (that.getEndDate() != null && that.getStartDate().compareTo(that.getEndDate()) == 0) {
-// iterator.remove();
-// }
-// }
-// }
-// }
+ return total.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+ }
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java
index bc813fc..9dbbae0 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java
@@ -18,6 +18,7 @@ package com.ning.billing.invoice.model;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoiceItemType;
import org.joda.time.DateTime;
import java.math.BigDecimal;
@@ -30,8 +31,8 @@ public class RecurringInvoiceItem extends InvoiceItemBase {
public RecurringInvoiceItem(UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
DateTime startDate, DateTime endDate,
BigDecimal amount, BigDecimal rate,
- Currency currency) {
- super(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency);
+ Currency currency) {
+ super(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, InvoiceItemType.RECURRING);
this.rate = rate;
this.reversedItemId = null;
}
@@ -41,7 +42,7 @@ public class RecurringInvoiceItem extends InvoiceItemBase {
BigDecimal amount, BigDecimal rate,
Currency currency, UUID reversedItemId) {
super(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate,
- amount, currency);
+ amount, currency, InvoiceItemType.REVERSAL);
this.rate = rate;
this.reversedItemId = reversedItemId;
}
@@ -51,7 +52,7 @@ public class RecurringInvoiceItem extends InvoiceItemBase {
DateTime startDate, DateTime endDate,
BigDecimal amount, BigDecimal rate,
Currency currency) {
- super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency);
+ super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, InvoiceItemType.RECURRING);
this.rate = rate;
this.reversedItemId = null;
}
@@ -61,7 +62,7 @@ public class RecurringInvoiceItem extends InvoiceItemBase {
DateTime startDate, DateTime endDate,
BigDecimal amount, BigDecimal rate,
Currency currency, UUID reversedItemId) {
- super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency);
+ super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, InvoiceItemType.REVERSAL);
this.rate = rate;
this.reversedItemId = reversedItemId;
}
@@ -132,6 +133,7 @@ public class RecurringInvoiceItem extends InvoiceItemBase {
RecurringInvoiceItem that = (RecurringInvoiceItem) o;
+ // do not include invoice item type, since a reversing item can be equal to the original item
if (accountId.compareTo(that.accountId) != 0) return false;
if (amount.compareTo(that.amount) != 0) return false;
if (currency != that.currency) return false;
@@ -162,6 +164,7 @@ public class RecurringInvoiceItem extends InvoiceItemBase {
result = 31 * result + amount.hashCode();
result = 31 * result + rate.hashCode();
result = 31 * result + currency.hashCode();
+ result = 31 * result + invoiceItemType.hashCode();
result = 31 * result + (reversedItemId != null ? reversedItemId.hashCode() : 0);
return result;
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
index ed50d2e..1ca7824 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
@@ -120,8 +120,13 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
}
@Override
- public BigDecimal getTotalAmount() {
- return invoice.getTotalAmount();
+ public BigDecimal getAmountCharged() {
+ return invoice.getAmountCharged();
+ }
+
+ @Override
+ public BigDecimal getAmountCredited() {
+ return invoice.getAmountCredited();
}
@Override
diff --git a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
index f1a2e8d..9f49eb5 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
@@ -18,6 +18,7 @@ package com.ning.billing.invoice.template.formatters;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoiceItemType;
import com.ning.billing.invoice.api.formatters.InvoiceItemFormatter;
import com.ning.billing.util.template.translation.DefaultCatalogTranslator;
import com.ning.billing.util.template.translation.Translator;
@@ -55,6 +56,11 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
}
@Override
+ public InvoiceItemType getInvoiceItemType() {
+ return item.getInvoiceItemType();
+ }
+
+ @Override
public InvoiceItem asReversingItem() {
return item.asReversingItem();
}
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/CreditInvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/CreditInvoiceItemSqlDao.sql.stg
new file mode 100644
index 0000000..d3bef75
--- /dev/null
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/CreditInvoiceItemSqlDao.sql.stg
@@ -0,0 +1,69 @@
+group CreditInvoiceItemSqlDao;
+
+fields(prefix) ::= <<
+ <prefix>id,
+ <prefix>invoice_id,
+ <prefix>account_id,
+ <prefix>credit_date,
+ <prefix>amount,
+ <prefix>currency,
+ <prefix>created_by,
+ <prefix>created_date
+>>
+
+getById() ::= <<
+ SELECT <fields()>
+ FROM credit_invoice_items
+ WHERE id = :id;
+>>
+
+getInvoiceItemsByInvoice() ::= <<
+ SELECT <fields()>
+ FROM credit_invoice_items
+ WHERE invoice_id = :invoiceId;
+>>
+
+getInvoiceItemsByAccount() ::= <<
+ SELECT <fields("cii.")>
+ FROM credit_invoice_items cii
+ INNER JOIN invoices i ON i.id = cii.invoice_id
+ WHERE i.account_id = :accountId;
+>>
+
+create() ::= <<
+ INSERT INTO credit_invoice_items(<fields()>)
+ VALUES(:id, :invoiceId, :accountId, :creditDate, :amount, :currency, :userName, :createdDate);
+>>
+
+batchCreateFromTransaction() ::= <<
+ INSERT INTO credit_invoice_items(<fields()>)
+ VALUES(:id, :invoiceId, :accountId, :creditDate, :amount, :currency, :userName, :createdDate);
+>>
+
+getRecordIds() ::= <<
+ SELECT record_id, id
+ FROM credit_invoice_items
+ WHERE invoice_id = :invoiceId;
+>>
+
+auditFields(prefix) ::= <<
+ <prefix>table_name,
+ <prefix>record_id,
+ <prefix>change_type,
+ <prefix>change_date,
+ <prefix>changed_by,
+ <prefix>reason_code,
+ <prefix>comments,
+ <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+ INSERT INTO audit_log(<auditFields()>)
+ VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, :reasonCode, :comment, :userToken);
+>>
+
+test() ::= <<
+ SELECT 1
+ FROM credit_invoice_items;
+>>
+;
\ No newline at end of file
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
index 5ec38d3..3773a1c 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
@@ -7,18 +7,21 @@ invoicePaymentFields(prefix) ::= <<
<prefix>payment_attempt_date,
<prefix>amount,
<prefix>currency,
+ <prefix>reversed_invoice_payment_id,
<prefix>created_by,
<prefix>created_date
>>
create() ::= <<
INSERT INTO invoice_payments(<invoicePaymentFields()>)
- VALUES(:id, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency, :userName, :createdDate);
+ VALUES(:id, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency,
+ :reversedInvoicePaymentId, :userName, :createdDate);
>>
batchCreateFromTransaction() ::= <<
INSERT INTO invoice_payments(<invoicePaymentFields()>)
- VALUES(:id, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency, :userName, :createdDate);
+ VALUES(:id, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency,
+ :reversedInvoicePaymentId, :userName, :createdDate);
>>
getByPaymentAttemptId() ::= <<
@@ -32,6 +35,12 @@ get() ::= <<
FROM invoice_payments;
>>
+getById() ::= <<
+ SELECT <invoicePaymentFields()>
+ FROM invoice_payments
+ WHERE id = :id;
+>>
+
getPaymentsForInvoice() ::= <<
SELECT <invoicePaymentFields()>
FROM invoice_payments
@@ -40,7 +49,8 @@ getPaymentsForInvoice() ::= <<
notifyOfPaymentAttempt() ::= <<
INSERT INTO invoice_payments(<invoicePaymentFields()>)
- VALUES(:id, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency, :userName, :createdDate);
+ VALUES(:id, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency,
+ :reversedInvoicePaymentId, :userName, :createdDate);
>>
getInvoicePayment() ::= <<
@@ -78,6 +88,35 @@ insertAuditFromTransaction() ::= <<
>>
test() ::= <<
- SELECT 1 FROM invoice_payments;
+ SELECT 1 FROM invoice_payments;
+>>
+
+getRemainingAmountPaid() ::= <<
+ SELECT SUM(amount)
+ FROM invoice_payments
+ WHERE id = :invoicePaymentId
+ OR reversed_invoice_payment_id = :invoicePaymentId;
+>>
+
+getAccountIdFromInvoicePaymentId() ::= <<
+ SELECT account_id
+ FROM invoice_payments ip
+ INNER JOIN invoices i ON i.id = ip.invoice_id
+ WHERE ip.id = :invoicePaymentId;
+>>
+
+getChargeBacksByAccountId() ::= <<
+ SELECT <invoicePaymentFields("ip.")>
+ FROM invoice_payments ip
+ INNER JOIN invoices i ON i.id = ip.invoice_id
+ WHERE i.account_id = :accountId
+ AND reversed_invoice_payment_id IS NOT NULL;
+>>
+
+getChargebacksByAttemptPaymentId() ::= <<
+ SELECT <invoicePaymentFields()>
+ FROM invoice_payments
+ WHERE reversed_invoice_payment_id IN
+ (SELECT id FROM invoice_payments WHERE payment_attempt_id = :paymentAttemptId);
>>
;
\ No newline at end of file
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
index 6db5db5..fe942a8 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
@@ -39,11 +39,11 @@ getInvoicesByAccountAfterDate() ::= <<
>>
getInvoicesBySubscription() ::= <<
- SELECT record_id as invoice_number, <invoiceFields("i.")>
+ SELECT i.record_id as invoice_number, <invoiceFields("i.")>
FROM invoices i
LEFT JOIN recurring_invoice_items rii ON i.id = rii.invoice_id
- WHERE rii.subscription_id = :subscriptionId AND migrated = 'FALSE'
- GROUP BY record_id as invoice_number, <invoiceFields("i.")>;
+ WHERE rii.subscription_id = :subscriptionId AND migrated = 'FALSE'
+ GROUP BY i.record_id, <invoiceFields("i.")>;
>>
getById() ::= <<
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
index 8bda35c..ee67f37 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
+++ b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
@@ -45,6 +45,22 @@ CREATE UNIQUE INDEX fixed_invoice_items_id ON fixed_invoice_items(id);
CREATE INDEX fixed_invoice_items_subscription_id ON fixed_invoice_items(subscription_id ASC);
CREATE INDEX fixed_invoice_items_invoice_id ON fixed_invoice_items(invoice_id ASC);
+DROP TABLE IF EXISTS credit_invoice_items;
+CREATE TABLE credit_invoice_items (
+ record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+ id char(36) NOT NULL,
+ invoice_id char(36) NOT NULL,
+ account_id char(36) NOT NULL,
+ credit_date datetime NOT NULL,
+ amount numeric(10,4) NULL,
+ currency char(3) NOT NULL,
+ created_by varchar(50) NOT NULL,
+ created_date datetime NOT NULL,
+ PRIMARY KEY(record_id)
+) ENGINE=innodb;
+CREATE UNIQUE INDEX credit_invoice_items_id ON credit_invoice_items(id);
+CREATE INDEX credit_invoice_items_invoice_id ON credit_invoice_items(invoice_id ASC);
+
DROP TABLE IF EXISTS invoice_locking;
DROP TABLE IF EXISTS invoices;
@@ -68,16 +84,17 @@ CREATE TABLE invoice_payments (
record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
id char(36) NOT NULL,
invoice_id char(36) NOT NULL,
- payment_attempt_id char(36) COLLATE utf8_bin NOT NULL,
- payment_attempt_date datetime,
- amount numeric(10,4),
- currency char(3),
+ payment_attempt_id char(36) COLLATE utf8_bin,
+ payment_attempt_date datetime NOT NULL,
+ amount numeric(10,4) NOT NULL,
+ currency char(3) NOT NULL,
+ reversed_invoice_payment_id char(36) DEFAULT NULL,
created_by varchar(50) NOT NULL,
created_date datetime NOT NULL,
PRIMARY KEY(record_id)
) ENGINE=innodb;
CREATE UNIQUE INDEX invoice_payments_id ON invoice_payments(id);
-CREATE UNIQUE INDEX invoice_payments_unique ON invoice_payments(invoice_id, payment_attempt_id);
+CREATE INDEX invoice_payments_reversals ON invoice_payments(reversed_invoice_payment_id);
DROP VIEW IF EXISTS invoice_payment_summary;
CREATE VIEW invoice_payment_summary AS
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
index efedbaf..05f7179 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
@@ -19,11 +19,8 @@ package com.ning.billing.invoice.api.migration;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
import java.util.UUID;
-import com.ning.billing.invoice.tests.InvoicingTestBase;
import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
@@ -45,10 +42,10 @@ import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.dbi.MysqlTestingHelper;
import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.billing.BillingEvent;
import com.ning.billing.entitlement.api.billing.BillingModeType;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.invoice.InvoiceDispatcher;
+import com.ning.billing.invoice.MockBillingEventSet;
import com.ning.billing.invoice.TestInvoiceDispatcher;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceMigrationApi;
@@ -58,7 +55,9 @@ import com.ning.billing.invoice.api.InvoiceUserApi;
import com.ning.billing.invoice.dao.InvoiceDao;
import com.ning.billing.invoice.model.InvoiceGenerator;
import com.ning.billing.invoice.notification.NullInvoiceNotifier;
+import com.ning.billing.invoice.tests.InvoicingTestBase;
import com.ning.billing.junction.api.BillingApi;
+import com.ning.billing.junction.api.BillingEventSet;
import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
import com.ning.billing.util.bus.BusService;
@@ -179,7 +178,7 @@ public class TestDefaultInvoiceMigrationApi extends InvoicingTestBase {
Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
((ZombieControl)subscription).addResult("getId", subscriptionId);
((ZombieControl)subscription).addResult("getBundleId", new UUID(0L,0L));
- SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
+ BillingEventSet events = new MockBillingEventSet();
Plan plan = MockPlan.createBicycleNoTrialEvergreen1USD();
PlanPhase planPhase = MockPlanPhase.create1USDMonthlyEvergreen();
DateTime effectiveDate = new DateTime().minusDays(1);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java
index 09b809c..1bde0c6 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java
@@ -27,6 +27,7 @@ import org.joda.time.DateTime;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.model.DefaultInvoicePayment;
import com.ning.billing.util.callcontext.CallContext;
+import org.joda.time.DateTimeZone;
public class MockInvoicePaymentApi implements InvoicePaymentApi
{
@@ -101,4 +102,67 @@ public class MockInvoicePaymentApi implements InvoicePaymentApi
notifyOfPaymentAttempt(invoicePayment, context);
}
+ @Override
+ public void processChargeback(UUID invoicePaymentId, BigDecimal amount, CallContext context) throws InvoiceApiException {
+ InvoicePayment existingPayment = null;
+ for (InvoicePayment payment : invoicePayments) {
+ if (payment.getId() == invoicePaymentId) {
+ existingPayment = payment;
+ }
+ }
+
+ if (existingPayment != null) {
+ invoicePayments.add(existingPayment.asChargeBack(amount, DateTime.now(DateTimeZone.UTC)));
+ }
+ }
+
+ @Override
+ public void processChargeback(UUID invoicePaymentId, CallContext context) throws InvoiceApiException {
+ InvoicePayment existingPayment = null;
+ for (InvoicePayment payment : invoicePayments) {
+ if (payment.getId() == invoicePaymentId) {
+ existingPayment = payment;
+ }
+ }
+
+ if (existingPayment != null) {
+ this.processChargeback(invoicePaymentId, existingPayment.getAmount(), context);
+ }
+ }
+
+ @Override
+ public BigDecimal getRemainingAmountPaid(UUID invoicePaymentId) {
+ BigDecimal amount = BigDecimal.ZERO;
+ for (InvoicePayment payment : invoicePayments) {
+ if (payment.getId().equals(invoicePaymentId)) {
+ amount = amount.add(payment.getAmount());
+ }
+
+ if (payment.getReversedInvoicePaymentId().equals(invoicePaymentId)) {
+ amount = amount.add(payment.getAmount());
+ }
+ }
+
+ return amount;
+ }
+
+ @Override
+ public List<InvoicePayment> getChargebacksByAccountId(UUID accountId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public UUID getAccountIdFromInvoicePaymentId(UUID uuid) throws InvoiceApiException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<InvoicePayment> getChargebacksByPaymentAttemptId(UUID paymentAttemptId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public InvoicePayment getChargebackById(UUID chargebackId) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
index 0e99dab..afba58b 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
@@ -20,6 +20,14 @@ import static org.testng.Assert.assertTrue;
import java.io.IOException;
+import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.invoice.notification.MockNextBillingDatePoster;
+import com.ning.billing.invoice.notification.NextBillingDatePoster;
+import com.ning.billing.util.callcontext.TestCallContext;
+import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.tag.dao.AuditedTagDao;
+import com.ning.billing.util.tag.dao.MockTagDao;
+import com.ning.billing.util.tag.dao.TagDao;
import org.apache.commons.io.IOUtils;
import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.IDBI;
@@ -29,28 +37,21 @@ import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Stage;
import com.ning.billing.config.InvoiceConfig;
-import com.ning.billing.invoice.glue.InvoiceModuleWithEmbeddedDb;
import com.ning.billing.invoice.model.DefaultInvoiceGenerator;
import com.ning.billing.invoice.model.InvoiceGenerator;
import com.ning.billing.invoice.tests.InvoicingTestBase;
-import com.ning.billing.util.bus.BusService;
-import com.ning.billing.util.bus.DefaultBusService;
import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallOrigin;
-import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import com.ning.billing.util.callcontext.UserType;
import com.ning.billing.util.clock.Clock;
public abstract class InvoiceDaoTestBase extends InvoicingTestBase {
protected IDBI dbi;
+ private MysqlTestingHelper mysqlTestingHelper;
protected InvoiceDao invoiceDao;
protected RecurringInvoiceItemSqlDao recurringInvoiceItemDao;
+ protected FixedPriceInvoiceItemSqlDao fixedPriceInvoiceItemSqlDao;
+ protected CreditInvoiceItemSqlDao creditInvoiceItemSqlDao;
protected InvoicePaymentSqlDao invoicePaymentDao;
- protected InvoiceModuleWithEmbeddedDb module;
protected Clock clock;
protected CallContext context;
protected InvoiceGenerator generator;
@@ -66,44 +67,44 @@ public abstract class InvoiceDaoTestBase extends InvoicingTestBase {
@BeforeClass(alwaysRun = true)
protected void setup() throws IOException {
- module = new InvoiceModuleWithEmbeddedDb();
- dbi = module.getDbi();
+ mysqlTestingHelper = new MysqlTestingHelper();
+ dbi = mysqlTestingHelper.getDBI();
final String invoiceDdl = IOUtils.toString(DefaultInvoiceDao.class.getResourceAsStream("/com/ning/billing/invoice/ddl.sql"));
final String utilDdl = IOUtils.toString(DefaultInvoiceDao.class.getResourceAsStream("/com/ning/billing/util/ddl.sql"));
- module.startDb();
- module.initDb(invoiceDdl);
- module.initDb(utilDdl);
+ mysqlTestingHelper.startMysql();
+ mysqlTestingHelper.initDb(invoiceDdl);
+ mysqlTestingHelper.initDb(utilDdl);
- final Injector injector = Guice.createInjector(Stage.DEVELOPMENT, module);
-
- invoiceDao = injector.getInstance(InvoiceDao.class);
+ NextBillingDatePoster nextBillingDatePoster = new MockNextBillingDatePoster();
+ TagDao tagDao = new AuditedTagDao(dbi);
+ invoiceDao = new DefaultInvoiceDao(dbi, nextBillingDatePoster, tagDao);
invoiceDao.test();
- recurringInvoiceItemDao = module.getInvoiceItemSqlDao();
+ recurringInvoiceItemDao = dbi.onDemand(RecurringInvoiceItemSqlDao.class);
+ fixedPriceInvoiceItemSqlDao = dbi.onDemand(FixedPriceInvoiceItemSqlDao.class);
+ creditInvoiceItemSqlDao = dbi.onDemand(CreditInvoiceItemSqlDao.class);
+ invoicePaymentDao = dbi.onDemand(InvoicePaymentSqlDao.class);
- invoicePaymentDao = module.getInvoicePaymentSqlDao();
- clock = injector.getInstance(Clock.class);
- context = new DefaultCallContextFactory(clock).createCallContext("Count Rogan", CallOrigin.TEST, UserType.TEST);
+ clock = new ClockMock();
+ context = new TestCallContext("Invoice Dao Tests");
generator = new DefaultInvoiceGenerator(clock, invoiceConfig);
- BusService busService = injector.getInstance(BusService.class);
- ((DefaultBusService) busService).startBus();
-
assertTrue(true);
-
}
@BeforeMethod(alwaysRun = true)
public void cleanupData() {
- module.getDbi().inTransaction(new TransactionCallback<Void>() {
+ dbi.inTransaction(new TransactionCallback<Void>() {
@Override
public Void inTransaction(Handle h, TransactionStatus status)
throws Exception {
h.execute("truncate table invoices");
h.execute("truncate table fixed_invoice_items");
h.execute("truncate table recurring_invoice_items");
+ h.execute("truncate table credit_invoice_items");
+ h.execute("truncate table invoice_payments");
return null;
}
@@ -112,7 +113,7 @@ public abstract class InvoiceDaoTestBase extends InvoicingTestBase {
@AfterClass(alwaysRun = true)
protected void tearDown() {
- module.stopDb();
+ mysqlTestingHelper.stopMysql();
assertTrue(true);
}
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
index 809c141..97d7532 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
@@ -28,10 +28,6 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
-import com.ning.billing.util.dao.ObjectType;
-import com.ning.billing.util.tag.Tag;
-import com.ning.billing.util.tag.dao.AuditedTagDao;
-import com.ning.billing.util.tag.dao.TagDao;
import org.joda.time.DateTime;
import org.testng.annotations.Test;
@@ -49,17 +45,22 @@ import com.ning.billing.entitlement.api.SubscriptionTransitionType;
import com.ning.billing.entitlement.api.billing.BillingEvent;
import com.ning.billing.entitlement.api.billing.BillingModeType;
import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.invoice.MockBillingEventSet;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceApiException;
import com.ning.billing.invoice.api.InvoiceItem;
import com.ning.billing.invoice.api.InvoicePayment;
-import com.ning.billing.invoice.model.BillingEventSet;
import com.ning.billing.invoice.model.DefaultInvoice;
import com.ning.billing.invoice.model.DefaultInvoicePayment;
import com.ning.billing.invoice.model.RecurringInvoiceItem;
+import com.ning.billing.junction.api.BillingEventSet;
import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.util.dao.ObjectType;
import com.ning.billing.util.tag.ControlTagType;
+import com.ning.billing.util.tag.Tag;
+import com.ning.billing.util.tag.dao.AuditedTagDao;
+import com.ning.billing.util.tag.dao.TagDao;
@Test(groups = {"slow", "invoicing", "invoicing-invoiceDao"})
public class InvoiceDaoTests extends InvoiceDaoTestBase {
@@ -79,7 +80,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
assertTrue(thisInvoice.getInvoiceDate().compareTo(invoiceDate) == 0);
assertEquals(thisInvoice.getCurrency(), Currency.USD);
assertEquals(thisInvoice.getNumberOfItems(), 0);
- assertTrue(thisInvoice.getTotalAmount().compareTo(BigDecimal.ZERO) == 0);
+ assertTrue(thisInvoice.getBalance().compareTo(BigDecimal.ZERO) == 0);
}
@Test
@@ -99,7 +100,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
Invoice savedInvoice = invoiceDao.getById(invoiceId);
assertNotNull(savedInvoice);
- assertEquals(savedInvoice.getTotalAmount().compareTo(new BigDecimal("21.00")), 0);
+ assertEquals(savedInvoice.getBalance().compareTo(new BigDecimal("21.00")), 0);
assertEquals(savedInvoice.getBalance().compareTo(new BigDecimal("21.00")), 0);
assertEquals(savedInvoice.getAmountPaid(), BigDecimal.ZERO);
assertEquals(savedInvoice.getInvoiceItems().size(), 1);
@@ -112,7 +113,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
Invoice retrievedInvoice = invoiceDao.getById(invoiceId);
assertNotNull(retrievedInvoice);
assertEquals(retrievedInvoice.getInvoiceItems().size(), 1);
- assertEquals(retrievedInvoice.getTotalAmount().compareTo(new BigDecimal("21.00")), 0);
+ assertEquals(retrievedInvoice.getAmountCharged().compareTo(new BigDecimal("21.00")), 0);
assertEquals(retrievedInvoice.getBalance().compareTo(new BigDecimal("10.00")), 0);
assertEquals(retrievedInvoice.getAmountPaid().compareTo(new BigDecimal("11.00")), 0);
}
@@ -417,7 +418,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
"testEvent1", 1L, SubscriptionTransitionType.CREATE);
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
events.add(event1);
Invoice invoice1 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD);
@@ -446,10 +447,10 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
invoiceDao.create(invoice2, context);
Invoice savedInvoice1 = invoiceDao.getById(invoice1.getId());
- assertEquals(savedInvoice1.getTotalAmount(), ZERO);
+ assertEquals(savedInvoice1.getBalance(), ZERO);
Invoice savedInvoice2 = invoiceDao.getById(invoice2.getId());
- assertEquals(savedInvoice2.getTotalAmount(), FIFTEEN);
+ assertEquals(savedInvoice2.getBalance(), FIFTEEN);
}
@Test
@@ -466,7 +467,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
BillingEvent event = createMockBillingEvent(null, subscription, effectiveDate, plan, phase, null,
recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 15, BillingModeType.IN_ADVANCE,
"testEvent", 1L, SubscriptionTransitionType.CREATE);
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
events.add(event);
DateTime targetDate = buildDateTime(2011, 1, 15);
@@ -474,7 +475,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
// expect one pro-ration item and one full-period item
assertEquals(invoice.getNumberOfItems(), 2);
- assertEquals(invoice.getTotalAmount().compareTo(ZERO), 0);
+ assertEquals(invoice.getBalance().compareTo(ZERO), 0);
}
private Subscription getZombieSubscription() {
@@ -505,14 +506,14 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
BillingEvent event1 = createMockBillingEvent(null, subscription, effectiveDate1, plan, phase1, fixedPrice.getPrice(currency),
null, currency, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
"testEvent1", 1L, SubscriptionTransitionType.CREATE);
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
events.add(event1);
UUID accountId = UUID.randomUUID();
Invoice invoice1 = generator.generateInvoice(accountId, events, null, effectiveDate1, Currency.USD);
assertNotNull(invoice1);
assertEquals(invoice1.getNumberOfItems(), 1);
- assertEquals(invoice1.getTotalAmount().compareTo(ZERO), 0);
+ assertEquals(invoice1.getBalance().compareTo(ZERO), 0);
List<Invoice> invoiceList = new ArrayList<Invoice>();
invoiceList.add(invoice1);
@@ -526,7 +527,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, effectiveDate2, Currency.USD);
assertNotNull(invoice2);
assertEquals(invoice2.getNumberOfItems(), 1);
- assertEquals(invoice2.getTotalAmount().compareTo(cheapAmount), 0);
+ assertEquals(invoice2.getBalance().compareTo(cheapAmount), 0);
invoiceList.add(invoice2);
@@ -534,12 +535,12 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
Invoice invoice3 = generator.generateInvoice(accountId, events, invoiceList, effectiveDate3, Currency.USD);
assertNotNull(invoice3);
assertEquals(invoice3.getNumberOfItems(), 1);
- assertEquals(invoice3.getTotalAmount().compareTo(cheapAmount), 0);
+ assertEquals(invoice3.getBalance().compareTo(cheapAmount), 0);
}
@Test
public void testInvoiceForEmptyEventSet() throws InvoiceApiException {
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, new DateTime(), Currency.USD);
assertNull(invoice);
}
@@ -565,7 +566,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
fixedPrice.getPrice(currency), null, currency,
BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
"testEvent1", 1L, SubscriptionTransitionType.CREATE);
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
events.add(event1);
DateTime effectiveDate2 = effectiveDate1.plusDays(30);
@@ -577,14 +578,14 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, effectiveDate2, Currency.USD);
assertNotNull(invoice);
assertEquals(invoice.getNumberOfItems(), 2);
- assertEquals(invoice.getTotalAmount().compareTo(cheapAmount), 0);
+ assertEquals(invoice.getBalance().compareTo(cheapAmount), 0);
invoiceDao.create(invoice, context);
Invoice savedInvoice = invoiceDao.getById(invoice.getId());
assertNotNull(savedInvoice);
assertEquals(savedInvoice.getNumberOfItems(), 2);
- assertEquals(savedInvoice.getTotalAmount().compareTo(cheapAmount), 0);
+ assertEquals(savedInvoice.getBalance().compareTo(cheapAmount), 0);
}
@Test
@@ -604,7 +605,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
PlanPhase phase2 = BrainDeadProxyFactory.createBrainDeadProxyFor(PlanPhase.class);
((ZombieControl) phase2).addResult("getName", "plan-phase2");
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
List<Invoice> invoices = new ArrayList<Invoice>();
BillingEvent event1 = createMockBillingEvent(null, subscription, targetDate1, plan, phase1, null,
@@ -648,7 +649,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
TEN, currency,
BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
"testEvent1", 1L, SubscriptionTransitionType.CHANGE);
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
events.add(event1);
Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate1, Currency.USD);
@@ -679,7 +680,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
TEN, currency,
BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
"testEvent1", 1L, SubscriptionTransitionType.CHANGE);
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
events.add(event1);
Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate1, Currency.USD);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java
index 9acde8e..c97e775 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java
@@ -18,11 +18,15 @@ package com.ning.billing.invoice.dao;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;
+import com.ning.billing.invoice.model.CreditInvoiceItem;
+import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
import org.joda.time.DateTime;
import org.testng.annotations.Test;
@@ -31,9 +35,9 @@ import com.ning.billing.invoice.api.InvoiceItem;
import com.ning.billing.invoice.model.DefaultInvoice;
import com.ning.billing.invoice.model.RecurringInvoiceItem;
-@Test(groups = {"invoicing", "invoicing-invoiceDao"})
+@Test(groups = {"slow", "invoicing", "invoicing-invoiceDao"})
public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
- @Test(groups = "slow")
+ @Test
public void testInvoiceItemCreation() {
UUID accountId = UUID.randomUUID();
UUID invoiceId = UUID.randomUUID();
@@ -52,8 +56,8 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
assertEquals(thisItem.getId(), item.getId());
assertEquals(thisItem.getInvoiceId(), item.getInvoiceId());
assertEquals(thisItem.getSubscriptionId(), item.getSubscriptionId());
- assertEquals(thisItem.getStartDate(), item.getStartDate());
- assertEquals(thisItem.getEndDate(), item.getEndDate());
+ assertTrue(thisItem.getStartDate().compareTo(item.getStartDate()) == 0);
+ assertTrue(thisItem.getEndDate().compareTo(item.getEndDate()) == 0);
assertEquals(thisItem.getAmount().compareTo(item.getRate()), 0);
assertEquals(thisItem.getRate().compareTo(item.getRate()), 0);
assertEquals(thisItem.getCurrency(), item.getCurrency());
@@ -61,7 +65,7 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
// assertEquals(thisItem.getCreatedDate().compareTo(item.getCreatedDate()), 0);
}
- @Test(groups = "slow")
+ @Test
public void testGetInvoiceItemsBySubscriptionId() {
UUID accountId = UUID.randomUUID();
UUID subscriptionId = UUID.randomUUID();
@@ -82,7 +86,7 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
assertEquals(items.size(), 3);
}
- @Test(groups = "slow")
+ @Test
public void testGetInvoiceItemsByInvoiceId() {
UUID accountId = UUID.randomUUID();
UUID invoiceId = UUID.randomUUID();
@@ -104,7 +108,7 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
assertEquals(items.size(), 5);
}
- @Test(groups = "slow")
+ @Test
public void testGetInvoiceItemsByAccountId() {
UUID accountId = UUID.randomUUID();
UUID bundleId = UUID.randomUUID();
@@ -127,4 +131,31 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
List<InvoiceItem> items = recurringInvoiceItemDao.getInvoiceItemsByAccount(accountId.toString());
assertEquals(items.size(), 1);
}
+
+ @Test
+ public void testCreditInvoiceSqlDao() {
+ UUID invoiceId = UUID.randomUUID();
+ UUID accountId = UUID.randomUUID();
+ DateTime creditDate = new DateTime(2012, 4, 1, 0, 10, 22, 0);
+
+ InvoiceItem creditInvoiceItem = new CreditInvoiceItem(invoiceId, accountId, creditDate, TEN, Currency.USD);
+ creditInvoiceItemSqlDao.create(creditInvoiceItem, context);
+
+ InvoiceItem savedItem = creditInvoiceItemSqlDao.getById(creditInvoiceItem.getId().toString());
+ assertEquals(savedItem, creditInvoiceItem);
+ }
+
+ @Test
+ public void testFixedPriceInvoiceSqlDao() {
+ UUID invoiceId = UUID.randomUUID();
+ UUID accountId = UUID.randomUUID();
+ DateTime startDate = new DateTime(2012, 4, 1, 0, 10, 22, 0);
+
+ InvoiceItem fixedPriceInvoiceItem = new FixedPriceInvoiceItem(invoiceId, accountId, UUID.randomUUID(),
+ UUID.randomUUID(), "test plan", "test phase", startDate, startDate.plusMonths(1), TEN, Currency.USD);
+ fixedPriceInvoiceItemSqlDao.create(fixedPriceInvoiceItem, context);
+
+ InvoiceItem savedItem = fixedPriceInvoiceItemSqlDao.getById(fixedPriceInvoiceItem.getId().toString());
+ assertEquals(savedItem, fixedPriceInvoiceItem);
+ }
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
index 2c65cd8..e24effb 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
@@ -23,6 +23,8 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.InvoiceApiException;
import org.joda.time.DateTime;
import com.google.inject.Inject;
@@ -210,4 +212,44 @@ public class MockInvoiceDao implements InvoiceDao {
public void removeWrittenOff(UUID objectId, CallContext context) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public void postChargeback(UUID invoicePaymentId, BigDecimal amount, CallContext context) throws InvoiceApiException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public BigDecimal getRemainingAmountPaid(UUID invoicePaymentId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public UUID getAccountIdFromInvoicePaymentId(UUID invoicePaymentId) throws InvoiceApiException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<InvoicePayment> getChargebacksByAccountId(UUID accountId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<InvoicePayment> getChargebacksByPaymentAttemptId(UUID paymentAttemptId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public InvoicePayment getChargebackById(UUID chargebackId) throws InvoiceApiException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public InvoiceItem getCreditById(UUID creditId) throws InvoiceApiException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public InvoiceItem insertCredit(UUID accountId, BigDecimal amount, DateTime effectiveDate, Currency currency, CallContext context) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/HtmlInvoiceGeneratorTest.java b/invoice/src/test/java/com/ning/billing/invoice/HtmlInvoiceGeneratorTest.java
index 95f39c9..144fb13 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/HtmlInvoiceGeneratorTest.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/HtmlInvoiceGeneratorTest.java
@@ -90,7 +90,7 @@ public class HtmlInvoiceGeneratorTest {
zombie.addResult("getInvoiceDate", startDate);
zombie.addResult("getInvoiceNumber", 42);
zombie.addResult("getCurrency", Currency.USD);
- zombie.addResult("getTotalAmount", price1.add(price2));
+ zombie.addResult("getAmountCharged", price1.add(price2));
zombie.addResult("getAmountPaid", BigDecimal.ZERO);
zombie.addResult("getBalance", price1.add(price2));
diff --git a/invoice/src/test/java/com/ning/billing/invoice/MockBillingEventSet.java b/invoice/src/test/java/com/ning/billing/invoice/MockBillingEventSet.java
new file mode 100644
index 0000000..e8002f0
--- /dev/null
+++ b/invoice/src/test/java/com/ning/billing/invoice/MockBillingEventSet.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010-2011 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;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import com.ning.billing.entitlement.api.billing.BillingEvent;
+import com.ning.billing.junction.api.BillingEventSet;
+
+public class MockBillingEventSet extends TreeSet<BillingEvent> implements BillingEventSet {
+
+ private static final long serialVersionUID = 1L;
+
+ private boolean isAccountInvoiceOff;
+ private List<UUID> subscriptionIdsWithAutoInvoiceOff = new ArrayList<UUID>();
+
+ public void addSubscriptionWithAutoInvoiceOff(UUID subscriptionId) {
+ subscriptionIdsWithAutoInvoiceOff.add(subscriptionId);
+ }
+
+ @Override
+ public boolean isLast(BillingEvent event) {
+ return event == last();
+ }
+
+ @Override
+ public boolean isAccountAutoInvoiceOff() {
+ return isAccountInvoiceOff;
+ }
+
+ @Override
+ public List<UUID> getSubscriptionIdsWithAutoInvoiceOff() {
+ return subscriptionIdsWithAutoInvoiceOff;
+ }
+
+ public void setAccountInvoiceOff(boolean isAccountInvoiceOff) {
+ this.isAccountInvoiceOff = isAccountInvoiceOff;
+ }
+
+ public void setSubscriptionIdsWithAutoInvoiceOff(List<UUID> subscriptionIdsWithAutoInvoiceOff) {
+ this.subscriptionIdsWithAutoInvoiceOff = subscriptionIdsWithAutoInvoiceOff;
+ }
+
+ public void clearSubscriptionsWithAutoInvoiceOff() {
+ subscriptionIdsWithAutoInvoiceOff.clear();
+ }
+}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
index 992274d..679049a 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
@@ -16,16 +16,10 @@
package com.ning.billing.invoice;
-import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
import java.util.UUID;
-import com.ning.billing.invoice.api.InvoiceNotifier;
-import com.ning.billing.invoice.notification.NullInvoiceNotifier;
-import com.ning.billing.invoice.tests.InvoicingTestBase;
import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
@@ -47,18 +41,20 @@ import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
import com.ning.billing.dbi.MysqlTestingHelper;
import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.billing.BillingEvent;
import com.ning.billing.entitlement.api.billing.BillingModeType;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceApiException;
+import com.ning.billing.invoice.api.InvoiceNotifier;
import com.ning.billing.invoice.dao.InvoiceDao;
import com.ning.billing.invoice.model.InvoiceGenerator;
import com.ning.billing.invoice.notification.NextBillingDateNotifier;
+import com.ning.billing.invoice.notification.NullInvoiceNotifier;
+import com.ning.billing.invoice.tests.InvoicingTestBase;
import com.ning.billing.junction.api.BillingApi;
+import com.ning.billing.junction.api.BillingEventSet;
import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
-import com.ning.billing.mock.glue.MockJunctionModule;
import com.ning.billing.util.bus.BusService;
import com.ning.billing.util.bus.DefaultBusService;
import com.ning.billing.util.callcontext.CallContext;
@@ -145,7 +141,7 @@ public class TestInvoiceDispatcher extends InvoicingTestBase {
Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
((ZombieControl)subscription).addResult("getId", subscriptionId);
((ZombieControl)subscription).addResult("getBundleId", new UUID(0L,0L));
- SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
+ BillingEventSet events = new MockBillingEventSet();
Plan plan = MockPlan.createBicycleNoTrialEvergreen1USD();
PlanPhase planPhase = MockPlanPhase.create1USDMonthlyEvergreen();
DateTime effectiveDate = new DateTime().minusDays(1);
@@ -184,5 +180,7 @@ public class TestInvoiceDispatcher extends InvoicingTestBase {
Assert.assertEquals(invoices.size(),1);
}
+
+ //MDW add a test to cover when the account auto-invoice-off tag is present
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/ChargeBackTests.java b/invoice/src/test/java/com/ning/billing/invoice/tests/ChargeBackTests.java
new file mode 100644
index 0000000..6eac0dc
--- /dev/null
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/ChargeBackTests.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2010-2011 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.tests;
+
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceApiException;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoicePayment;
+import com.ning.billing.invoice.api.InvoicePaymentApi;
+import com.ning.billing.invoice.api.invoice.DefaultInvoicePaymentApi;
+import com.ning.billing.invoice.dao.DefaultInvoiceDao;
+import com.ning.billing.invoice.dao.InvoiceDao;
+import com.ning.billing.invoice.dao.InvoiceSqlDao;
+import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
+import com.ning.billing.invoice.notification.MockNextBillingDatePoster;
+import com.ning.billing.invoice.notification.NextBillingDatePoster;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.TestCallContext;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.tag.dao.MockTagDao;
+import com.ning.billing.util.tag.dao.TagDao;
+import org.skife.jdbi.v2.IDBI;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+@Test(groups = {"slow", "invoicing"})
+public class ChargeBackTests {
+ private final static BigDecimal FIFTEEN = new BigDecimal("15.00");
+ private final static BigDecimal THIRTY = new BigDecimal("30.00");
+ private final static BigDecimal ONE_MILLION = new BigDecimal("1000000.00");
+ private InvoiceSqlDao invoiceSqlDao;
+ private InvoicePaymentApi invoicePaymentApi;
+ private CallContext context;
+ private final Clock clock = new ClockMock();
+ private final static Currency CURRENCY = Currency.EUR;
+
+ @BeforeClass
+ public void setup() {
+ MysqlTestingHelper helper = new MysqlTestingHelper();
+ IDBI dbi = helper.getDBI();
+ invoiceSqlDao = dbi.onDemand(InvoiceSqlDao.class);
+ invoiceSqlDao.test();
+
+ NextBillingDatePoster nextBillingDatePoster = new MockNextBillingDatePoster();
+ TagDao tagDao = new MockTagDao();
+ InvoiceDao invoiceDao = new DefaultInvoiceDao(dbi, nextBillingDatePoster, tagDao);
+ invoicePaymentApi = new DefaultInvoicePaymentApi(invoiceDao);
+
+ context = new TestCallContext("Charge back tests");
+ }
+
+ @Test
+ public void testCompleteChargeBack() throws InvoiceApiException {
+ Invoice invoice = createAndPersistInvoice(THIRTY);
+ InvoicePayment payment = createAndPersistPayment(invoice.getId(), THIRTY);
+
+ // create a full charge back
+ invoicePaymentApi.processChargeback(payment.getId(), THIRTY, context);
+
+ // check amount owed
+ BigDecimal amount = invoicePaymentApi.getRemainingAmountPaid(payment.getId());
+ assertTrue(amount.compareTo(BigDecimal.ZERO) == 0);
+ }
+
+ @Test
+ public void testPartialChargeBack() throws InvoiceApiException {
+ Invoice invoice = createAndPersistInvoice(THIRTY);
+ InvoicePayment payment = createAndPersistPayment(invoice.getId(), THIRTY);
+
+ // create a partial charge back
+ invoicePaymentApi.processChargeback(payment.getId(), FIFTEEN, context);
+
+ // check amount owed
+ BigDecimal amount = invoicePaymentApi.getRemainingAmountPaid(payment.getId());
+ assertTrue(amount.compareTo(FIFTEEN) == 0);
+ }
+
+ @Test(expectedExceptions = InvoiceApiException.class)
+ public void testChargeBackLargerThanPaymentAmount() throws InvoiceApiException {
+ Invoice invoice = createAndPersistInvoice(THIRTY);
+ InvoicePayment payment = createAndPersistPayment(invoice.getId(), THIRTY);
+
+ // create a large charge back
+ invoicePaymentApi.processChargeback(payment.getId(), ONE_MILLION, context);
+ }
+
+ @Test(expectedExceptions = InvoiceApiException.class)
+ public void testNegativeChargeBackAmount() throws InvoiceApiException {
+ Invoice invoice = createAndPersistInvoice(THIRTY);
+ InvoicePayment payment = createAndPersistPayment(invoice.getId(), THIRTY);
+
+ // create a partial charge back
+ invoicePaymentApi.processChargeback(payment.getId(), BigDecimal.ONE.negate(), context);
+ }
+
+ @Test
+ public void testGetAccountIdFromPaymentIdHappyPath() throws InvoiceApiException {
+ Invoice invoice = createAndPersistInvoice(THIRTY);
+ InvoicePayment payment = createAndPersistPayment(invoice.getId(), THIRTY);
+ UUID accountId = invoicePaymentApi.getAccountIdFromInvoicePaymentId(payment.getId());
+ assertEquals(accountId, invoice.getAccountId());
+ }
+
+ @Test(expectedExceptions = InvoiceApiException.class)
+ public void testGetAccountIdFromPaymentIdBadPaymentId() throws InvoiceApiException {
+ invoicePaymentApi.getAccountIdFromInvoicePaymentId(UUID.randomUUID());
+ }
+
+ @Test
+ public void testGetChargeBacksByAccountIdWithEmptyReturnSet() throws InvoiceApiException {
+ List<InvoicePayment> chargebacks = invoicePaymentApi.getChargebacksByAccountId(UUID.randomUUID());
+ assertNotNull(chargebacks);
+ assertEquals(chargebacks.size(), 0);
+ }
+
+ @Test
+ public void testGetChargeBacksByAccountIdHappyPath() throws InvoiceApiException {
+ Invoice invoice = createAndPersistInvoice(THIRTY);
+ InvoicePayment payment = createAndPersistPayment(invoice.getId(), THIRTY);
+
+ // create a partial charge back
+ invoicePaymentApi.processChargeback(payment.getId(), FIFTEEN, context);
+
+ List<InvoicePayment> chargebacks = invoicePaymentApi.getChargebacksByAccountId(invoice.getAccountId());
+ assertNotNull(chargebacks);
+ assertEquals(chargebacks.size(), 1);
+ assertEquals(chargebacks.get(0).getReversedInvoicePaymentId(), payment.getId());
+ }
+
+ @Test
+ public void testGetChargeBacksByPaymentAttemptIdWithEmptyReturnSet() throws InvoiceApiException {
+ List<InvoicePayment> chargebacks = invoicePaymentApi.getChargebacksByPaymentAttemptId(UUID.randomUUID());
+ assertNotNull(chargebacks);
+ assertEquals(chargebacks.size(), 0);
+ }
+
+ @Test
+ public void testGetChargeBacksByInvoicePaymentIdHappyPath() throws InvoiceApiException {
+ Invoice invoice = createAndPersistInvoice(THIRTY);
+ InvoicePayment payment = createAndPersistPayment(invoice.getId(), THIRTY);
+
+ // create a partial charge back
+ invoicePaymentApi.processChargeback(payment.getId(), FIFTEEN, context);
+
+ List<InvoicePayment> chargebacks = invoicePaymentApi.getChargebacksByPaymentAttemptId(payment.getPaymentAttemptId());
+ assertNotNull(chargebacks);
+ assertEquals(chargebacks.size(), 1);
+ assertEquals(chargebacks.get(0).getReversedInvoicePaymentId(), payment.getId());
+ }
+
+ private Invoice createAndPersistInvoice(BigDecimal amount) {
+ Invoice invoice = BrainDeadProxyFactory.createBrainDeadProxyFor(Invoice.class);
+ UUID invoiceId = UUID.randomUUID();
+ UUID accountId = UUID.randomUUID();
+ ZombieControl zombie = (ZombieControl) invoice;
+ zombie.addResult("getId", invoiceId);
+ zombie.addResult("getAccountId", accountId);
+ zombie.addResult("getInvoiceDate", clock.getUTCNow());
+ zombie.addResult("getTargetDate", clock.getUTCNow());
+ zombie.addResult("getCurrency", CURRENCY);
+ zombie.addResult("isMigrationInvoice", false);
+
+ List<InvoiceItem> items = new ArrayList<InvoiceItem>();
+ items.add(createInvoiceItem(invoiceId, accountId, amount));
+ zombie.addResult("getInvoiceItems", items);
+
+ invoiceSqlDao.create(invoice, context);
+
+ return invoice;
+ }
+
+ private InvoiceItem createInvoiceItem(UUID invoiceId, UUID accountId, BigDecimal amount) {
+ return new FixedPriceInvoiceItem(invoiceId, accountId, UUID.randomUUID(), UUID.randomUUID(),
+ "charge back test", "charge back phase", clock.getUTCNow(), clock.getUTCNow(), amount, CURRENCY);
+ }
+
+ private InvoicePayment createAndPersistPayment(UUID invoiceId, BigDecimal amount) {
+ InvoicePayment payment = BrainDeadProxyFactory.createBrainDeadProxyFor(InvoicePayment.class);
+ ZombieControl zombie = (ZombieControl) payment;
+ zombie.addResult("getId", UUID.randomUUID());
+ zombie.addResult("getInvoiceId", invoiceId);
+ zombie.addResult("getPaymentAttemptId", UUID.randomUUID());
+ zombie.addResult("getPaymentAttemptDate", clock.getUTCNow());
+ zombie.addResult("getAmount", amount);
+ zombie.addResult("getCurrency", CURRENCY);
+ zombie.addResult("getReversedInvoicePaymentId", BrainDeadProxyFactory.ZOMBIE_VOID);
+
+ invoicePaymentApi.notifyOfPaymentAttempt(payment, context);
+
+ return payment;
+ }
+}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
index 75b57ec..8f381bc 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
@@ -19,16 +19,18 @@ package com.ning.billing.invoice.tests;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
-import static org.testng.Assert.fail;
+import static org.testng.Assert.assertTrue;
import java.math.BigDecimal;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
import javax.annotation.Nullable;
-import com.ning.billing.invoice.model.DefaultInvoicePayment;
import org.joda.time.DateTime;
import org.testng.annotations.Test;
@@ -47,13 +49,18 @@ import com.ning.billing.entitlement.api.SubscriptionTransitionType;
import com.ning.billing.entitlement.api.billing.BillingEvent;
import com.ning.billing.entitlement.api.billing.BillingModeType;
import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.invoice.MockBillingEventSet;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceApiException;
-import com.ning.billing.invoice.model.BillingEventSet;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.model.CreditInvoiceItem;
import com.ning.billing.invoice.model.DefaultInvoiceGenerator;
+import com.ning.billing.invoice.model.DefaultInvoice;
+import com.ning.billing.invoice.model.DefaultInvoicePayment;
import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
import com.ning.billing.invoice.model.InvoiceGenerator;
import com.ning.billing.invoice.model.RecurringInvoiceItem;
+import com.ning.billing.junction.api.BillingEventSet;
import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
import com.ning.billing.util.clock.Clock;
@@ -96,7 +103,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
@Test
public void testWithEmptyEventSet() throws InvoiceApiException {
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
UUID accountId = UUID.randomUUID();
Invoice invoice = generator.generateInvoice(accountId, events, null, new DateTime(), Currency.USD);
@@ -106,7 +113,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
@Test
public void testWithSingleMonthlyEvent() throws InvoiceApiException, CatalogApiException {
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
Subscription sub = createZombieSubscription();
DateTime startDate = buildDateTime(2011, 9, 1);
@@ -124,7 +131,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
assertNotNull(invoice);
assertEquals(invoice.getNumberOfItems(), 2);
- assertEquals(invoice.getTotalAmount(), TWENTY);
+ assertEquals(invoice.getBalance(), TWENTY);
assertEquals(invoice.getInvoiceItems().get(0).getSubscriptionId(), sub.getId());
}
@@ -142,7 +149,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
@Test
public void testWithSingleMonthlyEventWithLeadingProRation() throws InvoiceApiException, CatalogApiException {
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
Subscription sub = createZombieSubscription();
DateTime startDate = buildDateTime(2011, 9, 1);
@@ -163,12 +170,12 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
BigDecimal expectedNumberOfBillingCycles;
expectedNumberOfBillingCycles = ONE.add(FOURTEEN.divide(THIRTY_ONE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD));
BigDecimal expectedAmount = expectedNumberOfBillingCycles.multiply(rate).setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
- assertEquals(invoice.getTotalAmount(), expectedAmount);
+ assertEquals(invoice.getBalance(), expectedAmount);
}
@Test
public void testTwoMonthlySubscriptionsWithAlignedBillingDates() throws InvoiceApiException, CatalogApiException {
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
Plan plan1 = new MockPlan();
BigDecimal rate1 = FIVE;
@@ -192,12 +199,12 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
assertNotNull(invoice);
assertEquals(invoice.getNumberOfItems(), 2);
- assertEquals(invoice.getTotalAmount(), rate1.add(rate2).setScale(NUMBER_OF_DECIMALS));
+ assertEquals(invoice.getBalance(), rate1.add(rate2).setScale(NUMBER_OF_DECIMALS));
}
@Test
public void testOnePlan_TwoMonthlyPhases_ChangeImmediate() throws InvoiceApiException, CatalogApiException {
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
Plan plan1 = new MockPlan();
BigDecimal rate1 = FIVE;
@@ -229,12 +236,12 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
expectedValue = expectedValue.add(numberOfCyclesEvent2.multiply(rate2));
expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
- assertEquals(invoice.getTotalAmount(), expectedValue);
+ assertEquals(invoice.getBalance(), expectedValue);
}
@Test
public void testOnePlan_ThreeMonthlyPhases_ChangeEOT() throws InvoiceApiException, CatalogApiException {
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
Plan plan1 = new MockPlan();
BigDecimal rate1 = FIVE;
@@ -260,12 +267,12 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
assertNotNull(invoice);
assertEquals(invoice.getNumberOfItems(), 4);
- assertEquals(invoice.getTotalAmount(), rate1.add(rate2).add(TWO.multiply(rate3)).setScale(NUMBER_OF_DECIMALS));
+ assertEquals(invoice.getBalance(), rate1.add(rate2).add(TWO.multiply(rate3)).setScale(NUMBER_OF_DECIMALS));
}
@Test
public void testSingleEventWithExistingInvoice() throws InvoiceApiException, CatalogApiException {
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
Subscription sub = createZombieSubscription();
DateTime startDate = buildDateTime(2011, 9, 1);
@@ -289,6 +296,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
assertNull(invoice2);
}
+ // TODO: modify this test to keep a running total of expected invoice amount over time
@Test
public void testMultiplePlansWithUtterChaos() throws InvoiceApiException, CatalogApiException {
// plan 1: change of phase from trial to discount followed by immediate cancellation; (covers phase change, cancel, pro-ration)
@@ -341,7 +349,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
BigDecimal expectedAmount;
List<Invoice> invoices = new ArrayList<Invoice>();
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
// on 1/5/2011, create subscription 1 (trial)
events.add(createBillingEvent(subscriptionId1, plan1StartDate, plan1, plan1Phase1, 5));
@@ -372,7 +380,8 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
// on 4/29/2011, cancel subscription 1
events.add(createBillingEvent(subscriptionId1, plan1CancelDate, plan1, plan1Phase3, 5));
- expectedAmount = TWELVE.multiply(SIX.divide(THIRTY, NUMBER_OF_DECIMALS, ROUNDING_METHOD)).negate().setScale(NUMBER_OF_DECIMALS);
+ // previous invoices are adjusted; this is the pro-ration amount only
+ expectedAmount = TWELVE.multiply(TWENTY_FOUR.divide(THIRTY, NUMBER_OF_DECIMALS, ROUNDING_METHOD)).setScale(NUMBER_OF_DECIMALS);
testInvoiceGeneration(accountId, events, invoices, plan1CancelDate, 2, expectedAmount);
// on 5/10/2011, invoice subscription 2 (trial)
@@ -417,8 +426,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
// on 7/31/2011, convert subscription 3 to annual
events.add(createBillingEvent(subscriptionId3, plan3UpgradeToAnnualDate, plan3, plan3Phase2, 31));
- expectedAmount = ONE_HUNDRED.subtract(TEN);
- expectedAmount = expectedAmount.add(TEN.multiply(ELEVEN.divide(THIRTY_ONE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD)));
+ expectedAmount = ONE_HUNDRED.add(TEN.multiply(ELEVEN.divide(THIRTY_ONE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD)));
expectedAmount = expectedAmount.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
testInvoiceGeneration(accountId, events, invoices, plan3UpgradeToAnnualDate, 3, expectedAmount);
@@ -442,7 +450,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
// on 10/7/2011, invoice subscription 4 (plan 2), cancel subscription 5
events.add(createBillingEvent(subscriptionId5, plan5CancelDate, plan5, plan5Phase2, 10));
- expectedAmount = TWENTY_FOUR.add(TWENTY.multiply(THREE.divide(THIRTY)).negate().setScale(NUMBER_OF_DECIMALS));
+ expectedAmount = TWENTY_FOUR.add(TWENTY.multiply(TWENTY_SEVEN.divide(THIRTY)).setScale(NUMBER_OF_DECIMALS));
testInvoiceGeneration(accountId, events, invoices, plan5CancelDate, 3, expectedAmount);
// on 10/10/2011, invoice plan 2 (evergreen)
@@ -454,7 +462,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
public void testZeroDollarEvents() throws InvoiceApiException, CatalogApiException {
Plan plan = new MockPlan();
PlanPhase planPhase = createMockMonthlyPlanPhase(ZERO);
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
DateTime targetDate = buildDateTime(2011, 1, 1);
events.add(createBillingEvent(UUID.randomUUID(), targetDate, plan, planPhase, 1));
@@ -467,7 +475,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
public void testEndDateIsCorrect() throws InvoiceApiException, CatalogApiException {
Plan plan = new MockPlan();
PlanPhase planPhase = createMockMonthlyPlanPhase(ZERO);
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
DateTime targetDate = new DateTime();
events.add(createBillingEvent(UUID.randomUUID(), targetDate, plan, planPhase, targetDate.getDayOfMonth()));
@@ -492,7 +500,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
DateTime changeDate = new DateTime("2012-04-1T00:00:00.000-08:00");
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
BillingEvent event1 = createMockBillingEvent(null, subscription, new DateTime("2012-01-1T00:00:00.000-08:00"),
plan, phase1,
@@ -529,7 +537,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
BigDecimal fixedCost = TEN;
PlanPhase phase1 = createMockMonthlyPlanPhase(monthlyRate, fixedCost, PhaseType.TRIAL);
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
UUID subscriptionId = UUID.randomUUID();
UUID accountId = UUID.randomUUID();
@@ -541,7 +549,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
Invoice invoice1 = generator.generateInvoice(accountId, events, null, startDate, Currency.USD);
assertNotNull(invoice1);
assertEquals(invoice1.getNumberOfItems(), 2);
- assertEquals(invoice1.getTotalAmount(), FIFTEEN);
+ assertEquals(invoice1.getBalance(), FIFTEEN);
List<Invoice> invoiceList = new ArrayList<Invoice>();
invoiceList.add(invoice1);
@@ -553,7 +561,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, currentDate, Currency.USD);
assertNotNull(invoice2);
assertEquals(invoice2.getNumberOfItems(), 1);
- assertEquals(invoice2.getTotalAmount(), FIVE);
+ assertEquals(invoice2.getBalance(), FIVE);
}
@Test
@@ -565,7 +573,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
PlanPhase phase1 = createMockMonthlyPlanPhase(null, fixedCost1, PhaseType.TRIAL);
PlanPhase phase2 = createMockMonthlyPlanPhase(null, fixedCost2, PhaseType.EVERGREEN);
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
UUID subscriptionId = UUID.randomUUID();
UUID accountId = UUID.randomUUID();
@@ -577,7 +585,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
Invoice invoice1 = generator.generateInvoice(accountId, events, null, startDate, Currency.USD);
assertNotNull(invoice1);
assertEquals(invoice1.getNumberOfItems(), 1);
- assertEquals(invoice1.getTotalAmount(), fixedCost1);
+ assertEquals(invoice1.getBalance(), fixedCost1);
List<Invoice> invoiceList = new ArrayList<Invoice>();
invoiceList.add(invoice1);
@@ -591,12 +599,12 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, phaseChangeDate, Currency.USD);
assertNotNull(invoice2);
assertEquals(invoice2.getNumberOfItems(), 1);
- assertEquals(invoice2.getTotalAmount(), fixedCost2);
+ assertEquals(invoice2.getBalance(), fixedCost2);
}
@Test
- public void testNutsFailure() throws InvoiceApiException, CatalogApiException {
- BillingEventSet events = new BillingEventSet();
+ public void testInvoiceGenerationFailureScenario() throws InvoiceApiException, CatalogApiException {
+ BillingEventSet events = new MockBillingEventSet();
UUID subscriptionId = UUID.randomUUID();
UUID accountId = UUID.randomUUID();
final int BILL_CYCLE_DAY = 15;
@@ -623,7 +631,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
Invoice invoice1 = generator.generateInvoice(accountId, events, null, creationDate, Currency.USD);
assertNotNull(invoice1);
assertEquals(invoice1.getNumberOfItems(), 1);
- assertEquals(invoice1.getTotalAmount().compareTo(ZERO), 0);
+ assertEquals(invoice1.getBalance().compareTo(ZERO), 0);
List<Invoice> invoiceList = new ArrayList<Invoice>();
invoiceList.add(invoice1);
@@ -632,7 +640,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
assertNotNull(invoice2);
assertEquals(invoice2.getNumberOfItems(), 1);
assertEquals(invoice2.getInvoiceItems().get(0).getStartDate().compareTo(trialPhaseEndDate), 0);
- assertEquals(invoice2.getTotalAmount().compareTo(new BigDecimal("3.21")), 0);
+ assertEquals(invoice2.getBalance().compareTo(new BigDecimal("3.21")), 0);
invoiceList.add(invoice2);
DateTime targetDate = trialPhaseEndDate.toMutableDateTime().dayOfMonth().set(BILL_CYCLE_DAY).toDateTime();
@@ -640,7 +648,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
assertNotNull(invoice3);
assertEquals(invoice3.getNumberOfItems(), 1);
assertEquals(invoice3.getInvoiceItems().get(0).getStartDate().compareTo(targetDate), 0);
- assertEquals(invoice3.getTotalAmount().compareTo(DISCOUNT_PRICE), 0);
+ assertEquals(invoice3.getBalance().compareTo(DISCOUNT_PRICE), 0);
invoiceList.add(invoice3);
targetDate = targetDate.plusMonths(6);
@@ -652,7 +660,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
@Test(expectedExceptions = {InvoiceApiException.class})
public void testTargetDateRestrictionFailure() throws InvoiceApiException, CatalogApiException {
DateTime targetDate = DateTime.now().plusMonths(60);
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
Plan plan1 = new MockPlan();
PlanPhase phase1 = createMockMonthlyPlanPhase(null, ZERO, PhaseType.TRIAL);
events.add(createBillingEvent(UUID.randomUUID(), DateTime.now(), plan1, phase1, 1));
@@ -706,9 +714,10 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
Invoice invoice = generator.generateInvoice(accountId, events, existingInvoices, targetDate, currency);
assertNotNull(invoice);
assertEquals(invoice.getNumberOfItems(), expectedNumberOfItems);
-
existingInvoices.add(invoice);
- assertEquals(invoice.getTotalAmount(), expectedAmount);
+
+ distributeItems(existingInvoices);
+ assertEquals(invoice.getBalance(), expectedAmount);
}
@Test
@@ -725,14 +734,14 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
MockInternationalPrice price20 = new MockInternationalPrice(new DefaultPrice(TWENTY, Currency.USD));
PlanPhase basePlanEvergreen = new MockPlanPhase(price10, null, BillingPeriod.MONTHLY, PhaseType.EVERGREEN);
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
events.add(createBillingEvent(baseSubscription.getId(), april25, basePlan, basePlanEvergreen, 25));
// generate invoice
Invoice invoice1 = generator.generateInvoice(accountId, events, null, april25, Currency.USD);
assertNotNull(invoice1);
assertEquals(invoice1.getNumberOfItems(), 1);
- assertEquals(invoice1.getTotalAmount().compareTo(TEN), 0);
+ assertEquals(invoice1.getBalance().compareTo(TEN), 0);
List<Invoice> invoices = new ArrayList<Invoice>();
invoices.add(invoice1);
@@ -754,11 +763,11 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
invoices.add(invoice2);
assertNotNull(invoice2);
assertEquals(invoice2.getNumberOfItems(), 2);
- assertEquals(invoice2.getTotalAmount().compareTo(TWENTY_FIVE.multiply(new BigDecimal("0.9")).setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD)), 0);
+ assertEquals(invoice2.getBalance().compareTo(TWENTY_FIVE.multiply(new BigDecimal("0.9")).setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD)), 0);
// perform a repair (change base plan; remove one add-on)
// event stream should include just two plans
- BillingEventSet newEvents = new BillingEventSet();
+ MockBillingEventSet newEvents = new MockBillingEventSet();
Plan basePlan2 = new MockPlan("base plan 2");
MockInternationalPrice price13 = new MockInternationalPrice(new DefaultPrice(THIRTEEN, Currency.USD));
PlanPhase basePlan2Phase = new MockPlanPhase(price13, null, BillingPeriod.MONTHLY, PhaseType.EVERGREEN);
@@ -771,7 +780,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
assertNotNull(invoice3);
assertEquals(invoice3.getNumberOfItems(), 5);
// -4.50 -18 - 10 (to correct the previous 2 invoices) + 4.50 + 13
- assertEquals(invoice3.getTotalAmount().compareTo(FIFTEEN.negate()), 0);
+ assertEquals(invoice3.getBalance().compareTo(FIFTEEN.negate()), 0);
}
@Test
@@ -787,10 +796,11 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
MockInternationalPrice price10 = new MockInternationalPrice(new DefaultPrice(TEN, Currency.USD));
PlanPhase originalPlanEvergreen = new MockPlanPhase(price10, null, BillingPeriod.MONTHLY, PhaseType.EVERGREEN);
- BillingEventSet events = new BillingEventSet();
+ BillingEventSet events = new MockBillingEventSet();
events.add(createBillingEvent(originalSubscription.getId(), april25, originalPlan, originalPlanEvergreen, 25));
Invoice invoice1 = generator.generateInvoice(accountId, events, null, april25, Currency.USD);
+ assertEquals(invoice1.getNumberOfItems(), 1);
List<Invoice> invoices = new ArrayList<Invoice>();
invoices.add(invoice1);
@@ -808,41 +818,120 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
// generate a new invoice
Invoice invoice2 = generator.generateInvoice(accountId, events, invoices, april25, Currency.USD);
+ assertEquals(invoice2.getNumberOfItems(), 4);
invoices.add(invoice2);
// move items to the correct invoice (normally, the dao calls will sort that out)
- generator.distributeItems(invoices);
+ distributeItems(invoices);
// ensure that the original invoice balance is zero
-
assertEquals(invoice1.getBalance().compareTo(ZERO), 0);
// ensure that the account balance is correct
- assertEquals(invoice2.getBalance().compareTo(FIVE.negate()), 0);
+ assertEquals(invoice2.getBalance().compareTo(ZERO), 0);
+ // ensure that the account has a credit balance
+ BigDecimal creditBalance = invoice1.getAmountCredited().add(invoice2.getAmountCredited());
+ assertTrue(creditBalance.compareTo(FIVE) == 0);
}
- /*
- test scenario: create invoice, pay invoice, change entitlement (repair)
+ private void distributeItems(List<Invoice> invoices) {
+ Map<UUID, Invoice> invoiceMap = new HashMap<UUID, Invoice>();
- test scenario: two subscriptions, one with auto_invoice_off
+ for (Invoice invoice : invoices) {
+ invoiceMap.put(invoice.getId(), invoice);
+ }
- test scenario: create invoice, pay invoice, change entitlement, generate invoices to use up credits
+ for (final Invoice invoice: invoices) {
+ Iterator<InvoiceItem> itemIterator = invoice.getInvoiceItems().iterator();
+ final UUID invoiceId = invoice.getId();
- test scenario: create invoice, pay invoice, add account-level credit, generate invoice
+ while (itemIterator.hasNext()) {
+ InvoiceItem item = itemIterator.next();
-
- */
+ if (!item.getInvoiceId().equals(invoiceId)) {
+ Invoice thisInvoice = invoiceMap.get(item.getInvoiceId());
+ if (thisInvoice == null) {
+ throw new NullPointerException();
+ }
+ thisInvoice.addInvoiceItem(item);
+ itemIterator.remove();
+ }
+ }
+ }
+ }
@Test
- public void testAutoInvoiceOff() {
- BillingEventSet eventSet = new BillingEventSet();
- fail();
+ public void testAutoInvoiceOffAccount() throws Exception {
+ MockBillingEventSet events = new MockBillingEventSet();
+ events.setAccountInvoiceOff(true);
+
+ Subscription sub = createZombieSubscription();
+ DateTime startDate = buildDateTime(2011, 9, 1);
+
+ Plan plan = new MockPlan();
+ BigDecimal rate1 = TEN;
+ PlanPhase phase = createMockMonthlyPlanPhase(rate1);
+
+ BillingEvent event = createBillingEvent(sub.getId(), startDate, plan, phase, 1);
+ events.add(event);
+
+ DateTime targetDate = buildDateTime(2011, 10, 3);
+ UUID accountId = UUID.randomUUID();
+ Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+
+ assertNull(invoice);
}
+
+ public void testAutoInvoiceOffWithCredits() throws CatalogApiException, InvoiceApiException {
+ Currency currency = Currency.USD;
+ List<Invoice> invoices = new ArrayList<Invoice>();
+ MockBillingEventSet eventSet = new MockBillingEventSet();
+ UUID accountId = UUID.randomUUID();
+
+ DateTime startDate = new DateTime(2012, 1, 1, 0, 12, 34, 0);
+
+ // add first subscription creation event
+ UUID subscriptionId1 = UUID.randomUUID();
+ Plan plan1 = new MockPlan();
+ PlanPhase plan1phase1 = createMockMonthlyPlanPhase(FIFTEEN, null, PhaseType.DISCOUNT);
+ BillingEvent subscription1creation = createBillingEvent(subscriptionId1, startDate, plan1, plan1phase1, 1);
+ eventSet.add(subscription1creation);
+
+ // add second subscription creation event
+ UUID subscriptionId2 = UUID.randomUUID();
+ Plan plan2 = new MockPlan();
+ PlanPhase plan2phase1 = createMockMonthlyPlanPhase(TWELVE, null, PhaseType.EVERGREEN);
+ eventSet.add(createBillingEvent(subscriptionId2, startDate, plan2, plan2phase1, 1));
+
+ // generate the first invoice
+ Invoice invoice1 = generator.generateInvoice(accountId, eventSet, invoices, startDate, currency);
+ assertNotNull(invoice1);
+ assertTrue(invoice1.getBalance().compareTo(FIFTEEN.add(TWELVE)) == 0);
+ invoices.add(invoice1);
- @Test(enabled = false)
+ // set auto invoice off for first subscription (i.e. remove event from BillingEventSet and add subscription id to the list
+ // generate invoice
+ eventSet.remove(subscription1creation);
+ eventSet.addSubscriptionWithAutoInvoiceOff(subscriptionId1);
+
+ DateTime targetDate2 = startDate.plusMonths(1);
+ Invoice invoice2 = generator.generateInvoice(accountId, eventSet, invoices, targetDate2, currency);
+ assertNotNull(invoice2);
+ assertTrue(invoice2.getBalance().compareTo(TWELVE) == 0);
+ invoices.add(invoice2);
+
+ DateTime targetDate3 = targetDate2.plusMonths(1);
+ eventSet.clearSubscriptionsWithAutoInvoiceOff();
+ eventSet.add(subscription1creation);
+ Invoice invoice3 = generator.generateInvoice(accountId, eventSet, invoices, targetDate3, currency);
+ assertNotNull(invoice3);
+ assertTrue(invoice3.getBalance().compareTo(FIFTEEN.multiply(TWO).add(TWELVE)) == 0);
+ }
+
+ @Test
public void testAccountCredit() throws CatalogApiException, InvoiceApiException {
- BillingEventSet billingEventSet = new BillingEventSet();
+ BillingEventSet billingEventSet = new MockBillingEventSet();
DateTime startDate = new DateTime(2012, 3, 1, 0, 0, 0, 0);
UUID accountId = UUID.randomUUID();
@@ -853,9 +942,24 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
BillingEvent creation = createBillingEvent(subscriptionId, startDate, plan, planPhase, 1);
billingEventSet.add(creation);
- Invoice invoice = generator.generateInvoice(accountId, billingEventSet, null, startDate, Currency.USD);
- assertNotNull(invoice);
- assertEquals(invoice.getNumberOfItems(), 1);
- assertEquals(invoice.getTotalAmount().compareTo(TEN), 0);
+ List<Invoice> invoices = new ArrayList<Invoice>();
+
+ Invoice initialInvoice = generator.generateInvoice(accountId, billingEventSet, null, startDate, Currency.USD);
+ assertNotNull(initialInvoice);
+ assertEquals(initialInvoice.getNumberOfItems(), 1);
+ assertEquals(initialInvoice.getBalance().compareTo(TEN), 0);
+ invoices.add(initialInvoice);
+
+ // add account-level credit
+ DateTime creditDate = startDate.plusDays(5);
+ Invoice invoiceWithCredit = new DefaultInvoice(accountId, creditDate, creditDate, Currency.USD);
+ InvoiceItem accountCredit = new CreditInvoiceItem(invoiceWithCredit.getId(), accountId, creditDate, FIVE, Currency.USD);
+ invoiceWithCredit.addInvoiceItem(accountCredit);
+ invoices.add(invoiceWithCredit);
+
+ // invoice one month after the initial subscription
+ Invoice finalInvoice = generator.generateInvoice(accountId, billingEventSet, invoices, startDate.plusMonths(1), Currency.USD);
+ assertEquals(finalInvoice.getBalance().compareTo(FIVE), 0);
+ assertEquals(finalInvoice.getNumberOfItems(), 2);
}
}
\ No newline at end of file
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/InvoicingTestBase.java b/invoice/src/test/java/com/ning/billing/invoice/tests/InvoicingTestBase.java
index 25be5e2..5beea5c 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/InvoicingTestBase.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/InvoicingTestBase.java
@@ -62,6 +62,7 @@ public abstract class InvoicingTestBase {
protected static final BigDecimal TWENTY_FOUR = new BigDecimal("24.0").setScale(NUMBER_OF_DECIMALS);
protected static final BigDecimal TWENTY_FIVE = new BigDecimal("25.0").setScale(NUMBER_OF_DECIMALS);
+ protected static final BigDecimal TWENTY_SEVEN = new BigDecimal("27.0").setScale(NUMBER_OF_DECIMALS);
protected static final BigDecimal TWENTY_EIGHT = new BigDecimal("28.0").setScale(NUMBER_OF_DECIMALS);
protected static final BigDecimal TWENTY_NINE = new BigDecimal("29.0").setScale(NUMBER_OF_DECIMALS);
protected static final BigDecimal THIRTY = new BigDecimal("30.0").setScale(NUMBER_OF_DECIMALS);
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJson.java
index ae9220f..2d0eab4 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJson.java
@@ -181,7 +181,7 @@ public class AccountJson extends AccountJsonSimple {
public AccountJson(@JsonProperty("accountId") String accountId,
@JsonProperty("name") String name,
@JsonProperty("firstNameLength") Integer length,
- @JsonProperty("external_key") String externalKey,
+ @JsonProperty("externalKey") String externalKey,
@JsonProperty("email") String email,
@JsonProperty("billingDay") Integer billCycleDay,
@JsonProperty("currency") String currency,
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
index 2b573c1..0afc104 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
@@ -25,7 +25,6 @@ import java.util.UUID;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonView;
-
import com.ning.billing.account.api.Account;
import com.ning.billing.entitlement.api.timeline.BundleTimeline;
import com.ning.billing.invoice.api.Invoice;
@@ -40,20 +39,21 @@ public class AccountTimelineJson {
private final List<InvoiceJsonWithBundleKeys> invoices;
private final AccountJsonSimple account;
-
+
+
private final List<BundleJsonWithSubscriptions> bundles;
-
+
@JsonCreator
public AccountTimelineJson(@JsonProperty("account") AccountJsonSimple account,
@JsonProperty("bundles") List<BundleJsonWithSubscriptions> bundles,
- @JsonProperty("invoices") List<InvoiceJsonWithBundleKeys> invoices,
+ @JsonProperty("invoices") List<InvoiceJsonWithBundleKeys> invoices,
@JsonProperty("payments") List<PaymentJsonWithBundleKeys> payments) {
this.account = account;
this.bundles = bundles;
this.invoices = invoices;
this.payments = payments;
}
-
+
private String getBundleExternalKey(UUID invoiceId, List<Invoice> invoices, List<BundleTimeline> bundles) {
for (Invoice cur : invoices) {
if (cur.getId().equals(invoiceId)) {
@@ -62,7 +62,7 @@ public class AccountTimelineJson {
}
return null;
}
-
+
private String getBundleExternalKey(Invoice invoice, List<BundleTimeline> bundles) {
Set<UUID> b = new HashSet<UUID>();
for (final InvoiceItem cur : invoice.getInvoiceItems()) {
@@ -84,21 +84,26 @@ public class AccountTimelineJson {
}
return tmp.toString();
}
-
+
public AccountTimelineJson(Account account, List<Invoice> invoices, List<Payment> payments, List<BundleTimeline> bundles) {
this.account = new AccountJsonSimple(account.getId().toString(), account.getExternalKey());
this.bundles = new LinkedList<BundleJsonWithSubscriptions>();
for (BundleTimeline cur : bundles) {
- this.bundles.add(new BundleJsonWithSubscriptions(account.getId(), cur));
+ this.bundles.add(new BundleJsonWithSubscriptions(account.getId(), cur));
}
this.invoices = new LinkedList<InvoiceJsonWithBundleKeys>();
for (Invoice cur : invoices) {
- this.invoices.add(new InvoiceJsonWithBundleKeys(cur.getTotalAmount(), cur.getId().toString(), cur.getInvoiceDate(), cur.getTargetDate(),
- Integer.toString(cur.getInvoiceNumber()), cur.getBalance(),
- getBundleExternalKey(cur, bundles)));
+ this.invoices.add(new InvoiceJsonWithBundleKeys(cur.getAmountPaid(),
+ cur.getAmountCredited(),
+ cur.getId().toString(),
+ cur.getInvoiceDate(),
+ cur.getTargetDate(),
+ Integer.toString(cur.getInvoiceNumber()),
+ cur.getBalance(),
+ cur.getAccountId().toString(),
+ getBundleExternalKey(cur, bundles)));
}
this.payments = new LinkedList<PaymentJsonWithBundleKeys>();
-
for (Payment cur : payments) {
String status = cur.getPaymentStatus().toString();
@@ -110,7 +115,7 @@ public class AccountTimelineJson {
getBundleExternalKey(cur.getInvoiceId(), invoices, bundles)));
}
}
-
+
public AccountTimelineJson() {
this.account = null;
this.bundles = null;
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/ChargebackCollectionJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/ChargebackCollectionJson.java
new file mode 100644
index 0000000..3da8e81
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/ChargebackCollectionJson.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+
+public class ChargebackCollectionJson {
+ private final String accountId;
+ private final List<ChargebackJson> chargebacks;
+
+ @JsonCreator
+ public ChargebackCollectionJson(@JsonProperty("accountId") final String accountId,
+ @JsonProperty("chargebacks") final List<ChargebackJson> chargebacks) {
+ this.accountId = accountId;
+ this.chargebacks = chargebacks;
+ }
+
+ public String getAccountId() {
+ return accountId;
+ }
+
+ public List<ChargebackJson> getChargebacks() {
+ return chargebacks;
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/ChargebackJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/ChargebackJson.java
new file mode 100644
index 0000000..071f971
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/ChargebackJson.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ning.billing.invoice.api.InvoicePayment;
+import org.joda.time.DateTime;
+
+import java.math.BigDecimal;
+
+// TODO: populate reason code, requested date from audit log
+public class ChargebackJson {
+ private final DateTime requestedDate;
+ private final DateTime effectiveDate;
+ private final BigDecimal chargebackAmount;
+ private final String paymentId;
+ private final String reason;
+
+ @JsonCreator
+ public ChargebackJson(@JsonProperty("requestedDate") DateTime requestedDate,
+ @JsonProperty("effectiveDate") DateTime effectiveDate,
+ @JsonProperty("chargebackAmount") BigDecimal chargebackAmount,
+ @JsonProperty("paymentId") String paymentId,
+ @JsonProperty("reason") String reason) {
+ this.requestedDate = requestedDate;
+ this.effectiveDate = effectiveDate;
+ this.chargebackAmount = chargebackAmount;
+ this.paymentId = paymentId;
+ this.reason = reason;
+ }
+
+ public ChargebackJson(InvoicePayment chargeback) {
+ this.requestedDate = null;
+ this.effectiveDate = chargeback.getPaymentAttemptDate();
+ this.chargebackAmount = chargeback.getAmount().negate();
+ this.paymentId = chargeback.getReversedInvoicePaymentId().toString();
+ this.reason = null;
+
+ }
+
+ public DateTime getRequestedDate() {
+ return requestedDate;
+ }
+
+ public DateTime getEffectiveDate() {
+ return effectiveDate;
+ }
+
+ public BigDecimal getChargebackAmount() {
+ return chargebackAmount;
+ }
+
+ public String getPaymentId() {
+ return paymentId;
+ }
+
+ public String getReason() {
+ return reason;
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CreditCollectionJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CreditCollectionJson.java
new file mode 100644
index 0000000..66f4d0c
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CreditCollectionJson.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+import java.util.UUID;
+
+public class CreditCollectionJson {
+ private final UUID accountId;
+ private final List<CreditJson> credits;
+
+ @JsonCreator
+ public CreditCollectionJson(@JsonProperty("accountId") final UUID accountId,
+ @JsonProperty("credits") final List<CreditJson> credits) {
+ this.accountId = accountId;
+ this.credits = credits;
+ }
+
+ public UUID getAccountId() {
+ return accountId;
+ }
+
+ public List<CreditJson> getCredits() {
+ return credits;
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CreditJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CreditJson.java
new file mode 100644
index 0000000..bea3cf4
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CreditJson.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ning.billing.invoice.api.InvoiceItem;
+import org.joda.time.DateTime;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+// TODO: add invoice number, reason and requested date to the json
+public class CreditJson {
+ private final BigDecimal creditAmount;
+ private final UUID invoiceId;
+ private final String invoiceNumber;
+ private final DateTime requestedDate;
+ private final DateTime effectiveDate;
+ private final String reason;
+
+ @JsonCreator
+ public CreditJson(@JsonProperty("creditAmount") final BigDecimal creditAmount,
+ @JsonProperty("invoiceId") final UUID invoiceId,
+ @JsonProperty("invoiceNumber") final String invoiceNumber,
+ @JsonProperty("requestedDate") final DateTime requestedDate,
+ @JsonProperty("effectiveDate") final DateTime effectiveDate,
+ @JsonProperty("reason") final String reason) {
+ this.creditAmount = creditAmount;
+ this.invoiceId = invoiceId;
+ this.invoiceNumber = invoiceNumber;
+ this.requestedDate = requestedDate;
+ this.effectiveDate = effectiveDate;
+ this.reason = reason;
+ }
+
+ public CreditJson(InvoiceItem credit) {
+ this.creditAmount = credit.getAmount();
+ this.invoiceId = credit.getInvoiceId();
+ this.invoiceNumber = null;
+ this.requestedDate = null;
+ this.effectiveDate = credit.getStartDate();
+ this.reason = null;
+ }
+
+ public BigDecimal getCreditAmount() {
+ return creditAmount;
+ }
+
+ public UUID getInvoiceId() {
+ return invoiceId;
+ }
+
+ public String getInvoiceNumber() {
+ return invoiceNumber;
+ }
+
+ public DateTime getRequestedDate() {
+ return requestedDate;
+ }
+
+ public DateTime getEffectiveDate() {
+ return effectiveDate;
+ }
+
+ public String getReason() {
+ return reason;
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceItemJsonSimple.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceItemJsonSimple.java
new file mode 100644
index 0000000..e3011f3
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceItemJsonSimple.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.InvoiceItem;
+
+public class InvoiceItemJsonSimple {
+ private final UUID invoiceId;
+ private final UUID accountId;
+ private final UUID bundleId;
+ private final UUID subscriptionId;
+ private final String planName;
+ private final String phaseName;
+ private final String description;
+ private final DateTime startDate;
+ private final DateTime endDate;
+ private final BigDecimal amount;
+ private final Currency currency;
+
+ public InvoiceItemJsonSimple(@JsonProperty("invoiceId") UUID invoiceId,
+ @JsonProperty("accountId") UUID accountId,
+ @JsonProperty("bundleId") UUID bundleId,
+ @JsonProperty("subscriptionId") UUID subscriptionId,
+ @JsonProperty("planName") String planName,
+ @JsonProperty("phaseName") String phaseName,
+ @JsonProperty("description") String description,
+ @JsonProperty("startDate") DateTime startDate,
+ @JsonProperty("endDate") DateTime endDate,
+ @JsonProperty("amount") BigDecimal amount,
+ @JsonProperty("currency") Currency currency) {
+ this.invoiceId = invoiceId;
+ this.accountId = accountId;
+ this.bundleId = bundleId;
+ this.subscriptionId = subscriptionId;
+ this.planName = planName;
+ this.phaseName = phaseName;
+ this.description = description;
+ this.startDate = startDate;
+ this.endDate = endDate;
+ this.amount = amount;
+ this.currency = currency;
+ }
+
+ public InvoiceItemJsonSimple(InvoiceItem item) {
+ this.invoiceId = item.getInvoiceId();
+ this.accountId = item.getAccountId();
+ this.bundleId = item.getBundleId();
+ this.subscriptionId = item.getSubscriptionId();
+ this.planName = item.getPlanName();
+ this.phaseName = item.getPhaseName();
+ this.description = item.getDescription();
+ this.startDate = item.getStartDate();
+ this.endDate = item.getEndDate();
+ this.amount = item.getAmount();
+ this.currency = item.getCurrency();
+ }
+
+ public UUID getInvoiceId() {
+ return invoiceId;
+ }
+
+ public UUID getAccountId() {
+ return accountId;
+ }
+
+ public UUID getBundleId() {
+ return bundleId;
+ }
+
+ public UUID getSubscriptionId() {
+ return subscriptionId;
+ }
+
+ public String getPlanName() {
+ return planName;
+ }
+
+ public String getPhaseName() {
+ return phaseName;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public DateTime getStartDate() {
+ return startDate;
+ }
+
+ public DateTime getEndDate() {
+ return endDate;
+ }
+
+ public BigDecimal getAmount() {
+ return amount;
+ }
+
+ public Currency getCurrency() {
+ return currency;
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonSimple.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonSimple.java
index 1f4100b..0921030 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonSimple.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonSimple.java
@@ -18,66 +18,73 @@ package com.ning.billing.jaxrs.json;
import java.math.BigDecimal;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonView;
import org.joda.time.DateTime;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.ning.billing.invoice.api.Invoice;
public class InvoiceJsonSimple {
private final BigDecimal amount;
-
private final String invoiceId;
-
private final DateTime invoiceDate;
-
private final DateTime targetDate;
-
private final String invoiceNumber;
-
+ private final BigDecimal credit;
private final BigDecimal balance;
+ private final String accountId;
-
public InvoiceJsonSimple() {
- this.amount = null;
+ this.amount = BigDecimal.ZERO;
+ this.credit = BigDecimal.ZERO;
this.invoiceId = null;
this.invoiceDate = null;
- this.targetDate = null;
+ this.targetDate = null;
this.invoiceNumber = null;
- this.balance = null;
+ this.balance = BigDecimal.ZERO;
+ this.accountId = null;
}
-
+
@JsonCreator
public InvoiceJsonSimple(@JsonProperty("amount") BigDecimal amount,
- @JsonProperty("invoiceId") String invoiceId,
- @JsonProperty("invoiceDate") DateTime invoiceDate,
- @JsonProperty("targetDate") DateTime targetDate,
- @JsonProperty("invoiceNumber") String invoiceNumber,
- @JsonProperty("balance") BigDecimal balance) {
+ @JsonProperty("credit") BigDecimal credit,
+ @JsonProperty("invoiceId") String invoiceId,
+ @JsonProperty("invoiceDate") DateTime invoiceDate,
+ @JsonProperty("targetDate") DateTime targetDate,
+ @JsonProperty("invoiceNumber") String invoiceNumber,
+ @JsonProperty("balance") BigDecimal balance,
+ @JsonProperty("accountId") String accountId) {
super();
this.amount = amount;
+ this.credit = credit;
this.invoiceId = invoiceId;
this.invoiceDate = invoiceDate;
this.targetDate = targetDate;
this.invoiceNumber = invoiceNumber;
this.balance = balance;
+ this.accountId = accountId;
}
public InvoiceJsonSimple(Invoice input) {
- this.amount = input.getTotalAmount();
+ this.amount = input.getAmountCharged();
+ this.credit = input.getAmountCredited();
this.invoiceId = input.getId().toString();
this.invoiceDate = input.getInvoiceDate();
this.targetDate = input.getTargetDate();
this.invoiceNumber = String.valueOf(input.getInvoiceNumber());
this.balance = input.getBalance();
+ this.accountId = input.getAccountId().toString();
}
-
+
public BigDecimal getAmount() {
return amount;
}
+ public BigDecimal getCredit() {
+ return credit;
+ }
+
public String getInvoiceId() {
return invoiceId;
}
@@ -98,12 +105,17 @@ public class InvoiceJsonSimple {
return balance;
}
+ public String getAccountId() {
+ return accountId;
+ }
+
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((amount == null) ? 0 : amount.hashCode());
result = prime * result + ((balance == null) ? 0 : balance.hashCode());
+ result = prime * result + ((credit == null) ? 0 : credit.hashCode());
result = prime * result
+ ((invoiceDate == null) ? 0 : invoiceDate.hashCode());
result = prime * result
@@ -127,26 +139,43 @@ public class InvoiceJsonSimple {
return false;
} else if (!amount.equals(other.amount))
return false;
+
if (balance == null) {
if (other.balance != null)
return false;
} else if (!balance.equals(other.balance))
return false;
+
+ if (credit == null) {
+ if (other.credit != null)
+ return false;
+ } else if (!credit.equals(other.credit))
+ return false;
+
if (invoiceDate == null) {
if (other.invoiceDate != null)
return false;
} else if (!invoiceDate.equals(other.invoiceDate))
return false;
+
if (invoiceId == null) {
if (other.invoiceId != null)
return false;
} else if (!invoiceId.equals(other.invoiceId))
return false;
+
if (invoiceNumber == null) {
if (other.invoiceNumber != null)
return false;
} else if (!invoiceNumber.equals(other.invoiceNumber))
return false;
+
+ if (accountId == null) {
+ if (other.accountId != null)
+ return false;
+ } else if (!accountId.equals(other.accountId))
+ return false;
+
return true;
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonWithBundleKeys.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonWithBundleKeys.java
index 98e2844..da3ccf4 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonWithBundleKeys.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonWithBundleKeys.java
@@ -1,13 +1,13 @@
package com.ning.billing.jaxrs.json;
import java.math.BigDecimal;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
import org.joda.time.DateTime;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.ning.billing.invoice.api.Invoice;
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
@@ -24,25 +24,24 @@ import com.ning.billing.invoice.api.Invoice;
*/
public class InvoiceJsonWithBundleKeys extends InvoiceJsonSimple {
-
-
private final String bundleKeys;
-
public InvoiceJsonWithBundleKeys() {
super();
this.bundleKeys = null;
}
-
+
@JsonCreator
public InvoiceJsonWithBundleKeys(@JsonProperty("amount") BigDecimal amount,
- @JsonProperty("invoiceId") String invoiceId,
- @JsonProperty("invoiceDate") DateTime invoiceDate,
- @JsonProperty("targetDate") DateTime targetDate,
- @JsonProperty("invoiceNumber") String invoiceNumber,
- @JsonProperty("balance") BigDecimal balance,
- @JsonProperty("externalBundleKeys") String bundleKeys) {
- super(amount, invoiceId, invoiceDate, targetDate, invoiceNumber, balance);
+ @JsonProperty("credit") BigDecimal credit,
+ @JsonProperty("invoiceId") String invoiceId,
+ @JsonProperty("invoiceDate") DateTime invoiceDate,
+ @JsonProperty("targetDate") DateTime targetDate,
+ @JsonProperty("invoiceNumber") String invoiceNumber,
+ @JsonProperty("balance") BigDecimal balance,
+ @JsonProperty("accountId") String accountId,
+ @JsonProperty("externalBundleKeys") String bundleKeys) {
+ super(amount, credit, invoiceId, invoiceDate, targetDate, invoiceNumber, balance, accountId);
this.bundleKeys = bundleKeys;
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonWithItems.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonWithItems.java
new file mode 100644
index 0000000..b68d34d
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonWithItems.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.joda.time.DateTime;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceItem;
+
+public class InvoiceJsonWithItems extends InvoiceJsonSimple {
+ private final List<InvoiceItemJsonSimple> items;
+
+ @JsonCreator
+ public InvoiceJsonWithItems(@JsonProperty("amount") BigDecimal amount,
+ @JsonProperty("credit") BigDecimal credit,
+ @JsonProperty("invoiceId") String invoiceId,
+ @JsonProperty("invoiceDate") DateTime invoiceDate,
+ @JsonProperty("targetDate") DateTime targetDate,
+ @JsonProperty("invoiceNumber") String invoiceNumber,
+ @JsonProperty("balance") BigDecimal balance,
+ @JsonProperty("accountId") String accountId,
+ @JsonProperty("items") List<InvoiceItemJsonSimple> items) {
+ super(amount, credit, invoiceId, invoiceDate, targetDate, invoiceNumber, balance, accountId);
+ this.items = new ArrayList<InvoiceItemJsonSimple>(items);
+ }
+
+ public InvoiceJsonWithItems(Invoice input) {
+ super(input);
+ this.items = new ArrayList<InvoiceItemJsonSimple>(input.getInvoiceItems().size());
+ for (InvoiceItem item : input.getInvoiceItems()) {
+ this.items.add(new InvoiceItemJsonSimple(item));
+ }
+ }
+
+ public List<InvoiceItemJsonSimple> getItems() {
+ return Collections.unmodifiableList(items);
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonSimple.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonSimple.java
index c9ccd59..1eafded 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonSimple.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonSimple.java
@@ -19,11 +19,10 @@ package com.ning.billing.jaxrs.json;
import java.math.BigDecimal;
import java.util.UUID;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonView;
import org.joda.time.DateTime;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.ning.billing.payment.api.Payment;
import com.ning.billing.payment.api.PaymentInfoEvent;
import com.ning.billing.util.clock.DefaultClock;
@@ -41,15 +40,15 @@ public class PaymentJsonSimple {
private final String paymentId;
private final DateTime requestedDate;
-
+
private final DateTime effectiveDate;
-
+
private final Integer retryCount;
-
+
private final String currency;
-
+
private final String status;
-
+
public PaymentJsonSimple() {
this.amount = null;
this.paidAmount = null;
@@ -72,7 +71,7 @@ public class PaymentJsonSimple {
@JsonProperty("requestedDate") DateTime requestedDate,
@JsonProperty("effectiveDate") DateTime effectiveDate,
@JsonProperty("retryCount") Integer retryCount,
- @JsonProperty("currency") String currency,
+ @JsonProperty("currency") String currency,
@JsonProperty("status") String status) {
super();
this.amount = amount;
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonWithBundleKeys.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonWithBundleKeys.java
index 839f70d..8f9cf08 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonWithBundleKeys.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonWithBundleKeys.java
@@ -19,14 +19,15 @@ package com.ning.billing.jaxrs.json;
import java.math.BigDecimal;
import java.util.UUID;
+import org.joda.time.DateTime;
+
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
-import org.joda.time.DateTime;
public class PaymentJsonWithBundleKeys extends PaymentJsonSimple {
private final String bundleKeys;
-
+
public PaymentJsonWithBundleKeys() {
super();
this.bundleKeys = null;
@@ -41,13 +42,14 @@ public class PaymentJsonWithBundleKeys extends PaymentJsonSimple {
@JsonProperty("requestedDt") DateTime requestedDate,
@JsonProperty("effectiveDt") DateTime effectiveDate,
@JsonProperty("retryCount") Integer retryCount,
- @JsonProperty("currency") String currency,
+ @JsonProperty("currency") String currency,
@JsonProperty("status") String status,
@JsonProperty("externalBundleKeys") String bundleKeys) {
super(amount, paidAmount, accountId, invoiceId, paymentId, requestedDate, effectiveDate, retryCount, currency, status);
+
this.bundleKeys = bundleKeys;
}
-
+
public String getBundleKeys() {
return bundleKeys;
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PlanDetailJason.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PlanDetailJason.java
new file mode 100644
index 0000000..7474315
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PlanDetailJason.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.InternationalPrice;
+import com.ning.billing.catalog.api.Listing;
+
+public class PlanDetailJason {
+
+ final String productName;
+ final String planName;
+ final BillingPeriod billingPeriod;
+ final String priceListName;
+ final InternationalPrice finalPhasePrice;
+ public PlanDetailJason(
+ @JsonProperty("product") String productName,
+ @JsonProperty("plan") String planName,
+ @JsonProperty("final_phase_billing_period") BillingPeriod billingPeriod,
+ @JsonProperty("priceList") String priceListName,
+ @JsonProperty("final_phase_recurring_price") InternationalPrice finalPhasePrice
+ ) {
+ this.productName = productName;
+ this.planName = planName;
+ this.billingPeriod = billingPeriod;
+ this.priceListName = priceListName;
+ this.finalPhasePrice = finalPhasePrice;
+ }
+
+ public PlanDetailJason(Listing listing) {
+ this.productName = listing.getPlan().getProduct().getName();
+ this.planName = listing.getPlan().getName();
+ this.billingPeriod = listing.getPlan().getBillingPeriod();
+ this.priceListName = listing.getPriceList().getName();
+ this.finalPhasePrice = listing.getPlan().getFinalPhase().getRecurringPrice();
+ }
+
+ public String getProductName() {
+ return productName;
+ }
+
+ public String getPlanName() {
+ return planName;
+ }
+
+ public BillingPeriod getBillingPeriod() {
+ return billingPeriod;
+ }
+
+ public String getPriceListName() {
+ return priceListName;
+ }
+
+ public InternationalPrice getFinalPhasePrice() {
+ return finalPhasePrice;
+ }
+
+
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/CatalogResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/CatalogResource.java
new file mode 100644
index 0000000..ec6e5c0
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/CatalogResource.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.APPLICATION_XML;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.Listing;
+import com.ning.billing.catalog.api.StaticCatalog;
+import com.ning.billing.jaxrs.json.PlanDetailJason;
+import com.ning.billing.util.config.XMLWriter;
+
+@Singleton
+@Path(JaxrsResource.CATALOG_PATH)
+public class CatalogResource implements JaxrsResource {
+
+ private CatalogService catalogService;
+
+ @Inject
+ public CatalogResource(final CatalogService catalogService)
+ {
+ this.catalogService = catalogService;
+ }
+
+ @GET
+ @Produces(APPLICATION_XML)
+ public Response getCatalog() throws Exception {
+ return Response.status(Status.OK).entity(XMLWriter.writeXML((StaticCatalog) catalogService.getCurrentCatalog(), StaticCatalog.class)).build();
+ }
+
+ // Need to figure out dependency on StandaloneCatalog
+ // @GET
+ // @Path("/xsd")
+ // @Produces(APPLICATION_XML)
+ // public String getCatalogXsd() throws Exception
+ // {
+ // InputStream stream = XMLSchemaGenerator.xmlSchema(StandaloneCatalog.class);
+ // StringWriter writer = new StringWriter();
+ // IOUtils.copy(stream, writer);
+ // String result = writer.toString();
+ //
+ // return result;
+ // }
+
+
+
+ @GET
+ @Path("/availableAddons")
+ @Produces(APPLICATION_JSON)
+ public Response getAvailableAddons(@QueryParam("baseProductName") final String baseProductName) throws CatalogApiException {
+ StaticCatalog catalog = catalogService.getCurrentCatalog();
+ List<Listing> listings = catalog.getAvailableAddonListings(baseProductName);
+ List<PlanDetailJason> details = new ArrayList<PlanDetailJason>();
+ for(Listing listing : listings) {
+ details.add(new PlanDetailJason(listing));
+ }
+ return Response.status(Status.OK).entity(details).build();
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/ChargebackResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/ChargebackResource.java
new file mode 100644
index 0000000..b1b63ec
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/ChargebackResource.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.UUID;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.ning.billing.invoice.api.InvoiceApiException;
+import com.ning.billing.invoice.api.InvoicePayment;
+import com.ning.billing.invoice.api.InvoicePaymentApi;
+import com.ning.billing.jaxrs.json.ChargebackCollectionJson;
+import com.ning.billing.jaxrs.json.ChargebackJson;
+import com.ning.billing.jaxrs.util.Context;
+import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
+import com.ning.billing.payment.api.Payment;
+import com.ning.billing.payment.api.Payment.PaymentAttempt;
+import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
+import com.ning.billing.payment.api.PaymentStatus;
+
+@Singleton
+@Path(JaxrsResource.CHARGEBACKS_PATH)
+public class ChargebackResource implements JaxrsResource {
+ private static final Logger log = LoggerFactory.getLogger(ChargebackResource.class);
+
+ private final JaxrsUriBuilder uriBuilder;
+ private final InvoicePaymentApi invoicePaymentApi;
+ private final PaymentApi paymentApi;
+ private final Context context;
+
+ @Inject
+ public ChargebackResource(final JaxrsUriBuilder uriBuilder,
+ final InvoicePaymentApi invoicePaymentApi,
+ final PaymentApi paymentApi,
+ final Context context) {
+ this.uriBuilder = uriBuilder;
+ this.invoicePaymentApi = invoicePaymentApi;
+ this.paymentApi = paymentApi;
+ this.context = context;
+ }
+
+ @GET
+ @Path("/{chargebackId:" + UUID_PATTERN + "}")
+ @Produces(APPLICATION_JSON)
+ public Response getChargeback(@PathParam("chargebackId") String chargebackId) {
+ try {
+ InvoicePayment chargeback = invoicePaymentApi.getChargebackById(UUID.fromString(chargebackId));
+ ChargebackJson chargebackJson = new ChargebackJson(chargeback);
+
+ return Response.status(Response.Status.OK).entity(chargebackJson).build();
+ } catch (InvoiceApiException e) {
+ final String error = String.format("Failed to locate chargeback for id %s", chargebackId);
+ log.info(error, e);
+ return Response.status(Response.Status.NO_CONTENT).build();
+ }
+ }
+
+ @GET
+ @Path("/accounts/{accountId:" + UUID_PATTERN + "}")
+ @Produces(APPLICATION_JSON)
+ public Response getForAccount(@PathParam("accountId") String accountId) {
+ List<InvoicePayment> chargebacks = invoicePaymentApi.getChargebacksByAccountId(UUID.fromString(accountId));
+ List<ChargebackJson> chargebacksJson = convertToJson(chargebacks);
+
+ ChargebackCollectionJson json = new ChargebackCollectionJson(accountId, chargebacksJson);
+ return Response.status(Response.Status.OK).entity(json).build();
+ }
+
+ @GET
+ @Path("/payments/{paymentId:" + UUID_PATTERN + "}")
+ @Produces(APPLICATION_JSON)
+ public Response getForPayment(@PathParam("paymentId") String paymentId) {
+
+ try {
+ Payment payment = paymentApi.getPayment(UUID.fromString(paymentId));
+ Collection<PaymentAttempt> attempts = Collections2.filter(payment.getAttempts(), new Predicate<PaymentAttempt>() {
+ @Override
+ public boolean apply(PaymentAttempt input) {
+ return input.getPaymentStatus() == PaymentStatus.SUCCESS;
+ }
+ });
+ if (attempts.size() == 0) {
+ final String error = String.format("Failed to locate succesful payment attempts for paymentId %s", paymentId);
+ return Response.status(Response.Status.NO_CONTENT).entity(error).build();
+ }
+ UUID paymentAttemptId = attempts.iterator().next().getId();
+
+ List<InvoicePayment> chargebacks = invoicePaymentApi.getChargebacksByPaymentAttemptId(paymentAttemptId);
+ List<ChargebackJson> chargebacksJson = convertToJson(chargebacks);
+
+ String accountId = invoicePaymentApi.getAccountIdFromInvoicePaymentId(UUID.fromString(paymentId)).toString();
+
+ ChargebackCollectionJson json = new ChargebackCollectionJson(accountId, chargebacksJson);
+ return Response.status(Response.Status.OK).entity(json).build();
+
+ } catch (PaymentApiException e) {
+ final String error = String.format("Failed to locate payment attempt for payment id %s", paymentId);
+ return Response.status(Response.Status.NO_CONTENT).entity(error).build();
+ } catch (InvoiceApiException e) {
+ final String error = String.format("Failed to locate account for payment id %s", paymentId);
+ return Response.status(Response.Status.NO_CONTENT).entity(error).build();
+ }
+ }
+
+ @POST
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Response createChargeback(final ChargebackJson json,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
+ try {
+ invoicePaymentApi.processChargeback(UUID.fromString(json.getPaymentId()), json.getChargebackAmount(),
+ context.createContext(createdBy, reason, comment));
+ return uriBuilder.buildResponse(ChargebackResource.class, "getChargeback", json.getPaymentId());
+ } catch (InvoiceApiException e) {
+ final String error = String.format("Failed to create chargeback %s", json);
+ log.info(error, e);
+ return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
+ } catch (IllegalArgumentException e) {
+ return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();
+ }
+ }
+
+ private List<ChargebackJson> convertToJson(List<InvoicePayment> chargebacks) {
+ List<ChargebackJson> result = new ArrayList<ChargebackJson>();
+ for (InvoicePayment chargeback : chargebacks) {
+ result.add(new ChargebackJson(chargeback));
+ }
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/CreditResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/CreditResource.java
index 076dbff..226457e 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/CreditResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/CreditResource.java
@@ -16,6 +16,123 @@
package com.ning.billing.jaxrs.resources;
-public class CreditResource {
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import java.util.UUID;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.invoice.api.InvoiceApiException;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.jaxrs.json.CreditJson;
+import com.ning.billing.jaxrs.util.Context;
+import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
+
+@Singleton
+@Path(JaxrsResource.CREDITS_PATH)
+public class CreditResource implements JaxrsResource {
+ private static final Logger log = LoggerFactory.getLogger(CreditResource.class);
+
+ private final JaxrsUriBuilder uriBuilder;
+ private final InvoiceUserApi invoiceUserApi;
+ private final AccountUserApi accountUserApi;
+ private final Context context;
+
+ @Inject
+ public CreditResource(JaxrsUriBuilder uriBuilder, InvoiceUserApi invoiceUserApi, AccountUserApi accountUserApi, Context context) {
+ this.uriBuilder = uriBuilder;
+ this.invoiceUserApi = invoiceUserApi;
+ this.accountUserApi = accountUserApi;
+ this.context = context;
+ }
+
+ @GET
+ @Path("/{creditId:" + UUID_PATTERN + "}")
+ @Produces(APPLICATION_JSON)
+ public Response getCredit(@PathParam("creditId") String creditId) {
+ try {
+ InvoiceItem credit = invoiceUserApi.getCreditById(UUID.fromString(creditId));
+ CreditJson creditJson = new CreditJson(credit);
+
+ return Response.status(Response.Status.OK).entity(creditJson).build();
+ } catch (InvoiceApiException e) {
+ final String error = String.format("Failed to locate credit for id %s", creditId);
+ log.info(error, e);
+ return Response.status(Response.Status.NO_CONTENT).build();
+ }
+ }
+
+ @POST
+ @Path("/accounts/{accountId:" + UUID_PATTERN + "}")
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Response createCredit(final CreditJson json,
+ @PathParam("accountId") final String accountId,
+ @HeaderParam(HDR_CREATED_BY) final String createdBy,
+ @HeaderParam(HDR_REASON) final String reason,
+ @HeaderParam(HDR_COMMENT) final String comment) {
+ try {
+ Account account = accountUserApi.getAccountById(UUID.fromString(accountId));
+
+ InvoiceItem credit = invoiceUserApi.insertCredit(account.getId(), json.getCreditAmount(), json.getEffectiveDate(),
+ account.getCurrency(), context.createContext(createdBy, reason, comment));
+
+ return uriBuilder.buildResponse(ChargebackResource.class, "getCredit", credit.getId());
+ } catch (InvoiceApiException e) {
+ final String error = String.format("Failed to create credit %s", json);
+ log.info(error, e);
+ return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
+ } catch (IllegalArgumentException e) {
+ return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();
+ } catch (AccountApiException e) {
+ final String error = String.format("Failed to create credit %s", json);
+ log.info(error, e);
+ return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
+ }
+ }
+
}
+
+
+//POST /1.0/accounts/<account_id>/credits Creates a credit for that account 201 (CREATED), 400 (BAD_REQUEST), 404 (NOT_FOUND)
+//Semantics:
+//
+//All operations are synchronous
+//JSON Credit GET:
+// {
+// "accountId" : "theAccountId",
+// "credits" : [{
+// "requestedDate" : "2012-05-12T15:34:22.000Z",
+// "effectiveDate" : "2012-05-12T15:34:22.000Z",
+// "creditAmount" : 54.32,
+// "invoiceId" : "theInvoiceId",
+// "invoiceNumber" : "TheInvoiceNumber",
+// "reason" : "whatever"
+// }]
+// }
+//
+//JSON Credit POST:
+// {
+// "creditAmount" : 54.32,
+// "reason" : "whatever",
+// "requestedDate" : "2012-05-12T15:34:22.000Z",
+// "invoiceId" : "theInvoiceId",
+// "invoiceNumber" : "TheInvoiceNumber"
+// }
\ No newline at end of file
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
index 46c7a48..b1ab41f 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
@@ -33,15 +33,9 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
-
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
-import com.ning.billing.jaxrs.json.CustomFieldJson;
-import com.ning.billing.jaxrs.util.TagHelper;
-import com.ning.billing.util.api.CustomFieldUserApi;
-import com.ning.billing.util.api.TagUserApi;
-import com.ning.billing.util.dao.ObjectType;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
@@ -56,14 +50,19 @@ import com.ning.billing.account.api.AccountUserApi;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceApiException;
import com.ning.billing.invoice.api.InvoiceUserApi;
-
+import com.ning.billing.jaxrs.json.CustomFieldJson;
import com.ning.billing.jaxrs.json.InvoiceJsonSimple;
+import com.ning.billing.jaxrs.json.InvoiceJsonWithItems;
import com.ning.billing.jaxrs.json.PaymentJsonSimple;
import com.ning.billing.jaxrs.util.Context;
import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
+import com.ning.billing.jaxrs.util.TagHelper;
import com.ning.billing.payment.api.Payment;
import com.ning.billing.payment.api.PaymentApi;
import com.ning.billing.payment.api.PaymentApiException;
+import com.ning.billing.util.api.CustomFieldUserApi;
+import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.dao.ObjectType;
@Path(JaxrsResource.INVOICES_PATH)
@@ -76,13 +75,13 @@ public class InvoiceResource extends JaxRsResourceBase {
private static final String TAG_URI = JaxrsResource.TAGS + "/{" + ID_PARAM_NAME + ":" + UUID_PATTERN + "}";
private final DateTimeFormatter DATE_TIME_FORMATTER = ISODateTimeFormat.dateTime();
-
+
private final AccountUserApi accountApi;
private final InvoiceUserApi invoiceApi;
private final PaymentApi paymentApi;
private final Context context;
private final JaxrsUriBuilder uriBuilder;
-
+
@Inject
public InvoiceResource(final AccountUserApi accountApi,
final InvoiceUserApi invoiceApi,
@@ -99,12 +98,12 @@ public class InvoiceResource extends JaxRsResourceBase {
this.context = context;
this.uriBuilder = uriBuilder;
}
-
+
@GET
@Produces(APPLICATION_JSON)
public Response getInvoices(@QueryParam(QUERY_ACCOUNT_ID) final String accountId) {
try {
-
+
Preconditions.checkNotNull(accountId, "% query parameter must be specified", QUERY_ACCOUNT_ID);
accountApi.getAccountById(UUID.fromString(accountId));
List<Invoice> invoices = invoiceApi.getInvoicesByAccount(UUID.fromString(accountId));
@@ -114,18 +113,18 @@ public class InvoiceResource extends JaxRsResourceBase {
}
return Response.status(Status.OK).entity(result).build();
} catch (AccountApiException e) {
- return Response.status(Status.NO_CONTENT).build();
+ return Response.status(Status.NO_CONTENT).build();
} catch (NullPointerException e) {
- return Response.status(Status.BAD_REQUEST).build();
+ return Response.status(Status.BAD_REQUEST).build();
}
}
@GET
@Path("/{invoiceId:\\w+-\\w+-\\w+-\\w+-\\w+}")
@Produces(APPLICATION_JSON)
- public Response getInvoice(@PathParam("invoiceId") String invoiceId) {
+ public Response getInvoice(@PathParam("invoiceId") String invoiceId, @QueryParam("withItems") @DefaultValue("false") boolean withItems) {
Invoice invoice = invoiceApi.getInvoice(UUID.fromString(invoiceId));
- InvoiceJsonSimple json = new InvoiceJsonSimple(invoice);
+ InvoiceJsonSimple json = withItems ? new InvoiceJsonWithItems(invoice) : new InvoiceJsonSimple(invoice);
return Response.status(Status.OK).entity(json).build();
}
@@ -141,12 +140,12 @@ public class InvoiceResource extends JaxRsResourceBase {
@HeaderParam(HDR_COMMENT) final String comment) {
try {
-
+
Preconditions.checkNotNull(accountId, "% needs to be specified", QUERY_ACCOUNT_ID);
Preconditions.checkNotNull(targetDate, "% needs to be specified", QUERY_TARGET_DATE);
-
- DateTime inputDate = (targetDate != null) ? DATE_TIME_FORMATTER.parseDateTime(targetDate) : null;
-
+
+ DateTime inputDate = (targetDate != null) ? DATE_TIME_FORMATTER.parseDateTime(targetDate) : null;
+
accountApi.getAccountById(UUID.fromString(accountId));
Invoice generatedInvoice = invoiceApi.triggerInvoiceGeneration(UUID.fromString(accountId), inputDate, dryRun.booleanValue(),
context.createContext(createdBy, reason, comment));
@@ -156,11 +155,11 @@ public class InvoiceResource extends JaxRsResourceBase {
return uriBuilder.buildResponse(InvoiceResource.class, "getInvoice", generatedInvoice.getId());
}
} catch (AccountApiException e) {
- return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
} catch (InvoiceApiException e) {
- return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
} catch (NullPointerException e) {
- return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
}
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
index f334d77..b9be27c 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
@@ -75,7 +75,17 @@ public interface JaxrsResource {
public static final String PAYMENTS = "payments";
public static final String PAYMENTS_PATH = PREFIX + "/" + PAYMENTS;
-
+
+ public static final String CREDITS = "credits";
+ public static final String CREDITS_PATH = PREFIX + "/" + CREDITS;
+
+ public static final String CHARGEBACKS = "chargebacks";
+ public static final String CHARGEBACKS_PATH = PREFIX + "/" + CHARGEBACKS;
+
public static final String TAGS = "tags";
public static final String CUSTOM_FIELDS = "custom_fields";
+
+ public static final String CATALOG = "catalog";
+ public static final String CATALOG_PATH = PREFIX + "/" + CATALOG;
+
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java
index f6b7d67..c49616b 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java
@@ -43,7 +43,7 @@ public class Context {
throws IllegalArgumentException {
try {
Preconditions.checkNotNull(createdBy, String.format("Header %s needs to be set", JaxrsResource.HDR_CREATED_BY));
- return contextFactory.createCallContext(createdBy, origin, userType, UUID.randomUUID());
+ return contextFactory.createCallContext(createdBy, origin, userType, reason, comment, UUID.randomUUID());
} catch (NullPointerException e) {
throw new IllegalArgumentException(e.getMessage());
}
junction/pom.xml 19(+12 -7)
diff --git a/junction/pom.xml b/junction/pom.xml
index 4efa966..1824a28 100644
--- a/junction/pom.xml
+++ b/junction/pom.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- ~ Copyright 2010-2011 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. -->
+ 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. -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
@@ -73,6 +73,11 @@
<artifactId>killbill-catalog</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
index 999c5d6..e33c063 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
+import java.util.concurrent.atomic.AtomicLong;
import org.joda.time.DateTime;
@@ -36,12 +37,13 @@ import com.ning.billing.entitlement.api.SubscriptionTransitionType;
import com.ning.billing.entitlement.api.billing.BillingEvent;
import com.ning.billing.entitlement.api.billing.BillingModeType;
import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.junction.api.Blockable;
import com.ning.billing.junction.api.BlockingApi;
import com.ning.billing.junction.api.BlockingState;
import com.ning.billing.junction.api.DefaultBlockingState;
public class BlockingCalculator {
+ private static AtomicLong globaltotalOrder = new AtomicLong();
+
private final BlockingApi blockingApi;
protected static class DisabledDuration {
@@ -196,7 +198,7 @@ public class BlockingCalculator {
final BillingModeType billingModeType = previousEvent.getBillingMode();
final BillingPeriod billingPeriod = previousEvent.getBillingPeriod();
final SubscriptionTransitionType type = SubscriptionTransitionType.CANCEL;
- final Long totalOrdering = 0L; //TODO
+ final Long totalOrdering = globaltotalOrder.getAndIncrement();
return new DefaultBillingEvent(account, subscription, effectiveDate, plan, planPhase,
fixedPrice, recurringPrice, currency,
@@ -218,7 +220,7 @@ public class BlockingCalculator {
final BillingModeType billingModeType = previousEvent.getBillingMode();
final BillingPeriod billingPeriod = previousEvent.getBillingPeriod();
final SubscriptionTransitionType type = SubscriptionTransitionType.RE_CREATE;
- final Long totalOrdering = 0L; //TODO
+ final Long totalOrdering = globaltotalOrder.getAndIncrement();
return new DefaultBillingEvent(account, subscription, effectiveDate, plan, planPhase,
fixedPrice, recurringPrice, currency,
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
index 43e8a2a..6d91e7c 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
@@ -16,7 +16,9 @@
package com.ning.billing.junction.plumbing.billing;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.SortedSet;
import java.util.UUID;
@@ -41,10 +43,14 @@ import com.ning.billing.entitlement.api.user.SubscriptionBundle;
import com.ning.billing.entitlement.api.user.SubscriptionEvent;
import com.ning.billing.junction.api.BillingApi;
import com.ning.billing.junction.api.BillingEventSet;
+import com.ning.billing.util.api.TagUserApi;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallContextFactory;
import com.ning.billing.util.callcontext.CallOrigin;
import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.tag.ControlTagType;
+import com.ning.billing.util.tag.Tag;
public class DefaultBillingApi implements BillingApi {
private static final String API_USER_NAME = "Billing Api";
@@ -56,12 +62,12 @@ public class DefaultBillingApi implements BillingApi {
private final EntitlementUserApi entitlementUserApi;
private final CatalogService catalogService;
private final BlockingCalculator blockCalculator;
-// private final TagUserApi tagApi;
+ private final TagUserApi tagApi;
@Inject
public DefaultBillingApi(final ChargeThruApi chargeThruApi, final CallContextFactory factory, final AccountUserApi accountApi,
final BillCycleDayCalculator bcdCalculator, final EntitlementUserApi entitlementUserApi, final BlockingCalculator blockCalculator,
- final CatalogService catalogService) { //, final TagUserApi tagApi) {
+ final CatalogService catalogService, final TagUserApi tagApi) {
this.chargeThruApi = chargeThruApi;
this.accountApi = accountApi;
@@ -70,53 +76,91 @@ public class DefaultBillingApi implements BillingApi {
this.entitlementUserApi = entitlementUserApi;
this.catalogService = catalogService;
this.blockCalculator = blockCalculator;
- // this.tagApi = tagApi;
+ this.tagApi = tagApi;
}
@Override
- public SortedSet<BillingEvent> getBillingEventsForAccountAndUpdateAccountBCD(final UUID accountId) {
+ public BillingEventSet getBillingEventsForAccountAndUpdateAccountBCD(final UUID accountId) {
CallContext context = factory.createCallContext(API_USER_NAME, CallOrigin.INTERNAL, UserType.SYSTEM);
List<SubscriptionBundle> bundles = entitlementUserApi.getBundlesForAccount(accountId);
- BillingEventSet result = new DefaultBillingEventSet();
+ DefaultBillingEventSet result = new DefaultBillingEventSet();
try {
Account account = accountApi.getAccountById(accountId);
-
-
- for (final SubscriptionBundle bundle: bundles) {
- List<Subscription> subscriptions = entitlementUserApi.getSubscriptionsForBundle(bundle.getId());
-
- for (final Subscription subscription: subscriptions) {
- for (final SubscriptionEvent transition : subscription.getBillingTransitions()) {
- try {
- int bcd = bcdCalculator.calculateBcd(bundle, subscription, transition, account);
-
- if(account.getBillCycleDay() == 0) {
- MutableAccountData modifiedData = account.toMutableAccountData();
- modifiedData.setBillCycleDay(bcd);
- accountApi.updateAccount(account.getExternalKey(), modifiedData, context);
- }
-
- BillingEvent event = new DefaultBillingEvent(account, transition, subscription, bcd, account.getCurrency(), catalogService.getFullCatalog());
- result.add(event);
- } catch (CatalogApiException e) {
- log.error("Failing to identify catalog components while creating BillingEvent from transition: " +
- transition.getId().toString(), e);
- } catch (Exception e) {
- log.warn("Failed while getting BillingEvent", e);
- }
- }
- }
+ // Check to see if billing is off for the account
+ Map<String,Tag> accountTags = tagApi.getTags(accountId,ObjectType.ACCOUNT);
+ if(accountTags.get(ControlTagType.AUTO_INVOICING_OFF.name()) != null) {
+ result.setAccountAutoInvoiceIsOff(true);
+ return result; // billing is off, we are done
}
+
+ addBillingEventsForBundles(bundles, account, context, result);
+
} catch (AccountApiException e) {
log.warn("Failed while getting BillingEvent", e);
}
+
+ debugLog(result, "********* Billing Events Raw");
blockCalculator.insertBlockingEvents(result);
+ debugLog(result,"********* Billing Events After Blocking");
+
return result;
}
+
+
+ private void debugLog(SortedSet<BillingEvent> result, String title) {
+ log.debug(title);
+ Iterator<BillingEvent> i = result.iterator();
+ while(i.hasNext()) {
+ log.debug(i.next().toString());
+ }
+
+ }
+
+ private void addBillingEventsForBundles(List<SubscriptionBundle> bundles, Account account, CallContext context,
+ DefaultBillingEventSet result) {
+
+ for (final SubscriptionBundle bundle: bundles) {
+ List<Subscription> subscriptions = entitlementUserApi.getSubscriptionsForBundle(bundle.getId());
+
+ //Check if billing is off for the bundle
+ Map<String,Tag> bundleTags = tagApi.getTags(bundle.getId(), ObjectType.BUNDLE);
+ if(bundleTags.get(ControlTagType.AUTO_INVOICING_OFF.name()) != null) {
+ for (final Subscription subscription: subscriptions) { // billing is off so list sub ids in set to be excluded
+ result.getSubscriptionIdsWithAutoInvoiceOff().add(subscription.getId());
+ }
+ } else { // billing is not off
+ addBillingEventsForSubscription(subscriptions, bundle, account, context, result);
+ }
+ }
+ }
+
+ private void addBillingEventsForSubscription(List<Subscription> subscriptions, SubscriptionBundle bundle, Account account, CallContext context, DefaultBillingEventSet result) {
+ for (final Subscription subscription: subscriptions) {
+ for (final SubscriptionEvent transition : subscription.getBillingTransitions()) {
+ try {
+ int bcd = bcdCalculator.calculateBcd(bundle, subscription, transition, account);
+ if(account.getBillCycleDay() == 0) {
+ MutableAccountData modifiedData = account.toMutableAccountData();
+ modifiedData.setBillCycleDay(bcd);
+ accountApi.updateAccount(account.getExternalKey(), modifiedData, context);
+ }
+
+ BillingEvent event = new DefaultBillingEvent(account, transition, subscription, bcd, account.getCurrency(), catalogService.getFullCatalog());
+ result.add(event);
+ } catch (CatalogApiException e) {
+ log.error("Failing to identify catalog components while creating BillingEvent from transition: " +
+ transition.getId().toString(), e);
+ } catch (Exception e) {
+ log.warn("Failed while getting BillingEvent", e);
+ }
+
+ }
+ }
+ }
@Override
public UUID getAccountIdFromSubscriptionId(UUID subscriptionId) throws EntitlementBillingApiException {
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEventSet.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEventSet.java
index fdda46c..d26f70b 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEventSet.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEventSet.java
@@ -55,5 +55,17 @@ public class DefaultBillingEventSet extends TreeSet<BillingEvent> implements Sor
this.subscriptionIdsWithAutoInvoiceOff = subscriptionIdsWithAutoInvoiceOff;
}
+ public boolean isLast(final BillingEvent event) {
+ return last() == event;
+ }
+
+ @Override
+ public String toString() {
+ return "DefaultBillingEventSet [accountAutoInvoiceOff=" + accountAutoInvoiceOff
+ + ", subscriptionIdsWithAutoInvoiceOff=" + subscriptionIdsWithAutoInvoiceOff + ", Events="
+ + super.toString() + "]";
+ }
+
+
}
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
index 435ee50..b501c98 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
@@ -556,7 +556,7 @@ public class TestBlockingCalculator {
final BillingModeType billingModeType = BillingModeType.IN_ADVANCE;
final BillingPeriod billingPeriod = BillingPeriod.MONTHLY;
final SubscriptionTransitionType type = SubscriptionTransitionType.CHANGE;
- final Long totalOrdering = 0L; //TODO
+ final Long totalOrdering = 0L;
return new DefaultBillingEvent(account, subscription, effectiveDate, plan, planPhase,
fixedPrice, recurringPrice, currency,
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java
index 9f45075..d13fdef 100644
--- a/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java
@@ -29,6 +29,7 @@ import com.ning.billing.overdue.listener.OverdueListener;
import com.ning.billing.overdue.service.DefaultOverdueService;
import com.ning.billing.util.notificationq.NotificationQueue;
import com.ning.billing.util.notificationq.NotificationQueueService;
+import com.ning.billing.util.notificationq.NotificationQueueService.NoSuchNotificationQueue;
import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueAlreadyExists;
import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
@@ -94,6 +95,11 @@ public class DefaultOverdueCheckNotifier implements OverdueCheckNotifier {
public void stop() {
if (overdueQueue != null) {
overdueQueue.stopQueue();
+ try {
+ notificationQueueService.deleteNotificationQueue(overdueQueue.getServiceName(), overdueQueue.getQueueName());
+ } catch (NoSuchNotificationQueue e) {
+ log.error("Error deleting a queue by its own name - this should never happen", e);
+ }
}
}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
index 958d8b9..cc0acb2 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
@@ -58,7 +58,7 @@ public class OverdueStateApplicator<T extends Blockable>{
}
} catch(OverdueApiException e) {
if(e.getCode() != ErrorCode.OVERDUE_NO_REEVALUATION_INTERVAL.getCode()) {
- new OverdueError(e);
+ throw new OverdueError(e);
}
}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java
index 6d3b967..0abc240 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java
@@ -46,7 +46,7 @@ public class OverdueWrapperFactory {
private final OverdueStateApplicator<SubscriptionBundle> overdueStateApplicatorBundle;
private final BlockingApi api;
private final Clock clock;
- private OverdueStateSet<SubscriptionBundle> overdueStates;
+ private OverdueConfig config;
@Inject
public OverdueWrapperFactory(BlockingApi api, Clock clock,
@@ -64,7 +64,7 @@ public class OverdueWrapperFactory {
public <T extends Blockable> OverdueWrapper<T> createOverdueWrapperFor(T bloackable) throws OverdueError {
if(bloackable instanceof SubscriptionBundle) {
- return (OverdueWrapper<T>)new OverdueWrapper<SubscriptionBundle>((SubscriptionBundle)bloackable, api, overdueStates,
+ return (OverdueWrapper<T>)new OverdueWrapper<SubscriptionBundle>((SubscriptionBundle)bloackable, api, getOverdueStateSetBundle(),
clock, billingStateCalcuatorBundle, overdueStateApplicatorBundle);
} else {
throw new OverdueError(ErrorCode.OVERDUE_TYPE_NOT_SUPPORTED, bloackable.getId(), bloackable.getClass());
@@ -79,7 +79,7 @@ public class OverdueWrapperFactory {
switch (state.getType()) {
case SUBSCRIPTION_BUNDLE : {
SubscriptionBundle bundle = entitlementApi.getBundleFromId(id);
- return (OverdueWrapper<T>) new OverdueWrapper<SubscriptionBundle>(bundle, api, overdueStates,
+ return (OverdueWrapper<T>) new OverdueWrapper<SubscriptionBundle>(bundle, api, getOverdueStateSetBundle(),
clock, billingStateCalcuatorBundle, overdueStateApplicatorBundle );
}
default : {
@@ -92,11 +92,9 @@ public class OverdueWrapperFactory {
}
}
- public void setOverdueConfig(OverdueConfig config) {
- if(config != null) {
- overdueStates = config.getBundleStateSet();
- } else {
- overdueStates = new DefaultOverdueStateSet<SubscriptionBundle>() {
+ private OverdueStateSet<SubscriptionBundle> getOverdueStateSetBundle() {
+ if(config == null || config.getBundleStateSet() == null) {
+ return new DefaultOverdueStateSet<SubscriptionBundle>() {
@SuppressWarnings("unchecked")
@Override
@@ -104,7 +102,13 @@ public class OverdueWrapperFactory {
return new DefaultOverdueState[0];
}
};
+ } else {
+ return config.getBundleStateSet();
}
}
+
+ public void setOverdueConfig(OverdueConfig config) {
+ this.config = config;
+ }
}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/applicator/ApplicatorMockJunctionModule.java b/overdue/src/test/java/com/ning/billing/overdue/applicator/ApplicatorMockJunctionModule.java
index 25721d5..0dcf12e 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/applicator/ApplicatorMockJunctionModule.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/applicator/ApplicatorMockJunctionModule.java
@@ -48,43 +48,37 @@ public class ApplicatorMockJunctionModule extends MockJunctionModule {
@Override
public Type getType() {
- // TODO Auto-generated method stub
+
return null;
}
@Override
public DateTime getTimestamp() {
- // TODO Auto-generated method stub
return null;
}
@Override
public boolean isBlockChange() {
- // TODO Auto-generated method stub
return false;
}
@Override
public boolean isBlockEntitlement() {
- // TODO Auto-generated method stub
return false;
}
@Override
public boolean isBlockBilling() {
- // TODO Auto-generated method stub
return false;
}
@Override
public int compareTo(BlockingState arg0) {
- // TODO Auto-generated method stub
return 0;
}
@Override
public String getDescription() {
- // TODO Auto-generated method stub
return null;
}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/applicator/TestOverdueStateApplicator.java b/overdue/src/test/java/com/ning/billing/overdue/applicator/TestOverdueStateApplicator.java
index e95740a..ca6f682 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/applicator/TestOverdueStateApplicator.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/applicator/TestOverdueStateApplicator.java
@@ -49,7 +49,7 @@ public class TestOverdueStateApplicator extends OverdueTestBase {
@Inject
OverdueStateApplicator<SubscriptionBundle> applicator;
- @Test( groups={"slow"} , enabled = false)
+ @Test( groups={"slow"} , enabled = true)
public void testApplicator() throws Exception {
InputStream is = new ByteArrayInputStream(configXml.getBytes());
config = XMLLoader.getObjectFromStreamNoValidation(is, OverdueConfig.class);
@@ -73,9 +73,6 @@ public class TestOverdueStateApplicator extends OverdueTestBase {
applicator.apply(bundle, BlockingApi.CLEAR_STATE_NAME, state);
checkStateApplied(state);
-
- //TODO
- // Check notification is posted with correct time delay
}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/OverdueTestBase.java b/overdue/src/test/java/com/ning/billing/overdue/OverdueTestBase.java
index f233a9a..55163ca 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/OverdueTestBase.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/OverdueTestBase.java
@@ -22,11 +22,12 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
+import javax.management.RuntimeErrorException;
+
import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
-import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Guice;
@@ -50,12 +51,11 @@ import com.ning.billing.mock.BrainDeadProxyFactory;
import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
import com.ning.billing.mock.glue.MockClockModule;
import com.ning.billing.mock.glue.MockInvoiceModule;
-import com.ning.billing.mock.glue.MockJunctionModule;
import com.ning.billing.mock.glue.MockPaymentModule;
import com.ning.billing.mock.glue.TestDbiModule;
import com.ning.billing.overdue.applicator.ApplicatorMockJunctionModule;
-import com.ning.billing.overdue.applicator.TestOverdueStateApplicator;
import com.ning.billing.overdue.applicator.ApplicatorMockJunctionModule.ApplicatorBlockingApi;
+import com.ning.billing.overdue.applicator.TestOverdueStateApplicator;
import com.ning.billing.overdue.config.OverdueConfig;
import com.ning.billing.overdue.glue.DefaultOverdueModule;
import com.ning.billing.overdue.service.DefaultOverdueService;
@@ -64,6 +64,7 @@ import com.ning.billing.util.bus.BusService;
import com.ning.billing.util.clock.ClockMock;
import com.ning.billing.util.glue.BusModule;
import com.ning.billing.util.glue.NotificationQueueModule;
+import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueAlreadyExists;
//@Guice(modules = {MockJunctionModule.class, MockInvoiceModule.class, DefaultOverdueModule.class})
@Guice( modules = {DefaultOverdueModule.class, MockClockModule.class, ApplicatorMockJunctionModule.class, CatalogModule.class, MockInvoiceModule.class, MockPaymentModule.class, BusModule.class, NotificationQueueModule.class, TestDbiModule.class})
@@ -119,14 +120,14 @@ public class OverdueTestBase {
@Inject
protected BlockingApi blockingApi;
-
+
@Inject
protected OverdueWrapperFactory overdueWrapperFactory;
-
+
@Inject
protected OverdueUserApi overdueApi;
-
-
+
+
@Inject
protected InvoiceUserApi invoiceApi;
@@ -135,7 +136,7 @@ public class OverdueTestBase {
protected String productName;
protected BillingPeriod term;
protected String planSetName;
-
+
@Inject
EntitlementUserApi entitlementApi;
@@ -153,13 +154,19 @@ public class OverdueTestBase {
helper.initDb(utilDdl);
}
-
+
@BeforeClass(groups = "slow")
public void setup() throws Exception{
setupMySQL();
service.registerForBus();
- service.initialize();
+ try {
+ service.initialize();
+ }catch (RuntimeException e) {
+ if(!(e.getCause() instanceof NotificationQueueAlreadyExists)) {
+ throw e;
+ }
+ }
service.start();
}
@@ -198,11 +205,12 @@ public class OverdueTestBase {
UUID bundleId = UUID.randomUUID();
((ZombieControl)bundle).addResult("getId", bundleId);
((ZombieControl)bundle).addResult("getAccountId", UUID.randomUUID());
-
+
Invoice invoice = BrainDeadProxyFactory.createBrainDeadProxyFor(Invoice.class);
((ZombieControl)invoice).addResult("getInvoiceDate",dateOfLastUnPaidInvoice);
((ZombieControl)invoice).addResult("getBalance",BigDecimal.TEN);
((ZombieControl)invoice).addResult("getId",UUID.randomUUID());
+ ((ZombieControl)invoice).addResult("hashCode", UUID.randomUUID().hashCode());
InvoiceItem item = BrainDeadProxyFactory.createBrainDeadProxyFor(InvoiceItem.class);
((ZombieControl)item).addResult("getBundleId",bundleId);
@@ -210,18 +218,18 @@ public class OverdueTestBase {
items.add(item);
((ZombieControl)invoice).addResult("getInvoiceItems",items);
-
+
List<Invoice> invoices = new ArrayList<Invoice>();
invoices.add(invoice);
((ZombieControl)invoiceApi).addResult("getUnpaidInvoicesByAccountId", invoices);
-
-
+
+
Subscription base = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
((ZombieControl)base).addResult("getCurrentPlan", MockPlan.createBicycleNoTrialEvergreen1USD());
((ZombieControl)base).addResult("getCurrentPriceList", new MockPriceList());
((ZombieControl)base).addResult("getCurrentPhase", MockPlan.createBicycleNoTrialEvergreen1USD().getFinalPhase());
((ZombieControl)entitlementApi).addResult("getBaseSubscription", base);
-
+
return bundle;
}
}
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
index 69c5cbf..fa52399 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
@@ -22,6 +22,7 @@ import java.util.Set;
import java.util.UUID;
import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
import com.ning.billing.account.api.Account;
import com.ning.billing.payment.core.AccountProcessor;
import com.ning.billing.payment.core.PaymentMethodProcessor;
@@ -49,9 +50,6 @@ public class DefaultPaymentApi implements PaymentApi {
this.refundProcessor = refundProcessor;
}
-
-
-
@Override
public Payment createPayment(final String accountKey, final UUID invoiceId, final BigDecimal amount, final CallContext context)
throws PaymentApiException {
@@ -64,6 +62,14 @@ public class DefaultPaymentApi implements PaymentApi {
return paymentProcessor.createPayment(account, invoiceId, amount, context, true);
}
+ @Override
+ public Payment getPayment(UUID paymentId) throws PaymentApiException {
+ Payment payment = paymentProcessor.getPayment(paymentId);
+ if (payment == null) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT, paymentId);
+ }
+ return payment;
+ }
@Override
public List<Payment> getInvoicePayments(UUID invoiceId) {
@@ -144,5 +150,4 @@ public class DefaultPaymentApi implements PaymentApi {
throws PaymentApiException {
methodProcessor.setDefaultPaymentMethod(account, paymentMethodId);
}
-
}
diff --git a/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
index a2d2bd1..88ab7ad 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
@@ -19,6 +19,7 @@ import static com.ning.billing.payment.glue.PaymentModule.PLUGIN_EXECUTOR_NAMED;
import java.math.BigDecimal;
import java.math.RoundingMode;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
@@ -101,7 +102,11 @@ public class PaymentProcessor extends ProcessorBase {
this.voidPluginDispatcher = new PluginDispatcher<Void>(executor);
}
+ public Payment getPayment(UUID paymentId) {
+ return getPayments(Collections.singletonList(paymentDao.getPayment(paymentId))).get(0);
+ }
+
public List<Payment> getInvoicePayments(UUID invoiceId) {
return getPayments(paymentDao.getPaymentsForInvoice(invoiceId));
}
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
index 6ff1ae8..e8a49d4 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
@@ -19,6 +19,7 @@ import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;
+
import org.skife.jdbi.v2.IDBI;
import org.skife.jdbi.v2.Transaction;
import org.skife.jdbi.v2.TransactionStatus;
@@ -26,8 +27,11 @@ import org.skife.jdbi.v2.TransactionStatus;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.inject.Inject;
+import com.ning.billing.payment.api.PaymentApiException;
+import com.ning.billing.payment.api.PaymentInfoEvent;
import com.ning.billing.payment.api.PaymentStatus;
import com.ning.billing.payment.retry.PluginFailureRetryService.PluginFailureRetryServiceScheduler;
+
import com.ning.billing.util.ChangeType;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.dao.EntityAudit;
@@ -273,13 +277,8 @@ public class AuditedPaymentDao implements PaymentDao {
return paymentSqlDao.getPaymentsForAccount(accountId.toString());
}
-
-
@Override
public List<PaymentAttemptModelDao> getAttemptsForPayment(UUID paymentId) {
return paymentAttemptSqlDao.getPaymentAttempts(paymentId.toString());
}
-
-
-
}
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptSqlDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptSqlDao.java
index 8932594..b1b53d6 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptSqlDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptSqlDao.java
@@ -15,12 +15,14 @@
*/
package com.ning.billing.payment.dao;
+
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.UUID;
+
import org.joda.time.DateTime;
import org.skife.jdbi.v2.SQLStatement;
import org.skife.jdbi.v2.StatementContext;
@@ -71,7 +73,6 @@ public interface PaymentAttemptSqlDao extends Transactional<PaymentAttemptSqlDao
void insertHistoryFromTransaction(@PaymentAttemptHistoryBinder final EntityHistory<PaymentAttemptModelDao> payment,
@CallContextBinder final CallContext context);
-
public static final class PaymentAttemptModelDaoBinder extends BinderBase implements Binder<Bind, PaymentAttemptModelDao> {
@Override
public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, PaymentAttemptModelDao attempt) {
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
index 11c4a8e..b0db533 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
@@ -76,6 +76,7 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, UpdatableEn
@CallContextBinder final CallContext context);
+
public static final class PaymentModelDaoBinder extends BinderBase implements Binder<Bind, PaymentModelDao> {
@Override
public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, PaymentModelDao payment) {
@@ -98,7 +99,7 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, UpdatableEn
UUID id = getUUID(rs, "id");
UUID accountId = getUUID(rs, "account_id");
UUID invoiceId = getUUID(rs, "invoice_id");
- UUID paymentMethodId = null; //getUUID(rs, "payment_method_id");
+ UUID paymentMethodId = null; //getUUID(rs, "payment_method_id"); // STEPH needs to be fixed!
Integer paymentNumber = rs.getInt("payment_number");
BigDecimal amount = rs.getBigDecimal("amount");
DateTime effectiveDate = getDate(rs, "effective_date");
@@ -109,3 +110,4 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, UpdatableEn
}
}
}
+
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/DefaultPaymentProviderPluginRegistry.java b/payment/src/main/java/com/ning/billing/payment/provider/DefaultPaymentProviderPluginRegistry.java
index 3c7f9f0..c762e93 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/DefaultPaymentProviderPluginRegistry.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/DefaultPaymentProviderPluginRegistry.java
@@ -28,6 +28,7 @@ import com.ning.billing.payment.plugin.api.PaymentPluginApi;
public class DefaultPaymentProviderPluginRegistry implements PaymentProviderPluginRegistry {
+
private final String defaultPlugin;
private final Map<String, PaymentPluginApi> pluginsByName = new ConcurrentHashMap<String, PaymentPluginApi>();
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java b/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
index b9605c2..63f11f6 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
@@ -45,8 +45,8 @@ public class NoOpPaymentProviderPlugin implements PaymentPluginApi {
@Override
public PaymentInfoPlugin processPayment(final String externalAccountKey, final UUID paymentId, final BigDecimal amount)
throws PaymentPluginApiException {
+
PaymentInfoPlugin paymentResult = new PaymentInfoPlugin() {
-
@Override
public DateTime getEffectiveDate() {
return null;
diff --git a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentAttemptSqlDao.sql.stg b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentAttemptSqlDao.sql.stg
index 174b349..89b76b1 100644
--- a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentAttemptSqlDao.sql.stg
+++ b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentAttemptSqlDao.sql.stg
@@ -52,6 +52,12 @@ getRecordId() ::= <<
WHERE id = :id;
>>
+getPaymentAttemptIdFromPaymentId() ::= <<
+ SELECT id
+ FROM payment_attempts
+ WHERE payment_id = :paymentId;
+>>
+
historyFields(prefix) ::= <<
<prefix>record_id,
<prefix>id,
diff --git a/payment/src/test/java/com/ning/billing/payment/MockInvoice.java b/payment/src/test/java/com/ning/billing/payment/MockInvoice.java
index d195b59..802b49a 100644
--- a/payment/src/test/java/com/ning/billing/payment/MockInvoice.java
+++ b/payment/src/test/java/com/ning/billing/payment/MockInvoice.java
@@ -23,6 +23,7 @@ import java.util.UUID;
import javax.annotation.Nullable;
+import com.ning.billing.invoice.api.InvoiceItemType;
import org.joda.time.DateTime;
import com.ning.billing.catalog.api.Currency;
@@ -178,23 +179,37 @@ public class MockInvoice extends EntityBase implements Invoice {
}
@Override
- public BigDecimal getTotalAmount() {
+ public BigDecimal getAmountCharged() {
BigDecimal result = BigDecimal.ZERO;
for(InvoiceItem i : invoiceItems) {
- result = result.add(i.getAmount());
+ if (!i.getInvoiceItemType().equals(InvoiceItemType.CREDIT)) {
+ result = result.add(i.getAmount());
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public BigDecimal getAmountCredited() {
+ BigDecimal result = BigDecimal.ZERO;
+
+ for(InvoiceItem i : invoiceItems) {
+ if (i.getInvoiceItemType().equals(InvoiceItemType.CREDIT)) {
+ result = result.add(i.getAmount());
+ }
}
return result;
}
@Override
public BigDecimal getBalance() {
- return getTotalAmount().subtract(getAmountPaid());
+ return getAmountCharged().subtract(getAmountPaid().subtract(getAmountCredited()));
}
@Override
public boolean isDueForPayment(final DateTime targetDate, final int numberOfDays) {
- if (getTotalAmount().compareTo(BigDecimal.ZERO) == 0) {
+ if (getBalance().compareTo(BigDecimal.ZERO) == 0) {
return false;
}
diff --git a/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java b/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java
index 93c90fa..e55c7e4 100644
--- a/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java
+++ b/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java
@@ -18,6 +18,7 @@ package com.ning.billing.payment;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoiceItemType;
import com.ning.billing.util.entity.EntityBase;
import org.apache.commons.lang.NotImplementedException;
@@ -151,6 +152,12 @@ public class MockRecurringInvoiceItem extends EntityBase implements InvoiceItem
public Currency getCurrency() {
return currency;
}
+
+ @Override
+ public InvoiceItemType getInvoiceItemType() {
+ return InvoiceItemType.RECURRING;
+ }
+
@Override
public InvoiceItem asReversingItem() {
throw new NotImplementedException();
pom.xml 20(+13 -7)
diff --git a/pom.xml b/pom.xml
index 2801091..f516c7a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,11 +1,11 @@
<!-- ~ Copyright 2010-2011 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. -->
+ 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. -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
@@ -344,6 +344,12 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>com.samskivert</groupId>
<artifactId>jmustache</artifactId>
<version>1.5</version>
diff --git a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
index b21195f..68b2f28 100644
--- a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
+++ b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
@@ -16,9 +16,6 @@
package com.ning.billing.server.modules;
-import com.ning.billing.util.email.EmailModule;
-import com.ning.billing.util.email.templates.TemplateModule;
-import com.ning.billing.util.glue.GlobalLockerModule;
import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.IDBI;
@@ -31,17 +28,22 @@ import com.ning.billing.entitlement.glue.DefaultEntitlementModule;
import com.ning.billing.invoice.glue.DefaultInvoiceModule;
import com.ning.billing.jaxrs.resources.AccountResource;
import com.ning.billing.jaxrs.resources.BundleResource;
+import com.ning.billing.jaxrs.resources.CatalogResource;
import com.ning.billing.jaxrs.resources.InvoiceResource;
import com.ning.billing.jaxrs.resources.SubscriptionResource;
import com.ning.billing.jaxrs.resources.TagResource;
import com.ning.billing.jaxrs.util.KillbillEventHandler;
import com.ning.billing.jaxrs.util.TagHelper;
import com.ning.billing.junction.glue.DefaultJunctionModule;
+
import com.ning.billing.payment.glue.PaymentModule;
+import com.ning.billing.util.email.EmailModule;
+import com.ning.billing.util.email.templates.TemplateModule;
import com.ning.billing.util.glue.BusModule;
import com.ning.billing.util.glue.CallContextModule;
import com.ning.billing.util.glue.ClockModule;
import com.ning.billing.util.glue.CustomFieldModule;
+import com.ning.billing.util.glue.GlobalLockerModule;
import com.ning.billing.util.glue.NotificationQueueModule;
import com.ning.billing.util.glue.TagStoreModule;
import com.ning.jetty.jdbi.guice.providers.DBIProvider;
@@ -67,6 +69,7 @@ public class KillbillServerModule extends AbstractModule
bind(SubscriptionResource.class).asEagerSingleton();
bind(InvoiceResource.class).asEagerSingleton();
bind(TagResource.class).asEagerSingleton();
+ bind(CatalogResource.class).asEagerSingleton();
bind(KillbillEventHandler.class).asEagerSingleton();
}
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
index cc78462..ee4cd87 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
@@ -111,7 +111,7 @@ public class TestJaxrsBase {
protected ClockMock clock;
protected TestApiListener busHandler;
- // Context informtation to be passed around
+ // Context information to be passed around
private static final String createdBy = "Toto";
private static final String reason = "i am god";
private static final String comment = "no comment";
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestTag.java b/server/src/test/java/com/ning/billing/jaxrs/TestTag.java
index da8318f..6248357 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestTag.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestTag.java
@@ -23,8 +23,6 @@ import java.util.List;
import javax.ws.rs.core.Response.Status;
import com.ning.billing.jaxrs.resources.JaxrsResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.testng.annotations.Test;
import com.fasterxml.jackson.core.type.TypeReference;
@@ -32,13 +30,10 @@ import com.ning.billing.jaxrs.json.TagDefinitionJson;
import com.ning.http.client.Response;
public class TestTag extends TestJaxrsBase {
-
- private static final Logger log = LoggerFactory.getLogger(TestTag.class);
-
@Test(groups="slow", enabled=true)
public void testTagDefinitionOk() throws Exception {
- TagDefinitionJson input = new TagDefinitionJson("blue", "realxing color");
+ TagDefinitionJson input = new TagDefinitionJson("blue", "relaxing color");
String baseJson = mapper.writeValueAsString(input);
Response response = doPost(JaxrsResource.TAG_DEFINITIONS_PATH, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
@@ -66,7 +61,7 @@ public class TestTag extends TestJaxrsBase {
List<TagDefinitionJson> objFromJson = mapper.readValue(baseJson, new TypeReference<List<TagDefinitionJson>>() {});
int sizeSystemTag = (objFromJson == null || objFromJson.size() == 0) ? 0 : objFromJson.size();
- TagDefinitionJson input = new TagDefinitionJson("blue", "realxing color");
+ TagDefinitionJson input = new TagDefinitionJson("blue", "relaxing color");
baseJson = mapper.writeValueAsString(input);
response = doPost(JaxrsResource.TAG_DEFINITIONS_PATH, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
@@ -81,7 +76,7 @@ public class TestTag extends TestJaxrsBase {
response = doPost(JaxrsResource.TAG_DEFINITIONS_PATH, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
- input = new TagDefinitionJson("green", "super realxing color");
+ input = new TagDefinitionJson("green", "super relaxing color");
baseJson = mapper.writeValueAsString(input);
response = doPost(JaxrsResource.TAG_DEFINITIONS_PATH, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/CallContextFactory.java b/util/src/main/java/com/ning/billing/util/callcontext/CallContextFactory.java
index d9f18c9..3194c02 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/CallContextFactory.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/CallContextFactory.java
@@ -22,7 +22,10 @@ import org.joda.time.DateTime;
public interface CallContextFactory {
CallContext createCallContext(String userName, CallOrigin callOrigin, UserType userType, UUID userToken);
-
+
+ CallContext createCallContext(String userName, CallOrigin callOrigin, UserType userType,
+ String reasonCode, String comment, UUID userToken);
+
CallContext createCallContext(String userName, CallOrigin callOrigin, UserType userType);
CallContext createMigrationCallContext(String userName, CallOrigin callOrigin, UserType userType, DateTime createdDate, DateTime updatedDate);
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContext.java b/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContext.java
index 4cde143..4bb7c24 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContext.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContext.java
@@ -22,7 +22,6 @@ import com.ning.billing.util.clock.Clock;
import org.joda.time.DateTime;
public class DefaultCallContext extends CallContextBase {
-
private final Clock clock;
public DefaultCallContext(final String userName, final CallOrigin callOrigin, final UserType userType, final UUID userToken, final Clock clock) {
@@ -30,6 +29,13 @@ public class DefaultCallContext extends CallContextBase {
this.clock = clock;
}
+ public DefaultCallContext(final String userName, final CallOrigin callOrigin, final UserType userType,
+ final String reasonCode, final String comment,
+ final UUID userToken, final Clock clock) {
+ super(userName, callOrigin, userType, reasonCode, comment, userToken);
+ this.clock = clock;
+ }
+
public DefaultCallContext(String userName, CallOrigin callOrigin, UserType userType, Clock clock) {
this(userName, callOrigin, userType, null, clock);
}
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContextFactory.java b/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContextFactory.java
index 52ac313..53b5ba1 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContextFactory.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/DefaultCallContextFactory.java
@@ -22,6 +22,8 @@ import com.google.inject.Inject;
import com.ning.billing.util.clock.Clock;
import org.joda.time.DateTime;
+import javax.annotation.Nullable;
+
public class DefaultCallContextFactory implements CallContextFactory {
private final Clock clock;
@@ -31,11 +33,18 @@ public class DefaultCallContextFactory implements CallContextFactory {
}
@Override
- public CallContext createCallContext(String userName, CallOrigin callOrigin, UserType userType, UUID userToken) {
+ public CallContext createCallContext(String userName, CallOrigin callOrigin, UserType userType,
+ @Nullable UUID userToken) {
return new DefaultCallContext(userName, callOrigin, userType, userToken, clock);
}
@Override
+ public CallContext createCallContext(String userName, CallOrigin callOrigin, UserType userType,
+ String reasonCode, String comment, UUID userToken) {
+ return new DefaultCallContext(userName, callOrigin, userType, reasonCode, comment, userToken, clock);
+ }
+
+ @Override
public CallContext createCallContext(String userName, CallOrigin callOrigin, UserType userType) {
return createCallContext(userName, callOrigin, userType, null);
}
diff --git a/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java b/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java
index ba7084c..6c09c85 100644
--- a/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java
+++ b/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java
@@ -53,7 +53,7 @@ public abstract class AuditedCollectionDaoBase<T extends Entity> implements Audi
entityIterator.remove();
existingEntityIterator.remove();
- // if the entities have the same hashcode (e.g. same data), don't bother updating
+ // if the entities have the same hash code (e.g. same data), don't bother updating
if (entity.hashCode() != existingEntity.hashCode()) {
entitiesToUpdate.add(entity);
}
diff --git a/util/src/main/java/com/ning/billing/util/dao/BinderBase.java b/util/src/main/java/com/ning/billing/util/dao/BinderBase.java
index ef20575..df36442 100644
--- a/util/src/main/java/com/ning/billing/util/dao/BinderBase.java
+++ b/util/src/main/java/com/ning/billing/util/dao/BinderBase.java
@@ -19,9 +19,18 @@ package com.ning.billing.util.dao;
import org.joda.time.DateTime;
import java.util.Date;
+import java.util.UUID;
public abstract class BinderBase {
protected Date getDate(DateTime dateTime) {
return dateTime == null ? null : dateTime.toDate();
}
+
+ protected String uuidToString(UUID uuid) {
+ if (uuid == null) {
+ return null;
+ } else {
+ return uuid.toString();
+ }
+ }
}
diff --git a/util/src/main/java/com/ning/billing/util/dao/TableName.java b/util/src/main/java/com/ning/billing/util/dao/TableName.java
index 28fa045..98ec80d 100644
--- a/util/src/main/java/com/ning/billing/util/dao/TableName.java
+++ b/util/src/main/java/com/ning/billing/util/dao/TableName.java
@@ -21,6 +21,7 @@ public enum TableName {
ACCOUNT_HISTORY("account_history"),
ACCOUNT_EMAIL_HISTORY("account_email_history"),
BUNDLES("bundles"),
+ CREDIT_INVOICE_ITEMS("credit_invoice_items"),
CUSTOM_FIELD_HISTORY("custom_field_history"),
FIXED_INVOICE_ITEMS("fixed_invoice_items"),
INVOICE_PAYMENTS("invoice_payments"),
diff --git a/util/src/main/java/com/ning/billing/util/entity/collection/dao/EntityCollectionSqlDao.java b/util/src/main/java/com/ning/billing/util/entity/collection/dao/EntityCollectionSqlDao.java
index 6fe2ec6..475ae8d 100644
--- a/util/src/main/java/com/ning/billing/util/entity/collection/dao/EntityCollectionSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/entity/collection/dao/EntityCollectionSqlDao.java
@@ -58,7 +58,7 @@ public interface EntityCollectionSqlDao<T extends Entity> {
@RegisterMapper(RecordIdMapper.class)
@SqlQuery
public List<Mapper<UUID, Long>> getRecordIds(@Bind("objectId") final String objectId,
- @ObjectTypeBinder final ObjectType objectType);
+ @ObjectTypeBinder final ObjectType objectType);
@SqlUpdate
public void test();
diff --git a/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java b/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java
index 9b67ede..b988bde 100644
--- a/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java
+++ b/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagUserApi.java
@@ -20,6 +20,7 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
+import com.ning.billing.invoice.api.InvoiceApiException;
import com.ning.billing.util.dao.ObjectType;
import com.ning.billing.util.tag.dao.TagDao;
@@ -84,7 +85,7 @@ public class DefaultTagUserApi implements TagUserApi {
}
@Override
- public void removeTags(UUID objectId, ObjectType objectType, List<TagDefinition> tagDefinitions, CallContext context) {
+ public void removeTags(UUID objectId, ObjectType objectType, List<TagDefinition> tagDefinitions, CallContext context) {
// TODO: consider making this batch
for (TagDefinition tagDefinition : tagDefinitions) {
tagDao.deleteTag(objectId, objectType, tagDefinition, context);
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
index 1b6ce2a..39970da 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
@@ -52,6 +52,12 @@ public class DefaultTagDefinitionDao implements TagDefinitionDao {
@Override
public TagDefinition getByName(final String definitionName) {
+ // add control tag definitions
+ for (ControlTagType controlTag : ControlTagType.values()) {
+ if(definitionName.equals(controlTag.name())) {
+ return new DefaultTagDefinition(controlTag.toString(), controlTag.getDescription(), true);
+ }
+ }
return dao.getByName(definitionName);
}
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java
index 91cac4d..4e29fc2 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java
@@ -16,6 +16,7 @@
package com.ning.billing.util.tag.dao;
+import com.ning.billing.invoice.api.InvoiceApiException;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.dao.AuditedCollectionDao;
import com.ning.billing.util.dao.ObjectType;
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java
index 986e49d..bf08dcd 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java
@@ -42,12 +42,11 @@ public class TagMapper extends MapperBase implements ResultSetMapper<Tag> {
}
}
+ UUID id = UUID.fromString(result.getString("id"));
if (thisTagType == null) {
- UUID id = UUID.fromString(result.getString("id"));
-
return new DescriptiveTag(id, name);
} else {
- return new DefaultControlTag(thisTagType);
+ return new DefaultControlTag(id, thisTagType);
}
}
}
diff --git a/util/src/main/resources/com/ning/billing/util/email/templates/HtmlInvoiceTemplate.mustache b/util/src/main/resources/com/ning/billing/util/email/templates/HtmlInvoiceTemplate.mustache
index 73c70b3..aef1dce 100644
--- a/util/src/main/resources/com/ning/billing/util/email/templates/HtmlInvoiceTemplate.mustache
+++ b/util/src/main/resources/com/ning/billing/util/email/templates/HtmlInvoiceTemplate.mustache
@@ -78,7 +78,7 @@
<tr>
<td colspan=2 />
<td align=right><strong>{{text.invoiceAmount}}</strong></td>
- <td align=right><strong>{{invoice.totalAmount}}</strong></td>
+ <td align=right><strong>{{invoice.amountCharged}}</strong></td>
</tr>
<tr>
<td colspan=2 />
diff --git a/util/src/test/java/com/ning/billing/util/email/DefaultCatalogTranslationTest.java b/util/src/test/java/com/ning/billing/util/email/DefaultCatalogTranslationTest.java
index 0be05ac..a42829f 100644
--- a/util/src/test/java/com/ning/billing/util/email/DefaultCatalogTranslationTest.java
+++ b/util/src/test/java/com/ning/billing/util/email/DefaultCatalogTranslationTest.java
@@ -35,7 +35,7 @@ public class DefaultCatalogTranslationTest {
translation = new DefaultCatalogTranslator(config);
}
- @Test(groups = {"fast", "email"})
+ @Test(groups = {"fast", "email"}, enabled = false)
public void testInitialization() {
String ningPlusText = "ning-plus";
String ningProText = "ning-pro";
@@ -54,7 +54,7 @@ public class DefaultCatalogTranslationTest {
assertEquals(translation.getTranslation(Locale.CHINA, badText), badText);
}
- @Test
+ @Test(enabled = false)
public void testExistingTranslation() {
// if the translation exists, return the translation
String originalText = "ning-plus";
@@ -68,7 +68,7 @@ public class DefaultCatalogTranslationTest {
assertEquals(translation.getTranslation(Locale.US, originalText), originalText);
}
- @Test
+ @Test(enabled = false)
public void testMissingTranslationFileWithEnglishText() {
// if the translation file doesn't exist, return the "English" translation
String originalText = "ning-plus";
diff --git a/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java b/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java
index f37b636..e67ef75 100644
--- a/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java
+++ b/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java
@@ -22,6 +22,7 @@ import com.ning.billing.util.tag.Tag;
import com.ning.billing.util.tag.TagDefinition;
import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -77,6 +78,10 @@ public class MockTagDao implements TagDao {
}
};
+ if (tagStore.get(objectId) == null) {
+ tagStore.put(objectId, new ArrayList<Tag>());
+ }
+
tagStore.get(objectId).add(tag);
}
diff --git a/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java b/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
index 1bded44..b452203 100644
--- a/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
+++ b/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
@@ -22,6 +22,7 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
+import com.ning.billing.invoice.api.InvoiceApiException;
import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.callcontext.CallOrigin;
import com.ning.billing.util.callcontext.UserType;
@@ -417,7 +418,7 @@ public class TestTagStore {
Handle handle = dbi.open();
String query = String.format("select * from audit_log a inner join tag_history th on a.record_id = th.history_record_id where a.table_name = 'tag_history' and th.id='%s' and a.change_type='DELETE'",
- tag.getId().toString());
+ tag.getId().toString());
List<Map<String, Object>> result = handle.select(query);
handle.close();
@@ -440,7 +441,7 @@ public class TestTagStore {
}
@Test
- public void testRemoveTag() {
+ public void testRemoveTag() throws InvoiceApiException {
UUID objectId = UUID.randomUUID();
ObjectType objectType = ObjectType.INVOICE;
TagDefinition tagDefinition = new DefaultTagDefinition("test tag", "test", false);