killbill-memoizeit

Merging with latest

5/10/2012 6:31:29 PM

Changes

overdue/pom.xml 7(+0 -7)

Details

diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
index 15c4a94..8d107ef 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
@@ -35,6 +35,7 @@ import com.ning.billing.analytics.dao.BusinessAccountDao;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceUserApi;
 import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
 import com.ning.billing.payment.api.PaymentAttempt;
 import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.util.tag.Tag;
@@ -59,14 +60,14 @@ public class BusinessAccountRecorder {
         Account account;
         try {
             account = accountApi.getAccountByKey(data.getExternalKey());
-        final BusinessAccount bac = createBusinessAccountFromAccount(account);
+            final BusinessAccount bac = createBusinessAccountFromAccount(account);
 
-        log.info("ACCOUNT CREATION " + bac);
-        dao.createAccount(bac);
+            log.info("ACCOUNT CREATION " + bac);
+            dao.createAccount(bac);
         } catch (AccountApiException e) {
-           log.warn("Error encountered creating BusinessAccount",e);
+            log.warn("Error encountered creating BusinessAccount",e);
         }
-   }
+    }
 
     /**
      * Notification handler for Account changes
@@ -85,17 +86,19 @@ public class BusinessAccountRecorder {
      * @param paymentInfo payment object (from the payment plugin)
      */
     public void accountUpdated(final PaymentInfoEvent paymentInfo) {
-        final PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(paymentInfo.getPaymentId());
-        if (paymentAttempt == null) {
-            return;
-        }
         try {
+            final PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(paymentInfo.getPaymentId());
+            if (paymentAttempt == null) {
+                return;
+            }
+
             final Account account = accountApi.getAccountById(paymentAttempt.getAccountId());
             accountUpdated(account.getId());
         } catch (AccountApiException e) {
             log.warn("Error encountered creating BusinessAccount",e);
+        } catch (PaymentApiException e) {
+            log.warn("Error encountered creating BusinessAccount",e);            
         }
-
     }
 
     /**
@@ -152,51 +155,56 @@ public class BusinessAccountRecorder {
     }
 
     private void updateBusinessAccountFromAccount(final Account account, final BusinessAccount bac) {
-        DateTime lastInvoiceDate = null;
-        BigDecimal totalInvoiceBalance = BigDecimal.ZERO;
-        String lastPaymentStatus = null;
-        String paymentMethod = null;
-        String creditCardType = null;
-        String billingAddressCountry = null;
-
-        // Retrieve invoices information
-        final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId());
-        if (invoices != null && invoices.size() > 0) {
-            final List<String> invoiceIds = new ArrayList<String>();
-            for (final Invoice invoice : invoices) {
-                invoiceIds.add(invoice.getId().toString());
-                totalInvoiceBalance = totalInvoiceBalance.add(invoice.getBalance());
-
-                if (lastInvoiceDate == null || invoice.getInvoiceDate().isAfter(lastInvoiceDate)) {
-                    lastInvoiceDate = invoice.getInvoiceDate();
+
+        try {
+            DateTime lastInvoiceDate = null;
+            BigDecimal totalInvoiceBalance = BigDecimal.ZERO;
+            String lastPaymentStatus = null;
+            String paymentMethod = null;
+            String creditCardType = null;
+            String billingAddressCountry = null;
+
+            // Retrieve invoices information
+            final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId());
+            if (invoices != null && invoices.size() > 0) {
+                final List<String> invoiceIds = new ArrayList<String>();
+                for (final Invoice invoice : invoices) {
+                    invoiceIds.add(invoice.getId().toString());
+                    totalInvoiceBalance = totalInvoiceBalance.add(invoice.getBalance());
+
+                    if (lastInvoiceDate == null || invoice.getInvoiceDate().isAfter(lastInvoiceDate)) {
+                        lastInvoiceDate = invoice.getInvoiceDate();
+                    }
                 }
-            }
 
-            // Retrieve payments information for these invoices
-            DateTime lastPaymentDate = null;
-            final List<PaymentInfoEvent> payments = paymentApi.getPaymentInfo(invoiceIds);
-            if (payments != null) {
-                for (final PaymentInfoEvent payment : payments) {
-                    // Use the last payment method/type/country as the default one for the account
-                    if (lastPaymentDate == null || payment.getCreatedDate().isAfter(lastPaymentDate)) {
-                        lastPaymentDate = payment.getCreatedDate();
-
-                        lastPaymentStatus = payment.getStatus();
-                        paymentMethod = payment.getPaymentMethod();
-                        creditCardType = payment.getCardType();
-                        billingAddressCountry = payment.getCardCountry();
+                // Retrieve payments information for these invoices
+                DateTime lastPaymentDate = null;
+                final List<PaymentInfoEvent> payments = paymentApi.getPaymentInfo(invoiceIds);
+                if (payments != null) {
+                    for (final PaymentInfoEvent payment : payments) {
+                        // Use the last payment method/type/country as the default one for the account
+                        if (lastPaymentDate == null || payment.getCreatedDate().isAfter(lastPaymentDate)) {
+                            lastPaymentDate = payment.getCreatedDate();
+
+                            lastPaymentStatus = payment.getStatus();
+                            paymentMethod = payment.getPaymentMethod();
+                            creditCardType = payment.getCardType();
+                            billingAddressCountry = payment.getCardCountry();
+                        }
                     }
                 }
             }
-        }
 
-        bac.setLastPaymentStatus(lastPaymentStatus);
-        bac.setPaymentMethod(paymentMethod);
-        bac.setCreditCardType(creditCardType);
-        bac.setBillingAddressCountry(billingAddressCountry);
-        bac.setLastInvoiceDate(lastInvoiceDate);
-        bac.setTotalInvoiceBalance(totalInvoiceBalance);
+            bac.setLastPaymentStatus(lastPaymentStatus);
+            bac.setPaymentMethod(paymentMethod);
+            bac.setCreditCardType(creditCardType);
+            bac.setBillingAddressCountry(billingAddressCountry);
+            bac.setLastInvoiceDate(lastInvoiceDate);
+            bac.setTotalInvoiceBalance(totalInvoiceBalance);
 
-        bac.setBalance(invoiceUserApi.getAccountBalance(account.getId()));
+            bac.setBalance(invoiceUserApi.getAccountBalance(account.getId()));
+        } catch (PaymentApiException e) {
+            log.error("Failed to update Business account", e);
+        }
     }
 }
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java b/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java
index 3a2baac..725c62b 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java
@@ -28,6 +28,7 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionStatusDryRun;
 import com.ning.billing.junction.api.BlockingState;
 import com.ning.billing.overdue.OverdueState;
 import com.ning.billing.util.callcontext.CallContext;
@@ -136,4 +137,11 @@ public class MockEntitlementUserApi implements EntitlementUserApi
     public Subscription getBaseSubscription(UUID bundleId) {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public List<SubscriptionStatusDryRun> getDryRunChangePlanStatus(
+            UUID subscriptionId, String productName, DateTime requestedDate)
+            throws EntitlementUserApiException {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/billing/ChargeThruApi.java b/api/src/main/java/com/ning/billing/entitlement/api/billing/ChargeThruApi.java
index 0dec9b9..69eb454 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/billing/ChargeThruApi.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/billing/ChargeThruApi.java
@@ -29,7 +29,7 @@ public interface ChargeThruApi {
      * @param subscriptionId
      * @return UUID of
      */
-    public UUID getAccountIdFromSubscriptionId(UUID subscriptionId);
+    public UUID getAccountIdFromSubscriptionId(UUID subscriptionId) throws EntitlementBillingApiException;
     
     /**
      * Sets the charged through date for the subscription with that Id.
@@ -39,16 +39,4 @@ public interface ChargeThruApi {
      * @param context
      */
     public void setChargedThroughDate(UUID subscriptionId, DateTime ctd, CallContext context);
-
-    /**
-     * Sets the charged through date for the subscription with that Id. Within the context of a SQL Transaction
-     * 
-     * @param transactionalDao
-     * @param subscriptionId
-     * @param ctd
-     * @param context
-     */
-    public void setChargedThroughDateFromTransaction(Transmogrifier transactionalDao, UUID subscriptionId,
-                                                     DateTime ctd, CallContext context);
-
 }
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
index 0e74f86..1e8d7fd 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
@@ -21,6 +21,8 @@ import java.util.UUID;
 
 import com.ning.billing.util.callcontext.CallContext;
 import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 
 
