fix(salary): surface missing sender bankgiro/IBAN before betalfil download (#1640)

* fix(salary): surface missing sender bankgiro/IBAN before betalfil download

Users see a bankgiro under BANKUPPGIFTER in settings (Bolagsverket
snapshot, display only) while the payment-file routes read
company_settings.bankgiro, so the LB download failed with an error
that pointed at a page that looked correct. 153 companies have a
registry bankgiro but an empty settings field.

- PaymentFilePanel warns up front when the sender bankgiro (bg_lb)
  or IBAN (pain001) is missing, linking to Installningar -> Fakturering
- betalkonton form offers a one-click prefill of the bankgiro from
  companies.tic_snapshot (Luhn-validated, user still saves)
- bg-lb and skattekonto payment-file error copy now names the exact
  place to fix instead of 'foretagsinstallningar'

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(salary): harden bankgiro prefill and warning per skeptic review

- bankgiroFromTicSnapshot now requires the snapshot's orgNumber to match
  companies.org_number before suggesting anything: stale fuzzy-matched
  snapshots can hold another entity's profile, and this field becomes the
  payee account on invoices and Peppol e-invoices
- salary run page refetches settings when the URL returns from the
  intercepting settings modal, so a bankgiro/IBAN saved there clears the
  missing-sender warning instead of leaving it stale

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Mattsson
2026-08-17 11:15:37 +02:00
committed by GitHub
co-authored by Claude Fable 5
parent 25524e1df4
commit 1bb423b2b3
11 changed files with 310 additions and 16 deletions
@@ -72,6 +72,26 @@ describe('GET /api/salary/runs/[id]/payment/bg-lb', () => {
expect(response.status).toBe(403)
})
it('returns 400 pointing at the invoicing settings when bankgiro is empty', async () => {
const { enqueueMany } = authed()
enqueueMany([
{ data: { id: 'run-1', status: 'approved', period_year: 2026, period_month: 3, payment_date: '2026-03-25' } },
{ data: { name: 'Bolaget AB' } }, // companies
{ data: { company_name: 'Bolaget AB', bankgiro: null } }, // company_settings
])
const response = await GET(
createMockRequest('/api/salary/runs/run-1/payment/bg-lb'),
createMockRouteParams({ id: 'run-1' }),
)
expect(response.status).toBe(400)
const body = await response.json()
// The message must name where the setting lives: the settings overview
// shows a registry bankgiro this route does not read.
expect(body.error).toContain('Inställningar → Fakturering')
})
it('generates a Bankgirot LB file for an approved run', async () => {
const { enqueueMany } = authed()
enqueueMany([
@@ -58,7 +58,9 @@ export const GET = withRouteContext<{ params: Promise<{ id: string }> }>(
if (!settings?.bankgiro) {
return NextResponse.json(
{ error: 'Bankgironummer saknas i företagsinställningar. Krävs för Bankgirot LB-fil.' },
// The settings overview shows a bankgiro from the Bolagsverket snapshot,
// which is display data only; point at the field this route reads.
{ error: 'Företagets bankgironummer är inte ifyllt. Fyll i det under Inställningar → Fakturering för att skapa Bankgirot LB-fil.' },
{ status: 400 }
)
}
@@ -91,7 +91,9 @@ export const GET = withRouteContext<{ params: Promise<{ period: string }> }>(
if (!settings?.bankgiro) {
return NextResponse.json(
{ error: 'Bankgironummer saknas i företagsinställningar.' },
// Same wording as the salary LB route: the settings overview shows a
// registry bankgiro that this route does not read.
{ error: 'Företagets bankgironummer är inte ifyllt. Fyll i det under Inställningar → Fakturering för att skapa betalfilen.' },
{ status: 400 }
)
}