123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- <?php
- // +----------------------------------------------------------------------
- // | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
- // +----------------------------------------------------------------------
- // | Copyright (c) 2017~2024 https://www.yiovo.com All rights reserved.
- // +----------------------------------------------------------------------
- // | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
- // +----------------------------------------------------------------------
- // | Author: 萤火科技 <admin@yiovo.com>
- // +----------------------------------------------------------------------
- declare (strict_types=1);
- namespace app\common\service\delivery;
- use app\common\library\helper;
- use app\common\enum\Setting as SettingEnum;
- use app\common\model\Delivery as DeliveryModel;
- use app\common\model\store\Setting as SettingModel;
- use app\common\service\BaseService;
- /**
- * 快递配送服务类
- * Class Delivery
- * @package app\common\service
- */
- class Express extends BaseService
- {
- // 用户收货城市id
- private int $cityId;
- // 订单商品列表
- private iterable $goodsList;
- // 不在配送范围的商品ID
- private ?int $notInRuleGoodsId = null;
- // 运费模板数据集
- private array $data = [];
- /**
- * 构造方法
- * Express constructor.
- * @param $cityId
- * @param $goodsList
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function __construct($cityId, $goodsList)
- {
- parent::__construct();
- // 赋值传参
- $this->cityId = $cityId;
- $this->goodsList = $goodsList;
- // 整合运费模板
- $this->initDeliveryTemplate();
- }
- /**
- * 验证用户收货地址是否在配送范围
- * @return bool
- */
- public function isIntraRegion(): bool
- {
- if (!$this->cityId) {
- return false;
- }
- foreach ($this->data as $item) {
- $cityIds = [];
- foreach ($item['delivery']['rule'] as $ruleItem) {
- $cityIds = array_merge($cityIds, $ruleItem['region']);
- }
- if (!in_array($this->cityId, $cityIds)) {
- $this->notInRuleGoodsId = current($item['goodsList'])['goods_id'];
- return false;
- }
- }
- return true;
- }
- /**
- * 获取不在配送范围的商品名称
- * @return null
- */
- public function getNotInRuleGoodsName()
- {
- $item = helper::getArrayItemByColumn($this->goodsList, 'goods_id', $this->notInRuleGoodsId);
- return !empty($item) ? $item['goods_name'] : null;
- }
- /**
- * 获取订单的配送费用
- * @return string
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getDeliveryFee(): string
- {
- if (empty($this->cityId) || empty($this->goodsList) || $this->notInRuleGoodsId > 0) {
- return helper::number2(0.00);
- }
- // 处理商品包邮
- $this->freeshipping();
- // 计算配送金额
- foreach ($this->data as &$item) {
- // 计算当前配送模板的运费
- $item['delivery_fee'] = $this->calcDeliveryAmount($item);
- }
- // 根据运费组合策略获取最终运费金额
- return helper::number2($this->getFinalFreight());
- }
- /**
- * 根据运费组合策略 计算最终运费
- * @return float|int|mixed
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- private function getFinalFreight()
- {
- // 运费合集
- $expressPriceArr = helper::getArrayColumn($this->data, 'delivery_fee');
- if (empty($expressPriceArr)) {
- return 0.00;
- }
- // 最终运费金额
- $expressPrice = 0.00;
- // 判断运费组合策略
- switch (SettingModel::getItem('trade')['freight_rule']) {
- case '10': // 策略1: 叠加
- $expressPrice = array_sum($expressPriceArr);
- break;
- case '20': // 策略2: 以最低运费结算
- $expressPrice = min($expressPriceArr);
- break;
- case '30': // 策略3: 以最高运费结算
- $expressPrice = max($expressPriceArr);
- break;
- }
- return $expressPrice;
- }
- /**
- * 商品满额包邮
- * @return void
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- private function freeshipping(): void
- {
- // 订单商品总金额
- $orderTotalPrice = helper::getArrayColumnSum($this->goodsList, 'total_price');
- // 获取满额包邮设置
- $options = SettingModel::getItem(SettingEnum::FULL_FREE);
- foreach ($this->data as &$item) {
- $item['free_goods_list'] = [];
- foreach ($item['goodsList'] as $goodsItem) {
- if (
- $options['is_open']
- && $orderTotalPrice >= $options['money']
- && !in_array($goodsItem['goods_id'], $options['excludedGoodsIds'])
- && !in_array($this->cityId, $options['excludedRegions']['cityIds'])
- ) {
- $item['free_goods_list'][] = $goodsItem['goods_id'];
- }
- }
- }
- }
- /**
- * 计算当前配送模板的运费
- * @param $item
- * @return float|mixed|string
- */
- private function calcDeliveryAmount($item)
- {
- // 获取运费模板下商品总数量or总重量
- if (!$totality = $this->getItemGoodsTotal($item)) {
- return 0.00;
- }
- // 当前收货城市配送规则
- $deliveryRule = $this->getCityDeliveryRule($item['delivery']);
- if ($totality <= $deliveryRule['first']) {
- return $deliveryRule['first_fee'];
- }
- // 续件or续重 数量
- $additional = $totality - $deliveryRule['first'];
- if ($additional <= $deliveryRule['additional']) {
- return helper::bcadd($deliveryRule['first_fee'], $deliveryRule['additional_fee']);
- }
- // 计算续重/件金额
- if ($deliveryRule['additional'] < 1) {
- // 配送规则中续件为0
- $additionalFee = 0.00;
- } else {
- $additionalFee = helper::bcdiv($deliveryRule['additional_fee'], $deliveryRule['additional']) * $additional;
- }
- return helper::bcadd($deliveryRule['first_fee'], $additionalFee);
- }
- /**
- * 获取运费模板下商品总数量or总重量
- * @param $item
- * @return int|string
- */
- private function getItemGoodsTotal($item)
- {
- $totalWeight = 0; // 总重量
- $totalNum = 0; // 总数量
- foreach ($item['goodsList'] as $goodsItem) {
- // 如果商品为包邮,则不计算总量中
- if (!in_array($goodsItem['goods_id'], $item['free_goods_list'])) {
- $goodsWeight = helper::bcmul($goodsItem['skuInfo']['goods_weight'], $goodsItem['total_num']);
- $totalWeight = helper::bcadd($totalWeight, $goodsWeight);
- $totalNum = helper::bcadd($totalNum, $goodsItem['total_num']);
- }
- }
- return $item['delivery']['method'] == 10 ? $totalNum : $totalWeight;
- }
- /**
- * 根据城市id获取规则信息
- * @param
- * @return array|false
- */
- private function getCityDeliveryRule($delivery)
- {
- foreach ($delivery['rule'] as $item) {
- if (in_array($this->cityId, $item['region'])) {
- return $item;
- }
- }
- return false;
- }
- /**
- * 整合运费模板
- * @return void
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- private function initDeliveryTemplate(): void
- {
- // 运费模板ID集
- $deliveryIds = $this->getDeliveryIds();
- if (empty($deliveryIds)) {
- return;
- }
- // 运费模板列表
- $deliveryList = (new DeliveryModel)->getListByIds($deliveryIds);
- // 整理数据集
- foreach ($deliveryList as $item) {
- $this->data[$item['delivery_id']]['delivery'] = $item;
- $this->data[$item['delivery_id']]['goodsList'] = $this->getGoodsListByDeliveryId($item['delivery_id']);
- }
- }
- /**
- * 运费模板ID集
- * @return array
- */
- private function getDeliveryIds(): array
- {
- $deliveryIds = helper::getArrayColumn($this->goodsList, 'delivery_id');
- return array_values(array_unique(array_filter($deliveryIds)));
- }
- /**
- * 根据运费模板id整理商品集
- * @param $deliveryId
- * @return array
- */
- private function getGoodsListByDeliveryId($deliveryId): array
- {
- $data = [];
- foreach ($this->goodsList as $item) {
- $item['delivery_id'] == $deliveryId && $data[] = $item;
- }
- return $data;
- }
- }
|