{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "bf789e9d-beac-493f-b81d-7d194783a8f1",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -496,
        1792
      ],
      "parameters": {
        "width": 460,
        "height": 960,
        "content": "### This n8n template demonstrates how to export NetSuite Inventory Items and Upsert into Salesforce as Products.\n\n### How it works\n* Workflow processes 20 records per iteration until there are no records left.\n* To find unique records - NetSuite Internal Id is used in Salesforce as External Id.\n\n\n### How to use\n* Set up NetSuite and Salesforce connections.\n* The 'Execute Workflow Daily' node is used as an example but feel free to replace it with any other trigger.\n* Run the flow manually to process all records. Non-existing records will be created, all existing - updated.\n* After running workflow manually - you can set up schedule to run the flow. To process only records updated after last workflow run date - switch 'NS: Inventory Item - Get list of All records' node with 'NS: Inventory Item - Get Delta records'\n\n\n### Requirements\n* Salesforce connection working and External Id field exists.\n* NetSuite connection working. Please refer to the details provided in [NetSuite REST Node description](https://www.npmjs.com/package/n8n-nodes-netsuite-rest).\n\n### Note\n* When running a workflow with Schedule trigger - on a first run workflow will use {today} date as a last export date.\n* Currently workflow uses NetSuite REST community node   and can run on self-hosted n8n instance only.\n\n### Need Help?\nFeel free to reach out to support@entechsolutions.com\n\nHappy Integrating!"
      },
      "typeVersion": 1
    },
    {
      "id": "56d52e50-2ed7-46c7-abbc-0b0645ccf9a4",
      "name": "Split Customers Array",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1744,
        2176
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "items"
      },
      "typeVersion": 1
    },
    {
      "id": "63b00445-05fc-41d6-bd95-be6a098cfe59",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2576,
        1920
      ],
      "parameters": {
        "color": 5,
        "width": 432,
        "height": 560,
        "content": "## Salesforce section 2\n\n### Records are inserted/updated into Salesforce here"
      },
      "typeVersion": 1
    },
    {
      "id": "56fc814e-50da-47f2-99d4-650f49989ab9",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1392,
        1856
      ],
      "parameters": {
        "color": 7,
        "width": 800,
        "height": 560,
        "content": "## Netsuite section\n\n### Records are pulled from NetSuite here\n\n### Fell free to use filter with Q parameter passed in 'NS: Inventory Item - Get list of All records' step\n\nRead about using Q parameter in [NetSuite Docs](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_1545222128.html)\n\n### Note\n* In this workflow only one Netsuite price level value is used"
      },
      "typeVersion": 1
    },
    {
      "id": "3e1bc7bf-49b9-4cb6-8b98-38a2fefeebd2",
      "name": "Workflow is finished",
      "type": "n8n-nodes-base.noOp",
      "position": [
        1552,
        2704
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "7158e1e8-c545-4478-91e9-4d7f78c819b0",
      "name": "Has More Records?",
      "type": "n8n-nodes-base.if",
      "position": [
        976,
        2240
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "da799032-1cc2-421d-91cd-4eb174744162",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.hasMore }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "534b785f-eb2e-49be-ad48-a389321b7b9b",
      "name": "Retrieve Paging Offset and LastExportDate",
      "type": "n8n-nodes-base.code",
      "position": [
        1200,
        2176
      ],
      "parameters": {
        "jsCode": "const workflowStaticData = $getWorkflowStaticData('global');\nconst lastExportDate = workflowStaticData.lastExportDate ? workflowStaticData.lastExportDate : $today.minus({days: 1}).toFormat('MM/dd/yyyy')\n\nreturn [\n  {\n      offset: workflowStaticData.offset,\n      lastExportDate: lastExportDate\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "0dffa714-f495-438c-a63a-ef756007d9ab",
      "name": "Update Paging Offset and LastExportDate",
      "type": "n8n-nodes-base.code",
      "position": [
        3296,
        2352
      ],
      "parameters": {
        "jsCode": "const workflowStaticData = $getWorkflowStaticData('global');\n\nworkflowStaticData.offset = workflowStaticData.offset+20\nworkflowStaticData.hasMore = $('NS: Inventory Item - Get list of All records').isExecuted ? $('NS: Inventory Item - Get list of All records').first().json.hasMore: $('NS: Inventory Item - Get Delta records').first().json.hasMore\n\nreturn [\n  {\n      offset: workflowStaticData.offset,\n      hasMore: workflowStaticData.hasMore\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "88568793-5119-4776-8800-bfdc50e1c45c",
      "name": "Execute Workflow Daily",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        80,
        2240
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "dcea2618-5270-419b-9d92-60b1dc9a83ee",
      "name": "Init Offset",
      "type": "n8n-nodes-base.code",
      "position": [
        752,
        2240
      ],
      "parameters": {
        "jsCode": "// initialize staticData object\nconst workflowStaticData = $getWorkflowStaticData('global');\n\nworkflowStaticData.offset = 0\nworkflowStaticData.hasMore = true\n\nreturn [\n  {\n      offset: workflowStaticData.offset,\n      hasMore: workflowStaticData.hasMore\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "20116ec6-ecf7-4e3e-aaca-b2ec48e27a7b",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1392,
        1344
      ],
      "parameters": {
        "width": 368,
        "height": 480,
        "content": "## Run for Delta records\n\n### Replace a 'NS: Inventory Item - Get list of All records' node with a node below to run flow only for records changed after Last Workflow Run"
      },
      "typeVersion": 1
    },
    {
      "id": "8b0944ab-ad8d-4299-90b8-507db45d6c5c",
      "name": "Update LastExportDate",
      "type": "n8n-nodes-base.code",
      "position": [
        1344,
        2704
      ],
      "parameters": {
        "jsCode": "const workflowStaticData = $getWorkflowStaticData('global');\n\nworkflowStaticData.lastExportDate = DateTime.now().toFormat('MM/dd/yyyy')\n\nreturn [\n  {\n      lastExportDate: workflowStaticData.lastExportDate\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "02494af3-a865-4cdb-973e-0f5dcc1ecff7",
      "name": "NS: Inventory Item - Get record",
      "type": "n8n-nodes-netsuite-rest.netSuiteRest",
      "position": [
        1984,
        2176
      ],
      "parameters": {
        "id": "={{ $json.id }}",
        "resource": "InventoryItem",
        "operation": "get /inventoryItem/{id}",
        "additionalFields": {
          "expandSubResources": true
        }
      },
      "credentials": {
        "netSuiteRestOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "fa8ac58b-5a18-4ff7-9ce3-89d494594a50",
      "name": "Salesforce: Add Products",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2736,
        2176
      ],
      "parameters": {
        "url": "https://entechsolutions4-dev-ed.develop.my.salesforce.com/services/data/v64.0/composite",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"allOrNone\": true,\n  \"compositeRequest\": [\n    {\n      \"method\": \"PATCH\",\n      \"url\": \"/services/data/v64.0/sobjects/Product2/External_ID__c/{{ $json.External_ID__c }}\",\n      \"referenceId\": \"prodUpsert\",\n      \"body\": {\n        \"Name\": \"{{ $json.Name }}\",\n        \"IsActive\": true\n      }\n    },\n    {\n      \"method\": \"PATCH\",\n      \"url\": \"/services/data/v64.0/sobjects/PricebookEntry/External_ID__c/{{ $json.External_ID__c }}-{{ $('Salesforce: Get Pricebook values').item.json.records[0].Id }}\",\n      \"referenceId\": \"pbeUpsert\",\n      \"body\": {\n        \"Pricebook2Id\": \"{{ $('Salesforce: Get Pricebook values').item.json.records[0].Id }}\",\n        \"Product2Id\": \"@{prodUpsert.id}\",\n        \"UnitPrice\": 100,\n        \"IsActive\": true\n      }\n    }\n  ]\n}\n",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "salesforceOAuth2Api"
      },
      "credentials": {
        "salesforceOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "typeVersion": 4.2
    },
    {
      "id": "26d29287-2073-4ee3-b705-92455f8a93a5",
      "name": "NS: Inventory Item - Get Delta records",
      "type": "n8n-nodes-netsuite-rest.netSuiteRest",
      "position": [
        1504,
        1632
      ],
      "parameters": {
        "resource": "InventoryItem",
        "isDebugMode": true,
        "additionalFields": {
          "q": "=lastModifiedDate ON_OR_AFTER \"{{ $json.lastExportDate }}\"",
          "limit": 20,
          "offset": "={{ $json.offset }}"
        }
      },
      "credentials": {
        "netSuiteRestOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "797c443b-3e82-420e-abec-b103845234d8",
      "name": "NS: Inventory Item - Get list of All records",
      "type": "n8n-nodes-netsuite-rest.netSuiteRest",
      "position": [
        1504,
        2176
      ],
      "parameters": {
        "resource": "InventoryItem",
        "additionalFields": {
          "limit": "=20",
          "offset": "={{ $json.offset }}"
        }
      },
      "credentials": {
        "netSuiteRestOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2a1b0bce-475d-4382-a84b-9d0238ed5626",
      "name": "Salesforce: Get Pricebook values",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        400,
        2240
      ],
      "parameters": {
        "url": "https://entechsolutions4-dev-ed.develop.my.salesforce.com/services/data/v64.0/query?q=SELECT+Id,Name,IsStandard,IsActive+FROM+Pricebook2+WHERE+IsActive=true",
        "options": {},
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "salesforceOAuth2Api"
      },
      "credentials": {
        "salesforceOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "typeVersion": 4.2
    },
    {
      "id": "e6c044d6-57a4-42ce-88ba-bd735dd5466c",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        256,
        1920
      ],
      "parameters": {
        "color": 5,
        "width": 384,
        "height": 496,
        "content": "## Salesforce section 1\n\n### Salesforce Pricebook values are fetched here\n\n### Note\n* In this workflow only one Salesforce Pricebook value is used"
      },
      "typeVersion": 1
    },
    {
      "id": "b499cf83-6e96-41ab-b009-719409344370",
      "name": "Prepare Salesforce Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        2336,
        2176
      ],
      "parameters": {
        "jsCode": "const records = $input.all();\n\nconst result = records.reduce((acc, item) => {\n  const data = item.json;\n  const prices = data.price?.items ?? [];\n\n  const quantityPrice = prices.find(p => p?.priceLevelName === \"Quantity\")?.price ?? null;\n\n  acc.push({\n    Name: data.itemId,\n    External_ID__c: data.id,\n    IsActive: data.isinactive === \"F\",\n    PricebookEntry_Price__c: quantityPrice\n  });\n\n  return acc;\n}, []);\n\nreturn result.map(r => ({ json: r }));\n"
      },
      "typeVersion": 2
    }
  ],
  "connections": {
    "Init Offset": {
      "main": [
        [
          {
            "node": "Has More Records?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has More Records?": {
      "main": [
        [
          {
            "node": "Retrieve Paging Offset and LastExportDate",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Update LastExportDate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Customers Array": {
      "main": [
        [
          {
            "node": "NS: Inventory Item - Get record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update LastExportDate": {
      "main": [
        [
          {
            "node": "Workflow is finished",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute Workflow Daily": {
      "main": [
        [
          {
            "node": "Salesforce: Get Pricebook values",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Salesforce: Add Products": {
      "main": [
        [
          {
            "node": "Update Paging Offset and LastExportDate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Salesforce Payload": {
      "main": [
        [
          {
            "node": "Salesforce: Add Products",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "NS: Inventory Item - Get record": {
      "main": [
        [
          {
            "node": "Prepare Salesforce Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Salesforce: Get Pricebook values": {
      "main": [
        [
          {
            "node": "Init Offset",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "NS: Inventory Item - Get Delta records": {
      "main": [
        []
      ]
    },
    "Update Paging Offset and LastExportDate": {
      "main": [
        [
          {
            "node": "Has More Records?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Retrieve Paging Offset and LastExportDate": {
      "main": [
        [
          {
            "node": "NS: Inventory Item - Get list of All records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "NS: Inventory Item - Get list of All records": {
      "main": [
        [
          {
            "node": "Split Customers Array",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}