Skip to main content

Salesforce Commerce Cloud Create Custom Job Step-I Task Oriented Script Module

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 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 executeargsPipelineDictionary ) : Number 
    var workingFolderargs.WorkingFolder;
    var filePatternargs.FilePattern;
    var importModeargs.ImportMode;
    var afterProcessAction =  argsAfterProcessAction ;
    var sourceFolderFilenew File(File.IMPEXFile.SEPARATOR'src'File.SEPARATORworkingFolder);
    if (!sourceFolder.exists()) {
        sourceFolder.mkdirs(); 
}
    var listFilesListsourceFolder.listFiles();
    var regExpRegExpnew RegExp(filePattern);
    for each (var _fileFile in listFiles) {
        if(regExp.test(_file.name)){
           var fileworkingFolderFile.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.nameimportResult.ErrorMsg);
                return PIPELET_ERROR;
else {
                // Import success
             afterProcessActionHandler(afterProcessActionworkingFolder_file);
}
}
}

    return PIPELET_NEXT;
}

function afterProcessActionHandlerafterProcessActionStringworkingFolderStringfileImportFile ) {
    try {
        ifafterProcessAction == "DELETE_FILE" ) {
            fileImport.remove();
else if afterProcessAction == "ARCHIVE_FILE" ) {
            afterProcessActionArchiveHandler(workingFolderfileImport);
}
        return true;
catch (e) {
        Logger.error("Error occurred processing afterProcessAction: "e.message);
        return false;
}
}

function afterProcessActionArchiveHandlerworkingFolderStringfileImportFile ) {
    try {
        ifworkingFolder.charAt(0) == File.SEPARATOR ) {
            workingFolderworkingFolder.substring(1);
}

        var archiveFolderFilenew File(File.IMPEXFile.SEPARATOR'src'File.SEPARATORworkingFolderFile.SEPARATOR'archive'File.SEPARATOR);
        if (!archiveFolder.exists()) {
            archiveFolder.mkdirs();
}

        var fileImportArchivePathFilenew 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 profileSyncargsPipelineDictionary ) : Status {
    var importFailedStatusargs.ImportFailedStatus;
    ifexecute(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

Popular posts from this blog

SFCC Development environment setup-III Create a Storefront Project

Creating a storefront project depends on whether you are using SFRA or SGJC. SFCC recommends SFRA for new implementation In this section we will see how to create a storefront using SFRA Create Custom SFRA cartridges Implementing a site requires at least one custom cartridge. However, if you intend to create multiple sites, we suggest you create multiple custom cartridges. Each cartridge can separate functionality specific to a brand or locale, so that you can reuse most of your cartridge stack for a new site Cartridges can be created using  sgmf -scripts   This script is useful for creating Storefront Reference Architecture overlay cartridges. All of the scripts are executable through CLI [ https://www.npmjs.com/package/sgmf-scripts ] Follow the steps to install  sgmf -scripts globally and use the script to create new custom cartridge 1.   Update the node by using below command D :\ SFCC \ temp \ demo - site > npm   install - ...

Salesforce Commerce Cloud Hooks - SFCC Hooks

Hooks in SFCC is a CommonJS script module. Hooks can be configured as a piece of functionality to use it in a specific point in your application flow or at a specific event. You can use these hook s with a Salesforce B2C Commerce storefront application OCAPI hook s B2C Commerce provides extension points to call scripts before or after specific OCAPI calls Custom hook s You can define custom extension points and call them in your storefront code using the B2C Commerce script System package HookMgr class methods. You can then access the hook in either OCAPI or your storefront code. This flexibility makes them useful for functionality in a multichannel set of applications based on the same site. Hook Definition The package.json file will have the hook file entry for a cartridge. The hook file definitions shown as below {     "hooks" :  "./hooks.json" } The hook file defines a uniquely named extension point and...