Skip to content

ملاحظات نموذج البيانات والقواعد المحاسبية — نظام إدارة المغسلة

معلومات الوثيقة

الحقل القيمة
المشروع نظام إدارة المغسلة
الإصدار 1.0
اللغة العربية
التقنيات ASP.NET Core + Angular + PostgreSQL (مركزي) / SQLite (فروع غير متصلة)
نوع الوثيقة مذكرات تقنية لنموذج البيانات

جدول المحتويات

  1. نظرة عامة على الكيانات
  2. الكيانات الأساسية والعلاقات
  3. دليل الحسابات والأستاذ العام
  4. محرك القواعد المحاسبية
  5. التدفقات المحاسبية حسب نوع المعاملة
  6. استراتيجية UUID والمزامنة غير المتصلة
  7. نمط عقد API التقارير
  8. نماذج تسوية شركات السجاد
  9. نماذج دفع الخياطين
  10. تكوين استراتيجيات التسعير
  11. الحذف الناعم وسجل التدقيق
  12. مراجع المكتبات التقنية

1. نظرة عامة على الكيانات

ينقسم النظام إلى أربع طبقات من الكيانات:

الطبقة الغرض أمثلة
البيانات الرئيسية تكوين، نادراً ما يتغير المستخدمون، الفروع، دليل الحسابات، العملات، قوائم الأسعار، أنواع القطع، أنواع الخدمات، التصنيفات، أنواع السجاد
البيانات التشغيلية معاملات الأعمال اليومية الفواتير، أسطر الفواتير، إيصالات السجاد، بنود إيصالات السجاد، فواتير السجاد النهائية، طلبات الخياطة، مهام الخياطة، حركات المخزون
البيانات المالية سجلات محاسبية (لا تعدل مباشرة أبداً) قيود اليومية، أسطر قيود اليومية (الأستاذ العام)، المدفوعات
البيانات المساعدة تتبع وتسجيل أرصدة الزبائن الدائنة، بطاقات الباركود، جلسات الورديات، سجل التدقيق، حزم المزامنة

2. الكيانات الأساسية والعلاقات

2.1 كيانات البيانات الرئيسية

branches (id uuid PK, code, name, mode [online|offline], default_currency_id, status)
users (id uuid PK, username, password_hash, role, branch_id FK, status)
roles (id uuid PK, name)
role_permissions (role_id FK, module, action, is_allowed)
customers (id uuid PK, name, phone, classification_id FK, branch_id FK, credit_limit, status, is_transient)
customer_classifications (id uuid PK, name, default_price_list_id FK, default_discount_pct, allow_deferred_payment, is_default)
garment_types (id uuid PK, code, name_en, name_ar, category, status)
service_types (id uuid PK, code, name_en, name_ar, status)
garment_service_links (garment_type_id FK, service_type_id FK) — أي الخدمات تنطبق على أي القطع
price_lists (id uuid PK, name, currency_id FK, status)
price_list_entries (id uuid PK, price_list_id FK, garment_type_id FK, service_type_id FK, base_price numeric(18,4), effective_from, effective_to)
currencies (id uuid PK, code, name, symbol, decimal_places)
currency_rates (id uuid PK, from_currency_id FK, to_currency_id FK, rate numeric(18,6), effective_date)
fiscal_years (id uuid PK, name, start_date, end_date, is_closed)
tax_settings (id uuid PK, is_enabled bool, tax_name, tax_rate numeric(8,4), is_inclusive bool, tax_account_code)
carpet_types (id uuid PK, code, name_en, name_ar)
carpet_companies (id uuid PK, name, contact, phone, address, settlement_model [accrual|cash|prepayment], status)
carpet_company_prices (id uuid PK, company_id FK, carpet_type_id FK, price_per_sqm numeric(18,4), price_per_piece numeric(18,4), effective_date)
tailors (id uuid PK, name, phone, payout_model [periodic|peritem|salary_commission], base_salary numeric(18,4), status)
inventory_items (id uuid PK, code, name_en, name_ar, category, uom, selling_price numeric(18,4), cost_price numeric(18,4), current_quantity numeric(18,4), reorder_level numeric(18,4), branch_id FK, status)

2.2 الكيانات التشغيلية

