plan.md 6.0 KB

Implementation Plan: 商家 ezPay 发票开通管理

Branch: test(不新建分支,按用户要求在当前分支开发) | Date: 2026-06-15 | Spec: spec.md

Input: Feature specification from specs/009-ezpay-invoice-onboarding/spec.md

Summary

平台代商家到 ezPay(线下人工)注册申请发票,拿到凭证后由运营在平台后台录入并验证,验证通过标记"已开通"才具备开票前提。本期交付:①平台后台"ezPay 发票开通管理"列表(状态/筛选/快捷过滤)②状态推进(未申请→申请中→已开通)③凭证录入+ezPay 接口验证④启用开关⑤免用发票标记(新字段挂在 pos_store)⑥商家端上传统编。技术方案:新增独立表 pos_store_ezpay(1:1 门店)+ pos_storeinvoice_exempt 列;复用已有 EzPay/EzPayConfig/EzPayEncryptUtil 工具类,用 invoice_search 只读调用验证凭证(避开 CheckValue 不确定性)。

Technical Context

Language/Version: Java 17+(Spring Boot,若依 RuoYi 框架;代码用 jakarta.servletHexFormat 表明 JDK17+)

Primary Dependencies:

  • 后端:Spring Boot、MyBatis-Plus(@TableName/@TableId/LambdaQueryWrapper)+ XML mapper、Apache HttpClient、fastjson2、hutool、若依通用(AjaxResult/TableDataInfo/BaseController/@PreAuthorize("@ss.hasPermi(...)")
  • 复用:com.ruoyi.app.utils.ezPay.EzPay(issue/search/doPost)、EzPayConfigezPayCrypto.EzPayEncryptUtil
  • 前端:Vue.js + Element UI(平台后台 foodie-admin-vue、商家端 foodie-store,均 vue-i18n 四语言)

Storage: MySQL(新增表 pos_store_ezpaypos_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 前端

Constitution Check

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 后复核:无违反。

Project Structure

Documentation (this feature)

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 不创建)

Source Code (repository root)

# ===== 后端 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。

Complexity Tracking

无宪法违反项,无需填写。

Violation Why Needed Simpler Alternative Rejected Because