دليل واتساب API

الدليل العملي لربط Odoo بـ WhatsApp عبر Whats360: Webhooks وAPI ومعالجة الرسائل والميديا

ربط Odoo بـ WhatsApp عبر Whats360 باستخدام Webhooks وAPI ومعالجة الرسائل والمرفقات

الدليل الهندسي الشامل لربط Odoo بمنظومة Whats360: كود Python، استقبال الميديا وحل أخطاء Webhook

ربط Odoo بواتساب لا ينبغي أن يُبنى باعتباره مجرد زر لإرسال رسالة. التكامل الحقيقي هو طبقة اتصال بين نظام ERP وبين محادثات العملاء، بحيث يستطيع Odoo استقبال الأحداث من WhatsApp، ربطها بالعميل المناسب، حفظ الرسائل والمرفقات، وفي الاتجاه العكسي إرسال الإشعارات والفواتير والمستندات.

المشكلة أن الصورة تبدو بسيطة على الورق: Webhook يدخل إلى Odoo، ثم يتم حفظ الرسالة. لكن عند الانتقال إلى التنفيذ تظهر التفاصيل المهمة: طلب يرجع 403 Forbidden، أو 401 Unauthorized، أو تصل الرسالة النصية بينما لا تصل الصورة، أو تظهر الرسائل التي يرسلها الموظف من هاتفه خارج سجل المحادثة.

لذلك يركز هذا الدليل على الجانب الهندسي للتكامل: تصميم Webhook داخل Odoo، فهم الـ Payload، مطابقة العملاء، تسجيل الرسائل، التعامل مع الوسائط، إرسال الرسائل من Odoo، ثم تشخيص المشكلات التي قد تظهر أثناء التشغيل.

الخلاصة التقنية السريعة

يتم ربط Odoo بمنظومة Whats360 عبر Webhook لاستقبال أحداث WhatsApp داخل Controller في Odoo، ثم معالجة الـ Payload وربطه بجهات الاتصال أو CRM. وفي الاتجاه العكسي يستخدم Odoo واجهة API لإرسال الرسائل والمرفقات عبر Whats360. أما الصور والملفات فلا ينبغي افتراض أن وصول Event الخاص بها يعني أن الملف أصبح جاهزًا مباشرة؛ فقد تحتاج الوسائط إلى مرحلة منفصلة للاسترجاع باستخدام آلية المصادقة المناسبة.

المعمارية الصحيحة لتدفق البيانات بين Odoo وWhatsApp

قبل كتابة أول سطر Python، يجب تحديد اتجاه البيانات بوضوح. هذه الخطوة تمنع كثيرًا من الأخطاء التي تحدث عندما يتم التعامل مع التكامل باعتباره API للإرسال فقط.

الرسائل الواردة من العملاء

عندما يرسل العميل رسالة عبر WhatsApp، يكون المسار المنطقي للبيانات كالتالي:

Customer
   ↓
WhatsApp
   ↓
Whats360
   ↓
Webhook
   ↓
Odoo Controller
   ↓
Customer / CRM / Chatter

يستقبل Odoo الحدث القادم من Whats360، ثم يبدأ في تحليل البيانات. وقد يحتوي الحدث على معرف الرسالة، رقم الهاتف، اسم المرسل، معرف المحادثة، نص الرسالة، بيانات الوسائط، وقت الرسالة، ومعرف الـ Instance.

المهم هنا أن الـ Webhook يمثل قناة لإبلاغ Odoo بحدوث الحدث. لذلك يجب ألا تُبنى طبقة البيانات داخل Odoo على افتراض أن كل المعلومات المطلوبة لتشغيل كل وظيفة ستكون موجودة دائمًا داخل Event واحد.

الرسائل الصادرة من حساب WhatsApp

إذا كان الهدف هو بناء سجل محادثة متكامل داخل Odoo، فإن استقبال رسائل العملاء فقط لا يكفي. يجب أيضًا التعامل مع الرسائل التي يرسلها حساب WhatsApp نفسه، سواء تم إرسالها من Odoo أو من تطبيق الهاتف، عندما يكون الحدث المقابل متاحًا في التكامل.

إذا كان Payload يحتوي على حقل مثل:

{
  "is_from_me": true
}

