تخطَّ إلى المحتوى
Uttra

إصدار فاتورة إلكترونية متوافقة مع الزكاة من تطبيقك

في المرحلة الأولى من «فاتورة» يكفي أن يصدر تطبيقك الفاتورة إلكترونيًا بالحقول الإلزامية، ومع الفاتورة المبسطة رمز QR بصيغة TLV فيه اسم البائع ورقمه الضريبي والوقت والإجمالي والضريبة. في المرحلة الثانية تحتاج فاتورة XML بمعيار UBL 2.1 موقّعة ومربوطة بمنصة الهيئة، والأسلم أن يتم ذلك عبر حل فوترة معتمد.

آخر تحديث:

لماذا يحدث هذا: «فاتورة PDF جميلة» ليست فاتورة إلكترونية

حين تطلب من أداة ذكاء اصطناعي «أضف فاتورة ضريبية»، تحصل عادة على صفحة HTML أو ملف PDF فيه شعارك والمبلغ وعبارة «شامل الضريبة»، ومعه أحيانًا رمز QR يحمل رابط الفاتورة. هذا شكل فاتورة، لكنه لا يحقق متطلبات هيئة الزكاة والضريبة والجمارك. رمز QR في الفاتورة المبسطة ليس رابطًا، بل بيانات مرمّزة بصيغة محددة اسمها TLV ثم Base64، وتطبيق الهيئة للتحقق يقرأ هذه البيانات لا صفحة موقعك.

والخلط الثاني بين المرحلتين: المرحلة الأولى (الإصدار والحفظ) بدأت في 4 ديسمبر 2021 وتطلب إصدار الفاتورة وحفظها إلكترونيًا بحقولها الإلزامية. المرحلة الثانية (الربط والتكامل) تُطبَّق على المنشآت على موجات تحددها الهيئة وتُبلغ بها المنشأة مسبقًا، وفيها تصبح الفاتورة ملف XML موقّعًا يُرسَل إلى منصة «فاتورة». أداة الذكاء الاصطناعي لا تعرف في أي موجة أنت، فاعرف ذلك أولًا.

ما الذي تحتاجه

  • رقم التسجيل الضريبي المكوّن من 15 رقمًا والاسم المسجّل للمنشأة كما في شهادة التسجيل.
  • تحديد نوع الفاتورة: فاتورة ضريبية مبسطة للبيع للأفراد (B2C)، وفاتورة ضريبية (قياسية) للبيع لمنشأة مسجّلة (B2B) وتتضمن بيانات المشتري ورقمه الضريبي.
  • ترقيم تسلسلي فريد لا يُعاد استخدامه ولا تُحذف منه فاتورة؛ التصحيح يكون بإشعار دائن أو مدين.
  • ختم زمني بتوقيت ISO 8601 لكل فاتورة.
  • معرفة موجتك في المرحلة الثانية من إشعار الهيئة، وحل فوترة معتمد إن كنت مشمولًا.
الفرق العملي بين النوعين
فاتورة ضريبية مبسطةفاتورة ضريبية (قياسية)
لمنمستهلك فردمنشأة، غالبًا مسجّلة ضريبيًا
بيانات المشتريغير إلزامية في الغالبالاسم والعنوان والرقم الضريبي
رمز QRإلزاميإلزامي في المرحلة الثانية
المرحلة الثانيةتُرسل للهيئة خلال مدة محددة بعد الإصدار (Reporting)تُعتمد من الهيئة قبل تسليمها للمشتري (Clearance)

الشرح التنظيمي الكامل للمرحلتين والغرامات والجدول الزمني موجود في دليل الفوترة الإلكترونية وفي دليل الفواتير والضريبة. هنا نركّز على ما يكتبه تطبيقك فعليًا.

الحل خطوة بخطوة

  1. احسب الضريبة في الخادم وخزّن الأرقام

    احسب الإجمالي قبل الضريبة والضريبة 15% والإجمالي بعدها، بتقريب إلى منزلتين، واحفظها في جدول الفواتير مع رقم تسلسلي. لا تعِد حسابها عند كل عرض حتى لا تختلف الهللات.

  2. ابنِ حقول TLV الخمسة

    كل حقل يُكتب كبايت للرقم (Tag)، ثم بايت للطول بالبايتات، ثم القيمة بترميز UTF-8. انتبه: الطول بالبايتات لا بعدد الحروف، والحرف العربي يأخذ بايتين.

  3. رمّز النتيجة Base64 وحوّلها إلى QR

    النص الناتج هو ما يُوضع في رمز QR، لا رابط ولا JSON.

  4. اختبر الرمز بتطبيق الهيئة

    امسح الرمز بتطبيق التحقق الذي تنشره الهيئة، وتأكد أن الاسم العربي يظهر صحيحًا وأن المبالغ مطابقة.

  5. خطّط للمرحلة الثانية مبكرًا

    اجعل جدول الفواتير يحفظ كل ما يحتاجه ملف UBL لاحقًا: بنود الفاتورة، والكميات، ورمز الفئة الضريبية، ورقم الفاتورة السابقة وبصمتها (Hash).

