تخطَّ إلى المحتوى

الموافقة على المستندات والتوقيع

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

كود الموافقة ليس جزءًا من cmp.js. يُحمَّل تلقائيًا عند أول استدعاء لإحدى الدالتين أدناه (أو مسبقًا عبر data-modules="documents")؛ راجع الحزم والوحدات المحملة عند الطلب.


1. CMP.showDocumentApproval(slug, options) — مربع حوار HashEntry

Section titled “1. CMP.showDocumentApproval(slug, options) — مربع حوار HashEntry”

تحمّل الإصدار النشط من المستند، وتعرضه في مربع حوار بزرَّي “قبول” و”رفض”، وتسجّل الموافقة عندما يقبل الشخص.

const result = await CMP.showDocumentApproval('distance-sales-agreement', {
language: 'en', // اختياري، الافتراضي لغة الحزمة
metadata: { order_id: 'ORD-54321' }, // اختياري
approvalToken: tokenFromYourBackend // اختياري / مطلوب، انظر أدناه
});
if (result.success && result.decision === 'accepted') {
continueCheckout(result.consent_token);
} else if (result.decision === 'rejected') {
// رفض الشخص
} else {
showError(result.error); // { code, status, message }
}
الخيارالوصف
languageلغة إصدار المستند المراد عرضه.
metadataأزواج مفتاح/قيمة تُخزَّن مع السجل (تُدمج مع CMP.setMetadata).
approvalTokenرمز مميز (token) للموافقة لمرة واحدة يصدره خادمك الخلفي.

للتوافق مع الإصدارات السابقة، يُعامَل الكائن العادي الخالي من أي من هذه المفاتيح على أنه metadata.

الرفض يغلق مربع الحوار ويطلق document:rejected؛ ولا يُرسل أي سجل إلى الخادم. إذا فشل الحفظ بخطأ مؤقت، يبقى مربع الحوار مفتوحًا ويستطيع الشخص الضغط على “قبول” مرة أخرى — وتستخدم إعادة المحاولة مفتاح عدم التكرار (idempotency key) نفسه (والرمز المميز نفسه).

2. CMP.approveDocument(slug, options) — واجهتك الخاصة

Section titled “2. CMP.approveDocument(slug, options) — واجهتك الخاصة”

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

const result = await CMP.approveDocument('terms-of-service', {
approvalToken: tokenFromYourBackend,
metadata: { order_id: 'ORD-54321' }
});
الخياريُرسل باسمالوصف
version_iddocument_version_idالإصدار المراد الموافقة عليه. إذا أُغفل، تحدد الحزمة الإصدار النشط للغة language.
version—تسمية الإصدار التي تُعاد في النتيجة عندما تمرّر version_id.
languagelanguageلغة الإصدار.
decisiondecision'accepted' (الافتراضي) أو 'rejected'.
visitor_idvisitor_idمرجعك الخاص للشخص (100 محرف كحد أقصى). يُتجاهل عند استخدام رمز موافقة مميز — إذ تُخزَّن قيمة subject الخاصة بالرمز بدلًا منه.
approvalTokenapproval_tokenرمز مميز للموافقة لمرة واحدة.
document_content_base64custom_document_contentمحتوى مستند أنشأه نظامك (HTML أو نص عادي أو PDF؛ حتى نحو 500 KB بعد فك الترميز).
document_mime_typecustom_document_mime_typetext/html أو text/plain أو application/pdf.
signatureحقول في المستوى الأعلىراجع حقول التوقيع.
metadatametadataأزواج مفتاح/قيمة تُخزَّن مع السجل.

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


الرموز المميزة للموافقة لمرة واحدة

Section titled “الرموز المميزة للموافقة لمرة واحدة”

توقّع حزمة المتصفح طلباتها بمفتاح API للموقع، وهو ظاهر في مصدر صفحتك. ولذلك فإن الموافقة على مستند المرسلة من متصفح تثبت أن شخصًا ما لديه وصول إلى صفحتك أرسلها؛ أما الاسم أو عنوان البريد الإلكتروني الوارد فيها فهو ما كُتب أيًّا كان.

