killbill-aplcache
Changes
catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java 192(+192 -0)
profiles/killbill/src/main/resources/CatalogMos.xml 515(+515 -0)
Details
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultFixed.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultFixed.java
index 8480115..d3d525a 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultFixed.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultFixed.java
@@ -27,6 +27,7 @@ import org.killbill.billing.catalog.api.Fixed;
import org.killbill.billing.catalog.api.FixedType;
import org.killbill.billing.catalog.api.InternationalPrice;
import org.killbill.billing.catalog.api.PlanPhase;
+import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.xmlloader.ValidatingConfig;
import org.killbill.xmlloader.ValidationErrors;
@@ -54,6 +55,13 @@ public class DefaultFixed extends ValidatingConfig<StandaloneCatalog> implements
}
+ public DefaultFixed() {}
+
+ public DefaultFixed(final DefaultFixed in, final PlanPhasePriceOverride override) {
+ this.type = in.getType();
+ this.fixedPrice = new DefaultInternationalPrice(fixedPrice, override, true);
+ }
+
@Override
public void initialize(final StandaloneCatalog root, final URI uri) {
if (fixedPrice != null) {
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultInternationalPrice.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultInternationalPrice.java
index 2607cfd..0cea252 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultInternationalPrice.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultInternationalPrice.java
@@ -27,6 +27,7 @@ import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.catalog.api.CurrencyValueNull;
import org.killbill.billing.catalog.api.InternationalPrice;
+import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.Price;
import org.killbill.xmlloader.ValidatingConfig;
import org.killbill.xmlloader.ValidationErrors;
@@ -48,8 +49,20 @@ public class DefaultInternationalPrice extends ValidatingConfig<StandaloneCatalo
return prices;
}
-
-
+ public DefaultInternationalPrice() {}
+
+ public DefaultInternationalPrice(final DefaultInternationalPrice in, final PlanPhasePriceOverride override, final boolean fixed) {
+ this.prices = new DefaultPrice[in.getPrices().length];
+ // There is a question on whether we keep the other prices that were not overridden or only have one entry for the overridden price on that currency.
+ for (int i = 0; i < in.getPrices().length; i++) {
+ final DefaultPrice curPrice = (DefaultPrice) in.getPrices()[i];
+ if (curPrice.getCurrency().equals(override.getCurrency())) {
+ prices[i] = new DefaultPrice(fixed ? override.getFixedPrice() : override.getRecurringPrice(), override.getCurrency());
+ } else {
+ prices[i] = curPrice;
+ }
+ }
+ }
/* (non-Javadoc)
* @see org.killbill.billing.catalog.IInternationalPrice#getPrice(org.killbill.billing.catalog.api.Currency)
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java
index 505414c..7770d74 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
+import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
@@ -38,6 +39,7 @@ import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.PhaseType;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhase;
+import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.Product;
import org.killbill.billing.catalog.api.Recurring;
import org.killbill.xmlloader.ValidatingConfig;
@@ -76,6 +78,22 @@ public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements
@XmlElement(required = false)
private Integer plansAllowedInBundle = 1;
+
+ public DefaultPlan() {}
+
+ public DefaultPlan(final String planName, final DefaultPlan in, final PlanPhasePriceOverride[] overrides) {
+ this.name = planName;
+ this.retired = in.isRetired();
+ this.effectiveDateForExistingSubscriptons = in.getEffectiveDateForExistingSubscriptons();
+ this.product = (DefaultProduct) in.getProduct();
+ this.initialPhases = new DefaultPlanPhase[in.getInitialPhases().length];
+ for (int i = 0; i< overrides.length; i++) {
+ final DefaultPlanPhase newPhase = new DefaultPlanPhase(in.getFinalPhase(), overrides[i]);
+ initialPhases[i] = newPhase;
+ }
+ this.finalPhase = new DefaultPlanPhase(in.getFinalPhase(), overrides[overrides.length - 1]);
+
+ }
/* (non-Javadoc)
* @see org.killbill.billing.catalog.IPlan#getEffectiveDateForExistingSubscriptons()
*/
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhase.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhase.java
index ec69d44..77971a8 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhase.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhase.java
@@ -20,6 +20,7 @@ package org.killbill.billing.catalog;
import java.net.URI;
+import javax.annotation.Nullable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
@@ -33,6 +34,7 @@ import org.killbill.billing.catalog.api.Fixed;
import org.killbill.billing.catalog.api.PhaseType;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhase;
+import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.Recurring;
import org.killbill.billing.catalog.api.Usage;
import org.killbill.xmlloader.ValidatingConfig;
@@ -61,6 +63,20 @@ public class DefaultPlanPhase extends ValidatingConfig<StandaloneCatalog> implem
//Not exposed in XML
private Plan plan;
+ public DefaultPlanPhase() {}
+
+ public DefaultPlanPhase(final DefaultPlanPhase in, @Nullable final PlanPhasePriceOverride override) {
+ this.type = in.getPhaseType();
+ this.duration = (DefaultDuration) in.getDuration();
+ this.fixed = override != null && override.getFixedPrice() != null ? new DefaultFixed((DefaultFixed) in.getFixed(), override) : (DefaultFixed) in.getFixed();
+ this.recurring = override != null && override.getRecurringPrice() != null ? new DefaultRecurring((DefaultRecurring) in.getRecurring(), override) : (DefaultRecurring) in.getRecurring();
+ this.usages = new DefaultUsage[in.getUsages().length];
+ for (int i = 0; i < in.getUsages().length; i++) {
+ usages[i] = (DefaultUsage) in.getUsages()[i];
+ }
+ this.plan = in.plan;
+ }
+
public static String phaseName(final String planName, final PhaseType phasetype) {
return planName + "-" + phasetype.toString().toLowerCase();
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultRecurring.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultRecurring.java
index 644052e..b28f371 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultRecurring.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultRecurring.java
@@ -26,6 +26,7 @@ import javax.xml.bind.annotation.XmlElement;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhase;
+import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.Recurring;
import org.killbill.xmlloader.ValidatingConfig;
import org.killbill.xmlloader.ValidationError;
@@ -44,6 +45,13 @@ public class DefaultRecurring extends ValidatingConfig<StandaloneCatalog> implem
private Plan plan;
private PlanPhase phase;
+ public DefaultRecurring() {};
+
+ public DefaultRecurring(final DefaultRecurring in, final PlanPhasePriceOverride override) {
+ this.billingPeriod = in.getBillingPeriod();
+ this.recurringPrice = new DefaultInternationalPrice(recurringPrice, override, false);
+ }
+
@Override
public BillingPeriod getBillingPeriod() {
return billingPeriod;
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java b/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java
index 66501d1..bf4c557 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java
@@ -24,19 +24,19 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.List;
-import com.google.common.io.Resources;
-import com.google.inject.Inject;
-
import org.killbill.billing.ErrorCode;
import org.killbill.billing.catalog.StandaloneCatalog;
+import org.killbill.billing.catalog.StandaloneCatalogWithPriceOverride;
import org.killbill.billing.catalog.VersionedCatalog;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.override.PriceOverride;
-import org.killbill.billing.platform.api.KillbillService.ServiceException;
import org.killbill.clock.Clock;
import org.killbill.xmlloader.UriAccessor;
import org.killbill.xmlloader.XMLLoader;
+import com.google.common.io.Resources;
+import com.google.inject.Inject;
+
public class VersionedCatalogLoader implements CatalogLoader {
private static final Object PROTOCOL_FOR_FILE = "file";
@@ -82,7 +82,7 @@ public class VersionedCatalogLoader implements CatalogLoader {
final VersionedCatalog result = new VersionedCatalog(clock);
for (final URI u : xmlURIs) {
final StandaloneCatalog catalog = XMLLoader.getObjectFromUri(u, StandaloneCatalog.class);
- result.add(catalog);
+ result.add(new StandaloneCatalogWithPriceOverride(catalog, priceOverride));
}
return result;
} catch (Exception e) {
@@ -98,8 +98,7 @@ public class VersionedCatalogLoader implements CatalogLoader {
for (final String cur : catalogXMLs) {
final InputStream curCatalogStream = new ByteArrayInputStream(cur.getBytes());
final StandaloneCatalog catalog = XMLLoader.getObjectFromStream(uri, curCatalogStream, StandaloneCatalog.class);
- catalog.setPriceOverride(priceOverride);
- result.add(catalog);
+ result.add(new StandaloneCatalogWithPriceOverride(catalog, priceOverride));
}
return result;
} catch (Exception e) {
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/override/DefaultPriceOverride.java b/catalog/src/main/java/org/killbill/billing/catalog/override/DefaultPriceOverride.java
index c5415f2..6dcb2e1 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/override/DefaultPriceOverride.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/override/DefaultPriceOverride.java
@@ -19,21 +19,60 @@ package org.killbill.billing.catalog.override;
import java.util.List;
+import org.joda.time.DateTime;
+import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.catalog.DefaultPlan;
+import org.killbill.billing.catalog.DefaultPlanPhasePriceOverride;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.Plan;
+import org.killbill.billing.catalog.api.PlanPhase;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
+import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.dao.CatalogOverrideDao;
+import org.killbill.billing.catalog.dao.CatalogOverridePlanDefinitionModelDao;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
import com.google.inject.Inject;
public class DefaultPriceOverride implements PriceOverride {
+ private final CatalogOverrideDao overrideDao;
+
@Inject
- public DefaultPriceOverride() {
+ public DefaultPriceOverride(final CatalogOverrideDao overrideDao) {
+ this.overrideDao = overrideDao;
}
@Override
- public DefaultPlan getOverriddenPlan(final Plan parentPlan, final List<PlanPhasePriceOverride> overrides) throws CatalogApiException {
- return null;
+ public DefaultPlan getOrCreateOverriddenPlan(final Plan parentPlan, final DateTime catalogEffectiveDate, final List<PlanPhasePriceOverride> overrides, final InternalCallContext context) throws CatalogApiException {
+
+ final PlanPhasePriceOverride[] resolvedOverride = new PlanPhasePriceOverride[parentPlan.getAllPhases().length];
+ int index = 0;
+ for (final PlanPhase curPhase : parentPlan.getAllPhases()) {
+ final PlanPhasePriceOverride curOverride = Iterables.tryFind(overrides, new Predicate<PlanPhasePriceOverride>() {
+ @Override
+ public boolean apply(final PlanPhasePriceOverride input) {
+ if (input.getPhaseName() != null && input.getPhaseName().equals(curPhase.getName())) {
+ return true;
+ }
+ // If the phaseName was not passed, we infer by matching the phaseType. This obvously would not work in a case where
+ // a plan is defined with multiple phases of the same type.
+ final PlanPhaseSpecifier curPlanPhaseSpecifier = input.getPlanPhaseSpecifier();
+ if (curPlanPhaseSpecifier.getPhaseType().equals(curPhase.getPhaseType())) {
+ return true;
+ }
+ return false;
+ }
+ }).orNull();
+ resolvedOverride[index++] = curOverride != null ?
+ new DefaultPlanPhasePriceOverride(curPhase.getName(), curOverride.getCurrency(), curOverride.getFixedPrice(), curOverride.getRecurringPrice()) :
+ null;
+ }
+
+ final CatalogOverridePlanDefinitionModelDao overriddenPlan = overrideDao.getOrCreateOverridePlanDefinition(parentPlan.getName(), catalogEffectiveDate, resolvedOverride, context);
+ final String planName = new StringBuffer(parentPlan.getName()).append("-").append(overriddenPlan.getRecordId()).toString();
+ final DefaultPlan result = new DefaultPlan(planName, (DefaultPlan) parentPlan, resolvedOverride);
+ return result;
}
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/override/PriceOverride.java b/catalog/src/main/java/org/killbill/billing/catalog/override/PriceOverride.java
index 5303b8d..b60befe 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/override/PriceOverride.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/override/PriceOverride.java
@@ -19,11 +19,14 @@ package org.killbill.billing.catalog.override;
import java.util.List;
+import org.joda.time.DateTime;
+import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.catalog.DefaultPlan;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.Plan;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
public interface PriceOverride {
- DefaultPlan getOverriddenPlan(Plan parentPlan, List<PlanPhasePriceOverride> overrides) throws CatalogApiException;
+
+ DefaultPlan getOrCreateOverriddenPlan(final Plan parentPlan, final DateTime catalogEffectiveDate, final List<PlanPhasePriceOverride> overrides, final InternalCallContext context) throws CatalogApiException;
}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
index 399db49..a603547 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
@@ -92,8 +92,6 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
private URI catalogURI;
- private PriceOverride priceOverride;
-
public StandaloneCatalog() {
}
@@ -165,7 +163,7 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
* @see org.killbill.billing.catalog.ICatalog#getPlan(java.lang.String, java.lang.String)
*/
@Override
- public DefaultPlan findCurrentPlan(final String productName, final BillingPeriod period, final String priceListName, final List<PlanPhasePriceOverride> overrides) throws CatalogApiException {
+ public DefaultPlan findCurrentPlan(final String productName, final BillingPeriod period, final String priceListName, final List<PlanPhasePriceOverride> nullOverrides) throws CatalogApiException {
if (productName == null) {
throw new CatalogApiException(ErrorCode.CAT_NULL_PRODUCT_NAME);
}
@@ -178,11 +176,7 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
final String periodString = (period == null) ? "NULL" : period.toString();
throw new CatalogApiException(ErrorCode.CAT_PLAN_NOT_FOUND, productName, periodString, priceListName);
}
- if (overrides != null && !overrides.isEmpty()) {
- return priceOverride.getOverriddenPlan(result, overrides);
- } else {
- return result;
- }
+ return result;
}
@Override
@@ -352,10 +346,6 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
return this;
}
- public void setPriceOverride(final PriceOverride priceOverride) {
- this.priceOverride = priceOverride;
- }
-
@Override
public boolean canCreatePlan(final PlanSpecifier specifier) throws CatalogApiException {
final Product product = findCurrentProduct(specifier.getProductName());
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java
new file mode 100644
index 0000000..3564fb1
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project 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 org.killbill.billing.catalog;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.catalog.api.BillingActionPolicy;
+import org.killbill.billing.catalog.api.BillingAlignment;
+import org.killbill.billing.catalog.api.BillingMode;
+import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.catalog.api.Listing;
+import org.killbill.billing.catalog.api.Plan;
+import org.killbill.billing.catalog.api.PlanAlignmentChange;
+import org.killbill.billing.catalog.api.PlanAlignmentCreate;
+import org.killbill.billing.catalog.api.PlanChangeResult;
+import org.killbill.billing.catalog.api.PlanPhase;
+import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
+import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.PlanSpecifier;
+import org.killbill.billing.catalog.api.PriceList;
+import org.killbill.billing.catalog.api.Product;
+import org.killbill.billing.catalog.api.StaticCatalog;
+import org.killbill.billing.catalog.api.Unit;
+import org.killbill.billing.catalog.override.PriceOverride;
+import org.killbill.xmlloader.ValidatingConfig;
+import org.killbill.xmlloader.ValidationErrors;
+
+public class StandaloneCatalogWithPriceOverride extends ValidatingConfig<StandaloneCatalogWithPriceOverride> implements StaticCatalog {
+
+ private final StandaloneCatalog standaloneCatalog;
+ private final PriceOverride priceOverride;
+
+ public StandaloneCatalogWithPriceOverride(final StandaloneCatalog staticCatalog, final PriceOverride priceOverride) {
+ this.standaloneCatalog = staticCatalog;
+ this.priceOverride = priceOverride;
+ }
+
+ @Override
+ public String getCatalogName() {
+ return standaloneCatalog.getCatalogName();
+ }
+
+ @Override
+ public BillingMode getRecurringBillingMode() {
+ return standaloneCatalog.getRecurringBillingMode();
+ }
+
+ @Override
+ public Date getEffectiveDate() {
+ return standaloneCatalog.getEffectiveDate();
+ }
+
+ @Override
+ public Currency[] getCurrentSupportedCurrencies() throws CatalogApiException {
+ return standaloneCatalog.getCurrentSupportedCurrencies();
+ }
+
+ @Override
+ public DefaultProduct[] getCurrentProducts() throws CatalogApiException {
+ return standaloneCatalog.getCurrentProducts();
+ }
+
+ @Override
+ public Unit[] getCurrentUnits() throws CatalogApiException {
+ return standaloneCatalog.getCurrentUnits();
+ }
+
+ @Override
+ public DefaultPlan[] getCurrentPlans() throws CatalogApiException {
+ return standaloneCatalog.getCurrentPlans();
+ }
+
+ @Override
+ public Plan findCurrentPlan(final String productName, final BillingPeriod period, final String priceListName, final List<PlanPhasePriceOverride> overrides) throws CatalogApiException {
+ final Plan defaultPlan = standaloneCatalog.findCurrentPlan(productName, period, priceListName, null);
+ if (overrides == null || overrides.isEmpty()) {
+ return defaultPlan;
+ }
+ // STEPH_PO Hum, how am i supposed to create a context here???
+ final InternalCallContext context = null;
+ return priceOverride.getOrCreateOverriddenPlan(defaultPlan, new DateTime(getEffectiveDate()), overrides, context);
+ }
+
+ @Override
+ public Plan findCurrentPlan(final String planName) throws CatalogApiException {
+ return standaloneCatalog.findCurrentPlan(planName);
+ }
+
+ @Override
+ public Product findCurrentProduct(final String productName) throws CatalogApiException {
+ return standaloneCatalog.findCurrentProduct(productName);
+ }
+
+ @Override
+ public PlanPhase findCurrentPhase(final String phaseName) throws CatalogApiException {
+ return standaloneCatalog.findCurrentPhase(phaseName);
+ }
+
+ @Override
+ public PriceList findCurrentPricelist(final String priceListName) throws CatalogApiException {
+ return standaloneCatalog.findCurrentPricelist(priceListName);
+ }
+
+ @Override
+ public BillingActionPolicy planChangePolicy(final PlanPhaseSpecifier planPhaseSpecifier, final PlanSpecifier planSpecifier) throws CatalogApiException {
+ return standaloneCatalog.planChangePolicy(planPhaseSpecifier, planSpecifier);
+ }
+
+ @Override
+ public PlanChangeResult planChange(final PlanPhaseSpecifier planPhaseSpecifier, final PlanSpecifier planSpecifier) throws CatalogApiException {
+ return standaloneCatalog.planChange(planPhaseSpecifier, planSpecifier);
+ }
+
+ @Override
+ public BillingActionPolicy planCancelPolicy(final PlanPhaseSpecifier planPhaseSpecifier) throws CatalogApiException {
+ return standaloneCatalog.planCancelPolicy(planPhaseSpecifier);
+ }
+
+ @Override
+ public PlanAlignmentCreate planCreateAlignment(final PlanSpecifier planSpecifier) throws CatalogApiException {
+ return standaloneCatalog.planCreateAlignment(planSpecifier);
+ }
+
+ @Override
+ public BillingAlignment billingAlignment(final PlanPhaseSpecifier planPhaseSpecifier) throws CatalogApiException {
+ return standaloneCatalog.billingAlignment(planPhaseSpecifier);
+ }
+
+ @Override
+ public PlanAlignmentChange planChangeAlignment(final PlanPhaseSpecifier planPhaseSpecifier, final PlanSpecifier planSpecifier) throws CatalogApiException {
+ return standaloneCatalog.planChangeAlignment(planPhaseSpecifier, planSpecifier);
+ }
+
+ @Override
+ public boolean canCreatePlan(final PlanSpecifier planSpecifier) throws CatalogApiException {
+ return standaloneCatalog.canCreatePlan(planSpecifier);
+ }
+
+ @Override
+ public List<Listing> getAvailableBasePlanListings() throws CatalogApiException {
+ return standaloneCatalog.getAvailableBasePlanListings();
+ }
+
+ @Override
+ public List<Listing> getAvailableAddOnListings(final String baseProductName, @Nullable final String priceListName) throws CatalogApiException {
+ return standaloneCatalog.getAvailableAddOnListings(baseProductName, priceListName);
+ }
+
+ @Override
+ public boolean compliesWithLimits(final String phaseName, final String unit, final double value) throws CatalogApiException {
+ return standaloneCatalog.compliesWithLimits(phaseName, unit, value);
+ }
+
+ @Override
+ public ValidationErrors validate(final StandaloneCatalogWithPriceOverride root, final ValidationErrors errors) {
+ return standaloneCatalog.validate(root.standaloneCatalog, errors);
+ }
+
+ @Override
+ public void initialize(final StandaloneCatalogWithPriceOverride root, final URI sourceURI) {
+ standaloneCatalog.initialize(root.standaloneCatalog, sourceURI);
+ }
+
+ public DefaultPriceList findCurrentPriceList(final String priceListName) throws CatalogApiException {
+ return standaloneCatalog.findCurrentPriceList(priceListName);
+ }
+
+
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
index 2bfb1ec..e647ad5 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
@@ -60,14 +60,14 @@ import org.killbill.xmlloader.ValidationErrors;
@XmlRootElement(name = "catalog")
@XmlAccessorType(XmlAccessType.NONE)
-public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implements Catalog, StaticCatalog {
+public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPriceOverride> implements Catalog, StaticCatalog {
private final Clock clock;
private String catalogName;
private BillingMode recurringBillingMode;
@XmlElement(name = "catalogVersion", required = true)
- private final List<StandaloneCatalog> versions = new ArrayList<StandaloneCatalog>();
+ private final List<StandaloneCatalogWithPriceOverride> versions = new ArrayList<StandaloneCatalogWithPriceOverride>();
// Default CTOR for XMLWriter.writeXML
public VersionedCatalog() {
@@ -82,12 +82,12 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
//
// Private methods
//
- private StandaloneCatalog versionForDate(final DateTime date) throws CatalogApiException {
+ private StandaloneCatalogWithPriceOverride versionForDate(final DateTime date) throws CatalogApiException {
return versions.get(indexOfVersionForDate(date.toDate()));
}
- private List<StandaloneCatalog> versionsBeforeDate(final Date date) throws CatalogApiException {
- final List<StandaloneCatalog> result = new ArrayList<StandaloneCatalog>();
+ private List<StandaloneCatalogWithPriceOverride> versionsBeforeDate(final Date date) throws CatalogApiException {
+ final List<StandaloneCatalogWithPriceOverride> result = new ArrayList<StandaloneCatalogWithPriceOverride>();
final int index = indexOfVersionForDate(date);
for (int i = 0; i <= index; i++) {
result.add(versions.get(i));
@@ -97,7 +97,7 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
private int indexOfVersionForDate(final Date date) throws CatalogApiException {
for (int i = versions.size() - 1; i >= 0; i--) {
- final StandaloneCatalog c = versions.get(i);
+ final StandaloneCatalogWithPriceOverride c = versions.get(i);
if (c.getEffectiveDate().getTime() <= date.getTime()) {
return i;
}
@@ -125,7 +125,7 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
this.overrides = overrides;
}
- public Plan findPlan(final StandaloneCatalog catalog) throws CatalogApiException {
+ public Plan findPlan(final StandaloneCatalogWithPriceOverride catalog) throws CatalogApiException {
if (name != null) {
return catalog.findCurrentPlan(name);
} else {
@@ -138,13 +138,13 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
final DateTime requestedDate,
final DateTime subscriptionStartDate)
throws CatalogApiException {
- final List<StandaloneCatalog> catalogs = versionsBeforeDate(requestedDate.toDate());
+ final List<StandaloneCatalogWithPriceOverride> catalogs = versionsBeforeDate(requestedDate.toDate());
if (catalogs.size() == 0) {
throw new CatalogApiException(ErrorCode.CAT_NO_CATALOG_FOR_GIVEN_DATE, requestedDate.toDate().toString());
}
for (int i = catalogs.size() - 1; i >= 0; i--) { // Working backwards to find the latest applicable plan
- final StandaloneCatalog c = catalogs.get(i);
+ final StandaloneCatalogWithPriceOverride c = catalogs.get(i);
Plan plan;
try {
plan = wrapper.findPlan(c);
@@ -176,7 +176,7 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
//
// Public methods not exposed in interface
//
- public void add(final StandaloneCatalog e) throws CatalogApiException {
+ public void add(final StandaloneCatalogWithPriceOverride e) throws CatalogApiException {
if (catalogName == null) {
catalogName = e.getCatalogName();
} else {
@@ -192,15 +192,15 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
}
}
versions.add(e);
- Collections.sort(versions, new Comparator<StandaloneCatalog>() {
+ Collections.sort(versions, new Comparator<StandaloneCatalogWithPriceOverride>() {
@Override
- public int compare(final StandaloneCatalog c1, final StandaloneCatalog c2) {
+ public int compare(final StandaloneCatalogWithPriceOverride c1, final StandaloneCatalogWithPriceOverride c2) {
return c1.getEffectiveDate().compareTo(c2.getEffectiveDate());
}
});
}
- public Iterator<StandaloneCatalog> iterator() {
+ public Iterator<StandaloneCatalogWithPriceOverride> iterator() {
return versions.iterator();
}
@@ -346,15 +346,15 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
// VerifiableConfig API
//
@Override
- public void initialize(final StandaloneCatalog catalog, final URI sourceURI) {
- for (final StandaloneCatalog c : versions) {
+ public void initialize(final StandaloneCatalogWithPriceOverride catalog, final URI sourceURI) {
+ for (final StandaloneCatalogWithPriceOverride c : versions) {
c.initialize(catalog, sourceURI);
}
}
@Override
- public ValidationErrors validate(final StandaloneCatalog catalog, final ValidationErrors errors) {
- for (final StandaloneCatalog c : versions) {
+ public ValidationErrors validate(final StandaloneCatalogWithPriceOverride catalog, final ValidationErrors errors) {
+ for (final StandaloneCatalogWithPriceOverride c : versions) {
errors.addAll(c.validate(c, errors));
}
//TODO MDW validation - ensure all catalog versions have a single name
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/io/TestVersionedCatalogLoader.java b/catalog/src/test/java/org/killbill/billing/catalog/io/TestVersionedCatalogLoader.java
index 64d5075..9f0d0f9 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/io/TestVersionedCatalogLoader.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/io/TestVersionedCatalogLoader.java
@@ -32,6 +32,7 @@ import javax.xml.transform.TransformerException;
import org.joda.time.DateTime;
import org.killbill.billing.catalog.CatalogTestSuiteNoDB;
import org.killbill.billing.catalog.StandaloneCatalog;
+import org.killbill.billing.catalog.StandaloneCatalogWithPriceOverride;
import org.killbill.billing.catalog.VersionedCatalog;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.InvalidConfigException;
@@ -119,7 +120,7 @@ public class TestVersionedCatalogLoader extends CatalogTestSuiteNoDB {
public void testLoad() throws IOException, SAXException, InvalidConfigException, JAXBException, TransformerException, URISyntaxException, CatalogApiException {
final VersionedCatalog c = loader.load(Resources.getResource("versionedCatalog").toString());
Assert.assertEquals(c.size(), 3);
- final Iterator<StandaloneCatalog> it = c.iterator();
+ final Iterator<StandaloneCatalogWithPriceOverride> it = c.iterator();
DateTime dt = new DateTime("2011-01-01T00:00:00+00:00");
Assert.assertEquals(it.next().getEffectiveDate(), dt.toDate());
dt = new DateTime("2011-02-02T00:00:00+00:00");
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/MockInternationalPrice.java b/catalog/src/test/java/org/killbill/billing/catalog/MockInternationalPrice.java
index 1500ce1..1e7f747 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/MockInternationalPrice.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/MockInternationalPrice.java
@@ -34,6 +34,7 @@ public class MockInternationalPrice extends DefaultInternationalPrice {
return new MockInternationalPrice(new DefaultPrice().setCurrency(Currency.USD).setValue(new BigDecimal(value)));
}
+
public MockInternationalPrice(final DefaultPrice... price) {
setPrices(price);
}
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java b/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java
index b004cd8..08adf80 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java
@@ -52,7 +52,7 @@ public class TestVersionedCatalog extends CatalogTestSuiteNoDB {
@Test(groups = "fast")
public void testAddCatalog() throws IOException, SAXException, InvalidConfigException, JAXBException, TransformerException, URISyntaxException, ServiceException, CatalogApiException {
- vc.add((new StandaloneCatalog(new Date()).setCatalogName(vc.getCatalogName()).setRecurringBillingMode(vc.getRecurringBillingMode())));
+ vc.add(new StandaloneCatalogWithPriceOverride(new StandaloneCatalog(new Date()).setCatalogName(vc.getCatalogName()).setRecurringBillingMode(vc.getRecurringBillingMode()), null));
Assert.assertEquals(vc.size(), 4);
}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
index 25e526e..25c4de8 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
@@ -123,8 +123,12 @@ public class PhasePriceOverrideJson {
@Override
public PlanPhasePriceOverride apply(@Nullable final PhasePriceOverrideJson input) {
final PhaseType phaseType = input.getPhaseType() != null ? PhaseType.valueOf(input.getPhaseType()) : null;
- final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier(spec.getProductName(), spec.getProductCategory(), spec.getBillingPeriod(), spec.getPriceListName(), phaseType);
- return new DefaultPlanPhasePriceOverride(input.getPhaseName(), planPhaseSpecifier, currency, input.getFixedPrice(), input.getRecurringPrice());
+ if (input.getPhaseName() != null) {
+ return new DefaultPlanPhasePriceOverride(input.getPhaseName(), currency, input.getFixedPrice(), input.getRecurringPrice());
+ } else {
+ final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier(spec.getProductName(), spec.getProductCategory(), spec.getBillingPeriod(), spec.getPriceListName(), phaseType);
+ return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, currency, input.getFixedPrice(), input.getRecurringPrice());
+ }
}
}));
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
index e5ef133..497756c 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
@@ -925,7 +925,11 @@ public class InvoiceResource extends JaxRsResourceBase {
@Nullable
@Override
public PlanPhasePriceOverride apply(@Nullable final PhasePriceOverrideJson input) {
- return new DefaultPlanPhasePriceOverride(input.getPhaseName(), planPhaseSpecifier, currency, input.getFixedPrice(), input.getRecurringPrice());
+ if (input.getPhaseName() != null) {
+ return new DefaultPlanPhasePriceOverride(input.getPhaseName(), currency, input.getFixedPrice(), input.getRecurringPrice());
+ } else {
+ return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, currency, input.getFixedPrice(), input.getRecurringPrice());
+ }
}
})) : ImmutableList.<PlanPhasePriceOverride>of();
}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
index cc7ccd4..e1eb4dc 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
@@ -249,7 +249,6 @@ public class SubscriptionResource extends JaxRsResourceBase {
final CallContext callContext = context.createContext(createdBy, reason, comment, request);
final UUID accountId = entitlement.getAccountId() != null ? UUID.fromString(entitlement.getAccountId()) : null;
- final Account account = accountUserApi.getAccountById(accountId, callContext);
final EntitlementCallCompletionCallback<Response> callback = new EntitlementCallCompletionCallback<Response>() {
private boolean isImmediateOp = true;
@@ -263,6 +262,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
final LocalDate inputLocalDate = toLocalDate(current.getAccountId(), requestedDate, callContext);
final Entitlement newEntitlement;
+ final Account account = accountUserApi.getAccountById(accountId, callContext);
final PlanSpecifier planSpec = new PlanSpecifier(entitlement.getProductName(),
ProductCategory.valueOf(entitlement.getProductCategory()),
BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList());
profiles/killbill/src/main/resources/CatalogMos.xml 515(+515 -0)
diff --git a/profiles/killbill/src/main/resources/CatalogMos.xml b/profiles/killbill/src/main/resources/CatalogMos.xml
new file mode 100644
index 0000000..f86c487
--- /dev/null
+++ b/profiles/killbill/src/main/resources/CatalogMos.xml
@@ -0,0 +1,515 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="catalog.xsd ">
+
+ <effectiveDate>2011-01-01T00:00:00+00:00</effectiveDate>
+ <catalogName>MOSCatalog</catalogName>
+
+ <recurringBillingMode>IN_ADVANCE</recurringBillingMode>
+
+ <currencies>
+ <currency>USD</currency>
+ </currencies>
+
+ <products>
+ <product name="cafe">
+ <category>BASE</category>
+ </product>
+ <product name="custom">
+ <category>BASE</category>
+ </product>
+ <product name="flagship">
+ <category>BASE</category>
+ </product>
+ <product name="free">
+ <category>BASE</category>
+ </product>
+ <product name="mx60mr12_2_license">
+ <category>BASE</category>
+ </product>
+ <product name="mx60mr12_3_license">
+ <category>BASE</category>
+ </product>
+ <product name="mx60mr12_4_license">
+ <category>BASE</category>
+ </product>
+ <product name="mx60mr12_5_license">
+ <category>BASE</category>
+ </product>
+ <product name="mx60_license">
+ <category>BASE</category>
+ </product>
+ <product name="mx60mr12_license">
+ <category>BASE</category>
+ </product>
+ <product name="mx80mr12_6_license">
+ <category>BASE</category>
+ </product>
+ <product name="z1_mr12">
+ <category>BASE</category>
+ </product>
+ <product name="z1_license">
+ <category>BASE</category>
+ </product>
+ <product name="midsize">
+ <category>BASE</category>
+ </product>
+ <product name="mr12_license">
+ <category>BASE</category>
+ </product>
+ <product name="solo">
+ <category>BASE</category>
+ </product>
+ </products>
+
+ <rules>
+ <changePolicy>
+ <changePolicyCase>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ </changePolicy>
+ <changeAlignment>
+ <changeAlignmentCase>
+ <alignment>START_OF_BUNDLE</alignment>
+ </changeAlignmentCase>
+ </changeAlignment>
+ <cancelPolicy>
+ <cancelPolicyCase>
+ <policy>END_OF_TERM</policy>
+ </cancelPolicyCase>
+ </cancelPolicy>
+ <createAlignment>
+ <createAlignmentCase>
+ <alignment>START_OF_BUNDLE</alignment>
+ </createAlignmentCase>
+ </createAlignment>
+ <billingAlignment>
+ <billingAlignmentCase>
+ <alignment>SUBSCRIPTION</alignment>
+ </billingAlignmentCase>
+ </billingAlignment>
+ <priceList>
+ <priceListCase>
+ <toPriceList>DEFAULT</toPriceList>
+ </priceListCase>
+ </priceList>
+ </rules>
+
+ <plans>
+ <plan name="cafe-monthly">
+ <product>cafe</product>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>199.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="custom-monthly">
+ <product>custom</product>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>450.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="flagship-monthly">
+ <product>flagship</product>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>399.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="free-monthly"> <!-- May be alternative ways to model this - not sure if it matters though -->
+ <product>free</product>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>0.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="mx60mr12_2_license-annual">
+ <product>mx60mr12_2_license</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>YEARS</unit>
+ <number>1</number>
+ </duration>
+ <fixed>
+ <fixedPrice>
+ </fixedPrice>
+ </fixed>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>206.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="mx60mr12_3_license-annual">
+ <product>mx60mr12_3_license</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>YEARS</unit>
+ <number>1</number>
+ </duration>
+ <fixed>
+ <fixedPrice>
+ </fixedPrice>
+ </fixed>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>262.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="mx60mr12_4_license-annual">
+ <product>mx60mr12_4_license</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>YEARS</unit>
+ <number>1</number>
+ </duration>
+ <fixed>
+ <fixedPrice>
+ </fixedPrice>
+ </fixed>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>318.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="mx60mr12_5_license-annual">
+ <product>mx60mr12_5_license</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>YEARS</unit>
+ <number>1</number>
+ </duration>
+ <fixed>
+ <fixedPrice>
+ </fixedPrice>
+ </fixed>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>374.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="mx60_license-annual">
+ <product>mx60_license</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>YEARS</unit>
+ <number>1</number>
+ </duration>
+ <fixed>
+ <fixedPrice>
+ </fixedPrice>
+ </fixed>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>94.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="mx60mr12_license-annual">
+ <product>mx60mr12_license</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>YEARS</unit>
+ <number>1</number>
+ </duration>
+ <fixed>
+ <fixedPrice>
+ </fixedPrice>
+ </fixed>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>150.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="mx80mr12_6_license-annual">
+ <product>mx80mr12_6_license</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>YEARS</unit>
+ <number>1</number>
+ </duration>
+ <fixed>
+ <fixedPrice>
+ </fixedPrice>
+ </fixed>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>696.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="z1_mr12-annual">
+ <product>z1_mr12</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>YEARS</unit>
+ <number>1</number>
+ </duration>
+ <fixed>
+ <fixedPrice>
+ </fixedPrice>
+ </fixed>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>71.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="z1_license-annual">
+ <product>z1_license</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>YEARS</unit>
+ <number>1</number>
+ </duration>
+ <fixed>
+ <fixedPrice>
+ </fixedPrice>
+ </fixed>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>15.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="midsize-monthly">
+ <product>midsize</product>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>299.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="mr12_license-annual">
+ <product>mr12_license</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>YEARS</unit>
+ <number>1</number>
+ </duration>
+ <fixed>
+ <fixedPrice>
+ </fixedPrice>
+ </fixed>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>56.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ <plan name="solo-monthly">
+ <product>solo</product>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <recurring>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price>
+ <currency>USD</currency>
+ <value>99.00</value>
+ </price>
+ </recurringPrice>
+ </recurring>
+ </finalPhase>
+ </plan>
+ </plans>
+ <priceLists>
+ <defaultPriceList name="DEFAULT">
+ <plans>
+ <plan>cafe-monthly</plan>
+ <plan>custom-monthly</plan>
+ <plan>flagship-monthly</plan>
+ <plan>free-monthly</plan>
+ <plan>mx60mr12_2_license-annual</plan>
+ <plan>mx60mr12_3_license-annual</plan>
+ <plan>mx60mr12_4_license-annual</plan>
+ <plan>mx60mr12_5_license-annual</plan>
+ <plan>mx60_license-annual</plan>
+ <plan>mx60mr12_license-annual</plan>
+ <plan>mx80mr12_6_license-annual</plan>
+ <plan>z1_mr12-annual</plan>
+ <plan>z1_license-annual</plan>
+ <plan>midsize-monthly</plan>
+ <plan>mr12_license-annual</plan>
+ <plan>solo-monthly</plan>
+ </plans>
+ </defaultPriceList>
+ </priceLists>
+</catalog>
diff --git a/profiles/killbill/src/main/resources/killbill-server.properties.mos b/profiles/killbill/src/main/resources/killbill-server.properties.mos
new file mode 100644
index 0000000..735f895
--- /dev/null
+++ b/profiles/killbill/src/main/resources/killbill-server.properties.mos
@@ -0,0 +1,88 @@
+#
+# Copyright 2010-2013 Ning, Inc.
+# Copyright 2014 Groupon, Inc
+# Copyright 2014 The Billing Project, LLC
+#
+# The Billing Project 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.
+#
+
+#
+# KILLBILL GENERIC PROPERTIES
+#
+# Database config
+#org.killbill.dao.url=jdbc:mysql://127.0.0.1:3306/killbill
+org.killbill.dao.url=jdbc:mysql://127.0.0.1:3306/killbil_analytics_mos
+org.killbill.dao.user=root
+org.killbill.dao.password=root
+org.killbill.dao.logLevel=DEBUG
+
+# Use the SpyCarAdvanced.xml catalog
+#org.killbill.catalog.uri=SpyCarAdvanced.xml
+org.killbill.catalog.uri=CatalogMos.xml
+
+# NotificationQ, Bus, ExtBus config
+org.killbill.notificationq.main.sleep=1000
+org.killbill.notificationq.main.claimed=10
+org.killbill.notificationq.main.sticky=true
+
+org.killbill.persistent.bus.external.sticky=true
+org.killbill.persistent.bus.external.inMemory=true
+
+org.killbill.persistent.bus.main.sticky=true
+org.killbill.persistent.bus.main.claimed=1
+org.killbill.persistent.bus.main.inflight.claimed=1
+org.killbill.persistent.bus.main.nbThreads=1
+org.killbill.persistent.bus.main.sleep=0
+org.killbill.persistent.bus.main.useInflightQ=true
+org.killbill.persistent.bus.main.queue.capacity=100
+
+# Start KB in multi-tenant
+org.killbill.server.multitenant=true
+
+# Override polling from Tenant Broadcast Task
+org.killbill.tenant.broadcast.rate=1s
+
+#
+# PLUGIN SPECIFIC PROPERTIES
+#
+# Database config (OSGI plugins)
+#org.killbill.billing.osgi.dao.url=jdbc:mysql://127.0.0.1:3306/killbill
+org.killbill.billing.osgi.dao.url=jdbc:mysql://127.0.0.1:3306/killbil_analytics_mos
+org.killbill.billing.osgi.dao.user=root
+org.killbill.billing.osgi.dao.password=root
+
+# Allow jruby concurrency
+org.killbill.jruby.context.scope=THREADSAFE
+
+# Path for plugin config
+#org.killbill.billing.osgi.bundles.jruby.conf.dir=/var/tmp/bundles/plugins/config
+org.killbill.osgi.bundle.install.dir=/var/tmp/bundles_analytics_mos
+
+# Config property files for plugin to access
+org.killbill.server.properties=/Users/sbrossier/Src/killbill/killbill/profiles/killbill/src/main/resources/killbill-server.properties
+
+#
+# INTEGRATION TESTS ONLY
+#
+# To enable test endpoint and have Kill Bill run with a ClockMock (should not be used for production server)
+org.killbill.server.test.mode=true
+
+# Set payment calls to timeout after 5 sec -- mostly for integration tests
+org.killbill.payment.plugin.timeout=5s
+
+org.killbill.payment.retry.days=
+
+org.killbill.catalog.bundlePath=CatalogTranslation
+org.killbill.template.bundlePath=InvoiceTranslation
+org.killbill.template.name=HtmlInvoiceTemplate.mustache
+
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
index a885df7..39c2c7c 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
@@ -64,8 +64,10 @@ public class TestEntitlement extends TestJaxrsBase {
final String newProductName = "Assault-Rifle";
final Subscription newInput = new Subscription();
+ newInput.setAccountId(entitlementJson.getAccountId());
newInput.setSubscriptionId(entitlementJson.getSubscriptionId());
newInput.setProductName(newProductName);
+ newInput.setProductCategory(ProductCategory.BASE);
newInput.setBillingPeriod(entitlementJson.getBillingPeriod());
newInput.setPriceList(entitlementJson.getPriceList());
objFromJson = killBillClient.updateSubscription(newInput, CALL_COMPLETION_TIMEOUT_SEC, createdBy, reason, comment);
@@ -128,8 +130,10 @@ public class TestEntitlement extends TestJaxrsBase {
public void testWithNonExistentEntitlement() throws Exception {
final UUID subscriptionId = UUID.randomUUID();
final Subscription subscription = new Subscription();
+ subscription.setAccountId(UUID.randomUUID());
subscription.setSubscriptionId(subscriptionId);
subscription.setProductName("Pistol");
+ subscription.setProductCategory(ProductCategory.BASE);
subscription.setBillingPeriod(BillingPeriod.ANNUAL);
subscription.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
@@ -175,8 +179,10 @@ public class TestEntitlement extends TestJaxrsBase {
// Change billing period immediately
final Subscription newInput = new Subscription();
+ newInput.setAccountId(accountJson.getAccountId());
newInput.setSubscriptionId(subscriptionJson.getSubscriptionId());
newInput.setProductName(subscriptionJson.getProductName());
+ newInput.setProductCategory(ProductCategory.BASE);
newInput.setBillingPeriod(BillingPeriod.MONTHLY);
newInput.setPriceList(subscriptionJson.getPriceList());
objFromJson = killBillClient.updateSubscription(newInput, BillingActionPolicy.IMMEDIATE, CALL_COMPLETION_TIMEOUT_SEC, createdBy, reason, comment);