فيمكن استخدامه للمساعدة في تحديد اتجاه الرسالة. لكن لا ينبغي افتراض وجود هذا الحقل في كل Event أو اعتباره قاعدة ثابتة دون فحص الـ Payload الفعلي.

الهدف النهائي هو أن يصبح سجل المحادثة في Odoo قادرًا على تمثيل الاتجاهين:

Customer Message
       ↓
      Odoo
       ↑
Employee Message
       ↑
WhatsApp Phone

وهذا مهم خصوصًا عندما يستخدم فريق المبيعات WhatsApp من هواتفه، لأن النظام يجب ألا يسجل نصف المحادثة ويترك النصف الآخر خارج الـ CRM.

فهم @lid وPhone وChat JID داخل التكامل

من الأخطاء الشائعة في تكاملات WhatsApp التعامل مع كل معرف يظهر في الـ Payload باعتباره رقم هاتف العميل. هذا الأسلوب قد يسبب مشاكل في ربط المحادثات بجهات الاتصال، خصوصًا عندما تظهر معرفات مرتبطة بالمحادثة أو بالهوية مثل @lid.

الأفضل تصميم طبقة Mapping داخل Odoo تفصل بين هوية العميل ورقم الهاتف ومعرف المحادثة.

WhatsApp Identifier
       ↓
Identifier Mapping
       ↓
res.partner

ويمكن أن يحتوي سجل الربط على معلومات مثل:

partner_id
phone
chat_jid
whatsapp_identifier
instance_id

الفكرة الأساسية هي عدم استخدام معرف واحد باعتباره الحقيقة الوحيدة للعميل. عندما يحتفظ النظام بالمعرفات المختلفة، يصبح من الأسهل التعامل مع تغير شكل Identifier أو وجود أكثر من Instance أو أكثر من محادثة.

تنبيه هندسي

ظهور @lid لا يعني تلقائيًا أن رقم الهاتف غير متاح أو أن الرسالة لا يمكن ربطها بالعميل. يجب قراءة الحقول الفعلية في الـ Payload وبناء Mapping مناسب بدل استخدام معرف المحادثة كبديل مباشر لرقم الهاتف.

إعداد Webhook داخل Whats360

بعد فهم المعمارية، تأتي مرحلة إعداد نقطة الاستقبال داخل Odoo. لنفترض أن Controller سيكون متاحًا على المسار التالي:

https://your-odoo-domain.com/whatsapp/webhook

هذا عنوان توضيحي، ويجب استبداله بعنوان خادم Odoo الفعلي.

يجب أن يكون Endpoint قادرًا على استقبال الطلبات القادمة من Whats360، وأن يكون متاحًا عبر HTTPS، وأن يستخدم HTTP Method المناسب، وأن تكون آلية الحماية متوافقة مع طبيعة Webhook.

قبل كتابة Controller كامل، من الأفضل اختبار شكل البيانات التي تصل فعلًا إلى Odoo. هذه الخطوة تختصر وقتًا كبيرًا في التطوير، لأن الكثير من المشاكل تبدأ من كتابة الكود على Payload متخيل بدل Payload حقيقي.

الحقول الأساسية في Payload

يمكن أن يكون لدينا Payload توضيحي مثل:

{
  "event": "incoming_message",
  "instance_id": "{{instance_id}}",
  "message_id": "{{message_id}}",
  "phone": "{{phone}}",
  "sender_name": "{{sender_name}}",
  "chat_jid": "{{chat_jid}}",
  "message": "{{message}}",
  "media_url": "{{media_url}}",
  "timestamp": "{{timestamp}}"
}

ويجب التعامل مع هذه البيانات بحسب وظيفتها، وليس فقط حفظها كنص JSON.

الحقل الوظيفة الاستخدام داخل Odoo
event تحديد نوع الحدث Event Router
instance_id تحديد الحساب أو الجهاز Multi-instance Mapping
message_id معرف فريد للرسالة Deduplication
phone رقم العميل res.partner
sender_name اسم المرسل إنشاء أو تحديث جهة الاتصال
chat_jid معرف المحادثة Conversation Mapping
message محتوى الرسالة Chatter / CRM
media_url مرجع محتمل للوسائط Media Processing
timestamp وقت الحدث Message Log

يجب مراجعة Payload الفعلي قبل تثبيت أسماء الحقول في الكود، لأن أنواع الأحداث المختلفة قد تحتوي على بيانات مختلفة.

