From bb336eba88bfac3c6eccf3dd5c4ef268706f43c8 Mon Sep 17 00:00:00 2001 From: Mattsson <111893710+mattssonn@users.noreply.github.com> Date: Thu, 9 Apr 2026 16:22:51 +0200 Subject: [PATCH] Fix/user feedback (#210) * Add delete policies for provider consent tokens and provider OTC * Add trade name support for companies in settings and documents * Resolved currency selection issue * Enhance invoice line display with foreign currency support and update delivery date schema to allow empty values * Add currency display for journal entries and include currency metadata in transaction creation * Add trade_name column to company_settings for external display --- app/(dashboard)/bookkeeping/[id]/page.tsx | 100 ++++++++++------ app/(dashboard)/settings/company/page.tsx | 1 + app/(dashboard)/transactions/page.tsx | 40 ++++++- app/api/invoices/[id]/send/route.ts | 2 +- app/api/invoices/route.ts | 1 + app/api/mcp-oauth/authorize/route.ts | 4 +- .../pending-operations/[id]/commit/route.ts | 2 +- .../transactions/[id]/__tests__/route.test.ts | 112 ++++++++++++++++++ app/api/transactions/[id]/route.ts | 62 ++++++++++ components/bookkeeping/JournalEntryForm.tsx | 6 + components/bookkeeping/JournalEntryList.tsx | 17 ++- components/settings/CompanyInfoForm.tsx | 12 ++ .../transactions/TransactionBookingDialog.tsx | 42 +++++-- .../transactions/TransactionInboxCard.tsx | 21 +++- .../general/email/lib/invoice-templates.ts | 13 +- .../general/email/lib/reminder-templates.ts | 7 +- lib/api/schemas.ts | 9 +- lib/bookkeeping/transaction-entries.ts | 2 + lib/email/invoice-templates.ts | 13 +- lib/email/reminder-templates.ts | 7 +- lib/invoices/pdf-template.tsx | 8 +- lib/invoices/reminder-processor.ts | 2 +- lib/reports/full-archive-export.ts | 3 +- lib/reports/ink2/ink2-engine.ts | 4 +- lib/reports/ne-bilaga/ne-engine.ts | 4 +- lib/reports/sie-export.ts | 2 +- lib/utils.ts | 21 ++++ .../20260402010000_provider_consents.sql | 14 +++ .../20260409130001_add_trade_name.sql | 5 + tests/helpers.ts | 1 + types/index.ts | 2 + 31 files changed, 452 insertions(+), 87 deletions(-) create mode 100644 app/api/transactions/[id]/__tests__/route.test.ts create mode 100644 app/api/transactions/[id]/route.ts create mode 100644 supabase/migrations/20260409130001_add_trade_name.sql diff --git a/app/(dashboard)/bookkeeping/[id]/page.tsx b/app/(dashboard)/bookkeeping/[id]/page.tsx index 3118a87f..bdaa9a16 100644 --- a/app/(dashboard)/bookkeeping/[id]/page.tsx +++ b/app/(dashboard)/bookkeeping/[id]/page.tsx @@ -211,22 +211,39 @@ export default function JournalEntryDetailPage({ params }: { params: Promise<{ i
- {lines.map((line) => ( -{line.line_description}
- )} + {lines.map((line) => { + const hasForeignCurrency = line.currency && line.currency !== 'SEK' && line.amount_in_currency != null + return ( +{line.line_description}
+ )} ++ {Number(line.debit_amount).toLocaleString('sv-SE', { minimumFractionDigits: 2 })} D + {hasForeignCurrency && ( + + {Number(line.amount_in_currency).toLocaleString('sv-SE', { minimumFractionDigits: 2 })} {line.currency} + + )} +
+ )} + {Number(line.credit_amount) > 0 && ( ++ {Number(line.credit_amount).toLocaleString('sv-SE', { minimumFractionDigits: 2 })} K + {hasForeignCurrency && ( + + {Number(line.amount_in_currency).toLocaleString('sv-SE', { minimumFractionDigits: 2 })} {line.currency} + + )} +
+ )} +{Number(line.debit_amount).toLocaleString('sv-SE', { minimumFractionDigits: 2 })} D
- )} - {Number(line.credit_amount) > 0 && ( -{Number(line.credit_amount).toLocaleString('sv-SE', { minimumFractionDigits: 2 })} K
- )} -Kan inte ändras efter att kontot skapats
)}+ Valfritt. Visas som huvudnamn på fakturor och e-post, med det juridiska namnet i parentes. +
+${documentType}nummer: ${invoice.invoice_number} @@ -136,7 +136,8 @@ export function generateInvoiceEmailHtml(data: InvoiceEmailData): string {
Med vänliga hälsningar,
- ${company.company_name}
+ ${getCompanyPrimaryName(company)}
+ ${company.trade_name && company.company_name ? `
(${company.company_name})` : ''}
@@ -165,7 +166,7 @@ export function generateInvoiceEmailText(data: InvoiceEmailData): string { const isProforma = docType === 'proforma' const hidePayment = isCreditNote || isDeliveryNote || isProforma - let text = `${documentType} från ${company.company_name}\n` + let text = `${documentType} från ${getCompanyPrimaryName(company)}\n` text += `${documentType}nummer: ${invoice.invoice_number}\n\n` text += `Hej${customer.name ? ` ${customer.name.split(' ')[0]}` : ''},\n\n` @@ -197,7 +198,7 @@ export function generateInvoiceEmailText(data: InvoiceEmailData): string { text += `Har du frågor om fakturan? Svara direkt på detta mejl så hjälper vi dig.\n\n` text += `Med vänliga hälsningar,\n` - text += `${company.company_name}\n` + text += `${getCompanyDisplayName(company)}\n` if (company.org_number) { text += `\nOrg.nr: ${company.org_number}` @@ -216,5 +217,5 @@ export function generateInvoiceEmailSubject(data: InvoiceEmailData): string { const { invoice, company } = data const documentType = getDocumentLabel(invoice) - return `${documentType} ${invoice.invoice_number} från ${company.company_name}` + return `${documentType} ${invoice.invoice_number} från ${getCompanyPrimaryName(company)}` } diff --git a/extensions/general/email/lib/reminder-templates.ts b/extensions/general/email/lib/reminder-templates.ts index 8ee3a8ef..5d5cc6e3 100644 --- a/extensions/general/email/lib/reminder-templates.ts +++ b/extensions/general/email/lib/reminder-templates.ts @@ -1,5 +1,5 @@ import type { Invoice, Customer, CompanySettings } from '@/types' -import { formatCurrency, formatDate } from '@/lib/utils' +import { formatCurrency, formatDate, getCompanyDisplayName, getCompanyPrimaryName } from '@/lib/utils' export interface ReminderEmailData { invoice: Invoice @@ -179,7 +179,8 @@ export function generateReminderEmailHtml(data: ReminderEmailData): string {
Med vänliga hälsningar,
- ${company.company_name}
+ ${getCompanyPrimaryName(company)}
+ ${company.trade_name && company.company_name ? `
(${company.company_name})` : ''}
@@ -247,7 +248,7 @@ export function generateReminderEmailText(data: ReminderEmailData): string { text += `Har du frågor? Svara direkt på detta mejl så hjälper vi dig.\n\n` text += `Med vänliga hälsningar,\n` - text += `${company.company_name}\n` + text += `${getCompanyDisplayName(company)}\n` if (company.org_number) { text += `\nOrg.nr: ${company.org_number}` diff --git a/lib/api/schemas.ts b/lib/api/schemas.ts index 5919d25a..af0ce6f2 100644 --- a/lib/api/schemas.ts +++ b/lib/api/schemas.ts @@ -153,11 +153,13 @@ export const CreateInvoiceItemSchema = z.object({ vat_rate: z.number().min(0).max(100).optional(), }) +const optionalIsoDate = isoDate.or(z.literal('')).transform(v => v || undefined).optional() + export const CreateInvoiceSchema = z.object({ customer_id: uuid, invoice_date: isoDate, due_date: isoDate, - delivery_date: isoDate.optional(), + delivery_date: optionalIsoDate, currency: CurrencySchema, document_type: InvoiceDocumentTypeSchema.optional(), your_reference: z.string().optional(), @@ -254,7 +256,7 @@ export const CreateSupplierInvoiceSchema = z.object({ supplier_invoice_number: z.string().min(1, 'Supplier invoice number is required'), invoice_date: isoDate, due_date: isoDate, - delivery_date: isoDate.optional(), + delivery_date: optionalIsoDate, currency: CurrencySchema.optional(), exchange_rate: z.number().positive().optional(), vat_treatment: VatTreatmentSchema.optional(), @@ -275,7 +277,7 @@ export const UpdateSupplierInvoiceSchema = z.object({ supplier_invoice_number: z.string().min(1).optional(), invoice_date: isoDate.optional(), due_date: isoDate.optional(), - delivery_date: isoDate.optional(), + delivery_date: optionalIsoDate, payment_reference: z.string().optional(), notes: z.string().optional(), }) @@ -349,6 +351,7 @@ export const MatchSupplierInvoiceSchema = z.object({ export const UpdateSettingsSchema = z.object({ entity_type: EntityTypeSchema.optional(), company_name: z.string().optional(), + trade_name: z.string().nullable().optional(), org_number: z.string().optional(), address_line1: z.string().optional(), address_line2: z.string().optional(), diff --git a/lib/bookkeeping/transaction-entries.ts b/lib/bookkeeping/transaction-entries.ts index 5abd3d27..b3fbc66c 100644 --- a/lib/bookkeeping/transaction-entries.ts +++ b/lib/bookkeeping/transaction-entries.ts @@ -196,6 +196,7 @@ export async function createTransactionJournalEntry( debit_amount: absAmount, credit_amount: 0, line_description: transaction.description, + ...(debitAccount === '1930' ? currencyMeta : {}), }) // Credit revenue for net amount lines.push({ @@ -221,6 +222,7 @@ export async function createTransactionJournalEntry( debit_amount: absAmount, credit_amount: 0, line_description: transaction.description, + ...(debitAccount === '1930' ? currencyMeta : {}), }, { account_number: creditAccount, diff --git a/lib/email/invoice-templates.ts b/lib/email/invoice-templates.ts index 1da8ab53..6915f2cb 100644 --- a/lib/email/invoice-templates.ts +++ b/lib/email/invoice-templates.ts @@ -1,5 +1,5 @@ import type { Invoice, Customer, CompanySettings, InvoiceDocumentType } from '@/types' -import { formatCurrency, formatDate } from '@/lib/utils' +import { formatCurrency, formatDate, getCompanyDisplayName, getCompanyPrimaryName } from '@/lib/utils' function getDocumentLabel(invoice: Invoice): string { if (invoice.credited_invoice_id) return 'Kreditfaktura' @@ -41,7 +41,7 @@ export function generateInvoiceEmailHtml(data: InvoiceEmailData): string {
${documentType}nummer: ${invoice.invoice_number} @@ -136,7 +136,8 @@ export function generateInvoiceEmailHtml(data: InvoiceEmailData): string {
Med vänliga hälsningar,
- ${company.company_name}
+ ${getCompanyPrimaryName(company)}
+ ${company.trade_name && company.company_name ? `
(${company.company_name})` : ''}
@@ -165,7 +166,7 @@ export function generateInvoiceEmailText(data: InvoiceEmailData): string { const isProforma = docType === 'proforma' const hidePayment = isCreditNote || isDeliveryNote || isProforma - let text = `${documentType} från ${company.company_name}\n` + let text = `${documentType} från ${getCompanyPrimaryName(company)}\n` text += `${documentType}nummer: ${invoice.invoice_number}\n\n` text += `Hej${customer.name ? ` ${customer.name.split(' ')[0]}` : ''},\n\n` @@ -197,7 +198,7 @@ export function generateInvoiceEmailText(data: InvoiceEmailData): string { text += `Har du frågor om fakturan? Svara direkt på detta mejl så hjälper vi dig.\n\n` text += `Med vänliga hälsningar,\n` - text += `${company.company_name}\n` + text += `${getCompanyDisplayName(company)}\n` if (company.org_number) { text += `\nOrg.nr: ${company.org_number}` @@ -216,5 +217,5 @@ export function generateInvoiceEmailSubject(data: InvoiceEmailData): string { const { invoice, company } = data const documentType = getDocumentLabel(invoice) - return `${documentType} ${invoice.invoice_number} från ${company.company_name}` + return `${documentType} ${invoice.invoice_number} från ${getCompanyPrimaryName(company)}` } diff --git a/lib/email/reminder-templates.ts b/lib/email/reminder-templates.ts index 8ee3a8ef..5d5cc6e3 100644 --- a/lib/email/reminder-templates.ts +++ b/lib/email/reminder-templates.ts @@ -1,5 +1,5 @@ import type { Invoice, Customer, CompanySettings } from '@/types' -import { formatCurrency, formatDate } from '@/lib/utils' +import { formatCurrency, formatDate, getCompanyDisplayName, getCompanyPrimaryName } from '@/lib/utils' export interface ReminderEmailData { invoice: Invoice @@ -179,7 +179,8 @@ export function generateReminderEmailHtml(data: ReminderEmailData): string {
Med vänliga hälsningar,
- ${company.company_name}
+ ${getCompanyPrimaryName(company)}
+ ${company.trade_name && company.company_name ? `
(${company.company_name})` : ''}
@@ -247,7 +248,7 @@ export function generateReminderEmailText(data: ReminderEmailData): string {
text += `Har du frågor? Svara direkt på detta mejl så hjälper vi dig.\n\n`
text += `Med vänliga hälsningar,\n`
- text += `${company.company_name}\n`
+ text += `${getCompanyDisplayName(company)}\n`
if (company.org_number) {
text += `\nOrg.nr: ${company.org_number}`
diff --git a/lib/invoices/pdf-template.tsx b/lib/invoices/pdf-template.tsx
index 2a6a6cb6..bdc68305 100644
--- a/lib/invoices/pdf-template.tsx
+++ b/lib/invoices/pdf-template.tsx
@@ -317,7 +317,10 @@ export function InvoicePDF({ invoice, customer, items, company, originalInvoiceN
{company.logo_url && (