简道云fastapi
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
# 后台任务模块结构说明
|
||||
|
||||
## 模块结构
|
||||
|
||||
后台任务已按功能拆分为以下模块:
|
||||
|
||||
```
|
||||
app/tasks/
|
||||
├── __init__.py # 统一导出入口
|
||||
├── common.py # 通用功能模块(简道云表单更新、工作流审批)
|
||||
├── brand_tasks.py # 品牌相关任务
|
||||
├── delete_tasks.py # 删除相关任务
|
||||
└── customer_tasks.py # 客户相关任务
|
||||
```
|
||||
|
||||
## 模块说明
|
||||
|
||||
### common.py - 通用功能模块
|
||||
包含所有任务共用的功能:
|
||||
- `update_jiandaoyun()` - 更新简道云表单
|
||||
- `approve_workflow()` - 工作流审批
|
||||
|
||||
### brand_tasks.py - 品牌任务模块
|
||||
品牌相关的后台任务:
|
||||
- `create_brand_background()` - 品牌批量创建
|
||||
|
||||
### delete_tasks.py - 删除任务模块
|
||||
删除相关的后台任务:
|
||||
- `delete_history_background()` - 删除历史维修记录
|
||||
- `delete_customer_background()` - 删除客户信息
|
||||
- `delete_car_background()` - 删除客户车辆信息
|
||||
|
||||
### customer_tasks.py - 客户任务模块
|
||||
客户相关的后台任务:
|
||||
- `modify_customer_info_background()` - 修改客户信息
|
||||
|
||||
## 向后兼容
|
||||
|
||||
原有的 `app.back_ground_tasks` 模块仍然可用,它现在作为向后兼容的入口,实际功能已拆分到 `app.tasks` 模块中。
|
||||
|
||||
## 添加新功能模块
|
||||
|
||||
如需添加新的功能模块,请按以下步骤:
|
||||
|
||||
1. 在 `app/tasks/` 目录下创建新的模块文件,例如 `new_feature_tasks.py`
|
||||
2. 在新模块中实现相关功能函数
|
||||
3. 在 `app/tasks/__init__.py` 中导入并导出新函数
|
||||
4. 在 `app/back_ground_tasks.py` 中导入新函数以保持向后兼容
|
||||
|
||||
示例:
|
||||
|
||||
```python
|
||||
# app/tasks/new_feature_tasks.py
|
||||
from app.tasks.common import update_jiandaoyun, approve_workflow
|
||||
|
||||
def new_feature_background(data, cookies):
|
||||
# 实现新功能
|
||||
result = "执行结果"
|
||||
msg = update_jiandaoyun(data, result)
|
||||
if msg.get('msg'):
|
||||
approve_workflow(data)
|
||||
```
|
||||
|
||||
```python
|
||||
# app/tasks/__init__.py 中添加
|
||||
from app.tasks.new_feature_tasks import new_feature_background
|
||||
|
||||
__all__ = [
|
||||
# ... 其他函数
|
||||
'new_feature_background',
|
||||
]
|
||||
```
|
||||
|
||||
## 使用方式
|
||||
|
||||
### 方式一:使用新的模块结构(推荐)
|
||||
```python
|
||||
from app.tasks import create_brand_background
|
||||
from app.tasks.brand_tasks import create_brand_background # 也可以直接导入
|
||||
```
|
||||
|
||||
### 方式二:使用向后兼容的导入方式
|
||||
```python
|
||||
from app import back_ground_tasks
|
||||
back_ground_tasks.create_brand_background(...)
|
||||
```
|
||||
|
||||
两种方式都可以正常工作,代码执行逻辑完全一致。
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
"""
|
||||
后台任务模块统一导出入口
|
||||
保持向后兼容,所有原有导入方式仍然有效
|
||||
"""
|
||||
# 通用功能
|
||||
from app.tasks.common import update_jiandaoyun, approve_workflow
|
||||
|
||||
# 品牌相关任务
|
||||
from app.tasks.brand_tasks import create_brand_background
|
||||
|
||||
# 删除相关任务
|
||||
from app.tasks.delete_tasks import (
|
||||
delete_history_background,
|
||||
delete_customer_background,
|
||||
delete_car_background
|
||||
)
|
||||
|
||||
# 客户相关任务
|
||||
from app.tasks.customer_tasks import modify_customer_info_background
|
||||
|
||||
__all__ = [
|
||||
# 通用功能
|
||||
'update_jiandaoyun',
|
||||
'approve_workflow',
|
||||
# 品牌任务
|
||||
'create_brand_background',
|
||||
# 删除任务
|
||||
'delete_history_background',
|
||||
'delete_customer_background',
|
||||
'delete_car_background',
|
||||
# 客户任务
|
||||
'modify_customer_info_background',
|
||||
]
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
品牌相关后台任务模块
|
||||
包含品牌批量创建等功能
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
import requests
|
||||
import pandas as pd
|
||||
from typing import Dict, Any
|
||||
from tqdm import tqdm
|
||||
from app.tasks.common import update_jiandaoyun, approve_workflow
|
||||
|
||||
logger = logging.getLogger('app')
|
||||
|
||||
|
||||
def create_brand_background(data: Dict[str, Any], cookies: Dict[str, str], df: pd.DataFrame, save_path: str):
|
||||
"""
|
||||
品牌批量创建后台运行函数
|
||||
:param data: 包含表单id、数据id等的字典
|
||||
:param cookies: 用户登录f6系统的cookies信息
|
||||
:param df: 表格读取到的内容,DataFrame格式
|
||||
:param save_path: 文件保存的地址
|
||||
:return: None
|
||||
"""
|
||||
df = df.where(pd.notnull(df), None)
|
||||
# 定义请求URL
|
||||
url = 'https://yunxiu.f6car.cn/camaro/brand/getOrCreate'
|
||||
# 遍历DataFrame中的每一行数据
|
||||
results = []
|
||||
for index, row in tqdm(df.iterrows(), total=df.shape[0], desc="创建品牌"):
|
||||
brand_name = row[df.columns[0]]
|
||||
|
||||
if brand_name is None or pd.isna(brand_name) or str(brand_name).strip() == '':
|
||||
results.append({f'{brand_name}': '无效品牌名', '状态': '跳过'})
|
||||
logger.warning(f"跳过无效品牌名: {brand_name}")
|
||||
continue
|
||||
|
||||
try:
|
||||
response = requests.post(url, cookies=cookies, json={"brandName": brand_name})
|
||||
response.raise_for_status() # 抛出HTTP错误
|
||||
results.append({'品牌名': brand_name, '状态': '创建成功'})
|
||||
except requests.exceptions.RequestException as e:
|
||||
results.append({'品牌名': brand_name, '状态': f'创建失败: {str(e)}'})
|
||||
print({'msg': '已执行', 'msg_details': f'{results}'})
|
||||
logger.info(f"品牌创建结果: {results}")
|
||||
os.remove(save_path)
|
||||
print(f'{save_path}已删除')
|
||||
print(data)
|
||||
# 调用api回写改掉 执行明细与执行状态
|
||||
msg = update_jiandaoyun(data, f'{results}')
|
||||
|
||||
if msg.get('msg'):
|
||||
approve_workflow(data)
|
||||
print('表单已自动提交至下一步')
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
"""
|
||||
通用后台任务模块
|
||||
包含简道云表单更新和工作流审批等通用功能
|
||||
"""
|
||||
import logging
|
||||
import time
|
||||
from typing import Dict, Any
|
||||
from app.api import API
|
||||
|
||||
api_instance = API()
|
||||
logger = logging.getLogger('app')
|
||||
|
||||
|
||||
def update_jiandaoyun(data: Dict[str, Any], results: str):
|
||||
"""
|
||||
更新简道云表单
|
||||
:param data: 包含表单id、应用id、数据id的字典
|
||||
:param results: 执行结果信息
|
||||
:return: 更新结果字典
|
||||
"""
|
||||
# 定义简道云数据配置
|
||||
jiandaoyun_data = {
|
||||
'api_key': data['api_key'],
|
||||
'entry_id': data['entry_id'],
|
||||
'data_id': data['data_id'],
|
||||
"data": {
|
||||
'_widget_1731379774828': {"value": "已执行"}, # f6系统批量操作测试 是否执行成功
|
||||
'_widget_1731381334870': {"value": results} # f6系统批量操作测试 执行明细
|
||||
}
|
||||
}
|
||||
|
||||
time.sleep(1)
|
||||
print(jiandaoyun_data)
|
||||
|
||||
try:
|
||||
response = api_instance.entry_data_update(jiandaoyun_data)
|
||||
logger.info(f"简道云表单更新成功: {response}")
|
||||
return {'msg': True}
|
||||
except Exception as e:
|
||||
logger.error(f"简道云表单更新失败: {e}")
|
||||
return {'msg': False}
|
||||
|
||||
|
||||
def approve_workflow(data: Dict[str, Any]):
|
||||
"""
|
||||
获取简道云当前流程节点并直接提交
|
||||
:param data: 包含表单id、应用id、数据id的字典
|
||||
:return: None
|
||||
"""
|
||||
# 获取简道云当前流程列表
|
||||
json = api_instance.workflow_instance_get(data)
|
||||
|
||||
# 检查返回数据是否有效
|
||||
if not json:
|
||||
logger.error("未获取到工作流实例信息")
|
||||
return
|
||||
|
||||
# 安全地获取任务列表
|
||||
tasks = json.get('tasks', [])
|
||||
if not tasks:
|
||||
logger.error("未找到待处理任务")
|
||||
return
|
||||
|
||||
# 将JSON字符串转换为Python字典
|
||||
username = ''
|
||||
instance_id = ''
|
||||
task_id = ''
|
||||
|
||||
for task in tasks:
|
||||
if task.get('status') == 0:
|
||||
assignee = task.get('assignee', {})
|
||||
username = assignee.get('username', '')
|
||||
instance_id = task.get('instance_id', '')
|
||||
task_id = task.get('task_id', '')
|
||||
|
||||
if username and instance_id and task_id:
|
||||
break
|
||||
|
||||
if not username or not instance_id or not task_id:
|
||||
logger.error("未找到有效的待处理任务信息")
|
||||
return
|
||||
|
||||
task_data = {
|
||||
"username": username,
|
||||
"instance_id": instance_id,
|
||||
"task_id": task_id,
|
||||
}
|
||||
|
||||
try:
|
||||
response = api_instance.workflow_task_approve(task_data)
|
||||
logger.info(f"简道云工作流任务提交成功: {response}")
|
||||
except Exception as e:
|
||||
logger.error(f"简道云工作流任务提交失败: {e}")
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
"""
|
||||
客户相关后台任务模块
|
||||
包含修改客户信息等功能
|
||||
"""
|
||||
import logging
|
||||
import requests
|
||||
import pandas as pd
|
||||
import time
|
||||
import re
|
||||
from typing import Dict, Any, Optional
|
||||
from app.tasks.common import update_jiandaoyun, approve_workflow
|
||||
|
||||
logger = logging.getLogger('app')
|
||||
|
||||
|
||||
def modify_customer_info_background(data: Dict[str, Any], cookies: Dict[str, str], df: pd.DataFrame, save_path: str):
|
||||
"""
|
||||
修改客户信息后台任务。
|
||||
|
||||
此函数用于后台任务,用于修改会员信息。
|
||||
|
||||
Args:
|
||||
data (Dict[str, Any]): 前端请求发送过来的数据,包含文件信息和其他必要参数。
|
||||
cookies (Dict[str, str]): 登录用户的Cookies。
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
df = df.where(pd.notnull(df), None)
|
||||
params = {
|
||||
'pageSize': 100,
|
||||
'pageNo': '1',
|
||||
}
|
||||
|
||||
res = requests.get(
|
||||
'https://yunxiu.f6car.cn/member/customer/listForPermission',
|
||||
params=params,
|
||||
cookies=cookies,
|
||||
)
|
||||
|
||||
total = int(res.json().get("data").get("total"))
|
||||
total_pages = (total // params["pageSize"]) + (1 if total % params["pageSize"] > 0 else 0)
|
||||
print(f"总计{total_pages}页")
|
||||
|
||||
all_customers = []
|
||||
max_retries = 10
|
||||
retry_count = 0
|
||||
for page in range(1, total_pages + 1):
|
||||
print(f"正在请求第 {page} 页...")
|
||||
params["pageNo"] = page
|
||||
|
||||
while retry_count < max_retries:
|
||||
response = requests.get(
|
||||
'https://yunxiu.f6car.cn/member/customer/listForPermission',
|
||||
params=params,
|
||||
cookies=cookies,
|
||||
timeout=10
|
||||
)
|
||||
time.sleep(1)
|
||||
if response.status_code == 200:
|
||||
suppliers = response.json().get("data", {}).get("data", [])
|
||||
all_customers.extend(suppliers)
|
||||
break
|
||||
else:
|
||||
retry_count += 1
|
||||
print(f"请求第 {page} 页失败,正在重试(第 {retry_count} 次)...")
|
||||
time.sleep(3)
|
||||
|
||||
# 获取专属运营顾问列表
|
||||
json_data = {
|
||||
'includeStopedEmployee': False,
|
||||
'pageSize': 1000,
|
||||
'filterNullUser': False,
|
||||
'keyword': '',
|
||||
'idOwnOrgList': [],
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
'https://yunxiu.f6car.cn/hive/employee/searchStaffInGroup',
|
||||
cookies=cookies,
|
||||
json=json_data,
|
||||
)
|
||||
|
||||
staff_list = response.json().get("data").get("list")
|
||||
name_to_userid = {
|
||||
emp['name']: emp['userId']
|
||||
for emp in staff_list
|
||||
if emp['userId'] is not None
|
||||
}
|
||||
df['userId'] = df['专属运营顾问'].map(name_to_userid)
|
||||
|
||||
def extract_province_city_district(address: Optional[str]) -> Dict[str, Optional[str]]:
|
||||
"""安全解析省市区信息,所有返回值都可能为None"""
|
||||
if not address:
|
||||
return {'省': None, '市': None, '区': None}
|
||||
|
||||
try:
|
||||
pattern = r'(?P<省>(?:[\u4e00-\u9fa5]+(?:省|自治区|特别行政区))?)' \
|
||||
r'(?P<市>(?:[\u4e00-\u9fa5]+(?:市|自治州|地区|盟))?)' \
|
||||
r'(?P<区>(?:[\u4e00-\u9fa5]+区|[\u4e00-\u9fa5]+县|[\u4e00-\u9fa5]+旗)?)'
|
||||
match = re.match(pattern, address.strip())
|
||||
return {k: v if v else None for k, v in match.groupdict().items()} if match else {'省': None, '市': None,
|
||||
'区': None}
|
||||
except Exception:
|
||||
return {'省': None, '市': None, '区': None}
|
||||
|
||||
def safe_get(d: Optional[Dict], *keys, default=None):
|
||||
"""多层字典安全获取值,始终返回可能为None的值"""
|
||||
if not isinstance(d, dict):
|
||||
return default
|
||||
|
||||
for key in keys:
|
||||
d = d.get(key, {})
|
||||
if not isinstance(d, dict):
|
||||
break
|
||||
return d if d != {} else default
|
||||
|
||||
def convert_to_request_data(original_data: Optional[Dict[str, Any]], df: pd.DataFrame) -> Dict[str, Any]:
|
||||
"""
|
||||
完全安全的字典转换函数
|
||||
特点:
|
||||
1. 每个字段的值都可能为None
|
||||
2. 不会因为任何字段为空而报错
|
||||
3. 不使用任何默认值,完全保留原始数据的空值状态
|
||||
"""
|
||||
customer_info = safe_get(original_data, 'data', 'customerInfo') if original_data else None
|
||||
|
||||
address_parts = extract_province_city_district(
|
||||
safe_get(customer_info, 'provinceCityAreaName') if customer_info else None
|
||||
)
|
||||
|
||||
cell_phone = safe_get(customer_info, 'cellPhone')
|
||||
|
||||
exclusive_info = None
|
||||
df_row = None
|
||||
if cell_phone and not df.empty:
|
||||
matched_rows = df[df['客户手机号'] == cell_phone]
|
||||
if not matched_rows.empty:
|
||||
df_row = matched_rows.iloc[0]
|
||||
exclusive_info = {
|
||||
'userId': df_row.get('userId'),
|
||||
'name': df_row.get('专属运营顾问')
|
||||
}
|
||||
|
||||
request_data = {
|
||||
"pkId": safe_get(customer_info, 'idCustomer'),
|
||||
"idCustomer": safe_get(customer_info, 'idCustomer'),
|
||||
"name": df_row.get('客户姓名') if df_row is not None and pd.notna(df_row.get('客户姓名')) else safe_get(
|
||||
customer_info, 'name'),
|
||||
"sex": safe_get(customer_info, 'sex'),
|
||||
"customerType": df_row.get('客户类型') if df_row is not None and pd.notna(
|
||||
df_row.get('客户类型')) else safe_get(
|
||||
customer_info, 'customerType'),
|
||||
"customerSource": safe_get(customer_info, 'customerSource'),
|
||||
"customerSourceName": df_row.get('客户来源') if df_row is not None and pd.notna(
|
||||
df_row.get('客户来源')) else safe_get(customer_info, 'customerSourceName'),
|
||||
"companyName": df_row.get('单位名称') if df_row is not None and pd.notna(
|
||||
df_row.get('单位名称')) else safe_get(
|
||||
customer_info, 'companyName'),
|
||||
"cellPhone": cell_phone,
|
||||
"wechart": safe_get(customer_info, 'wechart'),
|
||||
"qq": safe_get(customer_info, 'qq'),
|
||||
"contacts": safe_get(customer_info, 'contacts'),
|
||||
"contactTelephone": safe_get(customer_info, 'contactTelephone'),
|
||||
"province": safe_get(customer_info, 'province'),
|
||||
"city": safe_get(customer_info, 'city'),
|
||||
"area": safe_get(customer_info, 'area'),
|
||||
"street": safe_get(customer_info, 'street'),
|
||||
"address": safe_get(customer_info, 'address'),
|
||||
"detailAddress": safe_get(customer_info, 'detailAddress'),
|
||||
"pId": safe_get(customer_info, 'province'),
|
||||
"cId": safe_get(customer_info, 'city'),
|
||||
"aId": safe_get(customer_info, 'area'),
|
||||
"provinceName": address_parts.get('省'),
|
||||
"cityName": address_parts.get('市'),
|
||||
"areaName": address_parts.get('区'),
|
||||
"provinceCityAreaName": safe_get(customer_info, 'provinceCityAreaName'),
|
||||
"birthday": safe_get(customer_info, 'birthday'),
|
||||
"creationtime": safe_get(customer_info, 'creationtime'),
|
||||
"modifiedtime": safe_get(customer_info, 'modifiedtime'),
|
||||
"creator": safe_get(customer_info, 'creator'),
|
||||
"creatorName": safe_get(customer_info, 'creatorName'),
|
||||
"modifier": safe_get(customer_info, 'modifier'),
|
||||
"idOwnOrg": safe_get(customer_info, 'idOwnOrg'),
|
||||
"idOwnGroup": safe_get(customer_info, 'idOwnGroup'),
|
||||
"insuranceCompany": safe_get(customer_info, 'insuranceCompany'),
|
||||
"maritalStatus": safe_get(customer_info, 'maritalStatus'),
|
||||
"monthlyIncome": safe_get(customer_info, 'monthlyIncome'),
|
||||
"idNumber": safe_get(customer_info, 'idNumber'),
|
||||
"personHobby": safe_get(customer_info, 'personHobby'),
|
||||
"credentialsType": safe_get(customer_info, 'credentialsType'),
|
||||
"points": safe_get(customer_info, 'points'),
|
||||
"maxAccountAmount": safe_get(customer_info, 'maxAccountAmount'),
|
||||
"pointsEnable": safe_get(customer_info, 'pointsEnable'),
|
||||
"level": safe_get(customer_info, 'level'),
|
||||
"memberCardNo": safe_get(customer_info, 'memberCardNo'),
|
||||
"customerLevel": safe_get(customer_info, 'customerLevel'),
|
||||
"exclusiveConsultantId": exclusive_info['userId'] if exclusive_info else safe_get(customer_info,
|
||||
'exclusiveConsultantId'),
|
||||
"exclusiveConsultantName": exclusive_info['name'] if exclusive_info else safe_get(customer_info,
|
||||
'exclusiveConsultantName'),
|
||||
"exclusiveOrgId": safe_get(customer_info, 'exclusiveOrgId'),
|
||||
"exclusiveOrgName": safe_get(customer_info, 'exclusiveOrgName'),
|
||||
"customerMemo": df_row.get('客户备注') if df_row is not None and pd.notna(
|
||||
df_row.get('客户备注')) else safe_get(
|
||||
customer_info, 'customerMemo'),
|
||||
"isDel": safe_get(customer_info, 'isDel'),
|
||||
"idFrom": safe_get(customer_info, 'idFrom'),
|
||||
"mnemonic": safe_get(customer_info, 'mnemonic'),
|
||||
"idOrgSource": safe_get(customer_info, 'idOrgSource'),
|
||||
"firstArrivalIdSourceBill": safe_get(customer_info, 'firstArrivalIdSourceBill'),
|
||||
"lastArrivalIdSourceBill": safe_get(customer_info, 'lastArrivalIdSourceBill'),
|
||||
"customerInfoType": safe_get(customer_info, 'customerInfoType'),
|
||||
"customerInfoCompleteDate": safe_get(customer_info, 'customerInfoCompleteDate'),
|
||||
"customerInfoCompleteType": safe_get(customer_info, 'customerInfoCompleteType'),
|
||||
"xczUserId": safe_get(customer_info, 'xczUserId'),
|
||||
"xczUuid": safe_get(customer_info, 'xczUuid'),
|
||||
"idWxbCustomer": safe_get(customer_info, 'idWxbCustomer'),
|
||||
"promoteEmployeeId": safe_get(customer_info, 'promoteEmployeeId'),
|
||||
"promoteEmployeeName": safe_get(customer_info, 'promoteEmployeeName'),
|
||||
"promoteMemberId": safe_get(customer_info, 'promoteMemberId'),
|
||||
"promoteMemberName": safe_get(customer_info, 'promoteMemberName'),
|
||||
"driverExpiryDate": safe_get(customer_info, 'driverExpiryDate'),
|
||||
"crmDeleteExclusiveFlag": safe_get(customer_info, 'crmDeleteExclusiveFlag'),
|
||||
"totalObtainPoints": safe_get(customer_info, 'totalObtainPoints'),
|
||||
"totalUsedPoints": safe_get(customer_info, 'totalUsedPoints'),
|
||||
"orgName": safe_get(customer_info, 'orgName'),
|
||||
"weChatFollower": safe_get(customer_info, 'weChatFollower'),
|
||||
"pointsEnableConfig": safe_get(customer_info, 'pointsEnableConfig'),
|
||||
"personalPointsEnableConfig": safe_get(customer_info, 'personalPointsEnableConfig'),
|
||||
"pointsButtonStatus": safe_get(customer_info, 'pointsButtonStatus'),
|
||||
"tmallInstallMember": safe_get(customer_info, 'tmallInstallMember'),
|
||||
"corpId": safe_get(customer_info, 'corpId'),
|
||||
"thirdCorpId": safe_get(customer_info, 'thirdCorpId'),
|
||||
}
|
||||
|
||||
return request_data
|
||||
|
||||
for customer in all_customers:
|
||||
phone = customer.get("cellPhone")
|
||||
if phone in df["客户手机号"].tolist():
|
||||
print("开始修改")
|
||||
cus_id = customer.get("idCustomer", {})
|
||||
cus_response = requests.get(f'https://yunxiu.f6car.cn/member/customer/{cus_id}', cookies=cookies)
|
||||
original_data = cus_response.json()
|
||||
final_json_data = convert_to_request_data(original_data, df)
|
||||
response = requests.post(
|
||||
'https://yunxiu.f6car.cn/member/customer/modifyCustomer',
|
||||
cookies=cookies,
|
||||
json=final_json_data,
|
||||
)
|
||||
print("修改完成")
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
msg = update_jiandaoyun(data, f'修改完成')
|
||||
|
||||
if msg.get('msg'):
|
||||
approve_workflow(data)
|
||||
print('表单已自动提交至下一步')
|
||||
|
||||
@@ -0,0 +1,304 @@
|
||||
"""
|
||||
删除相关后台任务模块
|
||||
包含删除历史维修记录、删除客户信息、删除客户车辆信息等功能
|
||||
"""
|
||||
import logging
|
||||
import traceback
|
||||
import requests
|
||||
import time
|
||||
from typing import Dict, Any, List
|
||||
from datetime import datetime
|
||||
from tqdm import tqdm
|
||||
from app.tasks.common import update_jiandaoyun, approve_workflow
|
||||
|
||||
logger = logging.getLogger('app')
|
||||
|
||||
|
||||
def delete_history_background(data: Dict[str, Any], cookies: Dict[str, str], org_id: str, org_name: str):
|
||||
"""
|
||||
删除历史维修数据后台运行函数
|
||||
:param data: 包含表单id、数据id等的字典
|
||||
:param cookies: 用户登录F6系统的cookies信息
|
||||
:param org_id: 需要删除历史维修记录的门店id
|
||||
:param org_name: 需要删除历史维修记录的门店名称
|
||||
:return: 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()
|
||||
|
||||
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')}")
|
||||
|
||||
# 调用api回写改掉 执行明细与执行状态
|
||||
time.sleep(1)
|
||||
msg = update_jiandaoyun(data, f'{results}')
|
||||
|
||||
if msg.get('msg'):
|
||||
approve_workflow(data)
|
||||
print('表单已自动提交至下一步')
|
||||
|
||||
|
||||
def delete_customer_background(data: Dict[str, Any], cookies: Dict[str, str], json_data: List[Dict[str, Any]]):
|
||||
"""
|
||||
删除客户信息后台运行函数
|
||||
:param data: 包含表单id、数据id等字典
|
||||
:param cookies: 用户登录f6系统的cookies信息
|
||||
:param json_data: 获取到的客户信息列表,列表最大值取决url里面的值
|
||||
:return: None
|
||||
"""
|
||||
success = 0
|
||||
fail = 0
|
||||
|
||||
# 获取门店ID
|
||||
org_url = "https://yunxiu.f6car.cn/hive/org/getPageOrgGroupMembers?currentPage=1&pageSize=10&name="
|
||||
org_res = requests.get(url=org_url, cookies=cookies)
|
||||
|
||||
# 安全地获取门店ID
|
||||
org_data = org_res.json().get("data", {})
|
||||
org_list = org_data.get("list", [])
|
||||
|
||||
if not org_list or len(org_list) == 0:
|
||||
logger.error("未获取到门店信息")
|
||||
msg = update_jiandaoyun(data, '删除失败: 未获取到门店信息')
|
||||
if msg.get('msg'):
|
||||
approve_workflow(data)
|
||||
return
|
||||
|
||||
operate_org_id = org_list[0].get("orgId")
|
||||
if not operate_org_id:
|
||||
logger.error("门店ID为空")
|
||||
msg = update_jiandaoyun(data, '删除失败: 门店ID为空')
|
||||
if msg.get('msg'):
|
||||
approve_workflow(data)
|
||||
return
|
||||
|
||||
print(operate_org_id)
|
||||
# 获取会员卡列表
|
||||
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"))
|
||||
print(total_card)
|
||||
total_page = total_card // 100 + (total_card % 100 > 0)
|
||||
card_list_customers = []
|
||||
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}")
|
||||
|
||||
card_res = requests.get(url=card_url, cookies=cookies)
|
||||
card_cars_list = card_res.json().get("data").get("data")
|
||||
|
||||
for card_customer in card_cars_list:
|
||||
if card_customer.get("idCustomer") is None:
|
||||
continue
|
||||
else:
|
||||
card_list_customers.append(card_customer.get("idCustomer", None))
|
||||
time.sleep(0.2)
|
||||
|
||||
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) # 客户信息删除
|
||||
res_data = res.json()
|
||||
if res_data.get('success'):
|
||||
success += 1
|
||||
logger.info(f"客户删除成功: ID={id_customer}, 手机号={phone}")
|
||||
else:
|
||||
fail += 1
|
||||
logger.error(f"客户删除失败: ID={id_customer}, 手机号={phone}, 错误信息: {res_data.get('message')}")
|
||||
time.sleep(0.2)
|
||||
except Exception as e:
|
||||
fail += 1
|
||||
print("删除失败,", item, id_customer, phone, e)
|
||||
logger.error(f"删除客户时发生错误: ID={id_customer}, 手机号={phone}, 错误信息: {e}")
|
||||
if success + fail < len(json_data):
|
||||
continue
|
||||
|
||||
now = datetime.now()
|
||||
if 20 <= now.hour <= 8:
|
||||
time.sleep(1)
|
||||
else:
|
||||
time.sleep(3)
|
||||
|
||||
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],
|
||||
all_page: str):
|
||||
"""
|
||||
删除客户车辆信息后台运行函数
|
||||
:param header: 应包含账号登录的请求头
|
||||
:param url: 包含请求客户车辆信息的url
|
||||
:param all_page: 客户车辆信息的页数
|
||||
:param data: 包含表单id、数据id等的字典
|
||||
:param cookies: 登录F6系统后的请求信息
|
||||
:return: None
|
||||
"""
|
||||
print(cookies)
|
||||
success = 0
|
||||
fail = 0
|
||||
try:
|
||||
# 确保 all_page 是一个整数
|
||||
all_page = int(all_page)
|
||||
|
||||
# 获取门店ID
|
||||
org_url = "https://yunxiu.f6car.cn/hive/org/getPageOrgGroupMembers?currentPage=1&pageSize=10&name="
|
||||
org_res = requests.get(url=org_url, cookies=cookies)
|
||||
|
||||
# 安全地获取门店ID
|
||||
org_data = org_res.json().get("data", {})
|
||||
org_list = org_data.get("list", [])
|
||||
|
||||
if not org_list or len(org_list) == 0:
|
||||
logger.error("未获取到门店信息")
|
||||
msg = update_jiandaoyun(data, '删除失败: 未获取到门店信息')
|
||||
if msg.get('msg'):
|
||||
approve_workflow(data)
|
||||
return
|
||||
|
||||
operate_org_id = org_list[0].get("orgId")
|
||||
if not operate_org_id:
|
||||
logger.error("门店ID为空")
|
||||
msg = update_jiandaoyun(data, '删除失败: 门店ID为空')
|
||||
if msg.get('msg'):
|
||||
approve_workflow(data)
|
||||
return
|
||||
|
||||
print(operate_org_id)
|
||||
# 获取会员卡列表
|
||||
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"))
|
||||
print(total_card)
|
||||
total_page = total_card // 100 + (total_card % 100 > 0)
|
||||
card_list_cars = []
|
||||
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}")
|
||||
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
|
||||
for car in card_car.get("cars", []):
|
||||
card_list_cars.append(car.get("idCar", None))
|
||||
time.sleep(0.2)
|
||||
|
||||
itemlist = []
|
||||
# 使用 range() 创建一个可迭代的对象
|
||||
for page in range(1, all_page + 1):
|
||||
json_data = {
|
||||
"pageSize": 100,
|
||||
"pageNo": page
|
||||
}
|
||||
|
||||
# 获取当前页的数据
|
||||
res = requests.post(url=url, cookies=cookies, json=json_data, headers=header)
|
||||
res.raise_for_status() # 检查请求是否成功
|
||||
response_data = res.json()
|
||||
|
||||
if 'data' not in response_data or 'data' not in response_data['data']:
|
||||
print(f"警告: 页码 {page} 返回的数据格式不正确")
|
||||
continue
|
||||
|
||||
items = response_data['data']['data']
|
||||
for item in items:
|
||||
itemlist.append(item)
|
||||
|
||||
for item in tqdm(itemlist, desc="删除车辆信息"):
|
||||
car_id = item.get('tmCarInfo', {}).get('pkId')
|
||||
customer_id = item.get('tmCustomerInfo', {}).get('pkId')
|
||||
consume_last_time = item.get('tmCustomerInfo', {}).get('consumeLastTime')
|
||||
|
||||
if consume_last_time:
|
||||
logger.info(f"{customer_id}最近消费时间: {consume_last_time},跳过删除")
|
||||
fail += 1
|
||||
continue
|
||||
|
||||
if car_id in card_list_cars:
|
||||
logger.info(f"{customer_id} 存在会员卡,跳过删除")
|
||||
fail += 1
|
||||
continue
|
||||
|
||||
if not car_id or not customer_id:
|
||||
logger.info(f"页码 {page} 中缺少必要的ID信息")
|
||||
fail += 1
|
||||
continue
|
||||
|
||||
try:
|
||||
delete_url = (
|
||||
f"https://yunxiu.f6car.cn/member/car/deleteCar/{car_id}/{customer_id}"
|
||||
)
|
||||
delete_res = requests.delete(delete_url, cookies=cookies)
|
||||
delete_res.raise_for_status() # 检查删除请求是否成功
|
||||
delete_data = delete_res.json()
|
||||
|
||||
if delete_data.get('data'):
|
||||
success += 1
|
||||
else:
|
||||
fail += 1
|
||||
logger.error(
|
||||
f"删除失败: 页码 {page}, 车辆ID {car_id}, 客户ID {customer_id},"
|
||||
f" 错误信息: {delete_data.get('message', '未知错误')}")
|
||||
print(
|
||||
f"删除失败: 页码 {page}, 车辆ID {car_id}, 客户ID {customer_id},"
|
||||
f" 错误信息: {delete_data.get('message', '未知错误')}")
|
||||
|
||||
time.sleep(0.2) # 避免过快请求
|
||||
except requests.exceptions.RequestException as e:
|
||||
fail += 1
|
||||
print(f"删除失败: 页码 {page}, 车辆ID {car_id}, 客户ID {customer_id}, 错误信息: {e}")
|
||||
logger.error(f"删除失败: 页码 {page}, 车辆ID {car_id}, 客户ID {customer_id}, 错误信息: {e}")
|
||||
continue
|
||||
|
||||
now = datetime.now()
|
||||
if 20 <= now.hour <= 8:
|
||||
time.sleep(1)
|
||||
else:
|
||||
time.sleep(3)
|
||||
|
||||
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() # 打印堆栈跟踪信息
|
||||
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('表单已自动提交至下一步')
|
||||
|
||||
Reference in New Issue
Block a user