مقدمة
في نظام Odoo تُعبر النماذج عن كيفية تنظيم البيانات وتخزينها في قاعدة البيانات. كل سجل عمل تتعامل معه — من عروض الأسعار إلى الفواتير وقوائم العملاء — يتم تمثيله داخل نموذج محدد.
فهم النماذج أمر لا غنى عنه لمطوري Odoo والاستشاريين الوظيفيين. هذه النماذج تشكّل العمود الفقري لهندسة البيانات في النظام، فهي تحدد الحقول، والعلاقات، والقواعد التي تطبّق منطق العمل.
التركيز هنا على نموذج مهم في وحدة المبيعات: sale.order.line. سواء كنت تطور إضافات مخصصة، توصل النظام بأنظمة خارجية أو تضبط سياسات التسعير، ستصادف هذا النموذج كثيراً.
ما هو نموذج sale.order.line
يمثل نموذج sale.order.line كل بند مفرد يظهر في عرض سعر أو أمر بيع داخل Odoo. كل سطر عادةً يصف قطعة أو خدمة مع الكمية، السعر، والضرائب المرتبطة.
هذا النموذج جزء من تطبيق المبيعات (sale) ويرث بعض السلوكيات المفيدة مثل mixin التحليلي لتتبع تكاليف المشاريع وربط إدخالات الوقت. عند إضافة منتج إلى عرض السعر تضاف سطرًا جديدًا في sale.order.line.
التعريف الأساسي للنموذج موجود في وحدة sale، بينما وحدات أخرى تضيف امتدادات عبر وراثة النماذج في Odoo. فمثلاً sale_stock يضيف حقول مرتبطة بالتسليم، وsale_margin يضيف حسابات هامش الربح — كل إضافة تُكمّل البنية الأساسية دون تكرارها.
الحقول الرئيسة في النموذج
فيما يلي الحقول الأهم في sale.order.line التي تحتاج معرفتها لتتعامل مع عروض الأسعار وأوامر البيع بشكل عملي.
1. order_id
النوع: Many2one (sale.order). إلزامي. يشير إلى أمر البيع الأب. يربط كل سطر بأمره، وعادةً تُحذف الأسطر مع حذف الأمر (cascade).
2. sequence
النوع: Integer. القيمة الافتراضية 10. يتحكم بترتيب عرض الأسطر في الفاتورة أو العرض؛ يستخدم لترتيب الأقسام والملاحظات وأسطر المنتجات.
3. company_id
النوع: Many2one (res.company). مرتبط من order_id. يُستخدم لقواعد الشركات المتعددة والتحكم بالوصول.
4. currency_id
النوع: Many2one (res.currency). مرتبط من order_id. يُستخدم في الحقول النقدية لضمان العملة الصحيحة في التسعير.
5. order_partner_id
النوع: Many2one (res.partner). مرتبط من order_id. العميل؛ تُبنى عليه قواعد السجل الضريبي وقوائم الأسعار.
6. salesman_id
النوع: Many2one (res.users). مرتبط من order_id. مندوب المبيعات — يؤثر على العمولات والتقارير.
7. state
النوع: Selection. مرتبط من order_id. حالة الأمر (مثل draft, sale, done, cancel) وتحدّد أي الحقول قابلة للتعديل.
8. display_type
النوع: Selection. قيمته إما line_section أو line_note. عندما تُعيّن، يصبح السطر عنوان قسم أو ملاحظة وليس سطر منتج؛ إذ تبقى حقول المنتج فارغة.
9. is_downpayment
النوع: Boolean. يبيّن أن السطر عبارة عن دفعة مقدمة تُفوَتَر بصورة منفصلة.
10. is_expense
النوع: Boolean. صحيح عند ورود السطر من مصروف أو فاتورة مورد، ويُستخدم لتتبّع تكاليف المشروع.
11. product_id
النوع: Many2one (product.product). المنتج المُباع. النطاق يقتصر على المنتجات المبيعة؛ مطلوب للأسطر التي تمثل منتجات.
12. product_template_id
النوع: Many2one (product.template). محسوب من product_id. يُستخدم في مُكوّن إعداد المنتج لاختيار الصيغة/النسخة.
13. name
النوع: Text. وصف السطر. يُبنى عادةً من بيانات المنتج وخصائص مخصصة ويشمل تفاصيل الصنف عند وجود متغيرات.
14. product_uom_qty
النوع: Float. إلزامي. كمية الطلب؛ القيمة الافتراضية 1.0 ويمكن أن تتأثر بالتغليف.
15. product_uom
النوع: Many2one (uom.uom). وحدة القياس. تُعرّف افتراضيًا من إعدادات المنتج وتؤثر على التسعير والكمية.
16. tax_id
النوع: Many2many (account.tax). الضرائب المطبقة على السطر؛ تُحسب عادةً بناءً على المنتج والمركز الضريبي.
17. price_unit
النوع: Float. إلزامي. سعر الوحدة اعتمادًا على وحدة القياس. يُحتسب من قائمة الأسعار أو من إعداد المنتج ويمكن تغييره يدويًا.
18. discount
النوع: Float. نسبة الخصم المطبقة على سعر الوحدة قبل الضريبة.
19. price_subtotal
النوع: Monetary. المجموع قبل الضريبة. محسوب من الكمية، وسعر الوحدة، والخصم.
20. price_tax
النوع: Float. مقدار الضريبة على السطر. يُحتسب من السعر الفرعي والضرائب المعتمدة.
21. price_total
النوع: Monetary. الإجمالي بعد الضريبة؛ القيمة الأساسية المستخدمة عند إعداد الفواتير.
22. product_packaging_id
النوع: Many2one (product.packaging). تغليف اختياري مثل عبوة من 12؛ عند وجوده قد تُحدَّد الكميات تلقائيًا حسب التغليف.
23. customer_lead
النوع: Float. زمن التسليم بالأيام بين تأكيد الطلب والشحن؛ يُستخدم لحساب مواعيد التسليم.
24. qty_delivered
النوع: Float. الكمية المسلَّمة. يتحدّث تلقائيًا عبر حركات المخزون أو يمكن تحديثه يدويًا، ويُستخدم للفوترة الجزئية.
25. qty_invoiced
النوع: Float. الكمية التي فُوّرت بالفعل؛ يحسبها النظام من خطوط الفاتورة.
26. qty_to_invoice
النوع: Float. الكمية المتبقية للفوترة؛ تحسب من الفرق بين المسلَّم والمفوتر.
27. invoice_status
النوع: Selection. قيم مثل invoiced، to invoice، no — تبين حالة الفوترة للسطر.
28. invoice_lines
النوع: Many2many (account.move.line). وصلات لأسطر الفاتورة المولَّدة من هذا السطر لتتبع الأثر.
29. create_date
النوع: Datetime. وقت إنشاء السجل. يُدار أوتوماتيكياً بواسطة Odoo.
30. write_date
النوع: Datetime. آخر وقت تعديل للسجل. يُستخدم في تدقيق التغييرات.
كيف يُستخدم هذا النموذج في سير عمل الشركات
1. عروض الأسعار وأوامر البيع
عندما يُعد مندوب المبيعات عرضًا، يضيف سطورًا لكل منتج؛ كل سطر يظهر الكمية، السعر، الخصم والمجموع. يتحول العرض إلى أمر عند قبول العميل.
2. قوائم الأسعار والخصومات
قواعد قوائم الأسعار تُطبّق على كل سطر؛ الحقول price_unit وdiscount تُحتسب وفق سياسات القائمة، بما في ذلك خصومات الحجم أو تسعير عملاء مخصّص.
3. التسليم والفوترة
عند تنفيذ الشحن تتحدّث qty_delivered، ويمكن إصدار الفاتورة بناءً على التسليم أو دفعة واحدة. حقل invoice_status يوجّه المستخدم بخصوص ما تبقى للفوترة.
4. المشاريع والخدمات
بالنسبة للمنتجات الخدمية، ترتبط الأسطر بمهام المشروع وبسجلات الوقت، والوراثة التحليلية تمكّن تتبّع التكلفة لكل مشروع.
5. التجارة الإلكترونية والبورتال
زوار الموقع يضيفون عناصر إلى السلة، وكل سطر في السلة يصبح sale.order.line عند إنشاء الأمر. مُكوّن تهيئة المنتج يعتمد على product_template_id والصفات المخصصة.
كيف يطوّر المطورون هذا النموذج
المطورون يوسّعون sale.order.line عبر أنماط متعددة داخل منصة Odoo، حيث أن وراثة النماذج هي الآلية الأساسية.
وراثة النماذج
استعمل _inherit = 'sale.order.line' لإضافة حقول أو تغيير سلوكيات أو فرض قيود. إبقاء التعديلات في وحدة منفصلة يسهل الصيانة والترقية.
إضافة حقول
عرّف الحقول الجديدة في النموذج الموروث مستخدمًا النوع المناسب مثل Char، Many2one، Boolean، Integer، Text أو Selection. فكر في جعل بعض الحقول معتمدة على الشركة في بيئات متعددة الشركات.
امتدادات بايثون
يمكن تجاوز دوال مثل _compute_price_unit أو _compute_price_subtotal أو إضافة منطق عند create/write. استدعِ super() دائماً لتتفادى كسر سلوك أصلي، وكن حذرًا مع الحقول المحسوبة واعتمادياتها.
Odoo Studio
تسمح Odoo Studio بإضافة حقول بدون كود وهي مفيدة للتعديلات السريعة؛ لكن للمشروعات المعقدة أو عند الحاجة لترقيات طويلة الأمد، الوحدات المخصصة أفضل من ناحية الصيانة.
أفضل الممارسات
- استخدم display_type لتمييز الأقسام والملاحظات بدل إدخال أسطر وهمية كمنتجات؛ هذا يحافظ على تقارير نظيفة وصحيحة.
- عند بناء تكاملات API أنشئ الأسطر في سياق الأمر باستخدام order_id أو استخدم order_line_ids على sale.order مع صيغة أوامر Odoo الصحيحة.
- احترم قيود قاعدة البيانات وSQL: خطّ المنتج يحتاج product_id وproduct_uom، أما سطر القسم أو الملاحظة فيجب أن يحدد display_type.
- للسعر المخصص، حاول الاستفادة من قواعد قوائم الأسعار قبل الكتابة المباشرة للدوال المحسوبة؛ غيّر الحسابات فقط عندما لا تغطي القوائم حالتك.
- لحقولك المخصصة، ضع بادئة
x_أو بادئة خاصة بوحدتك لتجنب تعارض مع إصدارات Odoo المستقبلية.
أخطاء شائعة
- إنشاء أسطر دون order_id. الحقل مطلوب؛ أنشئ الأسطر دائمًا داخل سياق أمر حتى تتجنب أخطاء سلامة البيانات.
- الخلط بين product_id وproduct_template_id. لأسطر المنتج ضع product_id، ولعمليات التهيئة حيث تختار النسخة استخدم product_template_id.
- تعديل price_unit أو discount بعد إصدار فاتورة جزئية. بعد أن تصبح qty_invoiced أكبر من صفر، تغيير الأسعار قد يسبب تناقضات في الحسابات.
- تجاوز الدوال الأساسية دون استدعاء super(). هذا قد يكسر وظائف إضافية أو يعقد ترقيات لاحقة.
- نسيان ضبط display_type لأسطر الأقسام أو الملاحظات. بدونها يُعامَل السطر كسطر منتج وقد يفشل في التحقق من الصحة.
خاتمة
نموذج sale.order.line هو حجر الزاوية في مبيعات Odoo، فهو يخزن تفاصيل كل سطر على عروض الأسعار وأوامر البيع. معرفة حقوله وكيفية تمديده يساعد في إعداد وتخصيص وربط النظام بكفاءة.
سواء كنت استشاريًا وظيفيًا يقوم برسم العمليات أو مطورًا يبني وحدات مخصصة، فهم sale.order.line يوفر وقتك ويقلّل الأخطاء.
هل تحتاج مساعدة في تنفيذ Odoo الخاص بك؟
تقوم Dasolo بمساعدة الشركات في تنفيذ وتخصيص وتحسين Odoo. نتخصص في تكاملات API وتطوير Odoo، وفريقنا يمتلك خبرة عميقة ببُنية البيانات ونماذج مثل sale.order.line.
إذا احتجت لمساعدة في تنفيذ Odoo، أو تطوير وحدات مخصصة، أو تكاملات، نحن جاهزون لدعمك. احجز عرضًا تجريبيًا لمناقشة مشروعك.