zatca-qr.js: رمز QR للمرحلة الأولى بصيغة TLV ثم Base64 (Node 18+ أو المتصفح)
// Phase-1 QR: tags 1..5, each as [tag][length][UTF-8 value]
function tlv(tag, value) {
  const bytes = new TextEncoder().encode(String(value));
  if (bytes.length > 255) throw new Error(`Tag ${tag} is too long`);
  return Uint8Array.from([tag, bytes.length, ...bytes]);
}

export function zatcaQrBase64({ sellerName, vatNumber, timestamp, totalWithVat, vatAmount }) {
  const parts = [
    tlv(1, sellerName),
    tlv(2, vatNumber),
    tlv(3, timestamp),                 // ISO 8601, e.g. 2026-11-05T14:30:00Z
    tlv(4, Number(totalWithVat).toFixed(2)),
    tlv(5, Number(vatAmount).toFixed(2)),
  ];
  const all = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
  let i = 0;
  for (const p of parts) { all.set(p, i); i += p.length; }
  let bin = "";
  for (const b of all) bin += String.fromCharCode(b);
  return btoa(bin);
}

// Example: a coffee roastery in Riyadh
console.log(zatcaQrBase64({
  sellerName: "محمصة الريان",
  vatNumber: "300000000000003",
  timestamp: "2026-11-05T14:30:00Z",
  totalWithVat: 115,
  vatAmount: 15,
}));
عرض الرمز في صفحة الفاتورة بمكتبة qrcode
// npm i qrcode
import QRCode from "qrcode";
import { zatcaQrBase64 } from "./zatca-qr.js";

export async function invoiceQrDataUrl(invoice) {
  const payload = zatcaQrBase64({
    sellerName: invoice.sellerName,
    vatNumber: invoice.sellerVat,
    timestamp: invoice.issuedAt,
    totalWithVat: invoice.totalWithVat,
    vatAmount: invoice.vatAmount,
  });
  return QRCode.toDataURL(payload, { errorCorrectionLevel: "M", margin: 1 });
}

الرقم الضريبي في المثال للتوضيح فقط. وفي المرحلة الثانية يحتوي رمز الفاتورة المبسطة حقولًا إضافية (بصمة الفاتورة والتوقيع الرقمي والمفتاح العام وتوقيع الشهادة) تُولَّد من عملية التوقيع نفسها، فلا تحاول تقليدها يدويًا.

المرحلة الثانية: XML بمعيار UBL 2.1 وحل معتمد

في الربط والتكامل تصبح الفاتورة ملف XML وفق معيار UBL 2.1 بالمواصفات التي نشرتها الهيئة، يُوقَّع بشهادة تشفير تصدرها الهيئة لجهازك أو حلّك بعد التسجيل عبر بوابة المطورين (Onboarding)، ويُربط بسلسلة بصمات مع الفاتورة السابقة. ثم تُرسل الفاتورة إلى منصة «فاتورة»: القياسية للاعتماد قبل التسليم، والمبسطة للإبلاغ بعد الإصدار.

بناء هذا كله داخل تطبيق صغير ممكن تقنيًا، لكنه يعني إدارة الشهادات والتوقيع والتعامل مع رفض الفواتير وإعادة الإرسال. لمعظم المتاجر والمنشآت الصغيرة، مثل صالون في جدة أو متجر إلكتروني ناشئ، الأوفر وقتًا أن يتكامل تطبيقك مع حل فوترة إلكترونية معتمد عبر واجهته البرمجية: تطبيقك يرسل بيانات الفاتورة، والحل يولّد XML ويوقّعه ويرسله ويعيد لك الرمز والحالة.

برومبت لتجهيز التطبيق للمرحلة الثانيةجرّبه في أوترا

أنشئ جدول فواتير يحفظ لكل فاتورة: رقمًا تسلسليًا لا يتكرر، ونوعها (مبسطة أو ضريبية)، وبنودها بالكمية والسعر ورمز الفئة الضريبية، والإجمالي قبل الضريبة والضريبة 15% والإجمالي بعدها، وتاريخ الإصدار ISO 8601. أضف دالة تولّد رمز QR للمرحلة الأولى بصيغة TLV و Base64، واجعل إرسال الفاتورة لحل فوترة خارجي في وحدة مستقلة يمكن تفعيلها لاحقًا.

الحل الأسرع: أوترا

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

أوترا ليست حل فوترة إلكترونية معتمدًا من الهيئة، ولا تُصدر فواتير مشروعك الضريبية نيابة عنك؛ هي تبني لك الكود الذي يحسب ويخزن ويولّد الرمز، أو يرسل البيانات إلى الحل المعتمد الذي تختاره. والتحقق النهائي من الامتثال مسؤولية المنشأة ومحاسبها.

جرّبه في أوتراجرّبه في أوترا

أضف إلى متجري صفحة فاتورة ضريبية مبسطة بالعربية فيها اسم المتجر ورقمه الضريبي ورقم الفاتورة والبنود والضريبة 15%، مع رمز QR بصيغة TLV للمرحلة الأولى، وزر تنزيل PDF للعميل.

أسئلة شائعة

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

صفحات ذات صلة