quanwei
7 days ago 30563323a53b0d0260c97d08a9e8bd4cc8227a95
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
<?php
 
namespace app\shop\model\plus\shareholder;
 
use app\common\model\plus\shareholder\Bonus as BonusModel;
use app\common\model\plus\shareholder\User as UserModel;
use app\shop\model\plus\shareholder\Order;
use app\shop\model\order\Order as OrderModel;
use app\shop\model\plus\team\Order as TeamOrderModel;
 
/**
 * 分红结算模型
 */
class Bonus extends BonusModel
{
    /**
     * 获取列表
     */
    public function getList($year = '', $month = '', $week = '')
    {
        $model = $this;
        // 检索查询条件
        if ($year) {
            
        }
        return $model->order(['create_time' => 'desc'])
            ->paginate(15);
    }
 
    /**
     * 获取可分红结算数据
     */
    public function getBonus()
    {
        $setting = Setting::getItem('basic');
        if(!$setting['is_open']) {
            $this->error = '未开启股东分红';
            return false;
        }
        //是否有可分红订单,1有,0无
        $is_bonus = 1;
        $first_data = Order::orderFirst();
        if (empty($first_data)||!isset($first_data)) {
            $is_bonus = 0;
            $first_data['create_time']=date('Y-m-d');
        }
        //可结算时间需要加上分红结算天数
        $create_time = strtotime($first_data['create_time']) + intval(Setting::getItem('settlement')['settle_days']) * 86400;
        $year = date('Y', $create_time) ?? '';
        $mouth = date('m', $create_time) ?? '';
        $day = date('d', $create_time) ?? '';
        $week = '';
 
        $first_day = '';
        $last_day = '';
        if ($setting['bonus_type'] == 10) { //按周
            if ($day >= 1 && $day <= 7) {
                $week = '第一周';
                $first_day = $year . '-' . $mouth . '-01 00:00:00';
                $last_day = $year . '-' . $mouth . '-07 23:59:59';
            } else if ($day >= 8 && $day <= 14) {
                $week = '第二周';
                $first_day = $year . '-' . $mouth . '-08 00:00:00';
                $last_day = $year . '-' . $mouth . '-14 23:59:59';
            } else if ($day >= 15 && $day <= 21) {
                $week = '第三周';
                $first_day = $year . '-' . $mouth . '-15 00:00:00';
                $last_day = $year . '-' . $mouth . '-21 23:59:59';
            } else if ($day >= 22 && $day <= 31) {
                $week = '第四周';
                $first_day = $year . '-' . $mouth . '-22 00:00:00';
                $last_day = date('Y-m-t 23:59:59', $create_time);//月末日期时间
            }
        } elseif ($setting['bonus_type'] == 20) {
            $first_day = date('Y-m-01 00:00:00', $create_time);//月头日期时间
            $last_day = date('Y-m-t 23:59:59', $create_time);//月末日期时间
        } elseif($setting['bonus_type'] == 30) {
            $first_day = date('Y-01-01 00:00:00', $create_time);//年头日期时间
            $last_day = date('Y-12-t 23:59:59', $create_time);//年末日期时间
        } else {
            $this->error = '结算周期参数错误';
            return false;
        }
        if (strtotime($last_day) >= time()) {
            $is_bonus = 0;
        }
        $model = new Order;
        $model = $model->where('is_settled', '=', 0)
            ->where('create_time', '>=', strtotime($first_day))
            ->where('create_time', '<=', strtotime($last_day));
        $order_num = $model->count();
        $order_price = $model->sum('order_price');
        $orderData = [
            'is_bonus' => $is_bonus,
            'year' => $year . '年',
            'mouth' => $mouth . '月',
            'week' => $week,
            'start_time' => $first_day,
            'end_time' => $last_day,
            'first_day' => substr($first_day, 0, 10),
            'last_day' => substr($last_day, 0, 10),
            'order_num' => $order_num,
            'total_pay_price' => $order_price,
            'bonus_price' => bcmul($order_price, $setting['total_rate'] / 100, 2),
            'total_rate' => (string)$setting['total_rate'],
            'shareholder_num' => UserModel::shareholderCount(), //股东数量
        ];
        return $orderData;
    }
 
