﻿---
name: jd-shop-data-skill
description: >-
  京东店铺数据获取与毛利分析技能。自动从京东API获取店铺销售数据、商品SKU销售数据、京准通付费推广数据，计算毛利指标（供货回款、毛保返利、产品成本、毛利润、毛利率），生成Excel报表。支持多店铺合并报表（店铺配置表配置多个店铺，按"所属店铺"字段自动分组处理）。支持综合毛保和商品毛保两种模式，Cookie过期自动检测，支持昨天、近7天、近30天、自定义日期范围。所有SKU统一使用 getDealDetailData 逐个查询（getHotSalesTable已废弃，返回-407不安全的请求）。所有SKU均导出（含零成交）。支持周报/日报HTML生成，含流量→销售、推广→产出、毛利拆解、库存健康四维分析。v4.2.0新增：API缓存层（自动缓存24h，同天同数据不重复请求）+ 历史数据仓库（SQLite永久存储，支持日环比/周环比/SKU趋势查询）。v4.4.0新增：周报HTML生成器（7板块，本周vs上周环比）、库存明细自动写入（多键容错+SKU聚合）、代码清理（移除废弃API和死代码）。触发词：京东数据、店铺数据、商品销售数据、获取数据、生成报表、毛保计算、日报、周报、库存、经营日报、历史数据、趋势、环比。
license: MIT
metadata:
  author: hxhw
  version: 4.4.0
  created: 2026-05-18
  last_reviewed: 2026-07-10
  review_interval_days: 90
  python_dependencies:
    - pandas
    - openpyxl
    - requests
  dependencies:
    - url: https://zhgateway.jd.com/brand/dealAnalysis/dealSummary/getVenderDealSummayData.ajax
      name: 京东商智SKU销售API (ppzh)
      type: api
    - url: https://atoms-api.jd.com/reweb/common/index/indicator
      name: 京准通付费推广API
      type: api
    - url: https://atoms-api.jd.com/reweb/common/index/overview
      name: 京准通总花费拆解API
      type: api
    - url: https://jzt-api.jd.com/reweb/swa/account/campaign/list
      name: 全站营销效果报表API
      type: api
    - url: https://jzt-api.jd.com/dataCenter/customreport/msa/report/operateData
      name: 快车效果报表API
      type: api
    - url: https://jdsz.jd.com/brand/dealAnalysis/dealDetail/getDealDetailData.ajax
      name: 商品销售明细API（SKU级，按天/范围查询，所有SKU统一使用）
      type: api
    - url: https://szgateway.jd.com/api/inventoryajax/lowcf/v1/inventoryOverview/overviewCard.ajax
      name: 库存概览卡片API（汇总指标）
      type: api
    - url: https://szgateway.jd.com/api/inventoryajax/paasf/v1/productInventoryDetail/overviewDetail.ajax
      name: 商品库存明细API（SKU+仓库维度）
      type: api
---

# /jd-shop-data — 京东店铺数据获取与毛利分析

你是一个专业的京东店铺数据分析专家。你的任务是帮助用户获取京东店铺销售数据、商品SKU销售数据、京准通付费推广数据，并自动计算毛利相关指标，生成Excel报表。

## 部署方式（解压即用）

1. 将整个 `jd-shop-data-skill` 文件夹放到 skills 目录：
   - **Codex**: `~/.codex/skills/jd-shop-data-skill/`
   - **通用 Agent**: `~/.agents/skills/jd-shop-data-skill/`
   - **WorkBuddy**: `~/.workbuddy/skills/jd-shop-data-skill/`
   - **TRAE SOLO**: `~/.trae/skills/jd-shop-data-skill/`
2. 直接用，无需任何安装命令。

**首次使用自动初始化**：
- Python依赖（pandas/openpyxl/requests）**自动安装**
- 配置模板（店铺配置.xlsx / 商品配置.xlsx）**自动生成**到当前工作目录
- 用户只需打开Excel填入自己的Cookie、品牌ID、SKU和价格即可

> 安全说明：公开下载包不包含任何店铺 Cookie、品牌 ID、SKU 或经营数据。请只在自己的电脑上填写配置，不要把配置表上传到公共仓库或转发给他人。

## 触发方式

用户可以通过以下方式调用此技能：

**可用命令**：
```
/jd-shop-data 获取近7天数据
/jd-shop-data 获取昨天数据
/jd-shop-data 获取2024-01-01到2024-01-31的数据
/jd-shop-data 生成店铺销售报表
/jd-shop-data 生成日报
/jd-shop-data 生成周报
/jd-shop-data 库存分析
```

**快速模式（仅店铺数据，跳过SKU）**:
```
/jd-shop-data 获取昨天数据 --store-only
python jd_data_workflow.py --date-range "昨天" --store-only
```

**周报/日报模式（v2.4.0 新增）**:
```
/jd-shop-data 获取近7天数据 并生成周报
/jd-shop-data 获取昨天数据 并生成日报
```
- 获取数据时会自动提问是否生成周报/日报
- 也可在命令中直接指定需要生成

**库存分析模式（v3.0.0）**:
```
/jd-shop-data 库存分析
/jd-shop-data 库存分析 2026-05-27
```
- 默认获取昨天的库存概览、库存健康指标、滞销商品明细
- 可指定日期获取特定日期的库存数据

## 工作流程

### 🏪 多店铺支持（v2.1.0 新增，v2.2.0 优化sheet结构）

