Creating custom task oriented job steps involves the following steps,
1. Create a CommonJS module that exposes a function to be called as the main function for the job step
2. When administrators create jobs using Business Manager, they set parameters that are available as scriptable objects for the module's function
3. The dw.job.JobStepExecution object allows read-only access to information about the current step execution and job execution.
4. To control the exit status, the script module's function can return a dw.system.Status object
5. If the script finishes with an unhandled exception, the exit status code is ERROR, and the error status flag is true by default
6. If no status object is returned and no exception occurs, the status code is OK by default.
Consider the following use case to explain the Task oriented job steps.
The system want to update the profile information when it got updated by other system. The file will be place to a particular IMPEX/src location
1. Create a CommonJS module file. It is recommended to create file in the path app_demo_storefront/cartridge/scripts
/**
* Sync profile from the WebDav Directory
*
* @input WorkingFolder : String Local folder relatively to IMPEX/src.
* @input FilePattern : String Input File pattern to search in local folder relatively to IMPEX/ (default is "^Profile_sync_(\d){14}\.xml$").
* @input ImportMode : String The import mode (DELETE|MERGE|REPLACE|UPDATE)
* @input ImportFailedStatus : String Import status object after import failed.
* @input AfterProcessAction : String When file is uploaded, delete or keep it? ("Delete" / "Keep on server").
*/
importPackage( dw.system );
importPackage( dw.io );
/**
* Execute for Pipeline
*/
function execute( args : PipelineDictionary ) : Number {
var workingFolder = args.WorkingFolder;
var filePattern = args.FilePattern;
var importMode = args.ImportMode;
var afterProcessAction = args . AfterProcessAction ;
var sourceFolder : File = new File(File.IMPEX + File.SEPARATOR + 'src' + File.SEPARATOR + workingFolder);
if (!sourceFolder.exists()) {
sourceFolder.mkdirs();
}
var listFiles : List = sourceFolder.listFiles();
var regExp : RegExp = new RegExp(filePattern);
for each (var _file : File in listFiles) {
if(regExp.test(_file.name)){
var file = workingFolder + File.SEPARATOR + _file.name;
//Read the file and update the Profile information
if (importResult.ErrorCode != 0) {
// Import failed
Logger.error("Import failded file {0}, message: {1}", _file.name, importResult.ErrorMsg);
return PIPELET_ERROR;
} else {
// Import success
afterProcessActionHandler(afterProcessAction, workingFolder, _file);
}
}
}
return PIPELET_NEXT;
}
function afterProcessActionHandler( afterProcessAction : String, workingFolder : String, fileImport : File ) {
try {
if ( afterProcessAction == "DELETE_FILE" ) {
fileImport.remove();
} else if ( afterProcessAction == "ARCHIVE_FILE" ) {
afterProcessActionArchiveHandler(workingFolder, fileImport);
}
return true;
} catch (e) {
Logger.error("Error occurred processing afterProcessAction: " + e.message);
return false;
}
}
function afterProcessActionArchiveHandler( workingFolder : String, fileImport : File ) {
try {
if ( workingFolder.charAt(0) == File.SEPARATOR ) {
workingFolder = workingFolder.substring(1);
}
var archiveFolder : File = new File(File.IMPEX + File.SEPARATOR + 'src' + File.SEPARATOR + workingFolder + File.SEPARATOR + 'archive' + File.SEPARATOR);
if (!archiveFolder.exists()) {
archiveFolder.mkdirs();
}
var fileImportArchivePath : File = new File(archiveFolder.getFullPath() + fileImport.getName());
fileImport.renameTo(fileImportArchivePath);
return true;
} catch (e) {
Logger.error("Error occurred processing afterProcessActionArchiveHandler: " + e.message);
return false;
}
}
/**
* Execute for Scriptmodule
*/
function profileSync( args : PipelineDictionary ) : Status {
var importFailedStatus = args.ImportFailedStatus;
if ( execute(args) == PIPELET_ERROR ) {
if (importFailedStatus == 'WARN') {
return new Status(Status.OK, 'WARN');
} else {
return new Status(Status.ERROR);
}
}
return new Status(Status.OK);
}
/** Exported functions **/
module.exports = {
execute: execute,
profileSync : profileSync
}
2. Create steptypes.json file in the path app_demo_storefront/steptypes.json
This file describes custom job steps. It has a specific JSON syntax.
If a steptypes.json file contains errors, the errors are logged and the steps are not registered. The system then loads steps from the steptypes.json files.
{
"step-types": {
"script-module-step": [
{
"@name": "Profile Synchronization",
"@type-id": "custom.ProfileSync",
"module": "app_demo_storefront//cartridge/scripts/profileSync",
"function": "profileSync",
"parameters": {
"parameters": [
{
"@name": "WorkingFolder",
"@description": "Local folder relatively to IMPEX/src. (e.g download/profileSync)",
"@type": "string",
"@required": false,
"@trim": true
},
{
"@name": "FilePattern",
"@description": "Input File pattern to search in local folder relatively to IMPEX/ (default is ^ProfileSync_(\\d){14}\\.xml).",
"@type": "string",
"@required": false,
"@trim": true
},
{
"@name": "ImportMode",
"@description": "Import Mode",
"@type": "string",
"@required": true,
"@trim": true,
"enum-values": {
"value": [
"MERGE",
"REPLACE",
"UPDATE",
"DELETE"
]
}
},
{
"@name": "ImportFailedStatus",
"@description": "Treat Import Failed as",
"@type": "string",
"@required": true,
"@trim": true,
"enum-values": {
"value": [
"WARN",
"ERROR"
]
}
},
{
"@name": "AfterProcessAction",
"@description": "Handle file after process",
"@type": "string",
"@required": true,
"@trim": true,
"enum-values": {
"value": [
"DELETE_FILE",
"KEEP_FILE",
"ARCHIVE_FILE"
]
}
}
]
},
"status-codes": {
"status": [
{
"@code": "ERROR",
"description": "Used when an error occurred."
},
{
"@code": "OK",
"description": "Used when everything went well."
},
{
"@code": "WARN",
"description": "Used when small, but acceptable problems occurred."
}
]
}
}
]
}
}
3. Creating Job in SFCC Business Manager
Once the custom step is registered it will be listed in the “Select and Configure Step”.
4. 
Comments
Post a Comment