diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
index 6368518..2e644a2 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentMethodProcessor.java
@@ -116,8 +116,15 @@ public class PaymentMethodProcessor extends ProcessorBase {
pluginApi = getPaymentPluginApi(paymentPluginServiceName);
pm = new DefaultPaymentMethod(paymentMethodExternalKey, account.getId(), paymentPluginServiceName, paymentMethodProps);
pluginApi.addPaymentMethod(account.getId(), pm.getId(), paymentMethodProps, setDefault, properties, callContext);
- final PaymentMethodModelDao pmModel = new PaymentMethodModelDao(pm.getId(), pm.getExternalKey(), pm.getCreatedDate(), pm.getUpdatedDate(),
- pm.getAccountId(), pm.getPluginName(), pm.isActive());
+
+ final String actualPaymentMethodExternalKey = retrieveActualPaymentMethodExternalKey(account, pm, pluginApi, properties, callContext, context);
+ final PaymentMethodModelDao pmModel = new PaymentMethodModelDao(pm.getId(),
+ actualPaymentMethodExternalKey,
+ pm.getCreatedDate(),
+ pm.getUpdatedDate(),
+ pm.getAccountId(),
+ pm.getPluginName(),
+ pm.isActive());
paymentDao.insertPaymentMethod(pmModel, context);
if (setDefault) {
@@ -135,6 +142,30 @@ public class PaymentMethodProcessor extends ProcessorBase {
uuidPluginNotificationDispatcher);
}
+ private String retrieveActualPaymentMethodExternalKey(final Account account, final PaymentMethod pm, final PaymentPluginApi pluginApi, final Iterable<PluginProperty> properties, final TenantContext callContext, final InternalCallContext context) {
+ // If the user specified an external key, use it
+ if (pm.getExternalKey() != null) {
+ return pm.getExternalKey();
+ }
+
+ // Otherwise, check if the plugin sets an external payment method id
+ final PaymentMethodPlugin paymentMethodPlugin;
+ try {
+ paymentMethodPlugin = pluginApi.getPaymentMethodDetail(account.getId(), pm.getId(), properties, callContext);
+ } catch (final PaymentPluginApiException e) {
+ log.warn("Error retrieving payment method " + pm.getId() + " from plugin " + pm.getPluginName(), e);
+ return null;
+ }
+
+ if (paymentMethodPlugin != null && paymentMethodPlugin.getExternalPaymentMethodId() != null) {
+ // An external payment method id is set but make sure it doesn't conflict with an existing one
+ final String externalKey = paymentMethodPlugin.getExternalPaymentMethodId();
+ return paymentDao.getPaymentMethodByExternalKeyIncludedDeleted(externalKey, context) == null ? externalKey : null;
+ } else {
+ return null;
+ }
+ }
+
public List<PaymentMethod> getPaymentMethods(final UUID accountId, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final InternalTenantContext context) throws PaymentApiException {
return getPaymentMethods(accountId, withPluginInfo, properties, buildTenantContext(context), context);
}
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentMethodProcessorNoDB.java b/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentMethodProcessorNoDB.java
index 522f3c4..fd355dc 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentMethodProcessorNoDB.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentMethodProcessorNoDB.java
@@ -24,6 +24,7 @@ import java.util.UUID;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.payment.PaymentTestSuiteNoDB;
import org.killbill.billing.payment.api.PaymentMethod;
+import org.killbill.billing.payment.api.PaymentMethodPlugin;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.payment.provider.ExternalPaymentProviderPlugin;
import org.mockito.Mockito;
@@ -35,6 +36,28 @@ import com.google.common.collect.ImmutableList;
public class TestPaymentMethodProcessorNoDB extends PaymentTestSuiteNoDB {
@Test(groups = "fast")
+ public void testPaymentMethodExternalKeySetByPluginIfNonSpecified() throws Exception {
+ final Account account = Mockito.mock(Account.class);
+ final PaymentMethodPlugin paymentMethodPlugin = Mockito.mock(PaymentMethodPlugin.class);
+ final Iterable<PluginProperty> properties = ImmutableList.<PluginProperty>of();
+
+ final String paymentMethodExternalKey = UUID.randomUUID().toString();
+ final UUID paymentMethodId1 = paymentMethodProcessor.addPaymentMethod(paymentMethodExternalKey, "__EXTERNAL_PAYMENT__", account, false, paymentMethodPlugin, properties, callContext, internalCallContext);
+ final PaymentMethod paymentMethod1 = paymentMethodProcessor.getPaymentMethodById(paymentMethodId1, false, false, properties, callContext, internalCallContext);
+ Assert.assertEquals(paymentMethod1.getExternalKey(), paymentMethodExternalKey);
+
+ // By default, the external payment plugin sets the external payment method id to "unknown"
+ final UUID paymentMethodId2 = paymentMethodProcessor.addPaymentMethod(null, "__EXTERNAL_PAYMENT__", account, false, paymentMethodPlugin, properties, callContext, internalCallContext);
+ final PaymentMethod paymentMethod2 = paymentMethodProcessor.getPaymentMethodById(paymentMethodId2, false, false, properties, callContext, internalCallContext);
+ Assert.assertEquals(paymentMethod2.getExternalKey(), "unknown");
+
+ // Make sure we don't try to set the same external key if the plugin returns duplicate external ids
+ final UUID paymentMethodId3 = paymentMethodProcessor.addPaymentMethod(null, "__EXTERNAL_PAYMENT__", account, false, paymentMethodPlugin, properties, callContext, internalCallContext);
+ final PaymentMethod paymentMethod3 = paymentMethodProcessor.getPaymentMethodById(paymentMethodId3, false, false, properties, callContext, internalCallContext);
+ Assert.assertNotEquals(paymentMethod3.getExternalKey(), "unknown");
+ }
+
+ @Test(groups = "fast")
public void testGetExternalPaymentProviderPlugin() throws Exception {
final Iterable<PluginProperty> properties = ImmutableList.<PluginProperty>of();
final UUID accountId = UUID.randomUUID();