killbill-memoizeit

Details

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();