++
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
import xmlrpc.client
|
||||
import httpx
|
||||
import time
|
||||
import sys
|
||||
|
||||
# Odoo 连接配置
|
||||
ODOO_URL = "http://192.168.31.41:32000"
|
||||
DB_NAME = "quantify"
|
||||
USERNAME = "rpc"
|
||||
@@ -16,75 +15,91 @@ class OdooClient:
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.uid = None
|
||||
self.models = None
|
||||
self.client = None
|
||||
self._connect()
|
||||
|
||||
def _connect(self):
|
||||
"""建立 XML-RPC 连接"""
|
||||
try:
|
||||
common = xmlrpc.client.ServerProxy(f"{self.url}/xmlrpc/2/common")
|
||||
self.uid = common.authenticate(self.db, self.username, self.password, {})
|
||||
self.client = httpx.Client(timeout=30.0)
|
||||
|
||||
payload = {
|
||||
"jsonrpc": "2.0",
|
||||
"method": "call",
|
||||
"params": {
|
||||
"service": "common",
|
||||
"method": "login",
|
||||
"args": [self.db, self.username, self.password]
|
||||
},
|
||||
"id": 1
|
||||
}
|
||||
|
||||
response = self.client.post(f"{self.url}/jsonrpc", json=payload)
|
||||
result = response.json()
|
||||
|
||||
if "error" in result:
|
||||
raise Exception(f"登录失败: {result['error']}")
|
||||
|
||||
self.uid = result.get("result")
|
||||
if not self.uid:
|
||||
raise Exception("认证失败,请检查用户名和密码")
|
||||
self.models = xmlrpc.client.ServerProxy(f"{self.url}/xmlrpc/2/object")
|
||||
|
||||
print(f"[INFO] 连接成功,UID: {self.uid}")
|
||||
except Exception as e:
|
||||
print(f"[ERROR] 连接失败: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
def _execute(self, model, method, args=None, kwargs=None):
|
||||
if args is None:
|
||||
args = []
|
||||
if kwargs is None:
|
||||
kwargs = {}
|
||||
|
||||
payload = {
|
||||
"jsonrpc": "2.0",
|
||||
"method": "call",
|
||||
"params": {
|
||||
"service": "object",
|
||||
"method": "execute_kw",
|
||||
"args": [self.db, self.uid, self.password, model, method, args, kwargs]
|
||||
},
|
||||
"id": 2
|
||||
}
|
||||
|
||||
response = self.client.post(f"{self.url}/jsonrpc", json=payload)
|
||||
result = response.json()
|
||||
|
||||
if "error" in result:
|
||||
raise Exception(f"RPC错误: {result['error']}")
|
||||
|
||||
return result.get("result")
|
||||
|
||||
def search_draft_records(self):
|
||||
"""搜索所有状态为 draft 的 alpha.datasets 记录"""
|
||||
try:
|
||||
ids = self.models.execute_kw(
|
||||
self.db, self.uid, self.password,
|
||||
'alpha.datasets', 'search',
|
||||
[[('status', '=', 'draft')]]
|
||||
)
|
||||
ids = self._execute('alpha.datasets', 'search', [[('status', '=', 'draft')]])
|
||||
print(f"[INFO] 找到 {len(ids)} 条 draft 记录: {ids}")
|
||||
return ids
|
||||
except xmlrpc.client.Fault as e:
|
||||
print(f"[ERROR] XML-RPC Fault 搜索记录失败: {e.faultCode} - {e.faultString}")
|
||||
return []
|
||||
except Exception as e:
|
||||
print(f"[ERROR] 搜索 draft 记录失败: {e}")
|
||||
return []
|
||||
|
||||
def get_record_status(self, record_id):
|
||||
"""获取单条记录的状态"""
|
||||
try:
|
||||
records = self.models.execute_kw(
|
||||
self.db, self.uid, self.password,
|
||||
'alpha.datasets', 'read',
|
||||
[[record_id], ['status', 'result_message', 'datasets_id', 'name']]
|
||||
)
|
||||
records = self._execute('alpha.datasets', 'read', [[record_id], ['status', 'result_message', 'datasets_id', 'name']])
|
||||
if records:
|
||||
return records[0]
|
||||
return None
|
||||
except xmlrpc.client.Fault as e:
|
||||
print(f"[ERROR] XML-RPC Fault 获取记录 {record_id} 状态失败: {e.faultCode} - {e.faultString}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"[ERROR] 获取记录 {record_id} 状态失败: {e}")
|
||||
return None
|
||||
|
||||
def trigger_btn_get_datasets(self, record_id):
|
||||
"""
|
||||
调用 btn_get_datasets 方法
|
||||
返回: (success, message)
|
||||
"""
|
||||
try:
|
||||
result = self.models.execute_kw(
|
||||
self.db, self.uid, self.password,
|
||||
'alpha.datasets', 'btn_get_datasets',
|
||||
[[record_id]]
|
||||
)
|
||||
result = self._execute('alpha.datasets', 'btn_get_datasets', [[record_id]])
|
||||
|
||||
# 处理不同的返回值
|
||||
if result is True:
|
||||
print(f"[INFO] 记录 {record_id} 的 btn_get_datasets 调用成功")
|
||||
return True, "调用成功"
|
||||
elif isinstance(result, dict) and result.get('type') == 'ir.actions.client':
|
||||
# 返回的是 notification 字典
|
||||
message = result.get('params', {}).get('message', '')
|
||||
msg_type = result.get('params', {}).get('type', 'info')
|
||||
if msg_type == 'danger':
|
||||
@@ -97,20 +112,12 @@ class OdooClient:
|
||||
print(f"[INFO] 记录 {record_id} 的 btn_get_datasets 调用完成,返回: {result}")
|
||||
return True, "调用成功"
|
||||
|
||||
except xmlrpc.client.Fault as e:
|
||||
error_msg = f"XML-RPC Fault: {e.faultCode} - {e.faultString}"
|
||||
print(f"[ERROR] 调用记录 {record_id} 的 btn_get_datasets 失败: {error_msg}")
|
||||
return False, error_msg
|
||||
except Exception as e:
|
||||
error_msg = f"Exception: {str(e)}"
|
||||
print(f"[ERROR] 调用记录 {record_id} 的 btn_get_datasets 失败: {error_msg}")
|
||||
return False, error_msg
|
||||
|
||||
def wait_for_status_change(self, record_id, check_interval=5, max_wait_minutes=30):
|
||||
"""
|
||||
轮询等待记录状态变为 done 或 failed
|
||||
返回: (status, result_message)
|
||||
"""
|
||||
max_attempts = (max_wait_minutes * 60) // check_interval
|
||||
attempt = 0
|
||||
|
||||
@@ -139,22 +146,18 @@ class OdooClient:
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("=" * 60)
|
||||
print("Odoo 批量处理 draft 数据集脚本")
|
||||
print("=" * 60)
|
||||
|
||||
# 初始化客户端
|
||||
client = OdooClient(ODOO_URL, DB_NAME, USERNAME, PASSWORD)
|
||||
|
||||
# 统计信息
|
||||
total_processed = 0
|
||||
success_count = 0
|
||||
failed_count = 0
|
||||
timeout_count = 0
|
||||
|
||||
while True:
|
||||
# 搜索所有 draft 记录
|
||||
draft_ids = client.search_draft_records()
|
||||
|
||||
if not draft_ids:
|
||||
@@ -166,7 +169,6 @@ def main():
|
||||
for record_id in draft_ids:
|
||||
print(f"\n--- 处理记录 ID: {record_id} ---")
|
||||
|
||||
# 再次确认状态(防止在搜索后状态被改变)
|
||||
current_record = client.get_record_status(record_id)
|
||||
if not current_record:
|
||||
print(f"[ERROR] 无法获取记录 {record_id} 的信息,跳过")
|
||||
@@ -184,7 +186,6 @@ def main():
|
||||
print(f"[INFO] 数据集名称: {name}")
|
||||
print(f"[INFO] 数据集 ID: {datasets_id}")
|
||||
|
||||
# 触发 btn_get_datasets
|
||||
success, message = client.trigger_btn_get_datasets(record_id)
|
||||
|
||||
if not success:
|
||||
@@ -192,21 +193,15 @@ def main():
|
||||
failed_count += 1
|
||||
total_processed += 1
|
||||
|
||||
# 更新记录状态为 failed(如果触发失败)
|
||||
try:
|
||||
client.models.execute_kw(
|
||||
client.db, client.uid, client.password,
|
||||
'alpha.datasets', 'write',
|
||||
[[record_id], {
|
||||
'status': 'failed',
|
||||
'result_message': f'Trigger failed: {message}'
|
||||
}]
|
||||
)
|
||||
client._execute('alpha.datasets', 'write', [[record_id], {
|
||||
'status': 'failed',
|
||||
'result_message': f'Trigger failed: {message}'
|
||||
}])
|
||||
except Exception as e:
|
||||
print(f"[WARN] 无法更新记录状态: {e}")
|
||||
continue
|
||||
|
||||
# 等待状态变化
|
||||
status, result_msg = client.wait_for_status_change(record_id)
|
||||
|
||||
if status == 'done':
|
||||
@@ -225,10 +220,8 @@ def main():
|
||||
|
||||
total_processed += 1
|
||||
|
||||
# 短暂延迟,避免请求过快
|
||||
time.sleep(1)
|
||||
|
||||
# 输出统计
|
||||
print("\n" + "=" * 60)
|
||||
print("处理完成统计:")
|
||||
print(f" 总处理记录数: {total_processed}")
|
||||
|
||||
Reference in New Issue
Block a user