数量, 'weight' => 重量], ...] * - deliveryPlatform: 配送平台(shansong/huolala/fengniao等) * - ghsInfo: 供货商信息 ['mainId' => xxx, 'shopId' => xxx] * - custom: 客户信息对象(包含 name, mobile, fullAddress, lat, long 等) * - order: 订单基础信息 ['orderSn' => xxx, 'itemTotalAmount' => xxx, 'remark' => xxx] * - mainId: 当前操作者的 mainId * - productCount: 商品总数量(用于免费配送判断) * * @return array 返回数组 * - sendCost: 配送费用(元) * - sendDistance: 配送距离(米) * - deliveryList: 可选配送方式列表 * - platformQuotes: 原始平台报价数据 * * @throws \Exception 当报价失败时抛出异常 */ public static function getDeliveryQuote($params) { // 1. 参数验证 self::validateParams($params); // 2. 计算商品总重量 $weight = self::calculateTotalWeight($params['productList']); // 3. 构建订单数据 $order = self::buildOrderData($params, $weight); // 4. 获取供货商店铺信息 $ghsShop = ShopClass::getById($params['ghsInfo']['shopId']); if (empty($ghsShop)) { throw new \Exception("供货商店铺信息不存在:shopId={$params['ghsInfo']['shopId']}"); } // 5. 调用跑腿平台获取报价 $orderTime = date('Y-m-d H:i:s'); $ds = new DispatchService($params['ghsInfo']['mainId'], $params['deliveryPlatform']); $platformQuotes = $ds->getAllPlatformPrice($order, $ghsShop, $orderTime); // 6. 检查报价结果 if (isset($platformQuotes['error'])) { $errorMsg = $platformQuotes['error']; Yii::error($errorMsg); noticeUtil::push("{$params['deliveryPlatform']}-跑腿平台估价接口获取费用与距离失败:mainId={$params['mainId']}"); throw new \Exception($errorMsg); } // 7. 格式化平台报价 $deliveryList = $ds->formatPlatformQuotesForDisplay($platformQuotes); // 8. 重试机制(如果第一次失败) if (is_array($deliveryList) && empty($deliveryList)) { sleep(2); $platformQuotes = $ds->getAllPlatformPrice($order, $ghsShop, $orderTime); $deliveryList = $ds->formatPlatformQuotesForDisplay($platformQuotes); } // 9. 检查是否有可用的配送方式 if (is_array($deliveryList) && empty($deliveryList)) { $errorMsg = "ghsMainId={$params['ghsInfo']['mainId']}, orderSn={$order['orderSn']} 请求{$params['deliveryPlatform']}平台报价失败。"; noticeUtil::push($errorMsg); Yii::error($errorMsg); throw new \Exception($errorMsg); } // 10. 获取报价结果 $result = null; if (in_array($params['deliveryPlatform'], ['huolala', 'fengniao', 'didi'])) { $bracketContent = $params['deliveryBracketContent'] ?? ''; if ($params['deliveryPlatform'] == 'didi') { $bracketContent = "滴滴 ({$bracketContent})"; } $key = ''; foreach ($deliveryList as $item) { if ($params['deliveryPlatform'] == 'huolala') { $key = 'vehicle_type'; } if ($params['deliveryPlatform'] == 'fengniao') { $key = 'base_goods_id'; } if ($params['deliveryPlatform'] == 'didi') { $key = 'name'; } if ($item[$key] == $bracketContent) { $result = $item; } } if ($result === null) { throw new \Exception('没有找到对应的配送方式'); } } else { $result = $deliveryList[0]; } $sendCost = ($result['price'] ?? 0) / 100; $sendDistance = $result['distance'] ?? 0; // 11. 应用免费配送规则 if(isset($params['order']['freightType']) && $params['order']['freightType'] == 0) { //用于处理及区分花束订单是否部分免跑腿费,还是完全收取跑腿费 $finalSendCost= $sendCost; }else{ $finalSendCost = self::applyFreeDeliveryRules( $sendCost, $sendDistance, $params['ghsInfo']['shopId'], $params['productCount'], $params['order']['itemTotalAmount'], $params['ghsInfo']['mainId'], $order['orderSn'], $order['goodsType'] ); } return [ 'sendCost' => $finalSendCost, 'sendDistance' => $sendDistance, 'deliveryList' => $deliveryList, 'platformQuotes' => $platformQuotes, ]; } /** * 计算商品总重量 * * @param array $productList 商品列表 * @return float 总重量(公斤) */ private static function calculateTotalWeight($productList) { $weight = 0; // foreach ($productList as $itemData) { // $bigNum = $itemData['bigNum'] ?? 0; // $thisWeight = $itemData['weight'] ?? 0; // $currentWeight = bcmul($thisWeight, $bigNum, 2); // $weight = bcadd($currentWeight, $weight, 2); // } // TODO 先默认都是 1 公斤 $weight = 1; return $weight; } /** * 构建订单数据 * * @param array $params 参数数组 * @param float $weight 总重量 * @return array 订单数据 */ private static function buildOrderData($params, $weight) { $custom = $params['custom']; $orderInfo = $params['order']; return [ 'orderSn' => $orderInfo['orderSn'], 'customName' => $custom->name, 'customMobile' => $custom->mobile, 'fullAddress' => $custom->fullAddress, 'floor' => $custom->floor, 'dist' => $custom->dist, 'lat' => $custom->lat, 'long' => $custom->long, 'address' => $custom->address, 'city' => $custom->city, 'weight' => $weight, 'remark' => $orderInfo['remark'] ?? '', 'prePrice' => $orderInfo['itemTotalAmount'] ?? 0, 'actPrice' => $orderInfo['itemTotalAmount'] ?? 0, 'goodsType' => $orderInfo['goodsType'], ]; } /** * 应用免费配送规则 * * @param float $sendCost 原始配送费用 * @param int $sendDistance 配送距离(米) * @param int $shopId 店铺ID * @param int $productCount 商品数量 * @param float $itemTotalAmount 商品总金额 * @param int $ghsMainId 供货商mainId * @param string $orderSn 订单号 * @param int $goodsType 商品类型:0花束 1花材 * @return float 最终配送费用 */ private static function applyFreeDeliveryRules( $sendCost, $sendDistance, $shopId, $productCount, $itemTotalAmount, $ghsMainId, $orderSn, $goodsType ){ // 获取店铺扩展信息(免费配送设置) $shopExt = ShopExtClass::getByCondition(['shopId' => $shopId], false, null, 'id,hcFreeKm,hcMap,hsFreeKm,hsAddFee'); if (empty($shopExt)) { return $sendCost; } if ($goodsType == 1) {//花材 // 获取花材的免费配送设置 $hcFreeKm = ($shopExt['hcFreeKm'] ?? 0) * 1000; // 转换为米 $hcMapString = $shopExt['hcMap'] ?? ''; $hcMap = []; if (!empty($hcMapString)) { $hcMap = json_decode($hcMapString, true); } // 判断是否免跑腿费 if ($sendDistance > $hcFreeKm) { // 超过免费距离,检查是否满足其他免费条件 if (count($hcMap) > 0) { foreach ($hcMap as $rule) { $ruleNum = $rule['num'] ?? 0; $rulePrice = $rule['price'] ?? 0; $ruleDistance = ($rule['distance'] ?? 0) * 1000; if ($productCount >= $ruleNum && $itemTotalAmount >= $rulePrice && $sendDistance <= $ruleDistance) { //noticeUtil::push("ghsMainId={$ghsMainId}, orderSn={$orderSn}, 免跑腿费,满足条件:" . json_encode($rule)); return 0; } } } } else { // 在免费配送距离内 return 0; } } else if ($goodsType == 0) {//花束 // 获取花束的免费配送设置 $hsFreeKm = ($shopExt['hsFreeKm'] ?? 0) * 1000; // 转换为米 $hsAddFee = $shopExt['hsAddFee'] ?? 0; // 判断是否免跑腿费 if ($sendDistance > $hsFreeKm) { $pass = bcsub($sendDistance, $hsFreeKm, 2); $km = bcdiv($pass,1000,2); //向上取整,不足1公里的按1公里算 $km = ceil($km); return bcmul($km,$hsAddFee,2); } else { // 在免费配送距离内 return 0; } } else { new \Exception('不支持的订单类型'); } return $sendCost; } /** * 参数验证 * * @param array $params 参数数组 * @throws \Exception 当参数不合法时抛出异常 */ private static function validateParams($params) { $requiredFields = [ 'productList', 'deliveryPlatform', 'ghsInfo', 'custom', 'order', 'mainId' ]; foreach ($requiredFields as $field) { if (!isset($params[$field])) { throw new \Exception("缺少必要参数:{$field}"); } } if (empty($params['productList']) || !is_array($params['productList'])) { throw new \Exception("商品列表不能为空"); } if (empty($params['ghsInfo']['mainId']) || empty($params['ghsInfo']['shopId'])) { throw new \Exception("供货商信息不完整"); } } }