# 闪送骑手 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:///pay/line/flash/confirm` 和 `LINE_PAY_FLASH_CANCEL_URL=https:///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 请求体: ```json {} ``` `id` 为闪送订单数字 ID,仅寄件付款人可发起。不要提交 riderId、channelId、channelSecret、金额或币种;服务端从订单及凭证读取。未接单、取消/已取件、不是 LINE 单或收款凭证未就绪时拒绝。 示例(虚构订单及地址): ```json { "code": 200, "msg": "操作成功", "data": { "orderId": 101, "paymentId": 202, "status": "WAITING_AUTH", "refundStatus": null, "paymentUrl": "https:///<付款路径>" } } ``` 重复 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 多连接测试。未提交/推送。