Aries的IT部落格

技术交流和分享

飞书推送销售报表源代码

import os
from datetime import datetime, timedelta
import configparser
import logging
import json
import requests
from typing import  Dict, Any



class RWorkInfo:
    def __init__(self, project: str, webhook_url: str):
        self.project_name = project
        self.webhook_url = webhook_url
        self.DEFAULT_EMPTY = "未提供"  # 数据缺失时的默认显示文本
 
    def _format_amount(self, amount: Any) -> str:
        """
        金额格式化:转为万元单位(保留2位小数),处理异常值
        :param amount: 原始金额(整数/浮点数/None)
        :return: 格式化后的金额字符串(如“180.56万”)
        """
        try:
            if amount is None:
                return self.DEFAULT_EMPTY
            amount_float = float(amount)
            return f"{amount_float / 10000:.2f}万"
        except (ValueError, TypeError):
            return self.DEFAULT_EMPTY

    def _format_percent(self, ratio: Any) -> str:
        """
        百分比格式化:保留1-2位小数,添加升降符号,处理异常值
        :param ratio: 原始比例(小数/None,如-0.3947代表-39.47%)
        :return: 格式化后的百分比字符串(如“-39.5%↓”)
        """
        try:
            if ratio is None:
                return f"{self.DEFAULT_EMPTY}↓"  # 缺失时默认带↓(与示例格式对齐)
            ratio_float = float(ratio)
            percent_str = f"{ratio_float * 100:.1f}%"  # 保留1位小数(示例风格)
            return f"{percent_str}↓" if ratio_float < 0 else f"{percent_str}↑"
        except (ValueError, TypeError):
            return f"{self.DEFAULT_EMPTY}↓"

    def _format_customer_flow(self, flow: Any, is_cumulative: bool = False) -> str:
        """
        客流格式化:普通客流保留整数,累计客流转“万人次”(保留2位小数)
        :param flow: 原始客流(整数/浮点数/None)
        :param is_cumulative: 是否为累计客流(是则转万人次)
        :return: 格式化后的客流字符串(如“24973”或“86.21万人次”)
        """
        try:
            if flow is None:
                return self.DEFAULT_EMPTY
            flow_int = int(flow)
            if is_cumulative:
                return f"{flow_int / 10000:.2f}万人次"
            return str(flow_int)
        except (ValueError, TypeError):
            return self.DEFAULT_EMPTY
    def format_message(self, date: str, data: Dict[str, Any]) -> Dict[str, Any]:
        logging.info(f"正在生成{self.project_name}{date}飞书日报卡片消息")

        # 安全提取数据
        weather_info=data.get("weather_info", {})
        basic_info = data.get("mall_basic_info", {})
        key_indices = data.get("mall_key_indices", {})
        mem_data = data.get("mem_data", {})
        top_stores = data.get("store_sale_top_10", [])

        # 工具函数:格式化金额(万元)和百分比
        def format_sales(amount: Any) -> str:
            try:
                return f"{float(amount)/10000:.2f}万"
            except (ValueError, TypeError):
                return "0.00万"

        def format_percent_arrow(ratio: Any) -> str:
            try:
                val = float(ratio) * 100
                return f"{val:.1f}%↓" if val < 0 else f"{val:.1f}%↑"
            except (ValueError, TypeError):
                return "0.0%"
            
        def format_percent(ratio: Any) -> str:
            try:
                val = float(ratio) * 100
                return f"{val:.1f}%"
            except (ValueError, TypeError):
                return "0.0%"

        def format_number(value: Any) -> str:
            try:
                return f"{int(value)}"
            except (ValueError, TypeError):
                return "0"

        # 构建销售前十店铺文本
        store_items = []
        for idx, store in enumerate(top_stores[:10], 1):
            store_name = store.get("store_name", "未知店铺")
            sales = format_sales(store.get("sales_amt", 0))
            store_items.append({
                "tag": "div",
                "text": {
                    "tag": "plain_text",
                    "content": f"{idx}. {store_name}:{sales}"
                }
            })

        # 构建卡片消息内容
        elements = [
            # 天气信息
            {
                "tag": "div",
                "text": {
                    "tag": "plain_text",
                    "content": f"**天气情况**"
                }
            },

            {
                "tag": "div",
                "fields": [
                    {
                        "is_short": False,
                        "text": {
                            "tag": "plain_text",
                            "content": f"天气: {weather_info.get('condition')}  最高气温:{weather_info.get('max_temp')}°C  最低气温:{weather_info.get('min_temp')}°C" 
                        }
                    }
            
                ]
            },
            # 项目基础信息
            {
                "tag": "div",
                "text": {
                    "tag": "plain_text",
                    "content": "**一、项目基础信息**"
                }
            },

            {
                "tag": "div",
                "fields": [
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"GLA:{format_number(basic_info.get('gla', 0))}m²"
                        }
                    },
                    {
                        "is_short": True,
                        "text": {
                        "tag": "plain_text",
                        "content": f"面积开业率:{format_percent(basic_info.get('open_store_arearate', 0))}"                     
                        }
                    }
                ]
            },
            {
                "tag": "div",
                "fields": [
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"在营店铺数量:{format_number(basic_info.get('act_store_cnt', 0))}家"
                        }
                    },
                    {
                        "is_short": True,
                        "text": {
                        "tag": "plain_text",
                        "content": f"全场店铺数量:{format_number(basic_info.get('all_store_cnt', 0))}家"                       
                        }
                    }
                ]
            },
            {"tag": "hr"},  # 分隔线
            # 关键指标
            {
                "tag": "div",
                "text": {
                    "tag": "plain_text",
                    "content": "**二、关键指标**"
                }
            },
            {
                "tag": "div",
                "fields": [
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"当日销售额:{format_sales(key_indices.get('mall_daily_sales_amt', 0))}"
                        }
                    },
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"周环比:{format_percent_arrow(key_indices.get('lastweek_daily_sales_circle_rate', 0))}"
                        }
                    }
                ]
            },
            {
                "tag": "div",
                "fields": [
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"月累计零售:{format_sales(key_indices.get('month_sale_amt', 0))}"
                        }
                    },
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"年累计零售:{format_sales(key_indices.get('year_sale_amt', 0))}"
                        }
                    }
                ]
            },
            {
                "tag": "div",
                "fields": [
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"当日客流:{format_number(key_indices.get('cust_flow', 0))}人次"
                        }
                    },
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"周环比:{format_percent_arrow(key_indices.get('lastweek_cust_circle_reate', 0))}"
                        }
                    }
                ]
            },
            {
                "tag": "div",
                "fields": [
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"月累计客流:{format_sales(key_indices.get('month_cust_flow', 0))}"
                        }
                    },
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"年累计客流:{format_sales(key_indices.get('year_cust_flow', 0))}"
                        }
                    }
                ]
            },
                        {
                "tag": "div",
                "fields": [
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"当日车流:{format_number(key_indices.get('car_flow', 0))}辆"
                        }
                    },
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"周环比:{format_percent_arrow(key_indices.get('lastweek_car_circle_reate', 0))}"
                        }
                    }
                ]
            },
            {
                "tag": "div",
                "fields": [
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"月累计车流:{format_sales(key_indices.get('month_car_flow', 0))}"
                        }
                    },
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"年累计车流:{format_sales(key_indices.get('year_car_flow', 0))}"
                        }
                    }
                ]
            },
            {"tag": "hr"},  # 分隔线

            # 会员数据模块
            {
                "tag": "div",
                "text": {
                    "tag": "plain_text",
                    "content": "**三、会员数据**"
                }
            },
            {
                "tag": "div",
                "fields": [
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"新增会员数:{format_number(mem_data.get('inc_mem_cnt', 0))}人"
                        }
                    },
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"消费会员数:{format_number(mem_data.get('mem_exp_cnt', 0))}人"
                        }
                    }
                ]
            },
            {
                "tag": "div",
                "fields": [
                    {
                        "is_short": True,
                        "text": {
                            "tag": "plain_text",
                            "content": f"会员消费占比:{format_percent(mem_data.get('mem_exp_ratio', 0))}"
                        }
                    }
                ]
            },
            {"tag": "hr"},

            # 销售前十店铺模块
            {
                "tag": "div",
                "text": {
                    "tag": "plain_text",
                    "content": "**四、销售前十店铺**"
                }
            },
            *store_items,  # 展开店铺列表

            # 底部备注
            {
                "tag": "div",
                "text": {
                    "tag": "lark_md",
                    "content": "⚠️ 以上数据来源于万象生活总部数据平台"
                }
            }
        ]

        # 返回符合飞书规范的消息结构
        return {
            "msg_type": "interactive",
            "card": {
                "config": {"wide_screen_mode": True},
                "header": {
                    "title": {
                        "content": f"📊{date}{self.project_name}简报",
                        "tag": "plain_text"
                    },
                    "template": "green"
                },
                "elements": elements
            }
        }
    def send_to_feishu(self, message: Dict[str, Any]) -> bool:
        """发送消息到飞书机器人"""
        try:
            headers = {'Content-Type': 'application/json'}
            response = requests.post(
                self.webhook_url,
                headers=headers,
                data=json.dumps(message)
            )
            
            if response.status_code == 200:
                result = response.json()
                if result.get('code') == 0:
                    return True
                logging.error(f"发送失败: {result.get('msg')}")
                return False
            
            logging.error(f"HTTP错误: {response.status_code}")
            return False
            
        except Exception as e:
            logging.exception(f"发送消息时发生错误: {str(e)}")
            return False


