# 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` 测试网关与测试凭证,生产环境与凭证后续切换。