الكتابات/blog/2026/08
Blog10 أغسطس 2026·6 دقيقة

دليل المطور: تكامل نظامك مع مُدد لأتمتة الرواتب في السعودية

كيف تبني طبقة تكامل بين نظامك ومنصة مُدد لأتمتة رفع ملفات حماية الأجور وتتبع الامتثال — دليل تقني عملي.

كل دورة رواتب في المنشأة السعودية تنتهي بنفس اللحظة الحرجة: هل رُفع الملف إلى مُدد؟ هل قُبلت السجلات؟ هل النسبة كافية لحماية شهادة السعودة؟

المشكلة ليست في الرواتب نفسها — بل في الفجوة بين نظام الموارد البشرية أو المحاسبة ومنصة مُدد. كل منشأة تحل هذه الفجوة بطريقتها: إكسل يدوي، تصدير CSV، نسخ لصق. كل هذه الطرق تعمل — حتى لا تعمل، ويكتشف أحد أن ثلاثة موظفين لم يُرفع لهم سجل منذ شهرين.

هذا الدليل يشرح كيف تبني طبقة تكامل موثوقة بين نظامك البرمجي ومنصة مُدد، بدلاً من الاعتماد على العمل اليدوي.

ما هي منصة مُدد وكيف تعمل

مُدد منصة تقنية مرخّصة تديرها وزارة الموارد البشرية والتنمية الاجتماعية بالشراكة مع المؤسسة العامة للتأمينات الاجتماعية والبنك المركزي السعودي (ساما). تنقسم إلى منظومتين:

مُدد الأعمال — نظام إدارة الرواتب للمنشآت الصغيرة والمتوسطة. يُتيح تحويل الرواتب مباشرةً عبر الربط المصرفي، ويرفع ملف حماية الأجور تلقائياً عند إتمام التحويل.

مُدد الامتثال — نظام رفع ملفات حماية الأجور (WPS) للمنشآت التي تستخدم أنظمة رواتب خارجية. تُرفع الملفات بصيغة CSV وفق مواصفات وزارة الموارد البشرية، وتتحقق المنصة من التطابق مع سجلات التأمينات والبنوك.

المسار المزدوج للامتثال:

نظام الرواتب → توليد ملف WPS → مُدد → مطابقة مع GOSI + البنوك → تقرير الامتثال

المنشآت التي تُحوّل مباشرةً عبر مُدد الأعمال تتجاوز خطوة الرفع — لكن أي منشأة تستخدم نظام محاسبة أو ERP خارجي تحتاج إلى مسار الرفع اليدوي، وهذا هو المكان الذي تحدث فيه معظم الأخطاء.

ما الذي تحتاجه فعلاً لبناء التكامل

لا تنشر مُدد توثيقاً عاماً للـ API — التكامل البرمجي المباشر متاح لشركاء التقنية المعتمدين مثل ZenHR وJisr والأنظمة المدمجة مع الشبكة المصرفية السعودية. للمنشآت الأخرى، المسار هو:

  1. بناء الملف الصحيح بالمواصفات المطلوبة
  2. رفع الملف عبر واجهة مُدد أو SFTP حسب حجم المنشأة
  3. قراءة تقرير الامتثال وإعادة معالجة السجلات المرفوضة

الخطأ الأكثر شيوعاً: أنظمة تُنتج الملف بشكل صحيح من حيث التنسيق، لكن البيانات الداخلية — أرقام الإقامة، مبالغ الرواتب، أرقام الحسابات — لا تطابق سجلات التأمينات. الملف يُقبل، والسجلات تُرفض. النتيجة: مخالفة لا تكتشفها إلا بعد صدور التقرير الشهري.

بناء طبقة التحقق قبل الرفع

الاستثمار الحقيقي ليس في رفع الملف — بل في التحقق منه قبل أن يصل إلى مُدد. هذا مثال بـ TypeScript يوضح البنية الأساسية:

interface MudadEmployee {
  iqamaOrNationalId: string;   // 10 أرقام بالضبط
  employeeName: string;
  bankAccountIBAN: string;     // SA + 22 رقم
  basicSalary: number;         // بالريال السعودي
  allowances: number;
  deductions: number;
  netSalary: number;
  paymentMonth: string;        // YYYY-MM
}
 
interface ValidationResult {
  isValid: boolean;
  errors: string[];
  employeeId: string;
}
 