بناء Odoo Controller لاستقبال Webhook

الـ Controller هو نقطة الدخول الأساسية إلى Odoo. وفي أبسط صورة عملية يمكن أن يكون التصميم كالتالي:

from odoo import http
from odoo.http import request
import logging

_logger = logging.getLogger(__name__)


class WhatsAppWebhookController(http.Controller):

    @http.route(
        "/whatsapp/webhook",
        type="json",
        auth="public",
        methods=["POST"],
        csrf=False
    )
    def whatsapp_webhook(self, **kwargs):

        try:
            payload = request.jsonrequest or {}

            _logger.info(
                "WhatsApp Webhook received: %s",
                payload
            )

            event = payload.get("event")

            if event == "incoming_message":
                self._handle_incoming(payload)

            elif event == "message_outgoing":
                self._handle_outgoing(payload)

            else:
                _logger.info(
                    "Unhandled WhatsApp event: %s",
                    event
                )

            return {
                "success": True
            }

        except Exception:
            _logger.exception(
                "WhatsApp Webhook processing failed"
            )

            return {
                "success": False
            }

    def _handle_incoming(self, payload):

        phone = payload.get("phone")
        sender_name = payload.get("sender_name")
        message = payload.get("message")

        partner = self._find_or_create_partner(
            phone,
            sender_name
        )

        _logger.info(
            "Incoming message for partner %s: %s",
            partner.id,
            message
        )

    def _handle_outgoing(self, payload):

        message = payload.get("message")
        phone = payload.get("phone")

        _logger.info(
            "Outgoing message to %s: %s",
            phone,
            message
        )

    def _find_or_create_partner(self, phone, name=None):

        Partner = request.env["res.partner"].sudo()

        if not phone:
            return Partner.browse()

        partner = Partner.search(
            [("phone", "=", phone)],
            limit=1
        )

        if partner:
            return partner

        return Partner.create({
            "name": name or phone,
            "phone": phone,
        })

هذا المثال يوضح الهيكل الأساسي، لكنه لا يمثل تكامل Production كاملًا بمفرده. في بيئة حقيقية يجب إضافة التحقق من مصدر الطلب، ومنع التكرار، وربط الـ Instance، ومعالجة الوسائط، وإدارة الأخطاء وإعادة المحاولة.

لماذا نستخدم sudo داخل Webhook؟

الطلب القادم من خارج Odoo لا يكون مرتبطًا بالضرورة بجلسة مستخدم Odoo عادية. ولذلك قد تظهر مشاكل صلاحيات عند محاولة إنشاء أو تعديل سجلات مثل res.partner.

في هذه الحالة يمكن استخدام:

request.env["res.partner"].sudo()

لكن يجب التفريق بين مشكلتين مختلفتين تمامًا:

  • Permission Problem: المستخدم أو السياق الحالي لا يمتلك الصلاحية.
  • Authentication Problem: الطلب الخارجي نفسه غير موثق أو غير مصرح له.

استخدام sudo() يمكن أن يعالج الأولى، لكنه لا ينبغي أن يُستخدم باعتباره حلًا للمشكلة الثانية.

قاعدة أمنية مهمة

إذا كان Webhook يستخدم auth="public" لأن الطلب يأتي من خدمة خارجية، فلا يعني ذلك أن Endpoint يجب أن يكون مفتوحًا بلا حماية. يجب تطبيق آلية تحقق مناسبة للطلبات بحسب الإمكانيات التي توفرها المنظومة.

مطابقة رقم الهاتف مع res.partner

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

مثلًا:

2010XXXXXXXX
+2010XXXXXXXX
002010XXXXXXXX

إذا تعامل Odoo مع كل صيغة باعتبارها رقمًا مختلفًا، يمكن أن ينتهي الأمر بإنشاء أكثر من Contact لنفس العميل.

لذلك من المفيد إنشاء طبقة Normalize:

def normalize_phone(phone):

    if not phone:
        return False

    phone = str(phone).strip()

    phone = phone.replace(" ", "")
    phone = phone.replace("-", "")
    phone = phone.replace("(", "")
    phone = phone.replace(")", "")

    if phone.startswith("+"):
        phone = phone[1:]

    if phone.startswith("00"):
        phone = phone[2:]

    return phone

ثم:

