killbill-aplcache

More ongoing payment rework

5/31/2012 11:23:40 PM

Changes

beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/MockPaymentInfoReceiver.java 53(+0 -53)

beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/PaymentTestModule.java 68(+0 -68)

beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestHelper.java 129(+0 -129)

beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestPaymentInvoiceIntegration.java 169(+0 -169)

beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestPaymentProvider.java 98(+0 -98)

payment/src/test/java/com/ning/billing/payment/api/TestMockPaymentApi.java 36(+0 -36)

Details

diff --git a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentInfoPlugin.java b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentInfoPlugin.java
index 344d1c0..aac15fa 100644
--- a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentInfoPlugin.java
+++ b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentInfoPlugin.java
@@ -36,24 +36,4 @@ public interface PaymentInfoPlugin {
     public PaymentPluginStatus getStatus();
     
     public String getError();
-    
-    
-    /** 
-     * STEPH  
-
-     * Zuora specific
-
-    public String getExternalPaymentId();
-    
-    public String getReferenceId();
-    
-    public String getPaymentMethodId();
-
-    public String getPaymentNumber();
-
-    public String getStatus();
-
-    public String getType();
-     *
-     */    
 }
diff --git a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentProviderPlugin.java b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentProviderPlugin.java
index 1e3b205..cf4ee46 100644
--- a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentProviderPlugin.java
+++ b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentProviderPlugin.java
@@ -16,22 +16,22 @@
 
 package com.ning.billing.payment.plugin.api;
 
+import java.math.BigDecimal;
 import java.util.List;
 import java.util.UUID;
 
 import com.ning.billing.account.api.Account;
