{
 "id": "r2pdfinvoicetocs",
 "name": "AutomateRecipes \u2013 pdf-invoice-to-csv",
 "nodes": [
  {
   "parameters": {
    "rule": {
     "interval": [
      {
       "field": "days",
       "triggerAtHour": 8
      }
     ]
    }
   },
   "name": "Schedule Trigger",
   "type": "n8n-nodes-base.scheduleTrigger",
   "typeVersion": 1.2,
   "position": [
    0,
    0
   ],
   "id": "4c976ab2-cf09-4062-a332-116a61c3466e"
  },
  {
   "parameters": {
    "jsCode": "// EDIT THESE SETTINGS\nreturn [{json:{\n \"ntfyTopic\": \"CHANGE-ME-to-a-long-random-topic\",\n \"pdfUrl\": \"https://automaterecipes.pages.dev/samples/sample-invoice.pdf\",\n \"cfAccountId\": \"YOUR_CLOUDFLARE_ACCOUNT_ID\",\n \"kvNamespaceId\": \"YOUR_KV_NAMESPACE_ID\",\n \"csvKey\": \"invoices.csv\"\n}}];"
   },
   "name": "Config",
   "type": "n8n-nodes-base.code",
   "typeVersion": 2,
   "position": [
    240,
    0
   ],
   "id": "a3496a91-f69f-417f-b2b8-5318ac94c86d"
  },
  {
   "parameters": {
    "url": "={{ $json.pdfUrl }}",
    "options": {
     "response": {
      "response": {
       "responseFormat": "file"
      }
     }
    }
   },
   "name": "Download PDF",
   "type": "n8n-nodes-base.httpRequest",
   "typeVersion": 4.2,
   "position": [
    480,
    0
   ],
   "id": "ccb145c5-72af-49a4-afe3-64e85c55f4a5"
  },
  {
   "parameters": {
    "operation": "pdf",
    "options": {}
   },
   "name": "Extract PDF text",
   "type": "n8n-nodes-base.extractFromFile",
   "typeVersion": 1,
   "position": [
    720,
    0
   ],
   "id": "0e56cceb-af82-43dc-8e08-2bea3fa84e25"
  },
  {
   "parameters": {
    "jsCode": "const t=String($input.first().json.text||'');\nconst g=re=>{const m=t.match(re);return m?m[1].trim():''};\nconst f={invoice_number:g(/Invoice (?:number|no\\.?|#)\\s*[:#]?\\s*([A-Z0-9-]+)/i),supplier:g(/(?:Supplier|From|Vendor)\\s*:\\s*(.+)/i),invoice_date:g(/Invoice date\\s*:\\s*([0-9]{4}-[0-9]{2}-[0-9]{2}|[0-9/.-]+)/i),due_date:g(/Due date\\s*:\\s*([0-9]{4}-[0-9]{2}-[0-9]{2}|[0-9/.-]+)/i),subtotal:g(/Subtotal\\s*:\\s*([0-9.,]+)/i),vat:g(/VAT[^:]*:\\s*([0-9.,]+)/i),total:g(/\\bTotal\\s*:\\s*([0-9.,]+)/i),currency:g(/Currency\\s*:\\s*([A-Z]{3})/)};\nf.source=$('Config').first().json.pdfUrl;f.extracted_at=new Date().toISOString();\nf.needs_review=(!f.invoice_number||!f.total)?'yes':'no';\nreturn [{json:f}];"
   },
   "name": "Parse invoice fields",
   "type": "n8n-nodes-base.code",
   "typeVersion": 2,
   "position": [
    960,
    0
   ],
   "id": "300c6843-f213-42db-87e7-255fd494817d"
  },
  {
   "parameters": {
    "url": "=https://api.cloudflare.com/client/v4/accounts/{{ $('Config').first().json.cfAccountId }}/storage/kv/namespaces/{{ $('Config').first().json.kvNamespaceId }}/values/{{ $('Config').first().json.csvKey }}",
    "authentication": "genericCredentialType",
    "genericAuthType": "httpHeaderAuth",
    "options": {
     "response": {
      "response": {
       "responseFormat": "text",
       "outputPropertyName": "raw",
       "neverError": true
      }
     }
    }
   },
   "name": "Read existing CSV",
   "type": "n8n-nodes-base.httpRequest",
   "typeVersion": 4.2,
   "position": [
    1200,
    0
   ],
   "id": "62ef1671-0f63-486a-9374-15becc3244f3",
   "credentials": {
    "httpHeaderAuth": {
     "id": "REPLACE_WITH_YOUR_CREDENTIAL",
     "name": "Cloudflare API token"
    }
   }
  },
  {
   "parameters": {
    "jsCode": "const f=$('Parse invoice fields').first().json;let csv=String($input.first().json.raw||'');\nif(csv.includes('\"errors\"')||!csv.startsWith('invoice_number'))csv='';\nconst cols=['invoice_number','supplier','invoice_date','due_date','subtotal','vat','total','currency','needs_review','source','extracted_at'];\nconst q=v=>'\"'+String(v??'').replace(/\"/g,'\"\"')+'\"';\nif(!csv)csv=cols.join(',')+'\\n';\nconst dup=csv.split('\\n').some(l=>l.startsWith(q(f.invoice_number)+',')&&f.invoice_number);\nif(!dup)csv+=cols.map(c=>q(f[c])).join(',')+'\\n';\nreturn [{json:{csv,dup,rows:csv.trim().split('\\n').length-1}}];"
   },
   "name": "Append CSV row",
   "type": "n8n-nodes-base.code",
   "typeVersion": 2,
   "position": [
    1440,
    0
   ],
   "id": "67d86864-07ba-4177-b6f4-2d7961015432"
  },
  {
   "parameters": {
    "method": "PUT",
    "url": "=https://api.cloudflare.com/client/v4/accounts/{{ $('Config').first().json.cfAccountId }}/storage/kv/namespaces/{{ $('Config').first().json.kvNamespaceId }}/values/{{ $('Config').first().json.csvKey }}",
    "authentication": "genericCredentialType",
    "genericAuthType": "httpHeaderAuth",
    "sendBody": true,
    "contentType": "raw",
    "rawContentType": "text/plain",
    "body": "={{ $json.csv }}",
    "options": {}
   },
   "name": "Save CSV to Cloudflare KV",
   "type": "n8n-nodes-base.httpRequest",
   "typeVersion": 4.2,
   "position": [
    1680,
    0
   ],
   "id": "76f37337-ce3a-48f5-99fa-624a631225cf",
   "credentials": {
    "httpHeaderAuth": {
     "id": "REPLACE_WITH_YOUR_CREDENTIAL",
     "name": "Cloudflare API token"
    }
   }
  },
  {
   "parameters": {
    "jsCode": "if($input.first().json.success!==true)throw new Error('KV write failed');const f=$('Parse invoice fields').first().json,a=$('Append CSV row').first().json;\nreturn [{json:{title:(a.dup?'Duplicate invoice skipped: ':'Invoice logged: ')+f.invoice_number,tags:f.needs_review=='yes'?'warning':'receipt',message:`${f.supplier}\\nTotal ${f.total} ${f.currency} (VAT ${f.vat}) due ${f.due_date}\\nNeeds review: ${f.needs_review} \u00b7 CSV rows: ${a.rows}`}}];"
   },
   "name": "Build alert",
   "type": "n8n-nodes-base.code",
   "typeVersion": 2,
   "position": [
    1920,
    0
   ],
   "id": "4626cf6f-a708-48d9-9755-aaec046eb3a3"
  },
  {
   "parameters": {
    "method": "POST",
    "url": "=https://ntfy.sh/{{ $('Config').first().json.ntfyTopic }}",
    "sendHeaders": true,
    "headerParameters": {
     "parameters": [
      {
       "name": "Title",
       "value": "={{ $json.title }}"
      },
      {
       "name": "Tags",
       "value": "={{ $json.tags || 'bell' }}"
      }
     ]
    },
    "sendBody": true,
    "contentType": "raw",
    "rawContentType": "text/plain",
    "body": "={{ $json.message }}",
    "options": {}
   },
   "name": "Send ntfy alert",
   "type": "n8n-nodes-base.httpRequest",
   "typeVersion": 4.2,
   "position": [
    2160,
    0
   ],
   "id": "36c6a827-3b6f-4a8d-96ed-3820a526d265"
  },
  {
   "parameters": {},
   "name": "Run manually (test)",
   "type": "n8n-nodes-base.manualTrigger",
   "typeVersion": 1,
   "position": [
    0,
    200
   ],
   "id": "5072f5c8-b738-43fc-9f60-7b5376c8d804"
  }
 ],
 "connections": {
  "Schedule Trigger": {
   "main": [
    [
     {
      "node": "Config",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Config": {
   "main": [
    [
     {
      "node": "Download PDF",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Download PDF": {
   "main": [
    [
     {
      "node": "Extract PDF text",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Extract PDF text": {
   "main": [
    [
     {
      "node": "Parse invoice fields",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Parse invoice fields": {
   "main": [
    [
     {
      "node": "Read existing CSV",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Read existing CSV": {
   "main": [
    [
     {
      "node": "Append CSV row",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Append CSV row": {
   "main": [
    [
     {
      "node": "Save CSV to Cloudflare KV",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Save CSV to Cloudflare KV": {
   "main": [
    [
     {
      "node": "Build alert",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Build alert": {
   "main": [
    [
     {
      "node": "Send ntfy alert",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Run manually (test)": {
   "main": [
    [
     {
      "node": "Config",
      "type": "main",
      "index": 0
     }
    ]
   ]
  }
 },
 "settings": {
  "executionOrder": "v1"
 },
 "active": false,
 "pinData": {}
}