/* Bonyan ERP — الحسابات: كشوف ديون موحّدة (عملاء/موردون) مع فلترة ذكية، دمج المؤسسات، طباعة PDF لكل الديون الظاهرة، والنقر يفتح حساب الجهة. */ function AccountsScreen({ onNav }) { const I = window.BnyIcon; const D = window.BnyData; const cur = window.BnyCur; const { Card, Button, Money, Badge, Input } = window.BonyanDesignSystem_ad3ca0; const isMobile = window.useBnyMobile(); window.useBnyInvoices(); // إعادة الرسم عند أي تعديل فاتورة/دفعة const user = window.BnyCurrentUser; const canSuppliers = window.BnyCan(user, "suppliers"); const [side, setSide] = React.useState("customers"); // customers | suppliers const [view, setView] = React.useState("people"); // people | orgs (للعملاء) const [q, setQ] = React.useState(""); const [status, setStatus] = React.useState("all"); // all | debt | settled const [curF, setCurF] = React.useState("all"); // all | iqd | usd const [typeF, setTypeF] = React.useState("all"); // all | نقدي | آجل const [orgF, setOrgF] = React.useState("all"); // all | | none const [sort, setSort] = React.useState("debt-desc"); // debt-desc|debt-asc|recent|alpha const [from, setFrom] = React.useState(""); // مدى التاريخ: من const [to, setTo] = React.useState(""); // إلى const [printing, setPrinting] = React.useState(false); const forceRender = React.useReducer((x) => x + 1, 0)[1]; const reset = () => { setQ(""); setStatus("all"); setCurF("all"); setTypeF("all"); setOrgF("all"); setSort("debt-desc"); setFrom(""); setTo(""); }; // مدى التاريخ المختار (فارغ = كل الفترات) — يحصر الحساب بفواتير المدى const range = (from || to) ? { from: from || "", to: to || "" } : null; // المصدر: عملاء (أفراد أو مؤسسات) أو موردون — مع حصر المدى let rows = side === "suppliers" ? window.BnySupplierAccounts(range) : view === "orgs" ? window.BnyOrgAccounts(range) : window.BnyCustomerAccounts(range); // عند تفعيل المدى: أظهر فقط من له نشاط (فواتير) ضمن الفترة if (range) rows = rows.filter((r) => (r.invCount || 0) > 0); // ---- فلترة ذكية ---- const qn = q.trim(); if (qn) rows = rows.filter((r) => r.name.includes(qn) || (r.phone || "").includes(qn) || (r.orgName || "").includes(qn)); if (status === "debt") rows = rows.filter((r) => r.remaining > 0.0001); if (status === "settled") rows = rows.filter((r) => r.remaining <= 0.0001); if (curF === "iqd") rows = rows.filter((r) => (r.remIqd || 0) > 0.0001); if (curF === "usd") rows = rows.filter((r) => (r.remUsd || 0) > 0.0001); if (typeF !== "all") rows = rows.filter((r) => r.type === typeF); if (side === "customers" && view === "people" && orgF !== "all") { rows = rows.filter((r) => orgF === "none" ? !r.org : r.org === orgF); } rows = rows.slice().sort((a, b) => { if (sort === "debt-desc") return b.remaining - a.remaining; if (sort === "debt-asc") return a.remaining - b.remaining; if (sort === "alpha") return String(a.name).localeCompare(String(b.name), "ar"); const da = a.lastMove || "", db = b.lastMove || ""; if (da === db) return 0; if (!da) return 1; if (!db) return -1; return db < da ? -1 : 1; }); // إجماليات (بالمكافئ بالدينار) const totRemaining = rows.reduce((s, r) => s + r.remaining, 0); const totCount = rows.length; const debtorsCount = rows.filter((r) => r.remaining > 0.0001).length; // ---- التنقّل إلى حساب الجهة ---- const openRow = (r) => { if (r.kind === "supplier") { window.BnyPendingSupplierId = r.id; onNav("suppliers"); return; } if (r.kind === "org") { const first = (r.members && r.members[0]) ? r.members[0].id : null; if (first != null) { window.BnyPendingCustomerId = first; window.BnyPendingCustomerScope = "org"; onNav("customers"); } return; } window.BnyPendingCustomerId = r.id; onNav("customers"); }; // ---- طباعة PDF لكل الصفوف الظاهرة ---- React.useEffect(() => { if (!printing) return; document.body.classList.add("bny-printing-stmt"); const after = () => { document.body.classList.remove("bny-printing-stmt"); setPrinting(false); }; window.addEventListener("afterprint", after); const t = setTimeout(() => window.print(), 140); return () => { clearTimeout(t); window.removeEventListener("afterprint", after); document.body.classList.remove("bny-printing-stmt"); }; }, [printing]); const fmt = (n) => Number(n || 0).toLocaleString("en-US"); const sideLabel = side === "suppliers" ? "الموردون" : (view === "orgs" ? "المؤسسات" : "العملاء"); const printTitle = "كشف ديون " + sideLabel + " الإجمالي"; // شريط تجزئة معاد استخدامه const Seg = ({ value, set, opts }) => (
{opts.map((o) => )}
); const selStyle = { height: 38, minWidth: 130, padding: "0 10px", borderRadius: "var(--radius-md)", border: "1px solid var(--border-subtle)", background: "var(--surface-card)", color: "var(--text-body)", fontFamily: "var(--font-body)", fontSize: 13 }; return (
{/* رأس: تبديل عملاء/موردون + طباعة */}
{ setSide(v); setOrgF("all"); }} opts={[{ v: "customers", l: "عملاء" }].concat(canSuppliers ? [{ v: "suppliers", l: "موردون" }] : [])} /> {side === "customers" && ( )}
{/* ملخّص علوي */}
إجمالي المتبقّي (مكافئ د.ع)
0 ? "debt" : "credit"} style={{ fontSize: 20 }} />
عدد الجهات المدينة
{debtorsCount} من {totCount}
القسم
{sideLabel}
{/* شريط الفلترة الذكي */}
setQ(e.target.value)} placeholder="ابحث بالاسم أو الهاتف أو المؤسسة" icon={} />
{side === "customers" && view === "people" && ( )}
{/* فلترة حسب مدى التاريخ (من – إلى) — تحصر الأرقام بفواتير الفترة */}
مدى التاريخ setFrom(e.target.value)} aria-label="من تاريخ" style={{ height: 38, width: 160, padding: "0 10px", fontFamily: "var(--font-mono)", fontSize: 13 }} /> setTo(e.target.value)} aria-label="إلى تاريخ" style={{ height: 38, width: 160, padding: "0 10px", fontFamily: "var(--font-mono)", fontSize: 13 }} /> {range && (الأرقام محصورة بفواتير الفترة المحددة)} {range && }
{/* الجدول */}
{rows.map((r, i) => ( openRow(r)} onMouseEnter={(e) => (e.currentTarget.style.background = "var(--surface-hover)")} onMouseLeave={(e) => (e.currentTarget.style.background = "transparent")} style={{ borderTop: "1px solid var(--border-subtle)", cursor: "pointer", transition: "background var(--dur-fast,160ms) ease" }}> ))} {rows.length === 0 && }
# الاسم الإجمالي المدفوع المتبقّي / الدين آخر حركة
{i + 1}
{r.kind === "org" && } {r.name} {r.kind === "org" && {r.count} أعضاء}
{r.kind === "customer" && r.orgName &&
{r.orgName}{r.title ? " · " + r.title : ""}
}
{fmt(r.total)} د.ع {fmt(r.paid)} د.ع {r.remaining > 0.0001 ?
{r.remIqd > 0 && } {r.remUsd > 0 && }
: مسدّد}
{r.lastMove || "—"}
لا حسابات مطابقة للفلترة
{/* ورقة الطباعة (مخفية على الشاشة) */} {printing && (
r.name + (r.orgName && r.kind === "customer" ? " (" + r.orgName + ")" : (r.kind === "org" ? " — مؤسسة" : "")) }, { label: "الإجمالي", align: "end", mono: true, render: (r) => fmt(r.total) }, { label: "المدفوع", align: "end", mono: true, render: (r) => fmt(r.paid) }, { label: "المتبقّي (د.ع)", align: "end", mono: true, render: (r) => fmt(r.remIqd) + (r.remUsd ? " + " + fmt(r.remUsd) + "$" : "") }, ]} rows={rows} totals={[{ label: "إجمالي المتبقّي (مكافئ بالدينار)", value: fmt(totRemaining) + " د.ع", strong: true }]} />
)}
); } window.AccountsScreen = AccountsScreen;