Fix/supp ag fb (#1023)

* fix: prevent credit notes from entering payment flow

* fix: persist and display customer personal numbers

* feat: configure automatic invoice reminder days

* fix: issue credit notes through send flow

* chore: add repository agent guidance

* feat(mcp): route tools across user companies

* fix(articles): delete unused register entries

* feat(invoices): improve issued invoice actions

* feat(supplier-invoices): retain uploaded source documents

* docs: record implementation decisions

* feat: enhance customer personal number handling and validation

- Updated CustomerForm to allow personal numbers in the format of "********-1234" for individual customers.
- Added validation to ensure personal numbers are only accepted for individual customers in CreateCustomerSchema.
- Implemented masking and encryption for personal numbers to enhance data protection.
- Introduced new utility functions for masking and encrypting personal numbers.
- Added database migration to enforce unique constraints on credit note relationships and prevent duplicate entries.
- Enhanced error handling and logging for credit note issuance and invoice processing.
- Updated tests to cover new credit note creation guards and personal number handling.

* test: enhance list companies test with supabase query mocks
This commit is contained in:
Mattsson
2026-07-15 15:53:15 +02:00
committed by GitHub
parent a558c75678
commit 072aedeaf9
116 changed files with 5708 additions and 669 deletions
+91 -8
View File
@@ -828,15 +828,16 @@
"edit_dialog_title": "Edit customer",
"viewer_disabled_tooltip": "You only have viewer access in this company",
"section_contact": "Contact details",
"section_business": "Business details",
"section_business": "Customer details",
"section_summary": "Overview",
"section_notes": "Notes",
"section_invoices": "Invoices",
"no_contact_info": "No contact details",
"no_business_info": "No business details",
"no_business_info": "No additional customer details",
"no_invoices": "No invoices linked to this customer",
"label_customer_number": "Customer number:",
"label_org_number": "Org. no.:",
"label_personal_number": "Personal no.:",
"label_vat": "VAT:",
"label_payment_terms": "Payment terms:",
"payment_terms_value": "{days} days",
@@ -1531,7 +1532,12 @@
"default_days_label": "Payment terms (days)",
"default_notes_label": "Default invoice text",
"default_notes_placeholder": "E.g. payment terms, delivery info...",
"default_notes_help": "Suggested automatically for new invoices."
"default_notes_help": "Suggested automatically for new invoices.",
"reminder_days_heading": "Automatic reminders",
"reminder_days_help": "Choose how many days after the due date each reminder is sent. The days must be in ascending order.",
"reminder_days_level_1": "First reminder (days)",
"reminder_days_level_2": "Second reminder (days)",
"reminder_days_level_3": "Final reminder (days)"
},
"settings_pdf_print": {
"coming_soon": "Coming soon",
@@ -2498,9 +2504,15 @@
"title_invoice": "New invoice",
"title_proforma": "New proforma invoice",
"title_delivery_note": "New delivery note",
"title_copy": "Copy invoice",
"subtitle_invoice": "Create a new invoice",
"subtitle_proforma": "Create a proforma invoice (no bookkeeping)",
"subtitle_delivery_note": "Create a delivery note (without prices)",
"subtitle_copy": "Create a new invoice from reused content",
"copy_notice": "The content was copied from {number}. A new draft is created with a new date and invoice number. Check the customer, references, and ROT/RUT details before continuing.",
"copy_load_failed_title": "Could not copy the invoice",
"copy_load_failed_description": "The invoice does not exist or cannot be used as a template.",
"close": "Close",
"bank_missing_warning": "Payment details missing: you need to add them before creating an invoice.",
"bank_add_now": "Add now",
"customer_card_title": "Customer",
@@ -2710,9 +2722,13 @@
"sent_at_suffix": " • Sent {date}",
"convert_to_invoice": "Convert to invoice",
"send_via_email": "Send via email",
"send_via_email_and_book": "Send via email and post",
"mark_sent_manually": "Sent manually",
"mark_sent_and_book": "Mark as sent and post",
"complete_credit_bookkeeping": "Complete bookkeeping",
"mark_as_sent": "Mark as sent",
"mark_as_paid": "Mark as paid",
"copy_invoice": "Copy invoice",
"download_pdf": "Download PDF",
"viewer_disabled_tooltip": "You only have read-only access to this company",
"customer_card_title": "Customer",
@@ -2754,7 +2770,7 @@
"payment_status_view_voucher_unlinked": "No voucher linked",
"payment_status_empty": "No payments recorded yet.",
"reminders_card_title": "Reminders",
"reminders_description": "Automatic reminders are sent at 15, 30 and 45 days overdue",
"reminders_description": "Automatic reminders are sent when the invoice is {day1}, {day2} and {day3} days overdue",
"reminders_empty": "No reminders have been sent yet.",
"reminder_level_label": "Level {level}",
"reminder_level_1": "Friendly reminder",
@@ -2765,6 +2781,8 @@
"reminder_objection": "Customer has objections",
"credited_card_title": "Credited",
"see_credit_note": "See credit note {number}",
"credit_draft_card_title": "Credit note waiting to be sent",
"open_credit_draft": "Open draft {number}",
"credit_note_card_title": "Credit note",
"credit_note_description": "This credit note credits",
"see_original_invoice": "See invoice {number}",
@@ -2774,6 +2792,7 @@
"actions_card_title": "Actions",
"cancel_action": "Cancel",
"delete_draft": "Cancel draft",
"remove_credit_draft": "Delete credit draft",
"create_credit_note": "Create credit note",
"no_customer_email_warning": "The customer has no email address. Add an email to be able to send the invoice digitally.",
"send_manual_hint_with_email": "Use if you've already sent the invoice another way (post, another system)",
@@ -2801,6 +2820,9 @@
"remove_dialog_title": "Delete draft?",
"remove_dialog_desc": "The draft and its rows are permanently deleted. Since no invoice number was assigned, the number series is unaffected. This cannot be undone.",
"remove_dialog_confirm": "Delete",
"remove_credit_dialog_title": "Delete credit draft?",
"remove_credit_dialog_desc": "The credit note has not been issued or posted. The draft and its lines are permanently deleted and can be created again.",
"remove_credit_dialog_confirm": "Delete draft",
"removed_toast_title": "Draft deleted",
"removed_toast_description": "The draft has been removed.",
"status_update_toast_title": "Updated",
@@ -2830,8 +2852,8 @@
"back": "Back",
"title": "Create credit note",
"subtitle": "Credits invoice {number}",
"warning_title": "Irreversible action",
"warning_description": "A credit note fully cancels the original invoice. All amounts become negative, a bookkeeping verifikat is created, and the original invoice is marked as credited. This action cannot be undone.",
"warning_title": "The credit note is created as a draft",
"warning_description": "All amounts become negative. The original invoice is marked as credited only when the credit note is sent or marked as sent. Bookkeeping is then handled according to the company's selected accounting method.",
"original_card_title": "Original invoice",
"invoice_number_label": "Invoice number:",
"date_label": "Date:",
@@ -2867,7 +2889,7 @@
"already_credited_title": "Already credited",
"already_credited_description": "This invoice has already been credited",
"created_toast_title": "Credit note created",
"created_toast_description": "Credit note {number} has been created",
"created_toast_description": "Credit note {number} was created as a draft.",
"create_failed_title": "Could not create credit note",
"create_failed_fallback": "Failed to create credit note",
"try_again": "Try again."
@@ -2956,26 +2978,54 @@
"invoice_send_dialog": {
"title_email": "Send invoice",
"title_manual": "Mark as sent",
"title_credit_email": "Send credit note",
"title_credit_manual": "Mark credit note as sent",
"title_credit_repair": "Complete credit-note bookkeeping",
"title_suffix": ": {number}",
"description_sek_suffix": " ({amount} SEK)",
"description_to_email": " to {email}",
"load_failed_title": "Could not load settings",
"no_active_company": "No active company",
"company_settings_failed": "Could not load company settings",
"fiscal_period_failed": "Could not load the fiscal period",
"original_invoice_failed": "Could not load the original invoice",
"journal_preview_intro": "The following bookkeeping verifikat is created automatically:",
"voucher_description": "Sales invoice{numberSpace}{customerSuffix}",
"credit_voucher_description": "Credit note{numberSpace}{customerSuffix}",
"explain_cash": "Cash method: bookkeeping happens on payment, not on invoicing.",
"explain_credit_cash": "Cash method: the original invoice is unpaid, so no verifikat is created when the credit note is issued.",
"explain_email": "The invoice is sent to {email}.",
"explain_manual": "The invoice is marked as sent.",
"cancel": "Cancel",
"later": "Do later",
"send_invoice": "Send invoice",
"send_invoice_and_book": "Send and post",
"mark_as_sent": "Mark as sent",
"mark_as_sent_and_book": "Mark as sent and post",
"send_credit_note": "Send credit note",
"send_credit_note_and_book": "Send and post credit note",
"mark_credit_note_sent": "Mark as sent",
"mark_credit_note_sent_and_book": "Mark as sent and post",
"complete_credit_bookkeeping": "Complete bookkeeping",
"send_failed_title": "Could not send invoice",
"credit_send_failed_title": "Could not issue the credit note",
"send_failed_fallback": "Could not send the invoice",
"send_success_title": "Invoice sent",
"send_book_success_title": "Sent and posted",
"credit_send_success_title": "Credit note sent",
"credit_send_book_success_title": "Credit note sent and posted",
"credit_send_success": "The credit note was sent to {email} and issued.",
"send_success_default": "The invoice was sent to {email}",
"partial_success": "{message}. A follow-up step failed. Check the invoice and the bookkeeping.",
"mark_success_title": "Invoice marked as sent",
"mark_book_success_title": "Sent and posted",
"credit_mark_success_title": "Credit note issued",
"credit_mark_book_success_title": "Credit note sent and posted",
"credit_repair_success_title": "Bookkeeping completed",
"credit_mark_success_voucher_created": "The credit note was marked as sent and the verifikat was created.",
"credit_mark_success_no_voucher": "The credit note was marked as sent. The cash method requires no verifikat for an unpaid original invoice.",
"mark_success_voucher_created": "The bookkeeping verifikat has been created.",
"mark_partial_success": "The invoice was marked as sent, but a follow-up step failed. Check the invoice and the bookkeeping.",
"try_again": "Try again."
},
"invoice_payment_dialog": {
@@ -3060,6 +3110,14 @@
"due_date_label": "Due date",
"payment_reference_label": "OCR / Payment reference",
"payment_reference_placeholder": "OCR-nummer",
"document_label": "Invoice document",
"document_help": "Attach the supplier's PDF or an image. The document is stored with the invoice and automatically attached to the verifikation.",
"document_upload_in_progress_title": "The document is still uploading",
"document_upload_in_progress_description": "Wait for the upload to finish before registering the invoice.",
"document_upload_failed_title": "The document could not be uploaded",
"document_upload_failed_description": "Remove the file and try uploading it again.",
"document_link_warning_title": "The invoice was registered, but the document is missing from the verifikation",
"document_link_warning_description": "Open the verifikation and attach the document there.",
"add_row": "Add row",
"currency_label": "Currency",
"exchange_rate_label": "Exchange rate",
@@ -3267,6 +3325,9 @@
"registration_voucher": "Registration verifikat",
"no_registration_voucher": "No registration verifikat (cash method)",
"payment_voucher": "Payment verifikat",
"document_title": "Invoice document",
"document_attached": "The supplier invoice is attached and archived.",
"view_document": "View document",
"notes_title": "Notes",
"pay_dialog_title": "Mark as paid",
"tab_new_payment": "New payment",
@@ -3474,11 +3535,27 @@
"corrupt_replace_cta": "Upload new version",
"integrity_unknown": "File integrity could not be verified: try again later if the preview does not appear."
},
"document_upload": {
"session_expired": "Your session has expired. Reload the page and sign in again.",
"server_status": "The server responded with {status}.",
"failed_status": "Upload failed ({status})",
"network_error": "Upload failed: network error",
"unsupported_type": "This file type is not supported",
"too_large": "The file is too large (max 10 MB)",
"compact_prompt": "Drag and drop or click",
"prompt": "Drag and drop files here",
"format_hint": "PDF or image (max 10 MB)",
"uploaded": "Uploaded",
"error": "Error",
"remove_file": "Remove file",
"uploading": "Uploading..."
},
"journal_attachments": {
"loading": "Loading documents...",
"title": "Documents",
"add": "Add document",
"empty": "No documents attached.",
"via_supplier_invoice": "Via supplier invoice",
"download": "Download",
"remove": "Remove",
"replace": "Replace with new version",
@@ -3924,7 +4001,7 @@
"ext_enable_banking_long_description": "Connect your bank account directly and sync transactions automatically via secure PSD2 bank integration. Supports most Swedish banks.",
"ext_email_name": "Email (Resend)",
"ext_email_description": "Send invoices and reminders via email",
"ext_email_long_description": "Enables email features: send invoices to customers, automatic payment reminders (15/30/45 days), and email notifications. Requires a Resend account with a verified domain.",
"ext_email_long_description": "Enables email features: send invoices to customers, automatic payment reminders on your chosen schedule, and email notifications. Requires a Resend account with a verified domain.",
"ext_arcim_migration_name": "System migration",
"ext_arcim_migration_description": "Migrate bookkeeping from Fortnox, Visma, Bokio, Björn Lundén or Briox",
"ext_arcim_migration_long_description": "Move all bookkeeping data from your old system to accounted. Imports chart of accounts, vouchers, customers, suppliers and open invoices automatically via a secure API integration directly with the provider.",
@@ -4217,6 +4294,7 @@
"back": "Back to articles",
"edit": "Edit",
"deactivate": "Deactivate",
"delete": "Delete",
"edit_dialog_title": "Edit article",
"viewer_disabled_tooltip": "You only have viewer access in this company",
"type_vara": "Goods",
@@ -4247,6 +4325,11 @@
"deactivate_confirm_label": "Deactivate",
"deactivated_title": "Article deactivated",
"deactivate_failed_title": "Could not deactivate article",
"delete_confirm_title": "Delete {name}",
"delete_confirm_description": "The article and its article number are permanently deleted. This is only possible if the article has never been used on an invoice.",
"delete_confirm_label": "Delete",
"deleted_title": "Article deleted",
"delete_failed_title": "Could not delete article",
"activate_and_save": "Activate and save"
},
"form_article": {