invoices (id uuid PK, invoice_number, customer_id FK nullable, branch_id FK, date, due_date, operational_status [draft|confirmed|in_progress|ready|delivered], financial_status [unpaid|partially_paid|paid|deferred], subtotal numeric(18,4), discount_amount numeric(18,4), tax_amount numeric(18,4), grand_total numeric(18,4), paid_amount numeric(18,4), remaining_amount numeric(18,4), notes, created_by_user_id FK, currency_id FK)

invoice_items (id uuid PK, invoice_id FK, garment_type_id FK, service_type_id FK, quantity int, unit_price numeric(18,4), line_total numeric(18,4), discount_amount numeric(18,4), is_tailoring bool, tailor_id FK nullable, tailor_cost numeric(18,4), line_status [active|damaged|lost], compensation_amount numeric(18,4))

barcode_tags (id uuid PK, tag_code, invoice_id FK, invoice_item_id FK, garment_type_id FK, printed_at, scanned_at_delivery)

carpet_receipts (id uuid PK, receipt_number, customer_id FK, branch_id FK, date, advance_amount numeric(18,4), advance_method, notes, status [received|assigned_to_company|returned|ready|delivered], external_company_id FK nullable)

carpet_receipt_items (id uuid PK, receipt_id FK, carpet_type_id FK, quantity int, estimated_size, notes_damages)

carpet_final_invoices (id uuid PK, invoice_number, linked_receipt_id FK UNIQUE, customer_id FK, branch_id FK, date, operational_status, financial_status, subtotal numeric(18,4), discount_amount numeric(18,4), tax_amount numeric(18,4), grand_total numeric(18,4), advance_deduction numeric(18,4), paid_amount numeric(18,4), remaining_amount numeric(18,4), notes)

carpet_final_invoice_items (id uuid PK, final_invoice_id FK, carpet_type_id FK, pricing_strategy [per_sqm|per_piece|cost_plus], actual_area_sqm numeric(18,4) nullable, quantity int, unit_rate numeric(18,4), company_cost numeric(18,4), markup_pct numeric(8,4), line_total numeric(18,4))

tailoring_orders (id uuid PK, order_number, customer_id FK, linked_invoice_id FK nullable, branch_id FK, date, operational_status, financial_status)

tailoring_tasks (id uuid PK, order_id FK, service_description, garment_type_id FK, quantity int, unit_price numeric(18,4), assigned_tailor_id FK, tailor_cost numeric(18,4), task_status [pending|in_progress|completed])

inventory_transactions (id uuid PK, item_id FK, branch_id FK, transaction_type [sale|sale_cancellation|stock_receipt|adjustment], quantity_change numeric(18,4), reference_type, reference_id, date)

2.3 الكيانات المالية

chart_of_accounts (id uuid PK, account_code, account_name_en, account_name_ar, account_type [asset|liability|equity|income|expense], parent_id FK nullable, is_active, is_contra)

journal_entries (id uuid PK, entry_number, date, reference_type, reference_id, narration, branch_id FK, fiscal_year_id FK, is_manual bool, created_by_user_id FK, status [draft|posted|reversed])

journal_entry_lines (id uuid PK, journal_entry_id FK, account_code FK, debit numeric(18,4), credit numeric(18,4), branch_id FK, customer_id FK nullable, supplier_id FK nullable, tailor_id FK nullable, currency_id FK, narration)

payments (id uuid PK, payment_number, invoice_id FK nullable, carpet_final_invoice_id FK nullable, customer_id FK, branch_id FK, date, amount numeric(18,4), method [cash|card|bank_transfer|customer_credit|other], reference_no, notes, shift_id FK, status)

supplier_payments (id uuid PK, payment_number, supplier_type [carpet_company|tailor], supplier_id, branch_id FK, date, amount numeric(18,4), method, reference_no, notes)

customer_credits (id uuid PK, customer_id FK, branch_id FK, amount numeric(18,4), source_type, source_id, date, notes, remaining_amount numeric(18,4))

2.4 الكيانات المساعدة

shift_sessions (id uuid PK, user_id FK, branch_id FK, open_time, close_time, opening_float numeric(18,4), expected_cash numeric(18,4), actual_cash numeric(18,4), discrepancy numeric(18,4), notes)

audit_logs (id uuid PK, entity_type, entity_id, action, user_id FK, timestamp, old_value jsonb, new_value jsonb, branch_id FK)

