Skip to content
Developerhome
X3

Computed properties and getValue

  Less than to read

A computed property is a non-stored or non-persistent property primarily associated with a node in the Node bindings function (GESANODEB) in the Computed properties tab.

In other words, a computed property is a property of a node not linked to a field in the table definition, but its value is computed or derived based on other properties or calculations.

Computed properties allow you to define a property whose value is dynamically determined at runtime.

Computed properties are useful when want to expose certain calculations or derived values as if they are regular properties of a node so you can encapsulate them in the GraphQL capabilities and logic.

There are two options to define computed properties in the Node bindings function:

  • Computed properties: computeValue.
  • getValue properties: getValue.

Difference between computed value and getValue

  • getValue properties can be used for basic operations. For example, a piece of code that can be easily transformed into an SQL statement such as orderedQuantity * salesPrice.
    • The following tokens can be used in getValue expressions:
      • Basic operators: +, - , / , * , || , && , < , <= , > , >=, (, )
      • Non-typed comparisons where types are converted and resulting values are compared: == , !=
      • Typed comparison where type and value are compared: === , !==
      • Null value alternative: ??
      • Note: || and && operators are allowed to define Boolean expressions only.
      • An error is thrown if any unsupported tokens are used in a getValue expression.
  • computeValue propertiescan be used for more complex statements. You can encapsulate a piece of TypeScript code of your choice into a function. The code is added in the Sage X3 Services development environment:
    • Developers can create their own subdirectories in the lib directory of the relevant application.
    • Those directories must be referenced in the Node bindings function in the Computed property grid.
    • The index.ts script, in the lib directory, must be updated as well.

Creating a computed value or a getValue in Node bindings

You need to provide the following information to create a getValue or a computeValue in the Node bindings function:

  • Event: Choose the property type (computeValue or getValue) depending on the use case.
  • Property: The name of the property.
  • Denormalized collection: Name of the denormalized collection linked to this property.
  • Type: One of Boolean, Integer, Decimal, String, Date, Node, Enum.
  • Menu code: Links the property to the specified local menu. Mandatory when the type is Enum (Local menu).
  • Target: Indicates the name of the node linked to this property. It turns that property into a reference or a link to a collection. Mandatory when the type is Node.
  • Join type: Reference indicates it’s a one-to-one link and Collection indicates it’s a one-to-many relationship. Mandatory when the type is Node.
  • Package name: Name of the package where the property is generated.
  • Depends on: List of the properties that computeValue depends on. The elements of the list should be separated by commas.
  • Expression: Expression used to compute getValue.
  • Function package: Package where the function is delivered, for a computeValue, expressed as @[namespace]/[package].
  • Function path: Path where the function is located inside the package for a computeValue. It is expressed as directory.function.

Examples

getValue properties

</tr>
X3 metadata - Node binding expression Code generated (X3 Services) Note
project.id+'~'+operation.number
async getValue() {return (await (await this.project).id) + '~' + (await (await this.operation).number);}


@decorators.stringProperty<OperationAssignement, 'keyConcat'>({
    isPublished:true,
    dataType: () => sageXtremX3SystemUtils.datatypes.genericDataTypes.textDatatype,
    async getValue(){
    return (
        (await (await this.project).id) +
        '~' +
        (await (await this.task).code)+
        '~' +
        (await(await this.operation).number) +
        '~' +
        (await this.firstOperationSplit)+
        '~' +
        (await this.lineNumber)
    );
    },
})
journalEntry.journalEntryNumber
async getValue() {return (await this.journalEntry).journalEntryNumber;}


@decorators.stringProperty<JournalEntryLine, 'journalEntryNumber'>({
    isPublished: true,
    dataType: () => sageXtremX3SystemUtils.datatypes.genericDataTypes.textDatatype,
    asyn getValue(){
        return (await this.journalEntry).journalEntryNumber;
    },
    dependsOn: ['journalEntry'],
})
readonly journalEntryNumber: Promise<string|null>;
'manufacturing'
getValue() {return 'manufacturing';}
project.id+'~'+!operation.number
async getValue() {

return (await (await this.project).id) + '~' + !(await (await this.operation).number);

}

computedValue properties

Example 1: computeLedgerAmount function

Property generated in the node:

@decorators.decimalProperty<JournalEntryLine,'creditAmountInLedgerCurrency'>({
    isPublished: true,
    isNullable: true,
    dataType: () => sageXtremX3SystemUtils.datatypes.genericDataTypes.decimalDatatype,
    computeValue(){
        return sageX3Finance.functions.computeLedgerAmount(this);
    },
    dependsOn: ['ledgerAmount','sign'],
})
readonly creditAmountInLedgerCurrency: Promise<decimal|null>;

Function:

import {JournalEntryLine} from "../nodes";

export async function computeLedgerAmount(_this: JournalEntryLine){
    const sign= await _this.sign;
    if(sign && sign ===1){
        return _this.ledgerAmount;
    }
    return 0;
}

The function (X3 Services):

  • The functions directory and the functions it contains are developed by developers.
  • The functions directory and the subdirectories can have any name except client-functions reserved for pages.
  • Under the functions folder, the index.ts must be added too: export * from './computeLedgerAmount';.
  • Under the lib folder, the index.ts file must be amended too with this new line: export * as functions from './functions';.
Example 2: computeRemainingQty function

Property generated in the node:

@decorators.decimalProperty<WorkOrderMaterialLine, 'remainingQuantity'>({
        isPublished: true,
        isNullable: true,
        dataType: () => sageXtremX3SystemUtils.datatypes.genericDataTypes.decimalDatatype,
        computeValue() {
            return sageX3Manufacturing.functions.computeRemainingQty(this);
        },
    })
    readonly remainingQuantity: Promise<decimal | null>;

Function:

import { WorkOrderMaterialLine } from "../nodes";

export async function computeRemainingQty(_this:WorkOrderMaterialLine){
    const returnValue: number = ((await _this.requiredQuantity)??0) - ((await _this.consumedQuantity)??0);
    return returnValue < 0 ? 0 : returnValue;
}