killbill-aplcache
Changes
payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentControlPluginApi.java 17(+15 -2)
pom.xml 2(+1 -1)
Details
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentRefund.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentRefund.java
index 81d7a94..b501af7 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentRefund.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestPaymentRefund.java
@@ -116,6 +116,20 @@ public class TestPaymentRefund extends TestIntegrationBase {
}
}
+ @Test(groups = "slow", description = "https://github.com/killbill/killbill/issues/255",
+ expectedExceptions = PaymentApiException.class, expectedExceptionsMessageRegExp = "Payment method .* does not exist")
+ public void testRefundWithDeletedPaymentMethod() throws Exception {
+
+ // delete payment method
+ busHandler.pushExpectedEvent(NextEvent.TAG);
+ paymentApi.deletePaymentMethod(account, account.getPaymentMethodId(), true, true, new ArrayList<PluginProperty>(), callContext);
+ assertListenerStatus();
+
+ // try to create a refund for a payment with its payment method deleted
+ paymentApi.createRefund(account, payment.getId(), payment.getPurchasedAmount(), payment.getCurrency(),
+ UUID.randomUUID().toString(), PLUGIN_PROPERTIES, callContext);
+ }
+
private void setupRefundTest() throws Exception {
final int billingDay = 31;
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
index 8c14531..f2f1a01 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
@@ -145,6 +145,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
@ApiResponse(code = 404, message = "Account or payment not found")})
public Response createRefundWithAdjustments(final InvoicePaymentTransactionJson json,
@PathParam("paymentId") final String paymentId,
+ @QueryParam(QUERY_PAYMENT_EXTERNAL) @DefaultValue("false") final Boolean externalPayment,
@QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
@HeaderParam(HDR_CREATED_BY) final String createdBy,
@HeaderParam(HDR_REASON) final String reason,
@@ -160,6 +161,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
final Iterable<PluginProperty> pluginProperties;
final String transactionExternalKey = json.getTransactionExternalKey() != null ? json.getTransactionExternalKey() : UUIDs.randomUUID().toString();
+ final String paymentExternalKey = json.getPaymentExternalKey() != null ? json.getPaymentExternalKey() : UUIDs.randomUUID().toString();
if (json.isAdjusted() != null && json.isAdjusted()) {
if (json.getAdjustments() != null && json.getAdjustments().size() > 0) {
final Map<UUID, BigDecimal> adjustments = new HashMap<UUID, BigDecimal>();
@@ -177,8 +179,17 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
pluginProperties = extractPluginProperties(pluginPropertiesString);
}
- final Payment result = paymentApi.createRefundWithPaymentControl(account, payment.getId(), json.getAmount(), account.getCurrency(), transactionExternalKey,
- pluginProperties, createInvoicePaymentControlPluginApiPaymentOptions(false), callContext);
+ final Payment result;
+ if (externalPayment) {
+
+ result = paymentApi.createCreditWithPaymentControl(account, null, null, json.getAmount(), account.getCurrency(),
+ paymentExternalKey, transactionExternalKey, pluginProperties,
+ createInvoicePaymentControlPluginApiPaymentOptions(false), callContext);
+ } else {
+ result = paymentApi.createRefundWithPaymentControl(account, payment.getId(), json.getAmount(), account.getCurrency(), transactionExternalKey,
+ pluginProperties, createInvoicePaymentControlPluginApiPaymentOptions(false), callContext);
+ }
+
return uriBuilder.buildResponse(InvoicePaymentResource.class, "getInvoicePayment", result.getId(), uriInfo.getBaseUri().toString());
}
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 a5f5ab1..ba275b6 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
@@ -648,7 +648,7 @@ public class InvoiceResource extends JaxRsResourceBase {
verifyNonNullOrEmpty(payment.getAccountId(), "InvoicePaymentJson accountId needs to be set",
payment.getTargetInvoiceId(), "InvoicePaymentJson targetInvoiceId needs to be set",
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");
+ Preconditions.checkArgument(!externalPayment || payment.getPaymentMethodId() == null, "InvoicePaymentJson should not contain a paymentMethodId when this is an external payment");
final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
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 394320d..f1430b9 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
@@ -299,6 +299,10 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
throw new PaymentApiException(ErrorCode.PAYMENT_NO_DEFAULT_PAYMENT_METHOD, "paymentMethodId", "should not be null");
}
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
+
+ // TODO validate if the code is located properly here
+ // The code should understand that the external payment method needs to be created
+ // if it doesn't exist yet and trigger a CREDIT using the (built-in) external payment plugin.
final UUID nonNulPaymentMethodId = (paymentMethodId != null) ?
paymentMethodId :
paymentMethodProcessor.createOrGetExternalPaymentMethod(UUIDs.randomUUID().toString(), account, properties, callContext, internalCallContext);
@@ -499,7 +503,6 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
@Nullable final String paymentExternalKey, @Nullable final String paymentTransactionExternalKey,
final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
checkNotNullParameter(account, "account");
- checkNotNullParameter(paymentMethodId, "paymentMethodId");
if (paymentId == null) {
checkNotNullParameter(amount, "amount");
checkNotNullParameter(currency, "currency");
@@ -513,7 +516,11 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, null);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
- payment = paymentProcessor.createCredit(IS_API_PAYMENT, NULL_ATTEMPT_ID, account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey,
+ final UUID nonNulPaymentMethodId = (paymentMethodId != null) ?
+ paymentMethodId :
+ paymentMethodProcessor.createOrGetExternalPaymentMethod(UUIDs.randomUUID().toString(), account, properties, callContext, internalCallContext);
+
+ payment = paymentProcessor.createCredit(IS_API_PAYMENT, NULL_ATTEMPT_ID, account, nonNulPaymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey,
SHOULD_LOCK_ACCOUNT, properties, callContext, internalCallContext);
paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
@@ -545,7 +552,6 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
}
checkNotNullParameter(account, "account");
- checkNotNullParameter(paymentMethodId, "paymentMethodId");
if (paymentId == null) {
checkNotNullParameter(amount, "amount");
checkNotNullParameter(currency, "currency");
@@ -559,7 +565,15 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, paymentControlPluginNames);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
- payment = pluginControlPaymentProcessor.createCredit(IS_API_PAYMENT, account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey,
+
+ // TODO validate if the code is located properly here
+ // The code should understand that the external payment method needs to be created
+ // if it doesn't exist yet and trigger a CREDIT using the (built-in) external payment plugin.
+ final UUID nonNulPaymentMethodId = (paymentMethodId != null) ?
+ paymentMethodId :
+ paymentMethodProcessor.createOrGetExternalPaymentMethod(UUIDs.randomUUID().toString(), account, properties, callContext, internalCallContext);
+
+ payment = pluginControlPaymentProcessor.createCredit(IS_API_PAYMENT, account, nonNulPaymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey,
properties, paymentControlPluginNames, callContext, internalCallContext);
paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonRunner.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonRunner.java
index 012d7c0..de91986 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonRunner.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonRunner.java
@@ -68,6 +68,7 @@ import org.killbill.billing.payment.core.sm.payments.VoidCompleted;
import org.killbill.billing.payment.core.sm.payments.VoidInitiated;
import org.killbill.billing.payment.core.sm.payments.VoidOperation;
import org.killbill.billing.payment.dao.PaymentDao;
+import org.killbill.billing.payment.dao.PaymentMethodModelDao;
import org.killbill.billing.payment.dao.PaymentModelDao;
import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
import org.killbill.billing.payment.dispatcher.PluginDispatcher;
@@ -128,8 +129,10 @@ public class PaymentAutomatonRunner {
final Iterable<PluginProperty> properties,
final CallContext callContext,
final InternalCallContext internalCallContext) throws PaymentApiException {
+
// Retrieve the payment id from the payment external key if needed
final UUID effectivePaymentId = paymentId != null ? paymentId : retrievePaymentId(paymentExternalKey, paymentTransactionExternalKey, internalCallContext);
+ verifyPaymentMethodExistsForRefund(effectivePaymentId, transactionType, internalCallContext);
return new PaymentStateContext(isApiPayment,
effectivePaymentId,
@@ -284,4 +287,15 @@ public class PaymentAutomatonRunner {
return paymentIdCandidate;
}
+
+ private void verifyPaymentMethodExistsForRefund(final UUID paymentId, final TransactionType transactionType, final InternalCallContext internalCallContext) throws PaymentApiException {
+ if (TransactionType.REFUND.equals(transactionType) && (paymentId != null)) {
+ final PaymentModelDao payment = paymentDao.getPayment(paymentId, internalCallContext);
+ final PaymentMethodModelDao paymentMethod = paymentDao.getPaymentMethod(payment.getPaymentMethodId(), internalCallContext);
+ if (paymentMethod == null) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, payment.getPaymentMethodId());
+ }
+ }
+ }
+
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentControlPluginApi.java b/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentControlPluginApi.java
index 912d736..e9441b1 100644
--- a/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentControlPluginApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/invoice/InvoicePaymentControlPluginApi.java
@@ -131,7 +131,8 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
Preconditions.checkArgument(paymentControlContext.getPaymentApiType() == PaymentApiType.PAYMENT_TRANSACTION);
Preconditions.checkArgument(transactionType == TransactionType.PURCHASE ||
transactionType == TransactionType.REFUND ||
- transactionType == TransactionType.CHARGEBACK);
+ transactionType == TransactionType.CHARGEBACK ||
+ transactionType == TransactionType.CREDIT);
final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(paymentControlContext.getAccountId(), paymentControlContext);
switch (transactionType) {
@@ -141,6 +142,8 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
return getPluginRefundResult(paymentControlContext, pluginProperties, internalContext);
case CHARGEBACK:
return new DefaultPriorPaymentControlResult(false, paymentControlContext.getAmount());
+ case CREDIT:
+ return getPluginCreditResult(paymentControlContext, pluginProperties, internalContext);
default:
throw new IllegalStateException("Unexpected transactionType " + transactionType);
}
@@ -151,7 +154,8 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
final TransactionType transactionType = paymentControlContext.getTransactionType();
Preconditions.checkArgument(transactionType == TransactionType.PURCHASE ||
transactionType == TransactionType.REFUND ||
- transactionType == TransactionType.CHARGEBACK);
+ transactionType == TransactionType.CHARGEBACK ||
+ transactionType == TransactionType.CREDIT);
final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(paymentControlContext.getAccountId(), paymentControlContext);
try {
@@ -216,6 +220,10 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
}
break;
+ case CREDIT:
+ // TODO implement
+ break;
+
default:
throw new IllegalStateException("Unexpected transactionType " + transactionType);
}
@@ -401,6 +409,11 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
return new DefaultPriorPaymentControlResult(isAborted, amountToBeRefunded);
}
+ private PriorPaymentControlResult getPluginCreditResult(final PaymentControlContext paymentControlPluginContext, final Iterable<PluginProperty> pluginProperties, final InternalCallContext internalContext) throws PaymentControlApiException {
+ // TODO implement
+ return new DefaultPriorPaymentControlResult(false, paymentControlPluginContext.getAmount());
+ }
+
private Map<UUID, BigDecimal> extractIdsWithAmountFromProperties(final Iterable<PluginProperty> properties) {
final PluginProperty prop = getPluginProperty(properties, PROP_IPCD_REFUND_IDS_WITH_AMOUNT_KEY);
if (prop == null) {
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index 12119d8..03d6a18 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.123</version>
+ <version>0.124-SNAPSHOT</version>
</parent>
<artifactId>killbill</artifactId>
<version>0.17.3-SNAPSHOT</version>
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
index 1380883..4854bc7 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
@@ -36,7 +36,12 @@ import org.killbill.billing.client.model.PaymentMethod;
import org.killbill.billing.client.model.PaymentMethodPluginDetail;
import org.killbill.billing.client.model.PluginProperty;
import org.killbill.billing.client.model.Subscription;
+import org.killbill.billing.client.model.Tags;
+import org.killbill.billing.payment.provider.ExternalPaymentProviderPlugin;
+import org.killbill.billing.util.UUIDs;
+import org.killbill.billing.util.tag.ControlTagType;
+import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedDB {
@@ -111,6 +116,16 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
return killBillClient.getAccount(input.getExternalKey());
}
+ protected Account createAccountWithExternalPaymentMethod() throws Exception {
+ final Account input = createAccount();
+
+ final PaymentMethodPluginDetail info = new PaymentMethodPluginDetail();
+ final PaymentMethod paymentMethodJson = new PaymentMethod(null, UUIDs.randomUUID().toString(), input.getAccountId(),
+ true, ExternalPaymentProviderPlugin.PLUGIN_NAME, info);
+ killBillClient.createPaymentMethod(paymentMethodJson, requestOptions);
+ return killBillClient.getAccount(input.getExternalKey(), requestOptions);
+ }
+
protected Account createAccount() throws Exception {
return createAccount(null);
}
@@ -147,6 +162,24 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
return accountJson;
}
+ protected Account createAccountWithExternalPMBundleAndSubscriptionAndManualPayTagAndWaitForFirstInvoice() throws Exception {
+ final Account accountJson = createAccountWithExternalPaymentMethod();
+ assertNotNull(accountJson);
+
+ final Tags accountTag = killBillClient.createAccountTag(accountJson.getAccountId(), ControlTagType.MANUAL_PAY.getId(), requestOptions);
+ assertNotNull(accountTag);
+ assertEquals(accountTag.get(0).getTagDefinitionId(), ControlTagType.MANUAL_PAY.getId());
+
+ // Add a bundle, subscription and move the clock to get the first invoice
+ final Subscription subscriptionJson = createEntitlement(accountJson.getAccountId(), UUID.randomUUID().toString(), "Shotgun",
+ ProductCategory.BASE, BillingPeriod.MONTHLY, true);
+ assertNotNull(subscriptionJson);
+ clock.addDays(32);
+ crappyWaitForLackOfProperSynchonization();
+
+ return accountJson;
+ }
+
protected Account createAccountNoPMBundleAndSubscription() throws Exception {
// Create an account with no payment method
final Account accountJson = createAccount();
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExternalRefund.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExternalRefund.java
new file mode 100644
index 0000000..e364682
--- /dev/null
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestExternalRefund.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
+ *
+ * The Billing Project 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.jaxrs;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import org.joda.time.DateTime;
+import org.killbill.billing.client.model.Account;
+import org.killbill.billing.client.model.Invoice;
+import org.killbill.billing.client.model.InvoiceItem;
+import org.killbill.billing.client.model.InvoicePayment;
+import org.killbill.billing.client.model.InvoicePaymentTransaction;
+import org.killbill.billing.client.model.Invoices;
+import org.killbill.billing.client.model.Payment;
+import org.killbill.billing.client.model.Payments;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+public class TestExternalRefund extends TestJaxrsBase {
+
+ @Test(groups = "slow", description = "#255 - Scenario 1 - Can refund a manual payment though an external refund")
+ public void testManualPaymentAndExternalRefund() throws Exception {
+ final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
+ clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
+
+ final Account accountJson = createAccountWithExternalPMBundleAndSubscriptionAndManualPayTagAndWaitForFirstInvoice();
+
+ final Invoices invoicesForAccount = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), requestOptions);
+ final Invoice unpaidInvoice = invoicesForAccount.get(1);
+ assertEquals(unpaidInvoice.getBalance().compareTo(BigDecimal.valueOf(249.95)), 0);
+
+ final Payments paymentsForAccount = killBillClient.getPaymentsForAccount(accountJson.getAccountId(), requestOptions);
+ assertEquals(paymentsForAccount.size(), 0);
+
+ final InvoicePayment invoicePaymentRequest = new InvoicePayment();
+ invoicePaymentRequest.setTargetInvoiceId(unpaidInvoice.getInvoiceId());
+ invoicePaymentRequest.setAccountId(accountJson.getAccountId());
+ invoicePaymentRequest.setCurrency(unpaidInvoice.getCurrency().toString());
+ invoicePaymentRequest.setPurchasedAmount(unpaidInvoice.getAmount());
+ final InvoicePayment invoicePayment = killBillClient.createInvoicePayment(invoicePaymentRequest, true, requestOptions);
+ assertEquals(invoicePayment.getPurchasedAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
+ assertEquals(invoicePayment.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
+
+ final InvoicePaymentTransaction invoicePaymentTransactionRequest = new InvoicePaymentTransaction();
+ invoicePaymentTransactionRequest.setAmount(BigDecimal.valueOf(249.95));
+ invoicePaymentTransactionRequest.setPaymentId(invoicePayment.getPaymentId());
+ final InvoicePayment invoicePaymentRefund = killBillClient.createInvoicePaymentRefund(invoicePaymentTransactionRequest, requestOptions);
+
+ assertNotNull(invoicePaymentRefund);
+ assertEquals(invoicePaymentRefund.getPurchasedAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
+ assertEquals(invoicePaymentRefund.getRefundedAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
+ }
+
+ @Test(groups = "slow", description = "#255 - Scenario 2a - Can refund an automatic payment though an external refund")
+ public void testAutomaticPaymentAndExternalRefund() throws Exception {
+ final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
+ clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
+
+ final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
+ // delete PM
+ killBillClient.deletePaymentMethod(accountJson.getPaymentMethodId(), true, true, requestOptions);
+ final Payments paymentsForAccount = killBillClient.getPaymentsForAccount(accountJson.getAccountId(), requestOptions);
+ final Payment payment = paymentsForAccount.get(paymentsForAccount.size() - 1);
+
+ // external refund
+ final InvoicePaymentTransaction invoicePaymentTransactionRequest = new InvoicePaymentTransaction();
+ invoicePaymentTransactionRequest.setAmount(BigDecimal.valueOf(249.95));
+ invoicePaymentTransactionRequest.setCurrency(accountJson.getCurrency().toString());
+ invoicePaymentTransactionRequest.setPaymentId(payment.getPaymentId());
+ final InvoicePayment invoicePaymentRefund = killBillClient.createInvoicePaymentRefund(invoicePaymentTransactionRequest, true, requestOptions);
+ assertNotNull(invoicePaymentRefund);
+ assertEquals(invoicePaymentRefund.getCreditedAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
+
+ // TODO check account balance
+ // TODO check invoice items
+
+ }
+
+ @Test(groups = "slow", description = "#255 - Scenario 2a - Can refund an automatic payment though an external refund over item adjustments")
+ public void testAutomaticPaymentAndExternalRefundWithAdjustments() throws Exception {
+ final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
+ clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
+
+ final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
+ // delete PM
+ killBillClient.deletePaymentMethod(accountJson.getPaymentMethodId(), true, true, requestOptions);
+ final Payments paymentsForAccount = killBillClient.getPaymentsForAccount(accountJson.getAccountId(), requestOptions);
+ final Payment payment = paymentsForAccount.get(paymentsForAccount.size() - 1);
+
+ final Invoices invoices = killBillClient.getInvoicesForAccount(accountJson.getAccountId(), true, true, requestOptions);
+ final List<InvoiceItem> itemsToBeAdjusted = invoices.get(1).getItems();
+
+ // external refund
+ final InvoicePaymentTransaction invoicePaymentTransactionRequest = new InvoicePaymentTransaction();
+ invoicePaymentTransactionRequest.setAmount(BigDecimal.valueOf(249.95));
+ invoicePaymentTransactionRequest.setCurrency(accountJson.getCurrency().toString());
+ invoicePaymentTransactionRequest.setPaymentId(payment.getPaymentId());
+ invoicePaymentTransactionRequest.setIsAdjusted(true);
+ invoicePaymentTransactionRequest.setAdjustments(itemsToBeAdjusted);
+ final InvoicePayment invoicePaymentRefund = killBillClient.createInvoicePaymentRefund(invoicePaymentTransactionRequest, true, requestOptions);
+ assertNotNull(invoicePaymentRefund);
+ assertEquals(invoicePaymentRefund.getCreditedAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
+
+ // TODO check account balance
+ // TODO check invoice items
+
+ }
+
+ @Test(groups = "slow", description = "#255 - Scenario 2b - Can refund an automatic payment though an external refund")
+ public void testAutomaticPaymentAndRefundWithDifferentPM() throws Exception {
+ final DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
+ clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
+
+ final Account accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
+
+ // TODO complete test
+
+ }
+
+}