merchant-offline-app-integration.md 9.4 KB

LINE Pay 商家扫码支付前端接入说明

适用端:Foodie 商家 App(uni-app)

场景:客户出示 LINE Pay My Code,商家 App 扫码收款

1. 前端整体流程

按以下顺序接入:

  1. 商家端创建订单,支付方式传 paymentMethod="3"。
  2. 订单必须只有一个门店。
  3. 商家点击“LINE Pay 扫码收款”。
  4. 前端调用 uni.scanCode 扫描客户出示的 LINE Pay My Code。
  5. 扫码结果必须是 18 位数字,即 oneTimeKey。
  6. 前端把订单号 ddId 和 oneTimeKey 提交给扫码付款接口。
  7. 根据付款接口返回的 status 展示当前状态。
  8. 如果状态是处理中,定时调用状态查询接口。
  9. 按第 6 节结合状态查询的订单及退款状态判断;不能只凭 PAID 提示当前收款成功。

2. 商家创建订单

调用现有接口:

POST /system/orderShOprate/createOrder
Header: token

前端只需注意:

  • paymentMethod 必须传字符串 "3"。
  • items 只能有一个门店。
  • 创建成功后取得订单号 ddId。
  • 只有这个接口创建的商家订单可以使用扫码付款。

商品、金额、备注、发票等字段继续使用商家端现有下单格式,不需要为 LINE Pay 新增字段。

3. 扫描客户付款码

前端调用 uni-app 扫码方法:

uni.scanCode

需要支持:

  • 条形码。
  • 二维码。
  • 扫码结果必须匹配 18 位数字。

扫码得到的内容作为 oneTimeKey。

注意:

  • 不要打印 oneTimeKey。
  • 不要保存到本地缓存或数据库。
  • 不要把它放到页面 URL。
  • 每次客户重新生成 My Code 后,都要重新扫码。

4. 提交扫码付款

POST /system/orderShOprate/linePay/offline/pay
Header: token
Content-Type: application/json

请求参数:

{
  "ddId": "202608180001",
  "oneTimeKey": "123456789012345678"
}
字段 类型 说明
ddId string 商家端创建的订单号
oneTimeKey string 扫描得到的 18 位 LINE Pay My Code

成功响应:

{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "ddId": "202608180001",
    "paymentId": 84,
    "lineOrderId": "LPOFF123456789",
    "transactionId": "2026081800000000001",
    "status": "AUTH_REQUIRED",
    "reusedAttempt": false,
    "updatedAt": "2026-08-18T12:34:56+08:00"
  }
}

前端主要使用:

  • status:判断付款状态。
  • reusedAttempt:判断后端是否复用了已有支付记录。
  • transactionId:仅用于展示或排查,必须作为字符串处理。

reusedAttempt=true 表示订单已经有一笔付款正在处理。本次新扫描的付款码没有再次发送给 LINE,前端直接查询原付款状态,不要再次扫码或提交付款。

5. 查询付款状态

GET /system/orderShOprate/linePay/offline/status?ddId=202608180001
Header: token

响应 data 保留付款流水字段,并额外返回以下当前本地信息(仅 GET 查询填充,POST 付款响应不能代替此查询):

字段 类型 说明
orderState number 订单当前 state;4 为已取消
orderPayStatus number 订单当前 payStatus:0 未支付、1 已支付、2 已退款
refundStatus string/null 所选 Offline 流水的退款状态;无对应退款记录时为空

即使 status=NOT_STARTED,也返回订单状态;它不代表整单未付款。POST 返回 PAID 后也应调用此 GET 查询,确认当前订单及退款状态。

查询时机:

  • 付款接口返回 AUTH_REQUIRED。
  • 付款接口返回 PROCESSING。
  • App 从后台回到前台。
  • 商家重新打开订单详情。
  • 付款接口发生网络超时。

建议处理中每 5 秒查询一次。页面退出后停止轮询;重新进入页面时再查询一次。

6. 状态处理

status 含义 前端操作
NOT_STARTED 查询时尚无本地扫码付款记录 不显示服务器错误;刷新订单及付款方式,禁止自动重发付款或自动重扫
AUTH_REQUIRED 客户需要在 LINE Pay 完成选择付款方式或认证 提示客户在 LINE Pay 完成操作,继续查询状态,不允许重新扫码
PROCESSING 后端正在确认付款结果 显示“支付结果确认中”,继续查询状态,不允许重新扫码
PAID 此流水曾成功扣款,退款后仍保留 结合下述订单和退款信息展示,不能单独作为当前收款或打印依据
CANCELLED 此付款尝试取消或付款码过期 停止本次付款轮询,先确认订单仍可付款,再由客户生成新 My Code 重扫
FAILED 此付款尝试明确失败 停止本次付款轮询,先确认订单仍可付款,再由客户生成新 My Code 重扫
MANUAL_REVIEW 金额异常或付款结果需要人工核对 停止查询,提示联系平台处理,不允许重新扫码

