Input: Design documents from /specs/011-newebpay-payment/
Prerequisites: plan.md, spec.md, research.md, data-model.md, contracts/, quickstart.md(均已就绪)
Tests: 未要求 TDD;验证以 NewebPayEncryptUtil.main 自测 + quickstart.md 端到端场景为准。
Organization: 按 user story 组织,每个 story 可独立实现与验证。MVP = US1 + US2(支付闭环)。
[ID] [P?] [Story] DescriptionPurpose: 数据库 DDL 与配置就位
updatesql/sql.md(pos_store_newebpay、pos_order_payment,取自 data-model.md,标注 2026-06-22 蓝新支付接入)ruoyi-admin/src/main/resources/application.yml 新增 newebpay 配置段(base-url=ccore.newebpay.com、notify-url、return-url、mpg-version=2.3),仿 ezpay 段Purpose: 加密工具、HTTP 客户端、实体、Mapper——所有 story 的公共地基
⚠️ CRITICAL: 本阶段完成前不得开始任何 user story
ruoyi-admin/src/main/java/com/ruoyi/app/utils/newebpay/NewebPayConfig.java(merchantId/hashKey/hashIV,仿 EzPayConfig)ruoyi-admin/src/main/java/com/ruoyi/app/utils/newebpay/NewebPayEncryptUtil.java:AES-256-CBC/PKCS7Padding(块16) encrypt/decrypt(hex)、genTradeSha(HashKey=&{enc}&HashIV=)、genCheckValue(IV=&{Amt/MerchantID/MerchantOrderNo 排序}&Key=)、genCheckCode(HashIV=&{Amt/MerchantID/MerchantOrderNo/TradeNo 排序}&HashKey=);含 main 自测用 NDNF §4.1 示例(Key=Fs5cX1TGqYM2PpdbE14a9H83YQSQF5jn/IV=C6AcmfqJILwgnhIP/MID=MS127874575)验证加解密 round-trip 与 TradeSha 规则ruoyi-system/src/main/java/com/ruoyi/system/domain/PosStoreNewebpay.java(@TableName pos_store_newebpay,字段见 data-model.md)ruoyi-system/src/main/java/com/ruoyi/system/domain/PosOrderPayment.java(@TableName pos_order_payment,字段见 data-model.md)ruoyi-system/src/main/java/com/ruoyi/system/mapper/PosStoreNewebpayMapper.java + ruoyi-system/src/main/resources/mapper/chanting/PosStoreNewebpayMapper.xml(仿 PosStoreEzpayMapper,基础 CRUD)ruoyi-system/src/main/java/com/ruoyi/system/mapper/PosOrderPaymentMapper.java + ruoyi-system/src/main/resources/mapper/chanting/PosOrderPaymentMapper.xml(insert、selectByTradeNo、selectByDdId、updateById)ruoyi-admin/src/main/java/com/ruoyi/app/utils/newebpay/NewebPay.java HTTP 客户端:端点常量(URL_MPG_GATEWAY、URL_QUERY_TRADE_INFO、BASE_TEST=ccore/BASE_PROD=core)、createMpgForm(baseUrl,cfg,params)→加密form字段Map、queryTrade(baseUrl,cfg,amt,orderNo)→JSONObject、buildQuery(http_build_query)、postFormCheckpoint: 加密自测通过、表可建、实体/Mapper 就绪 → 可开始 user story
Goal: C端用户下单后调发起接口拿到加密form参数,前端Form Post跳转蓝新付款页
Independent Test: 对已开通蓝新的门店下单 → 调 /pay/newebpay/create → 返回 gatewayUrl+TradeInfo+TradeSha → 前端跳转蓝新页出现信用卡选项;pos_order_payment 落一行(pay_status=0)、pos_order.pay_type=6
ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/StoreNewebpayCredentialDto.java(storeId/merchantId/hashKey/hashIv/enabledPayments)与 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/PosStoreNewebpayVo.java(列表/详情VO)ruoyi-system/.../service/IPosStoreNewebpayService.java + impl/PosStoreNewebpayServiceImpl.java(纯DB:getOrCreateByStoreId、getEnabledConfig(storeId)返回启用且已开通的凭证或null、基础保存),仿 PosStoreEzpayServiceImplruoyi-system/.../service/IPosOrderPaymentService.java + impl/PosOrderPaymentServiceImpl.java(createPayment(ddId,merchantOrderNo,storeId,merchantId,amount)发起流水、getByTradeNo、getByMerchantOrderNo、markSuccess(tradeNo,payType,authCode,payTime,callbackRaw)、markFail)ruoyi-system/.../domain/PosOrder.java 附近定义 payType 蓝新取值常量(PAY_TYPE_NEWEBPAY="6"),或新建枚举类;不改表结构ruoyi-admin/src/main/java/com/ruoyi/app/pay/NewebpayPayController.java 实现 POST /pay/newebpay/create(@Anonymous+@Auth):校验订单存在/未支付/属当前用户 → 查门店启用凭证(无则报错) → 生成 merchant_order_no="NB"+ddId → 组装TradeInfo明文(MerchantID/RespondType=JSON/TimeStamp/Version=2.3/MerchantOrderNo/Amt=amount/ItemDesc/NotifyURL/ReturnURL/CREDIT=1) → NewebPayEncryptUtil 加密+TradeSha → 落 pos_order_payment → 更新 pos_order.payType=6/payUrl=gatewayUrl → 返回 form 字段(见 contracts/api.md B1)E:\QtwCode\foodie\foodie-store\ 新增"蓝新支付"入口:用户下单后调 /pay/newebpay/create,用返回字段构建隐藏 form 自动 submit 到 gatewayUrl;支付方式相关文案用 $t() 四语 i18n(zh/tw/en/vi,key 加到对应对象层级,如支付/订单对象内)Checkpoint: 发起支付链路通,可跳转蓝新测试页(此时回调未接,订单状态待 US2 更新)
Goal: 蓝新NotifyURL回调到达后,解密验签+幂等+金额校验,更新订单payStatus=1并触发推送;ReturnURL仅引导
Independent Test: US1发起并跳转后用测试卡付款 → 蓝新回调 /pay/newebpay/notify → 订单payStatus变1、pos_order_payment写trade_no/pay_type=CREDIT、商家/骑手收到推送;重复回调不变;金额不符/伪造签名拒绝
NewebpayPayController.java 实现 POST /pay/newebpay/notify(@Anonymous):收Form参数 → 记IpnLog → 由MerchantID查门店凭证 → 无凭证记录返回genTradeSha(TradeInfo,key,iv)==TradeSha 校验,不符拒绝记录;通过则 NewebPayEncryptUtil.decrypt(TradeInfo) 解出 Status/MerchantOrderNo/TradeNo/Amt/PaymentType/PayTime/Auth{"Status":"SUCCESS","Message":"OK"}NewebpayPayController.java 实现 GET/POST /pay/newebpay/return(@Anonymous):仅302重定向前端结果页(带ddId),不改订单状态(FR-015)E:\QtwCode\foodie\foodie-store\ 支付结果页:展示支付状态,轮询订单payStatus(因ReturnURL不改状态,以轮询/回调后状态为准);文案四语 i18nCheckpoint: US1+US2 构成完整 MVP——下单→付款→订单已支付→推送,可端到端验证(quickstart 场景2、3)
Goal: 用户在蓝新页可选 LINE Pay / Apple Pay,回调方式记录正确
Independent Test: 门店enabled_payments含LINEPAY/APPLEPAY → 发起参数带LINEPAY=1/APPLEPAY=1 → 蓝新页出现选项 → 付款后回调pay_type为LINEPAY/APPLEPAY
NewebpayPayController.create:按门店 enabled_payments 在TradeInfo明文中设 LINEPAY=1 / APPLEPAY=1(与CREDIT并存),读取门店 pos_store_newebpay.enabled_paymentsE:\QtwCode\foodie\foodie-store\ 支付方式展示:按门店启用方式渲染可选标识(发起前提示),文案四语 i18nCheckpoint: 三种支付方式均可完成闭环(quickstart 场景4;Apple Pay 需具备 HTTPS+Apple 配置)
Goal: 运营在平台后台录入/验证/启停门店蓝新凭证,复用009模式
Independent Test: 后台为门店录入测试凭证 → 调QueryTradeInfo验证通过 → 状态已开通 → 该门店可发起支付;停用后不可
ruoyi-admin/src/main/java/com/ruoyi/app/mendian/PosStoreNewebpayController.java(/system/storeNewebpay,@PreAuthorize chanting:storeNewebpay:*):list/{storeId}/apply/saveCredentials/toggleEnable/reset/enabledPayments,仿 PosStoreEzpayControllerPosStoreNewebpayServiceImpl:apply(0→1)、enableWithCredentials、toggleEnable、reset、setEnabledPayments、recordVerifyResult(仿 PosStoreEzpayServiceImpl 状态机)E:\QtwCode\foodie\foodie-admin-vue\ 新增门店蓝新凭证管理页(列表分页/详情/录入凭证/启停/重置/设置支付方式),文案四语 i18nupdatesql/sql.md(sys_menu 插入,仿 storeEzpay 菜单)Checkpoint: 凭证可全流程管理,US1/US3 发起支付有真实凭证来源(不必手插数据)
Goal: 回调丢失或对账时,主动查蓝新并校正订单状态
Independent Test: 回调丢失(订单未支付) → 调 /pay/newebpay/query → 蓝新返回TradeStatus=1 → 补更新payStatus=1+推送
NewebpayPayController.java 实现 POST /pay/newebpay/query(@Auth):查订单+门店凭证 → genCheckValue → NewebPay.queryTrade 调 /API/QueryTradeInfo → 解析 TradeStatus/PaymentType/PayTimeE:\QtwCode\foodie\foodie-store\ 订单详情增加"查询支付状态"入口(展示蓝新TradeStatus/支付方式/时间),文案四语 i18nCheckpoint: 对账与补单可用(quickstart 场景5)
Purpose: 多 story 共享的收尾
specs/011-newebpay-payment/quickstart.md 全部 6 场景端到端验证(测试环境 ccore + 测试卡 + 内网穿透),记录结果updatesql/sql.md 中所有 SQL 齐全(两建表 + 菜单权限)# 以下任务文件互不冲突,可并行:
Task: "NewebPayConfig in ruoyi-admin/.../utils/newebpay/NewebPayConfig.java"
Task: "PosStoreNewebpay in ruoyi-system/.../domain/PosStoreNewebpay.java"
Task: "PosOrderPayment in ruoyi-system/.../domain/PosOrderPayment.java"
Task: "PosStoreNewebpayMapper + XML"
Task: "PosOrderPaymentMapper + XML"
Task: "NewebPay HTTP 客户端骨架 in ruoyi-admin/.../utils/newebpay/NewebPay.java"
# 仅 NewebPayEncryptUtil(T004) 含被他人依赖的加密契约,建议优先完成并跑通自测
updatesql/sql.md,不直接执行