| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- <?php
- declare (strict_types = 1);
- namespace app\api\command;
- use app\api\controller\h5\User;
- use app\common\model\BoxHandleModel;
- use app\common\model\MoneyLogModel;
- use app\common\model\SubmeterModel;
- use app\common\model\UserModel;
- use app\common\service\LevelSettingService;
- use think\console\Command;
- use think\console\Input;
- use think\console\Output;
- use think\facade\Db;
- use utils\RedisCache;
- /**
- * 结算团队收益 by wes 每天晚上21点后运行1次
- * Class SettleTeamAward
- * @package app\api\command
- */
- class SettleTeamAward extends Command
- {
- protected $cacheTime = 86400; // 一天
- protected function configure()
- {
- $this->setName('settle_team_award')
- ->setDescription('the settle_team_award command');
- }
- /**
- * 处理分表
- * @param Input $input
- * @param Output $output
- * @return int
- */
- protected function execute(Input $input, Output $output)
- {
- $cacheKey = "caches:settleTeamAward:".date('Ymd').":";
- if(RedisCache::get($cacheKey.'lock')){
- echo json_encode(['code'=>'error','msg'=>'请不要频繁提交,正在结算中稍后再试~','date'=>date('Y-m-d H:i:s')],256)."\n";
- return false;
- }
- if(date('H:i') < '21:00'){
- echo json_encode(['code'=>'error','msg'=>'未到结算时间,结算时间为每日21:00后~','date'=>date('Y-m-d H:i:s')],256)."\n";
- return false;
- }
- RedisCache::setnx($cacheKey.'lock', date('Y-m-d H:i:s'), rand(30, 60));
- Db::startTrans();
- try {
- if($result = $this->settleTeamAward()){
- echo json_encode($result, 256)."\n";
- Db::commit();
- }
- } catch (\Exception $e) {
- Db::rollback();
- $log = ['msg'=> $e->getMessage(),'trace'=>$e->getTrace(),'date'=>date('Y-m-d H:i:s')];
- RedisCache::set($cacheKey."fail", $log, 5 * 3600);
- RedisCache::clear($cacheKey.'lock');
- echo json_encode(['code'=>'error','msg'=>$e->getMessage(),'date'=>date('Y-m-d H:i:s')], 256)."\n";
- }
- return true;
- }
- /**
- * 团队奖金结算
- * @return array
- * @throws \think\Exception
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function settleTeamAward()
- {
- // 获取开出的福袋盒子
- $boxList = BoxHandleModel::alias('a')
- ->leftJoin('user u','u.id=a.uid')
- ->where('a.is_team_handle', '0')
- ->where('a.open_time', '<=', date('Y-m-d H:i:s'))
- ->field('a.id,a.uid,a.rid,u.pid,u.level,u.path,u.has_fd,u.money')
- ->order('a.id desc')
- ->select();
- $boxList = $boxList? $boxList->toArray() : [];
- if(empty($boxList)){
- sr_throw('暂无团队奖金可结算');
- }
- // 获取等级配置
- $levelConfig = LevelSettingService::make()->getConfigData(0,1);
- if(empty($levelConfig)){
- sr_throw('请先配置等级参数');
- }
- $date = date('Y-m-d H:i:s');
- $catchIds = $moneyLogs = []; // 处理的数据
- $awardCounts = [];
- $cacheKey = "caches:settleTeamAward:".date('Ymd').":";
- foreach ($boxList as $k => $val){
- $boxId = isset($val['id'])? $val['id'] : 0;
- $uid = isset($val['uid'])? $val['uid'] : 0;
- $pid = isset($val['pid'])? $val['pid'] : 0;
- $path = isset($val['path'])? $val['path'] : '';
- if($pid<=0 || empty($path)){
- $catchIds[] = $boxId;
- continue;
- }
- /* TODO 验证上级是否存在,并且计算直推奖金*/
- $pInfo = UserModel::where(['id'=> $pid])
- ->field('id,money,level,pid,path,has_fd,total_appoint_count,store_expire_time')
- ->find();
- $pHasFd = isset($pInfo['has_fd'])? intval($pInfo['has_fd']) : 0;
- $pLevel = isset($pInfo['level'])? intval($pInfo['level']) : 0;
- $appointCount = isset($pInfo['total_appoint_count'])? intval($pInfo['total_appoint_count']) : 0;
- $storeExpireTime = isset($pInfo['store_expire_time']) && $pInfo['store_expire_time']? strtotime($pInfo['store_expire_time']) : 0;
- if($pInfo && $pHasFd){
- // 计算上级V0以上,当前等级的直推奖金:v1-1元,v2-2元,v3-3元,v4-1元(没分完得)
- $ztAward = isset($levelConfig[$pLevel]['zt_money'])? floatval($levelConfig[$pLevel]['zt_money']) : 0;
- if($pLevel>0 && $ztAward>0){
- $pMoney = isset($pInfo['money'])? $pInfo['money'] : 0;
- // 今日直推奖金
- $todayZtMoney = ($appointCount>=0 && $storeExpireTime>=time())? $ztAward : 0;
- // 直推奖流水
- $log = [
- 'uid'=> $pid,
- 'type'=> 5,
- 'money'=> $ztAward,
- 'create_at'=> sr_getcurtime(time()),
- 'state'=> 1,
- 'before_money'=> $pMoney,
- 'after_money'=> floatval($pMoney + $ztAward),
- 'from_id'=> $boxId,
- 'uid2'=> $uid,
- 'free_type'=> 0,
- 'remark'=> "V{$pLevel}直推1个福袋奖金".($todayZtMoney>0? ",有今日奖金{$todayZtMoney}":'')
- ];
- $moneyLogs[] = $log;
- if(!UserModel::where('id', $pid)->inc('money', $ztAward)->inc('today_money', $todayZtMoney)->update()){
- $logData = ['ztAward'=>$ztAward,'data'=> $val,'pInfo'=> $pInfo,'log'=>$log,'msg'=>"直推用户[{$pid}]结算直推奖错误",'date'=> $date];
- RedisCache::set($cacheKey."box_{$uid}_{$boxId}:{$pid}_{$pLevel}_error", $logData, 3*3600);
- sr_throw("直推用户[{$pid}]结算直推奖错误");
- }
- // 累计当前用户获得的奖金
- $awardCounts[$pid] = isset($awardCounts[$pid])? round($awardCounts[$pid]+$ztAward, 2) : $ztAward;
- }
- }
- /* TODO 计算团队奖金 */
- $maxLevel = 0;
- $awardTotal = 0;
- $teamMoneys = [];
- $teamAwardEnd = $sameLevelAwardEnd = 0; // 是否给完奖金
- $pIds = explode(',', $path);
- $pIds = array_reverse($pIds);
- $ids = implode(',', $pIds);
- $order = 'field(id,' . $ids . ')';
- $teamList = UserModel::whereIn('id', $pIds)
- ->field('id,money,level,has_fd,total_appoint_count,store_expire_time')
- ->order(Db::raw($order))
- ->select();
- $teamList = $teamList? $teamList->toArray() : [];
- if(!empty($teamList)){
- foreach($teamList as $key => $item){
- // 计算团队奖金
- $tId = isset($item['id'])? $item['id'] : 0;
- $tLevel = isset($item['level'])? $item['level'] : 0;
- $tLastId = isset($teamList[$key-1]['id'])? intval($teamList[$key-1]['id']) : 0;
- $tLastLevel = isset($teamList[$key-1]['level'])? intval($teamList[$key-1]['level']) : 0; // 前一个人的等级
- $tMoney = isset($item['money'])? $item['money'] : 0;
- $tHasFd = isset($item['has_fd'])? $item['has_fd'] : 0;
- $tAppointCount = isset($item['total_appoint_count'])? intval($item['total_appoint_count']) : 0;
- $tStoreExpireTime = isset($item['store_expire_time']) && !empty($item['store_expire_time'])? strtotime($item['store_expire_time']) : 0;
- $levelData = isset($levelConfig[$tLevel])? $levelConfig[$tLevel] : [];
- if($key == 0){
- // 等级大于V0
- if($tLevel > 0){
- $teamAward = isset($levelData['dynamic_scale'])? round($levelData['dynamic_scale'], 2) : 0;
- if($teamAward>0){
- $teamMoneys[$tId] = $teamAward;
- $awardTotal += $teamAward;
- $maxLevel = $tLevel;
- // V4以及以上等级直接分完后结束,不再往下分
- if($tLevel >= 4){
- $teamAwardEnd = true;
- }
- }
- }
- }
- // 如果未分完,且等级比上一级和当前分到到用户等级都高,则再分剩余奖金
- else if(!$teamAwardEnd && $tLevel > $tLastLevel && $tLevel > $maxLevel){
- $teamAward = isset($levelData['dynamic_scale'])? floatval($levelData['dynamic_scale']) : 0;
- $teamAward = max(0, $teamAward - $awardTotal);
- if($teamAward>0){
- $teamMoneys[$tId] = $teamAward;
- $awardTotal += $teamAward;
- }
- }
- /* TODO 计算平级奖金:未分完(金额小于0.1)情况下一直分 */
- $sameTeamAward = 0;
- if($key>0 && !$sameLevelAwardEnd){
- if($tLevel == $tLastLevel){
- $sameAward = isset($teamMoneys[$tLastId])? floatval($teamMoneys[$tLastId]) : 0;
- $sameTeamAward = round($sameAward * 0.1, 2);
- $sameTeamAward = $sameTeamAward>=0.1? $sameTeamAward : 0;
- if($sameTeamAward>0){
- $teamMoneys[$tId] = $sameTeamAward;
- }
- }
- }
- /* TODO 当前用户最终是否有团队奖金,有且预约过福袋则入账 */
- $endTeamAward = isset($teamMoneys[$tId])? floatval($teamMoneys[$tId]) : 0;
- if($endTeamAward>0 && $tAppointCount>0){
- // 今日团队奖金
- $tTodayAward = ($appointCount>=10 && $tStoreExpireTime >= time())? $endTeamAward : 0;
- // 流水
- $log = [
- 'uid'=> $tId,
- 'type'=> 7,
- 'money'=> $endTeamAward,
- 'create_at'=> sr_getcurtime(time()),
- 'state'=> 1,
- 'before_money'=> $tMoney,
- 'after_money'=> floatval($tMoney + $endTeamAward),
- 'from_id'=> $boxId,
- 'uid2'=> $sameTeamAward? $tLastId : $uid,
- 'free_type'=> $sameTeamAward? 0 : 1,
- 'remark'=> ($sameTeamAward? "V{$tLevel}得[ID:{$tLastId}]1个福袋平级奖":"V{$tLevel}得[ID:{$uid}]1个福袋团队奖").($tTodayAward>0? ",有今日奖金{$tTodayAward}":'')
- ];
- $moneyLogs[] = $log;
- if(!UserModel::where('id', $tId)->inc('money', $endTeamAward)->inc('today_money', $tTodayAward)->update()){
- $logData = ['endAward'=>$endTeamAward,'todayAward'=>$tTodayAward,'data'=> $val,'tInfo'=> $item,'log'=>$log,'msg'=>"用户[{$tId}]结算团队奖错误",'date'=> $date];
- RedisCache::set($cacheKey."box_{$uid}_{$boxId}:{$pid}_{$pLevel}_error", $logData, 3*3600);
- sr_throw("用户[{$tId}]结算团队奖错误");
- }
- $awardCounts[$tId] = isset($awardCounts[$tId])? round($awardCounts[$tId]+$endTeamAward, 2) : $endTeamAward;
- }
- }
- }
- $catchIds[] = $boxId;
- $logData = ['teamAwards'=>$teamMoneys,'data'=> $val,'teamAward'=> $awardTotal,'msg'=>"盒子[{$boxId}]团队奖金处理完成",'date'=> $date];
- RedisCache::set($cacheKey."box_{$uid}_{$boxId}:catch", $logData, 3*3600);
- }
- if(empty($catchIds)){
- sr_throw('结算失败,没有结算成功数据');
- }
- // 更新处理记录状态
- if(!BoxHandleModel::whereIn('id', $catchIds)->save(['is_team_handle' => 1,'update_time'=> $date])){
- sr_throw('更新处理数据状态失败');
- }
- // 写入奖金流水
- if($moneyLogs && !MoneyLogModel::insertAll($moneyLogs)){
- sr_throw('处理奖金流水错误');
- }
- $logData = ['count'=> count($catchIds),'data'=> $val,'awards'=> $awardCounts,'msg'=>"团队奖金结算成功",'date'=> $date];
- RedisCache::set($cacheKey."result", $logData, 3*3600);
- return ['code'=>200, 'msg'=> "团队奖金结算成功,累计结算记录".count($catchIds).",结算人数".count($awardCounts)."人,总奖金".array_sum($awardCounts),'date'=> $date];
- }
- }
|