/** * Copyright since 2025 Mifos Initiative * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** * One Share Collection receipt the counter can choose, in a single shape whatever it came from. * * {@code GET /shareadvancecollection/unattributed} answers with two differently-shaped lists — the * member's own receipts under {@code own}, and every other receipt still going spare under * {@code rows} — and normalising both to this on arrival is what lets a screen show one plain list * of vouchers instead of two tables whose difference a counter has to understand before they can * pick anything. * * Shared by the two screens that settle a share purchase (the first application's Apply Collection * dialog and the Apply Additional Shares dialog) so a receipt reads identically on both. */ export interface ReceiptOption { /** Stable identity for tracking and comparison; unique across both source lists. */ key: string; /** * The {@code m_share_advance_collection} row behind this receipt, or null while it is still only * a voucher number. A null one is attached to the member on first pick. */ collectionId: number | null; voucherNo: string; glAccountNo: string; glAccountName: string; date: string; amount: number; description: string; cashierName: string; } /** * A receipt that already has an {@code m_share_advance_collection} row — ready to settle as-is. * * Also the shape {@code GET /shareadvancecollection/by-voucher} answers with, so a receipt found by * number arrives here too, already attached. */ export function receiptFromOwn(row: any): ReceiptOption { return { key: `c${row.id}`, collectionId: Number(row.id), voucherNo: row.voucher_no || row.receipt_no || '', glAccountNo: row.gl_code || '', glAccountName: '', date: String(row.collection_date || '').slice(0, 10), amount: Number(row.amount || 0), description: row.note || '', cashierName: row.collected_by_name || '' }; } /** A receipt that is still only a voucher, attached to the member when it is picked. */ export function receiptFromUnattached(row: any): ReceiptOption { return { key: `v${row.id}`, collectionId: null, voucherNo: row.voucherNo || '', glAccountNo: row.glAccountNo || '', glAccountName: row.glAccountName || '', date: String(row.txnDate || '').slice(0, 10), amount: Number(row.amount || 0), description: row.description || '', cashierName: row.cashierName || '' }; } /** * The GL account a receipt sits in, named where the name is known and coded where it is not. * * An attached receipt carries only its {@code gl_code}, so the name is looked up in whatever GL * account list the screen already loaded for its voucher search rather than fetched again. */ export function receiptGlLabel(option: ReceiptOption, glAccounts: any[]): string { const name = option.glAccountName || glAccounts.find((gl) => gl.gl_code === option.glAccountNo)?.name || ''; if (!option.glAccountNo) { return name || '—'; } return name ? `${option.glAccountNo} — ${name}` : option.glAccountNo; }