phone = normalize_phone(payload.get("phone"))

لكن قواعد تطبيع الأرقام يجب أن تتناسب مع الأسواق التي يعمل فيها النظام. لا توجد قاعدة واحدة تصلح لكل دولة وكل صيغة إدخال.

تسجيل الرسائل داخل Odoo

بعد تحديد العميل، يمكن تسجيل الرسالة داخل Chatter:

partner.message_post(
    body=message or "",
    message_type="comment",
    subtype_xmlid="mail.mt_note"
)

هذا مناسب عندما يكون الهدف إظهار الرسالة داخل سجل العميل، لكنه قد لا يكون كافيًا عندما يصبح Odoo نظام محادثات كاملًا.

في الأنظمة الأكبر يمكن إنشاء Model مخصص مثل:

whatsapp.message

ويحتوي على بيانات مثل:

message_id
instance_id
partner_id
phone
chat_jid
direction
message
event
timestamp
media_id
status

هذا التصميم يعطيك طبقة مستقلة للمحادثات، ويمكن بعد ذلك ربطها بـ CRM أو Contacts أو Chatter بحسب احتياجات المشروع.

لغز الميديا: لماذا تصل الصورة بينما يكون media_url فارغًا؟

هذه من أهم المشكلات في تكامل WhatsApp مع الأنظمة الخارجية.

عند وصول رسالة تحتوي على صورة أو ملف، قد يظهر Payload مثل:

{
  "message": "",
  "media_url": ""
}

ومن السهل أن يستنتج المطور أن WhatsApp لم يرسل الصورة.

لكن هذا الاستنتاج ليس بالضرورة صحيحًا.

يجب الفصل بين مفهومين:

  • Message Event: حدث يخبر النظام بأن رسالة وصلت.
  • Media Retrieval: عملية الحصول على محتوى الملف نفسه.

وبالتالي يمكن أن يكون المسار:

WhatsApp Media
      ↓
Whats360
      ↓
Webhook Event
      ↓
Media Reference / Metadata
      ↓
Authenticated Media Request
      ↓
File
      ↓
Odoo
      ↓
ir.attachment

وهنا يجب استخدام Endpoint وطريقة Authentication التي يوفرها Whats360 فعليًا لجلب الوسائط. لا ينبغي اختراع URL أو Header من عند المطور ثم اعتبار فشل الطلب دليلًا على وجود مشكلة في Odoo.

حفظ الصور والملفات داخل ir.attachment

بعد الحصول على المحتوى الحقيقي للملف، يمكن حفظه داخل Odoo باستخدام ir.attachment.

import base64

attachment = request.env["ir.attachment"].sudo().create({
    "name": "whatsapp-image.jpg",
    "type": "binary",
    "datas": base64.b64encode(file_content),
    "res_model": "res.partner",
    "res_id": partner.id,
    "mimetype": "image/jpeg",
})

المتغير file_content هنا يجب أن يحتوي على محتوى الملف الفعلي الذي تم الحصول عليه من مسار Media Retrieval.

لا ينبغي وضع رابط URL داخل datas باعتباره محتوى الملف. الرابط والمحتوى الثنائي شيئان مختلفان.

منع تكرار الرسائل باستخدام Message ID

Webhooks لا ينبغي افتراض أنها ستصل دائمًا مرة واحدة فقط. عند وجود Retry أو إعادة إرسال للطلب، يمكن أن يستقبل Odoo نفس الحدث أكثر من مرة.

إذا كان لدينا:

message_id = ABC123

يجب أن يعرف النظام أن الحدث سبق تسجيله.

existing = request.env[
    "whatsapp.message"
].sudo().search(
    [("message_id", "=", message_id)],
    limit=1
)

if existing:
    return

هذه النقطة مهمة جدًا عند الانتقال من Prototype إلى Production، لأن التكرار في رسائل العملاء أو إشعارات الفواتير يمكن أن يؤدي إلى سجلات خاطئة أو عمليات إرسال مكررة.

حل خطأ 403 Forbidden في Odoo Webhook

عندما يظهر:

403 Forbidden

لا تبدأ مباشرة بتغيير Token الخاص بـ Whats360.

ابدأ من جهة Odoo وافحص:

  • هل الـ Route موجود؟
  • هل HTTP Method صحيح؟
  • هل CSRF يمنع الطلب؟
  • هل Authentication مناسبة للـ Webhook؟
  • هل Reverse Proxy يغير الطلب؟
  • هل Firewall يمنع الاتصال؟

