Odoo API Integration: REST, JSON-RPC, and XML-RPC Guide

Complete developer guide to Odoo API integration using REST, JSON-RPC, and XML-RPC. Includes authentication, endpoints, code examples, and best practices.

E
ECOSIRE Research and Development Team
|19 مارس 202610 دقائق قراءة2.2k كلمات|

تكامل واجهة برمجة تطبيقات Odoo: دليل REST وJSON-RPC وXML-RPC

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

يقدم هذا الدليل أمثلة على أكواد العمل، وتدفقات المصادقة، والتوصيات المعمارية لعمليات تكامل REST، وJSON-RPC، وXML-RPC — الواجهات الأساسية الثلاث المتوفرة في Odoo 19 Enterprise.

الوجبات الرئيسية

  • يوفر Odoo 19 واجهات REST (OpenAPI 3.0)، وJSON-RPC 2.0، وXML-RPC
  • تستخدم المصادقة مفاتيح واجهة برمجة التطبيقات (مستحسن) أو تسجيل الدخول المستند إلى الجلسة
  • JSON-RPC هي الواجهة الأكثر اكتمالاً للميزات للعمليات المعقدة
  • تتبع REST API مواصفات OpenAPI 3.0 وتدعم أفعال HTTP القياسية
  • يعتبر XML-RPC قديمًا ولكنه لا يزال مدعومًا بالكامل للتوافق مع الإصدارات السابقة
  • يجب تنفيذ تحديد المعدل ومعالجة الأخطاء من جانب العميل
  • تعمل خطافات الويب في Odoo 19 على دفع البيانات إلى الأنظمة الخارجية عند تسجيل التغييرات
  • تحترم جميع مكالمات واجهة برمجة التطبيقات (API) حقوق الوصول وقواعد التسجيل الخاصة بـ Odoo

مقارنة واجهة API

قبل كتابة سطر واحد من التعليمات البرمجية، اختر واجهة API المناسبة لحالة الاستخدام الخاصة بك:

ميزةريست APIجسون-RPCXML-RPC
البروتوكولHTTP/HTTPSHTTP/HTTPSHTTP/HTTPS
تنسيق الحمولةجيسونجيسونأكس أم أل
مواصفات OpenAPIنعم (اختيال)لالا
عمليات الخامنعمنعمنعم
استدعاءات الطريقةمحدودةكاملكامل
مشغلات سير العملعبر الإجراءاتعبر Execute_kwعبر التنفيذ
موصى به لـعمليات التكامل الجديدةمنطق معقدالأنظمة القديمة
مكتبة بايثونطلباتodoo-xmlrpc / طلباتxmlrpc.client

متى تستخدم REST: إنشاء تطبيق جوال، أو التكامل مع منصات الويب الأصلية (Shopify، Stripe)، أو عندما يشعر فريقك براحة أكبر مع اتفاقيات REST.

متى يتم استخدام JSON-RPC: تنفيذ أساليب معقدة من جانب خادم Odoo، أو قراءة مجموعات كبيرة من البيانات باستخدام مرشحات النطاق، أو عندما تحتاج إلى الوصول إلى الأساليب التي لم يتم الكشف عنها عبر REST.

متى تستخدم XML-RPC: الحفاظ على عمليات التكامل الحالية التي تم إنشاؤها قبل توفر REST، أو عندما يكون النظام الأساسي الخاص بك يحتوي على مكتبات عملاء XML-RPC ناضجة.


المصادقة

مصادقة مفتاح واجهة برمجة التطبيقات (مستحسن)

يدعم Odoo 19 مصادقة مفتاح API لجميع الواجهات الثلاث. قم بإنشاء مفتاح API ضمن الإعدادات → المستخدمون → المستخدم الخاص بك → مفاتيح واجهة برمجة التطبيقات.

import requests

ODOO_URL = "https://your-odoo.com"
API_KEY = "your_api_key_here"
DATABASE = "your_database"

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

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

المصادقة المستندة إلى الجلسة (JSON-RPC / XML-RPC)