# Configure logging system
class LoggerSetup:
    @staticmethod
    def setup_logger():
        """设置按日期分割的日志记录器"""
        # 创建logs目录
        script_dir = os.path.dirname(os.path.abspath(__file__))
        log_dir = os.path.join(script_dir, 'logs')
        os.makedirs(log_dir, exist_ok=True)
        
        # 创建日期对应的日志文件
        log_file = os.path.join(
            log_dir, 
            f"dailysalescheck_{datetime.now().strftime('%Y-%m-%d')}.log"
        )
        
        # 配置日志格式
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s [%(levelname)s] %(message)s',
            handlers=[
                logging.FileHandler(log_file, encoding='utf-8'),
                logging.StreamHandler()
            ]
        )

class FeishuWeatherBot:
    def get_weather(self, city):
        """
        获取天气信息
        """
        weather_api_key = "天气平台API"
        weather_api_url = "https://api.weatherapi.com/v1/forecast.json"
        
        params = {
            "key": weather_api_key,
            "q": city,
            "days": 3,  # 修改为获取3天的预报
            "aqi": "yes",
            "lang": "zh"
        }
        
        try:
            response = requests.get(weather_api_url, params=params)
            weather_data = response.json()
            return weather_data
        except Exception as e:
            print(f"获取天气信息失败: {str(e)}")
            return None

    def get_historical_weather(self, city, start_date, end_date=None):
        """
        获取历史天气信息
        :param city: 城市名
        :param start_date: 起始日期 (格式: YYYY-MM-DD)
        :param end_date: 结束日期 (格式: YYYY-MM-DD, 可选)
        :return: 历史天气数据或 None
        """
        weather_api_key = "fa8eab70fd174443aa873221251104"
        weather_api_url = "https://api.weatherapi.com/v1/history.json"
        
        params = {
            "key": weather_api_key,
            "q": city,
            "dt": start_date,  # 指定查询日期
            "lang": "zh"
        }
        
        if end_date:
            params["end_dt"] = end_date  # 可选结束日期

        try:
            response = requests.get(weather_api_url, params=params)
            weather_data = response.json()
            return weather_data
        except Exception as e:
            print(f"获取历史天气信息失败: {str(e)}")
            return None



