diff --git a/app/channel/service/system/Baidumnpapi.php b/app/channel/service/system/Baidumnpapi.php new file mode 100644 index 0000000..10e4c7c --- /dev/null +++ b/app/channel/service/system/Baidumnpapi.php @@ -0,0 +1,116 @@ +host .'?mobile='.$mobile; + $headers = [ + 'Content-Type'=>'application/json', + 'X-Bce-Signature'=>'AppCode/'.$this->mid, + ]; + + + + + $response = $this->curl('post', $url, [] ,true,$headers); + $response = $this->response($response); + //$response['data'] = '{}'; + //$response['msg'] = 'ok'; + if($response['msg'] == 'ok'){ + if(isset($response['array']['result']['Now_isp'])){ + if($response['array']['result']['Now_isp'] == '移动'){ + return 1; + }elseif ($response['array']['result']['Now_isp'] == '联通'){ + return 2; + }else{ + return 3; + } + } + } + + + return $response['msg']; + + } + + + + + + + + + # 数据响应格式处理 + public function response($data) + { + $log['type'] = 'response'; + $log['data'] = $data; + $log['config'] = $this->data; + $this->log($log); + + $array = $this->json_decode($data); + if (!$array) { + $msg = 'error'; + } elseif (isset($array['code']) && $array['code'] == 0) { + # 正确 + $msg = 'ok'; + + } else { + # 错误 + $msg = isset($array['info']) ? $array['info'] : 'error'; + } + + + + return array + ( + 'msg' => $msg, + 'data' => $data, + 'array' => $array, + ); + } + + + + # 查询余额接口 + public function account($day) + { +// $request['day'] = $day; +// $request['appid'] = $this->mid; +// $request['version'] = 'v4'; +// $request['product'] = 'query'; +// list($msec, $sec) = explode(' ', microtime()); +// $msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000); +// $request['time'] = $msectime; +// $request['nonce'] = substr(sha1(microtime()), rand(10, 15)); +// $request['sign'] = $this->_sign($request); +// $url = $this->host . 'handle/accountByDay'; +// $response = $this->curl('post', $url, $request,true); +// $response = $this->response($response); +// +// return $response['array']['data']; + } + + # 提交数据 + private function submit($param, $check) + { + + } + + +} \ No newline at end of file diff --git a/app/gateway/controller/v4/Core.php b/app/gateway/controller/v4/Core.php index 2b9ffe3..e269e54 100644 --- a/app/gateway/controller/v4/Core.php +++ b/app/gateway/controller/v4/Core.php @@ -2,6 +2,8 @@ namespace app\gateway\controller\v4; +use app\core\Service; +use app\merchant\service\MerchantLogService; use app\merchant\service\OrderLastHistoryService; use app\merchant\service\OrderLastweekHistoryService; use app\merchant\service\OrderTwoHistoryService; @@ -138,12 +140,18 @@ class Core extends Controller } + + if (!$this->product) { $this->no(-2); } # 从数据库中或者缓存中取出商户的信息,并验证是否有效 $this->getMerchant(); + if($this->product == 'dhcz_mnp'){ + $this->getMnp_isp($this->input['mobile']); + + } #验证安全进价是否匹配 if($this->product && $this->product != 'query' && $this->product != '' && isset($this->input['safe_price'])){ @@ -228,6 +236,74 @@ class Core extends Controller } return $this->request->ip(); // 如果没有X-Forwarded-For头,则返回当前请求的IP + } + + #检测运营商并更新运营商 + public function getMnp_isp($mobile) + { + $settingPhoneMNPStatus = sysconf('settingPhoneMNPStatus'); + if ($settingPhoneMNPStatus == 1) { + $mnp_cid = sysconf('PhoneMnp_cid'); + if($mnp_cid){ + $mnp_isp = ChannelService::instance()->call('phone_mnp', $mnp_cid, $mobile); + if($mnp_isp == 1){ + $this->product = 'ydcz'; + $this->input['mnp_isp'] = '移动'; + $this->Kou_Mnp($mobile); + return $this->product ; + + }elseif($mnp_isp == 2){ + $this->product = 'ltcz'; + $this->input['mnp_isp'] = '联通'; + $this->Kou_Mnp($mobile); + return $this->product ; + }elseif($mnp_isp == 3){ + $this->product = 'dxcz'; + $this->input['mnp_isp'] = '电信'; + $this->Kou_Mnp($mobile); + return $this->product ; + } + + + } + } + + + $isp = Service::instance()->isp($this->input['mobile']); + if ($isp == 1) { + $this->product = 'ydcz'; + } elseif ($isp == 2) { + $this->product = 'ltcz'; + } elseif ($isp == 3) { + $this->product = 'dxcz'; + } + return $this->product ; + } + + public function Kou_Mnp($mobile) + { + $new_cash = 0.002; + if ($this->merchant['account_surplus'] >= $new_cash) { + $account_type = 1; + } elseif ($this->merchant['credit_surplus'] >= $new_cash) { + $account_type = 2; + } + + $redis = RedisService::getInstance(); + // 记录扣费到 Redis + // 根据 this->mid 分别记录不同用户的调用次数 + $redis_key = 'merchant_cash_deduction:' . $this->mid; + $deduction_count = $redis->incr($redis_key,1); + if ($deduction_count % 10 == 0) { + $new_cash = $new_cash*10; + MerchantLogService::instance()->add($this->mid, $new_cash, $account_type, 3, 'API扣费: 业务余额扣除 - 10次调用携号转网'); + + // 重置 Redis 中的调用次数 + $redis->set($redis_key, 0); + } + + + } # 检测开放或者维护时间 diff --git a/app/private_api/controller/merchantApi/Order.php b/app/private_api/controller/merchantApi/Order.php index 39244f1..8fdfb10 100644 --- a/app/private_api/controller/merchantApi/Order.php +++ b/app/private_api/controller/merchantApi/Order.php @@ -3,6 +3,9 @@ namespace app\private_api\controller\merchantApi; use app\channel\service\ChannelService; +use app\core\Service; +use app\gateway\service\RedisService; +use app\merchant\service\MerchantLogService; /** * 接口处理 @@ -26,11 +29,21 @@ class Order extends Core $this->getMerchant(); + $param['cash'] = $this->input['cash']; $param['mobile'] = $this->input['account']; - $param['product'] = $this->input['product_key']; + + if($this->product == 'dhcz_mnp'){ + $this->getMnp_isp($this->input['account']); + if(isset($this->input['mnp_isp'])){ + $param['mnp_isp'] = $this->input['mnp_isp']; + } + + } + $param['product'] =$this->product; + $param['order'] = $this->input['order_no']; @@ -39,6 +52,77 @@ class Order extends Core } + #检测运营商并更新运营商 + public function getMnp_isp($mobile) + { + $settingPhoneMNPStatus = sysconf('settingPhoneMNPStatus'); + if ($settingPhoneMNPStatus == 1) { + $mnp_cid = sysconf('PhoneMnp_cid'); + if($mnp_cid){ + $mnp_isp = ChannelService::instance()->call('phone_mnp', $mnp_cid, $mobile); + if($mnp_isp == 1){ + $this->product = 'ydcz'; + $this->input['mnp_isp'] = '移动'; + $this->Kou_Mnp($mobile); + return $this->product ; + + }elseif($mnp_isp == 2){ + $this->product = 'ltcz'; + $this->input['mnp_isp'] = '联通'; + $this->Kou_Mnp($mobile); + return $this->product ; + }elseif($mnp_isp == 3){ + $this->product = 'dxcz'; + $this->input['mnp_isp'] = '电信'; + $this->Kou_Mnp($mobile); + return $this->product ; + } + + + } + } + + + $isp = Service::instance()->isp($this->input['mobile']); + if ($isp == 1) { + $this->product = 'ydcz'; + } elseif ($isp == 2) { + $this->product = 'ltcz'; + } elseif ($isp == 3) { + $this->product = 'dxcz'; + } + return $this->product ; + } + + public function Kou_Mnp($mobile) + { + $new_cash = 0.002; + if ($this->merchant['account_surplus'] >= $new_cash) { + $account_type = 1; + } elseif ($this->merchant['credit_surplus'] >= $new_cash) { + $account_type = 2; + } + + $redis = RedisService::getInstance(); + // 记录扣费到 Redis + // 根据 this->mid 分别记录不同用户的调用次数 + $redis_key = 'merchant_cash_deduction:' . $this->mid; + $deduction_count = $redis->incr($redis_key,1); + if ($deduction_count % 10 == 0) { + $new_cash = $new_cash*10; + MerchantLogService::instance()->add($this->mid, $new_cash, $account_type, 3, 'API扣费: 业务余额扣除 - 10次调用携号转网'); + + // 重置 Redis 中的调用次数 + $redis->set($redis_key, 0); + } + + + + } + + + + protected function maketime($v): float|false|int|string { if (!$v) { diff --git a/app/private_api/controller/monitorApi/Core.php b/app/private_api/controller/monitorApi/Core.php new file mode 100644 index 0000000..aa5cebc --- /dev/null +++ b/app/private_api/controller/monitorApi/Core.php @@ -0,0 +1,279 @@ + 'ok', + # 小于0为失败 + -1 => 'mid为空', + -2 => '产品错误', + -3 => 'appid无效', + -4 => '余额不足或者没有传入价格', + + -5 => 'sign不能为空', + -6 => 'nonce不能为空', + -7 => 'time不能为空', + -8 => 'sign已失效', + -9 => 'sign验证失败', + -10 => '参数错误', + + -100 => '请求错误', + -101 => '订单不存在', + -102 => '订单号重复', + -103 => '请求错误,请求格式不正确,请使用json请求', + -104 => '回调渠道订单号不匹配,请核对', + + -201 => '安全进价低于实际进价', + + -801 => 'ip: 请求错误,不在白名单', + -802 => '方法不存在', + -803 => '版本号不正确', + + -1000 => '系统维护中', + + + ); + + #找不到方法错误响应 + public function __call($name, $arguments) + { + + $this->error('请求' . $name . '错误', '{-null-}', -802); + } + + public function initialize(): void + { + + parent::initialize(); + $this->sign_type = sysconf('sign_type'); + if ($this->check) { + $this->check(); + } + } + + # 获取输入的信息 + public function input(): void + { + $this->input = input(); + if (!$this->input) { + $this->no(-100); + } + } + + + + /** + * 检测输入信息是否合法 + */ + protected function check() + { + if (!str_contains($this->request->header('content_type'), "application/json")) $this->no(-103); + + +// $this->input(); + $input = input(); + if (!$input) { + $this->no(-100); + } + + $ip_white_data = sysconf('MerchantSystem_ip_white'); + $request_ip = $this->getRealIp(); +// if() + $ip_white_array = $ip_white_data ? explode(',', $ip_white_data) : []; + + + if (!$ip_white_array || !in_array($request_ip, $ip_white_array)) { + $this->no(-801, 'ip:' . $request_ip . ',请求错误,不在白名单内。'); + } + + $old_sign = $input['sign']; + unset($input['sign']); + #版本签名 + + $signature = $this->sign($input, $this->merchant['token'], $request_ip); + + if($signature != $old_sign){ + $this->no(-9, 'sign验证失败'); + } + } + + public function sign($dta,$token,$ip) + { + ksort($dta); + $signature_string = ''; + foreach ($dta as $k => $v) { + $signature_string .= $k . '=' . $v . '&'; + } + + $tokens = md5($token.'||'.$ip); + + $signature_string .= 'key='.$tokens; + #此处采用ip+token进行签名 + return md5($signature_string); + + } + + public function getRealIp(): string + { + $forwardedFor = $this->request->header('x-forwarded-for'); + + if ($forwardedFor) { + // 可能有多个IP,第一个通常是真实的 + $ips = explode(',', $forwardedFor); + return trim($ips[0]); + } + + return $this->request->ip(); // 如果没有X-Forwarded-For头,则返回当前请求的IP + } + + # 检测开放或者维护时间 + protected function checkOpenTime($opentime): void + { + if ($opentime && strstr($opentime, ':')) { + $opentime = str_replace(':', '', $opentime); + if (str_contains($opentime, '-')) { + $value = explode('-', $opentime); + $cur = intval(date('Hi')); + $value[0] = intval($value[0]); + $value[1] = intval($value[1]); + if ($value[1] < $value[0]) { + if ($cur >= $value[0] || $cur < $value[1]) { + $this->no(-1000); + } + } else { + if ($cur >= $value[0] && $cur < $value[1]) { + $this->no(-1000); + } + } + } + } + } + + + + # 获取商户信息 + protected function getMerchant(): void + { + $this->merchant = MerchantService::instance()->get($this->mid); + if (!$this->merchant) { + $this->no(-3); + } + + if ($this->product != 'query') { + if (empty($this->input['cash'])) { + $this->no(-4); + } + if ($this->product == 'dxdc') { + $cash = 0.23;//这里后续处理 + if ($this->merchant['credit_surplus'] < $cash && $this->merchant['account_surplus'] < $cash) { + $this->no(-4); + } + } else { + if ($this->merchant['credit_surplus'] < $this->input['cash'] && $this->merchant['account_surplus'] < $this->input['cash']) { + $this->no(-4); + } + } + } + + $this->mid = $this->merchant['id']; + if ($this->sign_type == 2) { + $this->key = $this->merchant['appsecret']; + } else { + $this->key = $this->appid . '|' . $this->merchant['appsecret']; + } + + } + + # 查找订单 + + + + + + /** + * 返回失败的消息 + * @param mixed $info + * @param string $data + * @param integer $code + */ + protected function no(int $code = 0, $info = '', $data = '{-null-}') + { + $msg = $this->code[$code] ?? 'error'; + if ($info) { + $msg .= ':' . $info; + } + $data = '{-null-}'; + $this->error($msg, $data, $code); + } + + /** + * 返回成功的消息 + * @param mixed $info + * @param string $data + * @param integer $code + */ + protected function yes($data = '{-null-}', $info = 'ok', $code = 1) + { + if (is_string($data) && $data != 'ok' && $data != 'success') { + if ($data == '订单号重复') { + return $this->no(-102); + } + return $this->no(-100, $data); + } + $this->success($info, $data, $code); + } + + # 记录日志 + protected function log($data) + { + Log::write('private_api', 'merchantApi', $data); + } + + # 队列 + protected function queue($key, $value = false) + { + $redis = RedisService::getInstance(); + if (!$value) { + return $redis->pop($key); + } else { + return $redis->push($key, $value); + } + } +} \ No newline at end of file diff --git a/app/private_api/controller/monitorApi/Merchant.php b/app/private_api/controller/monitorApi/Merchant.php new file mode 100644 index 0000000..796e906 --- /dev/null +++ b/app/private_api/controller/monitorApi/Merchant.php @@ -0,0 +1,85 @@ +getAll(); + + $where['is_deleted'] = 0; + $where['status'] = 1; + $data = MerchantService::instance()->db()->field('name,account_surplus,credit_surplus,appid')->where($where)->select()->toArray(); + $this->yes($data); + + } + + protected function maketime($v): float|false|int|string + { + if (!$v) { + return ''; + } + + if (is_numeric($v)) { + return $v; + } + + if (is_array($v)) { + $v = $v[1]; + } + + if (strstr($v, ' ')) { + $t = explode(' ', $v); + $v = $t[0]; + $s = explode(':', $t[1]); + } else { + $s = array(0, 0, 0); + } + + if (!isset($s[1])) { + $s[1] = 0; + } + + if (!isset($s[2])) { + $s[2] = 0; + } + + if (strstr($v, '-')) { + $t = explode('-', $v); + } elseif (strstr($v, '/')) { + $u = explode('/', $v); + $t[0] = $u[2]; + $t[1] = $u[0]; + $t[2] = $u[1]; + } + + if (!isset($t)) { + $t = array(0, 0, 0); + } + + if (!isset($t[1])) { + $t[1] = 0; + } + + if (!isset($t[2])) { + $t[2] = 0; + } + + $v = mktime($s[0], $s[1], $s[2], $t[1], $t[2], $t[0]); + + return $v; + } + +} \ No newline at end of file diff --git a/app/private_api/controller/robotApi/WeChatBot.php b/app/private_api/controller/robotApi/WeChatBot.php index 290a9ec..b938f8e 100644 --- a/app/private_api/controller/robotApi/WeChatBot.php +++ b/app/private_api/controller/robotApi/WeChatBot.php @@ -85,6 +85,21 @@ class WeChatBot extends Core // var_dump($data['sender']);die; return $RobotService->send_text('测试自动回复 @'.$ac,$data['roomid'],$data['sender']); } + if($roomid == '47576792968@chatroom' && str_contains($data['xml'],'wxid_9iv1hha8g3ok29')){ + $AllContacts = $RobotService->get_all_contacts(); +// var_dump($AllContacts);die; + $Contacts_array = json_decode($AllContacts,true); + $acc = $Contacts_array['data']['contacts']; +// var_dump($acc);die; + $ac = ''; + foreach ($acc as $k=>$v){ + if($v['wxid'] == $data['sender']){ + $ac = $v['name']; + } + } +// var_dump($data['sender']);die; + return $RobotService->send_text('测试自动回复 @'.$ac,$data['roomid'],$data['sender']); + } $this->response(['code'=>1]); } diff --git a/app/queue/command/monitor/MerchantBalanceMonitor.php b/app/queue/command/monitor/MerchantBalanceMonitor.php new file mode 100644 index 0000000..bdfdd3a --- /dev/null +++ b/app/queue/command/monitor/MerchantBalanceMonitor.php @@ -0,0 +1,114 @@ +setName('xQueue:MerchantBalanceMonitor')->setDescription('[ 监控系统 ] 商户余额监控预警'); + } + + /** + * @param Input $input + * @param Output $output + * @throws \think\admin\Exception + */ + protected function execute(Input $input, Output $output) + { + ini_set('memory_limit', '1024M'); + + $merchantService = MerchantService::instance(); + + $merchantsList = $merchantService->db()->where(['merchant_type'=>1,'status'=>1])->select()->toArray(); +// if(!$channelList) $this->setQueueSuccess("未找到支持查询的渠道"); + $merchantsList_num = count($merchantsList); + $count_sum = 0; + $total_sum=0; + $redisStatus = sysconf('settingRedisQueryOrder'); + + foreach($merchantsList as $merchants) { + + $class = OrderService::instance(); + $where['cid'] = $channel['id']; + $where['status'] = 4; + if($redisStatus == 1){ + #多线程此处只传入队列 + $orderList = $class->db()->field('cid,order_id')->where($where)->order('id asc')->select()->toArray(); + foreach ($orderList as $vo) { + $this->queue('query', $vo); + } +// $this->queue('query', $orderList); + + }else{ + list($count, $total) = [0, $class->db()->where($where)->order('id asc')->count()]; + $total_sum += $total; +// $data = $class->db()->where($where)->limit(100)->select()->toArray(); + $class->db()->where($where)->order('id asc')->chunk(1000, function (Collection $data) use (&$count, $total,$channel,$channelService,&$count_sum) { + $array = $data->toArray(); + + + foreach ($array as $k => $vo) { + if(isset($vo['num']) && $vo['num']>0) { + $vo['order_id'] = $vo['order_id'].'_'.$vo['num']; + } + + $result = $channelService->call('query', $vo['cid'], $vo); + if ($result['status'] != 4) { + $count_sum++; + $count++; + $notifyClass = new Notify($this->app); + $notifyClass->queue_query($vo['order_id'], $result); + $this->setQueueProgress("查询 {$vo['order_id']} 新的状态进行主动更新", $count / $total * 100); + } + } + + }); + + } + + + + + + } + + + $this->setQueueSuccess("共处理 {$channelList_num} 个渠道,共有 {$total_sum} 个订单处理查询中, 完成{$count_sum} 个订单查询新状态更新!"); + + + } + + # 队列 + protected function queue($key, $value = false) + { + $redis = RedisService::getInstance(); + if (!$value) { + return $redis->pop($key); + } else { + return $redis->push($key, $value); + } + } + + +} + + + diff --git a/app/setting/view/config/index.html b/app/setting/view/config/index.html index 5650eab..24dca9f 100644 --- a/app/setting/view/config/index.html +++ b/app/setting/view/config/index.html @@ -47,6 +47,33 @@ 请填写维护时间,为空则24小时开启,值为22:30-00:30 + +
+