إعادة تصميم دورة المشتريات على حالتك الفعلية
🔄 الفلو المُحكَم للمشتريات: الحالة المطلوبة مقابل الحالية — وزرار واحد يشغّل كل الفلو
ده تحليل عميق لدورة الشراء زي ما إنت عايزها بالظبط (طلب → أمر → إذن استلام مبدئي → جودة تحط الكميات والصلاحية والباتش → اعتماد → إذن إضافة بموافقة أمين المخازن → فاتورة بالمستلم فعلًا مع تسوية الفروق)، مقارنة بما يفعله الكود الآن، وتحديد ٧ مشاكل بجذورها في الكود، ثم الحل: إعداد واحد يفعّل الدورة كلها من غير ما تلمس ٢٠ سيتنج، مع توزيع صلاحيات الموافقة والمعالجة المحاسبية للفروق حسب المعايير.
١ الفلو المطلوب — زي ما إنت وصفته بالظبط
كل خطوة مكتوبة كأنها لمستخدم عادي: مين بيعملها + بتعمل إيه + الحالة اللي بتوصلها.
🛒 المشتريات
🏬 أمين المخازن
🔬 الجودة
🧮 الحسابات
⚙️ النظام تلقائيًا
3
المشتريات
اعتماد أمر الشراءياخد موافقته ويتبعت للمورّد. دلوقتي بس يظهر زر «إنشاء إذن استلام».
4
أمين المخازن
إذن استلام مبدئي (GRN)على أمر الشراء، بإدخال الكميات اللي وصلت فعلًا.
إذون الاستلام ↗
5
النظام
قفل: إذن استلام واحد فعّالأمر الشراء يبان عليه «تم إنشاء إذن استلام»، ومايسمحش بإذن استلام تاني طول ما في واحد شغّال.
6
الجودة
فحص الجودةلو رفضت جزء → الإذن ياخد الكميات الجديدة اللي الجودة وافقت عليها.
7
الجودة
الصلاحية + رقم الباتشالجودة بتحط تاريخ الصلاحية (مهم جدًا) ورقم الباتش على كل منتج.
8
المشتريات
اعتماد إذن الاستلامبكميات الجودة — والكمية تتقفل، مفيش تعديل تاني عليها خلاص.
9
النظام
إذن إضافة (مربوط)يتولّد تلقائيًا بالكمية المقفولة، مستنّي موافقة أمين المخازن — ومايتعملش إذن إضافة جديد بدالُه.
10
أمين المخازن
اعتماد إذن الإضافة→ الرصيد يدخل المخزن فعلًا، وأمر الشراء يبان عليه «تمت الإضافة».
إذون الإضافة ↗
11
الحسابات
فاتورة الشراءبالكمية اللي المخزن
استلمها فعلًا (كميات الجودة)، مع تسوية فرق السعر محاسبيًا.
الفواتير ↗
12
النظام
فاتورة واحدة + تتبّع كاملفاتورة واحدة فعّالة لكل دورة، وبتحمل حالة كل المراحل اللي مرّت بيها (PR→PO→استلام→إضافة→فاتورة).
٢ الوضع الحالي مقابل المطلوب — ٧ مشاكل بجذورها
كل مشكلة: إيه اللي بيحصل دلوقتي، إيه المفروض يحصل، وفين جذرها في الكود (متأكَّد بقراءة مباشرة).
Aإذن الإضافة بيطلع فاضي 🔴 (باج مؤكّد)
دلوقتي
في وضع الجودة تقدر تعتمد إذن استلام وهو Draft (الجودة ما جرتش) — فالكمية المقبولة = فاضية → النظام يتخطّى كل صنف → إذن إضافة يتولد فاضي بلا حركة مخزون.
المفروض
في وضع الجودة، الاعتماد مايتمّش غير بعد فحص الجودة، وبكميات الجودة — ومستحيل يتولّد إذن فاضي أبدًا.
الجذر
PurchaseGrnStatus::canApprove() بيسمح بـDraft؛ وبانّاء الإذن فيه if (stockQty <= 0) continue;.
الحل
اعتماد مشروط بالوضع: في الجودة → QualityApproved بس. + قاطع أمان: لو مفيش أي صنف بكمية > 0 → إلغاء العملية برسالة، بدل إذن فاضي.
Bالجودة مش بتسجّل الصلاحية والباتش 🔴
دلوقتي
شاشة الجودة بتسجّل الكميات المقبولة/المرفوضة بس. الصلاحية والباتش بيتكتبوا وقت إنشاء الإذن (من المستلِم)، والجودة مش بتقدر تعدّلهم.
المفروض
الجودة هي اللي بتحط/تصحّح الصلاحية والباتش لكل منتج، وفي الوضع المُحكَم الصلاحية إلزامية للأصناف اللي بصلاحية قبل القبول.
الجذر
تحقّق qualityCheck() بيقبل accepted/rejected_quantity فقط.
الحل
إضافة batch_number + expiry_date لشاشة الجودة (الأعمدة موجودة أصلًا) + إلزامها في الوضع المُحكَم.
Cالفاتورة بتتعمل بالكمية المطلوبة مش المستلمة 🔴
دلوقتي
«إنشاء فاتورة من أمر الشراء» بيملأ الكمية = المطلوب − المفوتر، ومابيبصّش للمستلَم/المقبول من الجودة.
المفروض
الفاتورة تتملأ بالكمية اللي المخزن استلمها فعلًا (كميات الجودة)، والمحاسب يعدّل السعر بس ليطابق فاتورة المورّد.
الجذر
remainingBillQuantity() = مطلوب − مفوتر (مش مستلم). مفيش createFromGrn.
الحل
تعبئة من المقبول-المستلم − المفوتر، + مسار createFromGrn يبني الفاتورة من إذن الاستلام مباشرة.
Dالصلاحية/الباتش بتضيع من المخزون للأصناف بالباتش 🔴 (معماري)
دلوقتي
الصلاحية والباتش بيتنسخوا لسطر إذن الإضافة، لكن لما الرصيد يدخل المخزون مابيتخزّنوش مع الرصيد — مفيش جدول lot/batch للمخزون. بيتحفظوا للأصناف المسلسلة (serial) بس.
المفروض
تتبّع الصلاحية على مستوى المخزون عشان تقارير الانتهاء والصرف بالأقدم-انتهاءً (FEFO).
الجذر
StockService::increaseStock بيكتب أرصدة/طبقات تكلفة/حركات بدون باتش/صلاحية؛ مفيش نموذج دفعات للمخزون.
الحل
مرحلي: تخزين الباتش/الصلاحية على حركات المخزون (نَسَب + تقارير انتهاء). التتبّع الكامل FEFO = مشروع منفصل (تفاصيل في القسم ⑦).
Eالفاتورة مش قابلة للتتبّع عبر السلسلة 🔴
دلوقتي
الفاتورة مربوطة بأمر الشراء بس. مفيش ربط بإذن الاستلام أو الإضافة، ومفيش سجل حالات.
المفروض
من الفاتورة تقدر تشوف السلسلة كاملة: طلب → أمر → استلام → إضافة → فاتورة، مع مين اعتمد وامتى.
الجذر
مفيش grn_id/inventory_receipt_id على الفاتورة، ومفيش status_history/سجل نشاط على مستندات الشراء.
الحل
عمود purchase_grn_id على الفاتورة (يقفل كمان «فاتورة واحدة لكل إذن») + نقطة API trail بتمشي السلسلة + مكوّن Timeline في الواجهة.
Fمفيش قفل يمنع مستند مكرّر 🔴 (نقطة الخطر اللي حسّيت بيها)
دلوقتي
مفيش أي قفل يمنع إذن استلام تاني أو فاتورة تانية على نفس أمر الشراء. الموجود بس سقف كمية — ومقفول افتراضيًا. وكمان ممكن يتعمل إذن إضافة مستقل من المخازن يتخطّى حوكمة الشراء.
المفروض
دورة استلام واحدة مفتوحة لكل أمر شراء في المرة (إذن استلام واحد فعّال)؛ لما إذن الإضافة يتعتمد، الدورة تتقفل ويُسمح بالتالية للكمية المتبقية. وفاتورة واحدة لكل إذن استلام.
الجذر
مفيش حارس في الطلب/الكنترولر/قاعدة البيانات؛ الأقفال الكمية Off افتراضيًا.
الحل
حارس «دورة واحدة مفتوحة» بـ٣ طبقات (رسالة ودّية في الطلب / قفل صف أمر الشراء داخل المعاملة = الحاسم / فهرس فريد بعمود مولَّد كخط دفاع). + purchase_grn_id فريد على الفاتورة. + الإذون المستقلة تتقيّد بصلاحية منفصلة.
Gإذن الإضافة بيتعمله اعتماد تلقائي — مفيش موافقة أمين مخازن منفصلة 🔴
دلوقتي
اعتماد إذن الاستلام بيعمل اعتماد تلقائي فوري لإذن الإضافة ويدخّل الرصيد في خطوة واحدة — مفيش بوابة موافقة لأمين المخازن.
المفروض
اعتماد إذن الاستلام يُنشئ إذن الإضافة كمسودة، وأمين المخازن يعتمده منفصل → ساعتها بس الرصيد يدخل (خطوتك ٩ و١٠).
الجذر
approve() بيستدعي ApproveReceipt فورًا جوّه اعتماد الـGRN.
الحل
في الوضع المُحكَم: يُنشأ الإذن كمسودة بس؛ الاعتماد يبقى بصلاحية inventory.receipts.approve لأمين المخازن.
٤ خريطة الإصلاح — بالمراحل (كل مرحلة تُختبر لوحدها)
P0 — مكاسب سريعة (بلا مخاطرة تصميم)أيام
إصلاح باج «الإذن الفاضي» (A) بطبقتين + قاطع أمان · فصل صلاحية الجودة (D6) · شاشة الجودة تسجّل الصلاحية/الباتش (B) · أمر تنظيف للإذون الفاضية القديمة. → يخلّي وضع الجودة آمن فعلًا للعرض.
P1 — الزرار الواحد~أسبوع
إعداد procurement_mode + مُحلِّل السياسة (ProcurementPolicy) + نقل مواضع القراءة إليه + اختبار معماري يمنع القراءة المباشرة + التحقق من الحسابات وفحص المستندات المفتوحة + قفل شاشة الإعدادات في الوضع المُحكَم. → عند P1 الدورة شبه كاملة لأنها بتركّب إعدادات موجودة.
P2 — أقفال الوضع المُحكَم + الفوترة١–٢ أسبوع
حارس «دورة استلام واحدة» بـ٣ طبقات (F) · purchase_grn_id فريد على الفاتورة · createFromGrn + تعبئة بالمستلَم (C) · لوحة تسوية الفروق قبل الترحيل · نقطة trail + Timeline (E) · سياسة الإذون المستقلة · موافقة أمين المخازن المنفصلة (G) · شارات حالة على أمر الشراء («تم الاستلام»/«تمت الإضافة»). → لأن الزرار «محسوب»، كل عميل بياخد الأقفال بمجرد التحديث.
P3 — حفظ الصلاحية على الحركاتأيام–أسبوع
تخزين الباتش/الصلاحية على حركات المخزون + تقرير «دفعات مستلمة قرب انتهائها». → قيمة ظاهرة للقطاع الصحي، مستقلة.
P4 — تتبّع الدفعات الكامل FEFOمشروع كبير منفصل
أرصدة على مستوى الدفعة + صرف بالأقدم-انتهاءً + منع الصرف المنتهي — يمسّ المبيعات/POS/الإنتاج/المعمل. خارج هذه الخطة بموضوع KB خاص. أساسه بيتبني من حركات P3.
٥ توزيع صلاحيات الموافقة — مين يعتمد كل خطوة
حاليًا فحص الجودة + اعتماد الاستلام على صلاحية واحدة. الحل: نفصلهم، بإضافة صلاحيتين جديدتين بس. الجدول ده هو الفصل نفسه (مفيش سيتنج «فصل مهام» — الجدول يكفي).
| الخطوة (الموافقة) | الصلاحية | مين يمسكها |
| اعتماد أمر الشراء | purchases.orders.approve (موجودة) | مدير المشتريات |
| إنشاء إذن الاستلام + الإرسال للجودة | purchases.grns.create (موجودة — المستلِم نفسه يرسل) | أمين مخازن (مُستلِم) |
| فحص الجودة (كميات + صلاحية + باتش) | purchases.grns.quality_check (جديدة) | مفتّش الجودة — ومايمسكش grns.approve |
| اعتماد إذن الاستلام (يقفل الكمية ويولّد الإضافة) | purchases.grns.approve (تتضيّق) | مشرف الاستلام/المشتريات |
| اعتماد إذن الإضافة (الرصيد يدخل) | inventory.receipts.approve (موجودة) | أمين المخازن — وحده |
| إنشاء + ترحيل الفاتورة | purchases.bills.* (موجودة) | المحاسب |
| إذن إضافة يدوي/مستقل (في الوضع المُحكَم) | inventory.receipts.create_manual (جديدة) | مدير المخزون فقط |
ترقية غير كاسرة: نزرع صلاحية
quality_check ونديها لكل مين عنده حاليًا
grns.approve (فمحدش يخسر قدرة عند التحديث)، وبعدين الأدمن يضيّق حسب الجدول. تفاصيل إنشاء الأدوار/اليوزرز في
ملف الأدوار — عبر
/core/roles +
/core/users.
٦ تسوية الفروق محاسبيًا — حسب المعايير
الآلية المحاسبية الصح موجودة ومختبرة (GR/IR + انحراف الأسعار). المطلوب توجيه كل الفروق خلالها + إظهارها.
| نوع الفرق | المعالجة (حسب المعيار) |
| فرق كمية (المقبول < المطلوب) | لا يحتاج أي قيد. الـGR/IR اتسجّل عند الاستلام بالكمية المقبولة، والفاتورة مسقوفة بالمقبول، والباقي من أمر الشراء بيتقفل ناقص. (معالجة GR/IR القياسية.) |
| فرق سعر (سعر الفاتورة ≠ سعر أمر الشراء) | قيد انحراف أسعار الشراء (PPV) عند الفاتورة: مدين GR/IR بسعر الأمر × الكمية، مدين/دائن PPV للفرق، دائن الموردين بمبلغ الفاتورة. متوافق مع IAS 2. |
| المورّد فوتر أكتر من المقبول | المطابقة الثلاثية بتمنعها → تدفعها لمسار إشعار مدين/خصم برّه الفاتورة (الافتراضي الصح؛ حساب «مطالبات مورّد» تحسين لاحق). |
الميزة اللي بتفرق مع المستخدم: «لوحة تسوية» قبل ترحيل الفاتورة — لكل سطر: المطلوب / المستلَم / المقبول / المفوتر، وسعر الأمر مقابل سعر الفاتورة، ومبلغ الانحراف المحسوب، والحسابات اللي هتتأثّر بالظبط. المحاسبة شغّالة أصلًا — الميزة إننا نخليها ظاهرة قبل الترحيل.
٧ الصلاحية والباتش — الحقيقة بوضوح (مهم)
عشان ما يحصلش سوء فهم، ده الخط الفاصل بالظبط:
| القدرة | دلوقتي | بعد P0+P3 | يحتاج P4 (مشروع منفصل) |
| الجودة تحط صلاحية + باتش لكل منتج | ✗ | ✓ (P0) | — |
| حفظ الصلاحية/الباتش على حركة الدخول (نَسَب) | ✗ | ✓ (P3) | — |
| تقرير «دفعات مستلمة قرب انتهائها» | ✗ | ✓ (P3) | — |
| رصيد على مستوى الدفعة (كام في كل دفعة) | ✗ | ✗ | ✓ |
| الصرف بالأقدم انتهاءً (FEFO) | ✗ | ✗ | ✓ |
| منع صرف/بيع صنف منتهي | ✗ | ✗ | ✓ |
باختصار: بعد P0+P3 الصلاحية تتسجّل وتتتبّع وتتقرّر — لكن مش بتتفرض عند الصرف. الفرض عند البيع/الصرف (FEFO ومنع المنتهي) محتاج نظام دفعات كامل (P4) بيمسّ المبيعات وPOS والإنتاج والمعمل، فهو مشروع لوحده بموضوع KB خاص، وأساسه بيتبني من حركات P3.
٨ الخلاصة والخطوة القادمة
- الفلو اللي عايزه دقيق وسليم ومطابق لأفضل الممارسات — والنظام واصل ٧٥٪ منه (المستندات والحالات موجودة، والمحاسبة GR/IR جاهزة).
- ٧ فجوات بتفصل الوضع الحالي عن المطلوب — أخطرها باج الإذن الفاضي (A) وغياب الأقفال (F) والاعتماد التلقائي (G).
- زرار واحد («نمط الشراء = مُحكَم») يفعّل الدورة كلها بأمان، من غير ما تلمس ٢٠ سيتنج، ومن غير ما يكسر أي عميل حالي.
- الإصلاح على ٤ مراحل؛ P0 مكاسب سريعة تصلح الباجات، وP1 الزرار، وP2 الأقفال والفوترة، وP3 الصلاحية، وP4 (FEFO) منفصل.
اختار الخطوة القادمة:
- (أ) أبدأ P0 فورًا (إصلاح باج الإذن الفاضي + فصل صلاحية الجودة + الجودة تسجّل الصلاحية/الباتش) — ده اللي بيوجعك دلوقتي، بلا مخاطرة.
- (ب) أكتب خطة تنفيذ تفصيلية (مهام صغيرة قابلة للاختبار) لكل المراحل قبل ما أكتب أي كود.
- (ج) نراجع التصميم ده سوا الأول ونعدّل أي حاجة، وبعدين ننفّذ.
هذا المستند مبني على قراءة مباشرة للكود (PurchaseGrnController · PurchaseBillController · PurchaseOrder · StockService · SettingDefinitionSeeder · صلاحيات الوسطاء) — كل مشكلة من الـ٧ موثّقة باقتباس ملف/سطر (تحقّق مزدوج بوكيلين مستقلين) — + مراجعة تصميم من Fable 5. (تعذّر تشغيل Codex كمدقّق إضافي لقيد sandbox في الاستضافة؛ فالتحقّق تمّ بالقراءة المباشرة بدلًا منه.) يكمّل التحليل الفني ودليل المستخدم وملف الأدوار.