رموز أخطاء DI API في SAP B1: معنى -5002 و -1029 و -2035 و -5006 وطريقة إصلاحها

بقلم زين عباس, كودينوفا · آخر تحديث

الإجابة المختصرةيعيد استدعاء DI API القيمة 0 عند النجاح ورمزًا سالبًا عند الفشل. اقرأ الرمز والنص باستخدام Company.GetLastError مباشرة بعد الاستدعاء الفاشل. أكثر الرموز ظهورًا في المشاريع الحقيقية هي -5002 (غلاف لأخطاء التحقق؛ النص الذي يليه يسمّي الحقل الحقيقي)، و -1029 (لا يمكن تحديث الحقل)، و -2035 (السجل موجود بالفعل)، و -2028 (لا توجد سجلات مطابقة)، و -5006 (الإجراء غير مدعوم، مثل Cancel على فاتورة مبيعات)، و -5001 (خطأ داخلي، غالبًا قيمة null في جسم طلب Service Layer).

يعيد استدعاء DI API القيمة 0 عند النجاح ورقمًا سالبًا عند الفشل. يخبرك هذا الرقم بالفئة؛ ويخبرك النص الذي تعيده Company.GetLastError بالسبب. في تكاملات SAP Business One التي أبنيها (بوابات الويب، والإضافات، وجسور الفوترة الإلكترونية)، تغطي سبعة رموز كل حالات الفشل تقريبًا: -5002 و -1029 و -2035 و -2028 و -5006 و -5001 و -4006. فيما يلي معنى كل رمز، والرسالة الحرفية التي أعادتها SAP في اختباراتنا، وطريقة الإصلاح.

كيف تقرأ خطأ DI API بشكل صحيح؟

كل استدعاء Add() و Update() و Cancel() و Remove() يعيد قيمة int. إذا لم تكن 0، فاستدعِ GetLastError فورًا. ينتمي الخطأ إلى كائن Company، والاستدعاء التالي لـ DI يكتب فوقه، لذلك فإن سطر السجل الذي يُكتب بعد استدعاء ثانٍ يُظهر غالبًا خطأً خاطئًا أو لا يُظهر شيئًا.

فخّان من مشاريع حقيقية:

  1. كود .NET بالربط المتأخر (Late Binding). إذا استخدمت dynamic لكائن Company، فإن c.GetLastError(out int code, out string msg) يرمي الاستثناء Could not convert argument 0 for call to GetLastError. لا يستطيع الرابط الديناميكي في .NET تمرير معاملات COM من نوع out. استدعِها عبر Reflection بدلًا من ذلك.
  2. تسجيل الرقم فقط. الرقم -5002 وحده بلا فائدة. يحمل النص رقم رسالة داخليًا وغالبًا الحقل نفسه، مثل [INC1.UomCode] أو [DocumentLines.UnitPrice][line: 1].
// Read the DI error without dynamic: works with late binding (no Interop DLL)
public static (int Code, string Message) ReadLastError(object company)
{
    var args = new object[] { 0, null };
    var byRef = new ParameterModifier(2);
    byRef[0] = true; byRef[1] = true;
    company.GetType().InvokeMember("GetLastError",
        BindingFlags.InvokeMethod, null, company, args,
        new[] { byRef }, CultureInfo.InvariantCulture, null);
    return (Convert.ToInt32(args[0]), Convert.ToString(args[1]) ?? "");
}

int rc = doc.Add();
if (rc != 0)
{
    var (code, msg) = ReadLastError(company);   // read it NOW, before any other DI call
    log.Error("DI Add failed [{Code}] {Msg}", code, msg);
}

في Service Layer تعود الرموز نفسها بصيغة JSON، مثل {"error":{"code":-4006,"message":{"lang":"en-us","value":"Update the exchange rate"}}}.

ما رموز أخطاء DI API الأكثر ظهورًا؟

الرمزنص SAP (مختصر)ما يعنيه عادةًأول ما تتحقق منه
-5002يختلف، مثل “UoM code cannot be empty [INC1.UomCode]”فشل تحقق من قواعد العمل؛ والنص يسمّي الحقلاقرأ الحقل بين القوسين المربعين
-1029“Field cannot be updated”غيّرت حقلًا تقفله SAP على ذلك المستند أو السجلحالة المستند، والأسطر المرحّلة، وترحيلات الحساب
-2035“This entry already exists in the following tables”مفتاح مكرر: UDF أو UDT أو رمز شريك أعمال أو رمز صنفتحقق من الوجود قبل Add
-2028“No matching records found”المفتاح أو الرمز أو الاستعلام المحفوظ غير موجود في هذه الشركةقاعدة بيانات الشركة والمفتاح الدقيق
-5006“The requested action is not supported for this object”طريقة خاطئة لنوع الكائن، مثل Cancel على فاتورةاستخدم الطريقة التي يدعمها الكائن
-5001“Internal error”مدخلات مشوّهة، غالبًا قيمة null في جسم طلب Service Layerأزل قيم null والنصوص الفارغة
-4006“Update the exchange rate”لا يوجد سعر صرف لعملة المستند في ذلك التاريخجدول ORTT لتاريخ الترحيل

ماذا يعني -5002 في SAP Business One؟

‏-5002 غلاف عام. تعيده SAP لمعظم عمليات التحقق في المستندات والبيانات الرئيسية وتضع السبب الحقيقي في النص. هذه رسائل حصلنا عليها على شركات اختبار حقيقية، مع الإصلاح لكل منها:

  • [-5002] 1470000542 - UoM code cannot be empty [INC1.UomCode] في جرد مخزون. كان للصنف مجموعة وحدات قياس بوحدتين (MT/KG). أما الأصناف ذات وحدة القياس الواحدة فمرّت. الإصلاح: أرسل UoMCode (وحدة قياس المخزون للصنف) مع الكمية المجرودة.
  • [-5002] 480000112 ... does not exist في صرف بضاعة بأرقام تسلسلية. أرسلنا الرقم التسلسلي الداخلي. المستندات الصادرة تحتاج SystemSerialNumber (العدّاد الذي تعيّنه SAP لكل صنف). احتفظ بالأرقام التسلسلية الداخلية وأرقام المصنّع لمستندات الاستلام فقط.
  • “G/L Increase account is missing” في إعادة تقييم المخزون. لم تكن الشركة قد حددت حسابات الأستاذ العام للزيادة/النقصان للفترة أو لأي مستودع. هذه مشكلة إعداد وليست مشكلة كود: حدد الحسابات في تحديد حسابات الأستاذ العام.
  • المستند الأساسي مغلق بالفعل. نسخ مذكرة تسليم من أمر بيع سُلّم بالكامل أو أُغلق يفشل مع -5002. تحقق من السطر الأساسي قبل بناء المستند الهدف (الاستعلام أدناه).
  • حقل UDF من نوع Float بلا SubType. إنشاء حقل UDF رقمي باستخدام st_None أو بدون EditSize أعاد -5002. حدد SubType إلى Price أو Quantity أو Rate أو Sum أو Percentage، وحدد الحجم.
  • تحويل مبني على طلب تحويل. رفضت بعض إصدارات DI سطر OWTR مرتبطًا بأساس OWTQ ‏(BaseType 1250000001) بينما قبله Service Layer للبيانات نفسها. نعيد الآن المحاولة مرة واحدة كنسخة عادية ونطلب من المستخدم إغلاق الطلب يدويًا.
  • مرفقات على كائن مغلق. قبلت SAP روابط المرفقات على مسودات الاتفاقيات الإطارية وطلبات الخدمة المفتوحة فقط. أما الاتفاقيات المعتمدة والطلبات المغلقة فأعادت -5002.

وحالة أخرى أضاعت علينا ظهيرة كاملة: عندما حاولنا إنشاء حقل UDF موجود بالفعل عبر Service Layer، لم تُعِد SAP الرمز -2035، بل أعادت [-5002] No records. لذلك لا تعتمد على -2035 وحده لاكتشاف «موجود بالفعل»؛ تحقق من CUFD أولًا.

لماذا أحصل على -1029 «Field cannot be updated»؟

يعني -1029 أن الحقل موجود لكن SAP لن تسمح لك بتغييره في الحالة الحالية للكائن. الحقل بين القوسين المربعين يخبرك أيها. حالات من اختباراتنا:

  • [-1029] [DocumentLines.UnitPrice][line: 1] 'Field cannot be updated' في مرتجع مبيعات وفي إشعار دائن للمبيعات. تقفل SAP السعر والخصم في تلك الأسطر بعد ترحيلها. أما ملاحظات الرأس فما زالت تُحدَّث.
  • [ORDR.VatSum] عند تعديل مستند مبيعات مغلق. تقبل المستندات المغلقة والملغاة تعديل التعليقات، لكن أي تغيير في سطر أو سعر أو ضريبة يعطي -1029. تحقق من DocStatus قبل أن تعرض زر التعديل.
  • [OACT.Postable] عند «إيقاف» حساب أستاذ عام عليه ترحيلات بالفعل. كانت البوابة تعدّل الخاصية الخطأ. لجعل الحساب غير نشط، اضبط FrozenFor = Y (مع FrozenFrom / FrozenTo إذا احتجت نطاق تاريخ) ولا تلمس Postable.
  • سطر أمر شراء منسوخ. بعد استلام سطر أمر الشراء جزئيًا (الكمية المفتوحة أقل من الكمية)، تقفل SAP سعره وخصمه وكميته. اقفل هذه المدخلات في واجهتك حتى لا يصل المستخدم إلى الخطأ أبدًا.

يُظهر موضوع قديم في مجتمع SAP الرمز نفسه على ORDR.DocRate، فهذا ليس سلوكًا جديدًا. تعامل مع -1029 على أنه «واجهتك سمحت للمستخدم بتعديل شيء تعتبره SAP نهائيًا».

كيف تصلح -2035 «This entry already exists»؟

‏-2035 مفتاح مكرر. يظهر أكثر عندما تنشئ إضافة أو تكامل جداول UDT وحقول UDF الخاصة بها عند بدء التشغيل، أو عندما يرسل استيراد رمز شريك الأعمال أو الصنف نفسه مرتين.

اجعل إنشاء المخطط قابلًا للتكرار دون أثر (Idempotent): ابحث عن الحقل أولًا، وأنشئه فقط إذا كان مفقودًا، وتعامل مع -2035 عند الإنشاء على أنه نجاح. أما بيانات الأعمال، فتحقق بمفتاحك الخارجي قبل Add(). لفواتير المبيعات أو المشتريات القادمة من استيراد، يكون ذلك CardCode مع NumAtCard.

-- SQL Server: does the UDF exist? (TableID without @ for system tables)
SELECT FieldID, AliasID, Descr
FROM   CUFD
WHERE  TableID = 'OITM' AND AliasID = 'HSCode';

-- SAP HANA
SELECT "FieldID", "AliasID", "Descr"
FROM   "CUFD"
WHERE  "TableID" = 'OITM' AND "AliasID" = 'HSCode';

-- Is the base sales order line still open before you copy it? (SQL Server)
SELECT T0.DocNum, T0.DocStatus, T1.LineNum, T1.LineStatus, T1.OpenQty
FROM   ORDR T0 JOIN RDR1 T1 ON T1.DocEntry = T0.DocEntry
WHERE  T0.DocEntry = 1234;

-- SAP HANA
SELECT T0."DocNum", T0."DocStatus", T1."LineNum", T1."LineStatus", T1."OpenQty"
FROM   "ORDR" T0 JOIN "RDR1" T1 ON T1."DocEntry" = T0."DocEntry"
WHERE  T0."DocEntry" = 1234;

لاحظ أن AliasID في CUFD يُخزَّن دون البادئة U_.

ماذا يعني -2028 «No matching records found»؟

السجل الذي طلبته غير موجود في قاعدة بيانات هذه الشركة. في DI API، تعيد GetByKey القيمة false بدل إطلاق -2028، لذلك اختبر نتيجتها دائمًا. وفي Service Layer تحصل على -2028 عند GET بالمفتاح، وأيضًا عند SQLQueries('code')/List إذا لم يكن الاستعلام المحفوظ موجودًا في تلك الشركة. هذه الحالة، وكيفية إعادة إنشاء الاستعلام تلقائيًا، مشروحة في دليل أخطاء SQLQueries في Service Layer.

الأسباب الشائعة: أنت مسجّل الدخول إلى شركة أخرى (اختبار مقابل إنتاج)، أو للرمز حالة أحرف مختلفة أو مسافات زائدة في نهايته، أو المفتاح DocNum بينما تتوقع SAP قيمة DocEntry.

لماذا تعيد Cancel() الرمز -5006 على فاتورة مبيعات؟

يقول -5006 إن الطريقة غير مدعومة لذلك الكائن. الحالة الكلاسيكية: Documents.Cancel() على فاتورة مبيعات أو مذكرة تسليم. تلغي SAP مستندات الترحيل بإنشاء مستند عكسي. حمّل الفاتورة، واستدعِ CreateCancellationDocument() التي تعيد مستندًا جديدًا في الذاكرة (وليس int)، ثم استدعِ Add() عليه. بعدها يُعلَّم المستند الأصلي ملغى.

أوامر البيع وأوامر الشراء وطلبات الشراء وعروض الأسعار تدعم Cancel() العادية. وتعمل ترحيلات المخزون بالعكس: في إصدار DI الذي نستخدمه، لا تتيح مستندات استلام البضاعة (59) وصرف البضاعة (60) وتحويل المخزون (67) الطريقة CreateCancellationDocument إطلاقًا، وتعمل Cancel(). حدد الطريقة لكل نوع كائن بدل استخدام مسار إلغاء واحد لكل شيء.

ما سبب -5001 «Internal error»؟

لا يسمّي -5001 Internal error المجرّد أي شيء، ما يجعله الأصعب تتبعًا. في عملنا مع Service Layer كان السبب جسم JSON يحتوي "Field": null. في .NET يتجاهل JsonIgnoreCondition.WhenWritingNull خصائص الكائنات الفارغة، لكنه لا يتجاهل القيم الفارغة داخل قاموس (Dictionary)، فالطلب المبني من Dictionary<string, object> يرسلها رغم ذلك. الإصلاح: أضف الحقول عبر دالة مساعدة تحذف قيم null والنصوص الفارغة، ولن ترى -5001 من هذا المصدر مرة أخرى.

كيف تصلح -4006 «Update the exchange rate»؟

المستند بعملة أجنبية ولا يوجد سعر في ORTT لتلك العملة في تاريخ الترحيل. لن تخمّن SAP سعرًا. إما أن تحمّل السعر اليومي أولًا، أو تضبط DocRate على المستند عندما يكون لدى نظامك المصدر السعر المتفق عليه.

-- SQL Server: is there a rate for USD on the posting date?
SELECT RateDate, Currency, Rate FROM ORTT
WHERE  Currency = 'USD' AND RateDate = '2026-10-25';

-- SAP HANA
SELECT "RateDate", "Currency", "Rate" FROM "ORTT"
WHERE  "Currency" = 'USD' AND "RateDate" = '2026-10-25';

ماذا تعني أخطاء اتصال DI API ‏-111 و -132 و -8037؟

تأتي هذه الثلاثة من Company.Connect()، قبل لمس أي مستند. يعني -111 أن DI API لم تستطع فتح قاعدة البيانات SBO-COMMON، ويعني -132 أن تسجيل الدخول إلى SAP Business One نفسه رُفض، ويعني -8037 أن DI API لم تستطع الوصول إلى System Landscape Directory ‏(SLD) باسم الخادم الذي أعطيته لها.

الرمزنص SAPالسبب المعتادأول ما تتحقق منه
-111“Failed to connect to SBO-Common”لا تستطيع DI API تسجيل الدخول إلى SBO-COMMON: قيمة Server أو DbServerType خاطئة، أو بيانات اعتماد قاعدة البيانات خاطئة، أو تصحيح DI API لا يطابق الخادماسم الخادم و DbServerType؛ ثبّت DI API من التصحيح نفسه الذي على الخادم
-132“Error during SBO user authentication”LicenseServer غير مضبوط، أو تصحيح DI API لا يطابق الشركة، أو إعدادات تسجيل دخول مختلطةاضبط LicenseServer؛ ومع UseTrusted = true اترك DbUserName و DbPassword فارغين؛ ويجب أن يتطابق Server و SLDServer بما في ذلك حالة الأحرف
-8037“Failed to connect or logon to SLD”قيمة Company.Server ليست الاسم المسجّل في SLD / Control Center (مثل localhost)، أو أن الملف b1-local-machine.xml في مجلد Conf الخاص بـ DI API يشير إلى خادم آخراستخدم اسم الخادم المسجّل بالضبط؛ وانسخ b1-local-machine.xml من مجلد Conf في عميل SAP Business One إلى مجلد Conf الخاص بـ DI API

ملاحظتان حول -132. تربطه SAP بعدم مصادقة اتصال DI API بالشركة مقابل خادم التراخيص (SAP KBA 3394748). وقد يظهر بين حين وآخر فقط: تصف SAP KBA 3663692 ظهور -132 بشكل متقطع عند تشغيل كثير من تسجيلات الدخول إلى DI API أو Service Layer في الوقت نفسه، لذلك يجب على بوابة الويب التي تفتح اتصالًا جديدًا لكل طلب أن تعيد استخدام اتصال واحد بدلًا من ذلك.

