自动通过 Gmail 发送 Square 月度销售报告
高级
这是一个Content Creation, Multimodal AI领域的自动化工作流,包含 16 个节点。主要使用 If, Code, Gmail, SplitOut, HttpRequest 等节点。 自动通过 Gmail 发送 Square 月度销售报告
前置要求
- •Google 账号和 Gmail API 凭证
- •可能需要目标 API 的认证凭证
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"meta": {
"instanceId": "d6e2f2f655b1125bbcac14a4cac6d2e46c7a150e927f85fc96fdca1a6dc39e0e",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "49c8db5b-81ca-42de-b51b-20b55b564d08",
"name": "获取 Square 位置",
"type": "n8n-nodes-base.httpRequest",
"position": [
1312,
544
],
"parameters": {
"url": "https://connect.squareup.com/v2/locations",
"options": {},
"sendHeaders": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"credentials": {
"httpHeaderAuth": {
"id": "n1GRrdbh899dbLYB",
"name": "Square Header Auth"
}
},
"typeVersion": 4.2
},
{
"id": "ddd37765-27c7-4e42-8c55-3aaac40181c3",
"name": "将位置转换为列表",
"type": "n8n-nodes-base.splitOut",
"position": [
1536,
544
],
"parameters": {
"include": "selectedOtherFields",
"options": {},
"fieldToSplitOut": "locations",
"fieldsToInclude": "id"
},
"typeVersion": 1
},
{
"id": "e030b283-e555-44f1-862f-b001cfb1e128",
"name": "忽略无销售的位置",
"type": "n8n-nodes-base.if",
"position": [
2032,
544
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "498f5fab-6930-4e89-9fbe-0d67671da8d2",
"operator": {
"type": "array",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.orders }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "de5bca22-f883-41dd-a82e-960c6e3a9328",
"name": "从 Square 获取销售数据",
"type": "n8n-nodes-base.httpRequest",
"position": [
1792,
544
],
"parameters": {
"url": "https://connect.squareup.com/v2/orders/search",
"method": "POST",
"options": {
"batching": {
"batch": {}
}
},
"jsonBody": "={\n \"location_ids\": [\"{{ $json.locations.id }}\"],\n \"query\": {\n \"filter\": {\n \"state_filter\": {\n \"states\": [\"COMPLETED\"]\n },\n \"date_time_filter\": {\n \"created_at\": {\n \"start_at\": \"{{ $('Get Dates From Last Month').item.json.date }}T00:00:00-05:00\",\n \"end_at\": \"{{ $('Get Dates From Last Month').item.json.date }}T23:59:59-05:00\"\n }\n }\n }\n },\n \"limit\": 1000,\n \"return_entries\": false\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"credentials": {
"httpHeaderAuth": {
"id": "n1GRrdbh899dbLYB",
"name": "Square Header Auth"
}
},
"executeOnce": false,
"typeVersion": 4.2
},
{
"id": "fd52f1c3-b58e-4452-82a9-20451d613768",
"name": "编译销售报告",
"type": "n8n-nodes-base.code",
"position": [
2320,
544
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Date and Location Metadata\nconst date = $('Get Dates From Last Month').item.json.date;\nconst location_id = $json.orders[0].location_id || null;\nconst location_name = $('Get Square Locations').item.json.locations.find(locations => locations.id === location_id)?.name;\n\n// Our Result Variables\nlet total_money = 0;\nlet total_tax = 0;\nlet total_discount = 0;\nlet total_tip = 0;\nlet total_returns = 0;\nlet cash_rounding = 0;\n\nlet cash_tender = 0;\nlet card_tender = 0;\nlet gift_card_tender = 0;\nlet other_tender = 0;\nlet fees = 0;\n\n// Loop Through Each Order\nfor (const sale of $json.orders) {\n\n // Add the sales, taxes, discounts and tips\n total_money += sale.total_money?.amount || 0;\n total_tax += sale.total_tax_money?.amount || 0;\n total_discount += -(sale.total_discount_money?.amount || 0);\n total_tip += sale.total_tip_money?.amount || 0;\n if (sale.rounding_adjustment) {\n cash_rounding += sale.rounding_adjustment.amount_money?.amount || 0;\n }\n\n \n if (sale.return_amounts) {\n // If there are returns, subtract from sales totals and add to return amount total\n total_money -= sale.return_amounts?.total_money?.amount || 0;\n total_tax -= sale.return_amounts?.tax_money?.amount || 0;\n total_discount -= sale.return_amounts?.discount_money?.amount || 0;\n total_tip -= sale.return_amounts?.tip_money?.amount || 0;\n \n total_returns += -(sale.return_amounts?.total_money?.amount || 0);\n total_returns -= -(sale.return_amounts?.tax_money?.amount || 0);\n total_returns -= -(sale.return_amounts?.tip_money?.amount || 0);\n total_returns -= -(sale.return_amounts?.discount_money?.amount || 0);\n \n // If an array of refunds is provided\n for (const refund of sale.refunds || []) {\n const transaction_id = refund.transaction_id;\n \n // Look for the original sale this refund refers to\n const original_sale = $json.orders.find(original =>\n original.id && transaction_id && original.id.includes(transaction_id)\n );\n \n if (original_sale) {\n if (original_sale.rounding_adjustment) {\n const amount = original_sale.rounding_adjustment.amount_money?.amount || 0;\n cash_rounding -= amount;\n total_returns += amount;\n }\n \n if (original_sale.tenders) {\n for (const tender of original_sale.tenders) {\n if (tender.id === refund.tender_id) {\n const amount = refund.amount_money?.amount || 0;\n if (tender.type === 'CARD') card_tender -= amount;\n else if (tender.type === 'CASH') cash_tender -= amount;\n else if (tender.type === 'SQUARE_GIFT_CARD') gift_card_tender -= amount;\n else other_tender -= amount;\n \n if (refund.processing_fee_money && tender.id === refund.tender_id) {\n fees -= refund.processing_fee_money.amount || 0;\n }\n }\n }\n }\n }\n }\n }\n \n if (sale.tenders) {\n for (const tender of sale.tenders) {\n const amount = tender.amount_money?.amount || 0;\n if (tender.type === 'CARD') card_tender += amount;\n else if (tender.type === 'CASH') cash_tender += amount;\n else if (tender.type === 'SQUARE_GIFT_CARD') gift_card_tender += amount;\n else other_tender += amount;\n \n if (tender.processing_fee_money) {\n fees -= tender.processing_fee_money.amount || 0;\n }\n }\n }\n \n}\n\n// Final computed values\nconst net_sales = total_money - total_tip - total_tax - cash_rounding;\nconst gross_sales = net_sales - total_discount - total_returns;\nconst net_total = cash_tender + card_tender + gift_card_tender + other_tender + fees;\n\nreturn {\n json: {\n date,\n location_id,\n location_name,\n gross_sales: gross_sales / 100.0,\n total_returns: total_returns / 100.0,\n total_discount: total_discount / 100.0,\n net_sales: net_sales / 100.0,\n total_tax: total_tax / 100.0,\n total_tip: total_tip / 100.0,\n cash_rounding: cash_rounding / 100.0,\n total_payments_collected: total_money / 100.0,\n cash: cash_tender / 100.0,\n card: card_tender / 100.0,\n gift_card: gift_card_tender / 100.0,\n other: other_tender / 100.0,\n fees: fees / 100.0,\n net_total: net_total / 100.0,\n }\n};"
},
"typeVersion": 2
},
{
"id": "cae9b53a-144d-482a-be43-245acb088f35",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
704,
352
],
"parameters": {
"color": 5,
"height": 420,
"content": "## 触发器"
},
"typeVersion": 1
},
{
"id": "93058d76-e0fa-4479-a6cd-d3df49dcb185",
"name": "便签2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1232,
352
],
"parameters": {
"color": 5,
"width": 460,
"height": 420,
"content": "## 获取 Square 位置并分别处理每个位置"
},
"typeVersion": 1
},
{
"id": "7636415e-1d8b-4643-9935-072fff0f8fdb",
"name": "便签3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1712,
352
],
"parameters": {
"color": 5,
"height": 420,
"content": "## 从 Square 获取销售数据"
},
"typeVersion": 1
},
{
"id": "7a4389ca-bde6-4eb4-a28f-600352bdcde8",
"name": "便签说明4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2256,
352
],
"parameters": {
"color": 5,
"height": 420,
"content": "## 为每个位置编译报告"
},
"typeVersion": 1
},
{
"id": "645aae4e-6bd7-40da-94bd-d43e108f445a",
"name": "定时触发器",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
784,
544
],
"parameters": {
"rule": {
"interval": [
{
"field": "months",
"triggerAtHour": 8
}
]
}
},
"typeVersion": 1.2
},
{
"id": "c9f0d20a-ab6f-4027-97b2-bda40e2e0a85",
"name": "便签说明5",
"type": "n8n-nodes-base.stickyNote",
"position": [
2512,
352
],
"parameters": {
"color": 5,
"height": 420,
"content": "## 将 Square 销售摘要转换为 CSV 文件"
},
"typeVersion": 1
},
{
"id": "ed7fe015-7025-41db-be57-2712514115dc",
"name": "将销售摘要转换为 CSV 文件",
"type": "n8n-nodes-base.convertToFile",
"position": [
2576,
544
],
"parameters": {
"options": {
"fileName": "=sales_report_{{ $('Schedule Trigger').item.json.timestamp }}.csv"
},
"binaryPropertyName": "sales_report"
},
"typeVersion": 1.1
},
{
"id": "b06c9ef4-4711-4e3a-9f00-e15fb1a67f53",
"name": "便签 6",
"type": "n8n-nodes-base.stickyNote",
"position": [
2768,
352
],
"parameters": {
"color": 5,
"height": 420,
"content": "## 将报告发送给财务团队/经理"
},
"typeVersion": 1
},
{
"id": "1cd8c221-c9ee-47a3-b878-74b6a47738c0",
"name": "发送报告",
"type": "n8n-nodes-base.gmail",
"position": [
2848,
544
],
"webhookId": "b38e72a3-bcf6-4e82-840e-d0171ea71138",
"parameters": {
"sendTo": "rosh.edwin15@gmail.com",
"message": "=<p>Hello User,</p><p>Please see the attached report containing last month's sales!</p><p>Best,<br> An Efficient Person</p>",
"options": {
"attachmentsUi": {
"attachmentsBinary": [
{
"property": "sales_report"
}
]
}
},
"subject": "=Your Last Month's Square Sales Report"
},
"credentials": {
"gmailOAuth2": {
"id": "x5LsvRUYpInxYmcG",
"name": "Rosh's Personal Email"
}
},
"typeVersion": 2.1
},
{
"id": "2b30411b-4154-4a06-addb-3c6a4e681b16",
"name": "便签 7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-64,
-32
],
"parameters": {
"width": 736,
"height": 1440,
"content": "## 通过 Gmail 自动发送来自 Square 的月度销售报告"
},
"typeVersion": 1
},
{
"id": "9effe5b0-f320-4313-989d-a5745f9a44d5",
"name": "获取上个月日期",
"type": "n8n-nodes-base.code",
"position": [
1040,
544
],
"parameters": {
"jsCode": "const inputDate = new Date($input.first().json.timestamp);\nconst year = inputDate.getFullYear();\nconst month = inputDate.getMonth();\n\n// Get first day of previous month\nconst firstDay = new Date(year, month - 1, 1);\n\n// Get last day of previous month by setting date to 0 of current month\nconst lastDay = new Date(year, month, 0).getDate();\n\nconst output = [];\n\nfor (let day = 1; day <= lastDay; day++) {\n const date = new Date(year, month - 1, day);\n const formatted = date.toISOString().split('T')[0];\n output.push({ json: { date: formatted } });\n}\n\nreturn output;\n"
},
"typeVersion": 2
}
],
"pinData": {},
"connections": {
"Send Report": {
"main": [
[]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Get Dates From Last Month",
"type": "main",
"index": 0
}
]
]
},
"Get Square Locations": {
"main": [
[
{
"node": "Turn Locations Into List",
"type": "main",
"index": 0
}
]
]
},
"Compile Sales Reports": {
"main": [
[
{
"node": "Convert Sales Summary to CSV File",
"type": "main",
"index": 0
}
]
]
},
"Get Sales from Square": {
"main": [
[
{
"node": "Ignore Locations w/o Sales",
"type": "main",
"index": 0
}
]
]
},
"Turn Locations Into List": {
"main": [
[
{
"node": "Get Sales from Square",
"type": "main",
"index": 0
}
]
]
},
"Get Dates From Last Month": {
"main": [
[
{
"node": "Get Square Locations",
"type": "main",
"index": 0
}
]
]
},
"Ignore Locations w/o Sales": {
"main": [
[
{
"node": "Compile Sales Reports",
"type": "main",
"index": 0
}
]
]
},
"Convert Sales Summary to CSV File": {
"main": [
[
{
"node": "Send Report",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - 内容创作, 多模态 AI
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
自动通过 Outlook 发送 Square 月度销售报告
自动通过 Outlook 发送 Square 月度销售报告
If
Code
Split Out
+5
16 节点Rosh Ragel
文档提取
自动通过 Gmail 发送 Square 每日销售报告
自动通过 Gmail 发送 Square 每日销售报告
If
Code
Gmail
+5
15 节点Rosh Ragel
客户关系管理
自动通过 Gmail 发送 Square 每周销售报告
自动通过 Gmail 发送 Square 每周销售报告
If
Code
Gmail
+5
16 节点Rosh Ragel
客户关系管理
使用Groq、Gemini和Slack审批系统自动化RSS到Medium发布
通过Groq、Gemini和Slack审批系统实现RSS到Medium发布的自动化流程
If
Set
Code
+16
41 节点ObisDev
内容创作
WordPress博客自动化专业版(深度研究)v2.1市场
使用GPT-4o、Perplexity AI和多语言支持自动化SEO优化的博客创建
If
Set
Xml
+27
125 节点Daniel Ng
内容创作
自动通过 Microsoft Outlook 发送 Square 每日销售摘要报告
自动通过 Microsoft Outlook 发送 Square 每日销售摘要报告
If
Code
Split Out
+5
15 节点Rosh Ragel
客户关系管理