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

تسجيل خطوة إضافة على الخادم

معرّف المخطط: plugin-step@1 المخطط القابل للقراءة آليًا: plugin-step.schema.json

الغلاف المرجعي لتسجيل خطوة إضافة على الخادم (القسم 6.6) — وهي منطق يعمل على الخادم عند إنشاء سجل على جدول أو تحديثه أو حذفه. ويحدد الغلاف متى يعمل المنطق وكيف؛ أما التنفيذ المكتوب بلغة BS Lang فيحمل السكربت مضمَّنًا أيضًا، ويجري التحقق منه بقواعد لغة BS Lang إضافةً إلى هذا المخطط. ويجري التحقق من التسجيل بالطريقة نفسها سواء جاء من مصمّم، أو من استدعاء API، أو من مساعد ذكاء اصطناعي، أو من استيراد حل.

الشكل​

الحقلالنوعمطلوبملاحظات
logicalNamestringنعممسبوق ببادئة الناشر، بصيغة snake_case صغيرة.
displayNamestringنعماسم الخطوة المقروء.
publisherPrefixstringنعمبادئة الناشر المالك التي يجب أن يُنسَب إليها logicalName — لا بادئة الجدول الذي تراقبه الخطوة. فالجدول القياسي مثل account بلا بادئة عن قصد، والتحقق مقابله كان يجعل تسمية خطوة عليه مستحيلة.
entitystringنعمالجدول الذي تُطلق عمليات الكتابة عليه الخطوة.
messagestringنعمCreate أو Update أو Delete.
stagestringنعمPreValidation أو PreOperation أو PostOperation.
executionModestringنعمSynchronous (متزامن، داخل عملية الكتابة) أو Asynchronous (يُصفّ عبر صندوق الصادر ويُنفَّذ بعد اعتماد الكتابة). والخطوة غير المتزامنة يجب أن تكون PostOperation: فهي تعمل بعد حفظ السجل فعلاً، فلم يبقَ لها ما ترفضه.
rankintegerنعمترتيب التنفيذ بين الخطوات المشتركة في الجدول والرسالة والمرحلة نفسها؛ والأقل يعمل أولًا.
isEnabledbooleanنعمالخطوة المعطّلة تُخزَّن لكنها لا تُنفَّذ أبدًا.
implementationobjectنعمتنفيذ واحد بالضبط (انظر أدناه).

التنفيذ​

الحقلالنوعمطلوبملاحظات
typestringنعمBsLangScript أو DotNetAssembly.
scriptstringعند BsLangScriptشيفرة BS Lang المصدرية.
assemblyReferencestringعند DotNetAssemblyمفتاح التخزين للتجميعة المرفوعة.
typeNamestringعند DotNetAssemblyنوع الإضافة المراد إنشاء مثيل منه.

المراحل​

  • PreValidation — تعمل قبل العملية؛ لفحوص الشكل والأمان العامة.
  • PreOperation — تعمل قبيل الكتابة مباشرةً؛ ويجوز لها تغيير قيم حقول على السجل أو رفض العملية بأكملها.
  • PostOperation — تعمل بُعيد الكتابة مباشرةً؛ للتغييرات المتتالية أو التابعة.

ترفض الخطوة عمليةً باستدعاء throwValidationError("reason")، وهو ما يوقف الكتابة ويعيد السبب إلى المستدعي.

مثال​

{
"logicalName": "par_invoice_reject_negative",
"displayName": "Reject negative invoice total",
"entity": "par_invoice",
"message": "Create",
"stage": "PreOperation",
"executionMode": "Synchronous",
"rank": 1,
"isEnabled": true,
"implementation": {
"type": "BsLangScript",
"script": "if (getValue(\"par_total\") < 0) { throwValidationError(\"Total cannot be negative.\"); }"
}
}

دوال المضيف لسكربتات BS Lang​

تقرأ خطوة من نوع BsLangScript السجلَ وتغيّره عبر دوال المضيف هذه:

الدالةالغرض
getValue("field")القيمة الحالية لحقل على السجل الجاري كتابته.
setValue("field", value)تغيير قيمة حقل (يُعتدّ بها في PreOperation فقط).
getPreValue("field")القيمة السابقة للحقل (في التحديثات والحذف).
throwValidationError("message")رفض العملية والتراجع عنها.
message() / stage() / entityName()العملية والمرحلة والجدول الحالي.
userId() / depth()المستخدم الذي أطلق العملية وعمق التكرار.

الوصول إلى جداول أخرى​

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

الدالةالغرض
getRecord("table", id)سجل واحد ككائن، أو فارغ إن لم يوجد. و.id عليه.
queryRecords("table", "field", value)الصفوف التي يساوي فيها حقلٌ قيمةً، كقائمة كائنات. بحد أقصى 200.
runQuery({ … })ينفّذ مستند parsware-query@1 كاملاً — مرشّحات and/or متداخلة بعشرة معاملات، وارتباطات، وترتيب، وتصفّح، أو aggregate يجيب بمجموعات. وهي لغة الاستعلام نفسها التي يُنتجها «البحث المتقدم» ويخزّنها الاستعلام المحفوظ. الصفوف محدودة بـ200؛ والتجميع غير محدود. والعمود المرتبط يُقرأ تحت اسمه المستعار (row.acct.par_industry)، و'from' في الارتباط يجب أن يكون بين اقتباسين لأن from كلمة مفتاحية في BS Lang.
runSavedQuery("name")ينفّذ استعلاماً محفوظاً باسمه المنطقي. فالتعقيد يبقى في مصمّم ويسافر مع الحل، ولا يسمّي السكربت إلا السؤال.
countRecords("table", "field", value)كم عددها، دون جلبها — عدٌّ حقيقي، فيصحّ حتى بعد حد الـ200 صف الذي يحدّ queryRecords.
createRecord("table", { field: value, … })يُنشئ سجلاً ويعيد معرّفه.
updateRecord("table", id, { field: value, … })يغيّر الحقول المذكورة وحدها.
deleteRecord("table", id)يحذف سجلاً.

الكتابة بهذه الطريقة تُشغّل القواعد المعتادة، فالخطوة المسجّلة على الجدول المكتوب تعمل بدورها. وهذا التداخل محدود بعمق ثمانية، وdepth() تخبر السكربت أين هو — لكن الحد شبكة أمان لا تصميم. فالخطوة التي تكتب الجدول الذي تراقبه ستُطلق نفسها، وعلاجها شرطٌ أو جدولٌ آخر.

استيراد منطق مشترك​

يمكن لسكربت الخطوة أن يستورد سكربت حلّ بالاسم بـ import، تماماً كقاعدة عمل على جهة العميل، فتُكتب القاعدة التي تفرضها عدة خطوات مرة واحدة:

import 'par_approval_rules';

if (getValue('par_total') > par_approval_rules.limit()) { … }

كلا نوعَي علامات الاقتباس يعمل. ويجب أن تكون الوحدة سكربت حلّ في البيئة نفسها؛ وأي شيء آخر يفشل عند حفظ الخطوة لا عند تنفيذها.