الرمز المميز للموافقة يتيح لخادمك الخلفي أن يشهد بهوية من يوافق:

  1. خادمك الخلفي — الذي يعرف المستخدم المسجَّل دخوله — يستدعي POST /tool/v1/s2s/approval-tokens (راجع REST API) ويتلقى رمزًا مميزًا (hat_…).
  2. تمرّر الرمز إلى الصفحة وتسلّمه إلى الحزمة بصفة approvalToken.
  3. ترسله الحزمة في الحقل approval_token في المستوى الأعلى. يستهلكه الخادم بعملية ذرّية، ويأخذ هوية الشخص من الرمز لا من المتصفح، ويخزّن السجل مع identity_assurance: tenant_attested.

القواعد:

  • الرمز صالح لموقع واحد ومستند واحد (واختياريًا لإصدار واحد)، لمدة محدودة (الافتراضي 10 دقائق، والحد الأقصى ساعة واحدة)، ولمرة واحدة.
  • يمكن ضبط مستند في لوحة التحكم بحيث يتطلب رمزًا. في مثل هذا المستند تفشل الحزمة فورًا، دون إرسال أي طلب، إذا لم يُعطَ رمز: error.code = "APPROVAL_TOKEN_REQUIRED". ويفرض الخادم القاعدة نفسها.
  • رموز الأخطاء الصادرة عن الخادم تُمرَّر دون تغيير: APPROVAL_TOKEN_REQUIRED و APPROVAL_TOKEN_INVALID (غير معروف، أو منتهي الصلاحية، أو مستخدَم من قبل، أو صادر لموقع/مستند آخر) و APPROVAL_TOKEN_CONFLICT (حقل من حقول الموقِّع أو محتوى المستند المرسل من المتصفح يناقض ما يشهد به الرمز).
  • عند فشل الشبكة أو رد 5xx تعيد الحزمة المحاولة بالرمز نفسه وبمفتاح عدم التكرار نفسه؛ ويعامل الخادم التكرار على أنه الطلب نفسه. بعد جواب 4xx نهائي لا تُعاد أي محاولة، والموافقات لا تُخزَّن أبدًا في قائمة الانتظار غير المتصلة. أصدر رمزًا جديدًا للمحاولة من جديد.

تقبل approveDocument كائن signature للموافقات التي تُجمع بتوقيع مرسوم أو بإقرار صريح. لا تتضمن الحزمة لوحة توقيع: أنت تعرض اللوحة (أو مربع اختيار الإقرار) وتمرّر النتيجة.

await CMP.approveDocument('service-contract', {
approvalToken: tokenFromYourBackend,
signature: {
image_base64: canvas.toDataURL('image/png'),
mime_type: 'image/png',
signer_name: 'Jane Doe',
signer_email: '[email protected]',
declaration_text: 'I have read and accept the service contract.',
input_type: 'touch',
stroke_count: 14,
drawing_duration_ms: 3200,
screen_resolution: '390x844'
}
});
الحقليُرسل باسمملاحظات
image_base64signature_imagePNG أو JPEG أو WebP؛ حتى نحو 150 KB بعد فك الترميز.
mime_typesignature_mime_type
signer_name, signer_email, signer_phone, signer_id_numberالأسماء نفسهاما يصرّح به الموقِّع عن نفسه، ما لم يشهد به رمز موافقة مميز.
declaration_textdeclaration_textالجملة التي وافق عليها الشخص (1000 محرف كحد أقصى).
input_typeinput_typetouch أو mouse أو pen.
stroke_count, drawing_duration_ms, strokes_dataالأسماء نفسهابيانات قياس الرسم.
screen_resolutionscreen_resolution

تُرسل هذه كلها حقولًا في المستوى الأعلى من الطلب، لا داخل metadata. الحقلان otp_verified / otp_reference لا يُقبلان من متصفح؛ ولا يُعتدّ بهما إلا على مسار خادم إلى خادم أو عبر رمز موافقة مميز.

ما معنى “توقيع إلكتروني بسيط” هنا

Section titled “ما معنى “توقيع إلكتروني بسيط” هنا”

