killbill-uncached

Details

diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
index 759fa00..49e8b32 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
@@ -125,7 +125,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
             }
 
             final DefaultSubscriptionBase baseSubscription = (DefaultSubscriptionBase) dao.getBaseSubscription(bundleId, context);
-            final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, requestedDate, effectiveDate);
+            final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, requestedDate, effectiveDate, context);
             final CallContext callContext = internalCallContextFactory.createCallContext(context);
             return apiService.createPlan(new SubscriptionBuilder()
                                                  .setId(UUID.randomUUID())
@@ -355,9 +355,9 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
                 final DryRunChangeReason reason;
                 // If baseProductName is null, it's a cancellation dry-run. In this case, return all addons, so they are cancelled
-                if (baseProductName != null && addonUtils.isAddonIncludedFromProdName(baseProductName, requestedDate, cur.getCurrentPlan(), context)) {
+                if (baseProductName != null && addonUtils.isAddonIncludedFromProdName(baseProductName, cur.getCurrentPlan(), requestedDate, context)) {
                     reason = DryRunChangeReason.AO_INCLUDED_IN_NEW_PLAN;
-                } else if (baseProductName != null && addonUtils.isAddonAvailableFromProdName(baseProductName, requestedDate, cur.getCurrentPlan(), context)) {
+                } else if (baseProductName != null && addonUtils.isAddonAvailableFromProdName(baseProductName, cur.getCurrentPlan(), requestedDate, context)) {
                     reason = DryRunChangeReason.AO_AVAILABLE_IN_NEW_PLAN;
                 } else {
                     reason = DryRunChangeReason.AO_NOT_AVAILABLE_IN_NEW_PLAN;
@@ -406,7 +406,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
                         final DefaultSubscriptionBase baseSubscription = (DefaultSubscriptionBase) dao.getBaseSubscription(bundleId, context);
                         final DateTime startEffectiveDate = dryRunArguments.getEffectiveDate() != null ? dryRunArguments.getEffectiveDate() : utcNow;
-                        final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, startEffectiveDate, startEffectiveDate);
+                        final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, startEffectiveDate, startEffectiveDate, context);
                         final UUID subscriptionId = UUID.randomUUID();
                         dryRunEvents = apiService.getEventsOnCreation(bundleId, subscriptionId, startEffectiveDate, bundleStartDate, 1L, plan, inputSpec.getPhaseType(), realPriceList,
                                                                       utcNow, startEffectiveDate, utcNow, false, context);
@@ -471,7 +471,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
     }
 
     private DateTime getBundleStartDateWithSanity(final UUID bundleId, @Nullable final DefaultSubscriptionBase baseSubscription, final Plan plan,
-                                                  final DateTime requestedDate, final DateTime effectiveDate) throws SubscriptionBaseApiException, CatalogApiException {
+                                                  final DateTime requestedDate, final DateTime effectiveDate, final InternalTenantContext context) throws SubscriptionBaseApiException, CatalogApiException {
         switch (plan.getProduct().getCategory()) {
             case BASE:
                 if (baseSubscription != null &&
@@ -487,7 +487,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                 if (effectiveDate.isBefore(baseSubscription.getStartDate())) {
                     throw new SubscriptionBaseApiException(ErrorCode.SUB_INVALID_REQUESTED_DATE, effectiveDate.toString(), baseSubscription.getStartDate().toString());
                 }
-                addonUtils.checkAddonCreationRights(baseSubscription, plan);
+                addonUtils.checkAddonCreationRights(baseSubscription, plan, requestedDate, context);
                 return baseSubscription.getStartDate();
 
             case STANDALONE:
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/SubscriptionDataRepair.java b/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/SubscriptionDataRepair.java
index e6e1ee9..d9d8c0b 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/SubscriptionDataRepair.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/SubscriptionDataRepair.java
@@ -25,6 +25,7 @@ import org.joda.time.DateTime;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
@@ -106,16 +107,19 @@ public class SubscriptionDataRepair extends DefaultSubscriptionBase {
             throws SubscriptionBaseRepairException {
 
         try {
+
+            final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(baseSubscription.getId(), ObjectType.SUBSCRIPTION, context);
+
             final PlanPhaseSpecifier spec = input.getPlanPhaseSpecifier();
             switch (input.getSubscriptionTransitionType()) {
                 case CREATE:
                 case RE_CREATE:
                     recreate(spec, input.getRequestedDate(), context);
-                    checkAddonRights(baseSubscription);
+                    checkAddonRights(baseSubscription, internalTenantContext);
                     break;
                 case CHANGE:
                     changePlanWithDate(spec.getProductName(), spec.getBillingPeriod(), spec.getPriceListName(), input.getRequestedDate(), context);
-                    checkAddonRights(baseSubscription);
+                    checkAddonRights(baseSubscription, internalTenantContext);
                     trickleDownBPEffectForAddon(addonSubscriptions, getLastUserEventEffectiveDate(), context);
                     break;
                 case CANCEL:
@@ -174,9 +178,11 @@ public class SubscriptionDataRepair extends DefaultSubscriptionBase {
                 continue;
             }
             final Plan addonCurrentPlan = cur.getCurrentPlan();
+            final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(cur.getId(), ObjectType.SUBSCRIPTION, context);
+
             if (baseProduct == null ||
-                addonUtils.isAddonIncluded(baseProduct, addonCurrentPlan) ||
-                !addonUtils.isAddonAvailable(baseProduct, addonCurrentPlan)) {
+                addonUtils.isAddonIncludedFromProdName(baseProduct.getName(), addonCurrentPlan, effectiveDate, internalCallContext) ||
+                !addonUtils.isAddonAvailableFromProdName(baseProduct.getName(), addonCurrentPlan, effectiveDate, internalCallContext)) {
 
                 final SubscriptionBaseEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder()
                                                                                 .setSubscriptionId(cur.getId())
@@ -185,7 +191,6 @@ public class SubscriptionDataRepair extends DefaultSubscriptionBase {
                                                                                 .setEffectiveDate(effectiveDate)
                                                                                 .setRequestedDate(now)
                                                                                 .setFromDisk(true));
-                final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(cur.getId(), ObjectType.SUBSCRIPTION, context);
                 repairDao.cancelSubscription(cur, cancelEvent, internalCallContext, 0);
                 final Catalog fullCatalog = catalogService.getFullCatalog(internalCallContext);
                 cur.rebuildTransitions(repairDao.getEventsForSubscription(cur.getId(), internalCallContextFactory.createInternalTenantContext(context)), fullCatalog);
@@ -193,10 +198,10 @@ public class SubscriptionDataRepair extends DefaultSubscriptionBase {
         }
     }
 
-    private void checkAddonRights(final SubscriptionDataRepair baseSubscription)
+    private void checkAddonRights(final SubscriptionDataRepair baseSubscription, final InternalTenantContext internalTenantContext)
             throws SubscriptionBaseApiException, CatalogApiException {
         if (getCategory() == ProductCategory.ADD_ON) {
-            addonUtils.checkAddonCreationRights(baseSubscription, getCurrentPlan());
+            addonUtils.checkAddonCreationRights(baseSubscription, getCurrentPlan(), clock.getUTCNow(), internalTenantContext);
         }
     }
 
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
index 2933c3b..c8e6580 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
@@ -480,8 +480,8 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
             final Plan addonCurrentPlan = cur.getCurrentPlan();
             if (baseProduct == null ||
-                addonUtils.isAddonIncluded(baseProduct, addonCurrentPlan) ||
-                !addonUtils.isAddonAvailable(baseProduct, addonCurrentPlan)) {
+                addonUtils.isAddonIncludedFromProdName(baseProduct.getName(), addonCurrentPlan, requestedDate, internalTenantContext) ||
+                !addonUtils.isAddonAvailableFromProdName(baseProduct.getName(), addonCurrentPlan, requestedDate, internalTenantContext)) {
                 //
                 // Perform AO cancellation using the effectiveDate of the BP
                 //
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/addon/AddonUtils.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/addon/AddonUtils.java
index 2f0a3e4..6d5a679 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/addon/AddonUtils.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/addon/AddonUtils.java
@@ -39,14 +39,14 @@ public class AddonUtils {
         this.catalogService = catalogService;
     }
 
-    public void checkAddonCreationRights(final DefaultSubscriptionBase baseSubscription, final Plan targetAddOnPlan)
+    public void checkAddonCreationRights(final DefaultSubscriptionBase baseSubscription, final Plan targetAddOnPlan, final DateTime requestedDate, final InternalTenantContext context)
             throws SubscriptionBaseApiException, CatalogApiException {
 
         if (baseSubscription.getState() != EntitlementState.ACTIVE) {
             throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_BP_NON_ACTIVE, targetAddOnPlan.getName());
         }
 
-        final Product baseProduct = baseSubscription.getCurrentPlan().getProduct();
+        final Product baseProduct = catalogService.getFullCatalog(context).findProduct(baseSubscription.getCurrentPlan().getProduct().getName(), requestedDate);
         if (isAddonIncluded(baseProduct, targetAddOnPlan)) {
             throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_ALREADY_INCLUDED,
                                                    targetAddOnPlan.getName(), baseSubscription.getCurrentPlan().getProduct().getName());
@@ -58,7 +58,7 @@ public class AddonUtils {
         }
     }
 
-    public boolean isAddonAvailableFromProdName(final String baseProductName, final DateTime requestedDate, final Plan targetAddOnPlan, final InternalTenantContext context) {
+    public boolean isAddonAvailableFromProdName(final String baseProductName, final Plan targetAddOnPlan, final DateTime requestedDate, final InternalTenantContext context) {
         try {
             final Product product = catalogService.getFullCatalog(context).findProduct(baseProductName, requestedDate);
             return isAddonAvailable(product, targetAddOnPlan);
@@ -67,7 +67,7 @@ public class AddonUtils {
         }
     }
 
-    public boolean isAddonAvailableFromPlanName(final String basePlanName, final DateTime requestedDate, final Plan targetAddOnPlan, final InternalTenantContext context) {
+    public boolean isAddonAvailableFromPlanName(final String basePlanName, final Plan targetAddOnPlan, final DateTime requestedDate, final InternalTenantContext context) {
         try {
             final Plan plan = catalogService.getFullCatalog(context).findPlan(basePlanName, requestedDate);
             final Product product = plan.getProduct();
@@ -77,19 +77,8 @@ public class AddonUtils {
         }
     }
 
-    public boolean isAddonAvailable(final Product baseProduct, final Plan targetAddOnPlan) {
-        final Product targetAddonProduct = targetAddOnPlan.getProduct();
-        final Product[] availableAddOns = baseProduct.getAvailable();
 
-        for (final Product curAv : availableAddOns) {
-            if (curAv.getName().equals(targetAddonProduct.getName())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public boolean isAddonIncludedFromProdName(final String baseProductName, final DateTime requestedDate, final Plan targetAddOnPlan, final InternalTenantContext context) {
+    public boolean isAddonIncludedFromProdName(final String baseProductName, final Plan targetAddOnPlan, final DateTime requestedDate, final InternalTenantContext context) {
         try {
             final Product product = catalogService.getFullCatalog(context).findProduct(baseProductName, requestedDate);
             return isAddonIncluded(product, targetAddOnPlan);
@@ -99,7 +88,7 @@ public class AddonUtils {
 
     }
 
-    public boolean isAddonIncludedFromPlanName(final String basePlanName, final DateTime requestedDate, final Plan targetAddOnPlan, final InternalTenantContext context) {
+    public boolean isAddonIncludedFromPlanName(final String basePlanName, final Plan targetAddOnPlan, final DateTime requestedDate, final InternalTenantContext context) {
         try {
             final Plan plan = catalogService.getFullCatalog(context).findPlan(basePlanName, requestedDate);
             final Product product = plan.getProduct();
@@ -109,7 +98,20 @@ public class AddonUtils {
         }
     }
 
-    public boolean isAddonIncluded(final Product baseProduct, final Plan targetAddOnPlan) {
+
+    private boolean isAddonAvailable(final Product baseProduct, final Plan targetAddOnPlan) {
+        final Product targetAddonProduct = targetAddOnPlan.getProduct();
+        final Product[] availableAddOns = baseProduct.getAvailable();
+
+        for (final Product curAv : availableAddOns) {
+            if (curAv.getName().equals(targetAddonProduct.getName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isAddonIncluded(final Product baseProduct, final Plan targetAddOnPlan) {
         final Product targetAddonProduct = targetAddOnPlan.getProduct();
         final Product[] includedAddOns = baseProduct.getIncluded();
         for (final Product curAv : includedAddOns) {
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
index 1dc62ac..6d770f8 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
@@ -899,8 +899,8 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
                     for (final ApiEventChange baseChangeEvent : baseChangeEvents) {
                         final String baseProductName = baseChangeEvent.getEventPlan();
 
-                        if ((!addonUtils.isAddonAvailableFromPlanName(baseProductName, baseChangeEvent.getEffectiveDate(), targetAddOnPlan, context)) ||
-                            (addonUtils.isAddonIncludedFromPlanName(baseProductName, baseChangeEvent.getEffectiveDate(), targetAddOnPlan, context))) {
+                        if ((!addonUtils.isAddonAvailableFromPlanName(baseProductName, targetAddOnPlan, baseChangeEvent.getEffectiveDate(), context)) ||
+                            (addonUtils.isAddonIncludedFromPlanName(baseProductName, targetAddOnPlan, baseChangeEvent.getEffectiveDate(), context))) {
                             if (baseTriggerEventForAddOnCancellation != null) {
                                 if (baseTriggerEventForAddOnCancellation.getEffectiveDate().isAfter(baseChangeEvent.getEffectiveDate())) {
                                     baseTriggerEventForAddOnCancellation = baseChangeEvent;