killbill-uncached

jaxrs: add invoice API to post external charges Add corresponding

8/8/2012 8:16:05 PM

Details

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 265a608..21bc8c5 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
@@ -16,9 +16,6 @@
 
 package com.ning.billing.jaxrs.resources;
 
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import static javax.ws.rs.core.MediaType.TEXT_HTML;
-
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.LinkedList;
@@ -46,11 +43,11 @@ import org.joda.time.format.ISODateTimeFormat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
 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.catalog.api.Currency;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceItem;
@@ -74,6 +71,12 @@ import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.dao.ObjectType;
 
+import com.google.common.base.Objects;
+import com.google.inject.Inject;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.TEXT_HTML;
+
 @Path(JaxrsResource.INVOICES_PATH)
 public class InvoiceResource extends JaxRsResourceBase {
 
@@ -222,6 +225,68 @@ public class InvoiceResource extends JaxRsResourceBase {
         return uriBuilder.buildResponse(InvoiceResource.class, "getInvoice", adjustmentItem.getInvoiceId());
     }
 
+    @POST
+    @Produces(APPLICATION_JSON)
+    @Consumes(APPLICATION_JSON)
+    @Path(CHARGES)
+    public Response createExternalCharge(final InvoiceItemJsonSimple externalChargeJson,
+                                         @QueryParam(QUERY_REQUESTED_DT) final String requestedDateTimeString,
+                                         @HeaderParam(HDR_CREATED_BY) final String createdBy,
+                                         @HeaderParam(HDR_REASON) final String reason,
+                                         @HeaderParam(HDR_COMMENT) final String comment,
+                                         @javax.ws.rs.core.Context final UriInfo uriInfo) throws AccountApiException, InvoiceApiException {
+        final Account account = accountApi.getAccountById(UUID.fromString(externalChargeJson.getAccountId()));
+        final CallContext callContext = context.createContext(createdBy, reason, comment);
+
+        // Get the effective date of the external charge, in the account timezone
+        final LocalDate requestedDate;
+        if (requestedDateTimeString == null) {
+            requestedDate = clock.getUTCToday();
+        } else {
+            final DateTime requestedDateTime = DATE_TIME_FORMATTER.parseDateTime(requestedDateTimeString);
+            requestedDate = requestedDateTime.toDateTime(account.getTimeZone()).toLocalDate();
+        }
+
+        final Currency currency = Objects.firstNonNull(externalChargeJson.getCurrency(), account.getCurrency());
+        final InvoiceItem externalCharge = invoiceApi.insertExternalCharge(account.getId(), externalChargeJson.getAmount(),
+                                                                           externalChargeJson.getDescription(), requestedDate,
+                                                                           currency, callContext);
+
+        return uriBuilder.buildResponse(InvoiceResource.class, "getInvoice", externalCharge.getInvoiceId(), uriInfo.getBaseUri().toString());
+    }
+
+    @POST
+    @Produces(APPLICATION_JSON)
+    @Consumes(APPLICATION_JSON)
+    @Path("/{invoiceId:" + UUID_PATTERN + "}/" + CHARGES)
+    public Response createExternalChargeForInvoice(final InvoiceItemJsonSimple externalChargeJson,
+                                                   @PathParam("invoiceId") final String invoiceIdString,
+                                                   @QueryParam(QUERY_REQUESTED_DT) final String requestedDateTimeString,
+                                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
+                                                   @HeaderParam(HDR_REASON) final String reason,
+                                                   @HeaderParam(HDR_COMMENT) final String comment,
+                                                   @javax.ws.rs.core.Context final UriInfo uriInfo) throws AccountApiException, InvoiceApiException {
+        final Account account = accountApi.getAccountById(UUID.fromString(externalChargeJson.getAccountId()));
+        final CallContext callContext = context.createContext(createdBy, reason, comment);
+
+        // Get the effective date of the external charge, in the account timezone
+        final LocalDate requestedDate;
+        if (requestedDateTimeString == null) {
+            requestedDate = clock.getUTCToday();
+        } else {
+            final DateTime requestedDateTime = DATE_TIME_FORMATTER.parseDateTime(requestedDateTimeString);
+            requestedDate = requestedDateTime.toDateTime(account.getTimeZone()).toLocalDate();
+        }
+
+        final UUID invoiceId = UUID.fromString(invoiceIdString);
+        final Currency currency = Objects.firstNonNull(externalChargeJson.getCurrency(), account.getCurrency());
+        final InvoiceItem externalCharge = invoiceApi.insertExternalChargeForInvoice(account.getId(), invoiceId,
+                                                                                     externalChargeJson.getAmount(), externalChargeJson.getDescription(),
+                                                                                     requestedDate, currency, callContext);
+
+        return uriBuilder.buildResponse(InvoiceResource.class, "getInvoice", externalCharge.getInvoiceId(), uriInfo.getBaseUri().toString());
+    }
+
     @GET
     @Path("/{invoiceId:" + UUID_PATTERN + "}/" + PAYMENTS)
     @Produces(APPLICATION_JSON)
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 567a72b..790ade4 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
@@ -13,16 +13,17 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
+
 package com.ning.billing.jaxrs.resources;
 
 public interface JaxrsResource {
+
     public static final String API_PREFIX = "";
     public static final String API_VERSION = "/1.0";
     public static final String API_POSTFIX = "/kb";
 
     public static final String PREFIX = API_PREFIX + API_VERSION + API_POSTFIX;
 
-
     public static final String TIMELINE = "timeline";
 
     /*
@@ -81,6 +82,9 @@ public interface JaxrsResource {
     public static final String INVOICES = "invoices";
     public static final String INVOICES_PATH = PREFIX + "/" + INVOICES;
 
+    public static final String CHARGES = "charges";
+    public static final String CHARGES_PATH = PREFIX + "/" + INVOICES + "/" + CHARGES;
+
     public static final String PAYMENTS = "payments";
     public static final String PAYMENTS_PATH = PREFIX + "/" + PAYMENTS;
 
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java b/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
index 675159a..66cfb7c 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
@@ -186,4 +186,44 @@ public class TestInvoice extends TestJaxrsBase {
         final BigDecimal adjustedInvoiceBalance = invoice.getBalance().add(adjustedAmount.negate().setScale(2, RoundingMode.HALF_UP));
         assertEquals(adjustedInvoice.getBalance().compareTo(adjustedInvoiceBalance), 0);
     }
+
+    @Test(groups = "slow")
+    public void testExternalChargeOnNewInvoice() throws Exception {
+        final AccountJson accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
+
+        // Get the invoices
+        assertEquals(getInvoicesForAccount(accountJson.getAccountId()).size(), 2);
+
+        // Post an external charge
+        final BigDecimal chargeAmount = BigDecimal.TEN;
+        final InvoiceJsonWithItems invoiceWithItems = createExternalCharge(accountJson.getAccountId(), chargeAmount, null, null);
+        assertEquals(invoiceWithItems.getBalance().compareTo(chargeAmount), 0);
+        assertEquals(invoiceWithItems.getItems().size(), 1);
+
+        // Verify the total number of invoices
+        assertEquals(getInvoicesForAccount(accountJson.getAccountId()).size(), 3);
+    }
+
+    @Test(groups = "slow")
+    public void testExternalChargeOnExistingInvoice() throws Exception {
+        final AccountJson accountJson = createAccountNoPMBundleAndSubscriptionAndWaitForFirstInvoice();
+
+        // Get the invoices
+        final List<InvoiceJsonWithItems> invoices = getInvoicesWithItemsForAccount(accountJson.getAccountId());
+        // 2 invoices but look for the non zero dollar one
+        assertEquals(invoices.size(), 2);
+        final String invoiceId = invoices.get(1).getInvoiceId();
+        final BigDecimal originalInvoiceAmount = invoices.get(1).getAmount();
+        final int originalNumberOfItemsForInvoice = invoices.get(1).getItems().size();
+
+        // Post an external charge
+        final BigDecimal chargeAmount = BigDecimal.TEN;
+        final InvoiceJsonWithItems invoiceWithItems = createExternalChargeForInvoice(accountJson.getAccountId(), invoiceId, chargeAmount, null, null);
+        assertEquals(invoiceWithItems.getItems().size(), originalNumberOfItemsForInvoice + 1);
+
+        // Verify the new invoice balance
+        final InvoiceJsonSimple adjustedInvoice = getInvoice(invoiceId);
+        final BigDecimal adjustedInvoiceBalance = originalInvoiceAmount.add(chargeAmount.setScale(2, RoundingMode.HALF_UP));
+        assertEquals(adjustedInvoice.getBalance().compareTo(adjustedInvoiceBalance), 0);
+    }
 }
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 6708ddf..9585672 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
@@ -565,6 +565,46 @@ public class TestJaxrsBase extends ServerTestSuiteWithEmbeddedDB {
         Assert.assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
     }
 
+    protected InvoiceJsonWithItems createExternalCharge(final String accountId, final BigDecimal amount, @Nullable final Currency currency,
+                                                        @Nullable final DateTime requestedDate) throws Exception {
+        return doCreateExternalCharge(accountId, null, amount, currency, requestedDate, JaxrsResource.CHARGES_PATH);
+    }
+
+    protected InvoiceJsonWithItems createExternalChargeForInvoice(final String accountId, final String invoiceId, final BigDecimal amount,
+                                                        @Nullable final Currency currency, @Nullable final DateTime requestedDate) throws Exception {
+        final String uri = JaxrsResource.INVOICES_PATH + "/" + invoiceId + "/" + JaxrsResource.CHARGES;
+        return doCreateExternalCharge(accountId, invoiceId, amount, currency, requestedDate, uri);
+    }
+
+    private InvoiceJsonWithItems doCreateExternalCharge(final String accountId, @Nullable final String invoiceId, @Nullable final BigDecimal amount,
+                                                        @Nullable final Currency currency, final DateTime requestedDate, final String uri) throws IOException {
+        final Map<String, String> queryParams = new HashMap<String, String>();
+        if (requestedDate != null) {
+            queryParams.put(JaxrsResource.QUERY_REQUESTED_DT, requestedDate.toDateTimeISO().toString());
+        }
+
+        final InvoiceItemJsonSimple externalCharge = new InvoiceItemJsonSimple(null, invoiceId, accountId, null, null, null, null,
+                                                                               null, null, null, amount, currency, null);
+        final String externalChargeJson = mapper.writeValueAsString(externalCharge);
+        final Response response = doPost(uri, externalChargeJson, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+
+        final String location = response.getHeader("Location");
+        Assert.assertNotNull(location);
+
+        final Map<String, String> queryParamsForInvoice = new HashMap<String, String>();
+        queryParamsForInvoice.put(JaxrsResource.QUERY_ACCOUNT_ID, accountId);
+        queryParamsForInvoice.put(JaxrsResource.QUERY_INVOICE_WITH_ITEMS, "true");
+        final Response invoiceResponse = doGetWithUrl(location, queryParamsForInvoice, DEFAULT_HTTP_TIMEOUT_SEC);
+        assertEquals(invoiceResponse.getStatusCode(), Status.OK.getStatusCode());
+
+        final String invoicesBaseJson = invoiceResponse.getResponseBody();
+        final InvoiceJsonWithItems invoice = mapper.readValue(invoicesBaseJson, new TypeReference<InvoiceJsonWithItems>(){});
+        assertNotNull(invoice);
+
+        return invoice;
+    }
+
     //
     // PAYMENT UTILITIES
     //