في بعض Webhook Controllers قد يكون التصميم:

@http.route(
    "/whatsapp/webhook",
    type="json",
    auth="public",
    methods=["POST"],
    csrf=False
)

لكن هذه الإعدادات يجب التعامل معها وفق طبيعة الـ Endpoint، ولا تعني أن Webhook أصبح آمنًا تلقائيًا.

إذا كان Route عامًا، يجب أن توجد طبقة تحقق مناسبة مثل Secret أو Signature أو Token عندما تكون هذه الآلية متاحة.

تشخيص 401 Unauthorized بطريقة صحيحة

رمز 401 وحده لا يخبرك بكل شيء.

يجب قراءة Response Body لمعرفة السبب الحقيقي.

401
│
├── Authentication Problem
│     ├── Token
│     ├── Header
│     └── Credentials
│
└── Session Problem
      ├── Device
      ├── Socket
      └── Session State

إذا كان الـ API المستخدم يتطلب مثلًا:

Authorization: Bearer YOUR_TOKEN

فيجب أن يكون طلب Python مطابقًا لذلك:

headers = {
    "Authorization": f"Bearer {token}",
    "Content-Type": "application/json"
}

ولا يجب استبداله بـ Header آخر مثل:

X-API-Token

إلا إذا كان هذا الـ Header موثقًا صراحة في الـ API المستخدمة.

قاعدة التشخيص

لا تعالج كل حالات 401 بالطريقة نفسها. اقرأ رسالة الخطأ أولًا، ثم حدد هل المشكلة في بيانات المصادقة أم في Session أو Device State.

session_invalid_or_expired: عندما تكون المشكلة في الجلسة

إذا كانت استجابة API تشير إلى مشكلة مثل session_invalid_or_expired، فإعادة كتابة Controller داخل Odoo لن تحل المشكلة بالضرورة.

في هذه الحالة يجب فحص حالة الـ Instance والجهاز واتصال الـ Session أو الـ Socket بحسب النظام المستخدم.

التشخيص يصبح:

Odoo
 ↓
API Request
 ↓
401
 ↓
Read Error Body
 ↓
Authentication?
    ↓ نعم
Check Token/Header

Session?
    ↓ نعم
Check Device/Socket/Session

وهذا يوضح لماذا لا يكفي الاعتماد على Status Code وحده في تشخيص مشاكل التكامل.

قاعدة إعادة ربط الجهاز واختبار الميديا

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

إذا حدث:

Unpair
   ↓
New QR
   ↓
Re-pair

ثم فشلت محاولة استرجاع Media قديمة، فلا ينبغي استخدام هذه الرسالة القديمة وحدها للحكم على أن التكامل الجديد لا يعمل.

الاختبار الأفضل هو:

Re-pair
   ↓
Send NEW Image
   ↓
Receive Webhook
   ↓
Retrieve NEW Media
   ↓
Store in Odoo

إذا نجح الاختبار على رسالة Media جديدة، فهذا يعطي مؤشرًا أقوى على أن مسار التشغيل الحالي يعمل.

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

إرسال الرسائل من Odoo إلى WhatsApp

حتى الآن كان التركيز على Incoming. لكن التكامل الحقيقي يجب أن يكون ثنائي الاتجاه.

المسار المنطقي للإرسال هو:

Sale Order / Invoice / CRM
          ↓
Odoo Automation
          ↓
Whats360 API
          ↓
WhatsApp

يمكن بناء Client بسيط باستخدام Python:

import requests


def send_whatsapp_message(
    endpoint,
    token,
    phone,
    message
):

    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }

    payload = {
        "phone": phone,
        "message": message,
    }

    response = requests.post(
        endpoint,
        headers=headers,
        json=payload,
        timeout=30,
    )

    response.raise_for_status()

    return response.json()

الكود السابق يوضح طريقة بناء الطلب، بينما يجب وضع الـ Endpoint وأسماء الحقول الفعلية وفق API المستخدمة.

إرسال الفواتير والمستندات من Odoo

من أكثر سيناريوهات التكامل العملية أن يتم إرسال فاتورة أو أمر بيع تلقائيًا إلى العميل عبر WhatsApp.

