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
X3 metadata - Node binding expression | Code generated (X3 Services) | Note |
---|---|---|
project.id+'~'+operation.number |
|
|
journalEntry.journalEntryNumber |
|
|
</tr>
'manufacturing' |
|
|
project.id+'~'+!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;
}