本文目录导读:

我来全面介绍PHP项目与Odoo集成的各种方案。
Odoo REST API 集成
使用官方XML-RPC/JSON-RPC
// XML-RPC 连接示例
class OdooClient {
private $url;
private $db;
private $username;
private $password;
private $uid;
public function __construct($url, $db, $username, $password) {
$this->url = $url;
$this->db = $db;
$this->username = $username;
$this->password = $password;
$this->authenticate();
}
private function authenticate() {
$models = new \PhpXmlRpc\Client($this->url . '/xmlrpc/2/common');
$this->uid = $models->call('authenticate', [
$this->db,
$this->username,
$this->password,
[]
]);
}
public function searchAndRead($model, $domain, $fields = ['id', 'name']) {
$models = new \PhpXmlRpc\Client($this->url . '/xmlrpc/2/object');
return $models->call('execute_kw', [
$this->db,
$this->uid,
$this->password,
$model,
'search_read',
[$domain],
['fields' => $fields, 'limit' => 100]
]);
}
public function create($model, $data) {
$models = new \PhpXmlRpc\Client($this->url . '/xmlrpc/2/object');
return $models->call('execute_kw', [
$this->db,
$this->uid,
$this->password,
$model,
'create',
[$data]
]);
}
public function update($model, $id, $data) {
$models = new \PhpXmlRpc\Client($this->url . '/xmlrpc/2/object');
return $models->call('execute_kw', [
$this->db,
$this->uid,
$this->password,
$model,
'write',
[[$id], $data]
]);
}
public function delete($model, $id) {
$models = new \PhpXmlRpc\Client($this->url . '/xmlrpc/2/object');
return $models->call('execute_kw', [
$this->db,
$this->uid,
$this->password,
$model,
'unlink',
[[$id]]
]);
}
}
// 使用示例
$odoo = new OdooClient(
'http://localhost:8069',
'mydb',
'admin',
'password'
);
// 查询客户
$customers = $odoo->searchAndRead('res.partner',
[['customer_rank', '>', 0]],
['id', 'name', 'email', 'phone']
);
// 创建订单
$orderId = $odoo->create('sale.order', [
'partner_id' => $customerId,
'order_line' => [[
0, 0, [
'product_id' => $productId,
'product_uom_qty' => 10,
'price_unit' => 100
]
]]
]);
使用第三方库
rikudou/odoo-api
composer require rikudou/odoo-api
// 使用示例
use Rikudou\Odoo\OdooConnection;
use Rikudou\Odoo\Odoo;
$connection = new OdooConnection(
'localhost',
8069,
'mydb',
'admin',
'password'
);
$odoo = new Odoo($connection);
// 获取合作伙伴
$partners = $odoo->getModel('res.partner')
->fields(['id', 'name', 'email'])
->where('customer_rank', '>', 0)
->limit(50)
->execute();
Baxtian/odoo-xmlrpc
composer require baxtian/odoo-xmlrpc
use Baxtian\OdooXmlRpc\Client;
$client = new Client('http://localhost:8069', 'mydb');
$client->authenticate('admin', 'password');
// 查询产品
$products = $client->searchRead(
'product.template',
[['sale_ok', '=', true]],
['name', 'list_price', 'default_code']
);
REST API 扩展(Odoo 16+)
安装Odoo REST API模块
# 安装社区版REST API模块 pip install odoo-rest-api # 或使用官方Web API # Odoo 16 内置了JSON-RPC
PHP调用示例
class OdooRestClient {
private $baseUrl;
private $token;
public function __construct($baseUrl, $apiKey) {
$this->baseUrl = rtrim($baseUrl, '/');
$this->token = $apiKey;
}
public function get($endpoint, $params = []) {
$url = $this->baseUrl . '/api/' . ltrim($endpoint, '/');
if (!empty($params)) {
$url .= '?' . http_build_query($params);
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $this->token,
'Content-Type: application/json'
]
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
public function post($endpoint, $data = []) {
$url = $this->baseUrl . '/api/' . ltrim($endpoint, '/');
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $this->token,
'Content-Type: application/json'
]
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
}
// 使用REST API
$client = new OdooRestClient('http://localhost:8069', 'your-api-key');
$orders = $client->get('sale.order', ['limit' => 20]);
数据同步方案
双向同步实现
class OdooSyncManager {
private $odoo;
private $localDB;
public function __construct($odooClient, $pdo) {
$this->odoo = $odooClient;
$this->localDB = $pdo;
}
// 从Odoo同步产品到本地
public function syncProductsFromOdoo() {
$lastSync = $this->getLastSyncTime('products');
// 获取Odoo中更新的产品
$domain = [['write_date', '>', $lastSync]];
$products = $this->odoo->searchAndRead(
'product.template',
$domain,
['id', 'name', 'default_code', 'list_price', 'categ_id']
);
foreach ($products as $product) {
$this->upsertLocalProduct($product);
}
$this->updateSyncTime('products');
return count($products);
}
// 从本地同步订单到Odoo
public function syncOrdersToOdoo() {
$orders = $this->getPendingOrders();
foreach ($orders as $order) {
try {
$odooOrderId = $this->odoo->create('sale.order', [
'partner_id' => $this->getOdooPartnerId($order['customer_id']),
'date_order' => $order['created_at'],
'order_line' => $this->buildOrderLines($order['items']),
'note' => $order['notes']
]);
// 确认订单
$this->odoo->executeMethod(
'sale.order',
'action_confirm',
[$odooOrderId]
);
$this->markOrderSynced($order['id'], $odooOrderId);
} catch (Exception $e) {
$this->logSyncError($order['id'], $e->getMessage());
}
}
}
private function upsertLocalProduct($odooProduct) {
$stmt = $this->localDB->prepare(
"INSERT INTO products (odoo_id, name, sku, price, category_id, updated_at)
VALUES (:odoo_id, :name, :sku, :price, :category_id, NOW())
ON DUPLICATE KEY UPDATE
name = VALUES(name),
sku = VALUES(sku),
price = VALUES(price),
category_id = VALUES(category_id),
updated_at = NOW()"
);
return $stmt->execute([
'odoo_id' => $odooProduct['id'],
'name' => $odooProduct['name'],
'sku' => $odooProduct['default_code'],
'price' => $odooProduct['list_price'],
'category_id' => $odooProduct['categ_id'][0] ?? null
]);
}
}
Webhook集成
Odoo端配置
# odoo/custom_addons/php_integration/models/webhook.py
from odoo import models, api
class WebhookManager(models.Model):
_name = 'webhook.manager'
_description = 'Webhook Manager'
def send_webhook(self, event, data):
webhook_url = self.env['ir.config_parameter'].get_param(
'php_webhook_url'
)
if webhook_url:
import requests
requests.post(webhook_url, json={
'event': event,
'timestamp': fields.Datetime.now(),
'data': data
})
@api.model
def create(self, vals):
record = super().create(vals)
if record._name == 'sale.order':
self.send_webhook('sale.order.created', {
'id': record.id,
'name': record.name,
'partner_id': record.partner_id.id
})
return record
PHP Webhook接收端
// webhook_handler.php
class OdooWebhookHandler {
private $secretKey;
public function __construct($secretKey) {
$this->secretKey = $secretKey;
}
public function handle() {
$payload = json_decode(file_get_contents('php://input'), true);
if (!$this->validateSignature($payload)) {
http_response_code(401);
exit('Invalid signature');
}
switch ($payload['event']) {
case 'sale.order.created':
$this->handleOrderCreated($payload['data']);
break;
case 'product.updated':
$this->handleProductUpdated($payload['data']);
break;
case 'stock.movement':
$this->handleStockMovement($payload['data']);
break;
}
http_response_code(200);
echo json_encode(['status' => 'success']);
}
private function handleOrderCreated($data) {
// 更新本地数据库
$this->updateLocalOrder($data);
// 通知仓库系统
$this->notifyWarehouse($data);
// 发送邮件通知
$this->sendNotification($data);
}
private function validateSignature($payload) {
$signature = $_SERVER['HTTP_X_ODOO_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', json_encode($payload), $this->secretKey);
return hash_equals($expected, $signature);
}
}
$handler = new OdooWebhookHandler('your-secret-key');
$handler->handle();
批量操作和性能优化
class OdooBatchProcessor {
private $odoo;
private $batchSize = 100;
public function batchCreate($model, $records) {
$chunks = array_chunk($records, $this->batchSize);
$results = [];
foreach ($chunks as $chunk) {
try {
// 批量创建
$ids = $this->odoo->executeMethod(
$model,
'create',
[$chunk]
);
$results = array_merge($results, $ids);
} catch (Exception $e) {
// 单个重试
foreach ($chunk as $record) {
try {
$results[] = $this->odoo->create($model, $record);
} catch (Exception $e) {
$this->logError($record, $e);
}
}
}
}
return $results;
}
public function batchRead($model, $ids) {
$chunks = array_chunk($ids, $this->batchSize);
$results = [];
foreach ($chunks as $chunk) {
$records = $this->odoo->searchAndRead(
$model,
[['id', 'in', $chunk]],
['id', 'name', 'write_date']
);
$results = array_merge($results, $records);
}
return $results;
}
// 使用缓存
public function getCachedData($model, $domain, $fields, $ttl = 3600) {
$cacheKey = md5($model . serialize($domain) . serialize($fields));
$cached = apcu_fetch($cacheKey);
if ($cached !== false) {
return $cached;
}
$data = $this->odoo->searchAndRead($model, $domain, $fields);
apcu_store($cacheKey, $data, $ttl);
return $data;
}
}
错误处理和日志
class OdooLogger {
private $logFile;
private $context;
public function __construct($logFile = 'odoo_integration.log') {
$this->logFile = $logFile;
$this->context = [
'timestamp' => date('Y-m-d H:i:s'),
'server' => $_SERVER['SERVER_NAME'] ?? 'cli',
'user' => $_SESSION['user_id'] ?? 'system'
];
}
public function logApiCall($method, $params, $result, $duration) {
$entry = [
'type' => 'API_CALL',
'method' => $method,
'params' => $this->sanitizeParams($params),
'result' => $result,
'duration' => $duration,
'success' => !empty($result),
'context' => $this->context
];
$this->writeEntry($entry);
}
public function logError($error, $additionalData = []) {
$entry = [
'type' => 'ERROR',
'message' => $error->getMessage(),
'trace' => $error->getTraceAsString(),
'additional_data' => $additionalData,
'context' => $this->context
];
$this->writeEntry($entry);
// 发送告警
if ($error->getCode() >= 500) {
$this->sendAlert($entry);
}
}
private function sanitizeParams($params) {
// 移除敏感信息
if (isset($params['password'])) {
$params['password'] = '***';
}
if (isset($params['api_key'])) {
$params['api_key'] = '***';
}
return $params;
}
private function writeEntry($entry) {
$line = json_encode($entry) . PHP_EOL;
file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX);
}
}
最佳实践建议
- 连接管理:使用连接池,避免频繁创建连接
- 错误处理:实现重试机制和降级策略
- 安全考虑:
- 使用HTTPS传输
- 限制API访问IP
- 使用强密码和密钥
- 性能优化:
- 批量操作(bulk create/write)
- 数据缓存
- 异步处理
- 监控告警:
- 监控API响应时间
- 设置错误告警
- 记录同步状态
需要我详细说明某个具体集成方案吗?
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播