feat(worklist): the next Skatteverket payment with bankgiro, OCR and due date under Att göra on Hem (#2435)

Part (a) of #2187. A twelfth worklist category, skattekonto_payment_due:
the earliest upcoming skattekonto charge whose sum exceeds the last synced
saldo, computed once in lib/worklist (server-side twin of the /skattekonto
page's Nästa dragning math) and rendered as one Betala row on Hem with the
shortfall, bankgiro 5050-1055, the OCR reference and the due date.

The row appears only when money has to move: a saldo that covers the charge
yields nothing, and no upcoming charge yields nothing. Ignored rows take
part, since Skatteverket draws them regardless of our flag. Without a
balance snapshot the full charge is the amount. Without an org number the
row keeps its bankgiro and date and drops the OCR.

No table, route or migration: /api/worklist/counts picks the category up
through getWorklistCounts, and Hem passes the computed row into the same
options wave as the expense payouts.

Part (b), a betalfil for the skattekonto payment, stays a follow-up: the
existing payment-file route is AGI-scoped.


Claude-Session: https://claude.ai/code/session_0179bdetHyofL6ATfQxB5wP5

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-09-08 21:25:01 +02:00
committed by GitHub
co-authored by Jakob Wennberg Claude Fable 5.1
parent a7dcaac6ad
commit 20925f6c65
10 changed files with 353 additions and 9 deletions
+16 -1
View File
@@ -6,6 +6,7 @@ import { HemNotices } from '@/components/dashboard/HemNotices'
import {
getWorklistCounts,
listExpensePayoutsDue,
listSkattekontoPaymentDue,
listSuggestedMatches,
SUGGESTED_MATCH_SCAN_CAP,
} from '@/lib/worklist'
@@ -199,16 +200,29 @@ export async function HemPanesSection({
// Same pattern for people owed for utlägg: Hem renders one row per person
// and the worklist count is the list's length.
const expensePayoutsPromise = listExpensePayoutsDue(supabase, companyId)
const [worklist, suggestedMatches, expensePayouts, resumeItems, bankConnectionsRes, postedEntries] =
// And for the next uncovered skattekonto charge: Hem renders the Betala
// row with amount, bankgiro and OCR; the worklist count is 1 or 0 from it.
const skattekontoPaymentPromise = listSkattekontoPaymentDue(supabase, companyId)
const [
worklist,
suggestedMatches,
expensePayouts,
skattekontoPayment,
resumeItems,
bankConnectionsRes,
postedEntries,
] =
await Promise.all([
// Pending-work counts come from lib/worklist: the same source as the
// sidebar badges, so the numbers can never diverge.
getWorklistCounts(supabase, companyId, {
suggestedMatches: suggestedMatchesPromise,
expensePayoutsDue: expensePayoutsPromise,
skattekontoPaymentDue: skattekontoPaymentPromise,
}),
suggestedMatchesPromise,
expensePayoutsPromise,
skattekontoPaymentPromise,
// In-progress work for the Fortsätt pane: pure draft-state derivation.
listResumeItems(supabase, companyId, now),
supabase.from('bank_connections').select('id, status, consent_expires, bank_name, last_sie_sweep').eq('company_id', companyId).eq('status', 'active'),
@@ -242,6 +256,7 @@ export async function HemPanesSection({
worklist={worklist}
suggestedMatches={suggestedMatches.slice(0, 5)}
expensePayouts={expensePayouts}
skattekontoPayment={skattekontoPayment}
expiringBankConnections={expiringBankConnections}
emptyLedger={emptyLedger}
hasActiveBankConnection={hasActiveBankConnection}