diff --git a/app/module/F6_Plugin_module.py b/app/module/F6_Plugin_module.py index 43dcb50..591604d 100644 --- a/app/module/F6_Plugin_module.py +++ b/app/module/F6_Plugin_module.py @@ -65,7 +65,7 @@ class F6PluginModule: Returns: tuple: 包含文件保存路径和处理后的数据的元组。如果文件保存成功,返回保存路径和数据;如果失败,返回 None 和数据。 """ - data = api_instance.entry_data_get(data=data) + data = api_instance.entry_data_get(data=data,replace= True) print(data) try: # 安全地访问附件信息 @@ -191,7 +191,7 @@ class F6PluginModule: Returns: Dict[str, str]: 包含执行状态的字典,{'msg': '正在执行', 'msg_details': '正在执行,请稍后看结果'} """ - entry_data = api_instance.entry_data_get(data=data) + entry_data = api_instance.entry_data_get(data=data,replace= True) print('执行 品牌批量新建') username = entry_data['data']['账号'] password = entry_data['data']['密码'] @@ -232,7 +232,7 @@ class F6PluginModule: Returns: Dict[str, str]: 包含执行状态的字典 """ - entry_data = api_instance.entry_data_get(data=data) + entry_data = api_instance.entry_data_get(data=data,replace= True) username = entry_data['data']['账号'] password = entry_data['data']['密码'] company_name = entry_data['data']['公司名称'] @@ -279,7 +279,7 @@ class F6PluginModule: Dict[str, str]: 包含执行状态的字典 """ print('执行 删除客户') - entry_data = api_instance.entry_data_get(data=data) + entry_data = api_instance.entry_data_get(data=data,replace= True) username = entry_data['data']['账号'] password = entry_data['data']['密码'] company_name = entry_data['data']['公司名称'] @@ -318,7 +318,7 @@ class F6PluginModule: Returns: Dict[str, str]: 包含执行状态的字典 """ - entry_data = api_instance.entry_data_get(data=data) + entry_data = api_instance.entry_data_get(data=data,replace= True) username = entry_data['data']['账号'] password = entry_data['data']['密码'] company_name = entry_data['data']['公司名称'] @@ -364,7 +364,7 @@ class F6PluginModule: Returns: Dict[str, str]: 包含执行状态的字典 """ - entry_data = api_instance.entry_data_get(data=data) + entry_data = api_instance.entry_data_get(data=data,replace= True) username = entry_data['data']['账号'] password = entry_data['data']['密码'] company_name = entry_data['data']['公司名称'] @@ -403,7 +403,7 @@ class F6PluginModule: Returns: Dict[str, str]: 包含执行状态的字典,{'msg': '正在执行', 'msg_details': '正在执行,请稍后看结果'} """ - entry_data = api_instance.entry_data_get(data=data) + entry_data = api_instance.entry_data_get(data=data,replace= True) print('执行 BI任务') # 获取必要的参数(根据实际需求调整) diff --git a/app/tasks/common.py b/app/tasks/common.py index b283860..fc29c25 100644 --- a/app/tasks/common.py +++ b/app/tasks/common.py @@ -117,6 +117,28 @@ def approve_workflow(data: Dict[str, Any]): logger.error(f"简道云工作流任务提交失败: {e}") +def execute_failure_handler(data: Dict[str, Any]): + """ + 简道云失败流程通知 + + 函数执行失败时调用,通过钉钉webhook通知到指定人员 + """ + now = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()) + pay_load = { + "api_key":"6694d3c4fcb69ca9a111a6c4", + "entry_id":"6938e011b360a1132522a62a", + "data": { + "_widget_1765335060501": {"value": now}, # 失败时间 + "_widget_1765335060502": {"value": data['failure_name']}, # 任务名称 + "_widget_1765335060503": {"value": data['failure_details']} # 失败明细 + } + } + + api_instance.data_batch_create(pay_load) + + + + def get_operate_org_id(cookies: Dict[str, str]) -> Optional[str]: """ 获取操作门店ID diff --git a/app/tasks/delete_tasks.py b/app/tasks/delete_tasks.py index 505e512..a925720 100644 --- a/app/tasks/delete_tasks.py +++ b/app/tasks/delete_tasks.py @@ -16,7 +16,8 @@ import time from typing import Dict, Any, List, Optional from datetime import datetime from tqdm import tqdm -from app.tasks.common import update_jiandaoyun, approve_workflow, get_operate_org_id, get_card_list +from app.tasks.common import update_jiandaoyun, approve_workflow, get_operate_org_id, get_card_list, \ + execute_failure_handler logger = logging.getLogger('app') @@ -37,29 +38,39 @@ def delete_history_background(data: Dict[str, Any], cookies: Dict[str, str], org Returns: None """ - url = f'https://yunxiu.f6car.cn/maintain-dump/maintainHistory/?orgid={org_id}' # 删除url - res = requests.delete(url=url, cookies=cookies) - res_data = res.json() + try: - if res.status_code == 200 and res_data.get('code') == 200: - results = f'{org_name} 历史维修记录已删除' - print(results) - logger.info(f"删除 {org_name} 历史维修记录成功") - else: - results = f'删除 {org_name} 历史维修记录失败: {res_data.get("message")}' - print(results) - logger.error(f"删除 {org_name} 历史维修记录失败: {res_data.get('message')}") + url = f'https://yunxiu.f6car.cn/maintain-dump/maintainHistory/?orgid={org_id}' # 删除url + res = requests.delete(url=url, cookies=cookies) + res_data = res.json() - # 调用api回写改掉 执行明细与执行状态 - time.sleep(1) - msg = update_jiandaoyun(data, f'{results}') + if res.status_code == 200 and res_data.get('code') == 200: + results = f'{org_name} 历史维修记录已删除' + print(results) + logger.info(f"删除 {org_name} 历史维修记录成功") + else: + results = f'删除 {org_name} 历史维修记录失败: {res_data.get("message")}' + data["failure_name"] = "删除历史维修记录后台任务" + data["failure_details"] = results + execute_failure_handler(data) + logger.error(f"删除 {org_name} 历史维修记录失败: {res_data.get('message')}") - if msg.get('msg'): - approve_workflow(data) - print('表单已自动提交至下一步') + # 调用api回写改掉 执行明细与执行状态 + time.sleep(1) + msg = update_jiandaoyun(data, f'{results}') + + if msg.get('msg'): + approve_workflow(data) + print('表单已自动提交至下一步') + except Exception as e: + logger.error(f"删除 {org_name} 历史维修记录失败: {e}") + logger.error(traceback.format_exc()) + data["failure_name"] = "删除历史维修记录后台任务" + data["failure_details"] = traceback.format_exc() + execute_failure_handler(data) -def delete_customer_background(data: Dict[str, Any], cookies: Dict[str, str], total:int ): +def delete_customer_background(data: Dict[str, Any], cookies: Dict[str, str], total: int): """ 删除客户信息后台任务 @@ -78,110 +89,118 @@ def delete_customer_background(data: Dict[str, Any], cookies: Dict[str, str], to - 8-20点之间每3.5秒删除一条数据,其余时间每1.5秒删除一条数据 - 执行结果会更新到简道云表单 """ - print('开始删除客户信息') - success = 0 - fail = 0 + try: + logger.info("开始删除客户信息") + success = 0 + fail = 0 + + json_data = [] + total_page = total // 100 + (total % 100 > 0) + logger.info("正在加载客户信息") + for page in tqdm(range(1, total_page + 1)): + url = f"https://yunxiu.f6car.cn/member/customer/listForPermission?pageSize=100&pageNo={page}" + res = requests.get(url, cookies=cookies) + json_data.extend(res.json().get('data', {}).get('data', [])) + + # 获取门店ID + operate_org_id = get_operate_org_id(cookies) + if not operate_org_id: + msg = update_jiandaoyun(data, '删除失败: 未获取到门店信息') + if msg.get('msg'): + approve_workflow(data) + return - json_data = [] - total_page = total // 100 + (total % 100 > 0) - for page in tqdm(range(1, total_page + 1)): - url = f"https://yunxiu.f6car.cn/member/customer/listForPermission?pageSize=100&pageNo={page}" - res = requests.get(url, cookies=cookies) - json_data.extend(res.json().get('data', {}).get('data',[])) + # 获取会员卡列表(提取客户ID) + card_list_customers = get_card_list(cookies, operate_org_id) + + for item in tqdm(json_data, desc="删除客户"): + id_customer = item['idCustomer'] + phone = item['cellPhone'] + consume_last_time = item['consumeLastTime'] + if consume_last_time: + print(f'{id_customer}最近消费时间: {consume_last_time},跳过删除') + logger.warning(f"{id_customer}最近消费时间: {consume_last_time},跳过删除") + continue + + if id_customer in card_list_customers: + logger.info(f"{id_customer} 存在会员卡,跳过删除") + fail += 1 + continue + + try: + url = f"https://yunxiu.f6car.cn/member/customer/{id_customer}" # 客户信息删除url + res = requests.delete(url, cookies=cookies, timeout=10) # 客户信息删除 + + # 检查HTTP状态码 + if res.status_code != 200: + fail += 1 + error_msg = f"HTTP状态码错误: {res.status_code}" + logger.error(f"客户删除失败: ID={id_customer}, 手机号={phone}, {error_msg}") + print(f"删除失败: ID={id_customer}, 手机号={phone}, {error_msg}") + time.sleep(0.2) + continue + + # 解析响应数据 + try: + res_data = res.json() + except ValueError as json_error: + fail += 1 + error_msg = f"响应不是有效的JSON格式: {json_error}, 响应内容: {res.text[:200]}" + logger.error(f"客户删除失败: ID={id_customer}, 手机号={phone}, {error_msg}") + print(f"删除失败: ID={id_customer}, 手机号={phone}, {error_msg}") + time.sleep(0.2) + continue + + # 检查多种可能的成功标识 + # 有些API返回 success 字段,有些返回 code=200,有些返回 data 字段 + is_success = ( + res_data.get('success') is True or + res_data.get('code') == 200 or + (res_data.get('code') is None and res_data.get('data') is not None) + ) + + if is_success: + success += 1 + logger.info(f"客户删除成功: ID={id_customer}, 手机号={phone}") + else: + fail += 1 + error_msg = res_data.get('message') or res_data.get('msg') or '未知错误' + error_detail = f"错误信息: {error_msg}, 完整响应: {res_data}" + logger.error(f"客户删除失败: ID={id_customer}, 手机号={phone}, {error_detail}") + print(f"删除失败: ID={id_customer}, 手机号={phone}, {error_msg}") + time.sleep(0.2) + except requests.exceptions.RequestException as e: + fail += 1 + error_msg = f"网络请求异常: {str(e)}" + print(f"删除失败: ID={id_customer}, 手机号={phone}, {error_msg}") + logger.error(f"删除客户时发生网络错误: ID={id_customer}, 手机号={phone}, {error_msg}") + except Exception as e: + fail += 1 + error_msg = f"未知错误: {str(e)}" + print(f"删除失败: ID={id_customer}, 手机号={phone}, {error_msg}") + logger.error(f"删除客户时发生错误: ID={id_customer}, 手机号={phone}, {error_msg}", exc_info=True) + + now = datetime.now() + if 8 <= now.hour <= 20: + time.sleep(3.5) + else: + time.sleep(1.5) + + logger.info(f"客户删除结果: 成功次数={success}, 失败次数={fail}") + + msg = update_jiandaoyun(data, f'成功次数{success},失败次数{fail}') - # 获取门店ID - operate_org_id = get_operate_org_id(cookies) - if not operate_org_id: - msg = update_jiandaoyun(data, '删除失败: 未获取到门店信息') if msg.get('msg'): approve_workflow(data) - return - - print(operate_org_id) - # 获取会员卡列表(提取客户ID) - card_list_customers = get_card_list(cookies, operate_org_id) + print('表单已自动提交至下一步') + except Exception as e: + logger.error(f"删除客户信息时发生错误: {str(e)}") + logger.error(traceback.format_exc()) + data["failure_name"] = "删除客户信息后台任务" + data["failure_details"] = traceback.format_exc() + execute_failure_handler(data) - for item in tqdm(json_data, desc="删除客户"): - id_customer = item['idCustomer'] - phone = item['cellPhone'] - consume_last_time = item['consumeLastTime'] - if consume_last_time: - print(f'{id_customer}最近消费时间: {consume_last_time},跳过删除') - logger.warning(f"{id_customer}最近消费时间: {consume_last_time},跳过删除") - continue - - if id_customer in card_list_customers: - logger.info(f"{id_customer} 存在会员卡,跳过删除") - fail += 1 - continue - - try: - url = f"https://yunxiu.f6car.cn/member/customer/{id_customer}" # 客户信息删除url - res = requests.delete(url, cookies=cookies, timeout=10) # 客户信息删除 - - # 检查HTTP状态码 - if res.status_code != 200: - fail += 1 - error_msg = f"HTTP状态码错误: {res.status_code}" - logger.error(f"客户删除失败: ID={id_customer}, 手机号={phone}, {error_msg}") - print(f"删除失败: ID={id_customer}, 手机号={phone}, {error_msg}") - time.sleep(0.2) - continue - - # 解析响应数据 - try: - res_data = res.json() - except ValueError as json_error: - fail += 1 - error_msg = f"响应不是有效的JSON格式: {json_error}, 响应内容: {res.text[:200]}" - logger.error(f"客户删除失败: ID={id_customer}, 手机号={phone}, {error_msg}") - print(f"删除失败: ID={id_customer}, 手机号={phone}, {error_msg}") - time.sleep(0.2) - continue - - # 检查多种可能的成功标识 - # 有些API返回 success 字段,有些返回 code=200,有些返回 data 字段 - is_success = ( - res_data.get('success') is True or - res_data.get('code') == 200 or - (res_data.get('code') is None and res_data.get('data') is not None) - ) - - if is_success: - success += 1 - logger.info(f"客户删除成功: ID={id_customer}, 手机号={phone}") - else: - fail += 1 - error_msg = res_data.get('message') or res_data.get('msg') or '未知错误' - error_detail = f"错误信息: {error_msg}, 完整响应: {res_data}" - logger.error(f"客户删除失败: ID={id_customer}, 手机号={phone}, {error_detail}") - print(f"删除失败: ID={id_customer}, 手机号={phone}, {error_msg}") - time.sleep(0.2) - except requests.exceptions.RequestException as e: - fail += 1 - error_msg = f"网络请求异常: {str(e)}" - print(f"删除失败: ID={id_customer}, 手机号={phone}, {error_msg}") - logger.error(f"删除客户时发生网络错误: ID={id_customer}, 手机号={phone}, {error_msg}") - except Exception as e: - fail += 1 - error_msg = f"未知错误: {str(e)}" - print(f"删除失败: ID={id_customer}, 手机号={phone}, {error_msg}") - logger.error(f"删除客户时发生错误: ID={id_customer}, 手机号={phone}, {error_msg}", exc_info=True) - - now = datetime.now() - if 8 <= now.hour <= 20: - time.sleep(3.5) - else: - time.sleep(1.5) - - logger.info(f"客户删除结果: 成功次数={success}, 失败次数={fail}") - - msg = update_jiandaoyun(data, f'成功次数{success},失败次数{fail}') - - if msg.get('msg'): - approve_workflow(data) - print('表单已自动提交至下一步') def delete_car_background(data: Dict[str, Any], url: str, cookies: Dict[str, str], header: Dict[str, Any], @@ -208,40 +227,41 @@ def delete_car_background(data: Dict[str, Any], url: str, cookies: Dict[str, str - 有会员卡或最近消费记录的车辆会被跳过 - 执行结果会更新到简道云表单 """ - print(cookies) - success = 0 - fail = 0 try: - # 确保 all_page 是一个整数 - all_page = int(all_page) - - # 获取门店ID - operate_org_id = get_operate_org_id(cookies) - if not operate_org_id: - msg = update_jiandaoyun(data, '删除失败: 未获取到门店信息') - if msg.get('msg'): - approve_workflow(data) - return - - print(operate_org_id) - # 获取会员卡列表(提取车辆ID) - # 注意:需要获取所有车辆的ID,所以不能直接使用 get_card_list - # 需要自定义提取逻辑,返回所有车辆的ID列表 - card_list_cars = [] + print(cookies) + success = 0 + fail = 0 try: + # 确保 all_page 是一个整数 + all_page = int(all_page) + + # 获取门店ID + operate_org_id = get_operate_org_id(cookies) + if not operate_org_id: + msg = update_jiandaoyun(data, '删除失败: 未获取到门店信息') + if msg.get('msg'): + approve_workflow(data) + return + + print(operate_org_id) + # 获取会员卡列表(提取车辆ID) + # 注意:需要获取所有车辆的ID,所以不能直接使用 get_card_list + # 需要自定义提取逻辑,返回所有车辆的ID列表 + card_list_cars = [] + # 获取第一页,确定总页数 card_url = f"https://yunxiu.f6car.cn/marketing/card/paging?useStationIdOwnOrgList={operate_org_id}&pageSize=100&pageNo=1" card_res = requests.get(url=card_url, cookies=cookies) total_card = int(card_res.json().get("data", {}).get("total", 0)) - + if total_card > 0: total_page = total_card // 100 + (total_card % 100 > 0) for page in tqdm(range(1, total_page + 1), desc="查询会员卡"): card_url = (f"https://yunxiu.f6car.cn/marketing/card/paging?useStationIdOwnOrgList={operate_org_id}" - f"&pageSize=100&pageNo={page}") + f"&pageSize=100&pageNo={page}") card_res = requests.get(url=card_url, cookies=cookies) card_cars_list = card_res.json().get("data", {}).get("data", []) - + for card_car in card_cars_list: if card_car.get("cars") is None: continue @@ -329,16 +349,15 @@ def delete_car_background(data: Dict[str, Any], url: str, cookies: Dict[str, str print(f"完成: 成功删除 {success} 辆车, 失败 {fail} 辆车") logger.info(f"完成: 成功删除 {success} 辆车, 失败 {fail} 辆车") - except ValueError as e: - print(f"Error converting all_page to integer: {e}") - traceback.print_exc() # 打印堆栈跟踪信息 + + msg = update_jiandaoyun(data, f'成功次数{success},失败次数{fail}') + + if msg.get('msg'): + approve_workflow(data) + print('表单已自动提交至下一步') except Exception as e: - print(f"An unexpected error occurred: {e}") - traceback.print_exc() # 打印堆栈跟踪信息 - - msg = update_jiandaoyun(data, f'成功次数{success},失败次数{fail}') - - if msg.get('msg'): - approve_workflow(data) - print('表单已自动提交至下一步') - + logger.error(f"删除客户车辆信息时发生错误: {str(e)}") + logger.error(traceback.format_exc()) + data["failure_name"] = "删除客户车辆信息后台任务" + data["failure_details"] = traceback.format_exc() + execute_failure_handler(data)