The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "ShoppingCalendar",
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
0,
80
],
"id": "ba1b1125-aaa5-4494-8653-982627e8b680",
"name": "When clicking \u2018Execute workflow\u2019"
},
{
"parameters": {
"resource": "worksheet",
"operation": "readRows",
"workbook": {
"__rl": true,
"value": "9FBB0DE07F2BDB9D!s230bc0dd71bd43c8a72825f046562e9e",
"mode": "id"
},
"worksheet": {
"__rl": true,
"value": "{00000000-0001-0000-0000-000000000000}",
"mode": "list",
"cachedResultName": "\u5718\u8cfc\u6e05\u55ae",
"cachedResultUrl": "https://onedrive.live.com/personal/9fbb0de07f2bdb9d/_layouts/15/doc.aspx?resid=230bc0dd-71bd-43c8-a728-25f046562e9e&cid=9fbb0de07f2bdb9d&activeCell=%E5%9C%98%E8%B3%BC%E6%B8%85%E5%96%AE!A1"
},
"options": {}
},
"type": "n8n-nodes-base.microsoftExcel",
"typeVersion": 2.2,
"position": [
224,
80
],
"id": "0d74cd2e-6770-46eb-b639-d07a8fdbc22c",
"name": "Get rows from sheet",
"credentials": {
"microsoftExcelOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"options": {}
},
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 3,
"position": [
448,
80
],
"id": "8fa2506a-5117-4ac3-ba14-445c946d14ef",
"name": "Loop Over Items"
},
{
"parameters": {
"jsCode": "// N8N Code \u7bc0\u9ede\uff1a\u8655\u7406\u5718\u8cfc\u8cc7\u6599\u4e26\u6e96\u5099\u5efa\u7acb Google \u65e5\u66c6\u4e8b\u4ef6\n// \u7bc0\u9ede\u540d\u7a31\uff1aProcess Group Buying Data\n\n// \u53d6\u5f97\u6240\u6709\u8f38\u5165\u7684\u8cc7\u6599\u9805\u76ee\nconst items = $input.all();\n\n// \u6e96\u5099\u8f38\u51fa\u9663\u5217\nconst processedEvents = [];\n\n// \u8655\u7406\u6bcf\u4e00\u7b46\u5718\u8cfc\u8cc7\u6599\nfor (const item of items) {\n const data = item.json;\n \n // 1. \u9a57\u8b49\u5fc5\u8981\u6b04\u4f4d\n if (!data.\u5718\u8cfc\u540d\u7a31 || !data.\u958b\u5718\u65e5\u671f) {\n console.log(`\u8df3\u904e\u7121\u6548\u8cc7\u6599: ${JSON.stringify(data)}`);\n continue; // \u8df3\u904e\u6c92\u6709\u540d\u7a31\u6216\u65e5\u671f\u7684\u8cc7\u6599\n }\n \n // 2. \u7d44\u5408\u5b8c\u6574\u7684\u65e5\u671f\u6642\u9593\n const startDate = data.\u958b\u5718\u65e5\u671f; // \u683c\u5f0f: 2025-11-21\n const endDate = data.\u7d50\u675f\u65e5\u671f || data.\u958b\u5718\u65e5\u671f; // \u5982\u679c\u6c92\u6709\u7d50\u675f\u65e5\u671f\uff0c\u4f7f\u7528\u958b\u5718\u65e5\u671f\n const startTime = data.\u958b\u5718\u6642\u9593 || '09:00'; // \u9810\u8a2d 09:00\n const endTime = data.\u7d50\u675f\u6642\u9593 || '18:00'; // \u9810\u8a2d 18:00\n \n // \u7d44\u5408\u6210 ISO 8601 \u683c\u5f0f\n const startDateTime = `${startDate}T${startTime}:00+08:00`; // \u53f0\u7063\u6642\u5340 UTC+8\n const endDateTime = `${endDate}T${endTime}:00+08:00`;\n \n // 3. \u5efa\u7acb\u4e8b\u4ef6\u63cf\u8ff0\uff08\u5305\u542b\u6240\u6709\u8a73\u7d30\u8cc7\u8a0a\uff09\n const description = `\n\ud83d\udccd \u5730\u9ede\uff1a${data.\u5730\u9ede || '\u672a\u6307\u5b9a'}\n\ud83d\udc64 \u8ca0\u8cac\u4eba\uff1a${data.\u8ca0\u8cac\u4eba || '\u672a\u6307\u5b9a'}\n\ud83d\udcde \u806f\u7d61\u96fb\u8a71\uff1a${data.\u806f\u7d61\u96fb\u8a71 || '\u672a\u63d0\u4f9b'}\n\ud83d\udcb0 \u9810\u4f30\u91d1\u984d\uff1aNT$ ${data.\u9810\u4f30\u91d1\u984d || '0'}\n\n\ud83d\udcdd \u5099\u8a3b\uff1a\n${data.\u5099\u8a3b || '\u7121'}\n\n---\n\ud83e\udd16 \u6b64\u6d3b\u52d5\u7531 N8N \u81ea\u52d5\u5efa\u7acb\n\u23f0 \u532f\u5165\u6642\u9593\uff1a${new Date().toLocaleString('zh-TW', { timeZone: 'Asia/Taipei' })}\n `.trim();\n \n // 4. \u5efa\u7acb\u4e8b\u4ef6\u7269\u4ef6\n const event = {\n // Google Calendar \u9700\u8981\u7684\u6b04\u4f4d\n summary: data.\u5718\u8cfc\u540d\u7a31, // \u4e8b\u4ef6\u6a19\u984c\n description: description, // \u4e8b\u4ef6\u63cf\u8ff0\n location: data.\u5730\u9ede || '', // \u5730\u9ede\n startDateTime: startDateTime, // \u958b\u59cb\u6642\u9593\n endDateTime: endDateTime, // \u7d50\u675f\u6642\u9593\n \n // \u4e8b\u4ef6\u984f\u8272 (Google Calendar \u984f\u8272 ID)\n // 1=\u6de1\u7d2b, 2=\u6de1\u7da0, 3=\u7d2b\u8272, 4=\u7c89\u7d05, 5=\u9ec3\u8272, 6=\u6a58\u8272, 7=\u9752\u8272, 8=\u7070\u8272, 9=\u85cd\u8272, 10=\u7da0\u8272, 11=\u7d05\u8272\n colorId: '9', // \u85cd\u8272\n \n // \u63d0\u9192\u8a2d\u5b9a\n reminders: {\n useDefault: false,\n overrides: [\n { method: 'popup', minutes: 1440 }, // \u63d0\u524d 1 \u5929\u63d0\u9192\n { method: 'popup', minutes: 60 }, // \u63d0\u524d 1 \u5c0f\u6642\u63d0\u9192\n ]\n },\n \n // \u81ea\u8a02\u5c6c\u6027\uff08\u7528\u65bc\u8ffd\u8e64\u548c\u53bb\u91cd\uff09\n extendedProperties: {\n private: {\n source: 'onedrive_excel',\n importDate: new Date().toISOString(),\n responsiblePerson: data.\u8ca0\u8cac\u4eba || '',\n estimatedAmount: data.\u9810\u4f30\u91d1\u984d || ''\n }\n },\n \n // \u4fdd\u7559\u539f\u59cb\u8cc7\u6599\uff08\u65b9\u4fbf\u9664\u932f\uff09\n _originalData: data\n };\n \n // 5. \u52a0\u5165\u5230\u8f38\u51fa\u9663\u5217\n processedEvents.push({\n json: event,\n pairedItem: { item: item.pairedItem?.item || 0 }\n });\n}\n\n// \u8f38\u51fa\u8655\u7406\u5f8c\u7684\u8cc7\u6599\nconsole.log(`\u6210\u529f\u8655\u7406 ${processedEvents.length} \u7b46\u5718\u8cfc\u8cc7\u6599`);\nreturn processedEvents;"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
672,
0
],
"id": "d2e374bb-1471-4775-9a13-6bbfe0acabe7",
"name": "Code in JavaScript"
},
{
"parameters": {
"calendar": {
"__rl": true,
"value": "abc12207@gmail.com",
"mode": "list",
"cachedResultName": "abc12207@gmail.com"
},
"start": "={{ $json.startDateTime }}",
"end": "={{ $json.endDateTime }}",
"additionalFields": {
"allday": "no",
"color": "={{ $json.colorId }}",
"description": "={{ $json.description }}",
"location": "={{ $json.location }}",
"summary": "={{ $json.summary }}"
}
},
"type": "n8n-nodes-base.googleCalendar",
"typeVersion": 1.3,
"position": [
896,
80
],
"id": "a184f8b8-09c4-4198-a403-20188b6c1fe3",
"name": "Create an event",
"credentials": {
"googleCalendarOAuth2Api": {
"name": "<your credential>"
}
}
}
],
"connections": {
"When clicking \u2018Execute workflow\u2019": {
"main": [
[
{
"node": "Get rows from sheet",
"type": "main",
"index": 0
}
]
]
},
"Get rows from sheet": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "Code in JavaScript",
"type": "main",
"index": 0
}
]
]
},
"Code in JavaScript": {
"main": [
[
{
"node": "Create an event",
"type": "main",
"index": 0
}
]
]
},
"Create an event": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "a136f344-907c-400d-af45-05cb765d31dc",
"meta": {
"templateCredsSetupCompleted": true
},
"id": "1ocyjZR4RZSpPHGP",
"tags": []
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
googleCalendarOAuth2ApimicrosoftExcelOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
ShoppingCalendar. Uses microsoftExcel, googleCalendar. Event-driven trigger; 5 nodes.
Source: https://github.com/MoneyDemo/20251119.N8N/blob/efec3c86841a734b8c62aa13873734ebc25f3d9d/demo/workflows/ShoppingCalendar.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Agendamiento. Uses n8n-nodes-evolution-api, redis, dataTable, executeWorkflowTrigger. Event-driven trigger; 60 nodes.
This automated n8n workflow checks daily travel itineraries, syncs upcoming trips to Google Calendar, and sends reminder notifications to travelers via email or SMS. Perfect for travel agencies, tour
This automated n8n workflow checks daily class schedules, syncs upcoming classes to Google Calendar, and sends reminder notifications to students via email or SMS. Perfect for educational institutions
Create Zoom Meeting Link From Google Calendar Invite. Uses manualTrigger, zoom, dateTime, googleCalendar. Event-driven trigger; 6 nodes.
Gets Google Calendar events for the day (12 hours from execution time), and filters out in-person meetings, Signal meetings, and meetings canceled by Calendly ("transparent").