wyyl/beike/Shop/Services/TotalServices/ShippingService.php

199 lines
8.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* ShippingService.php
*
* @copyright 2022 beikeshop.com - All Rights Reserved
* @link https://beikeshop.com
* @author Edward Yang <yangjin@guangda.work>
* @created 2022-07-22 17:58:14
* @modified 2022-07-22 17:58:14
*/
namespace Beike\Shop\Services\TotalServices;
use Beike\Libraries\Weight;
use Beike\Models\Logistics;
use Beike\Shop\Services\CheckoutService;
use Illuminate\Support\Str;
class ShippingService{
// 运费计算
public static function getTotal(CheckoutService $checkout): ?array{
$totalService = $checkout->totalService;
$shippingMethod = $totalService->getShippingMethod();
$amount = 0;
if($shippingMethod && !is_int($checkout->cart->shipping_method_code)){
// 通过插件(固定运费) 进行计算
if(empty($shippingMethod)) return NULL;
$shippingPluginCode = self::parseShippingPluginCode($shippingMethod);
$pluginCode = Str::studly($shippingPluginCode);
if(!app('plugin')->checkActive($shippingPluginCode)){
$cart = $checkout->cart;
$cart->shipping_method_code = '';
$cart->saveOrFail();
return [];
}
$className = "Plugin\\{$pluginCode}\\Bootstrap";
if(!method_exists($className,'getShippingFee')){
throw new \Exception("请在插件 {$className} 实现方法: public function getShippingFee(CheckoutService \$checkout)");
}
$amount = (float)(new $className)->getShippingFee($checkout);
}
else{
// 通过物流进行计算
$logisticsId = (int)$checkout->cart->shipping_method_code;
$logisticsInfo = self::getLogistics($logisticsId,$checkout->cart);
if($logisticsInfo) {
// 商品信息处理 获取同一个商品的数量
$products = $checkout->selectedProducts->toArray() ?? [];
$productsList = collect($products)->groupBy('product_id')->map(function($group){
$firstInfo = $group->first();
// 重量转换 - 物流重量单位为 千克;商品重量需要进行转换
$weight = $firstInfo['product']['weight'] ?? 0;
$sumQuantity = $group->sum('quantity');
$sumWeight = (float)sprintf("%.2f",($weight * $sumQuantity));
$weightClass = $firstInfo['product']['weight_class'];
$sumWeight = Weight::convert($sumWeight,$weightClass);// 总重量 单位:克
return [
'product_id' => $firstInfo['product_id'],
'sum_quantity' => $sumQuantity,
'sum_weight' => $sumWeight,
'weight' => $weight,
'weight_class' => $weightClass,
];
});
// weight按重量计费num按数量计费free卖家包邮
$logisticsHandleFun = 'compute_'.$logisticsInfo['type'];
$amount = self::$logisticsHandleFun($logisticsInfo,$productsList);
}
}
$totalData = [
'code' => 'shipping',
'title' => trans('shop/carts.shipping_fee'),
'amount' => $amount,
'amount_format' => currency_format($amount),
];
$totalService->amount += $totalData['amount'];
$totalService->totals[] = $totalData;
return $totalData;
}
/**
* Common: 运费计算 - 物流运费 - 获取使用的物流
* Author: wu-hui
* Time: 2023/08/22 11:55
* @param $logisticsId
* @param $cart
* @return array|mixed|mixed[]
*/
private static function getLogistics($logisticsId,$cart){
if($logisticsId <= 0){
// 获取当前收货地址国家ID
$address = $cart->guest_shipping_address ?? $cart->guest_payment_address;
$countryId = $address['country_id'];
// 获取全部物流 返回第一个物流信息ID
$logisticsList = Logistics::getAll($countryId,['type','first_weight','first_weight_fee','continuation_weight_max','add_weight','continuation_weight_fee','num_fee']);
return $logisticsList[0] ?? [];
}else{
// 获取物流信息
$logisticsInfo = Logistics::query()
->select(['type','first_weight','first_weight_fee','continuation_weight_max','add_weight','continuation_weight_fee','num_fee'])
->find($logisticsId)
->toArray();
return $logisticsInfo;
}
}
/**
* Common: 运费计算 - 物流运费 - 运费计算(按重量计费)
* Author: wu-hui
* Time: 2023/08/22 15:34
* @param $logisticsInfo
* @param $productsList
* @return float|int
*/
private static function compute_weight($logisticsInfo,$productsList){
/**
* 计算规则:
* 总重量 - 低于首重;则运费 = 【首重运费】
* 总重量 - 高于首重;则运费 = 首重按照【首重运费】计算;(剩余重量 / 每增加重量 * 续重运费
*/
$amount = (int)0;
$firstWeight = (int)$logisticsInfo['first_weight'];// 首重
$firstWeightFee = (float)$logisticsInfo['first_weight_fee'];// 首重运费
$addWeight = (int)$logisticsInfo['add_weight'];// 每增加重量
$continuationWeightFee = (float)$logisticsInfo['continuation_weight_fee'];// 续重运费
// 循环处理商品
foreach($productsList as $productInfo){
// 首重运费
$amount += (float)sprintf("%.2f",$firstWeightFee);
// 判断:如果总重量超过首重 则计算续重运费
$surplus = (int)$productInfo['sum_weight'] - $firstWeight;
if($surplus > 0) $amount += (float)sprintf("%.2f",($surplus / $addWeight) * $continuationWeightFee);
}
return $amount;
}
/**
* Common: 运费计算 - 物流运费 - 运费计算(按数量计费)
* Author: wu-hui
* Time: 2023/08/22 14:47
* @param $logisticsInfo
* @param $productsList
* @return float|int
*/
private static function compute_num($logisticsInfo,$productsList){
/**
* 计算规则:
* 购买数量 - 低于首件数量;则运费 = 【首件运费】
* 购买数量 - 高于首件数量;则运费 = 首件数量按照【首件运费】计算;(剩余购买数量 / 每增加件数量 * 续件运费
*/
$amount = (int)0;
$firstWeight = (int)$logisticsInfo['first_weight'];// 首件数量
$firstWeightFee = (float)$logisticsInfo['first_weight_fee'];// 首件运费
$addWeight = (int)$logisticsInfo['add_weight'];// 每增加件
$continuationWeightFee = (float)$logisticsInfo['continuation_weight_fee'];// 续件运费
// 循环处理商品
foreach($productsList as $productInfo){
// 首件运费
$amount += (float)sprintf("%.2f",$firstWeightFee);
// 判断:如果数量超过首件数量 则计算续件运费
$surplus = (int)$productInfo['sum_quantity'] - $firstWeight;
if($surplus > 0) $amount += (float)sprintf("%.2f",($surplus / $addWeight) * $continuationWeightFee);
}
return $amount;
}
/**
* Common: 运费计算 - 物流运费 - 运费计算(卖家包邮)
* Author: wu-hui
* Time: 2023/08/22 11:59
* @param $logisticsInfo
* @param $productsList
* @return int
*/
private static function compute_free($logisticsInfo,$productsList){
return 0;
}
/**
* 通过配送方式获取插件编码
*
* @param $shippingMethod
* @return string
*/
public static function parseShippingPluginCode($shippingMethod): string
{
$methodArray = explode('.', $shippingMethod);
return $methodArray[0];
}
}