TorbatYar/frontend/app/accounting/vouchers/page.tsx
Mortezakoohjani 12c8615615 Ship enterprise Accounting FE/API with CRUD parity and production wiring.
Adds accounting-service PATCH/archive, fiscal helpers, COA templates and setup status, plus SuperApp Accounting UI (DS, scoreboard, masters, vouchers, ledger, ops modules) with session refresh and HTTPS public API URLs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-24 15:26:43 +03:30

73 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import Link from "next/link";
import { useQuery } from "@tanstack/react-query";
import { Plus } from "lucide-react";
import { accountingApi } from "@/lib/accounting-api";
import { useTenantId } from "@/hooks/useTenantId";
import { formatMoney } from "@/lib/utils";
import { PageHeader, Button, DataTable, EmptyState, LoadingState, ErrorState, Badge, JalaliDateText } from "@/components/ds";
export default function VouchersPage() {
const { tenantId } = useTenantId();
const listQ = useQuery({
queryKey: ["accounting", tenantId, "vouchers"],
queryFn: () => accountingApi.vouchers.list(tenantId!),
enabled: !!tenantId,
});
if (!tenantId || listQ.isLoading) return <LoadingState />;
if (listQ.error) return <ErrorState message={listQ.error.message} onRetry={() => listQ.refetch()} />;
return (
<div>
<PageHeader
title="اسناد حسابداری"
description="چرخه عمر سند از طریق Posting Engine — بدون ایجاد مستقیم Journal Entry."
actions={
<Link href="/accounting/vouchers/new">
<Button><Plus className="h-4 w-4" />سند جدید</Button>
</Link>
}
/>
<DataTable
columns={[
{
key: "voucher_number",
header: "شماره",
render: (r) => (
<Link className="font-medium text-primary hover:underline" href={`/accounting/vouchers/${r.id}`}>
{String(r.voucher_number)}
</Link>
),
},
{ key: "voucher_date", header: "تاریخ", render: (r) => <JalaliDateText value={String(r.voucher_date ?? "")} /> },
{
key: "status",
header: "وضعیت",
render: (r) => (
<Badge tone={r.status === "posted" ? "success" : r.status === "draft" ? "default" : "warning"}>
{String(r.status)}
</Badge>
),
},
{ key: "total_debit", header: "بدهکار", render: (r) => formatMoney(String(r.total_debit)) },
{ key: "total_credit", header: "بستانکار", render: (r) => formatMoney(String(r.total_credit)) },
{ key: "description", header: "شرح" },
]}
rows={(listQ.data ?? []) as unknown as Record<string, unknown>[]}
empty={
<EmptyState
title="سندی وجود ندارد"
action={
<Link href="/accounting/vouchers/new">
<Button>ایجاد سند</Button>
</Link>
}
/>
}
/>
</div>
);
}