function validateEmployee(emp: MudadEmployee): ValidationResult {
  const errors: string[] = [];
 
  // التحقق من رقم الهوية/الإقامة
  if (!/^\d{10}$/.test(emp.iqamaOrNationalId)) {
    errors.push(`رقم الهوية غير صحيح: ${emp.iqamaOrNationalId}`);
  }
 
  // التحقق من IBAN
  if (!/^SA\d{22}$/.test(emp.bankAccountIBAN)) {
    errors.push(`IBAN غير صحيح: ${emp.bankAccountIBAN}`);
  }
 
  // التحقق من توازن الراتب
  const calculatedNet = emp.basicSalary + emp.allowances - emp.deductions;
  if (Math.abs(calculatedNet - emp.netSalary) > 0.01) {
    errors.push(
      `عدم توازن: ${emp.basicSalary} + ${emp.allowances} - ${emp.deductions} = ${calculatedNet} لا يساوي ${emp.netSalary}`
    );
  }
 
  // الراتب الصافي يجب أن يكون أكبر من صفر
  if (emp.netSalary <= 0) {
    errors.push(`الراتب الصافي يجب أن يكون موجباً`);
  }
 
  return {
    isValid: errors.length === 0,
    errors,
    employeeId: emp.iqamaOrNationalId,
  };
}
 
function validatePayrollBatch(employees: MudadEmployee[]): {
  valid: MudadEmployee[];
  invalid: Array<{ employee: MudadEmployee; errors: string[] }>;
  summary: string;
} {
  const valid: MudadEmployee[] = [];
  const invalid: Array<{ employee: MudadEmployee; errors: string[] }> = [];
 
  for (const emp of employees) {
    const result = validateEmployee(emp);
    if (result.isValid) {
      valid.push(emp);
    } else {
      invalid.push({ employee: emp, errors: result.errors });
    }
  }
 
  const rate = ((valid.length / employees.length) * 100).toFixed(1);
  const summary = `${valid.length}/${employees.length} سجل صحيح (${rate}%)`;
 
  return { valid, invalid, summary };
}

هذه الطبقة تمسك المشاكل قبل الرفع — لا بعده.

توليد ملف WPS بالمواصفات الصحيحة

بعد التحقق، تأتي مرحلة توليد الملف بالتنسيق المطلوب لمُدد:

import { createObjectCsvWriter } from 'csv-writer';
import * as path from 'path';
 
async function generateMudadWPSFile(
  employees: MudadEmployee[],
  establishmentId: string,
  paymentMonth: string,
  outputDir: string
): Promise<string> {
  const fileName = `WPS_${establishmentId}_${paymentMonth.replace('-', '')}.csv`;
  const filePath = path.join(outputDir, fileName);
 
  const csvWriter = createObjectCsvWriter({
    path: filePath,
    header: [
      { id: 'EmployeeID', title: 'EmployeeID' },
      { id: 'EmployeeName', title: 'EmployeeName' },
      { id: 'IBAN', title: 'IBAN' },
      { id: 'BasicSalary', title: 'BasicSalary' },
      { id: 'HousingAllowance', title: 'HousingAllowance' },
      { id: 'OtherAllowances', title: 'OtherAllowances' },
      { id: 'Deductions', title: 'Deductions' },
      { id: 'NetSalary', title: 'NetSalary' },
      { id: 'PaymentDate', title: 'PaymentDate' },
    ],
    encoding: 'utf8',
  });
 
  const records = employees.map((emp) => ({
    EmployeeID: emp.iqamaOrNationalId,
    EmployeeName: emp.employeeName,
    IBAN: emp.bankAccountIBAN,
    BasicSalary: emp.basicSalary.toFixed(2),
    HousingAllowance: '0.00',
    OtherAllowances: emp.allowances.toFixed(2),
    Deductions: emp.deductions.toFixed(2),
    NetSalary: emp.netSalary.toFixed(2),
    PaymentDate: new Date().toISOString().split('T')[0],
  }));
 
  await csvWriter.writeRecords(records);
  return filePath;
}

الخطأ الأكثر شيوعاً: السجل يُرفع، لكن لا يُقبل

المنشآت التي تعتمد على رفع الملف اليدوي تقع في فخ شائع: تُسجّل على النظام نجاح الرفع، لكن تقرير الامتثال يُظهر نسبة أقل من المتوقع. السبب في الغالب:

أرقام الهوية لا تطابق سجلات GOSI — موظف تم تحديث رقم إقامته في نظام HR لكن السجل القديم لا يزال في التأمينات. يتطلب هذا تحديث بيانات المنشأة في GOSI أولاً.

IBAN محفوظ بتنسيق خاطئ — بعض الأنظمة تحفظ IBAN بدون "SA" أو بمسافات. الملف يخرج منسقاً بشكل صحيح لكن البيانات الداخلية غير صحيحة.

مبلغ الراتب الصافي لا يطابق التحويل البنكي الفعلي — إذا تحمّلت المنشأة رسوم تحويل مصرفية وخُصمت من المبلغ، يظهر فرق بين ما في الملف وما وصل إلى الموظف.

كل هذه الحالات تنتج سجلاً مرفوضاً بصمت — الملف مقبول، النسبة منخفضة. راجع مقالنا حول أسباب مخالفات WPS ولماذا تحدث في البيانات لا في الرواتب للتعمق في منطق المطابقة.

