flash-delivery-line-pay-app-integration.md 8.7 KB

闪送骑手 LINE Pay Online 接入(019 增量)

2026-10-10。仅提供接口契约,App 代码由前端人员实现。普通外卖仍支付给商家,本功能不改变外卖配送费结算。

前置条件

  • 开发者手工执行 updatesql/sql.md 中「2026-10-10 019 骑手 LINE Pay 与闪送 Online」迁移和菜单,给平台角色分配权限。
  • 骑手已由 LINE Pay 开通 Online,平台「骑手支付配置」录入其独立凭证并验证启用。骑手必须为正常 userType=2 账号;接单仍受原骑手审核、容量、车型等规则约束。
  • LINE_PAY_ENVIRONMENT 与 LINE_PAY_BASE_URL 必须匹配:sandbox 对应 https://sandbox-api-pay.line.me,production 对应 https://api-pay.line.me;不能混用。骑手凭证探测、付款、历史核实及退款调用前都会校验,错配时不调用网关。凭证环境来自服务端,不由页面或 App 选择。
  • 新增公网 HTTPS 配置 LINE_PAY_FLASH_CONFIRM_URL=https://<API域名>/pay/line/flash/confirm 和 LINE_PAY_FLASH_CANCEL_URL=https://<API域名>/pay/line/flash/cancel。默认留空,未配置时不允许发起闪送支付;外卖回跳配置不变。反向代理需放行这两个匿名 GET 入口。
  • 每次付款固定骑手凭证版本,轮换/禁用只阻止新请求,不把历史交易转到新骑手或新密钥。服务器恢复任务、Redis 和数据库须正常工作。

主流程

  1. 用户沿用现有闪送创建接口,payType="3"。此时仅创建配送订单,不发起扣款。
  2. 有启用 LINE 凭证且接受此支付方式的骑手看到订单并接单;服务器接单时重新校验,不能只依赖列表。
  3. 寄件用户读取订单,状态为 ACCEPTED 后显示付款入口,调用下面的 create。
  4. create 返回 WAITING_AUTH 和 paymentUrl 时打开链接进行 LINE 认证。认证/浏览器返回不等于已付款。
  5. App 回链、重新打开订单或完成认证后调用 status;服务端通过 LINE Check/Confirm/Retrieve 核实。只有 status=PAID 且没有退款阻断才可取件。
  6. 骑手单站及逐站取件均由服务端校验可信资金流水。旧线上单只有 paymentStatus=1 而没有可信流水,也不能取件。
  7. 取件前用户/平台合法取消:配送订单立即取消,已付资金生成全额退款意图,恢复任务处理退款。任一取货站已取件后禁止取消,客服另行处理异常。

App 接口

沿用用户/骑手 JWT token 请求头,不是平台 Authorization。返回仍为项目 AjaxResult,HTTP 200 不代表业务成功,须检查业务 code。

发起付款

POST /system/flashDelivery/orders/{id}/linePay/create

显式 JSON 请求体:

{}

id 为闪送订单数字 ID,仅寄件付款人可发起。不要提交 riderId、channelId、channelSecret、金额或币种;服务端从订单及凭证读取。未接单、取消/已取件、不是 LINE 单或收款凭证未就绪时拒绝。

示例(虚构订单及地址):

{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "orderId": 101,
    "paymentId": 202,
    "status": "WAITING_AUTH",
    "refundStatus": null,
    "paymentUrl": "https://<LINE付款域名>/<付款路径>"
  }
}

重复 create 返回现有活跃尝试,不重复扣款。REQUEST_UNKNOWN、CONFIRM_UNKNOWN、MANUAL_REVIEW 不可当成支付失败后重新支付。已发送的未知尝试保留资金阻断;CREATED 尚未发送的意图因凭证禁用/轮换而取消,不代表已发生扣款。

查询支付/退款

GET /system/flashDelivery/orders/{id}/linePay/status

寄件付款人及本单接单骑手可查询;他人拒绝。字段与 create 一致,骑手不返回 paymentUrl。无尝试时 status=NOT_STARTED、paymentId/paymentUrl/refundStatus 为空。

status 前端处理
NOT_STARTED / CREATED 尚未完成付款请求,仅在服务器允许时发起/继续当前尝试
REQUESTING / CONFIRMING 请求处理中,查询当前尝试,不重复付款
WAITING_AUTH 待用户认证/付款;寄件人可打开当前 paymentUrl
REQUEST_UNKNOWN / CONFIRM_UNKNOWN 结果待核实,查询并等待,禁止第二次扣款
PAID 服务端已核实到账;如 refundStatus 非空则不能据此继续取件
FAILED / CANCELLED / EXPIRED 此尝试结束,不等于配送订单已取消;只有有效 ACCEPTED 订单才能按服务端规则重试
MANUAL_REVIEW 资金需要人工核对,不能伪造成功或自动重新支付

refundStatus:空=无退款意图;CREATED=待退款,PROCESSING=退款请求中,UNKNOWN=退款结果待核实,REFUNDED=已证实全额退款,FAILED/MANUAL_REVIEW=失败/人工核对。支付 PAID 历史事实不会被退款擦除。

订单原 paymentStatus:LINE 单 0=未核实到账、1=已到账、2=已证实全额退款;现金/转账沿用 0/1。不要只按此汇总标记放行取件;最终由取件接口校验。

回链

服务器专属回跳 /pay/line/flash/confirm、/cancel 根据已保存 LINE 订单号及字符串交易号定位尝试,仅排队核实,不根据浏览器参数写支付成功。

App 深链:com.twanmsdyh.app://payment/result?orderSource=FLASH&orderId=<闪送数字ID>。前端依据 orderSource=FLASH 调用本文件的 status,不要调用外卖查询,不要信任深链判定成功。不含有效绑定的浏览器回跳显示通用提示;定时任务仍会核实资金。浏览器取消认证不取消配送订单。

返回页有 CSP/no-store;手机浏览器自动唤起可能受限,提供手工打开入口。iOS/Android Scheme 注册和真实 LINE WebView 联调由 App 人员验证。

取消与资金恢复

  • 用户取消沿用原接口;平台取消仍须原因、属于本单的问题站、处理结果。取件后即使提供物品去向/交接照片也不能取消;历史交接记录仍可读。
  • 平台列表行/详情返回 canAdminCancel;按钮只在严格为 true 时展示,缺字段安全隐藏。平台打开弹窗时再读取详情,接口最终在订单锁内复核站点。
  • 取消与已付款退款意图同一事务提交,退款网络调用在事务外;真实退款成功前不展示“已退款”。
  • 取消先成功后不再新发 Confirm;已经在途的扣款若迟到证实,只创建退款补偿,不恢复配送状态。
  • Confirm/Refund 超时或进程失联后只读查询证据,不盲目重发。退款证据已存在则直接登记事实;部分/异常退款进入人工核对,防止超额退款或已退订单继续取件。
  • 复用 line-pay.reconcile 批量、间隔、租约及截止配置,独立任务锁 lock:flash-line-pay:reconcile。租约至少 120 秒覆盖现有 HTTP 超时;到期不等于网关未扣款,人工核对保留活跃阻断。
  • 每次探测(含未变状态或查询失败)推进下一次核实时间,按最早到期、ID 排队,避免前一批等待认证/未决退款挤占后续订单。仍有有效租约的请求不被探测更新干扰。
  • 取件在订单锁之后对支付、退款使用数据库当前读,不能读到退款前旧快照;已经证实 REFUNDED 的事实不能被旧探测的截止时间降级。
  • 骑手不能通过 confirmPayment 手工把 LINE 单标记已收款;现金及线下转账原送达后确认收款不变。

平台配置接口

平台使用既有后台登录 Authorization。GET /system/riderLinePay/list(分页/userName)、GET /{riderId}、PUT /saveCredentials(riderId/channelId/channelSecret)、PUT /toggleEnable(riderId/enabled)。

分别需要 infouser:riderLinePay:list/query/saveCredentials/toggleEnable 权限。列表不查询 Secret;授权详情可用于回显当前凭证;保存时只读随机不存在订单探测,验证失败不替换原版本。Secret 不进操作审计、App 响应或浏览器持久缓存;凭证保存请求专门绕过通用重复提交 sessionStorage 缓存,页面 saving 仍防重复点击。本文不提供真实密钥。

验证边界

本地测试覆盖签名/请求契约、可信事实、重复/未知保护、退款补偿、权限归属和取件/取消门禁。SQL 本次未执行;真实 MySQL 多连接竞态、LINE Sandbox/正式骑手收款和退款、部署、App/浏览器联调须另行验证,不能用 mock 测试代替真实资金验收。

2026-10-10 最终本地回归:164 个后端测试类、1140 项测试,0 失败/错误/跳过;JDK 21 模块 package 成功;平台三组行为测试 16/16,全部现有测试 25/25,build:stage 成功。独立审查的 5 项重要发现已用失败→通过回归修复。当前读仅验证 Mapper 实际生成的锁定 SQL 和旧快照行为模型,不代表已运行真实 MySQL 多连接测试。未提交/推送。