بالنسبة إلى JSON-RPC، قم بالمصادقة باستخدام نقطة النهاية /web/dataset/call_kw بعد إنشاء الجلسة:

import requests
import json

session = requests.Session()

# Authenticate
auth_payload = {
    "jsonrpc": "2.0",
    "method": "call",
    "params": {
        "db": "your_database",
        "login": "admin",
        "password": "your_password"
    }
}

response = session.post(
    f"{ODOO_URL}/web/session/authenticate",
    json=auth_payload
)
uid = response.json()['result']['uid']
print(f"Authenticated as UID: {uid}")

بالنسبة إلى XML-RPC، استخدم المصادقة القياسية المكونة من خطوتين:

import xmlrpc.client

url = "https://your-odoo.com"
db = "your_database"
username = "admin"
password = "your_password"

# Step 1: Get UID
common = xmlrpc.client.ServerProxy(f"{url}/xmlrpc/2/common")
uid = common.authenticate(db, username, password, {})

# Step 2: Use UID for subsequent calls
models = xmlrpc.client.ServerProxy(f"{url}/xmlrpc/2/object")

واجهة برمجة تطبيقات REST: OpenAPI 3.0

يقدم Odoo 19 واجهة REST API كاملة مع مواصفات OpenAPI 3.0. قم بالوصول إلى الوثائق التفاعلية على https://your-odoo.com/api/docs.

قائمة السجلات

# GET /api/sale.order — list all sales orders
response = requests.get(
    f"{ODOO_URL}/api/sale.order",
    headers=headers,
    params={
        "domain": '[["state", "=", "sale"]]',
        "fields": '["name", "partner_id", "amount_total", "state"]',
        "limit": 50,
        "offset": 0
    }
)
orders = response.json()

قراءة سجل واحد

# GET /api/sale.order/{id}
order_id = 123
response = requests.get(
    f"{ODOO_URL}/api/sale.order/{order_id}",
    headers=headers
)
order = response.json()

إنشاء سجل

# POST /api/sale.order
payload = {
    "partner_id": 42,
    "order_line": [
        {
            "product_id": 7,
            "product_uom_qty": 5,
            "price_unit": 100.0
        }
    ]
}
response = requests.post(
    f"{ODOO_URL}/api/sale.order",
    headers=headers,
    json=payload
)
new_order = response.json()

تحديث السجل

# PATCH /api/sale.order/{id}
response = requests.patch(
    f"{ODOO_URL}/api/sale.order/{order_id}",
    headers=headers,
    json={"note": "Rush order — priority handling required"}
)

حذف السجل

# DELETE /api/sale.order/{id}
response = requests.delete(
    f"{ODOO_URL}/api/sale.order/{order_id}",
    headers=headers
)

واجهة JSON-RPC

يوفر JSON-RPC إمكانية الوصول إلى واجهة برمجة تطبيقات Odoo Python الكاملة، بما في ذلك الأساليب من جانب الخادم التي لم يتم الكشف عنها عبر REST. نقطة النهاية الأساسية هي /web/dataset/call_kw.

البحث الأساسي والقراءة

def call_kw(model, method, args, kwargs=None):
    payload = {
        "jsonrpc": "2.0",
        "method": "call",
        "params": {
            "model": model,
            "method": method,
            "args": args,
            "kwargs": kwargs or {}
        }
    }
    response = session.post(
        f"{ODOO_URL}/web/dataset/call_kw",
        json=payload
    )
    return response.json().get('result')

# Search for confirmed sales orders
order_ids = call_kw(
    "sale.order",
    "search",
    [[["state", "=", "sale"]]],
    {"limit": 100, "order": "date_order desc"}
)

# Read specific fields
orders = call_kw(
    "sale.order",
    "read",
    [order_ids],
    {"fields": ["name", "partner_id", "amount_total", "date_order"]}
)

قراءة البحث (مدمجة)

orders = call_kw(
    "sale.order",
    "search_read",
    [[["partner_id.country_id.code", "=", "US"]]],
    {
        "fields": ["name", "partner_id", "amount_total"],
        "limit": 50,
        "offset": 0,
        "order": "amount_total desc"
    }
)

