/** * What counts as a valid discount amount, for the UI and the API alike. * * `Disc` is always the computed monetary discount and `RecDisc` is the * record-level discount already pro-rated onto a line, so a negative value in * either increases what a sale customer is charged. A return reverses its original discounts with nonpositive amounts. This * module decides that question once, so the Angular client and the Node API * cannot disagree about whether a given value is acceptable. * * Deliberately not in scope: whether a discount is *authorized*, whether `Disc` * agrees with `Perc`, whether a line's reference price was inflated, and * reconciling document totals. Those need a trusted basis and stored policy, * neither of which belongs in a pure function. * * Sharing the implementation removes drift between the two callers. It does not * make the client trustworthy: an installed client can be an old version or be * bypassed entirely, so the API remains the authority and must run these checks * at its own write boundary regardless of what the client did. * * Returns findings rather than throwing. The caller decides what a finding * means -- an HTTP 400 on the server, a red field on the client -- and the * stable `Code` lets the UI phrase its own message without depending on server * wording. */ export declare const DiscountIssueCodes: Readonly<{ /** The exact decimal value is below zero. */ readonly NEGATIVE_AMOUNT: "NEGATIVE_AMOUNT"; /** Not a number at all, or not a finite one: NaN, Infinity, text, an object. */ readonly INVALID_NUMBER: "INVALID_NUMBER"; }>; export type DiscountIssueCode = typeof DiscountIssueCodes[keyof typeof DiscountIssueCodes]; export interface DiscountIssue { /** Where the offending value sits, e.g. `Items[3].RecDisc`. */ readonly Field: string; readonly Code: DiscountIssueCode; /** Diagnostic text for logs and server messages. The UI should use `Code`. */ readonly Detail: string; } /** * The shared shape these checks read. * * Declared here as plain data on purpose. The package must not know about * Mongoose documents or about any one endpoint's request envelope: a caller * passes something structurally like this, and gets findings back. */ export interface DiscountLineInput { readonly Disc?: unknown; readonly RecDisc?: unknown; } export interface InvoiceDiscountInput { readonly Disc?: unknown; readonly PDisc?: unknown; readonly LDisc?: unknown; readonly Items?: unknown; readonly Ops?: unknown; } export interface SalesReceiptDiscountInput { readonly Disc?: unknown; readonly Items?: unknown; } /** * Checks one discount amount, returning a finding or `null`. * * An absent value is not a finding: on a patch an omitted amount keeps whatever * is stored, and on a create it means no discount. * * A numeric string is accepted because clients do send them and Mongoose casts * one to a number on the way in. The parse is strict rather than `Number()`, * which reads `""` and `" "` as zero -- a forgiving fallback would turn * invalid input into "no discount" instead of reporting it. * * The sign is taken from the exact decimal value through `Big`, never from the * converted double. `Number("-0.000…001")` with enough zeros underflows to `-0`, * and `-0 < 0` is false, so a float comparison would pass a value whose written * form is negative. `"-0"` and `"-0.0"` are accepted, because their exact value * is zero. */ export declare function CheckDiscountAmount(value: unknown, field: string): DiscountIssue | null; /** Convenience for a UI field check, where only valid/invalid matters. */ export declare function IsValidDiscountAmount(value: unknown): boolean; /** * Checks the discount amounts on one line. * * A returned line is not exempt. A sales-receipt return is a negative quantity * alongside a return marker; that negative quantity is legitimate and is not * read here. The discount on such a line still describes a reduction and is * nonpositive when allowReturns is set; invoice lines retain the sale rule. */ export declare function CheckLineDiscounts(line: DiscountLineInput | unknown, fieldPath: string, allowReturns?: boolean): DiscountIssue[]; /** * Every discount finding on an invoice: its header amounts and both line arrays. * * `fieldPath` prefixes the reported fields, for a caller that nests the document * inside an envelope. */ export declare function FindInvoiceDiscountIssues(document: InvoiceDiscountInput | unknown, fieldPath?: string): DiscountIssue[]; /** The sales-receipt equivalent. Receipts carry `Items` only, and no `Ops`. */ export declare function FindSalesReceiptDiscountIssues(document: SalesReceiptDiscountInput | unknown, fieldPath?: string): DiscountIssue[]; /** One line of text summarising findings, for a server error message or a log. */ export declare function DescribeDiscountIssues(issues: readonly DiscountIssue[]): string;