{"id":112,"date":"2025-09-22T20:51:41","date_gmt":"2025-09-22T20:51:41","guid":{"rendered":"http:\/\/bjornproost.nl\/?page_id=112"},"modified":"2025-09-26T20:18:11","modified_gmt":"2025-09-26T20:18:11","slug":"activa-verwerker","status":"publish","type":"page","link":"https:\/\/bjornproost.nl\/?page_id=112","title":{"rendered":"ActivAI"},"content":{"rendered":"\n<h3 class=\"wp-block-heading\">Van Factuur tot Advies: Automatiseer Investeringen en Afschrijvingen<\/h3>\n\n\n\n<p>Effici\u00ebntie maakt het verschil. Toch worstelen veel accountants- en administratiekantoren met het verwerken van kapitaalinvesteringen. Dit proces is vaak complexer dan alleen het inboeken van een factuur. Het begint al bij de aankoopovereenkomst en eindigt pas jaren later na de laatste afschrijving.<\/p>\n\n\n\n<p>Het handmatig verwerken van een investeringsfactuur, het opzoeken van de juiste RGS-codes, het opstellen van een afschrijvingsschema in Excel (zowel commercieel als fiscaal), en vervolgens periodiek de journaalposten aanmaken is een tijdrovende en foutgevoelige klus.<\/p>\n\n\n\n<p>De oplossing ligt in het slim automatiseren van dit volledige traject met deze tool.<\/p>\n\n\n\n<p><strong>Maak kennis met de slimme investerings- en afschrijvingsassistent.<\/strong><\/p>\n\n\n\n<p>Deze applicatie is geen simpele calculator. Het is een intelligent instrument dat de volledige workflow \u2013 van document tot UBL-journaalpost \u2013 stroomlijnt en automatiseert.<\/p>\n\n\n\n<!DOCTYPE html>\n<html lang=\"nl\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Investeringsafschrijving App<\/title>\n    <script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\n    <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/2.11.338\/pdf.min.js\"><\/script>\n    <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/xlsx\/0.18.5\/xlsx.full.min.js\"><\/script>\n    <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jszip\/3.10.1\/jszip.min.js\"><\/script>\n    <style>\n        \/* Aangepaste stijlen voor een betere look & feel *\/\n        @import url('https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&display=swap');\n        body {\n            font-family: 'Inter', sans-serif;\n        }\n        .step-indicator {\n            transition: background-color 0.3s ease, color 0.3s ease;\n        }\n    <\/style>\n<\/head>\n<body class=\"bg-slate-50\">\n\n    <div id=\"app-container\" class=\"max-w-4xl mx-auto p-4 sm:p-6 lg:p-8\">\n        <!-- Deze container zal de app bevatten -->\n    <\/div>\n\n<script type=\"module\">\n    \/\/ --- CONFIGURATIE & CONSTANTEN ---\n    const ASSET_GROUPS_DEFAULTS = {\n        kantoorinventaris: {\n            lifespan: 5, \/\/ years\n            residualValuePercentage: 10,\n            rgsCodeAsset: \"02100\",\n            rgsCodeDepreciationCost: \"44100\",\n            rgsCodeAccumulatedDepreciation: \"02109\"\n        },\n        ict: {\n            lifespan: 3, \/\/ years\n            residualValuePercentage: 5,\n            rgsCodeAsset: \"02200\",\n            rgsCodeDepreciationCost: \"44200\",\n            rgsCodeAccumulatedDepreciation: \"02209\"\n        },\n        auto: {\n            lifespan: 5, \/\/ years\n            residualValuePercentage: 20,\n            rgsCodeAsset: \"02300\",\n            rgsCodeDepreciationCost: \"45100\",\n            rgsCodeAccumulatedDepreciation: \"02309\"\n        },\n        gebouwen: {\n            lifespan: 30,\n            residualValuePercentage: 50,\n            rgsCodeAsset: \"01000\",\n            rgsCodeDepreciationCost: \"43100\",\n            rgsCodeAccumulatedDepreciation: \"01009\"\n        }\n    };\n\n    \/\/ --- STATE MANAGEMENT ---\n    let state = {\n        currentStep: 1,\n        invoiceData: {\n            invoiceDate: new Date().toISOString().split('T')[0],\n            amountExclVat: '',\n            supplier: '',\n            invoiceNumber: '',\n            description: ''\n        },\n        investmentParams: {\n            assetGroup: 'kantoorinventaris',\n            lifespan: ASSET_GROUPS_DEFAULTS.kantoorinventaris.lifespan,\n            residualValue: ASSET_GROUPS_DEFAULTS.kantoorinventaris.residualValuePercentage,\n            residualValueType: 'percentage',\n            depreciationStartDate: new Date().toISOString().split('T')[0],\n            depreciationMethod: 'lineair',\n            calculationType: 'beide',\n            period: 'maand',\n            rgsCodeAsset: ASSET_GROUPS_DEFAULTS.kantoorinventaris.rgsCodeAsset,\n        },\n        commercialSchedule: [],\n        fiscalSchedule: [],\n        activeTab: 'commercial', \/\/ 'commercial' of 'fiscal'\n        bulkSendEnabled: true,\n        selectedCommercialPeriods: new Set(),\n        selectedFiscalPeriods: new Set(),\n        emailForExport: '',\n        isPdfParsing: false,\n    };\n    \n    \/\/ Globale PDF worker source\n    pdfjsLib.GlobalWorkerOptions.workerSrc = `https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/2.11.338\/pdf.worker.min.js`;\n\n\n    \/\/ --- RENDERING FUNCTIES ---\n    function render() {\n        const appContainer = document.getElementById('app-container');\n        appContainer.innerHTML = App();\n        attachEventListeners();\n    }\n\n    \/\/ --- HOOFDCOMPONENT ---\n    function App() {\n        return `\n            <div class=\"bg-white rounded-xl shadow-lg p-6 sm:p-8 space-y-8\">\n                ${ProgressIndicator()}\n                <div id=\"step-content\">\n                    ${renderCurrentStep()}\n                <\/div>\n            <\/div>\n        `;\n    }\n\n    function renderCurrentStep() {\n        switch (state.currentStep) {\n            case 1:\n                return InvoiceForm();\n            case 2:\n                return InvestmentParamsForm();\n            case 3:\n                return DepreciationView();\n            default:\n                return `<h1>Onbekende stap<\/h1>`;\n        }\n    }\n\n    \/\/ --- COMPONENTEN (STAPPEN) ---\n    function ProgressIndicator() {\n        const steps = ['Factuurgegevens', 'Parameters', 'Resultaat'];\n        return `\n            <div>\n                <h1 class=\"text-2xl sm:text-3xl font-bold text-sky-800 mb-2\">Investerings- en Afschrijvingsassistent<\/h1>\n                <p class=\"text-slate-600 mb-6\">Automatiseer het volledige traject: van factuur tot UBL-journaalpost.<\/p>\n                <div class=\"flex justify-between items-center\">\n                    ${steps.map((step, index) => `\n                        <div class=\"step-indicator flex-1 text-center\">\n                            <div class=\"\n                                ${state.currentStep > index + 1 ? 'bg-green-500 text-white' : ''}\n                                ${state.currentStep === index + 1 ? 'bg-sky-600 text-white' : 'bg-slate-200 text-slate-600'}\n                                rounded-full w-8 h-8 mx-auto flex items-center justify-center font-bold text-sm\n                            \">\n                                ${state.currentStep > index + 1 ? '&#10003;' : index + 1}\n                            <\/div>\n                            <p class=\"text-xs sm:text-sm mt-2 font-medium ${state.currentStep >= index + 1 ? 'text-sky-700' : 'text-slate-500'}\">${step}<\/p>\n                        <\/div>\n                        ${index < steps.length - 1 ? '<div class=\"flex-1 h-0.5 bg-slate-200\"><\/div>' : ''}\n                    `).join('')}\n                <\/div>\n            <\/div>\n        `;\n    }\n\n    function InvoiceForm() {\n        return `\n            <div class=\"space-y-6\">\n                <div>\n                    <h2 class=\"text-xl font-semibold text-sky-700\">Stap 1: Factuurgegevens<\/h2>\n                    <p class=\"text-slate-500 mt-1\">Upload een PDF of vul de gegevens handmatig in.<\/p>\n                <\/div>\n                <div class=\"border-2 border-dashed border-slate-300 rounded-lg p-6 text-center\">\n                    <label for=\"pdf-upload\" class=\"cursor-pointer\">\n                        <svg class=\"mx-auto h-12 w-12 text-slate-400\" stroke=\"currentColor\" fill=\"none\" viewBox=\"0 0 48 48\" aria-hidden=\"true\"><path d=\"M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><\/path><\/svg>\n                        <span class=\"mt-2 block text-sm font-medium text-sky-600 hover:text-sky-500\">\n                            ${state.isPdfParsing ? 'PDF verwerken...' : 'Upload een PDF-factuur'}\n                        <\/span>\n                    <\/label>\n                    <input id=\"pdf-upload\" name=\"pdf-upload\" type=\"file\" class=\"sr-only\" accept=\".pdf\">\n                     ${state.isPdfParsing ? '<div class=\"mt-4\"><div class=\"animate-spin rounded-full h-6 w-6 border-b-2 border-sky-600 mx-auto\"><\/div><\/div>' : ''}\n                <\/div>\n                <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n                    <div>\n                        <label for=\"supplier\" class=\"block text-sm font-medium text-slate-700\">Leverancier<\/label>\n                        <input type=\"text\" id=\"supplier\" value=\"${state.invoiceData.supplier}\" class=\"mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\">\n                    <\/div>\n                    <div>\n                        <label for=\"invoice-number\" class=\"block text-sm font-medium text-slate-700\">Factuurnummer<\/label>\n                        <input type=\"text\" id=\"invoice-number\" value=\"${state.invoiceData.invoiceNumber}\" class=\"mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\">\n                    <\/div>\n                    <div>\n                        <label for=\"invoice-date\" class=\"block text-sm font-medium text-slate-700\">Factuurdatum<\/label>\n                        <input type=\"date\" id=\"invoice-date\" value=\"${state.invoiceData.invoiceDate}\" class=\"mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\">\n                    <\/div>\n                    <div>\n                        <label for=\"amount-excl-vat\" class=\"block text-sm font-medium text-slate-700\">Bedrag (excl. btw)<\/label>\n                        <input type=\"number\" id=\"amount-excl-vat\" value=\"${state.invoiceData.amountExclVat}\" class=\"mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\" placeholder=\"0.00\">\n                    <\/div>\n                    <div class=\"md:col-span-2\">\n                        <label for=\"description\" class=\"block text-sm font-medium text-slate-700\">Omschrijving<\/label>\n                        <input type=\"text\" id=\"description\" value=\"${state.invoiceData.description}\" class=\"mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\">\n                    <\/div>\n                <\/div>\n                <div class=\"flex justify-end\">\n                    <button id=\"next-step-1\" class=\"bg-sky-600 hover:bg-sky-700 text-white font-bold py-2 px-6 rounded-lg shadow-md transition-transform transform hover:scale-105\">Volgende<\/button>\n                <\/div>\n            <\/div>\n        `;\n    }\n\n    function InvestmentParamsForm() {\n        return `\n            <div class=\"space-y-6\">\n                <div>\n                    <h2 class=\"text-xl font-semibold text-sky-700\">Stap 2: Investeringsparameters<\/h2>\n                    <p class=\"text-slate-500 mt-1\">Definieer hoe de investering moet worden afgeschreven.<\/p>\n                <\/div>\n                <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n                    <div>\n                        <label for=\"asset-group\" class=\"block text-sm font-medium text-slate-700\">Activagroep<\/label>\n                        <select id=\"asset-group\" class=\"mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\">\n                            ${Object.keys(ASSET_GROUPS_DEFAULTS).map(group => `<option value=\"${group}\" ${state.investmentParams.assetGroup === group ? 'selected' : ''}>${group.charAt(0).toUpperCase() + group.slice(1)}<\/option>`).join('')}\n                        <\/select>\n                    <\/div>\n                     <div>\n                        <label for=\"rgs-code-asset\" class=\"block text-sm font-medium text-slate-700\">RGS Code Activum<\/label>\n                        <input type=\"text\" id=\"rgs-code-asset\" value=\"${state.investmentParams.rgsCodeAsset}\" class=\"mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\">\n                    <\/div>\n                    <div>\n                        <label for=\"lifespan\" class=\"block text-sm font-medium text-slate-700\">Levensduur (jaren)<\/label>\n                        <input type=\"number\" id=\"lifespan\" value=\"${state.investmentParams.lifespan}\" class=\"mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\">\n                    <\/div>\n                    <div>\n                        <label for=\"residual-value\" class=\"block text-sm font-medium text-slate-700\">Restwaarde<\/label>\n                        <div class=\"flex mt-1\">\n                            <input type=\"number\" id=\"residual-value\" value=\"${state.investmentParams.residualValue}\" class=\"flex-grow rounded-l-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\">\n                            <select id=\"residual-value-type\" class=\"rounded-r-md border-l-0 border-slate-300 bg-slate-50 focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\">\n                                <option value=\"percentage\" ${state.investmentParams.residualValueType === 'percentage' ? 'selected' : ''}>%<\/option>\n                                <option value=\"euro\" ${state.investmentParams.residualValueType === 'euro' ? 'selected' : ''}>\u20ac<\/option>\n                            <\/select>\n                        <\/div>\n                    <\/div>\n                    <div>\n                        <label for=\"depreciation-start-date\" class=\"block text-sm font-medium text-slate-700\">Startdatum Afschrijving<\/label>\n                        <input type=\"date\" id=\"depreciation-start-date\" value=\"${state.investmentParams.depreciationStartDate}\" class=\"mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\">\n                    <\/div>\n                    <div>\n                        <label for=\"depreciation-method\" class=\"block text-sm font-medium text-slate-700\">Afschrijvingsmethode<\/label>\n                        <select id=\"depreciation-method\" class=\"mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\">\n                            <option value=\"lineair\" ${state.investmentParams.depreciationMethod === 'lineair' ? 'selected' : ''}>Lineair<\/option>\n                            <option value=\"degressief\" ${state.investmentParams.depreciationMethod === 'degressief' ? 'selected' : ''}>Degressief (vereenvoudigd)<\/option>\n                        <\/select>\n                    <\/div>\n                    <div>\n                        <label class=\"block text-sm font-medium text-slate-700\">Berekening<\/label>\n                        <select id=\"calculation-type\" class=\"mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\">\n                            <option value=\"beide\" ${state.investmentParams.calculationType === 'beide' ? 'selected' : ''}>Commercieel & Fiscaal<\/option>\n                            <option value=\"commercieel\" ${state.investmentParams.calculationType === 'commercieel' ? 'selected' : ''}>Alleen Commercieel<\/option>\n                            <option value=\"fiscaal\" ${state.investmentParams.calculationType === 'fiscaal' ? 'selected' : ''}>Alleen Fiscaal<\/option>\n                        <\/select>\n                    <\/div>\n                    <div>\n                        <label class=\"block text-sm font-medium text-slate-700\">Periode<\/label>\n                        <select id=\"period\" class=\"mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\">\n                            <option value=\"maand\" ${state.investmentParams.period === 'maand' ? 'selected' : ''}>Per Maand<\/option>\n                            <option value=\"kwartaal\" ${state.investmentParams.period === 'kwartaal' ? 'selected' : ''}>Per Kwartaal<\/option>\n                        <\/select>\n                    <\/div>\n                <\/div>\n                <div class=\"flex justify-between\">\n                    <button id=\"prev-step-2\" class=\"bg-slate-200 hover:bg-slate-300 text-slate-800 font-bold py-2 px-6 rounded-lg transition-colors\">Terug<\/button>\n                    <button id=\"calculate-depreciation\" class=\"bg-sky-600 hover:bg-sky-700 text-white font-bold py-2 px-6 rounded-lg shadow-md transition-transform transform hover:scale-105\">Bereken Afschrijving<\/button>\n                <\/div>\n            <\/div>\n        `;\n    }\n    \n    function DepreciationView() {\n        const hasCommercial = state.commercialSchedule.length > 0;\n        const hasFiscal = state.fiscalSchedule.length > 0;\n\n        return `\n            <div class=\"space-y-6\">\n                 <div>\n                    <h2 class=\"text-xl font-semibold text-sky-700\">Stap 3: Resultaten & Export<\/h2>\n                    <p class=\"text-slate-500 mt-1\">Bekijk de schema's en genereer UBL-journaalposten.<\/p>\n                <\/div>\n\n                ${hasCommercial && hasFiscal ? `\n                    <div class=\"border-b border-slate-200\">\n                        <nav class=\"-mb-px flex space-x-8\" aria-label=\"Tabs\">\n                            <button id=\"tab-commercial\" class=\"tab-btn ${state.activeTab === 'commercial' ? 'border-sky-500 text-sky-600' : 'border-transparent text-slate-500 hover:text-slate-700 hover:border-slate-300'} whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm\">Commercieel<\/button>\n                            <button id=\"tab-fiscal\" class=\"tab-btn ${state.activeTab === 'fiscal' ? 'border-sky-500 text-sky-600' : 'border-transparent text-slate-500 hover:text-slate-700 hover:border-slate-300'} whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm\">Fiscaal<\/button>\n                        <\/nav>\n                    <\/div>` : ''\n                }\n                \n                <div class=\"flex flex-col md:flex-row md:items-center md:justify-between gap-4\">\n                     <div class=\"flex items-center space-x-3\">\n                         <input type=\"checkbox\" id=\"bulk-send-enabled\" class=\"h-4 w-4 rounded border-slate-300 text-sky-600 focus:ring-sky-500\" ${state.bulkSendEnabled ? 'checked' : ''}>\n                         <label for=\"bulk-send-enabled\" class=\"text-sm font-medium text-slate-700\">Activeer bulk export<\/label>\n                    <\/div>\n                    <div class=\"flex-grow\">\n                        <label for=\"email-for-export\" class=\"sr-only\">E-mail voor Export<\/label>\n                        <input type=\"email\" id=\"email-for-export\" value=\"${state.emailForExport}\" placeholder=\"E-mailadres (voor individuele verzending)...\" class=\"block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm p-3 text-black\">\n                    <\/div>\n                <\/div>\n\n                <div id=\"commercial-schedule\" class=\"${state.activeTab === 'commercial' ? '' : 'hidden'}\">\n                    ${hasCommercial ? DepreciationTable(state.commercialSchedule, 'commercial') : '<p class=\"text-center text-slate-500\">Geen commercieel schema berekend.<\/p>'}\n                <\/div>\n\n                <div id=\"fiscal-schedule\" class=\"${state.activeTab === 'fiscal' ? '' : 'hidden'}\">\n                    ${hasFiscal ? DepreciationTable(state.fiscalSchedule, 'fiscal') : '<p class=\"text-center text-slate-500\">Geen fiscaal schema berekend.<\/p>'}\n                <\/div>\n\n                <div class=\"flex flex-col sm:flex-row justify-between items-center gap-4 pt-4 border-t border-slate-200\">\n                    <button id=\"restart-calculation\" class=\"w-full sm:w-auto bg-slate-600 hover:bg-slate-700 text-white font-bold py-2 px-6 rounded-lg shadow transition-colors\">Nieuwe Berekening Starten<\/button>\n                    <div class=\"w-full sm:w-auto flex flex-col sm:flex-row gap-4\">\n                        <button id=\"export-excel\" class=\"bg-orange-500 hover:bg-orange-600 text-white font-bold py-2 px-6 rounded-lg shadow-md transition-transform transform hover:scale-105\">Exporteer naar Excel<\/button>\n                        ${state.bulkSendEnabled ? `<button id=\"download-zip-xml\" class=\"bg-orange-500 hover:bg-orange-600 text-white font-bold py-2 px-6 rounded-lg shadow-md transition-transform transform hover:scale-105\">Download Geselecteerde (.zip)<\/button>` : ''}\n                    <\/div>\n                <\/div>\n            <\/div>\n        `;\n    }\n    \n    function DepreciationTable(schedule, type) {\n        const selectedPeriods = type === 'commercial' ? state.selectedCommercialPeriods : state.selectedFiscalPeriods;\n        const allSelected = selectedPeriods.size === schedule.length && schedule.length > 0;\n\n        return `\n            <div class=\"overflow-x-auto rounded-lg border border-slate-200\">\n                <table class=\"min-w-full divide-y divide-slate-200\">\n                    <thead class=\"bg-slate-100\">\n                        <tr>\n                            ${state.bulkSendEnabled ? `<th scope=\"col\" class=\"py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-slate-900\"><input type=\"checkbox\" data-type=\"${type}\" class=\"select-all-checkbox h-4 w-4 rounded border-gray-300 text-sky-600 focus:ring-sky-500\" ${allSelected ? 'checked' : ''}><\/th>` : ''}\n                            <th scope=\"col\" class=\"py-3.5 px-3 text-left text-sm font-semibold text-slate-900\">Periode<\/th>\n                            <th scope=\"col\" class=\"py-3.5 px-3 text-left text-sm font-semibold text-slate-900\">Datum<\/th>\n                            <th scope=\"col\" class=\"py-3.5 px-3 text-right text-sm font-semibold text-slate-900\">Afschrijving<\/th>\n                            <th scope=\"col\" class=\"py-3.5 px-3 text-right text-sm font-semibold text-slate-900\">Cumulatief<\/th>\n                            <th scope=\"col\" class=\"py-3.5 px-3 text-right text-sm font-semibold text-slate-900\">Boekwaarde<\/th>\n                            <th scope=\"col\" class=\"relative py-3.5 pl-3 pr-4\"><span class=\"sr-only\">Acties<\/span><\/th>\n                        <\/tr>\n                    <\/thead>\n                    <tbody class=\"divide-y divide-slate-200 bg-white\">\n                        ${schedule.map((item, index) => `\n                            <tr class=\"hover:bg-slate-50\">\n                                ${state.bulkSendEnabled ? `<td class=\"whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-slate-900\"><input type=\"checkbox\" data-date=\"${item.date}\" data-type=\"${type}\" class=\"period-checkbox h-4 w-4 rounded border-gray-300 text-sky-600 focus:ring-sky-500\" ${selectedPeriods.has(item.date) ? 'checked' : ''}><\/td>` : ''}\n                                <td class=\"whitespace-nowrap py-4 px-3 text-sm text-slate-500\">${index + 1}<\/td>\n                                <td class=\"whitespace-nowrap py-4 px-3 text-sm text-slate-500\">${item.date}<\/td>\n                                <td class=\"whitespace-nowrap py-4 px-3 text-sm text-slate-500 text-right\">\u20ac ${item.depreciation.toFixed(2)}<\/td>\n                                <td class=\"whitespace-nowrap py-4 px-3 text-sm text-slate-500 text-right\">\u20ac ${item.cumulativeDepreciation.toFixed(2)}<\/td>\n                                <td class=\"whitespace-nowrap py-4 px-3 text-sm text-slate-500 text-right\">\u20ac ${item.bookValue.toFixed(2)}<\/td>\n                                <td class=\"whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium\">\n                                    <div class=\"flex justify-end items-center gap-2\">\n                                        <button class=\"download-xml-btn\" data-date=\"${item.date}\" data-type=\"${type}\" title=\"Download UBL XML\">\n                                            <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"h-5 w-5 text-sky-500 hover:text-sky-700\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M3 17a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm3.293-7.707a1 1 0 011.414 0L9 10.586V3a1 1 0 112 0v7.586l1.293-1.293a1 1 0 111.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z\" clip-rule=\"evenodd\" \/><\/svg>\n                                        <\/button>\n                                        <button class=\"send-xml-btn\" data-date=\"${item.date}\" data-type=\"${type}\" title=\"Verstuur UBL XML per e-mail\">\n                                            <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"h-5 w-5 text-green-500 hover:text-green-700\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path d=\"M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z\" \/><path d=\"M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z\" \/><\/svg>\n                                        <\/button>\n                                    <\/div>\n                                <\/td>\n                            <\/tr>\n                        `).join('')}\n                    <\/tbody>\n                <\/table>\n            <\/div>`;\n    }\n\n\n    \/\/ --- EVENT LISTENERS & HANDLERS ---\n    function attachEventListeners() {\n        \/\/ Step 1\n        const nextStep1Btn = document.getElementById('next-step-1');\n        if (nextStep1Btn) nextStep1Btn.addEventListener('click', handleNextStep1);\n        \n        const pdfUpload = document.getElementById('pdf-upload');\n        if(pdfUpload) pdfUpload.addEventListener('change', handlePdfUpload);\n\n        \/\/ Step 2\n        const prevStep2Btn = document.getElementById('prev-step-2');\n        if (prevStep2Btn) prevStep2Btn.addEventListener('click', () => updateStep(1));\n        \n        const calculateBtn = document.getElementById('calculate-depreciation');\n        if (calculateBtn) calculateBtn.addEventListener('click', handleCalculateDepreciation);\n\n        const assetGroupSelect = document.getElementById('asset-group');\n        if (assetGroupSelect) assetGroupSelect.addEventListener('change', handleAssetGroupChange);\n\n        \/\/ Step 3\n        const restartBtn = document.getElementById('restart-calculation');\n        if (restartBtn) restartBtn.addEventListener('click', handleRestart);\n\n        document.querySelectorAll('.tab-btn').forEach(btn => btn.addEventListener('click', handleTabClick));\n        document.querySelectorAll('.download-xml-btn').forEach(btn => btn.addEventListener('click', handleDownloadXml));\n        document.querySelectorAll('.send-xml-btn').forEach(btn => btn.addEventListener('click', handleSendXmlByEmail));\n        \n        const bulkSendEnabledCheckbox = document.getElementById('bulk-send-enabled');\n        if(bulkSendEnabledCheckbox) bulkSendEnabledCheckbox.addEventListener('change', handleBulkSendToggle);\n        \n        const downloadZipBtn = document.getElementById('download-zip-xml');\n        if (downloadZipBtn) downloadZipBtn.addEventListener('click', handleDownloadZip);\n        \n        document.querySelectorAll('.period-checkbox').forEach(cb => cb.addEventListener('change', handlePeriodSelection));\n        document.querySelectorAll('.select-all-checkbox').forEach(cb => cb.addEventListener('change', handleSelectAll));\n\n        const emailInput = document.getElementById('email-for-export');\n        if (emailInput) emailInput.addEventListener('input', (e) => state.emailForExport = e.target.value);\n        \n        const exportExcelBtn = document.getElementById('export-excel');\n        if (exportExcelBtn) exportExcelBtn.addEventListener('click', handleExportToExcel);\n\n    }\n\n    function updateStep(step) {\n        state.currentStep = step;\n        render();\n    }\n    \n    function updateState(newState) {\n        Object.assign(state, newState);\n        render();\n    }\n\n    function handleNextStep1() {\n        \/\/ Data van formulier in state opslaan\n        state.invoiceData.supplier = document.getElementById('supplier').value;\n        state.invoiceData.invoiceNumber = document.getElementById('invoice-number').value;\n        state.invoiceData.invoiceDate = document.getElementById('invoice-date').value;\n        state.invoiceData.amountExclVat = parseFloat(document.getElementById('amount-excl-vat').value) || 0;\n        state.invoiceData.description = document.getElementById('description').value;\n        \n        \/\/ Startdatum afschrijving standaard op factuurdatum zetten\n        state.investmentParams.depreciationStartDate = state.invoiceData.invoiceDate;\n\n        updateStep(2);\n    }\n    \n    function handleCalculateDepreciation() {\n        \/\/ Data van formulier 2 in state opslaan\n        state.investmentParams.assetGroup = document.getElementById('asset-group').value;\n        state.investmentParams.lifespan = parseInt(document.getElementById('lifespan').value) || 0;\n        state.investmentParams.residualValue = parseFloat(document.getElementById('residual-value').value) || 0;\n        state.investmentParams.residualValueType = document.getElementById('residual-value-type').value;\n        state.investmentParams.depreciationStartDate = document.getElementById('depreciation-start-date').value;\n        state.investmentParams.depreciationMethod = document.getElementById('depreciation-method').value;\n        state.investmentParams.calculationType = document.getElementById('calculation-type').value;\n        state.investmentParams.period = document.getElementById('period').value;\n        state.investmentParams.rgsCodeAsset = document.getElementById('rgs-code-asset').value;\n        \n        const schedules = calculateDepreciationSchedules();\n        \n        state.commercialSchedule = schedules.commercial;\n        state.fiscalSchedule = schedules.fiscal;\n        \n        \/\/ Reset and pre-select all periods if bulk mode is on\n        state.selectedCommercialPeriods = new Set();\n        state.selectedFiscalPeriods = new Set();\n        if (state.bulkSendEnabled) {\n            if (schedules.commercial.length > 0) {\n                 state.selectedCommercialPeriods = new Set(schedules.commercial.map(p => p.date));\n            }\n            if (schedules.fiscal.length > 0) {\n                 state.selectedFiscalPeriods = new Set(schedules.fiscal.map(p => p.date));\n            }\n        }\n        \n        \/\/ Set active tab logically\n        if (state.investmentParams.calculationType === 'fiscaal') {\n            state.activeTab = 'fiscal';\n        } else {\n            state.activeTab = 'commercial';\n        }\n\n        updateStep(3);\n    }\n\n    function handleRestart() {\n        \/\/ Reset state to initial values, but keep some settings\n        const email = state.emailForExport;\n        const bulkEnabled = state.bulkSendEnabled;\n        \n        state = {\n            ...state, \/\/ keep old state to retain keys\n            currentStep: 1,\n            invoiceData: {\n                invoiceDate: new Date().toISOString().split('T')[0],\n                amountExclVat: '', supplier: '', invoiceNumber: '', description: ''\n            },\n            investmentParams: {\n                assetGroup: 'kantoorinventaris',\n                lifespan: ASSET_GROUPS_DEFAULTS.kantoorinventaris.lifespan,\n                residualValue: ASSET_GROUPS_DEFAULTS.kantoorinventaris.residualValuePercentage,\n                residualValueType: 'percentage',\n                depreciationStartDate: new Date().toISOString().split('T')[0],\n                depreciationMethod: 'lineair',\n                calculationType: 'beide',\n                period: 'maand',\n                rgsCodeAsset: ASSET_GROUPS_DEFAULTS.kantoorinventaris.rgsCodeAsset,\n            },\n            commercialSchedule: [],\n            fiscalSchedule: [],\n            activeTab: 'commercial',\n            selectedCommercialPeriods: new Set(),\n            selectedFiscalPeriods: new Set(),\n            isPdfParsing: false,\n            \/\/ Restore user preferences\n            emailForExport: email,\n            bulkSendEnabled: bulkEnabled\n        };\n        handleAssetGroupChange({ target: { value: 'kantoorinventaris' }}); \/\/ To set defaults\n        updateStep(1);\n    }\n\n    function handleTabClick(e) {\n        state.activeTab = e.target.id === 'tab-commercial' ? 'commercial' : 'fiscal';\n        render();\n    }\n    \n    function handleAssetGroupChange(e) {\n        const group = e.target.value;\n        const defaults = ASSET_GROUPS_DEFAULTS[group];\n        if (defaults) {\n            state.investmentParams.assetGroup = group;\n            state.investmentParams.lifespan = defaults.lifespan;\n            state.investmentParams.residualValue = defaults.residualValuePercentage;\n            state.investmentParams.residualValueType = 'percentage';\n            state.investmentParams.rgsCodeAsset = defaults.rgsCodeAsset;\n\n            \/\/ Update UI fields directly\n            document.getElementById('lifespan').value = defaults.lifespan;\n            document.getElementById('residual-value').value = defaults.residualValuePercentage;\n            document.getElementById('residual-value-type').value = 'percentage';\n            document.getElementById('rgs-code-asset').value = defaults.rgsCodeAsset;\n        }\n    }\n    \n     async function handlePdfUpload(event) {\n        const file = event.target.files[0];\n        if (!file) return;\n\n        updateState({ isPdfParsing: true });\n\n        try {\n            const fileReader = new FileReader();\n            fileReader.onload = async (e) => {\n                const typedarray = new Uint8Array(e.target.result);\n                const pdf = await pdfjsLib.getDocument(typedarray).promise;\n                let fullText = '';\n                for (let i = 1; i <= pdf.numPages; i++) {\n                    const page = await pdf.getPage(i);\n                    const textContent = await page.getTextContent();\n                    fullText += textContent.items.map(item => item.str).join('\\n');\n                }\n                const parsedData = parseInvoiceText(fullText);\n                \n                updateState({\n                    invoiceData: { ...state.invoiceData, ...parsedData },\n                    isPdfParsing: false,\n                });\n            };\n            fileReader.readAsArrayBuffer(file);\n        } catch (error) {\n            console.error(\"Error parsing PDF:\", error);\n            alert(\"Kon de PDF niet verwerken. Controleer of het een tekstgebaseerde PDF is.\");\n            updateState({ isPdfParsing: false });\n        }\n    }\n    \n    function handleBulkSendToggle(e) {\n        updateState({ bulkSendEnabled: e.target.checked });\n    }\n    \n    function handlePeriodSelection(e) {\n        const date = e.target.dataset.date;\n        const type = e.target.dataset.type;\n        const selectedSet = type === 'commercial' ? state.selectedCommercialPeriods : state.selectedFiscalPeriods;\n        \n        if (e.target.checked) {\n            selectedSet.add(date);\n        } else {\n            selectedSet.delete(date);\n        }\n        render(); \/\/ Re-render to update the 'select all' checkbox state\n    }\n\n    function handleSelectAll(e) {\n        const type = e.target.dataset.type;\n        const schedule = type === 'commercial' ? state.commercialSchedule : state.fiscalSchedule;\n        const selectedSet = type === 'commercial' ? state.selectedCommercialPeriods : state.selectedFiscalPeriods;\n\n        selectedSet.clear();\n        if (e.target.checked) {\n            schedule.forEach(item => selectedSet.add(item.date));\n        }\n        render();\n    }\n    \n    \/\/ --- BEREKENINGSLOGICA ---\n    function calculateDepreciationSchedules() {\n        const { calculationType } = state.investmentParams;\n        let commercial = [];\n        let fiscal = [];\n\n        if (calculationType === 'commercieel' || calculationType === 'beide') {\n            commercial = calculateSchedule('commercial');\n        }\n        if (calculationType === 'fiscaal' || calculationType === 'beide') {\n            fiscal = calculateSchedule('fiscaal');\n        }\n        return { commercial, fiscal };\n    }\n    \n    function calculateSchedule(type) {\n        const { amountExclVat } = state.invoiceData;\n        const {\n            lifespan,\n            residualValue,\n            residualValueType,\n            depreciationStartDate,\n            depreciationMethod,\n            period\n        } = state.investmentParams;\n\n        if (!amountExclVat || !lifespan || isNaN(amountExclVat) || isNaN(lifespan) || lifespan === 0) {\n            return [];\n        }\n\n        let finalResidualValue = 0;\n        if (residualValueType === 'percentage') {\n            finalResidualValue = amountExclVat * (residualValue \/ 100);\n        } else {\n            finalResidualValue = residualValue;\n        }\n\n        const amountToDepreciate = amountExclVat - finalResidualValue;\n        const totalPeriods = lifespan * (period === 'maand' ? 12 : 4);\n        \n        let schedule = [];\n        let bookValue = amountExclVat;\n        let cumulativeDepreciation = 0;\n\n        const startDate = new Date(depreciationStartDate);\n\n        for (let i = 0; i < totalPeriods; i++) {\n            let depreciationThisPeriod = 0;\n            if (totalPeriods > 0) {\n                 if (depreciationMethod === 'lineair') {\n                    depreciationThisPeriod = amountToDepreciate \/ totalPeriods;\n                } else { \/\/ Simplified degressive\n                    const degressiveFactor = 2; \/\/ Example factor\n                    const yearlyDepreciation = (bookValue \/ lifespan) * degressiveFactor;\n                    depreciationThisPeriod = yearlyDepreciation \/ (period === 'maand' ? 12 : 4);\n                    \/\/ Switch to linear if it's higher\n                    const linearDepreciation = (bookValue - finalResidualValue) \/ (totalPeriods - i);\n                    if (depreciationThisPeriod < linearDepreciation) {\n                        depreciationThisPeriod = linearDepreciation;\n                    }\n                }\n            }\n           \n\n            if (bookValue - depreciationThisPeriod < finalResidualValue) {\n                depreciationThisPeriod = bookValue - finalResidualValue;\n            }\n            \n            if (depreciationThisPeriod < 0) depreciationThisPeriod = 0;\n\n            bookValue -= depreciationThisPeriod;\n            cumulativeDepreciation += depreciationThisPeriod;\n\n            let periodDate;\n            if (period === 'maand') {\n                periodDate = new Date(startDate.getFullYear(), startDate.getMonth() + i + 1, 0);\n            } else { \/\/ kwartaal\n                periodDate = new Date(startDate.getFullYear(), startDate.getMonth() + (i * 3) + 3, 0);\n            }\n\n            schedule.push({\n                date: periodDate.toISOString().split('T')[0],\n                depreciation: depreciationThisPeriod,\n                cumulativeDepreciation,\n                bookValue,\n            });\n        }\n\n        return schedule;\n    }\n\n    \/\/ --- XML &#038; EXPORT LOGICA ---\n    function getUblXmlStringForPeriod(date, type) {\n        const schedule = type === 'commercial' ? state.commercialSchedule : state.fiscalSchedule;\n        const periodData = schedule.find(p => p.date === date);\n        if (!periodData) return '';\n        \n        const { invoiceNumber, supplier, description } = state.invoiceData;\n        const { assetGroup } = state.investmentParams;\n        const rgsDefaults = ASSET_GROUPS_DEFAULTS[assetGroup] || {};\n\n        const rgsCost = rgsDefaults.rgsCodeDepreciationCost || \"44XXX\";\n        const rgsAccumulated = rgsDefaults.rgsCodeAccumulatedDepreciation || \"02XXX\";\n\n        return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ubl:GeneralLedgerJournal xmlns:ubl=\"urn:oasis:names:specification:ubl:schema:xsd:GeneralLedgerJournal-2\" xmlns:cac=\"urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2\" xmlns:cbc=\"urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2\">\n    <cbc:UBLVersionID>2.1<\/cbc:UBLVersionID>\n    <cbc:ID>${invoiceNumber || 'N\/A'}-${date}<\/cbc:ID>\n    <cbc:IssueDate>${new Date().toISOString().split('T')[0]}<\/cbc:IssueDate>\n    <cac:AccountingSupplierParty>\n        <cac:Party>\n            <cac:PartyName>\n                <cbc:Name>${supplier || 'Onbekende Leverancier'}<\/cbc:Name>\n            <\/cac:PartyName>\n        <\/cac:Party>\n    <\/cac:AccountingSupplierParty>\n    <cac:JournalLine>\n        <cbc:ID>1<\/cbc:ID>\n        <cbc:Note>Afschrijving ${description || 'investering'} (${type})<\/cbc:Note>\n        <cbc:DebitLineAmount currencyID=\"EUR\">${periodData.depreciation.toFixed(2)}<\/cbc:DebitLineAmount>\n        <cac:GLAccount>\n            <cbc:ID schemeID=\"RGS\">${rgsCost}<\/cbc:ID>\n        <\/cac:GLAccount>\n        <cac:AccountingPeriod>\n            <cbc:EndDate>${date}<\/cbc:EndDate>\n        <\/cac:AccountingPeriod>\n    <\/cac:JournalLine>\n    <cac:JournalLine>\n        <cbc:ID>2<\/cbc:ID>\n        <cbc:Note>Tegenrekening afschrijving ${description || 'investering'}<\/cbc:Note>\n        <cbc:CreditLineAmount currencyID=\"EUR\">${periodData.depreciation.toFixed(2)}<\/cbc:CreditLineAmount>\n        <cac:GLAccount>\n            <cbc:ID schemeID=\"RGS\">${rgsAccumulated}<\/cbc:ID>\n        <\/cac:GLAccount>\n         <cac:AccountingPeriod>\n            <cbc:EndDate>${date}<\/cbc:EndDate>\n        <\/cac:AccountingPeriod>\n    <\/cac:JournalLine>\n<\/ubl:GeneralLedgerJournal>`;\n    }\n\n    function handleDownloadXml(e) {\n        const { date, type } = e.currentTarget.dataset;\n        const xmlString = getUblXmlStringForPeriod(date, type);\n        const blob = new Blob([xmlString], { type: 'application\/xml' });\n        const url = URL.createObjectURL(blob);\n        const a = document.createElement('a');\n        a.href = url;\n        a.download = `journaalpost-${date}.xml`;\n        document.body.appendChild(a);\n        a.click();\n        document.body.removeChild(a);\n        URL.revokeObjectURL(url);\n    }\n\n    function handleSendXmlByEmail(e) {\n        if (!state.emailForExport) {\n            alert(\"Vul alstublieft een e-mailadres in.\");\n            return;\n        }\n        const { date, type } = e.currentTarget.dataset;\n        const xmlString = getUblXmlStringForPeriod(date, type);\n        const subject = `XML Journaalpost voor ${date}`;\n        const body = `Hieronder de UBL XML voor de afschrijving van periode ${date}:\\n\\n${xmlString}`;\n        window.location.href = `mailto:${state.emailForExport}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;\n    }\n    \n    async function handleDownloadZip() {\n        const selectedPeriods = state.activeTab === 'commercial' ? state.selectedCommercialPeriods : state.selectedFiscalPeriods;\n        if (selectedPeriods.size === 0) {\n            alert(\"Selecteer alstublieft ten minste \u00e9\u00e9n periode om te downloaden.\");\n            return;\n        }\n\n        const zip = new JSZip();\n        \n        Array.from(selectedPeriods).sort().forEach(date => {\n            const xmlString = getUblXmlStringForPeriod(date, state.activeTab);\n            zip.file(`journaalpost-${date}.xml`, xmlString);\n        });\n\n        try {\n            const content = await zip.generateAsync({ type: \"blob\" });\n            const url = URL.createObjectURL(content);\n            const a = document.createElement('a');\n            a.href = url;\n            a.download = `xml_export_${state.activeTab}.zip`;\n            document.body.appendChild(a);\n            a.click();\n            document.body.removeChild(a);\n            URL.revokeObjectURL(url);\n        } catch (error) {\n            console.error(\"Fout bij het genereren van het zip-bestand:\", error);\n            alert(\"Er is een fout opgetreden bij het maken van het zip-bestand.\");\n        }\n    }\n    \n    function handleExportToExcel() {\n        const wb = XLSX.utils.book_new();\n        const hasCommercial = state.commercialSchedule.length > 0;\n        const hasFiscal = state.fiscalSchedule.length > 0;\n        \n        if (hasCommercial) {\n            const commercialData = state.commercialSchedule.map((row, index) => ({\n                'Periode': index + 1,\n                'Datum': row.date,\n                'Afschrijving': row.depreciation,\n                'Cumulatief': row.cumulativeDepreciation,\n                'Boekwaarde': row.bookValue\n            }));\n            const ws = XLSX.utils.json_to_sheet(commercialData);\n            \/\/ Apply number formatting\n            ws['C2:E' + (commercialData.length + 1)].forEach(cell => cell.z = '\u20ac #,##0.00');\n            XLSX.utils.book_append_sheet(wb, ws, \"Commercieel\");\n        }\n        \n        if (hasFiscal) {\n             const fiscalData = state.fiscalSchedule.map((row, index) => ({\n                'Periode': index + 1,\n                'Datum': row.date,\n                'Afschrijving': row.depreciation,\n                'Cumulatief': row.cumulativeDepreciation,\n                'Boekwaarde': row.bookValue\n            }));\n            const ws = XLSX.utils.json_to_sheet(fiscalData);\n            \/\/ Apply number formatting\n            ws['C2:E' + (fiscalData.length + 1)].forEach(cell => cell.z = '\u20ac #,##0.00');\n            XLSX.utils.book_append_sheet(wb, ws, \"Fiscaal\");\n        }\n        \n        if (!hasCommercial && !hasFiscal) {\n            alert('Er is geen data om te exporteren.');\n            return;\n        }\n\n        XLSX.writeFile(wb, 'afschrijvingsschema.xlsx');\n    }\n\n    \/\/ --- PDF PARSING LOGICA (AI-gesimuleerd) ---\n    function parseInvoiceText(text) {\n        const data = {};\n        const lines = text.split('\\n').map(line => line.trim()).filter(line => line.length > 2);\n\n        \/\/ --- REGEX DEFINITIES ---\n        const amountRegex = \/(?:Totaal|Subtotaal|Bedrag)(?:.*excl.*?btw)?[\\s:]*[\u20ac\\s]*([\\d,.]*[\\d])\/i;\n        const invoiceNumRegex = \/(?:Factuurnummer|Invoice no\\.?|Factuur)\\s*:?\\s*(\\S+)\/i;\n        const dateRegex = \/(?:Factuurdatum|Date)\\s*:?\\s*(\\d{1,2}[-\\\/\\.]\\d{1,2}[-\\\/\\.]\\d{2,4})\/i;\n        const descriptionRegex = \/(?:Omschrijving|Description)\\s*:\\s*(.*)\/i;\n        \n        \/\/ --- DATA EXTRACTIE ---\n        let amountMatch = text.match(amountRegex);\n        if (amountMatch && amountMatch[1]) {\n            data.amountExclVat = parseFloat(amountMatch[1].replace(\/\\.\/g, '').replace(',', '.'));\n        }\n\n        let invoiceNumMatch = text.match(invoiceNumRegex);\n        if (invoiceNumMatch && invoiceNumMatch[1]) {\n            data.invoiceNumber = invoiceNumMatch[1];\n        }\n\n        let dateMatch = text.match(dateRegex);\n        if (dateMatch && dateMatch[1]) {\n            const parts = dateMatch[1].split(\/[-\\\/\\.]\/);\n            if (parts.length === 3) {\n                const day = parts[0].padStart(2, '0');\n                const month = parts[1].padStart(2, '0');\n                let year = parts[2];\n                if (year.length === 2) year = `20${year}`;\n                data.invoiceDate = `${year}-${month}-${day}`;\n            }\n        }\n        \n        \/\/ --- \"AI\" VOORSTEL VOOR LEVERANCIER ---\n        \/\/ Simpele logica: De eerste regel die geen label is (zoals \"Factuur\") is vaak de leverancier.\n        const potentialSupplier = lines.find(line => \n            line.length > 3 && \n            !\/factuur|invoice|datum|date|nummer|number\/i.test(line) &&\n            \/[a-zA-Z]\/.test(line) \/\/ Moet letters bevatten\n        );\n        data.supplier = potentialSupplier || \"Niet gevonden\";\n\n\n        \/\/ --- \"AI\" VOORSTEL VOOR OMSCHRIJVING ---\n        \/\/ 1. Zoek naar een expliciet label.\n        let descriptionMatch = text.match(descriptionRegex);\n        if (descriptionMatch && descriptionMatch[1]) {\n            data.description = descriptionMatch[1].trim();\n        } else {\n            \/\/ 2. Zoek naar de langste regel die waarschijnlijk een product is (geen adres, geen totaalbedrag).\n            const potentialDescriptions = lines.filter(line => \n                line.length > 10 && \/\/ Voldoende lang\n                !\/straat|weg|laan|postcode|totaal|subtotaal|btw|vat\/i.test(line) && \/\/ Geen adres of bedrag\n                !\/\u20ac|\\d{2,}-\\d{2,}-\\d{4,}\/.test(line) \/\/ Geen bedrag of datum\n            );\n            \/\/ Sorteer op lengte en neem de langste\n            if (potentialDescriptions.length > 0) {\n                data.description = potentialDescriptions.sort((a, b) => b.length - a.length)[0];\n            } else {\n                data.description = \"Niet gevonden\";\n            }\n        }\n\n        return data;\n    }\n\n\n    \/\/ --- INITIALISATIE ---\n    document.addEventListener('DOMContentLoaded', render);\n\n<\/script>\n\n<\/body>\n<\/html>\n\n\n\n\n\n<p><strong>Hoe deze tool uw kantoor helpt:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Intelligente Documentherkenning:<\/strong> Upload een investeringsfactuur en de tool haalt direct de kerndata zoals leverancier, bedrag en omschrijving uit het document.<\/li>\n\n\n\n<li><strong>Direct Inzicht en Prognose:<\/strong> Voer de levensduur en restwaarde in en ontvang direct een compleet afschrijvingsschema, zowel commercieel als fiscaal. De juiste RGS-codes worden al voor u klaargezet.<\/li>\n\n\n\n<li><strong>Naadloze Export:<\/strong> Met \u00e9\u00e9n klik genereert u voor elke periode een UBL-conforme XML-journaalpost, klaar voor import in uw boekhoudsoftware. Handmatig boeken is verleden tijd.<\/li>\n\n\n\n<li><strong>Focus op Strategisch Advies:<\/strong> De tijd die u bespaart, is direct inzetbaar voor waardevol advies. Modelleer de impact van een investering al op het moment dat de koopovereenkomst binnenkomt en help uw klant betere beslissingen te nemen.<\/li>\n<\/ul>\n\n\n\n<p><strong>Integreer de tool in uw proces<\/strong><\/p>\n\n\n\n<p>Dit is geen losse gadget, maar een integraal onderdeel van uw adviespraktijk. Zodra een klant een grote aankoop overweegt of een overeenkomst heeft getekend, kunt u deze assistent inzetten. Stel direct een voorlopig afschrijvingsplan op om de financi\u00eble impact voor de komende jaren te tonen.<\/p>\n\n\n\n<p>Zo transformeert u van een verwerker van historische data naar een proactieve regisseur die vanaf het begin van het investeringsproces meedenkt en adviseert.<\/p>\n\n\n\n<p><strong>Dit is geen vervanging, maar een versterking van uw expertise.<\/strong><\/p>\n\n\n\n<p>Deze tool neemt het repetitieve werk uit handen, zodat u zich kunt focussen op waar uw ware kracht ligt: interpretatie, strategisch denken en persoonlijk advies. U behoudt de controle en gebruikt de output om uw klanten het beste, toekomstgerichte advies te geven.<\/p>\n\n\n\n<p><strong>Probeer het zelf.<\/strong> Upload hieronder een (voorbeeld)document en ervaar hoe snel en eenvoudig u een compleet investeringstraject opzet.<\/p>\n\n\n\n<p>Daar is het vanzelf belangrijk dat je de eigen kantoor kennis\/visie meeneem zodat het echt een versterking personificatie wordt.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Van Factuur tot Advies: Automatiseer Investeringen en Afschrijvingen Effici\u00ebntie maakt het verschil. Toch worstelen veel accountants- en administratiekantoren met het verwerken van kapitaalinvesteringen. Dit proces is vaak complexer dan alleen het inboeken van een factuur. Het begint al bij de aankoopovereenkomst en eindigt pas jaren later na de laatste afschrijving. Het handmatig verwerken van een [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":39,"menu_order":2,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_joinchat":[],"footnotes":""},"class_list":["post-112","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/bjornproost.nl\/index.php?rest_route=\/wp\/v2\/pages\/112","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bjornproost.nl\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/bjornproost.nl\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/bjornproost.nl\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bjornproost.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=112"}],"version-history":[{"count":6,"href":"https:\/\/bjornproost.nl\/index.php?rest_route=\/wp\/v2\/pages\/112\/revisions"}],"predecessor-version":[{"id":121,"href":"https:\/\/bjornproost.nl\/index.php?rest_route=\/wp\/v2\/pages\/112\/revisions\/121"}],"up":[{"embeddable":true,"href":"https:\/\/bjornproost.nl\/index.php?rest_route=\/wp\/v2\/pages\/39"}],"wp:attachment":[{"href":"https:\/\/bjornproost.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=112"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}