Price integration

Prices are either handles in Norce and then sent to the ERP or the other way around.

Update prices in Norce

For some client some prices are calculated in the ERP, in those cases it is often one standard price for each product, but can also be many other different price lists, like contract prices for specific customers (companies) or temporary campaigns.

These are imported using Norce Commerce Connect. The endpoints that can be used are:

  • ImportProducts ImportProducts allows for one price list to be added to the large contract of updating almost everything else on the product. This could be any price list, but only one is allowed.
  • ImportSkuPriceList ImportSkuPriceList takes many pricelists and products at a time, use this if you have many prices that needs to be updated and more often than other product data.
  • ImportPriceList ImportPriceList updates metadata on the price list , not on the products. Use this to create or update new price lists. For example if you get new Contract price lists

Important information

Field Entity Description Usage
PartNo SkuPriceList Required, identifies the product that should be updated
PriceListCode / Code SkuPriceList / PriceList Required, identifies the pricelist
IsActive SkuPriceList Default is true, if you send in PriceSale it will forcely set to true
PriceCatalog SkuPriceList A alternative amount, to keep track of
PriceRecommended SkuPriceList An alternative amount to keep track of
PriceSale SkuPriceList If sent in, the price rule will automatically be set to "fixed price" and isactive will be set to true
QuantityBreak SkuPriceList Threshold value, determines minimum number of items required for getting this price, you can have many prices therefore on same product and price list, if they have different quantitybreak
Name PriceList Name of the price list
CurrencyCode PriceList the currency of the price list (The data model allows for different currency on each price record, but this functionality is deprecated. All prices should be in same currency as is defined on its price list, if you find discrepances this is an error that should be reported)
StartDate PriceList Optional start date
EndDate PriceList Optiona end date
IsPublic PriceList a flag that decides if the pricelist is public on the application (the application specifified in the http header), which means that it will be automatically applied on the application.
(Warehouse)Code Warehouse Pricelists should have at least one warehouse and location, decides which warehouses that should be part of the availability aggregations in Norce
(Location)Code WarehouseLocation Pricelists should have at least one warehouse and location, decides which warehouses that should be part of the availability aggregations in Norce
Example calling ImportSkuPriceList in Norce Commerce Connect

https://connect.lab.storm.io/4.0//api/Product/ImportSkuPriceLists

  1. Simple import with fixed prices only
HeaderBody
Copy
Copied
{
    "AccountId": 0,
    "FullFile": false,
    "SerializationType": 0,
    "_SkuPriceListFieldsThatAreSet_Explanation": "PriceSale",
    "SkuPriceListFieldsThatAreSet": [3]
}
Copy
Copied
[
    {
        "_comment": "import fixed price ",
        "PartNo": "266639",
        "PriceListCode": "pl_campaign_mm",
        "PriceSale": 100,
        "QuantityBreak": 1
    },
    {
        "_comment": "import fixed price, w qty break",
        "PartNo": "266639",
        "PriceListCode": "pl_campaign_mm",
        "PriceSale": 90,
        "QuantityBreak": 10
    }
]
  1. Import with other price fields, except SalePrice The price record is not activated by the integration, require population rule and price rules on the price list. Some fields will be ignored if they are null, while some others will update the price record with null.
HeaderBody
Copy
Copied
{
    "AccountId": 0,
    "FullFile": false,
    "_IgnoreSkuPriceListFieldsWhenEmpty_Explanation": "CostPurchase, PriceRecommended",
    "IgnoreSkuPriceListFieldsWhenEmpty": [4, 6],
    "SerializationType": 0,
    "_SkuPriceListFieldsThatAreSet_Explanation": "CostUnit, PriceRecommended, IsActive",
    "SkuPriceListFieldsThatAreSet": [5, 6, 10]
}
Copy
Copied
[
    {
        "_comment": "Price recommended and cost will be updated, overwrite values that already exist",
        "CostUnit": 2000,
        "CurrencyCode": "SEK",
        "IsActive": 1,
        "PartNo": "ERPPartNo0000004-1",
        "PriceListCode": "STD",
        "PriceRecommended": 4999,
        "QuantityBreak": 1
    },
    {
         "_comment": "Price recommended will be updated, costs will be ignored since they are null",
        "CostUnit": null,
        "CurrencyCode": "SEK",
        "IsActive": 1,
        "PartNo": "ERPPartNo0000004-2",
        "PriceListCode": "STD",
        "PriceRecommended": 5999,
        "QuantityBreak": 1
    }
]

Company price lists

To set company or customer price lists you need to do three things

  1. Create the price list
  2. Update the price list with SkuPriceList items
  3. Add the price list to the customer or company
Example calling ImportPriceList in Norce Commerce Connect
  1. Create a price list

https://connect.lab.storm.io/4.0//api/Product/ImportPriceLists

HeaderBody
Copy
Copied
{
    "AccountId": 0,
    "FullFile": false,
    "_PriceListFieldsThatAreSet_Explanation": "Name, CurrencyCode, StartDate, EndDate, IsPublic, Warehouses, Description",
    "PriceListFieldsThatAreSet": [0, 1, 2, 3, 4, 7, 9],
    "SerializationType": 0,
    "_WarehouseFieldsThatAreSet_Explanation": "No values, only code is used.",
    "WarehouseFieldsThatAreSet": [],
    "_WarehouseLocationFieldsThatAreSet_Explanation": "No values, only code is used.",
    "WarehouseLocationFieldsThatAreSet": []
}
Copy
Copied
[
    {
    	"_comment": "Company price list, with fixed price rule Use recommended price Fixed price",
        "Code": "ContractYYY",
        "CurrencyCode": "SEK",
        "Description": "Price list from the ERP System with contract prices for Company XXX",
        "EndDate": "2025-10-01Z",
        "IsPublic": false,
        "Name": "Contract prices for customer XXX",
        "StartDate": "2023-04-01Z",
        "Warehouses": [
            {
            	"_comment": "A price list must have association to at least one warehouse.",
                "Code": "STD",
                "Locations": [
                    {
                        "Code": "STD"
                    }
                ]
            }
        ]
    }
]
  1. Update SkuPriceLists

Same as examples above

  1. Add the price list to the customer or company (showing Companies, since that is the most common scenario)

https://connect.lab.storm.io/4.0/api/Customer/ImportCompanies

HeaderBody
Copy
Copied
{
    "AccountId": 0,
    "FullFile": false,
    "_AccountFieldsThatAreSet_Explanation": "n/a",
    "AccountFieldsThatAreSet": [],
    "_CompanyFieldsThatAreSet_Explanation": "Code, PriceLists",
    "CompanyFieldsThatAreSet": [2, 19],
    "_CustomerFieldsThatAreSet_Explanation": "None",
    "CustomerFieldsThatAreSet": []
}
Copy
Copied
[
    {
        "Id": null,
        "Code": "XXX",
        "Name": "Company XXX",
        "PriceLists": [
            {
                "Code": "ContractYYY",
                "IsExclusive": false
            }
        ]
    }
]

Update prices in ERP

For many scenarios, prices are handled in Norce, and later passed on to other systems, like the ERP. In this case, the ERP can handle other related information like cost that Norce need to set up its rules, see cost (coming) for more. But the primary responsibility for the ERP integration is to listen for changes to the prices in Norce and pass those on to the ERP. This is done by listening to events and calling Norce Commerce Query for the relevant information.

For Norce [Storm] clients:

Important information

The most important fields and their purpose:

Field Entity Description
PartNo ProductSkuPricelist Identifies the product
PriceListId ProductSkuPricelist Identifies the price list (internal norce id, lookup id from code in separate lookup)
QtyBreak ProductSkuPricelist Threshold value, determines minimum number of items required for getting this price, you can have many prices therefore on same product and price list, if they have different quantitybreak
CurrencyId ProductSkuPricelist the currency of the price list (internal noce id, lookup id form code in separate lookup)
PriceSale ProductSkuPricelist calculated sale price, either a fixed value or calculated based on price rules
CostPurchase ProductSkuPricelist the cost of the item or service when purchased from supplier, see cost (coming) for more.
PriceStandard ProductSkuPricelist old price, inherited from parent, is null if no parent price list exist
PriceRecommended ProductSkuPricelist recommended price, MSRP. Can be inherited from parent or from supplier
ChosenSupplierId ProductSkuPricelist if exist, there is a preferred supplier that the pricing business rules uses, lookup the supplier code separatelt if you need.
ChosenSupplierPartNo ProductSkuPricelist the product identifier for the supplier, if you need to create a purchase request
ChosenSupplierPriceListId ProductSkuPricelist the supplier's price list id, lookup separately if needed
ChosenSupplierQtyBreak ProductSkuPricelist threshold value from the supplier pricelist (rarely used)
IsActive ProductSkuPricelist if false, the price is disabled and the product is disabled on the pricelist, note that a disabled price record is no longer updated from business rules in Norce.
An example fetching price information from Norce Commerce Query

https://query.lab.storm.io/2.0//Products/ProductSkuPriceLists?$filter=in ('MyPartNo1', 'MyPartNo2') and PriceListId eq 1 and IsActive eq true&$select=PartNo,PriceListId,QtyBreak,CurrencyId,PriceSale,CostPurchase,PriceStandard,PriceRecommended,ChosenSupplierId,ChosenSupplierPartNo,ChosenSupplierPriceListId,ChosenSupplierQtyBreak

Copy
Copied
{
    "@odata.context": "https://query.lab.storm.io/Query/2.0/Products/$metadata#ProductSkuPriceLists(PartNo,PriceListId,QtyBreak,CurrencyId,PriceSale,CostPurchase,PriceStandard,PriceRecommended,ChosenSupplierId,ChosenSupplierPartNo,ChosenSupplierPriceListId,ChosenSupplierQtyBreak)",
    "value": [
        {
            "PartNo": "MyPartNo1",
            "PriceListId": 1,
            "QtyBreak": 1,
            "CurrencyId": 2,
            "PriceSale": 6375.2000,
            "CostPurchase": 5734.3440,
            "PriceStandard": 0.0000,
            "PriceRecommended": null,
            "ChosenSupplierId": 1545,
            "ChosenSupplierPartNo": "MySupplierPartNo1",
            "ChosenSupplierPriceListId": 16810,
            "ChosenSupplierQtyBreak": 1
        },
        {
            "PartNo": "MyPartNo2",
            "PriceListId": 1,
            "QtyBreak": 1,
            "CurrencyId": 2,
            "PriceSale": 583.0645,
            "CostPurchase": 1087.5480,
            "PriceStandard": 0.0000,
            "PriceRecommended": null,
            "ChosenSupplierId": 1545,
            "ChosenSupplierPartNo": "MySupplierPartNo2",
            "ChosenSupplierPriceListId": 16810,
            "ChosenSupplierQtyBreak": 1
        }
    ]
}

Event settings

Add events that should be used

You can either listen to SkuChangedNotification or SkuPriceChangedNotification.

SkuPriceChangedNotification is easier to set up, but will only trigger if SalePrice has changed, other changes, like PriceRecommended or a Cost will not trigger the event.

SkuPriceListChangedNotification will return several fields in the event message that you can use:

  • PartNo
  • PricelistId
  • PricelistCode
  • PriceSaleValue
  • QuantityBreak

SkuPriceChangedNotification has insted only PartNo and EntityChanged, and you must lookup in Norce Commerce Query more information. Here is an example on what you need to configure:

Entity On Insert On Update On Delete Filter
tClientProductSkuPriceList Yes Yes (see important fields above) No Filter on relevant price lists that the ERP needs

Note that there is only one configured event per client and type, so if you already need SkuChangedNotification to other integrations, you need to add these settings to the same listener and merge your business logic.

