Files
saas/back_ground_module/revisit_renew_services_90_120_180.py
T

972 lines
58 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
import time
import requests
from api import API
from back_ground_module import CommonModule
import pandas as pd
import datetime
import re
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()
class RenewServicesRevisit:
"""续约回访90-180"""
def __init__(self):
self.index = None
self.data_NGV = None
self.date_list = None
self.Smart_detection = None
self.service_remind = None
self.json_list = []
self.NGV_data_list = None
self.permissions_table = None
self.staff_id_list = None
self.get_feature_usage = None
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
def load_all_data(self):
"""加载所有必要的数据表"""
# 省市区人员关系表
payload = {"api_key": "675b900991ad2491c69389ca", "entry_id": "676512ac3e54dc3159460c0a"}
json_dict = api_instance.entry_data_list(payload)
if json_dict and "data" in json_dict:
self.json_list = json_dict.get("data")
else:
print("加载省市区人员关系表失败")
self.json_list = []
# 获取简道云员工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字典里
# 获取权限表信息
payload = {"api_key": "675b900991ad2491c69389ca", "entry_id": "675b96c14e839f90fef1647c"}
self.permissions_table = api_instance.entry_data_list(payload).get("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": "676bb7bda3029720f1083e99"}
self.service_remind = api_instance.entry_data_list(payload).get("data")
# 获取智能检测-数据支持表单数据
payload = {"api_key": "675b900991ad2491c69389ca", "entry_id": "676bb99649ab3ac975af6e39"}
self.Smart_detection = api_instance.entry_data_list(payload).get("data")
# 获取功能使用情况表
payload = {"api_key": "675b900991ad2491c69389ca", "entry_id": "6763bbf657bd8fb76fcb41b2"}
self.get_feature_usage = api_instance.entry_data_list(payload).get("data", [])
# 获取保单识别表
payload = {"api_key": "675b900991ad2491c69389ca", "entry_id": "6773a60d30ed87ff9f68d3c5"}
self.policy_recognition = api_instance.entry_data_list(payload).get("data")
# 提取 _widget_1735632397600 的值并存储在列表中
self.widget_list = [item['_widget_1735632397600'] for item in self.policy_recognition]
# 获取私域小程序-数据支持表单数据
payload = {"api_key": "675b900991ad2491c69389ca", "entry_id": "67e0f0fae622896749ba5087"}
self.private_domain = api_instance.entry_data_list(payload).get("data", [])
# 提取 _widget_1742795002375 的值并存储在列表中
# self.private_domain_list = [item['_widget_1742795002375'] for item in self.private_domain]
# 获取公域小程序-数据支持表单数据
payload = {"api_key": "675b900991ad2491c69389ca", "entry_id": "67e0c702c8f603b997980999"}
self.public_domain = api_instance.entry_data_list(payload).get("data", [])
# 提取 _widget_1742784257506 的值并存储在列表中
self.public_domain_list = [item['_widget_1742784257506'] for item in self.public_domain]
# 获取异业合作-数据支持表单数据
payload = {"api_key": "675b900991ad2491c69389ca", "entry_id": "67e24fdd8dfcfa918e17c30b"}
self.different_industries = api_instance.entry_data_list(payload).get("data", [])
# 提取 _widget_1742784257506 的值并存储在列表中
self.different_industries_list = [item['_widget_1742884829007'] for item in self.different_industries]
# 获取短信-数据支持表单数据
payload = {"api_key": "675b900991ad2491c69389ca", "entry_id": "67e5107198ba1b20d5df3974"}
self.groupnotification = api_instance.entry_data_list(payload).get("data", [])
# 获取多公司过滤表
payload = {"api_key": "675b900991ad2491c69389ca", "entry_id": "689bf5f8ba88a28cb0679ec9"}
self.get_filter_company_list = api_instance.entry_data_list(payload).get("data", [])
@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}")
@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_1734677164871' not in json_item: # 日常回访客服
raise KeyError("缺少 '日常回访客服'")
index[key] = json_item
except KeyError as e:
print(f"警告:{e},跳过该条记录: {json_item}")
continue
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 remove_parentheses(text: str) -> str:
# 使用正则表达式匹配并去除括号及其内容
# \s* 表示匹配零个或多个空白字符(处理括号前后可能存在的空格)
# $ 和 $ 分别表示匹配左括号和右括号
# 中间的 .*? 表示非贪婪地匹配任意数量的字符(包括没有字符的情况)
cleaned_text = re.sub(r'\s*$.*?$\s*', '', text)
# 为了确保同时处理中文括号,再进行一次替换
cleaned_text = re.sub(r'\s*.*?\s*', '', cleaned_text)
return cleaned_text.strip() # 去除两端多余的空白字符
@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)
# 定义一个辅助函数,用于安全地获取多层字段中的 username
def safe_get_username(data, key):
try:
if isinstance(data, dict):
return data.get(key, {}).get('username', "")
return ""
except:
return ""
relationship_manager = safe_get_username(customer_service_info, '_widget_1734677164864')
customer_service = safe_get_username(customer_service_info, '_widget_1734677164871')
technician = safe_get_username(customer_service_info, '_widget_1734677164866')
area_manager = safe_get_username(customer_service_info, '_widget_1734677164865')
return relationship_manager, customer_service, technician, area_manager
except Exception as e:
print(f"Error finding customer service: {e}")
return "分配失败,请检查", "分配失败,请检查", "分配失败,请检查"
def calculate_date_one(self, start_offset=0):
"""
计算从当前日期(或指定偏移量的日期)开始,往前遍历遇到date_list中日期的次数。
参数:
- start_offset: 从当前日期起始的天数偏移量,默认为0(即今天)。负数表示过去,正数表示未来。
返回:
- date_one: 遍历到date_list中日期的次数。
"""
# 设置起始日期
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
def main(self):
import datetime
task_start_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
try:
logger.info("开始执行任务")
# 主店过期,分店设置为主店
global png_url, upload_key
self.load_all_data()
logger.info("数据加载完成")
self.date_list = common_module.get_holiday_list() # 获取一年中的节假日
self.date_one = self.calculate_date_one(start_offset=0)
self.data_NGV = common_module.get_ngv_details(days_back=1) # 获取data_NGV 并转为str
self.index = self.build_index(self.json_list)
logger.info("获取多公司过滤公司id")
all_filter_company_list = [] # 获取多公司过滤公司id
for company in self.get_filter_company_list:
company_list = company.get("_widget_1755052002491")
for company_item in company_list:
if company_item.get("_widget_1755052002496") == "":
all_filter_company_list.append(company_item.get("_widget_1755052002495"))
logger.info(f"过滤公司条数:{len(all_filter_company_list)}")
# 将A列和B列的日期字符串转换为日期格式
data_NGV = self.data_NGV.copy()
data_NGV['A'] = pd.to_datetime(data_NGV['expiry_time'])
data_NGV['B'] = pd.to_datetime(data_NGV['renew_date'])
def replace_values(series):
# 使用条件判断来进行替换
return series.apply(lambda x: '' if pd.isna(x) or x in ['NA', 'None', ''] else x)
# 对整个DataFrame的所有列应用替换函数
# 处理字符串数据并显式指定数据类型
data_NGV = data_NGV.apply(replace_values)
# 过滤多公司
data_NGV = data_NGV[~data_NGV['id_own_group'].isin(all_filter_company_list)]
# 定义优先级顺序
edition_order = ['皇冠版', '至尊版', '尊享版', '旗舰版', '标准版', '进阶版', '基础版', '入门版']
customer_type_order = ["F", "E", "D", "C", "B", "A"] # 索引越小优先级越高
group_grade_order = ['全国KAFMVP', '区域KAMVP', '重要客户(SVIP', '普通客户(VIP']
# 创建映射字典,并为不在列表中的值设置默认值
edition_map = {edition: idx for idx, edition in enumerate(edition_order)}
customer_type_map = {ctype: idx for idx, ctype in enumerate(customer_type_order)}
group_grade_map = {grade: idx for idx, grade in enumerate(group_grade_order)}
# 添加用于排序的新列,并处理不在映射字典中的值
data_NGV['edition_rank'] = data_NGV['saas_edition_fmt'].map(edition_map).fillna(0).astype(
int) # 缺失值用最高优先级填充
data_NGV['customer_type_rank'] = data_NGV['saas_customer_type'].map(customer_type_map).fillna(0).astype(int)
data_NGV['group_grade_rank'] = data_NGV['group_grade'].map(group_grade_map).fillna(0).astype(int)
# data_NGV.to_csv("88855.csv")
# 找到每组中 edition_rank 最小值对应的行
best_edition_idx = data_NGV.groupby('id_own_group')['edition_rank'].idxmin()
best_edition_rows = data_NGV.loc[best_edition_idx]
best_edition_rows['max_saas_edition'] = best_edition_rows['saas_edition_fmt']
# 找到每组中 customer_type_rank 最小值对应的行
best_customer_type_idx = data_NGV.groupby('id_own_group')['customer_type_rank'].idxmin()
best_customer_type_rows = data_NGV.loc[best_customer_type_idx]
best_customer_type_rows['max_saas_customer_type'] = best_customer_type_rows['customer_type_rank'].apply(
lambda x: customer_type_order[x])
# 找到每组中 group_grade_rank 最小值对应的行
best_group_grade_idx = data_NGV.groupby('id_own_group')['group_grade_rank'].idxmin()
best_group_grade_rows = data_NGV.loc[best_group_grade_idx]
best_group_grade_rows['max_group_grade'] = best_group_grade_rows['group_grade']
# 合并最佳值回到原数据集
best_values = (
best_edition_rows[['id_own_group', 'max_saas_edition']]
.merge(best_customer_type_rows[['id_own_group', 'max_saas_customer_type']], on='id_own_group',
how='outer')
.merge(best_group_grade_rows[['id_own_group', 'max_group_grade']], on='id_own_group', how='outer')
)
# 将最佳值合并回原数据集
data_NGV = data_NGV.merge(best_values, on='id_own_group', how='left')
condition = (data_NGV['is_main_org'] == 1) & (data_NGV['org_status'] == '过期') # 步骤2: 过滤条件
ngvv2 = data_NGV[condition]
# ngvv2.to_excel(r"C:\Users\Administrator.DESKTOP-7IC2USJ\Desktop\NGVV2.xlsx")
data_NGV_V2 = data_NGV.copy() # 步骤3: 检查id_own_group是否存在于ngvv2中
data_NGV_V2['条件'] = ((data_NGV_V2['org_type'] == "一般") & (data_NGV_V2['org_status'] == '留存') &
(data_NGV_V2['area_manager'] != '殷昊') & (
data_NGV_V2['area_manager'] != '孙玉蕾') & (
data_NGV_V2['is_main_org'] != 1))
data_NGV_V2 = data_NGV_V2.loc[data_NGV_V2["条件"]]
# 步骤4: 过滤存在的记录
data_NGV_V2['exists_in_ngvv2'] = data_NGV_V2['id_own_group'].isin(ngvv2['id_own_group'])
filtered_data = data_NGV_V2[data_NGV_V2['exists_in_ngvv2']]
fixed_order = ['皇冠版', '至尊版', '尊享版', '旗舰版', '标准版', '进阶版', '基础版', '入门版']
# sorted_items = sorted(filtered_data, key=lambda x: fixed_order.index(x))
fixed_order_map = {edition: index for index, edition in enumerate(fixed_order)}
filtered_data['sort_key'] = filtered_data['saas_edition_fmt'].map(fixed_order_map)
filtered_data = filtered_data.sort_values(by='sort_key').drop('sort_key', axis=1)
result = filtered_data.drop_duplicates(subset='id_own_group', keep='first')
data_NGV['条件'] = (data_NGV['org_type'] == "一般") & (data_NGV['org_status'] == '留存') & (
data_NGV['area_manager'] != '殷昊') & (
data_NGV['area_manager'] != '孙玉蕾') & (
data_NGV['is_main_org'] == 1)
data_NGV = data_NGV.loc[data_NGV["条件"]]
data_NGV = pd.concat([data_NGV, result], axis=0)
data_details = data_NGV.copy()
# 重置索引
data_details = data_details.reset_index(drop=True)
# data_details.to_csv("dayin.csv")
# 判断A列的日期是否大于B列的日期730天,如果是的话,将B列的值设置为1
data_details['条件'] = data_details.apply(
lambda row: (
(pd.to_datetime(row['A']) - pd.to_datetime(row['B'])).days
if pd.to_datetime(row['A']) - pd.to_datetime(row['B']) >= pd.Timedelta(days=730)
else 0
),
axis=1
)
data_details = data_details.loc[data_details["条件"] > 0]
# 定义一个函数,用于将数字除以365并取整数
def divide_by_365(x):
if isinstance(x, (int, float)):
return int(x / 365)
else:
return x
# 使用applymap()函数将divide_by_365函数应用到DataFrame的每个元素
data_details[''] = data_details['条件'].apply(divide_by_365)
# 重置索引
data_details = data_details.reset_index(drop=True)
# data_details.to_excel(r"C:\Users\admin\Downloads\2.xlsx")
# 创建一个新的空的DataFrame
new_df = pd.DataFrame()
# 遍历原始DataFrame的每一行
from datetime import datetime
for index, row in data_details.iterrows():
# 根据A列的值来决定复制的次数
if row["renew_date"] != "2024-02-29":
for i_new in range(1, row['']):
# 修改日期
row_new = row.copy()
c = row_new["renew_date"]
date_obj = datetime.strptime(c, "%Y-%m-%d")
new_year = date_obj.year + i_new
new_date_obj = date_obj.replace(year=new_year)
new_c = new_date_obj.strftime("%Y-%m-%d")
row_new["renew_date"] = new_c
# 将当前行添加到新的DataFrame中
# new_df = new_df.append(row_new, ignore_index=True)
new_df = pd.concat([new_df, pd.DataFrame([row_new])], ignore_index=True)
# 合并两个DataFrame
merged_df = pd.concat([data_NGV, new_df], axis=0, ignore_index=True)
data_details = merged_df.copy() # 替换名称
data_details_not_null = data_details[data_details['renew_date'].notnull()]
# data_details_not_null = data_details_not_null[data_details_not_null['renew_date'].str.contains('2023')]
# data_details_not_null = data_details_not_null.sort_values(by='renew_date', ascending=True).drop_duplicates(
# subset='id_own_group') 重置索引
data_details_not_null = data_details_not_null.reset_index(drop=True)
data_details = data_details_not_null.copy() # 替换名称 v2
data_details['saas_create_time'] = data_details['saas_create_time'].str[:4] # 截取前10位
data_details['renew_date_new'] = data_details['renew_date'].str[:4] # 截取前10位
data_details = data_details[
data_details['saas_create_time'] != data_details['renew_date_new']] # 过滤掉等于renew_date的行
data_details = data_details.reset_index(drop=True)
logger.info(f"过滤后的数据长度为: {len(data_details)}")
# data_details.to_excel(r"C:\Users\admin\Downloads\4.xlsx")
import datetime
start_time = datetime.datetime.now()
date_90 = 83
date_120 = 113
date_180 = 173
# self.date_one = 1
now_time = start_time.replace()
if now_time.strftime("%Y-%m-%d") in self.date_list:
self.date_one = 0
print("开始次数:", self.date_one)
print("当前日期:", now_time)
logger.info(f"遍历次数:{self.date_one}")
now_time = start_time.replace()
for i in range(0, self.date_one):
logger.info(f"这是第{i}次遍历")
import datetime
now_time = datetime.datetime.now() + datetime.timedelta(days=-(i + 1))
today = now_time + datetime.timedelta(days=-date_90)
formatted_today_90 = today.strftime("%Y-%m-%d")
today = now_time + datetime.timedelta(days=-date_120)
formatted_today_120 = today.strftime("%Y-%m-%d")
today = now_time + datetime.timedelta(days=-date_180)
formatted_today_180 = today.strftime("%Y-%m-%d")
logger.info(f"90天为{formatted_today_90}180天为{formatted_today_180}")
# 获取数据
data_details_90 = data_details.copy()
data_details_90['条件'] = (data_details_90['renew_date'] == formatted_today_90) & (data_details_90[
'group_grade'] != "普通客户(VIP") # & (data_details_90['saas_edition_fmt'] != '基础版') & (data_details_90['saas_edition_fmt'] != '入门版')
data_details_90 = data_details_90.loc[data_details_90["条件"]]
data_details_120 = data_details.copy()
data_details_120['条件'] = (data_details_120['renew_date'] == formatted_today_120) & (
(data_details_120['saas_edition_fmt'] == '基础版') | (
data_details_120['saas_edition_fmt'] == '入门版'))
data_details_120 = data_details_120.loc[data_details_120["条件"]]
data_details_180 = data_details.copy()
data_details_180['条件'] = (data_details_180[
'renew_date'] == formatted_today_180) # & (data_details_180[
# 'saas_edition_fmt'] != '基础版') & (data_details_180['saas_edition_fmt'] != '入门版')
data_details_180 = data_details_180.loc[data_details_180["条件"]]
data_details_90["跟进阶段"] = "续约后90天回访"
data_details_90["主要目的"] = "关怀使用情况,促进更多功能使用,提升系统使用深度。"
data_details_120["跟进阶段"] = "续约后120天回访"
data_details_120["主要目的"] = "暂无"
data_details_180["跟进阶段"] = "续约后180天回访"
data_details_180["主要目的"] = "关怀使用情况,促进增购商机转化,识别潜在风险,及时提报。"
# 合并三个DataFrame
data_result = pd.concat([data_details_90, data_details_180],
ignore_index=True) # 去除续约120天回访 data_details_120
logger.info(f"派发数据长度:{len(data_result)}")
data_result = data_result.astype(str)
data_NGV = data_result.copy()
for index_num, row in data_NGV.iterrows(): # 对过滤后的每一条进行派发
try:
# print(row["org_code"]) # 数据验证
# print(row["service_impl_principal"])
# print(row["area_manager"])
# print(row["technician"])
# print("销售负责人是:", row["salesmen"])
payload_dict = {}
saas_use_year = re.findall(r'第([0-9]+)年', row["saas_use_year"])[0]
NGV_roles = {
'relationship_manager': row['service_impl_principal'], # 运营负责人
# 'relationship_manager': "张阳", # 运营负责人
'area_manager': row['area_manager'], # 区域经理
'technician': row['technician'], # 技术专家
'salesmen': row['salesmen'], # 销售负责人
}
for role, name in NGV_roles.items():
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
# 回访人员: 需确认 四年以下 technician
if int(saas_use_year) < 4:
relationship_manager, area_manager, technician, salesmen = [NGV_roles[role] for role in
['relationship_manager',
'area_manager',
'technician', 'salesmen']]
# 如果未找到运营负责人,则根据省市区派发给日常回访客服
if not relationship_manager:
relationship_manager = self.assign_customer_service(
row['province_name'], row['city_name'], row['area_name'], self.index
)[0]
if not technician:
technician = self.assign_customer_service(
row['province_name'], row['city_name'], row['area_name'], self.index
)[2]
if row["group_grade"] == "普通客户(VIP" or row["group_grade"] == "重要客户(SVIP":
payload_dict.update({
"_widget_1734590278288": {"value": relationship_manager}, # 跟进人是运营负责人
})
else:
payload_dict.update({
"_widget_1734590278288": {"value": technician}, # 跟进人是技术专家
})
else:
logger.info(
f"超过4年的客户,派发给客服,省市区:{row['province_name']} {row['city_name']} {row['area_name']}")
salesmen = [NGV_roles[role] for role in ['salesmen']][0]
# 直接根据省市区派发给日常回访客服
relationship_manager, customer_service, technician, area_manager = self.assign_customer_service(
row['province_name'], row['city_name'], row['area_name'], self.index
)
logger.info(f"派发给 {relationship_manager} {customer_service} {technician} {area_manager}")
if row["group_grade"] == "普通客户(VIP" or row["group_grade"] == "重要客户(SVIP":
payload_dict.update({
"_widget_1734590278288": {"value": customer_service} # 跟进人是日常回访客服
})
else:
payload_dict.update({
"_widget_1734590278288": {"value": technician} # 跟进人是技术专家
})
payload_dict.update({
# "_widget_1734590278288": {"value": relationship_manager}, # 跟进人是运营负责人
"_widget_1734590278289": {"value": relationship_manager}, # 运营负责人
"_widget_1734590278290": {"value": area_manager}, # 区域经理
"_widget_1734590278291": {"value": technician}, # 技术专家
"_widget_1735290738545": {"value": salesmen} # 销售负责人
})
logger.info(f"请求输出:{payload_dict}")
if payload_dict.get("_widget_1734590278288") == "02414917880947": # 如果跟进人是殷浩
payload_dict.update({
"_widget_1734590278288": {"value": "051612246035720178"}, # 跟进人是赵柄诚
})
# 输出结果
logger.info(f"SaaS开户回访人员:{relationship_manager}")
logger.info(f"SaaS技术专家:{technician}")
logger.info(f"SaaS区域经理:{area_manager}")
# 判断权限唯一值
group_grade = re.sub(r'[^]*', '', row['max_group_grade'])
if not row['saas_customer_type'] or row['saas_customer_type'] == 'NA' or row[
'saas_customer_type'] == 'None':
row['saas_customer_type'] = "F"
NGV_store_level_key = group_grade + row['max_saas_edition'] + row['max_saas_customer_type']
logger.info(f"权限唯一值: {NGV_store_level_key}")
Billing = None
for item in self.permissions_table:
if NGV_store_level_key == item.get("_widget_1734056507963"): # 合并(等级-类型-分层)
print("该门店开单的权限是:", item.get("_widget_1734055617039"))
Billing = item.get("_widget_1734055617039") # 开单
Service_Alerts = item.get("_widget_1734055617040") # 服务提醒
membership = item.get("_widget_1734055617041") # 会员卡
SMS = item.get("_widget_1734055617042") # 短信
Public_domain_applets = item.get("_widget_1734055617043") # 公域小程序
Private_domain_applets = item.get("_widget_1734055617044") # 私域小程序
Test_sheet = item.get("_widget_1734055617045") # 检测单
AI_poster = item.get("_widget_1734055617046") # AI海报
Business_wallets = item.get("_widget_1734055617047") # 企业钱包
Precision_marketing = item.get("_widget_1734055617049") # 精准营销
Paid_memberships = item.get("_widget_1734055617051") # 付费会员
business_WeCom = item.get("_widget_1734055617052") # 企业微信
Insurance_policy_identification = item.get("_widget_1734055617053") # 保险单识别
Insurance_bots = item.get("_widget_1734055617054") # 保险机器人
Camera_pick_up = item.get("_widget_1734055617055") # 摄像头接车
Camera_billing = item.get("_widget_1734055617056") # 摄像头开单
Transparent_workshop = item.get("_widget_1734055617057") # 透明车间
Cross_industry_cooperation = item.get("_widget_1734055617058") # 异业合作
BI_Insights = item.get("_widget_1734055617059") # BI洞察
payload_dict.update(
{
"_widget_1734073342350": {"value": Billing},
"_widget_1735004315757": {"value": Service_Alerts},
"_widget_1735004315756": {"value": membership},
"_widget_1735004315755": {"value": SMS},
"_widget_1735004315754": {"value": Public_domain_applets},
"_widget_1735004315753": {"value": Private_domain_applets},
"_widget_1735004315752": {"value": Test_sheet},
"_widget_1735004315751": {"value": AI_poster},
"_widget_1735004315750": {"value": Business_wallets},
"_widget_1735004315749": {"value": Precision_marketing},
"_widget_1735004315748": {"value": Paid_memberships},
"_widget_1735004315747": {"value": business_WeCom},
"_widget_1735004315746": {"value": Insurance_policy_identification},
"_widget_1735004315745": {"value": Insurance_bots},
"_widget_1735004315744": {"value": Camera_pick_up},
"_widget_1735004315743": {"value": Camera_billing},
"_widget_1735004315742": {"value": Transparent_workshop},
"_widget_1735004315741": {"value": Cross_industry_cooperation},
"_widget_1734073342352": {"value": BI_Insights},
}
)
feature_dict = {
"开单": "_widget_1734073342350",
"服务提醒": "_widget_1735004315757",
"会员卡": "_widget_1735004315756",
"短信": "_widget_1735004315755",
"公域小程序": "_widget_1735004315754",
"私域小程序": "_widget_1735004315753",
"检测单": "_widget_1735004315752",
"AI海报": "_widget_1735004315751",
"企业钱包": "_widget_1735004315750",
"精准营销": "_widget_1735004315749",
"付费会员": "_widget_1735004315748",
"企业微信": "_widget_1735004315747",
"保险单识别": "_widget_1735004315746",
"保险机器人": "_widget_1735004315745",
"摄像头接车": "_widget_1735004315744",
"摄像头开单": "_widget_1735004315743",
"透明车间": "_widget_1735004315742",
"异业合作": "_widget_1735004315741",
"BI洞察": "_widget_1734073342352",
}
# _widget_1735527329557 下次是否推荐
for new_item in self.get_feature_usage:
for feature_module, feature_value in feature_dict.items(): # 模块
if new_item.get("_widget_1735268263079") == feature_module and new_item.get(
"_widget_1735527329557") == "" and new_item.get(
"_widget_1735280720550") == \
row["id_own_org"]: # 下次是否推荐 功能使用情况表
logger.info(f"{feature_value}进行了更改")
payload_dict.update({f"{feature_value}": {"value": "×"}})
if new_item.get("_widget_1735268263079") == feature_module and new_item.get(
"_widget_1736414617462") == "" and new_item.get(
"_widget_1735280720550") == \
row["id_own_org"]: # 下次是否跟进
logger.info(f"{feature_value}进行了更改")
payload_dict.update({f"{feature_value}": {"value": "×"}})
fields_to_check = {
"_widget_1735004315763": Billing, # 开单
"_widget_1735106258016": Service_Alerts, # 服务提醒
"_widget_1735106258036": membership, # 会员卡
"_widget_1735106258086": SMS, # 短信
"_widget_1735106258112": Public_domain_applets, # 公域小程序
"_widget_1735106258141": Private_domain_applets, # 私域小程序
"_widget_1735107354648": Test_sheet, # 检测单
"_widget_1735107354725": AI_poster, # AI海报
"_widget_1735107354811": Business_wallets, # 企业钱包
"_widget_1735107354906": Precision_marketing, # 精准营销
"_widget_1735107354980": Paid_memberships, # 付费会员
"_widget_1735107355093": business_WeCom, # 企业微信
"_widget_1735107355143": Insurance_policy_identification, # 保险单识别
"_widget_1735107355235": Insurance_bots, # 保险机器人
"_widget_1735107355333": Camera_pick_up, # 摄像头接车
"_widget_1735107355392": Camera_billing, # 摄像头开单
"_widget_1735107355502": Transparent_workshop, # 透明车间
"_widget_1735107355618": Cross_industry_cooperation, # 异业合作
"_widget_1735107355740": BI_Insights # BI洞察
}
# 遍历每个字段,检查其值并更新payload_dict
for widget_id, field_name in fields_to_check.items():
if field_name == "":
payload_dict.update({widget_id: {"value": ""}})
break
is_continue = False
# 如果门店倒闭则不派发
for store in self.NGV_data_list:
if row["id_own_org"] == store.get("_widget_1734062123069") and store.get(
"_widget_1752027386523") == "门店倒闭":
is_continue = True
logger.info(f"{row["id_own_org"]}门店已关闭,不派发")
break
if is_continue:
continue
if not Billing:
logger.warning(f"权限表请求失败或者权限表无对应关系,权限唯一值是:{NGV_store_level_key}")
if row["active_status_fmt"] == "活跃": # 开单 是否使用
payload_dict.update({"_widget_1735004315765": {"value": ""}})
else:
payload_dict.update({"_widget_1735004315765": {"value": ""}})
try:
if row["saas_edition_fmt"] not in ["基础版", "入门版"]: # 会员卡 是否拥有
payload_dict.update({"_widget_1735106258036": {"value": ""}})
else:
payload_dict.update({"_widget_1735106258036": {"value": ""}})
except Exception as e:
error_task_logger.error(f"会员卡拥有识别:Error finding customer service: {e}")
common_module.send_task_error(task_start_time, "手动添加日常回访-会员卡拥有识别", str(e))
try:
if row["card_bill_day_count_last_30_day"] != "0": # 会员卡 是否使用
payload_dict.update({"_widget_1735106258038": {"value": ""}})
else:
payload_dict.update({"_widget_1735106258038": {"value": ""}})
except Exception as e:
error_task_logger.error(f"会员卡使用识别:Error finding customer service: {e}")
common_module.send_task_error(task_start_time, "手动添加日常回访-会员卡使用识别", str(e))
# print(self.service_remind.get("_widget_1735112637045"))
payload_dict["_widget_1735106258018"] = {"value": ""}
for item in self.service_remind:
if row["id_own_group"] == item.get("_widget_1735112637043"):
if int(item.get("_widget_1735112637045")) < 180 and int(
item.get("_widget_1735112637046")) == 1: # 服务提醒 是否使用
payload_dict.update({"_widget_1735106258018": {"value": ""}})
break
elif int(item.get("_widget_1735112637048")) > 0:
payload_dict.update({"_widget_1735106258018": {"value": ""}})
break
keys_to_check = [
"_widget_1735113110155"
] # 智能检测 是否使用
# 初始化默认值为"否"
payload_dict["_widget_1735107354650"] = {"value": ""}
# 检查每个键,如果有一个大于0,则更新为"是"并停止检查
for key in keys_to_check:
for item in self.Smart_detection:
if row["id_own_org"] == item.get("_widget_1735113110147"):
if int(item.get(key, 0)) > 0: # 使用get方法并提供默认值0防止键不存在的情况
payload_dict["_widget_1735107354650"]["value"] = ""
break
# 近30天业务单量=0 则其它所有模块均不推荐
try:
for feature_module, feature_value in feature_dict.items(): # 模块
if row["bill_count_last_30_day"] == '0' and payload_dict[feature_value]["value"] == '':
payload_dict.update({f"{feature_value}": {"value": "×"}})
except Exception as e:
error_task_logger.error(f"不开单识别:Error finding customer service: {e}")
common_module.send_task_error(task_start_time, "手动添加日常回访-不开单识别", str(e))
# 保单识别:从系统中抽取目标门店,针对门店抽取修改是否推荐
try:
if row["org_code"] in self.widget_list:
payload_dict.update({'_widget_1735004315746': {"value": ""}})
except Exception as e:
error_task_logger.error(f"保单识别:Error finding customer service: {e}")
common_module.send_task_error(task_start_time, "手动添加日常回访-保单识别", str(e))
# 私域小程序:根据是否开通微信小程序判断是否使用,旗舰版及以上算拥有
try:
for item in self.private_domain:
if row["id_own_group"] == item.get("_widget_1742795002375"): # 公司id
if int(item.get("_widget_1742795002379")) > 0: # 上架商品数
payload_dict.update({"_widget_1735106258143": {"value": ""}}) # DX:是否拥有
break
else:
payload_dict.update({"_widget_1735106258143": {"value": ""}}) # DX:是否拥有
break
except Exception as e:
error_task_logger.error(f"小程序识别:Error finding customer service: {e}")
common_module.send_task_error(task_start_time, "手动添加日常回访-小程序识别", str(e))
try:
high_version = ['皇冠版', '至尊版', '尊享版', '旗舰版']
if row["saas_edition_fmt"] in high_version:
payload_dict.update({'_widget_1735106258141': {"value": ""}}) # SYXCX:是否拥有
else:
payload_dict.update({'_widget_1735106258141': {"value": ""}}) # SYXCX:是否拥有
except Exception as e:
error_task_logger.error(f"私域小程序:Error finding customer service: {e}")
common_module.send_task_error(task_start_time, "手动添加日常回访-私域小程序", str(e))
# 公域小程序:根据是否开通微信小程序判断是否使用,旗舰版及以上算拥有
try:
for item in self.public_domain:
if row["id_own_org"] == item.get("_widget_1742784257506"): # 门店id
if int(item.get("_widget_1742784257509")) == 1: # 发布商品数量
payload_dict.update({"_widget_1735106258114": {"value": ""}}) # GYXCX:是否使用
break
else:
payload_dict.update({"_widget_1735106258114": {"value": ""}}) # GYXCX:是否使用
break
except Exception as e:
error_task_logger.error(f"公域小程序:Error finding customer service: {e}")
common_module.send_task_error(task_start_time, "手动添加日常回访-公域小程序", str(e))
try:
if row["id_own_org"] in self.public_domain_list:
payload_dict.update({'_widget_1735106258112': {"value": ""}}) # GYXCX:是否拥有
else:
payload_dict.update({'_widget_1735106258112': {"value": ""}}) # GYXCX:是否拥有
except Exception as e:
error_task_logger.error(f"公域小程序:Error finding customer service: {e}")
common_module.send_task_error(task_start_time, "手动添加日常回访-公域小程序", str(e))
# 异业合作:根据是否存在判断是否拥有,过滤条件 商品名称包含异业两个字
try:
if row["id_own_org"] in self.different_industries_list:
payload_dict.update({'_widget_1735107355618': {"value": ""}}) # YYHZ:是否拥有
else:
payload_dict.update({'_widget_1735107355618': {"value": ""}}) # YYHZ:是否拥有
except Exception as e:
error_task_logger.error(f"异业合作:Error finding customer service: {e}")
common_module.send_task_error(task_start_time, "手动添加日常回访-异业合作", str(e))
# 短信:根据是否启动短信功能判断是否拥有,根据
try:
for item in self.groupnotification:
if row["id_own_group"] == item.get("_widget_1743065201885"): # 公司id
if int(item.get("_widget_1743065201886")) == 1: # 是否启动短信功能
payload_dict.update({"_widget_1735106258086": {"value": ""}}) # DX:是否拥有
break
else:
payload_dict.update({"_widget_1735106258086": {"value": ""}}) # DX:是否拥有
break
except Exception as e:
error_task_logger.error(f"短信是否使用:Error finding customer service: {e}")
common_module.send_task_error(task_start_time, "手动添加日常回访-短信是否使用", str(e))
try:
for item in self.groupnotification:
if row["id_own_group"] == item.get("_widget_1743065201885"): # 公司id
if int(item.get("_widget_1743065201889")) > 0: # 累计发送成功总人数
payload_dict.update({"_widget_1735106258088": {"value": ""}}) # DX:是否使用
break
else:
payload_dict.update({"_widget_1735106258088": {"value": ""}}) # DX:是否使用
break
except Exception as e:
error_task_logger.error(f"短信是否使用:Error finding customer service: {e}")
common_module.send_task_error(task_start_time, "手动添加日常回访-短信是否使用", str(e))
NGV_data_id = None
# 获取关联数据
for NGV_Data in self.NGV_data_list:
# NGV_Data = NGV_Data.get("data")
if row["org_code"] == NGV_Data.get("_widget_1734062123071"): # 门店编码
NGV_data_id = NGV_Data.get("_id")
logger.info(f"关联数据数据id:{NGV_data_id}")
try:
png_url = NGV_Data.get('_widget_1742890765211', {})[0].get('url', "")
except:
png_url = ""
logger.info(f"关联数据图片:{png_url}")
if not NGV_data_id:
logger.warning("未找到数据ID")
distribution_date = datetime.datetime.now(datetime.timezone.utc)
distribution_date = distribution_date.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'
upload_key = None
UUid = time.strftime("%Y%m%d%H%M%S", time.localtime())
if png_url:
save_dir = "sampleCloud" # 设置输出目录
# 创建输出目录(如果不存在)
import os
os.makedirs(save_dir, exist_ok=True)
save_path = fr'{save_dir}\png\{time.strftime("%Y%m%d%H%M%S", time.localtime())}.png'
RenewServicesRevisit.download_url_content(png_url, save_path)
logger.info(f"已保存图片到 {save_path}")
up_data = api_instance.get_upload_token(
{"api_key": "675b900991ad2491c69389ca", "entry_id": "675b9c63925cd404038a6b86",
"transaction_id": UUid})
upload_url = up_data.get("upload_url")
upload_token = up_data.get("upload_token")
upload_result = api_instance.upload_file(
{"upload_url": upload_url, "upload_token": upload_token, "file_path": save_path})
upload_key = upload_result.get("key")
logger.info("已上传文件")
payload_dict.update({
"_widget_1734590278279": {"value": row["group_name"]}, # 公司名称
"_widget_1735112931760": {"value": row["id_own_group"]}, # 公司id
"_widget_1735112931761": {"value": row["id_own_org"]}, # 门店id
"_widget_1734590278281": {"value": row['org_name']}, # 门店名称
"_widget_1734590278292": {"value": row["跟进阶段"]}, # 跟进阶段
"_widget_1734321349021": {"value": NGV_data_id}, # 关data_get联数据
"_widget_1742548684369": {"value": row['主要目的']}, # 主要目的
"_widget_1734590278266": {"value": row['region_name']}, # 大区
"_widget_1734590278285": {"value": row['branch_name']}, # 小区
"_widget_1734590278284": {"value": row['province_name']}, # 省
"_widget_1734590278283": {"value": row['city_name']}, # 市
"_widget_1734590278282": {"value": row['area_name']}, # 区
"_widget_1734590278278": {"value": row['saas_customer_type']}, # 门店分层
"_widget_1734590278277": {"value": row['group_grade']}, # 公司等级
"_widget_1734590278276": {"value": row['limit_user_type']}, # 限制账户类型
"_widget_1734590278275": {"value": row['active_user_type']}, # 有效账户类型
"_widget_1734590278274": {"value": row['saas_version']}, # ERP操作模式
"_widget_1734590278273": {"value": row['saas_use_year']}, # 使用时长
"_widget_1734590278272": {"value": row['org_stage']}, # 门店阶段
"_widget_1734590278271": {"value": row['manage_model']}, # 经营模式
"_widget_1734590278267": {"value": row['contacts']}, # 联系人
"_widget_1734590278287": {"value": row['contact_mobile']}, # 联系手机号
"_widget_1734590278286": {"value": row['saas_edition_fmt']}, # SaaS版本
"_widget_1734590278280": {"value": row['org_code']}, # 门店编码
# "_widget_1735287791875": {"value": row['salesmen']}, # 销售负责人
"_widget_1735096489244": {"value": distribution_date}, # 派发时间
"_widget_1742895342914": {"value": row['business_scope_fmt']}, # 经营范围
"_widget_1742895342915": {"value": row['station_number']}, # 工位数
"_widget_1742895342916": {"value": [upload_key]} # 门头照片
})
routine_follow_up_payload = {
"api_key": "675b900991ad2491c69389ca",
"entry_id": "675b9c63925cd404038a6b86",
"is_start_workflow": "true",
"data": payload_dict,
"transaction_id": UUid
}
res = api_instance.data_batch_create(routine_follow_up_payload)
logger.info(f"创建结果:{res}")
time.sleep(1)
# print(res)
except:
pass
common_module.send_task_status(task_start_time, "续约客户回访")
logger.info("续约客户回访任务完成")
except Exception as e:
common_module.send_task_error(task_start_time, "续约客户回访", str(e))
error_task_logger.error(f"续约客户回访任务执行时发生异常: {e}")
if __name__ == '__main__':
start = RenewServicesRevisit()
start.main()