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

Merge branch 'redesign‌-260706' into dev

shizhongqi 3 недель назад
Родитель
Сommit
01ab79b72b

+ 423 - 0
app-mall/controllers/OrderController.php

@@ -903,6 +903,429 @@ class OrderController extends BaseController
 
     }
 
+    /**
+     * 花束+花材合并结算下单
+     * 复用 OrderService::createHdOrder,不改动 buy-item / create-order
+     */
+    public function actionCreateMixOrder()
+    {
+        $post = Yii::$app->request->post();
+        $post['sjId'] = $this->sjId;
+        $post['shopId'] = $this->shopId;
+        $post['payWay'] = 0;
+        $post['mainId'] = $this->mainId ?? 0;
+        $post['userId'] = $this->userId ?? 0;
+
+        $userId = $this->userId;
+        util::checkRepeatCommit($userId, 3);
+
+        $shop = $this->shop;
+        $openShop = \bizHd\shop\classes\ShopClass::getOpenShop($shop);
+        if ($openShop == 0) {
+            util::fail('已休店');
+        }
+
+        $mainId = $this->mainId;
+        if (getenv('YII_ENV') == 'production') {
+            if (in_array($mainId, [40057, 7779, 42940, 26374, 10536, 65381])) {
+                util::fail('暂时无法访问');
+            }
+        }
+
+        $hdId = $post['hdId'] ?? 0;
+        $hd = HdClass::getById($hdId, true);
+        if (empty($hd)) {
+            util::fail('没有找到花店');
+        }
+        if ($hd->shopId != $this->shopId) {
+            util::fail('不是你的花店');
+        }
+        $post['hdName'] = $hd->name ?? '';
+        // 合并结算沿用花材购物车的客户身份(花店客户)
+        $hdCustomId = $hd->customId ?? 0;
+        $custom = CustomClass::getById($hdCustomId, true);
+        if (empty($custom)) {
+            util::fail('没有找到客户');
+        }
+        $customName = $custom->name ?? '';
+        $post['customId'] = $hdCustomId;
+        $post['customName'] = $customName;
+        $post['customNamePy'] = stringUtil::py($customName);
+
+        $productJson = $post['product'] ?? '';
+        if (empty($productJson)) {
+            util::fail('请选择商品');
+        }
+        $productList = json_decode($productJson, true);
+        if (empty($productList) || !is_array($productList)) {
+            util::fail('请选择商品');
+        }
+
+        $itemRows = [];
+        $goodsRows = [];
+        foreach ($productList as $idx => $row) {
+            $property = intval($row['property'] ?? -1);
+            if ($property === 1) {
+                $itemRows[$idx] = $row;
+            } elseif ($property === 0) {
+                $goodsRows[$idx] = $row;
+            } else {
+                util::fail('商品类型错误');
+            }
+        }
+        if (empty($itemRows) && empty($goodsRows)) {
+            util::fail('请选择商品');
+        }
+
+        // ---- 花材校验与定价 ----
+        $productInfoList = [];
+        if (!empty($itemRows)) {
+            $ids = array_unique(array_filter(array_map(function ($r) {
+                return intval($r['productId'] ?? 0);
+            }, $itemRows)));
+            $productInfoList = ProductClass::getByIds($ids, null, 'id');
+            if (empty($productInfoList)) {
+                util::fail('花材不存在');
+            }
+            $presellData = [];
+            $nowTime = strtotime(date("Y-m-d"));
+            foreach ($productInfoList as $currentInfo) {
+                if (!isset($currentInfo['mainId']) || $currentInfo['mainId'] != $this->mainId) {
+                    util::fail('只能选一家的商品,请清空重新选呢');
+                }
+                $presell = $currentInfo['presell'] ?? 0;
+                $presellData[] = $presell;
+                if ($presell == 1) {
+                    if (empty($post['reachDate'])) {
+                        util::fail('请选择配送或取货日期');
+                    }
+                    $sendTimeWant = $post['reachDate'];
+                    if (strtotime($sendTimeWant) < $nowTime) {
+                        util::fail('不能选择过去时间');
+                    }
+                    $hasDateStr = $currentInfo['presellDate'] ?? [];
+                    $hasDate = explode(',', trim($hasDateStr));
+                    if (empty($hasDate)) {
+                        util::fail('预售日期有问题,请提醒门店');
+                    }
+                    if (!in_array(strtotime($sendTimeWant), $hasDate)) {
+                        util::fail("有预售花材在{$sendTimeWant}没到货");
+                    }
+                    $post['presell'] = 1;
+                }
+            }
+            if (count($productInfoList) != count($ids)) {
+                util::fail('存在无效花材');
+            }
+            $presellData = array_unique($presellData);
+            if (count($presellData) > 1) {
+                util::fail('预售和非预售花材不能一起下单');
+            }
+        }
+
+        $connection = Yii::$app->db;
+        $transaction = $connection->beginTransaction();
+        $transactionFinished = false;
+        register_shutdown_function(function () use (&$transactionFinished, $transaction) {
+            if ($transactionFinished) {
+                return;
+            }
+            \bizHd\product\classes\ProductClass::rollbackLimitBuySnapshot();
+            if ($transaction->isActive) {
+                $transaction->rollBack();
+            }
+        });
+
+        try {
+            $orderValidTime = !getenv('ORDER_VALID_TIME') ? 600 : getenv('ORDER_VALID_TIME');
+            $post['deadline'] = time() + $orderValidTime;
+            $post['reachDate'] = !empty($post['reachDate']) ? $post['reachDate'] : date("Y-m-d");
+            $post['needPrint'] = dict::getDict('needPrint', 'need');
+            $post['fromType'] = dict::getDict('fromType', 'mall');
+            $post['store'] = 0;
+            $user = $this->user;
+            $post['bookMobile'] = $user->mobile ?? '';
+            $post['bookName'] = $user->name ?? '';
+            $hasPay = 0;
+
+            $modifyPrice = 0;
+            $totalWeight = 0;
+            $totalNum = 0;
+            $totalReachDiscount = 0;
+            $resolvedProduct = [];
+
+            $priceMap = \bizGhs\custom\classes\CustomClass::$levelPriceKeyMap;
+            $addPriceMap = \bizGhs\custom\classes\CustomClass::$levelAddPriceKeyMap;
+
+            foreach ($productList as $eleKey => $element) {
+                $property = intval($element['property'] ?? -1);
+                if ($property === 1) {
+                    $level = 0;
+                    $productId = $element['productId'];
+                    $product = $productInfoList[$productId] ?? null;
+                    if (empty($product)) {
+                        util::fail('有花材信息没有找到');
+                    }
+                    $num = $element['num'] ?? 0;
+                    $limitKey = \bizHd\product\classes\ProductClass::LIMIT_BUY_KEY . $productId;
+                    $hasBuyNum = Yii::$app->redis->executeCommand('HGET', [$limitKey, $hdCustomId]);
+                    $hasBuyNum = $num + ($hasBuyNum == null ? 0 : $hasBuyNum);
+                    $price = \bizGhs\product\classes\ProductClass::getFinalPrice($product, $level, $priceMap, $addPriceMap, 0, $num, $hasBuyNum);
+                    $reachNum = $product['reachNum'] ?? 0;
+                    $reachNumDiscount = $product['reachNumDiscount'] ?? 0;
+                    if ($reachNum > 0 && $num >= $reachNum && $reachNumDiscount > 0) {
+                        $currentReachDiscount = bcmul($reachNumDiscount, $num, 2);
+                        $totalReachDiscount = bcadd($totalReachDiscount, $currentReachDiscount, 2);
+                    }
+                    $currentTotal = bcmul($price, $num, 2);
+                    $modifyPrice = bcadd($modifyPrice, $currentTotal, 2);
+                    $weight = $product['weight'] ?? 0;
+                    $currentWeight = bcmul($num, $weight, 2);
+                    $totalWeight = bcadd($totalWeight, $currentWeight, 2);
+                    $totalNum = bcadd($totalNum, $num);
+                    if (($product['limitBuy'] ?? 0) > 0) {
+                        $product['productId'] = $productId;
+                        \bizHd\product\classes\ProductClass::handleLimitBuy($product, $hdCustomId, floatval($num));
+                    }
+                    $resolvedProduct[] = [
+                        'productId' => $productId,
+                        'num' => $num,
+                        'itemId' => $element['itemId'] ?? 0,
+                        'unitType' => $element['unitType'] ?? 0,
+                        'property' => 1,
+                        'unitPrice' => $price,
+                    ];
+                } else {
+                    $goodsId = intval($element['goodsId'] ?? 0);
+                    $specGoodsId = intval($element['specGoodsId'] ?? 0);
+                    $saleGoodsId = intval($element['productId'] ?? 0);
+                    $goodsNum = isset($element['num']) && $element['num'] > 0 ? $element['num'] : 1;
+                    if ($goodsId <= 0 && $saleGoodsId > 0) {
+                        $probe = GoodsClass::getById($saleGoodsId, true);
+                        if (!empty($probe)) {
+                            $masterId = intval($probe->masterId ?? 0);
+                            if ($masterId > 0) {
+                                $goodsId = $masterId;
+                                $specGoodsId = $saleGoodsId;
+                            } else {
+                                $goodsId = $saleGoodsId;
+                            }
+                        }
+                    }
+                    if ($goodsId <= 0) {
+                        util::fail('请选择花束商品');
+                    }
+                    $goodsInfo = GoodsClass::getById($goodsId, true);
+                    if (empty($goodsInfo)) {
+                        util::fail('没有找到花束商品');
+                    }
+                    if ($goodsInfo->mainId != $mainId) {
+                        util::fail('不是你的商品');
+                    }
+                    if ($specGoodsId > 0) {
+                        $specGoods = GoodsClass::getById($specGoodsId, true);
+                        if (empty($specGoods) || $specGoods->mainId != $mainId || $specGoods->masterId != $goodsId || $specGoods->delStatus != 0 || $specGoods->status != 1) {
+                            util::fail('规格不可用');
+                        }
+                        $goodsInfo = $specGoods;
+                        $saleGoodsId = $specGoodsId;
+                    } else {
+                        if ((int)($goodsInfo->masterId ?? 0) === 0) {
+                            $hasSpecs = GoodsClass::getByCondition(['masterId' => $goodsId, 'delStatus' => 0], true);
+                            if (!empty($hasSpecs)) {
+                                util::fail('请选择规格');
+                            }
+                        }
+                        $saleGoodsId = $goodsId;
+                    }
+                    $stock = $goodsInfo->stock ?? 0;
+                    $stockSet = $goodsInfo->stockSet ?? 0;
+                    if ($stockSet == 1 && $stock <= 0) {
+                        util::fail('花束库存不足');
+                    }
+                    $goodsData = $goodsInfo->attributes;
+                    $ret = \bizHd\goods\classes\GoodsClass::getFinalPrice($goodsData, $shop, $custom, []);
+                    $priceType = $ret['priceType'] ?? 0;
+                    if ($priceType == 0) {
+                        util::fail('花束没有价格,不能下单');
+                    }
+                    $unitPrice = $ret['price'] ?? 0;
+                    if ($unitPrice <= 0) {
+                        util::fail('花束没有价格,不能下单');
+                    }
+                    $currentTotal = bcmul($unitPrice, $goodsNum, 2);
+                    $modifyPrice = bcadd($modifyPrice, $currentTotal, 2);
+                    $weight = $goodsInfo->weight ?? 0;
+                    if ($weight > 5) {
+                        $weight = 5;
+                    }
+                    $currentWeight = bcmul($weight, $goodsNum, 2);
+                    $totalWeight = bcadd($totalWeight, $currentWeight, 2);
+                    $totalNum = bcadd($totalNum, $goodsNum);
+                    $resolvedProduct[] = [
+                        'productId' => $saleGoodsId,
+                        'unitType' => 0,
+                        'property' => 0,
+                        'unitPrice' => $unitPrice,
+                        'num' => $goodsNum,
+                    ];
+                }
+            }
+
+            $post['product'] = $resolvedProduct;
+            $post['reachDiscountPrice'] = $totalReachDiscount;
+            unset($post['sendCost']);
+
+            $mapSet = ShopClass::hasIntraCity($this->shop);
+            $openIntraCity = $mapSet['openIntraCity'] ?? 0;
+            $hasItem = !empty($itemRows);
+            // 含花材(含混合)按花材报价 goodsType=1;纯花束按 0
+            $quoteGoodsType = $hasItem ? 1 : 0;
+
+            if (isset($post['sendType']) && $post['sendType'] == 2 && $openIntraCity != 0) {
+                if ($openIntraCity == 2) {
+                    util::fail('不能使用跑腿');
+                }
+                if (empty($post['long']) || empty($post['lat'])) {
+                    util::fail('位置错误');
+                }
+                $shopLat = $shop->lat ?? '';
+                $shopLong = $shop->long ?? '';
+                if (empty($shopLat) || empty($shopLong)) {
+                    util::fail('商家门店地址定位未设置,编号263');
+                }
+                $distance = 0;
+                $sendCost = 0;
+                $prefix = 'PT-MIX-' . $this->mainId . '-';
+                $orderSn = $prefix . round(microtime(true) * 1000);
+                $ghsInfo = ['mainId' => $this->mainId, 'shopId' => $this->shopId];
+                try {
+                    if (empty($post['deliveryPlatform'])) {
+                        util::fail('请选择跑腿');
+                    }
+                    $quoteCustom = $this->user;
+                    if ($quoteGoodsType === 0) {
+                        $quoteCustom = (object)[
+                            'name' => $post['receiveUserName'] ?? '',
+                            'mobile' => $post['receiveMobile'] ?? '',
+                            'fullAddress' => $post['address'] ?? '',
+                            'floor' => $post['floor'] ?? '',
+                            'dist' => '',
+                            'lat' => $post['lat'],
+                            'long' => $post['long'],
+                            'address' => $post['address'] ?? '',
+                            'city' => $post['city'] ?? '',
+                        ];
+                    }
+                    $quoteResult = DeliveryQuoteUtil::getDeliveryQuote([
+                        'productList' => $resolvedProduct,
+                        'deliveryPlatform' => $post['deliveryPlatform'],
+                        'deliveryBracketContent' => $post['deliveryBracketContent'] ?? '',
+                        'ghsInfo' => $ghsInfo,
+                        'custom' => $quoteCustom,
+                        'order' => [
+                            'orderSn' => $orderSn,
+                            'goodsType' => $quoteGoodsType,
+                            'itemTotalAmount' => $modifyPrice,
+                            'remark' => $post['remark'] ?? '',
+                        ],
+                        'mainId' => $this->mainId,
+                        'productCount' => $totalNum,
+                    ]);
+                    $sendCost = $quoteResult['sendCost'];
+                    $distance = $quoteResult['sendDistance'];
+                } catch (\Exception $e) {
+                    util::fail($e->getMessage());
+                }
+                $post['sendCost'] = $sendCost;
+                $post['sendDistance'] = $distance;
+                $modifyPrice = bcadd($modifyPrice, $sendCost, 2);
+            }
+
+            // 红包(归属花店客户,与 buy-item 一致)
+            $hbId = $post['hbId'] ?? 0;
+            $hb = null;
+            if ($hbId > 0) {
+                $hb = HbClass::getById($hbId, true);
+                if (!empty($hb)) {
+                    if ($hb->customId != $hdCustomId) {
+                        util::fail('不是你的红包');
+                    }
+                    if ($hb->amount != $post['hbAmount']) {
+                        util::fail('红包金额不相等');
+                    }
+                    if ($hb->status == 1) {
+                        util::fail('红包已使用');
+                    }
+                    if ($hb->status == -1) {
+                        util::fail('红包已作废');
+                    }
+                    if ($hb->endTime < time()) {
+                        $hb->status = -1;
+                        $hb->save();
+                        util::fail('红包已失效');
+                    }
+                    if ($hb->beginTime > time()) {
+                        util::fail('红包可使用期未到');
+                    }
+                    if (bccomp($modifyPrice, $hb->minConsume) == -1) {
+                        util::fail("不满足最低消费金额{$hb->minConsume}元");
+                    }
+                    $modifyPrice = bcsub($modifyPrice, $hb->amount, 2);
+                } else {
+                    util::fail('红包无效');
+                }
+            }
+
+            $sendType = $post['sendType'] ?? 0;
+            if ($sendType != 1) {
+                if (empty($post['reachPeriod'])) {
+                    util::fail('请选择配送时间哈');
+                }
+                $post['reachTime'] = strtotime($post['reachDate'] . ' ' . $post['reachPeriod']);
+            }
+
+            $post['bigNum'] = $totalNum;
+            $post['modifyPrice'] = $modifyPrice;
+            $return = \bizHd\order\services\OrderService::createHdOrder($post, $custom, $hasPay);
+
+            if (!empty($hb)) {
+                $hb->status = 1;
+                $hb->orderId = $return->id;
+                $hb->save();
+            }
+
+            if ($return->sendType == 2) {
+                $ext = ShopExtClass::getByCondition(['shopId' => $return->shopId], true, null, 'id,shopId,thirdSend');
+                if (!empty($ext) && $ext->thirdSend == 1) {
+                    util::fail('本店暂不能使用跑腿呢');
+                }
+            }
+
+            $transaction->commit();
+            $transactionFinished = true;
+            \bizHd\product\classes\ProductClass::clearLimitBuyRollbackSnapshot();
+
+            $orderSn = $return->orderSn ?? '';
+            $orderPrice = $return->orderPrice ?? ($return->actPrice ?? 0);
+            $id = $return->id ?? 0;
+            $getPayType = dict::getDict('getPayType');
+            util::success([
+                'orderSn' => $orderSn,
+                'totalPrice' => $orderPrice,
+                'couponId' => 0,
+                'id' => $id,
+                'getPayType' => $getPayType,
+            ]);
+        } catch (\Exception $e) {
+            $transaction->rollBack();
+            \bizHd\product\classes\ProductClass::rollbackLimitBuySnapshot();
+            $transactionFinished = true;
+            Yii::error("合并下单失败:" . $e->getMessage());
+            util::fail('下单失败');
+        }
+    }
+
     //下单要用到的相关信息 ssh 2019.12.6
     public function actionOrderRelate()
     {

+ 36 - 0
biz-hd/goods/classes/GoodsClass.php

@@ -505,6 +505,40 @@ class GoodsClass extends BaseClass
         return $data;
     }
 
