/*
* Copyright 2010-2013 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.killbill.billing.invoice.api.invoice;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.invoice.InvoiceTestSuiteWithEmbeddedDB;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoiceApiException;
import org.killbill.billing.invoice.api.InvoicePayment;
import org.killbill.billing.invoice.api.InvoicePaymentType;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import static org.killbill.billing.invoice.tests.InvoiceTestUtils.createAndPersistInvoice;
import static org.killbill.billing.invoice.tests.InvoiceTestUtils.createAndPersistPayment;
public class TestDefaultInvoicePaymentApi extends InvoiceTestSuiteWithEmbeddedDB {
private static final BigDecimal THIRTY = new BigDecimal("30.00");
private static final Currency CURRENCY = Currency.EUR;
@Test(groups = "slow")
public void testFullRefundWithNoAdjustment() throws Exception {
verifyRefund(THIRTY, THIRTY, THIRTY, false, ImmutableMap.<UUID, BigDecimal>of());
}
@Test(groups = "slow")
public void testPartialRefundWithNoAdjustment() throws Exception {
verifyRefund(THIRTY, BigDecimal.TEN, BigDecimal.TEN, false, ImmutableMap.<UUID, BigDecimal>of());
}
@Test(groups = "slow")
public void testFullRefundWithInvoiceAdjustment() throws Exception {
verifyRefund(THIRTY, THIRTY, BigDecimal.ZERO, true, ImmutableMap.<UUID, BigDecimal>of());
}
@Test(groups = "slow")
public void testPartialRefundWithInvoiceAdjustment() throws Exception {
verifyRefund(THIRTY, BigDecimal.TEN, BigDecimal.ZERO, true, ImmutableMap.<UUID, BigDecimal>of());
}
@Test(groups = "slow")
public void testFullRefundWithBothInvoiceItemAdjustments() throws Exception {
// Create an invoice with two items (30 \u20ac and 10 \u20ac)
final Invoice invoice = createAndPersistInvoice(invoiceDao, clock,
ImmutableList.<BigDecimal>of(THIRTY, BigDecimal.TEN), CURRENCY, internalCallContext);
// Fully adjust both items
final Map<UUID, BigDecimal> adjustments = new HashMap<UUID, BigDecimal>();
adjustments.put(invoice.getInvoiceItems().get(0).getId(), null);
adjustments.put(invoice.getInvoiceItems().get(1).getId(), null);
verifyRefund(invoice, new BigDecimal("40"), new BigDecimal("40"), BigDecimal.ZERO, true, adjustments);
}
@Test(groups = "slow")
public void testPartialRefundWithSingleInvoiceItemAdjustment() throws Exception {
// Create an invoice with two items (30 \u20ac and 10 \u20ac)
final Invoice invoice = createAndPersistInvoice(invoiceDao, clock,
ImmutableList.<BigDecimal>of(THIRTY, BigDecimal.TEN), CURRENCY, internalCallContext);
// Fully adjust both items
final Map<UUID, BigDecimal> adjustments = new HashMap<UUID, BigDecimal>();
adjustments.put(invoice.getInvoiceItems().get(0).getId(), null);
verifyRefund(invoice, new BigDecimal("40"), new BigDecimal("30"), BigDecimal.ZERO, true, adjustments);
}
@Test(groups = "slow")
public void testPartialRefundWithTwoInvoiceItemAdjustment() throws Exception {
// Create an invoice with two items (30 \u20ac and 10 \u20ac)
final Invoice invoice = createAndPersistInvoice(invoiceDao, clock,
ImmutableList.<BigDecimal>of(THIRTY, BigDecimal.TEN), CURRENCY, internalCallContext);
// Adjust partially both items: the invoice posted was 40 \u20ac, but we should really just have charged you 2 \u20ac
final ImmutableMap<UUID, BigDecimal> adjustments = ImmutableMap.<UUID, BigDecimal>of(invoice.getInvoiceItems().get(0).getId(), new BigDecimal("29"),
invoice.getInvoiceItems().get(1).getId(), new BigDecimal("9"));
verifyRefund(invoice, new BigDecimal("40"), new BigDecimal("38"), BigDecimal.ZERO, true, adjustments);
}
private void verifyRefund(final BigDecimal invoiceAmount, final BigDecimal refundAmount, final BigDecimal finalInvoiceAmount,
final boolean adjusted, final Map<UUID, BigDecimal> invoiceItemIdsWithAmounts) throws InvoiceApiException {
final Invoice invoice = createAndPersistInvoice(invoiceDao, clock, invoiceAmount, CURRENCY, internalCallContext);
verifyRefund(invoice, invoiceAmount, refundAmount, finalInvoiceAmount, adjusted, invoiceItemIdsWithAmounts);
}
private void verifyRefund(final Invoice invoice, final BigDecimal invoiceAmount, final BigDecimal refundAmount, final BigDecimal finalInvoiceAmount,
final boolean adjusted, final Map<UUID, BigDecimal> invoiceItemIdsWithAmounts) throws InvoiceApiException {
final InvoicePayment payment = createAndPersistPayment(invoiceInternalApi, clock, invoice.getId(), invoiceAmount, CURRENCY, internalCallContext);
// Verify the initial invoice balance
final BigDecimal initialInvoiceBalance = invoiceInternalApi.getInvoiceById(invoice.getId(), internalCallContext).getBalance();
Assert.assertEquals(initialInvoiceBalance.compareTo(BigDecimal.ZERO), 0);
// Create a full refund with no adjustment
final InvoicePayment refund = invoiceInternalApi.createRefund(payment.getPaymentId(), refundAmount, adjusted, invoiceItemIdsWithAmounts,
UUID.randomUUID().toString(), internalCallContext);
Assert.assertEquals(refund.getAmount().compareTo(refundAmount.negate()), 0);
Assert.assertEquals(refund.getCurrency(), CURRENCY);
Assert.assertEquals(refund.getInvoiceId(), invoice.getId());
Assert.assertEquals(refund.getPaymentId(), payment.getPaymentId());
Assert.assertEquals(refund.getType(), InvoicePaymentType.REFUND);
// Verify the current invoice balance
final BigDecimal newInvoiceBalance = invoiceInternalApi.getInvoiceById(invoice.getId(), internalCallContext).getBalance();
Assert.assertEquals(newInvoiceBalance.compareTo(finalInvoiceAmount), 0);
}
}