- 店铺配置表可配置**多个店铺**（每行一个），每个店铺有独立的 Cookie、品牌ID、毛保方式/点位
- 商品配置表中的 **"所属店铺"** 列用于匹配对应店铺的 Cookie 和毛保规则
- 执行时按店铺分组独立获取数据，最终汇总到**同一份 Excel**
- **商品销售数据**：按品牌自动分sheet（`全部商品` + 各品牌sheet），同品牌多店铺用店铺前缀区分
- **店铺销售数据**：所有店铺汇总到单sheet，每行一个店铺
- Cookie 过期的店铺自动跳过，不影响其他店铺数据获取
- 商品配置中无对应店铺的 SKU 会使用第一个店铺的配置（兼容旧版）

### Phase 1: 检查配置文件

**输入**: 当前工作目录
**输出**: 配置文件状态确认

检查以下配置文件是否存在：
- `店铺配置.xlsx` - 包含店铺信息（cookie、品牌ID、毛保点位、毛保方式）
- `商品配置.xlsx` - 包含商品信息（SKU、采购价、成本价）

**边界条件处理**:

| 场景 | 处理动作 |
|------|----------|
| 配置文件不存在 | **自动生成模板**到当前目录，提示用户填入真实数据后重试 |
| 配置表字段缺失 | 提示缺少的字段，终止执行 |
| Cookie为空 | 提示需要填写Cookie |
| 首次运行 | 自动安装pip依赖 + 生成配置模板（用户只需填数据）

### Phase 2: 解析日期范围

**输入**: 用户提供的日期范围字符串
**输出**: 开始日期、结束日期

支持的日期范围格式：

| 格式 | 说明 | 示例 |
|------|------|------|
| 不填/空 | 默认昨天 | - |
| `昨天` | 昨天 | `昨天` |
| `近7天` | 最近7天（不含今天） | `近7天` |
| `近30天` | 最近30天（不含今天） | `近30天` |
| `YYYY-MM-DD` | 单天 | `2026-05-17` |
| `YYYY-MM-DD ~ YYYY-MM-DD` | 自定义范围 | `2026-05-01 ~ 2026-05-17` |

**边界条件处理**:

| 场景 | 处理动作 |
|------|----------|
| 日期格式无法解析 | 提示支持的格式，要求重新输入 |
| 结束日期早于开始日期 | 交换两个日期 |
| 日期范围超过90天 | 提示范围过大可能影响性能，询问是否继续 |

### 🔴 Phase 3: 数据获取前确认（v2.3.0 新增检查点，v2.4.0 新增周报/日报提问）

> 🔴 **CHECKPOINT · 执行前确认**
> 
> **输入**: 已加载的配置、日期范围
> **输出**: 用户确认执行、是否生成周报/日报

向用户展示执行摘要并**等待确认**：

```
即将执行数据获取：
- 店铺数：2 个（示例店铺A、示例店铺B）
- 商品SKU：若干
- 日期范围：2026-05-19 ~ 2026-05-19（1 天）
- 预计耗时：约 60-90 秒（示例）

是否继续？[是/否]
```

**周报/日报提问（v2.4.0 新增）**：

根据日期范围自动判断并提问：

| 日期范围 | 提问内容 |
|----------|----------|
| 近1天/昨天/单天 | "是否同时生成日报？[是/否]" |
| 近7天/7天范围 | "是否同时生成周报？[是/否]" |
| 其他范围 | 不提问，直接执行 |

**边界条件**:

| 场景 | 处理动作 |
|------|----------|
| 店铺数≥5且SKU≥200 | 预估耗时3-5分钟，额外提示 |
| 日期范围>7天 | 提示可能耗时较长，建议分批执行 |
| 用户取消 | 终止执行，不产生任何文件 |
| 用户选择生成周报/日报 | 在数据获取完成后自动进入Phase 7 |


**快速模式分支（--store-only）**：

| 条件 | 处理 |
|------|------|
| 用户指定 --store-only | 仅获取店铺销售数据，跳过SKU获取、毛利计算，直接进入Phase 6生成店铺销售报表 |
| 用户未指定 | 默认获取全量数据（店铺+SKU+毛利） |
### Phase 4: 数据获取

**输入**: 配置文件、日期范围
**输出**: 原始销售数据、付费数据

**历史库前置检查 + 分粒度数据库（v4.3.1）**：

在实际调用 API 之前，系统根据日期跨度自动选择数据库，并检查是否已有目标数据：

| 日期跨度 | 数据库路径 | 是否支持 allow_range |
|---------|-----------|-------------------|
| 单日（`昨天` / `2026-07-08`） | `db/jd_history.db`（日报库） | 否（禁止多天聚合） |
| 2-7天（`近7天`） | `db/jd_weekly.db`（周报库） | 是 |
| 8-31天（`近30天`） | `db/jd_monthly.db`（月报库） | 是 |

前置检查逻辑：
| 条件 | 处理 |
|------|------|
| 所有店铺目标日期数据已存在 | **跳过 API 获取**，直接返回 `skipped_api=True`，进入报告生成 |
| 部分店铺缺失 | 正常走 API 获取流程 |
| `--force` 参数指定 | 强制重新获取，忽略前置检查 |

> 设计意图：昨天的数据永远不会变，历史库有了就不该再调接口。不同粒度数据分库存储，互不污染。api_cache（24h TTL）是"短期缓存"；历史库是"永久底仓"。两者配合：24h 内命中 api_cache → 24h 后命中历史库。

