Validation of characteristic values
In following validation of characteristic values is described only for items to make the documentation more readable. Please note, that the same feature is also provided in the standard Product 360 for products and variants as well.
Data Quality
In the "Data quality" perspective you will find a set of new rule configurations for characteristics. There is a rule configuration for each language and category combination existing. The rules can not be changed by the user. Changes in languages or categories are reflected here automatically.
When executed, these rules will check characteristic values for the following:
Mandatory record: Do all items have characteristic values for characteristics that are marked as mandatory ?
Cardinality: Do all items have the allowed amount of records as defined by their characteristics lower and upper bound?
Format pattern: Do all characteristic values match the format pattern defined at the characteristic?
Validation expression: Do all characteristic values match their characteristic validation expression?
You can select multiple data quality rule configurations (multiple languages and categories) to execute at once. Execution of data quality rules for a single characteristic is not supported.
Validation in the UI
The user gets direct feedback in the UI working on characteristic values. Here the same rule configurations are executed as are available for data quality. Colored bubbles inform the user about the validation status.
Results will be updated after a value is saved or when a new item is loaded.
Validation Expressions
Validation expressions are short scriptlets which can be used to implement a specific validation for a characteristic record.
The validation expression has certain parameters which can be used to obtain the value of the characteristic record. Additionally it can use most of the features of the standard java script language and its default objects. The supported scripting language is ECMAScript 5.1.
The validation expression must return a string which will then be visualized to the user in case the expression fails. Please note that this validation result is not translatable and might be persisted as part of the data quality execution for characteristics.
The validation expression is limited to 1000 characters per characteristic.
Limitations
Due to security reasons the scripting possibilities have been limited to the core ECMAScript 5.1. It is not possible to load external scripts or load classes outside of the java script engine.
Functions and Constants
The following functions and constants are disabled (will do nothing or return just null)
window
quit()
exit()
readFully()
readLine()
load()
loadWithNewGlobal()
$ARG
$ENV
$EXEC
$OPTIONS
$OUT
$ERR
$EXIT
These functions will only be available in case logging for com.heiler.ppm.characteristic.core.scripting.internal.CharacteristicScriptEngineFactory is set to DEBUG or TRACE
print()
=> Keep in mind that echo() is not available for debugging.
Java API and Reflection
The Java API and the Reflection APIs like Class.forName or Java.type are disabled. It is not possible to load any classes outside of the pre-existing standard objects of the Java Script language. Any attempt to do so will result in a java.lang.ClassNotFoundException.
User Impersonalization
All scripts will be executed in the context of a guest user which has no permission to modify any values.
The Expression
The validation expression is essentially a java script function body. The function itself is created by the scripting framework and provides a record and an entityItem parameter.
Record
/**
* Returns the language code (string) of the values, null in case the values are language independent!
*/
record.getLanguage();
/**
* Returns the identifier of the characteristic the record belongs to, never empty or null
*/
record.getCharacteristicIdentifier();
/**
* Returns the first value of the record. In case multiple values are possible,
* this method will return the first one without any specific order
*/
record.getFirstValue();
/**
* Returns an array of all values of the record without any specific order
*/
record.getValues();
/**
* Returns the parent record, might be null in case the current record is a root record and therefore has no parent
*/
record.getParent();
/**
* Returns the first child record for the given characteristic identifier, might be null in case there is no such
* record. In case there are multiple records for this characteristic, the method will return the first one, without any
* specific order
*/
record.getFirstChild( characteristicIdentifier );
/**
* Returns an array of all child records for the given characteristic identifier, it's never null, but might be empty
*/
record.getChildren( characteristicIdentifier );
/**
* Returns an array of all child records, it's never null, but might be empty
*/
record.getAllChildren();
/**
* Returns the first sibling record for the given characteristic identifier,
* might be null in case there is no such record.
* In case there are multiple records for this characteristic, the method will return the first one,
* without any specific order
* @since 10.0.0.03
*/
record.getFirstSibling( String characteristicIdentifier );
/**
* Returns an array of all sibling records for the given characteristic identifier,
* it's never null, but might be empty
* @since 10.0.0.03
*/
record.getSiblings( String characteristicIdentifier );
/**
* Returns an array of all sibling records, regardless of the characteristic. Never <code>null</code> but it might be empty
* @since 10.0.0.03
*/
record.getAllSiblings();
EntityItem
Some specific validation rules need to have access to entity item field values which are not part of the characteristic records of this entity item, but are stored in a plain old repository defined field. To provide access to these field values, the script function additionally provides the entityItem parameter.
Please note that access to field values of the entity item is a performance intensive task which should not be used if not really required.
/**
* Returns the field value for the given field. In case the field might
* have multiple values, it will return the first value. Might return null
* in case no value is available. Will also return null, if the entity item
* does not contain the requested field.
*/
entityItem.getFieldValue( serviceApiField ) ;
/**
* Returns an array of all values for the given field, never null but might be empty.
* Will also be empty if the entity item does not contain the requested fields.
*/
entityItem.getFieldValues( serviceApiField );
/**
* Returns true if the current object is an Article, otherwise false. This check
* is needed for example when an entity specific field is retrieved via
* getFieldValue( serviceApiField ) or getFieldValues( serviceApiField ).
* This is a convenient method for isEntity("Article")
*/
entityItem.isArticle();
/**
* Returns true if the current object is a Product, otherwise false. This check
* is needed for example when an entity specific field is retrieved via
* getFieldValue( serviceApiField ) or getFieldValues( serviceApiField ).
* This is a convenient method for isEntity("Product2G")
*/
entityItem.isProduct();
/**
* Returns true if the current object is a Variant, otherwise false. This check
* is needed for example when an entity specific field is retrieved via
* getFieldValue( serviceApiField ) or getFieldValues( serviceApiField ).
* This is a convenient method for isEntity("Variant")
*/
entityItem.isVariant();
/**
* Returns true if the current object is an entity with the given entityIdentifier,
* otherwise false. This check is needed for example when an entity specific field
* is retrieved via getFieldValue( serviceApiField ) or getFieldValues( serviceApiField ).
*/
entityItem.isEntity(entityIdentifier);
Service API Field
This is a fully qualified field reference in the syntax of the Service API. For example: ArticleLang.DescriptionShort(en) would return the English short description. Please refer to the Service API documentation for details, REST Field Qualification. Please be aware that the empty qualification keyword is not supported here.
Data Types
Fields in Product 360 can have different data types. In order to make any scripting task easier, a few specialties apply here.
If a field is mapped to an enumeration in the repository, we always try to return the external code as specified for the enumeration entry. The external code is always a string and usually a well known constant. So it's easy to use this in code. In case the enumeration does not have an external code available, we will return the enumeration entry key (for which the following conversions apply just like for any other field which is not bound to an enumeration!)
Field values which have an EntityProxy as data type, will be resolved for the external identifier of the corresponding object. (In the rare case the entity has no external identifier, the internal ID will be returned).
Data types like String, Long, BigDecimal, Date and Datetime will be provided as they are.
Data types
As characteristics do have different data types, also the data types of the values returned from the record object inside the validation expression are different.
Characteristic data type |
Data type of the value |
|
Text |
String |
|
Decimal |
Number |
|
Integer |
Number |
|
Boolean |
Boolean |
|
Datetime |
java.sql.Timestamp |
|
Date |
java.sql.Date |
|
Mime |
MIMEValue |
/** * Returns the human readable label for the MIME value, never <code>null</code> nor empty */ value.getLabel(); /** * Returns the MIME Type, never <code>null</code> nor empty */ value.getMimeType(); /** * Returns the relative file path under which this mime value is stored */ value.getRelativeFilePath(); |
Lookup |
LookupValue |
/** * Returns the unique alphanumeric identifier of the lookup (not of the lookup value!) */ value.getLookupIdentifier(); /** * Returns the alphanummeric code of the lookup value, which is unique within the lookup */ value.getCode(); /** * Returns if this lookup value is currently active or not (boolean) */ value.isActive(); |
Return Value
As the name "validation expression" suggests, the result of this can only be yes or no. The expression validates a single characteristic record - so if it returns true, the record is just fine. As the user might want to know a little bit more than just "is fine or not", we allow not only true/false as return values, but also a string. Any string besides an empty one will be interpreted as "validation failed" whereas the provided string will be shown to the user. If you return null, an empty string or true, the validation went ok.
Validation result |
Return value |
failed |
"this is my arbitrary message for this specific validation" or false |
succeeded |
null, "" (empty string) or true |
Multi-Language Characteristic Records
In order to make the implementation of validation expressions as simple as possible, we eliminated the language dimension from it. So, a validation expression might be executed multiple times in case the characteristic supports multi-language. The provided record object gives access to the language code of this execution, so, in case there is anything special just for one language, the implementer can check this.
Any string result of the validation expression will be concatenated in case it's called multiple times because it has multi-language values, unless the result string is the same, then it will be added just once.
Examples
Value after today
var
value = record.getFirstValue() ? record.getFirstValue().getTime() :
null
;
return
Date.now() > value ?
"Certificate outdated"
:
null
;
Characteristic is mandatory if item has a specific value in a repository based field
if
( record.getFirstValue() ==
null
&& entityItem.getFieldValue(
"Article.EAN"
) ==
"123"
)
{
return
“Mandatory value
for
items
with
EAN 123”;
}
Check if value contains special characters
return
/[~`!
#$%\^&*+=\-\[\]\\';,/{}|\\":<>\?]/g.test(record.getFirstValue()) ? "Special Characters detected" : null;
Show VariantNo if characteristic record is part of a variant
if
(entityItem.isVariant())
{
return
"Variant: "
+ entityItem.getFieldValue(
"Variant.VariantNo"
);
}