<?php
|
|
namespace app\shop\model\plus\region;
|
|
use app\common\model\plus\region\Bonus as BonusModel;
|
use app\common\model\plus\region\User as UserModel;
|
use app\shop\model\plus\region\Order;
|
use app\shop\model\order\Order as OrderModel;
|
use app\shop\model\plus\team\Order as TeamOrderModel;
|
use app\common\enum\plus\region\RegionLevelEnum;
|
|
/**
|
* 分红结算模型
|
*/
|
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)) {
|
$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'], RegionLevelEnum::PROVINCE);
|
$data['province_num'] = count($data['province_user']) ?? 0;
|
// 市代理
|
$data['city_user'] = User::getUser($data['city_id'], RegionLevelEnum::CITY);
|
$data['city_num'] = count($data['city_user']) ?? 0;
|
// 区/县代理
|
$data['area_user'] = User::getUser($data['region_id'], RegionLevelEnum::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;
|
}
|
}
|
|
}
|