class DataPlatform:
    def __init__(self, base_url: str, app_id: str, app_secret: str):
        self.base_url = base_url
        self.app_id = app_id
        self.app_secret = app_secret
        self.session = requests.Session()
        self.authorization = self.get_authorization()

    def get_authorization(self) -> str:
        """获取认证token"""
        headers = {
            'Accept': '*/*',
            'Content-Type': 'application/json',
        }
        json_data = {
            'appId': self.app_id,
            'appSecret': self.app_secret
        }
        response = self.session.post(f'{self.base_url}/login/appLogin', 
                                  headers=headers, json=json_data).json()
        return response['data']

    def get_api_data_exclude_params(self, api_id: str) -> Dict[str, Any]:
        """获取API数据(不包含参数)"""
        headers = {
            'Accept': '*/*',
            'Content-Type': 'application/json',
            'Authorization': self.authorization
        }
        json_data = {'apiId': api_id}
        response = self.session.post(f'{self.base_url}/callApi/callApiById', 
                                  headers=headers, json=json_data).json()
        return response

    def get_api_data_include_params(self, api_id: str, params: Dict[str, str]) -> Dict[str, Any]:
        """带参数的API调用"""
        headers = {
            'Accept': '*/*',
            'Authorization': self.authorization,
            'Content-Type': 'application/json'
        }
        json_data = {
            'apiId': api_id,
            'params': params
        }
        response = self.session.post(f'{self.base_url}/callApi/callApiById', 
                                  headers=headers, json=json_data).json()
        return response

