"use client"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { toast } from "sonner"; import { accountingApi } from "@/lib/accounting-api"; import { useTenantId } from "@/hooks/useTenantId"; import { PageHeader, LoadingState, ErrorState, Card, CardContent, CardHeader, CardTitle, Button, Checkbox, Select, Badge, } from "@/components/ds"; const AUTO_KEYS: { key: string; label: string; hint: string }[] = [ { key: "sales_invoice", label: "فاکتور فروش", hint: "با تأیید فاکتور فروش، سند GL خودکار صادر شود" }, { key: "sales_return", label: "مرجوعی فروش", hint: "ثبت خودکار برگشت فروش در دفتر" }, { key: "purchase_goods_receipt", label: "رسید کالا", hint: "Dr موجودی / Cr GRNI هنگام تأیید رسید" }, { key: "purchase_invoice", label: "فاکتور خرید", hint: "ثبت بدهی تأمین‌کننده هنگام تأیید فاکتور" }, { key: "purchase_return", label: "مرجوعی خرید", hint: "ثبت خودکار مرجوعی خرید" }, { key: "treasury_receipt", label: "دریافت خزانه", hint: "دریافت نقدی/بانکی همیشه به Posting Engine" }, { key: "treasury_payment", label: "پرداخت خزانه", hint: "پرداخت نقدی/بانکی همیشه به Posting Engine" }, { key: "payroll", label: "حقوق و دستمزد", hint: "پس از محاسبه/تأیید حقوق" }, { key: "assets_depreciation", label: "استهلاک دارایی", hint: "ثبت خودکار استهلاک دوره‌ای" }, ]; const POLICY_KEYS: { key: string; label: string; hint: string }[] = [ { key: "require_balanced", label: "اجبار تراز بدهکار/بستانکار", hint: "سند نامتوازن هرگز ذخیره یا قطعی نشود (استاندارد دوبل‌انتری)", }, { key: "require_source_reference", label: "الزام مرجع سند مبدأ", hint: "اسناد اتومات باید source_module و reference داشته باشند", }, { key: "lock_after_post", label: "قفل پس از ثبت قطعی", hint: "ویرایش مستقیم ممنوع؛ فقط برگشت از طریق Posting Engine", }, { key: "sequential_numbers", label: "شماره‌گذاری متوالی", hint: "استفاده از Document Number Sequence به‌جای شناسه تصادفی", }, { key: "idempotent_source", label: "جلوگیری از ثبت تکراری", hint: "یک سند مبدأ بیش از یک بار به GL نرود", }, ]; export default function AutoPostingSettingsPage() { const { tenantId } = useTenantId(); const qc = useQueryClient(); const policyQ = useQuery({ queryKey: ["accounting", tenantId, "posting-policy"], queryFn: () => accountingApi.setup.getPostingPolicy(tenantId!), enabled: !!tenantId, }); const saveM = useMutation({ mutationFn: (body: Parameters[1]) => accountingApi.setup.updatePostingPolicy(tenantId!, body), onSuccess: async () => { toast.success("سیاست اسناد اتومات ذخیره شد"); await qc.invalidateQueries({ queryKey: ["accounting", tenantId, "posting-policy"] }); }, onError: (e: Error) => toast.error(e.message), }); if (!tenantId || policyQ.isLoading) return ; if (policyQ.error) { return policyQ.refetch()} />; } const policy = policyQ.data!; const toggleAuto = (key: string, value: boolean) => { saveM.mutate({ auto_post: { ...policy.auto_post, [key]: value }, }); }; const togglePolicy = (key: string, value: boolean) => { saveM.mutate({ [key]: value } as Parameters[1]); }; return (
حالت ثبت {policy.posting_mode === "direct_post" ? "ثبت مستقیم" : "پیش‌نویس سپس قطعی"}

در حالت مستقیم، با تأیید سند عملیاتی (اگر ماژول روشن باشد) سند GL بلافاصله از طریق Posting Engine صادر می‌شود.

قواعد الزامی (Compliance) {POLICY_KEYS.map((item) => (
)[item.key])} disabled={saveM.isPending} onChange={(e) => togglePolicy(item.key, e.target.checked)} aria-label={item.label} /> {item.label} {item.hint}
))}
ثبت خودکار به تفکیک ماژول {AUTO_KEYS.map((item) => (
toggleAuto(item.key, e.target.checked)} aria-label={item.label} /> {item.label} {item.hint}
))}

قلب حسابداری فقط از مسیر Posting Engine می‌گذرد (ADR-010). تنظیمات بالا فقط زمان و شرط صدور را کنترل می‌کنند.

); }