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)) { $is_bonus = 0; } //可结算时间需要加上分红结算天数 $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'], 'region_num' => UserModel::regionCount(), //区域代理数量 ]; 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; } $this->startTrans(); try { // 获取订单数据 $order_data = (new Order)->alias('order') ->field('sum(order.order_price) as order_price,count(order.order_id) as order_num,order_address.province_id,order_address.city_id,order_address.region_id') ->join('order_address', 'order.order_id = order_address.order_id') ->where('is_settled', '=', 0) ->where('order.create_time', '>=', strtotime($bonusData['start_time'])) ->where('order.create_time', '<=', strtotime($bonusData['end_time'])) ->group('order_address.region_id,order_address.city_id,order_address.province_id') ->select() ->toArray(); //预记录分红 $pre_data = [ 'bonus_type' => $config['bonus_type'], 'pre_bonus_price' => 0, 'bonus_price' => 0, 'bonus_rate' => $config['total_rate'], 'pre_order_num' => 0, 'order_num' => 0, 'region_num' => 0, 'start_time' => strtotime($bonusData['start_time']), 'end_time' => strtotime($bonusData['end_time']), 'app_id' => self::$app_id ]; $bonusModel = new BonusModel; $bonusModel->save($pre_data); bcscale(6);//为了更精确 $user_num = 0;//参与分红人数 $pre_bonus_price = 0;//预计分红金额 $bonus_price = 0;//实际分红金额 $pre_order_num = 0;//预计分红订单数 $order_num = 0;//实际分红订单数 foreach ($order_data as &$item) { $pre_bonus_price += bcmul($item['order_price'], $bonusData['total_rate'] / 100); $pre_order_num += $item['order_num']; //分红数据处理 self::getBonusData($item); //计算各级代理分红 $user_num += $item['province_num'] + $item['city_num'] + $item['area_num']; $bonus_price += bcmul($item['order_price'], $bonusData['total_rate'] / 100); $order_num += $item['order_num']; //记录每个区域代理分红流水 $this->addBonusLog( $item['province_user'], $item, $item['province_price'], $item['province_rate'], $bonusModel->bonus_id ); $this->addBonusLog( $item['city_user'], $item, $item['city_price'], $item['city_rate'], $bonusModel->bonus_id ); $this->addBonusLog( $item['area_user'], $item, $item['area_price'], $item['area_rate'], $bonusModel->bonus_id ); } //完成用户记录后,更新分红信息 $final_data = [ 'pre_bonus_price' => bcmul($pre_bonus_price, 1, 2), // 取2位小数,不需要四舍五入 'bonus_price' => bcmul($bonus_price, 1, 2), 'pre_order_num' => $pre_order_num, 'order_num' => $order_num, 'region_num' => $user_num ]; $bonusModel->save($final_data); //分红后更新订单状态 $orderModel = new Order; $orderModel->orderUpdate( [ 'is_settled' => 1, 'bonus_id' => $bonusModel->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; } } /** * 分红数据处理 */ private static function getBonusData(&$data) { $config = Setting::getItem('bonus'); $config_basic = Setting::getItem('basic'); $data['province_rate'] = $config['province_ratio'] ?? 0; $data['city_rate'] = $config['city_ratio'] ?? 0; $data['area_rate'] = $config['area_ratio'] ?? 0; // 省代理 $data['province_user'] = User::getUser($data['province_id'], OperationsLevelEnum::PROVINCE); $data['province_num'] = count($data['province_user']) ?? 0; // 市代理 $data['city_user'] = User::getUser($data['city_id'], OperationsLevelEnum::CITY); $data['city_num'] = count($data['city_user']) ?? 0; // 区/县代理 $data['area_user'] = User::getUser($data['region_id'], OperationsLevelEnum::AREA); $data['area_num'] = count($data['area_user']) ?? 0; //总权重 bcscale(6); $weight = bcadd( bcadd( bcmul($data['province_rate'] / 100, $data['province_num']), bcmul($data['city_rate'] / 100, $data['city_num']) ), bcmul($data['area_rate'] / 100, $data['area_num']) ); //省 $data['province_bonus_rate'] = $weight == 0 ? 0 : bcdiv($data['province_rate'], $weight); $data['province_price'] = !empty($data['province_num']) && $weight != 0 ? bcmul( bcmul($data['order_price'], $config_basic['total_rate'] / 100), $data['province_bonus_rate'] / 100, 2 ) : 0; //市 $data['city_bonus_rate'] = $weight == 0 ? 0 : bcdiv($data['city_rate'], $weight); $data['city_price'] = !empty($data['city_num']) && $weight != 0 ? bcmul( bcmul($data['order_price'], $config_basic['total_rate'] / 100), $data['city_bonus_rate'] / 100, 2 ) : 0; //区 $data['area_bonus_rate'] = $weight == 0 ? 0 : bcdiv($data['area_rate'], $weight); $data['area_price'] = !empty($data['area_num']) && $weight != 0 ? bcmul( bcmul($data['order_price'], $config_basic['total_rate'] / 100), $data['area_bonus_rate'] / 100, 2 ) : 0; } /** * 记录每个代理分红情况 */ private function addBonusLog($users, $data, $price, $bonus_rate, $bonus_id) { foreach ($users as $item) { $log_data = [ 'user_id' => $item['user_id'], 'region_level' => $item['region_level']['value'], 'money' => $price, 'bonus_rate' => $bonus_rate, 'order_num' => $data['order_num'], 'bonus_id' => $bonus_id, 'province_id' => $data['province_id'], 'city_id' => $data['city_id'], 'area_id' => $data['region_id'], 'app_id' => self::$app_id ]; log_write($log_data); BonusLog::create($log_data); // 发放分红给股东 if ($price) { UserModel::grantMoney($item['user_id'], $price, 10); } } } /** * 计算等级分红比例 * @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 = bcdiv($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; } } }