يخبرنا «AN26000001» بأكثر مما يخبرنا به «S00001»: إنه عرض سعر، يعود إلى عام 2026، وهو الأول. وترغب شركات كثيرة، ولا سيما التي تنتقل من نظام قديم إلى Odoo، في الاحتفاظ بهذا النمط تحديدًا لأرقام مستنداتها. يستخدم Odoo تسلسلات خاصة لترقيم عروض الأسعار وأوامر البيع وإشعارات التسليم (S00001، WH/OUT/00001، P00001)، ويُرقّم الفواتير باستخدام بادئة دفتر اليومية والسنة (INV/2026/00001).
لهذا الغرض، طوّرنا وحدة Document Numbering by Prefix and Year (document_number_prefix_year) لـ Odoo 19. وهي متاحة على GitHub كبرمجية حرة بموجب ترخيص LGPL-3:
github.com/Alex0176/odoo-document-number-prefix-year
توضيح صريح قبل البدء: نحن لا نستخدم هذه الوحدة في Biricon IT Services. ننشرها لأنها مكتملة وموثّقة ومزوّدة باختبارات، وقد توفّر على الآخرين جهدًا. وينبغي لمن يستخدمها قراءة القسمَين المتعلقَين بـ الحدود و الاختبارات .
نمط الترقيم
يتكوّن كل رقم من ثلاثة أجزاء: بادئة لكل نوع من المستندات، والسنة، وعدّاد بعدد ثابت من الخانات. ويمكنك ضبط البادئة وتنسيق السنة (26 أو 2026) وعدد الخانات لكل شركة ضمن الإعدادات → ترقيم المستندات.
تشمل الوحدة عروض الأسعار وأوامر بيع العملاء وفواتير العملاء والإشعارات الدائنة وإشعارات التسليم واستلام البضائع وأوامر الشراء. والبادئات الظاهرة في الرسم مجرد أمثلة: AN، AU، RE، GU، LI، WE، BE. وإذا تركت بادئة أحد أنواع المستندات فارغة، فسيبقى ترقيم Odoo الافتراضي لهذا النوع. لذا لا تُجري الوحدة أي تغيير حتى تضبط إعداداتها.
آلية عمل الترقيم
- بداية جديدة كل عام. يبدأ العدّاد من 1 مجددًا عند الانتقال إلى سنة جديدة.
- متابعة الترقيم بعد الأرقام المستوردة. تبحث الوحدة عن أعلى رقم موجود يحمل البادئة والسنة نفسيهما، بغض النظر عن طوله. فإذا احتوت قاعدة البيانات على
AN26119من النظام القديم، فسيحمل عرض السعر التالي الرقمAN26000120. وهذا ما يجعل الوحدة مناسبة للانتقال بين الأنظمة: تُستورد المستندات القديمة بأرقامها الأصلية، وتتابع المستندات الجديدة الترقيم بسلاسة. - رقم أمر بيع جديد عند التأكيد. يمكن، حسب الرغبة، منح عرض السعر المؤكَّد رقمًا من تسلسل أوامر البيع. ويظل رقم عرض السعر محفوظًا في حقل رقم عرض السعر في أمر البيع، ويظهر في النموذج والقائمة والبحث.
- ترقيم الفواتير عند الترحيل. لا تحصل فواتير العملاء والإشعارات الدائنة على أرقامها عند الإنشاء، بل عند الترحيل. لذلك لا تترك المسودات المحذوفة فجوات في التسلسل. وتُؤخذ السنة من تاريخ الفاتورة: فالفاتورة المؤرخة في 30.12.2025 والمُرحَّلة في 2.1.2026 تحمل رقمًا يبدأ بـ
RE25…. - يبقى كل ما عدا ذلك كما هو. تحتفظ فواتير الموردين والمدفوعات والقيود المحاسبية وأوامر التصنيع بتسلسلات Odoo الافتراضية. ولا تُغيَّر الأسماء الموجودة مطلقًا، حتى عند تعطيل الوحدة.
الجزء الحساس: مستخدمان في الوقت نفسه
تبدو آلية الترقيم الخاصة بسيطة: ابحث عن أعلى رقم وأضف إليه واحدًا. لكنها تصبح معقدة عندما ينشئ مستخدمان عرض سعر في اللحظة نفسها. يقرأ كلاهما «أعلى رقم = 0»، ويُخصّص كلاهما الرقم AN26000001. يستخدم Odoo تسلسلات قاعدة البيانات لمعالجة ذلك في تسلسلاته الأصلية. أما الترقيم المخصّص فلا يملك هذه الآلية، وفوق ذلك لا يتحقق Odoo من تفرّد الاسم في عروض الأسعار وأوامر الشراء: فيُحفَظ مستندان بالرقم نفسه ببساطة.
الحماية البديهية هي استخدام قفل. تضع الوحدة قفلًا في قاعدة البيانات (PostgreSQL Advisory Lock) لكل شركة وبادئة وسنة، ويستمر حتى نهاية المعاملة. وينتظر المستخدم الثاني حتى ينتهي الأول. لكن ذلك لا يكفي، وقد اكتشفنا هذا من خلال تجربة على نسخة من قاعدة بيانات الإنتاج:
يعمل Odoo بمستوى العزل REPEATABLE READ. فتُثبَّت حالة قاعدة البيانات التي تراها المعاملة عند تنفيذ أول استعلام فيها. ويكون المستخدم B قد حصل على هذه الحالة قبل انتهاء A. فإذا انتظر B القفل بعد ذلك ثم حصل عليه، فسيقرأ «أعلى رقم = 0» من الحالة القديمة التي لديه، ويُخصّص الرقم مرة ثانية. لقد نظّم القفل ترتيب التنفيذ، لكنه لم يحدّث البيانات المرئية.
الحل هو إجراء قراءة ثانية عبر اتصال مستقل وقصير الأمد بقاعدة البيانات، يرى جميع الصفوف التي ثُبّتت معاملاتها بالفعل. وتُعتمد القيمة الأكبر من القيمتين. وتظل القراءة الأولى ضرورية، لأنها وحدها ترى الأرقام التي خصّصتها المعاملة نفسها ولم تُثبَّت بعد، مثلما يحدث عند استيراد عدة مستندات دفعة واحدة.
تحققنا من ذلك باستخدام معاملتين، وتأكدنا من أن الثانية قد أخذت لقطة حالتها قبل تثبيت الأولى، ثم انتظرت القفل. ومن دون القراءة الثانية، حصل أمرا البيع على الرقم نفسه؛ ومعها حصلا على الرقمين 1 و2.
توضيح مهم: هذه التجربة تحقق يدوي. وهي ليست جزءًا من الاختبارات الآلية، لأنها تتطلب اتصالين فعليين بقاعدة البيانات، وهو ما لا توفّره بيئة اختبار Odoo التي تستخدم معاملة واحدة لكل اختبار.
التنفيذ التقني
| المستند | نقطة الربط |
|---|---|
| عرض سعر | sale.order.create، عندما يكون الاسم فارغًا أو / أو New |
| أمر بيع عميل | sale.order.action_confirm، قبل التأكيد الافتراضي |
| فاتورة، إشعار دائن | account.move._set_next_sequence، تُستدعى عند الترحيل |
| إشعار التسليم، استلام البضائع | stock.picking.create بحسب نوع العملية |
| أمر شراء | purchase.order.create |
- العدّاد. يُستخدم تعبير نمطي (
^<Stamm>([0-9]{1,15})$، مع تهريب المحارف الخاصة في الجزء الثابت) للعثور على أعلى رقم لكل شركة، مع تضمين الأسماء غير المرتبطة بشركة. - الفواتير. تكتب
_set_next_sequenceالاسم وتستدعي_compute_split_sequenceللحفاظ على اتساق منطق التسلسل في Odoo، بما يشمل البادئة والرقم والتعرّف على السنة للفاتورة التالية في دفتر اليومية. - الإعدادات. تنعكس حقول الشركة
document_number_*فيres.config.settings. وترفض الإعدادات البادئات التي تحتوي على مسافات أو تنتهي برقم. - الترجمة. تتضمن الوحدة ترجمة ألمانية.
التثبيت والإعداد
- ضع المجلد
document_number_prefix_yearفي مسار الإضافات. - حدّث قائمة التطبيقات وثبّت الوحدة. يلزم تثبيت المبيعات والمشتريات والمخزون والمحاسبة مسبقًا.
- أدخل البادئات وتنسيق السنة وعدد الخانات ضمن الإعدادات → ترقيم المستندات.
- جرّب على نسخة أولًا. لا يمكن التراجع عن رقم المستند تلقائيًا لاحقًا، كما يرتبط رقم الفاتورة بمتطلبات الاحتفاظ بالسجلات والتدقيق.
الحدود
- تُرقَّم عروض الأسعار عند إنشائها. تترك عروض الأسعار المحذوفة أو الملغاة فجوات في التسلسل. وينطبق الأمر نفسه على كل أمر بيع عميل تنشئه وحدة أخرى: إذ إن سلال التسوق في المتجر الإلكتروني (
website_sale) هي أوامر بيع بحالة عرض سعر، وتستهلك كل منها رقمًا. ولا يخلو من الفجوات سوى تسلسل الفواتير والإشعارات الدائنة، لأنها تُرقَّم عند الترحيل. - لا تغيّر تنسيق السنة أثناء الاستخدام الفعلي. عند استخدام الجزء الثابت
AN26، تقرأ الوحدة الرقم الموجودAN2026000001على أن قيمة العدّاد هي26000001. حدّد التنسيق قبل إنشاء أول مستند. - العدّاد بحد أقصى 15 خانة. تُتجاهل سلاسل الأرقام الأطول التي تأتي بعد الجزء الثابت عند البحث عن أعلى رقم.
- لا توجد تسلسلات منفصلة لكل دفتر يومية أو مستودع. يُخصَّص العدّاد لكل شركة وبادئة وسنة. وتشترك دفاتر يومية المبيعات المتعددة في عدّاد الفواتير.
- يجب ألا تحتوي البادئات على مسافات أو تنتهي برقم، وإلا تعذّر فصل البادئة والسنة والعدّاد بعضها عن بعض.
- تقتصر المعالجة على أنواع المستندات المذكورة.
الاختبارات
تتضمن الوحدة عشرة اختبارات آلية تتحقق مما يلي:
- عرض السعر والتأكيد: رقما عرض السعر وأمر البيع، والاحتفاظ برقم عرض السعر
- متابعة العدّ بعد رقم مستورد (
AN26119→AN26000120) - عدم إعادة ترقيم المستندات الموجودة بأثر رجعي
- الفاتورة والإشعار الدائن والانتقال إلى سنة جديدة بحسب تاريخ الفاتورة
- أوامر الشراء وإشعارات التسليم
- بادئة فارغة: يبقى ترقيم Odoo الافتراضي
- سنة من أربع خانات
- بادئة تحتوي على محارف خاصة
- عدة أرقام في معاملة واحدة
- تجاهل سلاسل الأرقام الطويلة جدًا
أمر التشغيل:
odoo-bin -d <Testdatenbank> -i document_number_prefix_year --test-enable --test-tags=/document_number_prefix_year --stop-after-init
تُجرى الاختبارات باستخدام معاملات عادية. ولا تشمل سلوك النظام عند إنشاء مستندات بالتزامن بواسطة مستخدمَين؛ فقد جرى التحقق من ذلك يدويًا على نسخة من قاعدة البيانات، كما ورد أعلاه. ومن يستخدم الوحدة في نظام يعمل عليه عدد كبير من المستخدمين بالتزامن، ينبغي له تكرار هذه التجربة على قاعدة بياناته.
ملاحظة قانونية بشأن رقم الفاتورة
يجب أن تحمل الفواتير، بموجب المادة 11 من قانون ضريبة القيمة المضافة UStG، رقمًا تسلسليًا يُخصَّص مرة واحدة لتحديد هوية الفاتورة. وتُرقّم الوحدة الفواتير عند ترحيلها، باستخدام عدّاد مستقل لكل بادئة وسنة، وهو ما يتوافق مع هذا المبدأ. أما ما إذا كانت إعداداتك الفعلية، مثل تعدد دفاتر اليومية أو تخصيص بادئة مستقلة للإشعارات الدائنة أو الانتقال إلى سنة جديدة، تستوفي متطلبات مستشارك الضريبي، فعليك مناقشته معه. هذا المقال لا يُعدّ استشارة قانونية.
الأسئلة الشائعة
لماذا لا نكتفي بتعديل تسلسلات Odoo؟
يمكن فعل ذلك للفواتير باستخدام بادئة دفتر اليومية. لكن عروض الأسعار وأوامر البيع وإشعارات التسليم وأوامر الشراء لا تملك نمطًا موحّدًا من بادئة وسنة وعدّاد يُعاد بدؤه مع كل سنة جديدة، كما أن العدّاد لا يأخذ الأرقام القديمة المستوردة في الحسبان. وهنا يأتي دور الوحدة.
هل يُستبدل الترقيم الموجود؟
لا. تُخصّص الوحدة أرقامًا جديدة فقط. وتبقى الأسماء المحفوظة سابقًا كما هي، حتى عند تعطيلها.
كيف أعطّلها مجددًا؟
أفرغ بادئة نوع المستند المطلوب. وسيعود Odoo إلى ترقيمه بنفسه. كما أن إلغاء تثبيت الوحدة لا يغيّر أي رقم خُصّص سابقًا.
هل تستخدمونها أنتم؟
لا. نستخدم ترقيم Odoo الافتراضي. وقد تحققنا من الوحدة بالاختبارات الآلية والتجربة اليدوية الموضّحة، لكننا لم نختبرها في بيئة تشغيل فعلية يعمل عليها عدد كبير من المستخدمين.
هل تعمل مع Odoo 17 أو 18؟
اختبرناها فقط مع Odoo 19.0 Community. وقد تتوافق مع الإصدارات الأخرى أو لا تتوافق؛ لم نتحقق من ذلك.
ما ترخيصها؟
بموجب LGPL-3. ونرحّب ببلاغات الأخطاء ومقترحات التحسين على هيئة Issue في مستودع GitHub .
الدعم من Biricon IT Services
نتولى دعم أنظمة Odoo للشركات الصغيرة والمتوسطة، من التطبيق الأولي والتخصيص وترحيل البيانات إلى التشغيل المستمر. ويسعدنا مساعدتك إذا أردت الاحتفاظ بأرقام مستنداتك عند الانتقال، أو التحقق من آلية الترقيم تحت الضغط، أو إدخال وحدة كهذه بأمان إلى بيئة الإنتاج لديك. المزيد من تطويراتنا الخاصة: السجل التجاري والتحقق من عناوين العملاء النمساويين, مجموعات المنتجات كقسم في عرض السعر و Web RBL، قائمة حظر حركة البيانات الهجومية.
آخر تحديث: 3 نوفمبر 2026. إصدار الوحدة 19.0.1.0.0. جميع الأرقام الواردة في الأمثلة والرسوم توضيحية ومختارة اعتباطًا.