السجل المنشأ بهذه الطريقة هو توقيع إلكتروني بسيط: بيانات في شكل إلكتروني (الصورة المرسومة، والإقرار، والسياق التقني) مرتبطة بإصدار محدد من مستند واستخدمها الموقِّع للتوقيع. وهو ليس توقيعًا إلكترونيًا متقدمًا ولا مؤهلًا — فلا تُصدر شهادة للموقِّع، ولا يتحقق HashEntry من هوية الموقِّع.

ما يُظهره الدليل:

  • أي إصدار من المستند (بحسب تجزئة المحتوى) تمت الموافقة عليه، ومتى، ومن أي عنوان IP و user agent، وبأي بيانات مصرَّح بها عن الموقِّع؛
  • أن السجل لم يُعدَّل منذ كتابته (راجع التحقق من الأدلة دون اتصال)؛
  • مدى قوة إسناد الهوية، في الحقل identity_assurance:
القيمةالمعنى
self_declaredبيانات الموقِّع جاءت من المتصفح. لم يتحقق منها أحد.
tenant_attestedخادمك الخلفي شهد بهوية الشخص، إما برمز موافقة مميز لمرة واحدة أو بالتصريح بإتمام فحص OTP على مسار خادم إلى خادم. الضمان ضمانك أنت: يسجّل HashEntry أنك أنت من شهد بذلك، لا أن HashEntry تحقق منه.

كون التوقيع الإلكتروني البسيط كافيًا لعقد معيّن يتوقف على القانون الواجب التطبيق وعلى نوع المعاملة؛ وبعض المعاملات تتطلب شكلًا محددًا. اسأل مستشارك القانوني عن المستوى الذي تحتاج إليه.


عندما يتغير إصدار المستند

Section titled “عندما يتغير إصدار المستند”

إذا أجاب الخادم بـ 409 CONFIG_OUTDATED، تعيد الحزمة قراءة الإصدار النشط من المستند:

  • لم يتغير (كانت ذاكرة الخادم المؤقتة باردة) ← يُرسل الطلب نفسه مرة أخرى؛
  • تغيّر ← لا يُعاد إرسال الموافقة. تكون النتيجة success: false مع error.code = "DOCUMENT_VERSION_CHANGED"، ويُطلق document:error.

في الحالة الثانية اعرض المستند من جديد (فالشخص لم يرَ الإصدار الجديد) واجمع موافقة جديدة — برمز جديد إن كنت تستخدم الرموز المميزة.


النتائج والأحداث والأخطاء

Section titled “النتائج والأحداث والأخطاء”
CMP.on('document:approved', ({ slug, version, consentId }) => {});
CMP.on('document:rejected', ({ slug, version }) => {});
CMP.on('document:error', ({ slug, version, code, status, message }) => {});
error.codeما العمل
MODULE_LOAD_FAILEDتعذر تحميل ملف الوحدة (الشبكة، حاجب الإعلانات، CSP). استدعِ الدالة من جديد لإعادة المحاولة.
DOCUMENT_NOT_FOUND, VERSION_NOT_FOUNDتحقق من الـ slug، ومن أن المستند مرفق بالموقع وأن له إصدارًا نشطًا باللغة المطلوبة.
APPROVAL_TOKEN_REQUIREDأصدر رمزًا مميزًا من خادمك الخلفي ومرّره.
APPROVAL_TOKEN_INVALID, APPROVAL_TOKEN_CONFLICTأصدر رمزًا جديدًا؛ وتأكد من أن حقول الموقِّع تطابق الرمز.
DOCUMENT_VERSION_CHANGEDاعرض المستند من جديد.
CONFIG_OUTDATEDالإصدار الذي مرّرته غير نشط وتعذرت إعادة فحصه.
NETWORK_ERROR, TIMEOUT, RATE_LIMIT_EXCEEDED, QUEUE_OVERLOADEDمؤقت. دع الشخص يحاول من جديد.
VALIDATION_ERROR وأخطاء الحجم (SIGNATURE_IMAGE_TOO_LARGE, CUSTOM_DOCUMENT_TOO_LARGE, …)أصلح الطلب.

لا تعدّ الموافقة ممنوحة إلا عندما يكون result.success === true. احتفظ بـ result.consent_token: فهو يعرّف السجل للتحقق لاحقًا ولتصدير الأدلة.