{"flow":{"id":82,"summary":"Reimbursement","versions":[300,301,302,303,305],"created_by":"nextcloud","created_at":"2026-04-27T13:33:28.122Z","votes":0,"approved":true,"apps":["nextcloud"],"value":{"modules":[{"id":"model","value":{"lock":"{\n  \"dependencies\": {}\n}\n//bun.lock\n<empty>","type":"rawscript","content":"// import * as wmill from \"windmill-client\"\n\n// Local model that works well qwen3.4-4b or bigger\n// Google model that works well gemini 2.5-flash or better\n// Claude model that works well Sonnet 4.5 or better\nexport async function main() {\n  return \"mistralai/Mistral-Small-24B-Instruct\" \n}\n","language":"bun","input_transforms":{}},"summary":"Get model (Change model here)"},{"id":"submission","value":{"path":"hub/28147/nextcloud/get_a_form_submission_from_nextcloud_forms","type":"script","is_trigger":false,"input_transforms":{"formId":{"expr":"flow_input.event.submission.formId","type":"javascript"},"nextcloud":{"expr":"flow_input.authentication.trigger","type":"javascript"},"submissionId":{"expr":"flow_input.event.submission.id","type":"javascript"}}},"summary":"Get a form submission from Nextcloud Forms (nextcloud)"},{"id":"folder_name","value":{"lock":"{\n  \"dependencies\": {}\n}\n//bun.lock\n<empty>","type":"rawscript","content":"// import * as wmill from \"windmill-client\"\n\nexport async function main(userId: string) {\n  return `/Reimbursement/Reimbursement for ${userId} on ${(new Date()).toUTCString().replaceAll(\":\", \"-\").replaceAll(\",\",\"\")}`\n}\n","language":"bun","input_transforms":{"userId":{"expr":"flow_input.authentication.trigger.userId","type":"javascript"}}}},{"id":"d","value":{"lock":"{\n  \"dependencies\": {\n    \"axios\": \"latest\"\n  }\n}\n//bun.lock\n{\n  \"lockfileVersion\": 1,\n  \"configVersion\": 1,\n  \"workspaces\": {\n    \"\": {\n      \"dependencies\": {\n        \"axios\": \"latest\",\n      },\n    },\n  },\n  \"packages\": {\n    \"asynckit\": [\"asynckit@0.4.0\", \"\", {}, \"sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==\"],\n\n    \"axios\": [\"axios@1.13.6\", \"\", { \"dependencies\": { \"follow-redirects\": \"^1.15.11\", \"form-data\": \"^4.0.5\", \"proxy-from-env\": \"^1.1.0\" } }, \"sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==\"],\n\n    \"call-bind-apply-helpers\": [\"call-bind-apply-helpers@1.0.2\", \"\", { \"dependencies\": { \"es-errors\": \"^1.3.0\", \"function-bind\": \"^1.1.2\" } }, \"sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==\"],\n\n    \"combined-stream\": [\"combined-stream@1.0.8\", \"\", { \"dependencies\": { \"delayed-stream\": \"~1.0.0\" } }, \"sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==\"],\n\n    \"delayed-stream\": [\"delayed-stream@1.0.0\", \"\", {}, \"sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==\"],\n\n    \"dunder-proto\": [\"dunder-proto@1.0.1\", \"\", { \"dependencies\": { \"call-bind-apply-helpers\": \"^1.0.1\", \"es-errors\": \"^1.3.0\", \"gopd\": \"^1.2.0\" } }, \"sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==\"],\n\n    \"es-define-property\": [\"es-define-property@1.0.1\", \"\", {}, \"sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==\"],\n\n    \"es-errors\": [\"es-errors@1.3.0\", \"\", {}, \"sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==\"],\n\n    \"es-object-atoms\": [\"es-object-atoms@1.1.1\", \"\", { \"dependencies\": { \"es-errors\": \"^1.3.0\" } }, \"sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==\"],\n\n    \"es-set-tostringtag\": [\"es-set-tostringtag@2.1.0\", \"\", { \"dependencies\": { \"es-errors\": \"^1.3.0\", \"get-intrinsic\": \"^1.2.6\", \"has-tostringtag\": \"^1.0.2\", \"hasown\": \"^2.0.2\" } }, \"sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==\"],\n\n    \"follow-redirects\": [\"follow-redirects@1.15.11\", \"\", {}, \"sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==\"],\n\n    \"form-data\": [\"form-data@4.0.5\", \"\", { \"dependencies\": { \"asynckit\": \"^0.4.0\", \"combined-stream\": \"^1.0.8\", \"es-set-tostringtag\": \"^2.1.0\", \"hasown\": \"^2.0.2\", \"mime-types\": \"^2.1.12\" } }, \"sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==\"],\n\n    \"function-bind\": [\"function-bind@1.1.2\", \"\", {}, \"sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==\"],\n\n    \"get-intrinsic\": [\"get-intrinsic@1.3.0\", \"\", { \"dependencies\": { \"call-bind-apply-helpers\": \"^1.0.2\", \"es-define-property\": \"^1.0.1\", \"es-errors\": \"^1.3.0\", \"es-object-atoms\": \"^1.1.1\", \"function-bind\": \"^1.1.2\", \"get-proto\": \"^1.0.1\", \"gopd\": \"^1.2.0\", \"has-symbols\": \"^1.1.0\", \"hasown\": \"^2.0.2\", \"math-intrinsics\": \"^1.1.0\" } }, \"sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==\"],\n\n    \"get-proto\": [\"get-proto@1.0.1\", \"\", { \"dependencies\": { \"dunder-proto\": \"^1.0.1\", \"es-object-atoms\": \"^1.0.0\" } }, \"sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==\"],\n\n    \"gopd\": [\"gopd@1.2.0\", \"\", {}, \"sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==\"],\n\n    \"has-symbols\": [\"has-symbols@1.1.0\", \"\", {}, \"sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==\"],\n\n    \"has-tostringtag\": [\"has-tostringtag@1.0.2\", \"\", { \"dependencies\": { \"has-symbols\": \"^1.0.3\" } }, \"sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==\"],\n\n    \"hasown\": [\"hasown@2.0.2\", \"\", { \"dependencies\": { \"function-bind\": \"^1.1.2\" } }, \"sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==\"],\n\n    \"math-intrinsics\": [\"math-intrinsics@1.1.0\", \"\", {}, \"sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==\"],\n\n    \"mime-db\": [\"mime-db@1.52.0\", \"\", {}, \"sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==\"],\n\n    \"mime-types\": [\"mime-types@2.1.35\", \"\", { \"dependencies\": { \"mime-db\": \"1.52.0\" } }, \"sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==\"],\n\n    \"proxy-from-env\": [\"proxy-from-env@1.1.0\", \"\", {}, \"sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==\"],\n  }\n}\n","type":"rawscript","content":"import axios from \"axios\";\n\nexport async function main(\n    nextcloud: RT.Nextcloud,\n    path: string,\n) {\n\n    try {\n        const res = await axios.request(\n            {\n                method: \"MKCOL\",\n                url: `/remote.php/dav/files/${nextcloud.userId}/${path}`,\n                baseURL: nextcloud.baseUrl,\n                headers: {\n                    Authorization: `Basic ${btoa(`${nextcloud.userId}:${nextcloud.token}`)\n                    }`,\n                },\n            },\n        );\n        return res.data;\n    } catch (e) {\n        console.log(e.response.data);\n    }\n}","language":"bun","input_transforms":{"path":{"expr":"results.folder_name","type":"javascript"},"nextcloud":{"expr":"flow_input.authentication.owner","type":"javascript"}}},"summary":"Create Folder"},{"id":"dh","value":{"type":"branchall","branches":[{"expr":"","modules":[{"id":"file_analysis","value":{"type":"forloopflow","squash":false,"modules":[{"id":"path","value":{"path":"hub/28172/nextcloud/path_from_fileid","type":"script","is_trigger":false,"input_transforms":{"fileid":{"expr":"flow_input.iter.value.fileId","type":"javascript"},"ncResource":{"expr":"flow_input.authentication.trigger","type":"javascript"}}},"summary":"Path from Fileid (nextcloud)"},{"id":"c","value":{"lock":"{\n  \"dependencies\": {\n    \"axios\": \"latest\"\n  }\n}\n//bun.lock\n{\n  \"lockfileVersion\": 1,\n  \"configVersion\": 1,\n  \"workspaces\": {\n    \"\": {\n      \"dependencies\": {\n        \"axios\": \"latest\",\n      },\n    },\n  },\n  \"packages\": {\n    \"asynckit\": [\"asynckit@0.4.0\", \"\", {}, \"sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==\"],\n\n    \"axios\": [\"axios@1.13.6\", \"\", { \"dependencies\": { \"follow-redirects\": \"^1.15.11\", \"form-data\": \"^4.0.5\", \"proxy-from-env\": \"^1.1.0\" } }, \"sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==\"],\n\n    \"call-bind-apply-helpers\": [\"call-bind-apply-helpers@1.0.2\", \"\", { \"dependencies\": { \"es-errors\": \"^1.3.0\", \"function-bind\": \"^1.1.2\" } }, \"sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==\"],\n\n    \"combined-stream\": [\"combined-stream@1.0.8\", \"\", { \"dependencies\": { \"delayed-stream\": \"~1.0.0\" } }, \"sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==\"],\n\n    \"delayed-stream\": [\"delayed-stream@1.0.0\", \"\", {}, \"sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==\"],\n\n    \"dunder-proto\": [\"dunder-proto@1.0.1\", \"\", { \"dependencies\": { \"call-bind-apply-helpers\": \"^1.0.1\", \"es-errors\": \"^1.3.0\", \"gopd\": \"^1.2.0\" } }, \"sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==\"],\n\n    \"es-define-property\": [\"es-define-property@1.0.1\", \"\", {}, \"sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==\"],\n\n    \"es-errors\": [\"es-errors@1.3.0\", \"\", {}, \"sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==\"],\n\n    \"es-object-atoms\": [\"es-object-atoms@1.1.1\", \"\", { \"dependencies\": { \"es-errors\": \"^1.3.0\" } }, \"sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==\"],\n\n    \"es-set-tostringtag\": [\"es-set-tostringtag@2.1.0\", \"\", { \"dependencies\": { \"es-errors\": \"^1.3.0\", \"get-intrinsic\": \"^1.2.6\", \"has-tostringtag\": \"^1.0.2\", \"hasown\": \"^2.0.2\" } }, \"sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==\"],\n\n    \"follow-redirects\": [\"follow-redirects@1.15.11\", \"\", {}, \"sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==\"],\n\n    \"form-data\": [\"form-data@4.0.5\", \"\", { \"dependencies\": { \"asynckit\": \"^0.4.0\", \"combined-stream\": \"^1.0.8\", \"es-set-tostringtag\": \"^2.1.0\", \"hasown\": \"^2.0.2\", \"mime-types\": \"^2.1.12\" } }, \"sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==\"],\n\n    \"function-bind\": [\"function-bind@1.1.2\", \"\", {}, \"sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==\"],\n\n    \"get-intrinsic\": [\"get-intrinsic@1.3.0\", \"\", { \"dependencies\": { \"call-bind-apply-helpers\": \"^1.0.2\", \"es-define-property\": \"^1.0.1\", \"es-errors\": \"^1.3.0\", \"es-object-atoms\": \"^1.1.1\", \"function-bind\": \"^1.1.2\", \"get-proto\": \"^1.0.1\", \"gopd\": \"^1.2.0\", \"has-symbols\": \"^1.1.0\", \"hasown\": \"^2.0.2\", \"math-intrinsics\": \"^1.1.0\" } }, \"sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==\"],\n\n    \"get-proto\": [\"get-proto@1.0.1\", \"\", { \"dependencies\": { \"dunder-proto\": \"^1.0.1\", \"es-object-atoms\": \"^1.0.0\" } }, \"sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==\"],\n\n    \"gopd\": [\"gopd@1.2.0\", \"\", {}, \"sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==\"],\n\n    \"has-symbols\": [\"has-symbols@1.1.0\", \"\", {}, \"sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==\"],\n\n    \"has-tostringtag\": [\"has-tostringtag@1.0.2\", \"\", { \"dependencies\": { \"has-symbols\": \"^1.0.3\" } }, \"sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==\"],\n\n    \"hasown\": [\"hasown@2.0.2\", \"\", { \"dependencies\": { \"function-bind\": \"^1.1.2\" } }, \"sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==\"],\n\n    \"math-intrinsics\": [\"math-intrinsics@1.1.0\", \"\", {}, \"sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==\"],\n\n    \"mime-db\": [\"mime-db@1.52.0\", \"\", {}, \"sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==\"],\n\n    \"mime-types\": [\"mime-types@2.1.35\", \"\", { \"dependencies\": { \"mime-db\": \"1.52.0\" } }, \"sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==\"],\n\n    \"proxy-from-env\": [\"proxy-from-env@1.1.0\", \"\", {}, \"sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==\"],\n  }\n}\n","type":"rawscript","content":"import axios from \"axios\";\n\nexport async function main(\n    nextcloud: RT.Nextcloud,\n    sourcePath: string,\n    destinationPath: string,\n) {\n\n    try {\n        const res = await axios.request(\n            {\n                method: \"COPY\",\n                url: `/remote.php/dav/files/${nextcloud.userId}/${sourcePath}`,\n                baseURL: nextcloud.baseUrl,\n                headers: {\n                    Authorization: `Basic ${btoa(`${nextcloud.userId}:${nextcloud.token}`)\n                    }`,\n                    Destination: `${nextcloud.baseUrl}/remote.php/dav/files/${nextcloud.userId}/${destinationPath}`,\n                },\n            },\n        );\n\n        return res.data;\n    } catch (e) {\n        console.log(e.response.data);\n    }\n}","language":"bun","input_transforms":{"nextcloud":{"expr":"flow_input.authentication.owner","type":"javascript"},"sourcePath":{"expr":"results.path","type":"javascript"},"destinationPath":{"expr":"`${results.folder_name}/${results.path.split(\"/\")[results.path.split(\"/\").length - 1]}`","type":"javascript"}}},"summary":"Copy File"},{"id":"a","value":{"path":"hub/28171/nextcloud/analyze_image","type":"script","is_trigger":false,"input_transforms":{"model":{"expr":"results.model","type":"javascript"},"prompt":{"type":"static","value":"You are a precise data extraction assistant. Extract expense data from the provided text and respond ONLY with a valid CSV. Do not include markdown formatting (e.g., ```csv), greetings, or explanations. Just output the CSV header and rows.\n\nEvery column must have a value. Use \"Unknown\" for missing text, and \"0\" for missing numbers.\n\nCRITICAL EXTRACTION & AGGREGATION RULES:\n- Splitting: Do not unnecessarily split up the bill.\n- Exclusions: DO NOT extract payment methods (e.g., VISA, Mastercard, Cash), change due, subtotals, or grand total summary lines as purchase rows.\n- Hotel Food Rule: If the bill is from a hotel, any food or drink items must be categorized as 'hotel breakfast'.\n- Missing VAT Rule: If VAT information is explicitly stated on the receipt, use it. If VAT information is completely missing, infer it based on location and strictly output it as a percentage with the `%` sign:\n  * Outside of Germany: Output `0%`.\n  * Inside of Germany: Output `7%` for food/drinks and local transport ('hotel breakfast', 'hospitality', etc), and `19%` for all other categories.\n\nCSV Columns and Rules:\n1. purchase_name: The name of the item ensure that the name does not contain commas.\n2. category: Must be EXACTLY one of the following: plane, public transport, parking, car rental, taxi, hotel, hotel breakfast, hospitality, gas, phone, or other.\n3. total_price: The total cost of the item or grouped items (numeric only).\n4. tax: The VAT tax. Rule: Any time a percentage is used (including via the 'Missing VAT Rule'), you MUST include the `%` sign (e.g., `0%`, `7%`, `19%`). If a line item is purely a VAT charge, set 'tax' to '`100%`.\n5. currency: 3-letter ISO currency code (e.g., USD, EUR).\n\nValidation Step:\nBefore outputting, ensure that the sum of all values in the 'total_price' column exactly matches the grand total of the money spent in the provided text."},"ncResource":{"expr":"flow_input.authentication.owner","type":"javascript"},"timeout_ms":{"type":"static"},"interval_ms":{"type":"static"},"imageFileIds":{"expr":"[flow_input.iter.value.fileId]","type":"javascript"}}},"summary":"Analyze Image (nextcloud)"}],"iterator":{"expr":"results.submission.submission.answers.filter((e) => e.questionName === \"files\")","type":"javascript"},"parallel":true,"skip_failures":true}}],"summary":"","parallel":true,"skip_failure":false},{"expr":"false","modules":[{"id":"date","value":{"path":"hub/28171/nextcloud/analyze_image","type":"script","is_trigger":false,"input_transforms":{"model":{"expr":"results.model","type":"javascript"},"prompt":{"type":"static","value":"Based on these receipts when is the start and end date and time of this trip. Only respond with four comma separated date and corresponding times in the format YYYY-MM-DD,HH:MM:SS,YYYY-MM-DD,HH:MM:SS"},"ncResource":{"expr":"flow_input.authentication.owner","type":"javascript"},"timeout_ms":{"type":"static"},"interval_ms":{"type":"static"},"imageFileIds":{"expr":"results.submission.submission.answers.filter((e) => e.questionName === \"files\").map((e) =>e.fileId)","type":"javascript"}}},"summary":"Analyze Image (nextcloud)"}],"summary":"","parallel":true,"skip_failure":false},{"expr":"false","modules":[{"id":"location","value":{"path":"hub/28171/nextcloud/analyze_image","type":"script","is_trigger":false,"input_transforms":{"model":{"expr":"results.model","type":"javascript"},"prompt":{"type":"static","value":"Based on these receipts what is the city and country of the trip. Only respond in the format city, country."},"ncResource":{"expr":"flow_input.authentication.owner","type":"javascript"},"timeout_ms":{"type":"static"},"interval_ms":{"type":"static"},"imageFileIds":{"expr":"results.submission.submission.answers.filter((e) => e.questionName === \"files\").map((e) =>e.fileId)","type":"javascript"}}},"summary":"Analyze Image (nextcloud)"}],"summary":"","parallel":true,"skip_failure":false}],"parallel":true},"summary":""},{"id":"user","value":{"lock":"{\n  \"dependencies\": {}\n}\n//bun.lock\n<empty>","type":"rawscript","content":"/**\n * Fetches current user information from Nextcloud OCS API.\n */\ntype Nextcloud = {\n  baseUrl: string;\n  userId: string;\n  token: string;\n};\n\nexport async function main(ncResource: Nextcloud, userId: string): Promise<any> {\n  const baseUrl = ncResource.baseUrl.replace(/\\/$/, \"\");\n  const response = await fetch(`${baseUrl}/ocs/v2.php/cloud/users/${userId}?format=json`, {\n    method: \"GET\",\n    headers: {\n      Authorization: `Basic ${btoa(`${ncResource.userId}:${ncResource.token}`)}`,\n      \"OCS-APIRequest\": \"true\",\n      Accept: \"application/json\",\n    },\n  });\n\n  if (!response.ok) {\n    const body = await response.text();\n    throw new Error(\n      `Failed to fetch /ocs/v2.php/cloud/user: ${response.status} ${response.statusText} - ${body}`,\n    );\n  }\n\n  return (await response.json()).ocs.data;\n}\n","language":"bun","input_transforms":{"userId":{"expr":"results.submission.submission.userId","type":"javascript"},"ncResource":{"type":"static","value":"$res:u/janapeper/techpreview_nextcloud"}}},"summary":"about user","continue_on_error":false},{"id":"b","value":{"lock":"{\n  \"dependencies\": {\n    \"axios\": \"latest\",\n    \"xlsx-populate\": \"latest\",\n    \"papaparse\": \"latest\"\n  }\n}\n//bun.lock\n{\n  \"lockfileVersion\": 1,\n  \"configVersion\": 1,\n  \"workspaces\": {\n    \"\": {\n      \"dependencies\": {\n        \"axios\": \"latest\",\n        \"papaparse\": \"latest\",\n        \"xlsx-populate\": \"latest\",\n      },\n    },\n  },\n  \"packages\": {\n    \"adler-32\": [\"adler-32@1.3.1\", \"\", {}, \"sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==\"],\n\n    \"asynckit\": [\"asynckit@0.4.0\", \"\", {}, \"sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==\"],\n\n    \"axios\": [\"axios@1.15.0\", \"\", { \"dependencies\": { \"follow-redirects\": \"^1.15.11\", \"form-data\": \"^4.0.5\", \"proxy-from-env\": \"^2.1.0\" } }, \"sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==\"],\n\n    \"call-bind-apply-helpers\": [\"call-bind-apply-helpers@1.0.2\", \"\", { \"dependencies\": { \"es-errors\": \"^1.3.0\", \"function-bind\": \"^1.1.2\" } }, \"sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==\"],\n\n    \"cfb\": [\"cfb@1.2.2\", \"\", { \"dependencies\": { \"adler-32\": \"~1.3.0\", \"crc-32\": \"~1.2.0\" } }, \"sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==\"],\n\n    \"combined-stream\": [\"combined-stream@1.0.8\", \"\", { \"dependencies\": { \"delayed-stream\": \"~1.0.0\" } }, \"sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==\"],\n\n    \"core-util-is\": [\"core-util-is@1.0.3\", \"\", {}, \"sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==\"],\n\n    \"crc-32\": [\"crc-32@1.2.2\", \"\", { \"bin\": { \"crc32\": \"bin/crc32.njs\" } }, \"sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==\"],\n\n    \"delayed-stream\": [\"delayed-stream@1.0.0\", \"\", {}, \"sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==\"],\n\n    \"dunder-proto\": [\"dunder-proto@1.0.1\", \"\", { \"dependencies\": { \"call-bind-apply-helpers\": \"^1.0.1\", \"es-errors\": \"^1.3.0\", \"gopd\": \"^1.2.0\" } }, \"sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==\"],\n\n    \"es-define-property\": [\"es-define-property@1.0.1\", \"\", {}, \"sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==\"],\n\n    \"es-errors\": [\"es-errors@1.3.0\", \"\", {}, \"sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==\"],\n\n    \"es-object-atoms\": [\"es-object-atoms@1.1.1\", \"\", { \"dependencies\": { \"es-errors\": \"^1.3.0\" } }, \"sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==\"],\n\n    \"es-set-tostringtag\": [\"es-set-tostringtag@2.1.0\", \"\", { \"dependencies\": { \"es-errors\": \"^1.3.0\", \"get-intrinsic\": \"^1.2.6\", \"has-tostringtag\": \"^1.0.2\", \"hasown\": \"^2.0.2\" } }, \"sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==\"],\n\n    \"follow-redirects\": [\"follow-redirects@1.15.11\", \"\", {}, \"sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==\"],\n\n    \"form-data\": [\"form-data@4.0.5\", \"\", { \"dependencies\": { \"asynckit\": \"^0.4.0\", \"combined-stream\": \"^1.0.8\", \"es-set-tostringtag\": \"^2.1.0\", \"hasown\": \"^2.0.2\", \"mime-types\": \"^2.1.12\" } }, \"sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==\"],\n\n    \"function-bind\": [\"function-bind@1.1.2\", \"\", {}, \"sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==\"],\n\n    \"get-intrinsic\": [\"get-intrinsic@1.3.0\", \"\", { \"dependencies\": { \"call-bind-apply-helpers\": \"^1.0.2\", \"es-define-property\": \"^1.0.1\", \"es-errors\": \"^1.3.0\", \"es-object-atoms\": \"^1.1.1\", \"function-bind\": \"^1.1.2\", \"get-proto\": \"^1.0.1\", \"gopd\": \"^1.2.0\", \"has-symbols\": \"^1.1.0\", \"hasown\": \"^2.0.2\", \"math-intrinsics\": \"^1.1.0\" } }, \"sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==\"],\n\n    \"get-proto\": [\"get-proto@1.0.1\", \"\", { \"dependencies\": { \"dunder-proto\": \"^1.0.1\", \"es-object-atoms\": \"^1.0.0\" } }, \"sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==\"],\n\n    \"gopd\": [\"gopd@1.2.0\", \"\", {}, \"sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==\"],\n\n    \"has-symbols\": [\"has-symbols@1.1.0\", \"\", {}, \"sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==\"],\n\n    \"has-tostringtag\": [\"has-tostringtag@1.0.2\", \"\", { \"dependencies\": { \"has-symbols\": \"^1.0.3\" } }, \"sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==\"],\n\n    \"hasown\": [\"hasown@2.0.2\", \"\", { \"dependencies\": { \"function-bind\": \"^1.1.2\" } }, \"sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==\"],\n\n    \"immediate\": [\"immediate@3.0.6\", \"\", {}, \"sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==\"],\n\n    \"inherits\": [\"inherits@2.0.4\", \"\", {}, \"sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==\"],\n\n    \"isarray\": [\"isarray@1.0.0\", \"\", {}, \"sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==\"],\n\n    \"jszip\": [\"jszip@3.10.1\", \"\", { \"dependencies\": { \"lie\": \"~3.3.0\", \"pako\": \"~1.0.2\", \"readable-stream\": \"~2.3.6\", \"setimmediate\": \"^1.0.5\" } }, \"sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==\"],\n\n    \"lie\": [\"lie@3.3.0\", \"\", { \"dependencies\": { \"immediate\": \"~3.0.5\" } }, \"sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==\"],\n\n    \"lodash\": [\"lodash@4.18.1\", \"\", {}, \"sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==\"],\n\n    \"math-intrinsics\": [\"math-intrinsics@1.1.0\", \"\", {}, \"sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==\"],\n\n    \"mime-db\": [\"mime-db@1.52.0\", \"\", {}, \"sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==\"],\n\n    \"mime-types\": [\"mime-types@2.1.35\", \"\", { \"dependencies\": { \"mime-db\": \"1.52.0\" } }, \"sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==\"],\n\n    \"pako\": [\"pako@1.0.11\", \"\", {}, \"sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==\"],\n\n    \"papaparse\": [\"papaparse@5.5.3\", \"\", {}, \"sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==\"],\n\n    \"process-nextick-args\": [\"process-nextick-args@2.0.1\", \"\", {}, \"sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==\"],\n\n    \"proxy-from-env\": [\"proxy-from-env@2.1.0\", \"\", {}, \"sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==\"],\n\n    \"readable-stream\": [\"readable-stream@2.3.8\", \"\", { \"dependencies\": { \"core-util-is\": \"~1.0.0\", \"inherits\": \"~2.0.3\", \"isarray\": \"~1.0.0\", \"process-nextick-args\": \"~2.0.0\", \"safe-buffer\": \"~5.1.1\", \"string_decoder\": \"~1.1.1\", \"util-deprecate\": \"~1.0.1\" } }, \"sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==\"],\n\n    \"safe-buffer\": [\"safe-buffer@5.1.2\", \"\", {}, \"sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==\"],\n\n    \"sax\": [\"sax@1.6.0\", \"\", {}, \"sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==\"],\n\n    \"setimmediate\": [\"setimmediate@1.0.5\", \"\", {}, \"sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==\"],\n\n    \"string_decoder\": [\"string_decoder@1.1.1\", \"\", { \"dependencies\": { \"safe-buffer\": \"~5.1.0\" } }, \"sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==\"],\n\n    \"util-deprecate\": [\"util-deprecate@1.0.2\", \"\", {}, \"sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==\"],\n\n    \"xlsx-populate\": [\"xlsx-populate@1.21.0\", \"\", { \"dependencies\": { \"cfb\": \"^1.1.3\", \"jszip\": \"^3.2.2\", \"lodash\": \"^4.17.15\", \"sax\": \"^1.2.4\" } }, \"sha512-8v2Gm8BehXo6LU7KT802QoXTPkYY1SKk5V8g/UuYZnNB3JzXqud/P99Pxr2yXeKyt+sKlCatmidz6jQNie1hRw==\"],\n  }\n}\n","type":"rawscript","content":"import axios from \"axios\";\nimport XlsxPopulate from \"xlsx-populate\";\nimport Papa from 'papaparse';\n\ntype FormAnswer = {\n  id: number;\n  text: string;\n  fileId: number | undefined;\n  questionId: number;\n  questionName: string;\n};\n\nexport async function main(\n  nextcloud: RT.Nextcloud,\n  templatePath: string,\n  outputPath: string,\n  formAnswers: FormAnswer[],\n  imageAnalysis: string[],\n  datetime: string,\n  location: string,\n  displayName: string,\n) {\n  const getRes = await axios.get(\n    `${nextcloud.baseUrl}/remote.php/dav/files/${nextcloud.userId}/${templatePath}`,\n    {\n      auth: {\n        username: nextcloud.userId,\n        password: nextcloud.token,\n      },\n      responseType: \"arraybuffer\",\n    },\n  );\n  if (getRes.status !== 200) {\n    throw new Error(getRes.statusText);\n  }\n\n  const workbook = await XlsxPopulate.fromDataAsync(\n    Buffer.from(getRes.data as ArrayBuffer),\n  );\n\n  const reportSheet = workbook\n    .sheets()\n    .find((s) => s.name() === \"Report\");\n  const calculationSheet = workbook\n    .sheets()\n    .find((s) => s.name() === \"Calculation\");\n  if (!reportSheet || !calculationSheet) {\n    const available = workbook.sheets().map((s) => s.name()).join(\", \");\n    throw new Error(`Report or calculation sheet not found. Available: ${available}`);\n  }\n\n  let conversionRate = 1;\n  const transportationMeans = new Set<string>();\n\n  // Setup datetime parts and ensure the array has 4 parts\n  const datetimeParts = datetime.split(\",\").map((part) => part.trim());\n  while (datetimeParts.length < 4) {\n    datetimeParts.push(\"Unknown\");\n  }\n  while (datetimeParts.length > 4) {\n    datetimeParts.pop();\n  }\n  const [departureDate, departureTime, returnDate, returnTime] = datetimeParts;\n  reportSheet.cell(\"A10\").value(departureDate);\n  reportSheet.cell(\"B10\").value(departureTime);\n  reportSheet.cell(\"C10\").value(returnDate);\n  reportSheet.cell(\"D10\").value(returnTime);\n\n  // Add location to the report sheet\n  reportSheet.cell(\"A7\").value(location);\n\n  // Add display name\n  reportSheet.cell(\"A5\").value(displayName);\n\n  // Iterate over the form answers\n  for (const formAnswer of formAnswers) {\n    const questionName = formAnswer.questionName;\n    const answer = formAnswer.text;\n    switch (questionName) {\n      case \"name\":\n        reportSheet.cell(\"A5\").value(`${displayName}, ${answer}`);\n        break;\n      case \"visted\":\n        reportSheet.cell(\"E7\").value(answer);\n        break;\n      case \"purpose\":\n        reportSheet.cell(\"H7\").value(answer);\n        break;\n      case \"km\":\n        if (Number(answer) > 0) {\n          reportSheet.cell(\"E20\").value(Number(answer));\n          transportationMeans.add(\"car\");\n        }\n        break;\n      case \"advance_payment\":\n        if (Number(answer) > 0) {\n          reportSheet.cell(\"E40\").value(Number(answer));\n        }\n        break;\n      case \"exchange_rate\":\n        conversionRate = Number(answer);\n        reportSheet.cell(\"H5\").value(`${conversionRate} EUR`);\n        break;\n    }\n    \n  }\n  let counter = 1;\n  // Iterate over the image analysis CSV files\n  for (const imageCSV of imageAnalysis) {\n    const data = Papa.parse<string[]>(imageCSV, { skipEmptyLines: true });\n    for (const rawRow of data.data) {\n      const row = normalizeImageAnalysisRow(rawRow);\n      if (!row) continue;\n      if (row[0] === \"purchase_name\") {\n        continue;\n      }\n      const purchaseName = row[0];\n      const category = row[1];\n      const totalPriceForeignCurrency = Number(row[2]);\n      const currency = row[4];\n      const exchangeRate = currency === \"EUR\" ? 1 : conversionRate;\n      const totalPrice = totalPriceForeignCurrency * exchangeRate;\n      const potentialTax = row[3];\n      // Ensure that the tax is a number\n      const tax = !potentialTax\n        ? 0\n        : potentialTax.includes(\"%\")\n          ? (() => {\n              // `totalPrice` is gross (incl. tax). Extract tax portion from gross: gross * r/(1+r)\n              const r = Number(potentialTax.replace(\"%\", \"\")) / 100;\n              if (!Number.isFinite(r) || r <= 0) return 0;\n              return totalPrice * (r / (1 + r));\n            })()\n          : Number(potentialTax);\n      counter++;\n      if (counter > 100) {\n        throw new Error(\"Too many rows to process\");\n      }\n      calculationSheet.cell(`A${counter}`).value(purchaseName);\n      calculationSheet.cell(`B${counter}`).value(category);\n      calculationSheet.cell(`C${counter}`).value(totalPrice);\n      calculationSheet.cell(`D${counter}`).value(tax);\n      calculationSheet.cell(`F${counter}`).value(currency);\n      calculationSheet.cell(`G${counter}`).value(totalPriceForeignCurrency);\n      transportationMeans.add(category);\n    }\n  }\n  console.log(transportationMeans)\n\n  // Add transportation means to the report sheet\n  if (transportationMeans.has(\"plane\")) {\n    reportSheet.cell(\"F9\").value(\"X\");\n  }\n  if (transportationMeans.has(\"public transport\")) {\n    reportSheet.cell(\"F10\").value(\"X\");\n  }\n  if (transportationMeans.has(\"car rental\")) {\n    reportSheet.cell(\"F11\").value(\"X\");\n  }\n  if (transportationMeans.has(\"car\")) {\n    reportSheet.cell(\"K9\").value(\"X\");\n  }\n  if (transportationMeans.has(\"taxi\")) {\n    reportSheet.cell(\"K10\").value(\"X\");\n  }\n\n  // Put the current date into J3 in the report sheet\n  const now = new Date();\n  const formattedDate = `${now.getDate().toString().padStart(2, \"0\")}.${(now.getMonth() + 1).toString().padStart(2, \"0\")}.${now.getFullYear()}`;\n  reportSheet.cell(\"J3\").value(formattedDate);\n  // Get the month spelled out in English\n  const monthNames = [\n    \"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\n    \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"\n  ];\n  reportSheet.cell(\"L3\").value(monthNames[now.getMonth()]);\n\n\n  const out = await workbook.outputAsync();\n\n  try {\n    const putRes = await axios.request({\n      method: \"PUT\",\n      url: `/remote.php/dav/files/${nextcloud.userId}/${outputPath}`,\n      baseURL: nextcloud.baseUrl,\n      data: out,\n      headers: {\n        Authorization: `Basic ${btoa(`${nextcloud.userId}:${nextcloud.token}`)}`,\n        \"Content-Type\":\n          \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n      },\n      maxBodyLength: Infinity,\n      maxContentLength: Infinity,\n    });\n    return outputPath;\n  } catch (e: unknown) {\n    console.log(e);\n    throw e instanceof Error ? e : new Error(String(e));\n  }\n}\n\nfunction normalizeImageAnalysisRow(rawFields: unknown[]): [string, string, string, string, string] | null {\n  const fields = rawFields.map((v) => String(v ?? \"\").trim());\n  while (fields.length > 0 && fields[fields.length - 1] === \"\") fields.pop();\n\n  if (fields.length === 0) return null;\n\n  // Common failure modes:\n  // - Missing tax column: [name, category, amount, currency]\n  // - Commas inside purchase_name: [name_part1, name_part2, ..., category, amount, tax, currency]\n  let f = fields.slice();\n\n  if (f.length > 5) {\n    const mergedName = f.slice(0, f.length - 4).join(\", \").trim();\n    f = [mergedName, ...f.slice(f.length - 4)];\n  }\n\n  // Ensure that the length is at least 3\n  if (f.length < 3) {\n    return null;\n  }\n  // If the length is 3, add a missing tax column\n  if (f.length === 3) {\n    f = [f[0], f[1], f[2], \"0\"];\n  }\n  // If the length is 4, add a missing currency column\n  if (f.length === 4) {\n    f = [f[0], f[1], f[2], f[3], \"EUR\"];\n  }\n\n  // If the \"currency\" ended up in column 4 and tax is missing, fix it.\n  const looksLikeCurrency = (s: string) => /^[A-Z]{3}$/.test(s.trim());\n  if (looksLikeCurrency(f[3])) {\n    f = [f[0], f[1], f[2], \"0\", f[3]];\n  }\n\n  // Ensure exactly 5 columns.\n  if (f.length > 5) f = f.slice(0, 5);\n\n  return [f[0], f[1], f[2], f[3], f[4]];\n}","language":"bun","input_transforms":{"datetime":{"expr":"results.date.analysisText","type":"javascript"},"location":{"expr":"results.location.analysisText","type":"javascript"},"nextcloud":{"expr":"flow_input.authentication.owner","type":"javascript"},"outputPath":{"expr":"`${results.folder_name}/Form.xlsx`","type":"javascript"},"displayName":{"expr":"results.user.displayname","type":"javascript"},"formAnswers":{"expr":"results.submission.submission.answers","type":"javascript"},"templatePath":{"type":"static","value":"Reimbursement/Form.xlsx"},"imageAnalysis":{"expr":"results.file_analysis.map((e) => e.analysisText)","type":"javascript"}}},"summary":"Update xlsx","continue_on_error":false},{"id":"fileid_for_xlsx","value":{"lock":"{\n  \"dependencies\": {\n    \"webdav\": \"latest\"\n  }\n}\n//bun.lock\n{\n  \"lockfileVersion\": 1,\n  \"configVersion\": 1,\n  \"workspaces\": {\n    \"\": {\n      \"dependencies\": {\n        \"webdav\": \"latest\",\n      },\n    },\n  },\n  \"packages\": {\n    \"@buttercup/fetch\": [\"@buttercup/fetch@0.2.1\", \"\", { \"optionalDependencies\": { \"node-fetch\": \"^3.3.0\" } }, \"sha512-sCgECOx8wiqY8NN1xN22BqqKzXYIG2AicNLlakOAI4f0WgyLVUbAigMf8CZhBtJxdudTcB1gD5lciqi44jwJvg==\"],\n\n    \"balanced-match\": [\"balanced-match@1.0.2\", \"\", {}, \"sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==\"],\n\n    \"base-64\": [\"base-64@1.0.0\", \"\", {}, \"sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==\"],\n\n    \"brace-expansion\": [\"brace-expansion@2.0.3\", \"\", { \"dependencies\": { \"balanced-match\": \"^1.0.0\" } }, \"sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==\"],\n\n    \"byte-length\": [\"byte-length@1.0.2\", \"\", {}, \"sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==\"],\n\n    \"charenc\": [\"charenc@0.0.2\", \"\", {}, \"sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==\"],\n\n    \"crypt\": [\"crypt@0.0.2\", \"\", {}, \"sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==\"],\n\n    \"data-uri-to-buffer\": [\"data-uri-to-buffer@4.0.1\", \"\", {}, \"sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==\"],\n\n    \"entities\": [\"entities@6.0.1\", \"\", {}, \"sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==\"],\n\n    \"fast-xml-builder\": [\"fast-xml-builder@1.1.4\", \"\", { \"dependencies\": { \"path-expression-matcher\": \"^1.1.3\" } }, \"sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==\"],\n\n    \"fast-xml-parser\": [\"fast-xml-parser@5.5.11\", \"\", { \"dependencies\": { \"fast-xml-builder\": \"^1.1.4\", \"path-expression-matcher\": \"^1.4.0\", \"strnum\": \"^2.2.3\" }, \"bin\": { \"fxparser\": \"src/cli/cli.js\" } }, \"sha512-QL0eb0YbSTVWF6tTf1+LEMSgtCEjBYPpnAjoLC8SscESlAjXEIRJ7cHtLG0pLeDFaZLa4VKZLArtA/60ZS7vyA==\"],\n\n    \"fetch-blob\": [\"fetch-blob@3.2.0\", \"\", { \"dependencies\": { \"node-domexception\": \"^1.0.0\", \"web-streams-polyfill\": \"^3.0.3\" } }, \"sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==\"],\n\n    \"formdata-polyfill\": [\"formdata-polyfill@4.0.10\", \"\", { \"dependencies\": { \"fetch-blob\": \"^3.1.2\" } }, \"sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==\"],\n\n    \"hot-patcher\": [\"hot-patcher@2.0.1\", \"\", {}, \"sha512-ECg1JFG0YzehicQaogenlcs2qg6WsXQsxtnbr1i696u5tLUjtJdQAh0u2g0Q5YV45f263Ta1GnUJsc8WIfJf4Q==\"],\n\n    \"is-buffer\": [\"is-buffer@1.1.6\", \"\", {}, \"sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==\"],\n\n    \"layerr\": [\"layerr@3.0.0\", \"\", {}, \"sha512-tv754Ki2dXpPVApOrjTyRo4/QegVb9eVFq4mjqp4+NM5NaX7syQvN5BBNfV/ZpAHCEHV24XdUVrBAoka4jt3pA==\"],\n\n    \"md5\": [\"md5@2.3.0\", \"\", { \"dependencies\": { \"charenc\": \"0.0.2\", \"crypt\": \"0.0.2\", \"is-buffer\": \"~1.1.6\" } }, \"sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==\"],\n\n    \"minimatch\": [\"minimatch@9.0.9\", \"\", { \"dependencies\": { \"brace-expansion\": \"^2.0.2\" } }, \"sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==\"],\n\n    \"nested-property\": [\"nested-property@4.0.0\", \"\", {}, \"sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA==\"],\n\n    \"node-domexception\": [\"node-domexception@1.0.0\", \"\", {}, \"sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==\"],\n\n    \"node-fetch\": [\"node-fetch@3.3.2\", \"\", { \"dependencies\": { \"data-uri-to-buffer\": \"^4.0.0\", \"fetch-blob\": \"^3.1.4\", \"formdata-polyfill\": \"^4.0.10\" } }, \"sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==\"],\n\n    \"path-expression-matcher\": [\"path-expression-matcher@1.4.0\", \"\", {}, \"sha512-s4DQMxIdhj3jLFWd9LxHOplj4p9yQ4ffMGowFf3cpEgrrJjEhN0V5nxw4Ye1EViAGDoL4/1AeO6qHpqYPOzE4Q==\"],\n\n    \"path-posix\": [\"path-posix@1.0.0\", \"\", {}, \"sha512-1gJ0WpNIiYcQydgg3Ed8KzvIqTsDpNwq+cjBCssvBtuTWjEqY1AW+i+OepiEMqDCzyro9B2sLAe4RBPajMYFiA==\"],\n\n    \"querystringify\": [\"querystringify@2.2.0\", \"\", {}, \"sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==\"],\n\n    \"requires-port\": [\"requires-port@1.0.0\", \"\", {}, \"sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==\"],\n\n    \"strnum\": [\"strnum@2.2.3\", \"\", {}, \"sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==\"],\n\n    \"url-join\": [\"url-join@5.0.0\", \"\", {}, \"sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==\"],\n\n    \"url-parse\": [\"url-parse@1.5.10\", \"\", { \"dependencies\": { \"querystringify\": \"^2.1.1\", \"requires-port\": \"^1.0.0\" } }, \"sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==\"],\n\n    \"web-streams-polyfill\": [\"web-streams-polyfill@3.3.3\", \"\", {}, \"sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==\"],\n\n    \"webdav\": [\"webdav@5.9.0\", \"\", { \"dependencies\": { \"@buttercup/fetch\": \"^0.2.1\", \"base-64\": \"^1.0.0\", \"byte-length\": \"^1.0.2\", \"entities\": \"^6.0.1\", \"fast-xml-parser\": \"^5.3.4\", \"hot-patcher\": \"^2.0.1\", \"layerr\": \"^3.0.0\", \"md5\": \"^2.3.0\", \"minimatch\": \"^9.0.5\", \"nested-property\": \"^4.0.0\", \"node-fetch\": \"^3.3.2\", \"path-posix\": \"^1.0.0\", \"url-join\": \"^5.0.0\", \"url-parse\": \"^1.5.10\" } }, \"sha512-OMJ6wtK1WvCO++aOLoQgE96S8KT4e5aaClWHmHXfFU369r4eyELN569B7EqT4OOUb99mmO58GkyuiCv/Ag6J0Q==\"],\n  }\n}\n","type":"rawscript","content":"import { createClient } from \"webdav\";\n\n/**\n * Resolves a Nextcloud fileid from a path under the user's files root.\n * Use the same path shape as `get-nextcloud-path-by-fileid.ts` returns, e.g. `/Documents/file.pdf`.\n */\nexport async function main(\n  ncResource: RT.Nextcloud,\n  path: string\n): Promise<string> {\n\n  const baseUrl = ncResource.baseUrl.replace(/\\/$/, \"\");\n  // Same root as list-nextcloud-files.ts. User id is encoded here only once;\n  // the webdav client runs encodePath() on remote paths — do not pre-encode segments\n  // or emails like user@host become user%2540host and PROPFIND returns 404.\n  const davBaseUrl = `${baseUrl}/remote.php/dav/files/${encodeURIComponent(ncResource.userId)}`;\n  const client = createClient(davBaseUrl, {\n    username: ncResource.userId,\n    password: ncResource.token,\n  });\n\n  const davPath = path;\n  const propfindXml = buildPropfindFileIdXml();\n  const rawResponse = await client.customRequest(davPath, {\n    method: \"PROPFIND\",\n    data: propfindXml,\n    headers: {\n      \"Content-Type\": \"text/xml; charset=utf-8\",\n      Accept: \"application/xml, text/xml\",\n      Depth: \"0\",\n    },\n    responseType: \"text\",\n  });\n\n  const responseXml = await rawResponse.text();\n  if (!rawResponse.ok) {\n    throw new Error(\n      `PROPFIND failed (HTTP ${rawResponse.status}) for path \"${path}\"`\n    );\n  }\n\n  const fileid = extractFileIdFromPropfindResponse(responseXml);\n  if (!fileid) {\n    throw new Error(`Could not resolve fileid for path \"${path}\"`);\n  }\n\n  return fileid;\n}\n\n\nfunction buildPropfindFileIdXml(): string {\n  return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<d:propfind xmlns:d=\"DAV:\" xmlns:oc=\"http://owncloud.org/ns\">\n  <d:prop>\n    <oc:fileid/>\n  </d:prop>\n</d:propfind>`;\n}\n\nfunction extractFileIdFromPropfindResponse(xml: string): string | null {\n  const m = xml.match(/<oc:fileid>([^<]*)<\\/oc:fileid>/);\n  const id = m?.[1]?.trim();\n  return id && /^\\d+$/.test(id) ? id : null;\n}\n","language":"bun","input_transforms":{"path":{"expr":"`${results.folder_name}/Form.xlsx`","type":"javascript"},"ncResource":{"expr":"flow_input.authentication.owner","type":"javascript"}}},"summary":"Fileid from Path"},{"id":"di","value":{"lock":"{\n  \"dependencies\": {\n    \"axios\": \"latest\"\n  }\n}\n//bun.lock\n{\n  \"lockfileVersion\": 1,\n  \"configVersion\": 1,\n  \"workspaces\": {\n    \"\": {\n      \"dependencies\": {\n        \"axios\": \"latest\",\n      },\n    },\n  },\n  \"packages\": {\n    \"asynckit\": [\"asynckit@0.4.0\", \"\", {}, \"sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==\"],\n\n    \"axios\": [\"axios@1.15.0\", \"\", { \"dependencies\": { \"follow-redirects\": \"^1.15.11\", \"form-data\": \"^4.0.5\", \"proxy-from-env\": \"^2.1.0\" } }, \"sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==\"],\n\n    \"call-bind-apply-helpers\": [\"call-bind-apply-helpers@1.0.2\", \"\", { \"dependencies\": { \"es-errors\": \"^1.3.0\", \"function-bind\": \"^1.1.2\" } }, \"sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==\"],\n\n    \"combined-stream\": [\"combined-stream@1.0.8\", \"\", { \"dependencies\": { \"delayed-stream\": \"~1.0.0\" } }, \"sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==\"],\n\n    \"delayed-stream\": [\"delayed-stream@1.0.0\", \"\", {}, \"sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==\"],\n\n    \"dunder-proto\": [\"dunder-proto@1.0.1\", \"\", { \"dependencies\": { \"call-bind-apply-helpers\": \"^1.0.1\", \"es-errors\": \"^1.3.0\", \"gopd\": \"^1.2.0\" } }, \"sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==\"],\n\n    \"es-define-property\": [\"es-define-property@1.0.1\", \"\", {}, \"sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==\"],\n\n    \"es-errors\": [\"es-errors@1.3.0\", \"\", {}, \"sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==\"],\n\n    \"es-object-atoms\": [\"es-object-atoms@1.1.1\", \"\", { \"dependencies\": { \"es-errors\": \"^1.3.0\" } }, \"sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==\"],\n\n    \"es-set-tostringtag\": [\"es-set-tostringtag@2.1.0\", \"\", { \"dependencies\": { \"es-errors\": \"^1.3.0\", \"get-intrinsic\": \"^1.2.6\", \"has-tostringtag\": \"^1.0.2\", \"hasown\": \"^2.0.2\" } }, \"sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==\"],\n\n    \"follow-redirects\": [\"follow-redirects@1.15.11\", \"\", {}, \"sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==\"],\n\n    \"form-data\": [\"form-data@4.0.5\", \"\", { \"dependencies\": { \"asynckit\": \"^0.4.0\", \"combined-stream\": \"^1.0.8\", \"es-set-tostringtag\": \"^2.1.0\", \"hasown\": \"^2.0.2\", \"mime-types\": \"^2.1.12\" } }, \"sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==\"],\n\n    \"function-bind\": [\"function-bind@1.1.2\", \"\", {}, \"sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==\"],\n\n    \"get-intrinsic\": [\"get-intrinsic@1.3.0\", \"\", { \"dependencies\": { \"call-bind-apply-helpers\": \"^1.0.2\", \"es-define-property\": \"^1.0.1\", \"es-errors\": \"^1.3.0\", \"es-object-atoms\": \"^1.1.1\", \"function-bind\": \"^1.1.2\", \"get-proto\": \"^1.0.1\", \"gopd\": \"^1.2.0\", \"has-symbols\": \"^1.1.0\", \"hasown\": \"^2.0.2\", \"math-intrinsics\": \"^1.1.0\" } }, \"sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==\"],\n\n    \"get-proto\": [\"get-proto@1.0.1\", \"\", { \"dependencies\": { \"dunder-proto\": \"^1.0.1\", \"es-object-atoms\": \"^1.0.0\" } }, \"sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==\"],\n\n    \"gopd\": [\"gopd@1.2.0\", \"\", {}, \"sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==\"],\n\n    \"has-symbols\": [\"has-symbols@1.1.0\", \"\", {}, \"sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==\"],\n\n    \"has-tostringtag\": [\"has-tostringtag@1.0.2\", \"\", { \"dependencies\": { \"has-symbols\": \"^1.0.3\" } }, \"sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==\"],\n\n    \"hasown\": [\"hasown@2.0.2\", \"\", { \"dependencies\": { \"function-bind\": \"^1.1.2\" } }, \"sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==\"],\n\n    \"math-intrinsics\": [\"math-intrinsics@1.1.0\", \"\", {}, \"sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==\"],\n\n    \"mime-db\": [\"mime-db@1.52.0\", \"\", {}, \"sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==\"],\n\n    \"mime-types\": [\"mime-types@2.1.35\", \"\", { \"dependencies\": { \"mime-db\": \"1.52.0\" } }, \"sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==\"],\n\n    \"proxy-from-env\": [\"proxy-from-env@2.1.0\", \"\", {}, \"sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==\"],\n  }\n}\n","type":"rawscript","content":"import axios from \"axios\";\n\n/**\n * Assigns a collaborative (system) tag to a file via WebDAV.\n *\n * `fileId` and `tagId` are the numeric ids from Nextcloud (e.g. from DAV PROPFIND or other scripts).\n */\nexport async function main(\n  ncResource: RT.Nextcloud,\n  fileId: string | number,\n  tagId: string | number\n) {\n\n  const base = ncResource.baseUrl.replace(/\\/$/, \"\");\n  const response = await axios.put(\n    `${base}/remote.php/dav/systemtags-relations/files/${fileId}/${tagId}`,\n    \"\",\n    {\n      auth: {\n        username: ncResource.userId,\n        password: ncResource.token,\n      },\n      headers: { \"Content-Type\": \"text/xml\" },\n      validateStatus: () => true,\n    }\n  );\n\n  if (response.status === 201) {\n    return { fileId, tagId, alreadyAssigned: false };\n  }\n  if (response.status === 409) {\n    return { fileId, tagId, alreadyAssigned: true };\n  }\n\n  throw new Error(`Failed to assign tag (HTTP ${response.status})${response.data}`);\n}\n","language":"bun","input_transforms":{"tagId":{"type":"static","value":5},"fileId":{"expr":"results.fileid_for_xlsx","type":"javascript"},"ncResource":{"expr":"flow_input.authentication.owner","type":"javascript"}}},"summary":"Tag File"},{"id":"share_userid","value":{"lock":"{\n  \"dependencies\": {}\n}\n//bun.lock\n<empty>","type":"rawscript","content":"// import * as wmill from \"windmill-client\"\n\nexport async function main(triggerUserId: string, form: any, lineManager: string) {\n  const result = [triggerUserId]\n  // Adds line manager from form if exists\n  const lineManagerForm = form.submission.answers.filter((e) => e.questionName === \"line_manager\")\n  if (lineManagerForm.length > 0) {\n    result.push(lineManagerForm[0].text)\n  }\n  // Only add line manager if not an empty string\n  if (lineManager !== \"\") {\n    result.push(lineManager)\n  }\n  return result\n}\n","language":"bun","input_transforms":{"form":{"expr":"results.submission","type":"javascript"},"lineManager":{"expr":"results.user.manager","type":"javascript"},"triggerUserId":{"expr":"flow_input.authentication.trigger.userId","type":"javascript"}}},"summary":"Get Share List"},{"id":"shares","value":{"type":"forloopflow","squash":false,"modules":[{"id":"f","value":{"path":"hub/28173/nextcloud/create_share","type":"script","is_trigger":false,"input_transforms":{"path":{"expr":"results.folder_name","type":"javascript"},"settings":{"type":"static","value":{"note":"","label":"","password":"","sendMail":false,"shareWith":"","expireDate":"","publicUpload":false}},"shareType":{"type":"static","value":0},"shareWith":{"expr":"flow_input.iter.value","type":"javascript"},"ncResource":{"expr":"flow_input.authentication.owner","type":"javascript"}}},"summary":"Create Share form submission"}],"iterator":{"expr":"results.share_userid","type":"javascript"},"parallel":true,"skip_failures":true}},{"id":"dg","value":{"path":"hub/28136/nextcloud/send_a_notification_to_a_user","type":"script","is_trigger":false,"input_transforms":{"message":{"type":"static","value":"Your Expense Report has finished processing and has been shared with you. Please review and sign it."},"subject":{"type":"static","value":"Expense Report"},"nextcloud":{"expr":"flow_input.authentication.owner","type":"javascript"},"messageParameters":{"expr":"","type":"javascript"},"subjectParameters":{"expr":"","type":"javascript"},"notificationUserId":{"expr":"flow_input.authentication.trigger.userId","type":"javascript"}}},"summary":"Send a notification to a user (nextcloud)"}]},"schema":{"type":"object","order":["time","user","event","authentication"],"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"time":{"type":"integer","description":""},"user":{"type":"object","order":["uid","displayName"],"properties":{"uid":{"type":"string"},"displayName":{"type":"string"}},"additionalProperties":false},"event":{"type":"object","order":["form","class","submission"],"properties":{"form":{"type":"object","order":["id","hash","state","title","access","fileId","created","expires","ownerId","lockedBy","fileFormat","description","isAnonymous","lastUpdated","lockedUntil","showExpiration","submitMultiple","submissionMessage","allowEditSubmissions"],"properties":{"id":{"type":"integer"},"hash":{"type":"string"},"state":{"type":"integer"},"title":{"type":"string"},"access":{"type":"object","order":["permitAllUsers","showToAllUsers"],"properties":{"permitAllUsers":{"type":"boolean"},"showToAllUsers":{"type":"boolean"}},"additionalProperties":false},"fileId":{"type":"null"},"created":{"type":"integer"},"expires":{"type":"integer"},"ownerId":{"type":"string"},"lockedBy":{"type":"string"},"fileFormat":{"type":"null"},"description":{"type":"string"},"isAnonymous":{"type":"boolean"},"lastUpdated":{"type":"integer"},"lockedUntil":{"type":"integer"},"showExpiration":{"type":"boolean"},"submitMultiple":{"type":"boolean"},"submissionMessage":{"type":"null"},"allowEditSubmissions":{"type":"boolean"}},"additionalProperties":false},"class":{"type":"string"},"submission":{"type":"object","order":["id","formId","userId","timestamp"],"properties":{"id":{"type":"integer"},"formId":{"type":"integer"},"userId":{"type":"string"},"timestamp":{"type":"integer"}},"additionalProperties":false}},"additionalProperties":false},"authentication":{"type":"object","order":["owner","trigger"],"properties":{"owner":{"type":"object","order":["token","userId","baseUrl"],"properties":{"token":{"type":"string"},"userId":{"type":"string"},"baseUrl":{"type":"string","format":"url"}},"additionalProperties":false},"trigger":{"type":"object","order":["token","userId","baseUrl"],"properties":{"token":{"type":"string"},"userId":{"type":"string"},"baseUrl":{"type":"string","format":"url"}},"additionalProperties":false}},"additionalProperties":false}}},"description":"Autogenerates a reimbursement expense report from a filled form and uploaded receipt pictures\n\n- Trigger: Form submitted (form includes data to be filled in like name, destination etc, and a file upload)\n- get the files in the folder and send them through image recognition\n- get the travel data formatted for the document\n- copy a template document to the destination\n- fill in the template document \n- send it per mail to the line manager","recording":null,"vcreated_at":"2026-04-27T14:47:15.791Z","vcreated_by":"nextcloud","comments":[]}}