123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- <?php
- namespace app\api\library;
- use app\common\library\Ip;
- use app\common\library\Redis;
- use app\common\utility\WhiteList;
- use app\main\constants\UserConstants;
- use app\main\service\FinancialService;
- use app\main\service\UserService;
- use think\Config;
- use think\Log;
- use think\Model;
- class OrderDeduction{
- protected $redis = null;
- public function __construct(){
- $this->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;
- }
- }
|