TMForum API Version Support | Required Broadleaf Service(s) |
---|---|
v5 |
TMForum Resource | Description | Endpoints |
---|---|---|
|
|
|
|
|
|
|
|
|
Broadleaf supports TMF620 Product Catalog Management via an Extension Model on top of Broadleaf’s existing Catalog Microservice and Pricing Microservice. This extension model works by defining an extension library alongside Broadleaf’s default catalog and pricing services dependencies which will enable additional TMForum specific capabilities.
The core Broadleaf concept that underpins ProductOfferingPrice
is PriceData
.
In Broadleaf, every PriceData
record is associated with a PriceList
, which groups together PriceData
that need to share common characteristics such as currency.
Broadleaf supports an extended JSON property blcPriceListContextId
on the default ProductOfferingPrice
payload which can properly identify the Broadleaf Price List a certain price request is associated with.
Note that this field is optional and the system will default to a particular value specified in the API Context attributes if not in the request payload.
Broadleaf’s TMForum Extensions library provides several Spring utility components that are responsible for assisting in conversions between TMForum Concepts and Broadleaf Concepts. The following components can be extended to support a different mapping strategy if needed.
com.broadleafcommerce.tmforum.pricing.tmf620.service.mapping.ProductOfferingPriceIdProcessingUtility
ProductOfferingPrice.id
is derived from Broadleaf’s PriceData.id
, and this component is responsible for handling the conversion from both directions
com.broadleafcommerce.tmforum.pricing.tmf620.service.mapping.ProductOfferingPriceMappingUtility
The conversion logic between ProductOfferingPrice
and Broadleaf’s PriceData
is handled in multiple places. For 'read' operations, the mapping is handled by logic in JpaPriceDataProductOfferingPriceView
's ModelMapperMappable
implementation to go from the Broadleaf representation to the TMF representation. For modification operations like creates and updates, ProductOfferingPriceMappingUtility
is where the conversion from TMF representation to Broadleaf representation is defined.
Filtration and Sort
com.broadleafcommerce.tmforum.pricing.tmf620.web.attributefiltration.ProductOfferingPriceAttributeFiltersRequestResolver
Handles resolving the supported filtration parameters for requests against ProductOfferingPrice
com.broadleafcommerce.tmforum.pricing.tmf620.provider.jpa.filtering.JpaPriceDataProductOfferingPriceViewRsqlAndSortTransformer
Handles field transformations for filter and sort requests against ProductOfferingPrice
The following fields are supported for filtration/sort on ProductOfferingPrice
id
description
version
recurringChargePeriodType
recurringChargePeriodLength
name
priceType
lastUpdate
lifecycleStatus
validFor.startDateTime
validFor.endDateTime
unitOfMeasure.amount
unitOfMeasure.units
blcPriceListContextId
price.value
com.broadleafcommerce.tmforum.pricing.tmf620.service.validation.ProductOfferingPriceValidator
This component implements first-class validations on ProductOfferingPrice
request payloads to ensure API consumers cannot create an invalid state.
com.broadleafcommerce.tmforum.pricing.tmf620.service.DefaultProductOfferingPriceService
This is the top-level service component responsible for handling management of ProductOfferingPrice
. It orchestrates the main flow for CRUD operations, delegating specific responsibilities like validation and mapping to the other components as appropriate.
com.broadleafcommerce.tmforum.pricing.tmf620.service.apicontext.PricingCommonTMFApiContextKeys
shows which fields can be defaulted via API Context attributes out-of-box
com.broadleafcommerce.tmforum.pricing.tmf620.jackson.autoconfigure.TMForumPricingJacksonAutoConfiguration
Defines JacksonAnnotationMixinMapping
beans to drive behaviors related to attribute selection and polymorphic deserialization
com.broadleafcommerce.tmforum.pricing.tmf620.web.endpoint.AuxiliaryProductOfferingPriceEndpoint
Exposes some additional proprietary 'auxiliary' APIs - most notably, an endpoint used internally by the ProductOffering
mapping/hydration logic in CatalogServices to find the ProductOfferingPriceRef
instances related to a ProductOffering
ProductOfferingPrice
The TMForum ProductOfferingPrice
resource conceptually maps to Broadleaf’s PriceData
resource, the main difference being that Broadleaf aggregates ProductOfferingPrice
instances for different price types into a single PriceData
record.
In order to conform to the TMForum’s pagination, filtration, and sorting intent, Broadleaf employs a read-only database view (BLC_PRICE_DAT_PROD_OFFER_PRICE
) to expand a single PriceData
entry into multiple rows to achieve conformance with TMForum’s API.
The create/update/delete operations follow a tailored flow to preserve the external 'separate entity' abstraction.
Internally, the flow will make determinations about whether the operation needs to result in a net-new PriceData
record or if it should update an existing PriceData
record with the requested state.
For example, if a TMF request comes in to create a 'recurring' ProductOfferingPrice
for SKU ABC123
, and there is already a PriceData
for ABC123
that does not have a 'recurring' price, the system may update that existing PriceData
record instead of creating a net new one.
Below is a high level diagram describing the concept mapping strategies Broadleaf has employed to support this translation:
ProductOfferingPrice
The priceType
is the primary field on which a PriceData
is split into ProductOfferingPrice
.
The ProductOfferingPrice.id
is built from a combination of the PriceData.id
and a priceType
.
TMF requires that the priceType
value be PATCH
-able.
In Broadleaf, this creates a special case, since priceType
is used to identify a ProductOfferingPrice
in the first place.
Semantically, mutation of the priceType
is equivalent to 'deleting' the ProductOfferingPrice
of the existing type and then creating a new ProductOfferingPrice
for the requested type (potentially migrating the price for the existing type to the new type).
In the response, the new ProductOfferingPrice.id
will be returned so consumers can see the difference.
In Broadleaf, every PriceData
must have a non-null 'once' (upfront) price.
As a result, the system may automatically set this value to 0 in certain cases.
For example, if there is a request to create a ProductOfferingPrice
of type 'recurring', and it will result in a net new PriceData
, the system will automatically set PriceData.price
to 0.
This implicitly results in the creation of a ProductOfferingPrice
with type 'once'.
Since the API caller did not explicitly request this creation, the create, patch, and delete operations in DefaultProductOfferingPriceService
are flexible and will allow, for example, subsequent explicit create requests that attempt to overwrite this 0 value with something else.
While some fields on PriceData
are only used by a particular priceType
(ex: only the 'recurring' ProductOfferingPrice
will deal with the PriceData.recurringPeriodType
field), others like name
are shared by all ProductOfferingPrice
instances backed by the same PriceData
.
In the interest of remaining flexible instead of rejecting mutation attempts altogether, any update to such a 'shared' field will implicitly result in updating all ProductOfferingPrice
instances backed by the same PriceData
.
Note that blcPriceListContextId
is intentionally not honored as part of ProductOfferingPrice
update requests, as modification of this value would implicitly make a significant/fundamental change to all ProductOfferingPrice
instances backed by the same PriceData
.
The same is true for mutation attempts on PriceData.target
.
In TMF, ProductOfferingPrice
itself doesn’t have any fields that would specifically associate it to a ProductOffering
.
Technically, a ProductOfferingPrice
can be associated to 0 or more arbitrary offerings.
However, in Broadleaf, this is not the case: you can’t have a PriceData
without either a pricing key or a SKU - all PriceData
must be associated to exactly one 'thing'.
It could be that the 'thing' is a ProductOffering
, or it could be a selection in a product option.
Broadleaf requires that each ProductOfferingPrice
provides a ProductSpecificationCharacteristicValueUse
with name == SKU
or name == PRICING_KEY
with a string value corresponding to the reference.
Broadleaf has reversed the TMF behavior for how the relationship is managed.
Broadleaf doesn’t have any 'hard XREF' by ID between products and price data - it’s all decoupled soft-refs.
Thus, management of ProductOfferingPrice
from the ProductOffering.productOfferingPrice
field is not allowed - it will be a 'read only' field hydrated at fetch time with all the prices (in all price lists) that are referencing that product/variant.
An API caller may not remove/add entries from ProductOffering.productOfferingPrice
- instead, they must update the references in the price entities directly via the ProductOfferingPrice
API.
As they are updated (ex: pricing key is changed, sku changed, price data deleted as a whole, etc), the ProductOffering.productOfferingPrice
results themselves will naturally also reflect those additions/removals.
Note
|
An exception to the rule is that ProductOffering.productOfferingPrice will also contain values from Product.defaultPrice /Product.salePrice /etc.
These inline fields will not be 'refs' and instead be full inline ProductOfferingPrice values.
These can be managed from this field.
|
The core Broadleaf concept that underpins ProductSpecification
is BusinessType
(AKA 'Product Type').
Broadleaf’s TMForum Extensions library provides several Spring utility components that are responsible for assisting in conversions between TMForum Concepts and Broadleaf Concepts. The following components can be extended to support a different mapping strategy if needed.
com.broadleafcommerce.tmforum.catalog.tmf620.service.mapping.ProductSpecificationMappingUtility
The conversion logic between ProductSpecification
and Broadleaf’s BusinessType
is handled centrally here.
Note that this component also delegates to com.broadleafcommerce.tmforum.catalog.tmf620.service.mapping.CharacteristicValueSpecificationMappingHandler
beans to handle mapping of characteristics
Filtration and Sort
com.broadleafcommerce.tmforum.catalog.tmf620.web.attributefiltration.ProductSpecificationAttributeFiltersRequestResolver
Handles resolving the supported filtration parameters for requests against ProductSpecification
com.broadleafcommerce.tmforum.catalog.tmf620.service.filtering.ProductSpecificationBusinessTypeFilterAndSortTransformer
Handles field transformations for filter and sort requests against ProductSpecification
The following fields are supported for filtration/sort on ProductSpecification
id
description
lastUpdate
lifecycleStatus
version
name
blcTypeKey
com.broadleafcommerce.tmforum.catalog.tmf620.service.validation.ProductSpecificationValidator
This component implements first-class validations on ProductSpecification
request payloads to ensure API consumers cannot create an invalid state.
Delegates to com.broadleafcommerce.tmforum.catalog.tmf620.service.validation.characteristic.CharacteristicSpecificationValidationHelper
for validations on characteristics
com.broadleafcommerce.tmforum.catalog.tmf620.service.DefaultProductSpecificationService
This is the top-level service component responsible for handling management of ProductSpecification
. It orchestrates the main flow for CRUD operations, delegating specific responsibilities like validation and mapping to the other components as appropriate.
com.broadleafcommerce.tmforum.catalog.tmf620.service.hydration.ProductSpecificationMappingHydrationService
Responsible for collecting additional data/entities that are required for successfully mapping between ProductSpecification
and BLC BusinessType
com.broadleafcommerce.tmforum.catalog.tmf620.jackson.autoconfigure.TMForumCatalogJacksonAutoConfiguration
Defines JacksonAnnotationMixinMapping
beans to drive behaviors related to attribute selection and polymorphic deserialization
ProductSpecification
The TMForum ProductSpecification
resource conceptually maps to Broadleaf’s BusinessType
resource, with a fairly straightforward 1:1 mapping between the two.
The only meaningful difference is that in Broadleaf, Characteristic
entities are a top-level, independently managed resource, while in TMF they are anonymous inlined values.
This distinction typically doesn’t affect TMF API consumers, but it is important to keep in mind.
Below is a high level diagram describing the concept mapping strategies Broadleaf has employed to support this translation:
ProductSpecification
In Broadleaf, a product’s 'type' can either be a default type (one of the values in com.broadleafcommerce.catalog.domain.product.DefaultProductType
), or it can be a BusinessType
.
To represent the 'default' types, the system will manufacture a synthetic BusinessType
with a well-known ID (see com.broadleafcommerce.catalog.service.product.businessType.DefaultProductTypeBusinessTypeBuilder
), map it to a ProductSpecification
, and implicitly return them in GET /productSpecification/{id}
if requested.
This way, products that don’t explicitly inherit from a persisted BusinessType
can still be represented as referencing a particular ProductSpecification
, and its href
can actually be resolved by the API if needed.
The value for BusinessType.productType
can be automatically determined by the system or explicitly provided by the API caller
See ProductSpecificationValidator.validateProductSpecificationRelationshipsForCreate
and DefaultProductSpecificationRelationshipTypeValues.INHERITS_FROM
for more details on how to explicitly specify this value
See ProductSpecificationMappingUtility.determineDefaultProductType
for more details on how the system will automatically calculate this value
Because Characteristic
is a separate domain from BusinessType
in Broadleaf, CRUD operations on ProductSpecification
will also result in creation/deletion of Characteristic
instances to match the caller’s request.
Please review the Javadocs of ProductSpecificationValidator.validateCharacteristicsForCreate
and ProductSpecificationValidator.validateCharacteristicsForUpdate
for a thorough description of expected behavior
Please review DefaultProductSpecificationService.handleOrphanedCharacteristicsAfterFailedBusinessTypeCreate
and DefaultProductSpecificationService.handleOrphanedCharacteristicsAfterFailedBusinessTypeUpdate
for behavior engaged when Characteristic
persistence succeeds, but the persistence for the BusinessType
fails
The core Broadleaf concept that underpins ProductOffering
is Product
or Variant
(depending on the type of product).
Broadleaf’s TMForum Extensions library provides several Spring utility components that are responsible for assisting in conversions between TMForum Concepts and Broadleaf Concepts. The following components can be extended to support a different mapping strategy if needed.
com.broadleafcommerce.tmforum.catalog.tmf620.service.mapping.ProductOfferingMappingUtility
The conversion logic between ProductOffering
and Broadleaf’s Product
/Variant
is handled in multiple places.
For 'read' operations, the mapping is handled by logic in JpaProductOfferingView
's ModelMapperMappable
implementation to go from the JpaProductOfferingView
representation to a lightweight ProductOfferingViewDTO
representation.
Then, ProductOfferingMappingUtility
transforms the ProductOfferingViewDTO
into a ProductOffering
.
For modification operations like creates and updates, ProductOfferingMappingUtility
defines the conversion from TMF ProductOffering
to Broadleaf Product
/Variant
.
Note that this component also delegates to com.broadleafcommerce.tmforum.catalog.tmf620.service.mapping.CharacteristicValueSpecificationMappingHandler
beans to handle mapping of characteristics
com.broadleafcommerce.tmforum.catalog.tmf620.service.hydration.ProductOfferingMappingHydrationService
Responsible for collecting additional data/entities that are required for successfully mapping between ProductOffering
and BLC Product
/Variant
Filtration and Sort
com.broadleafcommerce.tmforum.catalog.tmf620.web.attributefiltration.ProductOfferingAttributeFiltersRequestResolver
Handles resolving the supported filtration parameters for requests against ProductOffering
com.broadleafcommerce.tmforum.catalog.tmf620.provider.jpa.filtering.JpaProductOfferingViewRsqlAndSortTransformer
Handles field transformations for filter and sort requests against ProductOffering
The following fields are supported for filtration/sort on ProductOffering
isBundle
statusReason
lifecycleStatus
lastUpdate
name
description
isSellable
id
version
validFor.startDateTime
validFor.endDateTime
blcProductOfferingSourceEntityType
com.broadleafcommerce.tmforum.catalog.tmf620.service.validation.ProductOfferingValidator
This component implements first-class validations on ProductOffering
request payloads to ensure API consumers cannot create an invalid state.
Delegates to com.broadleafcommerce.tmforum.catalog.tmf620.service.validation.characteristic.CharacteristicSpecificationValidationHelper
for validations on characteristics
com.broadleafcommerce.tmforum.catalog.tmf620.service.DefaultProductOfferingService
This is the top-level service component responsible for handling management of ProductOffering
. It orchestrates the main flow for CRUD operations, delegating specific responsibilities like validation and mapping to the other components as appropriate.
com.broadleafcommerce.tmforum.catalog.tmf620.jackson.autoconfigure.TMForumCatalogJacksonAutoConfiguration
Defines JacksonAnnotationMixinMapping
beans to drive behaviors related to attribute selection and polymorphic deserialization
com.broadleafcommerce.tmforum.catalog.tmf620.service.apicontext.CatalogCommonTMFApiContextKeys
shows which fields can be defaulted via API Context attributes out-of-box
com.broadleafcommerce.tmforum.catalog.tmf620.service.autoconfigure.ExternalPricingProviderProperties
Defines configuration properties under broadleaf.tmforum.catalog.pricingprovider.*
, which are relevant to configuring how CatalogServices will make a request to PricingServices to hydrate ProductOfferingPriceRefs
for each ProductOffering
com.broadleafcommerce.tmforum.catalog.tmf620.service.autoconfigure.ProductOfferingHydrationProperties
Defines configuration properties under broadleaf.tmforum.catalog.product-offering.hydration.*
, which are relevant to whether hydration of ProductOfferingPriceRefs
from PricingServices should occur when mapping ProductOffering
.
ProductOffering
The TMForum ProductOffering
resource conceptually maps to Broadleaf’s Product
and Variant
resources.
In order to conform to TMForum’s pagination, filtration, and sorting intent, Broadleaf employs a read-only database view (BLC_PRODUCT_OFFERING_VIEW
) to consolidate records from these different tables into one result set to achieve conformance with TMForum’s API.
The create/update/delete operations follow a tailored flow to preserve the external abstraction of a consolidated entity.
Internally, the flow will make determinations about whether the operation needs to target a Product
or Variant
and apply updates accordingly.
Below is a high level diagram describing the concept mapping strategies Broadleaf has employed to support this translation:
ProductOffering
Broadleaf’s Variant
concept is a nice feature to more easily reason about products and how they are surfaced.
However, in TMF, there is not enough information available to create Broadleaf’s Variant
directly.
Thus, while they can be fetched in 'read' operations and some updates are supported, a net new create of a Broadleaf Variant
is not possible from the TMF API.
In Broadleaf, a product’s 'product type' or BusinessType
is immutable after creation. This relationship is represented via the ProductOffering.productSpecification
field in TMF, and therefore attempts to change this after creation are not supported.
ProductOffering.productSpecification
must always have a value set during creates, as knowledge of what the Product.productType
should be is critical to ensure mapping is performed correctly.
As discussed in the Considerations for ProductSpecification documentation, this can be set to the ID of one of the 'synthetic' BusinessType
instances corresponding to a DefaultProductType
- it does not necessarily have to point to a separately persisted BusinessType
ID.
See ProductOfferingValidator.validateProductSpecificationRefForCreate
for more details on this validation.
Please see the Considerations for ProductOfferingPrice section for details on associations between ProductOfferingPrice
and ProductOffering
On ProductOffering
reads, the ProductOffering.prodSpecCharValueUse
field will only include the characteristics that have been explicitly assigned/overridden in Product.characteristics
.
If a characteristic from the parent BusinessType
is not explicitly present in Product.characteristics
, it will not be returned in the ProductOffering.prodSpecCharValueUse
field.
This follows TMF expectations where the caller is expected to get the parent ProductSpecification
to fetch all the non-overridden characteristics.
Please see ProductOfferingMappingUtility.transformProductCharsToProdSpecCharValUses
for more details
Certain fields from ProductOffering
are persisted in the attributes
column of JpaProduct
and JpaVariant
.
These are enumerated in com.broadleafcommerce.tmforum.catalog.tmf620.service.mapping.CommonProductOfferingSourceEntityAttributeKeys
.
There is logic in JpaProductOfferingViewRsqlAndSortTransformer
to support filtration against these values.
However, clients using Oracle will not be able to filter on these fields.
This is because on Oracle, the attributes
column for JpaProduct
/JpaVariant
exceeds the size threshold for VARCHAR
and has a datatype of CLOB
(which cannot be queried against).