""" 客户相关后台任务模块 包含修改客户信息等功能 """ import logging import requests import pandas as pd import time import re from typing import Dict, Any, Optional from app.tasks.common import update_jiandaoyun, approve_workflow logger = logging.getLogger('app') def modify_customer_info_background(data: Dict[str, Any], cookies: Dict[str, str], df: pd.DataFrame, save_path: str): """ 修改客户信息后台任务。 此函数用于后台任务,用于修改会员信息。 Args: data (Dict[str, Any]): 前端请求发送过来的数据,包含文件信息和其他必要参数。 cookies (Dict[str, str]): 登录用户的Cookies。 Returns: None """ df = df.where(pd.notnull(df), None) params = { 'pageSize': 100, 'pageNo': '1', } res = requests.get( 'https://yunxiu.f6car.cn/member/customer/listForPermission', params=params, cookies=cookies, ) total = int(res.json().get("data").get("total")) total_pages = (total // params["pageSize"]) + (1 if total % params["pageSize"] > 0 else 0) print(f"总计{total_pages}页") all_customers = [] max_retries = 10 retry_count = 0 for page in range(1, total_pages + 1): print(f"正在请求第 {page} 页...") params["pageNo"] = page while retry_count < max_retries: response = requests.get( 'https://yunxiu.f6car.cn/member/customer/listForPermission', params=params, cookies=cookies, timeout=10 ) time.sleep(1) if response.status_code == 200: suppliers = response.json().get("data", {}).get("data", []) all_customers.extend(suppliers) break else: retry_count += 1 print(f"请求第 {page} 页失败,正在重试(第 {retry_count} 次)...") time.sleep(3) # 获取专属运营顾问列表 json_data = { 'includeStopedEmployee': False, 'pageSize': 1000, 'filterNullUser': False, 'keyword': '', 'idOwnOrgList': [], } response = requests.post( 'https://yunxiu.f6car.cn/hive/employee/searchStaffInGroup', cookies=cookies, json=json_data, ) staff_list = response.json().get("data").get("list") name_to_userid = { emp['name']: emp['userId'] for emp in staff_list if emp['userId'] is not None } df['userId'] = df['专属运营顾问'].map(name_to_userid) def extract_province_city_district(address: Optional[str]) -> Dict[str, Optional[str]]: """安全解析省市区信息,所有返回值都可能为None""" if not address: return {'省': None, '市': None, '区': None} try: pattern = r'(?P<省>(?:[\u4e00-\u9fa5]+(?:省|自治区|特别行政区))?)' \ r'(?P<市>(?:[\u4e00-\u9fa5]+(?:市|自治州|地区|盟))?)' \ r'(?P<区>(?:[\u4e00-\u9fa5]+区|[\u4e00-\u9fa5]+县|[\u4e00-\u9fa5]+旗)?)' match = re.match(pattern, address.strip()) return {k: v if v else None for k, v in match.groupdict().items()} if match else {'省': None, '市': None, '区': None} except Exception: return {'省': None, '市': None, '区': None} def safe_get(d: Optional[Dict], *keys, default=None): """多层字典安全获取值,始终返回可能为None的值""" if not isinstance(d, dict): return default for key in keys: d = d.get(key, {}) if not isinstance(d, dict): break return d if d != {} else default def convert_to_request_data(original_data: Optional[Dict[str, Any]], df: pd.DataFrame) -> Dict[str, Any]: """ 完全安全的字典转换函数 特点: 1. 每个字段的值都可能为None 2. 不会因为任何字段为空而报错 3. 不使用任何默认值,完全保留原始数据的空值状态 """ customer_info = safe_get(original_data, 'data', 'customerInfo') if original_data else None address_parts = extract_province_city_district( safe_get(customer_info, 'provinceCityAreaName') if customer_info else None ) cell_phone = safe_get(customer_info, 'cellPhone') exclusive_info = None df_row = None if cell_phone and not df.empty: matched_rows = df[df['客户手机号'] == cell_phone] if not matched_rows.empty: df_row = matched_rows.iloc[0] exclusive_info = { 'userId': df_row.get('userId'), 'name': df_row.get('专属运营顾问') } request_data = { "pkId": safe_get(customer_info, 'idCustomer'), "idCustomer": safe_get(customer_info, 'idCustomer'), "name": df_row.get('客户姓名') if df_row is not None and pd.notna(df_row.get('客户姓名')) else safe_get( customer_info, 'name'), "sex": safe_get(customer_info, 'sex'), "customerType": df_row.get('客户类型') if df_row is not None and pd.notna( df_row.get('客户类型')) else safe_get( customer_info, 'customerType'), "customerSource": safe_get(customer_info, 'customerSource'), "customerSourceName": df_row.get('客户来源') if df_row is not None and pd.notna( df_row.get('客户来源')) else safe_get(customer_info, 'customerSourceName'), "companyName": df_row.get('单位名称') if df_row is not None and pd.notna( df_row.get('单位名称')) else safe_get( customer_info, 'companyName'), "cellPhone": cell_phone, "wechart": safe_get(customer_info, 'wechart'), "qq": safe_get(customer_info, 'qq'), "contacts": safe_get(customer_info, 'contacts'), "contactTelephone": safe_get(customer_info, 'contactTelephone'), "province": safe_get(customer_info, 'province'), "city": safe_get(customer_info, 'city'), "area": safe_get(customer_info, 'area'), "street": safe_get(customer_info, 'street'), "address": safe_get(customer_info, 'address'), "detailAddress": safe_get(customer_info, 'detailAddress'), "pId": safe_get(customer_info, 'province'), "cId": safe_get(customer_info, 'city'), "aId": safe_get(customer_info, 'area'), "provinceName": address_parts.get('省'), "cityName": address_parts.get('市'), "areaName": address_parts.get('区'), "provinceCityAreaName": safe_get(customer_info, 'provinceCityAreaName'), "birthday": safe_get(customer_info, 'birthday'), "creationtime": safe_get(customer_info, 'creationtime'), "modifiedtime": safe_get(customer_info, 'modifiedtime'), "creator": safe_get(customer_info, 'creator'), "creatorName": safe_get(customer_info, 'creatorName'), "modifier": safe_get(customer_info, 'modifier'), "idOwnOrg": safe_get(customer_info, 'idOwnOrg'), "idOwnGroup": safe_get(customer_info, 'idOwnGroup'), "insuranceCompany": safe_get(customer_info, 'insuranceCompany'), "maritalStatus": safe_get(customer_info, 'maritalStatus'), "monthlyIncome": safe_get(customer_info, 'monthlyIncome'), "idNumber": safe_get(customer_info, 'idNumber'), "personHobby": safe_get(customer_info, 'personHobby'), "credentialsType": safe_get(customer_info, 'credentialsType'), "points": safe_get(customer_info, 'points'), "maxAccountAmount": safe_get(customer_info, 'maxAccountAmount'), "pointsEnable": safe_get(customer_info, 'pointsEnable'), "level": safe_get(customer_info, 'level'), "memberCardNo": safe_get(customer_info, 'memberCardNo'), "customerLevel": safe_get(customer_info, 'customerLevel'), "exclusiveConsultantId": exclusive_info['userId'] if exclusive_info else safe_get(customer_info, 'exclusiveConsultantId'), "exclusiveConsultantName": exclusive_info['name'] if exclusive_info else safe_get(customer_info, 'exclusiveConsultantName'), "exclusiveOrgId": safe_get(customer_info, 'exclusiveOrgId'), "exclusiveOrgName": safe_get(customer_info, 'exclusiveOrgName'), "customerMemo": df_row.get('客户备注') if df_row is not None and pd.notna( df_row.get('客户备注')) else safe_get( customer_info, 'customerMemo'), "isDel": safe_get(customer_info, 'isDel'), "idFrom": safe_get(customer_info, 'idFrom'), "mnemonic": safe_get(customer_info, 'mnemonic'), "idOrgSource": safe_get(customer_info, 'idOrgSource'), "firstArrivalIdSourceBill": safe_get(customer_info, 'firstArrivalIdSourceBill'), "lastArrivalIdSourceBill": safe_get(customer_info, 'lastArrivalIdSourceBill'), "customerInfoType": safe_get(customer_info, 'customerInfoType'), "customerInfoCompleteDate": safe_get(customer_info, 'customerInfoCompleteDate'), "customerInfoCompleteType": safe_get(customer_info, 'customerInfoCompleteType'), "xczUserId": safe_get(customer_info, 'xczUserId'), "xczUuid": safe_get(customer_info, 'xczUuid'), "idWxbCustomer": safe_get(customer_info, 'idWxbCustomer'), "promoteEmployeeId": safe_get(customer_info, 'promoteEmployeeId'), "promoteEmployeeName": safe_get(customer_info, 'promoteEmployeeName'), "promoteMemberId": safe_get(customer_info, 'promoteMemberId'), "promoteMemberName": safe_get(customer_info, 'promoteMemberName'), "driverExpiryDate": safe_get(customer_info, 'driverExpiryDate'), "crmDeleteExclusiveFlag": safe_get(customer_info, 'crmDeleteExclusiveFlag'), "totalObtainPoints": safe_get(customer_info, 'totalObtainPoints'), "totalUsedPoints": safe_get(customer_info, 'totalUsedPoints'), "orgName": safe_get(customer_info, 'orgName'), "weChatFollower": safe_get(customer_info, 'weChatFollower'), "pointsEnableConfig": safe_get(customer_info, 'pointsEnableConfig'), "personalPointsEnableConfig": safe_get(customer_info, 'personalPointsEnableConfig'), "pointsButtonStatus": safe_get(customer_info, 'pointsButtonStatus'), "tmallInstallMember": safe_get(customer_info, 'tmallInstallMember'), "corpId": safe_get(customer_info, 'corpId'), "thirdCorpId": safe_get(customer_info, 'thirdCorpId'), } return request_data for customer in all_customers: phone = customer.get("cellPhone") if phone in df["客户手机号"].tolist(): print("开始修改") cus_id = customer.get("idCustomer", {}) cus_response = requests.get(f'https://yunxiu.f6car.cn/member/customer/{cus_id}', cookies=cookies) original_data = cus_response.json() final_json_data = convert_to_request_data(original_data, df) response = requests.post( 'https://yunxiu.f6car.cn/member/customer/modifyCustomer', cookies=cookies, json=final_json_data, ) print("修改完成") time.sleep(1) msg = update_jiandaoyun(data, f'修改完成') if msg.get('msg'): approve_workflow(data) print('表单已自动提交至下一步')