killbill-memoizeit

Implement new Entitlement API for getting status on AO when

5/9/2012 6:53:58 PM

Changes

Details

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/user/EntitlementUserApi.java b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
index 27a741d..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;
 
 
@@ -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 f31ece4..c317465 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 */
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/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 ce18d37..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;
@@ -214,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/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 bc0b0bd..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,22 +49,25 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
         this.checker = checker;
     }
 
+    @Override
     public SubscriptionBundle getBundleFromId(UUID id) throws EntitlementUserApiException {
         SubscriptionBundle bundle = entitlementUserApi.getBundleFromId(id);
         return new BlockingSubscriptionBundle(bundle, blockingApi);
     }
 
+    @Override
     public Subscription getSubscriptionFromId(UUID id) throws EntitlementUserApiException {
         Subscription subscription = entitlementUserApi.getSubscriptionFromId(id);
         return new BlockingSubscription(subscription, blockingApi, checker);
     }
 
-    
+    @Override
     public SubscriptionBundle getBundleForKey(String bundleKey) throws EntitlementUserApiException {
         SubscriptionBundle bundle = entitlementUserApi.getBundleForKey(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);
@@ -73,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);
@@ -82,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);
@@ -91,20 +97,30 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
         return result;
     }
 
+    @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 {
@@ -115,8 +131,8 @@ public class BlockingEntitlementUserApi implements EntitlementUserApi {
         }
     }
 
+    @Override
     public DateTime getNextBillingDate(UUID account) {
         return entitlementUserApi.getNextBillingDate(account);
     }
-
 }