diff --git a/api/src/main/java/com/ning/billing/BillingExceptionBase.java b/api/src/main/java/com/ning/billing/BillingExceptionBase.java
index 486e5da..3a458fc 100644
--- a/api/src/main/java/com/ning/billing/BillingExceptionBase.java
+++ b/api/src/main/java/com/ning/billing/BillingExceptionBase.java
@@ -30,6 +30,12 @@ public class BillingExceptionBase extends Exception {
private final int code;
private final String formattedMsg;
+ public BillingExceptionBase(Throwable cause, int code, final String msg) {
+ this.formattedMsg = msg;
+ this.code = code;
+ this.cause = cause;
+ }
+
public BillingExceptionBase(Throwable cause, ErrorCode code, final Object... args) {
String tmp = null;
try {
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApiException.java b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApiException.java
index c4b8c42..693938b 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApiException.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApiException.java
@@ -18,9 +18,15 @@ package com.ning.billing.entitlement.api.user;
import com.ning.billing.BillingExceptionBase;
import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogApiException;
public class EntitlementUserApiException extends BillingExceptionBase {
+ private static final long serialVersionUID = 19083233L;
+
+ public EntitlementUserApiException(CatalogApiException e) {
+ super(e, e.getCode(), e.getMessage());
+ }
public EntitlementUserApiException(Throwable e, ErrorCode code, Object...args) {
super(e, code, args);
}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/InternationalPrice.java b/catalog/src/main/java/com/ning/billing/catalog/InternationalPrice.java
index 21bf82a..4a64900 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/InternationalPrice.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/InternationalPrice.java
@@ -17,6 +17,7 @@
package com.ning.billing.catalog;
import java.math.BigDecimal;
+import java.net.URI;
import java.util.Date;
import javax.xml.bind.annotation.XmlAccessType;
@@ -32,6 +33,8 @@ import com.ning.billing.util.config.ValidationErrors;
@XmlAccessorType(XmlAccessType.NONE)
public class InternationalPrice extends ValidatingConfig<Catalog> implements IInternationalPrice {
+ private static Price[] zeroPrice;
+
//TODO MDW Validation - effectiveDateForExistingSubscriptons > catalog effectiveDate
@XmlElement(required=false)
private Date effectiveDateForExistingSubscriptons;
@@ -41,6 +44,7 @@ public class InternationalPrice extends ValidatingConfig<Catalog> implements IIn
@XmlElement(name="price")
private Price[] prices;
+
/* (non-Javadoc)
* @see com.ning.billing.catalog.IInternationalPrice#getPrices()
*/
@@ -70,16 +74,8 @@ public class InternationalPrice extends ValidatingConfig<Catalog> implements IIn
}
return new BigDecimal(0);
}
-
- private boolean currencyIsSupported(Currency currency, Currency[] supportedCurrencies) {
- for (Currency c : supportedCurrencies) {
- if(c == currency) {
- return true;
- }
- }
- return false;
- }
-
+
+
protected void setEffectiveDateForExistingSubscriptons(
Date effectiveDateForExistingSubscriptons) {
this.effectiveDateForExistingSubscriptons = effectiveDateForExistingSubscriptons;
@@ -90,6 +86,29 @@ public class InternationalPrice extends ValidatingConfig<Catalog> implements IIn
return this;
}
+
+
+ @Override
+ public void initialize(Catalog root, URI uri) {
+ if(prices == null) {
+ prices = getZeroPrice(root);
+ }
+ super.initialize(root, uri);
+ }
+
+ private synchronized Price[] getZeroPrice(Catalog root) {
+ if(zeroPrice == null) {
+ Currency[] currencies = root.getSupportedCurrencies();
+ zeroPrice = new Price[currencies.length];
+ for(int i = 0; i < currencies.length; i++) {
+ prices[i] = new Price();
+ prices[i].setCurrency(currencies[i]);
+ prices[i].setValue(new BigDecimal(0));
+ }
+ }
+ return zeroPrice;
+ }
+
@Override
public ValidationErrors validate(Catalog catalog, ValidationErrors errors) {
if(prices.length == 0) return errors;
@@ -103,7 +122,16 @@ public class InternationalPrice extends ValidatingConfig<Catalog> implements IIn
return errors;
}
+ private boolean currencyIsSupported(Currency currency, Currency[] supportedCurrencies) {
+ for (Currency c : supportedCurrencies) {
+ if(c == currency) {
+ return true;
+ }
+ }
+ return false;
+ }
+
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
index afcf053..5280209 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
@@ -29,9 +29,13 @@ import org.joda.time.DateTime;
import com.ning.billing.catalog.api.ActionPolicy;
import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.ICatalog;
import com.ning.billing.catalog.api.IPlan;
import com.ning.billing.catalog.api.IPlanPhase;
+import com.ning.billing.catalog.api.IPriceList;
+import com.ning.billing.catalog.api.IProduct;
+import com.ning.billing.catalog.api.PlanChangeResult;
import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.catalog.api.PlanSpecifier;
import com.ning.billing.catalog.api.ProductCategory;
@@ -257,7 +261,6 @@ public class Subscription extends PrivateFields implements ISubscription {
String priceList, DateTime requestedDate) throws EntitlementUserApiException {
String currentPriceList = getCurrentPriceList();
- String realPriceList = (priceList == null) ? currentPriceList : priceList;
SubscriptionState currentState = getState();
if (currentState != SubscriptionState.ACTIVE) {
@@ -269,30 +272,42 @@ public class Subscription extends PrivateFields implements ISubscription {
}
DateTime now = clock.getUTCNow();
- IPlan newPlan = catalog.getPlan(productName, term, realPriceList);
+ PlanChangeResult planChangeResult = null;
+ try {
+
+ IProduct destProduct = catalog.getProductFromName(productName);
+
+ IPlan currentPlan = getCurrentPlan();
+ PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
+ currentPlan.getProduct().getCategory(),
+ currentPlan.getBillingPeriod(),
+ currentPriceList, getCurrentPhase().getPhaseType());
+ PlanSpecifier toPlanPhase = new PlanSpecifier(productName,
+ destProduct.getCategory(),
+ term,
+ priceList);
+
+ planChangeResult = catalog.planChange(fromPlanPhase, toPlanPhase);
+ } catch (CatalogApiException e) {
+ throw new EntitlementUserApiException(e);
+ }
+
+ ActionPolicy policy = planChangeResult.getPolicy();
+ IPriceList newPriceList = planChangeResult.getNewPriceList();
+
+ IPlan newPlan = catalog.getPlan(productName, term, newPriceList.getName());
if (newPlan == null) {
throw new EntitlementUserApiException(ErrorCode.ENT_CREATE_BAD_CATALOG,
- productName, term.toString(), realPriceList);
+ productName, term.toString(), newPriceList.getName());
}
- IPlan currentPlan = getCurrentPlan();
- PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
- currentPlan.getProduct().getCategory(),
- currentPlan.getBillingPeriod(),
- currentPriceList, getCurrentPhase().getPhaseType());
- PlanSpecifier toPlanPhase = new PlanSpecifier(newPlan.getProduct().getName(),
- newPlan.getProduct().getCategory(),
- newPlan.getBillingPeriod(),
- realPriceList);
-
- ActionPolicy policy = catalog.getPlanChangePolicy(fromPlanPhase, toPlanPhase);
DateTime effectiveDate = getPlanChangeEffectiveDate(policy, now);
- TimedPhase currentTimedPhase = planAligner.getCurrentTimedPhaseOnChange(this, newPlan, realPriceList, effectiveDate);
+ TimedPhase currentTimedPhase = planAligner.getCurrentTimedPhaseOnChange(this, newPlan, newPriceList.getName(), effectiveDate);
IEvent changeEvent = new ApiEventChange(id, bundleStartDate, now, newPlan.getName(), currentTimedPhase.getPhase().getName(),
- realPriceList, now, effectiveDate, activeVersion);
+ newPriceList.getName(), now, effectiveDate, activeVersion);
- TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(this, newPlan, realPriceList, effectiveDate);
+ TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(this, newPlan, newPriceList.getName(), effectiveDate);
IPhaseEvent nextPhaseEvent = PhaseEvent.getNextPhaseEvent(nextTimedPhase, this, now);
List<IEvent> changeEvents = new ArrayList<IEvent>();
// Only add the PHASE if it does not coincide with the CHANGE, if not this is 'just' a CHANGE.