بناء مراقبة الامتثال الشهري

الخطوة الأهم بعد الرفع: مراقبة تقرير الامتثال وإطلاق تنبيه فوري عند انخفاض النسبة:

interface ComplianceReport {
  establishmentId: string;
  paymentMonth: string;
  totalEmployees: number;
  acceptedRecords: number;
  rejectedRecords: number;
  complianceRate: number;
  violations: Array<{
    employeeId: string;
    reason: string;
    correctionDeadline: string;
  }>;
}
 
function analyzeComplianceReport(report: ComplianceReport): {
  status: 'compliant' | 'at-risk' | 'violation';
  message: string;
  requiredAction: string;
} {
  const { complianceRate, violations } = report;
 
  // العتبة الحرجة: 95% حسب اشتراطات برنامج حماية الأجور
  if (complianceRate >= 95) {
    return {
      status: 'compliant',
      message: `نسبة الامتثال ${complianceRate}% — لا مخالفات`,
      requiredAction: 'لا يلزم اتخاذ إجراء',
    };
  }
 
  if (complianceRate >= 80) {
    const deadline = violations[0]?.correctionDeadline ?? 'غير محدد';
    return {
      status: 'at-risk',
      message: `نسبة الامتثال ${complianceRate}% — ${violations.length} سجل يحتاج مراجعة`,
      requiredAction: `تصحيح السجلات المرفوضة قبل ${deadline}`,
    };
  }
 
  return {
    status: 'violation',
    message: `نسبة الامتثال ${complianceRate}% — مخالفة فعلية`,
    requiredAction: 'إبلاغ إدارة الموارد البشرية فوراً وتقديم طعن أو تصحيح',
  };
}

التكامل مع الأنظمة الأخرى في منظومة الامتثال السعودية

مُدد ليست المنصة الوحيدة في معادلة الامتثال السعودي. إذا كنت تبني طبقة تكامل شاملة، تحتاج إلى ربطها مع:

  • قوي / نطاقات — لمتابعة نسب السعودة وربطها ببيانات WPS. راجع دليلنا حول تكامل Qiwa وأنظمة الموارد البشرية.
  • ZATCA / فاتورة — لمزامنة بيانات الرواتب مع الفواتير الإلكترونية في منشآت تستخدم نظام احتساب تكلفة العمالة. راجع دليل التكامل مع منصة فاتورة.
  • نظام مكافأة نهاية الخدمة — الإهمال في توثيق الرواتب الشهرية يؤثر على احتساب مكافآت نهاية الخدمة عند التدقيق.

نمط التكامل الموصى به

بناءً على ما نراه في المنشآت السعودية، النمط الأكثر موثوقية:

نظام ERP/HR
    ↓ تصدير بيانات الرواتب (JSON أو قاعدة بيانات)
طبقة التحقق (validate)
    ↓ تصفية السجلات غير الصحيحة + إشعار فوري
مولّد ملف WPS
    ↓ ملف CSV بالمواصفات الصحيحة
رفع إلى مُدد (يدوي أو عبر SFTP)
    ↓ تأكيد الاستلام
مراقب الامتثال
    ↓ قراءة تقرير الامتثال دورياً
لوحة تحكم داخلية
    ↓ تنبيه فوري عند انخفاض النسبة

الجزء المهم في هذا النمط: طبقة التحقق تعمل قبل الرفع، لا بعده. كل سجل مرفوض بعد الرفع يعني وقتاً ضائعاً في التصحيح والإعادة — وهو وقت لا تملكه دائماً قبل نهاية نافذة الامتثال.

ماذا لو كنت شريكاً تقنياً يبني منتجاً

إذا كنت تبني نظام HR أو محاسبة يستهدف السوق السعودي، التكامل مع مُدد ليس ميزة إضافية — هو شرط للحصول على عملاء في هذا السوق. ZenHR وJisr يُسوّقان التكامل مع مُدد كميزة رئيسية في صفحاتهم.

مسار الشراكة الرسمي مع مُدد يبدأ من التواصل المباشر مع فريقها التقني للحصول على بيانات اعتماد API للشركاء. غير ذلك، المسار العملي لمعظم الأنظمة هو مولّد ملف WPS عالي الجودة مع واجهة رفع مخصصة.

الخلاصة

مُدد ليست نظاماً معقداً من الناحية التقنية — لكن المنشآت التي تعاني منها في الغالب لا تعاني منها هي، بل من الفجوة بين نظامها الداخلي والملف الذي تُنتجه. بناء طبقة تحقق محكمة قبل الرفع، ومراقبة فعلية لتقارير الامتثال بعده، يختصر معظم المشاكل.

إذا كنت تبني تكاملاً برمجياً مع مُدد أو منظومة الامتثال السعودية الأشمل، تحدث مع فريق نقطة — نُساعد في تصميم البنية وبناء الطبقات التي تمنع المخالفات قبل وقوعها.