From 5c9ffdbb41796343248abb1875a15f811b870162 Mon Sep 17 00:00:00 2001 From: Matej Samler Date: Thu, 25 Sep 2025 18:53:33 +0200 Subject: [PATCH] feat: add documentation for Liquid templating and Record Creation Rules --- .../applications/utilities/liquid.md | 182 ++++++++++++++++++ .../utilities/recordcreationrules.md | 80 ++++++++ 2 files changed, 262 insertions(+) create mode 100644 src/en/developer-guide/applications/utilities/liquid.md create mode 100644 src/en/developer-guide/applications/utilities/recordcreationrules.md diff --git a/src/en/developer-guide/applications/utilities/liquid.md b/src/en/developer-guide/applications/utilities/liquid.md new file mode 100644 index 000000000..9ee74b797 --- /dev/null +++ b/src/en/developer-guide/applications/utilities/liquid.md @@ -0,0 +1,182 @@ +--- +title: Liquid +tagline: A series of custom tags and filters for use in Liquid templates, usable throughout our components +author: Matěj Samler +--- + +## Description + +Liquid templating language can be used to map data from source to a different format. Go to [Liquid documentation](https://shopify.github.io/liquid/) for full documentation. + +Bellow, we have multiple custom tags and filters we have created for easier work with Dataverse data. You can use these across our various components, such as Record Creation Rules, Power Automate connector, etc. + +## General Tags + +### JSON + +Use this tag to parse a string into json and work with its properties. + +**Syntax:** + +```liquid +{% json %} + +{% endjson %} +``` + +**Example:** + +Data: + +```json +{ + "input": "{'name': {'first': 'John', 'last':'Smith'}}" +} +``` + +Map: + +```liquid +My first name is {% json input %} name.first {% endjson %} +``` + +Output: + +```text +My first name is John +``` + +## CDS Tags + +### CDSLookup + +Use this tag to lookup a record URL based on a json of filters. The input is a logical name of the entity to search, the output is a record URL of the first found record. + +**Syntax:** + +```liquid +{% cdslookup %} + +{% endcdslookup %} +``` + +**Example:** + +Data: + +```json +{ + "Surname" : "Smith" +} +``` + +Map: + +```liquid +URL is {% cdslookup contact %} {'lastname' : '{{ Surname }}'} {% endcdslookup %} +``` + +Output: + +```text +URL is https://placeholder.crm4.dynamics.com/main.aspx?etn=contact&id=5caf3e4f-3737-4a88-8664-7d93d16ab2fc +``` + +### CDSOptionSetLocalizedLabel + +Use this tag to translate a value of option set to human readable string. + +**Syntax:** + +```liquid +{% cdsoptionsetlocalizedlabel ,, %} + +{% endcdsoptionsetlocalizedlabel %} +``` + +**Example:** + +Data: + +```json +{ "AccountType" : 820001 } +``` + +Map: + +```liquid +Account type is {% cdsoptionsetlocalizedlabel account,type,1033 %}{{ AccountType }}{% endcdsoptionsetlocalizedlabel %} +``` + +Output: + +```text +Account type is Vendor +``` + +### CDSGetFieldValue + +Use this tag to get a value of a field (or multiple) on an record. We are using CDSTypeConverter, so it should return readable input in all cases. We are returning recordUrl if the field is a lookup. + +**Syntax:** + +```liquid +{% cdsgetfieldvalue %} + +{% endcdsgetfieldvalue %} +``` + +**Example:** + +Data: + +```json +{ "RecordURL" : "https://placeholder.crm4.dynamics.com/main.aspx?etn=contact&id=5caf3e4f-3737-4a88-8664-7d93d16ab2fc"} +``` + +Map: + +```liquid +Contact surname is {% cdsgetfieldvalue lastname %}{{ RecordURL }}{% endcdsgetfieldvalue %} +``` + +Output: + +```text +Contact surname is Smith +``` + +**Note:** +This tag returns multiple values, but they are not separated in any way. It should be used to fetch a single value. + +### CDSIdToRecordUrl + +Transforms logical name and id into a redirectable record url. + +**Syntax:** + +```liquid +{% cdsidtorecordurl %} + +{% endcdsidtorecordurl %} +``` + +**Example:** + +Data: + +```json +{ "RecordId" : "5caf3e4f-3737-4a88-8664-7d93d16ab2fc"} +``` + +Map: + +```liquid +URL is {% cdsidtorecordurl contact %}{{ RecordId }}{% endcdsidtorecordurl %} +``` + +Output: + +```text +URL is https://placeholder.crm4.dynamics.com/main.aspx?etn=contact&id=5caf3e4f-3737-4a88-8664-7d93d16ab2fc&pagetype=entityrecord +``` diff --git a/src/en/developer-guide/applications/utilities/recordcreationrules.md b/src/en/developer-guide/applications/utilities/recordcreationrules.md new file mode 100644 index 000000000..bdf9067ca --- /dev/null +++ b/src/en/developer-guide/applications/utilities/recordcreationrules.md @@ -0,0 +1,80 @@ +--- +title: Record Creation Rules +tagline: Define rules for automatic record creation via Dataverse records +author: Matěj Samler +--- + +# Record Creation Rules + +Record Creation rules allow you to define custom rules for listening to CRUD operations on records and automatically creating new records in response to those operations. +These rules are defined via Dataverse records themselves, making them easy to manage and modify without needing to change any code. + +## Entities + +### Record Creation Rule + +Record creation rules is the main entity for defining rules. + +Looking at its form, we can see multiple sections: + +#### Source entity + +- Source Entity Name: Logical name of the entity to listen to +- Trigger Messages: A multiselect optionset for selecting which CRUD operations to listen to. We can select Create, Update, Delete or Assign. +- Filtering Attributes: A comma-separated list of attributes to filter on. This is only applicable when the Trigger Message is set to Update. If this is left empty, the rule will trigger on any update. +- Query: After saving of the record, a query builder will become available. This allows you to define additional filtering criteria for the rule. + +#### Target entity + +- Entity Name: Logical name of the entity to create records in +- Liquid Map: A liquid template for mapping attributes from the source entity to the target entity. The source entity is used as the data input, so all of its attributes can be accessed directly. There are also some custom Dataverse tags available, see [Liquid](../utilities/liquid.md) for more information. + +#### Update Source Record (After Action) + +- Success: A liquid template for updating the source record after the target record has been successfully created. Can be used to change status, set a lookup to the created record, etc. + +## Record Creation Rule Log + +In case of an error during the execution of a record creation rule, a log record will be created. In case of an error, the execution of the message is not halted and the operation will succeed, but the error will be logged for later review. + +## How it works + +In the background, there are multiple components working together to make this functionality work. + +**On create of a new record creation rule, we:** + +- Check if a record creation rule listener is already registered for the given source entity and for the selected message. If not, we register a new listener. + +**On delete of a record creation rule, we:** + +- Check if there are any other record creation rules for the same source entity and message. If not, we unregister the listener. + +**When a message is received by the listener, we:** + +- Retrieve all record creation rules for the given entity and message +- For each rule, check if the filtering attributes match (if defined) +- For each rule, check if the query matches (if defined) +- For each matching rule, create a new target record based on the liquid map +- For each matching rule, update the source record based on the after action liquid map (if defined) +- In case of an error during processing of a rule, create a log record + +The creation itself is done by using an Action + +## Implementation details + +The main components of the implementation are: + +### Workflow activity + +- **Plugin Registrator**: Responsible for registering the listeners. Registers a new SDK message on a processing step of the source entity. +- **Plugin Deletor**: Responsible for unregistering the listeners. Unregisters the SDK message if there are no more rules for the given entity and message. + +### Plugin + +- **ProcessRecordCreationRule**: The main listener plugin. Listens to the messages defined in the record creation rules and processes them. + +### Workflows + +- **DeleteRuleListener**: A workflow that is called by the plugin deletor to delete the listener. +- **RegisterRuleListener**: A workflow that is called by the plugin registrator to register the listener. +- **talxis_createrecordfromrule**: A workflow that is called by the main listener plugin to create the target record and update the source record. It uses the liquid maps defined in the rule to perform the creation and update.