    /**
     * 新增结算
     */
    public function add($data)
    {
        $config = Setting::getItem('basic');
        // 获取结算数据
        $bonusData = (new self)->getBonus();
        if (!$bonusData) {
            return false;
        }
        if(empty($bonusData['total_rate'])) {
            $this->error = '分红比例为0,不分红';
            return false;
        }
        if(empty($bonusData['total_pay_price'])) {
            $this->error = '没有可用的分红';
            return false;
        }
        // 获取满足分红条件的股东数据
        $userList = User::getEligibleListAll($bonusData);
        if ($userList->isEmpty()) {
            $this->error = '没有找到满足分红条件的股东,不分红';
            return false;
        }
        $this->startTrans();
        try {
            $grade_arr = []; // 记录等级,分红比例,人数,对应用户ids
            foreach ($userList as $item) {
                // 第一个
                if (empty($grade_arr)) {
                    $grade_arr[] = [
                        'grade_id' => $item['grade']['grade_id'],
                        'name' => $item['grade']['name'],
                        'share_type' => $item['grade']['share_type'], // 分红方式 10固定比例 20团队月业绩占平台月业绩比例    
                        'bonus_rate' => $item['grade']['share_type'] == 10 ? $item['grade']['equity'] : 0, // 固定比例时的分红比例
                        'num' => 1,
                        'user' => [
                            [
                            'user_id' => $item['user_id'],
                            'referee_id' => $item['referee_id'],
                            'bonus_rate' => $item['grade']['share_type'] == 20 ? self::getBonusRate($item['user_id'], $bonusData['start_time'], $bonusData['end_time'], $item['grade']['share_type']) : 0
                            ]
                        ]
                    ];
                } else {
                    //第二个后每个对比是否存在同一个等级的记录
                    $is_have = false;
                    foreach ($grade_arr as &$value) {
                        if ($value['grade_id'] === $item['grade']['grade_id']) {
                            $push_data = ['user_id' => $item['user_id'], 'referee_id' => $item['referee_id']];
                            if ($item['grade']['share_type'] == 20) {
                                $push_data['bonus_rate'] = self::getBonusRate($item['user_id'], $bonusData['start_time'], $bonusData['end_time'], $item['grade']['share_type']);
                            }
                            array_push($value['user'], $push_data);
                            $value['num']++;
                            $is_have = true;//已存在
                        }
                    }
                    //不存在,则新增
                    if (!$is_have) {
                        $grade_arr[] = [
                            'grade_id' => $item['grade']['grade_id'],
                            'name' => $item['grade']['name'],
                            'share_type' => $item['grade']['share_type'], // 分红方式 10固定比例 20团队月业绩占平台月业绩比例    
                            'bonus_rate' => $item['grade']['share_type'] == 10 ? $item['grade']['equity'] : 0, // 固定比例时的分红比例
                            'num' => 1,
                            'user' => [
                                [
                                'user_id' => $item['user_id'],
                                'referee_id' => $item['referee_id'],
                                'bonus_rate' => $item['grade']['share_type'] == 20 ? self::getBonusRate($item['user_id'], $bonusData['start_time'], $bonusData['end_time'], $item['grade']['share_type']) : 0
                                ]
                            ]
                        ];
                    }
                }
            }
            // 计算每个股东分红
            bcscale(6);// 为了更精确
            $all_rate = 0;
            $bonus_price_total = bcmul($bonusData['total_pay_price'], $bonusData['total_rate'] / 100);
            // 此计算只适用于固定比例模式
            foreach ($grade_arr as &$a) {
                $num = count($a['user']) ?? 0;
                $all_rate = bcadd($all_rate, bcmul($a['bonus_rate'] / 100, $num)); //记录每个等级分红比例  10%*2+20%*5+30%*10
                $a['bonus_price'] = bcmul($bonus_price_total, $a['bonus_rate'] / 100); // 第一次记录  10%*100元
            }
            // 记录分红
            $data = [
                'bonus_type' => $config['bonus_type'],
                'bonus_price' => $bonus_price_total,
                'bonus_rate' => $config['total_rate'],
                'order_num' => $bonusData['order_num'],
                'shareholder_num' => count($userList),
                'start_time' => strtotime($bonusData['start_time']),
                'end_time' => strtotime($bonusData['end_time']),
                'app_id' => self::$app_id
            ];
            $bonusModel = new BonusModel;
            $bonusModel->save($data);
            $bonus_id = $bonusModel->bonus_id;
            // 记录每个股东分红
            foreach ($grade_arr as $c) {
                foreach ($c['user'] as $d) {
                    bcscale(2); // 四舍五入,防止最后分红大于总分红
                    if ($c['share_type'] == 10) {
                        $price = bcdiv($c['bonus_price'], $all_rate) ?? 0;
                    } else {
                        // 非固定模式时,直接乘比例
                        $price = bcmul($bonus_price_total, $d['bonus_rate'] / 100) ?? 0;
                    }
                    $log_data = [
                        'user_id' => $d['user_id'],
                        'grade_id' => $c['grade_id'],
                        'grade_name' => $c['name'],
                        'money' => $price,
                        'share_type' => $c['share_type'],
                        'bonus_rate' => $c['share_type'] == 10 ? $c['bonus_rate'] : $d['bonus_rate'],
                        'order_num' => $bonusData['order_num'],
                        'bonus_id' => $bonus_id,
                        'app_id' => self::$app_id
                    ];
                    BonusLog::create($log_data);
                    // 发放分红给股东
                    if ($price) {
                        UserModel::grantMoney($d['user_id'], $price, 10);
                        // 发放平级奖
                        if ($d['referee_id'] && $config['pjaward'] && $config['pjaward_level']) {
                            $this->addPj($d['referee_id'], $log_data, $price, $config['pjaward_level']);
                        }
                    }
                }
            }
            //分红后更新订单状态
            $orderModel = new Order;
            $orderModel->orderUpdate(
                [
                    'is_settled' => 1,
                    'bonus_id' => $bonus_id,
                    'settle_time' => time()
                ],
                [
                    'start_time' => $bonusData['start_time'],
                    'end_time' => $bonusData['end_time']
                ]
            );
            $this->commit();
            return true;
        } catch (\Exception $e) {
            $this->error = $e->getMessage();
            $this->rollback();
            return false;
        }
    }
 
