diff --git a/app/(dashboard)/invoices/[id]/page.tsx b/app/(dashboard)/invoices/[id]/page.tsx index 17667003..e2c14ec5 100644 --- a/app/(dashboard)/invoices/[id]/page.tsx +++ b/app/(dashboard)/invoices/[id]/page.tsx @@ -512,10 +512,33 @@ export default function InvoiceDetailPage({ params }: { params: Promise<{ id: st Delsumma {formatCurrency(invoice.subtotal, invoice.currency)} -
- Momsbehandling: {getVatTreatmentLabel(vatRules.treatment)} + Momsbehandling: {getVatSummaryFromItems(watchItems).label}
{vatRules.reverseChargeText && (
@@ -664,10 +664,8 @@ export default function NewInvoicePage() {
vat_rate: item.vat_rate ?? (vatRules?.rate || 25),
}))}
subtotal={subtotal}
- vatRate={vatRules.rate}
vatAmount={vatAmount}
total={total}
- vatTreatment={vatRules.treatment}
yourReference={pendingData?.your_reference}
ourReference={pendingData?.our_reference}
notes={pendingData?.notes}
diff --git a/app/api/invoices/preview-pdf/route.ts b/app/api/invoices/preview-pdf/route.ts
index 0dd8b28a..8f7d77df 100644
--- a/app/api/invoices/preview-pdf/route.ts
+++ b/app/api/invoices/preview-pdf/route.ts
@@ -55,25 +55,33 @@ export async function POST(request: Request) {
const docType: InvoiceDocumentType = document_type || 'invoice'
const isDeliveryNote = docType === 'delivery_note'
- // Build items with line totals
- const invoiceItems: InvoiceItem[] = items.map((item: { description: string; quantity: number; unit: string; unit_price: number; vat_rate?: number }, index: number) => ({
- id: `preview-${index}`,
- invoice_id: 'preview',
- sort_order: index,
- description: item.description,
- quantity: item.quantity,
- unit: item.unit,
- unit_price: item.unit_price,
- line_total: Math.round(item.quantity * item.unit_price * 100) / 100,
- vat_rate: item.vat_rate ?? vatRules.rate,
- vat_amount: 0,
- created_at: new Date().toISOString(),
- }))
+ // Build items with line totals and per-item VAT
+ const invoiceItems: InvoiceItem[] = items.map((item: { description: string; quantity: number; unit: string; unit_price: number; vat_rate?: number }, index: number) => {
+ const lineTotal = Math.round(item.quantity * item.unit_price * 100) / 100
+ const rate = item.vat_rate ?? vatRules.rate
+ return {
+ id: `preview-${index}`,
+ invoice_id: 'preview',
+ sort_order: index,
+ description: item.description,
+ quantity: item.quantity,
+ unit: item.unit,
+ unit_price: item.unit_price,
+ line_total: lineTotal,
+ vat_rate: rate,
+ vat_amount: isDeliveryNote ? 0 : Math.round(lineTotal * (rate / 100) * 100) / 100,
+ created_at: new Date().toISOString(),
+ }
+ })
const subtotal = invoiceItems.reduce((sum, item) => sum + item.line_total, 0)
- const vatAmount = isDeliveryNote ? 0 : Math.round(subtotal * (vatRules.rate / 100) * 100) / 100
+ const vatAmount = isDeliveryNote ? 0 : invoiceItems.reduce((sum, item) => sum + item.vat_amount, 0)
const total = isDeliveryNote ? 0 : subtotal + vatAmount
+ // Derive vat_rate from items: single rate → that rate, mixed → null
+ const itemRates = new Set(invoiceItems.map((item) => item.vat_rate))
+ const effectiveVatRate = isDeliveryNote ? 0 : (itemRates.size === 1 ? itemRates.values().next().value! : null)
+
// Construct a temporary Invoice-like object
const previewInvoice = {
id: 'preview',
@@ -93,7 +101,7 @@ export async function POST(request: Request) {
total,
total_sek: null,
vat_treatment: vatRules.treatment,
- vat_rate: isDeliveryNote ? 0 : vatRules.rate,
+ vat_rate: effectiveVatRate,
moms_ruta: vatRules.momsRuta,
your_reference: your_reference || null,
our_reference: our_reference || null,
diff --git a/components/invoices/InvoiceReviewContent.tsx b/components/invoices/InvoiceReviewContent.tsx
index e25733f9..243f2b59 100644
--- a/components/invoices/InvoiceReviewContent.tsx
+++ b/components/invoices/InvoiceReviewContent.tsx
@@ -2,9 +2,9 @@
import { Badge } from '@/components/ui/badge'
import { Separator } from '@/components/ui/separator'
-import { getVatTreatmentLabel } from '@/lib/invoices/vat-rules'
+import { getVatSummaryFromItems } from '@/lib/invoices/vat-rules'
import { formatCurrency } from '@/lib/utils'
-import type { Customer, Currency, VatTreatment } from '@/types'
+import type { Customer, Currency } from '@/types'
interface ReviewItem {
description: string
@@ -21,10 +21,8 @@ interface InvoiceReviewContentProps {
currency: Currency
items: ReviewItem[]
subtotal: number
- vatRate: number
vatAmount: number
total: number
- vatTreatment: VatTreatment
yourReference?: string
ourReference?: string
notes?: string
@@ -37,10 +35,8 @@ export function InvoiceReviewContent({
currency,
items,
subtotal,
- vatRate,
vatAmount,
total,
- vatTreatment,
yourReference,
ourReference,
notes,
@@ -52,24 +48,20 @@ export function InvoiceReviewContent({
non_eu_business: 'Utanför EU',
}
- // Check if items have mixed VAT rates
- const hasPerLineVat = items.some((item) => item.vat_rate !== undefined)
- const uniqueRates = hasPerLineVat
- ? new Set(items.map((item) => item.vat_rate ?? vatRate))
- : new Set([vatRate])
- const showVatColumn = hasPerLineVat && uniqueRates.size > 1
+ // Derive VAT summary from items
+ const vatSummary = getVatSummaryFromItems(items)
// Calculate per-rate VAT breakdown
const vatByRate = new Map{item.unit}
{formatCurrency(item.unit_price, currency)}
{showVatColumn && (
- {item.vat_rate ?? vatRate}%
+ {item.vat_rate ?? 25}%
)}
{formatCurrency(item.quantity * item.unit_price, currency)}
@@ -136,21 +128,19 @@ export function InvoiceReviewContent({
Delsumma
{formatCurrency(subtotal, currency)}
- {vatByRate.size > 1 ? (
- // Per-rate breakdown
- Array.from(vatByRate.entries())
- .filter(([, vat]) => vat > 0)
- .sort(([a], [b]) => b - a)
- .map(([rate, vat]) => (
-