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>
50 lines
1.9 KiB
TypeScript
50 lines
1.9 KiB
TypeScript
export const INVOICE_NUMBER_DRAFT_LABEL = '(Utkast)'
|
|
|
|
export function invoiceNumberDisplay(value: string | null | undefined): string {
|
|
return value ?? INVOICE_NUMBER_DRAFT_LABEL
|
|
}
|
|
|
|
/**
|
|
* The number to show for an invoice. Self-billing invoices we received carry
|
|
* the counterparty's number in `external_invoice_number` (our own
|
|
* `invoice_number` is null by design), so fall back to it before the draft
|
|
* label.
|
|
*/
|
|
export function invoiceDisplayNumber(invoice: {
|
|
invoice_number?: string | null
|
|
external_invoice_number?: string | null
|
|
}): string {
|
|
return invoice.invoice_number ?? invoice.external_invoice_number ?? INVOICE_NUMBER_DRAFT_LABEL
|
|
}
|
|
|
|
/**
|
|
* The number a user must type to confirm crediting an invoice. Regular
|
|
* invoices confirm with their own `invoice_number`; self-billed invoices have
|
|
* `invoice_number` null by design, so the counterparty's
|
|
* `external_invoice_number` (the number shown everywhere in the UI) is the
|
|
* one to type. Null when the invoice carries no number at all: the credit
|
|
* flow must stay disabled then.
|
|
*/
|
|
export function creditConfirmNumber(invoice: {
|
|
invoice_number?: string | null
|
|
external_invoice_number?: string | null
|
|
}): string | null {
|
|
return invoice.invoice_number ?? invoice.external_invoice_number ?? null
|
|
}
|
|
|
|
/**
|
|
* True when an invoice line should render as a pure text row: description
|
|
* only, no quantity/unit/price/amount columns. Explicit text rows
|
|
* (line_type 'text') always qualify; so do product rows carrying no amounts
|
|
* at all (quantity and unit price both zero/absent). Users write free-text
|
|
* lines via the article picker's "Egen rad (fri text)" and leave antal/pris
|
|
* at zero; printing "0 / 0,00 SEK / 0,00 SEK" on those is noise (issue #1053).
|
|
*/
|
|
export function isTextLikeLine(item: {
|
|
line_type?: 'product' | 'text' | null
|
|
quantity?: number | null
|
|
unit_price?: number | null
|
|
}): boolean {
|
|
return item.line_type === 'text' || (!item.quantity && !item.unit_price)
|
|
}
|