{ "kind": "open-flow-workflow", "version": 1, "name": "Import Excel Contacts to Salesforce", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_8af847fd6e0374f4": { "name": "Import contacts", "kind": "start", "inputDefs": [] }, "n_b48d093aac418e10": { "inputs": { "itemId": { "kind": "value", "value": "YOUR_WORKBOOK_ITEM_ID" }, "worksheetId": { "kind": "value", "value": "Sheet1" }, "valuesOnly": { "kind": "value", "value": true } }, "name": "Read contact workbook", "kind": "task", "task": { "inputs": [ { "description": "Workbook drive item ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Workbook drive item ID." }, "nullable": false, "handle": "itemId" }, { "description": "Optional drive ID. Leave empty to use the current user's default OneDrive.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Optional drive ID. Leave empty to use the current user's default OneDrive." }, "nullable": true, "handle": "driveId", "value": null }, { "description": "Optional workbook session ID created by create_session.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Optional workbook session ID created by create_session." }, "nullable": true, "handle": "sessionId", "value": null }, { "description": "Worksheet name or worksheet ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Worksheet name or worksheet ID." }, "nullable": false, "handle": "worksheetId" }, { "description": "Whether to ignore formatting-only cells in the used range.", "jsonSchema": { "type": "boolean", "description": "Whether to ignore formatting-only cells in the used range." }, "nullable": true, "handle": "valuesOnly", "value": null } ], "outputs": [ { "description": "Used range returned by Microsoft Graph.", "jsonSchema": { "type": "object", "properties": { "address": { "type": "string", "description": "A1-style address of the range." }, "addressLocal": { "type": "string", "description": "Localized A1-style address of the range." }, "cellCount": { "type": "integer", "description": "Total number of cells in the range." }, "columnCount": { "type": "integer", "description": "Number of columns in the range." }, "rowCount": { "type": "integer", "description": "Number of rows in the range." }, "columnHidden": { "type": "boolean", "description": "Whether all columns in the range are hidden." }, "rowHidden": { "type": "boolean", "description": "Whether all rows in the range are hidden." }, "values": { "type": "array", "items": { "type": "array", "items": { "description": "An array item." }, "description": "An array item." }, "description": "Raw cell values in the range." }, "text": { "type": "array", "items": { "type": "array", "items": { "description": "An array item." }, "description": "An array item." }, "description": "Display text values in the range." }, "formulas": { "type": "array", "items": { "type": "array", "items": { "description": "An array item." }, "description": "An array item." }, "description": "A1-style formulas in the range." }, "formulasLocal": { "type": "array", "items": { "type": "array", "items": { "description": "An array item." }, "description": "An array item." }, "description": "Localized formulas in the range." }, "formulasR1C1": { "type": "array", "items": { "type": "array", "items": { "description": "An array item." }, "description": "An array item." }, "description": "R1C1-style formulas in the range." }, "numberFormat": { "type": "array", "items": { "type": "array", "items": { "description": "An array item." }, "description": "An array item." }, "description": "Excel number formats for the range." }, "valueTypes": { "type": "array", "items": { "type": "array", "items": { "description": "An array item." }, "description": "An array item." }, "description": "Cell value types for the range." } }, "additionalProperties": true, "description": "Used range returned by Microsoft Graph." }, "nullable": false, "handle": "range" } ], "name": "Read contact workbook", "executor": { "kind": "connector", "action": "excel.get_worksheet_used_range" } } }, "n_cdb415339cd64562": { "inputs": { "range": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_b48d093aac418e10", "output": "range" } ] } }, "name": "Validate contact rows", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "object", "properties": { "address": { "type": "string", "description": "A1-style address of the range." }, "addressLocal": { "type": "string", "description": "Localized A1-style address of the range." }, "cellCount": { "type": "integer", "description": "Total number of cells in the range." }, "columnCount": { "type": "integer", "description": "Number of columns in the range." }, "rowCount": { "type": "integer", "description": "Number of rows in the range." }, "columnHidden": { "type": "boolean", "description": "Whether all columns in the range are hidden." }, "rowHidden": { "type": "boolean", "description": "Whether all rows in the range are hidden." }, "values": { "type": "array", "items": { "type": "array", "items": { "description": "An array item." }, "description": "An array item." }, "description": "Raw cell values in the range." }, "text": { "type": "array", "items": { "type": "array", "items": { "description": "An array item." }, "description": "An array item." }, "description": "Display text values in the range." }, "formulas": { "type": "array", "items": { "type": "array", "items": { "description": "An array item." }, "description": "An array item." }, "description": "A1-style formulas in the range." }, "formulasLocal": { "type": "array", "items": { "type": "array", "items": { "description": "An array item." }, "description": "An array item." }, "description": "Localized formulas in the range." }, "formulasR1C1": { "type": "array", "items": { "type": "array", "items": { "description": "An array item." }, "description": "An array item." }, "description": "R1C1-style formulas in the range." }, "numberFormat": { "type": "array", "items": { "type": "array", "items": { "description": "An array item." }, "description": "An array item." }, "description": "Excel number formats for the range." }, "valueTypes": { "type": "array", "items": { "type": "array", "items": { "description": "An array item." }, "description": "An array item." }, "description": "Cell value types for the range." } }, "additionalProperties": true, "description": "Used range returned by Microsoft Graph." }, "nullable": false, "handle": "range" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "rows" } ], "name": "Validate contact rows", "moduleId": "n_35a4ce0fd96a5062", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_8e7ead1be683d15f": { "inputs": { "rows": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_cdb415339cd64562", "output": "rows" } ] }, "previousState": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_5b65a632dd973d7f", "output": "state" } ] } }, "name": "Prepare next contact", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "rows" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "previousState" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "row" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "more" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "known" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "accountId" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "soql" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "company" }, { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" } ], "name": "Prepare next contact", "moduleId": "n_c2e0e61cb8f48ae1", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_883d7c75268a3729": { "inputs": {}, "name": "More contacts?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "more", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_8e7ead1be683d15f", "output": "more" } }, "operator": "isTrue" } ] } ] } ] }, "n_f989bee5922f535a": { "inputs": { "soql": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8e7ead1be683d15f", "output": "soql" } ] }, "knownId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8e7ead1be683d15f", "output": "accountId" } ] }, "company": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8e7ead1be683d15f", "output": "company" } ] } }, "name": "Find account", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "soql" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "knownId" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "company" } ], "outputs": [ { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "found" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "id" } ], "name": "Find account", "moduleId": "n_7f6e4282819ea10d", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [ { "action": "salesforce.query" } ] } ] } }, "n_eaecd696a0372f43": { "inputs": {}, "name": "Account found?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "found", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_f989bee5922f535a", "output": "found" } }, "operator": "isTrue" } ] } ] } ] }, "n_65bb7e9a9c9d4d35": { "inputs": { "row": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8e7ead1be683d15f", "output": "row" } ] } }, "name": "Create account", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "row" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "id" } ], "name": "Create account", "moduleId": "n_accd00bf5c65ec60", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [ { "action": "salesforce.create_record" } ] } ] } }, "n_8758877e44da05bb": { "inputs": { "id": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_f989bee5922f535a", "output": "id" } ] } }, "name": "Use found account", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "id" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "id" } ], "name": "Use found account", "moduleId": "n_ca43a82142af1736", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_4dcfb3a9815bd829": { "inputs": { "row": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8e7ead1be683d15f", "output": "row" } ] }, "id": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8758877e44da05bb", "output": "id" }, { "kind": "node", "nodeId": "n_65bb7e9a9c9d4d35", "output": "id" } ] } }, "name": "Upsert contact", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "row" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "id" } ], "outputs": [ { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "ok" } ], "name": "Upsert contact", "moduleId": "n_1328d4c442324f18", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [ { "action": "salesforce.upsert_record" } ] } ] } }, "n_5b65a632dd973d7f": { "inputs": { "state": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8e7ead1be683d15f", "output": "state" } ] }, "row": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8e7ead1be683d15f", "output": "row" } ] }, "id": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8758877e44da05bb", "output": "id" }, { "kind": "node", "nodeId": "n_65bb7e9a9c9d4d35", "output": "id" } ] } }, "name": "Remember account", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "row" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "id" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" } ], "name": "Remember account", "moduleId": "n_f280702c17406fe9", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_67a3972f3a3d3301": { "name": "Imported contact count", "kind": "outputs", "outputDefs": [ { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" } ], "outputMappings": { "count": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8e7ead1be683d15f", "output": "count" } ] } } } }, "edges": [ { "source": "n_8af847fd6e0374f4", "target": "n_b48d093aac418e10" }, { "source": "n_b48d093aac418e10", "target": "n_cdb415339cd64562" }, { "source": "n_cdb415339cd64562", "target": "n_8e7ead1be683d15f" }, { "source": "n_8e7ead1be683d15f", "target": "n_883d7c75268a3729" }, { "source": "n_883d7c75268a3729", "target": "n_f989bee5922f535a", "sourceHandle": "more" }, { "source": "n_883d7c75268a3729", "target": "n_67a3972f3a3d3301", "sourceHandle": "otherwise" }, { "source": "n_f989bee5922f535a", "target": "n_eaecd696a0372f43" }, { "source": "n_eaecd696a0372f43", "target": "n_8758877e44da05bb", "sourceHandle": "found" }, { "source": "n_8758877e44da05bb", "target": "n_4dcfb3a9815bd829" }, { "source": "n_eaecd696a0372f43", "target": "n_65bb7e9a9c9d4d35", "sourceHandle": "otherwise" }, { "source": "n_65bb7e9a9c9d4d35", "target": "n_4dcfb3a9815bd829" }, { "source": "n_4dcfb3a9815bd829", "target": "n_5b65a632dd973d7f" }, { "source": "n_5b65a632dd973d7f", "target": "n_8e7ead1be683d15f" } ] } }, "modules": { "n_35a4ce0fd96a5062": { "name": "Validate contact rows", "imports": [], "source": "export default function({range}){const values=range?.values;if(!Array.isArray(values))throw Error('Invalid sheet data');if(!values.length)return {rows:[]};const header=values[0],names=['Company Name','First Name','Last Name','Email'];if(!Array.isArray(header))throw Error('Invalid header');const cols=names.map(n=>{const i=header.indexOf(n);if(i<0||header.lastIndexOf(n)!==i)throw Error('Expected unique '+n+' header');return i});const rows=values.slice(1).filter(r=>Array.isArray(r)&&r.some(x=>x!==''&&x!=null)).map(r=>{const [company,first,last,email]=cols.map(i=>r[i]);if(![company,first,last,email].every(x=>typeof x==='string'&&x.trim())||/[\\r\\n\\x00]/.test(company)||!/^\\S+@\\S+\\.\\S+$/.test(email))throw Error('Every row needs company, first name, last name and email');return {company,first,last,email}});return{rows}}\n" }, "n_c2e0e61cb8f48ae1": { "name": "Prepare next contact", "imports": [], "source": "export default function({rows,previousState}){const state=previousState??{index:0,accounts:{}};if(!Array.isArray(rows)||!Number.isInteger(state.index)||state.index<0||state.index>rows.length||!state.accounts||typeof state.accounts!=='object')throw Error('Invalid import state');if(state.index===rows.length)return {state,row:{},more:false,known:false,accountId:'',soql:'SELECT Id FROM Account LIMIT 1',company:'',count:state.index};const row=rows[state.index],id=Object.hasOwn(state.accounts,row.company)?state.accounts[row.company]:'',escaped=row.company.replace(/\\\\/g,'\\\\\\\\').replace(/'/g,\"\\\\'\");return {state,row,more:true,known:!!id,accountId:id,company:row.company,soql:\"SELECT Id, Name FROM Account WHERE Name = '\"+escaped+\"' LIMIT 2\",count:state.index}}\n" }, "n_7f6e4282819ea10d": { "name": "Find account", "imports": [], "source": "export default async function({soql,knownId,company},ctx){const r=await ctx.actions.call('salesforce.query',{soql});if(!r||!Array.isArray(r.records)||r.done!==true||r.records.length>1)throw Error('Account name is ambiguous or query incomplete');if(!r.records.length)return {found:!!knownId,id:knownId};if(typeof r.records[0]?.Name!=='string')throw Error('Invalid account name');if(r.records[0].Name!==company)return {found:!!knownId,id:knownId};const id=r.records[0]?.Id;if(typeof id!=='string'||!/^[A-Za-z0-9]{15}(?:[A-Za-z0-9]{3})?$/.test(id))throw Error('Invalid account ID');if(knownId&&knownId!==id)throw Error('Account changed during import');return {found:true,id}}\n" }, "n_accd00bf5c65ec60": { "name": "Create account", "imports": [], "source": "export default async function({row},ctx){const r=await ctx.actions.call('salesforce.create_record',{objectName:'Account',fields:{Name:row.company}});if(r?.success!==true||typeof r.id!=='string'||!/^[A-Za-z0-9]{15}(?:[A-Za-z0-9]{3})?$/.test(r.id))throw Error('Account creation was not confirmed');return{id:r.id}}\n" }, "n_ca43a82142af1736": { "name": "Use found account", "imports": [], "source": "export default function({id}){return {id}}" }, "n_1328d4c442324f18": { "name": "Upsert contact", "imports": [], "source": "export default async function({row,id},ctx){if(typeof id!=='string'||!/^[A-Za-z0-9]{15}(?:[A-Za-z0-9]{3})?$/.test(id))throw Error('Invalid account ID');const r=await ctx.actions.call('salesforce.upsert_record',{objectName:'Contact',externalIdField:'Email',externalId:row.email,fields:{FirstName:row.first,LastName:row.last,AccountId:id}});if(r?.success!==true)throw Error('Contact upsert was not confirmed');return{ok:true}}\n" }, "n_f280702c17406fe9": { "name": "Remember account", "imports": [], "source": "export default function({state,row,id}){return {state:{index:state.index+1,accounts:{...state.accounts,[row.company]:id}}}}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }