# Feature Specification: 国际机票（盘合 iFlight 分销接入）

**Feature Branch**: `（待创建，暂未建分支/未提交）`

**Created**: 2026-07-29

**Status**: Draft —— 范围与多项关键决策待定（见「待定决策」）

**Input**: 接入上海盘合 shpanhe 国际机票开放接口（`http://open.shpanhe.com/api/iFlight`），实现国际机票查询/预订等能力。凭证见 `文档/旅游/API测试接口.txt`。

---

## 集成背景（已确认事实）

- **盘合是分销平台，我方是分销商**：从同平台国内机票文档出现的「票面价 / 机建税 / 燃油费 / 结算价 / 返点返现政策」可确认这是 **B2B 分销结算模型**，不是消费者直连航司/盘合的透传支付。
- **测试凭证（国际机票）**：
  - AppKey：`4298c05600816da82abdbc899cd0c344`
  - SecretKey：`7ad3915eaf9a47156adcd31a1c51f2df`
  - 接口网关域名：`http://api.panhe.net`
  - 测试分销后台：`http://fxtest.panhe.net`（账号 `15978194868` / 密码 `086915`）
- **接口文档可获取性**：iFlight 在线文档（`open.shpanhe.com/api/iFlight`）需登录，自动抓取（HTTP/HTTPS/真实浏览器）均被屏蔽或超时失败，搜索引擎未收录。同平台**国内机票文档 `/api/flight` 公开**，可作为流程/签名/信封惯例的参考模板（国际机票大概率同源，待文档验证）。

### 资金模型：两层资金流（核心）

| 层级 | 方向 | 价格 | 通道 |
|------|------|------|------|
| 第一层（零售） | 消费者 → 平台 | 零售价（票面价 + 税费 + 我方加价/返点） | 平台自有支付通道（复用，见下） |
| 第二层（结算） | 平台 → 盘合 | 结算价 | 分销商账户（余额/授信/代扣，方式待文档确认） |

- 消费者全程不接触盘合。
- **结算价与零售价的差 / 返点返现 = 平台利润**。
- 第一层收款**复用 foodie 现有支付通道**，不为机票新建支付：当前 NewebPay 蓝新金流**代码就绪但未启用**，VNPay / ZaloPay 已废弃（详见 `project-deprecated-code` 记忆）。
- 真正新增的复杂点不是支付通道本身，而是：**零售价定价**、**结算价/利润记账**、**出票后资金核销与对账**。

---

## 待定决策（用户后续决定）

> 以下决策显著影响 spec 范围与用户场景，需用户拍板后再细化。当前 spec 先以「假设全流程」记录，范围边界以 D1 为准回收。

- **D1 — 范围边界**：仅查票展示 / 查票+生单（不含支付出票）/ 全流程（查→订→付→出票→售后）。
- **D2 — 落地端**：用户端（uni-app，消费者自助）/ 平台管理端（foodie-admin-vue）/ 两端。
- **D3 — iFlight 接口契约获取方式**：用户提供完整文档 / 以国内机票 `/api/flight` 为模板推断（后续校正）/ 仅写业务级 spec、接口细节推迟到 plan 的 research 步骤。
- **D4 — 第二层（平台→盘合）结算方式**：账户余额实时扣款 / 授信额度周期结算 / 下单网关代扣。（决定记账与资金风险设计）
- **D5 — 零售价定价策略**：直接用票面价 / 票面价 + 固定加价 / 按返点反算。（决定利润模型）
- **D6 — 第一层（消费者）收款通道**：是否启用 NewebPay 或使用当时可用通道。

> ⚠️ **硬阻塞**：在拿到 iFlight 接口契约（D3）前，`/speckit-plan` 的 research 与 `/speckit-tasks` 的实现细节无法落地，本 spec 只能停留在业务级。

---

## User Scenarios & Testing *(mandatory)*

> 优先级以「假设全流程（D1=全流程）」编写；若 D1 收窄为「仅查票」，则仅保留 US1，其余降级或移除。

### User Story 1 - 查询国际航班（Priority: P1）

消费者选择出发/到达城市（三字码）、出发日期、舱等，查看可选国际航班及其舱位票价（票面价、税费、飞行时段、航司、中转信息）。

**Why this priority**：查票是整个机票功能的入口和最小可用形态，即使后续环节都不做，单查票展示也有独立价值。

**Independent Test**：给定一条真实国际航线 + 日期，调用查询能返回航班与价格列表并在前端展示。

**Acceptance Scenarios**:

1. **Given** 消费者输入有效的出发地、到达地、日期，**When** 发起查询，**Then** 返回当日可选航班列表（含航司、起降时间、舱位、票价、税费、是否中转）。
2. **Given** 无效或无航班航线，**When** 查询，**Then** 返回明确的「无航班」提示而非报错。
3. **Given** 查询往返/联程，**When** 查询，**Then** 通过分段查询组合出往返/联程结果。

---

### User Story 2 - 下单与支付（Priority: P2）

消费者选定航班舱位、填写乘机人信息后生成订单，按零售价通过平台支付通道付款。

**Why this priority**：完成「能买到票」的核心交易闭环。

**Independent Test**：从选定航班到支付成功，生成一条待出票的机票订单。

**Acceptance Scenarios**:

1. **Given** 消费者选定舱位并填妥乘机人，**When** 提交订单，**Then** 生成机票订单并按零售价发起支付。
2. **Given** 支付成功，**When** 平台收到回调，**Then** 订单进入「待出票」，平台据此向盘合按结算价下单/订座。
3. **Given** 支付超时或失败，**When** 超时未支付，**Then** 订单自动取消、释放占座（若已占座）。

---

### User Story 3 - 出票与售后（Priority: P3）

支付成功后由盘合出票，消费者获得票号；支持退票/改签等售后。

**Why this priority**：完成完整购票体验，但可晚于 MVP。

**Independent Test**：支付成功后能拿到真实票号并展示；能发起一次退票流程。

**Acceptance Scenarios**:

1. **Given** 订单已支付且盘合侧下单成功，**When** 出票完成，**Then** 消费者可见票号/行程单。
2. **Given** 出票失败，**When** 平台感知失败，**Then** 自动重试或退款，并通知消费者。
3. **Given** 已出票订单，**When** 消费者申请退票/改签，**Then** 按航司规则计算手续费并退款/改期。

---

### Edge Cases

- 查票有结果但下单时座位已被占满（库存瞬时变化）如何处理？
- 支付成功但盘合侧出票失败的资金兜底（退款给消费者 + 平台与盘合的结算对账）。
- 价格在查票与下单之间发生变动（税费/汇率波动）。
- 多乘机人部分出票成功部分失败。
- 国际行程的护照/证件信息校验、签证提示（信息性，非校验）。
- 币种与汇率：盘合结算币种 vs 消费者支付币种。

## Requirements *(mandatory)*

### Functional Requirements

- **FR-001**：系统 MUST 支持按出发/到达城市（三字码）、日期、舱等查询国际航班，返回航班、舱位、票面价、税费、起降时间、航司、中转信息。
- **FR-002**：系统 MUST 支持往返/联程查询（分段组合实现）。
- **FR-003**：系统 MUST 在消费者选定舱位并填写乘机人后生成国际机票订单，订单含零售价与结算价两套价格记录。
- **FR-004**：系统 MUST 通过平台自有支付通道收取消费者零售价款项（复用，不新建支付通道）。
- **FR-005**：系统 MUST 在消费者支付成功后，按结算价向盘合完成下单/订座/出票，并记录票号。
- **FR-006**：系统 MUST 记录每笔订单的两层资金流（消费者零售收款 + 平台与盘合结算价/返点），支持对账与利润核算。
- **FR-007**：系统 MUST 支持出票失败的自动重试与退款兜底。
- **FR-008**：系统 MUST 支持退票/改签，按航司规则计算手续费。
- **FR-009**：功能范围（查票/下单/支付/出票/售后）以 **[NEEDS CLARIFICATION: D1 范围边界]** 为准。
- **FR-010**：功能落地端（用户端/管理端）以 **[NEEDS CLARIFICATION: D2 落地端]** 为准。
- **FR-011**：零售价定价以 **[NEEDS CLARIFICATION: D5 定价策略]** 为准。
- **FR-012**：第二层结算方式以 **[NEEDS CLARIFICATION: D4 结算方式]** 为准。

### Key Entities *(include if feature involves data)*

- **航班查询结果（FlightSearchResult）**：航班段、舱位、票面价、税费、结算价、返点政策、起降时间、航司、中转。
- **国际机票订单（IntlFlightOrder）**：订单号、消费者、航线、舱位、乘机人列表、零售价、结算价、状态（待支付/待出票/已出票/已退/已改）、关联支付流水、票号。
- **乘机人（Passenger）**：姓名（拼音/英文）、证件类型与号码（护照等）、性别、出生日期、手机号。
- **资金流水（FlightPaymentSettlement）**：消费者侧收款记录 + 平台与盘合的结算扣款/返点记录（用于对账与利润）。

## Success Criteria *(mandatory)*

### Measurable Outcomes

- **SC-001**：消费者发起国际航班查询后，95% 的查询在可接受时长内返回结果。
- **SC-002**：查票成功率（有航线的查询返回有效结果的比例）达到目标值。
- **SC-003**：从下单到出票完成（含支付）的端到端时长满足消费者预期。
- **SC-004**：每笔订单的两层资金（零售收款 vs 盘合结算）100% 可对账，利润可核算。
- **SC-005**：出票失败场景 100% 有明确的退款/重试兜底，无资金悬空。

## Assumptions

- 平台已作为**分销商**在盘合完成开户，测试凭证可用，生产凭证后续提供。
- 复用 foodie 现有的**用户体系、App 端框架、支付通道**，不为此功能新建用户体系或支付通道。
- 国际机票与国内机票同源（同一平台），**签名方式、请求信封、接口流程一致**——此为推断，待 iFlight 文档验证。
- 在拿到 iFlight 接口契约前，`plan`/`tasks`/`实现` 阶段无法进入字段级细节，本 spec 保持业务级。
- 接口调用走服务端（AppKey/SecretKey 不下发前端），签名在服务端完成。
- 测试先用 `api.panhe.net` 测试网关与测试凭证，生产环境与凭证后续切换。
