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.
242 lines
8.3 KiB
242 lines
8.3 KiB
import httpx
|
|
import time
|
|
import sys
|
|
|
|
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.client = None
|
|
self._connect()
|
|
|
|
def _connect(self):
|
|
try:
|
|
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("认证失败,请检查用户名和密码")
|
|
|
|
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):
|
|
try:
|
|
ids = self._execute('alpha.datasets', 'search', [[('status', '=', 'draft')]])
|
|
print(f"[INFO] 找到 {len(ids)} 条 draft 记录: {ids}")
|
|
return ids
|
|
except Exception as e:
|
|
print(f"[ERROR] 搜索 draft 记录失败: {e}")
|
|
return []
|
|
|
|
def get_record_status(self, record_id):
|
|
try:
|
|
records = self._execute('alpha.datasets', 'read', [[record_id], ['status', 'result_message', 'datasets_id', 'name']])
|
|
if records:
|
|
return records[0]
|
|
return None
|
|
except Exception as e:
|
|
print(f"[ERROR] 获取记录 {record_id} 状态失败: {e}")
|
|
return None
|
|
|
|
def trigger_btn_get_datasets(self, record_id):
|
|
try:
|
|
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':
|
|
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 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):
|
|
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_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}")
|
|
|
|
success, message = client.trigger_btn_get_datasets(record_id)
|
|
|
|
if not success:
|
|
print(f"[ERROR] 触发失败: {message},跳过记录 {record_id}")
|
|
failed_count += 1
|
|
total_processed += 1
|
|
|
|
try:
|
|
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':
|
|
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) |