sync_batches (id uuid PK, source_branch_id FK, target_branch_id FK nullable, export_date, import_date, total_rows, status [pending|imported|validated|rejected], file_path, validation_errors text)

system_settings (key text PK, value text)

3. دليل الحسابات والأستاذ العام

3.1 هيكل دليل الحسابات

دليل الحسابات (CoA) هو هيكل شجري هرمي. كل حساب ينتمي لواحد من خمسة أنواع رئيسية:

النوع مدى الأكواد أمثلة
الأصول (1XXX) 1000-1999 نقدية (1000)، بنك (1010)، ذمم مدينة (1200)، مخزون (1300)، مصروفات مدفوعة مقدماً (1400)
الخصوم (2XXX) 2000-2999 ذمم دائنة (2000)، مستحقات خياطين (2100)، ضريبة مستحقة (2200)، عربون زبائن / إيراد غير مكتسب (2300)
حقوق الملكية (3XXX) 3000-3999 رأس مال المالك (3000)، أرباح محتجزة (3100)
الإيرادات (4XXX) 4000-4999 إيراد غسيل (4000)، إيراد سجاد (4010)، إيراد خياطة (4020)، إيراد مبيعات منتجات (4030)
المصروفات (5XXX) 5000-5999 مستلزمات غسيل (5000)، مصروف غسيل سجاد (5010)، تكلفة خياطة (5020)، تكلفة بضاعة مباعة (5030)، رواتب (5040)، مصروف تالف/مفقود (5050)، مصروف استرداد (5060)

قاعدة: الحسابات الفرعية ترث نوع الحساب الأب. الكود الهرمي يعكس الشجرة (مثلاً: 1200 = ذمم مدينة، 1201 = ذمم مدينة - أفراد، 1202 = ذمم مدينة - شركات).

3.2 جدول الأستاذ العام

جدول journal_entry_lines هو الأستاذ العام نفسه. كل صف هو جانب واحد من قيد مزدوج.

القيود الأساسية: - لكل قيد يومية: SUM(debit) == SUM(credit). يفرض على مستوى التطبيق قبل الترحيل. - بمجرد ترحيل قيد اليومية، لا يمكن تعديله. التصحيحات تتم بإنشاء قيد عكسي. - كل سطر يحمل branch_id لتقارير مستوى الفرع. - كل سطر يحمل اختيارياً customer_id أو supplier_id أو tailor_id لتسويات الدفاتر المساعدة.

3.3 حساب الأرصدة

أرصدة الزبائن والموردين والخياطين لا تخزن أبداً في عمود balance على تلك الكيانات. يتم حسابها دائماً:

-- رصيد الزبون (الذمم المدينة)
SELECT COALESCE(SUM(debit), 0) - COALESCE(SUM(credit), 0) AS balance
FROM journal_entry_lines
WHERE account_code LIKE '120%'  -- جميع حسابات الذمم المدينة الفرعية
  AND customer_id = 'CUST-UUID';

لتحسين الأداء، يمكن الاحتفاظ بجدول مادي customer_balances، لكنه يعاد بناؤه من الأستاذ العام عند الطلب ولا يعامل أبداً كمصدر الحقيقة.


4. محرك القواعد المحاسبية

4.1 المفهوم

بدلاً من ترميز المنطق المحاسبي لكل نوع معاملة، يستخدم النظام جدول القواعد المحاسبية accounting_rules. كل قاعدة تعرف:

الحقل الوصف
معرف القاعدة UUID
كود القاعدة معرف قصير (مثلاً: "PAID_LAUNDRY_INVOICE")
الحدث الحدث التجاري الذي يشغل هذه القاعدة
كود حساب المدين
كود حساب الدائن
الشرط مرشح JSON اختياري (مثلاً: لطريقة دفع محددة فقط)
الأولوية ترتيب التنفيذ إذا تطابقت عدة قواعد

4.2 آلية العمل

عند وقوع حدث تجاري (مثلاً: InvoiceConfirmed، PaymentReceived، CarpetReturned)، يقوم النظام:

  1. بالبحث عن جميع القواعد المطابقة للحدث.
  2. لكل قاعدة، يقيم الشرط.
  3. يولد أسطر قيد اليومية (مدين X، دائن Y) للحسابات المطابقة.
  4. يغلف كل شيء في معاملة قاعدة بيانات واحدة مع تغييرات البيانات التشغيلية.

