Details
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java
index 69c89cd..558d7f4 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java
@@ -17,6 +17,7 @@
package com.ning.billing.analytics;
import com.ning.billing.analytics.utils.Rounder;
+import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.catalog.api.IDuration;
import com.ning.billing.catalog.api.IPlan;
@@ -121,7 +122,14 @@ public class BusinessSubscription
}
if (currentPhase.getRecurringPrice() != null) {
- price = currentPhase.getRecurringPrice().getPrice(USD);
+ //TODO check if this is the right way to handle exception
+ BigDecimal tmpPrice = null;
+ try {
+ tmpPrice = currentPhase.getRecurringPrice().getPrice(USD);
+ } catch (CatalogApiException e) {
+ tmpPrice = new BigDecimal(0);
+ }
+ price = tmpPrice;
mrr = getMrrFromISubscription(currentPhase.getDuration(), price);
}
else {
diff --git a/api/src/main/java/com/ning/billing/catalog/api/IInternationalPrice.java b/api/src/main/java/com/ning/billing/catalog/api/IInternationalPrice.java
index 47b206c..b771c31 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/IInternationalPrice.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/IInternationalPrice.java
@@ -24,7 +24,7 @@ public interface IInternationalPrice {
public abstract IPrice[] getPrices();
- public abstract BigDecimal getPrice(Currency currency);
+ public abstract BigDecimal getPrice(Currency currency) throws CatalogApiException;
public abstract Date getEffectiveDateForExistingSubscriptons();
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index 5cca8fa..aef5920 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -44,9 +44,45 @@ public enum ErrorCode {
/* Un-cancellation */
ENT_UNCANCEL_BAD_STATE(1070, "Subscription %s was not in a cancelled state"),
+ /*
+ *
+ * Range 2000 : CATALOG
+ *
+ */
+
+ /*
+ * Rules exceptions
+ */
+
+ /* Plan change is disallowed by the catalog */
CAT_ILLEGAL_CHANGE_REQUEST(2001, "Attempting to change plan from (product: '%s', billing period: '%s', " +
- "pricelist '%s') to (product: '%s', billing period: '%s', pricelist '%s'). This transition is not allowed by catalog rules")
+ "pricelist '%s') to (product: '%s', billing period: '%s', pricelist '%s'). This transition is not allowed by catalog rules"),
+
+ /*
+ * Price list
+ */
+
+ /*Attempt to reference a price that is not present - should only happen if it is a currency not available in the catalog */
+ CAT_NO_PRICE_FOR_CURRENCY(2010, "This price does not have a value for the currency '%s'."),
+ /* Price value explicitly set to NULL meaning there is no price available in that currency */
+ CAT_PRICE_VALUE_NULL_FOR_CURRENCY(2011, "The value for the currency '%s' is NULL. This plan cannot be bought in this currnency."),
+
+ /*
+ * Plans
+ */
+ CAT_PLAN_NOT_FOUND(2020,"Could not find a plan matching: (product: '%s', billing period: '%s', pricelist '%s')"),
+ CAT_NO_SUCH_PLAN(2021,"Could not find any plans named '%s'"),
+
+ /*
+ * Products
+ */
+ CAT_NO_SUCH_PRODUCT(2030,"Could not find any plans named '%s'"),
+
+ /*
+ * Phases
+ */
+ CAT_NO_SUCH_PHASE(2040,"Could not find any phases named '%s'")
;
private int code;
diff --git a/api/src/main/java/com/ning/billing/invoice/api/BillingEvent.java b/api/src/main/java/com/ning/billing/invoice/api/BillingEvent.java
index d17bc26..f7c7ab9 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/BillingEvent.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/BillingEvent.java
@@ -17,6 +17,7 @@
package com.ning.billing.invoice.api;
import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.catalog.api.IInternationalPrice;
import com.ning.billing.entitlement.api.billing.BillingMode;
@@ -90,9 +91,15 @@ public class BillingEvent implements IBillingEvent {
return price;
}
+ // TODO handle exception correctly
@Override
public BigDecimal getPrice(Currency currency) {
- return price.getPrice(currency);
+ try {
+ return price.getPrice(currency);
+ } catch (CatalogApiException e) {
+ e.printStackTrace();
+ return new BigDecimal(0);
+ }
}
@Override
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 26960b5..6a10084 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/InternationalPrice.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/InternationalPrice.java
@@ -24,10 +24,14 @@ import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.CurrencyValueNull;
import com.ning.billing.catalog.api.IInternationalPrice;
import com.ning.billing.catalog.api.IPrice;
import com.ning.billing.util.config.ValidatingConfig;
+import com.ning.billing.util.config.ValidationError;
import com.ning.billing.util.config.ValidationErrors;
@XmlAccessorType(XmlAccessType.NONE)
@@ -64,14 +68,13 @@ public class InternationalPrice extends ValidatingConfig<Catalog> implements IIn
* @see com.ning.billing.catalog.IInternationalPrice#getPrice(com.ning.billing.catalog.api.Currency)
*/
@Override
- public BigDecimal getPrice(Currency currency) {
- // Note if there are no prices specified we default to 0 for any currency
+ public BigDecimal getPrice(Currency currency) throws CatalogApiException {
for(IPrice p : prices) {
if(p.getCurrency() == currency) {
return p.getValue();
}
}
- return new BigDecimal(0);
+ throw new CatalogApiException(ErrorCode.CAT_NO_PRICE_FOR_CURRENCY, currency);
}
@@ -88,14 +91,28 @@ public class InternationalPrice extends ValidatingConfig<Catalog> implements IIn
@Override
public ValidationErrors validate(Catalog catalog, ValidationErrors errors) {
- if(prices.length == 0) return errors;
Currency[] supportedCurrencies = catalog.getSupportedCurrencies();
for (IPrice p : prices) {
Currency currency = p.getCurrency();
if(!currencyIsSupported(currency, supportedCurrencies)) {
errors.add("Unsupported currency: " + currency, catalog.getCatalogURI(), this.getClass(), "");
}
+ try {
+ if(p.getValue().doubleValue() < 0.0) {
+ errors.add("Negative value for price in currency: " + currency, catalog.getCatalogURI(), this.getClass(), "");
+ }
+ } catch (CurrencyValueNull e) {
+ // No currency => nothing to check, ignore exception
+ }
+ }
+ if(effectiveDateForExistingSubscriptons != null &&
+ catalog.getEffectiveDate().getTime() > effectiveDateForExistingSubscriptons.getTime()) {
+ errors.add(new ValidationError(String.format("Price effective date %s is before catalog effective date '%s'",
+ effectiveDateForExistingSubscriptons,
+ catalog.getEffectiveDate().getTime()),
+ catalog.getCatalogURI(), InternationalPrice.class, ""));
}
+
return errors;
}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/TestInternationalPrice.java b/catalog/src/test/java/com/ning/billing/catalog/TestInternationalPrice.java
index a02541d..535da6f 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/TestInternationalPrice.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/TestInternationalPrice.java
@@ -18,15 +18,22 @@ package com.ning.billing.catalog;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.Date;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.Test;
+import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.util.config.ValidationErrors;
public class TestInternationalPrice {
+ private static final Logger log = LoggerFactory.getLogger(TestInternationalPrice.class);
+
@Test
- public void testZeroValue() throws URISyntaxException {
+ public void testZeroValue() throws URISyntaxException, CatalogApiException {
Catalog c = new MockCatalog();
c.setSupportedCurrencies(new Currency[]{Currency.GBP, Currency.EUR, Currency.USD, Currency.BRL, Currency.MXN});
InternationalPrice p0 = new MockInternationalPrice();
@@ -55,4 +62,44 @@ public class TestInternationalPrice {
Assert.assertEquals(p1.getPrice(Currency.MXN), new BigDecimal(1));
}
+
+ @Test
+ public void testPriceInitialization() throws URISyntaxException, CatalogApiException {
+ Catalog c = new MockCatalog();
+ c.setSupportedCurrencies(new Currency[]{Currency.GBP, Currency.EUR, Currency.USD, Currency.BRL, Currency.MXN});
+ c.initialize(c, new URI("foo://bar"));
+ Assert.assertEquals(c.getPlans()[0].getFinalPhase().getRecurringPrice().getPrice(Currency.GBP), new BigDecimal(0));
+ }
+
+ @Test
+ public void testNegativeValuePrices(){
+ Catalog c = new MockCatalog();
+ c.setSupportedCurrencies(new Currency[]{Currency.GBP, Currency.EUR, Currency.USD, Currency.BRL, Currency.MXN});
+
+ InternationalPrice p1 = new MockInternationalPrice();
+ p1.setPrices(new Price[] {
+ new Price().setCurrency(Currency.GBP).setValue(new BigDecimal(-1)),
+ new Price().setCurrency(Currency.EUR).setValue(new BigDecimal(-1)),
+ new Price().setCurrency(Currency.USD).setValue(new BigDecimal(-1)),
+ new Price().setCurrency(Currency.BRL).setValue(new BigDecimal(1)),
+ new Price().setCurrency(Currency.MXN).setValue(new BigDecimal(1)),
+ });
+
+ ValidationErrors errors = p1.validate(c, new ValidationErrors());
+ errors.log(log);
+ Assert.assertEquals(errors.size(), 3);
+ }
+ @Test
+ public void testDateValidation(){
+ Catalog c = new MockCatalog();
+ c.setSupportedCurrencies(new Currency[]{Currency.GBP, Currency.EUR, Currency.USD, Currency.BRL, Currency.MXN});
+ InternationalPrice p1 = new MockInternationalPrice();
+ p1.setEffectiveDateForExistingSubscriptons(new Date((new Date().getTime()) - (1000 * 60 * 60 * 24)));
+ ValidationErrors errors = p1.validate(c, new ValidationErrors());
+ Assert.assertEquals(errors.size(), 1);
+ errors.log(log);
+ }
+
+
+
}