def calculate_total_sales(data):
    """
    计算销售数据列表中所有门店的销售额总和
    
    参数:
        data: 包含销售数据的列表,每个元素是一个字典,需包含'sales_amt'键
        
    返回:
        total: 所有门店的销售额总和
    """
    total = 0.0
    for item in data:
        # 确保'sales_amt'存在且不为None
        if 'sales_amt' in item and item['sales_amt'] is not None:
            total += item['sales_amt']
    return total

def main(app_id,app_secret,base_url,projectid):

    # 创建平台实例
    platform = DataPlatform(base_url, app_id, app_secret)

    #获取当前日期
    current_date = datetime.now()
    logging.info(f"当前日期:{current_date}")
    #获取昨天日期
    last_date = current_date - timedelta(days=1)
    last_date = last_date.strftime("%Y-%m-%d")

    #获取上周同一天日期
    last_week_date = current_date - timedelta(days=8)
    last_week_date = last_week_date.strftime("%Y-%m-%d")

    #创建天气实例
    weather=FeishuWeatherBot()
    #城市是北京
    city = "Beijing" 

    # 获取北京昨日的天气
    weather_data = weather.get_historical_weather(city, last_date)

    # 初始化 weather_info with default values
    if not weather_data:
        max_temp = "未知"
        min_temp = "未知"
        condition = "未知"
    else:
        try:
            for day in weather_data["forecast"]["forecastday"]:
                max_temp = day["day"]["maxtemp_c"]
                min_temp = day["day"]["mintemp_c"]
                condition = day["day"]["condition"]["text"]
                break  # Only take the first day's data
        except (KeyError, TypeError, IndexError):
            # Fallback to default values if any error occurs during parsing
            max_temp = "未知"
            min_temp = "未知"
            condition = "未知"

    #构建天气数据字典
    weather_info={
        "day_code":last_date,
        "max_temp":max_temp,
        "min_temp":min_temp,
        "condition":condition
    }    
    
    params={
        "day_code":last_date
    }
  
    # 获取店铺面积信息
    try:
        store_area = platform.get_api_data_include_params("merchant_org_rent_pick_open_story_area_for_any_region", params)
    except Exception as e:
        logging.error("接口调用失败: merchant_org_rent_pick_open_story_area_for_any_region, 错误: %s", str(e))
        store_area = {'data': []}  # 设置默认空值以防止后续索引错误

    try:
        store_area_info = [item for item in store_area.get('data', [])][0]
        #项目GLA、店铺面积、项目开店面积比率
        gla=store_area_info.get('gla')
        act_store_area=store_area_info.get('act_store_area')
        open_store_arearate=act_store_area/gla
    except IndexError:
        logging.warning("未获取到店铺面积信息数据,data为空")
        store_area_info = {}
    

    # 获取店铺数量信息
    try:
        store_count = platform.get_api_data_include_params("merchant_org_rent_pick_open_story_nums_for_any_region", params)       
    except Exception as e:
        logging.error("接口调用失败: merchant_org_rent_pick_open_story_nums_for_any_region, 错误: %s", str(e))
        store_count = {'data': []}  # 设置默认空值以防止后续索引错误

    try:
        store_count_info = [item for item in store_count.get('data', [])][0]
        #项目已开业店铺数量、项目总店铺数量
        act_store_cnt=store_count_info.get('act_store_cnt')
        all_store_cnt=store_count_info.get('act_store_cnt')+store_count_info.get('acpt_peno_store_cnt')+store_count_info.get('sigd_entd_store_cnt')+store_count_info.get('un_sigd_store_cnt')
    except IndexError:
        logging.warning("未获取到店铺数量信息数据,data为空")
        store_count_info = {}
 
    #项目基础信息
    mall_basic_info = {
        "gla": gla,
        "act_store_area": act_store_area,
        "open_store_arearate": open_store_arearate,
        "act_store_cnt": act_store_cnt,
        "all_store_cnt": all_store_cnt,
    }

    #print(mall_basic_info)
   
    #获取店铺销售数据参数
    mall_daily_sales_params={
        "day_date_end":last_date,
        "day_date_start":last_date,
        "org_code_list":[projectid],
    }

    # 获取店铺销售数据
    try:
        mall_daily_sales = platform.get_api_data_include_params("org_sales_day_sum_for_any_region", mall_daily_sales_params)
    except Exception as e:
        logging.error("接口调用失败: org_sales_day_sum_for_any_region, 错误: %s", str(e))
        mall_daily_sales = {'data': []}  # 设置默认空值以防止后续索引错误

    try:
        #昨日商场销售金额
        mall_daily_sales_info = [item for item in mall_daily_sales.get('data', [])][0]
        mall_daily_sales_amt:float = mall_daily_sales_info.get('sales_amt')
    except IndexError:
        logging.warning("未获取到店铺销售数据,data为空")
        mall_daily_sales_info = {}


    # 查询上周同一天参数
    mall_lastweek_daily_sales_params = {
        "day_date_end": last_week_date,
        "day_date_start": last_week_date,
        "org_code_list": [projectid],
    }

    # 获取上周同一天商场销售数据
    try:
        mall_lastweek_daily_sales = platform.get_api_data_include_params("org_sales_day_sum_for_any_region", mall_lastweek_daily_sales_params)
    except Exception as e:
        logging.error("接口调用失败: org_sales_day_sum_for_any_region (上周数据), 错误: %s", str(e))
        mall_lastweek_daily_sales = {'data': []}  # 设置默认空值以防止后续索引错误

    try:
        mall_lastweek_daily_sales_info = [item for item in mall_lastweek_daily_sales.get('data', [])][0]
        #上周同一天商场销售金额
        mall_lastweek_daily_sales_amt:float = mall_lastweek_daily_sales_info.get('sales_amt')
        #商场日销售金额周环比
        lastweek_daily_sales_circle_rate=(mall_daily_sales_amt-mall_lastweek_daily_sales_amt)/mall_lastweek_daily_sales_amt
    except IndexError:
        logging.warning("未获取到上周商场销售数据,data为空")
        mall_lastweek_daily_sales_info = {}
    


    # 获取客车流数据参数
    mall_daily_custcar_params = {
        "date_day_start": last_date,
        "date_day_end": last_date,
        "org_code_list": [projectid],
    }

    # 获取客车流数据
    try:
        mall_cust_car_flow = platform.get_api_data_include_params("org_cust_car_flow_for_any_region", mall_daily_custcar_params)
    except Exception as e:
        logging.error("接口调用失败: org_cust_car_flow_for_any_region, 错误: %s", str(e))
        mall_cust_car_flow = {'data': []}  # 设置默认空值以防止后续索引错误

    try:
        mall_cust_car_flow_info = [item for item in mall_cust_car_flow.get('data', [])][0]
        #昨日商场客户车辆数
        cust_flow=int(mall_cust_car_flow_info['cust_flow'])
        car_flow=int(mall_cust_car_flow_info['car_flow'])        
    except IndexError:
        logging.warning("未获取到客车流数据,data为空")
        mall_cust_car_flow_info = {}

    # 查询上周同一天客车流参数
    mall_lastweek_daily_custcar_params = {
        "date_day_start": last_week_date,
        "date_day_end": last_week_date,
        "org_code_list": [projectid],
    }

    # 获取上周同一天客车流数据
    try:
        mall_lastweek_daily_custcar_flow = platform.get_api_data_include_params(
            "org_cust_car_flow_for_any_region", 
            mall_lastweek_daily_custcar_params
        )
    except Exception as e:
        logging.error("接口调用失败: org_cust_car_flow_for_any_region (上周数据), 错误: %s", str(e))
        mall_lastweek_daily_custcar_flow = {'data': []}  # 默认空值防止后续索引错误

    try:
        mall_lastweek_daily_custcar_flow_info = [item for item in mall_lastweek_daily_custcar_flow.get('data', [])][0]
    except IndexError:
        logging.warning("未获取到上周客车流数据,data为空")
        mall_lastweek_daily_custcar_flow_info = {}

    # 上周同一天商场客车流数
    try:
        lastweek_cust_flow = int(mall_lastweek_daily_custcar_flow_info['cust_flow'])
        lastweek_car_flow = int(mall_lastweek_daily_custcar_flow_info['car_flow'])
    except KeyError:
        logging.warning("上周客车流数据中缺少 cust_flow 或 car_flow 字段")
        lastweek_cust_flow = 0
        lastweek_car_flow = 0

    # 客户流量周环比计算(带除零保护)
    if lastweek_cust_flow != 0:
        lastweek_cust_circle_reate = (cust_flow - lastweek_cust_flow) / lastweek_cust_flow
    else:
        logging.warning("上周客户流量为零,无法计算周环比")
        lastweek_cust_circle_reate = 0.0

    # 车辆流量周环比计算(带除零保护)
    if lastweek_car_flow != 0:
        lastweek_car_circle_reate = (car_flow - lastweek_car_flow) / lastweek_car_flow
    else:
        logging.warning("上周车辆流量为零,无法计算周环比")
        lastweek_car_circle_reate = 0.0

    #print(lastweek_cust_flow,lastweek_car_flow,lastweek_cust_circle_reate,lastweek_car_circle_reate)

    # 获取项目月累计和年累计参数
    project_month_total_params = {
        "date": last_date,
        "org_code_list": [projectid],
    }

    # 获取项目月累计和年累计数据
    try:
        project_month_total = platform.get_api_data_include_params(
            "day_org_weekly-monthly-year_performance_for_any_region", 
            project_month_total_params
        )
     
    except Exception as e:
        logging.error("接口调用失败: day_org_weekly-monthly-year_performance_for_any_region, 错误: %s", str(e))
        project_month_total = {'data': []}  # 默认空值防止后续索引错误

    try:
        project_month_total_info = [item for item in project_month_total.get('data', [])][0]
    
        #年累计销售额
        year_sale_amt=project_month_total_info.get('year_sale_amt')
        #月累计销售额
        month_sale_amt=project_month_total_info.get('month_sale_amt')

        #年累计车流辆数
        year_car_flow=int(project_month_total_info['year_car_flow'])
        #月累计车流车辆数
        month_car_flow=int(project_month_total_info['month_car_flow'])

        #月累计客流数
        month_cust_flow=int(project_month_total_info['month_cust_flow'])
        #年累计客流数
        year_cust_flow=int(project_month_total_info['year_cust_flow'])
    except IndexError:
        logging.warning("未获取到项目月/年累计数据,data为空")
        project_month_total_info = {}

    #关键指标数据(不含车)
    mall_key_indices_dict={
        "mall_daily_sales_amt":mall_daily_sales_amt,
        "lastweek_daily_sales_circle_rate":lastweek_daily_sales_circle_rate,
        "cust_flow":cust_flow,
        "lastweek_cust_circle_reate":lastweek_cust_circle_reate,
        "car_flow":car_flow,
        "lastweek_car_circle_reate":lastweek_car_circle_reate,
        "year_sale_amt":year_sale_amt,
        "month_sale_amt":month_sale_amt,
        "year_car_flow":year_car_flow,
        "month_car_flow":month_car_flow,
        "month_cust_flow":month_cust_flow,
        "year_cust_flow":year_cust_flow,
    }
    
    # 获取会员数据参数
    member_params = {
        "day_code": last_date,
        "org_code_list": [projectid],
    }

    # 获取会员数据
    try:
        member_data = platform.get_api_data_include_params("member_consume_day_stats_for_any_region", member_params)
    except Exception as e:
        logging.error("接口调用失败: member_consume_day_stats_for_any_region, 错误: %s", str(e))
        member_data = {'data': []}  # 默认空值防止后续索引错误

    try:
        member_data_info = [item for item in member_data.get('data', [])][0]
        #新增会员数
        inc_mem_cnt=member_data_info.get('inc_mem_cnt')
        #消费会员数
        mem_exp_cnt=member_data_info.get('mem_exp_cnt')
        #会员消费占比
        mem_exp_ratio=member_data_info.get('mem_exp_ratio')
    except IndexError:
        logging.warning("未获取到会员数据,data为空")
        member_data_info = {}

    #print(inc_mem_cnt,mem_exp_cnt,mem_exp_ratio)
    #会员数据
    mem_data_dict={
        "inc_mem_cnt":inc_mem_cnt,
        "mem_exp_cnt":mem_exp_cnt,
        "mem_exp_ratio":mem_exp_ratio,
    }

    # 获取店铺销售参数
    store_sale_params = {
        "day_date_end": last_date,
        "day_date_start": last_date,
        "org_code_list": [projectid],
    }

    # 获取店铺销售数据
    try:
        store_sale = platform.get_api_data_include_params("store_sales_day_sum_for_any_region", store_sale_params)
    except Exception as e:
        logging.error("接口调用失败: store_sales_day_sum_for_any_region, 错误: %s", str(e))
        store_sale = {'data': []}  # 默认空值防止后续索引错误

    # 提取店铺销售数据
    try:
        store_sale_data_info = [item for item in store_sale.get('data', [])]
        store_sale_sort_data=sorted(store_sale_data_info,key=lambda x:x['sales_amt'] if x['sales_amt'] is not None else -1,reverse=True)
        store_sale_top_10=store_sale_sort_data[:10]
    except IndexError:
        logging.warning("未获取到店铺销售数据,data为空")
        store_sale_data_info = []
        
    #销售前十店铺
    #print(store_sale_top_10)

    mall_daily_sales_brief_data={
        "weather_info":weather_info,
        "mall_basic_info":mall_basic_info,
        "mall_key_indices":mall_key_indices_dict,
        "mem_data":mem_data_dict,
        "store_sale_top_10":store_sale_top_10,
    }
    return mall_daily_sales_brief_data
    
 

