PHP 项目退款报错:订单金额或退款金额与之前请求不一致,请核实后再试
客服反馈操作订单退款失败,用户的消费记录显示,该订单并没有用余额扣款。这排除了因为实际支付金额与订单金额不一致导致的退款失败情况。
根据订单号查询日志,发现了这个报错 订单金额或退款金额与之前请求不一致,请核实后再试
。
{
"success": false,
"error_message": "wechat pay refund failed.",
"payInfo": {
"code": "INVALID_REQUEST",
"message": "订单金额或退款金额与之前请求不一致,请核实后再试"
}
}
查询微信支付分订单,参数支付金额 total_amount
为 230
,参数是在支付金额上乘以 100,与实际的支付金额 2.3 一致。这也表示支付金额没有问题。
查询日志中提交的支付参数,发现 total
为 229
,而非预期中的 230
。错误找到了:
'amount' => [
'refund' => intval(round($refund_money, 2) * 100)),
'total' => intval(round($total_money, 2) * 100)),
'currency' => "CNY"
]
本地 php -a
进入 php shell 中输出 intval(round(2.3, 2) * 100)
,得到的结果确实是 229。这意味着之前的修正精度的操作是失败的。之前遇到过这个问题,也百度过 php 高精度计算问题。可以通过 PHP 的 BC 高精度函数解决,但之前似乎有其他的想法可以解决,但并没有奏效。
百度同时发现了另外一种比较简洁的方法 round(2.3 * 100)
,可以直接解决问题。round
还有两个默认的参数,一个是精度,默认为 0,一个为舍入模式,默认为 PHP_ROUND_HALF_UP
,即四舍五入。
如果直接 2.3 * 100
也能拿到预期的 230
,那么使用函数 intval
来取整看起来不太明智的方法。就比如那个经典的示例 0.58 * 100
也是在 intval
取整的时候出现问题的,那么不取整似乎也没有问题。主要是因为该字段在取出到 PHP 内存中可能表示为 2.2999...
(众所周知的 php 精度问题)。所以取出来乘以 100 之后需要对结果进行取整,而 intval 取整结果也看到了,就是 229。所以需要使用 round 或者 bcmul 处理才行。
最终的写法为 intval(round($refund_money * 100))
或者 round($refund_money * 100)
。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。