4.3 لماذا محرك قواعد؟

  • يمكن لصاحب المغسلة إضافة نموذج تسوية جديد لشركات السجاد بإضافة صف في accounting_rules، بدون تغيير الكود.
  • يمكن للمحاسب تعديل توجيهات الأستاذ العام دون إعادة نشر التطبيق.
  • التوسع لتعدد العملات: إضافة قواعد لقيود تحويل العملات.

5. التدفقات المحاسبية حسب نوع المعاملة

5.1 فاتورة غسيل مدفوعة (نقداً عند الاستلام)

# الحساب مدين دائن
1 نقدية / بنك (1000) الإجمالي الكلي
2 إيراد غسيل (4000) الإجمالي الكلي

إذا كانت الضريبة مفعلة: | 3 | نقدية (1000) | قيمة الضريبة | | | 4 | ضريبة مستحقة (2200) | | قيمة الضريبة |

5.2 فاتورة غسيل آجلة

# الحساب مدين دائن
1 ذمم مدينة - الزبون (120X) الإجمالي الكلي
2 إيراد غسيل (4000) الإجمالي الكلي

عند استلام الدفع لاحقاً: | 3 | نقدية (1000) | المبلغ المدفوع | | | 4 | ذمم مدينة - الزبون (120X) | | المبلغ المدفوع |

5.3 الدفع الجزئي

المدفوعات الجزئية: مدين نقدية، دائن ذمم مدينة بقيمة الجزء المدفوع فقط.

5.4 فاتورة تحتوي على أصناف مخزون

# الحساب مدين دائن
1 نقدية / ذمم مدينة (1000/1200) الإجمالي الكلي
2 إيراد غسيل (4000) حصة الخدمات
3 إيراد مبيعات منتجات (4030) حصة المنتجات
4 تكلفة بضاعة مباعة (5030) تكلفة المنتج
5 أصل المخزون (1300) تكلفة المنتج

5.5 العربون / الدفع المقدم (سجاد)

# الحساب مدين دائن
1 نقدية (1000) مبلغ العربون
2 عربون زبائن - إيراد غير مكتسب (2300) مبلغ العربون

عند إنشاء فاتورة السجاد النهائية: | 3 | عربون زبائن (2300) | مبلغ العربون | | | 4 | إيراد سجاد (4010) | | الإجمالي النهائي | | 5 | إذا العربون > النهائي: عربون زبائن (2300) | الفائض | | | 6 | إذا العربون > النهائي: ذمم دائنة رصيد زبون (23XX) | | الفائض | | 7 | إذا النهائي > العربون: ذمم مدينة - الزبون (120X) | النقص | | | 8 | إذا النهائي > العربون: إيراد سجاد (4010) | | النقص |

5.6 شركة السجاد — نموذج المستحقات (Accrual)

عند ارتجاع السجاد من الشركة: | 1 | مصروف غسيل سجاد (5010) | تكلفة الشركة | | | 2 | ذمم دائنة - شركة س (200X) | | تكلفة الشركة |

عند الدفع للشركة: | 3 | ذمم دائنة - شركة س (200X) | المبلغ المدفوع | | | 4 | نقدية (1000) | | المبلغ المدفوع |

5.7 شركة السجاد — النموذج النقدي (Cash)

عند الدفع للشركة: | 1 | مصروف غسيل سجاد (5010) | المبلغ المدفوع | | | 2 | نقدية (1000) | | المبلغ المدفوع |

5.8 شركة السجاد — نموذج المقدم (Prepayment)

عند دفع العربون للشركة: | 1 | مصروف مدفوع مقدماً - شركة س (140X) | العربون | | | 2 | نقدية (1000) | | العربون |

عند ارتجاع السجاد: | 3 | مصروف غسيل سجاد (5010) | تكلفة الشركة | | | 4 | مصروف مدفوع مقدماً - شركة س (140X) | | تكلفة الشركة |

5.9 الخياطة — نموذج دوري / بالقطعة

عند اكتمال مهمة الخياطة: | 1 | تكلفة خياطة (5020) | تكلفة الخياط | | | 2 | مستحقات خياط - الخياط س (210X) | | تكلفة الخياط |

عند الدفع للخياط: | 3 | مستحقات خياط - الخياط س (210X) | المبلغ المدفوع | | | 4 | نقدية (1000) | | المبلغ المدفوع |

5.10 الخياطة — نموذج راتب + عمولة

الراتب الشهري (يولد تلقائياً عبر مهمة Quartz): | 1 | مصروف رواتب (5040) | الراتب الأساسي | | | 2 | مستحقات خياط - الخياط س (210X) | | الراتب الأساسي |

العمولة على القطع المنجزة: | 3 | مصروف مكافأة خياطة (5045) | قيمة العمولة | | | 4 | مستحقات خياط - الخياط س (210X) | | قيمة العمولة |

5.11 تعويض التالف / المفقود

# الحساب مدين دائن
1 مصروف تالف/مفقود (5050) قيمة التعويض
2 ذمم دائنة رصيد زبون (23XX) قيمة التعويض

أو إذا تم الاسترداد نقداً: | 1 | مصروف تالف/مفقود (5050) | قيمة التعويض | | | 2 | نقدية (1000) | | قيمة التعويض |

5.12 الاسترداد (فاتورة مدفوعة)

# الحساب مدين دائن
1 مصروف استرداد / إيراد مقابل (5060) مبلغ الاسترداد
2 نقدية / رصيد الزبون (1000 / 23XX) مبلغ الاسترداد

5.13 إلغاء فاتورة (غير مدفوعة)

يتم عكس القيد الأصلي: | # | الحساب | مدين | دائن | |---|--------|------|------| | 1 | إيراد غسيل (4000) | المبلغ الأصلي | | | 2 | ذمم مدينة (120X) | | المبلغ الأصلي |


6. استراتيجية UUID والمزامنة غير المتصلة

6.1 لماذا UUID

