• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

miaoxing / logistics / 10654302660

01 Sep 2024 01:03PM UTC coverage: 35.354% (-1.2%) from 36.522%
10654302660

push

github

semantic-release-bot
chore(release): publish

See CHANGELOG.md for more details.

24 of 103 branches covered (23.3%)

210 of 594 relevant lines covered (35.35%)

2.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Service/ShippingTpl.php
1
<?php
2

3
namespace Miaoxing\Logistics\Service;
4

5
use Miaoxing\Cart\Service\Cart;
6

7
class ShippingTpl extends \Miaoxing\Plugin\BaseService
8
{
9
    public const CUSTOM_RULE = 0;
10

11
    /**
12
     * {@inheritdoc}
13
     */
14
    protected $table = 'shippingTpls';
15

16
    /**
17
     * {@inheritdoc}
18
     */
19
    protected $data = [
20
        'freeShipping' => 0,
21
        'logisticsIds' => [],
22
        'useLogisticsIds' => [
23
            1 => 0, // 默认快递启用自定义规则
24
        ],
25
    ];
26

27
    /**
28
     * 默认的配送服务
29
     *
30
     * @var array
31
     */
32
    protected $defaultService = [
33
        'id' => 1,
34
        'name' => '快递',
35
        'fee' => '0.00',
36
    ];
37

38
    /**
39
     * @var ShippingTplRule[]|ShippingTplRule
40
     */
41
    protected $rules;
42

43
    /**
44
     * 特殊城市与所属"市辖区"ID的对应关系
45
     *
46
     * @var array
47
     */
48
    protected $cityIds = [
49
        '北京市' => 110100,
50
        '天津市' => 120100,
51
        '上海市' => 310100,
52
        '重庆市' => 500100,
53
    ];
54

55
    /**
56
     * {@inheritdoc}
57
     */
58
    protected $providers = [
59
        'db' => 'app.db',
60
    ];
61

62
    /**
63
     * Record: 获取运费模板规则
64
     *
65
     * @return ShippingTplRule|ShippingTplRule[]
66
     */
67
    public function getRules()
68
    {
69
        $this->rules || $this->rules = wei()->shippingTplRule()->findAll(['shippingTplId' => $this['id']]);
×
70

71
        return $this->rules;
×
72
    }
73

74
    /**
75
     * Record: 设置运费模板规则
76
     *
77
     * @param ShippingTplRule $shippingTplRules
78
     * @return $this
79
     * @phpstan-ignore-next-line
80
     */
81
    public function setRules(ShippingTplRule $shippingTplRules)
82
    {
83
        $this->rules = $shippingTplRules;
×
84

85
        return $this;
×
86
    }
87

88
    /**
89
     * 转换为数组时,附加规则的值
90
     *
91
     * @param array $returnFields
92
     * @return array
93
     */
94
    public function toArray($returnFields = [])
95
    {
96
        /** @phpstan-ignore-next-line */
97
        $data = parent::toArray($returnFields);
×
98
        // @phpstan-ignore-next-line
99
        if (!$this->isColl) {
×
100
            $data['rules'] = $this->getRules()->toArray();
×
101
        }
102

103
        return $data;
×
104
    }
105

106
    /**
107
     * Repo: 根据购物车和地址,获取可用的配送服务
108
     *
109
     * <code>
110
     * $return = [
111
     *   [
112
     *      'id' => '1', // 物流编号
113
     *      'name' => '' // 物流服务名称
114
     *      'fee' => '10.00', // 运费
115
     *   ]
116
     * ];
117
     * </code>
118
     *
119
     * @param Cart|\Miaoxing\Cart\Service\Cart[] $carts
120
     * @param \Miaoxing\Address\Service\Address $address
121
     * @return array
122
     * @phpstan-ignore-next-line
123
     */
124
    public function getShippingServices(Cart $carts, ?\Miaoxing\Address\Service\Address $address = null)
125
    {
126
        $cityId = $address ? $address->getCityIdOrName() : null;
×
127

128
        // 1. 构造物流配置数据
129
        $cartNum = $carts->length();
×
130
        $logisticsConfigs = [];
×
131
        foreach ($carts as $cart) {
×
132
            $product = $cart->getProduct();
×
133

134
            // 对虚拟商品不加入计算
135
            if ($product['isVirtual']) {
×
136
                --$cartNum;
×
137
                continue;
×
138
            }
139

140
            $shippingTpl = $product->getShippingTpl();
×
141

142
            // 对包邮或未设置运费模板的商品不加入计算
143
            if ($shippingTpl['freeShipping'] || $shippingTpl->isNew) {
×
144
                --$cartNum;
×
145
                continue;
×
146
            }
147

148
            $rules = $product->getShippingTpl()->getRulesByCity($cityId);
×
149

150
            // 对没有设置运费规则的商品不加入计算
151
            if (0 == $rules->length()) {
×
152
                --$cartNum;
×
153
                continue;
×
154
            }
155

156
            foreach ($rules as $rule) {
×
157
                $logisticsConfigs[$rule['logisticsId']][] = [
×
158
                    'cart' => $cart,
×
159
                    'rule' => $rule,
×
160
                ];
×
161
            }
162
        }
163

164
        // 2. 对所有商品都支持的物流方式,计算物流费用
165
        $services = [];
×
166
        $logistics = wei()->logistics;
×
167
        foreach ($logisticsConfigs as $logisticsId => $configs) {
×
168
            if (count($configs) == $cartNum) {
×
169
                $services[$logisticsId] = [
×
170
                    'id' => $logisticsId,
×
171
                    'name' => $logistics->getName($logisticsId),
×
172
                    'fee' => $this->getFeeByLogisticsConfigs($configs),
×
173
                ];
×
174
            }
175
        }
176

177
        // 3. 设置默认运费,或者将默认快递移到底部
178
        if (!$services) {
×
179
            $services[1] = $this->defaultService;
×
180
        } else {
181
            $defaultService = $services[1];
×
182
            unset($services[1]);
×
183
            $services[1] = $defaultService;
×
184
        }
185

186
        return array_values($services);
×
187
    }
188

189
    /**
190
     * Repo: 根据物流配置计算运费
191
     *
192
     * @param array $configs 包括cart, rule两个键
193
     * @return int
194
     */
195
    protected function getFeeByLogisticsConfigs(array $configs)
196
    {
197
        // 1. 计算首费
198
        // http://service.taobao.com/support/knowledge-1118327.htm
199
        $bestRule = null;
×
200
        $startFee = 0;
×
201

202
        foreach ($configs as $config) {
×
203
            /** @var $rule ShippingTplRule */
204
            $rule = $config['rule'];
×
205

206
            //  按“取最大首费,最小增费”作为首费来计算
207
            if (
208
                $rule['startFee'] > $startFee
×
209
                || ($rule['startFee'] == $startFee && $rule['plusFee'] < $bestRule['plusFee'])
×
210
            ) {
211
                $startFee = $rule['startFee'];
×
212
                $bestRule = $rule;
×
213
            }
214
        }
215

216
        // 2. 计算剩下的费用
217
        $fee = $startFee;
×
218
        foreach ($configs as $config) {
×
219
            $quantity = $config['cart']['quantity'];
×
220
            // 如果运费模板规则用在首费,减去首费的一件商品,并且只用1次
221
            if ($bestRule === $config['rule']) {
×
222
                $quantity = $config['cart']['quantity'] - 1;
×
223
                $bestRule = null;
×
224
            }
225
            $fee += $quantity * $config['rule']['plusFee'];
×
226
        }
227

228
        return sprintf('%.2f', $fee);
×
229
    }
230

231
    public function afterFind()
232
    {
233
        $this['logisticsIds'] = explode(',', $this['logisticsIds']);
×
234
        $this['useLogisticsIds'] = (array) json_decode($this['useLogisticsIds'], true);
×
235
    }
236

237
    public function beforeSave()
238
    {
239
        $this['logisticsIds'] = implode(',', (array) $this['logisticsIds']);
×
240
        // key是原来的物流服务商编号,value是要使用的物流商编号
241
        $this['useLogisticsIds'] = json_encode((array) $this['useLogisticsIds'], \JSON_FORCE_OBJECT);
×
242
    }
243

244
    public function afterSave()
245
    {
246
        $this['logisticsIds'] = explode(',', $this['logisticsIds']);
×
247
        $this['useLogisticsIds'] = (array) json_decode($this['useLogisticsIds'], true);
×
248
    }
249
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc