quanwei
2025-12-09 ca425b889f3c1b5847ffc26a0229307f7f8ef43e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
<?php
 
namespace app\common\service\delivery;
 
use app\common\library\helper;
use app\common\model\settings\Setting as SettingModel;
use app\common\enum\order\OrderTypeEnum;
 
/**
 * 快递配送服务类
 */
class ExpressService
{
    private $appId;   // 商城id
    private $cityId;    // 用户收货城市id
    private $productList;  // 订单商品列表
    private $orderType;  // 订单类型 (主商城、拼团)
 
    /**
     * 配送服务类构造方法
     */
    public function __construct(
        $appId,
        $cityId,
        $productList,
        $orderType = OrderTypeEnum::MASTER
    )
    {
        $this->appId = $appId;
        $this->cityId = $cityId;
        $this->productList = $productList;
        $this->orderType = $orderType;
    }
 
    /**
     * 根据用户收货城市id 验证是否在商品配送规则中
     */
    public function getNotInRuleProduct()
    {
        if ($this->cityId) {
            foreach ($this->productList as &$product) {
                if($product['is_virtual'] == 1||$product['is_virtual'] == 3){
                    continue;
                }
                if($product['delivery_id'] == 0){
                    continue;
                }
                $cityIds = [];
                foreach ($product['delivery']['rule'] as $item)
                    $cityIds = array_merge($cityIds, $item['region_data']);
                if (!in_array($this->cityId, $cityIds))
                    return $product;
            }
 
        }
        return false;
    }
 
    /**
     * 设置订单商品的运费
     */
    public function setExpressPrice()
    {
        // 订单商品总金额
        $orderTotalPrice = helper::getArrayColumnSum($this->productList, 'total_price');
        foreach ($this->productList as &$product) {
            // 如果是虚拟物品,则为0
            if($product['is_virtual'] == 1 || $product['is_virtual'] == 3){
                $product['express_price'] = 0;
            }else if($product['delivery_id'] == 0){
                // 包邮
                $product['express_price'] = 0;
            }else {
                $product['express_price'] = $this->onCalcProductfreight($product, $orderTotalPrice);
            }
        }
        return true;
    }
 
    /**
     * 获取订单最终运费
     */
    public function getTotalFreight()
    {
        if (empty($this->productList)) {
            return 0.00;
        }
        // 所有商品的运费金额
        $expressPriceArr = helper::getArrayColumn($this->productList, 'express_price');
        if (empty($expressPriceArr)) {
            return 0.00;
        }
        // 计算最终运费
        return $this->freightRule($expressPriceArr);
    }
 
    /**
     * 计算商品的配送费用
     */
    private function onCalcProductfreight(&$product, $orderTotalPrice)
    {
        // 判断是否满足满额包邮条件
        if ($this->isFullFree($product['product_id'], $orderTotalPrice, $product['shop_supplier_id'])) {
            return 0.00;
        }
        // 当前收货城市配送规则
        $rule = $this->getCityDeliveryRule($product);
        // 商品总重量
        $totalWeight = helper::bcmul($product['product_sku']['product_weight'], $product['total_num']);
        // 商品总数量or总重量
        $total = $product['delivery']['method']['value'] == 10 ? $product['total_num'] : $totalWeight;
        if ($total <= $rule['first']) {
            return helper::number2($rule['first_fee']);
        }
        // 续件or续重 数量
        $additional = $total - $rule['first'];
        if ($additional <= $rule['additional']) {
            return helper::number2(helper::bcadd($rule['first_fee'], $rule['additional_fee']));
        }
        // 计算续重/件金额
        if ($rule['additional'] < 1) {
            // 配送规则中续件为0
            $additionalFee = 0.00;
        } else {
            $additionalFee = helper::bcdiv($rule['additional_fee'], $rule['additional']) * $additional;
        }
        return helper::number2(helper::bcadd($rule['first_fee'], $additionalFee));
    }
 
    /**
     * 判断是否满足满额包邮条件
     */
    private function isFullFree($productId, $orderTotalPrice, $shop_supplier_id)
    {
        // 非商城主订单不参与满额包邮
        if ($this->orderType !== OrderTypeEnum::MASTER) {
            return false;
        }
        // 获取满额包邮设置
        $options = SettingModel::getSupplierItem('full_free',$shop_supplier_id, $this->appId);
        if (
            $options['is_open'] == false
            || $orderTotalPrice < $options['money']
        ) {
            return false;
        }
        return true;
    }
 
    /**
     * 根据城市id获取规则信息
     */
    private function getCityDeliveryRule(&$product)
    {
        foreach ($product['delivery']['rule'] as $item) {
            if (in_array($this->cityId, $item['region_data'])) {
                return $item;
            }
        }
        return false;
    }
 
    /**
     * 根据运费组合策略 计算最终运费
     */
    private function freightRule($expressPriceArr)
    {
        $expressPrice = 0.00;
        switch (SettingModel::getItem('trade', $this->appId)['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;
    }
 
}