'use client' import { Badge } from '@/components/ui/badge' import { Separator } from '@/components/ui/separator' import { AccountNumber } from '@/components/ui/account-number' import { formatCurrency } from '@/lib/utils' import type { Supplier } from '@/types' interface ReviewLineItem { description: string amount: number account_number: string vat_rate: number } interface SupplierInvoiceReviewContentProps { supplier: Supplier invoiceNumber: string invoiceDate: string dueDate: string deliveryDate?: string currency: string exchangeRate?: string reverseCharge: boolean paymentReference?: string items: ReviewLineItem[] subtotal: number totalVat: number total: number } function formatAmount(amount: number): string { return amount.toLocaleString('sv-SE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) } interface JournalPreviewLine { account_number: string description: string debit: number credit: number } function getOutputVatAccount(rate: number): string { if (rate === 0.12) return '2624' if (rate === 0.06) return '2634' return '2614' } function buildJournalPreview( items: ReviewLineItem[], subtotal: number, totalVat: number, total: number, reverseCharge: boolean, supplierType?: string, ): JournalPreviewLine[] { const lines: JournalPreviewLine[] = [] // Aggregate expense amounts by account number const expenseByAccount = new Map() for (const item of items) { const current = expenseByAccount.get(item.account_number) || 0 expenseByAccount.set(item.account_number, current + Math.round(item.amount * 100) / 100) } // Debit: Expense accounts for (const [accountNumber, amount] of expenseByAccount) { lines.push({ account_number: accountNumber, description: accountNumber, debit: Math.round(amount * 100) / 100, credit: 0, }) } if (reverseCharge) { // Reverse charge: fiktiv moms per VAT rate (matches engine groupVatByRate logic) const isDomesticRC = supplierType === 'swedish_business' const inputAccount = isDomesticRC ? '2647' : '2645' const vatByRate = new Map() for (const item of items) { if (item.vat_rate > 0) { const current = vatByRate.get(item.vat_rate) || 0 vatByRate.set(item.vat_rate, current + Math.round(item.amount * 100) / 100) } } for (const [rate, netAmount] of vatByRate) { const fiktivVat = Math.round(netAmount * rate * 100) / 100 const outputAccount = getOutputVatAccount(rate) lines.push({ account_number: inputAccount, description: inputAccount, debit: fiktivVat, credit: 0, }) lines.push({ account_number: outputAccount, description: outputAccount, debit: 0, credit: fiktivVat, }) } // Credit: 2440 at subtotal (no real VAT for reverse charge) lines.push({ account_number: '2440', description: 'Leverantörsskulder', debit: 0, credit: Math.round(subtotal * 100) / 100, }) } else { if (totalVat > 0) { lines.push({ account_number: '2641', description: 'Ingående moms', debit: Math.round(totalVat * 100) / 100, credit: 0, }) } // Credit: 2440 at total incl. VAT lines.push({ account_number: '2440', description: 'Leverantörsskulder', debit: 0, credit: Math.round(total * 100) / 100, }) } return lines } const ACCOUNT_LABELS: Record = { '2440': 'Leverantörsskulder', '2641': 'Ingående moms', '2645': 'Beräknad ing. moms förvärv utlandet', '2647': 'Beräknad ing. moms omvänd i Sverige', '2614': 'Utg. moms omvänd 25%', '2624': 'Utg. moms omvänd 12%', '2634': 'Utg. moms omvänd 6%', } export function SupplierInvoiceReviewContent({ supplier, invoiceNumber, invoiceDate, dueDate, deliveryDate, currency, exchangeRate, reverseCharge, paymentReference, items, subtotal, totalVat, total, }: SupplierInvoiceReviewContentProps) { const journalLines = buildJournalPreview(items, subtotal, totalVat, total, reverseCharge, supplier.supplier_type) const totalDebit = journalLines.reduce((sum, l) => sum + l.debit, 0) const totalCredit = journalLines.reduce((sum, l) => sum + l.credit, 0) return (
{/* Supplier info */}

{supplier.name}

Fakturanr: {invoiceNumber}

{reverseCharge && ( Omvänd skattskyldighet )} {currency !== 'SEK' && ( {currency} {exchangeRate && ` (kurs ${exchangeRate})`} )}
{/* Dates */}
Fakturadatum

{invoiceDate}

Förfallodatum

{dueDate}

{deliveryDate && (
Leveransdatum

{deliveryDate}

)}
{/* Line items — table on desktop, cards on mobile */}
{items.map((item, index) => { const vatAmount = Math.round(item.amount * item.vat_rate * 100) / 100 return ( ) })}
Konto Beskrivning Belopp Moms% Moms
{item.description} {formatAmount(item.amount)} {Math.round(item.vat_rate * 100)}% {formatAmount(vatAmount)}
{items.map((item, index) => { const vatAmount = Math.round(item.amount * item.vat_rate * 100) / 100 return (

{item.description}

{formatAmount(item.amount)} kr {Math.round(item.vat_rate * 100)}% moms ({formatAmount(vatAmount)})
) })}
{/* Totals */}
Netto (exkl. moms) {formatCurrency(subtotal, currency)}
Moms {formatCurrency(totalVat, currency)}
Totalt {formatCurrency(total, currency)}
{currency !== 'SEK' && exchangeRate && (
SEK-belopp (vid kurs {exchangeRate}) {formatCurrency(total * parseFloat(exchangeRate))}
)}
{/* Verifikation preview */}

Verifikation som bokförs

{journalLines.map((line, index) => ( ))}
Konto Beskrivning Debet Kredit
{ACCOUNT_LABELS[line.account_number] || line.description} {line.debit > 0 ? formatAmount(line.debit) : ''} {line.credit > 0 ? formatAmount(line.credit) : ''}
SUMMA {formatAmount(totalDebit)} {formatAmount(totalCredit)}
{journalLines.map((line, index) => (
{ACCOUNT_LABELS[line.account_number] || line.description}
{line.debit > 0 ? `D ${formatAmount(line.debit)}` : `K ${formatAmount(line.credit)}`}
))}
SUMMA D {formatAmount(totalDebit)} / K {formatAmount(totalCredit)}
{/* Payment reference */} {paymentReference && (

Betalningsreferens: {paymentReference}

)}
) }