Version History for Custom Fields in Orders and Order Lines

Summary

UIOR-1230: Custom Fields - consider Version historyOpen aims to extend the version history on orders and order lines to include custom fields. Currently, the information that is stored in audit records for orders and order lines is not sufficient to support all outlined requirements.

The requirements are:

  • The history should display custom fields with their corresponding labels for keys and values, e.g.:

    • Given the exemplary entry "customFields": { "membership": "opt_0" }

    • The key membership should display as "Membership"

    • The select option value opt_0 should display as "Yes"

  • If a custom field definition is deleted (via Settings) it should have no effect on already saved versions.

Current state

  • The version history view for orders and order lines does not display any information on custom fields.

  • The audit records with elements orderSnapshot and orderLineSnapshot do contain custom fields data, but the custom fields entries contain references to custom field definitions stored elsewhere.
    Currently such an audit record may look like this:

    { "orderAuditEvents": [ { "id": "a095b07d-94a8-4756-b999-4e5a0dba8be1", "action": "Edit", "orderId": "38cab6c5-4ba9-47f4-8c83-d4c192af8191", "userId": "4f218243-e15e-5a9e-9733-4e2ccd9d95d2", "eventDate": "2024-07-03T07:31:28.463+00:00", "actionDate": "2024-07-03T07:31:28.455+00:00", "orderSnapshot": { "map": { "id": "38cab6c5-4ba9-47f4-8c83-d4c192af8191", "notes": [], "vendor": "e0fb5df2-cdf1-11e8-a8d5-f2801f1b9fd1", "approved": false, "poNumber": "10006", "orderType": "One-Time", "acqUnitIds": [], "reEncumber": true, "customFields": { "externalOrderNumber": "7890" }, "workflowStatus": "Pending" }, "empty": false } } ] }
  • Custom field definitions are not stored in the audit records, so its currently not possible to resolve custom field values (in the above case, a label for externalOrderNumber) to a historic state.

  • The current definition for custom fields is available at the /custom-fields endpoint.

    { "customFields": [ { "id": "fd725b6f-8723-4003-878e-69ffe255ade7", "name": "External order number", "refId": "externalOrderNumber", "type": "TEXTBOX_SHORT", "entityType": "purchase_order", "visible": true, "required": false, "isRepeatable": false, "order": 1, "helpText": "", "textField": { "fieldFormat": "TEXT" }, "metadata": { "createdDate": "2024-07-03T01:55:13.433+00:00", "updatedDate": "2024-07-03T01:55:13.433+00:00" } }, { "id": "2970f8fc-3ace-441e-b994-879db86e1d52", "name": "Membership", "refId": "membership", "type": "SINGLE_SELECT_DROPDOWN", "entityType": "po_line", "visible": true, "required": false, "isRepeatable": false, "order": 1, "helpText": "", "selectField": { "multiSelect": false, "options": { "values": [ { "id": "opt_1", "value": "No", "default": false }, { "id": "opt_0", "value": "Yes", "default": false } ], "sortingOrder": "CUSTOM" } }, "metadata": { "createdDate": "2024-07-03T01:55:13.455+00:00", "updatedDate": "2024-07-03T01:55:13.455+00:00" } } ], "totalRecords": 2 }

Proposed backend changes

In order to be able to resolve the keys and values of custom fields to their corresponding (historic) labels, the custom fields definition needs to be stored as part of the audit record.

  • Introduce an additonal attribute customFieldsSnapshot to the audit records which contains the definitions of custom fields at the time a change to a order or order line was made:

    • order_audit_event for orders and

    • order_line_audit_event for order lines

    • An updated audit record might look like this:

      { "orderAuditEvents": [ { "id": "a095b07d-94a8-4756-b999-4e5a0dba8be1", "action": "Edit", "orderId": "38cab6c5-4ba9-47f4-8c83-d4c192af8191", "userId": "4f218243-e15e-5a9e-9733-4e2ccd9d95d2", "eventDate": "2024-07-03T07:31:28.463+00:00", "actionDate": "2024-07-03T07:31:28.455+00:00", "orderSnapshot": { "map": { "id": "38cab6c5-4ba9-47f4-8c83-d4c192af8191", "notes": [], "vendor": "e0fb5df2-cdf1-11e8-a8d5-f2801f1b9fd1", "approved": false, "poNumber": "10006", "orderType": "One-Time", "acqUnitIds": [], "reEncumber": true, "customFields": { "externalOrderNumber": "7890" }, "workflowStatus": "Pending" }, "empty": false }, "customFieldsSnapshot": [ { "id": "fd725b6f-8723-4003-878e-69ffe255ade7", "name": "External order number", "refId": "externalOrderNumber", "type": "TEXTBOX_SHORT", "entityType": "purchase_order", "visible": true, "required": false, "isRepeatable": false, "order": 1, "helpText": "", "textField": { "fieldFormat": "TEXT" } } ] } ] }
    • Using the additional information from customFieldsSnapshot the custom field values can be resolved and displayed in the version history view. Also, the history view is uneffected by any future changes to custom field defintions.

  • Adjust the implementation of AuditEventProducer in mod-orders-storage to include custom fields definitions into the OrderAuditEvent.

Proposed frontend changes

  • Add a component that renders custom fields to <POVersion> and <POLineVersion>

  • Evaluate if the <ViewCustomFieldsRecord> component from stripes-smart-components can be reused for this purpose

    • May require an option to supply a custom fields definition instead of fetching the current ones

    • May require an addition for being able to highlight changed values

Modules/Libraries in scope

  • mod-orders-storage

  • mod-audit

  • ui-orders

  • stripes-smart-components

Problems / Implications :

  • To prevent inconsistencies between the displayed version history and the actual current version, the proposed changes require triggering the creation of audit records for every entity affected by a custom field definition change – including label changes, display order adjustments and deletions.

  • Applying the proposed changes will significantly increase the size of audit records.

  • Audit records are likely to contain the same custom fields information repeatedly.