Details
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 f6e6eea..dc7488c 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
@@ -13,6 +13,7 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
+
package com.ning.billing.payment.api;
import java.math.BigDecimal;
@@ -28,17 +29,20 @@ public interface PaymentApi {
public Payment createPayment(final Account account, final UUID invoiceId, final BigDecimal amount, final CallContext context)
throws PaymentApiException;
+ public Payment createExternalPayment(final Account account, final UUID invoiceId, final BigDecimal amount, final CallContext context)
+ throws PaymentApiException;
+
public Refund getRefund(final UUID refundId)
- throws PaymentApiException;
+ throws PaymentApiException;
public Refund createRefund(final Account account, final UUID paymentId, final BigDecimal refundAmount, final boolean isAdjusted, final CallContext context)
- throws PaymentApiException;
+ throws PaymentApiException;
public List<Refund> getAccountRefunds(final Account account)
- throws PaymentApiException;
+ throws PaymentApiException;
public List<Refund> getPaymentRefunds(final UUID paymentId)
- throws PaymentApiException;
+ throws PaymentApiException;
public List<Payment> getInvoicePayments(final UUID invoiceId)
throws PaymentApiException;
@@ -50,8 +54,8 @@ public interface PaymentApi {
throws PaymentApiException;
/*
- * Payment method Apis
- */
+ * Payment method Apis
+ */
public Set<String> getAvailablePlugins();
public String initializeAccountPlugin(final String pluginName, final Account account)
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 7a9c201..20560e6 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
@@ -64,6 +64,7 @@ import com.ning.billing.util.api.CustomFieldUserApi;
import com.ning.billing.util.api.TagApiException;
import com.ning.billing.util.api.TagDefinitionApiException;
import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.callcontext.CallContext;
import com.ning.billing.util.dao.ObjectType;
import com.google.inject.Inject;
@@ -188,12 +189,16 @@ public class InvoiceResource extends JaxRsResourceBase {
@HeaderParam(HDR_CREATED_BY) final String createdBy,
@HeaderParam(HDR_REASON) final String reason,
@HeaderParam(HDR_COMMENT) final String comment) throws AccountApiException, PaymentApiException {
+ final Account account = accountApi.getAccountById(UUID.fromString(payment.getAccountId()));
+
+ final UUID invoiceId = UUID.fromString(payment.getInvoiceId());
+ final CallContext callContext = context.createContext(createdBy, reason, comment);
if (externalPayment) {
- return Response.status(Status.BAD_REQUEST).entity("External payments have not been implemented yet").build();
+ paymentApi.createExternalPayment(account, invoiceId, payment.getAmount(), callContext);
+ } else {
+ paymentApi.createPayment(account, invoiceId, payment.getAmount(), callContext);
}
- final Account account = accountApi.getAccountById(UUID.fromString(payment.getAccountId()));
- paymentApi.createPayment(account, UUID.fromString(payment.getInvoiceId()), null, context.createContext(createdBy, reason, comment));
return uriBuilder.buildResponse(InvoiceResource.class, "getPayments", payment.getInvoiceId());
}
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 c2e2fb2..b4631a2 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
@@ -21,7 +21,6 @@ import java.util.List;
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.PaymentMethodProcessor;
@@ -29,8 +28,9 @@ import com.ning.billing.payment.core.PaymentProcessor;
import com.ning.billing.payment.core.RefundProcessor;
import com.ning.billing.util.callcontext.CallContext;
-public class DefaultPaymentApi implements PaymentApi {
+import com.google.inject.Inject;
+public class DefaultPaymentApi implements PaymentApi {
private final PaymentMethodProcessor methodProcessor;
private final PaymentProcessor paymentProcessor;
@@ -48,7 +48,12 @@ public class DefaultPaymentApi implements PaymentApi {
@Override
public Payment createPayment(final Account account, final UUID invoiceId,
final BigDecimal amount, final CallContext context) throws PaymentApiException {
- return paymentProcessor.createPayment(account, invoiceId, amount, context, true);
+ return paymentProcessor.createPayment(account, invoiceId, amount, context, true, false);
+ }
+
+ @Override
+ public Payment createExternalPayment(final Account account, final UUID invoiceId, final BigDecimal amount, final CallContext context) throws PaymentApiException {
+ return paymentProcessor.createPayment(account, invoiceId, amount, context, true, true);
}
@Override
@@ -71,16 +76,14 @@ public class DefaultPaymentApi implements PaymentApi {
return paymentProcessor.getAccountPayments(accountId);
}
-
-
@Override
- public Refund getRefund(UUID refundId) throws PaymentApiException {
+ public Refund getRefund(final UUID refundId) throws PaymentApiException {
return refundProcessor.getRefund(refundId);
}
@Override
- public Refund createRefund(Account account, UUID paymentId,
- BigDecimal refundAmount, boolean isAdjusted, CallContext context)
+ public Refund createRefund(final Account account, final UUID paymentId,
+ final BigDecimal refundAmount, final boolean isAdjusted, final CallContext context)
throws PaymentApiException {
if (refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) {
throw new PaymentApiException(ErrorCode.PAYMENT_REFUND_AMOUNT_NEGATIVE_OR_NULL);
@@ -90,31 +93,28 @@ public class DefaultPaymentApi implements PaymentApi {
}
@Override
- public List<Refund> getAccountRefunds(Account account)
+ public List<Refund> getAccountRefunds(final Account account)
throws PaymentApiException {
return refundProcessor.getAccountRefunds(account);
}
@Override
- public List<Refund> getPaymentRefunds(UUID paymentId)
+ public List<Refund> getPaymentRefunds(final UUID paymentId)
throws PaymentApiException {
return refundProcessor.getPaymentRefunds(paymentId);
}
-
@Override
public Set<String> getAvailablePlugins() {
return methodProcessor.getAvailablePlugins();
}
-
@Override
public String initializeAccountPlugin(final String pluginName, final Account account)
throws PaymentApiException {
return methodProcessor.initializeAccountPlugin(pluginName, account);
}
-
@Override
public UUID addPaymentMethod(final String pluginName, final Account account,
final boolean setDefault, final PaymentMethodPlugin paymentMethodInfo, final CallContext context)
@@ -122,7 +122,6 @@ public class DefaultPaymentApi implements PaymentApi {
return methodProcessor.addPaymentMethod(pluginName, account, setDefault, paymentMethodInfo, context);
}
-
@Override
public List<PaymentMethod> refreshPaymentMethods(final String pluginName,
final Account account, final CallContext context)
diff --git a/payment/src/main/java/com/ning/billing/payment/bus/InvoiceHandler.java b/payment/src/main/java/com/ning/billing/payment/bus/InvoiceHandler.java
index 527a776..a690ea7 100644
--- a/payment/src/main/java/com/ning/billing/payment/bus/InvoiceHandler.java
+++ b/payment/src/main/java/com/ning/billing/payment/bus/InvoiceHandler.java
@@ -70,7 +70,7 @@ public class InvoiceHandler {
final CallContext context = new DefaultCallContext("PaymentRequestProcessor", CallOrigin.INTERNAL, UserType.SYSTEM, event.getUserToken(), clock);
account = accountUserApi.getAccountById(event.getAccountId());
- paymentProcessor.createPayment(account, event.getInvoiceId(), null, context, false);
+ paymentProcessor.createPayment(account, event.getInvoiceId(), null, context, false, false);
} catch (AccountApiException e) {
log.error("Failed to process invoice payment", e);
} catch (PaymentApiException e) {
diff --git a/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
index d0f9612..83e4146 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
@@ -42,10 +42,13 @@ import com.ning.billing.payment.api.DefaultPaymentMethodPlugin;
import com.ning.billing.payment.api.PaymentApiException;
import com.ning.billing.payment.api.PaymentMethod;
import com.ning.billing.payment.api.PaymentMethodPlugin;
+import com.ning.billing.payment.api.PaymentMethodPlugin.PaymentMethodKVInfo;
import com.ning.billing.payment.dao.PaymentDao;
import com.ning.billing.payment.dao.PaymentMethodModelDao;
import com.ning.billing.payment.plugin.api.PaymentPluginApi;
import com.ning.billing.payment.plugin.api.PaymentPluginApiException;
+import com.ning.billing.payment.provider.DefaultNoOpPaymentMethodPlugin;
+import com.ning.billing.payment.provider.ExternalPaymentProviderPlugin;
import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
import com.ning.billing.util.bus.Bus;
import com.ning.billing.util.callcontext.CallContext;
@@ -189,6 +192,27 @@ public class PaymentMethodProcessor extends ProcessorBase {
return (result.size() == 0) ? null : result.get(0);
}
+ public PaymentMethod getExternalPaymentMethod(final Account account) throws PaymentApiException {
+ final List<PaymentMethod> paymentMethods = getPaymentMethods(account, false);
+ for (final PaymentMethod paymentMethod : paymentMethods) {
+ if (ExternalPaymentProviderPlugin.PLUGIN_NAME.equals(paymentMethod.getPluginName())) {
+ return paymentMethod;
+ }
+ }
+
+ return null;
+ }
+
+ public ExternalPaymentProviderPlugin getExternalPaymentProviderPlugin(final Account account, final CallContext context) throws PaymentApiException {
+ // Check if this account has already used the external payment plugin
+ // If not, it's the first time - add a payment method for it
+ if (getExternalPaymentMethod(account) == null) {
+ final DefaultNoOpPaymentMethodPlugin props = new DefaultNoOpPaymentMethodPlugin(UUID.randomUUID().toString(), false, ImmutableList.<PaymentMethodKVInfo>of());
+ addPaymentMethod(ExternalPaymentProviderPlugin.PLUGIN_NAME, account, false, props, context);
+ }
+
+ return (ExternalPaymentProviderPlugin) pluginRegistry.getPlugin(ExternalPaymentProviderPlugin.PLUGIN_NAME);
+ }
private List<PaymentMethod> getPaymentMethodInternal(final List<PaymentMethodModelDao> paymentMethodModels, final UUID accountId, final String accountKey, final boolean withPluginDetail)
throws PaymentApiException {
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 c6d29a0..e0e64f4 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
@@ -15,6 +15,7 @@
*/
package com.ning.billing.payment.core;
+import javax.annotation.Nullable;
import javax.inject.Inject;
import java.math.BigDecimal;
import java.math.RoundingMode;
@@ -78,6 +79,7 @@ import static com.ning.billing.payment.glue.PaymentModule.PLUGIN_EXECUTOR_NAMED;
public class PaymentProcessor extends ProcessorBase {
+ private final PaymentMethodProcessor paymentMethodProcessor;
private final InvoicePaymentApi invoicePaymentApi;
private final TagUserApi tagUserApi;
private final FailedPaymentRetryServiceScheduler failedPaymentRetryService;
@@ -95,19 +97,21 @@ public class PaymentProcessor extends ProcessorBase {
@Inject
public PaymentProcessor(final PaymentProviderPluginRegistry pluginRegistry,
- final AccountUserApi accountUserApi,
- final InvoicePaymentApi invoicePaymentApi,
- final TagUserApi tagUserApi,
- final FailedPaymentRetryServiceScheduler failedPaymentRetryService,
- final PluginFailureRetryServiceScheduler pluginFailureRetryService,
- final AutoPayRetryServiceScheduler autoPayoffRetryService,
- final PaymentDao paymentDao,
- final Bus eventBus,
- final Clock clock,
- final GlobalLocker locker,
- @Named(PLUGIN_EXECUTOR_NAMED) final ExecutorService executor,
- final CallContextFactory factory) {
+ final PaymentMethodProcessor paymentMethodProcessor,
+ final AccountUserApi accountUserApi,
+ final InvoicePaymentApi invoicePaymentApi,
+ final TagUserApi tagUserApi,
+ final FailedPaymentRetryServiceScheduler failedPaymentRetryService,
+ final PluginFailureRetryServiceScheduler pluginFailureRetryService,
+ final AutoPayRetryServiceScheduler autoPayoffRetryService,
+ final PaymentDao paymentDao,
+ final Bus eventBus,
+ final Clock clock,
+ final GlobalLocker locker,
+ @Named(PLUGIN_EXECUTOR_NAMED) final ExecutorService executor,
+ final CallContextFactory factory) {
super(pluginRegistry, accountUserApi, eventBus, paymentDao, locker, executor);
+ this.paymentMethodProcessor = paymentMethodProcessor;
this.invoicePaymentApi = invoicePaymentApi;
this.tagUserApi = tagUserApi;
this.failedPaymentRetryService = failedPaymentRetryService;
@@ -197,9 +201,19 @@ public class PaymentProcessor extends ProcessorBase {
}
}
- public Payment createPayment(final Account account, final UUID invoiceId, final BigDecimal inputAmount, final CallContext context, final boolean isInstantPayment)
- throws PaymentApiException {
- final PaymentPluginApi plugin = getPaymentProviderPlugin(account);
+ public Payment createPayment(final Account account, final UUID invoiceId, @Nullable final BigDecimal inputAmount,
+ final CallContext context, final boolean isInstantPayment, final boolean isExternalPayment)
+ throws PaymentApiException {
+ // Use the special external payment plugin to handle external payments
+ final PaymentPluginApi plugin;
+ final UUID paymentMethodId;
+ if (isExternalPayment) {
+ plugin = paymentMethodProcessor.getExternalPaymentProviderPlugin(account, context);
+ paymentMethodId = paymentMethodProcessor.getExternalPaymentMethod(account).getId();
+ } else {
+ plugin = getPaymentProviderPlugin(account);
+ paymentMethodId = account.getPaymentMethodId();
+ }
try {
return paymentPluginDispatcher.dispatchWithAccountLock(new CallableWithAccountLock<Payment>(locker,
@@ -225,9 +239,9 @@ public class PaymentProcessor extends ProcessorBase {
final BigDecimal requestedAmount = getAndValidatePaymentAmount(invoice, inputAmount, isInstantPayment);
if (isAccountAutoPayOff) {
- return processNewPaymentForAutoPayOffWithAccountLocked(account, invoice, requestedAmount, context);
+ return processNewPaymentForAutoPayOffWithAccountLocked(paymentMethodId, account, invoice, requestedAmount, context);
} else {
- return processNewPaymentWithAccountLocked(plugin, account, invoice, requestedAmount, isInstantPayment, context);
+ return processNewPaymentWithAccountLocked(paymentMethodId, plugin, account, invoice, requestedAmount, isInstantPayment, context);
}
}
}));
@@ -285,7 +299,7 @@ public class PaymentProcessor extends ProcessorBase {
- private BigDecimal getAndValidatePaymentAmount(final Invoice invoice, final BigDecimal inputAmount, final boolean isInstantPayment)
+ private BigDecimal getAndValidatePaymentAmount(final Invoice invoice, @Nullable final BigDecimal inputAmount, final boolean isInstantPayment)
throws PaymentApiException {
if (invoice.getBalance().compareTo(BigDecimal.ZERO) <= 0) {
@@ -297,7 +311,7 @@ public class PaymentProcessor extends ProcessorBase {
throw new PaymentApiException(ErrorCode.PAYMENT_AMOUNT_DENIED,
invoice.getId(), inputAmount.floatValue(), invoice.getBalance().floatValue());
}
- BigDecimal result = inputAmount != null ? inputAmount : invoice.getBalance();
+ final BigDecimal result = inputAmount != null ? inputAmount : invoice.getBalance();
return result.setScale(2, RoundingMode.HALF_EVEN);
}
@@ -388,24 +402,21 @@ public class PaymentProcessor extends ProcessorBase {
}
}
- private Payment processNewPaymentForAutoPayOffWithAccountLocked(final Account account, final Invoice invoice, final BigDecimal requestedAmount, final CallContext context)
- throws PaymentApiException {
-
- final PaymentStatus paymentStatus = PaymentStatus.AUTO_PAY_OFF;
+ private Payment processNewPaymentForAutoPayOffWithAccountLocked(final UUID paymentMethodId, final Account account, final Invoice invoice,
+ final BigDecimal requestedAmount, final CallContext context)
+ throws PaymentApiException {
+ final PaymentStatus paymentStatus = PaymentStatus.AUTO_PAY_OFF;
- final PaymentModelDao paymentInfo = new PaymentModelDao(account.getId(), invoice.getId(), account.getPaymentMethodId(), requestedAmount, invoice.getCurrency(), clock.getUTCNow(), paymentStatus);
+ final PaymentModelDao paymentInfo = new PaymentModelDao(account.getId(), invoice.getId(), paymentMethodId, requestedAmount, invoice.getCurrency(), clock.getUTCNow(), paymentStatus);
final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), paymentInfo.getId(), paymentStatus, clock.getUTCNow(), requestedAmount);
paymentDao.insertPaymentWithAttempt(paymentInfo, attempt, context);
return new DefaultPayment(paymentInfo, Collections.singletonList(attempt), Collections.<RefundModelDao>emptyList());
}
-
- private Payment processNewPaymentWithAccountLocked(final PaymentPluginApi plugin, final Account account, final Invoice invoice,
- final BigDecimal requestedAmount, final boolean isInstantPayment, final CallContext context) throws PaymentApiException {
-
-
- final PaymentModelDao payment = new PaymentModelDao(account.getId(), invoice.getId(), account.getPaymentMethodId(), requestedAmount.setScale(2, RoundingMode.HALF_EVEN), invoice.getCurrency(), clock.getUTCNow());
+ private Payment processNewPaymentWithAccountLocked(final UUID paymentMethodId, final PaymentPluginApi plugin, final Account account, final Invoice invoice,
+ final BigDecimal requestedAmount, final boolean isInstantPayment, final CallContext context) throws PaymentApiException {
+ final PaymentModelDao payment = new PaymentModelDao(account.getId(), invoice.getId(), paymentMethodId, requestedAmount.setScale(2, RoundingMode.HALF_EVEN), invoice.getCurrency(), clock.getUTCNow());
final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), payment.getId(), clock.getUTCNow(), requestedAmount);
final PaymentModelDao savedPayment = paymentDao.insertPaymentWithAttempt(payment, attempt, context);
diff --git a/payment/src/test/java/com/ning/billing/payment/core/TestPaymentMethodProcessor.java b/payment/src/test/java/com/ning/billing/payment/core/TestPaymentMethodProcessor.java
new file mode 100644
index 0000000..8b80f43
--- /dev/null
+++ b/payment/src/test/java/com/ning/billing/payment/core/TestPaymentMethodProcessor.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2010-2012 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.payment.core;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.ExecutorService;
+
+import org.mockito.Mockito;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.config.PaymentConfig;
+import com.ning.billing.payment.PaymentTestSuite;
+import com.ning.billing.payment.api.PaymentMethod;
+import com.ning.billing.payment.dao.MockPaymentDao;
+import com.ning.billing.payment.provider.DefaultPaymentProviderPluginRegistry;
+import com.ning.billing.payment.provider.ExternalPaymentProviderPlugin;
+import com.ning.billing.util.bus.Bus;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.globallocker.GlobalLocker;
+
+public class TestPaymentMethodProcessor extends PaymentTestSuite {
+
+ private PaymentMethodProcessor processor;
+
+ @BeforeMethod
+ public void setUp() throws Exception {
+ final DefaultPaymentProviderPluginRegistry pluginRegistry = new DefaultPaymentProviderPluginRegistry(Mockito.mock(PaymentConfig.class));
+ pluginRegistry.register(new ExternalPaymentProviderPlugin(new ClockMock()), ExternalPaymentProviderPlugin.PLUGIN_NAME);
+
+ final AccountUserApi accountUserApi = Mockito.mock(AccountUserApi.class);
+ final Bus bus = Mockito.mock(Bus.class);
+ final MockPaymentDao paymentDao = new MockPaymentDao();
+ final GlobalLocker globalLocker = Mockito.mock(GlobalLocker.class);
+ final ExecutorService executorService = Mockito.mock(ExecutorService.class);
+ processor = new PaymentMethodProcessor(pluginRegistry, accountUserApi, bus, paymentDao, globalLocker, executorService);
+ }
+
+ @Test(groups = "fast")
+ public void testGetExternalPaymentProviderPlugin() throws Exception {
+ final UUID accountId = UUID.randomUUID();
+ final Account account = Mockito.mock(Account.class);
+ Mockito.when(account.getId()).thenReturn(accountId);
+ Mockito.when(account.getExternalKey()).thenReturn(accountId.toString());
+ final CallContext context = Mockito.mock(CallContext.class);
+
+ Assert.assertEquals(processor.getPaymentMethods(account, false).size(), 0);
+
+ // The first call should create the payment method
+ final ExternalPaymentProviderPlugin providerPlugin = processor.getExternalPaymentProviderPlugin(account, context);
+ Assert.assertEquals(providerPlugin.getName(), ExternalPaymentProviderPlugin.PLUGIN_NAME);
+ final List<PaymentMethod> paymentMethods = processor.getPaymentMethods(account, false);
+ Assert.assertEquals(paymentMethods.size(), 1);
+ Assert.assertEquals(paymentMethods.get(0).getPluginName(), ExternalPaymentProviderPlugin.PLUGIN_NAME);
+ Assert.assertEquals(paymentMethods.get(0).getAccountId(), account.getId());
+
+ // The succeeding calls should not create any other payment method
+ final UUID externalPaymentMethodId = paymentMethods.get(0).getId();
+ for (int i = 0; i < 50; i++) {
+ final ExternalPaymentProviderPlugin foundProviderPlugin = processor.getExternalPaymentProviderPlugin(account, context);
+ Assert.assertEquals(foundProviderPlugin.getName(), ExternalPaymentProviderPlugin.PLUGIN_NAME);
+
+ final List<PaymentMethod> foundPaymentMethods = processor.getPaymentMethods(account, false);
+ Assert.assertEquals(foundPaymentMethods.size(), 1);
+ Assert.assertEquals(foundPaymentMethods.get(0).getPluginName(), ExternalPaymentProviderPlugin.PLUGIN_NAME);
+ Assert.assertEquals(foundPaymentMethods.get(0).getAccountId(), account.getId());
+ Assert.assertEquals(foundPaymentMethods.get(0).getId(), externalPaymentMethodId);
+ }
+ }
+}
diff --git a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
index aef8f1b..0c021a6 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
@@ -172,7 +172,7 @@ public class TestRetryService extends PaymentTestSuite {
setPaymentFailure(failureType);
boolean failed = false;
try {
- paymentProcessor.createPayment(account, invoice.getId(), amount, context, false);
+ paymentProcessor.createPayment(account, invoice.getId(), amount, context, false, false);
} catch (PaymentApiException e) {
failed = true;
}
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 b6b73fb..4efe6cb 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
@@ -36,14 +36,18 @@ import com.ning.billing.jaxrs.json.AccountJson;
import com.ning.billing.jaxrs.json.BundleJsonNoSubscriptions;
import com.ning.billing.jaxrs.json.InvoiceJsonSimple;
import com.ning.billing.jaxrs.json.PaymentJsonSimple;
+import com.ning.billing.jaxrs.json.PaymentMethodJson;
import com.ning.billing.jaxrs.json.SubscriptionJsonNoEvents;
import com.ning.billing.jaxrs.resources.JaxrsResource;
+import com.ning.billing.payment.provider.ExternalPaymentProviderPlugin;
import com.ning.http.client.Response;
import com.fasterxml.jackson.core.type.TypeReference;
+import com.google.common.collect.ImmutableMap;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
public class TestInvoice extends TestJaxrsBase {
@@ -222,4 +226,71 @@ public class TestInvoice extends TestJaxrsBase {
assertTrue(cur.getAmount().compareTo(objFromJson.get(0).getAmount()) == 0);
}
}
+
+ @Test(groups = "slow")
+ public void testExternalPayment() throws Exception {
+ // Create an account with no payment method
+ final AccountJson accountJson = createAccount("eraahahildo", "sheqrgfhwe", "eraahahildo@yahoo.com");
+ assertNotNull(accountJson);
+
+ // Add a bundle, subscription and move the clock to get the first invoice
+ final BundleJsonNoSubscriptions bundleJson = createBundle(accountJson.getAccountId(), "317199");
+ assertNotNull(bundleJson);
+ final SubscriptionJsonNoEvents subscriptionJson = createSubscription(bundleJson.getBundleId(), "Shotgun", ProductCategory.BASE.toString(), BillingPeriod.MONTHLY.toString(), true);
+ assertNotNull(subscriptionJson);
+ clock.addMonths(1);
+ crappyWaitForLackOfProperSynchonization();
+
+ final String paymentsURI = JaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAccountId() + "/" + JaxrsResource.PAYMENTS;
+
+ // Verify we didn't get any payment
+ final Response noPaymentsResponse = doGet(paymentsURI, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(noPaymentsResponse.getStatusCode(), Status.OK.getStatusCode());
+ final String noPaymentsBaseJson = noPaymentsResponse.getResponseBody();
+ final List<PaymentJsonSimple> noPaymentsFromJson = mapper.readValue(noPaymentsBaseJson, new TypeReference<List<PaymentJsonSimple>>() {});
+ assertEquals(noPaymentsFromJson.size(), 0);
+
+ // Get the invoices
+ final Map<String, String> queryParams = new HashMap<String, String>();
+ queryParams.put(JaxrsResource.QUERY_ACCOUNT_ID, accountJson.getAccountId());
+ final String invoicesURI = JaxrsResource.INVOICES_PATH;
+ final Response invoicesResponse = doGet(invoicesURI, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(invoicesResponse.getStatusCode(), Status.OK.getStatusCode());
+ final String invoicesBaseJson = invoicesResponse.getResponseBody();
+ final List<InvoiceJsonSimple> invoices = mapper.readValue(invoicesBaseJson, new TypeReference<List<InvoiceJsonSimple>>() {});
+ assertNotNull(invoices);
+ // 2 invoices but look for the non zero dollar one
+ assertEquals(invoices.size(), 2);
+ final String invoiceId = invoices.get(1).getInvoiceId();
+
+ // Post an external payment
+ final BigDecimal paidAmount = BigDecimal.TEN;
+ final PaymentJsonSimple payment = new PaymentJsonSimple(paidAmount, BigDecimal.ZERO, accountJson.getAccountId(),
+ invoiceId, null, null, null, null, 0,
+ null, null, null, null, null, null);
+ final String postJson = mapper.writeValueAsString(payment);
+ final String paymentURI = JaxrsResource.INVOICES_PATH + "/" + invoiceId + "/" + JaxrsResource.PAYMENTS;
+ final Response paymentResponse = doPost(paymentURI, postJson, ImmutableMap.<String, String>of("externalPayment", "true"), DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(paymentResponse.getStatusCode(), Status.CREATED.getStatusCode());
+
+ // Verify we indeed got the payment
+ final Response paymentsResponse = doGet(paymentsURI, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(paymentsResponse.getStatusCode(), Status.OK.getStatusCode());
+ final String paymentsBaseJson = paymentsResponse.getResponseBody();
+ final List<PaymentJsonSimple> paymentsFromJson = mapper.readValue(paymentsBaseJson, new TypeReference<List<PaymentJsonSimple>>() {});
+ assertEquals(paymentsFromJson.size(), 1);
+ assertEquals(paymentsFromJson.get(0).getPaidAmount().compareTo(paidAmount), 0);
+
+ // Check the PaymentMethod from paymentMethodId returned in the Payment object
+ final String paymentMethodId = paymentsFromJson.get(0).getPaymentMethodId();
+ final String paymentMethodURI = JaxrsResource.PAYMENT_METHODS_PATH + "/" + paymentMethodId;
+
+ final Response paymentMethodResponse = doGet(paymentMethodURI, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+ assertEquals(paymentMethodResponse.getStatusCode(), Status.OK.getStatusCode());
+ final PaymentMethodJson paymentMethodJson = mapper.readValue(paymentMethodResponse.getResponseBody(), PaymentMethodJson.class);
+ assertEquals(paymentMethodJson.getPaymentMethodId(), paymentMethodId);
+ assertEquals(paymentMethodJson.getAccountId(), accountJson.getAccountId());
+ assertEquals(paymentMethodJson.getPluginName(), ExternalPaymentProviderPlugin.PLUGIN_NAME);
+ assertNull(paymentMethodJson.getPluginInfo());
+ }
}