**执行逻辑**:
1. 按店铺分组，使用 getDealDetailData 逐SKU获取销售数据（自动合并APP/PC/微信3渠道）
2. 获取店铺汇总销售数据
3. 获取京准通付费推广数据（overview API 取总花费，indicator API 取快车明细）
4. v3.0.0: 自动获取库存数据（需配置 brand_id + third_category_id）

**API 端点和参数细节**: 参见 `references/api-spec.md`

| 失败模式 | 一线修复 | 仍失败兜底 |
|---------|---------|-----------|
| Cookie过期 | 跳过该店铺 | 继续处理其他店铺 |
| 网络超时 | 自动重试3次（指数退避） | 跳过该SKU/店铺 |
| overview API失败 | 自动降级到 indicator API | 仅使用快车数据 |
| 某些指标无法计算 | 对应字段留空 | 标注"数据不足无法计算" |
| 有成交但付费为0 | 输出警告 | 提醒检查京准通开通状态 |

### Phase 5: 计算毛利指标

**输入**: 原始销售数据、付费数据
**输出**: 带毛利指标的数据

#### 商品销售数据计算公式

| 指标 | 公式 |
|------|------|
| 供货回款金额 | 成交件数 × 采购价 |
| 毛保返利 | 成交金额 × 毛保点位 - (成交金额 - 供货回款金额) |
| 产品成本 | 成交件数 × 采购成本价 |
| 成本合计 | 产品成本 + 毛保返利 |
| 毛利润 | 供货回款金额 - 成本合计 |
| 毛利率 | 毛利润 / 供货回款金额 × 100% |
| 京东毛利率 | (成交金额 - 供货回款金额) / 成交金额 × 100% |

使用 overview API 获取总花费及各类型拆解：

| 字段 | 说明 |
|------|------|
| totalCost | 总花费（快车+全站营销+站外） |
| msaCost | 快车花费 |
| swaCost | 全站营销花费 |
| zhanwaiCost | 站外广告花费 |

#### 店铺销售数据计算公式

| 指标 | 公式 |
|------|------|
| 供货回款金额 | 所有商品供货回款金额之和 |
| 毛保返利 | 所有商品毛保返利之和（商品毛保模式下只取正值） |
| 产品成本 | 所有商品产品成本之和 |
| **付费花费** | **overview API 返回的总花费 totalCost** |
| 成本合计 | 付费花费 + 毛保返利 + 产品成本 |
| 毛利润 | 供货回款金额 - 成本合计 |
| 毛利率 | 毛利润 / 供货回款金额 × 100% |
| 成交单价 | 成交金额 / 成交人数 |
| 成交转化率 | 成交人数 / 访客数 × 100% |
| 付费占比 | 付费花费 / 成交金额 × 100% |
| **总订单金额** | **京准通 API 返回的 totalOrderSum（付费推广带来的订单金额）** |
| **投产比** | **总订单金额 / 付费花费** |
| 广告双计30% | 付费花费 × 0.3（商品毛保模式下不计算，留空） |
| **日均毛利目标** | **店铺配置表中的"日均毛利需完成(单位W)"字段** |
| **日均毛利完成进度** | **毛利润(转换为万元) / 日均毛利目标 × 100%** |

#### 毛保方式说明

- **综合毛保**：所有商品毛保返利都计入求和
- **商品毛保**：只取商品毛保返利为正数的值求和，负数不计入

**边界条件处理**:

| 场景 | 处理动作 |
|------|----------|
| 供货回款金额为0 | 毛利率设为0，避免除零错误 |
| 毛保返利计算为负（商品毛保模式） | 设为0，不计入汇总 |
| 数据缺失 | 对应字段设为0，记录警告 |

### Phase 6: 生成报表

**输入**: 计算后的数据
**输出**: Excel文件

生成两个Excel文件到当前目录：
- `商品销售数据.xlsx` - 包含各SKU的销售数据和毛利指标
- `店铺销售数据.xlsx` - 包含店铺整体销售数据和毛利指标

**商品销售数据sheet结构（v2.2.0）**:
- `全部商品` — 所有店铺SKU汇总
- 按品牌分sheet（如`品牌示例A`、`品牌示例B`、`品牌示例C`）
  - 品牌提取规则：取店铺名前3字
  - 品牌重复时（如多个品牌示例B店铺），用店铺简称区分（前6字）

**文件命名规则**:
- 单日数据: `商品销售数据_2026-05-17.xlsx`
- 范围数据: `商品销售数据_2026-05-01_至_2026-05-17.xlsx`

**边界条件处理**:

| 场景 | 处理动作 |
|------|----------|
| 文件已存在 | 覆盖并提示 |
| 磁盘空间不足 | 提示用户清理空间 |
| 文件被占用 | 提示关闭文件后重试 |

### 🔴 Phase 7: 周报/日报生成（v2.4.0 新增，v3.0.0库存分析）

> 🔴 **CHECKPOINT · 数据获取确认**
> 
> **输入**: 店铺数据、商品销售数据、快车效果报表、全站营销效果报表、库存数据
> **输出**: 日报HTML（Freddy风格）或周报HTML（7板块，本周vs上周环比）

**触发条件**:
- 用户在Phase 3确认生成日报/周报

**前置条件（执行前必须确认）**：

