123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 |
- <?php
- /**
- * Created by PhpStorm.
- * User: Bear
- * Date: 2019/8/23
- * Time: 下午1:32
- */
- namespace app\main\service;
- use app\common\library\Ip;
- use app\common\library\Redis;
- use app\common\utility\WhiteList;
- use app\main\constants\PayConstants;
- use app\main\constants\UserConstants;
- use app\main\model\object\ReturnObject;
- use think\Config;
- /**
- * KL服务类
- * Class AdminKlService
- * @package app\main\service
- */
- class AdminKlService extends BaseService
- {
- public $business_line;
- public $suffix = '';
- public $cache_param = '';
- /**
- * @var AdminKlService
- */
- protected static $self = NULL;
- /**
- * @param string $business_line
- * @return $this|AdminKlService
- */
- public static function instance($business_line = PayConstants::BUSINESS_APP)
- {
- if (self::$self == NULL) {
- self::$self = new self();
- self::$self->business_line = $business_line;
- self::$self->setConfig();
- }
- return self::$self;
- }
- /**
- * 设置后缀
- */
- public function setConfig()
- {
- switch ($this->business_line) {
- case PayConstants::BUSINESS_APP:
- $this->suffix = '_app';
- $this->cache_param = 'APP';
- }
- }
- /**
- * 订单扣量
- * @param integer $admin_id 后台用户ID
- * @param integer $channel_id 渠道ID
- * @param array $order_data 订单数据
- * @param bool $is_activity 是否是活动订单
- * @return ReturnObject
- */
- public function orderKL($admin_id, $channel_id, $order_data, $is_activity = false)
- {
- if (WebUserService::instance()->getUserInfo()->is_black == UserConstants::USER_BLACK_NO) {
- $log_is_vip = $order_data['day'] ? '会员' : '普通';
- $adminConfig = AdminService::instance()->getAdminKlModel()->getAdminKl($channel_id, $this->business_line);
- //检查渠道是否开启扣量
- if (!$adminConfig['is_blacklist']) {
- LogService::info("NEW-KL逻辑-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:渠道未开启KL');
- return $this->setData(false)->getReturn();
- }
- //检查代理商ID白名单
- $kl_agent_blacklist = explode(',', $this->getConfig('kl_agent_blacklist'));
- if (in_array($admin_id, $kl_agent_blacklist)) {
- LogService::info("NEW-KL逻辑-{$log_is_vip} 代理商: {$admin_id} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:代理商ID白名单');
- return $this->setData(false)->getReturn();
- }
- //检查是否扣量白名单
- if (!$this->checkIgnore($admin_id, $channel_id, $order_data, 'KL逻辑', $is_activity)->data) {
- return $this->setData(false)->getReturn();
- }
- //检查扣量基数
- $kl_base = $this->getDeductionBase($adminConfig, $order_data['day'], false);
- if (!$kl_base || $kl_base < 0) {
- LogService::info("NEW-KL逻辑-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:渠道未开启KL');
- return $this->setData(false)->getReturn();
- }
- //检测是否到达扣量比例
- if (!$this->checkIsDeductThreshold($channel_id, $adminConfig, $order_data['user_id'])->data) {
- return $this->setData(false)->getReturn();
- }
- //获取计数器,未到扣量基数时累加,到扣量基数时暂停,直到扣量后继续累加
- $kl_index = $this->getDeductionCounter($channel_id, $order_data['day'], false, false)->data;
- //扣量计数器判断
- if ($kl_index % $kl_base != 0) {
- LogService::info("NEW-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)->data;
- return $this->setData(false)->getReturn();
- }
- $this->getDeductionCounter($channel_id, $order_data['day'], false)->data;
- LogService::info("NEW-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 = $this->getConfig('change_ids')) {
- LogService::info("KL逻辑-原因:目标账户为空");
- return $this->setData(false)->getReturn();
- }
- //获取渠道信息
- $arrchange = explode(',', $change_ids);
- $admin_id = $arrchange[array_rand($arrchange, 1)];
- if (!$thisAdminExtend = model('admin_extend')->where('admin_id', $admin_id)->find()) {
- LogService::info("KL逻辑-原因:获取目标账户信息失败:" . $admin_id);
- return $this->setData(false)->getReturn();
- }
- return $this->setData($thisAdminExtend)->getReturn();
- }
- /**
- * 订单转移
- * @param integer $admin_id 后台用户ID
- * @param integer $channel_id 渠道ID
- * @param array $order_data 订单数据
- * @param bool $is_activity 是否是活动订单
- * @param bool $business_line 业务线
- * @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 = AdminService::instance()->getAdminKlModel()->getAdminKl($channel_id);
- //检查是否开启转移
- if (!$adminConfig['agent_is_blacklist']) {
- LogService::info("NEW-订单转移-{$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)->data) {
- return false;
- }
- //检查扣量基数
- $kl_base = $this->getDeductionBase($adminConfig, $order_data['day'], true);
- if (!$kl_base || $kl_base < 0) {
- LogService::info("NEW-订单转移-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:渠道未开启KL');
- return false;
- }
- //获取计数器
- $kl_index = $this->getDeductionCounter($admin_id, $order_data['day'], true)->data;
- if ($kl_index % $kl_base != 0) {
- LogService::info("NEW-订单转移-{$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()) {
- LogService::info("NEW-订单转移-{$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()) {
- LogService::info("NEW-订单转移-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 基数:' . $kl_base . ' 单数:' . $kl_index . ' 取模:' . $kl_index % $kl_base . ' 原因:获取代理上级渠道信息失败');
- return false;
- }
- LogService::info("NEW-订单转移-{$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 是否自增
- * @param bool $business_line 是否自增
- * @return ReturnObject
- */
- public function getDeductionCounter($channel_id, $is_vip, $is_transfer = false, $is_incr = true)
- {
- if ($is_transfer) {
- if ($this->cache_param) {
- $vip_key = implode(':', ['KAV', $this->cache_param, $channel_id]);
- $nor_key = implode(':', ['KAN', $this->cache_param, $channel_id]);
- } else {
- $vip_key = implode(':', ['KAV', $channel_id]);
- $nor_key = implode(':', ['KAN', $channel_id]);
- }
- } else {
- if ($this->cache_param) {
- $vip_key = implode(':', ['KCV', $this->cache_param, $channel_id]);
- $nor_key = implode(':', ['KCN', $this->cache_param, $channel_id]);
- } else {
- $vip_key = implode(':', ['KCV', $channel_id]);
- $nor_key = implode(':', ['KCN', $channel_id]);
- }
- }
- if ($is_vip) {
- //vip
- if (Redis::instance()->exists($vip_key)) {
- if ($is_incr) {
- return $this->setData(Redis::instance()->incr($vip_key))->getReturn();
- } else {
- return $this->setData(Redis::instance()->get($vip_key))->getReturn();
- }
- } else {
- Redis::instance()->set($vip_key, 1);
- return $this->setData(1)->getReturn();
- }
- } else {
- //普通
- if (Redis::instance()->exists($nor_key)) {
- if ($is_incr) {
- return $this->setData(Redis::instance()->incr($nor_key))->getReturn();
- } else {
- return $this->setData(Redis::instance()->get($nor_key))->getReturn();
- }
- } else {
- Redis::instance()->set($nor_key, 1);
- return $this->setData(1)->getReturn();
- }
- }
- }
- /**
- * 获取扣量基数
- * @param array $adminConfig 后台用户信息
- * @param int $is_vip 是否是vip
- * @param bool $is_transfer 是否是转移订单
- * @param bool $business_line 是否是转移订单
- * @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($this->getConfig($vip_key));
- }
- } else {
- if (intval($adminConfig[$nor_key]) > 0) {
- return intval($adminConfig[$nor_key]);
- } else {
- return intval($this->getConfig($nor_key));
- }
- }
- }
- /**
- * 检测渠道扣量是否达到比例
- * @param $admin_id
- * @param $adminConfig
- * @return ReturnObject
- */
- public function checkIsDeductThreshold($admin_id, $adminConfig, $user_id)
- {
- try {
- if (isset($adminConfig['kl_rate'])) {
- $sys_rate = floatval($adminConfig['kl_rate']) ? $adminConfig['kl_rate'] : $this->getConfig('kl_rate');
- } else {
- $sys_rate = $this->getConfig('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)) {
- LogService::info("NEW-KL逻辑-阈值 渠道商:" . $admin_id . ' 用户ID:' . $user_id . ' IP:' . Ip::ip() . ' 处理:已执行 日志: 命中' . ' 已付款金额:' . strval(intval($all_money) / 100) . ' 已扣量金额:' . strval(intval($deduct_money) / 100) . ' 扣量比例:' . $deduct_rate . ' 配置比例:' . $sys_rate . ' 未到阈值');
- return $this->setData(true)->getReturn();
- } else {
- LogService::info("NEW-KL逻辑-阈值 渠道商:" . $admin_id . ' 用户ID:' . $user_id . ' IP:' . Ip::ip() . ' 处理:已执行 日志: 命中' . ' 已付款金额:' . strval(intval($all_money) / 100) . ' 已扣量金额:' . strval(intval($deduct_money) / 100) . ' 扣量比例:' . $deduct_rate . ' 配置比例:' . $sys_rate . ' 已到阈值');
- return $this->setData(false)->getReturn();
- }
- } catch (\Exception $e) {
- LogService::error('NEW-OrderDeduct->Info: 检测扣量金额阈值错误:' . $e->getMessage());
- return $this->setData(true)->getReturn();
- }
- }
- /**
- * 获取当前时间的前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) {
- $key = $this->getOrderPayMoneyKey($is_deduct, $admin_id, $val)->data;
- if (Redis::instance()->exists($key)) {
- $count_money += intval(Redis::instance()->get($key));
- }
- }
- return $count_money;
- }
- /**
- * 获取充值缓存key
- * @param $is_deduct
- * @param $admin_id
- * @param string $val
- * @return ReturnObject
- */
- public function getOrderPayMoneyKey($is_deduct, $admin_id, $val = '')
- {
- if ($is_deduct) {
- $prefix = 'KDM';
- } else {
- $prefix = 'KAM';
- }
- if ($val) {
- $hour = date('dH', $val);
- } else {
- $hour = date('dH');
- }
- if ($this->cache_param) {
- $list = [$prefix, $this->cache_param, $admin_id, $hour];
- } else {
- $list = [$prefix, $admin_id, $hour];
- }
- $key = implode(':', $list);
- return $this->setData($key)->getReturn();
- }
- /**
- * 添加渠道订单支付金额统计
- * @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'];
- }
- $key = $this->getOrderPayMoneyKey($is_deduct, $admin_id)->data;
- if (Redis::instance()->exists($key)) {
- Redis::instance()->incrBy($key, intval($money * 100));
- } else {
- Redis::instance()->set($key, intval($money * 100));
- Redis::instance()->expire($key, 86400);
- }
- LogService::info('NEW-OrderDeduct->Info: 添加渠道订单金额完成 IsDeduct:' . $is_deduct . ' ChannelID:' . $admin_id . ' OrderNo:' . $order_no . ' Monery:' . $money);
- } catch (\Exception $e) {
- LogService::error('NEW-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 ReturnObject
- */
- 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 (Redis::instance()->exists('UPT:' . $order_data['user_id'])) {
- WhiteList::addUserIdWhite($order_data['user_id']);
- LogService::info("NEW-白名单:" . ' 用户ID:' . $order_data['user_id'] . '添加时间: ' . date('Y-m-d H:i:s') . ' 原因:用户上一次充值成功时间小于两小时');
- LogService::info("NEW-{$msgTitle}-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' City:' . Ip::province() . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:用户上一次充值成功小于' . Config::get('site.pay_time'));
- return $this->setData(false)->getReturn();
- }
- //用户创建时间与支付时间小于指定时间时加入用户白名单
- if (Redis::instance()->exists('UCPT:' . $order_data['user_id'])) {
- WhiteList::addUserIdWhite($order_data['user_id']);
- LogService::info("NEW-白名单:" . ' 用户ID:' . $order_data['user_id'] . '添加时间: ' . date('Y-m-d H:i:s') . ' 原因:用户创建时间与支付时间小于指定时间时加入用户白名单');
- LogService::info("NEW-{$msgTitle}-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' City:' . Ip::province() . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:用户创建时间与下单间隔时间小于' . Config::get('site.create_pay_time'));
- return $this->setData(false)->getReturn();
- }
- //判断客户在不在ip白名单
- if (WhiteList::checkedIpWhite(Ip::ip())) {
- WhiteList::addUserIdWhite($order_data['user_id']);
- LogService::info("NEW-{$msgTitle}-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:渠道IP白名单');
- LogService::info("NEW-白名单:" . ' 用户ID:' . $order_data['user_id'] . '添加时间: ' . date('Y-m-d H:i:s') . ' 原因:用户IP在IP白名单内');
- return $this->setData(false)->getReturn();
- }
- //判断是不是用户白名单
- if (($user_info['is_white'] ?? 0)) {
- LogService::info("NEW-{$msgTitle}-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:用户ID白名单');
- return $this->setData(false)->getReturn();
- }
- //判断客户是否在同一城市
- if (WhiteList::checkedCityWhite($admin_id, Ip::province())) {
- LogService::info("NEW-{$msgTitle}-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' City:' . Ip::province() . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:渠道City白名单');
- return $this->setData(false)->getReturn();
- }
- //不是活动订单时,直冲不处理
- if (!$is_activity && empty($order_data['book_id'])) {
- LogService::info("NEW-{$msgTitle}-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' City:' . Ip::province() . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:不是活动时,直冲用户不扣量');
- return $this->setData(false)->getReturn();
- }
- //不是活动订单时,充值看点大于100不处理
- if (!$is_activity && $user_info) {
- if (FinancialService::instance()->getTotalKandian($order_data['user_id'])->data > 100) {
- LogService::info("NEW-{$msgTitle}-{$log_is_vip} 渠道商:" . $channel_id . ' 用户ID:' . $order_data['user_id'] . ' City:' . Ip::province() . ' IP:' . Ip::ip() . ' 处理:已执行 结果:未命中 原因:不是活动时,充值看点大于100不扣量');
- return $this->setData(false)->getReturn();
- }
- }
- return $this->setData(true)->getReturn();
- }
- /**
- * 获取配置
- * @param $name
- * @return mixed
- */
- public function getConfig($name)
- {
- $config = Config::get('site.' . $name . $this->suffix);
- return $config ? $config : '';
- }
- }
|