SAP Business One Service Layer: تسجيل الدخول و $filter و $select والترقيم مع أمثلة عملية

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

الإجابة المختصرةService Layer هي واجهة REST ‏(OData) البرمجية لـ SAP Business One. ترسل بطلب POST قاعدة بيانات الشركة واسم المستخدم وكلمة المرور إلى ‎/b1s/v1/Login أو ‎/b1s/v2/Login، ثم ترسل ملفي تعريف الارتباط B1SESSION و ROUTEID مع كل استدعاء. تقرأ البيانات بطلب GET مع خيارات OData مثل $select و $filter و $orderby، وتتبع nextLink للصفحات التالية، وتنشئ بطلب POST، وتحدّث بطلب PATCH، وتنهي الجلسة بـ Logout.

ما هي Service Layer

Service Layer هي واجهة الويب البرمجية لـ SAP Business One. تعرض كائنات الأعمال مثل شركاء الأعمال والأصناف والأوامر والفواتير عبر HTTPS باستخدام بروتوكول OData. يمكن لأي لغة تستطيع إرسال طلب HTTP أن تستخدمها: JavaScript أو Python أو C# أو PHP أو أداة low-code.

بدأت على إصدار HANA من SAP Business One. وتوفرها حزم الميزات الحديثة من الإصدار 10.0 أيضًا لـ SQL Server. افتراضيًا تستمع على المنفذ 50000 عبر HTTPS:

https://your-b1-server:50000/b1s/v1/
https://your-b1-server:50000/b1s/v2/

v1 أم v2

يصل المساران إلى كائنات الأعمال نفسها.

  • ‎/b1s/v1 يستخدم الإصدار 3 من OData. ما زال يعمل ومعظم الأكواد القديمة تستخدمه.
  • ‎/b1s/v2 يستخدم الإصدار 4 من OData، الذي تعتبره SAP الآن البروتوكول الأساسي.

الفرق الذي تلاحظه أولًا يكون في الاستجابات. يعيد v1 الحقل odata.nextLink، ويعيد v2 الحقل @odata.nextLink. للمشاريع الجديدة، اختر v2 والتزم به. تستخدم الأمثلة أدناه مسارات v1 لأنها ما زالت الأكثر شيوعًا في الواقع. استبدل v1 بـ v2 وستعمل بالطريقة نفسها.

الخطوة 1: تسجيل الدخول

أرسل طلب POST مع قاعدة بيانات الشركة والمستخدم وكلمة المرور:

POST https://your-b1-server:50000/b1s/v1/Login
Content-Type: application/json
{
  "CompanyDB": "SBODEMOUS",
  "UserName": "manager",
  "Password": "your-password"
}

تحتوي الاستجابة الناجحة على معرّف الجلسة والإصدار والمهلة بالدقائق:

{
  "SessionId": "1c9e4b2a-....",
  "Version": "1000xxx",
  "SessionTimeout": 30
}

ويضبط الخادم أيضًا ملفي تعريف ارتباط: B1SESSION و ROUTEID.

  • B1SESSION يعرّف جلستك.
  • ROUTEID يخبر موازن الأحمال في Service Layer بالعقدة التي تحمل جلستك، فيعود كل طلب إلى العقدة نفسها.

يخزن المتصفح هذين الملفين ويرسلهما عنك. أما خارج المتصفح، فيجب أن تضيف الاثنين إلى ترويسة Cookie في كل استدعاء لاحق:

Cookie: B1SESSION=1c9e4b2a-....; ROUTEID=.node1

تنتهي الجلسة افتراضيًا بعد 30 دقيقة من عدم النشاط. وكل استدعاء يعيد ضبط المؤقت. ابنِ عميلك بحيث تؤدي الاستجابة 401 إلى تسجيل دخول جديد واحد ثم إعادة المحاولة، لا إلى حلقة لا تنتهي.

الخطوة 2: قراءة البيانات بطلب GET

يعيد طلب GET العادي صفحة من السجلات بكل الحقول:

