import { Amount } from '../../commonStateTypes/amount'; import { SortOrder } from '../../commonStateTypes/selectorTypes/sortOrderTypes'; import { JournalEntryTransactionLine, Line, TransactionLineBase } from '../../entity/transaction/stateTypes/transactionLine'; /** * View-model helpers for the new Journal Entry table view (see * web-components `journalEntryTable`). Keeps presentation-agnostic * logic — totals, sort, line-filter — colocated in epic-state so it * is testable and reusable. */ export declare const JOURNAL_ENTRY_SORT_KEYS: readonly ["description", "name", "category", "class", "debit", "credit"]; export declare const toJournalEntrySortKey: (v: string) => "category" | "class" | "credit" | "debit" | "description" | "name"; export type JournalEntrySortKey = ReturnType; export interface JournalEntryRowSortConfig { sortKey: JournalEntrySortKey; sortOrder: SortOrder; } export declare const journalEntryDefaultSortConfig: JournalEntryRowSortConfig; type AmountBearer = Pick; /** * Sums the `amount.amount` field of every line and returns an `Amount` * whose currencyCode/currencySymbol are taken from the first line. * Returns `undefined` for an empty list, and also when the first line * has no currency to carry — a stray bare number with no symbol is * worse to render than nothing, so the caller is forced to handle the * absence. * * **Precondition:** all input lines must share a currency. Journal * entry lines on the same transaction always do, which is the only * caller today. Mixed-currency input is summed numerically (no FX * conversion) and tagged with the first line's currency, which will * silently produce a wrong total — if this helper is ever reused for * a cross-currency aggregate (e.g. a multi-transaction report), the * caller must pre-group by currency before calling. * * Mirrors legacy `calculateTotal` in * `web-components/src/components/transactionDetail/items/TransactionLinesJournalEntry.tsx` * but without the `Object.assign` ceremony and with stable currency carry-over. */ export declare const sumJournalEntryAmounts: (lines: ReadonlyArray) => Amount | undefined; /** * Splits `lines` by `postingType` into a single debit total and a * single credit total — the shape the new flat-table totals row * (`JournalEntryTotalsRow` in `web-components`, Figma frame * `5177:12750`) needs. * * The legacy `TransactionLinesJournalEntry` grouped lines into six * `JournalEntryItemType` buckets (`debit` / `uncategorizedDebit` / * `miscategorizedDebit` plus the credit triplet) for *visual banner * headers* in the line list; its bottom totals row was already two * combined numbers. The new flat table folds those banners away by * design, so we don't surface a per-status breakdown here. If the * design ever asks for sub-totals per status, that's a richer shape * (`{debit: {total, uncategorized, miscategorized}, credit: {…}}`) * and a follow-up — not a v1 of this helper. * * As a side effect, the legacy `calculateCombinedTotalAmount` * `??`/`+` precedence bug (`totalAmount?.amount ?? 0 + (uncat ?? 0) + * (miscat ?? 0)` parses as `totalAmount?.amount ?? (0 + uncat + * miscat)`, silently dropping the uncat/miscat pieces whenever * `totalAmount` was non-nullish) is gone by construction here: there * is no separate combine step, just one pass over the lines. */ export declare const journalEntryTotalsByPostingSide: (lines: ReadonlyArray>) => { creditTotal?: Amount; debitTotal?: Amount; }; type PostingBearer = Pick; export interface JournalEntrySplitReconciliation { creditTotal: number; debitTotal: number; /** Total debits == total credits == original transaction total. */ isBalanced: boolean; } /** * Sums debit and credit sides (big.js-exact) and reports whether the split is * balanced: total debits equal total credits AND equal the original * transaction total. The original total of a valid JE equals its total debits, * so it is passed in by the caller (`transaction.amount.amount`). */ export declare const journalEntrySplitReconciliation: (lines: ReadonlyArray, originalTotal: number) => JournalEntrySplitReconciliation; export type JournalEntrySplitErrorKey = 'lineNeedsDebitOrCredit' | 'totalsMustEqual'; export interface JournalEntrySplitValidation { ok: boolean; errorKey?: JournalEntrySplitErrorKey; } /** * Save-time validation for a JE split (Figma `4165:33028` / `4165:45379`): * 1. every line needs a non-zero debit or credit, and * 2. total debits == total credits == original total. * Returns the first failing rule's `errorKey` (maps to a strings entry). Does * NOT require category/class to be chosen — balance is the only gate. */ export declare const validateJournalEntrySplit: (lines: ReadonlyArray, originalTotal: number) => JournalEntrySplitValidation; /** * Drops `linked_transaction_line` entries — equivalent to legacy * `filterOutLinkedTransactionLine` in `transactionDetail.helpers.ts`. * * The literal lives in `LINE_TYPE_LINKED` next to `LineType` so the * filter discriminant stays bound to the union at the type level. * Other sites still inlining the literal (see `transactionDetailLocalDataHelper`, * `transactionDetailState`, `transactionCategorizationLocalDataHelper`, * `transactionLinePayload`, and the mocks) are a known follow-up. */ export declare const filterJournalEntryLinesExcludingLinked: >(lines?: ReadonlyArray) => T[]; /** * Accessor functions resolve the sort value for each column from a * line. The new table reads display-formatted values from the form * (selected option label, entity name, etc.), so callers pass in * accessors that match their `LineInfo` shape rather than baking the * column-to-form-field mapping into epic-state. */ export interface JournalEntrySortAccessors { category: (line: T) => string; class: (line: T) => string; credit: (line: T) => number; debit: (line: T) => number; description: (line: T) => string; name: (line: T) => string; } /** * Stable, accessor-driven sort over arbitrary line shapes. Lines that * resolve to the same key value preserve their original relative order * thanks to lodash's stable `orderBy`. * * Strings are lower-cased before comparison so the order is predictable * across mixed-case data. Numbers (debit/credit) compare directly. */ export declare const sortJournalEntryLines: (lines: ReadonlyArray, config: JournalEntryRowSortConfig, accessors: JournalEntrySortAccessors) => T[]; export {};