لماذا QR في فواتير ZATCA؟
أوجبت هيئة الزكاة والضريبة والجمارك (ZATCA) إدراج كود QR على كل فاتورة ضريبية مبسطة منذ ديسمبر 2021 ضمن المرحلة الأولى من الفوترة الإلكترونية. الهدف ليس مجرد عرض رقم، بل تضمين هوية البائع ورقمه الضريبي ووقت الفاتورة وقيمها داخل صورة واحدة يقرؤها أي تطبيق مستقل فورًا، بما في ذلك تطبيق ZATCA الرسمي للمستهلكين الذي يتحقق ميدانيًا من صحة البائع.
من منظور المطور، QR ليس صورة فقط — إنه حاوية بيانات منظمة. لكي تطبع رمزًا صحيحًا أو تفكّ رمزًا قائمًا عليك أن تفهم الطبقتين: طبقة الترميز الثنائية (TLV) وطبقة النقل النصي (Base64). هذه المقالة تشرح الطبقتين معًا وتمنحك مرجعًا تعود إليه عند أي خطأ تحقق في بيئة Sandbox الخاصة بـ ZATCA.
QR كجسر بين البائع والمستهلك والهيئة
يخدم كود QR ثلاثة أطراف في آن واحد: المستهلك الذي يتحقق من صحة البائع عبر التطبيق الرسمي، والبائع الذي يثبت التزامه بالفوترة الإلكترونية، وهيئة الزكاة التي تراجع البيانات ميدانيًا دون اتصال مباشر بنظام البائع. هذا التصميم اللامركزي هو ما يجعل QR قويًا: كل المعلومات الأساسية محمولة داخل الرمز نفسه ولا تحتاج استعلامًا خارجيًا للتحقق السريع.
الفرق بين QR العرضي وQR الموثّق
في المرحلة الأولى يكفي أن يحمل QR الحقول الخمسة الأساسية بصيغة TLV، وهو ما نسميه رمزًا عرضيًا (Visual). أما في المرحلة الثانية فيصبح الرمز موثّقًا تشفيريًا عبر إضافة الهاش والتوقيع الرقمي، ما يحوّله من مجرد عرض بيانات إلى إثبات سلامة لا يمكن العبث به. فهم هذا التدرّج يساعد المطوّر على معرفة أي الحقول يتوقع وجودها في كل مرحلة.
ما هو ترميز TLV؟
TLV اختصار لـ Tag-Length-Value، نمط ترميز ثنائي قديم يستخدم في البطاقات الذكية (EMV) وبروتوكولات SIM. الفكرة بسيطة: كل حقل بيانات يُمثَّل بثلاث قطع متتالية: بايت Tag يحدد معنى الحقل، ثم بايت Length يحدد طول القيمة بالبايت (0–255)، ثم Value يحتوي عدد البايتات المحدد مرمَّزًا UTF-8.
المفكّك يمشي على البايتات بشكل متتابع: يقرأ بايت Tag ثم بايت Length ثم يقطع Length بايتات كقيمة، ويكرر العملية حتى نهاية البيانات. هذا النمط يسمح بإضافات مستقبلية دون كسر القارئات القديمة — فهي ببساطة تتجاهل الـ Tags غير المعروفة. هذا هو السبب الذي جعل ZATCA تختاره: التوافق الخلفي بين Phase 1 و Phase 2.
لماذا TLV وليس JSON؟
قد يتساءل المطوّر لماذا لم تختر ZATCA صيغة JSON المألوفة بدل TLV الثنائي. السبب أن JSON يستهلك مساحة أكبر بكثير بسبب أسماء الحقول والأقواس وعلامات الاقتباس، وكود QR محدود السعة؛ كلما زادت البايتات زادت كثافة الرمز وصعب مسحه بكاميرات ضعيفة. TLV يضغط البيانات إلى الحد الأدنى: بايت للوسم وبايت للطول فقط دون أي حشو، ما يبقي الرمز صغيرًا وقابلاً للمسح بسهولة.
حدود الطول في بايت واحد
بما أن حقل Length بايت واحد، فإن أقصى طول لأي قيمة هو مئتان وخمسة وخمسون بايتًا. هذا كافٍ لأسماء البائعين والأرقام الضريبية، لكنه قيد مهم يجب أن يعيه مولّد الـ QR: اسم بائع طويل جدًا بالعربية قد يقترب من الحد بسبب ترميز البايتين لكل حرف. المفكّك الجيد يتعامل مع هذا الحد بأمان ولا يفترض أبدًا قيمًا أطول مما يسمح به البايت الواحد.
قراءة البايتات خطوة بخطوة
لنفترض أن الحقل الأول اسم البائع Shop (4 أحرف ASCII). البايتات تكون: 01 04 53 68 6F 70 — أي Tag=1، Length=4، ثم بايتات Shop في UTF-8. الخوارزمية في JavaScript واضحة: نحرّك مؤشرًا (cursor) من 0. في كل لفّة نقرأ bytes[cursor] كـ tag ثم bytes[cursor+1] كـ length ثم نقطع شريحة من cursor+2 إلى cursor+2+length، ونرفع cursor إلى cursor+2+length. نتوقف عند تجاوز طول المصفوفة.
let cursor = 0;
while (cursor < bytes.length) {
const tag = bytes[cursor];
const len = bytes[cursor + 1];
const value = bytes.subarray(cursor + 2, cursor + 2 + len);
fields[tag] = new TextDecoder("utf-8").decode(value);
cursor += 2 + len;
}ملاحظة مهمة: إذا كانت قيمة Length أكبر من البايتات المتبقية فعلًا، فهذا دليل على ملف تالف أو تم اقتطاعه — يجب إيقاف الفك وتسجيل خطأ truncated_value بدلًا من قراءة بايتات عشوائية من خارج النطاق.
لماذا نستخدم subarray وليس slice؟
في بيئة Uint8Array يعيد subarray عرضًا (view) على نفس الذاكرة دون نسخ، بينما slice ينسخ البايتات إلى مصفوفة جديدة. لفواتير بسيطة الفرق ضئيل، لكن عند فك ألوف الفواتير دفعة واحدة تصبح كفاءة الذاكرة مهمة، وsubarray أسرع لأنه يتجنّب النسخ المتكرر. مع ذلك يجب الانتباه إلى أن العرض يشارك الذاكرة، فلا تعدّل البايتات الأصلية بعد أخذ العرض وإلا تأثرت القيم المفكوكة.
إدارة المؤشر بأمان
أخطر خطأ في حلقة الفك هو تجاوز المؤشر حدود المصفوفة، ما ينتج عنه إما قيم undefined أو حلقة لا تنتهي. لذلك يجب التحقق قبل قراءة الطول من أن المؤشر زائد واحد لا يزال داخل النطاق، وبعد حساب نهاية القيمة أنها لا تتجاوز طول المصفوفة. أي تجاوز يُترجم إلى خطأ truncated_value بدل المتابعة العمياء.
دور Base64 في النقل
QR Code يحمل سلسلة نصية لا بايتات خام. ولأن TLV ثنائي ويحتوي على بايتات صفرية أو غير مطبوعة، يجب لفّه بـ Base64 قبل إدراجه في QR. العملية ميكانيكية: تأخذ كل 3 بايتات (24 بت) وتحوّلها إلى 4 أحرف من مجموعة 64 حرفًا آمنة (A-Z, a-z, 0-9, +, /). كل حرف يمثل 6 بت، ويُعاد التركيب بسهولة في الاتجاه المعاكس.
في JavaScript المتصفح، يكفي استدعاء atob(b64) للحصول على binary string ثم تحويلها إلى Uint8Array عبر charCodeAt لكل حرف. في Node.js يكفي Buffer.from(b64, "base64"). الأداة هنا تجرّب الاثنين تلقائيًا فتعمل في كل من Edge Runtime والمتصفح. لاحظ أن atob يرمي SyntaxError إذا احتوت السلسلة حروفًا غير مسموحة، لذلك نلفّ المحاولة في try/catch ونعيد invalid_base64 كخطأ منظم.
حشو Base64 وعلامة المساواة
تنتهي سلاسل Base64 أحيانًا بعلامة مساواة واحدة أو اثنتين، وهي حشو (padding) لجعل طول السلسلة من مضاعفات الأربعة. بعض المولّدات تحذف الحشو، وبعض المفكّكات الصارمة ترفض السلسلة بدونه. الأداة المتسامحة تعيد بناء الحشو تلقائيًا قبل الفك لتعمل مع المصادر المختلفة، مع تسجيل ملاحظة تدل على أن المصدر حذف الحشو خلافًا للمعيار.
URL-safe Base64 ولماذا لا تستخدمه ZATCA
توجد نسخة من Base64 تستبدل الرمزين + و/ بـ - و_ لتصبح آمنة داخل عناوين URL. لكن مواصفة ZATCA تستخدم Base64 القياسية لا URL-safe، لأن محتوى QR لا يُوضع في عنوان إنما يُقرأ كسلسلة خامة. إذا وردت سلسلة تحوي - أو _ فهذا مؤشر على مصدر خلط بين الصيغتين، وفكّها بالمعيار القياسي سيفشل.
معالجة UTF-8 للأسماء العربية
الخطأ الأكثر إحراجًا في أدوات الفك العربية أن تظهر أسماء البائعين كمربعات أو علامات استفهام. السبب دائمًا واحد: استخدام String.fromCharCode على البايتات مباشرة بدل TextDecoder. الأول يفترض ASCII أحادي البايت، والثاني يدرك أن الحرف العربي قد يأخذ 2-3 بايتات. الحل القياسي: new TextDecoder("utf-8").decode(uint8Array).
الحرف الواحد في UTF-8 يأخذ بين بايت واحد (ASCII) و4 بايتات (رموز Emoji). الأحرف العربية الأساسية كلها في النطاق U+0600 إلى U+06FF وتُرمَّز ببايتين. مع المسافات وعلامات الترقيم الإنجليزية يأخذ كل منها بايت واحد، ما يفسر التفاوت في طول Tag 1 من فاتورة لأخرى.
علامة ترتيب البايتات (BOM)
بعض الأنظمة تضيف ثلاثة بايتات في بداية النص تُسمّى BOM لتحديد ترميز UTF-8. داخل قيمة TLV لا يُفترض وجود BOM، وإذا ظهر فإنه يظهر كحرف غريب في بداية اسم البائع. المفكّك الجيد يكشف BOM في بداية القيمة ويزيله بصمت حتى لا يظهر في الواجهة، مع تسجيل ملاحظة أن المصدر أدرجه خلافًا للمواصفة.
الأرقام العربية الهندية في الأسماء
قد يحتوي اسم البائع على أرقام عربية هندية مثل فروع مرقّمة، وهذه تُرمّز UTF-8 ببايتين مثل الحروف العربية. لا تحوّلها إلى أرقام لاتينية عند العرض إلا إذا طُلب ذلك صراحة، لأن التحويل قد يغير الاسم الرسمي المسجل لدى الهيئة. العرض الأمين يحافظ على النص كما ورد تمامًا.
حقول Phase 2 الإضافية (6–9)
المرحلة الثانية أضافت أربعة tags إلى نفس الـ QR دون كسر القارئات القديمة: Tag 6 (هاش الفاتورة) و Tag 7 (التوقيع الرقمي) و Tag 8 (المفتاح العام لشهادة CSID) و Tag 9 (توقيع الـ CA). هذه التوقيعات مرمَّزة Base64 داخل TLV، وتُضاف فقط لفواتير B2B (الضريبية الكاملة)، أما الفواتير المبسطة B2C فتبقى على الحقول 1-5 وتُختم لاحقًا عبر Cryptographic Stamp.
المفكِّك الجيد يجب أن يتجاهل بصمت أي tag أكبر من 5 ولا يعتبره خطأ، وأن يعدّ عدد tags الإضافية في حقل extraTags كي يميّز المستخدم فورًا بين QR مرحلة أولى وأخرى مرحلة ثانية. هذا ما تفعله هذه الأداة.
لماذا توقيع الفواتير B2B فقط؟
فواتير الأعمال (B2B) تدخل في دورة خصم ضريبي بين منشأتين، لذلك تتطلب توقيعًا رقميًا يربط الفاتورة بشهادة البائع ويمنع أي تعديل لاحق. أما فواتير الأفراد (B2C) فتُختم لاحقًا عبر الختم التشفيري عند رفعها للهيئة، ولا تحتاج توقيعًا داخل QR لحظة الإصدار. فهم هذا التمييز يمنع المطوّر من توقع حقول توقيع في فاتورة مبسّطة.
حجم التوقيع وأثره على الرمز
حقول الهاش والتوقيع والمفتاح العام تضيف بايتات كثيرة إلى الرمز، ما يجعل QR في المرحلة الثانية أكبر وأكثف بصريًا من رمز المرحلة الأولى. لذلك يوصى باستخدام مستوى تصحيح أخطاء مناسب عند طباعة الرموز الموقّعة حتى تبقى قابلة للمسح حتى لو تعرضت لخدوش أو تلف جزئي على الورق.
التحقق من صحة الحقول
الفك الناجح لا يعني فاتورة صحيحة. التحقق المنطقي يأتي بعد الفك ويغطي: نمط VAT (15 رقمًا 3...3)، صيغة ISO 8601 للوقت، كون الإجمالي والضريبة أعدادًا عشرية موجبة، وألا تتجاوز الضريبة الإجمالي. هذه الأداة تنفذ التحقّقات الأربعة وتُرجع رمز خطأ منفصل لكل منها: invalid_vat_number_format و invalid_timestamp_format و invalid_invoice_total و vat_exceeds_total.
الفصل بين الفك والتحقق مفيد عمليًا: قد تريد قبول فاتورة بصيغة وقت غير قياسية للأرشفة فقط، أو ترفض أي قيمة سالبة في الضريبة قبل إدخالها قاعدة بياناتك. كل خطأ منفصل يسمح لك بإطفاء أو تشديد التحقّقات حسب سياق الاستخدام.
التحقق من رقم التسجيل الضريبي بدقة
لا يكفي أن يكون رقم VAT خمسة عشر رقمًا؛ فالمواصفة تشترط أن يبدأ بثلاثة وينتهي بثلاثة، وأن تكون الخانة قبل الأخيرة تحمل قيمة محددة ترمز لنوع المسجل. التحقق الأعمق يشمل خانة التحقق (check digit) إن وجدت، لكن حتى التحقق من النمط الأساسي يكشف أغلب الأخطاء الشائعة في إدخال الرقم الضريبي.
التحقق من اتساق القيم المالية
بعد التأكد من أن الإجمالي والضريبة أعداد عشرية موجبة، يمكن إجراء تحقق منطقي إضافي: هل تتناسب الضريبة مع الإجمالي عند النسبة القياسية؟ إذا كانت الضريبة أعلى بكثير من المتوقع فقد يكون البائع أدخل الإجمالي قبل الضريبة في خانة الإجمالي بعدها. هذه التحققات المنطقية تكشف أخطاء لا تظهرها التحققات الشكلية.
أخطاء الفك الشائعة
أبرز الأسباب لفشل الفك: نسخ ناقص للـ QR من شاشة الكاشير (truncated_value)، استخدام صورة QR التُقطت بكاميرا منخفضة الدقة فظهر طابع زمني مشوّش، أو لصق محتوى الـ QR ككود URL Encoded بدل Base64. التحقق الأول دائمًا يجب أن يكون: هل السلسلة تطابق /^[A-Za-z0-9+/=]+$/؟ إن لم تطابق فهي ليست Base64 خامة.
سبب آخر شائع: ZATCA Phase 1 تتطلب الحقول 1-5 جميعًا. غياب أي منها (missing_tag_N) يعني أن المصدر لم يلتزم بالمواصفة وليس عيبًا في الفك. أبلغ المورّد المعني فورًا لأن الفاتورة قد تُرفض من قِبل هيئة الزكاة عند المراجعة.
خلط ترميز الأحرف عند النسخ
أحد أخطر الأخطاء أن يُنسخ محتوى QR عبر تطبيق يغير ترميز الأحرف تلقائيًا، مثل لصق السلسلة في حقل يحوّل علامة + إلى مسافة. عندئذ تفشل عملية الفك بلا سبب ظاهر، ويظن المستخدم أن الفاتورة تالفة بينما العيب في وسيلة النقل. الحل: انسخ من حقل نصي خام وتجنّب التطبيقات التي تُعيد تنسيق النص.
رموز الخطأ المنظّمة وفائدتها
بدل رسالة خطأ عامة، تعيد الأداة رمز خطأ محددًا لكل حالة: invalid_base64 لسلسلة غير صالحة، وtruncated_value للاقتطاع، وmissing_tag لحقل غائب. هذا التفصيل يساعد المطوّر على توجيه المستخدم إلى الحل الصحيح بدل تركه يخمّن، ويسمح أيضًا ببناء لوحات مراقبة تصنف أسباب فشل الفواتير بدقة.
حالات الاستخدام
المراجعون والمحاسبون يستخدمون فك الـ QR للتأكد من تطابق رقم VAT المطبوع مع الرقم المرمَّز داخل QR (احتيال شائع: طباعة رقم VAT صحيح بصريًا مع QR يحوي رقمًا مختلفًا). مديرو ضبط الجودة في أنظمة POS يستخدمونه للتأكد من صحة الـ QR قبل إطلاق تحديث، لأن خطأ في توليده ينعكس على آلاف الفواتير قبل اكتشافه. للتحقق من صحة الرقم الضريبي المطبوع استخدم أداة التحقّق من الرقم الضريبي، ولمقارنة مخرجات الـ XML راجع محوّل فاتورة ZATCA إلى XML.
المطوّرون عند بناء تكامل ZATCA الأولي يستخدمون أداة الفك العكسي للتأكد من أن مولّد الـ QR لديهم ينتج البايتات المتوقعة. اقرأ مقالنا عن إنشاء فاتورة ZATCA للجانب الآخر من المعادلة.
التكامل مع أنظمة نقاط البيع
عند بناء تكامل جديد لنظام نقطة بيع، يفيد فك الـ QR المولّد داخليًا ومقارنة الحقول المفكوكة بما توقّعته الفاتورة الأصلية. هذا الاختبار العكسي يكشف أخطاء الترميز قبل إطلاق النظام للإنتاج، ويوفّر ساعات طويلة من تتبّع الأخطاء بعد أن تصل آلاف الفواتير إلى العملاء.
أتمتة الفحص في خط التكامل المستمر
يمكن دمج فك الـ QR في اختبارات آلية ضمن خط التكامل المستمر، بحيث تولّد الفاتورة ثم تُفكّ وتُقارن تلقائيًا في كل إصدار. أي انحراف في ترميز الأسماء العربية أو صيغة الوقت يوقف البناء فورًا، ما يمنع تسرّب الأخطاء إلى البيئة الإنتاجية ويحوّل التحقق إلى جزء روتيني من دورة التطوير.
ملاحظات أمنية
QR الفواتير ليس سريًا — مطبوع على ورق الفاتورة ومرئي لأي عميل. لكن أرقام VAT للمنشآت عند تجميعها بكميات كبيرة تصبح أصلًا ذا قيمة لخصوم تجاريين. لا تنشر سجلات قواعد البيانات الكاملة، ولا تستخدم بيانات QR إنتاجية في اختبارات تشاركها مع طرف ثالث دون إذن المنشأة المعنية.
الأداة هنا تعمل كاملة في المتصفح: لا يُرسل الـ Base64 إلى أي خادم. تستطيع التحقق بفتح Network tab وملاحظة عدم وجود أي طلب صادر أثناء الفك.
أسئلة شائعة حول فك QR فواتير ZATCA
هل يمكن فك أي QR بهذه الطريقة؟
لا؛ هذه الطريقة تخص رموز QR التي تتبع مواصفة ZATCA بصيغة TLV المُرمّزة Base64. رموز QR العادية التي تحمل روابط أو نصوصًا حرّة لا تتبع هذا الترميز، ولو حاولت فكّها كـ TLV ستحصل على بيانات عديمة المعنى. تأكد أولاً أن الرمز صادر عن فاتورة ضريبية سعودية.
ماذا أفعل إذا فشل الفك؟
ابدأ بالتحقق من أن السلسلة سليمة Base64 ولم تُقتطع عند النسخ، ثم تأكد من عدم وجود مسافات أو أسطر جديدة دخلت عند اللصق. رمز الخطأ المنظّم الذي تعيده الأداة يحدد لك السبب الدقيق: invalid_base64 أو truncated_value أو missing_tag، وكل منها يوجّهك إلى خطوة الإصلاح الصحيحة.
لماذا تظهر الأسماء العربية كمربعات؟
هذا دائمًا خطأ في فك ترميز UTF-8، وغالبًا سببه استخدام دالة تفترض بايتًا واحدًا لكل حرف بدل TextDecoder الذي يدرك ترميز البايتين للحرف العربي. الحل القياسي هو فك البايتات بـ UTF-8 صراحةً، والأداة هنا تفعل ذلك تلقائيًا.
هل الفك يثبت صحة الفاتورة؟
الفك يثبت أن الرمز مبني بشكل سليم ويستخرج الحقول، لكنه لا يثبت صحة الفاتورة قانونيًا. في المرحلة الثانية تثبت الصحة عبر التحقق من التوقيع الرقمي مقابل المفتاح العام، وهو إجراء أعمق من مجرد استخراج الحقول. للتحقق الرسمي استخدم تطبيق الهيئة.
هل تختلف الوسوم بين الفواتير المبسّطة والكاملة؟
الحقول الخمسة الأولى موجودة في النوعين، لكن الفواتير الكاملة للأعمال تضيف الحقول من ستة إلى تسعة الخاصة بالهاش والتوقيع والمفاتيح. المفكّك يعدّ الحقول الإضافية ليخبرك فورًا بنوع الفاتورة دون حاجة لفحص يدوي.
هل يمكن قراءة QR مرحلة ثانية دون مفتاح عام؟
نعم؛ يمكن فك الحقول من واحد إلى خمسة وقراءة بيانات الفاتورة الأساسية دون الحاجة إلى المفتاح العام. لكن التحقق من صحة التوقيع الرقمي في الحقول من ستة إلى تسعة يتطلب المفتاح العام للتأكد من أن الهاش يطابق محتوى الفاتورة. الفك إذن ممكن دائمًا، أما إثبات السلامة التشفيرية فيتطلب طبقة إضافية من التحقق لا يوفرها مجرد الفك.
ما الفرق بين الطابع الزمني المحلي وUTC؟
تشترط المواصفة صيغة ISO 8601 بتوقيت UTC تنتهي بحرف Z، لا التوقيت المحلي للمنشأة. الخلط بينهما يسبب فروقًا في الساعات عند المقارنة بين الأنظمة، وقد يُرفض الطابع المحلي عند التحقق. ولّد الطابع دائمًا بدالة تعيد الوقت العالمي مباشرة لتجنب أخطاء المناطق الزمنية، خصوصًا في المنشآت التي تعمل عبر فروع في مناطق مختلفة.
هل تتغير قيمة الضريبة إذا كانت الفاتورة معفاة؟
في الفواتير المعفاة أو الخاضعة لنسبة صفرية تكون قيمة الضريبة صفرًا، ويبقى الحقل موجودًا بقيمة عشرية تساوي صفرًا لا غائبًا. المفكّك يجب أن يقبل قيمة الضريبة الصفرية كقيمة صحيحة لا كخطأ، لأن غيابها التام هو الخطأ وليس كونها صفرًا. تمييز الحالتين مهم لتجنب رفض فواتير معفاة سليمة.
لماذا يختلف طول الرمز من فاتورة لأخرى؟
طول الرمز يعتمد مباشرة على طول القيم داخل الحقول، وأبرزها اسم البائع الذي قد يطول أو يقصر، وقيم الإجمالي والضريبة التي تتفاوت في عدد الخانات. لذلك من الطبيعي أن يكون رمز فاتورة كبيرة أكثف بصريًا من رمز فاتورة صغيرة. هذا التفاوت لا يعني خطأ، لكنه يذكّر بأهمية اختبار الطباعة على أطول اسم بائع متوقع لضمان وضوح المسح.
هل يمكن تخزين الحقول المفكوكة في قاعدة بيانات مباشرة؟
يمكن ذلك بعد إجراء التحقق المنطقي أولًا: تأكد من نمط رقم الضريبة وصيغة الوقت وموجبية القيم المالية قبل الإدخال. تخزين بيانات غير مُتحقَّق منها يلوّث قاعدة البيانات بقيم قد تكون مشوّهة أو مزوّرة. الفصل بين الفك والتحقق يمنحك مرونة في تشديد القواعد حسب حساسية الاستخدام، فأرشفة المراجعة قد تقبل ما ترفضه أنظمة الدفع.
هل أداة الفك بديل عن تطبيق الهيئة الرسمي؟
لا؛ أداة الفك مرجع تقني للمطورين والمحاسبين لفهم محتوى الرمز والتحقق من تطابق الحقول، لكنها لا تحل محل تطبيق هيئة الزكاة الرسمي الذي يقدّم التحقق الميداني المعتمد للمستهلكين. استخدم الأداة في بيئة التطوير والمراجعة، واعتمد على القنوات الرسمية عند الحاجة إلى إثبات قانوني لصحة الفاتورة.
كيف أتعامل مع رمز مدمج في صورة منخفضة الجودة؟
إذا التُقط الرمز بكاميرا منخفضة الدقة فقد تظهر بايتات مشوّشة تفسد الفك، خصوصًا في الحقول الطويلة مثل الاسم والطابع الزمني. الحل الأفضل أخذ النص الخام من نظام نقطة البيع مباشرة بدل تصوير الورقة، أو إعادة المسح بإضاءة جيدة وزاوية مستقيمة. عند تعذّر ذلك، يكشف رمز الخطأ المنظم أي الحقول تضرر فتعيد المسح بدل تخمين القيم.
هل تختلف معالجة الفاصلة العشرية بين الدول؟
المواصفة تشترط النقطة فاصلةً عشرية لا الفاصلة العربية أو الأوروبية، لذلك يجب ألا يحوّل المولّد القيمة وفق إعدادات المنطقة المحلية. الخطأ الشائع أن ينتج نظام مضبوط على لغة معينة قيمة بفاصلة بدل نقطة فتفشل عند التحقق. ثبّت تنسيق الأرقام صراحةً عند توليد الرمز لتجنب اعتماد إعدادات النظام المتغيّرة.
ماذا أفعل عند وجود وسم غير معروف أكبر من تسعة؟
المواصفة الحالية تعرّف الوسوم من واحد إلى تسعة، لكن التصميم يسمح بإضافات مستقبلية. لذلك يجب أن يتجاهل المفكّك بصمت أي وسم أكبر من المعروف دون اعتباره خطأ، مع تسجيله في قائمة الوسوم الإضافية. هذا السلوك المتسامح هو جوهر توافق TLV الخلفي، فهو يضمن أن القارئات القديمة تستمر بالعمل حتى لو أضافت الهيئة حقولًا جديدة في تحديثات لاحقة.
هل يفيد فك الرمز في كشف الفواتير المزوّرة؟
نعم بشكل مباشر؛ من أكثر صور الاحتيال شيوعًا طباعة رقم ضريبي صحيح بصريًا على الورقة مع رمز يحمل رقمًا مختلفًا. فك الرمز ومقارنة الحقول المستخرجة بما هو مطبوع يكشف هذا التلاعب فورًا، وهو فحص بسيط يوصى به للمراجعين عند تدقيق الفواتير الواردة من موردين جدد قبل اعتمادها في السجلات المحاسبية.