الموافقة على المستندات والتوقيع
إلى جانب الموافقة على ملفات تعريف الارتباط، تستطيع الحزمة تسجيل أن شخصًا وافق على إصدار محدد من مستند — شروط الخدمة، أو عقد بيع عن بُعد، أو إشعار خصوصية، أو مستند أنشأه نظامك أنت.
كود الموافقة ليس جزءًا من cmp.js. يُحمَّل تلقائيًا عند أول استدعاء لإحدى الدالتين أدناه (أو مسبقًا عبر data-modules="documents")؛ راجع الحزم والوحدات المحملة عند الطلب.
طريقتان لجمع الموافقة
Section titled “طريقتان لجمع الموافقة”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_id | document_version_id | الإصدار المراد الموافقة عليه. إذا أُغفل، تحدد الحزمة الإصدار النشط للغة language. |
version | — | تسمية الإصدار التي تُعاد في النتيجة عندما تمرّر version_id. |
language | language | لغة الإصدار. |
decision | decision | 'accepted' (الافتراضي) أو 'rejected'. |
visitor_id | visitor_id | مرجعك الخاص للشخص (100 محرف كحد أقصى). يُتجاهل عند استخدام رمز موافقة مميز — إذ تُخزَّن قيمة subject الخاصة بالرمز بدلًا منه. |
approvalToken | approval_token | رمز مميز للموافقة لمرة واحدة. |
document_content_base64 | custom_document_content | محتوى مستند أنشأه نظامك (HTML أو نص عادي أو PDF؛ حتى نحو 500 KB بعد فك الترميز). |
document_mime_type | custom_document_mime_type | text/html أو text/plain أو application/pdf. |
signature | حقول في المستوى الأعلى | راجع حقول التوقيع. |
metadata | metadata | أزواج مفتاح/قيمة تُخزَّن مع السجل. |
إذا تداخل زمنيًا استدعاءان للمستند نفسه والإصدار نفسه والقرار نفسه، فإنهما يتشاركان طلبًا واحدًا ونتيجة واحدة، ولذلك لا ينشئ النقر المزدوج سجلين.
الرموز المميزة للموافقة لمرة واحدة
Section titled “الرموز المميزة للموافقة لمرة واحدة”توقّع حزمة المتصفح طلباتها بمفتاح API للموقع، وهو ظاهر في مصدر صفحتك. ولذلك فإن الموافقة على مستند المرسلة من متصفح تثبت أن شخصًا ما لديه وصول إلى صفحتك أرسلها؛ أما الاسم أو عنوان البريد الإلكتروني الوارد فيها فهو ما كُتب أيًّا كان.
الرمز المميز للموافقة يتيح لخادمك الخلفي أن يشهد بهوية من يوافق:
- خادمك الخلفي — الذي يعرف المستخدم المسجَّل دخوله — يستدعي
POST /tool/v1/s2s/approval-tokens(راجع REST API) ويتلقى رمزًا مميزًا (hat_…). - تمرّر الرمز إلى الصفحة وتسلّمه إلى الحزمة بصفة
approvalToken. - ترسله الحزمة في الحقل
approval_tokenفي المستوى الأعلى. يستهلكه الخادم بعملية ذرّية، ويأخذ هوية الشخص من الرمز لا من المتصفح، ويخزّن السجل معidentity_assurance: tenant_attested.
القواعد:
- الرمز صالح لموقع واحد ومستند واحد (واختياريًا لإصدار واحد)، لمدة محدودة (الافتراضي 10 دقائق، والحد الأقصى ساعة واحدة)، ولمرة واحدة.
- يمكن ضبط مستند في لوحة التحكم بحيث يتطلب رمزًا. في مثل هذا المستند تفشل الحزمة فورًا، دون إرسال أي طلب، إذا لم يُعطَ رمز:
error.code = "APPROVAL_TOKEN_REQUIRED". ويفرض الخادم القاعدة نفسها. - رموز الأخطاء الصادرة عن الخادم تُمرَّر دون تغيير:
APPROVAL_TOKEN_REQUIREDوAPPROVAL_TOKEN_INVALID(غير معروف، أو منتهي الصلاحية، أو مستخدَم من قبل، أو صادر لموقع/مستند آخر) وAPPROVAL_TOKEN_CONFLICT(حقل من حقول الموقِّع أو محتوى المستند المرسل من المتصفح يناقض ما يشهد به الرمز). - عند فشل الشبكة أو رد 5xx تعيد الحزمة المحاولة بالرمز نفسه وبمفتاح عدم التكرار نفسه؛ ويعامل الخادم التكرار على أنه الطلب نفسه. بعد جواب 4xx نهائي لا تُعاد أي محاولة، والموافقات لا تُخزَّن أبدًا في قائمة الانتظار غير المتصلة. أصدر رمزًا جديدًا للمحاولة من جديد.
حقول التوقيع
Section titled “حقول التوقيع”تقبل approveDocument كائن signature للموافقات التي تُجمع بتوقيع مرسوم أو بإقرار صريح. لا تتضمن الحزمة لوحة توقيع: أنت تعرض اللوحة (أو مربع اختيار الإقرار) وتمرّر النتيجة.
await CMP.approveDocument('service-contract', { approvalToken: tokenFromYourBackend, signature: { image_base64: canvas.toDataURL('image/png'), mime_type: 'image/png', signer_name: 'Jane Doe', declaration_text: 'I have read and accept the service contract.', input_type: 'touch', stroke_count: 14, drawing_duration_ms: 3200, screen_resolution: '390x844' }});| الحقل | يُرسل باسم | ملاحظات |
|---|---|---|
image_base64 | signature_image | PNG أو JPEG أو WebP؛ حتى نحو 150 KB بعد فك الترميز. |
mime_type | signature_mime_type | |
signer_name, signer_email, signer_phone, signer_id_number | الأسماء نفسها | ما يصرّح به الموقِّع عن نفسه، ما لم يشهد به رمز موافقة مميز. |
declaration_text | declaration_text | الجملة التي وافق عليها الشخص (1000 محرف كحد أقصى). |
input_type | input_type | touch أو mouse أو pen. |
stroke_count, drawing_duration_ms, strokes_data | الأسماء نفسها | بيانات قياس الرسم. |
screen_resolution | screen_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: فهو يعرّف السجل للتحقق لاحقًا ولتصدير الأدلة.