{
  "id": "",
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "name": "Bookkeeping GDrive",
  "tags": [],
  "nodes": [
    {
      "id": "00537f01-be79-4aa1-b162-e428b9dbd8f2",
      "name": "Extract From PDF",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        1232,
        -528
      ],
      "parameters": {
        "options": {},
        "operation": "pdf",
        "binaryPropertyName": "=data"
      },
      "typeVersion": 1
    },
    {
      "id": "653108bc-f685-47c4-9d81-3f71b022df52",
      "name": "Extract & Format Data",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1424,
        -528
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o",
          "cachedResultName": "GPT-4o"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "=You are an intelligent assistant designed to extract structured invoice data from unformatted text.\nYour task is to analyze the provided invoice text, identify key details, and return them as a clean JSON object.\n\n\"invoiceNumber\" – The official invoice number exactly as shown on the document.\n\"invoiceDate\" – The date of the invoice in the format YYYY-MM-DD.\n\"company\" – The name of the business or organization that issued the invoice.\n\"description\" – A short, precise summary of the goods or services billed. It should be specific enough to meet accounting and tax documentation requirements.\nIf multiple dates appear, choose the one explicitly labeled as the invoice date, or use the payment date as a fallback.\n\"netAmount\" – The net amount (excluding VAT).\nIf it is not explicitly stated, calculate it based on the gross amount and the tax rate.\n\"taxRatePercent\" – The VAT rate in percent.\nIf not provided, determine the most likely tax rate based on the region and standard VAT rates.\n\"taxAmount\" – The calculated tax amount.\n\"grossAmount\" – The total amount including VAT.\n\"currency\" – The currency symbol used on the invoice.\n\nIf not specified, default to € for Euro or $ for US Dollar.\nAlways return the output as a pure JSON object, without any extra text, explanation, or markdown.\nIf a value cannot be clearly identified, leave it empty (\"\") but keep the field in the JSON structure.\nAll numeric amounts must use a comma (,) instead of a period (.) as the decimal separator (German number format).\nCurrency must always be expressed using the symbol (€ or $) rather than text codes.\nIf taxRatePercent or taxAmount are missing, return them as 0.\nDo not use currency codes like EUR or USD; always use the symbol (€, $).\n\n{\n  \"company\": \"Amazon\",\n  \"description\": \"RØDE NT-USB+ Professional USB Microphone\",\n  \"invoiceNumber\": \"028-9586789-4573109\",\n  \"invoiceDate\": \"2025-02-24\",\n  \"netAmount\": \"142,37\",\n  \"taxRatePercent\": \"19\",\n  \"taxAmount\": \"27,05\",\n  \"grossAmount\": \"169,42\",\n  \"currency\": \"€\"\n}\n\n\nHere is the invoice text to analyze:\n\n{{ $json.text }}"
            }
          ]
        },
        "jsonOutput": true
      },
      "credentials": {},
      "typeVersion": 1.8
    },
    {
      "id": "fd51efcc-6ed9-4012-8318-8ceee8bc524d",
      "name": "Get Additional Date Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1776,
        -528
      ],
      "parameters": {
        "jsCode": "const inputData = $input.first().json.message.content;\nconst dateString = inputData.invoiceDate;\nconst parsedDate = new Date(dateString);\nconst monthOptions = { month: 'long' };\nconst monthName = parsedDate.toLocaleDateString('de-DE', monthOptions);\nconst yearValue = parsedDate.getFullYear().toString();\nconst dayValue = String(parsedDate.getDate()).padStart(2, '0');\nconst monthValue = String(parsedDate.getMonth() + 1).padStart(2, '0');\nconst germanDate = dayValue + '.' + monthValue + '.' + yearValue;\nconst outputData = {\n  company: inputData.company,\n  description: inputData.description,\n  invoiceNumber: inputData.invoiceNumber,\n  netAmount: inputData.netAmount,\n  taxRatePercent: inputData.taxRatePercent,\n  taxAmount: inputData.taxAmount,\n  grossAmount: inputData.grossAmount,\n  currency: inputData.currency,\n  invoiceDate: inputData.invoiceDate,\n  datumDeutsch: germanDate,\n  monat: monthName,\n  jahr: yearValue\n};\nreturn [outputData];"
      },
      "typeVersion": 2
    },
    {
      "id": "b2509ccd-55d4-45c3-aa47-224056eefe20",
      "name": "Search Month Folder",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        400,
        -528
      ],
      "parameters": {
        "limit": 1,
        "filter": {
          "folderId": {
            "__rl": true,
            "mode": "id",
            "value": ""
          }
        },
        "options": {
          "fields": [
            "webViewLink"
          ]
        },
        "resource": "fileFolder",
        "queryString": "={{ $now.setLocale('de').toFormat('MMMM') }}"
      },
      "credentials": {},
      "typeVersion": 3,
      "alwaysOutputData": true
    },
    {
      "id": "8f03819a-3323-4650-9b5e-5f62b1adc59a",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -368,
        -464
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "d6cdabd3-5b9b-4c74-8240-3aa19b0710cc",
      "name": "Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2000,
        -528
      ],
      "parameters": {
        "columns": {
          "value": {
            "Company": "={{ $json.company }}",
            "Currency": "={{ $json.currency }}",
            "Net Amount": "={{ $json.netAmount }}",
            "Tax Amount": "={{ $json.taxAmount }}",
            "Description": "={{ $json.description }}",
            "Gross Amount": "={{ $json.grossAmount }}",
            "Invoice Date": "={{ $json.monat }}",
            "Invoice Number": "={{ $json.invoiceNumber }}",
            "Tax Rate Percent": "={{ $json.taxRatePercent }}"
          },
          "schema": [
            {
              "id": "Company",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Company",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Description",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice Date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Invoice Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice Number",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Invoice Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Net Amount",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Net Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Tax Rate Percent",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Tax Rate Percent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Tax Amount",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Tax Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Gross Amount",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Gross Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Currency",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": ""
        }
      },
      "credentials": {},
      "typeVersion": 4.5
    },
    {
      "id": "498d1043-b2cb-46b1-aee3-559e9c0c30b8",
      "name": "Email Trigger (IMAP)",
      "type": "n8n-nodes-base.emailReadImap",
      "position": [
        -848,
        -464
      ],
      "parameters": {
        "format": "resolved",
        "options": {}
      },
      "credentials": {},
      "typeVersion": 2.1
    },
    {
      "id": "e8f3c9a0-1234-5678-9abc-def012345678",
      "name": "Send to DateV",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        2688,
        -448
      ],
      "parameters": {
        "options": {},
        "subject": "Beleg Rechnung",
        "toEmail": "user@example.com",
        "fromEmail": "user@example.com"
      },
      "credentials": {},
      "typeVersion": 2.1
    },
    {
      "id": "b761dc97-01c1-4b3c-81b0-b2a9843e4766",
      "name": "MoveEmail email",
      "type": "n8n-nodes-imap.imap",
      "position": [
        3248,
        -288
      ],
      "parameters": {
        "emailUid": "={{ $('Email Trigger (IMAP)').item.json.attributes.uid }}",
        "resource": "email",
        "operation": "moveEmail",
        "sourceMailbox": {
          "__rl": true,
          "mode": "list",
          "value": "INBOX"
        },
        "authentication": "coreImapAccount",
        "destinationMailbox": {
          "__rl": true,
          "mode": "list",
          "value": "Rechnungen_DDB",
          "cachedResultName": "Rechnungen_DDB"
        }
      },
      "credentials": {},
      "typeVersion": 1
    },
    {
      "id": "81514faf-73f4-45d9-b98a-edcb2b61971e",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        912,
        -800
      ],
      "parameters": {
        "width": 1392,
        "height": 480,
        "content": "## Extract & Log Invoice Data\n\nSteps:\n\t1. Extract From PDF – Reads the uploaded invoice PDF and extracts all visible text for analysis.\n\t2. Extract & Format Data (AI) – Uses an AI model to identify and structure key fields (e.g. company, invoice number, date, amount).\n\t3. Get Additional Date Data – Adds metadata such as month and year for folder organization or tracking.\n\t4. Create Invoice Name (AI) – Generates a clean, standardized file name based on extracted data (e.g. Invoice_2025-10_Company.pdf).\n\t5. Google Sheets – Appends the extracted invoice data to a connected Google Sheet for centralized tracking and bookkeeping.\n\nThis section ensures all invoice details are automatically extracted, formatted, and logged into Google Sheets for easy overview."
      },
      "typeVersion": 1
    },
    {
      "id": "699ea44c-8703-4d51-8fe3-e19f7620d8ec",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2448,
        -656
      ],
      "parameters": {
        "width": 432,
        "height": 384,
        "content": "## Send to DateV\n\nStep:\nSends the processed invoice as an email to your DateV inbox for accounting. The message includes the correctly named PDF as an attachment. Use your individual Datev-Inbox Mail (which you can get in your company profile). "
      },
      "typeVersion": 1
    },
    {
      "id": "31a23f05-18dc-4ba4-bd99-77bd3ac71506",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2976,
        -464
      ],
      "parameters": {
        "width": 464,
        "height": 336,
        "content": "## Move Email to Archive/Folder\n\nStep:\nMoves the processed email to a specific folder  after all actions are completed."
      },
      "typeVersion": 1
    },
    {
      "id": "a11c1bc8-e810-4d38-98b6-adc0cf0f2dd8",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        96,
        -848
      ],
      "parameters": {
        "width": 560,
        "height": 528,
        "content": "## Upload to Temporary Storage\n\nSteps:\n\t1.\tDownload File – Retrieves the processed invoice PDF from the previous step or source node.\n\t2.\tUpload to Incoming Folder – Temporarily uploads the file to the designated Incoming Files folder on Google Drive.\n\t3.\tEnsure Accessibility – Storing the file in this shared location guarantees that all subsequent workflow steps (e.g., searching, renaming, or organizing) can access the same binary file.\n\nThis setup ensures the invoice file remains accessible throughout the entire workflow before being moved to its final folder."
      },
      "typeVersion": 1
    },
    {
      "id": "cd47d134-ecca-451d-bf26-5b382ee499d0",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -944,
        -816
      ],
      "parameters": {
        "width": 480,
        "height": 512,
        "content": "## Receive IMAP-Mail & Extract Attachments from Email\n\nSteps:\n\t1.\tEmail Trigger (IMAP) – Detects new incoming emails in the inbox and retrieves all attachments.\n\t2.\tSplit Attachments (JavaScript) – Processes each email item and splits multiple attachments into individual workflow items.\nEach output item contains only one binary file named data, making it easier to handle uploads and further processing in later steps.\n\nThis setup ensures every email attachment is treated as a separate, standardized file for downstream automation."
      },
      "typeVersion": 1
    },
    {
      "id": "cf5ff710-5a7d-4f67-a427-dd4b707e8ab2",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1632,
        -1104
      ],
      "parameters": {
        "width": 464,
        "height": 800,
        "content": "## Workflow Overview — Automated Invoice Processing\n\nGoal:\nThis workflow automatically processes incoming invoice emails, extracts and structures all relevant data, stores the files in Google Drive, logs details in Google Sheets, and prepares them for accounting — all fully automated.\n\nSteps:\n\t1. Email Trigger (IMAP): Starts when a new email with one or more attachments arrives in the inbox.\n\t2. Split Attachments (JavaScript): Converts each attachment into a separate workflow item to ensure consistent processing.\n\t3. Extract From PDF – Reads the text content from each invoice PDF.\n\t4. Extract & Format Data (AI): Uses an AI model to identify key invoice fields (company, invoice number, date, amount, etc.).\n\t5. Get Additional Date Data: Adds metadata like month, year, and formatted dates for categorization.\n\t6. Upload to Temporary Storage: Saves the invoice PDF to an Incoming Files folder on Google Drive, ensuring it stays accessible throughout the workflow.\n\t7. Search or Create Month Folder: Locates or creates the correct monthly folder on Google Drive (e.g., Invoices / October 2025).\n\t8. Upload to Final Destination: Moves the invoice from the temporary folder to the correct month folder with a clean, standardized file name (e.g., 2025-10-02_Motel-One_2025515030097.pdf).\n\t9. Google Sheets Log: Records all extracted invoice data for tracking and reporting.\n\t10. Send to DateV: Forwards the finalized invoice to your DateV accounting inbox by email.\n\t11. Move Email to Archive: Moves the original email to a dedicated archive folder to keep your inbox organized.\n\nThis setup ensures every invoice is automatically extracted, renamed, categorized, and stored — keeping your accounting workflow efficient, traceable, and fully automated."
      },
      "typeVersion": 1
    },
    {
      "id": "18ef9aa2-b377-4f87-95cc-63fac8b26e26",
      "name": "Upload file",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        192,
        -528
      ],
      "parameters": {
        "name": "={{ $binary.attachment_0.fileName }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive",
          "cachedResultUrl": "https://drive.google.com/drive/my-drive",
          "cachedResultName": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "url",
          "value": ""
        }
      },
      "credentials": {},
      "typeVersion": 3,
      "alwaysOutputData": true
    },
    {
      "id": "156bba85-1b84-4eab-8a8d-3916a343188e",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        -640,
        -464
      ],
      "parameters": {
        "jsCode": "const currentItem = $input.item;\nconst binaryData = currentItem.binary || {};\nconst resultItems = [];\nfor (const [keyName, binaryContent] of Object.entries(binaryData)) {\n  const newItem = {\n    json: { _sourceAttachmentKey: keyName },\n    binary: { data: binaryContent }\n  };\n  resultItems.push(newItem);\n}\nreturn resultItems;"
      },
      "typeVersion": 2
    },
    {
      "id": "21056d9c-e203-4402-ba04-f64ebdcddac9",
      "name": "Download file",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1040,
        -528
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Upload file').item.json.id }}"
        },
        "options": {},
        "operation": "download"
      },
      "credentials": {},
      "typeVersion": 3
    },
    {
      "id": "d770bb51-a13c-4143-9c03-5d1481891907",
      "name": "Download file1",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        2512,
        -448
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Upload file').item.json.id }}"
        },
        "options": {},
        "operation": "download"
      },
      "credentials": {},
      "typeVersion": 3
    },
    {
      "id": "e01165d1-2aef-4a47-971c-858d69ed93ca",
      "name": "Download file2",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        3024,
        -288
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Upload file').item.json.id }}"
        },
        "options": {},
        "operation": "download"
      },
      "credentials": {},
      "typeVersion": 3
    },
    {
      "id": "b85d1bbe-03de-4f8d-8de6-5a1df1c897df",
      "name": "Download file3",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        3664,
        -176
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Upload file').item.json.id }}"
        },
        "options": {},
        "operation": "download"
      },
      "credentials": {},
      "typeVersion": 3
    },
    {
      "id": "12bbabff-af3c-4eb7-b1fe-088896041e34",
      "name": "Upload file1",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        3856,
        -176
      ],
      "parameters": {
        "name": "={{ $json.invoiceDate + '_' + $json.company.replaceAll(' ', '-') + '_' + $json.invoiceNumber + '.pdf' }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "url",
          "value": "={{ $('Search Month Folder').item.json.webViewLink }}"
        }
      },
      "credentials": {},
      "typeVersion": 3
    },
    {
      "id": "7acea3fa-560e-4b07-aa83-e40385296055",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3568,
        -368
      ],
      "parameters": {
        "width": 464,
        "height": 352,
        "content": "## Upload to final destination\n\nSteps:\nDownloads the prepared file from the temporary storage and re-uploads it to the target folder defined by the month and year (based on the extracted invoice data)."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {},
  "versionId": "",
  "connections": {
    "Upload file": {
      "main": [
        [
          {
            "node": "Search Month Folder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload file1": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download file": {
      "main": [
        [
          {
            "node": "Extract From PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets": {
      "main": [
        [
          {
            "node": "Download file1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send to DateV": {
      "main": [
        [
          {
            "node": "Download file2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download file1": {
      "main": [
        [
          {
            "node": "Send to DateV",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download file2": {
      "main": [
        [
          {
            "node": "MoveEmail email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download file3": {
      "main": [
        [
          {
            "node": "Upload file1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [],
        [
          {
            "node": "Upload file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "MoveEmail email": {
      "main": [
        [
          {
            "node": "Download file3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract From PDF": {
      "main": [
        [
          {
            "node": "Extract & Format Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Month Folder": {
      "main": [
        [
          {
            "node": "Download file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email Trigger (IMAP)": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract & Format Data": {
      "main": [
        [
          {
            "node": "Get Additional Date Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Additional Date Data": {
      "main": [
        [
          {
            "node": "Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}