Division in Logic App Liquid

Posted: May 18, 2023  |  Categories: Azure
Tags: Liquid

I choose to write this blog about division in Logic App because I found it quite difficult to implement.

The problem

Implementing the following business rule was not easy for me.

If the UnitPrice is null then calculate the InnerPrice by dividing the CTNPrice by the multipler.

The source JSON fragment to be transformed looked like this

{
			"LineNum": "0",
			"ProductCode": "86048",
			"ProductDescription": "DIM SIMS VEGETARIAN",
			"ProductCodeRef": null,
			"PackSize": "12 X 80GR",
			"TaxRate": "0.000000",
			"CountryOfOriginCode": null,
			"InventoryGroup": "Freezer",
			"InventoryUOM": "BAG",
			"InventoryUOMDescription": "BAG",
			"InventoryUOMRef": null,
			"MinOrderUnitQty": "0",
			"AltProductCode": null,
			"PreferredProduct": "0",
			"Brand": "A&T",
			"BrandDescription": "A&T TRADING",
			"ProductLineCode": "B3656",
			"ProductLineDescription": "ASIAN ASSORTED",
			"ProductLineRef": null,
			"ProductSalesCategoryCode": "B2100",
			"ProductSalesCategoryDescription": "FINGER & SNACK FOODS",
			"ProductSalesCategoryRef": null,
			"UnitUOM": "BAG",
			"UnitUOMDescription": "BAG",
			"UnitUOMRef": null,
			"UnitPrice": null,
			"CtnUOM": "CTN",
			"CtnUOMDescription": "CARTON",
			"CtnUOMRef": null,
			"CtnPrice": "76.10",
			"AltUOM": null,
			"AlternateUOMDescription": null,
			"AlternateUOMRef": null,
			"PieceWeight": null,
			"AltPrice": null,
			"Multiplier": "10",
			"FixedPricePack": "False",
			"CustomerItemNumber": null,
			"WarehouseCode": "3030",
			"AccountCode": "338221",
			"QtyOnHand": "100.0",
			"AllowBackOrders": "False"
		},

My Liquid map was

{
  "BFAccountCode": "{{content.BID_STD_PRICE_.WDBHDR.Account}}",
  "AccountName": "{{content.BID_STD_PRICE_.WDBHDR.AccountName}}",
  "BFBranch": "{{content.BID_STD_PRICE_.WDBHDR.Branch}}",
  "BFBranchName": "{{content.BID_STD_PRICE_.WDBHDR.BranchName}}",
  "SiteID": {%- if content.BID_STD_PRICE_.WDBHDR.AccountRef != null -%}"{{content.BID_STD_PRICE_.WDBHDR.AccountRef}}",{%- else -%}null,{%- endif -%}
  "Lines": {
    "Line": [
	{%- for Line in content.BID_STD_PRICE_.WDBDTL -%} 
       {%- if forloop.last == true -%}
      {
        "ProductCode": {%- if Line.CustomerItemNumber != null -%}"{{Line.CustomerItemNumber}}",{%- else -%}null,{%- endif -%}
        "SupplierProductCode": {%- if Line.ProductCode != null -%}"{{Line.ProductCode}}",{%- else -%}null,{%- endif -%}
        "ProductSalesCategory": {%- if Line.ProductSalesCategoryDescription != null -%}"{{Line.ProductSalesCategoryDescription}}",{%- else -%}null,{%- endif -%}
        "Brand": {%- if Line.Brand != null -%}"{{Line.Brand}}",{%- else -%}null,{%- endif -%}
        "ProductDescription": {%- if Line.ProductDescription != null -%}"{{Line.ProductDescription}}",{%- else -%}null,{%- endif -%}
        "InnerPackSize": {%- if Line.PackSize != null -%}"{{Line.PackSize}}",{%- else -%}null,{%- endif -%}
        "InnerUOM": {%- if Line.InventoryUOM != null -%}"{{Line.InventoryUOM}}",{%- else -%}null,{%- endif -%}
        "InnerQtyOnHand": {%- if Line.QtyOnHand != null -%}"{{Line.QtyOnHand}}",{%- else -%}null,{%- endif -%}
        "InnerPrice": {%- if Line.UnitPrice != null -%}"{{Line.UnitPrice}}",{%- else -%}null,{%- endif -%}
        "OuterPackSize":{%- if Line.Multiplier != null -%}"{{Line.Multiplier}}",{%- else -%}null,{%- endif -%}
        "OuterUOM": {%- if Line.CtnUOM != null -%}"{{Line.CtnUOM}}",{%- else -%}null,{%- endif -%}
        "OuterPrice": {%- if Line.CtnPrice != null -%}"{{Line.CtnPrice}}",{%- else -%}null,{%- endif -%}        
        "BackOrder": {% if Line.AllowBackOrders == "True" %}true,{% elsif Line.AllowBackOrders == "False" %}false,{% else %}null,{% endif %}
        "TaxRate": {%- if Line.TaxRate != null -%}"{{Line.TaxRate}}"{%- else -%}null,{%- endif -%}
      }
    {%- else -%}
      {
        "ProductCode": {%- if Line.CustomerItemNumber != null -%}"{{Line.CustomerItemNumber}}",{%- else -%}null,{%- endif -%}
        "SupplierProductCode": {%- if Line.ProductCode != null -%}"{{Line.ProductCode}}",{%- else -%}null,{%- endif -%}
        "ProductSalesCategory": {%- if Line.ProductSalesCategoryDescription != null -%}"{{Line.ProductSalesCategoryDescription}}",{%- else -%}null,{%- endif -%}
        "Brand": {%- if Line.Brand != null -%}"{{Line.Brand}}",{%- else -%}null,{%- endif -%}
        "ProductDescription": {%- if Line.ProductDescription != null -%}"{{Line.ProductDescription}}",{%- else -%}null,{%- endif -%}
        "InnerPackSize": {%- if Line.PackSize != null -%}"{{Line.PackSize}}",{%- else -%}null,{%- endif -%}
        "InnerUOM": {%- if Line.InventoryUOM != null -%}"{{Line.InventoryUOM}}",{%- else -%}null,{%- endif -%}
        "InnerQtyOnHand": {%- if Line.QtyOnHand != null -%}"{{Line.QtyOnHand}}",{%- else -%}null,{%- endif -%}
        "InnerPrice": {%- if Line.UnitPrice != null -%}"{{Line.UnitPrice}}",{%- else -%}null,{%- endif -%}
        "OuterPackSize":{%- if Line.Multiplier != null -%}"{{Line.Multiplier}}",{%- else -%}null,{%- endif -%}
        "OuterUOM": {%- if Line.CtnUOM != null -%}"{{Line.CtnUOM}}",{%- else -%}null,{%- endif -%}
        "OuterPrice": {%- if Line.CtnPrice != null -%}"{{Line.CtnPrice}}",{%- else -%}null,{%- endif -%}
        {% assign BackOrder=false | boolean %}
        "BackOrder": {% if Line.AllowBackOrders == "True" %}true,{% elsif Line.AllowBackOrders == "False" %}false,{% else %}null,{% endif %}
        "TaxRate": {%- if Line.TaxRate != null -%}"{{Line.TaxRate}}"{%- else -%}null,{%- endif -%}
      },
   {%- endif -%}
{%- endfor -%}
]
  }
}

