From 89dfc33c24ac2584442be8e26273c86725377eaf Mon Sep 17 00:00:00 2001 From: BXY <103352887+BXY0414@users.noreply.github.com> Date: Tue, 8 Sep 2026 11:22:42 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 8196 -> 0 bytes README.md | 233 ++++++++++++++++++ .../project_bitable_common.cpython-312.pyc | Bin 87061 -> 89541 bytes 3 files changed, 233 insertions(+) delete mode 100644 .DS_Store create mode 100644 README.md diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index f65da4ae8099250fc8a3ae5aece2a7b77222cf72..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHM%We}f6g@7Hh#Cp;5)G;f^8-ZU2T*7e5MlvpVTT&>P9e#JOj-g9$P$Sy5<7l@ zpWvtH2F|rDnDI=ZD}>-$vd@g?K9B7g-2{NyKJ48DssPIDg6At73Yt8Zo@;A<<|5Hh zALydZK0+U@oU~3T1ImChpbRJj%D~^i0KeJN$|rpH-BTTv0cGI7WI)~z5xZdBmFAQttxH0>cMzb<4X+V)cHITabn%$%Ar$-aq2MMv+)&* zvEHc{S#g-ULmia?WgyRh)b15l>n+UiDpS9=?v3MaXB>AZ!9%q+B!2p4n>BNm(sNe& zZ7ewU0_m5Oxs{T>gdSpQJg4j&H+U6eLZ2}b&eZ6;&HHiIig_RSyc}5RV@mIHYKx@< zdsm~yQDEn5U}pmjJird_qlsPS{*Yr6ci4CEi1&}NhugTz`x>JPa>M7q+B&WM%x%Cp z#^`4wpf#9tDLytaWZqNDhGS4xU`{*FIM-!XElNyqMC>x7BSyj%%33vBK_u5sVO7>_ zfJ6H3{mQmPoLTR!Q`kiD`XkS8!-`W5y>;4h!?`{AK(y^9zH}{X#x@i3wRJ8vskI~a ur|i;1ZspLbaIob#(U#-HAAcC~I-;oP)IF{oa)wQR2(UEhpbY#`2EGGwHA#*D diff --git a/README.md b/README.md new file mode 100644 index 0000000..4dce4d1 --- /dev/null +++ b/README.md @@ -0,0 +1,233 @@ +# 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` | 跳过表匹配错误,默认未开启 | +| `--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.yaml` 对应 deployment 的 `parameters.skip_missing_tables` 改为 `true`,再重新执行 `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 +``` diff --git a/__pycache__/project_bitable_common.cpython-312.pyc b/__pycache__/project_bitable_common.cpython-312.pyc index 47c207784db39732fff6ba35c4719741c9060559..78a78a639e57bc39921fa6d0e7ac4f645b641afd 100644 GIT binary patch delta 18536 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 CZ`}I; delta 16769 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