Hi Alen,
interestingly enough, our internal implementation is similar to your suggestion. Product offering has a list of prices (abstract) and subclassing then determines whether it's a charge or alteration (and further the subtype of charge and alteration). This implementation required an additional structure indicating that an alteration impacts a charge (i.e. a discount is applied to a charge). TMF620 ProductOfferingPriceRefOrValue solves this problem by returning candidate alterations directly under charges.
You probably noticed that ProductOfferingPriceRefOrValue structure (returned through GET Product Offering) is different from ProductOfferingPrice resource. ProductOfferingPrice doesn't include POPAlterations, but has a more generic structure ProductOfferingPriceRelationship. We used POPRelationship to return impacts between alterations and charges.
Below is an example of GET Offering response. There is a ProductOfferingPriceRefOrValue representing a monthly fee with 2 candidate POPAlterations (50% off and 66,67% off monthly fee). The 66,67% discount is present on the product offering which instructs the order/quote module to apply the discount in the price calculation step.
{
"id": "11716346003",
"href": "http://plm-ws-multi-dev-env.k8s-svc.marand.si/plm-tmf620-marand-plmstage-sb3/tmf-ws/tmf-api/productCatalogManagement/v4/productOffering/11716346003",
"@type": "MarandProductOffering",
"productOfferingPrice": [
{
"id": "11716350001-70",
"href": "http://plm-ws-multi-dev-env.k8s-svc.marand.si/plm-tmf620-marand-plmstage-sb3/tmf-ws/tmf-api/productCatalogManagement/v4/productOfferingPrice/11716350001-70?version=11716351001&productOfferingId=11716346003",
"lastUpdate": "2023-02-16T09:44:00.711+01:00",
"lifecycleStatus": "Active",
"name": "NAROČNINA za Testna ponudba GAL-794-1",
"priceType": "RecurringCharge",
"recurringChargePeriod": "month",
"recurringChargePeriodLength": 1,
"version": "11716351001",
"constraint": [
{
"id": "70",
"name": "(TNAR) Naročnina"
}
],
"price": {
"taxCategory": "DDV",
"taxRate": 22,
"dutyFreeAmount": {
"unit": "EUR",
"value": 19.95
},
"@type": "MarandProductPriceValue",
"isRegulated": false,
"isDiscountable": false
},
"priceAlteration": [
{
"id": "11716350002-315450001",
"href": "http://plm-ws-multi-dev-env.k8s-svc.marand.si/plm-tmf620-marand-plmstage-sb3/tmf-ws/tmf-api/productCatalogManagement/v4/productOfferingPrice/11716350002-315450001?version=11716350002",
"description": "Popust - na naročnino",
"name": "PONAVLJAJOČI SE POPUST za Testni popust za GAL-794-1",
"priceType": "RecurringDiscount",
"priority": 1117000,
"recurringChargePeriod": "month",
"price": {
"percentage": 50,
"@type": "ProductPriceValue"
},
"unitOfMeasure": {
"amount": 1
},
"validFor": {
"endDateTime": "3000-01-01T00:00:00+01:00",
"startDateTime": "2023-02-16T00:00:00+01:00"
}
},
{
"id": "11716350003-315450001",
"href": "http://plm-ws-multi-dev-env.k8s-svc.marand.si/plm-tmf620-marand-plmstage-sb3/tmf-ws/tmf-api/productCatalogManagement/v4/productOfferingPrice/11716350003-315450001?version=11716350003",
"description": "Ponavljajoči se popust - Testna ponudba GAL-794-3 (akcija)",
"name": "PONAVLJAJOČI SE POPUST za Testna ponudba GAL-794-3 (akcija)",
"priceType": "RecurringDiscount",
"priority": 1117100,
"recurringChargePeriod": "month",
"applicationDuration": {
"amount": 12,
"units": "month"
},
"price": {
"percentage": 66.67,
"@type": "ProductPriceValue"
},
"unitOfMeasure": {
"amount": 1
},
"validFor": {
"endDateTime": "3000-01-01T00:00:00+01:00",
"startDateTime": "2023-02-16T00:00:00+01:00"
}
}
],
"unitOfMeasure": {
"amount": 1,
"units": "month"
},
"validFor": {
"endDateTime": "3000-01-01T00:00:00+01:00",
"startDateTime": "2023-02-16T00:00:00+01:00"
},
"@type": "MarandProductOfferingPriceRefOrValue",
"isParametricPrice": false,
"isPriceAlteration": false,
"isGrossAmount": false
},
{
"id": "11716350003-315450001",
"href": "http://plm-ws-multi-dev-env.k8s-svc.marand.si/plm-tmf620-marand-plmstage-sb3/tmf-ws/tmf-api/productCatalogManagement/v4/productOfferingPrice/11716350003-315450001?version=11716355002&productOfferingId=11716346003",
"lastUpdate": "2023-02-16T09:51:10.585+01:00",
"lifecycleStatus": "Active",
"name": "PONAVLJAJOČI SE POPUST za Testna ponudba GAL-794-3 (akcija)",
"priceType": "RecurringDiscount",
"version": "11716355002",
"constraint": [
{
"id": "315450001",
"name": "(1015) Ponavljajoči se popust"
}
],
"price": {
"percentage": 66.67,
"@type": "ProductPriceValue"
},
"priceAlteration": [],
"validFor": {
"endDateTime": "3000-01-01T00:00:00+01:00",
"startDateTime": "2023-02-16T00:00:00+01:00"
},
"@type": "MarandProductOfferingPriceRefOrValue",
"isParametricPrice": false,
"isPriceAlteration": true,
"isGrossAmount": false
}
]
}
If I obtain the product offering price resource representing the monthly subscription fee, I get the following response:
{
"id": "11716350001-70",
"href": "http://plm-ws-multi-dev-env.k8s-svc.marand.si/plm-tmf620-marand-plmstage-sb3/tmf-ws/tmf-api/productCatalogManagement/v4/productOfferingPrice/11716350001-70?version=11716351001&productOfferingId=11716346003",
"isBundle": false,
"lastUpdate": "2023-02-16T09:44:00.711+01:00",
"lifecycleStatus": "Active",
"name": "Naročnina - Testna ponudba GAL-794-1",
"priceType": "RecurringCharge",
"recurringChargePeriodLength": 1,
"recurringChargePeriodType": "month",
"version": "11716351001",
"constraint": [
{
"id": "70",
"name": "(TNAR) Naročnina"
}
],
"place": [],
"popRelationship": [
{
"id": "11716350002-1015",
"name": "Ponavljajoči se popust",
"relationshipType": "DISC",
"role": "PONAVLJAJOČI SE POPUST za Testni popust za GAL-794-1"
},
{
"id": "11716350003-1015",
"name": "Ponavljajoči se popust",
"relationshipType": "DISC",
"role": "PONAVLJAJOČI SE POPUST za Testna ponudba GAL-794-3 (akcija)"
}
],
"price": {
"unit": "EUR",
"value": 19.95
},
"pricingLogicAlgorithm": [],
"tax": [
{
"taxCategory": "ODS-3510",
"taxRate": 22
}
],
"unitOfMeasure": {
"amount": 1,
"units": "month"
},
"validFor": {
"endDateTime": "3000-01-01T00:00:00+01:00",
"startDateTime": "2023-02-16T00:00:00+01:00"
},
"@type": "MarandProductOfferingPrice",
"taxIncluded": false
}
As you can see, discounts (alterations) are returned as POPRelationships.
Never mind our extensions. :)
Hope this helps!
Bostjan
------------------------------
Bostjan Keber
Marand, software ltd
------------------------------
Original Message:
Sent: Mar 16, 2023 12:19
From: Alen Ruvic
Subject: TMF620 and productOfferingPriceRelationship
Hi,
Could the 620 swagger be simplified by removing POPAlteration (object) and POPCharge (object) entirely from it by adding priority (field) and applicationDuration (field) to ProductOfferingPriceRefOrValue (object) (and to ProductOfferingPrice) as the first step?
And subsequently replace and remove entire ProductOfferingPriceRefOrValue (object) with ProductOfferingPriceRef?
ProductOfferingPriceRefOrValue and ProductOfferingPrice both have priceType which can indicate subclasses of POPAlteration and POPCharge, isn't it?
Br,
------------------------------
Alen Ruvic
SES Astra S.A.
Original Message:
Sent: Feb 18, 2022 02:47
From: Bostjan Keber
Subject: TMF620 and productOfferingPriceRelationship
Hi Matthieu,
like you said, POP alteration is just another form of POP. POP can be subclassed into charges and alterations (1st level) and then charges can be further subclassed into onetime, recurring,..., and alterations can be subclassed into discounts (monetary & percentage) and allowances (2nd level). I believe the POP.priceType attribute is used for this distinction (see: TMF620, p.45: A category that describes the price, such as recurring, discount, allowance, penalty, and so forth.).
In our TMF620 implementation, the ProductOffering resource returns charges as POPs and alterations as POPAlterations (under POPs). This allows you to define exactly what allowance is applicable to what price and in what order. We use POPAlteration.Priority attribute to set the order of alterations.
The ProductOfferingPrice resource returns both, charges and alterations, as POPs. POPRelationship is used to associate charges with alterations. The API specification doesn't support alteration order/precedence in this case.
------------------------------
Bostjan Keber
Marand Software
Original Message:
Sent: Feb 16, 2022 16:05
From: Matthieu Hattab
Subject: TMF620 and productOfferingPriceRelationship
Hello Bostjan,
You made me realize that, in my first post, it was a coincidence that I use "price alterations". I didn't mean POPalteration.
I see in the SID that a POP alteration is just another form of POP and there are a handful alterations sub-classes:
I'd like to see how POPalterations are modelled in the ProductOfferingPrice resource model
Mabye POPalterations are "divided" into different ProductOfferingPrice sub-resources, such as:
- TaxItem = Tax alteration
- productOfferingPriceRelationship = discount alteration or replacement alteration
(hint: API doc, page 44 says "for example a price alteration such as allowance or discount.")
Which leaves:
bundledProductOfferingPriceRelationship = to be used to show component POP (where ProductOfferingPrice represents the composite POP)
It's not very clear, because SID also says:
A component may represent:
1. the amount charged (ProdOfferPriceCharge) such as a monthly internet connection fee.
2. Or, a component may represent an alteration (ProdOfferPriceAlteration)