PrestaShop 1.6.1.x payment module 未发送含运费总价
支付阿杰
结论
不要在 foreach ($products as $product) 循环中把运费直接加到每个商品的 $CartItem['Amount']。否则,每件商品都会重复计算一次运费;当 Quantity 大于 1 时,API 还可能再次放大这部分金额。
可以通过以下代码取得含税运费:
$cart->getOrderTotal(true, Cart::ONLY_SHIPPING)
然后将运费作为一条独立明细发送给 API,并将 Quantity 设为 1。如果 API 只接收订单总金额,直接使用 $cart->getOrderTotal(true, Cart::BOTH)。
将运费作为独立明细
商品价格使用 price_wt,也就是含税价格,因此运费也要按含税金额计算。以下代码保留了原有的货币转换方式:
/** CART ITEMS */
$products = $cart->getProducts();
$CartItems = [];
$api_currency_id = (int) Currency::getIdByIsoCode($currency_iso);
foreach ($products as $product) {
if ($this->context->currency->id != $api_currency_id) {
$price = Tools::convertPrice(
(float) $product['price_wt'],
$this->context->currency,
false
);
$price = Tools::convertPrice(
(float) $price,
$api_currency_id
);
} else {
$price = (float) $product['price_wt'];
}
$CartItem = [];
$CartItem['Amount'] = Tools::ps_round($price, 2);
$CartItem['Currency'] = $currency_iso;
$CartItem['Name'] = $product['name'];
$CartItem['Description'] = strip_tags($product['description_short']);
$CartItem['Quantity'] = (int) $product['cart_quantity'];
$CartItem['IsTaxFree'] =
(float) $product['price'] === (float) $product['price_wt'];
$CartItems[] = $CartItem;
}
/** SHIPPING */
$shipping = (float) $cart->getOrderTotal(
true,
Cart::ONLY_SHIPPING
);
if ($this->context->currency->id != $api_currency_id) {
$shipping = Tools::convertPrice(
$shipping,
$this->context->currency,
false
);
$shipping = Tools::convertPrice(
$shipping,
$api_currency_id
);
}
if ($shipping > 0) {
$ShippingItem = [];
$ShippingItem['Amount'] = Tools::ps_round($shipping, 2);
$ShippingItem['Currency'] = $currency_iso;
$ShippingItem['Name'] = 'Shipping';
$ShippingItem['Description'] = 'Shipping cost';
$ShippingItem['Quantity'] = 1;
$ShippingItem['IsTaxFree'] = false;
$CartItems[] = $ShippingItem;
}
发送给外部 API 的明细总额为:
商品单价 × 商品数量 + 运费
这样,运费只计算一次。
如果 API 只接收订单总金额
如果外部 API 不需要逐项商品明细,只接收一个支付金额,可以直接获取包含运费的购物车总价:
$total = (float) $cart->getOrderTotal(
true,
Cart::BOTH
);
if ($this->context->currency->id != $api_currency_id) {
$total = Tools::convertPrice(
$total,
$this->context->currency,
false
);
$total = Tools::convertPrice(
$total,
$api_currency_id
);
}
$amount = Tools::ps_round($total, 2);
订单中还可能有优惠、购物车规则等价格调整,因此使用 Cart::BOTH 通常比手工累加商品金额和运费更稳妥。
注意事项
getOrderTotal(true, ...)中的true表示含税,与price_wt的价格口径一致。如果 API 要求未税金额,应统一改用false和商品未税价格。- 执行这段代码前,购物车必须已经确定配送地址和承运商,否则运费可能为
0,之后也可能发生变化。 - 不要把完整运费加入每件商品的单价。API 通常会按
Amount × Quantity计算明细金额,这可能导致重复收费。 - 原代码中
IsTaxFree的判断方向可能相反。price与price_wt不相等,通常表示商品金额中含有税额,此时不应标记为免税。 - 正式提交支付前,应检查所有明细金额之和是否与
getOrderTotal(true, Cart::BOTH)转换后的金额一致,并特别留意折扣和舍入差异。
备注:内容仅供参考。
