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

fix(order): 避免拼团和秒杀订单叠加整单优惠

- 拼团订单按活动价结算,跳过会员折扣与门店满减
- 秒杀商品金额和件数不参与整单优惠,并统一优惠互斥比较与落单口径
- 保留秒杀订单标记,确保后续佣金等流程继续正确识别

API: 调整商城拼团与混合下单的优惠结算结果,活动商品不再重复享受整单优惠
shizhongqi 4 часов назад
Родитель
Сommit
f26f7cb0be

+ 5 - 0
app-mall/controllers/GroupBuyController.php

@@ -23,6 +23,7 @@ use Yii;
 /**
  * 商城端拼团接口
  * 落地页 / 团详情 / 开团 / 参团 / 我的拼团
+ * 开团/参团订单按团购价结算,不叠加会员折扣、门店满减等优惠
  */
 class GroupBuyController extends BaseController
 {
@@ -312,6 +313,7 @@ class GroupBuyController extends BaseController
 
     /**
      * 组装并创建拼团订单(核价以后端活动商品为准)
+     * 团购价已是活动优惠价:跳过会员折、门店满减,避免再叠折扣
      *
      * @param object $form
      * @param array $row
@@ -399,6 +401,9 @@ class GroupBuyController extends BaseController
             'cash' => 0,
             'needPrint' => dict::getDict('needPrint', 'need'),
             'groupBuyId' => intval($groupBuyId),
+            // 拼团价已是活动价:跳过会员折和门店满减,避免 createHdOrder/addOrder 再叠折扣
+            'skipMemberDiscount' => 1,
+            'skipShopMeetCut' => 1,
             'product' => [[
                 'productId' => $saleGoodsId,
                 'unitType' => 0,

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

@@ -975,6 +975,7 @@ class OrderController extends BaseController
      * 花束+花材合并结算下单
      * 复用 OrderService::createHdOrder,不改动 buy-item / create-order
      * 整单优惠:会员折扣与门店满减互斥,只落地优惠金额更大的一项(相等用会员折扣)
+     * 秒杀商品已是活动价:seckillGoodsPrice 不计入会员折、门店满减金额基数,seckillGoodsNum 不计入满减件数门槛,仍计入应付和最低消费数量
      */
     public function actionCreateMixOrder()
     {
@@ -1119,6 +1120,10 @@ class OrderController extends BaseController
             $totalReachDiscount = 0;
             $resolvedProduct = [];
             $hasSeckillGoods = false;
+            // 秒杀商品行合计:供会员折/门店满减剔除,避免活动价再叠整单优惠
+            $seckillGoodsPrice = 0;
+            // 秒杀花束份数:不计入门店满减件数门槛,最低消费数量仍按整单份数
+            $seckillGoodsNum = 0;
 
             $priceMap = \bizGhs\custom\classes\CustomClass::$levelPriceKeyMap;
             $addPriceMap = \bizGhs\custom\classes\CustomClass::$levelAddPriceKeyMap;
@@ -1264,6 +1269,10 @@ class OrderController extends BaseController
                     }
                     $currentTotal = bcmul($unitPrice, $goodsNum, 2);
                     $modifyPrice = bcadd($modifyPrice, $currentTotal, 2);
+                    if ($seckillRow) {
+                        $seckillGoodsPrice = bcadd($seckillGoodsPrice, $currentTotal, 2);
+                        $seckillGoodsNum = bcadd($seckillGoodsNum, $goodsNum, 2);
+                    }
                     $weight = $goodsInfo->weight ?? 0;
                     if ($weight > 5) {
                         $weight = 5;
@@ -1512,10 +1521,21 @@ class OrderController extends BaseController
             $post['bigNum'] = $totalNum;
             $post['modifyPrice'] = $modifyPrice;
             $post['hasSeckill'] = $hasSeckillGoods ? 1 : 0;
-            // 混合单:会员折扣与门店满减互斥,取优惠更大的一项,避免 createHdOrder 再叠满减
-            $wholePick = WholeOrderDiscountClass::pick(
+            $post['seckillGoodsPrice'] = $seckillGoodsPrice;
+            $post['seckillGoodsNum'] = $seckillGoodsNum;
+            // 互斥比较与落单使用同一口径:秒杀活动价不参与会员折和门店满减
+            $wholeDiscountPrice = bcsub(
                 $modifyPrice,
-                $unMeetBigNum,
+                HdOrderClass::capSeckillExcludePrice($seckillGoodsPrice, $modifyPrice),
+                2
+            );
+            $wholeDiscountNum = bcsub($unMeetBigNum, $seckillGoodsNum, 2);
+            if (bccomp($wholeDiscountNum, '0', 2) < 0) {
+                $wholeDiscountNum = 0;
+            }
+            $wholePick = WholeOrderDiscountClass::pick(
+                $wholeDiscountPrice,
+                $wholeDiscountNum,
                 $custom->discount ?? 1,
                 $shop
             );

+ 36 - 5
biz-hd/order/classes/OrderClass.php

@@ -191,24 +191,34 @@ class OrderClass extends BaseClass
 
         $book = $data['book'] ?? 0;
         // skipShopMeetCut:前端已写入满减后金额时跳过,避免二次门店满减
-        $skipShopMeetCut = !empty($data['skipShopMeetCut']);
-        unset($data['skipShopMeetCut'], $data['skipMemberDiscount']);
+        // 拼团单不叠加门店满减(团购价已是优惠价)
+        $skipShopMeetCut = !empty($data['skipShopMeetCut']) || intval($data['groupBuyId'] ?? 0) > 0;
+        $seckillGoodsPrice = self::capSeckillExcludePrice($data['seckillGoodsPrice'] ?? 0, $data['actPrice'] ?? 0);
+        $seckillGoodsNum = is_numeric($data['seckillGoodsNum'] ?? 0) ? $data['seckillGoodsNum'] : 0;
+        unset($data['skipShopMeetCut'], $data['skipMemberDiscount'], $data['seckillGoodsPrice'], $data['seckillGoodsNum']);
         if ($book == 0 && !$skipShopMeetCut) {
             $actPrice = $data['actPrice'];
             $meetNum = $shop->meetNum ?? 0;
             $meetAmount = $shop->meetAmount ?? 0;
             $cutOption = $shop->cutAmount ?? 0;
             $cutStyle = $shop->cutStyle ?? 0;
+            // 满减金额门槛和折扣额按剔除秒杀后的应付算,避免秒杀价凑满减或被打折
+            $discountablePrice = bcsub($actPrice, $seckillGoodsPrice, 2);
+            // 满减件数门槛不含秒杀份数,最低消费数量仍用订单 bigNum
+            $meetBigNum = isset($data['bigNum']) ? bcsub($data['bigNum'], $seckillGoodsNum, 2) : 0;
+            if (bccomp($meetBigNum, '0', 2) < 0) {
+                $meetBigNum = 0;
+            }
 
             if ($cutStyle == 0) {
                 $cutAmount = $cutOption;
             } else {
                 $miniOption = bcsub(1, $cutOption, 2);
-                $cutAmount = bcmul($actPrice, $miniOption, 2);
+                $cutAmount = bcmul($discountablePrice, $miniOption, 2);
             }
             if ($cutAmount > 0 && $meetNum >= 0 && $meetAmount > 0) {
-                if (isset($data['bigNum']) && $data['bigNum'] >= $meetNum && $data['actPrice'] >= $meetAmount) {
-                    if ($cutAmount < $actPrice) {
+                if (bccomp($meetBigNum, $meetNum, 2) >= 0 && bccomp($discountablePrice, $meetAmount, 2) >= 0) {
+                    if (bccomp($cutAmount, $discountablePrice, 2) < 0) {
                         $actPrice = bcsub($actPrice, $cutAmount, 2);
                         $data['orderReachDiscountPrice'] = $cutAmount;
                         $data['actPrice'] = $actPrice;
@@ -233,6 +243,27 @@ class OrderClass extends BaseClass
         return self::add($data, true);
     }
 
+    /**
+     * 将会员折/满减要剔除的秒杀金额限制在应付范围内。
+     * 红包把应付压到低于秒杀额时,不能用完整秒杀额去减,否则会抬高应付。
+     *
+     * @param mixed $seckillPrice 秒杀商品行合计
+     * @param mixed $payablePrice 当前应付(含运费包装、已减红包)
+     * @return string 不超过应付的秒杀剔除额
+     */
+    public static function capSeckillExcludePrice($seckillPrice, $payablePrice)
+    {
+        $seckillPrice = is_numeric($seckillPrice) ? $seckillPrice : 0;
+        $payablePrice = is_numeric($payablePrice) ? $payablePrice : 0;
+        if (bccomp($seckillPrice, '0', 2) <= 0 || bccomp($payablePrice, '0', 2) <= 0) {
+            return '0.00';
+        }
+        if (bccomp($seckillPrice, $payablePrice, 2) > 0) {
+            return bcadd($payablePrice, '0', 2);
+        }
+        return bcadd($seckillPrice, '0', 2);
+    }
+
     public static function getByOrderSn($orderSn)
     {
         return self::getByCondition(['orderSn' => $orderSn]);

+ 12 - 4
biz-hd/order/services/OrderService.php

@@ -239,13 +239,21 @@ class OrderService extends BaseService
 
         $modifyPrice = isset($data['modifyPrice']) && $data['modifyPrice'] > 0 ? $data['modifyPrice'] : 0;
         // skipMemberDiscount:前端(mall 混合单 / hd 开单页)已写入折后 modifyPrice 时跳过,避免二次会员折
-        $skipMemberDiscount = !empty($data['skipMemberDiscount']);
+        // 拼团单只按团购价结算,不再叠加会员折扣
+        $isGroupBuyOrder = intval($data['groupBuyId'] ?? 0) > 0;
+        $skipMemberDiscount = !empty($data['skipMemberDiscount']) || $isGroupBuyOrder;
         unset($data['skipMemberDiscount']);
         $memberDiscount = $custom->discount ?? 1;
+        // 秒杀已是活动价,会员折只打在非秒杀应付上,折后再加回秒杀额
+        $seckillGoodsPrice = OrderClass::capSeckillExcludePrice($data['seckillGoodsPrice'] ?? 0, $modifyPrice);
         if (!$skipMemberDiscount && is_numeric($memberDiscount) && $memberDiscount > 0 && $memberDiscount < 1.0 && $modifyPrice > 0) {
-            $modifyPrice = bcmul($modifyPrice, $memberDiscount, 2);
-            if (bccomp($modifyPrice, '0', 2) <= 0) {
-                $modifyPrice = 0.01;
+            $discountablePrice = bcsub($modifyPrice, $seckillGoodsPrice, 2);
+            if (bccomp($discountablePrice, '0', 2) > 0) {
+                $discountedPrice = bcmul($discountablePrice, $memberDiscount, 2);
+                if (bccomp($discountedPrice, '0', 2) <= 0) {
+                    $discountedPrice = 0.01;
+                }
+                $modifyPrice = bcadd($discountedPrice, $seckillGoodsPrice, 2);
             }
         }
         //优惠