Files

234 lines
9.3 KiB
Markdown

# GMV Analytics
按项目、店铺和日期统计销售金额、退款金额及 GMV,并同步到飞书多维表格。支持本地手动执行、历史日期补数,以及通过 Docker + Prefect 定时运行。
## 项目介绍
数据来自 PostgreSQL,通过 `店铺映射表.xlsx` 将 BI 店铺名称转换为业务店铺名称,再按项目和月份匹配飞书目标表。
- 支持项目:大眼睛、羽心堂、MMMJ、EM、春回盏、BROKEN ZOO。
- 计算口径:`GMV = 销售金额 - 退款金额`,具体取数 SQL 位于 `project_bitable_common.py`。
- 本地流水线逐日查询销售额和退款额,计算 GMV,写入对应项目的月份表。
- 当前流水线使用“日期”“指标”和各店铺数值列,指标包括“销售金额”“退款金额”“GMV”“汇总GMV”。汇总逻辑读取表内当月、不晚于处理日期的 GMV 记录进行累加。
- 可选择同步完成后向飞书群发送通知。
## 环境准备
需要 Python 3.12 或以上版本、可连接的 PostgreSQL 数据库,以及具有目标多维表格访问和写入权限的飞书应用。
以下命令均在项目根目录执行。已有 Conda / Python 环境时,先激活该环境。
使用 uv 安装依赖并进入虚拟环境:
```bash
uv sync
source .venv/bin/activate
```
也可以在已有 Python 环境中安装项目声明的依赖:
```bash
python - <<'PY'
import subprocess
import sys
import tomllib
from pathlib import Path
config = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))
subprocess.check_call([sys.executable, "-m", "pip", "install", *config["project"]["dependencies"]])
PY
```
## 配置 .env
在项目根目录创建或编辑 `.env`。下面均为占位值,请替换为实际配置:
```dotenv
ANALYTICS_DB_HOST=your-db-host
ANALYTICS_DB_PORT=5432
ANALYTICS_DB_NAME=your-db-name
ANALYTICS_DB_USER=your-db-user
ANALYTICS_DB_PASSWORD=your-db-password
FEISHU_APP_ID=your-app-id
FEISHU_APP_SECRET=your-app-secret
FEISHU_BASE_URL=https://your-tenant.feishu.cn/base/your-base-token
SYNC_START_DATE=2026-09-01
```
脚本自动加载项目根目录的 `.env`,已存在的进程环境变量优先于 `.env`。当前加载器按 `KEY=value` 读取,值不要额外加引号,也不要在值后追加行内注释。
`.env` 已加入 `.gitignore`,用于保存本地配置。
可选配置:
| 变量 | 用途与默认行为 |
| --- | --- |
| `PROJECT_MAPPING_FILE` | 店铺映射文件路径;不设置时使用脚本目录下的 `店铺映射表.xlsx` |
| `SYNC_START_DATE` | 本地流水线默认开始日期;未设置时为 `2026-04-01` |
| `FEISHU_CHAT_ID` | 应用机器人通知的目标群;配置后优先使用此方式 |
| `FEISHU_BOT_WEBHOOK` | 未设置群 ID 时使用的群机器人 Webhook |
| `FEISHU_REPORT_IMAGE_PATH` | 应用机器人通知使用的本地预览图路径 |
| `FEISHU_STORE_FIELD_NAME` | 独立脚本使用的店铺字段名,默认 `店铺名称` |
| `PREFECT_API_URL` | Prefect Server API 地址,本地流水线不需要 |
| `LOG_DIR` | 日志目录,默认项目下的 `logs` |
| `LOG_LEVEL` | 日志级别,默认 `INFO` |
映射文件读取第一个活动工作表,跳过第一行表头。三列及以上时,使用第 2 列作为业务店铺名称、第 3 列作为 BI 店铺名称;只有两列时,依次为业务店铺名称、BI 店铺名称。
## 本地执行
本地入口为 `run_project_bitable_pipeline.py`,可直接使用 Python 运行,无需启动 Docker 或 Prefect Server。未激活 uv 虚拟环境时,也可以将以下命令中的 `python` 替换为 `uv run python`。
### 指定一天
将开始日期和结束日期设为同一天:
```bash
python run_project_bitable_pipeline.py \
--start-date 2026-09-07 \
--end-date 2026-09-07 \
--no-notify \
--skip-missing-tables
```
### 指定日期范围
例如同步 2026 年 9 月 1 日至 9 月 7 日,包含首尾两天:
```bash
python run_project_bitable_pipeline.py \
--start-date 2026-09-01 \
--end-date 2026-09-07 \
--no-notify \
--skip-missing-tables
```
`--no-notify` 表示只同步数据,不发群通知。需要通知时,配置通知渠道并去掉该参数。
`--skip-missing-tables` 表示找不到对应表时记录日志并继续处理其他项目和日期,不会自动创建月份表。匹配到多个表、映射指定表不存在等配置错误仍会中断运行,避免写入错误的表。
### 预览执行
```bash
python run_project_bitable_pipeline.py \
--start-date 2026-09-01 \
--end-date 2026-09-07 \
--dry-run \
--no-notify \
--skip-missing-tables
```
`--dry-run` 会查询数据库、获取飞书访问令牌和表列表,并输出计划处理的表、日期和指标,不写入飞书、不发通知。因此仍需有效的数据库和飞书配置。
### 常用参数
| 参数 | 说明 |
| --- | --- |
| `--start-date YYYY-MM-DD` | 开始日期,默认读取 `SYNC_START_DATE` |
| `--end-date YYYY-MM-DD` | 结束日期,默认运行机器本地日期的昨天 |
| `--no-notify` | 跳过飞书群通知,默认未开启 |
| `--skip-missing-tables` | 本地流水线跳过缺失月份表,默认未开启;Prefect 默认开启,并在完成后推送缺失表提醒 |
| `--dry-run` | 预览,不执行飞书写入和通知 |
| `--mapping-file PATH` | 指定店铺映射 Excel 文件,覆盖环境变量配置 |
| `--table-map-file PATH` | 指定项目月份到飞书表名的 JSON 映射 |
| `--base-url URL` | 指定飞书多维表格地址;仍需在环境中配置 `FEISHU_BASE_URL`,当前参数解析会读取其默认值 |
日期范围的结束日期不能早于开始日期。本地流水线未传日期时会从默认开始日期一直同步到昨天;补数时建议明确传入两个日期。
完整参数可在配置好 `.env` 后查看:
```bash
python run_project_bitable_pipeline.py --help
```
## 常见问题
### 映射表路径不存在
如果出现 `FileNotFoundError`,且路径仍指向其他机器上的 `/Users/idss/...`,请修改 `.env` 中的 `PROJECT_MAPPING_FILE`,或删除该配置以使用项目自带文件。
也可以在命令中添加以下参数,直接覆盖旧路径:
```bash
--mapping-file ./店铺映射表.xlsx
```
### 找不到对应月份的飞书表
例如“羽心堂”只有 3—8 月表,执行 9 月数据时会报 `未找到匹配表`。临时跳过可添加 `--skip-missing-tables`;补齐月份表后,再运行对应日期范围。
### 表名不规范或匹配到多个表
创建 `table_map.json`,键格式为 `项目:YYYY-MM`,值为飞书中实际存在的完整表名:
```json
{
"大眼睛:2026-09": "大眼睛买买买-9月",
"羽心堂:2026-09": "羽心堂-9月"
}
```
执行时添加 `--table-map-file ./table_map.json`。自动匹配支持项目别名和月份文本,跨年份存在同名月份表时应显式指定映射。
## Prefect 执行与定时调度
手动触发一次 Prefect 数据同步:
```bash
python prefect_gmv_scheduler.py \
--mode sync \
--start-date 2026-09-01 \
--end-date 2026-09-07 \
--skip-missing-tables
```
| 模式 | 行为 |
| --- | --- |
| `--mode sync` | 只同步数据 |
| `--mode notify` | 只发送通知 |
| `--mode all` | 先同步再通知,默认模式 |
Prefect 同步未显式指定日期时,默认处理截至昨天的最近 5 天,并以 `SYNC_START_DATE` 为最早边界。缺失月份表会自动跳过,其余表仍会写入;同步结束后,缺失的“项目 + 月份”会汇总为一条飞书提醒。通知未指定日期时,优先读取上次成功同步保存的日期范围。
`prefect.yaml` 定义了北京时间每天 08:00 同步、09:00 通知两条调度。部署前需准备可访问的 Prefect Server,并配置 `PREFECT_API_URL`。
```bash
docker compose up -d --build
docker exec -it prefect-gmv-worker sh -lc 'cd /app && prefect deploy --all'
```
Compose 启动的是等待调度任务的 worker。当前 Prefect deployment 默认跳过缺失月份表,并在同步结束后推送一条汇总提醒。修改 `prefect.yaml` 后,执行 `prefect deploy --all` 注册新配置。
更多部署说明见项目中的 `DOCKER_PREFECT_USAGE.md`;其中示例的本机目录需要替换为实际项目目录。
## 文件说明与日志
| 文件 | 用途 |
| --- | --- |
| `run_project_bitable_pipeline.py` | 本地完整流水线入口,使用日期 / 指标行结构 |
| `project_bitable_common.py` | SQL、店铺映射、表匹配、飞书 API、同步与通知逻辑 |
| `prefect_gmv_scheduler.py` | Prefect flow、日期窗口和执行模式 |
| `generate_project_sales_csv.py` | 独立销售额同步脚本 |
| `generate_project_refund_csv.py` | 独立退款额同步脚本 |
| `generate_project_gmv_csv.py` | 从飞书销售额和退款额字段计算并回写 GMV |
| `店铺映射表.xlsx` | BI 店铺与业务店铺名称映射 |
| `logging_config.py` | 控制台与轮转文件日志 |
| `prefect.yaml` | 定时任务与 work pool 配置 |
| `docker-compose.yaml` / `Dockerfile` | 容器运行与构建配置 |
三个 `generate_project_*_csv.py` 文件虽带有 `csv` 后缀,实际执行飞书同步;它们使用以店铺为记录、日期指标为字段的结构,与当前完整流水线的表结构不同。日常运行使用完整流水线入口。
默认日志写入 `logs/gmv_sync.log`,单个文件达到 10 MiB 后轮转,保留 7 个备份。
```bash
tail -f logs/gmv_sync.log
```
Docker worker 日志:
```bash
docker logs -f prefect-gmv-worker
```