| 条件 | 获取方式 | 缺失时处理 |
|------|---------|-----------|
| pinId（京准通账号ID） | 从店铺配置表的pin_id列读取；若为空，询问用户提供 | 无pinId则跳过快车数据，在周报中标注[快车数据暂缺] |
| 	hirdCategoryId（三级类目ID） | 从店铺配置表的	hird_category_id列读取；若为空，通过商智品牌版类目查询API获取 | 无法获取则库存健康分析跳过，在报告中标注[类目ID暂缺] |
- 日报：日期范围为近1天/昨天/单天
- 周报：日期范围为近7天/7天范围

**数据来源**:
1. 店铺销售数据（店铺销售数据.xlsx）
2. 商品销售数据（商品销售数据.xlsx）
3. **非全站营销汇总数据**（快车+站外，通过 `jzt-api.jd.com/dataCenter/index/v2/summary/overview` API获取）
   - 需要 `pinIdList: [<your_pinId>]`，`businessType: [-4, 256]`
4. **全站营销效果明细**（通过 `jzt-api.jd.com/reweb/swa/account/campaign/list` API获取，必须传 `isDaily: False`）
5. **库存数据（v3.0.0）** — 生成日报/周报时自动获取以下3个库存API数据：
   - 库存概览卡片：8项汇总指标（库存金额/件数、出库金额/件数、周转、现货率等）
   - 库存健康指标：4项风险指标（滞销、长库龄、非上柜、不动销）
   - 库存健康-商品明细：滞销商品按配送中心分布明细

**非全站营销汇总API参数**:
```json
{
  "pinIdList": [<your_pinId>],
  "businessType": [-4, 256],
  "skuBrandId": [],
  "skuCid3": [],
  "clickOrOrderDay": 15,
  "clickOrOrderCaliber": 0,
  "impressionOrClickCaliber": 0,
  "isGift": 0,
  "orderStatusCategory": 1,
  "startDate": "YYYY-MM-DD",
  "endDate": "YYYY-MM-DD",
  "marketingObjectives": [],
  "marketingScenarios": [],
  "marketingTargetingTypes": []
}
```
请求参数: `requestFrom=0&businessFrom=1`

**全站营销效果报表API参数**:
```json
{
  "campaignTypes": [101],
  "startDay": "YYYY-MM-DD",
  "endDay": "YYYY-MM-DD",
  "pageNum": 1,
  "pageSize": 50,
  "obys": "cost|desc",
  "clickOrOrderCaliber": 0,
  "clickOrOrderDay": 15,
  "orderStatusCategory": 1,
  "requestFrom": 0
}
```

#### 日报格式（自由发挥，v3.0.0库存分析）

日报以专业电商运营角度分析当日数据，包含但不限于：
- 核心指标概览（GMV、订单数、转化率、ROI等）
- 流量来源分析（自然流量vs付费流量）
- 商品表现TOP5分析
- 广告投放效果（快车、全站营销）
- **库存状况分析（v3.0.0）**：
  - **库存水位**：库存金额、库存件数、采购未到货——判断是否需要补货/控货
  - **周转效率**：数量周转天数变化趋势（同比环比分分析）
  - **现货率**：PV现货率、实库现货率——是否存在缺货风险
  - **健康风险诊断**：
    - 滞销库存数量和占比——是否在合理范围内，趋势是否恶化
    - 长库龄/不动销库存——哪些商品需要加速清货
    - 非上柜库存——是否存在已下柜但未处理完的库存
  - **库存优化建议**：基于数据给出具体行动（如：XX配送中心XX商品周转115天已超标，建议降价清货或调拨）
- 异常指标预警
- 次日优化建议

输出格式：HTML（Freddy主题 + UTF-8 BOM），保存为 `京东店铺经营日报_YYYY-MM-DD.html`

#### 周报格式（HTML，7板块）

详见 `scripts/gen_weekly_report.py`（项目目录中）。周报HTML含以下7个板块：

1. **KPI仪表盘**：12个核心指标 + 本周 vs 上周环比
2. **店铺排名**：22店按成交排名 + 周均毛利进度 = 毛利润(万元) / (日均毛利目标×7)
3. **商品TOP10**：成交排行 + 涨幅/跌幅放大镜 + 亏本SKU列表
4. **推广效率诊断**：ROI排行 + 低效SKU(ROI<1) + 浪费搜索词(零成交) + 地域效率
5. **全站营销概览**：各店全站营销订单数和金额
6. **关键洞察**：主力店/ROI最高/付费效率/亏本汇总
7. **下周行动建议**：加预算/缩预算建议 + 关停低效SKU

**边界条件处理（v3.0.0库存）**:

### 失败模式 if-then 三段式表

| 触发条件 | 一线修复 | 仍失败兜底 |
|---------|---------|-----------|
| **非全站营销/全站营销API失败** | 跳过该部分数据分析 | 在报告中标注"数据获取失败"，其他数据正常展示 |
| **库存概览API失败** | 跳过库存概览部分 | 不影响销售数据报告，继续生成 |
| **库存健康/明细API失败** | 跳过库存健康分析 | 标注"库存健康数据获取失败"，销售数据正常 |
| **库存API返回空数据** | 检查thirdCategoryId是否正确 | 标注"当前无库存数据"，不报错 |
| **thirdCategoryId未配置** | 跳过库存分析，仅记录日志 | 不影响销售数据主流程 |
| **库存模块导入失败** | _HAS_INVENTORY=False，自动降级 | 主流程正常运行，库存功能不可用 |
| **某些指标无法计算** | 对应字段留空 | 不瞎写，标注"数据不足无法计算" |
| **Cookie过期** | 提示用户更新Cookie | 跳过该店铺，继续其他店铺 |
| **网络超时** | 自动重试（指数退避） | 重试3次后跳过，标注"连接超时" |
| **文件已存在** | 提示用户确认覆盖 | 用户选择覆盖/重命名/跳过 |
| **日期范围超过90天** | 提示范围过大 | 询问是否继续，或建议分批获取 |

