Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 82c6c5f94a | |||
| 3462c8df55 |
@@ -4,6 +4,9 @@ import pandas as pd
|
||||
from back_ground_module import CommonModule
|
||||
from api import API
|
||||
from log_config import configure_task_logger, configure_error_task_logger
|
||||
from datetime import datetime, timedelta, timezone
|
||||
import pandas as pd
|
||||
import os
|
||||
|
||||
# 获取已经配置好的常规日志记录器
|
||||
logger = configure_task_logger()
|
||||
@@ -24,6 +27,7 @@ class JCBEfficientCarPickup:
|
||||
|
||||
def __init__(self):
|
||||
# 使用 pymysql 连接数据库
|
||||
self.daily_revisit_list = None
|
||||
self.field_mapping = {}
|
||||
self.staff_id_list = None
|
||||
self.customer_service_list = None
|
||||
@@ -108,7 +112,8 @@ class JCBEfficientCarPickup:
|
||||
new_sign_abnormal_data = [self.row_to_dict(row, self.field_mapping) for index, row in
|
||||
df.iterrows()]
|
||||
|
||||
data = {'api_key': Config.EFFICIENT_CAR_PICKUP_APP_ID, 'entry_id': Config.EFFICIENT_CAR_PICKUP_ENTRY_ID,
|
||||
data = {'api_key': Config.EFFICIENT_CAR_PICKUP_APP_ID,
|
||||
'entry_id': Config.EFFICIENT_CAR_PICKUP_ENTRY_ID,
|
||||
"data_list": new_sign_abnormal_data}
|
||||
|
||||
result = api_instance.entry_data_batch_create(data)
|
||||
@@ -137,6 +142,14 @@ class JCBEfficientCarPickup:
|
||||
result2 = api_instance.entry_data_update(data2)
|
||||
logger.info(f"明日派发人员信息已修改:{result2}")
|
||||
|
||||
def load_all_data(self):
|
||||
# 获取接车宝日常回访单
|
||||
payload = {"api_key": "6717470a0b3975ef583c6df1",
|
||||
"entry_id": "67174710da507490d8ac12c1",
|
||||
}
|
||||
daily_revisit = api_instance.entry_data_list(payload)
|
||||
self.daily_revisit_list = daily_revisit.get("data") # api请求格式,将数据封装在data字典里
|
||||
|
||||
def main(self):
|
||||
task_start_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
try:
|
||||
@@ -145,6 +158,7 @@ class JCBEfficientCarPickup:
|
||||
if data_JCB is None:
|
||||
logger.error("获取接车宝数据失败,返回None")
|
||||
raise ValueError("获取接车宝数据失败,返回None")
|
||||
self.load_all_data()
|
||||
|
||||
logger.info(f"数据加载完成")
|
||||
|
||||
@@ -181,6 +195,97 @@ class JCBEfficientCarPickup:
|
||||
else:
|
||||
logger.info(f"新签异常待办回访无数据,跳过")
|
||||
|
||||
# 异常待办
|
||||
current_local = datetime.now() + timedelta(days=-1) # tz-naive,代表本地时间
|
||||
current_date_str = current_local.strftime("%Y-%m-%d")
|
||||
# 计算30天前的本地日期(用于开户日判断)
|
||||
thirty_days_ago_local = (current_local - timedelta(days=30)).date()
|
||||
|
||||
abnormal_data = []
|
||||
for index, row in data_JCB.iterrows():
|
||||
try:
|
||||
# 开户日是本地日期字符串,解析为 date 对象
|
||||
open_date = datetime.strptime(str(row['开户日']), "%Y-%m-%d").date()
|
||||
except (ValueError, TypeError):
|
||||
continue # 跳过无效日期
|
||||
|
||||
if (
|
||||
open_date < thirty_days_ago_local
|
||||
and row['近30天开单天数'] == 0
|
||||
and row['客户状态'] == "留存"
|
||||
):
|
||||
new_row = row.copy()
|
||||
new_row["日期"] = open_date.strftime("%Y-%m-%d")
|
||||
abnormal_data.append(new_row)
|
||||
|
||||
abnormal_data = pd.DataFrame(abnormal_data) if abnormal_data else pd.DataFrame()
|
||||
|
||||
if not abnormal_data.empty:
|
||||
abnormal_data["表单类型"] = "异常待办"
|
||||
abnormal_data["派发日期"] = current_date_str
|
||||
|
||||
# 清洗手机号(仅去除浮点型 .0)
|
||||
def clean_phone(x):
|
||||
if pd.isna(x) or x == "" or x == "None":
|
||||
return ""
|
||||
s = str(x)
|
||||
if s.endswith('.0') and s[:-2].isdigit():
|
||||
return s[:-2]
|
||||
return s
|
||||
|
||||
abnormal_data['联系手机号'] = abnormal_data['联系手机号'].apply(clean_phone)
|
||||
|
||||
# 构建云端已派发记录 DataFrame
|
||||
df_cloud = pd.DataFrame([
|
||||
{
|
||||
"数据id": item.get("_id", ""),
|
||||
"账号": item.get("_widget_1739258942667", ""),
|
||||
"提交时间": item.get("createTime", ""),
|
||||
"表单类型": item.get("_widget_1739951204545", "")
|
||||
}
|
||||
for item in self.daily_revisit_list
|
||||
])
|
||||
|
||||
recent_accounts = set()
|
||||
if not df_cloud.empty and not abnormal_data.empty:
|
||||
# 将 createTime 转为 UTC 时间(强制统一时区)
|
||||
df_cloud["提交时间"] = pd.to_datetime(df_cloud["提交时间"], utc=True, errors="coerce")
|
||||
df_cloud = df_cloud.dropna(subset=["提交时间"])
|
||||
|
||||
# 筛选“异常待办”
|
||||
df_abnormal_cloud = df_cloud[df_cloud["表单类型"] == "异常待办"]
|
||||
|
||||
if not df_abnormal_cloud.empty:
|
||||
# 每个账号保留最新一条
|
||||
df_recent = df_abnormal_cloud.sort_values("提交时间").groupby("账号", as_index=False).tail(1)
|
||||
|
||||
current_utc = datetime.now(timezone.utc)
|
||||
cutoff_utc = pd.Timestamp(current_utc) - pd.Timedelta(days=30)
|
||||
|
||||
# 安全比较:两边都是 UTC
|
||||
recent_accounts = set(df_recent[df_recent["提交时间"] > cutoff_utc]["账号"])
|
||||
|
||||
# 剔除已派发账号 + 过滤有效手机号
|
||||
if not abnormal_data.empty:
|
||||
abnormal_data = abnormal_data[
|
||||
(~abnormal_data["账号"].isin(recent_accounts)) &
|
||||
(abnormal_data["联系手机号"].notna()) &
|
||||
(abnormal_data["联系手机号"] != "") &
|
||||
(abnormal_data["联系手机号"] != "None")
|
||||
]
|
||||
|
||||
# # 保存结果
|
||||
output_path = os.path.join(output_dir, "异常待办1.csv")
|
||||
abnormal_data.to_csv(output_path, index=False)
|
||||
|
||||
# 发送或跳过
|
||||
if not abnormal_data.empty:
|
||||
abnormal_data = abnormal_data[:20]
|
||||
self.send_request(abnormal_data)
|
||||
logger.info(f"异常待办完成,共 {len(abnormal_data)} 条")
|
||||
else:
|
||||
logger.info("异常待办无数据,跳过")
|
||||
|
||||
# 优质客户转商机
|
||||
# current_date = datetime.now()
|
||||
thirty_days_ago = current_date - timedelta(days=30)
|
||||
|
||||
@@ -274,7 +274,7 @@ class CommonModule:
|
||||
else: # 如果没有数据,返回空 DataFrame
|
||||
data_NGV = pd.DataFrame()
|
||||
headers = [
|
||||
"门店编码", "类型", "占位", "价格"
|
||||
"门店编码", "类型", "订单商品名称", "价格"
|
||||
]
|
||||
|
||||
data_NGV.columns = headers
|
||||
|
||||
+9252
File diff suppressed because one or more lines are too long
@@ -112,7 +112,9 @@ class JCBEfficientCarPickup:
|
||||
new_sign_abnormal_data = [self.row_to_dict(row, self.field_mapping) for index, row in
|
||||
df.iterrows()]
|
||||
|
||||
data = {'api_key': Config.EFFICIENT_CAR_PICKUP_APP_ID, 'entry_id': Config.EFFICIENT_CAR_PICKUP_ENTRY_ID,
|
||||
data = {'api_key': Config.EFFICIENT_CAR_PICKUP_APP_ID,
|
||||
# 'entry_id': "69522f61d0195d3bf42ed251",
|
||||
'entry_id': Config.EFFICIENT_CAR_PICKUP_ENTRY_ID,
|
||||
"data_list": new_sign_abnormal_data}
|
||||
|
||||
result = api_instance.entry_data_batch_create(data)
|
||||
@@ -189,7 +191,7 @@ class JCBEfficientCarPickup:
|
||||
if new_sign_abnormal is not None and not new_sign_abnormal.empty:
|
||||
new_sign_abnormal["表单类型"] = "新签异常待办"
|
||||
new_sign_abnormal["派发日期"] = current_date_str
|
||||
# self.send_request(new_sign_abnormal) # 发送请求
|
||||
self.send_request(new_sign_abnormal) # 发送请求
|
||||
logger.info(f"新签异常待办回访完成")
|
||||
else:
|
||||
logger.info(f"新签异常待办回访无数据,跳过")
|
||||
@@ -279,8 +281,8 @@ class JCBEfficientCarPickup:
|
||||
|
||||
# 发送或跳过
|
||||
if not abnormal_data.empty:
|
||||
abnormal_data = abnormal_data[:40]
|
||||
# self.send_request(abnormal_data)
|
||||
abnormal_data = abnormal_data[:20]
|
||||
self.send_request(abnormal_data)
|
||||
logger.info(f"异常待办完成,共 {len(abnormal_data)} 条")
|
||||
else:
|
||||
logger.info("异常待办无数据,跳过")
|
||||
@@ -317,7 +319,7 @@ class JCBEfficientCarPickup:
|
||||
if customer_to_opportunity is not None and not customer_to_opportunity.empty:
|
||||
customer_to_opportunity["表单类型"] = "续约优质客户转商机"
|
||||
customer_to_opportunity["派发日期"] = current_date_str
|
||||
# self.send_request(customer_to_opportunity)
|
||||
self.send_request(customer_to_opportunity)
|
||||
logger.info(f"优质客户转商机完成")
|
||||
else:
|
||||
logger.info(f"优质客户转商机无数据,跳过")
|
||||
@@ -344,7 +346,7 @@ class JCBEfficientCarPickup:
|
||||
if outdated_30 is not None and not outdated_30.empty:
|
||||
outdated_30["表单类型"] = "过期7天回访"
|
||||
outdated_30["派发日期"] = current_date_str
|
||||
# self.send_request(outdated_30)
|
||||
self.send_request(outdated_30)
|
||||
logger.info(f"过期7天客服回访完成")
|
||||
else:
|
||||
logger.info(f"过期7天客服回访无数据,跳过")
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"id": "initial_id",
|
||||
"metadata": {
|
||||
"collapsed": true,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2025-12-17T08:57:05.953495Z",
|
||||
"start_time": "2025-12-17T08:57:05.580269Z"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"import pandas as pd\n",
|
||||
"import mysql.connector\n",
|
||||
"from mysql.connector import Error\n",
|
||||
"\n",
|
||||
"# 连接信息\n",
|
||||
"HS_DB_Config = {\n",
|
||||
" 'host': \"f6-public.rwlb.rds.aliyuncs.com\",\n",
|
||||
" 'user': \"rw_operation_data_relay\",\n",
|
||||
" 'password': \"m+q5Z4%IVuF9bf\",\n",
|
||||
" 'database': \"f6operation_data_relay\"\n",
|
||||
" } # 衡时数据库链接配置-mysql\n",
|
||||
"table_name = \"saas_period_product_fenmu\" # 请替换为实际的表名\n",
|
||||
"# table_name = \"yida_process_time_statistics\"\n",
|
||||
"\n",
|
||||
"# 连接\n",
|
||||
"connection = mysql.connector.connect(\n",
|
||||
" host=HS_DB_Config[\"host\"],\n",
|
||||
" user=HS_DB_Config[\"user\"],\n",
|
||||
" password=HS_DB_Config[\"password\"],\n",
|
||||
" database=HS_DB_Config[\"database\"]\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(f\"成功连接 {HS_DB_Config['database']}\")\n",
|
||||
"cursor = connection.cursor()\n",
|
||||
"\n",
|
||||
"# 读取Excel文件\n",
|
||||
"df = pd.read_excel(\n",
|
||||
" r\"C:\\Users\\zy187\\Desktop\\应续约信息-商户与商品-数据表格.xlsx\",\n",
|
||||
" sheet_name=\"Sheet1\")\n",
|
||||
"\n",
|
||||
"# 处理空值 - 将NaN/NaT/空字符串统一转为None\n",
|
||||
"df = df.map(lambda x: None if pd.isna(x) or str(x).strip() == '' else x)\n",
|
||||
"\n",
|
||||
"# 生成插入语句\n",
|
||||
"columns = ', '.join(df.columns)\n",
|
||||
"placeholders = ', '.join(['%s'] * len(df.columns))\n",
|
||||
"insert_query = f\"INSERT INTO {table_name} ({columns}) VALUES ({placeholders})\"\n",
|
||||
"\n",
|
||||
"# 批量插入数据,每次1000条\n",
|
||||
"records = [tuple(row) for row in df.values]\n",
|
||||
"batch_size = 1000\n",
|
||||
"total_records = len(records)\n",
|
||||
"inserted_count = 0\n",
|
||||
"\n",
|
||||
"for i in range(0, total_records, batch_size):\n",
|
||||
" batch = records[i:i+batch_size]\n",
|
||||
" cursor.executemany(insert_query, batch)\n",
|
||||
" connection.commit()\n",
|
||||
" inserted_count += len(batch)\n",
|
||||
" print(f\"已成功导入 {inserted_count}/{total_records} 条记录\")\n",
|
||||
"\n",
|
||||
"print(f\"总共成功导入 {inserted_count} 条记录到 {table_name} 表\")\n",
|
||||
"\n",
|
||||
"cursor.close()\n",
|
||||
"connection.close()"
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"成功连接 f6operation_data_relay\n",
|
||||
"已成功导入 6/6 条记录\n",
|
||||
"总共成功导入 6 条记录到 saas_period_product_fenmu 表\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 3
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 2
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython2",
|
||||
"version": "2.7.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"id": "initial_id",
|
||||
"metadata": {
|
||||
"collapsed": true,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2025-12-25T06:14:43.010877600Z",
|
||||
"start_time": "2025-12-25T06:14:42.705835200Z"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"import json\n",
|
||||
"import requests\n",
|
||||
"\n",
|
||||
"triggerConf = {\n",
|
||||
"\"_widget_17666295456371\": \"675b900991ad2491c69389ca\",\n",
|
||||
"\"_widget_17666295463651\": \"6931063d64187eaf6b927557\",\n",
|
||||
"\"_widget_17666295471001\": \"694caec6d3f22e2e1723b776\",\n",
|
||||
"\"_widget_17666325849471\": \"11240984669918342117\",\n",
|
||||
"\"_widget_17666340965771\": \"新起点养车维修\"\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# 获取输入参数(带默认空字符串)\n",
|
||||
"api_key = str(triggerConf.get('_widget_17666295456371', '')).strip()\n",
|
||||
"entry_id = str(triggerConf.get('_widget_17666295463651', '')).strip()\n",
|
||||
"data_id = str(triggerConf.get('_widget_17666295471001', '')).strip()\n",
|
||||
"company_id = str(triggerConf.get('_widget_17666325849471', '')).strip()\n",
|
||||
"org_str = triggerConf.get('_widget_17666340965771', '')\n",
|
||||
"\n",
|
||||
"# 安全校验:必要参数不能为空\n",
|
||||
"if not all([api_key, entry_id, data_id, company_id]):\n",
|
||||
" raise ValueError(\"缺少必要参数:应用ID、表单ID、数据ID 或 公司ID 不能为空\")\n",
|
||||
"\n",
|
||||
"# 解析连锁店列表\n",
|
||||
"org_list = []\n",
|
||||
"if org_str:\n",
|
||||
" if isinstance(org_str, str):\n",
|
||||
" org_list = [item.strip() for item in org_str.split(',') if item.strip()]\n",
|
||||
" elif isinstance(org_str, list):\n",
|
||||
" org_list = [str(item).strip() for item in org_str if str(item).strip()]\n",
|
||||
"\n",
|
||||
"# 请求头\n",
|
||||
"BEARER_TOKEN = \"qygHulymo1fekJk4CIZyNKjyQAzG8CFN\"\n",
|
||||
"headers = {\n",
|
||||
" 'Authorization': f'Bearer {BEARER_TOKEN}',\n",
|
||||
" 'Content-Type': 'application/json'\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# 第一步:获取当前触发数据的内容\n",
|
||||
"data_payload = {\n",
|
||||
" \"app_id\": api_key,\n",
|
||||
" \"entry_id\": entry_id,\n",
|
||||
" \"data_id\": data_id\n",
|
||||
"}\n",
|
||||
"trigger_data_url = \"https://api.jiandaoyun.com/api/v5/app/entry/data/get\"\n",
|
||||
"try:\n",
|
||||
" data_response = requests.post(trigger_data_url, headers=headers, data=json.dumps(data_payload), timeout=10)\n",
|
||||
" data_response.raise_for_status()\n",
|
||||
" data_resp_json = data_response.json()\n",
|
||||
" trigger_data = data_resp_json.get(\"data\", {})\n",
|
||||
" if not trigger_data:\n",
|
||||
" raise ValueError(\"未能获取到当前数据内容\")\n",
|
||||
"except Exception as e:\n",
|
||||
" raise RuntimeError(f\"获取当前数据失败: {str(e)}\")\n",
|
||||
"\n",
|
||||
"# 第二步:查询该公司下所有进行中的数据\n",
|
||||
"url = \"https://api.jiandaoyun.com/api/v5/app/entry/data/list\"\n",
|
||||
"payload = {\n",
|
||||
" \"app_id\": api_key,\n",
|
||||
" \"entry_id\": entry_id,\n",
|
||||
" \"filter\": {\n",
|
||||
" \"rel\": \"and\",\n",
|
||||
" \"cond\": [\n",
|
||||
" {\"field\": \"_widget_1766631811839\", \"type\": \"text\", \"method\": \"eq\", \"value\": company_id},\n",
|
||||
" {\"field\": \"flowState\", \"type\": \"flowstate\", \"method\": \"eq\", \"value\": [0]}\n",
|
||||
" ]\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"try:\n",
|
||||
" response = requests.post(url, headers=headers, json=payload, timeout=10)\n",
|
||||
" resp_json = response.json()\n",
|
||||
" data_list = resp_json.get(\"data\", [])\n",
|
||||
"except Exception as e:\n",
|
||||
" raise RuntimeError(f\"查询进行中数据失败: {str(e)}\")\n",
|
||||
"\n",
|
||||
"# # 要同步的字段映射(目标字段ID -> 触发数据中的源字段ID)\n",
|
||||
"# field_mapping = {\n",
|
||||
"# \"_widget_1764820541638\": \"_widget_1764820541638\", # 是否联系上\n",
|
||||
"# \"_widget_1764820541641\": \"_widget_1764820541641\", # 现阶段问题\n",
|
||||
"# \"_widget_1765330820509\": \"_widget_1765330820509\", # 未联系原因\n",
|
||||
"# \"_widget_1764820541653\": \"_widget_1764820541653\", # 联系情况及问题说明\n",
|
||||
"# \"_widget_1764820541697\": \"_widget_1764820541697\", # 回访方式\n",
|
||||
"# \"_widget_1764820541657\": \"_widget_1764820541657\", # 潜在商机\n",
|
||||
"# \"_widget_1764820541659\": \"_widget_1764820541659\", # 商机详情\n",
|
||||
"# \"_widget_1764820541654\": \"_widget_1764820541654\", # 续约意愿\n",
|
||||
"# \"_widget_1764820541700\": \"_widget_1764820541700\", # 不续约原因\n",
|
||||
"# \"_widget_1764820541707\": \"_widget_1764820541707\", # 产品原因\n",
|
||||
"# \"_widget_1764820541709\": \"_widget_1764820541709\", # 服务问题\n",
|
||||
"# \"_widget_1764820541711\": \"_widget_1764820541711\", # 门店原因\n",
|
||||
"# \"_widget_1764820541713\": \"_widget_1764820541713\", # 价格原因\n",
|
||||
"# \"_widget_1764820541702\": \"_widget_1764820541702\", # 不续约具体情况说明\n",
|
||||
"# }\n",
|
||||
"#\n",
|
||||
"# # 遍历匹配的连锁店数据\n",
|
||||
"# for data in data_list:\n",
|
||||
"# store_code = data.get(\"_widget_1764820541617\")\n",
|
||||
"# if not store_code or store_code not in org_list:\n",
|
||||
"# continue\n",
|
||||
"#\n",
|
||||
"# new_data_id = data.get(\"_id\")\n",
|
||||
"# if not new_data_id:\n",
|
||||
"# continue\n",
|
||||
"#\n",
|
||||
"# # 构建更新 payload(仅包含非 None 值)\n",
|
||||
"# update_data = {}\n",
|
||||
"# for target_field, source_field in field_mapping.items():\n",
|
||||
"# value = trigger_data.get(source_field)\n",
|
||||
"# # 如果值为 None 或空字符串(根据业务决定是否跳过)\n",
|
||||
"# if value is not None:\n",
|
||||
"# update_data[target_field] = {\"value\": value}\n",
|
||||
"#\n",
|
||||
"# if not update_data:\n",
|
||||
"# continue # 无有效字段可更新\n",
|
||||
"#\n",
|
||||
"# modify_payload = {\n",
|
||||
"# \"app_id\": api_key,\n",
|
||||
"# \"entry_id\": entry_id,\n",
|
||||
"# \"data_id\": new_data_id,\n",
|
||||
"# \"data\": update_data\n",
|
||||
"# }\n",
|
||||
"#\n",
|
||||
"# # 同步字段\n",
|
||||
"# try:\n",
|
||||
"# modif_url = \"https://api.jiandaoyun.com/api/v5/app/entry/data/update\"\n",
|
||||
"# res = requests.post(modif_url, headers=headers, data=json.dumps(modify_payload), timeout=10)\n",
|
||||
"# res.raise_for_status()\n",
|
||||
"# except Exception as e:\n",
|
||||
"# print(f\"更新数据 {new_data_id} 失败: {e}\")\n",
|
||||
"# continue # 继续处理下一个,不中断\n",
|
||||
"#\n",
|
||||
"# # 第三步:尝试自动审批(仅当处于指定节点)\n",
|
||||
"# try:\n",
|
||||
"# instance_url = \"https://api.jiandaoyun.com/api/v6/workflow/instance/get\"\n",
|
||||
"# instance_payload = {\n",
|
||||
"# \"instance_id\": new_data_id,\n",
|
||||
"# \"tasks_type\": 1\n",
|
||||
"# }\n",
|
||||
"# instance_res = requests.post(instance_url, headers=headers, data=json.dumps(instance_payload), timeout=10)\n",
|
||||
"# instance_res.raise_for_status()\n",
|
||||
"# instance_data = instance_res.json()\n",
|
||||
"# tasks = instance_data.get(\"tasks\", [])\n",
|
||||
"#\n",
|
||||
"# if not tasks:\n",
|
||||
"# continue\n",
|
||||
"#\n",
|
||||
"# last_task = tasks[-1]\n",
|
||||
"# flow_id = last_task.get(\"flow_id\")\n",
|
||||
"# task_id = last_task.get(\"task_id\")\n",
|
||||
"# assignee_info = last_task.get(\"assignee\") or {}\n",
|
||||
"# username = assignee_info.get(\"username\")\n",
|
||||
"#\n",
|
||||
"# if flow_id in [1, 2, 3, 9] and task_id and username:\n",
|
||||
"# allow_url = \"https://api.jiandaoyun.com/api/v1/workflow/task/approve\"\n",
|
||||
"# allow_payload = {\n",
|
||||
"# \"username\": username,\n",
|
||||
"# \"instance_id\": new_data_id,\n",
|
||||
"# \"task_id\": task_id\n",
|
||||
"# }\n",
|
||||
"# allo_result = requests.post(allow_url, headers=headers, data=json.dumps(allow_payload), timeout=10)\n",
|
||||
"# allo_result.raise_for_status()\n",
|
||||
"# print(f\"自动审批成功: data_id={new_data_id}, task_id={task_id}\")\n",
|
||||
"# else:\n",
|
||||
"# print(f\"跳过自动审批: flow_id={flow_id}, task_id={task_id}, username={username}\")\n",
|
||||
"#\n",
|
||||
"# except Exception as e:\n",
|
||||
"# print(f\"自动审批失败 (data_id={new_data_id}): {e}\")\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"execution_count": 8
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2025-12-25T06:14:45.807079300Z",
|
||||
"start_time": "2025-12-25T06:14:45.761404700Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": "resp_json",
|
||||
"id": "d4299d8a0596e5f8",
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'data': [{'_id': '694caec6d3f22e2e1723b775',\n",
|
||||
" 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0},\n",
|
||||
" 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0},\n",
|
||||
" 'deleter': None,\n",
|
||||
" 'createTime': '2025-12-25T03:25:58.151Z',\n",
|
||||
" 'updateTime': '2025-12-25T05:57:01.097Z',\n",
|
||||
" 'deleteTime': None,\n",
|
||||
" 'flowState': 0,\n",
|
||||
" '_widget_1764820541663': '680f49b134bee97fbb857ef1',\n",
|
||||
" '_widget_1764820541616': '新起点养车',\n",
|
||||
" '_widget_1764820541617': '新起点养车维修',\n",
|
||||
" '_widget_1764820541661': 'CHS202411050285054',\n",
|
||||
" '_widget_1764820541618': '',\n",
|
||||
" '_widget_1764820541672': '2026-04-23T16:00:00.000Z',\n",
|
||||
" '_widget_1764820541623': '基础版',\n",
|
||||
" '_widget_1764820541624': 'SaaS新签:999',\n",
|
||||
" '_widget_1764820541621': '王旭',\n",
|
||||
" '_widget_1764820541622': '19819386119',\n",
|
||||
" '_widget_1764820541625': {'name': '邵宝振',\n",
|
||||
" 'username': '032861373036352679',\n",
|
||||
" 'status': 1,\n",
|
||||
" 'type': 0,\n",
|
||||
" 'departments': [122333676],\n",
|
||||
" 'integrate_id': '032861373036352679'},\n",
|
||||
" '_widget_1766631811839': '11240984669918342117',\n",
|
||||
" '_widget_1764820541628': '',\n",
|
||||
" '_widget_1764820541634': None,\n",
|
||||
" '_widget_1765352838631': None,\n",
|
||||
" '_widget_1764820541630': '',\n",
|
||||
" '_widget_1764820541635': None,\n",
|
||||
" '_widget_1765352838632': None,\n",
|
||||
" '_widget_1764820541632': '',\n",
|
||||
" '_widget_1764820541636': None,\n",
|
||||
" '_widget_1765352838633': None,\n",
|
||||
" '_widget_1764820541638': '',\n",
|
||||
" '_widget_1764820541641': '',\n",
|
||||
" '_widget_1765330820509': '',\n",
|
||||
" '_widget_1764820541653': '',\n",
|
||||
" '_widget_1764820541697': '',\n",
|
||||
" '_widget_1764820541657': '',\n",
|
||||
" '_widget_1764820541659': '',\n",
|
||||
" '_widget_1764820541654': '',\n",
|
||||
" '_widget_1764820541700': '',\n",
|
||||
" '_widget_1764820541707': '',\n",
|
||||
" '_widget_1764820541709': '',\n",
|
||||
" '_widget_1764820541711': '',\n",
|
||||
" '_widget_1764820541713': '',\n",
|
||||
" '_widget_1764820541702': '',\n",
|
||||
" '_widget_1764820541717': [],\n",
|
||||
" '_widget_1764820541681': '',\n",
|
||||
" '_widget_1765330820391': [],\n",
|
||||
" '_widget_1764820541674': '',\n",
|
||||
" '_widget_1764820541679': None,\n",
|
||||
" '_widget_1764820541676': '',\n",
|
||||
" '_widget_1764820541680': '',\n",
|
||||
" '_widget_1764820541865': '2026-02-22T16:00:00.000Z',\n",
|
||||
" '_widget_1765964381895': '2026-03-24T16:00:00.000Z',\n",
|
||||
" '_widget_1765964381896': '2026-04-23T16:00:00.000Z',\n",
|
||||
" '_widget_1765964381897': '2026-07-22T16:00:00.000Z',\n",
|
||||
" '_widget_1765352838609': '',\n",
|
||||
" '_widget_1765352838610': '',\n",
|
||||
" '_widget_1765964381952': '单店',\n",
|
||||
" '_widget_1765866283543': '',\n",
|
||||
" '_widget_1764820541715': {'name': '申晓勇',\n",
|
||||
" 'username': '171201105229666119',\n",
|
||||
" 'status': 1,\n",
|
||||
" 'type': 0,\n",
|
||||
" 'departments': [177751223],\n",
|
||||
" 'integrate_id': '171201105229666119'},\n",
|
||||
" '_widget_1766130435561': '普通客户(VIP)',\n",
|
||||
" '_widget_1764820541678': {'name': '王斌',\n",
|
||||
" 'username': '1253235059942945',\n",
|
||||
" 'status': 1,\n",
|
||||
" 'type': 0,\n",
|
||||
" 'departments': [122333676],\n",
|
||||
" 'integrate_id': '1253235059942945'},\n",
|
||||
" '_widget_1766376046563': '00059',\n",
|
||||
" '_widget_1766469131897': '否',\n",
|
||||
" '_widget_1766633812134': '',\n",
|
||||
" 'appId': '675b900991ad2491c69389ca',\n",
|
||||
" 'entryId': '6931063d64187eaf6b927557'},\n",
|
||||
" {'_id': '694caec6d3f22e2e1723b776',\n",
|
||||
" 'creator': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0},\n",
|
||||
" 'updater': {'name': 'F6汽车科技', 'username': '#admin', 'status': 1, 'type': 0},\n",
|
||||
" 'deleter': None,\n",
|
||||
" 'createTime': '2025-12-25T03:25:58.151Z',\n",
|
||||
" 'updateTime': '2025-12-25T05:58:40.218Z',\n",
|
||||
" 'deleteTime': None,\n",
|
||||
" 'flowState': 0,\n",
|
||||
" '_widget_1764820541663': '680f48b90a8a958979d7a2d3',\n",
|
||||
" '_widget_1764820541616': '武陵区隆铖改汽车俱乐部',\n",
|
||||
" '_widget_1764820541617': '武陵区隆铖改汽车俱乐部',\n",
|
||||
" '_widget_1764820541661': 'CHS202504240297172',\n",
|
||||
" '_widget_1764820541618': '',\n",
|
||||
" '_widget_1764820541672': '2026-04-23T16:00:00.000Z',\n",
|
||||
" '_widget_1764820541623': '进阶版',\n",
|
||||
" '_widget_1764820541624': 'SaaS新签:1199',\n",
|
||||
" '_widget_1764820541621': '朱松松',\n",
|
||||
" '_widget_1764820541622': '18932158817',\n",
|
||||
" '_widget_1764820541625': {'name': '胡冰',\n",
|
||||
" 'username': '19212436541043695',\n",
|
||||
" 'status': 1,\n",
|
||||
" 'type': 0,\n",
|
||||
" 'departments': [122503482],\n",
|
||||
" 'integrate_id': '19212436541043695'},\n",
|
||||
" '_widget_1766631811839': '11240984669918342117',\n",
|
||||
" '_widget_1764820541628': '主动',\n",
|
||||
" '_widget_1764820541634': None,\n",
|
||||
" '_widget_1765352838631': None,\n",
|
||||
" '_widget_1764820541630': '主动',\n",
|
||||
" '_widget_1764820541635': None,\n",
|
||||
" '_widget_1765352838632': None,\n",
|
||||
" '_widget_1764820541632': '主动',\n",
|
||||
" '_widget_1764820541636': None,\n",
|
||||
" '_widget_1765352838633': None,\n",
|
||||
" '_widget_1764820541638': '否',\n",
|
||||
" '_widget_1764820541641': '',\n",
|
||||
" '_widget_1765330820509': '空号/停机/关机',\n",
|
||||
" '_widget_1764820541653': '234',\n",
|
||||
" '_widget_1764820541697': 'udesk外呼',\n",
|
||||
" '_widget_1764820541657': '',\n",
|
||||
" '_widget_1764820541659': '',\n",
|
||||
" '_widget_1764820541654': '否',\n",
|
||||
" '_widget_1764820541700': '服务问题',\n",
|
||||
" '_widget_1764820541707': '',\n",
|
||||
" '_widget_1764820541709': '联系不上运营顾问',\n",
|
||||
" '_widget_1764820541711': '',\n",
|
||||
" '_widget_1764820541713': '',\n",
|
||||
" '_widget_1764820541702': '',\n",
|
||||
" '_widget_1764820541717': [],\n",
|
||||
" '_widget_1764820541681': '是',\n",
|
||||
" '_widget_1765330820391': [],\n",
|
||||
" '_widget_1764820541674': '',\n",
|
||||
" '_widget_1764820541679': None,\n",
|
||||
" '_widget_1764820541676': '',\n",
|
||||
" '_widget_1764820541680': '',\n",
|
||||
" '_widget_1764820541865': '2026-02-22T16:00:00.000Z',\n",
|
||||
" '_widget_1765964381895': '2026-03-24T16:00:00.000Z',\n",
|
||||
" '_widget_1765964381896': '2026-04-23T16:00:00.000Z',\n",
|
||||
" '_widget_1765964381897': '2026-07-22T16:00:00.000Z',\n",
|
||||
" '_widget_1765352838609': '',\n",
|
||||
" '_widget_1765352838610': '',\n",
|
||||
" '_widget_1765964381952': '单店',\n",
|
||||
" '_widget_1765866283543': '',\n",
|
||||
" '_widget_1764820541715': {'name': '孙海程',\n",
|
||||
" 'username': '084119070623372941',\n",
|
||||
" 'status': 1,\n",
|
||||
" 'type': 0,\n",
|
||||
" 'departments': [177751223],\n",
|
||||
" 'integrate_id': '084119070623372941'},\n",
|
||||
" '_widget_1766130435561': '普通客户(VIP)',\n",
|
||||
" '_widget_1764820541678': {'name': '金华斌',\n",
|
||||
" 'username': '3704680936560271',\n",
|
||||
" 'status': 1,\n",
|
||||
" 'type': 0,\n",
|
||||
" 'departments': [122503482],\n",
|
||||
" 'integrate_id': '3704680936560271'},\n",
|
||||
" '_widget_1766376046563': '00060',\n",
|
||||
" '_widget_1766469131897': '否',\n",
|
||||
" '_widget_1766633812134': '',\n",
|
||||
" 'appId': '675b900991ad2491c69389ca',\n",
|
||||
" 'entryId': '6931063d64187eaf6b927557'}]}"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"execution_count": 9
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 2
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython2",
|
||||
"version": "2.7.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
+28
-12
@@ -85,6 +85,7 @@ class RenewalToDo:
|
||||
"经营模式": "_widget_1765964381952",
|
||||
"公司等级": "_widget_1766130435561",
|
||||
"公司id": "_widget_1766631811839",
|
||||
"订单商品名称":"_widget_1766730385209",
|
||||
"提交人": "creator",
|
||||
"提交时间": "createTime",
|
||||
"更新时间": "updateTime"
|
||||
@@ -346,9 +347,9 @@ class RenewalToDo:
|
||||
data_NGV['30天自动流转时间'] = data_NGV['过期日'] - pd.Timedelta(days=0)
|
||||
data_NGV['0天自动流转时间'] = data_NGV['过期日'] + pd.Timedelta(days=90)
|
||||
|
||||
data_NGV['120天是否跟进'] = "自动"
|
||||
data_NGV['60天是否跟进']= "自动"
|
||||
data_NGV['30天是否跟进']= "自动"
|
||||
data_NGV['120天是否跟进'] = "主动"
|
||||
data_NGV['60天是否跟进']= "主动"
|
||||
data_NGV['30天是否跟进']= "主动"
|
||||
# 格式化为字符串(去掉时区)
|
||||
for col in ['过期日', '120天自动流转时间', '60天自动流转时间', '30天自动流转时间', '0天自动流转时间']:
|
||||
data_NGV[col] = data_NGV[col].dt.strftime('%Y-%m-%d %H:%M:%S')
|
||||
@@ -361,24 +362,39 @@ class RenewalToDo:
|
||||
)
|
||||
|
||||
# 新增上次购买价格列
|
||||
# 1. 清洗并拼接类型+价格
|
||||
df_lp = self.last_price[['门店编码', '类型', '价格']].copy()
|
||||
# 1. 清洗数据
|
||||
df_lp = self.last_price[['门店编码', '类型', '订单商品名称', '价格']].copy()
|
||||
|
||||
# 处理“类型”和“订单商品名称”的缺失值
|
||||
df_lp['类型'] = df_lp['类型'].fillna('').astype(str)
|
||||
df_lp['订单商品名称'] = df_lp['订单商品名称'].fillna('').astype(str)
|
||||
|
||||
# 处理价格:转数字、四舍五入、填0、转字符串
|
||||
df_lp['价格'] = (
|
||||
pd.to_numeric(df_lp['价格'], errors='coerce')
|
||||
.round().fillna(0).astype(int).astype(str)
|
||||
)
|
||||
|
||||
# 2. 拼接“类型:价格”
|
||||
df_lp['类型_价格'] = df_lp['类型'] + ':' + df_lp['价格']
|
||||
|
||||
# 2. 按门店聚合,分号连接
|
||||
agg_df = df_lp.groupby('门店编码', as_index=False)['类型_价格'].apply(';'.join)
|
||||
# 3. 按门店聚合两列
|
||||
agg_df = df_lp.groupby('门店编码', as_index=False).agg({
|
||||
'类型_价格': lambda x: ';'.join(x),
|
||||
'订单商品名称': lambda x: ';'.join(x)
|
||||
})
|
||||
|
||||
# 3. 合并回主表
|
||||
data_NGV = data_NGV.merge(agg_df, on='门店编码', how='left').fillna({'类型_价格': ''})
|
||||
data_NGV.rename(columns={'类型_价格': '上次购买价格'}, inplace=True)
|
||||
# 4. 合并回主表
|
||||
data_NGV = data_NGV.merge(agg_df, on='门店编码', how='left')
|
||||
|
||||
# 4. 处理没有匹配记录的门店(填空或默认值)
|
||||
data_NGV['上次购买价格'] = data_NGV['上次购买价格'].fillna('')
|
||||
# 5. 填充缺失值为空字符串,并重命名列
|
||||
data_NGV['类型_价格'] = data_NGV['类型_价格'].fillna('')
|
||||
data_NGV['订单商品名称'] = data_NGV['订单商品名称'].fillna('')
|
||||
|
||||
data_NGV.rename(columns={
|
||||
'类型_价格': '上次购买价格',
|
||||
'订单商品名称': '订单商品名称'
|
||||
}, inplace=True)
|
||||
|
||||
# 成员字段替换(现在列名是中文)
|
||||
staff_name_cols = [
|
||||
|
||||
Reference in New Issue
Block a user