if __name__ == '__main__':
            # 初始化日志系统
    LoggerSetup.setup_logger()
    
    config = configparser.ConfigParser()
    
    config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.ini')
    print(config_path)
    if os.path.exists(config_path):
        config.read(config_path, encoding='utf-8')
        logging.info(f"配置文件已加载: {config_path}")
    else:
        # 创建默认配置文件
        config['interface'] = {
            'appId': '这里填写appId',
            'appSecret': '这里填写appSecret',
        }
        config['rworkinfo'] = {
            'webhook_url': '这里填写飞书机器人WebHook URL',
            'projectid': '这里填写项目ID',
            'project': '这里填写项目名称',
            'excludestore': '这里填写需要排除的店铺编号,多个店铺用英文逗号分隔'
        }
        with open(config_path, 'w') as f:
            config.write(f)
        logging.info(f"已创建默认配置文件: {config_path}")
    
    
    # 读取配置
    app_id = config.get('interface', 'appId')
    app_secret = config.get('interface', 'appSecret')
    base_url = "数据平台接口地址"
    webhook_url = config.get('rworkinfo', 'webhook_url')
    projectid = config.get('rworkinfo', 'projectid')
    project = config.get('rworkinfo', 'project')
    
    mall_daily_sales_brief_data=main(app_id,app_secret,base_url,projectid)
    #print(mall_daily_sales_brief_data)
    #创建RWork对象
    rwork=RWorkInfo(project,webhook_url)
    last_date = datetime.now() - timedelta(days=1)
    last_date = last_date.strftime("%Y-%m-%d")
    #格式化模板参数
    messages=rwork.format_message(last_date,mall_daily_sales_brief_data)
    #print(json.dumps(messages, ensure_ascii=False, indent=2))
    #发送消息
    
    logging.info("开始发送消息")
    try:
        rwork.send_to_feishu(messages)
        logging.info("消息已成功发送至*工作")
    except Exception as e:
        logging.error("发送消息至*工作失败: %s", str(e))


Powered By Z-BlogPHP 1.7.2

Mail to:hhesong@126.com. Copyright elecccom.cn.Some Rights Reserved.冀ICP备18030769号-1