Branch: test(不新建分支,按用户要求在当前分支开发) | Date: 2026-06-15 | Spec: spec.md
Input: Feature specification from specs/009-ezpay-invoice-onboarding/spec.md
平台代商家到 ezPay(线下人工)注册申请发票,拿到凭证后由运营在平台后台录入并验证,验证通过标记"已开通"才具备开票前提。本期交付:①平台后台"ezPay 发票开通管理"列表(状态/筛选/快捷过滤)②状态推进(未申请→申请中→已开通)③凭证录入+ezPay 接口验证④启用开关⑤免用发票标记(新字段挂在 pos_store)⑥商家端上传统编。技术方案:新增独立表 pos_store_ezpay(1:1 门店)+ pos_store 加 invoice_exempt 列;复用已有 EzPay/EzPayConfig/EzPayEncryptUtil 工具类,用 invoice_search 只读调用验证凭证(避开 CheckValue 不确定性)。
Language/Version: Java 17+(Spring Boot,若依 RuoYi 框架;代码用 jakarta.servlet、HexFormat 表明 JDK17+)
Primary Dependencies:
@TableName/@TableId/LambdaQueryWrapper)+ XML mapper、Apache HttpClient、fastjson2、hutool、若依通用(AjaxResult/TableDataInfo/BaseController/@PreAuthorize("@ss.hasPermi(...)"))com.ruoyi.app.utils.ezPay.EzPay(issue/search/doPost)、EzPayConfig、ezPayCrypto.EzPayEncryptUtilfoodie-admin-vue、商家端 foodie-store,均 vue-i18n 四语言)Storage: MySQL(新增表 pos_store_ezpay;pos_store 加列 invoice_exempt)
Testing: JUnit 单测(mock ezPay 回应验证判读分支)+ 手测(ezPay 测试环境 cinv.ezpay.com.tw 真凭证跑通录入→验证→已开通)
Target Platform: Windows 开发 / Linux 部署的 Spring Boot 服务 + Vue 后台/商家端
Project Type: web-service(Spring Boot 后端)+ 两个 Vue 前端
Performance Goals: 平台后台列表分页查询 p95 < 500ms;凭证验证调用(含 ezPay 网络往返)< 10s 超时
Constraints: ezPay 无注册 API(线下人工);凭证验证走只读接口不产生真实发票;本期不含订单自动开票
Scale/Scope: 1 新表 + 1 新列;后端 1 controller + 1 service + 1 mapper(含XML) + 1 domain;平台后台 1 新页面;商家端 1 表单字段;4 语言 i18n ×2 前端
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
.specify/memory/constitution.md 为未填充模板(占位符未替换),项目未定义具体宪法原则与门槛。无实质门槛需评估,设计遵循项目既有约定(若依分层、MyBatis-Plus、全栈字段清单、四语言 i18n、SQL 写 updatesql/sql.md)。Phase 1 后复核:无违反。
specs/009-ezpay-invoice-onboarding/
├── spec.md # 需求规格
├── plan.md # 本文件(技术方案)
├── research.md # Phase 0:关键技术决策与依据
├── data-model.md # Phase 1:表结构、字段、状态机
├── quickstart.md # Phase 1:跑通验证步骤
├── contracts/
│ └── api.md # Phase 1:REST 接口契约
├── checklists/
│ └── requirements.md # spec 质量检查
└── tasks.md # /speckit-tasks 生成(本期 plan 不创建)
# ===== 后端 foodie_server =====
ruoyi-system/src/main/java/com/ruoyi/system/
├── domain/
│ ├── PosStore.java # 已有:新增 invoice_exempt 字段
│ └── PosStoreEzpay.java # 新增:门店 ezPay 配置实体
├── mapper/
│ ├── PosStoreMapper.java # 已有:resultMap 加 invoice_exempt
│ └── PosStoreEzpayMapper.java # 新增
└── service/
├── IPosStoreEzpayService.java # 新增
└── impl/PosStoreEzpayServiceImpl.java # 新增
ruoyi-system/src/main/resources/mapper/chanting/
├── PosStoreMapper.xml # 已有:resultMap + select 列加 invoice_exempt
└── PosStoreEzpayMapper.xml # 新增
ruoyi-admin/src/main/java/com/ruoyi/app/
├── mendian/
│ ├── PosStoreController.java # 已有:addmendian/edit 携带 invoice_exempt;UBN 上传接口
│ └── PosStoreEzpayController.java # 新增:平台后台 ezPay 开通管理 REST
├── user/dto/ (或 mendian/dto)
│ └── StoreEzpayCredentialDto.java # 新增:录入凭证入参
└── utils/ezPay/ # 已有,不改内部:EzPay/EzPayConfig/EzPayEncryptUtil
# ===== SQL =====
updatesql/sql.md # 追加建表 + 加列语句(带日期注释)
# ===== 平台后台前端 foodie-admin-vue =====
src/api/.../storeEzpay.js # 新增:接口封装
src/views/.../storeEzpay/index.vue # 新增:ezPay 开通管理页面
src/lang/{zh,tw,en,vi}.js # 四语言加 key(新对象层级 storeEzpay:{})
# ===== 商家端前端 foodie-store =====
src/lang/{zh,tw,en,vi}.js # 四语言加统编相关 key
门店设置表单 # 新增"统一编号"字段
Structure Decision: 后端遵循既有若依分层(domain→mapper→service→controller),新表对应独立一套 CRUD;平台后台凭证管理用独立 PosStoreEzpayController(/system/storeEzpay,权限键 chanting:storeEzpay:*),与门店基础维护解耦;商家端 UBN 上传挂在门店设置流程。前端两个仓库各新增最小页面/字段,严格走四语言 i18n。
无宪法违反项,无需填写。
| Violation | Why Needed | Simpler Alternative Rejected Because |
|---|---|---|
| — | — | — |