GET /b1s/v1/BusinessPartners

هذا بطيء وثقيل. استخدم خيارات استعلام OData لتطلب ما تحتاجه فقط.

الخيارماذا يفعلمثال
$selectيعيد هذه الحقول فقط$select=CardCode,CardName,Balance
$filterيعيد السجلات المطابقة فقط$filter=CardType eq 'cCustomer'
$orderbyيرتّب النتائج$orderby=DocDate desc
$topيعيد n سجلًا على الأكثر$top=50
$skipيتخطى أول n سجلًا$skip=100

مجتمعة:

GET /b1s/v1/Orders?$select=DocEntry,DocNum,CardCode,DocDate,DocTotal&$filter=DocDate ge '2026-10-01' and DocumentStatus eq 'bost_Open'&$orderby=DocDate desc&$top=50

بعض الأمور التي توقع الناس في الخطأ:

  • أسماء الحقول هي أسماء Service Layer، وليست أسماء أعمدة SQL. فهي DocumentStatus وليست DocStatus. وقيم التعداد أسماء مثل bost_Open و cCustomer، وليست O و C.
  • النصوص والتواريخ توضع بين علامتي اقتباس مفردتين. أما الأرقام فلا.
  • عوامل التصفية كلمات: eq و ne و gt و ge و lt و le، وتُربط بـ and و or.
  • البحث النصي يستخدم دوالًا، مثل startswith(CardName, 'Al').
  • رمّز المسافات وعلامات الاقتباس في عنوان URL عندما لا تفعل مكتبة HTTP لديك ذلك نيابة عنك.

لقراءة سجل واحد، ضع مفتاحه بين قوسين: GET /b1s/v1/Orders(125) للأمر الذي قيمة DocEntry له 125، أو GET /b1s/v1/BusinessPartners('C20000') لشريك أعمال.

يجمع منشئ طلبات Service Layer هذه العناوين لك، مع علامات الاقتباس الصحيحة.

الخطوة 3: التعامل مع الترقيم

لا تعيد Service Layer كل شيء دفعة واحدة أبدًا. حجم الصفحة الافتراضي 20. وعندما توجد سجلات أكثر، تنتهي الاستجابة برابط للصفحة التالية:

{
  "value": [ ... 20 records ... ],
  "odata.nextLink": "Orders?$select=DocEntry,DocNum&$skip=20"
}

لديك طريقتان للتعامل مع ذلك.

  1. اتبع nextLink. استدعِ العنوان الذي يعطيه (وهو نسبي إلى /b1s/v1/) حتى لا يعود أي nextLink. هذه أكثر الطرق أمانًا لقراءة قائمة كاملة.
  2. اطلب صفحات أكبر. أرسل ترويسة Prefer:
GET /b1s/v1/Items?$select=ItemCode,ItemName,QuantityOnStock
Prefer: odata.maxpagesize=200

يؤكد الخادم الحجم الذي استخدمه في ترويسة Preference-Applied. القيمة odata.maxpagesize=0 توقف الترقيم، لكن تجنّبها في الجداول الكبيرة مثل الفواتير أو قيود اليومية. فالاستجابة الضخمة قد تنتهي مهلتها أو تُثقل الخادم.

الترقيم الذي يتحكم فيه الخادم: Prefer: odata.maxpagesize

يحدد الخادم حجم الصفحة ما لم يطلب الطلب شيئًا آخر. اطلب ذلك لكل طلب باستخدام ترويسة OData:

GET /b1s/v1/Orders?$select=DocEntry,DocNum
Prefer: odata.maxpagesize=100

تؤكد الاستجابة ما طُبّق:

HTTP/1.1 200 OK
Preference-Applied: odata.maxpagesize=100

تأتي القيمة الافتراضية 20 من الخيار PageSize في الملف conf/b1s.conf على خادم Service Layer. وتغييرها هناك يغيّر القيمة الافتراضية لكل عميل يستدعي تلك الـ Service Layer، لذلك فضّل الترويسة في كودك واترك إعداد الخادم كما هو. وعندما يُضبط الاثنان، تفوز ترويسة odata.maxpagesize.

