fix(salary): make pain.001 betalfil generatable (company IBAN + BIC) (#950)

The ISO 20022 pain.001 salary payment file could never be generated: the
route required company_settings.iban/bic, but no settings screen wrote
those columns, so every request returned 400. The specific reason was
also swallowed by getErrorMessage (isSwedishUserMessage did not know
"krävs"/"saknar"), surfacing only the generic "Förfrågan innehåller
ogiltiga uppgifter" (issue #945).

- Add IBAN + BIC inputs to Settings > Fakturering > Bankuppgifter. BIC
  auto-derives from the clearing number / bank already entered, so in
  practice only the IBAN is typed. Validated client- and server-side.
- Route requires the company IBAN (canonical debtor form every Swedish
  bank accepts) and derives the BIC, with clear actionable errors.
- Employees are unchanged: domestic clearing + account (BBAN), which is
  what Swedish payroll collects. Only the company (debtor) uses IBAN.
- getErrorMessage recognizes "krävs"/"saknar" so payment-file reasons
  surface instead of the generic 400.

Fixes #945

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-07-09 12:35:52 +02:00
committed by GitHub
co-authored by Claude Opus 4.8
parent bacc5914af
commit c1ea0d9bf2
12 changed files with 236 additions and 24 deletions
+9 -1
View File
@@ -40,10 +40,18 @@ describe('generatePain001', () => {
const xml = generatePain001(company, employees, options)
expect(xml).toContain('<Nm>Test AB</Nm>')
expect(xml).toContain('SE1234567890123456789012')
expect(xml).toContain('ESSESESS')
})
it('identifies the debtor (company) by its own IBAN', () => {
const xml = generatePain001(company, employees, options)
// The payer is the company's IBAN, inside DbtrAcct.
expect(xml).toContain('<IBAN>SE1234567890123456789012</IBAN>')
// Employees are still domestic BBAN (clearing+account), never IBAN.
expect(xml).toContain('<Othr><Id>56781234567890</Id></Othr>')
})
it('includes SALA category purpose for salary', () => {
const xml = generatePain001(company, employees, options)
expect(xml).toContain('<Cd>SALA</Cd>')