killbill-aplcache

Details

diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/util/AuditChecker.java b/beatrix/src/test/java/org/killbill/billing/beatrix/util/AuditChecker.java
index e149511..2593ad3 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/util/AuditChecker.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/util/AuditChecker.java
@@ -34,6 +34,7 @@ import org.killbill.billing.invoice.api.InvoiceItem;
 import org.killbill.billing.invoice.dao.InvoiceItemSqlDao;
 import org.killbill.billing.invoice.dao.InvoiceSqlDao;
 import org.killbill.billing.payment.api.DirectPayment;
+import org.killbill.billing.payment.api.DirectPaymentTransaction;
 import org.killbill.billing.payment.dao.DirectPaymentSqlDao;
 import org.killbill.billing.subscription.engine.dao.BundleSqlDao;
 import org.killbill.billing.subscription.engine.dao.SubscriptionEventSqlDao;
@@ -88,14 +89,6 @@ public class AuditChecker {
         checkAuditLog(ChangeType.UPDATE, context, result.getAuditLogsForAccount().get(1), account.getId(), AccountSqlDao.class, true, true);
     }
 
-    public void checkPaymentCreated(final DirectPayment payment, final CallContext context) {
-        final AccountAuditLogs result = auditUserApi.getAccountAuditLogs(payment.getAccountId(), AuditLevel.FULL, context);
-        final List<AuditLog> paymentLogs = result.getAuditLogsForPayment(payment.getId());
-        Assert.assertEquals(paymentLogs.size(), 2);
-        checkAuditLog(ChangeType.INSERT, context, paymentLogs.get(0), payment.getId(), DirectPaymentSqlDao.class, true, false);
-        checkAuditLog(ChangeType.UPDATE, context, paymentLogs.get(1), payment.getId(), DirectPaymentSqlDao.class, true, false);
-    }
-
     /**
      * ********************************************  BUNDLE *******************************************************
      */
@@ -168,6 +161,22 @@ public class AuditChecker {
         }
     }
 
