Details
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/api/user/DefaultCatalogUserApi.java b/catalog/src/main/java/org/killbill/billing/catalog/api/user/DefaultCatalogUserApi.java
index 3bafe9c..55b244c 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/api/user/DefaultCatalogUserApi.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/api/user/DefaultCatalogUserApi.java
@@ -98,6 +98,24 @@ public class DefaultCatalogUserApi implements CatalogUserApi {
}
}
+
+ @Override
+ public void createDefaultEmptyCatalog(final DateTime effectiveDate, final CallContext callContext) throws CatalogApiException {
+
+ try {
+ final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContextWithoutAccountRecordId(callContext);
+ final StandaloneCatalog currentCatalog = getCurrentStandaloneCatalogForTenant(internalTenantContext);
+ final CatalogUpdater catalogUpdater = (currentCatalog != null) ?
+ new CatalogUpdater(currentCatalog) :
+ new CatalogUpdater("dummy", BillingMode.IN_ADVANCE, effectiveDate, null);
+
+ catalogCache.clearCatalog(internalTenantContext);
+ tenantApi.updateTenantKeyValue(TenantKey.CATALOG.toString(), catalogUpdater.getCatalogXML(), callContext);
+ } catch (TenantApiException e) {
+ throw new CatalogApiException(e);
+ }
+ }
+
@Override
public void addSimplePlan(final SimplePlanDescriptor descriptor, final DateTime effectiveDate, final CallContext callContext) throws CatalogApiException {
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/CatalogUpdater.java b/catalog/src/main/java/org/killbill/billing/catalog/CatalogUpdater.java
index 8afdfa1..1c3f024 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/CatalogUpdater.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/CatalogUpdater.java
@@ -51,6 +51,7 @@ import com.google.common.collect.Iterables;
public class CatalogUpdater {
private static URI DUMMY_URI;
+
static {
try {
DUMMY_URI = new URI("dummy");
@@ -58,8 +59,6 @@ public class CatalogUpdater {
}
};
- private static final DefaultPriceList DEFAULT_PRICELIST = new DefaultPriceList().setName(PriceListSet.DEFAULT_PRICELIST_NAME);
-
private final DefaultMutableStaticCatalog catalog;
public CatalogUpdater(final StandaloneCatalog standaloneCatalog) {
@@ -67,15 +66,19 @@ public class CatalogUpdater {
}
public CatalogUpdater(final String catalogName, final BillingMode billingMode, final DateTime effectiveDate, final Currency... currencies) {
+
+ final DefaultPriceList defaultPriceList = new DefaultPriceList().setName(PriceListSet.DEFAULT_PRICELIST_NAME);
final StandaloneCatalog tmp = new StandaloneCatalog()
.setCatalogName(catalogName)
.setEffectiveDate(effectiveDate.toDate())
- .setSupportedCurrencies(currencies)
.setRecurringBillingMode(billingMode)
.setProducts(new DefaultProduct[0])
.setPlans(new DefaultPlan[0])
- .setPriceLists(new DefaultPriceListSet(DEFAULT_PRICELIST, new DefaultPriceList[0]))
- .setPlanRules(getSaneDefaultPlanRules());
+ .setPriceLists(new DefaultPriceListSet(defaultPriceList, new DefaultPriceList[0]))
+ .setPlanRules(getSaneDefaultPlanRules(defaultPriceList));
+ if (currencies != null && currencies.length > 0) {
+ tmp.setSupportedCurrencies(currencies);
+ }
tmp.initialize(tmp, DUMMY_URI);
this.catalog = new DefaultMutableStaticCatalog(tmp);
@@ -93,6 +96,7 @@ public class CatalogUpdater {
}
}
+
public void addSimplePlanDescriptor(final SimplePlanDescriptor desc) throws CatalogApiException {
// We need at least a planId
@@ -120,7 +124,7 @@ public class CatalogUpdater {
plan = new DefaultPlan();
plan.setName(desc.getPlanId());
- plan.setPriceListName(DEFAULT_PRICELIST.getName());
+ plan.setPriceListName(PriceListSet.DEFAULT_PRICELIST_NAME);
plan.setProduct(product);
if (desc.getTrialLength() > 0 && desc.getTrialTimeUnit() != TimeUnit.UNLIMITED) {
@@ -142,11 +146,10 @@ public class CatalogUpdater {
catalog.addCurrency(desc.getCurrency());
// Reset the fixed price to null so the isZero() logic goes through new currencies and set the zero price for all
if (plan.getInitialPhases().length == 1) {
- ((DefaultInternationalPrice)plan.getInitialPhases()[0].getFixed().getPrice()).setPrices(null);
+ ((DefaultInternationalPrice) plan.getInitialPhases()[0].getFixed().getPrice()).setPrices(null);
}
}
-
DefaultPlanPhase evergreenPhase = plan.getFinalPhase();
if (evergreenPhase == null) {
evergreenPhase = new DefaultPlanPhase();
@@ -200,7 +203,7 @@ public class CatalogUpdater {
if ((isDescConfiguredWithTrial && !isPlanConfiguredWithTrial) ||
(!isDescConfiguredWithTrial && isPlanConfiguredWithTrial)) {
failedValidation = true;
- // Both have trials , check they match
+ // Both have trials , check they match
} else if (isDescConfiguredWithTrial && isPlanConfiguredWithTrial) {
if (plan.getInitialPhases()[0].getDuration().getUnit() != desc.getTrialTimeUnit() ||
plan.getInitialPhases()[0].getDuration().getNumber() != desc.getTrialLength()) {
@@ -227,19 +230,17 @@ public class CatalogUpdater {
if (currentAmount.compareTo(desc.getAmount()) != 0) {
failedValidation = true;
}
- } catch (CatalogApiException ignoreIfCurrencyIsCurrentlyUndefined) {}
+ } catch (CatalogApiException ignoreIfCurrencyIsCurrentlyUndefined) {
+ }
}
}
}
-
if (failedValidation) {
throw new CatalogApiException(ErrorCode.CAT_FAILED_SIMPLE_PLAN_VALIDATION, plan.toString(), desc.toString());
}
}
-
-
private boolean isCurrencySupported(final Currency targetCurrency) {
return Iterables.any(ImmutableList.copyOf(catalog.getCurrentSupportedCurrencies()), new Predicate<Currency>() {
@Override
@@ -287,7 +288,7 @@ public class CatalogUpdater {
}).orNull();
}
- private DefaultPlanRules getSaneDefaultPlanRules() {
+ private DefaultPlanRules getSaneDefaultPlanRules(final DefaultPriceList defaultPriceList) {
final DefaultCaseChangePlanPolicy[] changePolicy = new DefaultCaseChangePlanPolicy[1];
changePolicy[0] = new DefaultCaseChangePlanPolicy();
@@ -311,7 +312,7 @@ public class CatalogUpdater {
final DefaultCasePriceList[] priceList = new DefaultCasePriceList[1];
priceList[0] = new DefaultCasePriceList();
- priceList[0].setToPriceList(DEFAULT_PRICELIST);
+ priceList[0].setToPriceList(defaultPriceList);
return new DefaultPlanRules()
.setChangeCase(changePolicy)
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceList.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceList.java
index 7d7903d..f912ecd 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceList.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPriceList.java
@@ -40,9 +40,9 @@ public class DefaultPriceList extends ValidatingConfig<StandaloneCatalog> implem
@XmlID
private String name;
- @XmlElementWrapper(name = "plans", required = true)
+ @XmlElementWrapper(name = "plans", required = false)
@XmlIDREF
- @XmlElement(name = "plan", required = true)
+ @XmlElement(name = "plan", required = false)
private DefaultPlan[] plans;
public DefaultPriceList() {
@@ -82,13 +82,15 @@ public class DefaultPriceList extends ValidatingConfig<StandaloneCatalog> implem
@Override
public ValidationErrors validate(final StandaloneCatalog catalog, final ValidationErrors errors) {
- for (final DefaultPlan cur : getPlans()) {
- final int numPlans = findNumberOfPlans(cur.getProduct(), cur.getRecurringBillingPeriod());
- if (numPlans > 1) {
- errors.add(new ValidationError(
- String.format("There are %d plans in pricelist %s and have the same product/billingPeriod (%s, %s)",
- numPlans, getName(), cur.getProduct().getName(), cur.getRecurringBillingPeriod()), catalog.getCatalogURI(),
- DefaultPriceListSet.class, getName()));
+ if (getPlans() != null) {
+ for (final DefaultPlan cur : getPlans()) {
+ final int numPlans = findNumberOfPlans(cur.getProduct(), cur.getRecurringBillingPeriod());
+ if (numPlans > 1) {
+ errors.add(new ValidationError(
+ String.format("There are %d plans in pricelist %s and have the same product/billingPeriod (%s, %s)",
+ numPlans, getName(), cur.getProduct().getName(), cur.getRecurringBillingPeriod()), catalog.getCatalogURI(),
+ DefaultPriceListSet.class, getName()));
+ }
}
}
return errors;
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 9d2fb75..fe0c663 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
@@ -66,23 +66,23 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
@XmlElement(required = true)
private BillingMode recurringBillingMode;
- @XmlElementWrapper(name = "currencies", required = true)
- @XmlElement(name = "currency", required = true)
+ @XmlElementWrapper(name = "currencies", required = false)
+ @XmlElement(name = "currency", required = false)
private Currency[] supportedCurrencies;
@XmlElementWrapper(name = "units", required = false)
@XmlElement(name = "unit", required = false)
private DefaultUnit[] units;
- @XmlElementWrapper(name = "products", required = true)
- @XmlElement(name = "product", required = true)
+ @XmlElementWrapper(name = "products", required = false)
+ @XmlElement(name = "product", required = false)
private DefaultProduct[] products;
@XmlElement(name = "rules", required = true)
private DefaultPlanRules planRules;
- @XmlElementWrapper(name = "plans", required = true)
- @XmlElement(name = "plan", required = true)
+ @XmlElementWrapper(name = "plans", required = false)
+ @XmlElement(name = "plan", required = false)
private DefaultPlan[] plans;
@XmlElement(name = "priceLists", required = true)
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/TestCatalogUpdater.java b/catalog/src/test/java/org/killbill/billing/catalog/TestCatalogUpdater.java
index 3bc6a66..c101cd0 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/TestCatalogUpdater.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/TestCatalogUpdater.java
@@ -20,6 +20,7 @@ package org.killbill.billing.catalog;
import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.net.URI;
+import java.net.URISyntaxException;
import java.nio.charset.Charset;
import org.joda.time.DateTime;
@@ -51,6 +52,18 @@ import static org.testng.Assert.fail;
public class TestCatalogUpdater extends CatalogTestSuiteNoDB {
@Test(groups = "fast")
+ public void testEmptyDefaultCatalog() throws Exception {
+
+ final DateTime now = clock.getUTCNow();
+
+ final CatalogUpdater catalogUpdater = new CatalogUpdater("dummy", BillingMode.IN_ADVANCE, now, null);
+ final String catalogXML = catalogUpdater.getCatalogXML();
+ final StandaloneCatalog catalog = XMLLoader.getObjectFromStream(new URI("dummy"), new ByteArrayInputStream(catalogXML.getBytes(Charset.forName("UTF-8"))), StandaloneCatalog.class);
+ assertEquals(catalog.getCurrentPlans().length, 0);
+ }
+
+
+ @Test(groups = "fast")
public void testAddNoTrialPlanOnFirstCatalog() throws CatalogApiException {
final DateTime now = clock.getUTCNow();
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
index 0c833c8..bfe6b8f 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
@@ -105,6 +105,8 @@ public interface JaxrsResource {
public static final String QUERY_PAYMENT_METHOD_ID = "paymentMethodId";
public static final String QUERY_PAYMENT_CONTROL_PLUGIN_NAME = "controlPluginName";
+ public static final String QUERY_TENANT_USE_GLOBAL_DEFAULT = "useGlobalDefault";
+
public static final String QUERY_TAGS = "tagList";
public static final String QUERY_CUSTOM_FIELDS = "customFieldList";
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java
index fb17eaf..baeb070 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java
@@ -23,6 +23,7 @@ import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
@@ -36,6 +37,8 @@ import javax.ws.rs.core.UriInfo;
import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.AccountUserApi;
+import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.catalog.api.CatalogUserApi;
import org.killbill.billing.jaxrs.json.TenantJson;
import org.killbill.billing.jaxrs.json.TenantKeyJson;
import org.killbill.billing.jaxrs.util.Context;
@@ -70,6 +73,7 @@ import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
public class TenantResource extends JaxRsResourceBase {
private final TenantUserApi tenantApi;
+ private final CatalogUserApi catalogUserApi;
@Inject
public TenantResource(final TenantUserApi tenantApi,
@@ -79,10 +83,12 @@ public class TenantResource extends JaxRsResourceBase {
final AuditUserApi auditUserApi,
final AccountUserApi accountUserApi,
final PaymentApi paymentApi,
+ final CatalogUserApi catalogUserApi,
final Clock clock,
final Context context) {
super(uriBuilder, tagUserApi, customFieldUserApi, auditUserApi, accountUserApi, paymentApi, null, clock, context);
this.tenantApi = tenantApi;
+ this.catalogUserApi = catalogUserApi;
}
@TimedResource
@@ -114,17 +120,22 @@ public class TenantResource extends JaxRsResourceBase {
@ApiOperation(value = "Create a tenant")
@ApiResponses(value = {@ApiResponse(code = 500, message = "Tenant already exists")})
public Response createTenant(final TenantJson json,
+ @QueryParam(QUERY_TENANT_USE_GLOBAL_DEFAULT) @DefaultValue("true") final Boolean useGlobalDefault,
@HeaderParam(HDR_CREATED_BY) final String createdBy,
@HeaderParam(HDR_REASON) final String reason,
@HeaderParam(HDR_COMMENT) final String comment,
@javax.ws.rs.core.Context final HttpServletRequest request,
- @javax.ws.rs.core.Context final UriInfo uriInfo) throws TenantApiException {
+ @javax.ws.rs.core.Context final UriInfo uriInfo) throws TenantApiException, CatalogApiException {
verifyNonNullOrEmpty(json, "TenantJson body should be specified");
verifyNonNullOrEmpty(json.getApiKey(), "TenantJson apiKey needs to be set",
json.getApiSecret(), "TenantJson apiSecret needs to be set");
final TenantData data = json.toTenantData();
final Tenant tenant = tenantApi.createTenant(data, context.createContext(createdBy, reason, comment, request));
+ if (!useGlobalDefault) {
+ final CallContext callContext = context.createContext(createdBy, reason, comment, request);
+ catalogUserApi.createDefaultEmptyCatalog(clock.getUTCNow(),callContext);
+ }
return uriBuilder.buildResponse(uriInfo, TenantResource.class, "getTenant", tenant.getId());
}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
index ffb96bd..8949aba 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
@@ -23,6 +23,7 @@ import java.sql.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.UUID;
import org.joda.time.DateTime;
import org.killbill.billing.catalog.api.BillingPeriod;
@@ -30,12 +31,14 @@ import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.catalog.api.TimeUnit;
import org.killbill.billing.client.KillBillClientException;
+import org.killbill.billing.client.RequestOptions;
import org.killbill.billing.client.model.Catalog;
import org.killbill.billing.client.model.Catalogs;
import org.killbill.billing.client.model.Plan;
import org.killbill.billing.client.model.PlanDetail;
import org.killbill.billing.client.model.Product;
import org.killbill.billing.client.model.SimplePlan;
+import org.killbill.billing.client.model.Tenant;
import org.killbill.billing.client.model.Usage;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -45,7 +48,9 @@ import com.google.common.io.Resources;
public class TestCatalog extends TestJaxrsBase {
- @Test(groups = "slow", description = "Upload and retrieve a per tenant catalog")
+
+
+ @Test(groups = "slow", description = "Upload and retrieve a per tenant catalog")
public void testMultiTenantCatalog() throws Exception {
final String catalogPath = Resources.getResource("SpyCarBasic.xml").getPath();
killBillClient.uploadXMLCatalog(catalogPath, createdBy, reason, comment);
@@ -141,4 +146,41 @@ public class TestCatalog extends TestJaxrsBase {
Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getPlans().size(), 2);
}
+
+ @Test(groups = "slow", description = "Upload and retrieve a per plugin payment state machine config")
+ public void testAddSimplePlanWithoutKBDefault() throws Exception {
+ // Create another tenant initialized with no default catalog,...
+ final Tenant otherTenantNoKBDefault = new Tenant();
+ otherTenantNoKBDefault.setApiKey(UUID.randomUUID().toString());
+ otherTenantNoKBDefault.setApiSecret(UUID.randomUUID().toString());
+
+ killBillClient.createTenant(otherTenantNoKBDefault, false, requestOptions);
+
+ final RequestOptions requestOptionsOtherTenant = requestOptions.extend()
+ .withTenantApiKey(otherTenantNoKBDefault.getApiKey())
+ .withTenantApiSecret(otherTenantNoKBDefault.getApiSecret())
+ .build();
+
+ killBillClient.addSimplePan(new SimplePlan("foo-monthly", "Foo", ProductCategory.BASE, Currency.USD, BigDecimal.TEN, BillingPeriod.MONTHLY, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()), requestOptionsOtherTenant);
+ List<Catalog> catalogsJson = killBillClient.getJSONCatalog(requestOptionsOtherTenant);
+ Assert.assertEquals(catalogsJson.size(),1);
+ Assert.assertEquals(catalogsJson.get(0).getProducts().size(),1);
+ Assert.assertEquals(catalogsJson.get(0).getProducts().get(0).getName(),"Foo");
+ Assert.assertEquals(catalogsJson.get(0).getPriceLists().size(),1);
+ Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getName(), "DEFAULT");
+ Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getPlans().size(), 1);
+ Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getPlans().get(0), "foo-monthly");
+
+
+ killBillClient.addSimplePan(new SimplePlan("foo-annual", "Foo", ProductCategory.BASE, Currency.USD, new BigDecimal("100.00"), BillingPeriod.ANNUAL, 0, TimeUnit.UNLIMITED, ImmutableList.<String>of()), requestOptionsOtherTenant);
+
+ catalogsJson = killBillClient.getJSONCatalog(requestOptionsOtherTenant);
+ Assert.assertEquals(catalogsJson.size(),1);
+ Assert.assertEquals(catalogsJson.get(0).getProducts().size(),1);
+ Assert.assertEquals(catalogsJson.get(0).getProducts().get(0).getName(),"Foo");
+ Assert.assertEquals(catalogsJson.get(0).getPriceLists().size(),1);
+ Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getName(), "DEFAULT");
+ Assert.assertEquals(catalogsJson.get(0).getPriceLists().get(0).getPlans().size(), 2);
+ }
+
}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTenantKV.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTenantKV.java
index f2539d8..5232201 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTenantKV.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestTenantKV.java
@@ -72,7 +72,7 @@ public class TestTenantKV extends TestJaxrsBase {
final Tenant otherTenantWithDifferentStateMachine = new Tenant();
otherTenantWithDifferentStateMachine.setApiKey(UUID.randomUUID().toString());
otherTenantWithDifferentStateMachine.setApiSecret(UUID.randomUUID().toString());
- killBillClient.createTenant(otherTenantWithDifferentStateMachine, requestOptions);
+ killBillClient.createTenant(otherTenantWithDifferentStateMachine, true, requestOptions);
final RequestOptions requestOptionsOtherTenant = requestOptions.extend()
.withTenantApiKey(otherTenantWithDifferentStateMachine.getApiKey())
.withTenantApiSecret(otherTenantWithDifferentStateMachine.getApiSecret())