{
  "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\" \u2013 The official invoice number exactly as shown on the document.\n\"invoiceDate\" \u2013 The date of the invoice in the format YYYY-MM-DD.\n\"company\" \u2013 The name of the business or organization that issued the invoice.\n\"description\" \u2013 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\" \u2013 The net amount (excluding VAT).\nIf it is not explicitly stated, calculate it based on the gross amount and the tax rate.\n\"taxRatePercent\" \u2013 The VAT rate in percent.\nIf not provided, determine the most likely tax rate based on the region and standard VAT rates.\n\"taxAmount\" \u2013 The calculated tax amount.\n\"grossAmount\" \u2013 The total amount including VAT.\n\"currency\" \u2013 The currency symbol used on the invoice.\n\nIf not specified, default to \u20ac 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 (\u20ac 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 (\u20ac, $).\n\n{\n  \"company\": \"Amazon\",\n  \"description\": \"R\u00d8DE 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\": \"\u20ac\"\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 \u2013 Reads the uploaded invoice PDF and extracts all visible text for analysis.\n\t2. Extract & Format Data (AI) \u2013 Uses an AI model to identify and structure key fields (e.g. company, invoice number, date, amount).\n\t3. Get Additional Date Data \u2013 Adds metadata such as month and year for folder organization or tracking.\n\t4. Create Invoice Name (AI) \u2013 Generates a clean, standardized file name based on extracted data (e.g. Invoice_2025-10_Company.pdf).\n\t5. Google Sheets \u2013 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 \u2013 Retrieves the processed invoice PDF from the previous step or source node.\n\t2.\tUpload to Incoming Folder \u2013 Temporarily uploads the file to the designated Incoming Files folder on Google Drive.\n\t3.\tEnsure Accessibility \u2013 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) \u2013 Detects new incoming emails in the inbox and retrieves all attachments.\n\t2.\tSplit Attachments (JavaScript) \u2013 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 \u2014 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 \u2014 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 \u2013 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 \u2014 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,
  "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
          }
        ]
      ]
    }
  }
}