متى تحتاج وحدة Odoo مخصصة؟ دليل قرار قبل البرمجة

ليست كل فجوة بين طريقة عمل الشركة وشاشة Odoo سبباً لبناء وحدة مخصصة. أحياناً يكون الحل حقلاً إضافياً، أو صلاحية أدق، أو مسار موافقة يمكن ضبطه دون كود. وفي أحيان أخرى تكون الفجوة نفسها جزءاً أساسياً من عمل الشركة، ولا يمكن تمثيلها بصورة آمنة وقابلة للصيانة إلا بوحدة Odoo مخصصة.

القرار الجيد لا يبدأ من سؤال: «هل يمكن برمجة هذا؟». يبدأ من سؤالين أصعب: ما المشكلة التشغيلية التي نحلها، وما أقل تغيير يحلها من دون أن يصنع عبئاً دائماً عند الاختبار والترقية؟

هذا الدليل يستخدم Odoo 19 مرجعاً تقنياً، لكن طريقة القرار صالحة للإصدارات القريبة أيضاً. عند التنفيذ يجب دائماً مراجعة توثيق الإصدار الفعلي وقاعدة البيانات المستهدفة.

سلّم القرار: الإعداد قبل التخصيص

أراجع الحاجة عبر أربع طبقات، ولا أنتقل إلى طبقة أعلى إلا إذا عجزت الطبقة السابقة عن تحقيق النتيجة المطلوبة.

المستوىمناسب عندماالتكلفة المستمرة
إعداد قياسيالتطبيق الموجود يملك الحقول والحالات والصلاحيات المطلوبةالأقل
Odoo Studioالتغيير محدود في الحقول والعروض والأتمتة البسيطة ولا يحتاج منطقاً خادمياً معقداًمتوسطة وتحتاج توثيقاً
تكامل خارجيالنظام الآخر هو مصدر الحقيقة ويجب تبادل بيانات واضحة معهتكلفة مراقبة API والأخطاء
وحدة مخصصةهناك نموذج بيانات أو قواعد عمل أو صلاحيات أو رحلة مستخدم لا توفرها الأدوات القياسية بأمانتطوير واختبار وترقية مستمرة

هذه ليست منافسة بين «بدون كود» و«كود». الهدف هو حماية العمل من تخصيص زائد، وفي الوقت نفسه عدم إجبار المستخدمين على حيل يدوية لأننا رفضنا تخصيصاً مبرراً.

متى تكون الوحدة المخصصة مبررة فعلاً؟

توجد إشارات قوية إلى أن الحاجة تتجاوز الإعداد القياسي:

  1. قاعدة العمل هي قلب النشاط. مثل طريقة خاصة لاعتماد طلبات الصيانة، أو حساب أهلية خدمة، أو ربط قطع الغيار بأمر عمل وفق حالات محددة.
  2. هناك بيانات يجب أن تعيش كنموذج واضح. تخزينها في ملاحظات أو حقول نصية يجعل البحث والتقارير والصلاحيات غير موثوقة.
  3. الصلاحية تعتمد على السجل نفسه. قد يرى الموظف سجلات فرعه فقط، بينما يرى المدير كل الفروع، ويستطيع مسؤول معين اعتماد حالة محددة دون الوصول إلى المحاسبة كلها.
  4. العملية تمتد بين تطبيقات متعددة. مثال ذلك انتقال من CRM إلى عرض سعر، ثم مخزون، ثم فاتورة، مع خطوة تشغيلية خاصة بالشركة بين هذه المراحل.
  5. التكامل يحتاج استرجاعاً ومراقبة. ليس المطلوب مجرد إرسال طلب API، بل منع التكرار، وحفظ معرف الطرف الآخر، ومعالجة الفشل، وإتاحة إعادة المحاولة.
  6. السلوك يحتاج اختباراً آلياً. إذا كان الخطأ قد يغير رصيداً أو صلاحية أو حالة مالية، فالاعتماد على اختبار يدوي عابر ليس كافياً.

أما تغيير لون زر أو إضافة حقل لا يدخل في أي قرار، فغالباً لا يحتاج وحدة أعمال جديدة. وقد يكون تعديل القالب أو Studio أو حتى حذف الطلب هو الحل الأنظف.

مثال: من طلب عام إلى أمر خدمة مضبوط

افترض شركة تستقبل طلبات صيانة، وتصدر عرض سعر، وتحجز قطعاً من المخزون، ثم تسجل تنفيذ الفني وتطلب موافقة العميل قبل الفاتورة.

يمكن أن تقدم تطبيقات CRM والمبيعات والمخزون والفوترة أجزاء كبيرة من الرحلة. الجزء المخصص المحتمل هو «أمر الخدمة» إذا كانت له بيانات وحالات وقواعد لا يغطيها التطبيق القياسي:

  • الأصل أو المركبة المرتبطة بالخدمة.
  • الأعراض والفحص والأعمال المقترحة.
  • الفني المسؤول وساعات العمل.
  • القطع المحجوزة والمستهلكة فعلياً.
  • حالة موافقة العميل مع سجل زمني.
  • منع الإغلاق قبل استكمال نقاط إلزامية.

الوحدة الجيدة لا تعيد بناء المبيعات أو المخزون. بل تربط النموذج الخاص بالتطبيقات القياسية عبر علاقات وإجراءات واضحة. كلما أعدنا اختراع جزء موجود في Odoo، زادت تكلفة الصيانة وخطر اختلاف السلوك عن التحديثات القياسية.

شكل الوحدة القابلة للصيانة

الوحدة التقليدية ليست ملف Python كبيراً. هي حزمة لها حدود مفهومة:

service_workflow/
├── __init__.py
├── __manifest__.py
├── models/
├── views/
├── security/
│   └── ir.model.access.csv
├── data/
└── tests/

يعرّف __manifest__.py اسم الوحدة واعتمادياتها وملفات البيانات والأصول. وتضع models/ منطق البيانات، بينما تفصل views/ العرض عن قواعد العمل. أما security/ فليست خطوة تكميلية؛ هي جزء من تصميم المنتج.

مثال مبسط للـ manifest:

{
    "name": "Service Workflow",
    "version": "19.0.1.0.0",
    "depends": ["sale_management", "stock"],
    "data": [
        "security/ir.model.access.csv",
        "security/service_rules.xml",
        "views/service_order_views.xml",
    ],
    "installable": True,
}

لا تكفي صحة الملف لترتيب الاعتماديات. يجب أن تكون كل dependency ضرورية فعلاً، وأن تكون معرفات XML مستقرة، وأن يتم تثبيت الوحدة على قاعدة فارغة وتجربتها على نسخة من بيانات المشروع قبل الإنتاج.

الصلاحيات ليست إخفاء قائمة

إخفاء عنصر من القائمة لا يمنع الوصول إلى النموذج عبر رابط أو استدعاء آخر. في Odoo توجد طبقات مختلفة:

  • Access rights تحدد القراءة والإنشاء والتعديل والحذف على مستوى النموذج.
  • Record rules تضيق الوصول إلى سجلات معينة وفق المستخدم أو الشركة أو الفرع.
  • Field groups تمنع مجموعات محددة من قراءة أو تعديل حقول حساسة.
  • التحقق داخل الإجراءات يحمي قواعد العمل عند الضغط على زر أو استدعاء method عامة.

ينبه توثيق Odoo إلى أن الـ record rules تعمل بعد access rights، وأن عدم وجود قاعدة مطابقة قد يبقي الوصول مسموحاً. لذلك يجب اختبار الصلاحيات بمستخدمين حقيقيين لكل دور، لا بحساب المدير فقط.

اختبار جيد لا يسأل فقط: هل يستطيع المدير اعتماد الطلب؟ بل يسأل أيضاً:

  • هل يستطيع الموظف رؤية سجل فرع آخر؟
  • هل يستطيع مستخدم portal استدعاء الإجراء مباشرة؟
  • ماذا يحدث إذا أرسل API معرف سجل لا يملكه؟
  • هل تعمل العملية في بيئة متعددة الشركات؟

