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; } } }