Optional metadata

To get more information on entities referred only with an id in query, you need to to extra lookups. Make sure to lookup many at a time, instead of doing lookups for each product fetch. Put the response in your memory cache instead.

Price lists

If you need to access price list information there are two endpoint that is useful

  • ClientPriceList , has most information about the price list, start and end date, name, currency, etc.
  • ApplicationPricelist , has all the price lists that are specifically added to the application (ie all public price lists), an one important attrubute - IsPrimary, which is the most important price list on the application that has the holds the standard prices and assortments.
Field Entity Description
PriceListId ClientPriceList Identifies the price list (internal norce id, lookup id from code in separate lookup)
Name ClientPriceList Name of the price list in the default language
Agreement ClientPriceList Identifier of the Price list (Note, renamed to Code in all contracts)
CurrencyId ClientPriceList the currency of the price list (internal noce id, lookup id form code in separate lookup)
ParentPriceListId ClientPriceList point to the parent, if one exist
StartDate ClientPriceList Optional start date
EndDate ClientPriceList Optional end date
SalesAreaId ClientPriceList Price lists can be tag:ed with a sales area, this lets Norce calculate and round prices correctly for prices inc vat

Note, the entity PriceList has some of the same fields as ClientPriceList, they are mostly deprecated, use ClientPriceList!

An example fetching price list information from Norce Commerce Query

Fetching all price lists https://query.lab.storm.io/2.0/Application/ClientPriceLists?$select=PriceListId,Name,Agreement,CurrencyId,ParentPriceListId,StartDate,EndDate,SalesAreaId

Fetching the primary price list for the current application: https://query.lab.storm.io/2.0/Application/ApplicationPriceLists?$filter=IsPrimary eq true

Lookup currency https://query.lab.storm.io/2.0/Core/Currencies

Sales area, see here

Supplier information

Sometimes you want additional supplier information about the price from Norce.

Note, you can read more about suppliers here (coming) .

An example lookup up more on chosen supplier from Norce Commerce Query

https://query.lab.storm.io/2.0/Products/SupplierProductSkus?$filter=PartNo eq 'chosensupplierpartno' and SupplierId eq supplierid&$expand=PriceLists($expand=PriceList($select=Id,DefaultName,Code);$select=SupplierId,SupplierPriceListId,QtyBreak,CurrencyId,CostPurchase,CostPurchaseLastChecked;$filter=SupplierPriceListId eq 16810),OnHands($select=WarehouseId,LocationId,OnHandValue,OnHandLastChecked)&$select=PartNo,SupplierId,Name

Copy
Copied
{
    "@odata.context": "https://query.lab.storm.io/Query/2.0/Products/$metadata#SupplierProductSkus(PartNo,SupplierId,Name,PriceLists(SupplierId,SupplierPriceListId,QtyBreak,CurrencyId,CostPurchase,CostPurchaseLastChecked,PriceList(Id,DefaultName,Code)),OnHands(WarehouseId,LocationId,OnHandValue,OnHandLastChecked))",
    "value": [
        {
            "PartNo": "chosensupplierpartno",
            "SupplierId": chosensupplierid,
            "Name": "",
            "PriceLists": [
                {
                    "SupplierId": chosensupplierid,
                    "SupplierPriceListId": chosensupplierpricelistid,
                    "QtyBreak": 1,
                    "CurrencyId": 1,
                    "CostPurchase": 580.0000,
                    "CostPurchaseLastChecked": "2017-02-14T09:40:44.96+01:00",
                    "PriceList": {
                        "Id": 16810,
                        "DefaultName": "Premium Supplies Standard Pricelist",
                        "Code": "STD1"
                    }
                }
            ],
            "OnHands": [
                {
                    "WarehouseId": 811,
                    "LocationId": 811,
                    "OnHandValue": 100.000,
                    "OnHandLastChecked": "2017-02-14T09:40:44.96+01:00"
                }
            ]
        }
    ]
}

Further reading