You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
alpha_tools/rpc_batch_fetch_dataset/rpc_batch_fetch_dataset.py

249 lines
9.1 KiB

import xmlrpc.client
import time
import sys
# Odoo 连接配置
ODOO_URL = "http://192.168.31.41:32000"
DB_NAME = "quantify"
USERNAME = "rpc"
PASSWORD = "aaaAAA111"
class OdooClient:
def __init__(self, url, db, username, password):
self.url = url
self.db = db
self.username = username
self.password = password
self.uid = None
self.models = 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, {})
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 search_draft_records(self):
"""搜索所有状态为 draft 的 alpha.datasets 记录"""
try:
ids = self.models.execute_kw(
self.db, self.uid, self.password,
'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']]
)
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]]
)
# 处理不同的返回值
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':
print(f"[WARN] 记录 {record_id} 返回错误通知: {message}")
return False, message
else:
print(f"[INFO] 记录 {record_id} 返回通知: {message}")
return True, message
else:
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
while attempt < max_attempts:
record = self.get_record_status(record_id)
if not record:
return 'unknown', '无法获取记录状态'
status = record.get('status')
result_message = record.get('result_message', '')
datasets_id = record.get('datasets_id', 'N/A')
name = record.get('name', 'N/A')
if status in ['done', 'failed']:
print(f"[INFO] 记录 {record_id} (name={name}, datasets_id={datasets_id}) 状态变为: {status}")
if status == 'failed':
print(f"[WARN] 失败原因: {result_message}")
return status, result_message
print(f"[INFO] 记录 {record_id} 当前状态: {status},等待 {check_interval} 秒后重试...")
time.sleep(check_interval)
attempt += 1
print(f"[WARN] 记录 {record_id} 等待超时 ({max_wait_minutes} 分钟)")
return 'timeout', '等待超时'
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:
print("[INFO] 没有更多 draft 记录,处理完成!")
break
print(f"\n[INFO] 开始处理 {len(draft_ids)} 条 draft 记录...")
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} 的信息,跳过")
failed_count += 1
total_processed += 1
continue
if current_record.get('status') != 'draft':
print(f"[INFO] 记录 {record_id} 状态已不是 draft (当前: {current_record.get('status')}),跳过")
total_processed += 1
continue
datasets_id = current_record.get('datasets_id', 'N/A')
name = current_record.get('name', 'N/A')
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:
print(f"[ERROR] 触发失败: {message},跳过记录 {record_id}")
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}'
}]
)
except Exception as e:
print(f"[WARN] 无法更新记录状态: {e}")
continue
# 等待状态变化
status, result_msg = client.wait_for_status_change(record_id)
if status == 'done':
success_count += 1
print(f"[SUCCESS] 记录 {record_id} 处理成功")
elif status == 'failed':
failed_count += 1
print(f"[FAILED] 记录 {record_id} 处理失败: {result_msg}")
elif status == 'timeout':
timeout_count += 1
failed_count += 1
print(f"[TIMEOUT] 记录 {record_id} 处理超时")
else:
failed_count += 1
print(f"[UNKNOWN] 记录 {record_id} 状态未知: {status}")
total_processed += 1
# 短暂延迟,避免请求过快
time.sleep(1)
# 输出统计
print("\n" + "=" * 60)
print("处理完成统计:")
print(f" 总处理记录数: {total_processed}")
print(f" 成功: {success_count}")
print(f" 失败: {failed_count - timeout_count}")
print(f" 超时: {timeout_count}")
print("=" * 60)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n[INFO] 用户中断脚本")
sys.exit(0)
except Exception as e:
print(f"[ERROR] 脚本异常: {e}")
sys.exit(1)