{ "nodes": [ { "name": "On clicking 'execute'", "type": "n8n-nodes-base.manualTrigger", "position": [ 120, 560 ], "parameters": {}, "typeVersion": 1, "id": "create-an-html-timesheet-report-0" }, { "name": "GetTimesheetRecords", "type": "n8n-nodes-base.function", "position": [ 300, 560 ], "parameters": { "functionCode": "return [{UserName: \"User 1 - Lead Programmer\",\n UserAvatar: \"https://www.gravatar.com/avatar/?d=robohash&s=32\",\n TaskTitle: \"Admin\",\n date: \"2022-05-31T00:00:00.0000000+02:00\",\n note: \"Creating invoices and submitting timesheets\",\n hours: 0.5},\n {UserName: \"User 1 - Lead Programmer\",\n UserAvatar: \"https://www.gravatar.com/avatar/?d=robohash&s=32\",\n TaskTitle: \"Admin\",\n date: \"2022-05-02T00:00:00.0000000+02:00\",\n note: \"Reporting last month's activity\",\n hours: 0.5},\n {UserName: \"User 2 - Designer\",\n UserAvatar: \"https://www.gravatar.com/avatar/?d=identicon&s=32\",\n TaskTitle: \"Admin\",\n date: \"2022-05-30T00:00:00.0000000+02:00\",\n note: \"Filling timesheets\",\n hours: 0.5},\n {UserName: \"User 2 - Designer\",\n UserAvatar: \"https://www.gravatar.com/avatar/?d=identicon&s=32\",\n TaskTitle: \"Admin\",\n date: \"2022-05-03T00:00:00.0000000+02:00\",\n note: \"Monthly retro meeting\",\n hours: 0.5},\n {UserName: \"User 1 - Lead Programmer\",\n UserAvatar: \"https://www.gravatar.com/avatar/?d=robohash&s=32\",\n TaskTitle: \"Client 1\",\n date: \"2022-05-26T00:00:00.0000000+02:00\",\n note: \"Weekly meeting\",\n hours: 0.5},\n {UserName: \"User 1 - Lead Programmer\",\n UserAvatar: \"https://www.gravatar.com/avatar/?d=robohash&s=32\",\n TaskTitle: \"Client 1\",\n date: \"2022-05-05T00:00:00.0000000+02:00\",\n note: \"Weekly meeting\",\n hours: 0.5},\n {UserName: \"User 1 - Lead Programmer\",\n UserAvatar: \"https://www.gravatar.com/avatar/?d=robohash&s=32\",\n TaskTitle: \"Client 1\",\n date: \"2022-05-19T00:00:00.0000000+02:00\",\n note: \"Weekly meeting\",\n hours: 0.5},\n {UserName: \"User 1 - Lead Programmer\",\n UserAvatar: \"https://www.gravatar.com/avatar/?d=robohash&s=32\",\n TaskTitle: \"Client 1\",\n date: \"2022-05-12T00:00:00.0000000+02:00\",\n note: \"Weekly meeting\",\n hours: 0.5},\n {UserName: \"User 1 - Lead Programmer\",\n UserAvatar: \"https://www.gravatar.com/avatar/?d=robohash&s=32\",\n TaskTitle: \"Client 1\",\n date: \"2022-05-12T00:00:00.0000000+02:00\",\n note: \"Programmed new feature\",\n hours: 4.5},\n {UserName: \"User 1 - Lead Programmer\",\n UserAvatar: \"https://www.gravatar.com/avatar/?d=robohash&s=32\",\n TaskTitle: \"Client 1\",\n date: \"2022-05-02T00:00:00.0000000+02:00\",\n note: \"Updated this and that\",\n hours: 2.75},\n {UserName: \"User 2 - Designer\",\n UserAvatar: \"https://www.gravatar.com/avatar/?d=identicon&s=32\",\n TaskTitle: \"Client 2\",\n date: \"2022-05-13T00:00:00.0000000+02:00\",\n note: \"Designed a new report template\",\n hours: 6.5},\n {UserName: \"User 2 - Designer\",\n UserAvatar: \"https://www.gravatar.com/avatar/?d=identicon&s=32\",\n TaskTitle: \"Client 2\",\n date: \"2022-05-23T00:00:00.0000000+02:00\",\n note: \"Presented the results\",\n hours: 1.5}\n ];" }, "typeVersion": 1, "id": "create-an-html-timesheet-report-1" }, { "name": "Build the timesheet report", "type": "n8n-nodes-base.function", "typeVersion": 1, "parameters": { "functionCode": "function report({records}){\n if(!Array.isArray(records)||!records.length)throw Error('Provide timesheet records');const esc=x=>String(x??'').replace(/[&<>\"']/g,c=>({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));const rows=records.map(r=>{if(!r||typeof r.UserName!=='string'||!r.UserName||typeof r.TaskTitle!=='string'||!r.TaskTitle||typeof r.date!=='string'||typeof r.UserAvatar!=='string'||!/^https:\\/\\//i.test(r.UserAvatar)||!Number.isFinite(Number(r.hours)))throw Error('Invalid timesheet record');return r}).sort((a,b)=>a.UserName.localeCompare(b.UserName)||a.TaskTitle.localeCompare(b.TaskTitle)||a.date.localeCompare(b.date));let html='Timesheet report

Timesheet report

',user='',task='',total=0;for(const r of rows){if(r.UserName!==user||r.TaskTitle!==task){if(task)html+='

'+total.toFixed(2)+' - Total hours for this task

';if(r.UserName!==user){user=r.UserName;html+='

\"\" '+esc(user)+'

'}task=r.TaskTitle;total=0;html+='

'+esc(task)+'

'}total+=Number(r.hours);html+=''}html+='
DateHoursTask Description
'+esc(r.date.split('T')[0])+''+Number(r.hours).toFixed(2)+''+esc(r.note)+'

'+total.toFixed(2)+' - Total hours for this task

Timesheet report generated on: '+new Date().toISOString().slice(0,10)+'

';return{html};}\n\nreturn [{json:{data:report({records:items.map(x=>x.json)}).html}}];" }, "id": "create-an-html-timesheet-report-2" }, { "name": "Move Binary Data1", "type": "n8n-nodes-base.moveBinaryData", "position": [ 1520, 580 ], "parameters": { "mode": "jsonToBinary", "options": { "fileName": "report.html", "mimeType": "text/html", "useRawData": true }, "convertAllData": false }, "typeVersion": 1, "id": "create-an-html-timesheet-report-3" } ], "connections": { "On clicking 'execute'": { "main": [ [ { "node": "GetTimesheetRecords", "type": "main", "index": 0 } ] ] }, "GetTimesheetRecords": { "main": [ [ { "node": "Build the timesheet report", "type": "main", "index": 0 } ] ] }, "Build the timesheet report": { "main": [ [ { "node": "Move Binary Data1", "type": "main", "index": 0 } ] ] } }, "name": "Create an HTML Timesheet Report", "active": false, "pinData": {} }