---

## 失败模式编码说明

每个Phase必须显式处理以下失败分支：

| Phase | 失败条件 | 处理动作 |
|-------|---------|---------|
| Phase 1 | 配置文件不存在 | 自动生成模板，提示用户填入数据后重试 |
| Phase 1 | 配置文件格式错误 | 提示错误位置，提供示例格式 |
| Phase 2 | Cookie过期/无效 | 提示更新Cookie，跳过该店铺继续其他 |
| Phase 4-6 | API调用失败 | 按 if-then 表处理，标注失败原因 |
| Phase 7 | 数据不足无法生成报告 | 提示数据缺失，建议扩大日期范围 |
| 全局 | 网络异常 | 指数退避重试3次，仍失败则跳过 |
| 全局 | 文件写入失败 | 提示检查权限，建议更换输出路径 |

---

## 反例与黑名单（禁止事项）

> ⚠️ **以下行为绝对禁止，执行时必须严格遵守**

### 🚫 数据安全黑名单

| 禁止行为 | 为什么禁止 | 正确做法 |
|---------|-----------|---------|
| **泄露用户Cookie** | Cookie是敏感凭证，泄露导致店铺被盗 | Cookie仅用于API调用，绝不输出到日志/报告 |
| **硬编码API密钥** | 安全风险，密钥泄露 | 所有凭证从配置文件读取 |
| **将数据发送到外部服务器** | 数据泄露风险 | 所有数据处理在本地完成 |
| **覆盖数据前不确认** | 可能导致重要数据丢失 | 文件已存在时必须提示确认 |

### 🚫 数据处理黑名单

| 禁止行为 | 为什么禁止 | 正确做法 |
|---------|-----------|---------|
| **API失败时编造数据** | 虚假数据误导决策 | 明确标注"数据获取失败"，留空处理 |
| **Cookie过期时停止全部** | 影响其他正常店铺 | 跳过该店铺，继续其他店铺 |
| **日期范围超过90天不警告** | 可能导致性能问题 | 提示范围过大，询问是否继续 |
| **网络超时立即放弃** | 偶发网络波动不应中断 | 自动重试3次（指数退避） |
| **有成交但付费为0时不提示** | 可能未开通京准通 | 输出警告，提醒检查 |

### 🚫 报表生成黑名单

| 禁止行为 | 为什么禁止 | 正确做法 |
|---------|-----------|---------|
| **指标无法计算时瞎写** | 虚假数据误导决策 | 对应字段留空，不瞎写 |
| **库存API失败时跳过不标注** | 报告不完整 | 明确标注"库存健康数据获取失败" |
| **多店铺数据混淆** | 数据归属错误 | 按"所属店铺"字段严格分组 |
| **毛保计算错误** | 影响利润核算 | 严格按公式计算，公式公开透明 |

### ✅ 数据安全原则

> **数据安全是底线，绝不触碰红线。**

1. **凭证安全**: Cookie/密钥绝不硬编码、绝不泄露
2. **本地处理**: 所有数据本地处理，不上传外部
3. **失败透明**: API失败明确标注，不编造数据
4. **覆盖确认**: 文件覆盖前必须用户确认

### ✅ 数据质量原则

1. **真实准确**: 数据来自官方API，不篡改
2. **失败标注**: 获取失败明确标注，不隐瞒
3. **公式透明**: 所有计算公式公开，可验证
4. **边界处理**: 异常情况有明确处理规则
| 周报模板字段无数据 | 留空或标注"暂无数据" |
| 用户取消生成 | 终止Phase 7，不影响已生成的Excel报表 |

### Phase 8: 库存分析（v4.0.0）

**输入**: 店铺配置表（需配置inventory_*字段）
**输出**: 库存数据报表.xlsx（库存概览 + 按店铺分sheet的商品库存明细）

**触发条件**:
- 店铺配置表中配置了 `inventory_cookie` + `inventory_third_category_id` + 概览/明细各自的 mup/mnp/uuid
- 运行 `--date-range` 日期时自动获取库存数据，支持昨天、近7天、近30天、自定义范围
- 支持独立命令：`/jd-shop-data 库存分析` 或 `/jd-shop-data 库存分析 YYYY-MM-DD`

**日期范围支持**:
- 函数签名：`fetch_inventory_data(shop_config, start_date, end_date=None)`
- 自动根据日期跨度选择 `dateType`：单天→`yestoday`/`day`，≤7天→`last7Day`/`d7`，≤30天→`last30Day`/`d30`
- 同比日期自动计算（年-1）
- 主流程自动传入 `date_range_obj.start_date` 和 `date_range_obj.end_date`

**数据来源（2个库存API）**:

