نظام واتساب في ڤاريونس: الربط والأزرار والفلوهات والقوالب وتأكيد الطلبات
نظام واتساب في ڤاريونس هو تكامل Meta WhatsApp Business داخل اللوحة: ربط الحساب من /dashboard/whatsapp عبر Embedded Signup، ثم إرسال تلقائي لقالب تأكيد الطلب بأزرار تأكيد/إلغاء/تعديل، وإرسال يدوي من CRM وصفحة الطلبات، مع تتبع التسليم والردود على الطلب نفسه.
آخر تحقق: 2026-09-19
يُدار نظام واتساب من مسار /dashboard/whatsapp، وصفحته هي WhatsAppDashboardPage من features/dashboard-whatsapp مع مخزن Zustand useWhatsAppStore وخطاف useWhatsAppConnected الذي يحدد ظهور عمود واتساب في /dashboard/orders وأزرار الإرسال في CRM.
الأزرار الموجودة فعلياً في الصفحة: مربع قبول الشروط وسياسة الخصوصية (بوابة قبل الربط)، زر ربط واتساب Connect، زر إلغاء الربط Disconnect بتأكيد المتصفح و phoneNumberId واحد فقط، زر إعادة مزامنة الويبهوك Resync webhooks، زر التفاصيل Details الذي يفتح حوار تشخيص الهاتف وWABA والقوالب، وزر الإعدادات Settings الذي يفتح OrderConfirmationSettingsDialog (تفعيل تلقائي + لغة ar/en). وفي /dashboard/orders يظهر عمود تأكيد واتساب وشارة WhatsAppConfirmationBadge وزر إرسال رسالة فقط عندما يوجد حساب isConnected.
فلو الربط: تحميل الحسابات GET /api/whatsapp/accounts، ثم بوابات (الشروط + متغيرات NEXT_PUBLIC_FACEBOOK_APP_ID و NEXT_PUBLIC_WHATSAPP_CONFIG_ID + HTTPS)، ثم تحويل يدوي إلى dialog/oauth مع redirect_uri يساوي origin+pathname و state في sessionStorage، ثم رجوع Facebook بنفس الصفحة مع ?code=&state= ثم POST /api/whatsapp/callback الذي يبادل الكود عبر GET /oauth/access_token قبل dbConnect، ويكتشف WABA عبر debug_token و granular_scopes ثم phone_numbers، ثم upsert ب WhatsAppAccount بمفتاح merchantId+phoneNumberId، ثم POST /{waba-id}/subscribed_apps مع override_callback_uri اختياري، ثم محاولة نشر قالبي order_confirmation_ar و order_confirmation_en دون تعطيل الربط عند الفشل.
فلو تأكيد الطلب: عند إنشاء طلب من Checkout العام أو يدوياً من اللوحة يُرسل القالب المختار fire-and-forget بعد الحفظ. النص يُبنى من lib/whatsapp/order-confirmation-body.js بمصدر واحد، بخمسة متغيرات مرقمة، مع تعقيم (أسطر جديدة وعلامات تبويب تتحول لمسافات). كل إرسال ناجح ينشئ صف WhatsAppOrderConfirmation بمفتاح outboundMessageId الفريد (source تلقائي أو يدوي). رد العميل بزر يُطابق عبر message.context.id على نفس الصف: تأكيد يحفظ confirmed ويحمي حجوزات المخزون النشطة دون تغيير data.status، وتعديل يسجل edit_requested دون حركة مخزون، وإلغاء يحرر المخزون أولاً عبر cancelOrderAndReleaseStock ثم يغير data.status غير المنتهي إلى cancelled فقط عند نجاح التحرير. بعد كل claim ناجح يُرسل إقرار نصي مجاني مخصوم بـ acknowledgementMessageId. حالات التسليم sent/delivered/read/failed تُطبق monotonic و failed نهائي.
الإرسال اليدوي POST /api/whatsapp/send يقبل to و type text/template و customerId مع template.name ولغة، ومصدر باراميترات واحد: components بشكل Meta الكامل، أو bodyParameters المختصر، أو orderId لقوالب تأكيد الطلب فقط حيث يبني الخادم الخمس قيم من نفس الطلب داخل نفس المتجر. حوار CRM (WhatsAppSenderDialog) يعد {{n}} في نص القالب ويرسم حقلاً لكل متغير، ولقوالب تأكيد الطلب يمرر رقم الطلب تلقائياً من صف الطلب دون إعادة إدخال. الأرقام تُطبَّع إلى E.164 digits عبر toWhatsAppSendNumber (صفر محلي يتحول لكود الدولة الافتراضي 20) قبل Graph، والمطابقة تستخدم whatsAppPhoneMatchFilter لتوسيع الصيغ.
المتطلبات الصارمة: Facebook JS SDK من connect.facebook.net، وHTTPS إجباري (Facebook Login يرفض http)، وطريقة دفع صالحة على WABA في Meta Business Manager وإلا يقبل Graph بـ 200 accepted دون تسليم فعلي، مع إكمال العملة والمنطقة الزمنية والعنوان والتحقق التجاري، وتطبيق Meta يجب أن يكون Live/Published لوصول الويبهوك الحقيقي، ونافذة 24 ساعة للرسائل النصية الحرة تتطلب inbound حديث بـ lastInboundAt من webhook فقط (رسائل التاجر الصادرة لا تفتح النافذة).
الخدمات والملفات: lib/whatsapp/service.js و order-confirmation.js و template-parameters.js و phone.js و send-debug.js و diagnostic-log.js و access-token.js (تشفير AES) و account-details.js و button-actions.js و delivery-status.js و inbound-message.js و webhook-*.js، وواجهات pages/api/whatsapp (accounts و account-details و callback و disconnect و send و connect القديم و templates و order-confirmation-settings و subscribe-webhooks و webhook)، وواجهة الأدمن POST /api/admin/whatsapp/deploy-order-confirmation-template من /admin/whatsapp-templates. سجل النشاط ActivityEvent يسجل connect و disconnect و webhook_resync و message_sent وإعدادات التأكيد دون تخزين توكنات أو هواتف كاملة أو نصوص رسائل. التشخيص الموحد [whatsapp/flow] مع traceId يتبع كل إرسال عبر docker compose logs web.
خطوات الإعداد في ڤاريونس
افتح صفحة واتساب واقبل الشروط
من اللوحة ادخل إلى /dashboard/whatsapp. فعّل مربع الشروط وسياسة الخصوصية (/dashboard/terms و /dashboard/privacy-policy). بدون القبول يبقى زر الربط معطلاً، ومعه بوابتا متغيرات العميل و HTTPS.
نفّذ الربط عبر Facebook
اضغط ربط واتساب ليحوّلك المتصفح إلى dialog/oauth مع redirect_uri يساوي نفس الصفحة. أكمل تسجيل Meta حتى الرجوع مع ?code=&state=، فيرسل المتصفح {code, redirect_uri} إلى POST /api/whatsapp/callback ويُنظف رابط الصفحة. تأكد من HTTPS ومن NEXT_PUBLIC_FACEBOOK_APP_ID و NEXT_PUBLIC_WHATSAPP_CONFIG_ID.
أكمل متطلبات Meta للدفع والتحقق
في Meta Business Manager أضف طريقة دفع صالحة على WABA، وأكمل العملة والمنطقة الزمنية وعنوان النشاط والتحقق التجاري. بدون الدفع يقبل Graph الرسائل accepted دون تسليم، وتظهر تنبيهات Missing valid payment method.
فعّل تأكيد الطلب التلقائي واللغة
عند وجود حساب متصل يظهر زر الإعدادات. افتحه عبر useWhatsAppFetchSettings ثم فعّل orderConfirmationEnabled واختر ar أو en. الحفظ يتم عبر GET/POST /api/whatsapp/order-confirmation-settings بصلاحية whatsapp:edit.
زامن الويبهوك وراقب التفاصيل
استخدم Resync webhooks لتنفيذ POST /{waba-id}/subscribed_apps مع override_callback_uri من WHATSAPP_WEBHOOK_CALLBACK_URL أو أصل النفق. وافتح Details لكل بطاقة حساب لفحص الهاتف و WABA وحالة القوالب عبر GET /api/whatsapp/account-details مع phoneNumberId.
أرسل من CRM والطلبات وتابع الردود
من صف العميل في CRM افتح حوار واتساب: اختر قالباً واملأ متغيرات {{n}} أو أرسل نصاً حراً داخل نافذة 24 ساعة. ومن /dashboard/orders استخدم عمود واتساب وشارة التأكيد وزر إرسال رسالة. ردود تأكيد/إلغاء/تعديل تُسجل على نفس الطلب مع حماية أو تحرير المخزون.
أسئلة شائعة
أين زر ربط واتساب وما شروط تفعيله؟
في /dashboard/whatsapp داخل WhatsAppDashboardHeader أو حالة الفراغ. يتطلب قبول الشروط ووجود NEXT_PUBLIC_FACEBOOK_APP_ID و NEXT_PUBLIC_WHATSAPP_CONFIG_ID وفتح الصفحة عبر HTTPS.
ماذا تفعل أزرار فصل ومزامنة وتفاصيل وإعدادات؟
فصل يوقف isConnected لرقم واحد فقط عبر phoneNumberId دون إلغاء توكن Meta عن بُعد. مزامنة تعيد subscribed_apps مع override_callback_uri. تفاصيل تفحص الهاتف و WABA والقوالب. إعدادات تحفظ تفعيل التأكيد التلقائي واللغة.
لماذا تصل accepted من Meta دون وصول الرسالة للعميل؟
السبب الشائع غياب طريقة دفع صالحة على WABA. يقبل Graph ثم يمنع التسليم. الحل في Meta: طريقة دفع وعملة ومنطقة زمنية وعنوان وتحقق تجاري، وليس في كود ڤاريونس.
متى يعمل النص الحر ومتى يجب استخدام قالب؟
النص الحر يتطلب محادثة WhatsAppChat بـ lastInboundAt حديث من ويبهوك حقيقي داخل 24 ساعة. رسائل التاجر لا تفتح النافذة. خارج النافذة أو لبدء المحادثة استخدم قالباً معتمداً.
أين تُخزن بيانات واتساب وهل هي معزولة لكل متجر؟
في WhatsAppAccount و WhatsAppChat و WhatsAppMessage و WhatsAppTemplate و WhatsAppOrderConfirmation مع merchantId/tenantId، ومفتاح upsert هو merchantId+phoneNumberId. كل واجهات اللوحة تمر عبر protectDashboardEndpoint وعزل المستأجر وصلاحيات whatsapp.
ماذا يحدث عند ضغط العميل تأكيد أو إلغاء أو تعديل؟
يُطابق context.id على صف outboundMessageId نفسه. تأكيد يحفظ confirmed ويحمي حجوزات المخزون دون تغيير حالة الطلب. تعديل يسجل edit_requested فقط. إلغاء يحرر المخزون أولاً ثم يلغي طلباً غير منتهٍ فقط، ثم يُرسل إقرار نصي.
استكشاف الأخطاء
1) زر الربط معطل: اقبل الشروط، وتأكد من HTTPS ومن NEXT_PUBLIC_FACEBOOK_APP_ID و NEXT_PUBLIC_WHATSAPP_CONFIG_ID. 2) خطأ OAuth 36008: يحدث عادة مع FB.login؛ يستخدم ڤاريونس dialog/oauth اليدوي مع redirect_uri مطابق تماماً ومسجل في Valid OAuth Redirect URIs. 3) رسائل accepted دون تسليم: أضف طريقة دفع على WABA وأكمل العملة والمنطقة الزمنية والعنوان والتحقق في Meta. 4) لا توجد رسائل واردة: تأكد أن تطبيق Meta منشور Live، وأن Callback URL وحقل messages مضبوطان، ثم استخدم Resync webhooks مع override_callback_uri. 5) فشل النص الحر: يتطلب lastInboundAt من ويبهوك داخل 24 ساعة؛ رسائل التاجر لا تفتح النافذة. 6) رقم المستلم مرفوض 131030: تُطبَّع الأرقام تلقائياً إلى E.164 digits (الصفر المحلي يصبح 20)؛ أرسل بصيغة مدعومة وتحقق من debug.toSendNumber. 7) قالب مرفوض 132000 أو 132018: تحقق من عدد {{n}} (خمسة لقوالب تأكيد الطلب) ومن إزالة الأسطر الجديدة والمسافات المتتالية. 8) زر العميل لا يحدّث الطلب: راجع أسباب NO_CONTEXT و UNKNOWN_ACTION و NO_MAPPING و DUPLICATE في سجلات [whatsapp/flow] مع traceId.
حدود مهمة
• فصل اللوحة soft فقط (isConnected=false) ولا يلغي توكن Meta عن بُعد. • التطبيقات غير المنشورة تستقبل غالباً ويبهوك الاختبار فقط من اللوحة. • تسليم الرسائل البادئة من التاجر يعتمد على فوترة Meta وسياسات القوالب. • النص الحر مقيد بنافذة 24 ساعة من inbound ويبهوك حقيقي. • سجلات التشخيص [whatsapp/flow] في stdout/stderr عبر Docker json-file وليست ملفاً داخل التطبيق.