جميع المفاتيح الرئيسية هي UUID مولدة من جانب الخادم (C# Guid.NewGuid()). هذا يمنع تضارب المعرفات عند دمج بيانات الفروع غير المتصلة في الخادم المركزي.

6.2 قاعدة توليد UUID

  • تولد UUID في طبقة التطبيق (ASP.NET Core)، وليس في قاعدة البيانات.
  • الواجهة لا تولد UUID أبداً — ترسل طلبات POST بدون معرفات، والخلفية تولد UUID.
  • هذا يضمن نقطة وحيدة لإنشاء UUID.

6.3 نموذج بيانات الفرع غير المتصل

تستخدم الفروع غير المتصلة SQLite بهيكل جداول مطابق. SQLite يدعم: - TEXT لـ UUID (يخزن كنص بطول 36 حرفاً). - NUMERIC للقيم العشرية. - مشغلات SQLite أو منطق التطبيق يفرضان نفس قاعدة SUM(debit) == SUM(credit).

6.4 هيكل حزمة المزامنة

كل صف في قاعدة البيانات غير المتصلة له sync_status = 'local' | 'pending' | 'synced'.

حزمة التصدير (بتنسيق JSON):

{
  "batch_id": "uuid",
  "source_branch_id": "uuid",
  "source_branch_code": "CAIRO-01",
  "export_date": "2026-05-09T18:00:00Z",
  "tables": {
    "journal_entry_lines": [
      { "id": "uuid", "journal_entry_id": "uuid", ... }
    ],
    "invoices": [ ... ],
    "payments": [ ... ],
    "customers": [ ... ],
    ...
  }
}

6.5 منطق الاستيراد والدمج

1. تحميل ملف JSON المصدر.
2. التحقق من تطابق branch_id مع المصدر المتوقع.
3. التحقق من SUM(debit) == SUM(credit) داخل الحزمة.
4. التحقق من وجود جميع مراجع account_code في دليل الحسابات المركزي.
5. لكل جدول، تكرار الصفوف:
   - إذا كان row.id غير موجود مركزياً ← INSERT.
   - إذا كان row.id موجوداً مركزياً (إعادة استيراد) ← UPSERT (تحديث إذا المصدر أحدث).
6. تسجيل sync_batch بحالة 'imported' أو 'validated'.
7. تحديث صفوف المصدر (إذا كانت متاحة) إلى sync_status = 'synced'.

6.6 حل التعارضات

  • تضارب رقم هاتف الزبون: إذا كان زبون بنفس رقم الهاتف موجوداً مركزياً، تعلم عملية الاستيراد بذلك. يختار المدير:
  • ربط (ربط الزبون غير المتصل بالزبون المركزي الموجود).
  • إبقاء منفصل (الاستيراد ينشئ سجل زبون جديد).
  • تضارب رقم الفاتورة: أرقام الفواتير مسبوقة بكود الفرع، لذا لا يفترض حدوث ذلك. إذا حدث، يرفض الاستيراد.
  • المزامنة المكررة: بما أن جميع المفاتيح UUID، إعادة استيراد نفس الملف آمنة (upsert حسب id).

7. نمط عقد API التقارير

7.1 تنسيق الاستجابة القياسي

كل نقطة API تقرير ترجع هذا الغلاف:

{
  "meta": {
    "reportName": "نص",
    "generatedAt": "ISO8601",
    "branchId": "uuid | 'all'",
    "currency": "EGP",
    "filters": {
      "dateFrom": "YYYY-MM-DD",
      "dateTo": "YYYY-MM-DD"
    }
  },
  "summary": {
    "totalRevenue": 12500.00,
    "totalInvoices": 45,
    ...
  },
  "details": [
    { /* صف محسوب مسبقاً */ }
  ],
  "pagination": {
    "page": 1,
    "pageSize": 50,
    "totalCount": 450
  }
}

7.2 المبادئ الأساسية

المبدأ القاعدة
جميع الحسابات في SQL الأرصدة الجارية، SUM، AVG، التجميع، التصفية — كلها تنفذ في قاعدة البيانات.
الواجهة لا تحسب المال أبداً حقول balance وtotal وremaining محسوبة مسبقاً. الواجهة فقط تنسق وتعرض.
ترقيم الصفحات للبيانات الكبيرة الخلفية ترقم الصفحات. الواجهة تستخدم التحميل الكسول على جداول PrimeNG.
نقطة ملخص منفصلة لوحات التحكم تستدعي /report/daily-sales/summary (تجميعات فقط). التفاصيل تستدعي /report/daily-sales/details (صفوف كاملة).
التفويض على مستوى API الخلفية ترجع فقط البيانات المسموح للمستخدم برؤيتها (مرشح الفرع، مرشح الدور).
حدود النطاق الزمني التقارير افتراضياً 30 يوماً. حد أقصى سنة واحدة بدون تجاوز المدير.

7.3 نقاط API التقارير (مرجع)

GET /api/reports/daily-sales          ?branchId=&dateFrom=&dateTo=
GET /api/reports/shift-closing        ?shiftId=
GET /api/reports/customer-statement   ?customerId=&dateFrom=&dateTo=
GET /api/reports/general-ledger       ?accountCode=&dateFrom=&dateTo=&page=&pageSize=
GET /api/reports/trial-balance        ?dateFrom=&dateTo=
GET /api/reports/income-statement     ?branchId=&dateFrom=&dateTo=
GET /api/reports/balance-sheet        ?date=
GET /api/reports/tailor-payout        ?tailorId=&dateFrom=&dateTo=
GET /api/reports/company-payables     ?companyId=&dateFrom=&dateTo=
GET /api/reports/inventory-levels     ?branchId=&category=
GET /api/reports/best-selling         ?dateFrom=&dateTo=&limit=
GET /api/reports/corporate-summary    ?customerId=&year=&month=
GET /api/reports/damage-report        ?dateFrom=&dateTo=
GET /api/reports/discounts-overrides  ?dateFrom=&dateTo=&userId=
GET /api/reports/branch-comparison    ?dateFrom=&dateTo=
GET /api/reports/audit-log            ?entityType=&entityId=&userId=&dateFrom=&dateTo=

8. نماذج تسوية شركات السجاد (قابلة للتكوين لكل شركة)

النموذج عند ارتجاع السجاد من الشركة عند الدفع للشركة
المستحقات (Accrual) مدين مصروف، دائن ذمم دائنة مدين ذمم دائنة، دائن نقدية
النقدي (Cash) لا شيء مدين مصروف، دائن نقدية
المقدم (Prepayment) مدين مصروف، دائن مصروف مدفوع مقدماً مدين مصروف مدفوع مقدماً (العربون)، دائن نقدية؛ الرصيد يحسب تلقائياً

كل carpet_company له حقل settlement_model يمكن تجاوزه لكل معاملة إذا لزم الأمر.


9. نماذج دفع الخياطين (قابلة للتكوين لكل خياط)

النموذج عند اكتمال المهمة عند الدفع
الدوري (Periodic) مدين تكلفة خياطة، دائن مستحقات مدين مستحقات، دائن نقدية
بالقطعة (Per-Item) مدين تكلفة خياطة، دائن مستحقات (فوري) مدين مستحقات، دائن نقدية (أي وقت)
راتب + عمولة الراتب: مهمة Quartz الشهرية: مدين رواتب، دائن مستحقات. العمولة: مثل الدوري لبنود المكافأة. مثل النماذج الأخرى

كل tailor له حقل payout_model. محرك المحاسبة يقرؤه ويطبق القاعدة المطابقة.


10. تكوين استراتيجيات التسعير

10.1 استراتيجيات تسعير السجاد

الاستراتيجية المعاملات حساب السعر
للمتر المربع actual_area_sqm, selling_rate_per_sqm actual_area_sqm × selling_rate_per_sqm
للقطعة (سعر ثابت) quantity, fixed_price_per_piece quantity × fixed_price_per_piece
هامش ربح على التكلفة company_cost, markup_pct company_cost × (1 + markup_pct / 100)

كل سجل carpet_type يحدد الاستراتيجيات المسموحة (allowed_strategies حقل JSON: ["per_sqm", "per_piece", "cost_plus"]).

10.2 معمارية قائمة الأسعار المرنة

تصنيف الزبون (CustomerClassification)
قائمة الأسعار (PriceList) — مختارة لكل تصنيف
إدخال قائمة الأسعار (PriceListEntry) — نوع_القطعة + نوع_الخدمة ← السعر_الأساسي
    ▼ (تجاوز اختياري مع سبب)
سطر الفاتورة (InvoiceItem) — سعر مجمد عند تأكيد الفاتورة

يمكن تفعيل عدة قوائم أسعار في وقت واحد. تغيير قائمة الأسعار لا يؤثر على الفواتير التاريخية.


11. الحذف الناعم وسجل التدقيق

11.1 لا حذف فعلي للبيانات المالية

  • الفواتير والمدفوعات وقيود اليومية والإيصالات لا تحذف فعلياً أبداً.
  • "الإلغاء" ينشئ تغيير حالة + قيد يومية عكسي.
  • فقط فواتير المسودة (غير المؤكدة، لا تأثير مالي) يمكن إزالتها.

11.2 جدول سجل التدقيق

CREATE TABLE audit_logs (
    id UUID PRIMARY KEY,
    entity_type VARCHAR(50) NOT NULL,    -- 'Invoice', 'Payment', 'Customer', إلخ
    entity_id UUID NOT NULL,
    action VARCHAR(20) NOT NULL,          -- 'CREATE', 'UPDATE', 'DELETE', 'STATUS_CHANGE'
    user_id UUID NOT NULL,
    timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    old_value JSONB,                      -- NULL لـ CREATE
    new_value JSONB,                      -- NULL لـ DELETE
    branch_id UUID NOT NULL
);

11.3 ما يشغل إدخال تدقيق

  • أي استدعاء API يعدل البيانات الرئيسية أو التشغيلية أو المالية.
  • تغييرات الحالة (مثلاً: فاتورة من "جاهز" إلى "مسلّم").
  • تجاوزات الأسعار والخصومات اليدوية (السعر القديم، السعر الجديد، السبب).
  • تغييرات الصلاحيات.

12. مراجع المكتبات التقنية

12.1 الخلفية (ASP.NET Core)

المكتبة حزمة NuGet الغرض
Entity Framework Core Microsoft.EntityFrameworkCore ORM
Npgsql EF Core Provider Npgsql.EntityFrameworkCore.PostgreSQL موفر PostgreSQL
Dapper Dapper SQL عالي الأداء للتقارير واستعلامات الأستاذ
MediatR MediatR نمط CQRS (أوامر للكتابة، استعلامات للقراءة)
FluentValidation FluentValidation.AspNetCore التحقق من المدخلات
AutoMapper AutoMapper تحويل DTO
Serilog Serilog.AspNetCore تسجيل منظم
Serilog Npgsql Sink Serilog.Sinks.PostgreSQL تسجيل إلى قاعدة البيانات
Quartz.NET Quartz.Extensions.Hosting مهام خلفية (توليد المستحقات، مزامنة ليلية)
BCrypt.Net BCrypt.Net-Next تشفير كلمات المرور
Microsoft Identity / JWT Microsoft.AspNetCore.Authentication.JwtBearer المصادقة

12.2 الواجهة (Angular)

المكتبة حزمة npm الغرض
PrimeNG primeng مكونات واجهة المستخدم (معتمدة من العميل)
PrimeFlex primeflex أدوات CSS
PrimeIcons primeicons الأيقونات
ngx-translate @ngx-translate/core ترجمة AR/EN
SheetJS xlsx تصدير Excel
html2canvas html2canvas تحويل HTML إلى لوحة رسم
jspdf jspdf إنشاء PDF
jsbarcode jsbarcode توليد باركود
RxJS rxjs إدارة الحالة التفاعلية

12.3 قاعدة البيانات

التقنية الدور
PostgreSQL 16+ قاعدة البيانات المركزية
SQLite 3 قاعدة بيانات الفروع غير المتصلة
Npgsql موفر .NET لـ PostgreSQL
Microsoft.Data.Sqlite موفر .NET لـ SQLite

ملحق أ: مخططات انتقال الحالة

أ.1 الحالة التشغيلية للفاتورة

stateDiagram-v2
    [*] --> مسودة
    مسودة --> مؤكدة : تأكيد
    مؤكدة --> قيد_التنفيذ : بدء المعالجة
    قيد_التنفيذ --> جاهزة : كل القطع جاهزة
    جاهزة --> مسلمة : استلام الزبون
    مسودة --> [*] : إزالة
    مؤكدة --> [*] : إلغاء (إذا غير مدفوعة)
    جاهزة --> تالف_مفقود : تعليم تالف/مفقود

أ.2 الحالة المالية للفاتورة

stateDiagram-v2
    [*] --> غير_مدفوع
    غير_مدفوع --> مدفوع_جزئيا : دفع جزئي
    مدفوع_جزئيا --> مدفوع : دفع المتبقي
    غير_مدفوع --> آجل : شروط دفع آجل
    آجل --> مدفوع_جزئيا : دفع جزئي
    آجل --> مدفوع : دفع كامل
    مدفوع --> استرداد : معالجة استرداد

أ.3 إيصال السجاد → الفاتورة النهائية

stateDiagram-v2
    [*] --> مستلم : استلام السجاد (إنشاء الإيصال)
    مستلم --> مسند : إسناد إلى الشركة
    مسند --> مرتجع : ارتجاع السجاد (قياس المساحة)
    مرتجع --> فاتورة_نهائية : إنشاء الفاتورة النهائية (مرتبطة 1-لـ-1)
    فاتورة_نهائية --> مخصوم : خصم العربون تلقائياً
    مخصوم --> دفع_المتبقي : العربون < النهائي → دفع المتبقي
    مخصوم --> رصيد_دائن : العربون > النهائي → رصيد دائن
    دفع_المتبقي --> [*]
    رصيد_دائن --> [*]

ملحق ب: مرجع سريع — أكواد الحسابات المحاسبية

الكود اسم الحساب النوع
1000 نقدية أصل
1010 بنك أصل
1200 ذمم مدينة أصل
1300 مخزون أصل
1400 مصروفات مدفوعة مقدماً أصل
2000 ذمم دائنة خصم
2100 مستحقات خياطين خصم
2200 ضريبة مستحقة خصم
2300 عربون زبائن / إيراد غير مكتسب خصم
3000 رأس مال المالك حقوق ملكية
3100 أرباح محتجزة حقوق ملكية
4000 إيراد غسيل إيراد
4010 إيراد سجاد إيراد
4020 إيراد خياطة إيراد
4030 إيراد مبيعات منتجات إيراد
5000 مصروف مستلزمات غسيل مصروف
5010 مصروف غسيل سجاد مصروف
5020 تكلفة خياطة مصروف
5030 تكلفة بضاعة مباعة مصروف
5040 مصروف رواتب مصروف
5045 مصروف مكافأة خياطة مصروف
5050 مصروف تالف/مفقود مصروف
5060 مصروف استرداد / إيراد مقابل مصروف

سجل المراجعة

التاريخ الإصدار المعد التغييرات
2026-05-10 1.0 محلل النظم الإصدار الأولي لمذكرات نموذج البيانات