-import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.payment.api.PaymentMethodInfo;
 
 public interface PaymentProviderPlugin {
     
-    public PaymentInfoPlugin processInvoice(Account account, Invoice invoice)
+    public PaymentInfoPlugin processPayment(String externalAccountKey, UUID paymentId, BigDecimal amount)
     throws PaymentPluginApiException;
 
     public String createPaymentProviderAccount(Account account)
     throws PaymentPluginApiException;
 
-    public PaymentInfoPlugin getPaymentInfo(String paymentId)
+    public PaymentInfoPlugin getPaymentInfo(UUID paymentId)
     throws PaymentPluginApiException;
 
     public PaymentProviderAccount getPaymentProviderAccount(String accountKey)
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
index d970921..f334d77 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
@@ -15,12 +15,6 @@
  */
 package com.ning.billing.jaxrs.resources;
 
-import com.ning.billing.jaxrs.json.CustomFieldJson;
-import com.ning.billing.util.callcontext.CallContext;
-
-import javax.ws.rs.core.Response;
-import java.util.List;
-import java.util.UUID;
 
 public interface JaxrsResource {
 	
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
index 538c2bd..9f8d421 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
@@ -43,8 +43,9 @@ import com.ning.billing.util.dao.ObjectType;
 import java.util.List;
 import java.util.UUID;
 
-@Path(JaxrsResource.INVOICES_PATH)
+@Path(JaxrsResource.PAYMENTS_PATH)
 public class PaymentResource extends JaxRsResourceBase {
+    
     private static final String ID_PARAM_NAME = "paymentId";
     private static final String CUSTOM_FIELD_URI = JaxrsResource.CUSTOM_FIELDS + "/{" + ID_PARAM_NAME + ":" + UUID_PATTERN + "}";
     private static final String TAG_URI = JaxrsResource.TAGS + "/{" + ID_PARAM_NAME + ":" + UUID_PATTERN + "}";
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 4c66cae..195cfea 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
@@ -43,7 +43,7 @@ public class DefaultPaymentApi implements PaymentApi {
             final RefundProcessor refundProcessor) {
         this.methodProcessor = methodProcessor;
         this.accountProcessor = accountProcessor;
-        this.paymentProcessor = null;
+        this.paymentProcessor = paymentProcessor;
         this.refundProcessor = refundProcessor;
     }
      
@@ -134,7 +134,6 @@ public class DefaultPaymentApi implements PaymentApi {
     @Override
     public PaymentProviderAccount getPaymentProviderAccount(String accountKey)
             throws PaymentApiException {
-        // TODO Auto-generated method stub
-        return null;
+        return accountProcessor.getPaymentProviderAccount(accountKey);
     }
 }
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 ba64c3d..ed945fe 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
@@ -16,6 +16,7 @@
 package com.ning.billing.payment.core;
 
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
@@ -47,22 +48,25 @@ import com.ning.billing.payment.plugin.api.PaymentPluginApiException;
 import com.ning.billing.payment.plugin.api.PaymentProviderPlugin;
 import com.ning.billing.payment.plugin.api.PaymentInfoPlugin.PaymentPluginStatus;
 import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
-import com.ning.billing.payment.retry.FailedPaymentRetryService;
+import com.ning.billing.payment.retry.FailedPaymentRetryService.FailedPaymentRetryServiceScheduler;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.BusEvent;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextFactory;
 import com.ning.billing.util.callcontext.CallOrigin;
 import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.globallocker.GlobalLocker;
 
 public class PaymentProcessor extends ProcessorBase {
     
     private final InvoicePaymentApi invoicePaymentApi;
-    private final FailedPaymentRetryService retryService;
+    private final FailedPaymentRetryServiceScheduler retryService;
     private final PaymentConfig config;
     private final PaymentDao paymentDao;
     private final CallContextFactory factory;
+    private final Clock clock;
+    
     
     private static final Logger log = LoggerFactory.getLogger(PaymentProcessor.class);
 
@@ -70,16 +74,18 @@ public class PaymentProcessor extends ProcessorBase {
     public PaymentProcessor(final PaymentProviderPluginRegistry pluginRegistry,
             final AccountUserApi accountUserApi,
             final InvoicePaymentApi invoicePaymentApi,
-            final FailedPaymentRetryService retryService,
+            final FailedPaymentRetryServiceScheduler retryService,
             final PaymentDao paymentDao,
             final PaymentConfig config,
             final Bus eventBus,
+            final Clock clock,
             final GlobalLocker locker,
             final CallContextFactory factory) {
         super(pluginRegistry, accountUserApi, eventBus, locker);
         this.invoicePaymentApi = invoicePaymentApi;
         this.retryService = retryService;
         this.paymentDao = paymentDao;
+        this.clock = clock;
         this.config = config;
         this.factory = factory;
     }
@@ -185,10 +191,8 @@ public class PaymentProcessor extends ProcessorBase {
 
     private Payment processNewPaymentWithAccountLocked(PaymentProviderPlugin plugin, Account account, Invoice invoice,
             CallContext context) throws PaymentApiException {
-
-        
-        PaymentModelDao payment = new PaymentModelDao(account.getId(), invoice.getId(), invoice.getTotalAmount(), invoice.getCurrency(), invoice.getTargetDate());
-        PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), payment.getId());
+        PaymentModelDao payment = new PaymentModelDao(account.getId(), invoice.getId(), invoice.getTotalAmount().setScale(2, RoundingMode.HALF_EVEN), invoice.getCurrency(), invoice.getTargetDate());
+        PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), payment.getId(), clock.getUTCNow());
             
         PaymentModelDao savedPayment = paymentDao.insertPaymentWithAttempt(payment, attempt, context);
         return processPaymentWithAccountLocked(plugin, account, invoice, savedPayment, attempt, context);
@@ -197,28 +201,30 @@ public class PaymentProcessor extends ProcessorBase {
     
     private Payment processRetryPaymentWithAccountLocked(PaymentProviderPlugin plugin, Account account, Invoice invoice, PaymentModelDao payment,
             CallContext context) throws PaymentApiException {
-        PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), payment.getId());
+        PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), payment.getId(), clock.getUTCNow());
         paymentDao.insertNewAttemptForPayment(payment.getId(), attempt, context);
         return processPaymentWithAccountLocked(plugin, account, invoice, payment, attempt, context);
     }
 
     private Payment processPaymentWithAccountLocked(PaymentProviderPlugin plugin, Account account, Invoice invoice,
-            PaymentModelDao payment, PaymentAttemptModelDao attemptInput, CallContext context) throws PaymentApiException {
-            
+            PaymentModelDao paymentInput, PaymentAttemptModelDao attemptInput, CallContext context) throws PaymentApiException {
+        
         BusEvent event = null;
         List<PaymentAttemptModelDao> allAttempts = null;
         PaymentAttemptModelDao lastAttempt = null;
+        PaymentModelDao payment = null;
         try {
-            allAttempts = paymentDao.getAttemptsForPayment(payment.getId());
-            lastAttempt = allAttempts.get(allAttempts.size() - 1);
-
             
-            PaymentInfoPlugin paymentPluginInfo =  plugin.processInvoice(account, invoice);
+            PaymentInfoPlugin paymentPluginInfo =  plugin.processPayment(account.getExternalKey(), paymentInput.getId(), paymentInput.getAmount());
+            
             // STEPH check if plugin returns UNKNOWN (exception from plugin)
             PaymentStatus paymentStatus = paymentPluginInfo.getStatus() ==  PaymentPluginStatus.ERROR ? PaymentStatus.ERROR : PaymentStatus.SUCCESS;
             
-            paymentDao.updateStatusForPaymentWithAttempt(payment.getId(), paymentStatus, paymentPluginInfo.getError(), attemptInput.getId(), context);
-            
+            paymentDao.updateStatusForPaymentWithAttempt(paymentInput.getId(), paymentStatus, paymentPluginInfo.getError(), attemptInput.getId(), context);
+
+            allAttempts = paymentDao.getAttemptsForPayment(paymentInput.getId());
+            lastAttempt = allAttempts.get(allAttempts.size() - 1);
+            payment = paymentDao.getPayment(paymentInput.getId());
             
             invoicePaymentApi.notifyOfPaymentAttempt(invoice.getId(),
                     paymentStatus == PaymentStatus.SUCCESS ? payment.getAmount() : null,
@@ -231,16 +237,20 @@ public class PaymentProcessor extends ProcessorBase {
                     invoice.getId(), payment.getId(), payment.getAmount(), payment.getPaymentNumber(), paymentStatus, context.getUserToken(), payment.getEffectiveDate());
       
         } catch (PaymentPluginApiException e) {
+
+            allAttempts = paymentDao.getAttemptsForPayment(paymentInput.getId());
+            lastAttempt = allAttempts.get(allAttempts.size() - 1);
+
             log.info(String.format("Could not process payment for account %s, invoice %s, error = %s",
                     account.getId(), invoice.getId(), e.getMessage()));
-            scheduleRetry(payment.getId(), lastAttempt.getEffectiveDate(), allAttempts.size());
-            event = new DefaultPaymentErrorEvent(account.getId(), invoice.getId(), payment.getId(), e.getErrorMessage(), context.getUserToken());                        
+            scheduleRetry(paymentInput.getId(), lastAttempt.getEffectiveDate(), allAttempts.size());
+            event = new DefaultPaymentErrorEvent(account.getId(), invoice.getId(), paymentInput.getId(), e.getErrorMessage(), context.getUserToken());                        
             throw new PaymentApiException(e, ErrorCode.PAYMENT_CREATE_PAYMENT, account.getId(), e.getMessage());
 
         } finally {
             postPaymentEvent(event, account.getId());
         }
-        return null;
+        return new DefaultPayment(payment, allAttempts);
     }
 
     private void scheduleRetry(final UUID paymentId, final DateTime lastAttemptDate, final int numberAttempts) {
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
index 7dde65f..a98b067 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
@@ -132,12 +132,24 @@ public class AuditedPaymentDao implements PaymentDao {
     
     private void updatePaymentStatusFromTransaction(final UUID paymentId, final PaymentStatus paymentStatus, final CallContext context, final PaymentSqlDao transactional) {
         transactional.updatePaymentStatus(paymentId.toString(), paymentStatus.toString(), context);
-        // STEPH check with Jeff
+        PaymentModelDao savedPayment = transactional.getPayment(paymentId.toString());
+        Long recordId = transactional.getRecordId(savedPayment.getId().toString());
+        EntityHistory<PaymentModelDao> history = new EntityHistory<PaymentModelDao>(savedPayment.getId(), recordId, savedPayment, ChangeType.UPDATE);
+        transactional.insertHistoryFromTransaction(history, context);
+        Long historyRecordId = transactional.getHistoryRecordId(recordId);
+        EntityAudit audit = new EntityAudit(TableName.PAYMENTS, historyRecordId, ChangeType.UPDATE);
+        transactional.insertAuditFromTransaction(audit, context);
     }
     
     private void updatePaymentAttemptStatusFromTransaction(final UUID attemptId, final PaymentStatus processingStatus, final String paymentError, final CallContext context, final PaymentAttemptSqlDao transactional) {
         transactional.updatePaymentAttemptStatus(attemptId.toString(), processingStatus.toString(), paymentError);
-        //STEPH check with Jeff        
+        PaymentAttemptModelDao savedAttempt = transactional.getPaymentAttempt(attemptId.toString());
+        Long recordId = transactional.getRecordId(savedAttempt.getId().toString());
+        EntityHistory<PaymentAttemptModelDao> history = new EntityHistory<PaymentAttemptModelDao>(savedAttempt.getId(), recordId, savedAttempt, ChangeType.UPDATE);
+        transactional.insertHistoryFromTransaction(history, context);
+        Long historyRecordId = transactional.getHistoryRecordId(recordId);
+        EntityAudit audit = new EntityAudit(TableName.PAYMENT_ATTEMPTS, historyRecordId, ChangeType.UPDATE);
+        transactional.insertAuditFromTransaction(audit, context);
     }
     
     @Override
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptModelDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptModelDao.java
index f80edd1..25254be 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptModelDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptModelDao.java
@@ -42,8 +42,8 @@ public class PaymentAttemptModelDao extends EntityBase {
         this.paymentError = paymentError;
     }
     
-    public PaymentAttemptModelDao(UUID accountId, UUID invoiceId, UUID paymentId) {
-        this(UUID.randomUUID(), accountId, invoiceId, paymentId, PaymentStatus.UNKNOWN, null, null);
+    public PaymentAttemptModelDao(UUID accountId, UUID invoiceId, UUID paymentId, DateTime effectiveDate) {
+        this(UUID.randomUUID(), accountId, invoiceId, paymentId, PaymentStatus.UNKNOWN, effectiveDate, null);
     }
 
     public PaymentAttemptModelDao(PaymentAttemptModelDao src, PaymentStatus newProcessingStatus, String paymentError) {
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentModelDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentModelDao.java
index 396a2dd..1511ca8 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentModelDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentModelDao.java
@@ -27,7 +27,7 @@ import com.ning.billing.util.entity.EntityBase;
 
 public class PaymentModelDao extends EntityBase {
 
-    private final static Integer INVALID_PAYMENT_NUMBER = new Integer(-13);
+    public final static Integer INVALID_PAYMENT_NUMBER = new Integer(-13);
     
     private final UUID accountId;
     private final UUID invoiceId;
diff --git a/payment/src/main/java/com/ning/billing/payment/glue/DefaultPaymentService.java b/payment/src/main/java/com/ning/billing/payment/glue/DefaultPaymentService.java
index 28740a4..6fdb703 100644
--- a/payment/src/main/java/com/ning/billing/payment/glue/DefaultPaymentService.java
+++ b/payment/src/main/java/com/ning/billing/payment/glue/DefaultPaymentService.java
@@ -32,9 +32,11 @@ import com.ning.billing.util.notificationq.NotificationQueueService.NoSuchNotifi
 import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueAlreadyExists;
 
 public class DefaultPaymentService implements PaymentService {
+
     private static final Logger log = LoggerFactory.getLogger(DefaultPaymentService.class);
 
-    private static final String SERVICE_NAME = "payment-service";
+    // STEPH for retry crappiness
+    public static final String SERVICE_NAME = "payment-service";
 
     private final RequestProcessor requestProcessor;
     private final Bus eventBus;
diff --git a/payment/src/main/java/com/ning/billing/payment/glue/PaymentModule.java b/payment/src/main/java/com/ning/billing/payment/glue/PaymentModule.java
index 877531d..4056f99 100644
--- a/payment/src/main/java/com/ning/billing/payment/glue/PaymentModule.java
+++ b/payment/src/main/java/com/ning/billing/payment/glue/PaymentModule.java
@@ -35,6 +35,8 @@ import com.ning.billing.payment.dao.PaymentDao;
 import com.ning.billing.payment.provider.DefaultPaymentProviderPluginRegistry;
 import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
 import com.ning.billing.payment.retry.FailedPaymentRetryService;
+import com.ning.billing.payment.retry.FailedPaymentRetryService.FailedPaymentRetryServiceScheduler;
+import com.ning.billing.payment.retry.TimedoutPaymentRetryService;
 
 public class PaymentModule extends AbstractModule {
     private final Properties props;
@@ -54,8 +56,17 @@ public class PaymentModule extends AbstractModule {
     protected void installPaymentProviderPlugins(PaymentConfig config) {
     }
 
-    protected void installRetryEngine() {
+    protected void installRetryEngines() {
         bind(FailedPaymentRetryService.class).asEagerSingleton();
+        bind(TimedoutPaymentRetryService.class).asEagerSingleton(); 
+        bind(FailedPaymentRetryServiceScheduler.class).asEagerSingleton();
+    }
+    
+    protected void installProcessors() {
+        bind(AccountProcessor.class).asEagerSingleton();
+        bind(PaymentProcessor.class).asEagerSingleton();
+        bind(RefundProcessor.class).asEagerSingleton();
+        bind(PaymentMethodProcessor.class).asEagerSingleton();
     }
 
     @Override
@@ -68,12 +79,9 @@ public class PaymentModule extends AbstractModule {
         bind(PaymentApi.class).to(DefaultPaymentApi.class).asEagerSingleton();
         bind(RequestProcessor.class).asEagerSingleton();
         bind(PaymentService.class).to(DefaultPaymentService.class).asEagerSingleton();
-        bind(AccountProcessor.class).asEagerSingleton();        
-        bind(PaymentProcessor.class).asEagerSingleton();        
-        bind(RefundProcessor.class).asEagerSingleton();                
-        bind(PaymentMethodProcessor.class).asEagerSingleton();                        
         installPaymentProviderPlugins(paymentConfig);
         installPaymentDao();
-        installRetryEngine();
+        installProcessors();
+        installRetryEngines();
     }
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java b/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
index 9f2c49b..98ca014 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
@@ -25,6 +25,7 @@ import org.joda.time.DateTimeZone;
 
 import com.ning.billing.account.api.Account;
 import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.payment.api.Payment;
 import com.ning.billing.payment.api.PaymentMethodInfo;
 import com.ning.billing.payment.plugin.api.PaymentInfoPlugin;
 import com.ning.billing.payment.plugin.api.PaymentPluginApiException;
@@ -44,9 +45,9 @@ public class NoOpPaymentProviderPlugin implements PaymentProviderPlugin {
     } 
 
     @Override
-    public PaymentInfoPlugin processInvoice(final Account account, final Invoice invoice)
+    public PaymentInfoPlugin processPayment(final String externalAccountKey, final UUID paymentId, final BigDecimal amount)
             throws PaymentPluginApiException {
-        PaymentInfoPlugin payment = new PaymentInfoPlugin() {
+        PaymentInfoPlugin paymentResult = new PaymentInfoPlugin() {
         
             @Override
             public DateTime getEffectiveDate() {
@@ -58,7 +59,7 @@ public class NoOpPaymentProviderPlugin implements PaymentProviderPlugin {
             }
             @Override
             public BigDecimal getAmount() {
-                return invoice.getBalance();
+                return amount;
             }
             @Override
             public PaymentPluginStatus getStatus() {
@@ -69,7 +70,7 @@ public class NoOpPaymentProviderPlugin implements PaymentProviderPlugin {
                 return null;
             }
         };
-        return payment;
+        return paymentResult;
     }
 
     @Override
@@ -80,7 +81,7 @@ public class NoOpPaymentProviderPlugin implements PaymentProviderPlugin {
     }
 
     @Override
-    public PaymentInfoPlugin getPaymentInfo(String paymentId)
+    public PaymentInfoPlugin getPaymentInfo(UUID paymentId)
             throws PaymentPluginApiException {
         
         return null;
diff --git a/payment/src/main/java/com/ning/billing/payment/retry/FailedPaymentRetryService.java b/payment/src/main/java/com/ning/billing/payment/retry/FailedPaymentRetryService.java
index 3e9e718..5cb6c4d 100644
--- a/payment/src/main/java/com/ning/billing/payment/retry/FailedPaymentRetryService.java
+++ b/payment/src/main/java/com/ning/billing/payment/retry/FailedPaymentRetryService.java
@@ -29,17 +29,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
-import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.config.PaymentConfig;
-import com.ning.billing.payment.api.Payment.PaymentAttempt;
-import com.ning.billing.payment.api.PaymentApi;
-import com.ning.billing.payment.api.PaymentApiException;
-import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.core.PaymentProcessor;
-import com.ning.billing.payment.dao.PaymentAttemptModelDao;
 import com.ning.billing.payment.dao.PaymentDao;
+import com.ning.billing.payment.glue.DefaultPaymentService;
 
 
 import com.ning.billing.util.notificationq.NotificationKey;
@@ -100,20 +94,39 @@ public class FailedPaymentRetryService implements RetryService {
         }
     }
 
-    public void scheduleRetry(final UUID paymentId, final DateTime timeOfRetry) {
-
-        NotificationKey key = new NotificationKey() {
-            @Override
-            public String toString() {
-                return paymentId.toString();
-            }
-        };
-        if (retryQueue != null) {
-            retryQueue.recordFutureNotification(timeOfRetry, key);
-        }
-    }
+    
 
     private void retry(final UUID paymentId, final CallContext context) {
         paymentProcessor.retryPayment(paymentId);
     }
+    
+    
+    public static class FailedPaymentRetryServiceScheduler {
+        
+        private final NotificationQueueService notificationQueueService;
+        
+        @Inject
+        public FailedPaymentRetryServiceScheduler(final NotificationQueueService notificationQueueService) {
+            this.notificationQueueService = notificationQueueService;
+        }
+    
+        
+        public void scheduleRetry(final UUID paymentId, final DateTime timeOfRetry) {
+
+            try {
+                NotificationQueue retryQueue = notificationQueueService.getNotificationQueue(DefaultPaymentService.SERVICE_NAME, QUEUE_NAME);
+                NotificationKey key = new NotificationKey() {
+                    @Override
+                    public String toString() {
+                        return paymentId.toString();
+                    }
+                };
+                if (retryQueue != null) {
+                    retryQueue.recordFutureNotification(timeOfRetry, key);
+                }
+            } catch (NoSuchNotificationQueue e) {
+                log.error(String.format("Failed to retrieve notification queue %s:%s", DefaultPaymentService.SERVICE_NAME, QUEUE_NAME));
+            }
+        }
+    }
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/retry/TimedoutPaymentRetryService.java b/payment/src/main/java/com/ning/billing/payment/retry/TimedoutPaymentRetryService.java
index 9ea8107..d1cbf77 100644
--- a/payment/src/main/java/com/ning/billing/payment/retry/TimedoutPaymentRetryService.java
+++ b/payment/src/main/java/com/ning/billing/payment/retry/TimedoutPaymentRetryService.java
@@ -23,7 +23,6 @@ import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
 import com.ning.billing.config.PaymentConfig;
-import com.ning.billing.payment.api.PaymentApi;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallOrigin;
 import com.ning.billing.util.callcontext.DefaultCallContext;
@@ -46,17 +45,14 @@ public class TimedoutPaymentRetryService implements RetryService {
     private final Clock clock;
     private final NotificationQueueService notificationQueueService;
     private final PaymentConfig config;
-    private final PaymentApi paymentApi;
     private NotificationQueue retryQueue;
 
     @Inject
     public TimedoutPaymentRetryService(Clock clock,
                         NotificationQueueService notificationQueueService,
-                        PaymentConfig config,
-                        PaymentApi paymentApi) {
+                        PaymentConfig config) {
         this.clock = clock;
         this.notificationQueueService = notificationQueueService;
-        this.paymentApi = paymentApi;
         this.config = config;
     }
 
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
index 59849a0..62e76e4 100644
--- a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
@@ -17,14 +17,11 @@
 package com.ning.billing.payment.api;
 
 import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
-import java.util.Arrays;
-import java.util.List;
 import java.util.UUID;
 
 import org.apache.commons.lang.RandomStringUtils;
@@ -32,6 +29,7 @@ import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
 import com.google.inject.Inject;
@@ -41,9 +39,12 @@ import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoicePaymentApi;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.mock.glue.MockClockModule;
+import com.ning.billing.mock.glue.MockJunctionModule;
 import com.ning.billing.payment.MockRecurringInvoiceItem;
 import com.ning.billing.payment.TestHelper;
 import com.ning.billing.payment.api.Payment.PaymentAttempt;
+import com.ning.billing.payment.glue.PaymentTestModuleWithMocks;
 import com.ning.billing.payment.plugin.api.PaymentProviderAccount;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.Bus.EventBusException;
@@ -52,8 +53,11 @@ import com.ning.billing.util.callcontext.CallOrigin;
 import com.ning.billing.util.callcontext.DefaultCallContext;
 import com.ning.billing.util.callcontext.UserType;
 import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.glue.CallContextModule;
 
-public abstract class TestPaymentApi {
+@Guice(modules = { PaymentTestModuleWithMocks.class, MockClockModule.class, MockJunctionModule.class, CallContextModule.class })
+@Test(groups = "fast")
+public class TestPaymentApi {
     @Inject
     private Bus eventBus;
     @Inject
@@ -102,7 +106,7 @@ public abstract class TestPaymentApi {
                                                        new BigDecimal("1.0"),
                                                        Currency.USD));
 
-        Payment paymentInfo =  paymentApi.createPayment(account.getExternalKey(), invoice.getId(), context);
+        Payment paymentInfo = paymentApi.createPayment(account.getExternalKey(), invoice.getId(), context);
 
         assertNotNull(paymentInfo.getId());
         assertTrue(paymentInfo.getAmount().compareTo(amount.setScale(2, RoundingMode.HALF_EVEN)) == 0);
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
index 899cc6f..e3b6a6c 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
@@ -26,6 +26,7 @@ import org.apache.commons.io.IOUtils;
 import org.joda.time.DateTime;
 import org.skife.config.ConfigurationObjectFactory;
 import org.skife.jdbi.v2.IDBI;
+import org.testng.Assert;
 import org.testng.annotations.AfterSuite;
 
 import org.testng.annotations.BeforeSuite;
@@ -36,6 +37,8 @@ import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.dbi.DBIProvider;
 import com.ning.billing.dbi.DbiConfig;
 import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.payment.api.DefaultPayment;
+import com.ning.billing.payment.api.Payment;
 import com.ning.billing.payment.api.PaymentStatus;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.TestCallContext;
@@ -101,7 +104,7 @@ public class TestPaymentDao {
         DateTime effectiveDate = clock.getUTCNow();
         
         PaymentModelDao payment = new PaymentModelDao(accountId, invoiceId, amount, currency, effectiveDate);
-        PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(accountId, invoiceId, payment.getId());
+        PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(accountId, invoiceId, payment.getId(), clock.getUTCNow());
         PaymentModelDao savedPayment = paymentDao.insertPaymentWithAttempt(payment, attempt, context);
         
         PaymentStatus paymentStatus = PaymentStatus.SUCCESS;
@@ -119,7 +122,7 @@ public class TestPaymentDao {
         assertEquals(savedPayment.getAmount().compareTo(amount), 0);        
         assertEquals(savedPayment.getCurrency(), currency);         
         assertEquals(savedPayment.getEffectiveDate().compareTo(effectiveDate), 0); 
-        assertEquals(savedPayment.getPaymentNumber(), new Integer(1));
+        Assert.assertNotEquals(savedPayment.getPaymentNumber(), PaymentModelDao.INVALID_PAYMENT_NUMBER);
         assertEquals(savedPayment.getPaymentStatus(), PaymentStatus.SUCCESS); 
         
         List<PaymentAttemptModelDao> attempts =  paymentDao.getAttemptsForPayment(payment.getId());
@@ -143,7 +146,7 @@ public class TestPaymentDao {
         DateTime effectiveDate = clock.getUTCNow();
         
         PaymentModelDao payment = new PaymentModelDao(accountId, invoiceId, amount, currency, effectiveDate);
-        PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(accountId, invoiceId, payment.getId());
+        PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(accountId, invoiceId, payment.getId(), clock.getUTCNow());
         
         PaymentModelDao savedPayment = paymentDao.insertPaymentWithAttempt(payment, attempt, context);
         assertEquals(savedPayment.getId(), payment.getId());
diff --git a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
index 93fb8ed..4349993 100644
--- a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
+++ b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
@@ -16,6 +16,8 @@
 
 package com.ning.billing.payment.provider;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -33,6 +35,7 @@ import com.ning.billing.account.api.Account;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.payment.api.CreditCardPaymentMethodInfo;
 import com.ning.billing.payment.api.DefaultPaymentInfoEvent;
+import com.ning.billing.payment.api.Payment;
 import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.api.PaymentMethodInfo;
 import com.ning.billing.payment.api.PaypalPaymentMethodInfo;
@@ -41,13 +44,14 @@ import com.ning.billing.payment.plugin.api.PaymentInfoPlugin;
 import com.ning.billing.payment.plugin.api.PaymentPluginApiException;
 import com.ning.billing.payment.plugin.api.PaymentProviderAccount;
 import com.ning.billing.payment.plugin.api.PaymentProviderPlugin;
+import com.ning.billing.payment.plugin.api.PaymentInfoPlugin.PaymentPluginStatus;
 import com.ning.billing.util.clock.Clock;
 
 public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
     
     private final AtomicBoolean makeNextInvoiceFail = new AtomicBoolean(false);
     private final AtomicBoolean makeAllInvoicesFail = new AtomicBoolean(false);
-    private final Map<UUID, PaymentInfoEvent> payments = new ConcurrentHashMap<UUID, PaymentInfoEvent>();
+    private final Map<UUID, PaymentInfoPlugin> payments = new ConcurrentHashMap<UUID, PaymentInfoPlugin>();
     private final Map<String, PaymentProviderAccount> accounts = new ConcurrentHashMap<String, PaymentProviderAccount>();
     private final Map<String, PaymentMethodInfo> paymentMethods = new ConcurrentHashMap<String, PaymentMethodInfo>();
     private final Clock clock;
@@ -57,7 +61,7 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
         this.clock = clock;
     }
 
-    public void makeNextInvoiceFail() {
+    public void makeNextPaymentFail() {
         makeNextInvoiceFail.set(true);
     }
 
@@ -66,49 +70,35 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
     }
 
     @Override
-    public PaymentInfoPlugin processInvoice(Account account, Invoice invoice) throws PaymentPluginApiException {
+    public PaymentInfoPlugin processPayment(String externalKey, UUID paymentId, BigDecimal amount) throws PaymentPluginApiException {
         if (makeNextInvoiceFail.getAndSet(false) || makeAllInvoicesFail.get()) {
             throw new PaymentPluginApiException("", "test error");
         }
-        // STEPH
-/*
-        PaymentInfoEvent payment = new DefaultPaymentInfoEvent.Builder().setId(UUID.randomUUID())
-                .setExternalPaymentId("238957t49regyuihfd")
-                .setAmount(invoice.getBalance())
-                .setStatus("Processed")
-                .setBankIdentificationNumber("1234")
-                .setCreatedDate(clock.getUTCNow())
-                .setEffectiveDate(clock.getUTCNow())
-                .setPaymentNumber("12345")
-                .setReferenceId("12345")
-                .setType("Electronic")
-                .setPaymentMethodId("123-456-678-89")
-                .build();
-        
-        return new MockPaymentInfoPlugin(payment);
-        *
-        */
-        return null;
+
+        PaymentInfoPlugin result = new MockPaymentInfoPlugin(amount, clock.getUTCNow(), clock.getUTCNow(), PaymentPluginStatus.PROCESSED, null);
+        payments.put(paymentId, result);
+        return result;
     }
 
 
     @Override
-    public PaymentInfoPlugin getPaymentInfo(String paymentId) throws PaymentPluginApiException {
-        PaymentInfoEvent payment = payments.get(paymentId);
+    public PaymentInfoPlugin getPaymentInfo(UUID paymentId) throws PaymentPluginApiException {
+        PaymentInfoPlugin payment = payments.get(paymentId);
         if (payment == null) {
             throw new PaymentPluginApiException("", "No payment found for id " + paymentId);
         }
-        /* return new MockPaymentInfoPlugin(payment); */
-        return null;
+        return payment;
     }
 
     @Override
     public String createPaymentProviderAccount(Account account)  throws PaymentPluginApiException {
         if (account != null) {
             String id = String.valueOf(RandomStringUtils.randomAlphanumeric(10));
+            String paymentMethodId = String.valueOf(RandomStringUtils.randomAlphanumeric(10));            
             accounts.put(account.getExternalKey(),
                          new PaymentProviderAccount.Builder().setAccountKey(account.getExternalKey())
                                                              .setId(id)
+                                                             .setDefaultPaymentMethod(paymentMethodId)
                                                              .build());
             return id;
         }
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 e247d4d..7156c12 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
@@ -81,8 +81,6 @@ public class TestRetryService {
     @Inject
     private PaymentProviderPluginRegistry registry;
     @Inject
-    private PaymentDao paymentDao;
-    @Inject
     private FailedPaymentRetryService retryService;
     @Inject
     private NotificationQueueService notificationQueueService;
@@ -138,7 +136,7 @@ public class TestRetryService {
                                                        new BigDecimal("1.0"),
                                                        Currency.USD));
 
-        mockPaymentProviderPlugin.makeNextInvoiceFail();
+        mockPaymentProviderPlugin.makeNextPaymentFail();
         boolean failed = false;
         try {
             paymentApi.createPayment(account.getExternalKey(), invoice.getId(), context);