يمكنك أيضًا الترقيم بنفسك باستخدام $top و $skip. إذا فعلت ذلك، فأضف دائمًا $orderby على حقل مفتاحي، وإلا قد تنتقل السجلات بين الصفحات.

الخطوة 4: إنشاء أمر بيع بطلب POST

POST /b1s/v1/Orders
Content-Type: application/json
Cookie: B1SESSION=...; ROUTEID=...
{
  "CardCode": "C20000",
  "DocDueDate": "2026-10-30",
  "Comments": "Created from web portal",
  "DocumentLines": [
    { "ItemCode": "A00001", "Quantity": 5, "WarehouseCode": "01" },
    { "ItemCode": "A00002", "Quantity": 2, "UnitPrice": 150.0 }
  ]
}

يعيد طلب POST الناجح 201 Created مع المستند الجديد كاملًا، بما في ذلك DocEntry و DocNum. احفظ قيمة DocEntry، فأنت تحتاجها لكل تحديث لاحق.

الخطوة 5: التحديث بطلب PATCH

يغيّر PATCH الحقول التي ترسلها فقط. ويبقى كل شيء آخر كما هو:

PATCH /b1s/v1/Orders(125)
Content-Type: application/json
{
  "Comments": "Delivery moved to Friday",
  "DocDueDate": "2026-11-06"
}

يعيد طلب PATCH الناجح 204 No Content. كن حذرًا عند تعديل أسطر المستند بطلب PATCH. اختبر على نسخة من الشركة أولًا، ثم اقرأ المستند بعد ذلك لتتأكد أن الأسطر كما تتوقع.

ربط الكيانات: $crossjoin و QueryService_PostQuery

يعمل $filter العادي على مجموعة كيانات واحدة، فلا يستطيع مثلًا ربط الأوامر بشركاء الأعمال. لذلك يصف دليل مستخدم Service Layer المورد $crossjoin ‏(SAP Business One 9.2 لـ SAP HANA ‏PL07 وما بعده):

GET /b1s/v1/$crossjoin(Orders,BusinessPartners)?$expand=Orders($select=DocEntry,DocNum),BusinessPartners($select=CardCode)&$filter=Orders/CardCode eq BusinessPartners/CardCode

وللتصفية على أسطر المستند (الرأس والأسطر معًا)، يصف الدليل خدمة استعلام، QueryService_PostQuery، تأخذ المسار وخيارات الاستعلام كحقلين منفصلين في جسم طلب POST:

POST /b1s/v1/QueryService_PostQuery
Content-Type: application/json
{
  "QueryPath": "$crossjoin(Orders,Orders/DocumentLines)",
  "QueryOption": "$expand=Orders($select=DocEntry,DocNum),Orders/DocumentLines($select=ItemCode,LineNum)&$filter=Orders/DocEntry eq Orders/DocumentLines/DocEntry and Orders/DocumentLines/LineNum eq 0"
}

راجع ملاحظات الإصدار في دليل المستخدم لإصدارك قبل أن تعتمد عليها. وإذا أصبح الربط معقدًا، فإن استعلام SQL محفوظًا يُستدعى عبر Service Layer يكون غالبًا أبسط؛ انظر أخطاء SQLQueries وحلولها.

الخطوة 6: تسجيل الخروج

POST /b1s/v1/Logout

يحرّر تسجيل الخروج الجلسة على الخادم. لمهمة ليلية، سجّل الدخول مرة واحدة، ونفّذ العمل، ثم سجّل الخروج. ولبوابة ويب، احتفظ بجلسة واحدة لكل مستخدم أو بمجموعة صغيرة من الجلسات، بدل تسجيل الدخول مع كل طلب.

الأخطاء الشائعة ومعناها