كيف يجب أن يتعامل التكامل مع هذه الأخطاء؟

ما ينجح لدينا في بيئة الإنتاج:

  1. سجّل الرمز والنص الكامل ونوع الكائن ومرجعك الخاص (مثل رقم الطلب في البوابة) عند كل فشل.
  2. قسّم الأخطاء إلى «أعِد المحاولة» و«توقف». يمكن إعادة محاولة انتهاء المهلة أو فقدان الجلسة. أما -5002 و -1029 و -2035 و -5006 فهي مشكلات بيانات أو تصميم؛ وإعادة محاولتها لا تصنع إلا ضجيجًا. وفي حالة الاستعلام المحفوظ المفقود (-2028 على SQLQueries)، فإن إعادة إنشائه والمحاولة مرة واحدة آمنة.
  3. ترجم للمستخدم، واحتفظ بالنص الخام للدعم. عبارة «هذا السطر مستلم بالفعل، لذلك سعره مقفل» تفيد المشتري أكثر من [-1029] [DocumentLines.UnitPrice]. أضف نص SAP في قسم التفاصيل.
  4. امنع بدل أن تلتقط. اختفت معظم حالات -1029 و -5002 أعلاه عندما صارت الواجهة تتحقق من حالة المستند أو حالة السطر أو إعداد الصنف قبل الإرسال.

إذا كنت تختار بين الواجهتين لمشروع جديد، فإن دليل تطوير الإضافات ودليل Service Layer يقارنان بينهما. ويسرد مرجع الجداول الجداول المستخدمة في الاستعلامات أعلاه، ويساعدك منشئ طلبات Service Layer على اختبار جسم الطلب قبل أن يصل إلى كودك. وإذا كنت تحتاج تكاملًا أو إضافة تُبنى وتُصان، فاطّلع على تطوير SAP Business One.

رسائل الخطأ المقتبسة أعلاه مأخوذة من اختبارات كودينوفا على شركات اختبار SAP Business One 10.0 ‏(DI API و Service Layer)، أكتوبر 2026.

المصادر

خدمات ذات صلة

الأسئلة الشائعة

أسئلة شائعة

أين توجد القائمة الكاملة لرموز أخطاء DI API في SAP Business One؟

لا تنشر SAP قائمة واحدة كاملة ومحدّثة. يشرح دليل SDK الدالة GetLastError، ونص الرسالة المرافق للرمز هو الجزء المفيد. والرمز -5002 تحديدًا يغطي مئات عمليات التحقق المختلفة، لذلك سجّل النص كاملًا، لا الرقم فقط.

هل يعيد Service Layer و DI API رموز الأخطاء نفسها؟

في الغالب نعم. يعمل Service Layer على منطق الأعمال نفسه، فـ -5002 و -1029 و -2035 و -2028 لها المعنى نفسه في الاثنين. يغلّفها Service Layer بصيغة JSON: ‏error.code و error.message.value.

كيف ألغي فاتورة مبيعات عبر DI API؟

ليس باستخدام Cancel()، التي تعيد -5006. استدعِ CreateCancellationDocument() على الفاتورة المحمّلة، ثم نفّذ Add() على المستند الذي تعيده. أما أوامر البيع وأوامر الشراء وعروض الأسعار فتدعم Cancel().

لماذا تعيد Company.Connect() الرمز -132؟

يعني -132 ‏«Error during SBO user authentication» أن DI API وصلت إلى الخادم لكن تسجيل الدخول إلى SAP Business One فشل. تحقق من ضبط LicenseServer، ومن تطابق تصحيح (Patch) DI API مع إصدار قاعدة بيانات الشركة، ومن استخدام وضع تسجيل دخول واحد (مع UseTrusted = true اترك DbUserName و DbPassword فارغين)، ومن أن Server و SLDServer يستخدمان الاسم نفسه وحالة الأحرف نفسها. كما توثّق SAP ظهور -132 بشكل متقطع عند تشغيل كثير من عمليات تسجيل الدخول إلى DI API أو Service Layer في الوقت نفسه.

جاهز للبدء؟

أخبرنا بما تحتاجه. ستحصل على إجابة تقنية واضحة ونطاق عمل محدد وسعر ثابت، عادةً خلال 24 ساعة.