1. **库存概览卡片** — `overviewCard.ajax`
   - URL: `https://szgateway.jd.com/api/inventoryajax/lowcf/v1/inventoryOverview/overviewCard.ajax`
   - 响应结构：`content[]`，每个元素是一个指标卡片
   - 返回8个指标：数量周转、PV现货率、实库现货率、库存金额、库存件数、出库金额、出库件数、采购未到货
   - ⚠️ 示例品牌店铺的kpis需要带 `logic` 前缀（含 `logicInstockRatio`）

2. **商品库存明细** — `overviewDetail.ajax`
   - URL: `https://szgateway.jd.com/api/inventoryajax/paasf/v1/productInventoryDetail/overviewDetail.ajax`
   - 响应结构：`content.datas[]`，每个元素是SKU+仓库维度的库存明细
   - 返回字段自动映射为中文：SKU_ID、商品名称、配送中心、库存件数、库存金额、可用库存、数量周转、预计可售天数、出库件数、出库金额、采购未到货、无货PV、预警标识等
   - ⚠️ 示例品牌店铺的字段名带 `logic` 前缀

**导出格式**（v4.0.0更新）:
- **库存概览 sheet**：一行一店，列：店铺名称、日期、数量周转、PV现货率、实库现货率、库存金额、库存件数、出库金额、出库件数、采购未到货
- **商品库存明细 sheets**：每个店铺独立一个 sheet（sheet名=店铺名前31字），API code 自动映射为中文列名
- API返回的 `code` 字段自动映射为中文（如 `spotStockTurnover`→数量周转，`logicStockAmount`→库存金额）

**通用请求头**（库存API认证）:
```python
headers = {
    "authority": "szgateway.jd.com",
    "accept": "*/*",
    "content-type": "application/json",
    "cookie": inventory_cookie,        # 从店铺配置表读取
    "origin": "https://jdsz.jd.com",
    "referer": "https://jdsz.jd.com/inventoryweb/view/supplychainAnalysis/inventoryOverview.html",  # 概览时使用
    # 商品库存明细时referer改为 inventoryDetail.html
    "user-mnp": overview_user_mnp,     # 库存概览专用
    "user-mup": overview_user_mup,     # 库存概览专用（需用固定值）
    "uuid": overview_uuid,             # 库存概览专用
    "x-requested-with": "XMLHttpRequest"
}
```

⚠️ **重要**：
- 库存概览和商品库存明细使用了**不同的认证参数**（mnp/mup/uuid各自独立），必须分别从对应页面抓包（步骤4a概览、步骤4b明细）
- `user-mup` 需要使用**抓包时的固定值**，不能动态生成时间戳
- 示例品牌店铺的kpi参数需要带 `logic` 前缀（如 `logicSpotStockTurnover` 而非 `spotStockTurnover`）
- Cookie 和 mup/mnp/uuid 必须来自**同一次浏览器登录会话**，否则返回403

**配置表新增字段**:

| 字段名 | 类型 | 说明 |
|--------|------|------|
| inventory_cookie | 共用 | 库存API专用Cookie |
| inventory_third_category_id | 共用 | 库存API专用三级类目ID |
| overview_user_mup | 概览专用 | 库存概览user-mup（固定时间戳） |
| overview_user_mnp | 概览专用 | 库存概览user-mnp |
| overview_uuid | 概览专用 | 库存概览uuid |
| detail_user_mup | 明细专用 | 商品库存明细user-mup（固定时间戳） |
| detail_user_mnp | 明细专用 | 商品库存明细user-mnp |
| detail_uuid | 明细专用 | 商品库存明细uuid |

**边界条件处理**:

| 场景 | 处理动作 |
|------|----------|
| 库存概览API返回空 | 跳过该指标，标注"暂无数据" |
| 库存健康API失败 | 跳过，标注"获取失败" |
| 商品明细为空 | 说明"当前无滞销商品" |
| Cookie过期 | 提示更新店铺配置表中的Cookie |
| 用户未指定日期 | 默认使用昨天 |
| thirdCategoryId为空 | 先通过品牌ID获取类目信息，或提示用户补充 |

## 配置文件格式

详细字段说明和填写示例参见 `references/config-guide.md`。

**核心配置**:
- `店铺配置.xlsx`: cookie, brand_id, shop_name, maobao_rate, maobao_type（必填），pin_id, third_category_id（可选），以及库存API字段（可选，见Phase 8）
- `商品配置.xlsx`: SKU, 所属店铺, 采购成本价, 采购价（必填），商品名称（可选）

**重要**: 商品配置中的"所属店铺"必须与店铺配置中的"shop_name"完全一致。

## 库存API参数提取

使用 `capture_inventory_params.html` 工具提取库存API参数：

1. 步骤1：提取商智Cookie（京准通页面）
2. 步骤2：提取商智参数（商智页面）
3. 步骤4a：粘贴库存概览页面 cURL → 提取 `overview_user_mup/mnp/uuid`
4. 步骤4b：粘贴商品库存明细页面 cURL → 提取 `detail_user_mup/mnp/uuid`

⚠️ 两个接口的 `user-mnp/user-mup/uuid` 不同，都需要分别抓取。
⚠️ `user-mup` 使用抓包时的固定值，不要动态生成。


## Cookie 更新方法

当检测到Cookie过期时，会提示需要更新的店铺名称。

更新方法：
1. 直接编辑 `店铺配置.xlsx` 中对应店铺的 `cookie` 列
2. 或使用Python代码更新：

