Two user reports (Anders, 2026-08-25 + 2026-08-29): 1. The seeded standardmallar "Inkop EU-varor/-tjanster, omvand moms 25%" booked the cost on 4010/6540, which no momsdeklaration ruta reads, so the fiktiv moms filled ruta 30/48 while ruta 20/21 (inkopsvarde) stayed 0; Skatteverket rejects that (FK004, ML 13 kap). The packs now book directly on the basis accounts 4515/4535 (ACCOUNT_RUTA -> ruta 20/21); the transaction-picker path already skips its own basis emission for basis debit accounts, so no double counting. Regression test pins every reverse-charge pack to a 44xx/45xx business debit. Prod rows update via the existing pack sync cron (upsert on pack_slug). 2. A kontantmetod payment verifikat stayed "Underlag saknas" although the invoice PDF was attached and eligible on every static condition: the inline anchorSupplierInvoiceDocument silently did nothing (prod case 2026-08-28, verified in audit_log: no document_attachments update between the payment booking and the user's manual re-upload). The helper now verifies the guarded update actually matched a row instead of claiming success on zero rows, logs its silent bail branches, and a new daily cron (/api/documents/reanchor/cron) re-runs the anchor for any floating retained document with a posted verifikat, replacing the pattern of one-off repair migrations (20260727180000, 20260824150000). The sweep names the FK in its embed and is idempotent; locked/closed periods are skipped as before. Claude-Session: https://claude.ai/code/session_01Jj6Rg1ViyFRej55gbxLVgj Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
41 lines
1.8 KiB
TypeScript
41 lines
1.8 KiB
TypeScript
import { NextResponse } from 'next/server'
|
|
import { withCronContext } from '@/lib/api/with-cron-context'
|
|
import { createServiceRoleClient } from '@/lib/supabase/service-client'
|
|
import { sweepFloatingSupplierInvoiceDocuments } from '@/lib/core/documents/supplier-invoice-underlag'
|
|
import { errorResponseFromCode } from '@/lib/errors/get-structured-error'
|
|
|
|
/**
|
|
* GET /api/documents/reanchor/cron: daily 03:30 UTC (schedule in vercel.json).
|
|
*
|
|
* Re-anchors supplier-invoice retained documents that are floating although
|
|
* the invoice has a posted verifikat. The inline anchoring in the payment
|
|
* routes is best-effort (the booking is already committed when it runs), so a
|
|
* transient failure there leaves the verifikat flagged "Underlag saknas" with
|
|
* the PDF plainly attached to the invoice, and until now only a hand-written
|
|
* repair migration ever retried. Prod case 2026-08-28: kontantmetod payment
|
|
* verifikat posted, document eligible, anchor silently did nothing.
|
|
*
|
|
* Idempotent: an anchored document is never moved, locked/closed periods are
|
|
* skipped, and a clean run touches nothing.
|
|
*/
|
|
|
|
export const maxDuration = 120
|
|
|
|
export const GET = withCronContext('cron.documents_reanchor', async (_request, ctx) => {
|
|
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL
|
|
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY
|
|
|
|
if (!supabaseUrl || !supabaseServiceKey) {
|
|
return errorResponseFromCode('INTERNAL_ERROR', ctx.log, {
|
|
requestId: ctx.requestId,
|
|
details: { reason: 'Missing Supabase configuration' },
|
|
})
|
|
}
|
|
|
|
const supabase = createServiceRoleClient(supabaseUrl, supabaseServiceKey)
|
|
const result = await sweepFloatingSupplierInvoiceDocuments(supabase)
|
|
|
|
ctx.log.info('reanchor sweep finished', { ...result })
|
|
return NextResponse.json({ data: result })
|
|
})
|