Adding division to the liquid template

My first try was

"InnerPrice": {%- if Line.UnitPrice != null -%}"{{Line.UnitPrice}}",{%- else -%}{{ Line.CtnPrice | divided_by: Line.Multiplier}},{%- endif -%}

This did not work because the template use Liquid filters, that follow the DotLiquid and C# naming conventions, which use sentence casing. For all Liquid transforms in Logic App, make sure that filter names in your template also use sentence casing. Otherwise, the filters won’t work. See Convert JSON and XML with Liquid templates – Azure Logic Apps | Microsoft Learn

Divided_by and Divided_By did not work either. Finally I found that DividedBy was the correct filter to use in Logic App liquid.

Unfortunately I now had the following error when testing with Kastenberg’s tool.

Liquid error: The binary operator Divide is not defined for the types 'System.String' and 'System.String'

This was because values are strings and not numbers. The trick is to use assign with a math filter.

        "InnerPrice": {%- if Line.UnitPrice != null -%}"{{Line.UnitPrice}}",{%- else -%}"{% assign CtnPrice = Line.CtnPrice | Times: 1.00 %}{% assign Multipler = Line.Multiplier | Times: 1.00 %}{{ CtnPrice | DividedBy: Multipler}}",{%- endif -%}
        "OuterPackSize":{%- if Line.Multiplier != null -%}"{{Line.Multiplier}}",{%- else -%}null,{%- endif -%}

Conclusion

In this short blog I have shown how to divide two number in a Logic App Liquid template. Further I have shown how to use assign to change the type from a string to a number.

Postscript 28/05/2023 Microsoft logic App Liquid treats nulls differently

Harris Kristanto said “

There seems to be a difference in the way that Azure Liquid Mapper parses the map with Kastenberg’s LiquidTransform.exe..

When I run your map locally using LiquidTransform.exe, it detects the null fine and applies your new mapping logic, but it doesn’t detect the null when I run it in Logic Apps.

So I had to add the following “and Line.UnitPrice != “““ condition to make the logic apps one detect that it is null.”

"InnerPrice": {%- if Line.UnitPrice != null and Line.UnitPrice != "" -%}"{{Line.UnitPrice}}",{%- else -%}"{% assign CtnPrice = Line.CtnPrice | Times: 1.00 %}{% assign Multipler = Line.Multiplier | Times: 1.00 %}{{ CtnPrice | DividedBy: Multipler | Round: 3}}",{%- endif -%}

This also shows how to round to 3 decimal places.

turbo360

Back to Top