الانتقال إلى المحتوى الرئيسي

فواتير المبيعات

يُنشئ POST /v1/sales-invoices فاتورة المبيعات ويصدرها في طلب واحد. لا توجد مرحلة مسودة، والفاتورة بعد إصدارها لا تُصحَّح إلا بإشعار دائن.

الخصم لا ينزل بالسعر عن الحد الأدنى للمنتج

إذا كان للمنتج حد أدنى لسعر البيع في كسور، فأي unitDiscount ينزل بسعر الوحدة عنه يُخفَّض تلقائياً إلى هذا الحد. والطلب ينجح مع ذلك، دون أي خطأ.

مثال: منتج سعره 100 ريال قبل الضريبة، وحده الأدنى 92 ريالاً شاملة الضريبة (80 ريالاً قبل الضريبة)، أقصى خصم عليه 20 ريالاً. إذا أرسلت unitDiscount: 50 فالفاتورة تطبّق 20 فقط.

اعتمد دائماً على قيمتي lines[].unitDiscount و total في الرد، وليس على ما أرسلته في الطلب. وإذا أرسلت payment.amount فقارنه بقيمة total في الرد.

الحقول المطلوبة​

كل طلب يرسل customerId و branchId و pricesIncludeVat و lines، وكل بند يرسل itemId و quantity. وإذا أرسلت payment فيجب أن يحمل paymentMethodId. ويجب أن تحمل كل فاتورة عميلاً محدداً، فلا يدعم الـ API البيع لعميل نقدي غير مسجّل.

فاتورة ضريبية أم مبسطة​

نوع العميل هو الذي يحدد نوع الفاتورة:

العميلالفاتورةهيئة الزكاة والضريبة والجمارك
شركةفاتورة ضريبية (standard)تعتمدها قبل الرد
فردفاتورة مبسطة (simplified)تُبلَّغ بها الهيئة بعد الرد

في الفاتورة الضريبية:

  • إذا اعتمدتها الهيئة: يرجع 201 مع zatca.status: "cleared" ورمز QR الذي أرجعته الهيئة.
  • إذا رفضتها الهيئة: يرجع 422 zatca_rejected ورسائل الهيئة في zatcaErrors، ولا يُحفظ أي شيء.
  • إذا لم ترد الهيئة في الوقت المحدد: يرجع 201 مع zatca.status: "pending"، وتعيد كسور إرسالها لاحقاً، فتصبح cleared، أو rejected مع رسائل الهيئة في zatca.errors. وفي الحالتين تبقى الفاتورة صادرة.

الفاتورة الضريبية تحتاج أيضاً عنوان العميل (الشركة) كاملاً مع الرقم الضريبي أو رقم الهوية (الخطأ customer_address_incomplete يوضح الناقص)، وفرعاً مربوطاً بالهيئة (branch_not_onboarded). وملفا PDF و XML يرجعان 409 invoice_not_cleared حتى تعتمدها الهيئة، ودائماً إذا رفضتها. أما الفاتورة المبسطة فملف PDF جاهز فوراً، وملف XML يرجع 409 invoice_not_cleared حتى تقبل الهيئة التبليغ بها، ودائماً إذا رفضتها.

الأسعار​

يحدد pricesIncludeVat هل كل قيم unitPrice و unitDiscount في الطلب شاملة الضريبة. البند الذي لا يحمل unitPrice يأخذ سعر المنتج في الكتالوج، أما المنتج الذي يختلف سعره حسب حجم السيارة فليس له سعر واحد في الكتالوج، فيجب إرسال unitPrice في بنده، وإلا يرجع 400 missing_parameter على lines[i].unitPrice.

تحفظ كسور كل سعر قبل الضريبة مقرّباً إلى الهللة، وتقرّب الضريبة مرة واحدة لكل نسبة على مستوى الفاتورة، بنفس طريقة الهيئة في حساب الإجمالي. والسعر الشامل للضريبة يُحوَّل أولاً، لذلك قد يختلف الإجمالي عمّا أرسلته بهللة: 12.00 شاملة الضريبة تصبح 10.43 قبل الضريبة وإجماليها 11.99. والرد يعرض مبالغ البنود دائماً قبل الضريبة. ولدفع فاتورة كهذه بالكامل أرسل payment بدون amount.

الدفع​

ما ترسلهالفاتورة
بدون paymentتُسجَّل على حساب العميل (للعميل من نوع شركة فقط، والعميل الفرد يرجع له 422 on_account_not_allowed)
payment بدون amountمدفوعة بالكامل
payment.amount أقل من الإجماليمدفوعة جزئياً، والباقي على حساب العميل (للعميل من نوع شركة فقط، والعميل الفرد يرجع له 422 on_account_not_allowed)
payment.amount أكبر من الإجماليتُرفض: 400 invalid_parameter

تقبل payment.amount منزلتين عشريتين على الأكثر. وقيمتا amountPaid و amountDue في الرد توضحان حالة الفاتورة.

قراءة الفواتير​

يعرض GET /v1/sales-invoices كل فاتورة صادرة في فروع المفتاح، أياً كانت القناة التي أنشأتها. ويضيف expand=customer بيانات العميل، ويحتاج صلاحية customers:read إلى جانب sales_invoices:read.