إنشاء السجلات

new_id = call_kw(
    "sale.order",
    "create",
    [{
        "partner_id": 42,
        "order_line": [
            (0, 0, {
                "product_id": 7,
                "product_uom_qty": 10,
                "price_unit": 150.0
            })
        ]
    }]
)

الاتصال بالطرق من جانب الخادم

يتيح JSON-RPC الوصول إلى جميع أساليب Python المحددة في نماذج Odoo:

# Confirm a sales order (triggers workflow)
call_kw("sale.order", "action_confirm", [[order_id]])

# Validate an inventory transfer
call_kw("stock.picking", "button_validate", [[picking_id]])

# Get the action for a button (useful for understanding what a button does)
action = call_kw("sale.order", "action_quotations_with_onboarding", [[]])

واجهة XML-RPC

XML-RPC هو واجهة برمجة تطبيقات Odoo الأصلية ويظل مدعومًا بالكامل. تتكون الواجهة من نقطتي نهاية:

  • /xmlrpc/2/common — الأساليب غير المصادقة (المصادقة، الإصدار)
  • /xmlrpc/2/object — جميع عمليات النموذج (يتطلب UID)
import xmlrpc.client

url = "https://your-odoo.com"
db, username, password = "mydb", "admin", "mypassword"

common = xmlrpc.client.ServerProxy(f"{url}/xmlrpc/2/common")
uid = common.authenticate(db, username, password, {})
models = xmlrpc.client.ServerProxy(f"{url}/xmlrpc/2/object")

# Search for products
product_ids = models.execute_kw(
    db, uid, password,
    'product.template', 'search',
    [[['sale_ok', '=', True]]],
    {'limit': 100}
)

# Read product data
products = models.execute_kw(
    db, uid, password,
    'product.template', 'read',
    [product_ids],
    {'fields': ['name', 'list_price', 'categ_id']}
)

# Create a new product
new_product_id = models.execute_kw(
    db, uid, password,
    'product.template', 'create',
    [{
        'name': 'My New Product',
        'list_price': 99.99,
        'type': 'consu'
    }]
)

مرشحات المجال

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

# Basic operators: =, !=, >, <, >=, <=, like, ilike, in, not in, child_of
domain = [
    ["state", "in", ["sale", "done"]],      # Confirmed or done orders
    ["amount_total", ">=", 1000],            # Total at least 1000
    ["partner_id.country_id.code", "=", "US"] # US customers (related field)
]

# Logical operators: & (AND, default), | (OR), ! (NOT)
domain = [
    "|",
    ["state", "=", "draft"],
    ["state", "=", "cancel"]
]

# Complex: orders from US or UK customers with total > 5000
domain = [
    "|",
    ["partner_id.country_id.code", "=", "US"],
    ["partner_id.country_id.code", "=", "GB"],
    ["amount_total", ">", 5000]
]

خطافات الويب والتكامل القائم على الأحداث

يدعم Odoo 19 خطافات الويب الصادرة الناتجة عن تغييرات السجل. قم بتكوين خطافات الويب ضمن الإعدادات → التقنية → خطافات الويب.

تكوين خطاف الويب:

  1. انتقل إلى الإعدادات ← التقنية ← خطافات الويب ← إنشاء
  2. قم بتعيين النموذج (على سبيل المثال، sale.order)
  3. حدد المشغل: إنشاء أو كتابة أو إلغاء الارتباط أو طريقة مخصصة
  4. أدخل عنوان URL لنقطة النهاية لخدمة الاستقبال الخاصة بك
  5. قم باختيار النطاق لتصفية السجلات التي تقوم بتشغيل خطاف الويب
  6. قم بتكوين الحقول لتضمينها في الحمولة

تلقي أحداث webhook في خدمة Flask:

from flask import Flask, request, jsonify
import hmac, hashlib

app = Flask(__name__)
WEBHOOK_SECRET = "your_webhook_secret"

