Просмотр исходного кода

Merge branch 'redesign‌-260706' into dev

shizhongqi 15 часов назад
Родитель
Сommit
97bebb0b8f

+ 3 - 2
app-mall/controllers/OrderController.php

@@ -2052,6 +2052,7 @@ class OrderController extends BaseController
 
     /**
      * 订单详情是否可申请售后(与 mall RefundController::canApplyRefund 规则一致)
+     * 现金为 0 时:红包仍挂单(hbId>0)且红包金额大于订单实付(hbAmount>mainPay)才允许申请
      * @param array $order 订单详情
      * @param array|null $apply 最新顾客申请,避免详情里重复查
      * @return bool
@@ -2077,8 +2078,8 @@ class OrderController extends BaseController
         if (DistributionOrderClass::isDistOrderSettled((int)($order['id'] ?? 0))) {
             return false;
         }
-        $could = bcsub((string)($order['orderPrice'] ?? 0), (string)($order['tkPrice'] ?? 0), 2);
-        if (bccomp($could, '0', 2) <= 0) {
+        // 可退现金>0 可申请;现金为 0 时需红包未退回且红包金额大于实付
+        if (!HdRefundMallClass::hasRefundableAmount($order)) {
             return false;
         }
         return true;

+ 4 - 5
app-mall/controllers/RefundController.php

@@ -29,9 +29,7 @@ class RefundController extends BaseController
         }
         $this->assertOrderOwner($order);
 
-        $orderPrice = (float)($order['orderPrice'] ?? 0);
-        $tkPrice = (float)($order['tkPrice'] ?? 0);
-        $couldRefundPrice = round(max(0, $orderPrice - $tkPrice), 2);
+        $couldRefundPrice = (float)HdRefundMallClass::remainRefundCash($order);
 
         $apply = HdRefundClass::getLatestByOrderId($id);
         if (!empty($apply) && is_array($apply)) {
@@ -213,6 +211,7 @@ class RefundController extends BaseController
 
     /**
      * 是否允许新开售后申请
+     * 现金为 0 时:红包仍挂单(hbId>0)且红包金额大于订单实付(hbAmount>mainPay)才允许申请
      * @param array $order
      * @param array|null $apply
      * @return int 1可申请 0不可
@@ -235,8 +234,8 @@ class RefundController extends BaseController
         if (DistributionOrderClass::isDistOrderSettled((int)($order['id'] ?? 0))) {
             return 0;
         }
-        $could = bcsub((string)($order['orderPrice'] ?? 0), (string)($order['tkPrice'] ?? 0), 2);
-        if (bccomp($could, '0', 2) <= 0) {
+        // 可退现金>0 可申请;现金为 0 时需红包未退回且红包金额大于实付
+        if (!HdRefundMallClass::hasRefundableAmount($order)) {
             return 0;
         }
         return 1;

+ 115 - 7
biz-hd/refund/classes/HdRefundMallClass.php

@@ -54,11 +54,14 @@ class HdRefundMallClass
         } else {
             $refundPrice = $post['price'] ?? 0;
         }
-        if (!is_numeric($refundPrice) || bccomp((string)$refundPrice, '0', 2) <= 0) {
+        $couldRefund = self::remainRefundCash($order);
+        // 红包全额抵扣后实付为 0:允许提交 0 元申请,审核通过后退回红包;其它 0 元仍拦截
+        if (!is_numeric($refundPrice) || bccomp((string)$refundPrice, '0', 2) < 0) {
+            util::fail('退款金额不正确');
+        }
+        if (bccomp((string)$refundPrice, '0', 2) === 0 && !self::allowZeroCashRefundByHb($order)) {
             util::fail('退款金额必须大于0');
         }
-
-        $couldRefund = bcsub((string)($order->orderPrice ?? 0), (string)($order->tkPrice ?? 0), 2);
         if (bccomp((string)$refundPrice, $couldRefund, 2) === 1) {
             util::fail('退款金额超过可退金额');
         }
@@ -276,10 +279,7 @@ class HdRefundMallClass
             $price = '0.00';
         }
 
-        $couldRefund = bcsub(self::toMoney($order->orderPrice ?? 0), self::toMoney($order->tkPrice ?? 0), 2);
-        if (bccomp($couldRefund, '0', 2) < 0) {
-            $couldRefund = '0.00';
-        }
+        $couldRefund = self::remainRefundCash($order);
         if (bccomp($price, $couldRefund, 2) === 1) {
             $price = $couldRefund;
         }
@@ -333,6 +333,114 @@ class HdRefundMallClass
         return number_format((float)$value, 2, '.', '');
     }
 
+    /**
+     * 从订单数组或对象取字段;详情接口和申请页传入形态不同
+     * @param array|object $order
+     * @param string $key
+     * @param mixed $default
+     * @return mixed
+     */
+    protected static function orderField($order, $key, $default = 0)
+    {
+        if (is_object($order)) {
+            return $order->$key ?? $default;
+        }
+        if (is_array($order)) {
+            return $order[$key] ?? $default;
+        }
+        return $default;
+    }
+
+    /**
+     * 剩余可退现金:实付合计 orderPrice 减已退 tkPrice
+     * 红包抵扣已计入 orderPrice,所以红包全额单这里为 0
+     * @param array|object $order
+     * @return string 两位小数字符串,不会为负
+     */
+    public static function remainRefundCash($order)
+    {
+        $could = bcsub(
+            self::toMoney(self::orderField($order, 'orderPrice', 0)),
+            self::toMoney(self::orderField($order, 'tkPrice', 0)),
+            2
+        );
+        if (bccomp($could, '0', 2) < 0) {
+            return '0.00';
+        }
+        return $could;
+    }
+
+    /**
+     * 红包是否仍占用本单未退回:下单写正数 hbId,退回后改成负数
+     * @param array|object $order
+     * @return bool
+     */
+    public static function hasUnreturnedHb($order)
+    {
+        return (int)self::orderField($order, 'hbId', 0) > 0;
+    }
+
+    /**
+     * 订单实付现金:优先 mainPay(详情「订单合计」),否则 actPrice / orderPrice
+     * @param array|object $order
+     * @return string 两位小数字符串
+     */
+    public static function orderPayAmount($order)
+    {
+        foreach (['mainPay', 'actPrice', 'orderPrice'] as $key) {
+            if (self::orderFieldExists($order, $key)) {
+                return self::toMoney(self::orderField($order, $key, 0));
+            }
+        }
+        return '0.00';
+    }
+
+    /**
+     * 字段是否存在于订单数组或对象上;mainPay=0 也算有值,不能当缺失
+     * @param array|object $order
+     * @param string $key
+     * @return bool
+     */
+    protected static function orderFieldExists($order, $key)
+    {
+        if (is_object($order)) {
+            return isset($order->$key);
+        }
+        if (is_array($order)) {
+            return array_key_exists($key, $order);
+        }
+        return false;
+    }
+
+    /**
+     * 现金为 0 时是否仍可申请:红包未退回,且红包金额大于订单实付
+     * 红包把合计抵成 0 时 hbAmount > mainPay;红包已退回或金额不足以覆盖实付则不允许
+     * @param array|object $order
+     * @return bool
+     */
+    public static function allowZeroCashRefundByHb($order)
+    {
+        if (!self::hasUnreturnedHb($order)) {
+            return false;
+        }
+        $hbAmount = self::toMoney(self::orderField($order, 'hbAmount', 0));
+        $payAmount = self::orderPayAmount($order);
+        return bccomp($hbAmount, $payAmount, 2) === 1;
+    }
+
+    /**
+     * 是否还有可售后标的:剩余现金>0,或现金为 0 但红包未退回且红包金额大于实付
+     * @param array|object $order
+     * @return bool
+     */
+    public static function hasRefundableAmount($order)
+    {
+        if (bccomp(self::remainRefundCash($order), '0', 2) > 0) {
+            return true;
+        }
+        return self::allowZeroCashRefundByHb($order);
+    }
+
     /**
      * 商家审核通过:复用已有待审核行执行真实退款 + 红包按过期退回 + 消费回退
      * @param object $refund xhHdRefund 待审核对象

+ 11 - 1
biz-hd/refund/services/HdRefundService.php

@@ -51,7 +51,11 @@ class HdRefundService extends BaseService
         }
 
         $refundPrice = bcadd((string)($post['price'] ?? '0'), '0', 2);
-        if (bccomp($refundPrice, '0', 2) <= 0) {
+        if (bccomp($refundPrice, '0', 2) < 0) {
+            util::fail('请填写退款金额');
+        }
+        // 红包全额抵扣的 0 元单允许 0 元售后(退货/退红包);其它 0 元仍拦截
+        if (bccomp($refundPrice, '0', 2) === 0 && (int)($order->hbId ?? 0) <= 0) {
             util::fail('请填写退款金额');
         }
 
@@ -270,6 +274,12 @@ class HdRefundService extends BaseService
             $refund = HdRefundClass::add($data, true);
         }
 
+        // 实付 0 仅退红包:不走拉卡拉/资金流水,避免 0 元通道失败;红包在 mall 审核通过后 hbBackIfNotExpired
+        if (bccomp($refundPrice, '0', 2) <= 0) {
+            HdNextDayRefundClass::syncRefundFundFlags($refund, ['hasReturn' => HdNextDayRefundClass::FLAG_YES]);
+            return HdRefundClass::getById($refund->id, true);
+        }
+
         $payWay = $order->payWay;
         $shopId = $order->shopId;
         $onlinePay = $order->onlinePay ?? 1;