diff --git a/components/salary/AGIPanel.tsx b/components/salary/AGIPanel.tsx index 68e29914..a3c90f04 100644 --- a/components/salary/AGIPanel.tsx +++ b/components/salary/AGIPanel.tsx @@ -338,9 +338,12 @@ export function AGIPanel(props: AGIPanelProps) { * status flips out of PROCESSING. Skatteverket's spec says polling is * usually instantaneous, but we cap at 8 attempts × 1s to be safe. * - * On DONE_SUCCESS we automatically call /agi/spara to commit into Eget - * utrymme, mirroring the user's intent ("send AGI") and matching what the - * old draft-then-lock UX promised. + * On DONE_SUCCESS the underlag is auto-persisted by SKV — no /spara call. + * Calling /spara when there are no errors returns 400 felkod 20 + * ("Inlämningen är redan sparad/borttagen eller innehöll inga felaktiga + * underlag") because /spara is specifically for re-persisting rejected + * underlag so the user can fix them later in Mina Sidor. Successful + * underlag move straight to the granskningsunderlag step. * * On DONE_REJECTED we surface the validation findings; the user can still * choose to save (so they can fix it in Mina Sidor) or abort. @@ -391,20 +394,10 @@ export function AGIPanel(props: AGIPanelProps) { setKontroller(findings) if (kr.status === 'DONE_SUCCESS') { - const sparaRes = await fetch('/api/extensions/ext/skatteverket/agi/spara', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - // Include salaryRunId so the handler can promote the matching - // agi_declarations row to status='pending_signature' without - // doing a fallback lookup against locally-cached submission state. - body: JSON.stringify({ inlamningId, salaryRunId }), - }) - const sparaJson = await sparaRes.json() - if (!sparaRes.ok || sparaJson.error) { - setError(sparaJson.error || `Kunde inte spara underlag (${sparaRes.status})`) - return - } - setSuccess('Underlag accepterat och sparat hos Skatteverket. Skapa granskningsunderlag för att fortsätta till BankID-signering.') + setSuccess( + 'Underlag accepterat hos Skatteverket. Klicka "Skapa signeringslänk" ' + + 'för att gå vidare till BankID-signering i Mina Sidor.', + ) } else if (kr.status === 'DONE_REJECTED') { setError(`Underlaget innehåller ${findings.filter(f => f.status === 'STOPP').length} stoppande fel. Åtgärda och skicka igen.`) } else { diff --git a/extensions/general/skatteverket/index.ts b/extensions/general/skatteverket/index.ts index 7f29a34f..f22f67ba 100644 --- a/extensions/general/skatteverket/index.ts +++ b/extensions/general/skatteverket/index.ts @@ -1099,6 +1099,25 @@ export const skatteverketExtension: Extension = { }), ) + // Flip the matching agi_declarations row to pending_signature when + // SKV returns a usable granskningsunderlag. Previously this happened + // in /agi/spara, but /spara is only valid for re-saving rejected + // underlag — successful underlag are auto-persisted by SKV, so + // /spara returns felkod 20 on the happy path. Doing the flip here + // ensures the audit trail still moves through pending_signature + // → submitted (BFNAR 2013:2 kap 8 / BFL 5 kap 6§) without /spara. + if (canSign) { + const periodYear = parseInt(period.slice(0, 4)) + const periodMonth = parseInt(period.slice(4, 6)) + await ctx.supabase + .from('agi_declarations') + .update({ status: 'pending_signature' }) + .eq('company_id', ctx.companyId) + .eq('period_year', periodYear) + .eq('period_month', periodMonth) + .in('status', ['generated', 'rejected']) + } + return NextResponse.json({ data: result.data }) } catch (err) { return handleSkvError(err) diff --git a/lib/invoices/pdf-template.tsx b/lib/invoices/pdf-template.tsx index b7815f3a..1fc93559 100644 --- a/lib/invoices/pdf-template.tsx +++ b/lib/invoices/pdf-template.tsx @@ -28,7 +28,7 @@ const styles = StyleSheet.create({ color: '#1a1a1a', }, companyInfo: { - textAlign: 'right', + textAlign: 'left', }, companyName: { fontSize: 14, @@ -373,15 +373,9 @@ export function InvoicePDF({ invoice, customer, items, company, originalInvoiceN {/* Header */} - - - {getDocumentTitle(invoice)} - - {invoice.invoice_number ?? 'FÖRHANDSGRANSKNING'} - {company.logo_url && ( - + )} {company.trade_name || company.company_name} {company.trade_name && company.company_name && ( @@ -396,6 +390,12 @@ export function InvoicePDF({ invoice, customer, items, company, originalInvoiceN )} {company.vat_number && VAT: {company.vat_number}} + + + {getDocumentTitle(invoice)} + + {invoice.invoice_number ?? 'FÖRHANDSGRANSKNING'} + {/* Credit note reference */}