异常待办时间更改

This commit is contained in:
2026-04-02 09:09:28 +08:00
parent 8e57195033
commit 976753d3c0
6 changed files with 12438 additions and 25 deletions
+44 -12
View File
@@ -353,13 +353,29 @@ class NewExceptionTask:
if stop_date:
# 解析暂停派发日期
parsed_stop_date = None
for fmt in date_formats:
stop_value = stop_date.get("value") if isinstance(stop_date, dict) else stop_date
if isinstance(stop_value, (int, float)):
parsed_stop_date = datetime.datetime.fromtimestamp(
stop_value / 1000, tz=datetime.timezone.utc
).replace(tzinfo=None)
elif isinstance(stop_value, str):
stop_str = stop_value.strip()
iso_candidate = stop_str[:-1] + "+00:00" if stop_str.endswith("Z") else stop_str
try:
parsed_stop_date = datetime.datetime.strptime(stop_date.strip(), fmt)
logger.debug(f"使用格式 {fmt} 成功解析暂停派发日期: {parsed_stop_date}")
break
iso_dt = datetime.datetime.fromisoformat(iso_candidate)
except ValueError:
continue
iso_dt = None
if iso_dt is not None:
parsed_stop_date = iso_dt.astimezone(datetime.timezone.utc).replace(tzinfo=None) if iso_dt.tzinfo else iso_dt
else:
for fmt in date_formats:
try:
parsed_stop_date = datetime.datetime.strptime(stop_str, fmt)
logger.debug(f"使用格式 {fmt} 成功解析暂停派发日期: {parsed_stop_date}")
break
except ValueError:
continue
if parsed_stop_date:
# 获取当前UTC时间
@@ -380,21 +396,37 @@ class NewExceptionTask:
if create_exception == "":
continue
# 新增:检查 create_date_str 是否存在且有效
if not create_date:
create_date_value = create_date.get("value") if isinstance(create_date, dict) else create_date
if not create_date_value:
logger.warning("上线日期为空,跳过该记录")
continue
parsed_date = None
for fmt in date_formats:
if isinstance(create_date_value, (int, float)):
local_tz = datetime.timezone(datetime.timedelta(hours=8))
parsed_date = datetime.datetime.fromtimestamp(create_date_value / 1000, tz=local_tz).date()
elif isinstance(create_date_value, str):
create_str = create_date_value.strip()
iso_candidate = create_str[:-1] + "+00:00" if create_str.endswith("Z") else create_str
try:
parsed_date = datetime.datetime.strptime(create_date.strip(), fmt).date()
logger.debug(f"使用格式 {fmt} 成功解析日期: {parsed_date}")
break
iso_dt = datetime.datetime.fromisoformat(iso_candidate)
except ValueError:
continue
iso_dt = None
if iso_dt is not None:
local_tz = datetime.timezone(datetime.timedelta(hours=8))
parsed_date = iso_dt.date() if iso_dt.tzinfo is None else iso_dt.astimezone(local_tz).date()
else:
for fmt in date_formats:
try:
parsed_date = datetime.datetime.strptime(create_str, fmt).date()
logger.debug(f"使用格式 {fmt} 成功解析日期: {parsed_date}")
break
except ValueError:
continue
if parsed_date is None:
logger.error(f"无法解析上线日期: '{create_date}',支持的格式: %Y-%m-%d, %Y-%m-%d %H:%M:%S 等")
logger.error(f"无法解析上线日期: '{create_date_value}',支持的格式: %Y-%m-%d, %Y-%m-%d %H:%M:%S 等")
continue # 解析失败,跳过
# 使用解析后的日期进行判断
+96
View File
@@ -2605,3 +2605,99 @@ Traceback (most recent call last):
form = data.get("formData")
^^^^
NameError: name 'data' is not defined
2026-04-01 14:23:45,579 - log_config.py - error_task_logger - ERROR - 异常服务待办派发执行时发生异常: 'str' object has no attribute 'get'
Traceback (most recent call last):
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 475, in main
customer_service = self.assign_customer_service(province_name, city_name, area_name, self.index)
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 227, in assign_customer_service
customer_service = customer_service_info.get('_widget_1734677164870', {}).get('username') # 异常回访客服
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
2026-04-01 14:23:49,233 - log_config.py - error_task_logger - ERROR - 异常服务待办派发执行时发生异常: 'str' object has no attribute 'get'
Traceback (most recent call last):
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 475, in main
customer_service = self.assign_customer_service(province_name, city_name, area_name, self.index)
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 227, in assign_customer_service
customer_service = customer_service_info.get('_widget_1734677164870', {}).get('username') # 异常回访客服
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
2026-04-01 14:23:51,145 - log_config.py - error_task_logger - ERROR - 异常服务待办派发执行时发生异常: 'str' object has no attribute 'get'
Traceback (most recent call last):
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 475, in main
customer_service = self.assign_customer_service(province_name, city_name, area_name, self.index)
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 227, in assign_customer_service
customer_service = customer_service_info.get('_widget_1734677164870', {}).get('username') # 异常回访客服
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
2026-04-01 14:24:02,662 - log_config.py - error_task_logger - ERROR - 异常服务待办派发执行时发生异常: 'str' object has no attribute 'get'
Traceback (most recent call last):
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 475, in main
customer_service = self.assign_customer_service(province_name, city_name, area_name, self.index)
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 227, in assign_customer_service
customer_service = customer_service_info.get('_widget_1734677164870', {}).get('username') # 异常回访客服
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
2026-04-01 14:24:12,213 - log_config.py - error_task_logger - ERROR - 异常服务待办派发执行时发生异常: 'str' object has no attribute 'get'
Traceback (most recent call last):
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 475, in main
customer_service = self.assign_customer_service(province_name, city_name, area_name, self.index)
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 227, in assign_customer_service
customer_service = customer_service_info.get('_widget_1734677164870', {}).get('username') # 异常回访客服
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
2026-04-01 14:24:19,850 - log_config.py - error_task_logger - ERROR - 异常服务待办派发执行时发生异常: 'str' object has no attribute 'get'
Traceback (most recent call last):
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 475, in main
customer_service = self.assign_customer_service(province_name, city_name, area_name, self.index)
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 227, in assign_customer_service
customer_service = customer_service_info.get('_widget_1734677164870', {}).get('username') # 异常回访客服
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
2026-04-01 14:24:20,919 - log_config.py - error_task_logger - ERROR - 异常服务待办派发执行时发生异常: 'str' object has no attribute 'get'
Traceback (most recent call last):
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 475, in main
customer_service = self.assign_customer_service(province_name, city_name, area_name, self.index)
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 227, in assign_customer_service
customer_service = customer_service_info.get('_widget_1734677164870', {}).get('username') # 异常回访客服
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
2026-04-01 14:24:21,410 - log_config.py - error_task_logger - ERROR - 异常服务待办派发执行时发生异常: 'str' object has no attribute 'get'
Traceback (most recent call last):
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 475, in main
customer_service = self.assign_customer_service(province_name, city_name, area_name, self.index)
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 227, in assign_customer_service
customer_service = customer_service_info.get('_widget_1734677164870', {}).get('username') # 异常回访客服
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
2026-04-01 14:24:29,458 - log_config.py - error_task_logger - ERROR - 异常服务待办派发执行时发生异常: 'str' object has no attribute 'get'
Traceback (most recent call last):
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 475, in main
customer_service = self.assign_customer_service(province_name, city_name, area_name, self.index)
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 227, in assign_customer_service
customer_service = customer_service_info.get('_widget_1734677164870', {}).get('username') # 异常回访客服
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
2026-04-01 14:24:30,227 - log_config.py - error_task_logger - ERROR - 异常服务待办派发执行时发生异常: 'str' object has no attribute 'get'
Traceback (most recent call last):
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 475, in main
customer_service = self.assign_customer_service(province_name, city_name, area_name, self.index)
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 227, in assign_customer_service
customer_service = customer_service_info.get('_widget_1734677164870', {}).get('username') # 异常回访客服
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
2026-04-01 14:24:35,451 - log_config.py - error_task_logger - ERROR - 异常服务待办派发执行时发生异常: 'str' object has no attribute 'get'
Traceback (most recent call last):
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 475, in main
customer_service = self.assign_customer_service(province_name, city_name, area_name, self.index)
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 227, in assign_customer_service
customer_service = customer_service_info.get('_widget_1734677164870', {}).get('username') # 异常回访客服
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
2026-04-01 14:24:36,797 - log_config.py - error_task_logger - ERROR - 异常服务待办派发执行时发生异常: 'str' object has no attribute 'get'
Traceback (most recent call last):
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 475, in main
customer_service = self.assign_customer_service(province_name, city_name, area_name, self.index)
File "d:\Idea Project\SaaS_V1.7\test\异常服务代办暂停派发不生效问题排查.py", line 227, in assign_customer_service
customer_service = customer_service_info.get('_widget_1734677164870', {}).get('username') # 异常回访客服
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
+11649
View File
File diff suppressed because it is too large Load Diff
+39
View File
@@ -0,0 +1,39 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "initial_id",
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import pandas as pd\n",
"\n",
"df = pd.read_excel(fr\"C:\\Users\\hp_z66\\Downloads\\商机问题跟进表_20260331114857.xlsx\")\n"
]
}
],
"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,605 @@
import datetime
import os
import sys
import time
import requests
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
if project_root not in sys.path:
sys.path.insert(0, project_root)
from api import API
from back_ground_module import CommonModule
import pandas as pd
from log_config import configure_task_logger, configure_error_task_logger
api_instance = API()
common_module = CommonModule()
# start_time = datetime.datetime.now()
# 获取已经配置好的常规日志记录器
logger = configure_task_logger()
# 获取已经配置好的错误任务日志记录器
error_task_logger = configure_error_task_logger()
output_dir = "output" # 设置输出目录
os.makedirs(output_dir, exist_ok=True)
class NewExceptionTask:
"""
SaaS异常回访
"""
def __init__(self):
self.exception_service_todo = None
self.get_feature_usage = None
self.saas_create_time = None
self.index = None
self.date_one = None
self.data_yichang_S = None
self.date_list = None
self.Smart_detection = None
self.service_remind = None
self.NGV_data_list = None
self.permissions_table = None
self.staff_id_list = None
self.json_list = []
self.policy_recognition = None
self.widget_list = None
self.private_domain = None
self.public_domain = None
self.public_domain_list = None
self.different_industries = None
self.different_industries_list = None
self.groupnotification = None
self.fields_mapping = {
"门店名称": "_widget_1748241895830",
"联系人": "_widget_1748241895831",
"开户时间": "_widget_1748241895839",
"门店编码": "_widget_1748241895842",
"联系方式": "_widget_1748241895832",
"系统版本": "_widget_1748241895850",
"公司名称": "_widget_1748241895844",
"运营顾问": "_widget_1748246808679",
"区域经理": "_widget_1748246808682",
"公司等级": "_widget_1748241895846",
"运营专家": "_widget_1748246808681",
"操作模式E.L/E.S": "_widget_1748241895853",
"活跃健康状态变化": "_widget_1748241895829",
"初始日": "_widget_1748241895833",
"推进日": "_widget_1748241895834",
"异常跟进情况描述": "_widget_1748512176640",
"异常变化原因": "_widget_1748512176641",
"正常使用": "_widget_1748512176643",
"门店原因": "_widget_1748512176645",
"服务原因": "_widget_1748512176647",
"产品原因": "_widget_1748512176649",
"未正式切换": "_widget_1748512176651",
"跟进状态": "_widget_1748512176655",
"是否可激活": "_widget_1758615839701",
"是否有续约风险": "_widget_1758615839703",
"当前跟进人": "_widget_1748246808678",
"激活策略": "_widget_1758615839717",
"跟进时间": "_widget_1748512176654",
"是否跟进完成": "_widget_1751273412737",
"区域客服": "_widget_1748246808680",
"大区": "_widget_1748241895847",
"": "_widget_1748241895848",
"城市": "_widget_1748241895855",
"门店类型": "_widget_1748241895849",
"saas客户类型": "_widget_1748241895851",
"门店阶段": "_widget_1748241895852",
"提交人": "creator",
"提交时间": "createTime",
"更新时间": "updateTime"
}
def calculate_date_one(self, start_offset=0):
"""
计算从当前日期或指定偏移量的日期开始往前遍历遇到date_list中日期的次数
参数:
- start_offset: 从当前日期起始的天数偏移量默认为0即今天负数表示过去正数表示未来
返回:
- date_one: 遍历到date_list中日期的次数
"""
jdy_date = datetime.datetime.now().strftime("%Y-%m-%d")
jdy_start_time = datetime.datetime.now().strftime("%Y-%m-%d ")
# 设置起始日期
now_time = datetime.datetime.now() + datetime.timedelta(days=start_offset)
# 初始化计数器
date_one = 1
print("当前日期:", now_time.strftime("%Y-%m-%d"))
# 检查起始日期是否在date_list中
if now_time.strftime("%Y-%m-%d") in self.date_list:
date_one = 0
print("开始次数:", date_one)
else:
# 遍历日期
for i in range(1, 10):
new_date = now_time + datetime.timedelta(days=-i)
new_date_str = new_date.strftime("%Y-%m-%d")
print("遍历日期:", new_date_str)
if new_date_str in self.date_list:
date_one += 1
print("节假日期:", new_date_str)
else:
break
print("遍历次数:", date_one)
return date_one
@staticmethod
def download_url_content(url, save_path):
"""
下载指定 URL 的内容并保存到本地文件
:param url: 要下载内容的 URL
:param save_path: 保存文件的路径
"""
try:
# 发送 GET 请求以获取内容
response = requests.get(url, stream=True)
response.raise_for_status() # 如果响应状态码不是 200,抛出异常
# 确保保存目录存在
os.makedirs(os.path.dirname(save_path), exist_ok=True)
# 将内容写入文件
with open(save_path, 'wb') as file:
for chunk in response.iter_content(chunk_size=8192): # 分块写入,避免占用过多内存
if chunk: # 过滤掉空块
file.write(chunk)
print(f"文件已成功保存到 {save_path}")
except requests.exceptions.RequestException as e:
print(f"下载失败: {e}")
except Exception as e:
print(f"发生错误: {e}")
def load_all_data(self):
"""加载所有必要的数据表"""
# 省市区人员关系表
payload = {"api_key": "675b900991ad2491c69389ca", "entry_id": "676512ac3e54dc3159460c0a"}
json_dict = api_instance.entry_data_list(payload)
self.json_list = json_dict.get("data")
# 获取简道云员工id
payload = {"api_key": "6694d3c4fcb69ca9a111a6c4",
"entry_id": "6769204a1902c9341340a1bc",
}
staff_id = api_instance.entry_data_list(payload)
self.staff_id_list = staff_id.get("data") # api请求格式,将数据封装在data字典里
# 获取NGV数据
payload = {"api_key": "675b900991ad2491c69389ca", "entry_id": "675bb02bd2d53c2034c665e4"}
self.NGV_data_list = api_instance.entry_data_list(payload).get("data", [])
# print("NGV获取后的类型:", type(self.NGV_data_list))
# 获取异常服务待办(添加过滤进行中的订单)
payload = {"api_key": "675b900991ad2491c69389ca", "entry_id": "68340de79f116c0b66b6b0cc",
"filter": {"rel": "and",
"cond": [{"field": "flowState", "type": "flowstate", "method": "eq", "value": [0]}]}}
self.exception_service_todo = api_instance.entry_data_list(payload).get("data", [])
# print(self.exception_service_todo)
@staticmethod
def build_index(json_list):
index = {}
for json_item in json_list:
try:
key = (json_item['_widget_1734677164861'], json_item['_widget_1734677164862'],
json_item['_widget_1734677164863']) # 省市区
if '_widget_1734677164870' not in json_item: # 异常回访客服
raise KeyError("缺少 '异常回访客服'")
index[key] = json_item
except KeyError as e:
print(f"警告:{e},跳过该条记录: {json_item}")
continue
print('index', index)
return index
@staticmethod
def find_customer_service(province_name, city_name, area_name, index):
key = (province_name, city_name, area_name)
# print(index)
if key not in index:
return "数据缺失: 未找到对应的异常回访客服"
return index[key]
@staticmethod
def get_staff_id(row_item, name):
"""辅助函数,用于获取员工ID"""
if str(row_item["_widget_1734942794144"]) == str(name): # 检查姓名是否匹配
return row_item["_widget_1734942794145"] # 返回员工ID
return None
def assign_customer_service(self, province_name, city_name, area_name, index):
"""根据省市区派发给异常回访客服"""
# try:
customer_service_info = self.find_customer_service(province_name, city_name, area_name, index)
if not isinstance(customer_service_info, dict):
logger.warning(
f"【省市区未匹配到客服】省={province_name} 市={city_name} 区={area_name} raw={customer_service_info}")
return None
customer_service = customer_service_info.get('_widget_1734677164870', {}).get('username') # 异常回访客服
return customer_service
# except Exception as e:
# print(f"Error finding customer service: {e}")
# return "分配失败,请检查", "分配失败,请检查", "分配失败,请检查"
def main(self):
task_start_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
all_data = []
try:
self.load_all_data()
data = None
for days_back in range(1, 15):
target_date_id = int(
(datetime.datetime.now() - datetime.timedelta(days=days_back)).strftime("%Y%m%d")
)
logger.info(f"尝试获取异常明细:pt={target_date_id} days_back={days_back}")
data = common_module.get_yichang_details(days_back=days_back)
if data is not None and not data.empty:
logger.info(f"获取异常明细成功:pt={target_date_id} rows={len(data)} days_back={days_back}")
break
logger.info(f"异常明细为空:pt={target_date_id} days_back={days_back}")
self.data_yichang_S = pd.DataFrame() if data is None or data.empty else data.astype(str)
self.index = self.build_index(self.json_list)
logger.info("开始运行SaaS异常回访")
if self.data_yichang_S.empty:
logger.info("未获取到数据或数据为空")
common_module.send_task_status(task_start_time, "异常服务待办派发")
return
data_yichang = self.data_yichang_S.copy()
# data_yichang.to_csv(os.path.join(output_dir,"data_yichang.csv"), index=False)
def replace_values(series):
# 使用条件判断来进行替换
return series.apply(lambda x: '' if pd.isna(x) or x in ['NA', 'None', ''] else x)
# 对整个DataFrame的所有列应用替换函数
data_yichang = data_yichang.apply(replace_values)
error_data = []
def extract_widget_value(widget_value):
if widget_value is None:
return None
if isinstance(widget_value, dict):
return widget_value.get("value")
return widget_value
existing_org_codes = set()
for exception_service in self.exception_service_todo:
try:
existing_value = extract_widget_value(exception_service.get("_widget_1748241895842"))
if existing_value is not None and str(existing_value).strip() != "":
existing_org_codes.add(str(existing_value).strip())
except Exception:
continue
dispatched_org_codes = set()
for index_num, row in data_yichang.iterrows(): # 对过滤后的每一条进行派发
try:
# 每次循环前清空省市区变量
province_name = None
city_name = None
area_name = None
org_code = str(row.get("org_code", "")).strip()
if not org_code:
logger.warning(f"数据缺少门店编码,跳过。index={index_num}")
continue
if org_code in dispatched_org_codes:
logger.info(f"同一轮数据中门店编码重复,跳过派发。org_code={org_code} index={index_num}")
continue
if org_code in existing_org_codes:
logger.info(f"已存在待办,跳过派发。org_code={org_code} index={index_num}")
continue
payload_dict = {}
distribution_date = datetime.datetime.now(datetime.timezone.utc)
distribution_date = distribution_date.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'
date_obj1 = datetime.datetime.strptime(row["init_day"], "%Y%m%d").strftime("%Y-%m-%d")
date_obj2 = datetime.datetime.strptime(row["push_day"], "%Y%m%d").strftime("%Y-%m-%d")
NGV_roles = {
'service_impl_principal': row['service_impl_principal'], # 运营负责人
'area_manager': row['area_manager'], # 区域经理
'technician': row['technician'], # 运营专家
}
for role, name in NGV_roles.items(): # 寻找对应的员工ID
for row_item in self.staff_id_list:
staff_id = self.get_staff_id(row_item, name)
if staff_id:
NGV_roles[role] = staff_id
break # 找到后退出循环
else:
NGV_roles[role] = None # 如果没有找到对应的员工ID
relationship_manager, area_manager, technician = [NGV_roles[role] for role in
['service_impl_principal',
'area_manager',
'technician']]
UUid = time.strftime("%Y%m%d%H%M%S", time.localtime())
NGV_data_id = None
reason = None
create_exception = None
create_date = None
# 优先从 data_yichang_S 获取省市区信息
province_name = row.get('province_name')
city_name = row.get('city_name')
area_name = row.get('area_name') if 'area_name' in row else row.get('district_name')
# 检查省市区是否完整(省市区是一体的,任意一个缺失就需要从NGV获取)
use_ngv_location = False
if (not province_name or province_name in ['', 'None', 'NA'] or
not city_name or city_name in ['', 'None', 'NA'] or
not area_name or area_name in ['', 'None', 'NA']):
use_ngv_location = True
logger.info(f"门店 {row['org_code']} 的省市区信息不完整,将从NGV_data_list获取")
stop_date = None
# 获取关联数据
for NGV_Data in self.NGV_data_list:
# NGV_Data = NGV_Data.get("data")
if org_code == str(NGV_Data.get("_widget_1734062123071", "")).strip(): # 门店编码
NGV_data_id = NGV_Data.get("_id")
# 如果需要从 NGV_data_list 获取省市区信息
if use_ngv_location:
province_name = NGV_Data.get("_widget_1734062123090")
city_name = NGV_Data.get("_widget_1734062123092")
area_name = NGV_Data.get("_widget_1734062123094")
logger.info(
f"【从NGV获取省市区】门店 {row['org_code']}: {province_name}, {city_name}, {area_name}")
# 门店原因
reason = NGV_Data.get("_widget_1758617393828")
logger.info(f"获取关联数据成功:{NGV_data_id}, {province_name}, {city_name}, {area_name}")
# 是否生成异常待办
create_exception = NGV_Data.get("_widget_1758769279995")
# 获取上线日期(文本)# 202512.3改为开户日
create_date = NGV_Data.get("_widget_1734062123081")
# 获取暂停派发日期
stop_date = NGV_Data.get("_widget_1772610343227", None)
logger.info(
f"【暂停派发字段】org_code={org_code} stop_date={stop_date} type={type(stop_date).__name__}")
break # 找到匹配的数据后退出循环
# 定义可能的日期格式(灵活应对不同格式)
date_formats = [
"%Y-%m-%d %H:%M:%S", # 含时间
"%Y-%m-%d", # 仅日期
"%Y/%m/%d",
"%Y/%m/%d %H:%M:%S"
]
if stop_date:
parsed_stop_date = None
stop_value = extract_widget_value(stop_date)
local_tz = datetime.timezone(datetime.timedelta(hours=8))
now_local = datetime.datetime.now(local_tz)
if isinstance(stop_value, (int, float)):
parsed_stop_date = datetime.datetime.fromtimestamp(stop_value / 1000, tz=local_tz)
elif isinstance(stop_value, str):
stop_str = stop_value.strip()
iso_candidate = stop_str[:-1] + "+00:00" if stop_str.endswith("Z") else stop_str
try:
iso_dt = datetime.datetime.fromisoformat(iso_candidate)
except ValueError:
iso_dt = None
if iso_dt is not None:
parsed_stop_date = iso_dt.replace(tzinfo=local_tz) if iso_dt.tzinfo is None else iso_dt.astimezone(local_tz)
else:
for fmt in date_formats:
try:
parsed_stop_date = datetime.datetime.strptime(stop_str, fmt).replace(
tzinfo=local_tz)
break
except ValueError:
continue
if parsed_stop_date is None:
logger.warning(
f"【暂停派发解析失败】org_code={org_code} stop_value={stop_value} type={type(stop_value).__name__}")
else:
logger.info(
f"【暂停派发校验】org_code={org_code} now={now_local} stop_until={parsed_stop_date}")
if now_local < parsed_stop_date:
logger.info(
f"【暂停派发生效】org_code={org_code} 当前时间未到暂停派发截止时间,跳过派发")
continue
# 判断门店原因
# if reason in ["门店倒闭", "门店转让", "加盟其他连锁","切换竞品","虚拟门店","重新开户","已退款","二套系统"]:
# continue
# 判断是否继续生成异常待办
if create_exception == "":
continue
# 新增:检查 create_date_str 是否存在且有效
create_date_value = extract_widget_value(create_date)
if not create_date_value:
logger.warning("上线日期为空,跳过该记录")
continue
parsed_date = None
for fmt in date_formats:
try:
if isinstance(create_date_value, (int, float)):
local_tz = datetime.timezone(datetime.timedelta(hours=8))
parsed_date = datetime.datetime.fromtimestamp(create_date_value / 1000, tz=local_tz).date()
else:
create_str = str(create_date_value).strip()
iso_candidate = create_str[:-1] + "+00:00" if create_str.endswith("Z") else create_str
try:
iso_dt = datetime.datetime.fromisoformat(iso_candidate)
except ValueError:
iso_dt = None
if iso_dt is not None:
parsed_date = (iso_dt.date() if iso_dt.tzinfo is None else iso_dt.astimezone(datetime.timezone(datetime.timedelta(hours=8))).date())
else:
parsed_date = datetime.datetime.strptime(create_str, fmt).date()
logger.debug(f"使用格式 {fmt} 成功解析日期: {parsed_date}")
break
except ValueError:
continue
if parsed_date is None:
logger.error(
f"无法解析上线日期: '{create_date_value}',支持的格式: %Y-%m-%d, %Y-%m-%d %H:%M:%S 等")
continue # 解析失败,跳过
# 使用解析后的日期进行判断
now_date = datetime.date.today()
delta = now_date - parsed_date
days_diff = delta.days
if days_diff > 30:
logger.info(f"上线日期 {parsed_date} 超过30天({days_diff}天),生成待办")
# ✅ 继续后续待办创建逻辑
else:
logger.info(f"上线日期 {parsed_date} 在30天内,跳过处理")
continue
if not NGV_data_id:
logger.warning(f"未找到关联数据,请检查门店编码: {org_code}")
# 根据省市区派发给异常回访客服
# 检查省市区是否都有值,如果有任何一个为空,则客服为空
if (not province_name or province_name in ['', 'None', 'NA'] or
not city_name or city_name in ['', 'None', 'NA'] or
not area_name or area_name in ['', 'None', 'NA']):
customer_service = None
logger.warning(f"【省市区信息缺失】门店 {row['org_code']} 省市区信息不完整,异常回访客服设置为空")
logger.warning(f"省: {province_name}, 市: {city_name}, 区: {area_name}")
else:
customer_service = self.assign_customer_service(province_name, city_name, area_name, self.index)
if customer_service is None:
logger.warning(
f"【派发客服失败】门店 {org_code} 省={province_name} 市={city_name} 区={area_name} 未匹配到客服,跳过派发")
error_data.append(row)
continue
logger.info(f"【派发客服】门店 {row['org_code']} 派发给客服: {customer_service}")
payload_dict.update({
"_widget_1748241895829": {"value": row["health_warning_info"]}, # 活跃健康状态变化
"_widget_1748241895830": {"value": row["org_name"]}, # 门店名称
"_widget_1748241895831": {"value": row["contacts"]}, # 联系人
"_widget_1748241895832": {"value": row['contact_mobile']}, # 联系方式
"_widget_1748241895833": {
"value": int(time.mktime(time.strptime(date_obj1, "%Y-%m-%d")) * 1000) if row[
"init_day"] != '' else ''},
# 初始日
"_widget_1748241895834": {
"value": int(time.mktime(time.strptime(date_obj2, "%Y-%m-%d")) * 1000) if row[
"push_day"] != '' else ''},
# 推进日
"_widget_1748246808678": {"value": customer_service}, # 当前跟进人
# "_widget_1748246808678": {"value": "083726094935447433"}, # 当前跟进人
"_widget_1748246808679": {"value": relationship_manager}, # 运营负责人
"_widget_1748246808680": {"value": customer_service}, # 区域客服
"_widget_1748241895839": {
"value": int(time.mktime(time.strptime(row["saas_create_time"], "%Y-%m-%d")) * 1000) if row[
"saas_create_time"] != '' else ''},
# 开户时间
"_widget_1748246808681": {"value": technician}, # 技术专家
"_widget_1748246808682": {"value": area_manager}, # 区域经理
"_widget_1748241895842": {"value": row['org_code']}, # 门店编码
"_widget_1748241895844": {"value": row['group_name']}, # 公司名称
"_widget_1748241895846": {"value": row['group_grade']}, # 公司等级
"_widget_1748241895847": {"value": row['region_name']}, # 大区
"_widget_1748241895848": {"value": row['province_name']}, # 省
"_widget_1748241895849": {"value": row['org_type']}, # 门店类型
"_widget_1748241895850": {"value": row['saas_edition_fmt']}, # 系统版本
"_widget_1748241895851": {"value": row['saas_customer_type']}, # saas客户类型
"_widget_1748241895852": {"value": row['org_stage']}, # 门店阶段
"_widget_1748241895853": {"value": row['contact_mobile']}, # 操作模式E.L/E.S
"_widget_1748241895855": {"value": row['city_name']}, # 城市
"_widget_1748247754304": {"value": NGV_data_id}, # 数据id
"_widget_1748512176655": {"value": "未处理"}, # 跟进状态
"_widget_1772761760440": {"value": "客服跟进节点"}, # 当前跟进节点
})
routine_follow_up_payload = {
"api_key": "675b900991ad2491c69389ca",
"entry_id": "68340de79f116c0b66b6b0cc", # 异常服务跟进待办
"is_start_workflow": "true",
"data": payload_dict,
"transaction_id": UUid
}
all_data.append(routine_follow_up_payload)
dispatched_org_codes.add(org_code)
# res = api_instance.data_batch_create(routine_follow_up_payload)
# logger.info(f"创建结果:{res}")
except Exception as e:
error_task_logger.exception(f"异常服务待办派发执行时发生异常: {e}")
error_data.append(row)
pass
if error_data:
error_df = pd.DataFrame(error_data)
error_df.to_csv(os.path.join(output_dir, "异常派发错误数据.csv"))
common_module.send_task_error(task_start_time=task_start_time, task_name="异常服务待办派发",
error_message="失败文件中省市区匹配不到,需要通过门店编码在客户资料表中查询正确的省市区,并更新到省市区人员关系表中",
df=error_df)
ndf = pd.DataFrame(all_data)
ndf.to_csv(os.path.join(output_dir, "异常派发.csv"))
common_module.send_task_status(task_start_time, "异常服务待办派发")
except Exception as e:
error_task_logger.error(f"异常服务待办派发执行时发生异常: {e}")
common_module.send_task_error(task_start_time, "异常服务待办派发", str(e))
if __name__ == '__main__':
start = NewExceptionTask()
start.main()
# -*- coding: utf-8 -*-
+5 -13
View File
@@ -1589,8 +1589,8 @@
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-03-26T03:42:42.714525800Z",
"start_time": "2026-03-26T03:37:29.209197400Z"
"end_time": "2026-03-31T06:24:52.996465800Z",
"start_time": "2026-03-31T06:21:23.287329300Z"
}
},
"cell_type": "code",
@@ -1599,7 +1599,7 @@
"from api import API\n",
"\n",
"api_instance = API()\n",
"df = pd.read_excel(r\"C:\\Users\\hp_z66\\OneDrive\\Desktop\\钉钉文件\\1111111商机问题跟进表_20260326092929.xlsx\",sheet_name=\"问题进行中删除\")\n",
"df = pd.read_excel(r\"C:\\Users\\hp_z66\\Downloads\\商机问题跟进表_20260331114857.xlsx\",sheet_name=\"Sheet8\")\n",
"for index, row in df.iterrows():\n",
" data_id = row[\"data_id\"]\n",
" payload = {\n",
@@ -1610,16 +1610,8 @@
" api_instance.entry_data_delete(payload)"
],
"id": "9982ace96792b53c",
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001B[92m2026-03-26 11:37:29,793 - api.py - task_logger - INFO - 返回结果:, {'code': 4001, 'msg': 'Data does not exist.'}\u001B[0m\n"
]
}
],
"execution_count": 5
"outputs": [],
"execution_count": 1
}
],
"metadata": {