前端必须遵守:

  • 扫码成功不等于付款成功。
  • HTTP 请求成功不等于付款成功。
  • 存在 transactionId 不等于付款成功。
  • status="PAID" 只代表曾成功扣款。当前展示按下面的规则处理。

订单和退款信息优先于付款流水状态:

  1. refundStatus="REFUNDED" 或 orderPayStatus=2:显示“已退款”。
  2. 其他非空 refundStatus:CREATED/PROCESSING/UNKNOWN/RETRY_WAIT 显示退款处理中或待确认;FAILED 显示退款失败、联系平台;MANUAL_REVIEW 显示退款待人工核对。未知退款状态也按待核对处理。
  3. orderState=4:显示订单已取消,并同时保留退款信息;取消不等于退款成功。
  4. 仅当本次 GET 查询返回 status="PAID"、orderPayStatus=1、明确的非取消 orderState 且无退款记录,才可展示当前收款成功。历史订单重新查询成功不应重复触发打印,打印仍按原有业务规则。
  5. 字段缺失或状态暂未一致时刷新订单,不默认当成正常已支付,不自动重扫或重发扣款。

7. 网络异常处理

付款接口超时

如果 /offline/pay 超时或断网:

  1. 不要自动重发付款接口。
  2. 不要重新使用刚才的 oneTimeKey。
  3. 网络恢复后调用 /offline/status 查询订单状态。
  4. 根据状态查询结果继续处理。

原因是 LINE 可能已经收到付款请求,重复提交可能造成重复付款风险。

状态查询失败

  • 提示“支付结果暂时无法确认,请稍后查询”。
  • 不要直接显示付款失败。
  • 不要自动重新扫码。
  • 商家重新进入订单页面后再次查询。

8. 接口错误处理

项目接口统一返回:

{
  "code": 500,
  "msg": "业务错误信息"
}
  • code === 200:读取 data。
  • code !== 200:展示后端返回的 msg。
  • 不要根据中文 msg 判断付款状态。
  • 付款事实读取 data.status;当前订单及退款展示同时读取 orderState/orderPayStatus/refundStatus。

9. Sandbox 联调步骤

Online API v4 和 Offline API v4 共用现有 Channel ID / Channel Secret,不需要重新注册 Sandbox。

测试步骤:

  1. 后端使用 Sandbox 环境。
  2. 测试门店已经录入并启用 Channel ID / Channel Secret。
  3. 商家端创建 paymentMethod="3" 的单门店订单。
  4. 打开台湾 Sandbox My Code 生成器:

    https://sandbox-web-pay.line.me/web/sandbox/payment/oneTimeKey?countryCode=TW&paymentMethod=balance
    
  5. 商家 App 扫描生成的测试付款码。

  6. 调用 /offline/pay。

  7. 如果返回处理中,继续调用 /offline/status。

  8. 查询返回 PAID 后按第 6 节确认订单及退款状态,再提示当前收款成功。

Sandbox 环境不能使用客户真实 LINE App 生成的 My Code。

10. 前端验收清单

  • 商家下单时 paymentMethod="3"。
  • 一笔订单只有一个门店。
  • 使用 uni.scanCode 扫描条形码和二维码。
  • 扫码结果必须为 18 位数字。
  • oneTimeKey 不记录、不缓存、不打印。
  • 提交付款期间禁用重复扫码。
  • AUTH_REQUIRED 和 PROCESSING 会继续查询状态。
  • PAID 结合订单及退款状态展示;已取消、退款中或已退款不误报正常收款成功。
  • 流水 CANCELLED/FAILED 后先刷新订单,确认未取消、未支付且可付款,再允许商家重新扫码。
  • MANUAL_REVIEW 不允许重新扫码。
  • 付款接口超时后不自动重发,只查询状态。
  • App 回到前台或重新进入订单页面时重新查询状态。

11. 接口汇总

操作 方法 接口
商家创建订单 POST /system/orderShOprate/createOrder
提交扫码付款 POST /system/orderShOprate/linePay/offline/pay
查询付款状态 GET /system/orderShOprate/linePay/offline/status?ddId={ddId}

2026-11-04 未扫码状态兼容

GET /offline/status 在授权通过但没有 Offline 流水时,改为返回:

{"code":200,"msg":"操作成功","data":{"ddId":"991793699529652","status":"NOT_STARTED"}}

其他支付流水字段为空或省略。NOT_STARTED只说明查询时尚无本地扫码记录,即使存在Online付款也不会在此接口返回Online流水。不能因此把订单标记未付款/失败,更不能自动重发/offline/pay。初次打开页面可显示尚未扫码;如果之前付款请求超时,应先刷新订单和状态,避免原请求仍在处理时直接重新扫码。实际付款仍由服务端支付锁、订单支付状态和活跃流水再次校验。