الفكرة العامة
موديول بيغطي دورة التدريب كاملة من التخطيط السنوي لحد تسجيل التدريب في ملف الموظف:
- خطة تدريب سنوية (Annual Training Plan).
- أجندة تفصيلية لكل تدريب (Training Agenda).
- تسجيل تلقائي للتدريب في ملف الموظف (Training Card).
- امتحان وتقييم لكل موظف حضر.
1) الخطة السنوية
⟸
اعتماد
⟸
تنبيه قبل التدريب بشهر
⟸
2) الأجندة
⟸
اعتماد
⟸
3) الحضور
⟸
4) الامتحان
⟸
5) كارت التدريب
الموديول مش بيبدأ من صفر: الأنشطة (training_activities) وكارت تدريب الموظف (employee_trainings) وموديول الامتحانات وبنية الإشعارات والـ cron كلها موجودة. اللي ناقص هو الخطة والأجندة والحضور والربط بينهم (التفاصيل في قسم "الموجود حاليًا").
1) إضافة خطة تدريب سنوية (Add Annual Training Plan)
| الحقل | الشرح |
| Topic | الموضوع: Activity / Sub activity — اختيار واحد من شجرة training_activities (النشاط ثم النشاط الفرعي) |
| Month | الشهر المخطط للتدريب (مع السنة) |
| Expected No. of days | عدد الأيام المتوقع للتدريب |
| Branch | Multi select — الفروع (Branch sites) اللي هتتدرب |
| Involved team | Multi select — الفرق المعنية (Department / Unit) |
يحتاج اعتماد: أول ما الخطة تتسجل بتتبعت للمعتمد، ويوصله إشعار (Approval Notification). بعد الاعتماد بتبقى الخطة مقفولة زي باقي الموديولات (Approve-then-lock).
تنبيه تجهيز الأجندة
قبل التدريب بشهر يوصل إشعار لمسؤول التدريب: "جهّز أجندة تدريب كذا". لازم الخطة تكون معتمدة، ولسه مفيش أجندة اتعملت ليها. بيتفحص يوميًا بـ cron زي باقي التنبيهات الزمنية في النظام.
الخطة فيها شهر بس مش تاريخ يوم، فـ "قبل شهر" بيتحسب من أول يوم في الشهر المخطط (مثلًا تدريب في مارس ← التنبيه بتاع أول فبراير). ده افتراض محتاج تأكيد.
2) إضافة أجندة تدريب (Add Training Agenda)
| الحقل | الشرح |
| Topic | Activity / Sub activity — يتعبى تلقائي لو الأجندة اتعملت من خطة، ويتعدّل لو لزم |
| Branch | الفرع (Branch site) اللي هيتعقد فيه التدريب |
| Involved team | Multi select — Department / Unit |
| From | تاريخ ووقت البداية (Date & Time) |
| To | تاريخ ووقت النهاية (Date & Time) |
| List of involved staff | قائمة الموظفين بتتجاب تلقائيًا حسب الفرع والقسم/الوحدة المختارين، ويقدر المستخدم يشيل أو يضيف |
يحتاج اعتماد: برضه بإشعار للمعتمد، والأجندة المعتمدة هي اللي بيتفتح لها الحضور.
3) الحضور والامتحان (Attendance & Post Exam)
تحضير الموظفين (Attendance check)
⟸
الحاضرين بس
⟸
Post exam يتبعت لكل الحاضرين
⟸
التدريب يتسجل في الكارت
- Attendance check: لكل موظف في قائمة الأجندة: حاضر / غايب، ومين اللي سجّل ووقته.
- Post exam: بعد تسجيل الحضور بيتبعت الامتحان لكل اللي حضروا (مش لكل المدعوين). بيتستخدم موديول الامتحانات الحالي (إنشاء محاولة بحالة
waiting وإشعار للموظف).
- التسجيل التلقائي: بمجرد تسجيل الحضور، التدريب بيتسجل لوحده في Training Card الخاص بالموظف، وبيترفق معاه نتيجة الامتحان أول ما الموظف يخلصه.
4) التسجيل التلقائي في كارت الموظف (Training Card)
الكارت هو جدول employee_trainings الموجود فعلًا (بيتملا يدويًا من شاشة الموظف). الجديد إنه يتملا أوتوماتيك من الأجندة:
| حقل الكارت | بيتعبى من |
employee_id | الموظف الحاضر |
training_activity_id / sub_training_activity_id | موضوع الأجندة (Activity / Sub activity) |
from_date / to_date | تاريخ From / To في الأجندة (الكارت بيخزن تاريخ بدون وقت) |
training_provider_id | فاضي (الأجندة مفيهاش مزوّد تدريب إلا لو العميل طلب) |
training_agenda_id جديد | الأجندة اللي اتولد منها السجل |
exam_attempt_id جديد | محاولة الامتحان اللي اتبعتت للموظف، ومنها بتتقرا الدرجة ونجح/رسب |
evaluation / evaluated_by | فاضيين: التقييم بيتسجل يدويًا (محتاج تحديد المقصود بـ "Evaluation for each staff") |
- نتيجة الامتحان بتتقرا من محاولة الامتحان نفسها مش بتتنسخ في الكارت (نفس مبدأ "احسب ولا تخزّن" في باقي الموديولات)، فلو الدرجة اتعدّلت الكارت يعرض الجديد.
- السجل بيتولد مرة واحدة لكل موظف في كل أجندة (مفتاح فريد)، فتكرار تسجيل الحضور مبيعملش تكرار.
- لو الحضور اتلغى والموظف لسه ماخدش الامتحان: السجل والمحاولة بيتشالوا. ولو خد الامتحان: التغيير بيتمنع.
سجل الخطط وسجل الأجندات (Logs)
سجل الخطط:
TopicMonthDaysBranchesTeamsStatus
سجل الأجندات:
TopicBranchFromToAttendeesExamStatus
| الحالة (Status) | للخطة | للأجندة |
| Draft | مسودة | مسودة |
| Pending approval | مُرسلة للاعتماد | مُرسلة للاعتماد |
| Approved | معتمدة (تفتح الأجندة وتشغّل تنبيه الشهر) | معتمدة (يفتح الحضور) |
| Rejected | مرفوضة (ترجع مسودة) | مرفوضة (ترجع مسودة) |
| Completed | — | تم تسجيل الحضور (والتدريب اتسجل في الكروت) |
الإشعارات (Notifications)
| الحدث | المستلم | التوقيت |
| خطة جديدة محتاجة اعتماد | المعتمدون (صلاحية approve_training_plans) | فورًا عند الإرسال |
| نتيجة اعتماد/رفض الخطة | اللي سجّل الخطة | فورًا |
| جهّز الأجندة (قبل التدريب بشهر) | مسؤول التدريب في الفرع | يوميًا (cron) |
| أجندة جديدة محتاجة اعتماد | المعتمدون (صلاحية approve_training_agendas) | فورًا عند الإرسال |
| نتيجة اعتماد/رفض الأجندة | اللي سجّل الأجندة | فورًا |
| الامتحان متاح | الموظفون الحاضرون | بعد تسجيل الحضور (الإشعار الموجود InformEmployeeExamNotification) |
كل إشعار جديد يتبع بنية النظام: كلاس في app/Notifications + صف في notifications_types + صلاحية للمستلمين + ربط المستلم بالفرع. ومفاتيح اللغة الجديدة لازم تتسجل في جدول الترجمات (ltm_translations) كمان عشان ما تضيعش عند Publish.
جداول قاعدة البيانات (6 جداول جديدة + تعديل جدول)
| الجدول | وظيفته |
training_plans | بند في الخطة السنوية: النشاط والنشاط الفرعي، السنة والشهر، عدد الأيام، الحالة، المعتمد وتاريخ الاعتماد |
training_plan_branches | فروع البند (Branch sites) — كثير لكثير |
training_plan_teams | الفرق المعنية: department_id + unit_id اختياري |
training_agendas | الأجندة: الخطة (اختياري)، النشاط والنشاط الفرعي، الفرع، من/إلى (datetime)، الامتحان، الحالة، المعتمد |
training_agenda_teams | الفرق المعنية بالأجندة (Department / Unit) |
training_agenda_attendees | الموظفون المدعوون + الحضور (حاضر/غايب/لم يُسجَّل) + مين سجّل ووقته + ربط بسجل الكارت ومحاولة الامتحان. مفتاح فريد (أجندة، موظف) |
employee_trainings تعديل | إضافة training_agenda_id وexam_attempt_id (اختياريين) |
training_activities ──< training_plans ──< training_plan_branches >── branch_sites
│ └──< training_plan_teams >── departments / units
│
└──< training_agendas ──< training_agenda_teams >── departments / units
│ └── exams
│
└──< training_agenda_attendees >── employees
│ │
│ └── exam_attempts
└── employee_trainings (كارت التدريب)
علاقات الحذف (Foreign Keys)
| العلاقة | عند الحذف | السبب |
| فروع/فرق الخطة والأجندة ← الخطة/الأجندة | CASCADE | تابعة للأب (pivots) |
| الحضور ← الأجندة | CASCADE | الحضور جزء من الأجندة |
| الحضور ← الموظف | CASCADE | بيانات الموظف نفسه |
| الأجندة ← الخطة، الامتحان | SET NULL | الأجندة تفضل لو الخطة أو الامتحان اتحذف |
| الكارت ← الأجندة، محاولة الامتحان | SET NULL | سجل التدريب في ملف الموظف ميضيعش |
| الخطة/الأجندة ← النشاط | RESTRICT | ممنوع حذف نشاط عليه خطط (مع رسالة واضحة) |
| المنشئ والمعتمد ← admins | SET NULL | السجل أهم من الشخص |
الصلاحيات (Permissions)
| الصلاحية | الاستخدام |
show / create / update / delete _training_plans | الخطة السنوية |
approve_training_plans | اعتماد الخطة (وتستقبل الإشعار) |
show / create / update / delete _training_agendas | الأجندات |
approve_training_agendas | اعتماد الأجندة (وتستقبل الإشعار) |
record_training_attendance | تسجيل الحضور وإرسال الامتحان |
الموجود حاليًا في النظام (نتيجة الفحص)
| المطلوب | الحالة | الموجود |
| أنشطة التدريب (Activity / Sub activity) | ✅ موجود | training_activities فيه parent_id، ومستخدم في الكارت |
| كارت تدريب الموظف | 🟡 جزئي | employee_trainings بيتملا يدويًا فقط، ومفيهوش ربط بأجندة ولا بامتحان |
| الخطة السنوية | ❌ ناقص | مفيش جدول ولا شاشة |
| الأجندة وقائمة الموظفين | ❌ ناقص | الموظفون ممكن يتجابوا من الفرع والقسم والوحدة (موجودين في employees) |
| اعتماد + إشعار | ❌ ناقص | نمط الاعتماد (Drill والمستندات) وبنية الإشعارات جاهزين للاستخدام |
| تنبيه قبل شهر | ❌ ناقص | مفيش cron للتدريب (نمط الـ cron موجود في Kernel.php) |
| الحضور | ❌ ناقص | — |
| إرسال الامتحان للحاضرين | 🟡 جزئي | ExamController@exams_assigns بينشئ محاولات waiting ويبعت إشعار لموظفين مختارين، بس مش مربوط بحدث تدريب |
ملاحظات على الموجود (تحتاج إصلاح)
- النشاط رقم 16 ("sub Skills") أبوه هو نفسه (
parent_id = id): مخفي من الشجرة ولا يظهر لأي مستخدم. يتصلح قبل الاعتماد على الشجرة في الخطة.
employee_trainings.sub_training_activity_id من غير Foreign Key (مفيش بيانات يتيمة حاليًا) — يتضاف SET NULL.
- FK
training_activities.parent_id هو SET NULL: حذف نشاط رئيسي بيحوّل أنشطته الفرعية لأنشطة رئيسية. غالبًا المطلوب منع الحذف أو حذفها معاه.
- فلتر الموظفين في شاشة تعيين الامتحانات (
getEmployees) بيدعم الفرع والمسمى الوظيفي والقسم ومش بيدعم الوحدة (Unit)، والمطلوب هنا قسم/وحدة.
- migration جدول
exam_scopes متسجل إنه اتنفذ والجدول مش موجود ومفيش كود بيستخدمه (migration ميت).
أسئلة مفتوحة للعميل
| # | السؤال | ليه مهم |
| 1 | الخطة السنوية: كل "إضافة خطة" بند واحد (موضوع واحد)، ولا خطة بعنوان وسنة وتحتها بنود؟ | بيحدد عدد الجداول وطريقة الاعتماد (للبند ولا للخطة كلها) |
| 2 | الأجندة بتتولد من بند في الخطة، ولا ممكن تتعمل مستقلة؟ وبند واحد ممكن يطلع منه أكتر من أجندة (فرع لكل أجندة)؟ | علاقة الخطة بالأجندة، وعدد الفروع في الأجندة (الملف بيقول Branch واحد) |
| 3 | "أجندة تفصيلية": هي الحدث نفسه، ولا فيها جلسات ومواعيد ومدربين؟ | الحقول المذكورة هي بيانات الحدث بس، فلو فيه جلسات يتضاف جدول |
| 4 | مين يعتمد الخطة؟ ومين يعتمد الأجندة؟ مرحلة واحدة ولا أكتر؟ وبعد الاعتماد بتتقفل؟ | الصلاحيات والإشعارات وقفل التعديل |
| 5 | "قبل التدريب بشهر": بيتحسب من أول الشهر المخطط؟ ومين بيستلم التنبيه؟ | الخطة فيها شهر مش يوم |
| 6 | الحضور: مرة واحدة للحدث كله، ولا لكل يوم لو التدريب أكتر من يوم؟ ومين بيسجّله؟ | جدول الحضور ممكن يبقى لكل (موظف × يوم) |
| 7 | أي امتحان لكل تدريب؟ بيتحدد في الأجندة؟ ولو الموظف رسب؟ | ربط الأجندة بالامتحان وأثر النتيجة على الكارت |
| 8 | "Evaluation for each staff": تقييم من المدرب/المدير بنص أو درجة، ولا مجرد نتيجة الامتحان؟ | حقل evaluation الحالي في الكارت نص حر |
| 9 | هل الأجندة محتاجة مزوّد تدريب (Training Provider) أو مدرب؟ | الكارت فيه training_provider_id |
نقاط تصميم مهمة
- مفيش تكرار بيانات: بيانات التدريب بتتخزن مرة واحدة في الأجندة، والكارت بيشاور عليها بـ ID بس. نتيجة الامتحان بتتقرا من محاولة الامتحان.
- إعادة استخدام الموجود: أنشطة التدريب، كارت الموظف، تعيين الامتحانات والإشعار بتاعها، والـ cron والإشعارات الحالية. لا يوجد موديول امتحانات جديد.
- قائمة الموظفين بتتولد وقت إنشاء الأجندة (snapshot): لو موظف اتنقل قسم بعدين، الأجندة القديمة تفضل زي ما كانت.
- المراحل المقترحة للتنفيذ: (1) الخطة + الاعتماد، (2) الأجندة + الموظفين + الاعتماد + تنبيه الشهر، (3) الحضور + إرسال الامتحان + التسجيل في الكارت.