killbill-uncached
Changes
pom.xml 2(+1 -1)
Details
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
index 83e5192..6f8e466 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
@@ -688,7 +688,7 @@ public class AccountResource extends JaxRsResourceBase {
invoice.getBalance() : remainingRequestPayment;
if (amountToPay.compareTo(BigDecimal.ZERO) > 0) {
final UUID paymentMethodId = externalPayment ? null : account.getPaymentMethodId();
- createPurchaseForInvoice(account, invoice.getId(), amountToPay, paymentMethodId, externalPayment, pluginProperties, callContext);
+ createPurchaseForInvoice(account, invoice.getId(), amountToPay, paymentMethodId, externalPayment, null, null, pluginProperties, callContext);
}
remainingRequestPayment = remainingRequestPayment.subtract(amountToPay);
if (remainingRequestPayment.compareTo(BigDecimal.ZERO) == 0) {
@@ -742,7 +742,7 @@ public class AccountResource extends JaxRsResourceBase {
final UUID paymentMethodId = paymentApi.addPaymentMethod(account, data.getExternalKey(), data.getPluginName(), isDefault, data.getPluginDetail(), pluginProperties, callContext);
if (payAllUnpaidInvoices && unpaidInvoices.size() > 0) {
for (final Invoice invoice : unpaidInvoices) {
- createPurchaseForInvoice(account, invoice.getId(), invoice.getBalance(), paymentMethodId, false, pluginProperties, callContext);
+ createPurchaseForInvoice(account, invoice.getId(), invoice.getBalance(), paymentMethodId, false, null, null, pluginProperties, callContext);
}
}
return uriBuilder.buildResponse(PaymentMethodResource.class, "getPaymentMethod", paymentMethodId, uriInfo.getBaseUri().toString());
@@ -830,7 +830,7 @@ public class AccountResource extends JaxRsResourceBase {
if (payAllUnpaidInvoices) {
final Collection<Invoice> unpaidInvoices = invoiceApi.getUnpaidInvoicesByAccountId(account.getId(), clock.getUTCToday(), callContext);
for (final Invoice invoice : unpaidInvoices) {
- createPurchaseForInvoice(account, invoice.getId(), invoice.getBalance(), newPaymentMethodId, false, pluginProperties, callContext);
+ createPurchaseForInvoice(account, invoice.getId(), invoice.getBalance(), newPaymentMethodId, false, null, null, pluginProperties, callContext);
}
}
return Response.status(Status.OK).build();
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
index fcda3be..a5f5ab1 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
@@ -93,6 +93,7 @@ import org.killbill.billing.tenant.api.TenantApiException;
import org.killbill.billing.tenant.api.TenantKV.TenantKey;
import org.killbill.billing.tenant.api.TenantUserApi;
import org.killbill.billing.util.LocaleUtils;
+import org.killbill.billing.util.UUIDs;
import org.killbill.billing.util.api.AuditUserApi;
import org.killbill.billing.util.api.CustomFieldApiException;
import org.killbill.billing.util.api.CustomFieldUserApi;
@@ -110,6 +111,7 @@ import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -490,6 +492,8 @@ public class InvoiceResource extends JaxRsResourceBase {
@QueryParam(QUERY_PAY_INVOICE) @DefaultValue("false") final Boolean payInvoice,
@QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@QueryParam(QUERY_AUTO_COMMIT) @DefaultValue("false") final Boolean autoCommit,
+ @QueryParam(QUERY_PAYMENT_EXTERNAL_KEY) final String paymentExternalKey,
+ @QueryParam(QUERY_TRANSACTION_EXTERNAL_KEY) final String transactionExternalKey,
@HeaderParam(HDR_CREATED_BY) final String createdBy,
@HeaderParam(HDR_REASON) final String reason,
@HeaderParam(HDR_COMMENT) final String comment,
@@ -505,13 +509,24 @@ public class InvoiceResource extends JaxRsResourceBase {
final LocalDate requestedDate = toLocalDateDefaultToday(account, requestedDateTimeString, callContext);
final List<InvoiceItem> createdExternalCharges = invoiceApi.insertExternalCharges(account.getId(), requestedDate, sanitizedExternalChargesJson, autoCommit, callContext);
+ // if all createdExternalCharges point to the same invoiceId, use the provided paymentExternalKey and / or transactionExternalKey
+ final boolean haveSameInvoiceId = Iterables.all(createdExternalCharges, new Predicate<InvoiceItem>() {
+ @Override
+ public boolean apply(final InvoiceItem input) {
+ return input.getInvoiceId().equals(createdExternalCharges.get(0).getInvoiceId());
+ }
+ });
+
if (payInvoice) {
final Collection<UUID> paidInvoices = new HashSet<UUID>();
for (final InvoiceItem externalCharge : createdExternalCharges) {
if (!paidInvoices.contains(externalCharge.getInvoiceId())) {
paidInvoices.add(externalCharge.getInvoiceId());
final Invoice invoice = invoiceApi.getInvoice(externalCharge.getInvoiceId(), callContext);
- createPurchaseForInvoice(account, invoice.getId(), invoice.getBalance(), account.getPaymentMethodId(), false, pluginProperties, callContext);
+ createPurchaseForInvoice(account, invoice.getId(), invoice.getBalance(), account.getPaymentMethodId(), false,
+ (haveSameInvoiceId && paymentExternalKey != null) ? paymentExternalKey : null,
+ (haveSameInvoiceId && transactionExternalKey != null) ? transactionExternalKey : null,
+ pluginProperties, callContext);
}
}
}
@@ -635,6 +650,7 @@ public class InvoiceResource extends JaxRsResourceBase {
payment.getPurchasedAmount(), "InvoicePaymentJson purchasedAmount needs to be set");
Preconditions.checkArgument(!externalPayment || payment.getPaymentMethodId() == null, "InvoicePaymentJson should not contain a paymwentMethodId when this is an external payment");
+
final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
final CallContext callContext = context.createContext(createdBy, reason, comment, request);
@@ -644,7 +660,8 @@ public class InvoiceResource extends JaxRsResourceBase {
final UUID invoiceId = UUID.fromString(payment.getTargetInvoiceId());
- final Payment result = createPurchaseForInvoice(account, invoiceId, payment.getPurchasedAmount(), paymentMethodId, externalPayment, pluginProperties, callContext);
+ final Payment result = createPurchaseForInvoice(account, invoiceId, payment.getPurchasedAmount(), paymentMethodId, externalPayment,
+ (payment.getPaymentExternalKey() != null) ? payment.getPaymentExternalKey() : null, null, pluginProperties, callContext);
return result != null ?
uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", result.getId()) :
Response.status(Status.NO_CONTENT).build();
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
index c4f18d3..0c833c8 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
@@ -69,6 +69,8 @@ public interface JaxrsResource {
public static final String QUERY_EXTERNAL_KEY = "externalKey";
public static final String QUERY_API_KEY = "apiKey";
public static final String QUERY_REQUESTED_DT = "requestedDate";
+ public static final String QUERY_PAYMENT_EXTERNAL_KEY = "paymentExternalKey";
+ public static final String QUERY_TRANSACTION_EXTERNAL_KEY = "transactionExternalKey";
public static final String QUERY_ENTITLEMENT_REQUESTED_DT = "entitlementDate";
public static final String QUERY_BILLING_REQUESTED_DT = "billingDate";
public static final String QUERY_CALL_COMPLETION = "callCompletion";
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
index 92b5571..35e4b29 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
@@ -454,7 +454,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
return properties;
}
- protected Payment createPurchaseForInvoice(final Account account, final UUID invoiceId, final BigDecimal amountToPay, final UUID paymentMethodId, final Boolean externalPayment, final Iterable<PluginProperty> pluginProperties, final CallContext callContext) throws PaymentApiException {
+ protected Payment createPurchaseForInvoice(final Account account, final UUID invoiceId, final BigDecimal amountToPay, final UUID paymentMethodId, final Boolean externalPayment, final String paymentExternalKey, final String transactionExternalKey, final Iterable<PluginProperty> pluginProperties, final CallContext callContext) throws PaymentApiException {
final List<PluginProperty> properties = new ArrayList<PluginProperty>();
final Iterator<PluginProperty> pluginPropertyIterator = pluginProperties.iterator();
@@ -462,8 +462,6 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
properties.add(pluginPropertyIterator.next());
}
- final String paymentExternalKey = UUIDs.randomUUID().toString();
- final String transactionExternalKey = UUIDs.randomUUID().toString();
final PluginProperty invoiceProperty = new PluginProperty("IPCD_INVOICE_ID" /* InvoicePaymentControlPluginApi.PROP_IPCD_INVOICE_ID (contract with plugin) */,
invoiceId.toString(), false);
properties.add(invoiceProperty);
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
index 07c4669..394320d 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
@@ -292,7 +292,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
checkNotNullParameter(amount, "amount");
checkNotNullParameter(currency, "currency");
}
- checkNotNullParameter(paymentTransactionExternalKey, "paymentTransactionExternalKey");
+
checkNotNullParameter(properties, "plugin properties");
if (paymentMethodId == null && !paymentOptions.isExternalPayment()) {
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index ebde347..cb64711 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
<parent>
<artifactId>killbill-oss-parent</artifactId>
<groupId>org.kill-bill.billing</groupId>
- <version>0.117</version>
+ <version>0.118-SNAPSHOT</version>
</parent>
<artifactId>killbill</artifactId>
<version>0.17.2-SNAPSHOT</version>
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
index 424b1dc..dfd8d8c 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestInvoice.java
@@ -30,6 +30,7 @@ import org.joda.time.LocalDate;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.client.KillBillClientException;
+import org.killbill.billing.client.RequestOptions;
import org.killbill.billing.client.model.Account;
import org.killbill.billing.client.model.AuditLog;
import org.killbill.billing.client.model.Credit;
@@ -40,6 +41,7 @@ import org.killbill.billing.client.model.InvoicePayment;
import org.killbill.billing.client.model.InvoicePayments;
import org.killbill.billing.client.model.Invoices;
import org.killbill.billing.client.model.PaymentMethod;
+import org.killbill.billing.client.model.Payments;
import org.killbill.billing.entitlement.api.SubscriptionEventType;
import org.killbill.billing.invoice.api.DryRunType;
import org.killbill.billing.invoice.api.InvoiceItemType;
@@ -54,6 +56,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
@@ -489,6 +492,56 @@ public class TestInvoice extends TestJaxrsBase {
assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId()).size(), 3);
}
+ @Test(groups = "slow", description = "Can create multiple external charges with same invoice and external keys")
+ public void testExternalChargesWithSameInvoiceAndExternalKeys() throws Exception {
+ final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
+
+ // Get the invoices
+ assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId()).size(), 2);
+
+ // Post an external charge
+ final BigDecimal chargeAmount = BigDecimal.TEN;
+
+ final List<InvoiceItem> externalCharges = new ArrayList<InvoiceItem>();
+
+ // Does not pass currency to test on purpose that we will default to account currency
+ final InvoiceItem externalCharge1 = new InvoiceItem();
+ externalCharge1.setAccountId(accountJson.getAccountId());
+ externalCharge1.setAmount(chargeAmount);
+ externalCharge1.setDescription(UUID.randomUUID().toString());
+ externalCharges.add(externalCharge1);
+
+ final InvoiceItem externalCharge2 = new InvoiceItem();
+ externalCharge2.setAccountId(accountJson.getAccountId());
+ externalCharge2.setAmount(chargeAmount);
+ externalCharge2.setCurrency(accountJson.getCurrency());
+ externalCharge2.setDescription(UUID.randomUUID().toString());
+ externalCharges.add(externalCharge2);
+
+ String paymentExternalKey = "anyPaymentExternalKey";
+ String transactionExternalKey = "anyTransactionExternalKey";
+
+ final List<InvoiceItem> createdExternalCharges =
+ killBillClient.createExternalCharges(externalCharges, clock.getUTCToday(), true, true,
+ paymentExternalKey, transactionExternalKey, RequestOptions.builder()
+ .withCreatedBy(createdBy)
+ .withReason(reason)
+ .withComment(comment).build());
+ assertEquals(createdExternalCharges.size(), 2);
+ assertEquals(createdExternalCharges.get(0).getCurrency().toString(), accountJson.getCurrency());
+ assertEquals(createdExternalCharges.get(1).getCurrency().toString(), accountJson.getCurrency());
+
+ // Verify the total number of invoices
+ assertEquals(killBillClient.getInvoicesForAccount(accountJson.getAccountId()).size(), 3);
+
+ Payments payments = killBillClient.getPaymentsForAccount(accountJson.getAccountId(), AuditLevel.NONE, RequestOptions.empty());
+ assertNotNull(payments);
+ // Verify payment with paymentExternalKey provided
+ assertEquals(payments.get(payments.size() - 1).getPaymentExternalKey(), paymentExternalKey);
+ // Verify transactions with transactionExternalKey provided
+ assertEquals(payments.get(payments.size() - 1).getTransactions().get(0).getTransactionExternalKey(), transactionExternalKey);
+ }
+
@Test(groups = "slow", description = "Can create an external charge and trigger a payment")
public void testExternalChargeOnNewInvoiceWithAutomaticPayment() throws Exception {
final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();