الخطأالسبب المعتادالإصلاح
401 Unauthorizedانتهت الجلسة، أو لم تُرسل ملفات تعريف الارتباطسجّل الدخول مجددًا؛ وتحقق من وجود الملفين في الطلب
خطأ CORS في المتصفحالمصدر غير مسموحفعّل CORS في إعدادات Service Layer ‏(CorsEnable و CorsAllowedOrigins)، أو استدعِ من الخادم الخلفي
خطأ SSL أو شهادةالشهادة الافتراضية موقّعة ذاتيًاثبّت شهادة صحيحة؛ ولا تثق بالشهادة الموقّعة ذاتيًا إلا في الاختبار
فشل تسجيل الدخول برسالة ترخيصالمستخدم ليس لديه ترخيص مناسبخصّص ترخيصًا للمستخدم في إدارة التراخيص (License Administration)
400 مع رسالة خطأحقل مفقود أو قيمة خاطئة أو قاعدة عملاقرأ error.message.value؛ فهي تسمّي الحقل

رموز الأخطاء داخل error.code هي في الغالب نفسها رموز DI API؛ انظر مقابلات رموز أخطاء Service Layer في DI API.

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

DI API أم Service Layer؟

الجانبDI APIService Layer
النوعمكتبة COMREST / OData عبر HTTPS
المنصةWindowsأي منصة عميل
اللغات.NET أساسًاأي لغة تدعم HTTP
الأنسب لـالإضافات التقليدية بجانب عميل B1بوابات الويب، وتطبيقات الجوال، والتكاملات السحابية
التزامناتصال واحد لكل عمليةجلسات كثيرة مع موازنة الأحمال

لكل جديد يتعامل مع SAP Business One من خارج العميل، نستخدم Service Layer. وهي ما نبني عليه بوابات الأعمال وتطبيقات الجوال. وما زال لـ DI API مكان في إضافات Windows القائمة.

لتجربة هذه الاستدعاءات على نظامك، ابدأ بـ منشئ طلبات Service Layer.

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

المصادر

خدمات ذات صلة

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

أسئلة شائعة

ما الفرق بين ‎/b1s/v1 و ‎/b1s/v2؟

يستخدم المسار v1 الإصدار 3 من OData، ويستخدم v2 الإصدار 4. تعتبر SAP الآن الإصدار v4 البروتوكول الأساسي. والفرق الظاهر الأبرز في الاستجابات هو بادئة التعليقات التوضيحية: يعيد v2 الحقل ‎@odata.nextLink بينما يعيد v1 الحقل odata.nextLink.

كم تدوم جلسة Service Layer؟

المهلة الافتراضية 30 دقيقة من عدم النشاط. تعيد استجابة Login القيمة في الحقل SessionTimeout. وكل استدعاء يعيد ضبط المؤقت، فالتكامل النشط يُبقي جلسته حية.

ما حجم الصفحة الافتراضي في SAP B1 Service Layer؟

20. لهذا يعيد طلب GET عشرين سجلًا فقط. اتبع nextLink في الاستجابة، أو أرسل الترويسة Prefer: odata.maxpagesize=100 للحصول على صفحات أكبر لذلك الطلب. القيمة الافتراضية على مستوى الخادم هي الخيار PageSize في conf/b1s.conf، وترويسة Prefer لها الأولوية عليه.

هل أستخدم DI API أم Service Layer لمشروع جديد؟

لتكاملات الويب والجوال والسحابة الجديدة، استخدم Service Layer. فهي تعمل عبر HTTPS من أي لغة وأي منصة. أما DI API فما زالت منطقية لإضافات .NET القائمة التي تعمل على Windows بجانب عميل SAP Business One.

لماذا يفشل تطبيق المتصفح لدي بخطأ CORS بينما يعمل Postman؟

تحظر المتصفحات الاستدعاءات بين المصادر المختلفة ما لم يسمح بها الخادم. وخاصية CORS معطّلة في Service Layer افتراضيًا. فعّلها في إعدادات Service Layer وأضف مصدر تطبيقك، أو استدعِ Service Layer من الخادم الخلفي الخاص بك بدلًا من ذلك.

جاهز للبدء؟

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