يمكن أن يكون الـ Workflow:

Invoice Confirmed
       ↓
Generate PDF
       ↓
Read Customer Phone
       ↓
Whats360 API
       ↓
Send Document
       ↓
Save Message ID
       ↓
Update Odoo Log

لكن النظام الجيد لا يكتفي بإرسال الملف.

يجب تسجيل نتيجة العملية، مثل:

invoice_id
partner_id
phone
message_id
status
timestamp
error

وبذلك يستطيع فريق المبيعات معرفة ما إذا كانت الفاتورة أُرسلت بالفعل أم أن العملية فشلت.

استخدام HookURL لاختبار التكامل قبل Odoo

عند تطوير Integration، من الأفضل أحيانًا اختبار Webhook أولًا بعيدًا عن تعقيد Odoo.

يمكن استخدام خدمة HookURL المتاحة ضمن المنظومة لفحص الـ Payload وفهم البيانات قبل بناء Controller النهائي.

Whats360
   ↓
HookURL
   ↓
Inspect JSON
   ↓
Understand Event
   ↓
Build Controller
   ↓
Odoo

هذه الطريقة تساعد المطور على رؤية:

  • اسم Event.
  • Message ID.
  • Phone.
  • Sender.
  • Message.
  • Media Information.
  • Timestamp.
  • Direction.
  • أي حقول إضافية يقدمها الحدث.

بعد فهم البيانات الحقيقية، يمكن نقل نفس المنطق إلى Odoo بدل بناء Controller على افتراضات.

لماذا يبدأ الاختبار بالـ Payload؟

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

استكشف Whats360 وابدأ اختبار التكامل

اختبار التكامل قبل إطلاقه في Production

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

اختبار الرسائل النصية الواردة

Customer
→ WhatsApp
→ Whats360
→ Odoo

تحقق من تسجيل العميل والرسالة ومعرف الرسالة.

اختبار الرسائل الصادرة من الهاتف

Employee Phone
→ WhatsApp
→ Whats360
→ Odoo

تحقق من أن الرسالة تظهر في سجل المحادثة عندما يكون Event الخاص بالرسائل الصادرة متاحًا.

اختبار الصور والملفات

Customer
→ Image
→ Whats360
→ Webhook
→ Media Retrieval
→ Odoo Attachment

لا تكتفِ بفحص Payload؛ تحقق من وصول الملف نفسه إلى ir.attachment.

اختبار التكرار

أرسل نفس Event أكثر من مرة وتأكد من أن Odoo لا ينشئ سجلات مكررة.

اختبار الإرسال من Odoo

أرسل رسالة من Odoo إلى رقم اختبار وتحقق من Response وتسجيل نتيجة العملية.

اختبار حالات الفشل

اختبر Token غير صحيح، Endpoint غير صحيح، وInstance غير متصل، وتأكد من أن Odoo يسجل الخطأ بوضوح بدل إسقاط العملية بصمت.

قائمة فحص التكامل قبل Production

  • HTTPS يعمل بشكل صحيح.
  • Webhook Endpoint صحيح.
  • Authentication مفعلة بالطريقة المناسبة.
  • CSRF مضبوط وفق طبيعة Endpoint.
  • Logging موجود.
  • Message ID مستخدم لمنع التكرار.
  • Phone Normalization مطبق.
  • Partner Mapping يعمل.
  • Incoming Message مختبر.
  • Outgoing Message مختبر.
  • Media Retrieval مختبر.
  • ir.attachment يعمل.
  • أخطاء 401 مفهومة.
  • أخطاء 403 مفهومة.
  • حالة Device وSession قابلة للمراقبة.
  • Retry Strategy موجودة.
  • أخطاء API مسجلة.
  • دعم أكثر من Instance متوفر إذا كان المشروع يحتاج إليه.

أخطاء تصميم شائعة يجب تجنبها

اعتبار Webhook هو كل شيء

الـ Webhook يخبر Odoo بحدث، لكنه لا يعني أن كل عملية مرتبطة بالحدث يجب أن تتم من نفس Payload. الرسائل والوسائط وحالات الإرسال يمكن أن تحتاج إلى معالجة منفصلة.

استخدام رقم الهاتف كمفتاح وحيد

