Torna ai modelli
MODELLO WORKFLOW
N8n Template Toggle Raport With Projects | Operasyon için n8n Otomasyon İş Akışı Şablonu (HTTP)
n8n için hazır otomasyon şablonu: N8n Template Toggle Raport With Projects. 7 düğüm. Entegrasyonlar: HTTP. JSON'u kopyalayıp n8n'e içe aktarın.
7 nodiN8n_Template_Toggle_Raport_With_Projects-workflow.json
{"id": "LLC5sbrvJwsCxFXq","meta": {"instanceId": "5e682be7cc4c76c24876e009260b2f7cab628b1b42d88efaa638dccb09cd1db5","templateCredsSetupCompleted": true},"name": "n8n template - toggle raport with projects","tags": ["toggle"],"nodes": [{"id": "2632242c-671b-4e26-a9f4-534ecf3cfea6","name": "Get Toggle Projects","type": "n8n-nodes-base.httpRequest","position": [-304,-128],"parameters": {"url": "https://api.track.toggl.com/api/v9/workspaces/TOGGL_WORKSPACE_ID/projects","options": {"pagination": {"pagination": {"parameters": {"parameters": [{"name": "page","value": "={{ $pageCount + 1 }}"}]}}}},"sendQuery": true,"authentication": "predefinedCredentialType","queryParameters": {"parameters": [{}]},"nodeCredentialType": "togglApi"},"credentials": {"togglApi": {"id": "MiPq5PIxcT1suV6B","name": "Unnamed credential"}},"typeVersion": 4.2},{"id": "60dd3732-4a0f-4544-b52e-1b2b2cb969cb","name": "Schedule Trigger","type": "n8n-nodes-base.scheduleTrigger","position": [-704,-240],"parameters": {"rule": {"interval": [{"field": "months","triggerAtHour": 4}]}},"typeVersion": 1.2},{"id": "63830937-0d2e-4ac2-bf8b-037483deba94","name": "Sticky Note1","type": "n8n-nodes-base.stickyNote","position": [-496,-560],"parameters": {"color": 4,"width": 662,"height": 602,"content": "## Fetch Toggl clients, projects, and summary data form last month via HTTP nodes\n\n1. Enter your TOGGL_WORKSPACE_ID"},"typeVersion": 1},{"id": "871b782a-06c8-464f-abe0-6cfbe93dfe3d","name": "Sticky Note3","type": "n8n-nodes-base.stickyNote","position": [176,-560],"parameters": {"color": 4,"width": 310,"height": 602,"content": "## Merge data to associate projects with clients.\n\n"},"typeVersion": 1},{"id": "43d03168-970c-44a1-93ac-6a1d0289def2","name": "Sticky Note4","type": "n8n-nodes-base.stickyNote","position": [496,-560],"parameters": {"color": 4,"width": 294,"height": 602,"content": "## Generate an HTML report with hours per client and per project\n\n"},"typeVersion": 1},{"id": "66c498df-8b6d-4ea7-b717-968411b1e918","name": "Sticky Note5","type": "n8n-nodes-base.stickyNote","position": [-800,-560],"parameters": {"color": 4,"width": 294,"height": 602,"content": "## Schedule automation (monthly)\n"},"typeVersion": 1},{"id": "8db1e677-00e5-416d-b0c8-97faf5725149","name": "README","type": "n8n-nodes-base.stickyNote","position": [-1232,-784],"parameters": {"width": 416,"height": 832,"content": "## Description\nThis workflow fetches Toggl Track summary data for the previous month, aggregates hours per client and project, and emails a clean HTML report via Resend.\n\n## How it works\n1) Compute previous month period.\n2) Fetch Toggl summary (grouping=clients, sub_grouping=projects).\n3) Fetch clients and projects for proper names.\n4) Merge and aggregate seconds to hours.\n5) Generate HTML raport \n6) Send raport via Resend API.\n\n## Requirements\n- [Toggl free account](https://accounts.toggl.com/track/signup/) (Login, Pass, TOGGL_WORKSPACE_ID)\n- Resend.com free account RESEND_API_KEY\n\n## Customization\n- Change trigger time in the Schedule Trigger node.\n- Modify period calculation for weekly/quarterly in Get Toggle Summary node.\n- Add archived projects by querying with active=false&archived=true and merging.\n\n## Documentation\n- [Toggle docs](https://engineering.toggl.com/docs/)\n- [Resend.com docs](https://resend.com/docs/)\n\n## Author\nKrystian Syryca - [krsweb.pl](https://krsweb.pl)\n"},"typeVersion": 1},{"id": "3aa03862-f0a0-40e7-9d68-20d656a0d304","name": "Get Toggle Summary","type": "n8n-nodes-base.httpRequest","position": [-304,-352],"parameters": {"url": "https://api.track.toggl.com/reports/api/v3/workspace/TOGGL_WORKSPACE_ID/summary/time_entries","method": "POST","options": {},"sendBody": true,"sendHeaders": true,"authentication": "predefinedCredentialType","bodyParameters": {"parameters": [{"name": "start_date","value": "={{ $now.minus({ months: 1 }).startOf('month').toFormat('yyyy-MM-dd') }}"},{"name": "end_date","value": "={{ $now.minus({ months: 1 }).endOf('month').toFormat('yyyy-MM-dd') }}"},{"name": "grouping","value": "clients"},{"name": "sub_grouping","value": "projects"}]},"headerParameters": {"parameters": [{"name": "Content-Type","value": "application/json"}]},"nodeCredentialType": "togglApi"},"credentials": {"togglApi": {"id": "MiPq5PIxcT1suV6B","name": "Unnamed credential"}},"typeVersion": 4.2},{"id": "6d86fedc-c291-43dd-b008-1e0395d48d9f","name": "Prepare html raport","type": "n8n-nodes-base.code","position": [576,-240],"parameters": {"jsCode": "const data = $input.all().map(i => i.json);\nconst period = $json.period || \"Previous month\";\n\n// Group by clinet\nconst clients = {};\nfor (const i of data) {\n const clientId = i.client_id || i.cid;\n const clientName = i.client_name || \"(missing customer name)\";\n if (!clients[clientId]) {\n clients[clientId] = { name: clientName, projects: [] };\n }\n clients[clientId].projects.push({\n project_id: i.project_id,\n project_name: i.name || \"(bez nazwy projektu)\",\n seconds: Number(i.seconds) || 0\n });\n}\n\n// Sum clients time\nfor (const c of Object.values(clients)) {\n c.totalSeconds = c.projects.reduce((a, p) => a + p.seconds, 0);\n}\n\n// Sort clients\nconst sortedClients = Object.entries(clients)\n .sort(([, a], [, b]) => b.totalSeconds - a.totalSeconds);\n\n// Generate html raport\nlet totalSeconds = 0;\nlet html = \"\";\nhtml += \"Time Report per Client and Project - \" + period + \"
\";\n\nfor (const [clientId, c] of sortedClients) {\n const clientHours = (c.totalSeconds / 3600).toFixed(2);\n totalSeconds += c.totalSeconds;\n\n html += \"\" + c.name + \" – \" + clientHours + \" h
\";\n html += \"\";\n\n const sortedProjects = c.projects.sort((a, b) => b.seconds - a.seconds);\n for (const p of sortedProjects) {\n const hours = (p.seconds / 3600).toFixed(2);\n html += \"
\";\n}\n\nhtml += \"- \" + p.project_name + \" – \" + hours + \" h
\";\n }\n\n html += \"Total hours: \" + (totalSeconds / 3600).toFixed(2) + \"
\";\nhtml += \"\";\n\nreturn [{\n json: {\n subject: \"Time Report per Client and Project - \" + period,\n html\n }\n}];\n"},"typeVersion": 2},{"id": "90949ac4-fd1d-4321-a9e1-c985a23e7b12","name": "Sticky Note","type": "n8n-nodes-base.stickyNote","position": [800,-560],"parameters": {"color": 4,"width": 294,"height": 602,"content": "## Send the report via Resend email API.\n1. Enter RESEND_API_KEY\n2. Enter FROM and TO email addresses\n\n"},"typeVersion": 1},{"id": "3cf0af49-6e80-4dbc-8395-9861ed371a69","name": "Send email via Resend","type": "n8n-nodes-base.httpRequest","position": [864,-240],"parameters": {"url": "https://api.resend.com/emails","method": "POST","options": {},"jsonBody": "={\n \"from\": \"\",\n \"to\": [\"to@yourdomain.com\"],\n \"subject\": \"{{$json.subject}}\",\n \"html\": \"{{$json.html}}\"\n}\n", "sendBody": true,"sendHeaders": true,"specifyBody": "json","headerParameters": {"parameters": [{"name": "Authorization","value": "Bearer YOUR_TOKEN_HERE"},{"name": "Content-Type","value": "application/json"}]}},"typeVersion": 4.2},{"id": "be2604f7-a5ca-46fe-b711-f53a81b1363e","name": "Merge data","type": "n8n-nodes-base.merge","position": [288,-240],"parameters": {"mode": "combine","options": {},"advanced": true,"joinMode": "enrichInput1","mergeByFields": {"values": [{"field1": "project_id","field2": "id"}]}},"typeVersion": 3.2},{"id": "29d8af43-2951-4c9e-80de-556f65588a65","name": "Prepare projects list","type": "n8n-nodes-base.code","position": [-80,-352],"parameters": {"jsCode": "const groups = $json.groups || [];\nconst result = [];\n\nfor (const g of groups) {\n const clientId = Number(g.id);\n const subs = g.sub_groups || [];\n for (const s of subs) {\n result.push({\n json: {\n client_id: clientId,\n project_id: Number(s.id),\n seconds: Number(s.seconds) || 0\n }\n });\n }\n}\n\nreturn result;\n"},"typeVersion": 2}],"active": false,"pinData": {},"settings": {"executionOrder": "v1"},"versionId": "873a699b-08da-4b2e-b0af-66c2cd539290","connections": {"Merge data": {"main": [[{"node": "Prepare html raport","type": "main","index": 0}]]},"Schedule Trigger": {"main": [[{"node": "Get Toggle Summary","type": "main","index": 0},{"node": "Get Toggle Projects","type": "main","index": 0}]]},"Get Toggle Summary": {"main": [[{"node": "Prepare projects list","type": "main","index": 0}]]},"Get Toggle Projects": {"main": [[{"node": "Merge data","type": "main","index": 1}]]},"Prepare html raport": {"main": [[{"node": "Send email via Resend","type": "main","index": 0}]]},"Prepare projects list": {"main": [[{"node": "Merge data","type": "main","index": 0}]]}}}
In n8n Editor: incolla con Ctrl+V→Il workflow verrà creato