@app.route("/odoo-webhook", methods=["POST"])
def handle_webhook():
    # Verify signature
    signature = request.headers.get("X-Odoo-Signature")
    body = request.get_data()
    expected = hmac.new(
        WEBHOOK_SECRET.encode(),
        body,
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(signature, expected):
        return jsonify({"error": "Invalid signature"}), 401

    event = request.json
    model = event.get("model")
    record_id = event.get("id")

    # Process the event
    if model == "sale.order":
        handle_order_event(record_id, event)

    return jsonify({"status": "ok"}), 200

معالجة الأخطاء وإعادة المحاولة المنطقية

يجب أن تتعامل عمليات التكامل القوية مع أخطاء Odoo API بأمان.

import time
import requests
from requests.exceptions import RequestException

def api_call_with_retry(url, payload, headers, max_retries=3, backoff=2):
    for attempt in range(max_retries):
        try:
            response = requests.post(url, json=payload, headers=headers, timeout=30)
            response.raise_for_status()

            data = response.json()
            if "error" in data:
                error = data["error"]
                code = error.get("code", 0)
                message = error.get("data", {}).get("message", "Unknown error")

                # Don't retry validation errors
                if code in [200, 100]:
                    raise ValueError(f"Odoo validation error: {message}")

                raise RuntimeError(f"Odoo API error {code}: {message}")

            return data.get("result")

        except (RequestException, RuntimeError) as e:
            if attempt == max_retries - 1:
                raise
            wait = backoff ** attempt
            print(f"Attempt {attempt + 1} failed: {e}. Retrying in {wait}s...")
            time.sleep(wait)

رموز الأخطاء الشائعة:

الكودمعنىالعمل
100خطأ في الخادمتحقق من سجلات Odoo
200تم رفض الوصولالتحقق من أذونات المستخدم
300سجل مفقودتحقق من وجود معرف السجل
304الحقل المطلوب مفقودمراجعة الحمولة

أفضل ممارسات الأداء

العمليات المجمعة: لا تستدعي واجهة برمجة التطبيقات مطلقًا في حلقة للسجلات الفردية. استخدم create_multi وwrite مع القوائم:

# Bad: loop with individual creates
for product in products:
    call_kw("product.template", "create", [product])

# Good: batch create
call_kw("product.template", "create", [products])

اختيار الحقل: حدد دائمًا المعلمة fields لتجنب جلب جميع الحقول:

# Good: only fetch needed fields
orders = call_kw(
    "sale.order", "search_read",
    [[["state", "=", "sale"]]],
    {"fields": ["name", "amount_total"], "limit": 1000}
)

ترقيم الصفحات: بالنسبة لمجموعات البيانات الكبيرة، قم بترقيم الصفحات باستخدام limit وoffset:

def fetch_all_records(model, domain, fields, batch_size=500):
    records = []
    offset = 0
    while True:
        batch = call_kw(
            model, "search_read", [domain],
            {"fields": fields, "limit": batch_size, "offset": offset}
        )
        records.extend(batch)
        if len(batch) < batch_size:
            break
        offset += batch_size
    return records

الأسئلة المتداولة

ما الفرق بين JSON-RPC وREST API في Odoo 19؟

يوفر JSON-RPC إمكانية الوصول إلى واجهة برمجة تطبيقات Odoo Python الكاملة بما في ذلك جميع الطرق من جانب الخادم، بينما يتبع REST اصطلاحات OpenAPI 3.0 ويكشف عن واجهة أكثر محدودية ولكنها موحدة. بالنسبة لعمليات التكامل الجديدة حيث يغطي REST حالة الاستخدام الخاصة بك، يُفضل REST لقابليته للاكتشاف. لأتمتة سير العمل المعقدة أو الوصول إلى أساليب Python المخصصة، استخدم JSON-RPC.

كيف أتعامل مع عمليات تصدير البيانات الكبيرة (أكثر من 100 ألف سجل) بكفاءة؟

استخدم ترقيم الصفحات مع search_read وحجم دفعة يتراوح من 500 إلى 1000 سجل. بالنسبة للصادرات الكبيرة جدًا، فكر في استخدام ميزة التصدير الخاصة بـ Odoo عبر واجهة المستخدم لعمليات الاستخراج لمرة واحدة، أو جدولة مهام الخلفية باستخدام نموذج ir.cron الخاص بـ Odoo لمعالجة البيانات في أجزاء خارج ساعات الذروة بدلاً من إجراء مكالمات API في الوقت الفعلي.

هل يمكنني استخدام مفاتيح API بدلاً من اسم المستخدم/كلمة المرور لـ XML-RPC؟

نعم. في Odoo 13+، يمكن استخدام مفاتيح API ككلمات مرور في استدعاء مصادقة XML-RPC. قم بإنشاء مفتاح API من ملف تعريف المستخدم الخاص بك واستخدمه بدلاً من كلمة المرور الخاصة بك: common.authenticate(db, username, api_key, {}). هذا هو الأسلوب الموصى به لحسابات الخدمة.

كيف يمكنني إنشاء سجلات Many2many وOne2many عبر واجهة برمجة التطبيقات؟

استخدم مجموعات أوامر Odoo: (0, 0, vals) يقوم بإنشاء سجل جديد ذي صلة، (1, id, vals) يقوم بتحديث سجل مرتبط موجود، (2, id, 0) يحذف سجل مرتبط، (4, id, 0) يربط سجل موجود، (5, 0, 0) يلغي ربط جميع السجلات ذات الصلة. تعمل هذه الأوامر بشكل مماثل عبر JSON-RPC، وXML-RPC، وREST.

كيف يمكنني تشغيل إجراء سير العمل (مثل تأكيد الطلب) عبر واجهة برمجة التطبيقات؟

استدعاء الطريقة المقابلة في النموذج. لتأكيد أمر المبيعات، اتصل بـ action_confirm على sale.order. للتحقق من صحة التسليم، اتصل على button_validate على stock.picking. تظهر هذه الأساليب في كود مصدر Odoo ويمكن اكتشافها من خلال فحص سمة الزر name في وضع مطور واجهة المستخدم.

ما هي حدود الأسعار التي يفرضها Odoo على استدعاءات واجهة برمجة التطبيقات (API)؟

لا يفرض Odoo حدودًا لمعدلات واجهة برمجة التطبيقات (API) أصلاً على مستوى التطبيق. يجب تكوين تحديد المعدل على مستوى الوكيل العكسي (Nginx) أو البنية التحتية. الافتراضي المعقول هو 60 طلبًا في الدقيقة لكل عنوان IP لعمليات التكامل الخارجية. بالنسبة لعمليات التكامل عالية الإنتاجية، استخدم أسلوبًا قائمًا على قائمة الانتظار مع مستخدم خدمة مخصص.


الخطوات التالية

يتطلب إنشاء تكامل موثوق لـ Odoo API أكثر من مجرد أمثلة التعليمات البرمجية العاملة - فهو يتطلب معالجة مناسبة للأخطاء، والمراقبة، وإدارة بيانات الاعتماد، والمواءمة مع نموذج بيانات Odoo.

قام فريق التكامل في ECOSIRE ببناء اتصالات على مستوى الإنتاج بين Odoo وعشرات المنصات بما في ذلك Shopify وAmazon وGoHighLevel وPower BI وأنظمة تخطيط موارد المؤسسات (ERP) المخصصة والأنظمة الخاصة. نحن نتعامل مع بنية المصادقة وتصميم خطاف الويب وتحويل البيانات والمراقبة المستمرة.

تحدث إلى ECOSIRE حول مشروع تكامل Odoo الخاص بك →

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

مشاركة:
E

بقلم

ECOSIRE Research and Development Team

بناء منتجات رقمية بمستوى المؤسسات في ECOSIRE. مشاركة رؤى حول تكاملات Odoo وأتمتة التجارة الإلكترونية وحلول الأعمال المدعومة بالذكاء الاصطناعي.

الدردشة على الواتساب