    /**
     * 计算等级分红比例
     * @param $user_id
     * @param $start_time
     * @param $end_time
     * @param $share_type
     */
    private static function getBonusRate($user_id, $start_time, $end_time, $share_type)
    {
        // 按结算周期内团队业绩占平台业绩比例
        if ($share_type == 20) {
            // 获取当前周期平台总业绩
            $data = (new OrderModel())->getOrderData($start_time, $end_time, 'order_total_price');
            log_write('平台总业绩:'.$data);
            if (empty($data)) {
                return 0;
            }
            // 获取团队业绩
            $teamData = (new TeamOrderModel)->getOrderData($user_id, $start_time, $end_time, 'order_total_price');
            log_write('团队业绩:'.$teamData);
            return round($teamData / $data * 100, 2);
        }
        return 0;
    }
 
    /**
     * 平级奖
     * @param $grade_id 股东等级id
     * @param $referee_id
     * @param $price
     * @param $pjaward_level
     * @param $ids 已发放过的user_id集合
     */
    private function addPj($referee_id, $log_data, $bonus, $pjaward_level, $level = 1, $ids = [])
    {
        if ($referee_id) {
            $model = UserModel::detail($referee_id, ['grade']);
            if ($model && $model['grade_id'] == $log_data['grade_id'] && !in_array($referee_id, $ids) && $level <= $pjaward_level) {
                bcscale(2); // 四舍五入,防止最后分红大于总分红
                $price = bcmul($bonus, $model['grade']['pjaward_percent'] / 100) ?? 0;
                $log_data['user_id'] = $referee_id;
                $log_data['money'] = $price;
                $log_data['log_type'] = 30;
                $log_data['bonus_rate'] = $model['grade']['pjaward_percent'];
                BonusLog::create($log_data);
                // 发放分红给股东
                if ($price) {
                    UserModel::grantMoney($referee_id, $price, 30);
                }
                array_push($ids, $referee_id);
                $level++;
            }
            if ($model['referee_id'] && $level <= $pjaward_level) {
                return $this->addPj($model['referee_id'], $log_data, $bonus, $pjaward_level, $level, $ids);
            }
            return true;
        }
    }
 
}