+    /**
+     * ********************************************  PAYMENT *******************************************************
+     */
+
+    public void checkPaymentCreated(final DirectPayment payment, final CallContext context) {
+        final List<AuditLog> invoiceLogs = getAuditLogForPayment(payment, context);
+        Assert.assertEquals(invoiceLogs.size(), 1);
+        checkAuditLog(ChangeType.INSERT, context, invoiceLogs.get(0), payment.getId(), DirectPaymentSqlDao.class, false, false);
+
+        for (DirectPaymentTransaction cur : payment.getTransactions()) {
+            final List<AuditLog> auditLogs = getAuditLogForPaymentTransaction(payment, cur, context);
+            Assert.assertEquals(auditLogs.size(), 1);
+            checkAuditLog(ChangeType.INSERT, context, auditLogs.get(0), cur.getId(), InvoiceItemSqlDao.class, false, false);
+        }
+    }
+
     private List<AuditLog> getAuditLogsForBundle(final UUID bundleId, final TenantContext context) {
         try {
             final SubscriptionBundle bundle = subscriptionApi.getSubscriptionBundle(bundleId, context);
@@ -206,6 +215,14 @@ public class AuditChecker {
         return auditUserApi.getAccountAuditLogs(invoiceItem.getAccountId(), AuditLevel.FULL, context).getAuditLogsForInvoiceItem(invoiceItem.getId());
     }
 
+    private List<AuditLog> getAuditLogForPayment(final DirectPayment payment, final TenantContext context) {
+        return auditUserApi.getAccountAuditLogs(payment.getAccountId(), AuditLevel.FULL, context).getAuditLogsForDirectPayment(payment.getId());
+    }
+
+    private List<AuditLog> getAuditLogForPaymentTransaction(final DirectPayment payment, final DirectPaymentTransaction paymentTransaction, final TenantContext context) {
+        return auditUserApi.getAccountAuditLogs(payment.getAccountId(), AuditLevel.FULL, context).getAuditLogsForDirectPaymentTransaction(paymentTransaction.getId());
+    }
+
     private void checkAuditLog(final ChangeType insert, final AuditLog auditLog) {
         checkAuditLog(insert, null, auditLog, null, EntitySqlDao.class, false, false);
     }
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/util/PaymentChecker.java b/beatrix/src/test/java/org/killbill/billing/beatrix/util/PaymentChecker.java
index a9d4520..a1eb39e 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/util/PaymentChecker.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/util/PaymentChecker.java
@@ -25,14 +25,18 @@ import java.util.UUID;
 import org.joda.time.LocalDate;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.payment.api.DirectPayment;
+import org.killbill.billing.payment.api.DirectPaymentTransaction;
 import org.killbill.billing.payment.api.PaymentApi;
 import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.PaymentStatus;
+import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
 import com.google.inject.Inject;
 
 public class PaymentChecker {
@@ -52,31 +56,40 @@ public class PaymentChecker {
         final List<DirectPayment> payments = paymentApi.getAccountPayments(accountId, context);
         Assert.assertEquals(payments.size(), paymentOrderingNumber);
         final DirectPayment payment = payments.get(paymentOrderingNumber - 1);
-        // TODO [PAYMENT]
-        //if (payment.getPaymentStatus() == PaymentStatus.UNKNOWN) {
-        //    checkPaymentNoAuditForRuntimeException(accountId, payment, context, expected);
-        //} else {
-        //    checkPayment(accountId, payment, context, expected);
-        //}
+        final DirectPaymentTransaction transaction = getPurchaseTransaction(payment);
+        if (transaction.getPaymentStatus() == PaymentStatus.UNKNOWN) {
+            checkPaymentNoAuditForRuntimeException(accountId, payment, expected);
+        } else {
+            checkPayment(accountId, payment, context, expected);
+        }
         return payment;
     }
 
+    private DirectPaymentTransaction getPurchaseTransaction(final DirectPayment payment) {
+        return Iterables.tryFind(payment.getTransactions(), new Predicate<DirectPaymentTransaction>() {
+            @Override
+            public boolean apply(final DirectPaymentTransaction input) {
+                return input.getTransactionType() == TransactionType.PURCHASE;
+            }
+        }).get();
+    }
+
     private void checkPayment(final UUID accountId, final DirectPayment payment, final CallContext context, final ExpectedPaymentCheck expected) {
         Assert.assertEquals(payment.getAccountId(), accountId);
-        // TODO [PAYMENT]
-        //Assert.assertTrue(payment.getAmount().compareTo(expected.getAmount()) == 0);
-        //Assert.assertEquals(payment.getPaymentStatus(), expected.getStatus());
-        //Assert.assertEquals(payment.getInvoiceId(), expected.getInvoiceId());
+        final DirectPaymentTransaction transaction = getPurchaseTransaction(payment);
+        Assert.assertTrue(transaction.getAmount().compareTo(expected.getAmount()) == 0);
+        Assert.assertEquals(transaction.getPaymentStatus(), expected.getStatus());
+        Assert.assertEquals(payment.getExternalKey(), expected.getInvoiceId().toString());
         Assert.assertEquals(payment.getCurrency(), expected.getCurrency());
         auditChecker.checkPaymentCreated(payment, context);
     }
 
-    private void checkPaymentNoAuditForRuntimeException(final UUID accountId, final DirectPayment payment, final CallContext context, final ExpectedPaymentCheck expected) {
+    private void checkPaymentNoAuditForRuntimeException(final UUID accountId, final DirectPayment payment, final ExpectedPaymentCheck expected) {
         Assert.assertEquals(payment.getAccountId(), accountId);
-        // TODO [PAYMENT]
-        //Assert.assertTrue(payment.getAmount().compareTo(expected.getAmount()) == 0);
-        //Assert.assertEquals(payment.getPaymentStatus(), expected.getStatus());
-        //Assert.assertEquals(payment.getInvoiceId(), expected.getInvoiceId());
+        final DirectPaymentTransaction transaction = getPurchaseTransaction(payment);
+        Assert.assertTrue(transaction.getAmount().compareTo(expected.getAmount()) == 0);
+        Assert.assertEquals(transaction.getPaymentStatus(), expected.getStatus());
+        Assert.assertEquals(payment.getExternalKey(), expected.getInvoiceId());
         Assert.assertEquals(payment.getCurrency(), expected.getCurrency());
     }
 
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/util/RefundChecker.java b/beatrix/src/test/java/org/killbill/billing/beatrix/util/RefundChecker.java
index 68a04a1..479ca93 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/util/RefundChecker.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/util/RefundChecker.java
@@ -32,8 +32,10 @@ import org.killbill.billing.invoice.api.InvoicePaymentApi;
 import org.killbill.billing.invoice.api.InvoicePaymentType;
 import org.killbill.billing.invoice.api.InvoiceUserApi;
 import org.killbill.billing.payment.api.DirectPayment;
+import org.killbill.billing.payment.api.DirectPaymentTransaction;
 import org.killbill.billing.payment.api.PaymentApi;
 import org.killbill.billing.payment.api.PaymentApiException;
+import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -41,6 +43,7 @@ import org.testng.Assert;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
+import com.google.common.collect.Iterables;
 import com.google.inject.Inject;
 
 public class RefundChecker {
@@ -69,11 +72,11 @@ public class RefundChecker {
         final InvoicePayment invoicePayment = getInvoicePaymentEntry(paymentId, InvoicePaymentType.ATTEMPT, context);
 
         final DirectPayment refund = refunds.get(0);
-        Assert.assertEquals(refund.getId(), expected.getPaymentId());
+        final DirectPaymentTransaction refundTransaction = getRefundTransaction(refund);
+
+        Assert.assertEquals(refundTransaction.getDirectPaymentId(), expected.getPaymentId());
         Assert.assertEquals(refund.getCurrency(), expected.getCurrency());
-        // TODO [PAYMENT]
-        //Assert.assertEquals(refund.isAdjusted(), expected.isAdjusted);
-        Assert.assertEquals(refund.getRefundedAmount().compareTo(expected.getRefundAmount()), 0);
+        Assert.assertEquals(refundTransaction.getAmount().compareTo(expected.getRefundAmount()), 0);
 
         Assert.assertEquals(refundInvoicePayment.getPaymentId(), paymentId);
         Assert.assertEquals(refundInvoicePayment.getLinkedInvoicePaymentId(), invoicePayment.getId());
@@ -85,6 +88,15 @@ public class RefundChecker {
         return refund;
     }
 
+    private DirectPaymentTransaction getRefundTransaction(final DirectPayment payment) {
+        return Iterables.tryFind(payment.getTransactions(), new Predicate<DirectPaymentTransaction>() {
+            @Override
+            public boolean apply(final DirectPaymentTransaction input) {
+                return input.getTransactionType() == TransactionType.REFUND;
+            }
+        }).get();
+    }
+
     private InvoicePayment getInvoicePaymentEntry(final UUID paymentId, final InvoicePaymentType type, final CallContext context) {
         final List<InvoicePayment> invoicePayments = invoicePaymentApi.getInvoicePayments(paymentId, context);
         final Collection<InvoicePayment> refundInvoicePayments = Collections2.filter(invoicePayments, new Predicate<InvoicePayment>() {
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultDirectPaymentApi.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultDirectPaymentApi.java
index 6a0ea11..29ba0da 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultDirectPaymentApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultDirectPaymentApi.java
@@ -87,6 +87,7 @@ public class DefaultDirectPaymentApi implements DirectPaymentApi {
                                                           final Iterable<PluginProperty> properties, final PaymentOptions paymentOptions, final CallContext callContext) throws PaymentApiException {
         final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
 
+        // STEPH should throw PaymentApiException -- at least when coming from API; also add description.
         Preconditions.checkArgument(paymentMethodId != null || paymentOptions.isExternalPayment());
         final UUID nonNulPaymentMethodId = (paymentMethodId != null) ?
                                            paymentMethodId :
diff --git a/payment/src/main/java/org/killbill/billing/payment/control/InvoicePaymentControlPluginApi.java b/payment/src/main/java/org/killbill/billing/payment/control/InvoicePaymentControlPluginApi.java
index 08021d7..880e625 100644
--- a/payment/src/main/java/org/killbill/billing/payment/control/InvoicePaymentControlPluginApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/control/InvoicePaymentControlPluginApi.java
@@ -49,7 +49,6 @@ import org.killbill.billing.payment.retry.DefaultFailureCallResult;
 import org.killbill.billing.payment.retry.DefaultPriorPaymentControlResult;
 import org.killbill.billing.retry.plugin.api.PaymentControlApiException;
 import org.killbill.billing.retry.plugin.api.PaymentControlPluginApi;
-import org.killbill.billing.retry.plugin.api.UnknownEntryException;
 import org.killbill.billing.util.api.TagUserApi;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
@@ -163,8 +162,9 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
     }
 
     private PriorPaymentControlResult getPluginPurchaseResult(final PaymentControlContext paymentControlPluginContext, final InternalCallContext internalContext) throws PaymentControlApiException {
-        final UUID invoiceId = UUID.fromString(paymentControlPluginContext.getPaymentExternalKey());
+
         try {
+            final UUID invoiceId = UUID.fromString(paymentControlPluginContext.getPaymentExternalKey());
             final Invoice invoice = rebalanceAndGetInvoice(invoiceId, internalContext);
             final BigDecimal requestedAmount = validateAndComputePaymentAmount(invoice, paymentControlPluginContext.getAmount(), paymentControlPluginContext.isApiPayment());
             final boolean isAborted = requestedAmount.compareTo(BigDecimal.ZERO) == 0;
@@ -176,8 +176,9 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
                 return new DefaultPriorPaymentControlResult(isAborted, requestedAmount);
             }
         } catch (InvoiceApiException e) {
-            // Invoice is not known so return UnknownEntryException so caller knows whether or not it should try with other plugins
-            throw new UnknownEntryException();
+            throw new PaymentControlApiException(e);
+        } catch (IllegalArgumentException e) {
+            throw new PaymentControlApiException(e);
         }
     }
 
@@ -192,7 +193,7 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
 
         final DirectPaymentModelDao directPayment = paymentDao.getDirectPayment(paymentControlPluginContext.getPaymentId(), internalContext);
         if (directPayment == null) {
-            throw new UnknownEntryException();
+            throw new PaymentControlApiException();
         }
         // STEPH this check for invoice item but we also need to check that refundAmount is less or equal to paymentAmount - all refund.
         final BigDecimal amountToBeRefunded = computeRefundAmount(directPayment.getId(), paymentControlPluginContext.getAmount(), idWithAmount, internalContext);
@@ -239,7 +240,7 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
 
             return Objects.firstNonNull(specifiedRefundAmount, amountFromItems);
         } catch (InvoiceApiException e) {
-            throw new UnknownEntryException();
+            throw new PaymentControlApiException(e);
         }
     }
 
@@ -282,7 +283,7 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
         DateTime result = null;
         final List<Integer> retryDays = paymentConfig.getPaymentRetryDays();
         final int attemptsInState = getNumberAttemptsInState(purchasedTransactions, PaymentStatus.PAYMENT_FAILURE_ABORTED);
-        final int retryCount  = (attemptsInState - 1) >= 0 ?  (attemptsInState - 1) : 0;
+        final int retryCount = (attemptsInState - 1) >= 0 ? (attemptsInState - 1) : 0;
         if (retryCount < retryDays.size()) {
             int retryInDays;
             final DateTime nextRetryDate = clock.getUTCNow();
@@ -300,7 +301,7 @@ public final class InvoicePaymentControlPluginApi implements PaymentControlPlugi
 
         DateTime result = null;
         final int attemptsInState = getNumberAttemptsInState(purchasedTransactions, PaymentStatus.PLUGIN_FAILURE_ABORTED);
-        final int retryAttempt  = (attemptsInState - 1) >= 0 ?  (attemptsInState - 1) : 0;
+        final int retryAttempt = (attemptsInState - 1) >= 0 ? (attemptsInState - 1) : 0;
 
         if (retryAttempt < paymentConfig.getPluginFailureRetryMaxAttempts()) {
             int nbSec = paymentConfig.getPluginFailureRetryStart();
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/DirectPaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/DirectPaymentProcessor.java
index ea88d43..62e2199 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/DirectPaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/DirectPaymentProcessor.java
@@ -20,6 +20,7 @@ package org.killbill.billing.payment.core;
 
 import java.math.BigDecimal;
 import java.util.Comparator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.ExecutorService;
@@ -73,6 +74,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.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Ordering;
@@ -280,7 +282,6 @@ public class DirectPaymentProcessor extends ProcessorBase {
         return getDirectPayment(paymentModelDao, withPluginInfo, properties, tenantContext, internalTenantContext);
     }
 
-
     public DirectPayment getPaymentByExternalKey(final String paymentExternalKey, final boolean withPluginInfo, final Iterable<PluginProperty> properties, final TenantContext tenantContext, final InternalTenantContext internalTenantContext) throws PaymentApiException {
         final DirectPaymentModelDao paymentModelDao = paymentDao.getDirectPaymentByExternalKey(paymentExternalKey, internalTenantContext);
         if (paymentModelDao == null) {
@@ -290,8 +291,6 @@ public class DirectPaymentProcessor extends ProcessorBase {
 
     }
 
-
-
     public Pagination<DirectPayment> getPayments(final Long offset, final Long limit, final Iterable<PluginProperty> properties,
                                                  final TenantContext tenantContext, final InternalTenantContext internalTenantContext) {
         return getEntityPaginationFromPlugins(getAvailablePlugins(),
@@ -351,33 +350,40 @@ public class DirectPaymentProcessor extends ProcessorBase {
         final PaymentPluginApi pluginApi = getPaymentPluginApi(pluginName);
 
         return getEntityPagination(limit,
-                                   new SourcePaginationBuilder<List<PaymentTransactionInfoPlugin>, PaymentApiException>() {
+                                   new SourcePaginationBuilder<PaymentTransactionInfoPlugin, PaymentApiException>() {
                                        @Override
-                                       public Pagination<List<PaymentTransactionInfoPlugin>> build() throws PaymentApiException {
-/*
-                                           STEPH broken : either return Pagination<List<PaymentTransactionInfoPlugin>> or Pagination<PaymentTransactionInfoPlugin> but then getEntityPagination signature is broken.
-
+                                       public Pagination<PaymentTransactionInfoPlugin> build() throws PaymentApiException {
                                            try {
-                                               // return pluginApi.searchPayments(searchKey, offset, limit, properties, tenantContext);
+                                               return pluginApi.searchPayments(searchKey, offset, limit, properties, tenantContext);
                                            } catch (final PaymentPluginApiException e) {
                                                throw new PaymentApiException(e, ErrorCode.PAYMENT_PLUGIN_SEARCH_PAYMENTS, pluginName, searchKey);
                                            }
-*/
-                                           return null;
                                        }
 
                                    },
-                                   new Function<List<PaymentTransactionInfoPlugin>, DirectPayment>() {
+                                   new Function<PaymentTransactionInfoPlugin, DirectPayment>() {
+
+                                       final List<PaymentTransactionInfoPlugin> cachedPaymentTransactions = new LinkedList<PaymentTransactionInfoPlugin>();
+
                                        @Override
-                                       public DirectPayment apply(final List<PaymentTransactionInfoPlugin> pluginTransactions) {
+                                       public DirectPayment apply(final PaymentTransactionInfoPlugin pluginTransaction) {
 
-                                           if (pluginTransactions.size() == 0) {
+                                           if (pluginTransaction.getKbPaymentId() == null) {
                                                // Garbage from the plugin?
                                                log.debug("Plugin {} returned a payment without a kbPaymentId for searchKey {}", pluginName, searchKey);
                                                return null;
                                            }
 
-                                           return toDirectPayment(pluginTransactions.get(0).getKbPaymentId(), pluginTransactions, internalTenantContext);
+                                           if (cachedPaymentTransactions.isEmpty() ||
+                                               (cachedPaymentTransactions.get(0).getKbPaymentId().equals(pluginTransaction.getKbPaymentId()))) {
+                                               cachedPaymentTransactions.add(pluginTransaction);
+                                               return null;
+                                           } else {
+                                               final DirectPayment result = toDirectPayment(pluginTransaction.getKbPaymentId(), ImmutableList.<PaymentTransactionInfoPlugin>copyOf(cachedPaymentTransactions), internalTenantContext);
+                                               cachedPaymentTransactions.clear();
+                                               cachedPaymentTransactions.add(pluginTransaction);
+                                               return result;
+                                           }
                                        }
                                    }
                                   );
@@ -438,11 +444,11 @@ public class DirectPaymentProcessor extends ProcessorBase {
 
                 final PaymentTransactionInfoPlugin info = pluginTransactions != null ?
                                                           Iterables.tryFind(pluginTransactions, new Predicate<PaymentTransactionInfoPlugin>() {
-                    @Override
-                    public boolean apply(final PaymentTransactionInfoPlugin input) {
-                        return input.getKbTransactionPaymentId().equals(input.getKbTransactionPaymentId());
-                    }
-                }).orNull() : null;
+                                                              @Override
+                                                              public boolean apply(final PaymentTransactionInfoPlugin input) {
+                                                                  return input.getKbTransactionPaymentId().equals(input.getKbTransactionPaymentId());
+                                                              }
+                                                          }).orNull() : null;
 
                 return new DefaultDirectPaymentTransaction(input.getId(), input.getTransactionExternalKey(), input.getCreatedDate(), input.getUpdatedDate(), input.getDirectPaymentId(),
                                                            input.getTransactionType(), input.getEffectiveDate(), input.getPaymentStatus(), input.getAmount(), input.getCurrency(),
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PluginControlledPaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PluginControlledPaymentProcessor.java
index e25443e..488c4fd 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PluginControlledPaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PluginControlledPaymentProcessor.java
@@ -195,7 +195,7 @@ public class PluginControlledPaymentProcessor extends ProcessorBase {
             final CallContext callContext = internalCallContext.toCallContext(tenantId);
 
 
-            // STEPH
+            // STEPH Nope, keep the original transactionExternalKey
             final String newTransactionExternalKey = UUID.randomUUID().toString();
             final State state = pluginControlledDirectPaymentAutomatonRunner.fetchState(attempt.getStateName());
             pluginControlledDirectPaymentAutomatonRunner.run(state,
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentOperation.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentOperation.java
index 5001b3e..4386de1 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentOperation.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/DirectPaymentOperation.java
@@ -64,7 +64,7 @@ public abstract class DirectPaymentOperation extends PluginOperation implements 
     private OperationResult doSimpleOperationCallback() throws OperationException {
         try {
             return doOperation();
-        } catch (PaymentApiException e) {
+        } catch (final PaymentApiException e) {
             throw new OperationException(e, OperationResult.FAILURE);
         }
     }
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryOperationCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryOperationCallback.java
index 7db07c8..7d9bc41 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryOperationCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/RetryOperationCallback.java
@@ -39,13 +39,11 @@ import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.payment.core.DirectPaymentProcessor;
 import org.killbill.billing.payment.core.ProcessorBase.WithAccountLockCallback;
 import org.killbill.billing.payment.dispatcher.PluginDispatcher;
-import org.killbill.billing.payment.retry.DefaultPriorPaymentControlResult;
 import org.killbill.billing.retry.plugin.api.PaymentControlApiException;
 import org.killbill.billing.retry.plugin.api.PaymentControlPluginApi;
 import org.killbill.billing.retry.plugin.api.PaymentControlPluginApi.FailureCallResult;
 import org.killbill.billing.retry.plugin.api.PaymentControlPluginApi.PaymentControlContext;
 import org.killbill.billing.retry.plugin.api.PaymentControlPluginApi.PriorPaymentControlResult;
-import org.killbill.billing.retry.plugin.api.UnknownEntryException;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.commons.locker.GlobalLocker;
 import org.slf4j.Logger;
@@ -67,12 +65,8 @@ public abstract class RetryOperationCallback extends PluginOperation implements 
     private PriorPaymentControlResult getPluginResult(final String pluginName, final PaymentControlContext paymentControlContext) throws PaymentControlApiException {
 
         final PaymentControlPluginApi plugin = paymentControlPluginRegistry.getServiceForName(pluginName);
-        try {
-            final PriorPaymentControlResult result = plugin.priorCall(paymentControlContext);
-            return result;
-        } catch (UnknownEntryException e) {
-            return new DefaultPriorPaymentControlResult(true);
-        }
+        final PriorPaymentControlResult result = plugin.priorCall(paymentControlContext);
+        return result;
     }
 
     private DateTime getNextRetryDate(final String pluginName, final PaymentControlContext paymentControlContext) {
@@ -139,7 +133,7 @@ public abstract class RetryOperationCallback extends PluginOperation implements 
                     ((RetryableDirectPaymentStateContext) directPaymentStateContext).setResult(result);
                     final DirectPaymentTransaction transaction = ((RetryableDirectPaymentStateContext) directPaymentStateContext).getCurrentTransaction();
 
-                    success  = transaction.getPaymentStatus() == PaymentStatus.SUCCESS || transaction.getPaymentStatus() == PaymentStatus.PENDING;
+                    success = transaction.getPaymentStatus() == PaymentStatus.SUCCESS || transaction.getPaymentStatus() == PaymentStatus.PENDING;
 
                     if (success) {
                         final PaymentControlContext updatedPaymentControlContext = new DefaultPaymentControlContext(directPaymentStateContext.account,
@@ -178,8 +172,10 @@ public abstract class RetryOperationCallback extends PluginOperation implements 
                                                                      @Nullable final PaymentApiException e) throws OperationException {
                 final DateTime retryDate = getNextRetryDate(retryableDirectPaymentStateContext.getPluginName(), paymentControlContext);
                 if (retryDate == null) {
+                    // STEPH only throw if e is not null
                     throw new OperationException(e, OperationResult.EXCEPTION);
                 } else {
+                    // STEPH only throw if e is not null
                     ((RetryableDirectPaymentStateContext) directPaymentStateContext).setRetryDate(retryDate);
                     throw new OperationException(e, OperationResult.FAILURE);
                 }
diff --git a/payment/src/main/java/org/killbill/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java b/payment/src/main/java/org/killbill/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java
index 0cd965e..427402e 100644
--- a/payment/src/main/java/org/killbill/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java
+++ b/payment/src/main/java/org/killbill/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java
@@ -20,6 +20,7 @@ package org.killbill.billing.payment.provider;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -27,8 +28,6 @@ import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import javax.annotation.Nullable;
-
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.payment.api.PaymentMethodPlugin;
 import org.killbill.billing.payment.api.PluginProperty;
@@ -50,8 +49,6 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.LinkedListMultimap;
-import com.google.common.collect.Multimap;
 import com.google.inject.Inject;
 
 public class DefaultNoOpPaymentProviderPlugin implements NoOpPaymentPluginApi {
@@ -132,20 +129,19 @@ public class DefaultNoOpPaymentProviderPlugin implements NoOpPaymentPluginApi {
     @Override
     public Pagination<PaymentTransactionInfoPlugin> searchPayments(final String searchKey, final Long offset, final Long limit, final Iterable<PluginProperty> properties, final TenantContext tenantContext) throws PaymentPluginApiException {
 
-        /*
-            STEPH depends on how we fix pagination
-        Collections2.<PaymentTransactionInfoPlugin>filter(payments.values(),
-                                                          new Predicate<List<PaymentTransactionInfoPlugin>>() {
-                                                              @Override
-                                                              public boolean apply(final List<PaymentTransactionInfoPlugin> input) {
-                                                                  return (input.getKbPaymentId() != null && input.getKbPaymentId().toString().equals(searchKey)) ||
-                                                                         (input.getFirstPaymentReferenceId() != null && input.getFirstPaymentReferenceId().contains(searchKey)) ||
-                                                                         (input.getSecondPaymentReferenceId() != null && input.getSecondPaymentReferenceId().contains(searchKey));
-                                                              }
-                                                          }
-                                                         );
-
-        final ImmutableList<PaymentTransactionInfoPlugin> allResults = ImmutableList.<PaymentTransactionInfoPlugin>copyOf();
+        final List<PaymentTransactionInfoPlugin> flattenedTransactions = ImmutableList.copyOf(Iterables.concat(payments.values()));
+        final Collection<PaymentTransactionInfoPlugin> filteredTransactions = Collections2.<PaymentTransactionInfoPlugin>filter(flattenedTransactions,
+                                                                                                                                new Predicate<PaymentTransactionInfoPlugin>() {
+                                                                                                                                    @Override
+                                                                                                                                    public boolean apply(final PaymentTransactionInfoPlugin input) {
+                                                                                                                                        return (input.getKbPaymentId() != null && input.getKbPaymentId().toString().equals(searchKey)) ||
+                                                                                                                                               (input.getFirstPaymentReferenceId() != null && input.getFirstPaymentReferenceId().contains(searchKey)) ||
+                                                                                                                                               (input.getSecondPaymentReferenceId() != null && input.getSecondPaymentReferenceId().contains(searchKey));
+                                                                                                                                    }
+                                                                                                                                }
+                                                                                                                               );
+
+        final ImmutableList<PaymentTransactionInfoPlugin> allResults = ImmutableList.<PaymentTransactionInfoPlugin>copyOf(filteredTransactions);
 
         final List<PaymentTransactionInfoPlugin> results;
         if (offset >= allResults.size()) {
@@ -157,8 +153,6 @@ public class DefaultNoOpPaymentProviderPlugin implements NoOpPaymentPluginApi {
         }
 
         return new DefaultPagination<PaymentTransactionInfoPlugin>(offset, limit, (long) results.size(), (long) payments.values().size(), results.iterator());
-        */
-        return null;
     }
 
     @Override
@@ -257,7 +251,6 @@ public class DefaultNoOpPaymentProviderPlugin implements NoOpPaymentPluginApi {
             throw new PaymentPluginApiException("", String.format("No payment found for payment id %s (plugin %s)", kbPaymentId.toString(), PLUGIN_NAME));
         }
 
-
         final Iterable<PaymentTransactionInfoPlugin> refundTransactions = Iterables.filter(transactions, new Predicate<PaymentTransactionInfoPlugin>() {
             @Override
             public boolean apply(final PaymentTransactionInfoPlugin input) {
@@ -277,7 +270,6 @@ public class DefaultNoOpPaymentProviderPlugin implements NoOpPaymentPluginApi {
         return getInternalNoopPaymentInfoResult(kbPaymentId, kbTransactionId, TransactionType.REFUND, refundAmount, currency);
     }
 
-
     private PaymentTransactionInfoPlugin getInternalNoopPaymentInfoResult(final UUID kbPaymentId, final UUID kbTransactionId, final TransactionType transactionType, final BigDecimal amount, final Currency currency) throws PaymentPluginApiException {
         if (makeNextInvoiceFailWithException.getAndSet(false)) {
             throw new PaymentPluginApiException("", "test error");