لا توجد واجهة برمجية لدى زاتكا لتقديم الإقرار الضريبي. توجد واجهة «فاتورة» للفواتير — خمس نقاط نهاية، فاتورة واحدة في كل طلب، شهادات وتصديق وإبلاغ — ثم يوجد نموذج ويب من ستة عشر سطراً يكتب فيه إنسانٌ أرقاماً مرة كل شهر أو كل ربع سنة.
تلك الفجوة هي العمل كله. كل ما يسبق النموذج قابل للأتمتة، والنموذج نفسه ليس كذلك. لذلك فإن المحرك الذي تبنيه لا «يقدّم» شيئاً. إنه ينتج ستة عشر رقماً قابلة للدفاع عنها أمام الفحص، وينتج أوراق العمل التي تثبت من أين جاء كل رقم منها.
هذا الدليل يبني ذلك المحرك. وهو عن قصد ليس جولة في بوابة زاتكا — فهناك العشرات من تلك الأدلة، وصفحة الخدمة لدى زاتكا نفسها تتفوق عليها جميعاً. إنه الجزء الذي لا يكتبه أحد: كيف يصبح دفتر الأستاذ إقراراً، والمواضع الاثنا عشر تقريباً التي يكون فيها التوزيع خاطئاً بصمت في أنظمة تقدّم إقرارات منذ سنوات.
ما الذي ستبنيه
دالة computeVatReturn() تأخذ فترة ضريبية ودليل حسابات وقائمة بحركات دفتر الأستاذ، وتعيد:
- الخانات الست عشرة، لكل منها
amountوadjustmentوvat - أثر تدقيق لكل خانة يسرد الحركات التي غذّتها
- قائمة بالمسائل المانعة (ضريبة مدخلات يجب عكسها، صادرات تنقصها الأدلة، تصحيحات تتجاوز الحد وتستلزم تعديل الإقرار الأصلي بدلاً من الخانة 14)
بالإضافة إلى الأمرين اللذين يُنسيان دائماً: التسوية السنوية للخصم التناسبي التي تنتمي إلى الإقرار الأخير من السنة الميلادية، وعكس ضريبة المدخلات على المورد غير المسدَّد الذي لا ينفذه أي تقرير جاهز.
المتطلبات المسبقة
- Node.js 20+ و TypeScript 5.5+
- فهم عملي للقيد المزدوج — هذا الدليل يفترض أنك تعرف ما هو تقرير أعمار الدائنين
- إلمام بضريبة القيمة المضافة على مستوى الفاتورة. إن كان حساب الضريبة نفسه هو السؤال المفتوح، فابدأ من كيف تُحسب ضريبة القيمة المضافة السعودية بنسبة 15% ثم عد
- إن كنت تحتاج أيضاً إلى تصديق الفواتير لدى زاتكا فتلك سلسلة منفصلة: تكامل الفوترة الإلكترونية المرحلة الثانية بـ TypeScript
ملاحظة عن المصادر. النسخة الإنجليزية من اللائحة التنفيذية لنظام ضريبة القيمة المضافة على موقع زاتكا هي الإصدار الثامن بتاريخ 09/11/2021. أما النسخة العربية فهي النص المحدَّث السائد وتتضمن قراري مجلس الإدارة 01-04-23 و01-06-24. قاعدتان مما يلي — حد التصحيح وقائمة الضريبة غير القابلة للخصم — تختلفان بين النسختين. وحيث تختلفان، فالنص العربي هو الحاكم. أرقام المواد في هذا الدليل مأخوذة من النص العربي المحدَّث.
الخطوة 1: اعرف شكل النموذج قبل أن تنمذجه
الإقرار مكوّن من ستة عشر سطراً. الأسطر من 1 إلى 5 مبيعات، ومن 7 إلى 11 مشتريات، والأسطر 6 و12 و13 و15 و16 تحسبها البوابة. وكل سطر إدخال له ثلاثة أعمدة: المبلغ (ريال) والتعديل (ريال) ومبلغ ضريبة القيمة المضافة (ريال).
| الخانة | السطر |
|---|---|
| 1 | المبيعات الخاضعة للنسبة الأساسية |
| 2 | الخدمات التعليمية الأهلية والرعاية الصحية والمسكن الأول المقدمة للمواطنين |
| 3 | المبيعات المحلية الخاضعة لنسبة الصفر |
| 4 | الصادرات |
| 5 | المبيعات المعفاة |
| 6 | إجمالي المبيعات (محسوب) |
| 7 | المشتريات المحلية الخاضعة للنسبة الأساسية |
| 8 | الواردات الخاضعة للضريبة المسددة لدى الجمارك |
| 9 | الواردات الخاضعة للضريبة المحتسبة عبر آلية الاحتساب العكسي |
| 10 | المشتريات الخاضعة لنسبة الصفر |
| 11 | المشتريات المعفاة |
| 12 | إجمالي المشتريات (محسوب) |
| 13 | إجمالي الضريبة المستحقة عن الفترة الحالية (محسوب) |
| 14 | التصحيحات من الفترة السابقة |
| 15 | رصيد الضريبة المرحّل (محسوب) |
| 16 | صافي الضريبة المستحقة أو المطالب باستردادها (محسوب) |
ثلاث خصائص لهذا النموذج تحكم التصميم بأكمله، وكل واحدة منها موضعٌ تخطئ فيه التطبيقات.
المبالغ تُدخل غير شاملة للضريبة. البوابة تحسب عمود الضريبة بنفسها. دليل التقديم لدى زاتكا يقول ذلك مرتين، وهو أشيع خطأ في البيانات على قائمة الأخطاء الشائعة التي تنشرها الهيئة نفسها: إدخال مبالغ شاملة للضريبة يضخّم الخصم فوراً.
عمود التعديل طرحيّ، وتُدخله رقماً موجباً. البوابة تشتق الضريبة من amount - adjustment. المثال العملي لدى زاتكا: مشتريات بـ 20,000 تحمل ضريبة 3,000، منها 7,500 من الوعاء غير قابلة للخصم، تُدخل كمبلغ 20,000 وتعديل 7,500 — فيبقى وعاء قابل للخصم 12,500 وضريبة 1,875. كثير من الأنظمة تنمذج هذا رقماً سالباً أو سطراً عكسياً منفصلاً. وكلاهما ينتج إقراراً لا يتطابق.
الخانة 14 ليست كسائر الخانات. تُدخل فيها مبلغ ضريبة فقط، بلا وعاء. وزاتكا صريحة: «تتم تعبئة خانة التصحيحات عبر إدخال قيمة ضريبة القيمة المضافة فقط».
انمذج ذلك بأمانة:
// src/types.ts
/** الريال مخزَّن كعدد صحيح من الهللات. لا تستخدم الأعداد العشرية مع الضريبة أبداً. */
export type Halalas = number;
export interface BoxValue {
/** الوعاء غير الشامل للضريبة، بالهللات. */
amount: Halalas;
/** طرحيّ، يُدخل موجباً. البوابة تحسب الضريبة على (amount - adjustment). */
adjustment: Halalas;
/** ما نتوقع أن تحسبه البوابة. للمطابقة، لا للتقديم. */
vat: Halalas;
}
export type BoxId =
| 1 | 2 | 3 | 4 | 5 | 6
| 7 | 8 | 9 | 10 | 11 | 12
| 13 | 14 | 15 | 16;
export interface VatReturn {
taxpayerVatNumber: string;
periodStart: string; // ISO date
periodEnd: string; // ISO date
frequency: "monthly" | "quarterly";
boxes: Record<BoxId, BoxValue>;
/** أي سطور دفتر الأستاذ أنتجت أي خانة. هذه هي ورقة العمل. */
trail: Record<BoxId, string[]>;
issues: Issue[];
}
export interface Issue {
severity: "blocking" | "review";
code: string;
message: string;
reference?: string; // مادة اللائحة التنفيذية
transactionIds?: string[];
}أعداد صحيحة، دائماً. الهللة جزء من مئة من الريال. خزّن كل قيمة نقدية كعدد صحيح من الهللات ولا تقسم إلا في طبقة العرض. الحساب العشري على 15% من دفتر أستاذ كبير ينتج إقراراً يختلف بهللات، ومطابقة تلك الهللات مع حساب البوابة تحرق بعد ظهيرة كل شهر إلى الأبد.
الخطوة 2: حدّد الفترة قبل أن تجمع أي شيء
المادة 58 تحدد الفترة الضريبية. شهرية إذا تجاوزت التوريدات الخاضعة للضريبة خلال الاثني عشر شهراً السابقة 40,000,000 ريال، وثلاثة أشهر فيما عدا ذلك. ويجوز لمن هو دون الحد أن يتقدم بطلب للانتقال إلى الشهرية، ويسري من الفترة التالية للموافقة، وبعد سنتين على الشهرية يجوز له طلب العودة.
المادة 62(1) تحدد موعد التقديم: آخر يوم من الشهر التالي لانتهاء الفترة الضريبية. والمادة 59(1) تجعل السداد في التاريخ نفسه.
ثم تأتي القاعدة التي تولّد الغرامات بصمت. المادة 74(1): تقديم الإقرارات وسداد الضريبة يجب أن يتم في التاريخ المحدد أو قبله سواء كان يوم عمل أم لا. أما الالتزامات الأخرى فتُرحَّل إلى يوم العمل التالي، ويوم العمل هو أي يوم عدا الجمعة والسبت وأيام العطل الرسمية.
معظم مكتبات الجدولة تفعل العكس افتراضياً. موعد 31 يناير الذي يصادف يوم جمعة يظل 31 يناير.
// src/period.ts
import { Halalas } from "./types";
const MONTHLY_THRESHOLD: Halalas = 40_000_000_00; // 40 مليون ريال بالهللات
export function requiredFrequency(
taxableSuppliesLast12Months: Halalas,
optedIntoMonthly = false,
): "monthly" | "quarterly" {
// المادة 58(1): «تتجاوز» حرفياً، لا «تبلغ».
if (taxableSuppliesLast12Months > MONTHLY_THRESHOLD) return "monthly";
// المادة 58(3): الانتقال الاختياري إلى الشهرية جائز بطلب.
return optedIntoMonthly ? "monthly" : "quarterly";
}
/**
* المادة 62(1) + المادة 59(1): آخر يوم من الشهر التالي لانتهاء الفترة.
* المادة 74(1): لا مهلة لعطلة نهاية الأسبوع أو العطل الرسمية. لا ترحّل.
*/
export function filingDeadline(periodEnd: Date): Date {
return new Date(Date.UTC(
periodEnd.getUTCFullYear(),
periodEnd.getUTCMonth() + 2, // أول الشهر الذي يلي الشهر التالي
0, // اليوم 0 = آخر يوم من الشهر السابق
));
}الخطأ هنا يقودك إلى المادة 42(3) — غرامة تأخير التقديم بما لا يقل عن 5% ولا يزيد على 25% من قيمة الضريبة التي كان يتعين الإقرار عنها — إضافة إلى المادة 43، وهي 5% من قيمة الضريبة غير المسددة عن كل شهر أو جزء منه تبقى فيه غير مسددة.
الخطوة 3: صنّف كل حركة مرة واحدة
التوزيع من سطر دفتر الأستاذ إلى خانة هو مسألة تصنيف، ويستحق أن يُعزل. وكل ما بعده مجرد جمع.
// src/classify.ts
export type SupplyKind =
| "standard_rated_sale"
| "citizen_health_edu_housing"
| "zero_rated_domestic_sale"
| "export"
| "exempt_sale"
| "standard_rated_purchase"
| "import_vat_at_customs"
| "import_reverse_charge"
| "zero_rated_purchase"
| "exempt_purchase"
| "out_of_scope";
export interface ExportEvidence {
customsDocument?: string;
commercialDocument?: string;
transportDocument?: string;
}
export interface LedgerTxn {
id: string;
date: string; // ISO، تاريخ استحقاق الضريبة
direction: "sale" | "purchase";
/** الوعاء غير الشامل للضريبة بالهللات، بالريال بعد أي تحويل عملة. */
netAmount: number;
vatAmount: number;
vatRate: number; // 0.15 أو 0
/** المعفى والخاضع لنسبة الصفر كلاهما بضريبة 0. دليل الحسابات وحده يميّزهما. */
exemptSupply: boolean;
counterpartyVatNumber?: string;
counterpartyCountry: string; // ISO-3166 alpha-2
counterpartyResident: boolean;
/** يُضبط عندما تمر السلع فعلياً عبر الجمارك السعودية وتُسدَّد الضريبة هناك. */
customsDeclarationNumber?: string;
exportEvidence?: ExportEvidence;
// --- جانب المشتريات فقط ---
expenseCategory?: ExpenseCategory;
/** المادة 51(1)/(2)/(3): كيف ترتبط ضريبة المدخلات هذه بالنشاط. */
attribution?: "taxable" | "exempt" | "residual";
/** المادة 50(1): بند محظور أُعيد توريده كتوريد خاضع للضريبة. */
resuppliedAsTaxableSupply?: boolean;
/** المادة 50(1)(ب)/(ج): التزام نظامي في المملكة يرفع الحظر عن البند. */
statutoryObligation?: boolean;
/** تاريخ سداد المورد فعلياً. عدم وجوده يعني أنه ما زال غير مسدَّد. */
supplierPaidOn?: string;
isCapitalAsset?: boolean;
isNominalSupply?: boolean;
}
export const BOX_BY_KIND: Record<Exclude<SupplyKind, "out_of_scope">, number> = {
standard_rated_sale: 1,
citizen_health_edu_housing: 2,
zero_rated_domestic_sale: 3,
export: 4,
exempt_sale: 5,
standard_rated_purchase: 7,
import_vat_at_customs: 8,
import_reverse_charge: 9,
zero_rated_purchase: 10,
exempt_purchase: 11,
};قاعدة التصنيف التي تُسقط الأنظمة أكثر من غيرها هي الخانة 8 مقابل الخانة 9. كلتاهما واردات. وليستا متبادلتين:
- الخانة 8 ضريبة استيراد سُدِّدت فعلياً للجمارك السعودية عند الحدود. لديك بيان جمركي.
- الخانة 9 ضريبة تحتسبها بنفسك: الاحتساب العكسي بموجب المادة 47، وكذلك ضريبة الاستيراد المؤجلة بموجب المادة 44 لمن وافقت لهم الهيئة على سداد ضريبة الاستيراد عبر الإقرار بدلاً من الجمارك.
النظام الذي يبني قراره على «هل الطرف الآخر أجنبي؟» سيوجّه كلتيهما إلى المكان نفسه. الفيصل هو ما إذا كانت الجمارك السعودية قد حصّلت الضريبة.
export function classify(txn: LedgerTxn): SupplyKind {
if (txn.direction === "sale") {
if (!txn.counterpartyResident || txn.counterpartyCountry !== "SA") return "export";
if (txn.vatRate === 0.15) return "standard_rated_sale";
// المعفى مقابل الخاضع لنسبة الصفر خاصية للتوريد لا للنسبة المحصّلة.
// كلاهما يظهر بضريبة 0. دليل الحسابات وحده يعرف أيهما أي.
return txn.exemptSupply ? "exempt_sale" : "zero_rated_domestic_sale";
}
if (!txn.counterpartyResident) {
// تأجيل المادة 44 والاحتساب العكسي في المادة 47 كلاهما في الخانة 9.
// الفيصل هو التحصيل الجمركي، لا بلد الطرف الآخر.
return txn.customsDeclarationNumber
? "import_vat_at_customs"
: "import_reverse_charge";
}
if (txn.vatRate === 0.15) return "standard_rated_purchase";
return txn.exemptSupply ? "exempt_purchase" : "zero_rated_purchase";
}الخطوة 4: الخانة 9 سطر واحد مُصفّى، لا سطران
هذه هي التي تفاجئ من نفّذ الاحتساب العكسي في الاتحاد الأوروبي أو المملكة المتحدة، حيث تقيّد سطر مخرجات وسطر مدخلات يلغي أحدهما الآخر.
دليل الاستيراد والتصدير لدى زاتكا صريح: الضريبة المحتسبة عبر آلية الاحتساب العكسي تُدرج في الحقل 9، ونموذج الإقرار يعامل ضريبة المدخلات تلقائياً على أنها قابلة للخصم. أما الخاضعون الذين لا يحق لهم خصم ضريبة المدخلات بالكامل فعليهم إجراء التعديلات اللازمة في الحقل 9.
فالخانة 9 إذن لا تحمل سطر مخرجات منفصلاً. إن كنت خاضعاً بالكامل فصافي الضريبة على ذلك السطر صفر ولا تُدخل تعديلاً. وإن كنت معفياً جزئياً فعمود التعديل هو موضع استرداد الحصة غير القابلة للخصم — وإن تركته فارغاً فقد أقررت بأقل من المستحق.
المثال العملي لدى زاتكا نفسها، بنك بنسبة استرداد 70% يتلقى خدمات قانونية أجنبية بـ 100,000 ريال: المبلغ 100,000، والتعديل 30,000. (المثال المنشور يستخدم نسبة 5% القديمة فيكون رقم الضريبة فيه 1,500؛ وبنسبة 15% يعطي الشكل نفسه 10,500.)
// src/box9.ts
import { Halalas } from "./types";
/**
* الاحتساب العكسي في المادة 47، كما ينمذجه الإقرار فعلياً.
* النموذج يخصم بالكامل تلقائياً، فالشيء الوحيد الذي يجعل إقرار المعفي جزئياً
* صحيحاً هو التعديل.
*/
export function box9(
reverseChargeBase: Halalas,
recoveryRate: number, // 0..1، من الخصم التناسبي في المادة 51
): { amount: Halalas; adjustment: Halalas; vat: Halalas } {
const nonRecoverableBase = Math.round(reverseChargeBase * (1 - recoveryRate));
const deductibleBase = reverseChargeBase - nonRecoverableBase;
return {
amount: reverseChargeBase,
adjustment: nonRecoverableBase,
vat: Math.round(deductibleBase * 0.15),
};
}وقاعدة أخرى في الخانة 9 تكلّف مالاً في الاتجاه المعاكس: تلقّي خدمة معفاة من غير مقيم — قرض أجنبي مثلاً — لا يُدرج إطلاقاً. والأنظمة التي تطبّق الاحتساب العكسي على كل فاتورة أجنبية تضخّم طرفي الإقرار بلا سبب وتستدعي الأسئلة.
الخطوة 5: ضريبة المدخلات غير القابلة للخصم — المادة 50 تغيّرت في 2024
إن كنت قد برمجت هذه القائمة من النسخة الإنجليزية للإصدار الثامن، أو من مقال مدونة، فهي متجاوَزة. القرار 01-06-24 عدّل المادة 50، ويسري اعتباراً من 18 أبريل 2025. القائمة الحالية لضريبة المدخلات غير القابلة للخصم، ما لم يُعَد توريد البند كتوريد خاضع للضريبة:
- (أ) أي شكل من أشكال الخدمات الترفيهية أو الرياضية أو الثقافية، أو حضور فعاليات ذات طابع ترفيهي
- (ب) الضيافة وتقديم المأكولات والمشروبات — ما لم يُلزم نظامٌ نافذ في المملكة الخاضع بتقديمها للموظفين في مقر العمل
- (ج) خدمات التأمين أو الرعاية الصحية المقدمة للموظفين ومن يعولون، ما لم تكن إلزامية نظاماً — وهذا البند جديد
- (د) شراء أو استئجار المركبات المقيدة
- (هـ) التأمين على المركبات المقيدة، أو إصلاحها أو تعديلها أو صيانتها
- (و) الوقود المستخدم في المركبات المقيدة
- (ز) أي سلع أو خدمات مقتناة للاستخدام الشخصي أو لأغراض غير النشاط
كما أعادت المادة 50(2) تعريف «المركبة المقيدة». صارت أي مركبة مصممة لنقل ما لا يزيد على عشرة أشخاص، باستثناء: الشاحنات والرافعات والمعدات الثقيلة المشابهة المستخدمة حصراً في النشاط وغير المتاحة للاستخدام الخاص؛ والمركبات المشتراة أو المستأجرة لإعادة توريدها بالبيع أو التأجير كتوريد خاضع للضريبة؛ والمركبات المسجلة كمركبات طوارئ؛ والمركبات المستخدمة حصراً في النشاط وغير المتاحة للاستخدام الخاص.
كان المعيار القديم «أي مركبة مصممة للاستخدام على الطريق». وقاعدة عدد المقاعد مسألة تصنيف مختلفة جوهرياً: فهي خاصية لطراز المركبة لا لحساب المصروف، ومن ثم مكانها سجل الأصول أو الأسطول لديك، لا جدول ربط في دليل الحسابات.
// src/blocked.ts
export type ExpenseCategory =
| "entertainment"
| "hospitality_catering"
| "employee_insurance_healthcare"
| "restricted_vehicle_acquisition"
| "restricted_vehicle_insurance_maintenance"
| "restricted_vehicle_fuel"
| "personal_use"
| "business";
export interface BlockingContext {
/** المادة 50(1): البنود المحظورة تصبح قابلة للخصم إذا أُعيد توريدها خاضعة. */
resuppliedAsTaxableSupply: boolean;
/** المادة 50(1)(ب) و(ج): التزام نظامي سعودي يرفع الحظر عن هذين البندين. */
statutoryObligation: boolean;
}
const ALWAYS_BLOCKED: ExpenseCategory[] = [
"entertainment",
"restricted_vehicle_acquisition",
"restricted_vehicle_insurance_maintenance",
"restricted_vehicle_fuel",
"personal_use",
];
const UNBLOCKED_BY_STATUTE: ExpenseCategory[] = [
"hospitality_catering", // 50(1)(ب): تقديم إلزامي نظاماً في مقر العمل
"employee_insurance_healthcare", // 50(1)(ج): أُضيف بالقرار 01-06-24
];
export function isInputTaxBlocked(
category: ExpenseCategory,
ctx: BlockingContext,
): boolean {
if (category === "business") return false;
if (ctx.resuppliedAsTaxableSupply) return false;
if (UNBLOCKED_BY_STATUTE.includes(category)) return !ctx.statutoryObligation;
return ALWAYS_BLOCKED.includes(category);
}
/**
* المادة 50(2) بعد التعديل: عدد المقاعد، مع أربعة استثناءات.
* هذه بيانات سجل المركبات، لا بيانات دليل الحسابات.
*/
export function isRestrictedMotorVehicle(v: {
seatingCapacity: number;
usedExclusivelyForActivity: boolean;
availableForPrivateUse: boolean;
heldForOnwardSupplyOrLease: boolean;
registeredEmergencyVehicle: boolean;
isHeavyEquipment: boolean;
}): boolean {
if (v.seatingCapacity > 10) return false;
if (v.heldForOnwardSupplyOrLease) return false;
if (v.registeredEmergencyVehicle) return false;
if (v.isHeavyEquipment && v.usedExclusivelyForActivity && !v.availableForPrivateUse) return false;
if (v.usedExclusivelyForActivity && !v.availableForPrivateUse) return false;
return true;
}ضريبة المدخلات المحظورة تُدرج في عمود التعديل بالخانة 7 — الوعاء لا الضريبة. وهذا بالضبط شكل مثال زاتكا 20,000 / 7,500.
الخطوة 6: الخصم التناسبي — المادة 51، والتسوية السنوية
إذا كان النشاط يقدّم توريدات خاضعة ومعفاة معاً، فمعظم ضريبة المدخلات ليست قابلة للخصم بالكامل. والمادة 51 تحدد الطريقة:
- 51(1) ضريبة المدخلات المنسوبة حصراً ومباشرة إلى التوريدات الخاضعة قابلة للخصم بالكامل.
- 51(2) المنسوبة حصراً إلى التوريدات المعفاة غير قابلة للخصم إطلاقاً.
- 51(3)–(4) ما عدا ذلك يستخدم كسراً: قيمة التوريدات الخاضعة في السنة الميلادية الأخيرة على قيمة التوريدات الخاضعة والمعفاة في السنة الميلادية الأخيرة. والتوريدات المقدمة خارج المملكة تُحتسب على أساس معاملتها لو قُدِّمت داخلها.
- 51(5) الكسر يستثني توريدات الأصول الرأسمالية والتوريدات المقدمة من منشأة للخاضع خارج المملكة.
- 51(6) غير المسجَّل في السنة السابقة يستخدم قيماً تقديرية للسنة الحالية.
- 51(7) في نهاية السنة الميلادية، تُقارن القيم المستخدمة بالفعلية وتُعدَّل ضريبة المدخلات في الإقرار الأخير من تلك السنة الميلادية.
ولا توجد قاعدة تقريب لنسبة الاسترداد. لا تستورد قاعدة «التقريب لأقرب نسبة صحيحة» من الممارسة البريطانية أو الأوروبية — فهي غير موجودة هنا، وتقريب 82.3% إلى 83% يضخّم خصمك.
// src/apportionment.ts
export interface AnnualSupplyValues {
taxableSupplies: number; // باستثناء الأصول الرأسمالية والمنشآت الخارجية (51(5))
exemptSupplies: number; // كذلك
}
/**
* المادة 51(3)-(5). تعيد نسبة غير مقرَّبة بين 0 و1.
* لا توجد قاعدة نظامية لتقريب هذه النسبة في المملكة. احتفظ بالدقة الكاملة.
*/
export function recoveryRate(prior: AnnualSupplyValues): number {
const denominator = prior.taxableSupplies + prior.exemptSupplies;
if (denominator === 0) return 1;
return prior.taxableSupplies / denominator;
}
/**
* المادة 51(7): التعديل السنوي إلزامي في الإقرار الأخير من السنة الميلادية —
* ديسمبر لمن يقدّم شهرياً، والربع الرابع لمن يقدّم ربع سنوي.
* النتيجة الموجبة = خصم إضافي. السالبة = استرداد من الخصم.
*/
export function annualApportionmentAdjustment(
residualInputTaxForYear: number,
rateUsedDuringYear: number,
actual: AnnualSupplyValues,
): number {
const actualRate = recoveryRate(actual);
return Math.round(residualInputTaxForYear * (actualRate - rateUsedDuringYear));
}
export function isFinalReturnOfCalendarYear(
periodEnd: Date,
frequency: "monthly" | "quarterly",
): boolean {
const isDecemberEnd = periodEnd.getUTCMonth() === 11;
return frequency === "monthly"
? isDecemberEnd
: isDecemberEnd && periodEnd.getUTCDate() === 31;
}وهناك جاران يستحقان الربط في الوقت نفسه. المادة 52 توجب تعديلات الأصول الرأسمالية على مدى فترة تعديل قدرها ست سنوات للأصول المنقولة الملموسة وغير الملموسة وعشر سنوات للعقارية — وهو ما يستلزم سجل أصول يحمل نسبة الاسترداد المطبقة عند الاقتناء، لا مجرد وحدة أصول ثابتة. والمادة 51(8)–(9) تجيزان طريقة بديلة بطلب إن كانت تعكس الاستخدام الفعلي بصورة أدق، لمدة تحددها الهيئة بحد أقصى خمس سنوات، ثم يُعاد التقدم بالطلب.
الخطوة 7: حد التصحيح هو 15,000 ريال
هذا هو الرقم الذي ما زالت معظم أدوات المحاسبة السعودية تخطئ فيه.
المادة 63(3) عُدِّلت بقرار مجلس الإدارة 01-04-23 بتاريخ 26/11/1444هـ، ويسري من 23 يونيو 2023. الحد الذي يجوز دونه إدراج النقص في الإقرار التالي، بدلاً من تعديل الإقرار الأصلي، ارتفع من 5,000 ريال إلى 15,000 ريال.
المادة 63 بصيغتها الحالية:
- 63(1) يجب إشعار الهيئة بالنقص في صافي الضريبة خلال 20 يوماً من العلم به، وذلك بتعديل الإقرار المقدَّم سابقاً — ما لم تنطبق 63(3).
- 63(2) الزيادة يجوز خصمها من صافي الضريبة المستحقة في أي إقرار لاحق بعد اكتشافها، مع مراعاة 63(4).
- 63(3) الاستثناء: النقص الذي يقل صافي قيمته عن 15,000 ريال يُضاف إلى صافي الضريبة المستحقة في إقرار الفترة التي اكتُشف فيها الخطأ. وذلك هو الخانة 14.
- 63(4) لا يجوز تصحيح الزيادة بعد خمس سنوات من نهاية السنة الميلادية التي تقع فيها الفترة الضريبية.
- 63(5) كل تصحيح يجب أن يبيّن الفترة أو الفترات، وضريبة المخرجات والمدخلات محل التصحيح لكل فترة، والسبب.
والحد صارم: أقل من 15,000، لا 15,000 فما دون.
ولماذا يهم هذا أكثر مما يهم حدٌّ عادة؟ لأن المادة 42(1) من نظام الضريبة تفرض غرامة 50% من الفرق على تقديم إقرار غير صحيح، أو تقديم مستند ينتج عنه احتساب الضريبة بأقل من المستحق — وكذلك، بنصها، على تعديل الإقرار بعد تقديمه. والتصحيح داخل الخانة 14 بموجب 63(3) يتجنب التعديل كلياً. وبرمجة الحد على 5,000 تدفع تصحيحاً مشروعاً تماماً بقيمة 12,000 إلى مسار التعديل وإلى نطاق مادة عقوبات لم يكن بحاجة إلى ملامستها.
// src/corrections.ts
/** المادة 63(3) بعد تعديل 23 يونيو 2023. ليست 5,000. وأقل من، حرفياً. */
export const CORRECTION_THRESHOLD = 15_000_00; // بالهللات
export interface PriorPeriodError {
id: string;
periodEnd: string;
/** الموجب = نقص في الإقرار. السالب = زيادة. بالهللات. */
netVatEffect: number;
reason: string;
discoveredOn: string;
}
export function routeCorrections(errors: PriorPeriodError[], now: Date) {
const box14: PriorPeriodError[] = [];
const requiresAmendment: PriorPeriodError[] = [];
const timeBarred: PriorPeriodError[] = [];
for (const e of errors) {
if (e.netVatEffect < 0) {
// المادة 63(4): خمس سنوات من نهاية السنة الميلادية للفترة.
const deadline = Date.UTC(new Date(e.periodEnd).getUTCFullYear() + 6, 0, 1);
(now.getTime() >= deadline ? timeBarred : box14).push(e);
continue;
}
// المادة 63(1) مقابل 63(3).
(e.netVatEffect < CORRECTION_THRESHOLD ? box14 : requiresAmendment).push(e);
}
return {
box14Vat: box14.reduce((sum, e) => sum + e.netVatEffect, 0),
box14,
requiresAmendment, // المادة 63(1): الإشعار خلال 20 يوماً
timeBarred,
};
}وتذكّر أن الخانة 14 تأخذ مبلغ ضريبة فقط. لا وعاء ولا تعديل في ذلك السطر.
الخطوة 8: الفحوص التي لا يؤتمتها أحد
كل ما سبق ينتج إقراراً يتطابق. وهذه هي القواعد التي تجعله صحيحاً، وهي التي يجدها الربط الضريبي لأنها كلها ظاهرة من تقارير بحوزة المدقق أصلاً.
المادة 40(10): عكس ضريبة المدخلات على المورد غير المسدَّد. إذا خصمت ضريبة مدخلات ولم تسدد للمورد خلال اثني عشر شهراً من تاريخ التوريد، وجب عليك تخفيض الخصم. والمادة 40(11) تعيده عند السداد لاحقاً. وهذا يستلزم ربط أعمار الدائنين بسجل الضريبة. ولا يكاد نظام جاهز يفعله — بينما يجده المدقق في أربع دقائق من كشف أعمار الدائنين.
المادة 32: أدلة التصدير خلال 90 يوماً. تسقط نسبة الصفر إن لم تحتفظ بالأدلة خلال تسعين يوماً من التوريد، والأدلة مجموعة ثلاثية: مستندات التصدير الجمركية، ومستندات تجارية تحدد العميل ومكان التسليم، ومستندات النقل. وقاعدة «عنوان العميل أجنبي، إذن نسبة صفر» هي أشيع ربط تصدير على الإطلاق.
المادة 61: تحويل العملة بسعر ساما اليومي في تاريخ استحقاق الضريبة. لا تاريخ الفاتورة، ولا سعر نهاية الشهر، ولا سعر سياسة المجموعة. أنظمة تخطيط الموارد تستخدم جدول أسعارها افتراضياً ولا ينتبه أحد حتى المطابقة.
المادة 62(2)(ج) والمادة 15: التوريدات الاعتبارية. يجب الإفصاح عن التوريدات الحكمية. والهدايا والعينات والسلع الممنوحة للموظفين معفاة فقط حتى 200 ريال لكل متلقٍّ في السنة الميلادية، وبحد إجمالي 50,000 ريال في السنة الميلادية. والهدايا التسويقية ومزايا الموظفين المقيدة مباشرة على حساب مصروف لا تصل إلى محرك الضريبة إطلاقاً.
المادة 49(8): يجوز خصم ضريبة المدخلات لاحقاً، لكن بما لا يتجاوز خمس سنوات ميلادية بعد السنة الميلادية للتوريد. فاستدراك الفواتير المتأخرة يحتاج بوابة عمر.
المادة 49(7)(أ): الفاتورة الضريبية المبسطة الصادرة بشكل صحيح دليل بديل مقبول للخصم. وهذه هي الخطأ المعاكس — البرمجيات التي تمنع الاسترداد نهائياً بدون فاتورة ضريبية كاملة تطالب بأقل من حقها. وإن فاجأتك هذه القاعدة فالتفصيل في قاعدة الفاتورة الضريبية المبسطة التي يخطئ فيها الجميع.
المادة 54، الجديدة في 2024: إشعارات الدائن والمدين خلال خمسة عشر يوماً من نهاية الشهر الذي وقع فيه الحدث الموجب. والأنظمة التي تجمّع إشعارات الدائن عند إقفال الربع تخالف الآن موعداً صارماً.
المادة 66 والحفظ. ست سنوات عموماً — لكن دليل زاتكا يحدد إحدى عشرة سنة لسجلات الأصول الرأسمالية المنقولة وخمس عشرة للعقارية، لأن فترة التعديل في المادة 52 تجري أولاً ثم تجري الخمس سنوات بعدها.
// src/checks.ts
import { Issue, LedgerTxn } from "./types";
const DAY = 86_400_000;
export function runComplianceChecks(txns: LedgerTxn[], periodEnd: Date): Issue[] {
const issues: Issue[] = [];
// المادة 40(10): ضريبة مدخلات مخصومة ومورد غير مسدَّد بعد 12 شهراً.
const unpaid = txns.filter((t) =>
t.direction === "purchase" &&
t.vatAmount > 0 &&
!t.supplierPaidOn &&
periodEnd.getTime() - Date.parse(t.date) > 365 * DAY,
);
if (unpaid.length) {
issues.push({
severity: "blocking",
code: "UNPAID_SUPPLIER_REVERSAL",
reference: "اللائحة التنفيذية، المادة 40(10)",
message:
`${unpaid.length} عملية شراء بضريبة مدخلات مخصومة ما زالت غير مسددة بعد 12 شهراً. ` +
`يجب عكس الخصم، ويُعاد عند السداد بموجب المادة 40(11).`,
transactionIds: unpaid.map((t) => t.id),
});
}
// المادة 32: يجب الاحتفاظ بأدلة التصدير خلال 90 يوماً.
const staleExports = txns.filter((t) =>
t.direction === "sale" &&
t.counterpartyCountry !== "SA" &&
!hasCompleteExportEvidence(t) &&
periodEnd.getTime() - Date.parse(t.date) > 90 * DAY,
);
if (staleExports.length) {
issues.push({
severity: "blocking",
code: "EXPORT_EVIDENCE_MISSING",
reference: "اللائحة التنفيذية، المادة 32",
message:
`${staleExports.length} عملية تصدير تنقصها مجموعة الأدلة الكاملة بعد 90 يوماً. ` +
`تسقط نسبة الصفر، فتنتقل من الخانة 4 إلى الخانة 1 بنسبة 15%.`,
transactionIds: staleExports.map((t) => t.id),
});
}
// المادة 49(8): ضريبة مدخلات أقدم من خمس سنوات ميلادية.
const cutoff = Date.UTC(periodEnd.getUTCFullYear() - 5, 0, 1);
const stale = txns.filter(
(t) => t.direction === "purchase" && t.vatAmount > 0 && Date.parse(t.date) < cutoff,
);
if (stale.length) {
issues.push({
severity: "blocking",
code: "INPUT_TAX_TIME_BARRED",
reference: "اللائحة التنفيذية، المادة 49(8)",
message: `${stale.length} عملية شراء تقع خارج نافذة الخصم البالغة خمس سنوات.`,
transactionIds: stale.map((t) => t.id),
});
}
return issues;
}
function hasCompleteExportEvidence(t: LedgerTxn): boolean {
const e = t.exportEvidence;
return Boolean(e?.customsDocument && e?.commercialDocument && e?.transportDocument);
}الخطوة 9: تجميع الإقرار
// src/compute.ts
import { BoxId, BoxValue, Issue, LedgerTxn, VatReturn } from "./types";
import { classify, BOX_BY_KIND } from "./classify";
import { isInputTaxBlocked } from "./blocked";
import { recoveryRate, annualApportionmentAdjustment, isFinalReturnOfCalendarYear } from "./apportionment";
import { routeCorrections, PriorPeriodError } from "./corrections";
import { runComplianceChecks } from "./checks";
const emptyBox = (): BoxValue => ({ amount: 0, adjustment: 0, vat: 0 });
export interface ComputeInput {
taxpayerVatNumber: string;
periodStart: Date;
periodEnd: Date;
frequency: "monthly" | "quarterly";
transactions: LedgerTxn[];
priorErrors: PriorPeriodError[];
priorYearSupplies: { taxableSupplies: number; exemptSupplies: number };
actualYearSupplies?: { taxableSupplies: number; exemptSupplies: number };
residualInputTaxForYear?: number;
creditCarriedForward: number;
}
export function computeVatReturn(input: ComputeInput): VatReturn {
const boxes = Object.fromEntries(
Array.from({ length: 16 }, (_, i) => [i + 1, emptyBox()]),
) as Record<BoxId, BoxValue>;
const trail = Object.fromEntries(
Array.from({ length: 16 }, (_, i) => [i + 1, [] as string[]]),
) as Record<BoxId, string[]>;
const issues: Issue[] = [];
const rate = recoveryRate(input.priorYearSupplies);
for (const txn of input.transactions) {
const kind = classify(txn);
if (kind === "out_of_scope") continue;
const box = BOX_BY_KIND[kind] as BoxId;
boxes[box].amount += txn.netAmount;
trail[box].push(txn.id);
if (txn.direction !== "purchase") {
boxes[box].vat += txn.vatAmount;
continue;
}
// المشتريات: احسب كم من الوعاء غير قابل للخصم.
// عمود التعديل طرحيّ ويُدخل موجباً.
let nonDeductibleBase = 0;
const blocked = isInputTaxBlocked(txn.expenseCategory ?? "business", {
resuppliedAsTaxableSupply: txn.resuppliedAsTaxableSupply ?? false,
statutoryObligation: txn.statutoryObligation ?? false,
});
if (blocked) {
// المادة 50: لا شيء منه قابل للخصم.
nonDeductibleBase = txn.netAmount;
} else if (txn.attribution === "exempt") {
// المادة 51(2).
nonDeductibleBase = txn.netAmount;
} else if (txn.attribution === "residual") {
// المادة 51(3)-(4). الأصول الرأسمالية مستثناة من الكسر (51(5))
// لكن ضريبة المدخلات عليها تخضع للنسبة مع ذلك.
nonDeductibleBase = Math.round(txn.netAmount * (1 - rate));
}
// attribution === "taxable" -> المادة 51(1)، خصم كامل، بلا تعديل.
boxes[box].adjustment += nonDeductibleBase;
boxes[box].vat += Math.round((txn.netAmount - nonDeductibleBase) * txn.vatRate);
}
// المادة 51(7): التسوية السنوية تنتمي إلى الإقرار الأخير من السنة.
if (
isFinalReturnOfCalendarYear(input.periodEnd, input.frequency) &&
input.actualYearSupplies &&
input.residualInputTaxForYear !== undefined
) {
const trueUp = annualApportionmentAdjustment(
input.residualInputTaxForYear,
rate,
input.actualYearSupplies,
);
if (trueUp !== 0) {
issues.push({
severity: "review",
code: "ANNUAL_APPORTIONMENT_TRUEUP",
reference: "اللائحة التنفيذية، المادة 51(7)",
message:
`تعديل الخصم التناسبي السنوي بقيمة ${(trueUp / 100).toFixed(2)} ريال مستحق ` +
`في هذا الإقرار. النسبة المستخدمة خلال السنة: ` +
`${(rate * 100).toFixed(4)}%; والفعلية: ` +
`${(recoveryRate(input.actualYearSupplies) * 100).toFixed(4)}%.`,
});
}
}
// الأسطر المحسوبة.
boxes[6] = sumBoxes(boxes, [1, 2, 3, 4, 5]);
boxes[12] = sumBoxes(boxes, [7, 8, 9, 10, 11]);
const outputVat = [1, 2, 3, 4, 5].reduce((s, b) => s + boxes[b as BoxId].vat, 0);
const inputVat = [7, 8, 9, 10, 11].reduce((s, b) => s + boxes[b as BoxId].vat, 0);
boxes[13] = { amount: 0, adjustment: 0, vat: outputVat - inputVat };
// المادة 63: الخانة 14 تحمل مبلغ ضريبة فقط.
const corrections = routeCorrections(input.priorErrors, input.periodEnd);
boxes[14] = { amount: 0, adjustment: 0, vat: corrections.box14Vat };
for (const e of corrections.requiresAmendment) {
issues.push({
severity: "blocking",
code: "CORRECTION_EXCEEDS_THRESHOLD",
reference: "اللائحة التنفيذية، المادة 63(1) و63(3)",
message:
`الخطأ ${e.id} ينقص الضريبة بمقدار ${(e.netVatEffect / 100).toFixed(2)} ريال، ` +
`أي عند حد 15,000 ريال أو فوقه. لا يجوز إدراجه في الخانة 14. ` +
`عدّل الإقرار الأصلي خلال 20 يوماً من الاكتشاف.`,
transactionIds: [e.id],
});
}
// المادة 69(6): الأصل هو الترحيل. الاسترداد لا يقع إلا بطلب.
boxes[15] = { amount: 0, adjustment: 0, vat: input.creditCarriedForward };
boxes[16] = {
amount: 0,
adjustment: 0,
vat: boxes[13].vat + boxes[14].vat - boxes[15].vat,
};
issues.push(...runComplianceChecks(input.transactions, input.periodEnd));
return {
taxpayerVatNumber: input.taxpayerVatNumber,
periodStart: input.periodStart.toISOString().slice(0, 10),
periodEnd: input.periodEnd.toISOString().slice(0, 10),
frequency: input.frequency,
boxes,
trail,
issues,
};
}
function sumBoxes(boxes: Record<BoxId, BoxValue>, ids: number[]): BoxValue {
return ids.reduce<BoxValue>(
(acc, id) => ({
amount: acc.amount + boxes[id as BoxId].amount,
adjustment: acc.adjustment + boxes[id as BoxId].adjustment,
vat: acc.vat + boxes[id as BoxId].vat,
}),
emptyBox(),
);
}الخطوة 10: الرصيد والاسترداد والتسليم
المادة 69 تحكم ما يحدث حين تخرج الخانة 16 سالبة. ثلاثة أمور تستحق البرمجة:
- 69(6) الأصل هو الترحيل. والاسترداد لا يقع إلا إذا طلبته. والنظام الذي يعلن تلقائياً «استرداد مستحق» يصف نتيجة لم يطلبها أحد.
- 69(2) يجوز تقديم الطلب عند تقديم الإقرار، أو في أي وقت آخر خلال خمس سنوات تلي نهاية السنة الميلادية التي تتعلق بها الظروف.
- 69(3) للهيئة رفض طلب الاسترداد إذا كانت هناك إقرارات لم تُقدَّم — فإن كان محركك قد أشّر على فترة ناقصة، فالاسترداد لن يمضي.
- 69(4) بعد الموافقة، على الهيئة إنهاء الإجراء وبدء السداد خلال ستين يوماً بتحويل بنكي.
- 69(5) للهيئة مقاصة الرصيد مقابل مبالغ أخرى مستحقة. وتعديل 2024 وسّع ذلك ليشمل أي مبالغ مستحقة بموجب أي لائحة تطبقها الهيئة — بما فيها الغرامات الجمركية.
ثم يأتي الجزء الذي ليس شفرة. مخرجات computeVatReturn() هي ستة عشر رقماً يكتبها إنسان في البوابة، وأثرٌ يبرر كل واحد منها.
اجعل مستند التسليم يقوم بالعمل: صفحة واحدة تلخص الخانات الست عشرة بترتيب البوابة، وخلفها كشف الحركات لكل خانة. وحين تسأل زاتكا بعد ثمانية عشر شهراً من أين جاء تعديل الخانة 7، يكون الجواب ملفاً لا مشروع تنقيب.
اختبار التنفيذ
اختبر القواعد، لا المجاميع. نجاح المجاميع يخبرك أن الحساب يعمل؛ ولا يخبرك شيئاً عمّا إذا كانت الخانتان 8 و9 في موضعيهما الصحيحين.
// src/__tests__/return.test.ts
import { describe, expect, it } from "vitest";
import { box9 } from "../box9";
import { routeCorrections, CORRECTION_THRESHOLD } from "../corrections";
import { classify } from "../classify";
import { filingDeadline } from "../period";
describe("الاحتساب العكسي في المادة 47، الخانة 9", () => {
it("يصفّي الضريبة إلى صفر للنشاط الخاضع بالكامل", () => {
const r = box9(100_000_00, 1);
expect(r.adjustment).toBe(0);
expect(r.vat).toBe(15_000_00);
});
it("يسترد الحصة غير القابلة للخصم في عمود التعديل", () => {
// شكل مثال زاتكا نفسه: بنك باسترداد 70%، خدمات بـ 100,000 ريال.
const r = box9(100_000_00, 0.7);
expect(r.amount).toBe(100_000_00);
expect(r.adjustment).toBe(30_000_00);
expect(r.vat).toBe(10_500_00);
});
});
describe("حد التصحيح في المادة 63(3)", () => {
it("هو 15,000 وليس 5,000", () => {
expect(CORRECTION_THRESHOLD).toBe(15_000_00);
});
it("يوجّه 14,999.99 إلى الخانة 14 و15,000.00 إلى تعديل الإقرار", () => {
const now = new Date("2026-08-31T00:00:00Z");
const mk = (id: string, v: number) => ({
id, periodEnd: "2026-06-30", netVatEffect: v,
reason: "test", discoveredOn: "2026-08-01",
});
const r = routeCorrections([mk("a", 14_999_99), mk("b", 15_000_00)], now);
expect(r.box14.map((e) => e.id)).toEqual(["a"]);
expect(r.requiresAmendment.map((e) => e.id)).toEqual(["b"]);
});
});
describe("الخانة 8 مقابل الخانة 9", () => {
const base = {
id: "t1", date: "2026-07-01", direction: "purchase" as const,
netAmount: 100_000_00, vatAmount: 15_000_00, vatRate: 0.15,
counterpartyCountry: "AE", counterpartyResident: false,
};
it("يوجّه الواردات المخلَّصة جمركياً إلى الخانة 8", () => {
expect(classify({ ...base, customsDeclarationNumber: "SA-123" }))
.toBe("import_vat_at_customs");
});
it("يوجّه الخدمات بلا بيان جمركي إلى الخانة 9", () => {
expect(classify(base)).toBe("import_reverse_charge");
});
});
describe("المادة 74(1): لا مهلة لعطلة نهاية الأسبوع", () => {
it("يبقي 31 يناير حتى لو صادف يوم جمعة", () => {
const deadline = filingDeadline(new Date("2026-12-31T00:00:00Z"));
expect(deadline.toISOString().slice(0, 10)).toBe("2027-01-31");
});
});ثم طابق النتيجة بالواقع. شغّل المحرك على فترة سبق أن قدّمتها وقارن الخانات الست عشرة بما قُدِّم فعلاً. وأي فرق هو إما خلل برمجي أو خطأ تقديم تاريخي — وكلاهما يستحق أن يُعرف ما دامت مبادرة إلغاء الغرامات مفتوحة.
استكشاف الأخطاء
عمود الضريبة لديك لا يطابق البوابة. متوقع، وغير ضار غالباً. المبالغ تُدخل غير شاملة للضريبة والبوابة تحسب الضريبة بنفسها؛ وتقريب كل سطر سيختلف بهللات. طابق الفرق بدلاً من تجاوزه. ولا توجد قاعدة نظامية للتقريب في الإقرار — التوجيه الوحيد على مستوى الأدلة الإرشادية، وهو أن مبالغ الضريبة تُقرَّب لأقرب هللة وأن الرقم المقرَّب نفسه يُستخدم في الإقرار.
الخانة 6 أو 12 لا تتطابق مع ميزان المراجعة. غالباً حركات خارج النطاق تسربت، أو العكس: توريد اعتباري بموجب المادة 15 لم يصل إلى محرك الضريبة لأنه قُيِّد مباشرة على مصروف تسويق.
تبيّن أن الرقم الضريبي لمورد هو رقم سجل تجاري. كلاهما سلسلة رقمية طويلة والحقول تتبادل باستمرار. تحقق قبل الإقرار لا بعده — التحقق من الرقم الضريبي السعودي يغطي الطرق الأربع وما يثبته كل منها فعلاً.
اكتشفت أخطاء في فترة مقدَّمة. وجّهها عبر المادة 63 قبل أي شيء آخر: ما دون 15,000 يذهب إلى الخانة 14 من الإقرار الحالي، وما بلغها أو تجاوزها يحتاج تعديلاً خلال 20 يوماً. ولاحظ أن مبادرة إلغاء الغرامات مستمرة حتى 31 ديسمبر 2026 وتشمل غرامات تصحيح الإقرارات — لكن تاريخ الاستحقاق فيها مجمَّد، فالانتظار لا ينفع. التفصيل في ما الذي يسقط فعلاً قبل 31 ديسمبر 2026.
تبحث عن واجهة برمجية للتقديم. لا توجد. عائلة الواجهات العامة الوحيدة لدى زاتكا هي «فاتورة»: شهادة الامتثال، وفحوص فواتير الامتثال، وإصدار شهادة الإنتاج وتجديدها، والتصديق والإبلاغ — شهادات وفاتورة واحدة في كل طلب. لا توجد نقطة نهاية لتقديم الإقرار، ولا مخطط XML للإقرار، ولا استيراد جماعي. كما أن السعودية لا تعتمد نموذج مزود خدمة معتمد للتقديم؛ ودليل مزودي الحلول تصفه الهيئة نفسها بأنه قائمة استرشادية غير ملزمة، ونطاقه الفوترة الإلكترونية فقط. وكل مزود جاد يقول «يولّد» ولا يقول «يقدّم» — والمزودون أنفسهم الذين يوفرون تقديماً مباشراً إلى منصة الإمارات لا يملكون مقابلاً لدى زاتكا.
الخطوات التالية
- اربط جانب الفواتير: تكامل الفوترة الإلكترونية المرحلة الثانية بـ TypeScript يغطي تسجيل الشهادة و UBL 2.1 وتوقيع XAdES ورمز QR بصيغة TLV، والتصديق مقابل الإبلاغ. والفاتورة التي ترفضها زاتكا تظل جزءاً من الإقرار — فالمساران يفشلان استقلالاً.
- صحّح تصنيف الفواتير الذي يغذي الخانتين 1 و3: قاعدة الفاتورة الضريبية المبسطة التي يخطئ فيها الجميع.
- راجع الأرقام المفردة بـحاسبة ضريبة القيمة المضافة المجانية، وأصدر مستنداً متوافقاً بـمولّد الفاتورة الضريبية.
- وسّع المحرك بسجل أصول رأسمالية بموجب المادة 52: ست سنوات للمنقولة وعشر للعقارية، يحمل كلٌّ منها نسبة الاسترداد المطبقة عند الاقتناء.
الخلاصة
الخانات الست عشرة هي الجزء السهل. وما يفصل إقراراً ينجو من الربط عن إقرار لا ينجو هو الطبقة التي تحته: هل يعكس تعديل الخانة 9 نسبة استردادك الفعلية، وهل عُكست ضريبة المدخلات على فاتورة غير مسددة منذ سنتين بموجب المادة 40(10)، وهل تحمل الصادرات التي طبّقت عليها نسبة الصفر مستنداتها الثلاثة، وهل نزلت التسوية السنوية في إقرار ديسمبر، وهل يقول حد التصحيح لديك 15,000 أم ما زال يقول 5,000.
لا شيء من ذلك ظاهر من البوابة. وكله ظاهر من دفتر أستاذك — وهذا بالضبط سبب انتماء المحرك إلى جانبك من الجدار، وسبب أن كون التقديم يدوياً يكلّفك أقل بكثير مما يفترض معظم الناس.
إن كنت تحمل هذا المنطق داخل جداول بيانات، أو داخل نظام تخطيط موارد لم تدقّق تعريبه السعودي فعلياً قط، فذلك يستحق نظرة قبل إقفال الفترة القادمة لا بعده. نقوم بهذا النوع من العمل كمراجعة محددة النطاق: أحضر فترة مقدَّمة واحدة ودفتر الأستاذ الخاص بها، ونطابق بينهما ونخبرك أي هذه القواعد يخطئ فيها إعدادك الحالي. ابدأ من تواصل معنا — فترة مقدَّمة ودليل حسابات يكفيان للبدء.