الرقم مهم، لكنه ليس دائمًا المعرف الوحيد الذي يجب الاحتفاظ به. الأفضل حفظ Mapping بين العميل ومعرفات المحادثة والـ Instance عند الحاجة.

تجاهل Message ID

بدون Deduplication قد تتكرر الرسائل عند إعادة إرسال Webhook.

استخدام sudo كحل أمني

sudo() يعالج الصلاحيات داخل Odoo، لكنه لا يحمي Webhook من الطلبات غير المصرح بها.

تشخيص 401 من الرقم فقط

لا يكفي رؤية 401. يجب قراءة رسالة الخطأ ومعرفة هل المشكلة في Authentication أم Session.

اختبار Media برسالة قديمة بعد إعادة الربط

اختبار Media يجب أن يعتمد على رسالة جديدة بعد إعادة ربط الجهاز عندما تكون هناك مشكلة في استرجاع الوسائط القديمة.

كيف تجعل التكامل قابلًا للتوسع؟

عندما يكون المشروع صغيرًا، قد يكفي Controller بسيط مع بعض الدوال. لكن عندما يزيد عدد الرسائل أو الـ Instances أو العمليات الآلية، يصبح فصل المسؤوليات أكثر أهمية.

من الأفضل التفكير في الطبقات التالية:

Webhook Layer
      ↓
Validation Layer
      ↓
Event Router
      ↓
Message Service
      ↓
Partner Mapping
      ↓
Media Service
      ↓
CRM / Chatter / Attachments
      ↓
Logging & Monitoring

وبهذه الطريقة لا يصبح كل شيء داخل Function واحدة ضخمة يصعب اختبارها وصيانتها.

مثلًا يمكن أن تكون وظيفة الـ Controller الأساسية هي استقبال الطلب وتوجيهه فقط:

payload
   ↓
validate()
   ↓
route_event()
   ↓
process()
   ↓
response

وهذا التصميم يسهل إضافة Event جديد لاحقًا دون إعادة كتابة كل النظام.

مقالات ذات صلة

الأسئلة الشائعة حول ربط Odoo بـ Whats360

هل يمكن ربط Odoo بواتساب باستخدام Webhook؟

نعم، يمكن بناء تكامل يعتمد على Webhook لاستقبال الأحداث داخل Controller في Odoo، ثم معالجة الرسائل وربطها بالعملاء أو CRM. وفي الاتجاه المعاكس يمكن استخدام API لإرسال الرسائل من Odoo.

هل يمكن تسجيل الرسائل التي يرسلها الموظف من هاتفه؟

يمكن ذلك عندما توفر المنظومة Event للرسائل الصادرة من الحساب. وإذا كان Payload يحتوي على مؤشر مثل is_from_me، فيمكن استخدامه للمساعدة في تحديد اتجاه الرسالة، مع الاعتماد دائمًا على Payload الفعلي.

هل ظهور @lid يعني أن العميل لا يمكن ربطه داخل Odoo؟

لا. يجب الفصل بين معرف المحادثة ورقم الهاتف، والاحتفاظ بالمعرفات المختلفة داخل طبقة Mapping مناسبة بدل اعتبار LID رقم الهاتف نفسه.

لماذا تصل الرسالة ولا تصل الصورة؟

قد يكون السبب أن Webhook يحمل Event الخاص بالرسالة بينما يحتاج الملف إلى عملية Media Retrieval منفصلة. يجب فحص Payload ثم استخدام مسار استرجاع الوسائط والمصادقة الصحيحين.

كيف أحفظ الصور في Odoo؟

بعد الحصول على محتوى الملف الحقيقي يمكن تخزينه داخل ir.attachment باستخدام Base64، مع ربط المرفق بالـ Partner أو السجل المناسب.

هل 403 يعني أن Token خاطئ؟

ليس بالضرورة. يجب فحص Route وHTTP Method وCSRF وAuthentication وReverse Proxy وFirewall في جهة Odoo قبل تحديد السبب.

هل 401 يعني دائمًا أن الـ API Token خاطئ؟

لا. قد تكون المشكلة في Authentication أو في Session أو Device State. قراءة Response Body هي الخطوة الأساسية لتحديد السبب.

ما معنى session_invalid_or_expired؟

عندما تشير الاستجابة إلى Session غير صالحة أو منتهية، يجب فحص حالة الـ Instance والجهاز والاتصال بالجلسة بدل التركيز فقط على كود Odoo.