الاختبارات التي تستحق كتابتها

يدعم Odoo اختبارات Python لمنطق النماذج، واختبارات JavaScript للواجهة، و Tours للمسارات المتكاملة. لا تحتاج كل وحدة إلى أكبر مجموعة ممكنة، لكن يجب تغطية المخاطر الأساسية.

للوحدة السابقة أبدأ عادةً بهذه الحالات:

  1. إنشاء أمر صالح بأقل بيانات مطلوبة.
  2. رفض الانتقال إلى حالة جديدة إذا غابت الموافقة.
  3. منع مستخدم غير مصرح له من القراءة أو الاعتماد.
  4. عدم استهلاك قطعة مرتين عند إعادة محاولة التكامل.
  5. إنشاء السجلات التابعة المتوقعة عند الإغلاق.
  6. ترقية الوحدة مع بقاء السجلات القديمة قابلة للقراءة.

التجربة اليدوية مهمة لتجربة المستخدم، لكنها لا تمنع رجوع خطأ قديم عند تعديل قاعدة عمل بعد أشهر.

الاستضافة جزء من القرار

تذكر وثائق Odoo 19 أن Odoo Online لا يدعم الوحدات المخصصة أو وحدات Odoo Apps. إذا كان المشروع يحتاج كوداً مخصصاً، فيجب اختيار بيئة تسمح به مثل Odoo.sh أو استضافة مُدارة ذاتياً، ثم تحديد مسؤولية النسخ الاحتياطي والمراقبة والتحديثات.

هذه النقطة يجب حسمها قبل التطوير. وحدة ممتازة لا تفيد إذا كانت خطة الاستضافة المختارة لا تستطيع تشغيلها.

تكلفة الوحدة ليست تكلفة إنشائها فقط

أي وحدة مخصصة تدخل دورة حياة المنتج. عند إصدار Odoo رئيسي جديد قد تتغير نماذج أو عروض أو أصول أو واجهات. لذلك يجب أن يتضمن قرار التطوير:

  • من يملك مستودع الكود؟
  • ما إصدار Odoo المدعوم؟
  • كيف يتم تثبيت الوحدة وترقيتها؟
  • ما اختبارات القبول التي تثبت سلامة العملية؟
  • من يصلحها عند تغير API خارجي؟
  • هل يوجد مسار ترحيل للبيانات عند تغير الحقول؟

توثيق Odoo لترقية قواعد البيانات المخصصة يوصي بجعل الوحدة قابلة للتثبيت على قاعدة فارغة وعلى القاعدة المُرقاة، ثم اختبار البيانات وإجراء rehearsal قبل ترقية الإنتاج. هذا سبب إضافي لرفض التعديلات السريعة غير الموثقة داخل ملفات أساسية.

قائمة قبول قبل التسليم

لا أعتبر الوحدة جاهزة لمجرد ظهور القائمة. أبحث عن دليل لكل بند:

  • تثبيت نظيف على قاعدة اختبار.
  • ترقية الوحدة المستهدفة دون استخدام -u all كاختصار خطير.
  • صلاحيات مجربة لكل دور.
  • مسار النجاح ومسارات الخطأ.
  • حالات متعددة الشركات إذا كانت ضمن النطاق.
  • رسائل مفهومة للمستخدم بدلاً من traceback غامض.
  • اختبارات آلية لقواعد العمل عالية المخاطر.
  • بيانات demo أو fixtures للاختبار فقط، لا أسرار إنتاج.
  • تعليمات تثبيت وتحديث واسترجاع.
  • موافقة UAT من صاحب العملية، لا من المطور وحده.

متى تبدأ التطوير؟

الوحدة المخصصة الصحيحة ليست أكثر كود يمكن إضافته إلى Odoo. هي أصغر امتداد واضح يحفظ ميزة العمل الخاصة بالشركة، ويحترم التطبيقات القياسية، ويضبط الصلاحيات، ويمكن اختباره وترقيته.

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

المراجع الرسمية