killbill-memoizeit

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);
+  }
+  
+  
+  
 }