{
  "id": "7BvmpMUEf7fRqYpm",
  "meta": {
    "aiBuilderAssisted": true
  },
  "name": "SAP B1 OData Sync to Google Sheets",
  "tags": [],
  "nodes": [
    {
      "id": "69a2acfe-f90c-4b28-bd2b-45f5575d8929",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        48,
        688
      ],
      "parameters": {
        "width": 480,
        "height": 864,
        "content": "## SAP B1 OData Sync to Google Sheets\n\n### How it works\n\nThis workflow runs on a daily schedule to synchronize SAP Business One OData records into Google Sheets. It logs in to SAP B1, fetches two pages of records in parallel, extracts and merges them, then maps the fields into a consistent sheet format. Records with valid email addresses are upserted into Google Sheets, while records without email addresses are logged as skipped before the valid path logs out of SAP B1.\n\n### Setup steps\n\n- Configure the schedule trigger with the desired daily run time and timezone.\n- Replace the SAP B1 Service Layer placeholder URLs with the correct login, record-fetch, and logout endpoints.\n- Add SAP B1 authentication details or credentials required by the HTTP Request nodes, including company database, username, and password/session handling as needed.\n- Configure the Google Sheets credential, spreadsheet ID, target sheet/range, and upsert key columns.\n- Review the extraction code nodes to match the exact SAP OData response structure and pagination format.\n\n### Customization\n\nAdjust the number of fetch/extract branches if more SAP OData pages are needed, change the mapped fields in the Transform & Map Fields node, or modify the email validation rule before writing to Google Sheets."
      },
      "typeVersion": 1
    },
    {
      "id": "a618b35d-9a1c-4bf9-953e-5ab6fec07440",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        608,
        816
      ],
      "parameters": {
        "color": 7,
        "width": 384,
        "height": 320,
        "content": "## Schedule and SAP login\n\nStarts the daily synchronization and establishes an SAP B1 session before data retrieval begins."
      },
      "typeVersion": 1
    },
    {
      "id": "58f177e4-32b0-4071-8799-ce7900a6bbf5",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1040,
        736
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 528,
        "content": "## Fetch and merge records\n\nFetches two spatially parallel SAP record pages, extracts their record arrays with code, and appends both results into one combined stream."
      },
      "typeVersion": 1
    },
    {
      "id": "97071d54-4ee0-4168-931c-f2178a6612e9",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1760,
        816
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 320,
        "content": "## Map and validate fields\n\nTransforms the merged SAP records into the target field structure and branches records based on whether they contain a valid email address."
      },
      "typeVersion": 1
    },
    {
      "id": "abe37149-d64d-40ce-be5f-886ac06a13a3",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2240,
        688
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 560,
        "content": "## Write or log results\n\nHandles the final output cluster: valid records are upserted to Google Sheets and followed by SAP logout, while records missing email information are marked as skipped with a reason."
      },
      "typeVersion": 1
    },
    {
      "id": "046a90d9-e9c0-4833-b95f-909b21ecbcfe",
      "name": "Run Daily SAP Sync",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        656,
        976
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 24
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "2f30c6ad-2a89-4644-b1d1-64a50df3b683",
      "name": "Post SAP Login",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        848,
        976
      ],
      "parameters": {
        "url": "<__PLACEHOLDER_VALUE__https://your-sap-server:50000/b1s/v1/Login__>",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "CompanyDB",
              "value": "<__PLACEHOLDER_VALUE__SBODEMOGB__>"
            },
            {
              "name": "UserName",
              "value": "<__PLACEHOLDER_VALUE__manager__>"
            },
            {
              "name": "Password",
              "value": "<__PLACEHOLDER_VALUE__your-password__>"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "b27da326-3f23-4fb3-a288-101d6d20291e",
      "name": "Fetch SAP Page 1 Records",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1088,
        864
      ],
      "parameters": {
        "url": "<__PLACEHOLDER_VALUE__https://your-sap-server:50000/b1s/v1/BusinessPartners__>",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        },
        "sendQuery": true,
        "sendHeaders": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "$top",
              "value": "20"
            },
            {
              "name": "$skip",
              "value": "0"
            },
            {
              "name": "$select",
              "value": "CardCode,CardName,CardType,Balance,Phone1,EmailAddress"
            },
            {
              "name": "$orderby",
              "value": "CardCode asc"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Cookie",
              "value": "=B1SESSION={{ $('Post SAP Login').item.json.SessionId }}; ROUTEID=.node1"
            },
            {
              "name": "Prefer",
              "value": "odata.maxpagesize=20"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "50c7ab62-03b7-40b4-a25f-9ba9575a3db9",
      "name": "Parse Page 1 Records",
      "type": "n8n-nodes-base.code",
      "position": [
        1328,
        864
      ],
      "parameters": {
        "jsCode": "\nconst records = $input.first().json.value || [];\nreturn records.map(r => ({ json: r }));\n"
      },
      "typeVersion": 2
    },
    {
      "id": "1d8ca860-d112-45a8-a369-8298c4d3821c",
      "name": "Merge Records from Both Pages",
      "type": "n8n-nodes-base.merge",
      "position": [
        1568,
        976
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "f9a56de3-8285-4f64-a08c-a9c776a57c8a",
      "name": "Fetch SAP Page 2 Records",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1088,
        1088
      ],
      "parameters": {
        "url": "<__PLACEHOLDER_VALUE__https://your-sap-server:50000/b1s/v1/BusinessPartners__>",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        },
        "sendQuery": true,
        "sendHeaders": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "$top",
              "value": "20"
            },
            {
              "name": "$skip",
              "value": "20"
            },
            {
              "name": "$select",
              "value": "CardCode,CardName,CardType,Balance,Phone1,EmailAddress"
            },
            {
              "name": "$orderby",
              "value": "CardCode asc"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Cookie",
              "value": "=B1SESSION={{ $('Post SAP Login').item.json.SessionId }}; ROUTEID=.node1"
            },
            {
              "name": "Prefer",
              "value": "odata.maxpagesize=20"
            }
          ]
        }
      },
      "executeOnce": true,
      "typeVersion": 4.3
    },
    {
      "id": "44212607-33f6-4926-9d83-b2803a1269d3",
      "name": "Parse Page 2 Records",
      "type": "n8n-nodes-base.code",
      "position": [
        1328,
        1088
      ],
      "parameters": {
        "jsCode": "\nconst records = $input.first().json.value || [];\nreturn records.map(r => ({ json: r }));\n"
      },
      "typeVersion": 2
    },
    {
      "id": "efe86309-80a9-4cbc-84be-14a0b63483ba",
      "name": "Set Customer Data Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        1808,
        976
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1",
              "name": "Customer Code",
              "type": "string",
              "value": "={{ $json.CardCode }}"
            },
            {
              "id": "2",
              "name": "Customer Name",
              "type": "string",
              "value": "={{ $json.CardName }}"
            },
            {
              "id": "3",
              "name": "Type",
              "type": "string",
              "value": "={{ $json.CardType === 'C' ? 'Customer' : $json.CardType === 'S' ? 'Supplier' : 'Lead' }}"
            },
            {
              "id": "4",
              "name": "Balance (SAR)",
              "type": "number",
              "value": "={{ $json.Balance }}"
            },
            {
              "id": "5",
              "name": "Phone",
              "type": "string",
              "value": "={{ $json.Phone1 }}"
            },
            {
              "id": "6",
              "name": "Email",
              "type": "string",
              "value": "={{ $json.EmailAddress }}"
            },
            {
              "id": "7",
              "name": "Last Synced",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "e97f02bc-febe-4130-a355-54ca8adf0e7a",
      "name": "Check Valid Email",
      "type": "n8n-nodes-base.if",
      "position": [
        2048,
        976
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "email-check",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              },
              "leftValue": "={{ $json.Email }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "5e5e2d33-233c-4bfc-b57b-273f25507ec7",
      "name": "Upsert Customer to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2288,
        864
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [
            "Customer Code"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": "={{ \"SAP_BusinessPartners\" }}",
        "documentId": "={{ \"your-google-sheet-id-here\" }}"
      },
      "typeVersion": 4.5
    },
    {
      "id": "71320247-884e-4aaa-8674-b39798c5c372",
      "name": "Post SAP Logout",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2528,
        864
      ],
      "parameters": {
        "url": "<__PLACEHOLDER_VALUE__https://your-sap-server:50000/b1s/v1/Logout__>",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Cookie",
              "value": "=B1SESSION={{ $('Post SAP Login').item.json.SessionId }}; ROUTEID=.node1"
            }
          ]
        }
      },
      "executeOnce": true,
      "typeVersion": 4.3
    },
    {
      "id": "897bcc8a-c5d9-4b33-b5a3-c651f8c6ccbd",
      "name": "Log Skips Without Email",
      "type": "n8n-nodes-base.set",
      "position": [
        2288,
        1088
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1",
              "name": "skipped_code",
              "type": "string",
              "value": "={{ $json[\"Customer Code\"] }}"
            },
            {
              "id": "2",
              "name": "skipped_name",
              "type": "string",
              "value": "={{ $json[\"Customer Name\"] }}"
            },
            {
              "id": "3",
              "name": "reason",
              "type": "string",
              "value": "Missing email address"
            }
          ]
        }
      },
      "typeVersion": 3.4
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": true,
    "executionOrder": "v1"
  },
  "versionId": "e8319938-cdca-4dba-bedc-e461257fc0aa",
  "connections": {
    "Post SAP Login": {
      "main": [
        [
          {
            "node": "Fetch SAP Page 1 Records",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch SAP Page 2 Records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Valid Email": {
      "main": [
        [
          {
            "node": "Upsert Customer to Sheets",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log Skips Without Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run Daily SAP Sync": {
      "main": [
        [
          {
            "node": "Post SAP Login",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Page 1 Records": {
      "main": [
        [
          {
            "node": "Merge Records from Both Pages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Page 2 Records": {
      "main": [
        [
          {
            "node": "Merge Records from Both Pages",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Fetch SAP Page 1 Records": {
      "main": [
        [
          {
            "node": "Parse Page 1 Records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch SAP Page 2 Records": {
      "main": [
        [
          {
            "node": "Parse Page 2 Records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Customer Data Fields": {
      "main": [
        [
          {
            "node": "Check Valid Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upsert Customer to Sheets": {
      "main": [
        [
          {
            "node": "Post SAP Logout",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Records from Both Pages": {
      "main": [
        [
          {
            "node": "Set Customer Data Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}