هل auth=”public” وcsrf=False يحلان مشكلة Webhook؟

قد تكون هذه الإعدادات مناسبة لطبيعة Webhook في بعض تصميمات Odoo، لكنها ليست حلًا أمنيًا كاملًا. يجب إضافة آلية تحقق مناسبة للطلبات الخارجية.

هل يمكن إرسال فواتير PDF من Odoo إلى WhatsApp؟

من الناحية المعمارية نعم، حيث يمكن لـ Odoo توليد ملف الفاتورة ثم إرساله عبر API المناسبة للمرفقات في Whats360، مع تسجيل نتيجة العملية داخل Odoo.

كيف أختبر Webhook قبل ربطه بـ Odoo؟

يمكن استخدام HookURL لفحص الـ Payload والأحداث أولًا، ثم بناء Controller داخل Odoo بناءً على البيانات الفعلية بدل الاعتماد على افتراضات.

هل يمكن دعم أكثر من رقم WhatsApp داخل Odoo؟

يمكن تصميم طبقة التكامل بحيث تعتمد على instance_id وتربط كل Instance بالبيانات المناسبة، إذا كان سيناريو المشروع والمنظومة يدعمان تعدد الـ Instances.

الخلاصة: ابنِ التكامل حول دورة البيانات وليس حول الرسالة فقط

التكامل الاحترافي بين Odoo وWhatsApp ليس مجرد:

Webhook → Message

بل هو طبقة متكاملة لإدارة دورة البيانات:

                  ┌──────────────┐
                  │   WhatsApp   │
                  └──────┬───────┘
                         │
                         ▼
                  ┌──────────────┐
                  │   Whats360   │
                  └──────┬───────┘
                         │
                    Webhook/API
                         │
                         ▼
                  ┌──────────────┐
                  │     Odoo     │
                  └──────┬───────┘
                         │
          ┌──────────────┼──────────────┐
          ▼              ▼              ▼
     res.partner       CRM          Attachments
          │              │              │
          └──────────────┼──────────────┘
                         ▼
                     Chatter

والتسلسل العملي الأفضل هو:

Create Instance
      ↓
Configure API
      ↓
Configure Webhook
      ↓
Inspect Payload
      ↓
Build Controller
      ↓
Test Incoming
      ↓
Test Media
      ↓
Test Outgoing
      ↓
Add Deduplication
      ↓
Add Monitoring
      ↓
Production

إذا كنت تبني Integration فعلية بين Odoo وWhatsApp، فابدأ بفهم الـ Payload الحقيقي، ثم اختبره، وبعد ذلك اكتب الـ Controller. هذه الطريقة أفضل من بناء الكود على افتراضات قد لا تطابق البيانات الفعلية.

وعندما تحتاج إلى طبقة API وWebhooks وربط Instances مع نظام Odoo، يمكنك التعرف على إمكانيات Whats360 والبدء من بيئة الاختبار قبل الانتقال إلى Production.

ابدأ التكامل من البيانات الحقيقية

اختبر الـ Webhook، افحص الـ Payload، تحقق من الرسائل الواردة والصادرة، ثم اختبر Media Retrieval قبل إطلاق التكامل في بيئة الإنتاج.

  • اختبار Webhook
  • فحص Payload
  • ربط Odoo CRM
  • معالجة الرسائل والمرفقات
  • اختبار API قبل Production

ابدأ مع Whats360

المسار النهائي للتنفيذ

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

وبهذه المعمارية يصبح Odoo قادرًا على التعامل مع WhatsApp كقناة بيانات متكاملة داخل منظومة الـ ERP، بدل أن يكون مجرد مكان لعرض إشعار أو إرسال رسالة منفردة.

الهدف النهائي هو أن تصبح دورة المحادثة قابلة للتتبع من لحظة وصول رسالة العميل وحتى تسجيلها داخل Odoo، ثم إرسال الرد أو المستند من Odoo إلى WhatsApp، مع وجود طبقة واضحة لتشخيص الأخطاء ومراقبة التشغيل.

للمطورين الذين يريدون تنفيذ هذا النوع من التكامل، يمكن البدء من Whats360 لاختبار API والـ Webhooks وبناء طبقة الاتصال المناسبة مع Odoo.

اترك تعليقاً

زر الذهاب إلى الأعلى