# مستند کامل سامانه حسابداری FunZone این سند توضیح می‌دهد **اعداد و شماره‌ها چطور ساخته می‌شوند**، و **هر بخش منو چطور به بقیه وصل است** — از داشبورد تا تنظیمات. --- ## ۱. نمای کلی معماری | لایه | تکنولوژی | آدرس تقریبی | |------|----------|-------------| | فرانت‌اند حسابداری | React + TypeScript + Vite | اپ `funzone-accounting` | | API حسابداری | Django REST | معمولاً `localhost:8010/api` | | API اصلی FunZone | Django (مشتری، پرداخت، مالک، رویداد) | معمولاً `localhost:8000/api` | **منبع حقیقت داده‌ها:** `AppStore` همه موجودیت‌ها را از API حسابداری بارگذاری می‌کند و CRUD را از همان‌جا انجام می‌دهد. همگام‌سازی با FunZone (بلیت، کیف پول، برداشت) از API اصلی می‌خواند و در دفتر حسابداری ثبت می‌کند. ``` ┌─────────────────┐ همگام‌سازی ┌──────────────────────┐ │ FunZone API │ ──────────────────► │ Accounting Frontend │ │ پرداخت/کیف‌پول │ │ AppStore + صفحات │ └─────────────────┘ └──────────┬───────────┘ │ REST ▼ ┌──────────────────────┐ │ Accounting Backend │ │ جداول دفتر / شماره سند│ └──────────────────────┘ ``` --- ## ۲. ساختار منو و مسیرها | گروه | برچسب منو | مسیر | صفحه اصلی | |------|-----------|------|-----------| | اصلی | داشبورد | `/` | `Dashboard.tsx` | | حسابداری | حساب‌ها (کدینگ) | `/accounts` | `Accounts.tsx` | | حسابداری | اسناد حسابداری | `/vouchers` | `Vouchers.tsx` | | عملیات | مشتریان و فروش | `/sales/*` | `Sales.tsx` + زیرصفحات | | عملیات | تأمین‌کنندگان و خرید | `/purchases/*` | `Purchases.tsx` | | عملیات | انبارداری | `/inventory` | `Inventory.tsx` | | عملیات | دریافت و پرداخت | `/treasury` | `Treasury.tsx` | | عملیات | حقوق و دستمزد | `/payroll` | `Payroll.tsx` | | تحلیل | گزارش‌ها | `/reports` | `Reports.tsx` | | سیستم | تنظیمات | `/settings` | `Settings.tsx` | ### زیرمنوی فروش | مسیر | نقش | |------|-----| | `/sales` | فرایند فروش | | `/sales/proforma` | پیش‌فاکتور | | `/sales/invoice` | فاکتور فروش | | `/sales/return` | برداشت‌ها و لغو شده | | `/sales/adjustments` | اعلامیه بدهکار/بستانکار | | `/sales/sales-types` | نوع فروش | | `/sales/customers` | مشتریان | | `/sales/review` | مرور فروش | تعریف منو: `src/components/layout/navigation.ts` --- ## ۳. تولید اعداد و شماره‌ها (قلب سیستم) ### ۳.۱ الگوریتم مشترک فرانت‌اند فایل: `src/utils/id.ts` ```ts // شناسه موقت کلاینت (قبل از UUID سرور) createId(prefix) → مثلاً "v-" + زمان + تصادفی // شماره ترتیبی سند/فاکتور/… nextNumber(items) → max(item.number) + 1 ``` **نکات مهم:** - هیچ جدول Sequence / سری شماره‌گذاری جدا در دیتابیس نیست. - **سال مالی (`fiscalYear`) فقط نمایشی است** و شماره‌ها را ریست یا جدا نمی‌کند. - برای بیشتر اسناد، شماره را **کلاینت** با `nextNumber` روی لیست فیلترشده می‌سازد و سرور همان عدد را ذخیره می‌کند. - **استثنا: شماره سند حسابداری (`Voucher.number`)** — سرور شماره کلاینت را نادیده می‌گیرد و خودش اختصاص می‌دهد. --- ### ۳.۲ ماتریس شماره‌گذاری | نوع سند | فیلد | محدوده سری | کی می‌سازد؟ | فایل / منطق | |---------|------|------------|-------------|-------------| | **سند حسابداری** | `number` | همه اسناد | **سرور** (`_next_number` + قفل ردیف) | `serializers.py` | | **پیش‌فاکتور فروش** | `number` | فقط `documentType=proforma` و `kind=sale` | کلاینت | `SalesDocumentSection` | | **فاکتور فروش** | `number` | فقط `documentType=invoice` و `kind=sale` | کلاینت | `SalesDocumentSection` + سینک FunZone | | **فاکتور خرید** | `number` | همه `kind=purchase` | کلاینت | `TradeModule` | | **دریافت** | `number` | فقط `kind=receipt` | کلاینت | `Treasury.tsx` / سینک خزانه | | **پرداخت** | `number` | فقط `kind=payment` | کلاینت | `Treasury.tsx` / سینک | | **برداشت کیف پول** | `number` | **کل** لیست `treasury` (نه فقط payment) | کلاینت | `withdrawalTreasury.ts` | | **اعلامیه بدهکار/بستانکار** | `number` | همه اعلامیه‌ها | کلاینت | `PartyAdjustmentsPage` | | **کد حساب** | `code` | دستی / یکتا در DB | کاربر | `Accounts.tsx` + seed | | **کد کالا / نوع فروش / پرسنل** | `code` | دستی | کاربر | بدون auto | | **فیش حقوقی** | — | ندارد | — | با `id` و `period` | --- ### ۳.۳ شماره سند حسابداری (تنها شماره قطعی سمت سرور) در `funzone-accounting-backend/accounting/serializers.py`: 1. فیلد `number` در `VoucherSerializer` **read-only** است. 2. هنگام `create`، سرور با `select_for_update` آخرین شماره را می‌گیرد و `+1` می‌کند. 3. بعد از ایجاد، شماره تغییر نمی‌کند (`update` فیلد `number` را حذف می‌کند). 4. اگر سندی با `number <= 0` باشد، در update می‌تواند شماره بگیرد. فرانت قبل از POST ممکن است شماره موقت با `nextNumber(data.vouchers)` نشان دهد؛ بعد از ذخیره، شماره واقعی همانی است که سرور برمی‌گرداند. --- ### ۳.۴ شناسه‌های داخلی (`createId`) | پیشوند | موجودیت | |--------|---------| | `v-` | سند | | `vl-` | سطر سند | | `inv-` | فاکتور | | `il-` | سطر فاکتور | | `tr-` | دریافت/پرداخت | | `acc-` | حساب | | `prod-` | کالا | | `party-` | طرف‌حساب | | `st-` | نوع فروش | | `adj-` | اعلامیه | | `emp-` | کارمند | | `ps-` | فیش حقوقی | این‌ها شناسه موقت UI هستند؛ بعد از ایجاد در بک‌اند معمولاً با UUID سرور جایگزین می‌شوند. --- ### ۳.۵ تگ‌های پایدار `source` (برای جلوگیری از دوباره‌ثبتی) | الگو | معنی | |------|------| | `invoice:{uuid}` | فاکتور دستی | | `funzone:invoice:{paymentId}` | سند بلیت درگاه | | `funzone:invoice:wallet:{paymentId}` | سند بلیت از کیف پول | | `adjustment:{id}` | اعلامیه | | `treasury:{id}` | خزانه دستی | | `funzone:cust-pay:{id}` | پرداخت مشتری (قدیمی/خزانه) | | `funzone:wallet-pay:{id}` | تراکنش کیف پول | | `funzone:owner-txn:{id}` | تراکنش مالک | | `withdrawal:{id}` | برداشت IBAN | فایل کلیدی لینک بلیت↔خزانه: `src/pages/sales/funzoneVoucherLink.ts` منبع حقیقت تقسیم کارمزد بلیت = **سند فاکتور فروش**؛ اگر سند خزانه تکراری برای همان پرداخت بماند، حذف می‌شود. --- ## ۴. کدینگ حساب‌ها و نقش هر کد حساب‌های پیش‌فرض از `seeding.py` (نمونه مهم‌ها): | کد | نام | نقش در سیستم | |----|-----|--------------| | 1001 | صندوق | نقدینگی داشبورد | | 1002 | بانک ملت | بدهکار/بستانکار نقد در اسناد خودکار | | 1003 | بانک سامان | نقدینگی | | 1004 | دریافتنی مشتریان | فروش عادی، اعلامیه، تسویه خزانه | | 1005 | موجودی کالا | فاکتور خرید | | 2001 | پرداختنی تأمین‌کنندگان | خرید | | 2002 | مالیات پرداختنی | ۱۰٪ بلیت FunZone | | 2003 / 2004 | حقوق / بیمه | در کدینگ هست؛ حقوق هنوز سند نمی‌زند | | 2005 | بدهی به مالکان (کیف پول) | ۷۶٪ سهم مالک | | 2006 | بدهی به مشتریان (کیف پول) | شارژ/برداشت/بلیت از کیف | | 4001 | درآمد فروش | فروش عادی + ۱۴٪ سود پلتفرم | | 5002 | هزینه حقوق | رزرو شده؛ Payroll وصل نیست | | 5007 | سهم مالکان | در تنظیمات مپ شده؛ مسیر فعلی بلیت بیشتر از 2005/4001/2002 استفاده می‌کند | **تنظیمات نگاشت حساب‌ها** (`Settings` → `voucherAccounts`): بانک، بدهی مالک، بدهی مشتری، سهم مالک، درآمد فروش. بدون کدینگ درست، `buildSalesVoucher` / `buildPurchaseVoucher` / `buildTreasuryVoucher` سند نمی‌سازند (`null`). --- ## ۵. فلوچارت اتصال ماژول‌ها ### ۵.۱ نمای کلی ارتباطات ```mermaid flowchart TB subgraph سیستم["سیستم"] SET[تنظیمات
نگاشت حساب‌ها / سال مالی نمایشی] end subgraph حسابداری["حسابداری"] ACC[حساب‌ها / کدینگ] VOC[اسناد حسابداری] end subgraph عملیات["عملیات"] SAL[مشتریان و فروش] PUR[تأمین‌کنندگان و خرید] INV[انبارداری] TRE[دریافت و پرداخت] PAY[حقوق و دستمزد] end subgraph تحلیل["تحلیل"] REP[گزارش‌ها] DAS[داشبورد] end subgraph خارجی["خارج از اپ"] FZ[FunZone API] end SET --> ACC SET --> SAL SET --> TRE ACC --> VOC ACC --> SAL ACC --> PUR ACC --> TRE FZ -->|سینک طرف‌حساب| SAL FZ -->|سینک بلیت / لغو| SAL FZ -->|شارژ کیف / پرداخت مالک| TRE FZ -->|رویداد / رزرو| INV SAL -->|buildSalesVoucher + موجودی| VOC SAL -->|اعلامیه| VOC PUR -->|buildPurchaseVoucher + موجودی| VOC PUR -->|افزایش stock| INV SAL -->|کاهش stock| INV TRE -->|buildTreasuryVoucher + تسویه فاکتور| VOC TRE -->|reconcile paid/confirmed| SAL PAY -.->|فعلاً بدون سند| VOC VOC --> REP VOC --> DAS SAL --> DAS PUR --> DAS INV --> DAS TRE --> DAS ``` ### ۵.۲ جریان تولید سند از عملیات ```mermaid flowchart LR A[عملیات کاربر یا سینک FunZone] --> B{نوع؟} B -->|فاکتور فروش/خرید| C[ذخیره Invoice] B -->|دریافت/پرداخت| D[ذخیره TreasuryTxn] B -->|اعلامیه| E[ذخیره PartyAdjustment] B -->|سند دستی| F[Vouchers UI] C --> G[invoiceSideEffects] G --> H[تغییر موجودی کالا] G --> I[buildInvoiceVoucher] D --> J[buildTreasuryVoucher] D --> K[reconcileInvoicePaymentStatus] E --> L[buildAdjustmentVoucher] F --> M[createDraft + nextNumber کلاینت] I --> N[POST سند] J --> N L --> N M --> N N --> O[سرور: شماره قطعی Voucher] O --> P[دفتر کل / تراز / داشبورد / گزارش] ``` ### ۵.۳ جریان بلیت FunZone (تقسیم مبالغ) برای مبلغ ناخالص `G`: | جزء | نرخ | حساب بستانکار معمول | |-----|-----|---------------------| | مالیات | ۱۰٪ | 2002 | | سود پلتفرم | ۱۴٪ | 4001 | | سهم مالک | ۷۶٪ (باقیمانده) | 2005 | **بدهکار:** - درگاه: 1002 بانک - کیف پول مشتری: 2006 تابع: `splitEventPayment` در `src/utils/funzoneFees.ts` سند: `buildSalesVoucher` وقتی note شامل `funzone:pay:` است. ```mermaid flowchart TB P[پرداخت بلیت در FunZone] --> S[funzoneSalesSync] S --> I[فاکتور فروش status=paid] I --> V[سند با source=funzone:invoice:…] V --> L1[بدهکار بانک یا کیف 2006] V --> L2[بستانکار مالک 2005] V --> L3[بستانکار درآمد 4001] V --> L4[بستانکار مالیات 2002] T[سند خزانه تکراری همان پرداخت] -.->|حذف توسط funzoneVoucherLink| X[حذف] ``` ### ۵.۴ ترتیب همگام‌سازی یکپارچه `unifiedVoucherSync.ts`: 1. سینک خزانه از FunZone (شارژ کیف، تراکنش مالک، …) 2. سینک فاکتورهای فروش بلیت + ثبت سند فاکتور 3. حذف اسناد تکراری / منسوخ (`supersededVoucherIds` + لینک بلیت) --- ## ۶. جزئیات هر بخش منو ### ۶.۱ داشبورد **می‌خواند از:** اسناد posted، فاکتورها، موجودی کالا، حساب‌های نقدی. **نمایش تقریبی:** - نقدینگی (کدهای 1001–1003) - جمع فروش / خرید از فاکتورها - سود و زیان و تراز از `trialBalance` روی اسناد - موجودی کم / فاکتورهای تسویه‌نشده - نمودار چندماهه **تولید عدد:** خودش شماره سند نمی‌سازد؛ فقط تجمیع می‌کند. --- ### ۶.۲ حساب‌ها (کدینگ) **نقش:** درخت حساب‌ها (`parentId`)، مانده افتتاحیه، نوع (دارایی/بدهی/درآمد/هزینه). **اتصال:** پایه همه سطرهای سند (`VoucherLine.accountId`). بدون حساب‌های اجباری، اسناد خودکار ساخته نمی‌شوند. **شماره:** کد حساب دستی و یکتا — بدون `nextNumber`. --- ### ۶.۳ اسناد حسابداری **ورودی‌ها:** | منبع | چگونه | |------|--------| | دستی در همین صفحه | پیش‌نویس + ثبت | | فروش | `buildSalesVoucher` | | خرید | `buildPurchaseVoucher` | | خزانه | `buildTreasuryVoucher` | | اعلامیه | `buildAdjustmentVoucher` | | دکمه همگام FunZone | `unifiedVoucherSync` | **شماره:** سرور قطعی می‌کند. **وضعیت:** `draft` | `posted` — گزارش‌ها معمولاً روی posted (منهای اسناد حذف‌شده/منسوخ). --- ### ۶.۴ مشتریان و فروش **موجودیت‌ها:** Party (مشتری)، Invoice فروش، نوع فروش، اعلامیه، سینک FunZone. | عمل | اثر حسابداری | اثر انبار | |-----|--------------|-----------| | پیش‌فاکتور | بدون سند | معمولاً بدون تغییر قطعی موجودی مسیر اصلی سند | | فاکتور فروش عادی confirmed | بدهکار 1004 / بستانکار درآمد | کاهش stock | | بلیت FunZone | تقسیم ۱۰/۱۴/۷۶ | — | | لغو بلیت درگاه | بانک بدهکار / 2006 بستانکار | — | | لغو بلیت کیف پول | حذف/بازگردانی سند قبلی | — | | اعلامیه بدهکار | ↑ مطالبات / ↑ درآمد | — | | اعلامیه بستانکار | عکس بالا | — | **شماره فاکتور:** سری جدا برای پیش‌فاکتور و فاکتور (`nextNumber` روی همان `documentType`). **تسویه:** خزانه با `reconcileInvoicePaymentStatus` به صورت FIFO وضعیت `confirmed` ↔ `paid` را عوض می‌کند (بلیت‌های FunZone prepaid می‌مانند). --- ### ۶.۵ تأمین‌کنندگان و خرید **موجودیت‌ها:** Party (supplier)، Invoice خرید. **سند خودکار (confirmed):** - بدهکار 1005 موجودی - بستانکار 2001 پرداختنی **شماره:** یک سری برای همه فاکتورهای خرید. **اتصال به خزانه:** پرداخت به تأمین‌کننده از ماژول دریافت/پرداخت؛ تسویه فاکتور خرید از همان منطق reconcile. --- ### ۶.۶ انبارداری **دو لایه:** 1. **موجودی کالا در حسابداری** — فیلد `Product.stock`؛ با تأیید فاکتور خرید/فروش عوض می‌شود (`applyStockChanges` / `stockDeltas`). 2. **نمای عملیاتی FunZone** — رویداد/رزرو زنده (`funzoneInventory.ts`)؛ **سند حسابداری نمی‌زند**. یعنی انبار «دفتر انبار جدا» ندارد؛ موجودی از فاکتورها مشتق می‌شود + نمای FunZone برای عملیات. --- ### ۶.۷ دریافت و پرداخت (خزانه) | نوع تراکنش | سند تقریبی | |------------|------------| | شارژ کیف پول مشتری | بدهکار بانک / بستانکار 2006 | | برداشت کیف پول | بدهکار 2006 / بستانکار بانک | | دریافت عادی از مشتری | بدهکار بانک / بستانکار 1004 | | پرداخت به تأمین‌کننده/مالک | بدهکار 2005 یا 2001 / بستانکار بانک | | مسیر قدیمی split روی خزانه | همان ۱۰/۱۴/۷۶ (امروز ترجیح با سند فاکتور بلیت است) | **شماره:** دریافت و پرداخت سری جدا در UI؛ مسیر برداشت ممکن است از `nextNumber` روی **کل** خزانه استفاده کند. --- ### ۶.۸ حقوق و دستمزد CRUD کارمند و فیش حقوقی. **اتصال به اسناد: فعلاً وجود ندارد.** حساب‌های 2003/2004/5002 در کدینگ آماده هستند ولی Payroll سند ثبت نمی‌کند. --- ### ۶.۹ گزارش‌ها از توابع `src/utils/accounting.ts`: - تراز آزمایشی (`trialBalance`) - دفتر حساب (`accountLedger`) - سود و زیان (`incomeStatement`) - ترازنامه (`balanceSheet`) ورودی: حساب‌ها (مانده افتتاحیه) + اسناد posted (فیلتر اسناد منسوخ). --- ### ۶.۱۰ تنظیمات - اطلاعات شرکت و **سال مالی نمایشی** - نگاشت حساب‌های پیش‌فرض اسناد خودکار - ریست/seed داده‌ها (در صورت فعال بودن در UI) بدون نگاشت درست، زنجیره فروش/خزانه/بلیت می‌شکند. --- ## ۷. موجودیت‌ها و روابط ``` Account (درخت) └── VoucherLine.accountId → Voucher Party (customer | supplier ، گاهی externalId از FunZone) ├── Invoice.partyId ├── PartyAdjustment.partyId └── TreasuryTxn.partyId Invoice (sale | purchase) └── Voucher با source پایدار TreasuryTxn └── Voucher با source خزانه / FunZone / withdrawal Employee → Payslip (بدون Voucher) CompanySettings (singleton) → FKs به Account ``` **وضعیت فاکتور:** `draft` | `confirmed` | `paid` | `cancelled` **وضعیت سند:** `draft` | `posted` --- ## ۸. فایل‌های کلیدی (مرجع سریع) | فایل | نقش | |------|-----| | `src/utils/id.ts` | `createId` / `nextNumber` | | `src/pages/sales/salesUtils.ts` | همه سازنده‌های سند + تسویه + source | | `src/pages/sales/invoiceEffects.ts` | اثر جانبی ذخیره فاکتور | | `src/utils/funzoneFees.ts` | تقسیم ۱۰٪ / ۱۴٪ / ۷۶٪ | | `src/pages/sales/funzoneVoucherLink.ts` | لینک بلیت و حذف سند تکراری خزانه | | `src/accounting/unifiedVoucherSync.ts` | ارکستراسیون سینک | | `src/accounting/voucherDedupe.ts` | حذف/مخفی اسناد تکراری | | `src/pages/sales/funzoneSalesSync.ts` | پرداخت FunZone → فاکتور | | `src/pages/treasury/funzoneTreasurySync.ts` | کیف پول / مالک → خزانه | | `src/utils/accounting.ts` | محاسبات گزارش و تراز | | `src/store/AppStore.tsx` | بارگذاری و CRUD | | `backend/.../serializers.py` | شماره قطعی سند | | `backend/.../seeding.py` | کدینگ اولیه | > ⚠️ `voucherSync.ts` مسیر قدیمی است؛ برای جلوگیری از دوباره‌ثبتی از مسیر یکپارچه (`unifiedVoucherSync`) استفاده شود. --- ## ۹. جمع‌بندی قوانین شماره‌گذاری (برای تیم) 1. **فقط شماره سند حسابداری روی سرور قطعی است**؛ بقیه `max+1` سمت کلاینت روی لیست فیلترشده. 2. **سال مالی شماره‌ها را جدا یا ریست نمی‌کند.** 3. **پیش‌فاکتور و فاکتور فروش سری جدا** دارند؛ **خرید یک سری** دارد. 4. **دریافت و پرداخت در UI سری جدا** دارند؛ مسیر برداشت ممکن است با سری دیگر هم‌پوشانی عددی داشته باشد. 5. **بلیت FunZone:** فاکتور + سند با تگ `funzone:invoice:…`؛ تقسیم کارمزد روی همان سند؛ خزانه برای همان بلیت نباید دوبار ثبت شود. 6. **حقوق هنوز به دفتر کل وصل نیست.** --- *آخرین به‌روزرسانی بر اساس کدبیس `funzone-accounting` و `funzone-accounting-backend`.*