Skip to main content

Price Plan Matrix

The PricePlanMatrix is the modern, versioned pricing structure in Opencell v12+. It replaces the older single PricePlan object with a multi-layered, versioned structure.

Structure Overview

PricePlanMatrix (parent container with filtering criteria)
└── PricePlanMatrixVersion (versioned, status: DRAFT/PUBLISHED/CLOSED)
├── validity: DatePeriod (when active)
├── isMatrix: boolean (single price vs matrix)
├── price: BigDecimal (if not matrix)
├── columns: Set<PricePlanMatrixColumn> (matrix dimensions)
└── lines: Set<PricePlanMatrixLine> (matrix rows)
├── priority: int (lower = higher)
├── ratingAccuracy: int (specificity score)
└── values: Set<PricePlanMatrixValue> (cell values)

PricePlanMatrix (Container)

The parent entity that links to ChargeTemplates and defines filtering criteria.

Key Fields:

FieldTypeDescription
codeStringUnique identifier
chargeTemplatesSetLinked ChargeTemplates (many-to-many)
sellerSellerFilter by seller
offerTemplateOfferTemplateFilter by offer
tradingCountryCountryFilter by country
tradingCurrencyCurrencyFilter by currency
criteria1-3StringCustom criteria (EL expressions)
minQuantityBigDecimalMinimum quantity for this plan
maxQuantityBigDecimalMaximum quantity for this plan
subscriptionDateRangeDatePeriodFilter by subscription date
ratingDateRangeDatePeriodFilter by rating date

Charge Template Linkage:

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "cat_price_plan_charge",
joinColumns = @JoinColumn(name = "price_plan_id"),
inverseJoinColumns = @JoinColumn(name = "charge_id"))
private Set<ChargeTemplate> chargeTemplates;

PricePlanMatrixVersion

Versioned pricing with lifecycle status.

Status Lifecycle:

DRAFT → PUBLISHED → CLOSED

Key Fields:

FieldTypeDescription
validityDatePeriodWhen this version is active
statusVersionStatusEnumDRAFT, PUBLISHED, CLOSED
isMatrixbooleanfalse = single price, true = matrix
priceBigDecimalPrice if not matrix
columnsSetMatrix dimensions (if matrix)
linesSetMatrix rows (if matrix)

PricePlanMatrixLine

Individual price lines within a matrix.

Key Fields:

FieldTypeDescription
priorityintLower = matched first
ratingAccuracyintSpecificity score (0 = default/fallback)
valuesSetColumn values for this line
priceBigDecimalPrice for this line
amountWithoutTaxELStringEL expression for dynamic pricing
amountWithTaxELStringEL expression for dynamic pricing
scriptInstanceScriptInstanceScript for complex pricing

ratingAccuracy Field

The ratingAccuracy indicates specificity (number of non-null column values):

  • ratingAccuracy=0: Default/fallback line (matches anything)
  • ratingAccuracy=1: Line with 1 specific column value
  • ratingAccuracy=3: Line with 3 specific column values (most specific)

Selection Priority:

  1. priority ASC (explicit priority)
  2. ratingAccuracy DESC (more specific lines preferred)
  3. id ASC (deterministic order)

PricePlanMatrixColumn

Defines dimensions for matrix pricing.

Column Types (ColumnTypeEnum):

TypeDescription
STRINGExact text match
LIST_TEXTMatch any in list
LIST_MULTIPLE_TEXTMatch all in list
EXPRESSION_LANGUAGEEL evaluation
LONGNumeric equality
LIST_NUMERICNumeric list match
DOUBLEDecimal with precision
Range_DateDate falls within from/to
Range_NumericValue falls within from/to
BooleanBoolean equality

Version Selection During Rating

The rating service selects the appropriate price through a 3-step process:

Step 1: Find PricePlanMatrix Container

SELECT ppm FROM PricePlanMatrix ppm
WHERE ppm.chargeTemplates CONTAINS :chargeTemplate
AND (ppm.seller IS NULL OR ppm.seller = :seller)
AND (ppm.offerTemplate IS NULL OR ppm.offerTemplate = :offer)
AND (ppm.tradingCountry IS NULL OR ppm.tradingCountry = :country)
AND (ppm.tradingCurrency IS NULL OR ppm.tradingCurrency = :currency)
AND (:quantity BETWEEN ppm.minQuantity AND ppm.maxQuantity)
ORDER BY ppm.priority ASC

Step 2: Select PUBLISHED Version

SELECT ppmv FROM PricePlanMatrixVersion ppmv
WHERE ppmv.pricePlanMatrix = :ppm
AND ppmv.status = 'PUBLISHED'
AND :operationDate BETWEEN ppmv.validity.from AND ppmv.validity.to

Step 3: Match Line (if matrix)

if (version.isMatrix()) {
// Load all lines ordered by priority ASC, ratingAccuracy DESC
List<PricePlanMatrixLine> lines = version.getLines()
.stream()
.sorted(Comparator.comparing(PricePlanMatrixLine::getPriority)
.thenComparing(PricePlanMatrixLine::getRatingAccuracy, Comparator.reverseOrder()))
.collect(Collectors.toList());

for (PricePlanMatrixLine line : lines) {
if (matchesAllColumns(line, ratingContext)) {
return line.getPrice();
}
}

// Fallback to default line (ratingAccuracy=0)
return findDefaultLine(lines).getPrice();
} else {
return version.getPrice();
}

Example Configurations

Simple Per-Unit Pricing

{
"pricePlanMatrix": {
"code": "API_CALL_PRICING",
"chargeTemplates": ["API_USAGE_CHARGE"],
"versions": [{
"status": "PUBLISHED",
"validity": { "from": "2024-01-01", "to": null },
"isMatrix": false,
"price": 0.10
}]
}
}

Tiered Pricing (OpenAI-style)

{
"pricePlanMatrix": {
"code": "TOKEN_TIERED_PRICING",
"chargeTemplates": ["TOKEN_USAGE_CHARGE"],
"versions": [{
"status": "PUBLISHED",
"validity": { "from": "2024-01-01", "to": null },
"isMatrix": true,
"columns": [{
"code": "QUANTITY_TIER",
"type": "Range_Numeric"
}],
"lines": [
{ "priority": 1, "ratingAccuracy": 1, "values": [{"from": 0, "to": 1000000}], "price": 0.002 },
{ "priority": 2, "ratingAccuracy": 1, "values": [{"from": 1000001, "to": 10000000}], "price": 0.0015 },
{ "priority": 3, "ratingAccuracy": 1, "values": [{"from": 10000001, "to": null}], "price": 0.001 }
]
}]
}
}

Multi-Dimensional Matrix

{
"pricePlanMatrix": {
"code": "ENTERPRISE_MATRIX",
"chargeTemplates": ["ENTERPRISE_CHARGE"],
"versions": [{
"status": "PUBLISHED",
"isMatrix": true,
"columns": [
{ "code": "REGION", "type": "STRING" },
{ "code": "CUSTOMER_TYPE", "type": "STRING" },
{ "code": "PRODUCT_TIER", "type": "STRING" }
],
"lines": [
{ "priority": 1, "ratingAccuracy": 3, "values": ["US", "Enterprise", "Pro"], "price": 500 },
{ "priority": 2, "ratingAccuracy": 2, "values": ["EU", "Government", null], "price": 450 },
{ "priority": 99, "ratingAccuracy": 0, "values": [null, null, null], "price": 600 }
]
}]
}
}