// +---------------------------------------------------------------------- declare (strict_types=1); namespace app\services\user; use app\model\user\UserBrokerage; use qiniu\basic\BaseServices; use think\exception\ValidateException; use qiniu\services\CacheService; /** * 用户佣金 * Class UserBrokerageServices * @package app\services\user * @mixin UserBrokerage */ class UserBrokerageServices extends BaseServices { /** * 用户记录模板 * @var array[] */ protected $incomeData = [ 'system_add_brokerage' => [ 'title' => '系统添加佣金', 'type' => 'system_add', 'mark' => '系统添加{%number%}佣金{%mark%}', 'status' => 1, 'pm' => 1 ], 'system_sub_brokerage' => [ 'title' => '系统减少佣金', 'type' => 'system_sub', 'mark' => '系统扣除{%number%}佣金{%mark%}', 'status' => 1, 'pm' => 0 ], 'trade_in' => [ 'title' => '佣金转入', 'type' => 'trade_in', 'mark' => '{%mark%}{%number%}元', 'status' => 1, 'pm' => 1 ], 'trade_out' => [ 'title' => '佣金转出', 'type' => 'trade_out', 'mark' => '{%mark%}{%number%}元', 'status' => 1, 'pm' => 0 ], ]; /** * UserBrokerageServices constructor. * @param UserBrokerage $model */ public function __construct(UserBrokerage $model) { $this->model = $model; } /** * 计算佣金 * @param array $where * @param int $time * @return mixed */ public function getUsersBrokerageSum(array $where, $time = 0) { $where_data = [ 'status' => 1, 'pm' => $where['pm'] ?? '', 'uid' => $where['uid'] ?? '', 'time' => $where['time'] ?? 0, 'type' => $where['type'] ?? '', 'not_type' => $where['not_type'] ?? '' ]; if ($time) $where_data['time'] = $time; return $this->getBrokerageSumColumn($where_data); } /** * 获取某些条件的bill总数 * @param array $where * @return mixed */ public function getBrokerageSumColumn(array $where) { if (isset($where['uid']) && is_array($where['uid'])) { return $this->search($where)->group('uid')->column('sum(number) as num', 'uid'); } else return $this->search($where)->sum('number'); } /** * 某个用户佣金总和 * @param int $uid * @param string $time * @param int $pm * @return float */ public function getUserBillBrokerageSum(int $uid, string $time = '', int $pm = 1) { $where = ['uid' => $uid]; $where['pm'] = $pm; $where['status'] = 1; if ($time) $where['time'] = $time; return $this->getBrokerageSum($where); } /** * 获取某个条件总数 * @param array $where * @return float */ public function getBrokerageSum(array $where) { return $this->search($where)->sum('number'); } /** * 写入用户记录 * @param string $type 写入类型 * @param int $uid * @param int|string|array $number * @param int|string $link_id * @return bool|mixed * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function income(string $type, int $uid, $number, $link_id = 0) { $data = $this->incomeData[$type] ?? null; if (!$data) { return true; } $data['uid'] = $uid; $data['link_id'] = $link_id; if (is_array($number)) { $key = array_keys($number); $key = array_map(function ($item) { return '{%' . $item . '%}'; }, $key); $value = array_values($number); $data['number'] = $number['number'] ?? 0; $data['frozen_time'] = $number['frozen_time'] ?? 0; $data['mark'] = str_replace($key, $value, $data['mark']); } else { $data['number'] = $number; $data['mark'] = str_replace(['{%number%}'], $number, $data['mark']); } /** @var UserServices $userService */ $userService = app()->make(UserServices::class); if ((float)$data['number'] > 0) { if ($data['status'] == 1) { $user = $userService->getUserInfo($uid); if ($data['pm'] == 1) { $data['balance'] = bcadd($user['brokerage_price'], $data['number'], 2); $userService->bcInc($uid, 'brokerage_price', $data['number'], 'uid'); } else { if ($data['number'] > $user['brokerage_price']) { throw new ValidateException('用户佣金不足'); } $data['balance'] = bcsub($user['brokerage_price'], $data['number'], 2); $userService->bcDec($uid, 'brokerage_price', $data['number'], 'uid'); } } return $this->save($data); } return true; } /** * 资金类型 */ public function bill_type() { $getBrokerageType = function () { $array = $this->incomeData; $list = []; foreach ($array as $v) { $list[] = ['type' => $v['type'], 'title' => $v['title'], 'pm' => $v['pm']]; } return compact('list'); }; return CacheService::get('user_brokerage_type_list', $getBrokerageType, 600); } /** * 获取资金列表 * @param array $where * @param string $field * @param int $limit * @return array * @throws \think\db\exception\DbException */ public function getBrokerageList(array $where, string $field = '*', int $limit = 0) { $where_data = []; if (isset($where['uid']) && $where['uid'] != '') { $where_data['uid'] = $where['uid']; } if ($where['start_time'] != '' && $where['end_time'] != '') { $where_data['time'] = str_replace('-', '/', $where['start_time']) . ' - ' . str_replace('-', '/', $where['end_time']); } if (isset($where['type']) && $where['type'] != '') { $where_data['type'] = $where['type']; } if (isset($where['nickname']) && $where['nickname'] != '') { $where_data['like'] = $where['nickname']; } if (isset($where['pm']) && $where['pm'] != '') { $where_data['pm'] = $where['pm']; } if ($limit) { [$page] = $this->getPageValue(); } else { [$page, $limit] = $this->getPageValue(); } $data = $this->getList($where_data, $field, $page, $limit, [ 'user' => function ($query) { $query->field('uid,nickname'); } ]); foreach ($data as &$item) { $item['nickname'] = $item['user']['nickname'] ?? ''; $item['_add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', $item['add_time']) : ''; unset($item['user']); } $count = $this->getCount($where_data); return compact('data', 'count'); } /** * 用户佣金详情 * @param int $uid * @return array */ public function user_info(int $uid) { /** @var UserServices $user */ $user = app()->make(UserServices::class); $user_info = $user->getUserWithTrashedInfo($uid, 'nickname,spread_uid,now_money,brokerage_price,add_time'); if (!$user_info) { throw new ValidateException('您查看的用户信息不存在!'); } $user_info = $user_info->toArray(); $income = $this->getUserBillBrokerageSum($uid); $expend = $this->getUserBillBrokerageSum($uid, '', 0); $number = (float)bcsub((string)$income, (string)$expend, 2); $user_info['number'] = max($number, 0); $user_info['add_time'] = date('Y-m-d H:i:s', $user_info['add_time']); $user_info['spread_name'] = $user_info['spread_uid'] ? $user->getUserInfo((int)$user_info['spread_uid'], 'nickname')['nickname'] ?? '' : ''; return compact('user_info'); } /** * 获取某个账户下的冻结佣金 * @param int $uid * @return float */ public function getUserFrozenPrice(int $uid) { return $this->search(['uid' => $uid, 'status' => 1, 'pm' => 1])->where('frozen_time', '>', time())->sum('number'); } public function trade(int $uid, int $to_uid, $num) { /** @var UserServices $userService */ $userService = app()->make(UserServices::class); $user = $userService->getUserInfo($uid); $to_user = $userService->getUserInfo($to_uid); if (!$user || !$to_user) { throw new ValidateException('数据不存在'); } if ($to_uid == $uid) throw new ValidateException('不能自己转给自己'); $broken_commission = $this->getUserFrozenPrice($uid); if ($broken_commission < 0) $broken_commission = 0; $brokerage_price = $user['brokerage_price']; //可提现佣金 $commissionCount = (float)bcsub((string)$brokerage_price, (string)$broken_commission, 2); if ($num > $commissionCount) { throw new ValidateException('可用佣金不足'); } $extractPrice = $user['brokerage_price']; if ($extractPrice < 0) { throw new ValidateException('转账佣金不足' . $num); } if ($num > $extractPrice) { throw new ValidateException('转账佣金不足' . $num); } if ($num <= 0) { throw new ValidateException('转账佣金大于0'); } return $this->transaction(function () use ($num, $user, $to_user, $userService) { //保存佣金记录 $this->income('trade_out', $user['uid'], ['mark' => '转账给' . $to_user['nickname'] . '(' . $to_user['uid'] . ')', 'number' => $num], $to_user['uid']); $this->income('trade_in', $to_user['uid'], ['mark' => '转账自' . $user['nickname'] . '(' . $user['uid'] . ')', 'number' => $num], $user['uid']); return true; }); } }