```python
from config_manager import update_cookie
update_cookie('示例店铺名称', '新的Cookie值')
```

## 新增工具（v3.1-v3.3）

### 配置校验
```bash
python scripts/validate_config.py --dir /path/to/config
```
一次性报告所有配置问题（缺失字段、数据类型错误、店铺名不匹配等）。

### API 缓存
- 自动启用，缓存文件：`jd_data_cache.db`
- 缓存 TTL：24 小时
- 重跑、补数据时自动命中缓存，速度提升 5-10 倍

### 趋势对比
```bash
python scripts/jd_data_workflow.py --date-range "近7天" --compare "上月同期"
```
自动获取两个时间段数据并打印环比变化表。

### 日报HTML生成
- 脚本位于项目目录 `scripts/gen_daily_report.py`，读 `db/jd_history.db` 生成 Freddy 风格 HTML
- 12个KPI卡片 + 店铺排名 + SKU TOP10(含环比) + 库存预警 + 投放效率诊断
- 自动计算今日 vs 昨日环比

## Python API 使用示例

```python
from jd_data_workflow import run_jd_data_workflow

# 获取近7天数据
result = run_jd_data_workflow(date_range='近7天')

# 获取昨天数据
result = run_jd_data_workflow(date_range='昨天')

# 获取自定义日期范围
result = run_jd_data_workflow(date_range='2024-01-01 ~ 2024-01-31')
```

## 命令行使用

```bash
python jd_data_workflow.py --date-range "近7天"
python jd_data_workflow.py --date-range "昨天"
python jd_data_workflow.py --date-range "2024-01-01 ~ 2024-01-31"

**商品销售数据接口测试（v3.5.0）**:
```bash
python test_sku_sales_api.py
python jd_data_workflow.py test-sku <SKU> [店铺配置.xlsx] [商品配置.xlsx] [YYYY-MM-DD]
```
```

## 日志记录

所有操作记录到 `logs/jd_data_YYYYMMDD.log`，包含：
- 数据获取开始/结束时间
- API调用结果
- 错误信息
- 生成的文件路径
- 周报/日报生成状态（v2.4.0）

## 失败模式速查表

高频失败场景的快速处理指引。完整版参见
`references/api-spec.md`。

| 触发条件 | 一线修复 | 仍失败兜底 |
|---------|---------|-----------|
| **Cookie过期** | 检测到401/403 → 提示用户更新对应店铺Cookie → 跳过该店铺继续其他店铺 | 所有店铺Cookie均过期 → 终止执行，输出已获取的部分数据 |
| **API请求失败** | 自动重试3次（指数退避：1s/2s/4s） | 重试仍失败 → 跳过该数据段，标注[获取失败] |
| **配置文件缺失** | 自动触发uto_init.py生成模板 → 提示用户填写 | 用户拒绝填写 → 终止执行 |
| **网络超时** | 等待30s后重试1次 | 仍超时 → 提示检查网络，终止当前API调用 |
| **SKU数量过多** | 按50个SKU一批分批获取 | 单批超时 → 缩小批次为25个重试 |
| **文件被占用** | 提示用户关闭Excel后重试 | 用户不关闭 → 以只读模式尝试 |



## 注意事项

1. **Cookie会定期过期**，需及时更新配置表
2. **跨天数据获取**：SKU数量多时耗时较长，请耐心等待
3. **店铺名称匹配**：商品配置中的"所属店铺"需与店铺配置中的"店铺名称"完全一致（包括大小写、空格、括号等字符），建议统一使用中文全称
4. **毛保点位格式**：在Excel中填写百分比数值（如10表示10%）
5. **日期范围限制**：建议单次查询不超过90天，避免超时
6. **周报/日报生成**（v2.4.0，v4.4.0 更新为HTML，项目结构 v5.0 scripts/db/output）：
   - 日报：`scripts/gen_daily_report.py` → 从 `db/jd_history.db` 读取数据 → 输出到 `output/日报/YYYY-MM-DD/`
   - 周报：`scripts/gen_weekly_report.py` → 从 `db/jd_weekly.db` 读取数据 → 输出到 `output/周报/2026-Wxx/`
   - 周均毛利进度 = 毛利润(万元) / (日均毛利目标×7天)
7. **快车效果商品明细报表**（MSA Report）：`assets/` 目录已内置报表模板（id+checkSum），代码通过 `msa/report/operateData` 接口动态调用，主流程自动生成 `快车商品效果报表_日期.xlsx` / `搜索词效果报表_日期.xlsx` / `地域效果报表_日期.xlsx`（需配置京准通Cookie，best-effort，失败不中断主流程）；订单级明细另通过 `reweb/msa/effect/order/list` 与 `reweb/swa/effect/order/list` 生成 `快车订单明细_日期.xlsx` / `全站营销订单明细_日期.xlsx`
8. **库存分析**（v2.5.0）：
   - 库存API与商智API共用同一套认证（p-pin + User-mup/User-mnp），Cookie过期时一并影响
   - 库存概览返回的是汇总指标卡片（8个），不是商品级数据
   - 库存健康-商品明细必须传 `chartName/ dim/ tabType` 三个参数，传错（如stockTagList/pageNum）会返回空
   - thirdCategoryId 从店铺的类目信息中获取，初次使用需用户确认类目ID是否正确
   - 库存数据非实时，可能有1天延迟（如5月28日获取的是5月27日的数据）

## 更新记录

