fix(invoices): make self-billed invoices creditable and their dates visible (#1827)
A self-billed invoice has invoice_number null by design (the counterparty's number lives in external_invoice_number), which broke the whole credit flow: the confirm input was disabled and compared against null, the API minted the literal number 'KR-null', and the credit-note PDF dropped its ML 17 kap 22 reference to the original. The editor also hid fakturadatum inside the collapsed Forval panel, so self-billed invoices silently registered with today's date and, being immutable, could not be corrected. - creditConfirmNumber() falls back to external_invoice_number; the credit page uses it for reason default, subtitle, original row, preview, confirm label/placeholder/disabled, mismatch check and submit gate - createCreditNote numbers 'KR-<external>' for self-billed originals and refuses with typed 400 INVOICE_CREDIT_NO_NUMBER when no number exists - mark-sent and send select external_invoice_number and fall back for the credit-note PDF's reference to the original - the Forval chip line now shows the invoice date in every mode, and self-billed mode renders fakturadatum + mottagningsdatum uncollapsed as transcription fields next to the external number Fixes #1820 Claude-Session: https://claude.ai/code/session_01SyDuePXxUFowaPBKpAv8SF Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Jakob Wennberg
Claude Fable 5
parent
21c63b8b12
commit
78525bd391
@@ -173,13 +173,30 @@ function chipsInput(overrides: Partial<ForvalChipsInput> = {}): ForvalChipsInput
|
||||
}
|
||||
|
||||
describe('deriveForvalChips', () => {
|
||||
it('shows only currency and due terms for an all-default invoice', () => {
|
||||
it('shows currency, invoice date and due terms for an all-default invoice', () => {
|
||||
expect(deriveForvalChips(chipsInput())).toEqual([
|
||||
{ kind: 'currency', currency: 'SEK' },
|
||||
{ kind: 'invoice_date', date: '2026-08-17' },
|
||||
{ kind: 'due_days', days: 30, date: '2026-09-16' },
|
||||
])
|
||||
})
|
||||
|
||||
// Issue #1820: the invoice date silently defaulted to today inside the
|
||||
// collapsed Förval panel; the chip makes the value visible in every mode.
|
||||
it('surfaces the invoice date as a chip, and skips it while unset', () => {
|
||||
expect(deriveForvalChips(chipsInput())).toContainEqual({
|
||||
kind: 'invoice_date',
|
||||
date: '2026-08-17',
|
||||
})
|
||||
expect(deriveForvalChips(chipsInput({ isSelfBilled: true }))).toContainEqual({
|
||||
kind: 'invoice_date',
|
||||
date: '2026-08-17',
|
||||
})
|
||||
expect(
|
||||
deriveForvalChips(chipsInput({ invoiceDate: '' })).find((c) => c.kind === 'invoice_date'),
|
||||
).toBeUndefined()
|
||||
})
|
||||
|
||||
it('surfaces a deviating document type first', () => {
|
||||
expect(deriveForvalChips(chipsInput({ documentType: 'proforma' }))[0]).toEqual({
|
||||
kind: 'doc_type',
|
||||
@@ -225,7 +242,7 @@ describe('deriveForvalChips', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('reduces to currency, due and received for self-billed mode', () => {
|
||||
it('reduces to currency, invoice date, due and received for self-billed mode', () => {
|
||||
const chips = deriveForvalChips(
|
||||
chipsInput({
|
||||
isSelfBilled: true,
|
||||
@@ -239,6 +256,7 @@ describe('deriveForvalChips', () => {
|
||||
)
|
||||
expect(chips).toEqual([
|
||||
{ kind: 'currency', currency: 'SEK' },
|
||||
{ kind: 'invoice_date', date: '2026-08-17' },
|
||||
{ kind: 'due_days', days: 30, date: '2026-09-16' },
|
||||
{ kind: 'received', date: '2026-08-15' },
|
||||
])
|
||||
|
||||
Reference in New Issue
Block a user