Skip to content

Custom Actions

Regulator|Scripting API · C# 14

Custom actions extend the built-in action system with Low-Code C# implementations. This is relevant for Regulators at the Regulation Developer level — see No-Code and Low-Code Development for the full picture.

The workflow for creating a custom action: 1. Implement the case action in C# 2. Add the action to the regulation 3. Test the action 4. Use the action

In the following tutorial example, an action is created to validate the company ID. It is to be checked whether the checksum of the company ID complies with the ISO 7064 standard.

Case Action

The case action consists of metadata in the form of C# attributes and the implementation. For validation actions, errors are included with the AddIssue method.

namespace PayrollEngine.Client.Scripting.Function;
public partial class CaseValidateFunction
{
    [ActionIssue("InvalidUId", "(0) with invalid UID: (1)", 2)]  // register issue message
    [ActionParameter("caseFieldName", "The case field name")]    // register parameter
    [ActionParameter("uid", "The UID text")]                     // register parameter
    [CaseValidateAction("CheckUId", "Validate for the Swiss company id (UID)")]  // register action
    public bool CheckUId(string caseFieldName, string uid)
    {
        // extract check value
        var checkValue = uid.RemoveFromStart("CHE-").Replace(".", string.Empty);
        try
        {
            // ISO 7064 digit check with modulus, radix, character-set and double-check-digit option
            new CheckDigit(11, 1, "0123456789", false).Check(checkValue);
            return true;  // valid UID
        }
        catch (CheckDigitException)
        {
            LogError($"Invalid Uid check value {checkValue}.");           // optional log
            AddCaseAttributeIssue("InvalidUId", caseFieldName, $"Invalid UId: {uid},");
        }
        return false;  // invalid UID
    }
}

You can also use the predefined digit checks Mod11Radix2, Mod37Radix2, Mod97Radix10, Mod661Radix26, Mod1271Radix36.

Regulation Action

Next, the script with the validation function is included in the regulation:

regulations:
- name: ActionRegulation
  lookups:
  - name: MyActions.Actions              # convention: ActionNamespace.Actions
    values:
    - key: InvalidUId
      value: "(0) is invalid: (1)"       # English issue message template
      valueLocalizations:
        de: "(0) ist ungültig: (1)"      # localized German variant
  cases:
  - name: UId
    caseType: Employee
    defaultReason: Test UId
    validateActions:
    - "? CheckUId('UId', ^:UId)"         # '?' = validate trigger; passes field name and value
    fields:
    - name: UId
      valueType: String
      timeType: Period
      valueMandatory: true
      defaultStart: today
      attributes:
        input.valueMask: CHE-000.000.000
        input.valueHelp: Format CHE-123.456.789
  scripts:
  - name: MyActions
    functionTypes:
    - CaseValidate                       # binds C# file to the CaseValidate function type
    valueFile: Scripts/CaseValidateFunction.cs

The lookups section registers the localized issue message under the convention ActionNamespace.Action (MyActions.Actions). The cases section defines the UId case field with the CheckUId validate action (see Action Syntax). The scripts section registers the C# file for the CaseValidate function type.

Action Test

The validation action UId is checked with the following test:

# yaml-language-server: $schema=../../Schemas/PayrollEngine.CaseTest.schema.json
testName: Test.UId
tenantIdentifier: ActionTenant
userIdentifier: lucy.smith@foo.com
employeeIdentifier: mario.nuñez@foo.com
payrollName: ActionPayroll
validateTests:

- testName: UId.Valid.999999996.Test    # valid UID — expect value accepted unchanged
  input:
    userIdentifier: lucy.smith@foo.com
    employeeIdentifier: mario.nuñez@foo.com
    divisionName: ActionDivision
    case:
      caseName: UId
      values:
      - caseFieldName: UId
        value: "999999996"
  output:
    values:
    - caseFieldName: UId
      value: "999999996"                # value passes through unchanged

- testName: UId.Invalid.999999997.Test # invalid UID — expect CaseInvalid issue
  input:
    userIdentifier: lucy.smith@foo.com
    employeeIdentifier: mario.nuñez@foo.com
    divisionName: ActionDivision
    case:
      caseName: UId
      values:
      - caseFieldName: UId
        value: "999999997"
  output:
    issues:
    - caseFieldName: UId
      issueType: CaseInvalid
      number: 400                       # HTTP 400 Bad Request

The first test (UId.Valid.999999996.Test) submits a valid UID value and expects it to be accepted unchanged in the output. The second test (UId.Invalid.999999997.Test) submits an invalid UID and expects a CaseInvalid issue with HTTP error code 400.

Command to execute the test:

PayrollConsole CaseTest Test.et.json

Action Usage

Finally, the validation also takes effect in the web application with a corresponding error message.

Case Validation

Next Steps