mirror of
https://github.com/renee-png/acmcc.git
synced 2026-06-21 09:50:01 +00:00
Accounting: show Payee/Payor on transaction-style lists
Add a Payee / Payor column to the bank register (Banking), the reconciliation list, and the Deposits 'awaiting deposit' list — showing the vendor (payee) for money out or the customer/homeowner (payor) for money in. Expenses already shows Vendor and Receive Payments shows Homeowner, so those were left as-is. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -832,6 +832,7 @@ export default function AccountingBankingPage() {
|
|||||||
<TableHead className="w-[100px]">Date</TableHead>
|
<TableHead className="w-[100px]">Date</TableHead>
|
||||||
<TableHead className="w-[80px]">Ref #</TableHead>
|
<TableHead className="w-[80px]">Ref #</TableHead>
|
||||||
<TableHead>Description</TableHead>
|
<TableHead>Description</TableHead>
|
||||||
|
<TableHead>Payee / Payor</TableHead>
|
||||||
<TableHead>Category</TableHead>
|
<TableHead>Category</TableHead>
|
||||||
<TableHead className="text-right w-[110px]">Payment</TableHead>
|
<TableHead className="text-right w-[110px]">Payment</TableHead>
|
||||||
<TableHead className="text-right w-[110px]">Deposit</TableHead>
|
<TableHead className="text-right w-[110px]">Deposit</TableHead>
|
||||||
@@ -845,7 +846,7 @@ export default function AccountingBankingPage() {
|
|||||||
<TableCell className="px-2" />
|
<TableCell className="px-2" />
|
||||||
<TableCell className="text-sm text-muted-foreground">{fmtDate(periodFrom)}</TableCell>
|
<TableCell className="text-sm text-muted-foreground">{fmtDate(periodFrom)}</TableCell>
|
||||||
<TableCell />
|
<TableCell />
|
||||||
<TableCell className="text-sm font-medium text-muted-foreground" colSpan={4}>Balance forward</TableCell>
|
<TableCell className="text-sm font-medium text-muted-foreground" colSpan={5}>Balance forward</TableCell>
|
||||||
<TableCell className="text-right text-sm font-medium tabular-nums">{money(balanceForward, cur)}</TableCell>
|
<TableCell className="text-right text-sm font-medium tabular-nums">{money(balanceForward, cur)}</TableCell>
|
||||||
<TableCell />
|
<TableCell />
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -873,6 +874,7 @@ export default function AccountingBankingPage() {
|
|||||||
<span className={row.voided ? "line-through text-muted-foreground" : ""}>{row.description}</span>
|
<span className={row.voided ? "line-through text-muted-foreground" : ""}>{row.description}</span>
|
||||||
</span>
|
</span>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell className="text-sm">{row.vendors?.name ?? row.customers?.name ?? row.payee_name ?? "—"}</TableCell>
|
||||||
<TableCell className="text-sm text-muted-foreground">{row.category ?? "—"}</TableCell>
|
<TableCell className="text-sm text-muted-foreground">{row.category ?? "—"}</TableCell>
|
||||||
<TableCell className={`text-right text-sm text-red-600 ${row.voided ? "line-through opacity-60" : ""}`}>
|
<TableCell className={`text-right text-sm text-red-600 ${row.voided ? "line-through opacity-60" : ""}`}>
|
||||||
{row.type === "debit" ? money(row.amount, cur) : ""}
|
{row.type === "debit" ? money(row.amount, cur) : ""}
|
||||||
@@ -905,14 +907,14 @@ export default function AccountingBankingPage() {
|
|||||||
))}
|
))}
|
||||||
{filteredRegister.length === 0 && (
|
{filteredRegister.length === 0 && (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={9} className="text-center text-muted-foreground py-8">
|
<TableCell colSpan={10} className="text-center text-muted-foreground py-8">
|
||||||
No transactions yet. Record a deposit or payment to get started.
|
No transactions yet. Record a deposit or payment to get started.
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
{filteredRegister.length > 0 && (
|
{filteredRegister.length > 0 && (
|
||||||
<TableRow className="bg-muted font-medium">
|
<TableRow className="bg-muted font-medium">
|
||||||
<TableCell colSpan={5} className="text-sm">Totals</TableCell>
|
<TableCell colSpan={6} className="text-sm">Totals</TableCell>
|
||||||
<TableCell className="text-right text-sm text-red-600">{money(totalDebits, cur)}</TableCell>
|
<TableCell className="text-right text-sm text-red-600">{money(totalDebits, cur)}</TableCell>
|
||||||
<TableCell className="text-right text-sm text-emerald-600">{money(totalCredits, cur)}</TableCell>
|
<TableCell className="text-right text-sm text-emerald-600">{money(totalCredits, cur)}</TableCell>
|
||||||
<TableCell className={`text-right text-sm ${computedBalance < 0 ? "text-destructive" : ""}`}>
|
<TableCell className={`text-right text-sm ${computedBalance < 0 ? "text-destructive" : ""}`}>
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export default function AccountingDepositsPage() {
|
|||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await accounting
|
const { data } = await accounting
|
||||||
.from("transactions")
|
.from("transactions")
|
||||||
.select("*")
|
.select("*, vendors(name), customers(name)")
|
||||||
.eq("company_id", cid)
|
.eq("company_id", cid)
|
||||||
.eq("account_id", undepositedId)
|
.eq("account_id", undepositedId)
|
||||||
.eq("type", "debit")
|
.eq("type", "debit")
|
||||||
@@ -93,7 +93,7 @@ export default function AccountingDepositsPage() {
|
|||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await accounting
|
const { data } = await accounting
|
||||||
.from("payments_received")
|
.from("payments_received")
|
||||||
.select("id,payment_date,amount,method,reference,memo,customer_id")
|
.select("id,payment_date,amount,method,reference,memo,customer_id,customers(name)")
|
||||||
.eq("company_id", cid)
|
.eq("company_id", cid)
|
||||||
.eq("deposited", false)
|
.eq("deposited", false)
|
||||||
.order("payment_date", { ascending: false });
|
.order("payment_date", { ascending: false });
|
||||||
@@ -101,17 +101,19 @@ export default function AccountingDepositsPage() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
type PendingRow = { key: string; kind: "tx" | "pmt"; id: string; date: string; description: string; reference: string | null; amount: number };
|
type PendingRow = { key: string; kind: "tx" | "pmt"; id: string; date: string; description: string; payor: string | null; reference: string | null; amount: number };
|
||||||
|
|
||||||
const pending = useMemo<PendingRow[]>(() => {
|
const pending = useMemo<PendingRow[]>(() => {
|
||||||
const rows: PendingRow[] = [
|
const rows: PendingRow[] = [
|
||||||
...(pendingTx as any[]).map((t) => ({
|
...(pendingTx as any[]).map((t) => ({
|
||||||
key: `tx:${t.id}`, kind: "tx" as const, id: t.id, date: t.date,
|
key: `tx:${t.id}`, kind: "tx" as const, id: t.id, date: t.date,
|
||||||
description: t.description, reference: t.reference ?? null, amount: Number(t.amount),
|
description: t.description, payor: t.customers?.name ?? t.vendors?.name ?? t.payee_name ?? null,
|
||||||
|
reference: t.reference ?? null, amount: Number(t.amount),
|
||||||
})),
|
})),
|
||||||
...(pendingPmt as any[]).map((p) => ({
|
...(pendingPmt as any[]).map((p) => ({
|
||||||
key: `pmt:${p.id}`, kind: "pmt" as const, id: p.id, date: p.payment_date,
|
key: `pmt:${p.id}`, kind: "pmt" as const, id: p.id, date: p.payment_date,
|
||||||
description: [p.method, p.memo].filter(Boolean).join(" · ") || "Customer payment",
|
description: [p.method, p.memo].filter(Boolean).join(" · ") || "Customer payment",
|
||||||
|
payor: p.customers?.name ?? null,
|
||||||
reference: p.reference ?? null, amount: Number(p.amount),
|
reference: p.reference ?? null, amount: Number(p.amount),
|
||||||
})),
|
})),
|
||||||
];
|
];
|
||||||
@@ -329,6 +331,7 @@ export default function AccountingDepositsPage() {
|
|||||||
</TableHead>
|
</TableHead>
|
||||||
<TableHead>Date</TableHead>
|
<TableHead>Date</TableHead>
|
||||||
<TableHead>Description</TableHead>
|
<TableHead>Description</TableHead>
|
||||||
|
<TableHead>Payee / Payor</TableHead>
|
||||||
<TableHead>Reference</TableHead>
|
<TableHead>Reference</TableHead>
|
||||||
<TableHead className="text-right">Amount</TableHead>
|
<TableHead className="text-right">Amount</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -343,13 +346,14 @@ export default function AccountingDepositsPage() {
|
|||||||
<TableCell><input type="checkbox" checked={selected.has(r.key)} readOnly /></TableCell>
|
<TableCell><input type="checkbox" checked={selected.has(r.key)} readOnly /></TableCell>
|
||||||
<TableCell>{fmtDate(r.date)}</TableCell>
|
<TableCell>{fmtDate(r.date)}</TableCell>
|
||||||
<TableCell>{r.description}</TableCell>
|
<TableCell>{r.description}</TableCell>
|
||||||
|
<TableCell className="text-sm">{r.payor ?? "—"}</TableCell>
|
||||||
<TableCell className="text-muted-foreground">{r.reference ?? "—"}</TableCell>
|
<TableCell className="text-muted-foreground">{r.reference ?? "—"}</TableCell>
|
||||||
<TableCell className="text-right tabular-nums">{money(r.amount, cur)}</TableCell>
|
<TableCell className="text-right tabular-nums">{money(r.amount, cur)}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
{pending.length === 0 && (
|
{pending.length === 0 && (
|
||||||
<TableRow className="hover:bg-transparent">
|
<TableRow className="hover:bg-transparent">
|
||||||
<TableCell colSpan={5} className="p-0">
|
<TableCell colSpan={6} className="p-0">
|
||||||
<EmptyState
|
<EmptyState
|
||||||
icon={Landmark}
|
icon={Landmark}
|
||||||
title="No payments awaiting deposit"
|
title="No payments awaiting deposit"
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ type Tx = {
|
|||||||
cleared: boolean;
|
cleared: boolean;
|
||||||
reconciliation_id: string | null;
|
reconciliation_id: string | null;
|
||||||
voided?: boolean;
|
voided?: boolean;
|
||||||
|
vendors?: { name: string } | null;
|
||||||
|
customers?: { name: string } | null;
|
||||||
|
payee_name?: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function AccountingReconcileDetailPage() {
|
export default function AccountingReconcileDetailPage() {
|
||||||
@@ -147,7 +150,7 @@ export default function AccountingReconcileDetailPage() {
|
|||||||
// and not voided.
|
// and not voided.
|
||||||
const { data } = await accounting
|
const { data } = await accounting
|
||||||
.from("transactions")
|
.from("transactions")
|
||||||
.select("id,date,description,reference,amount,type,cleared,reconciliation_id,voided")
|
.select("id,date,description,reference,amount,type,cleared,reconciliation_id,voided,payee_name,vendors(name),customers(name)")
|
||||||
.eq("account_id", accountId)
|
.eq("account_id", accountId)
|
||||||
.is("reconciliation_id", null)
|
.is("reconciliation_id", null)
|
||||||
.eq("voided", false)
|
.eq("voided", false)
|
||||||
@@ -469,6 +472,7 @@ export default function AccountingReconcileDetailPage() {
|
|||||||
</TableHead>
|
</TableHead>
|
||||||
<SortHead col="date" label="Date" sort={sort} onSort={toggleSort} />
|
<SortHead col="date" label="Date" sort={sort} onSort={toggleSort} />
|
||||||
<SortHead col="description" label="Description" sort={sort} onSort={toggleSort} />
|
<SortHead col="description" label="Description" sort={sort} onSort={toggleSort} />
|
||||||
|
<TableHead>Payee / Payor</TableHead>
|
||||||
<SortHead col="reference" label="Ref #" sort={sort} onSort={toggleSort} />
|
<SortHead col="reference" label="Ref #" sort={sort} onSort={toggleSort} />
|
||||||
<SortHead col="deposit" label="Deposit" sort={sort} onSort={toggleSort} align="right" />
|
<SortHead col="deposit" label="Deposit" sort={sort} onSort={toggleSort} align="right" />
|
||||||
<SortHead col="withdrawal" label="Withdrawal" sort={sort} onSort={toggleSort} align="right" />
|
<SortHead col="withdrawal" label="Withdrawal" sort={sort} onSort={toggleSort} align="right" />
|
||||||
@@ -497,6 +501,7 @@ export default function AccountingReconcileDetailPage() {
|
|||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>{fmtDate(t.date)}</TableCell>
|
<TableCell>{fmtDate(t.date)}</TableCell>
|
||||||
<TableCell className="max-w-[280px] truncate">{t.description}</TableCell>
|
<TableCell className="max-w-[280px] truncate">{t.description}</TableCell>
|
||||||
|
<TableCell className="text-sm">{t.vendors?.name ?? t.customers?.name ?? t.payee_name ?? "—"}</TableCell>
|
||||||
<TableCell className="text-muted-foreground">{t.reference ?? "—"}</TableCell>
|
<TableCell className="text-muted-foreground">{t.reference ?? "—"}</TableCell>
|
||||||
<TableCell className="text-right text-emerald-700">
|
<TableCell className="text-right text-emerald-700">
|
||||||
{t.type === "credit" ? money(t.amount, cur) : ""}
|
{t.type === "credit" ? money(t.amount, cur) : ""}
|
||||||
@@ -514,7 +519,7 @@ export default function AccountingReconcileDetailPage() {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{filtered.length === 0 && (
|
{filtered.length === 0 && (
|
||||||
<TableRow><TableCell colSpan={7} className="text-center text-muted-foreground py-8">
|
<TableRow><TableCell colSpan={8} className="text-center text-muted-foreground py-8">
|
||||||
No unreconciled transactions for this account.
|
No unreconciled transactions for this account.
|
||||||
</TableCell></TableRow>
|
</TableCell></TableRow>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user