@@ -38,7 +40,7 @@ public interface EntitlementUserApi {
 
     public List<Subscription> getSubscriptionsForKey(String bundleKey);
     
-    public Subscription getBaseSubscription(UUID bundleId);
+    public Subscription getBaseSubscription(UUID bundleId) throws EntitlementUserApiException;
 
     public SubscriptionBundle createBundleForAccount(UUID accountId, String bundleKey, CallContext context)
         throws EntitlementUserApiException;
@@ -46,5 +48,8 @@ public interface EntitlementUserApi {
     public Subscription createSubscription(UUID bundleId, PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
         throws EntitlementUserApiException;
 
+    public List<SubscriptionStatusDryRun> getDryRunChangePlanStatus(UUID subscriptionId, String productName, DateTime requestedDate)
+    throws EntitlementUserApiException;
+    
     public DateTime getNextBillingDate(UUID account);
 }
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java b/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
index 0dbada0..af8e237 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
@@ -41,7 +41,7 @@ public interface Subscription extends ExtendedEntity, Blockable {
     throws EntitlementUserApiException;
 
     public boolean changePlan(String productName, BillingPeriod term, String planSet, DateTime requestedDate, CallContext context)
-        throws EntitlementUserApiException;
+    throws EntitlementUserApiException;
 
     public boolean recreate(PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
         throws EntitlementUserApiException;
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionStatusDryRun.java b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionStatusDryRun.java
new file mode 100644
index 0000000..36048fa
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionStatusDryRun.java
@@ -0,0 +1,42 @@
+/* 
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package com.ning.billing.entitlement.api.user;
+
+import java.util.UUID;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+
+public interface SubscriptionStatusDryRun {
+
+    public UUID getId();
+    
+    public String getProductName();
+    
+    public BillingPeriod getBillingPeriod();
+    
+    public String getPriceList();
+    
+    public PhaseType getPhaseType();
+
+    public DryRunChangeReason getReason();
+    
+    public enum DryRunChangeReason {
+        AO_INCLUDED_IN_NEW_PLAN,
+        AO_NOT_AVAILABLE_IN_NEW_PLAN,
+        AO_AVAILABLE_IN_NEW_PLAN
+    }
+}
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index 829ffe3..860ae6c 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -46,6 +46,8 @@ public enum ErrorCode {
     /* Change plan */
     ENT_CHANGE_NON_ACTIVE(1021, "Subscription %s is in state %s: Failed to change plan"),
     ENT_CHANGE_FUTURE_CANCELLED(1022, "Subscription %s is future cancelled: Failed to change plan"),
+    ENT_CHANGE_DRY_RUN_NOT_BP(1022, "Change DryRun API is only available for BP"),
+    
     /* Cancellation */
     ENT_CANCEL_BAD_STATE(1031, "Subscription %s is in state %s: Failed to cancel"),
     /* Recreation */
@@ -59,6 +61,7 @@ public enum ErrorCode {
     ENT_GET_INVALID_BUNDLE_ID(1081, "Could not find a bundle matching id %s"),
     ENT_INVALID_SUBSCRIPTION_ID(1082, "Unknown subscription %s"),
     ENT_GET_INVALID_BUNDLE_KEY(1083, "Could not find a bundle matching key %s"),
+    ENT_GET_NO_SUCH_BASE_SUBSCRIPTION(1084, "Could not base subscription for bundle %s"),
 
     /* Repair */
     ENT_REPAIR_INVALID_DELETE_SET(1091, "Event %s is not deleted for subscription %s but prior events were"),
@@ -80,6 +83,8 @@ public enum ErrorCode {
     
     ENT_BUNDLE_IS_OVERDUE_BLOCKED(1090, "Changes to this bundle are blocked by overdue enforcement (%s :  %s)"),
     ENT_ACCOUNT_IS_OVERDUE_BLOCKED(1091, "Changes to this account are blocked by overdue enforcement (%s)"),
+ 
+    
     /*
     *
     * Range 2000 : CATALOG
@@ -197,7 +202,25 @@ public enum ErrorCode {
     BLOCK_BLOCKED_ACTION(6000, "The action %s is block on this %s with id=%s"),
     BLOCK_TYPE_NOT_SUPPORTED(6001, "The Blockable type '%s' is not supported"),
     
-   /*
+    
+    /*
+     * Range 7000 : Payment
+     */
+    PAYMENT_NO_SUCH_PAYMENT_METHOD(7001, "Payment method for account %s, and paymentId %s does not exist"),
+    PAYMENT_NO_PAYMENT_METHODS(7002, "Payment methods for account %s don't exist"),
+    PAYMENT_UPD_GATEWAY_FAILED(7003, "Failed to update payment gateway for account %s : %s"),
+    PAYMENT_GET_PAYMENT_PROVIDER(7004, "Failed to retrieve payment provider for account %s : %s"),    
+    PAYMENT_ADD_PAYMENT_METHOD(7005, "Failed to add payment method for account %s : %s"),        
+    PAYMENT_DEL_PAYMENT_METHOD(7006, "Failed to delete payment method for account %s : %s"),        
+    PAYMENT_UPD_PAYMENT_METHOD(7007, "Failed to update payment method for account %s : %s"),            
+    PAYMENT_CREATE_PAYMENT(7008, "Failed to create payment for account %s : %s"),                
+    PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT(7009, "Failed to create payment for account %s and attempt %s : %s"),                    
+    PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT_WITH_NON_POSITIVE_INV(70010, "Got payment attempt with negative or null invoice for account %s"),                        
+    PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT_BAD(7011, "Failed to create payment for attempts %s "),                    
+    PAYMENT_CREATE_PAYMENT_PROVIDER_ACCOUNT(7012, "Failed to create payment provider account for account %s : %s"),                
+    PAYMENT_UPD_PAYMENT_PROVIDER_ACCOUNT(7013, "Failed to update payment provider account for account %s : %s"),                    
+    PAYMENT_CREATE_REFUND(7014, "Failed to create refund for account %s : %s"),                
+    /*
     *
     * Range 9000: Miscellaneous
     *
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
index 1679f50..c7b5965 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
@@ -26,36 +26,54 @@ import com.ning.billing.util.callcontext.CallContext;
 
 public interface PaymentApi {
 
-    Either<PaymentErrorEvent, Void> updatePaymentGateway(String accountKey, CallContext context);
+    public void updatePaymentGateway(final String accountKey, final CallContext context)
+        throws PaymentApiException;
 
-    Either<PaymentErrorEvent, PaymentMethodInfo> getPaymentMethod(@Nullable String accountKey, String paymentMethodId);
+    public PaymentMethodInfo getPaymentMethod(final String accountKey, final String paymentMethodId)
+        throws PaymentApiException;
 
-    Either<PaymentErrorEvent, List<PaymentMethodInfo>> getPaymentMethods(String accountKey);
+    public List<PaymentMethodInfo> getPaymentMethods(final String accountKey)
+        throws PaymentApiException;
 
-    Either<PaymentErrorEvent, String> addPaymentMethod(@Nullable String accountKey, PaymentMethodInfo paymentMethod, CallContext context);
+    public String addPaymentMethod(final String accountKey, final PaymentMethodInfo paymentMethod, final CallContext context)
+        throws PaymentApiException;
 
-    Either<PaymentErrorEvent, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context);
+    public PaymentMethodInfo updatePaymentMethod(final String accountKey, final PaymentMethodInfo paymentMethodInfo, final CallContext context)
+        throws PaymentApiException;
 
-    Either<PaymentErrorEvent, Void> deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context);
+    public void deletePaymentMethod(final String accountKey, final String paymentMethodId, final CallContext context)
+        throws PaymentApiException;
 
-    List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(String accountKey, List<String> invoiceIds, CallContext context);
-    List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(Account account, List<String> invoiceIds, CallContext context);
-    Either<PaymentErrorEvent, PaymentInfoEvent> createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context);
+    public List<PaymentInfoEvent> createPayment(final String accountKey, final List<String> invoiceIds, final CallContext context)
+        throws PaymentApiException;
+    
+    public List<PaymentInfoEvent> createPayment(final Account account, final List<String> invoiceIds, final CallContext context)
+        throws PaymentApiException;
+    
+    public PaymentInfoEvent createPaymentForPaymentAttempt(final UUID paymentAttemptId, final CallContext context)
+        throws PaymentApiException;
 
-    List<Either<PaymentErrorEvent, PaymentInfoEvent>> createRefund(Account account, List<String> invoiceIds, CallContext context); //TODO
+    public List<PaymentInfoEvent> createRefund(final Account account, final List<String> invoiceIds, final CallContext context)
+        throws PaymentApiException;
 
-    Either<PaymentErrorEvent, PaymentProviderAccount> getPaymentProviderAccount(String accountKey);
+    public PaymentProviderAccount getPaymentProviderAccount(final String accountKey)
+        throws PaymentApiException;
 
-    Either<PaymentErrorEvent, String> createPaymentProviderAccount(Account account, CallContext context);
+    public String createPaymentProviderAccount(final Account account, final CallContext context)
+        throws PaymentApiException;
 
-    Either<PaymentErrorEvent, Void> updatePaymentProviderAccountContact(String accountKey, CallContext context);
+    public void updatePaymentProviderAccountContact(String accountKey, CallContext context)
+        throws PaymentApiException;
 
-    PaymentAttempt getPaymentAttemptForPaymentId(String id);
+    public PaymentAttempt getPaymentAttemptForPaymentId(final String id)
+        throws PaymentApiException;
 
-    List<PaymentInfoEvent> getPaymentInfo(List<String> invoiceIds);
+    public List<PaymentInfoEvent> getPaymentInfo(final List<String> invoiceIds)
+        throws PaymentApiException;
 
-    List<PaymentAttempt> getPaymentAttemptsForInvoiceId(String invoiceId);
-
-    PaymentInfoEvent getPaymentInfoForPaymentAttemptId(String paymentAttemptId);
+    public List<PaymentAttempt> getPaymentAttemptsForInvoiceId(final String invoiceId)
+        throws PaymentApiException;
 
+    public PaymentInfoEvent getPaymentInfoForPaymentAttemptId(final String paymentAttemptId)
+        throws PaymentApiException;
 }
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentApiException.java b/api/src/main/java/com/ning/billing/payment/api/PaymentApiException.java
new file mode 100644
index 0000000..ff81b16
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentApiException.java
@@ -0,0 +1,49 @@
+/* 
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package com.ning.billing.payment.api;
+
+import com.ning.billing.BillingExceptionBase;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.catalog.api.CatalogApiException;
+
+public class PaymentApiException extends BillingExceptionBase {
+    
+    private static final long serialVersionUID = 39445033L;
+
+
+    public PaymentApiException(AccountApiException e) {
+        super(e, e.getCode(), e.getMessage());
+    }
+
+    /*
+    public PaymentApiException(CatalogApiException e) {
+        super(e, e.getCode(), e.getMessage());
+    }
+    */
+    
+    public PaymentApiException(Throwable e, ErrorCode code, Object...args) {
+        super(e, code, args);
+    }
+
+    public PaymentApiException(Throwable e, int code, String message) {
+        super(e, code, message);
+    }
+
+    public PaymentApiException(ErrorCode code, Object...args) {
+        super(code, args);
+    }
+}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
index 5f442c6..7996141 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
@@ -185,7 +185,7 @@ public class TestIntegration extends TestIntegrationBase {
         // TODO: Jeff implement repair
     }
 
-    @Test(groups = "slow", enabled = false)
+    @Test(groups = "slow", enabled = true)
     public void testWithRecreatePlan() throws Exception {
 
         log.info("Starting testWithRecreatePlan");
@@ -250,7 +250,7 @@ public class TestIntegration extends TestIntegrationBase {
         term = BillingPeriod.MONTHLY;
         planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
 
-        busHandler.pushExpectedEvent(NextEvent.CREATE);
+        busHandler.pushExpectedEvent(NextEvent.RE_CREATE);
         busHandler.pushExpectedEvent(NextEvent.INVOICE);
         busHandler.pushExpectedEvent(NextEvent.PAYMENT);
         subscription.recreate(new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null), endDate, context);
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
index c733097..2203f41 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
@@ -54,13 +54,13 @@ import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 public class TestRepairIntegration extends TestIntegrationBase {
 
     
-    @Test(groups={"slow"}, enabled=true)
+    @Test(groups={"slow"}, enabled=false)
     public void testRepairChangeBPWithAddonIncludedIntrial() throws Exception {
         log.info("Starting testRepairChangeBPWithAddonIncludedIntrial");
         testRepairChangeBPWithAddonIncluded(true);
     }
     
-    @Test(groups={"slow"}, enabled=true)
+    @Test(groups={"slow"}, enabled=false)
     public void testRepairChangeBPWithAddonIncludedOutOfTrial() throws Exception {
         log.info("Starting testRepairChangeBPWithAddonIncludedOutOfTrial");
         testRepairChangeBPWithAddonIncluded(false);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java
index 7bde4a2..1c3cfc5 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java
@@ -16,11 +16,9 @@ w * Copyright 2010-2011 Ning, Inc.
 
 package com.ning.billing.entitlement.api.billing;
 
-import java.util.Date;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -30,19 +28,16 @@ import com.ning.billing.entitlement.api.SubscriptionFactory;
 import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
-import com.ning.billing.entitlement.engine.dao.SubscriptionSqlDao;
-import com.ning.billing.util.ChangeType;
-import com.ning.billing.util.audit.dao.AuditSqlDao;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextFactory;
 
 public class DefaultChargeThruApi implements ChargeThruApi {
-	private static final Logger log = LoggerFactory.getLogger(DefaultChargeThruApi.class);
+
+    private static final Logger log = LoggerFactory.getLogger(DefaultChargeThruApi.class);
 
     private final EntitlementDao entitlementDao;
     private final SubscriptionFactory subscriptionFactory;
   
-    private static final String SUBSCRIPTION_TABLE_NAME = "subscriptions";
 
     @Inject
     public DefaultChargeThruApi(final CallContextFactory factory, final SubscriptionFactory subscriptionFactory, final EntitlementDao dao, final AccountUserApi accountApi) {
@@ -65,23 +60,4 @@ public class DefaultChargeThruApi implements ChargeThruApi {
             .setPaidThroughDate(subscription.getPaidThroughDate());
         entitlementDao.updateChargedThroughDate(new SubscriptionData(builder), context);
     }
-
-    @Override
-    public void setChargedThroughDateFromTransaction(final Transmogrifier transactionalDao, final UUID subscriptionId,
-                                                     final DateTime ctd, final CallContext context) {
-        SubscriptionSqlDao subscriptionSqlDao = transactionalDao.become(SubscriptionSqlDao.class);
-        SubscriptionData subscription = (SubscriptionData) subscriptionSqlDao.getSubscriptionFromId(subscriptionId.toString());
-
-        if (subscription == null) {
-            log.warn("Subscription not found when setting CTD.");
-        } else {
-            DateTime chargedThroughDate = subscription.getChargedThroughDate();
-            if (chargedThroughDate == null || chargedThroughDate.isBefore(ctd)) {
-                subscriptionSqlDao.updateChargedThroughDate(subscriptionId.toString(),
-                        ctd.toDate(), context);
-                AuditSqlDao auditSqlDao = transactionalDao.become(AuditSqlDao.class);
-                auditSqlDao.insertAuditFromTransaction(SUBSCRIPTION_TABLE_NAME, subscriptionId.toString(), ChangeType.UPDATE, context);
-            }
-        }
-    }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/SubscriptionApiService.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/SubscriptionApiService.java
index 046b982..5b0f192 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/SubscriptionApiService.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/SubscriptionApiService.java
@@ -15,6 +15,8 @@
  */
 package com.ning.billing.entitlement.api;
 
+import java.util.List;
+
 import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.BillingPeriod;
@@ -23,6 +25,7 @@ import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.entitlement.api.user.SubscriptionStatusDryRun;
 import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
 import com.ning.billing.util.callcontext.CallContext;
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
index 115c60b..b8745fe 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
@@ -16,6 +16,7 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
 
@@ -23,6 +24,7 @@ import org.joda.time.DateTime;
 
 import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Catalog;
 import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.catalog.api.CatalogService;
@@ -31,9 +33,11 @@ import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.SubscriptionFactory;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
+import com.ning.billing.entitlement.api.user.SubscriptionStatusDryRun.DryRunChangeReason;
 import com.ning.billing.entitlement.engine.addon.AddonUtils;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
@@ -61,19 +65,32 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
         this.subscriptionFactory = subscriptionFactory;
     }
 
+    
     @Override
-    public SubscriptionBundle getBundleFromId(UUID id) {
-        return dao.getSubscriptionBundleFromId(id);
+    public SubscriptionBundle getBundleFromId(UUID id) throws EntitlementUserApiException {
+        SubscriptionBundle result = dao.getSubscriptionBundleFromId(id);
+        if (result == null) {
+            throw new EntitlementUserApiException(ErrorCode.ENT_GET_INVALID_BUNDLE_ID, id.toString());
+        }
+        return result;
     }
 
     @Override
-    public Subscription getSubscriptionFromId(UUID id) {
-        return dao.getSubscriptionFromId(subscriptionFactory, id);
+    public Subscription getSubscriptionFromId(UUID id) throws EntitlementUserApiException {
+        Subscription result = dao.getSubscriptionFromId(subscriptionFactory, id);
+        if (result == null) {
+            throw new EntitlementUserApiException(ErrorCode.ENT_INVALID_SUBSCRIPTION_ID, id);
+        }
+        return result;
     }
 
     @Override
-    public SubscriptionBundle getBundleForKey(String bundleKey) {
-        return dao.getSubscriptionBundleFromKey(bundleKey);
+    public SubscriptionBundle getBundleForKey(String bundleKey) throws EntitlementUserApiException {
+        SubscriptionBundle result =  dao.getSubscriptionBundleFromKey(bundleKey);
+        if (result == null) {
+            throw new EntitlementUserApiException(ErrorCode.ENT_GET_INVALID_BUNDLE_KEY, bundleKey);
+        }
+        return result;
     }
 
     @Override
@@ -92,8 +109,12 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
     }
 
     @Override
-    public Subscription getBaseSubscription(UUID bundleId) {
-        return dao.getBaseSubscription(subscriptionFactory, bundleId);
+    public Subscription getBaseSubscription(UUID bundleId) throws EntitlementUserApiException {
+        Subscription result =  dao.getBaseSubscription(subscriptionFactory, bundleId);
+        if (result == null) {
+            throw new EntitlementUserApiException(ErrorCode.ENT_GET_NO_SUCH_BASE_SUBSCRIPTION, bundleId);
+        }
+        return result;
     }
     
 
@@ -197,4 +218,42 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
         }
         return result;
     }
+
+
+    @Override
+    public List<SubscriptionStatusDryRun> getDryRunChangePlanStatus(UUID subscriptionId, String baseProductName, DateTime requestedDate)
+            throws EntitlementUserApiException {
+
+        Subscription subscription = dao.getSubscriptionFromId(subscriptionFactory, subscriptionId);
+        if (subscription == null) {
+            throw new EntitlementUserApiException(ErrorCode.ENT_INVALID_SUBSCRIPTION_ID, subscriptionId);
+        }
+        if (subscription.getCategory() != ProductCategory.BASE) {
+            throw new EntitlementUserApiException(ErrorCode.ENT_CHANGE_DRY_RUN_NOT_BP);
+        }
+        
+        List<SubscriptionStatusDryRun> result = new LinkedList<SubscriptionStatusDryRun>();
+        
+        List<Subscription> bundleSubscriptions = dao.getSubscriptions(subscriptionFactory, subscription.getBundleId());
+        for (Subscription cur : bundleSubscriptions) {
+            if (cur.getId().equals(subscriptionId)) {
+                continue;
+            }
+            
+            DryRunChangeReason reason = null;
+            if (addonUtils.isAddonIncludedFromProdName(baseProductName, requestedDate, cur.getCurrentPlan())) {
+                reason = DryRunChangeReason.AO_INCLUDED_IN_NEW_PLAN;
+            } else if (addonUtils.isAddonAvailableFromProdName(baseProductName, requestedDate, cur.getCurrentPlan())) {
+                reason = DryRunChangeReason.AO_AVAILABLE_IN_NEW_PLAN;
+            } else {
+                reason = DryRunChangeReason.AO_NOT_AVAILABLE_IN_NEW_PLAN;
+            }
+            SubscriptionStatusDryRun status = new DefaultSubscriptionStatusDryRun(cur.getId(), 
+                    cur.getCurrentPlan().getProduct().getName(), cur.getCurrentPhase().getPhaseType(),
+                    cur.getCurrentPlan().getBillingPeriod(),
+                    cur.getCurrentPriceList().getName(), reason);
+            result.add(status);
+        }
+        return result;
+    }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
index ed2cb05..0f2db75 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
@@ -17,6 +17,7 @@
 package com.ning.billing.entitlement.api.user;
 
 import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
 
 import org.joda.time.DateTime;
@@ -36,6 +37,7 @@ import com.ning.billing.catalog.api.PlanSpecifier;
 import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.alignment.PlanAligner;
 import com.ning.billing.entitlement.alignment.TimedPhase;
 import com.ning.billing.entitlement.api.SubscriptionApiService;
@@ -229,7 +231,7 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
                 subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId()), catalogService.getFullCatalog());
                 return true;
     }
-
+    
     public boolean changePlan(SubscriptionData subscription, String productName, BillingPeriod term,
             String priceList, DateTime requestedDate, CallContext context)
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionStatusDryRun.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionStatusDryRun.java
new file mode 100644
index 0000000..9971f41
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionStatusDryRun.java
@@ -0,0 +1,75 @@
+/* 
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package com.ning.billing.entitlement.api.user;
+
+import java.util.UUID;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+
+public class DefaultSubscriptionStatusDryRun implements SubscriptionStatusDryRun {
+        
+    private final UUID id;
+    private final String productName;
+    private final PhaseType phaseType;
+    private final BillingPeriod billingPeriod;
+    private final String priceList;
+    private final DryRunChangeReason reason;
+    
+    
+    public DefaultSubscriptionStatusDryRun(final UUID id, final String productName,
+            final PhaseType phaseType, final BillingPeriod billingPeriod, final String priceList,
+            final DryRunChangeReason reason) {
+        super();
+        this.id = id;
+        this.productName = productName;
+        this.phaseType = phaseType;
+        this.billingPeriod = billingPeriod;
+        this.priceList = priceList;
+        this.reason = reason;
+    }
+
+    @Override
+    public UUID getId() {
+        return id;
+    }
+
+    @Override
+    public String getProductName() {
+        return productName;
+    }
+
+    @Override
+    public PhaseType getPhaseType() {
+        return phaseType;
+    }
+
+    
+    @Override
+    public BillingPeriod getBillingPeriod() {
+        return billingPeriod;
+    }
+
+    @Override
+    public String getPriceList() {
+        return priceList;
+    }
+
+    @Override
+    public DryRunChangeReason getReason() {
+        return reason;
+    }
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
index 703e0bc..0bc6bb9 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
@@ -200,7 +200,6 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
         return apiService.recreatePlan(this, spec, requestedDate, context);
     }
 
-
     @Override
     public SubscriptionEvent getPendingTransition() {
         SubscriptionTransitionData data = getPendingTransitionData();
@@ -209,6 +208,11 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
         }
         return new DefaultSubscriptionEvent(data, startDate);
     }
+    
+    @Override
+    public BlockingState getBlockingState() {
+        throw new UnsupportedOperationException();
+    }
 
     protected SubscriptionTransitionData getPendingTransitionData() {
         if (transitions == null) {
@@ -520,10 +524,4 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
             previousPriceList = nextPriceList;
         }
     }
-
-    @Override
-    public BlockingState getBlockingState() {
-        throw new UnsupportedOperationException();
-    }
-
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java
index 3208f42..2a4a550 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/addon/AddonUtils.java
@@ -63,7 +63,16 @@ public class AddonUtils {
         }
     }
 
-    public boolean isAddonAvailable(final String basePlanName, final DateTime requestedDate, final Plan targetAddOnPlan) {
+    public boolean isAddonAvailableFromProdName(final String baseProductName, final DateTime requestedDate, final Plan targetAddOnPlan) {
+        try {
+            Product product = catalogService.getFullCatalog().findProduct(baseProductName, requestedDate);
+            return isAddonAvailable(product, targetAddOnPlan);
+        } catch (CatalogApiException e) {
+            throw new EntitlementError(e);
+        }
+    }
+
+    public boolean isAddonAvailableFromPlanName(final String basePlanName, final DateTime requestedDate, final Plan targetAddOnPlan) {
         try {
             Plan plan = catalogService.getFullCatalog().findPlan(basePlanName, requestedDate);
             Product product = plan.getProduct();
@@ -84,9 +93,19 @@ public class AddonUtils {
         }
         return false;
     }
+    
+    public boolean isAddonIncludedFromProdName(final String baseProductName, final DateTime requestedDate, final Plan targetAddOnPlan) {
+        try {            
+            Product product = catalogService.getFullCatalog().findProduct(baseProductName, requestedDate);
+            return isAddonIncluded(product, targetAddOnPlan);
+        } catch (CatalogApiException e) {
+            throw new EntitlementError(e);
+        }
 
-    public boolean isAddonIncluded(final String basePlanName,  final DateTime requestedDate, final Plan targetAddOnPlan) {
-        try {
+    }
+
+    public boolean isAddonIncludedFromPlanName(final String basePlanName, final DateTime requestedDate, final Plan targetAddOnPlan) {
+        try {            
             Plan plan = catalogService.getFullCatalog().findPlan(basePlanName, requestedDate);
             Product product = plan.getProduct();
             return isAddonIncluded(product, targetAddOnPlan);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
index 7534014..46ba0c3 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
@@ -527,8 +527,8 @@ public class EntitlementSqlDao implements EntitlementDao {
 
                         boolean createCancelEvent = (futureBaseEvent != null) &&
                         ((futureBaseEvent instanceof ApiEventCancel) ||
-                                ((! addonUtils.isAddonAvailable(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan)) ||
-                                        (addonUtils.isAddonIncluded(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan))));
+                                ((! addonUtils.isAddonAvailableFromPlanName(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan)) ||
+                                        (addonUtils.isAddonIncludedFromPlanName(baseProductName, futureBaseEvent.getEffectiveDate(), targetAddOnPlan))));
 
                         if (createCancelEvent) {
                             DateTime now = clock.getUTCNow();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
index d412e59..7990084 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
@@ -21,6 +21,8 @@ import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
+import java.util.List;
+
 import org.joda.time.DateTime;
 import org.joda.time.Interval;
 import org.testng.Assert;
@@ -42,6 +44,7 @@ import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
+import com.ning.billing.entitlement.api.user.SubscriptionStatusDryRun.DryRunChangeReason;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
 import com.ning.billing.util.clock.DefaultClock;
 
@@ -153,9 +156,9 @@ public class TestUserApiAddOn extends TestApiBase {
 
 
     @Test(enabled=true, groups={"slow"})
-    public void testChangeBPWithAddonNonIncluded() {
+    public void testChangeBPWithAddonIncluded() {
 
-        log.info("Starting testChangeBPWithAddonNonIncluded");
+        log.info("Starting testChangeBPWithAddonIncluded");
 
         try {
 
@@ -193,6 +196,15 @@ public class TestUserApiAddOn extends TestApiBase {
             BillingPeriod newBaseTerm = BillingPeriod.MONTHLY;
             String newBasePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
+            List<SubscriptionStatusDryRun> aoStatus = entitlementApi.getDryRunChangePlanStatus(baseSubscription.getId(), newBaseProduct, now);
+            assertEquals(aoStatus.size(), 1);
+            assertEquals(aoStatus.get(0).getId(), aoSubscription.getId());
+            assertEquals(aoStatus.get(0).getProductName(), aoProduct);
+            assertEquals(aoStatus.get(0).getBillingPeriod(), aoTerm);            
+            assertEquals(aoStatus.get(0).getPhaseType(), aoSubscription.getCurrentPhase().getPhaseType());                        
+            assertEquals(aoStatus.get(0).getPriceList(), aoSubscription.getCurrentPriceList().getName());
+            assertEquals(aoStatus.get(0).getReason(), DryRunChangeReason.AO_INCLUDED_IN_NEW_PLAN);            
+            
             testListener.reset();
             testListener.pushExpectedEvent(NextEvent.CHANGE);
             testListener.pushExpectedEvent(NextEvent.CANCEL);
@@ -250,9 +262,17 @@ public class TestUserApiAddOn extends TestApiBase {
             BillingPeriod newBaseTerm = BillingPeriod.MONTHLY;
             String newBasePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
 
+            List<SubscriptionStatusDryRun> aoStatus = entitlementApi.getDryRunChangePlanStatus(baseSubscription.getId(), newBaseProduct, now);
+            assertEquals(aoStatus.size(), 1);
+            assertEquals(aoStatus.get(0).getId(), aoSubscription.getId());
+            assertEquals(aoStatus.get(0).getProductName(), aoProduct);
+            assertEquals(aoStatus.get(0).getBillingPeriod(), aoTerm);   
+            assertEquals(aoStatus.get(0).getPhaseType(), aoSubscription.getCurrentPhase().getPhaseType());                                    
+            assertEquals(aoStatus.get(0).getPriceList(), aoSubscription.getCurrentPriceList().getName());
+            assertEquals(aoStatus.get(0).getReason(), DryRunChangeReason.AO_NOT_AVAILABLE_IN_NEW_PLAN);            
+            
             baseSubscription.changePlan(newBaseProduct, newBaseTerm, newBasePriceList, now, context);
 
-
             // REFETCH AO SUBSCRIPTION AND CHECK THIS IS ACTIVE
             aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId());
             assertEquals(aoSubscription.getState(), SubscriptionState.ACTIVE);
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index 0b064bb..fb30979 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -153,11 +153,6 @@ public class DefaultInvoiceDao implements InvoiceDao {
     @Override
     public void create(final Invoice invoice, final CallContext context) {
         
-        final InvoiceCreationEvent event = new DefaultInvoiceCreationEvent(invoice.getId(), invoice.getAccountId(),
-                invoice.getBalance(), invoice.getCurrency(),
-                invoice.getInvoiceDate(),
-                context.getUserToken());
-
         invoiceSqlDao.inTransaction(new Transaction<Void, InvoiceSqlDao>() {
             @Override
             public Void inTransaction(final InvoiceSqlDao transactional, final TransactionStatus status) throws Exception {
@@ -178,9 +173,6 @@ public class DefaultInvoiceDao implements InvoiceDao {
                     FixedPriceInvoiceItemSqlDao fixedPriceInvoiceItemDao = transactional.become(FixedPriceInvoiceItemSqlDao.class);
                     fixedPriceInvoiceItemDao.batchCreateFromTransaction(fixedPriceInvoiceItems, context);
 
-                    setChargedThroughDates(transactional, fixedPriceInvoiceItems, recurringInvoiceItems, context);
-
-                    // STEPH Why do we need that? Are the payments not always null at this point?
                     List<InvoicePayment> invoicePayments = invoice.getPayments();
                     InvoicePaymentSqlDao invoicePaymentSqlDao = transactional.become(InvoicePaymentSqlDao.class);
                     invoicePaymentSqlDao.batchCreateFromTransaction(invoicePayments, context);
@@ -190,18 +182,10 @@ public class DefaultInvoiceDao implements InvoiceDao {
                     auditSqlDao.insertAuditFromTransaction("recurring_invoice_items", getIdsFromInvoiceItems(recurringInvoiceItems), ChangeType.INSERT, context);
                     auditSqlDao.insertAuditFromTransaction("fixed_invoice_items", getIdsFromInvoiceItems(fixedPriceInvoiceItems), ChangeType.INSERT, context);
                     auditSqlDao.insertAuditFromTransaction("invoice_payments", getIdsFromInvoicePayments(invoicePayments), ChangeType.INSERT, context);
-
-                }
-                try {
-                    eventBus.postFromTransaction(event, transactional);
-                } catch (EventBusException e) {
-                    log.warn("Failed to post invoice event for invoiceId " + invoice.getId(), e);
                 }
                 return null;
             }
         });
-
-
     }
 
     private List<String> getIdsFromInvoiceItems(List<InvoiceItem> invoiceItems) {
@@ -377,34 +361,4 @@ public class DefaultInvoiceDao implements InvoiceDao {
             }
         }
     }
-    
-    private void setChargedThroughDates(final InvoiceSqlDao dao, final Collection<InvoiceItem> fixedPriceItems,
-                                        final Collection<InvoiceItem> recurringItems, CallContext context) {
-        Map<UUID, DateTime> chargeThroughDates = new HashMap<UUID, DateTime>();
-        addInvoiceItemsToChargeThroughDates(chargeThroughDates, fixedPriceItems);
-        addInvoiceItemsToChargeThroughDates(chargeThroughDates, recurringItems);
-
-        for (UUID subscriptionId : chargeThroughDates.keySet()) {
-            if(subscriptionId != null) {
-                DateTime chargeThroughDate = chargeThroughDates.get(subscriptionId);
-                log.info("Setting CTD for subscription {} to {}", subscriptionId.toString(), chargeThroughDate.toString());
-                billingApi.setChargedThroughDateFromTransaction(dao, subscriptionId, chargeThroughDate, context);
-            }
-        }
-    }
-
-    private void addInvoiceItemsToChargeThroughDates(Map<UUID, DateTime> chargeThroughDates, Collection<InvoiceItem> items) {
-        for (InvoiceItem item : items) {
-            UUID subscriptionId = item.getSubscriptionId();
-            DateTime endDate = item.getEndDate();
-
-            if (chargeThroughDates.containsKey(subscriptionId)) {
-                if (chargeThroughDates.get(subscriptionId).isBefore(endDate)) {
-                    chargeThroughDates.put(subscriptionId, endDate);
-                }
-            } else {
-                chargeThroughDates.put(subscriptionId, endDate);
-            }
-        }
-    }
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
index 53093a2..32d444d 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
@@ -17,7 +17,9 @@
 package com.ning.billing.invoice;
 
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.SortedSet;
 import java.util.UUID;
 
@@ -32,15 +34,20 @@ import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.entitlement.api.billing.BillingEvent;
+import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.api.user.SubscriptionEvent;
 import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceCreationEvent;
 import com.ning.billing.invoice.api.InvoiceNotifier;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.user.DefaultEmptyInvoiceEvent;
+import com.ning.billing.invoice.api.user.DefaultInvoiceCreationEvent;
 import com.ning.billing.invoice.dao.InvoiceDao;
 import com.ning.billing.invoice.model.BillingEventSet;
+import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
 import com.ning.billing.invoice.model.InvoiceGenerator;
+import com.ning.billing.invoice.model.RecurringInvoiceItem;
 import com.ning.billing.junction.api.BillingApi;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.Bus.EventBusException;
@@ -53,7 +60,7 @@ import com.ning.billing.util.globallocker.GlobalLocker.LockerService;
 import com.ning.billing.util.globallocker.LockFailedException;
 
 public class InvoiceDispatcher {
-	private final static Logger log = LoggerFactory.getLogger(InvoiceDispatcher.class);
+    private final static Logger log = LoggerFactory.getLogger(InvoiceDispatcher.class);
     private final static int NB_LOCK_TRY = 5;
 
     private final InvoiceGenerator generator;
@@ -69,12 +76,12 @@ public class InvoiceDispatcher {
 
     @Inject
     public InvoiceDispatcher(final InvoiceGenerator generator, final AccountUserApi accountUserApi,
-                             final BillingApi billingApi,
-                             final InvoiceDao invoiceDao,
-                             final InvoiceNotifier invoiceNotifier,
-                             final GlobalLocker locker,
-                             final Bus eventBus,
-                             final Clock clock) {
+            final BillingApi billingApi,
+            final InvoiceDao invoiceDao,
+            final InvoiceNotifier invoiceNotifier,
+            final GlobalLocker locker,
+            final Bus eventBus,
+            final Clock clock) {
         this.generator = generator;
         this.billingApi = billingApi;
         this.accountUserApi = accountUserApi;
@@ -89,7 +96,7 @@ public class InvoiceDispatcher {
     }
 
     public void processSubscription(final SubscriptionEvent transition,
-                                    final CallContext context) throws InvoiceApiException {
+            final CallContext context) throws InvoiceApiException {
         UUID subscriptionId = transition.getSubscriptionId();
         DateTime targetDate = transition.getEffectiveTransitionTime();
         log.info("Got subscription transition from InvoiceListener. id: " + subscriptionId.toString() + "; targetDate: " + targetDate.toString());
@@ -98,25 +105,24 @@ public class InvoiceDispatcher {
     }
 
     public void processSubscription(final UUID subscriptionId, final DateTime targetDate,
-                                    final CallContext context) throws InvoiceApiException {
-        if (subscriptionId == null) {
-            log.error("Failed handling entitlement change.", new InvoiceApiException(ErrorCode.INVOICE_INVALID_TRANSITION));
-            return;
-        }
-
-        UUID accountId = billingApi.getAccountIdFromSubscriptionId(subscriptionId);
-        if (accountId == null) {
+            final CallContext context) throws InvoiceApiException {
+        try {
+            if (subscriptionId == null) {
+                log.error("Failed handling entitlement change.", new InvoiceApiException(ErrorCode.INVOICE_INVALID_TRANSITION));
+                return;
+            }
+            UUID accountId = billingApi.getAccountIdFromSubscriptionId(subscriptionId);
+            processAccount(accountId, targetDate, false, context);
+        } catch (EntitlementBillingApiException e) {
             log.error("Failed handling entitlement change.",
                     new InvoiceApiException(ErrorCode.INVOICE_NO_ACCOUNT_ID_FOR_SUBSCRIPTION_ID, subscriptionId.toString()));
-            return;
         }
-
-        processAccount(accountId, targetDate, false, context);
+        return;
     }
-    
+
     public Invoice processAccount(final UUID accountId, final DateTime targetDate,
-                                  final boolean dryRun, final CallContext context) throws InvoiceApiException {
-		GlobalLock lock = null;
+            final boolean dryRun, final CallContext context) throws InvoiceApiException {
+        GlobalLock lock = null;
         try {
             lock = locker.lockWithNumberOfTries(LockerService.INVOICE, accountId.toString(), NB_LOCK_TRY);
 
@@ -134,15 +140,7 @@ public class InvoiceDispatcher {
         return null;
     }
 
-    private void postEmptyInvoiceEvent(final UUID accountId, final UUID userToken) {
-        try {
-            BusEvent event = new DefaultEmptyInvoiceEvent(accountId, clock.getUTCNow(), userToken);
-            eventBus.post(event);
-        } catch (EventBusException e){
-            log.error("Failed to post DefaultEmptyInvoiceNotification event for account {} ", accountId, e);
-        }
-    }
-
+   
     private Invoice processAccountWithLock(final UUID accountId, final DateTime targetDate,
             final boolean dryRun, final CallContext context) throws InvoiceApiException {
         try {
@@ -159,7 +157,8 @@ public class InvoiceDispatcher {
                 log.info("Generated null invoice.");
                 outputDebugData(events, invoices);
                 if (!dryRun) {
-                    postEmptyInvoiceEvent(accountId, context.getUserToken());
+                    BusEvent event = new DefaultEmptyInvoiceEvent(accountId, clock.getUTCNow(), context.getUserToken());
+                    postEvent(event, accountId);
                 }
             } else {
                 log.info("Generated invoice {} with {} items.", invoice.getId().toString(), invoice.getNumberOfItems());
@@ -172,6 +171,17 @@ public class InvoiceDispatcher {
                 outputDebugData(events, invoices);
                 if (!dryRun) {
                     invoiceDao.create(invoice, context);
+
+                    List<InvoiceItem> fixedPriceInvoiceItems = invoice.getInvoiceItems(FixedPriceInvoiceItem.class);
+                    List<InvoiceItem> recurringInvoiceItems = invoice.getInvoiceItems(RecurringInvoiceItem.class);
+                    setChargedThroughDates(fixedPriceInvoiceItems, recurringInvoiceItems, context);
+
+                    final InvoiceCreationEvent event = new DefaultInvoiceCreationEvent(invoice.getId(), invoice.getAccountId(),
+                            invoice.getBalance(), invoice.getCurrency(),
+                            invoice.getInvoiceDate(),
+                            context.getUserToken());
+
+                    postEvent(event, accountId);
                 }
             }
 
@@ -186,6 +196,47 @@ public class InvoiceDispatcher {
         }
     }
 
+    private void setChargedThroughDates(final Collection<InvoiceItem> fixedPriceItems,
+            final Collection<InvoiceItem> recurringItems, CallContext context) {
+
+        Map<UUID, DateTime> chargeThroughDates = new HashMap<UUID, DateTime>();
+        addInvoiceItemsToChargeThroughDates(chargeThroughDates, fixedPriceItems);
+        addInvoiceItemsToChargeThroughDates(chargeThroughDates, recurringItems);
+
+        for (UUID subscriptionId : chargeThroughDates.keySet()) {
+            if(subscriptionId != null) {
+                DateTime chargeThroughDate = chargeThroughDates.get(subscriptionId);
+                log.info("Setting CTD for subscription {} to {}", subscriptionId.toString(), chargeThroughDate.toString());
+                billingApi.setChargedThroughDate(subscriptionId, chargeThroughDate, context);
+            }
+        }
+    }
+    
+    private void postEvent(final BusEvent event, final UUID accountId) {
+        try {
+            eventBus.post(event);
+        } catch (EventBusException e){
+            log.error(String.format("Failed to post event {} for account {} ", event.getBusEventType(), accountId), e);
+        }
+    }
+
+
+    private void addInvoiceItemsToChargeThroughDates(Map<UUID, DateTime> chargeThroughDates, Collection<InvoiceItem> items) {
+        for (InvoiceItem item : items) {
+            UUID subscriptionId = item.getSubscriptionId();
+            DateTime endDate = item.getEndDate();
+
+            if (chargeThroughDates.containsKey(subscriptionId)) {
+                if (chargeThroughDates.get(subscriptionId).isBefore(endDate)) {
+                    chargeThroughDates.put(subscriptionId, endDate);
+                }
+            } else {
+                chargeThroughDates.put(subscriptionId, endDate);
+            }
+        }
+    }
+
+
     private void outputDebugData(Collection<BillingEvent> events, Collection<Invoice> invoices) {
         if (VERBOSE_OUTPUT) {
             log.info("Events");
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
index 5d7d14f..a7b0f09 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
@@ -132,7 +132,7 @@ public class TestDefaultInvoiceMigrationApi extends InvoicingTestBase {
 
 		busService.getBus().start();
 
-        ((ZombieControl)billingApi).addResult("setChargedThroughDateFromTransaction", BrainDeadProxyFactory.ZOMBIE_VOID);
+        ((ZombieControl)billingApi).addResult("setChargedThroughDate", BrainDeadProxyFactory.ZOMBIE_VOID);
 		migrationInvoiceId = createAndCheckMigrationInvoice();
 		regularInvoiceId = generateRegularInvoice();
 
@@ -189,11 +189,10 @@ public class TestDefaultInvoiceMigrationApi extends InvoicingTestBase {
                 fixedPrice, BigDecimal.ONE, currency, BillingPeriod.MONTHLY, 1,
                 BillingModeType.IN_ADVANCE, "", 1L, SubscriptionTransitionType.CREATE));
 
-		BillingApi entitlementBillingApi = BrainDeadProxyFactory.createBrainDeadProxyFor(BillingApi.class);
-        ((ZombieControl)entitlementBillingApi).addResult("getBillingEventsForAccountAndUpdateAccountBCD", events);
+		((ZombieControl)billingApi).addResult("getBillingEventsForAccountAndUpdateAccountBCD", events);
 
         InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
-		InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, entitlementBillingApi,
+		InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, billingApi,
                                                              invoiceDao, invoiceNotifier, locker, busService.getBus(), clock);
 
         CallContext context = new DefaultCallContextFactory(clock).createCallContext("Migration test", CallOrigin.TEST, UserType.TEST);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
index e591dfa..26403d0 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
@@ -115,7 +115,7 @@ public class TestInvoiceDispatcher extends InvoicingTestBase {
         context = new DefaultCallContextFactory(clock).createCallContext("Miracle Max", CallOrigin.TEST, UserType.TEST);
 
 		busService.getBus().start();
-		((ZombieControl)billingApi).addResult("setChargedThroughDateFromTransaction", BrainDeadProxyFactory.ZOMBIE_VOID);
+		((ZombieControl)billingApi).addResult("setChargedThroughDate", BrainDeadProxyFactory.ZOMBIE_VOID);
 	}
 
 	@AfterClass(alwaysRun = true)
@@ -155,13 +155,12 @@ public class TestInvoiceDispatcher extends InvoicingTestBase {
                 fixedPrice, BigDecimal.ONE, currency, BillingPeriod.MONTHLY, 1,
                 BillingModeType.IN_ADVANCE, "", 1L, SubscriptionTransitionType.CREATE));
 
-		BillingApi entitlementBillingApi = BrainDeadProxyFactory.createBrainDeadProxyFor(BillingApi.class);
-		((ZombieControl) entitlementBillingApi).addResult("getBillingEventsForAccountAndUpdateAccountBCD", events);
+		((ZombieControl) billingApi).addResult("getBillingEventsForAccountAndUpdateAccountBCD", events);
 
 		DateTime target = new DateTime();
 
         InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
-		InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, entitlementBillingApi, invoiceDao,
+		InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, billingApi, invoiceDao,
                                                              invoiceNotifier, locker, busService.getBus(), clock);
 
 		Invoice invoice = dispatcher.processAccount(accountId, target, true, context);
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
index 9061eac..07502cc 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
@@ -67,6 +67,7 @@ import com.ning.billing.jaxrs.util.Context;
 import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
 import com.ning.billing.jaxrs.util.TagHelper;
 import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
 import com.ning.billing.payment.api.PaymentAttempt;
 import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.util.api.TagDefinitionApiException;
@@ -268,6 +269,9 @@ public class AccountResource implements BaseJaxrsResource {
             return Response.status(Status.OK).entity(json).build();
         } catch (AccountApiException e) {
             return Response.status(Status.NO_CONTENT).build();
+        } catch (PaymentApiException e) {
+            log.error(e.getMessage());
+            return Response.status(Status.INTERNAL_SERVER_ERROR).build();
         } catch (EntitlementRepairException e) {
             log.error(e.getMessage());
             return Response.status(Status.INTERNAL_SERVER_ERROR).build();
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
index aeb3f7a..67c5b5c 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
@@ -92,7 +92,6 @@ public class SubscriptionResource implements BaseJaxrsResource {
         try {
             UUID uuid = UUID.fromString(subscriptionId);
             Subscription subscription = entitlementApi.getSubscriptionFromId(uuid);
-
             SubscriptionJsonNoEvents json = new SubscriptionJsonNoEvents(subscription);
             return Response.status(Status.OK).entity(json).build();
         } catch (EntitlementUserApiException e) {
@@ -101,7 +100,6 @@ public class SubscriptionResource implements BaseJaxrsResource {
             } else {
                 throw e;
             }
-
         }
     }
   
@@ -185,14 +183,13 @@ public class SubscriptionResource implements BaseJaxrsResource {
                     return operationResponse;
                 }
                 try {
-                return getSubscription(subscriptionId);
+                    return getSubscription(subscriptionId);
                 } catch (EntitlementUserApiException e) {
                     if (e.getCode() == ErrorCode.ENT_GET_INVALID_BUNDLE_ID.getCode()) {
                         return Response.status(Status.NO_CONTENT).build();
                     } else {
                         return Response.status(Status.INTERNAL_SERVER_ERROR).build();
                     }
-
                 }
             }
         };
@@ -333,13 +330,10 @@ public class SubscriptionResource implements BaseJaxrsResource {
                 return callback.doResponseOk(operationValue);
             } catch (EntitlementUserApiException e) {
                 log.info(String.format("Failed to complete operation"), e);
-                //throw new WebApplicationException(Response.Status.BAD_REQUEST);
                 return Response.status(Status.BAD_REQUEST).build();
             } catch (InterruptedException e) {
-                //throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);                
                 return Response.status(Status.INTERNAL_SERVER_ERROR).build();
             } catch (TimeoutException e) {
-                //throw new WebApplicationException(Response.Status.fromStatusCode(408));                
                 return Response.status(Status.fromStatusCode(408)).build();   
             } finally {
                 if (waiter != null) {
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingEntitlementUserApi.java b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingEntitlementUserApi.java
index 3d340da..9452146 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingEntitlementUserApi.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingEntitlementUserApi.java
@@ -29,6 +29,7 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionStatusDryRun;
 import com.ning.billing.junction.api.Blockable;
 import com.ning.billing.junction.api.BlockingApi;
 import com.ning.billing.junction.api.BlockingApiException;
@@ -40,7 +41,7 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
     private final EntitlementUserApi entitlementUserApi;
     private final BlockingApi blockingApi;
     private final BlockingChecker checker;
-    
+
     @Inject
     public BlockingEntitlementUserApi(@RealImplementation EntitlementUserApi userApi, BlockingApi blockingApi, BlockingChecker checker) {
         this.entitlementUserApi = userApi;
@@ -48,32 +49,25 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
         this.checker = checker;
     }
 
+    @Override
     public SubscriptionBundle getBundleFromId(UUID id) throws EntitlementUserApiException {
         SubscriptionBundle bundle = entitlementUserApi.getBundleFromId(id);
-        if(bundle == null) {
-            throw new EntitlementUserApiException(ErrorCode.ENT_GET_INVALID_BUNDLE_ID, id);
-        }
         return new BlockingSubscriptionBundle(bundle, blockingApi);
     }
 
+    @Override
     public Subscription getSubscriptionFromId(UUID id) throws EntitlementUserApiException {
         Subscription subscription = entitlementUserApi.getSubscriptionFromId(id);
-        if(subscription == null) {
-            throw new EntitlementUserApiException(ErrorCode.ENT_INVALID_SUBSCRIPTION_ID, id);
-        }
         return new BlockingSubscription(subscription, blockingApi, checker);
     }
 
-    
+    @Override
     public SubscriptionBundle getBundleForKey(String bundleKey) throws EntitlementUserApiException {
         SubscriptionBundle bundle = entitlementUserApi.getBundleForKey(bundleKey);
-        if(bundle == null) {
-            throw new EntitlementUserApiException(ErrorCode.ENT_GET_INVALID_BUNDLE_KEY, bundleKey);
-        }
-
         return new BlockingSubscriptionBundle(bundle, blockingApi);
     }
 
+    @Override
     public List<SubscriptionBundle> getBundlesForAccount(UUID accountId) {
         List<SubscriptionBundle> result = new ArrayList<SubscriptionBundle>();
         List<SubscriptionBundle> bundles = entitlementUserApi.getBundlesForAccount(accountId);
@@ -83,6 +77,7 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
         return result;
     }
 
+    @Override
     public List<Subscription> getSubscriptionsForBundle(UUID bundleId) {
         List<Subscription> result = new ArrayList<Subscription>();
         List<Subscription> subscriptions = entitlementUserApi.getSubscriptionsForBundle(bundleId);
@@ -92,6 +87,7 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
         return result;
     }
 
+    @Override
     public List<Subscription> getSubscriptionsForKey(String bundleKey) {
         List<Subscription> result = new ArrayList<Subscription>();
         List<Subscription> subscriptions = entitlementUserApi.getSubscriptionsForKey(bundleKey);
@@ -101,20 +97,30 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
         return result;
     }
 
-    public Subscription getBaseSubscription(UUID bundleId) {
+    @Override
+    public List<SubscriptionStatusDryRun> getDryRunChangePlanStatus(
+            UUID subscriptionId, String productName, DateTime requestedDate)
+            throws EntitlementUserApiException {
+        return entitlementUserApi.getDryRunChangePlanStatus(subscriptionId, productName, requestedDate);
+    }
+
+    @Override
+    public Subscription getBaseSubscription(UUID bundleId) throws EntitlementUserApiException {
         return new BlockingSubscription(entitlementUserApi.getBaseSubscription(bundleId), blockingApi, checker);
     }
 
+    @Override
     public SubscriptionBundle createBundleForAccount(UUID accountId, String bundleKey, CallContext context)
-            throws EntitlementUserApiException {
+    throws EntitlementUserApiException {
         try {
-           checker.checkBlockedChange(accountId, Blockable.Type.ACCOUNT);
-           return new BlockingSubscriptionBundle(entitlementUserApi.createBundleForAccount(accountId, bundleKey, context), blockingApi);
+            checker.checkBlockedChange(accountId, Blockable.Type.ACCOUNT);
+            return new BlockingSubscriptionBundle(entitlementUserApi.createBundleForAccount(accountId, bundleKey, context), blockingApi);
         }catch (BlockingApiException e) {
             throw new EntitlementUserApiException(e, e.getCode(), e.getMessage());
         }
-   }
+    }
 
+    @Override
     public Subscription createSubscription(UUID bundleId, PlanPhaseSpecifier spec, DateTime requestedDate,
             CallContext context) throws EntitlementUserApiException {
         try {
@@ -125,8 +131,8 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
         }
     }
 
+    @Override
     public DateTime getNextBillingDate(UUID account) {
         return entitlementUserApi.getNextBillingDate(account);
     }
-
 }
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BillCycleDayCalculator.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BillCycleDayCalculator.java
index 07dccb8..b1c5558 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BillCycleDayCalculator.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BillCycleDayCalculator.java
@@ -34,6 +34,7 @@ import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionEvent;
@@ -51,7 +52,8 @@ public class BillCycleDayCalculator {
 		this.entitlementApi = entitlementApi;
 	}
 
-	protected int calculateBcd(SubscriptionBundle bundle, Subscription subscription, final SubscriptionEvent transition, final Account account) throws CatalogApiException, AccountApiException {
+	protected int calculateBcd(SubscriptionBundle bundle, Subscription subscription, final SubscriptionEvent transition, final Account account)
+	throws CatalogApiException, AccountApiException, EntitlementUserApiException {
 
 	    Catalog catalog = catalogService.getFullCatalog();
 		
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
index e8945c5..3f14062 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
@@ -27,6 +27,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.AccountUserApi;
@@ -35,6 +36,7 @@ import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.entitlement.api.billing.BillingEvent;
 import com.ning.billing.entitlement.api.billing.ChargeThruApi;
+import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
@@ -108,27 +110,22 @@ public class DefaultBillingApi implements BillingApi {
         } catch (AccountApiException e) {
             log.warn("Failed while getting BillingEvent", e);
         }
-
         blockCalculator.insertBlockingEvents(result);
-
         return result;
     }
 
 
     @Override
-    public UUID getAccountIdFromSubscriptionId(UUID subscriptionId) {
-        return chargeThruApi.getAccountIdFromSubscriptionId(subscriptionId);
+    public UUID getAccountIdFromSubscriptionId(UUID subscriptionId) throws EntitlementBillingApiException {
+        UUID result = chargeThruApi.getAccountIdFromSubscriptionId(subscriptionId);
+        if (result == null) {
+            throw new EntitlementBillingApiException(ErrorCode.ENT_INVALID_SUBSCRIPTION_ID, subscriptionId.toString());
+        }
+        return result;
     }
 
     @Override
     public void setChargedThroughDate(UUID subscriptionId, DateTime ctd, CallContext context) {
         chargeThruApi.setChargedThroughDate(subscriptionId, ctd, context);
     }
-
-    @Override
-    public void setChargedThroughDateFromTransaction(Transmogrifier transactionalDao, UUID subscriptionId,
-            DateTime ctd, CallContext context) {
-        chargeThruApi.setChargedThroughDateFromTransaction(transactionalDao, subscriptionId, ctd, context);
-    }
-
 }

overdue/pom.xml 7(+0 -7)

diff --git a/overdue/pom.xml b/overdue/pom.xml
index 6d98d63..3662f2b 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -104,13 +104,6 @@
         <plugins>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <groups>fast,slow, stress</groups>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-jar-plugin</artifactId>
                 <executions>
                     <execution>
diff --git a/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java b/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
index 8da7713..83487ea 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
@@ -21,6 +21,7 @@ import org.apache.commons.lang.NotImplementedException;
 import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.junction.api.Blockable;
 import com.ning.billing.junction.api.BlockingApi;
@@ -35,7 +36,7 @@ import com.ning.billing.overdue.service.ExtendedOverdueService;
 import com.ning.billing.overdue.wrapper.OverdueWrapper;
 import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
 
-public class DefaultOverdueUserApi implements OverdueUserApi{
+public class DefaultOverdueUserApi implements OverdueUserApi { 
 
     
     private final OverdueWrapperFactory factory;
diff --git a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java
index 640ca9a..d47f3f3 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java
@@ -27,6 +27,7 @@ import java.util.UUID;
 import org.joda.time.DateTime;
 
 import com.google.inject.Inject;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceUserApi;
 import com.ning.billing.junction.api.Blockable;
@@ -56,7 +57,7 @@ public abstract class BillingStateCalculator<T extends Blockable> {
         this.clock = clock;
     }
     
-    public abstract BillingState<T> calculateBillingState(T overdueable);
+    public abstract BillingState<T> calculateBillingState(T overdueable) throws EntitlementUserApiException;
     
     protected DateTime earliest(SortedSet<Invoice> unpaidInvoices) {
         return unpaidInvoices.first().getInvoiceDate();
diff --git a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
index 544420f..89a7cc6 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
@@ -29,6 +29,7 @@ import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.invoice.api.Invoice;
@@ -50,7 +51,7 @@ public class BillingStateCalculatorBundle  extends BillingStateCalculator<Subscr
     }
     
     @Override
-    public BillingStateBundle calculateBillingState(SubscriptionBundle bundle) {
+    public BillingStateBundle calculateBillingState(SubscriptionBundle bundle) throws EntitlementUserApiException {
         
         SortedSet<Invoice> unpaidInvoices = unpaidInvoicesForBundle(bundle.getId(), bundle.getAccountId());
  
diff --git a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java
index 1aa4822..97220d5 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java
@@ -16,8 +16,7 @@
 
 package com.ning.billing.overdue.wrapper;
 
-import org.joda.time.Period;
-
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.junction.api.Blockable;
 import com.ning.billing.junction.api.BlockingApi;
 import com.ning.billing.overdue.OverdueApiException;
@@ -51,15 +50,19 @@ public class OverdueWrapper<T extends Blockable> {
     }
 
     public OverdueState<T> refresh() throws OverdueError, OverdueApiException {
-        OverdueState<T> nextOverdueState;
-        BillingState<T> billingState    = billingStateCalcuator.calculateBillingState(overdueable);
-        String previousOverdueStateName = api.getBlockingStateFor(overdueable).getStateName();
-        nextOverdueState                = overdueStateSet.calculateOverdueState(billingState, clock.getUTCNow());
+        try {
+            OverdueState<T> nextOverdueState;
+            BillingState<T> billingState    = billingStateCalcuator.calculateBillingState(overdueable);
+            String previousOverdueStateName = api.getBlockingStateFor(overdueable).getStateName();
+            nextOverdueState                = overdueStateSet.calculateOverdueState(billingState, clock.getUTCNow());
 
-        if(!previousOverdueStateName.equals(nextOverdueState.getName())) {
-            overdueStateApplicator.apply(overdueable, nextOverdueState, nextOverdueState); 
-        }
+            if(!previousOverdueStateName.equals(nextOverdueState.getName())) {
+                overdueStateApplicator.apply(overdueable, nextOverdueState, nextOverdueState); 
+            }
 
-        return nextOverdueState;
+            return nextOverdueState;
+        } catch (EntitlementUserApiException e) {
+            throw new OverdueError(e);
+        }
     }
 }
\ No newline at end of file
diff --git a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
index 3d5b855..bb7ece3 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
@@ -86,7 +86,8 @@ public class TestBillingStateCalculatorBundle extends TestBillingStateCalculator
     }
     
     @Test(groups = {"fast"}, enabled=true)
-    public void testcalculateBillingStateForBundle() {
+    public void testcalculateBillingStateForBundle() throws Exception {
+        
        UUID thisBundleId = new UUID(0L,0L);
        UUID thatBundleId = new UUID(0L,1L);
        
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 2ed490c..2ac89d2 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
@@ -18,6 +18,7 @@ package com.ning.billing.payment.api;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
 
@@ -29,6 +30,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.AccountUserApi;
@@ -68,9 +70,14 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public Either<PaymentErrorEvent, PaymentMethodInfo> getPaymentMethod(@Nullable String accountKey, String paymentMethodId) {
+    public PaymentMethodInfo getPaymentMethod(final String accountKey, final String paymentMethodId) 
+    throws PaymentApiException {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
-        return plugin.getPaymentMethodInfo(paymentMethodId);
+        Either<PaymentErrorEvent, PaymentMethodInfo> result = plugin.getPaymentMethodInfo(paymentMethodId);
+        if (result.isLeft()) {
+            throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, accountKey, paymentMethodId);
+        }
+        return result.getRight();
     }
 
     private PaymentProviderPlugin getPaymentProviderPlugin(String accountKey) {
@@ -100,60 +107,86 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public Either<PaymentErrorEvent, List<PaymentMethodInfo>> getPaymentMethods(String accountKey) {
+    public List<PaymentMethodInfo> getPaymentMethods(String accountKey)
+    throws PaymentApiException {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
-        return plugin.getPaymentMethods(accountKey);
+        Either<PaymentErrorEvent, List<PaymentMethodInfo>> result =  plugin.getPaymentMethods(accountKey);
+        if (result.isLeft()) {
+            throw new PaymentApiException(ErrorCode.PAYMENT_NO_PAYMENT_METHODS, accountKey);
+        }
+        return result.getRight();
     }
 
     @Override
-    public Either<PaymentErrorEvent, Void> updatePaymentGateway(String accountKey, CallContext context) {
+    public void updatePaymentGateway(String accountKey, CallContext context) 
+    throws PaymentApiException {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
-        return plugin.updatePaymentGateway(accountKey);
+        Either<PaymentErrorEvent, Void> result =  plugin.updatePaymentGateway(accountKey);
+        if (result.isLeft()) {
+            throw new PaymentApiException(ErrorCode.PAYMENT_UPD_GATEWAY_FAILED, accountKey, result.getLeft().getMessage());
+        }
+        return;
     }
 
     @Override
-    public Either<PaymentErrorEvent, PaymentProviderAccount> getPaymentProviderAccount(String accountKey) {
+    public PaymentProviderAccount getPaymentProviderAccount(String accountKey)
+    throws PaymentApiException {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
-        return plugin.getPaymentProviderAccount(accountKey);
+        Either<PaymentErrorEvent, PaymentProviderAccount> result = plugin.getPaymentProviderAccount(accountKey);
+        if (result.isLeft()) {
+            throw new PaymentApiException(ErrorCode.PAYMENT_GET_PAYMENT_PROVIDER, accountKey, result.getLeft().getMessage());
+        }
+        return result.getRight();
     }
 
     @Override
-    public Either<PaymentErrorEvent, String> addPaymentMethod(@Nullable String accountKey, PaymentMethodInfo paymentMethod, CallContext context) {
+    public String addPaymentMethod(String accountKey, PaymentMethodInfo paymentMethod, CallContext context) 
+    throws PaymentApiException {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
-        return plugin.addPaymentMethod(accountKey, paymentMethod);
+        Either<PaymentErrorEvent, String> result =  plugin.addPaymentMethod(accountKey, paymentMethod);
+        if (result.isLeft()) {
+            throw new PaymentApiException(ErrorCode.PAYMENT_ADD_PAYMENT_METHOD, accountKey, result.getLeft().getMessage());
+        }
+        return result.getRight();
     }
 
+
     @Override
-    public Either<PaymentErrorEvent, Void> deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context) {
+    public void deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context) 
+    throws PaymentApiException {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
-        return plugin.deletePaymentMethod(accountKey, paymentMethodId);
+        Either<PaymentErrorEvent, Void> result =  plugin.deletePaymentMethod(accountKey, paymentMethodId);
+        if (result.isLeft()) {
+            throw new PaymentApiException(ErrorCode.PAYMENT_DEL_PAYMENT_METHOD, accountKey, result.getLeft().getMessage());
+        }
+        return;
     }
 
     @Override
-    public Either<PaymentErrorEvent, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context) {
+    public PaymentMethodInfo updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context) 
+    throws PaymentApiException {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
-        return plugin.updatePaymentMethod(accountKey, paymentMethodInfo);
+        Either<PaymentErrorEvent, PaymentMethodInfo> result = plugin.updatePaymentMethod(accountKey, paymentMethodInfo);
+        if (result.isLeft()) {
+            throw new PaymentApiException(ErrorCode.PAYMENT_UPD_PAYMENT_METHOD, accountKey, result.getLeft().getMessage());
+        }
+        return result.getRight();
     }
 
     @Override
-    public List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(String accountKey, List<String> invoiceIds, CallContext context) {
+    public List<PaymentInfoEvent> createPayment(String accountKey, List<String> invoiceIds, CallContext context) 
+    throws PaymentApiException {
         try {
             final Account account = accountUserApi.getAccountByKey(accountKey);
             return createPayment(account, invoiceIds, context);
         } catch (AccountApiException e) {
-            log.error("Error getting payment provider plugin.", e);
-            List<Either<PaymentErrorEvent, PaymentInfoEvent>> result = new ArrayList<Either<PaymentErrorEvent, PaymentInfoEvent>>();
-            result.add(new Either.Left<PaymentErrorEvent, PaymentInfoEvent>((PaymentErrorEvent) new DefaultPaymentErrorEvent("createPaymentError", e.getMessage(),
-                    null,
-                    null,
-                    context.getUserToken())));
-            return result;
+            throw new PaymentApiException(e);
         }
-
     }
 
     @Override
-    public Either<PaymentErrorEvent, PaymentInfoEvent> createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context) {
+    public PaymentInfoEvent createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context) 
+    throws PaymentApiException {
 
         PaymentAttempt paymentAttempt = paymentDao.getPaymentAttemptById(paymentAttemptId);
         if (paymentAttempt != null) {
@@ -165,40 +198,35 @@ public class DefaultPaymentApi implements PaymentApi {
                     if (invoice.getBalance().compareTo(BigDecimal.ZERO) <= 0 ) {
                         // TODO: send a notification that invoice was ignored?
                         log.info("Received invoice for payment with outstanding amount of 0 {} ", invoice);
-                        return Either.left((PaymentErrorEvent) new DefaultPaymentErrorEvent("invoice_balance_0",
-                                "Invoice balance was 0 or less",
-                                paymentAttempt.getAccountId(),
-                                paymentAttempt.getInvoiceId(),
-                                context.getUserToken()));
-                    }
-                    else {
+                        throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT_WITH_NON_POSITIVE_INV, account.getId());
+
+                    } else {
+                        
                         PaymentAttempt newPaymentAttempt = new PaymentAttempt.Builder(paymentAttempt)
                         .setRetryCount(paymentAttempt.getRetryCount() + 1)
                         .setPaymentAttemptId(UUID.randomUUID())
                         .build();
 
                         paymentDao.createPaymentAttempt(newPaymentAttempt, context);
-                        return processPayment(getPaymentProviderPlugin(account), account, invoice, newPaymentAttempt, context);
+                        Either<PaymentErrorEvent, PaymentInfoEvent> result =  processPayment(getPaymentProviderPlugin(account), account, invoice, newPaymentAttempt, context);
+                        if (result.isLeft()) {
+                            throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT, account.getId(),  paymentAttemptId, result.getLeft().getMessage());                            
+                        }
+                        return result.getRight();
+
                     }
                 }
             } catch (AccountApiException e) {
-                log.error("Error creating payment attempt.", e);
-                return new Either.Left<PaymentErrorEvent, PaymentInfoEvent>((PaymentErrorEvent) new DefaultPaymentErrorEvent("createPaymentError", e.getMessage(),
-                        null,
-                        null,
-                        context.getUserToken()));
-
+                throw new PaymentApiException(e);
             }
         }
-        return Either.left((PaymentErrorEvent) new DefaultPaymentErrorEvent("retry_payment_error",
-                "Could not load payment attempt, invoice or account for id " + paymentAttemptId,
-                paymentAttempt.getAccountId(),
-                paymentAttempt.getInvoiceId(),
-                context.getUserToken()));
+        throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT_FOR_ATTEMPT_BAD, paymentAttemptId);
     }
 
     @Override
-    public List<Either<PaymentErrorEvent, PaymentInfoEvent>> createPayment(Account account, List<String> invoiceIds, CallContext context) {
+    public List<PaymentInfoEvent> createPayment(Account account, List<String> invoiceIds, CallContext context) 
+        throws PaymentApiException {
+        
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
 
         List<Either<PaymentErrorEvent, PaymentInfoEvent>> processedPaymentsOrErrors = new ArrayList<Either<PaymentErrorEvent, PaymentInfoEvent>>(invoiceIds.size());
@@ -225,7 +253,15 @@ public class DefaultPaymentApi implements PaymentApi {
             }
         }
 
-        return processedPaymentsOrErrors;
+        List<Either<PaymentErrorEvent, PaymentInfoEvent>> result =  processedPaymentsOrErrors;
+        List<PaymentInfoEvent> info = new LinkedList<PaymentInfoEvent>();
+        for (Either<PaymentErrorEvent, PaymentInfoEvent> cur : result) {
+            if (cur.isLeft()) {
+                throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT, account.getId(), cur.getLeft().getMessage());
+            }
+            info.add(cur.getRight());
+        }
+        return info;
     }
 
     private Either<PaymentErrorEvent, PaymentInfoEvent> processPayment(PaymentProviderPlugin plugin, Account account, Invoice invoice,
@@ -271,10 +307,10 @@ public class DefaultPaymentApi implements PaymentApi {
                 invoice.getId(),
                 paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : paymentInfo.getAmount(),
                         //                                                                         paymentInfo.getRefundAmount(), TODO
-                paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : invoice.getCurrency(),
-                paymentAttempt.getPaymentAttemptId(),
-                paymentAttempt.getPaymentAttemptDate(),
-                context);
+                        paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : invoice.getCurrency(),
+                                paymentAttempt.getPaymentAttemptId(),
+                                paymentAttempt.getPaymentAttemptDate(),
+                                context);
 
         return paymentOrError;
     }
@@ -311,24 +347,29 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public Either<PaymentErrorEvent, String> createPaymentProviderAccount(Account account, CallContext context) {
+    public String createPaymentProviderAccount(Account account, CallContext context) 
+        throws PaymentApiException {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin((Account)null);
-        return plugin.createPaymentProviderAccount(account);
+        Either<PaymentErrorEvent, String> result =  plugin.createPaymentProviderAccount(account);
+        if (result.isLeft()) {
+            throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT_PROVIDER_ACCOUNT, account.getId(), result.getLeft().getMessage());
+        }
+        return result.getRight();
     }
 
     @Override
-    public Either<PaymentErrorEvent, Void> updatePaymentProviderAccountContact(String externalKey, CallContext context) {
+    public void updatePaymentProviderAccountContact(String externalKey, CallContext context) 
+        throws PaymentApiException {
         try {
             Account account = accountUserApi.getAccountByKey(externalKey);
             final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
-            return plugin.updatePaymentProviderAccountExistingContact(account);
+            Either<PaymentErrorEvent, Void> result = plugin.updatePaymentProviderAccountExistingContact(account);
+            if (result.isLeft()) {
+                throw new PaymentApiException(ErrorCode.PAYMENT_UPD_PAYMENT_PROVIDER_ACCOUNT, account.getId(), result.getLeft().getMessage());
+            }
+            return;
         } catch (AccountApiException e) {
-            log.error("Error updating payment provider account contact.", e);
-            return new Either.Left<PaymentErrorEvent, Void>((PaymentErrorEvent) new DefaultPaymentErrorEvent("updatePaymentProviderAccountContactError", e.getMessage(),
-                    null,
-                    null,
-                    context.getUserToken()));
-
+            throw new PaymentApiException(e);
         }
     }
 
@@ -338,11 +379,19 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public List<Either<PaymentErrorEvent, PaymentInfoEvent>> createRefund(Account account,
-            List<String> invoiceIds,
-            CallContext context) {
+    public List<PaymentInfoEvent> createRefund(Account account, List<String> invoiceIds, CallContext context)
+        throws PaymentApiException {
+            
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
-        return plugin.processRefund(account);
+        List<Either<PaymentErrorEvent, PaymentInfoEvent>> result = plugin.processRefund(account);
+        List<PaymentInfoEvent> info =  new LinkedList<PaymentInfoEvent>();
+        for (Either<PaymentErrorEvent, PaymentInfoEvent> cur : result) {
+            if (cur.isLeft()) {
+                throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_REFUND, account.getId(), cur.getLeft().getMessage());
+            }
+            info.add(cur.getRight());
+        }
+        return info;
     }
 
     @Override
diff --git a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
index 3102e5c..2077c5e 100644
--- a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
@@ -18,23 +18,29 @@ package com.ning.billing.payment;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.UUID;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.eventbus.EventBus;
 import com.google.common.eventbus.Subscribe;
 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.invoice.api.InvoiceCreationEvent;
+import com.ning.billing.payment.api.DefaultPaymentErrorEvent;
 import com.ning.billing.payment.api.Either;
 import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
 import com.ning.billing.payment.api.PaymentErrorEvent;
 import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.Bus.EventBusException;
+import com.ning.billing.util.bus.BusEvent.BusEventType;
+import com.ning.billing.util.bus.BusEvent;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallOrigin;
 import com.ning.billing.util.callcontext.DefaultCallContext;
@@ -52,39 +58,51 @@ public class RequestProcessor {
 
     @Inject
     public RequestProcessor(Clock clock,
-                            AccountUserApi accountUserApi,
-                            PaymentApi paymentApi,
-                            PaymentProviderPluginRegistry pluginRegistry,
-                            Bus eventBus) {
+            AccountUserApi accountUserApi,
+            PaymentApi paymentApi,
+            PaymentProviderPluginRegistry pluginRegistry,
+            Bus eventBus) {
         this.clock = clock;
         this.accountUserApi = accountUserApi;
         this.paymentApi = paymentApi;
         this.eventBus = eventBus;
     }
+    
+    private void postPaymentEvent(BusEvent ev, UUID accountId) {
+        if (ev == null) {
+            return;
+        }
+        try {
+            eventBus.post(ev);
+        } catch (EventBusException e) {
+            log.error("Failed to post Payment event event for account {} ", accountId, e);
+        }
+    }
 
     @Subscribe
     public void receiveInvoice(InvoiceCreationEvent event) {
+
+
         log.info("Received invoice creation notification for account {} and invoice {}", event.getAccountId(), event.getInvoiceId());
+        PaymentErrorEvent errorEvent = null;
         try {
             final Account account = accountUserApi.getAccountById(event.getAccountId());
-
-            if (account == null) {
-                log.info("could not process invoice payment: could not find a valid account for event {}", event);
-            }
-            else {
+            if (account != null) {
                 CallContext context = new DefaultCallContext("PaymentRequestProcessor", CallOrigin.INTERNAL, UserType.SYSTEM, clock);
-                List<Either<PaymentErrorEvent, PaymentInfoEvent>> results = paymentApi.createPayment(account, Arrays.asList(event.getInvoiceId().toString()), context);
-                if (!results.isEmpty()) {
-                    Either<PaymentErrorEvent, PaymentInfoEvent> result = results.get(0);
-                    try {
-                        eventBus.post(result.isLeft() ? result.getLeft() : result.getRight());
-                    } catch (EventBusException e) {
-                        log.error("Failed to post Payment event event for account {} ", account.getId(), e);
-                    }
-                }
+                List<PaymentInfoEvent> results = paymentApi.createPayment(account, Arrays.asList(event.getInvoiceId().toString()), context);
+                PaymentInfoEvent infoEvent = (!results.isEmpty()) ?  results.get(0) : null;
+                postPaymentEvent(infoEvent, account.getId());
+                return;
+            } else {
+                errorEvent = new DefaultPaymentErrorEvent(null, "Failed to retrieve account", event.getAccountId(), null, null);
             }
         } catch(AccountApiException e) {
-            log.warn("could not process invoice payment", e);
+            log.error("Failed to process invoice payment", e);
+            errorEvent = new DefaultPaymentErrorEvent(null, e.getMessage(), event.getAccountId(), null, null);            
+        } catch (PaymentApiException e) {
+            log.error("Failed to process invoice payment", e);
+            errorEvent = new DefaultPaymentErrorEvent(null, e.getMessage(), event.getAccountId(), null, null);                        
         }
+        postPaymentEvent(errorEvent, event.getAccountId());
     }
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/RetryService.java b/payment/src/main/java/com/ning/billing/payment/RetryService.java
index 447bb74..abc1fde 100644
--- a/payment/src/main/java/com/ning/billing/payment/RetryService.java
+++ b/payment/src/main/java/com/ning/billing/payment/RetryService.java
@@ -24,6 +24,8 @@ import com.ning.billing.util.callcontext.DefaultCallContext;
 import com.ning.billing.util.callcontext.UserType;
 import com.ning.billing.util.clock.Clock;
 import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
 import com.ning.billing.config.PaymentConfig;
@@ -31,6 +33,7 @@ import com.ning.billing.lifecycle.KillbillService;
 import com.ning.billing.lifecycle.LifecycleHandlerType;
 import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
 import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
 import com.ning.billing.payment.api.PaymentAttempt;
 import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.api.PaymentStatus;
@@ -42,6 +45,9 @@ import com.ning.billing.util.notificationq.NotificationQueueService.Notification
 import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
 
 public class RetryService implements KillbillService {
+    
+    private static final Logger log = LoggerFactory.getLogger(RetryService.class);
+    
     public static final String SERVICE_NAME = "retry-service";
     public static final String QUEUE_NAME = "retry-events";
 
@@ -107,15 +113,14 @@ public class RetryService implements KillbillService {
     }
 
     private void retry(String paymentAttemptId, CallContext context) {
-        PaymentInfoEvent paymentInfo = paymentApi.getPaymentInfoForPaymentAttemptId(paymentAttemptId);
-
-        if (paymentInfo != null && PaymentStatus.Processed.equals(PaymentStatus.valueOf(paymentInfo.getStatus()))) {
-            // update payment attempt with success and notify invoice api of payment
-            System.out.println("Found processed payment");
-        }
-        else {
-            System.out.println("Creating payment for payment attempt " + paymentAttemptId);
+        try {
+            PaymentInfoEvent paymentInfo = paymentApi.getPaymentInfoForPaymentAttemptId(paymentAttemptId);
+            if (paymentInfo != null && PaymentStatus.Processed.equals(PaymentStatus.valueOf(paymentInfo.getStatus()))) {
+                return;
+            }
             paymentApi.createPaymentForPaymentAttempt(UUID.fromString(paymentAttemptId), context);
+        } catch (PaymentApiException e) {
+            log.error(String.format("Failed to retry payment for %s"), e);
         }
     }
 }
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 4d3c630..85aa07b 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
@@ -102,12 +102,11 @@ public abstract class TestPaymentApi {
                                                        new BigDecimal("1.0"),
                                                        Currency.USD));
 
-        List<Either<PaymentErrorEvent, PaymentInfoEvent>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
+        List<PaymentInfoEvent> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
 
         assertEquals(results.size(), 1);
-        assertTrue(results.get(0).isRight());
 
-        PaymentInfoEvent paymentInfo = results.get(0).getRight();
+        PaymentInfoEvent paymentInfo = results.get(0);
 
         assertNotNull(paymentInfo.getPaymentId());
         assertTrue(paymentInfo.getAmount().compareTo(amount.setScale(2, RoundingMode.HALF_EVEN)) == 0);
@@ -145,7 +144,7 @@ public abstract class TestPaymentApi {
 
     }
 
-    private PaymentProviderAccount setupAccountWithPaypalPaymentMethod() throws AccountApiException, EntityPersistenceException {
+    private PaymentProviderAccount setupAccountWithPaypalPaymentMethod() throws Exception  {
         final Account account = testHelper.createTestPayPalAccount();
         paymentApi.createPaymentProviderAccount(account, context);
 
@@ -156,32 +155,23 @@ public abstract class TestPaymentApi {
                                                                            .setEmail(account.getEmail())
                                                                            .setDefaultMethod(true)
                                                                            .build();
-        Either<PaymentErrorEvent, String> paymentMethodIdOrError = paymentApi.addPaymentMethod(accountKey, paymentMethod, context);
+        String paymentMethodId = paymentApi.addPaymentMethod(accountKey, paymentMethod, context);
 
-        assertTrue(paymentMethodIdOrError.isRight());
-        assertNotNull(paymentMethodIdOrError.getRight());
+        PaymentMethodInfo paymentMethodInfo = paymentApi.getPaymentMethod(accountKey, paymentMethodId);
 
-        Either<PaymentErrorEvent, PaymentMethodInfo> paymentMethodInfoOrError = paymentApi.getPaymentMethod(accountKey, paymentMethodIdOrError.getRight());
-
-        assertTrue(paymentMethodInfoOrError.isRight());
-        assertNotNull(paymentMethodInfoOrError.getRight());
-
-        Either<PaymentErrorEvent, PaymentProviderAccount> accountOrError = paymentApi.getPaymentProviderAccount(accountKey);
-
-        assertTrue(accountOrError.isRight());
-
-        return accountOrError.getRight();
+        PaymentProviderAccount accountResult = paymentApi.getPaymentProviderAccount(accountKey);
+        return accountResult;
     }
 
     @Test(enabled=true)
-    public void testCreatePaypalPaymentMethod() throws AccountApiException, EntityPersistenceException {
+    public void testCreatePaypalPaymentMethod() throws Exception  {
         PaymentProviderAccount account = setupAccountWithPaypalPaymentMethod();
         assertNotNull(account);
         paymentApi.getPaymentMethods(account.getAccountKey());
     }
 
     @Test(enabled=true)
-    public void testUpdatePaymentProviderAccountContact() throws AccountApiException, EntityPersistenceException {
+    public void testUpdatePaymentProviderAccountContact() throws Exception {
         final Account account = testHelper.createTestPayPalAccount();
         paymentApi.createPaymentProviderAccount(account, context);
 
@@ -198,19 +188,12 @@ public abstract class TestPaymentApi {
                                                                   .billingCycleDay(account.getBillCycleDay())
                                                                   .build();
 
-        Either<PaymentErrorEvent, Void> voidOrError = paymentApi.updatePaymentProviderAccountContact(accountToUpdate.getExternalKey(), context);
-        assertTrue(voidOrError.isRight());
+        paymentApi.updatePaymentProviderAccountContact(accountToUpdate.getExternalKey(), context);
     }
 
     @Test(enabled=true)
-    public void testCannotDeleteDefaultPaymentMethod() throws AccountApiException, EntityPersistenceException {
+    public void testCannotDeleteDefaultPaymentMethod() throws Exception  {
         PaymentProviderAccount account = setupAccountWithPaypalPaymentMethod();
-
-        Either<PaymentErrorEvent, Void> errorOrVoid = paymentApi.deletePaymentMethod(account.getAccountKey(), account.getDefaultPaymentMethodId(), context);
-
-        assertTrue(errorOrVoid.isLeft());
+        paymentApi.deletePaymentMethod(account.getAccountKey(), account.getDefaultPaymentMethodId(), context);
     }
-
-   
-
 }
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 5ab2157..9a49780 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
@@ -44,6 +44,7 @@ import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
 import com.ning.billing.mock.glue.MockJunctionModule;
 import com.ning.billing.payment.api.Either;
 import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
 import com.ning.billing.payment.api.PaymentAttempt;
 import com.ning.billing.payment.api.PaymentErrorEvent;
 import com.ning.billing.payment.api.PaymentInfoEvent;
@@ -139,11 +140,13 @@ public class TestRetryService {
                                                        Currency.USD));
 
         mockPaymentProviderPlugin.makeNextInvoiceFail();
-
-        List<Either<PaymentErrorEvent, PaymentInfoEvent>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
-
-        assertEquals(results.size(), 1);
-        assertTrue(results.get(0).isLeft());
+        boolean failed = false;
+        try {
+            paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
+        } catch (PaymentApiException e) {
+            failed = true;
+        }
+        assertTrue(failed);
 
         List<Notification> pendingNotifications = mockNotificationQueue.getPendingEvents();