redis = Redis::instance(); } /** * 订单扣量 * @param integer $admin_id 后台用户ID * @param integer $channel_id 渠道ID * @param array $order_data 订单数据 * @param bool $is_activity 是否是活动订单 * @return array|bool|false|\PDOStatement|string|Model * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function orderKL($admin_id, $channel_id, $order_data, $is_activity = false) { if (UserService::instance()->getUserInfo()->is_black == UserConstants::USER_BLACK_NO) { $log_is_vip = $order_data['day'] ? '会员' : '普通'; $adminConfig = model('AdminConfig')->getAdminInfoAll($channel_id); //检查渠道是否开启扣量 if (!$adminConfig['is_blacklist']) { Log::info("KL逻辑-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:渠道未开启KL'); return false; } //检查代理商ID白名单 $kl_agent_blacklist = explode(',', Config::get('site.kl_agent_blacklist') ?? ''); if (in_array($admin_id, $kl_agent_blacklist)) { Log::info("KL逻辑-{$log_is_vip} 代理商: {$admin_id} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:代理商ID白名单'); return false; } //检查扣量基数 $kl_base = $this->getDeductionBase($adminConfig, $order_data['day'], false); if (!$kl_base || $kl_base < 0) { Log::info("KL逻辑-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:渠道未开启KL'); return false; } //获取计数器,未到扣量基数时累加,到扣量基数时暂停,直到扣量后继续累加 $kl_index = $this->getDeductionCounter($channel_id, $order_data['day'], false, false); if ($kl_index % $kl_base != 0) { Log::info("KL逻辑-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 基数:' . $kl_base . ' 单数:' . $kl_index . ' 取模:' . $kl_index % $kl_base); $this->getDeductionCounter($channel_id, $order_data['day'], false); } //检测是否到达扣量比例 if (!$this->checkIsDeductThreshold($channel_id, $adminConfig, $order_data['user_id'])) { return false; } //检查是否扣量白名单 if (!$this->checkIgnore($admin_id, $channel_id, $order_data, 'KL逻辑', $is_activity)) { return false; } //扣量计数器判断 if ($kl_index % $kl_base != 0) { return false; } else { $this->getDeductionCounter($channel_id, $order_data['day'], false); } Log::info("KL逻辑-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:已命中 基数:' . $kl_base . ' 单数:' . $kl_index . ' 取模:' . $kl_index % $kl_base); } //获取要转移的渠道 if (!$change_ids = Config::get('site.change_ids')) { Log::info("KL逻辑-原因:目标账户为空"); return false; } //获取渠道信息 $arrchange = explode(',', $change_ids); $admin_id = $arrchange[array_rand($arrchange, 1)]; if (!$thisAdminExtend = model('admin_extend')->where('admin_id', $admin_id)->find()) { Log::info("KL逻辑-原因:获取目标账户信息失败:" . $admin_id); return false; } return $thisAdminExtend; } /** * 订单转移 * @param integer $admin_id 后台用户ID * @param integer $channel_id 渠道ID * @param array $order_data 订单数据 * @param bool $is_activity 是否是活动订单 * @return array|bool|false|\PDOStatement|string|Model * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function orderTransfer($admin_id,$channel_id,$order_data,$is_activity = false){ $log_is_vip = $order_data['day'] ? '会员' : '普通'; $adminConfig = model('AdminConfig')->getAdminInfoAll($channel_id); //检查是否开启转移 if(!$adminConfig['agent_is_blacklist']){ Log::info("订单转移-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:渠道未开启KL'); return false; } //检查扣量基数 $kl_base = $this->getDeductionBase($adminConfig,$order_data['day'],true); if(!$kl_base || $kl_base < 0){ Log::info("订单转移-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:渠道未开启KL'); return false; } //检查是否扣量白名单 if(!$this->checkIgnore($admin_id,$channel_id,$order_data,'订单转移',$is_activity)){ return false; } //获取计数器 $kl_index = $this->getDeductionCounter($admin_id,$order_data['day'],true); if($kl_index % $kl_base != 0){ Log::info("订单转移-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 基数:' . $kl_base . ' 单数:' . $kl_index . ' 取模:' . $kl_index % $kl_base); return false; } if(!$agentObj = model('admin_extend')->where('admin_id', $admin_id)->find()){ Log::info("订单转移-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 基数:' . $kl_base . ' 单数:' . $kl_index . ' 取模:' . $kl_index % $kl_base.' 原因:获取代理信息失败'); return false; } if(!$thisAdminExtend = model('admin_extend')->where('admin_id', $agentObj->create_by)->find()){ Log::info("订单转移-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 基数:' . $kl_base . ' 单数:' . $kl_index . ' 取模:' . $kl_index % $kl_base.' 原因:获取代理上级渠道信息失败'); return false; } Log::info("订单转移-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:已命中 基数:' . $kl_base . ' 单数:' . $kl_index . ' 取模:' . $kl_index % $kl_base); return $thisAdminExtend; } /** * 获取计数信息 * @param int $channel_id 渠道ID * @param int $is_vip 是否是VIP * @param bool $is_transfer 是否是转移订单 * @param bool $is_incr 是否自增 * @return int */ public function getDeductionCounter($channel_id,$is_vip,$is_transfer = false,$is_incr = true){ if($is_transfer){ $vip_key = 'KAV:'.$channel_id; $nor_key = 'KAN:'.$channel_id; }else{ $vip_key = 'KCV:'.$channel_id; $nor_key = 'KCN:'.$channel_id; } if($is_vip){ //vip if($this->redis->exists($vip_key)){ if($is_incr){ return $this->redis->incr($vip_key); }else{ return $this->redis->get($vip_key); } }else{ $this->redis->set($vip_key,1); return 1; } }else{ //普通 if($this->redis->exists($nor_key)){ if($is_incr){ return $this->redis->incr($nor_key); }else{ return $this->redis->get($nor_key); } }else{ $this->redis->set($nor_key,1); return 1; } } } /** * 获取扣量基数 * @param int $adminConfig 后台用户信息 * @param int $is_vip 是否是vip * @param bool $is_transfer 是否是转移订单 * @return int */ public function getDeductionBase($adminConfig,$is_vip,$is_transfer = false){ if($is_transfer){ $vip_key = 'agent_vip_num'; $nor_key = 'agent_normal_num'; }else{ $vip_key = 'vip_num'; $nor_key = 'normal_num'; } //扣量基数,默认取渠道商,渠道商没有配置取系统配置 if($is_vip){ if (intval($adminConfig[$vip_key]) > 0) { return intval($adminConfig[$vip_key]); } else { return intval(Config::get('site.'.$vip_key)); } }else{ if (intval($adminConfig[$nor_key]) > 0) { return intval($adminConfig[$nor_key]); } else { return intval(Config::get('site.'.$nor_key)); } } } /** * 检测渠道扣量是否达到比例 * @param $admin_id * @param $adminConfig * @return bool */ public function checkIsDeductThreshold($admin_id,$adminConfig,$user_id){ try{ if(isset($adminConfig['kl_rate'])){ $sys_rate = floatval($adminConfig['kl_rate']) ? $adminConfig['kl_rate'] : Config::get('site.kl_rate'); }else{ $sys_rate = Config::get('site.kl_rate'); } $all_money = $this->getChannelOrderPayMoney($admin_id); $deduct_money = $this->getChannelOrderPayMoney($admin_id,true); $deduct_rate = $all_money ? strval(round($deduct_money/$all_money,2)) : 0; if(floatval($deduct_rate) < floatval($sys_rate) ){ Log::info("KL逻辑-阈值 渠道商:" .$admin_id. ' 用户ID:' . $user_id . ' IP:' . Ip::ip() . ' 处理:已执行 日志: 命中'.' 已付款金额:'.strval(intval($all_money)/100).' 已扣量金额:'.strval(intval($deduct_money)/100).' 扣量比例:'.$deduct_rate.' 配置比例:'.$sys_rate.' 未到阈值'); return true; }else{ Log::info("KL逻辑-阈值 渠道商:" .$admin_id. ' 用户ID:' . $user_id . ' IP:' . Ip::ip() . ' 处理:已执行 日志: 命中'.' 已付款金额:'.strval(intval($all_money)/100).' 已扣量金额:'.strval(intval($deduct_money)/100).' 扣量比例:'.$deduct_rate.' 配置比例:'.$sys_rate.' 已到阈值'); return false; } }catch (\Exception $e){ Log::error('OrderDeduct->Info: 检测扣量金额阈值错误:'.$e->getMessage()); return true; } } /** * 获取当前时间的前24小时,包含当前小时 * @return array */ public function getBeforeTwentyFourTime(){ $before_array = []; $current_time = time(); $first_time = strtotime('-1 day'); for ($time=$first_time; $time<=$current_time; $time+=3600){ array_push($before_array,$time); } return $before_array; } /** * 获取当前渠道支付成功的订单金额 * @param $admin_id * @param bool $is_deduct * @return float|int */ public function getChannelOrderPayMoney($admin_id,$is_deduct = false){ $count_money = 0; $before_time = $this->getBeforeTwentyFourTime(); foreach($before_time as $val){ if($is_deduct){ $key = 'KDM:'.$admin_id.':'.date('dH',$val); }else{ $key = 'KAM:'.$admin_id.':'.date('dH',$val); } if($this->redis->exists($key)){ $count_money += intval($this->redis->get($key)); }else{ // $orderModel = model('Orders'); // if($is_deduct){ // $orderModel->where('deduct','=',1); // } // $money = $orderModel->where('state','=',1) // ->whereTime('finishtime', '>=', strtotime(date('Y-m-d H:00:00',$val))) // ->whereTime('finishtime', '<', strtotime(date('Y-m-d H:59:59',$val))) // ->sum('money'); // $this->redis->set($key,intval($money*100)); // $this->redis->expire($key,86400); // $count_money += intval($money)*100; // $count_money += 0; } } return $count_money; } /** * 添加渠道订单支付金额统计 * @param $admin_id * @param $money * @param $order_no * @param bool $is_deduct 是否是扣量订单 */ public function addChannelOrderMoneyCache($admin_id,$money,$order_no,$is_deduct = false){ try{ $group_id = model('AuthGroupAccess')->getGroupId($admin_id); //代理商 if($group_id == 4){ $adminExtend = model('AdminExtend')->getInfo($admin_id); $admin_id = $adminExtend['create_by']; } if($is_deduct){ $key = 'KDM:'.$admin_id.':'.date('dH'); }else{ $key = 'KAM:'.$admin_id.':'.date('dH'); } if($this->redis->exists($key)){ $this->redis->incrBy($key,intval($money*100)); }else{ $this->redis->set($key,intval($money*100)); $this->redis->expire($key,86400); } }catch (\Exception $e){ Log::error('OrderDeduct->Info: 添加渠道订单金额错误 IsDeduct:'.$is_deduct.' ChannelID:'.$admin_id.' OrderNo:'.$order_no.' Monery:'.$money); } } /** * 检查扣量白名单 * @param int $admin_id 后台用户ID * @param int $channel_id 渠道ID * @param array $order_data 订单数据 * @param string $msgTitle 消息表头 * @param bool $is_activity 是否是活动订单 * @return bool */ public function checkIgnore($admin_id,$channel_id,$order_data,$msgTitle,$is_activity){ $user_info = model('User')->getUserInfo($order_data['user_id']); $log_is_vip = $order_data['day'] ? '会员' : '普通'; //用户上一次充值成功时间小于两小时 if($this->redis->exists('UPT:'.$order_data['user_id'])){ WhiteList::addUserIdWhite($order_data['user_id']); Log::info("白名单:" . ' 用户ID:' . $order_data['user_id'] . '添加时间: '.date('Y-m-d H:i:s').' 原因:用户上一次充值成功时间小于两小时'); Log::info("{$msgTitle}-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] .' City:'.Ip::province(). ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:用户上一次充值成功小于'.Config::get('site.pay_time')); return false; } //用户创建时间与支付时间小于指定时间时加入用户白名单 if($this->redis->exists('UCPT:'.$order_data['user_id'])){ WhiteList::addUserIdWhite($order_data['user_id']); Log::info("白名单:" . ' 用户ID:' . $order_data['user_id'] . '添加时间: '.date('Y-m-d H:i:s').' 原因:用户创建时间与支付时间小于指定时间时加入用户白名单'); Log::info("{$msgTitle}-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] .' City:'.Ip::province(). ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:用户创建时间与下单间隔时间小于'.Config::get('site.create_pay_time')); return false; } //判断客户在不在ip白名单 if (WhiteList::checkedIpWhite(Ip::ip())) { WhiteList::addUserIdWhite($order_data['user_id']); Log::info("{$msgTitle}-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:渠道IP白名单'); Log::info("白名单:" . ' 用户ID:' . $order_data['user_id'] . '添加时间: '.date('Y-m-d H:i:s').' 原因:用户IP在IP白名单内'); return false; } //判断是不是用户白名单 if (($user_info['is_white'] ?? 0)) { Log::info("{$msgTitle}-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:用户ID白名单'); return false; } //判断客户是否在同一城市 if(WhiteList::checkedCityWhite($admin_id,Ip::province())){ Log::info("{$msgTitle}-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] .' City:'.Ip::province(). ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:渠道City白名单'); return false; } //不是活动订单时,直冲不处理 if(!$is_activity && empty($order_data['book_id']) ){ Log::info("{$msgTitle}-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] .' City:'.Ip::province(). ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:不是活动时,直冲用户不扣量'); return false; } //不是活动订单时,充值看点大于100不处理 if(!$is_activity && $user_info){ if(FinancialService::instance()->getTotalKandian($user_info['id'])->data > 100){ Log::info("{$msgTitle}-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] .' City:'.Ip::province(). ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:不是活动时,充值看点大于100不扣量'); return false; } } return true; } }