+    /**
+     * 批量判断主商品是否启用多规格(masterId 指向该商品且未删除)
+     * @param array $goodsIds 主商品 id 列表
+     * @return array [goodsId => 1|0]
+     */
+    public static function getSpecEnabledMap($goodsIds)
+    {
+        $map = [];
+        if (empty($goodsIds)) {
+            return $map;
+        }
+        $goodsIds = array_values(array_unique(array_filter(array_map('intval', $goodsIds))));
+        if (empty($goodsIds)) {
+            return $map;
+        }
+        foreach ($goodsIds as $gid) {
+            $map[$gid] = 0;
+        }
+        $specs = self::getAllByCondition(
+            ['masterId' => ['in', $goodsIds], 'delStatus' => 0],
+            null,
+            'masterId'
+        );
+        if (!empty($specs)) {
+            foreach ($specs as $spec) {
+                $masterId = intval($spec['masterId'] ?? 0);
+                if ($masterId > 0) {
+                    $map[$masterId] = 1;
+                }
+            }
+        }
+        return $map;
+    }
+
     public static function groupGoodsBaseInfo($list, $shop, $custom, $params)
     {
         if (empty($list)) {
@@ -514,6 +548,7 @@ class GoodsClass extends BaseClass
         $goodsIds = array_column($list, 'id');
         // 一次性获取所有商品的分类关系
         $allGoodsCategories = GoodsCategoryClass::getGoodsHasCategoryIdsBatch($goodsIds);
+        $specEnabledMap = self::getSpecEnabledMap($goodsIds);
         // &$val 这里的指向符号不能去掉
         foreach ($list as $key => &$val) {
             $id = $val['id'];
@@ -548,6 +583,7 @@ class GoodsClass extends BaseClass
             $val['classId'] = 0;
             $val['bigPrice'] = $price;
             $val['smallPrice'] = $price;
+            $val['specEnabled'] = intval($specEnabledMap[$id] ?? 0);
         }
         //获取最终需要的价格
         return $list;

+ 8 - 1
biz-hd/homePageConfig/classes/HomePageModuleClass.php

@@ -618,17 +618,24 @@ class HomePageModuleClass
     public static function formatGoodsRows($rows)
     {
         $list = [];
+        $goodsIds = [];
+        foreach ($rows as $row) {
+            $goodsIds[] = intval($row['id'] ?? 0);
+        }
+        $specEnabledMap = GoodsClass::getSpecEnabledMap($goodsIds);
         foreach ($rows as $row) {
+            $id = intval($row['id']);
             $cover = strval($row['cover'] ?? '');
             $coverUrl = $cover !== '' ? imgUtil::groupImg($cover) . '?x-oss-process=image/resize,m_fill,h_700,w_700' : '';
             $list[] = [
-                'id' => intval($row['id']),
+                'id' => $id,
                 'name' => strval($row['name'] ?? ''),
                 'price' => floatval($row['price'] ?? 0),
                 'stock' => intval($row['stock'] ?? 0),
                 'cover' => $cover,
                 'coverUrl' => $coverUrl,
                 'sold' => intval(bcadd($row['actualSold'] ?? 0, $row['sold'] ?? 0)),
+                'specEnabled' => intval($specEnabledMap[$id] ?? 0),
             ];
         }
         return $list;