Moneybird Auto Payment Registration

Automatically extracts invoice data and fills payment registration form

Size

6.7 KB

Version

1.0.1

Created

Jan 14, 2026

Updated

21 days ago

1// ==UserScript==
2// @name		Moneybird Auto Payment Registration
3// @description		Automatically extracts invoice data and fills payment registration form
4// @version		1.0.1
5// @match		https://*.moneybird.com/*
6// @icon		https://assets-app-cdn.moneybird.com/assets/favicon-b1fb00eb89b4530acc973e4c2cd93f58f7fc4095a79f9bb2a7d88f692b994273.ico
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    // Debounce function to prevent multiple rapid executions
12    function debounce(func, wait) {
13        let timeout;
14        return function executedFunction(...args) {
15            const later = () => {
16                clearTimeout(timeout);
17                func(...args);
18            };
19            clearTimeout(timeout);
20            timeout = setTimeout(later, wait);
21        };
22    }
23
24    // Extract invoice data from document page
25    function extractInvoiceData() {
26        console.log('Extracting invoice data...');
27        
28        const dateElement = document.querySelector('p.document-date');
29        const contactElement = document.querySelector('p.document-contact a');
30        
31        if (!dateElement || !contactElement) {
32            console.log('Invoice data elements not found on this page');
33            return null;
34        }
35        
36        const invoiceDate = dateElement.textContent.trim();
37        const contactName = contactElement.textContent.trim();
38        
39        console.log('Extracted Invoice Date:', invoiceDate);
40        console.log('Extracted Contact Name:', contactName);
41        
42        return { invoiceDate, contactName };
43    }
44
45    // Store invoice data and click register payment button
46    async function handleDocumentPage() {
47        console.log('On document page, checking for invoice data...');
48        
49        const invoiceData = extractInvoiceData();
50        if (!invoiceData) {
51            return;
52        }
53        
54        // Store the data for use on the next page
55        await GM.setValue('invoiceDate', invoiceData.invoiceDate);
56        await GM.setValue('contactName', invoiceData.contactName);
57        console.log('Invoice data stored successfully');
58        
59        // Find and click the register payment button
60        const registerButton = document.querySelector('a.btn.btn--secondary[title="Registreer betaling"]');
61        if (registerButton) {
62            console.log('Register payment button found, clicking...');
63            registerButton.click();
64        } else {
65            console.log('Register payment button not found');
66        }
67    }
68
69    // Fill in the payment form on the payment registration page
70    async function fillPaymentForm() {
71        console.log('On payment registration page, filling form...');
72        
73        // Retrieve stored invoice data
74        const invoiceDate = await GM.getValue('invoiceDate');
75        const contactName = await GM.getValue('contactName');
76        
77        if (!invoiceDate || !contactName) {
78            console.log('No stored invoice data found');
79            return;
80        }
81        
82        console.log('Retrieved Invoice Date:', invoiceDate);
83        console.log('Retrieved Contact Name:', contactName);
84        
85        // Fill ledger account field
86        const ledgerAccountSelect = document.querySelector('select[name="payment[ledger_account_id]"]');
87        if (ledgerAccountSelect) {
88            const targetValue = `Tussenrekening ${contactName}`;
89            console.log('Looking for ledger account option:', targetValue);
90            
91            // Find the option with matching text
92            const options = Array.from(ledgerAccountSelect.options);
93            const matchingOption = options.find(option => option.textContent.trim() === targetValue);
94            
95            if (matchingOption) {
96                ledgerAccountSelect.value = matchingOption.value;
97                console.log('Ledger account set to:', targetValue);
98                
99                // Trigger change event
100                ledgerAccountSelect.dispatchEvent(new Event('change', { bubbles: true }));
101            } else {
102                console.error('Could not find ledger account option:', targetValue);
103                console.log('Available options:', options.map(o => o.textContent.trim()));
104            }
105        } else {
106            console.log('Ledger account select field not found');
107        }
108        
109        // Fill payment date field
110        const dateInput = document.querySelector('div.date-picker.date-picker--long input.date-picker__input');
111        if (dateInput) {
112            dateInput.value = invoiceDate;
113            console.log('Payment date set to:', invoiceDate);
114            
115            // Trigger input and change events
116            dateInput.dispatchEvent(new Event('input', { bubbles: true }));
117            dateInput.dispatchEvent(new Event('change', { bubbles: true }));
118        } else {
119            console.log('Payment date input field not found');
120        }
121        
122        console.log('Payment form filled successfully');
123        
124        // Clear stored data after use
125        await GM.deleteValue('invoiceDate');
126        await GM.deleteValue('contactName');
127    }
128
129    // Determine which page we're on and take appropriate action
130    async function handlePage() {
131        const currentUrl = window.location.href;
132        
133        // Check if we're on a document detail page (not a payment page)
134        if (currentUrl.includes('/documents/') && !currentUrl.includes('/payments/')) {
135            await handleDocumentPage();
136        }
137        // Check if we're on a payment registration page
138        else if (currentUrl.includes('/payments/new') || currentUrl.includes('/payments/balance_settlement')) {
139            // Wait a bit for the page to fully load
140            setTimeout(async () => {
141                await fillPaymentForm();
142            }, 1000);
143        }
144    }
145
146    // Initialize the extension
147    async function init() {
148        console.log('Moneybird Auto Payment Registration extension loaded');
149        
150        // Handle the current page
151        await handlePage();
152        
153        // Watch for URL changes (for single-page app navigation)
154        let lastUrl = window.location.href;
155        const urlObserver = new MutationObserver(debounce(async () => {
156            const currentUrl = window.location.href;
157            if (currentUrl !== lastUrl) {
158                console.log('URL changed from', lastUrl, 'to', currentUrl);
159                lastUrl = currentUrl;
160                await handlePage();
161            }
162        }, 500));
163        
164        urlObserver.observe(document.body, {
165            childList: true,
166            subtree: true
167        });
168    }
169
170    // Wait for the page to be ready
171    if (document.readyState === 'loading') {
172        document.addEventListener('DOMContentLoaded', init);
173    } else {
174        init();
175    }
176})();
Moneybird Auto Payment Registration | Robomonkey