### v4.4.0（2026-07-10）
1. **删除废弃文件**：`fetch_inventory_data.py`（已标注废弃的8行占位）、`report_template.py`（59行死代码，被HTML模板替代）
2. **移除废弃API**：`getHotSalesTable.ajax`（持续返回-407不安全的请求），删除 `HOT_SALES_TABLE_URL` 常量和整个 `get_hot_sales_table` 方法。SKU获取统一使用 `getDealDetailData` 逐SKU查询
3. **简化日志**：移除 getHotSalesTable 完整响应体打印（4600byte json dump），改为简洁的code+msg
4. **修复 history_store.py 类型错误**：
   - 库存概览 `int()` → `int(float())`，兼容API返回 `'249.0'` 等浮点数字符串
5. **修复 daily_inventory_detail 字段映射**：
   - 新增 `_mget()` 多键容错取值，兼容 fetch_inventory_data 返回的混合键名（中文/英文）
   - 新增按SKU聚合多仓库行（库存求和、周转max、预警标识拆解去重并集）
6. **新增周报HTML生成器**：`scripts/gen_weekly_report.py`，7板块Freddy风格HTML，本周vs上周环比
7. **新增库存回填脚本**：`周报/backfill_inventory_weekly.py`，从库存Excel回填 weekly DB
8. **数据管线完善**：日报→db/jd_history.db / 周报→db/jd_weekly.db / 月报→db/jd_monthly.db 三库分粒度存储 + output/ 统一输出目录
1. **历史库前置检查**：`run_jd_data_workflow` 在 API 获取前先查 `history_store.has_data_for_date()`——单日获取时若所有店铺数据已存在于 `db/jd_history.db`，直接跳过 API 返回 `skipped_api=True`，避免重复请求
2. **分粒度数据库架构**：根据日期跨度自动选择数据库路径
   - 单日（`昨天` / `2026-07-08`）→ `db/jd_history.db`（日报库）
   - 2-7天（`近7天`）→ `db/jd_weekly.db`（周报库，allow_range=True）
   - 8-31天（`近30天`）→ `db/jd_monthly.db`（月报库，allow_range=True）
   - 周报/月报库存储聚合数据（date=end_date），与日报库互不污染
3. **`--force` 参数**：`python jd_data_workflow.py -d 昨天 --force --report`，强制重新获取数据，忽略历史库前置检查
4. **日报生成流程文档修正**：step1 从"读取库存Excel写入daily_inventory"修正为"直接从 jd_history.db 读取所有表"

### v4.3.0（2026-07-09）
1. **毛保计算修复**：`calculate_metrics()` 条件从 `('毛保', '综合毛保')` 改为 `('毛保', '综合毛保', '商品毛保')`，商品毛保店铺不再被跳过。两种毛保统一公式：`毛保返利 = 成交金额 × 毛保点位 - (成交金额 - 供货回款金额)`
2. **历史仓库存储保护**：`save_shop_data()`/`save_sku_data()` 强制校验 start_date == end_date，拒绝多天聚合数据入库（防止API取多天范围但只存end_date的问题）
3. **日报 v2 生成脚本**：`scripts/gen_daily_report.py`（v5.0 从 日报/ 移入 scripts/）
   - 12个KPI卡片（2排×6列，含环比）
   - 全店成交排名（含付费占比、日均毛利进度）
   - 商品成交金额 TOP10（含SKU环比、京东毛利率、毛保返利）
   - 关键洞察卡片（TOP1、最大涨跌幅、ROI最高、毛利为负）
   - 投产比排行（总订单金额/付费花费/付费访客/付费单量/ROI/环比）
   - 库存概览（按周转升序，≥50天标滞销，≤25天+现货率≤95%标缺货）
4. **预警规则更新**：
   - 🔴 销售角度：环比跌超40% 且 成交额>¥1,000
   - 🔴 付费角度：付费占比≥30% 且 ROI<1.5
   - 🔴 毛利角度：毛利率≤0%
   - 🔴 库存角度：周转≥50天 且 出库金额<500
   - 🔴 滞销角度：库存明细预警含滞销/不动销 且 库存≥10件
   - 🟡 日均毛利：完成进度≤30% 且 成交额≥¥500
   - 🟡 库存角度：实库现货率≤95% 且 周转≤25天
5. **库存明细表**：新增 `daily_inventory_detail` 表（含预警标识/滞销标识/不动销标识/低库存标识/无货标识）
6. **SKU环比**：读取 `daily_sku_stats` 前后两天数据，按 SKU_ID+店铺名匹配计算

## 日报生成流程
```
0. 历史库前置检查：如果所有店铺该日期数据已存在于对应数据库（日报/周报/月报），跳过 API 获取（v4.3.1）
1. python scripts/gen_daily_report.py → 从 db/jd_history.db 读取 daily_shop_stats / daily_sku_stats / daily_inventory / daily_inventory_detail 等 9 张表
2. 从daily_shop_stats读店铺数据 → 计算12个KPI → 生成排名表（含环比）
3. 从daily_sku_stats读SKU数据 → TOP10含环比
4. 从daily_inventory读库存概览 → 排序+标记
5. 从daily_inventory_detail读预警数据 → 滞销/不动销检查
6. 从daily_msa_reports/search_terms/region/orders读投放数据 → 板块7投放效率诊断
7. 合并生成HTML（Freddie主题，UTF-8 BOM）
```




