be368f3748 feat(channel): 新增卡密处理逻辑
- 在 Jinjiaqi.php 中添加 common 方法支持通用卡密提交
- 新增 KamiPool.php 和 System.php 两个新渠道服务类
- 修改 KamiOrderChanelNotify.php 等文件以支持新渠道的回调处理
- 更新 Order.php 文件以适配新的卡密提交逻辑
2025-06-16 00:03:59 +08:00

762 lines
22 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\openapi\controller\maSuDaApi;
use app\channel\service\ChannelService;
use app\gateway\service\CurlService;
use app\gateway\service\RedisService;
use app\merchant\service\MerchantService;
use app\merchant\service\OrderLastweekHistoryService;
use app\merchant\service\OrderService;
use app\order\service\AfterSalesOrderService;
use app\order\service\Kami91OrderService;
use think\admin\Controller;
use think\exception\HttpResponseException;
use think\facade\Db;
use think\facade\Log;
class Order extends Controller
{
# 是否检测数据
// protected bool $check = false;
protected $merchant_id;
protected string $host_url = 'https://supplier-api.wanmahui.com/api/openplatform/gateway';
# code码定义
protected $code = array
(
# 成功
1 => 'ok',
# 小于0为失败
0 => '暂时未处理',
1100 => '商品不存在',
);
protected string $uid = '';
protected string $secretKey = '';
public function message()
{
$log['type'] = 'message';
$input = input();
// $this->log ($input);
$mid = $input['mid']??null;
if(str_contains($mid, '?topic=')){
$array = explode('?topic=', $mid);
$mid = $array[0];
$input['topic'] = $array[1];
}
$method = $input['topic'];
$log['topic'] = $method;
$data = $input['data']??null;
if(!$data){
$data = $input;
}
$log['data'] = $data;
$this->log ($log);
if (method_exists($this, $method)) {
return $this->$method($data, $mid);
} else {
return 'error';
}
}
#退款消息创建
public function refund_created($datas, $mid = null)
{
if (is_string($datas)) {
$decodedData = json_decode($datas, true);
if (json_last_error() === JSON_ERROR_NONE) {
$datas = $decodedData;
} else {
return 'fail';
}
} elseif (!is_array($datas)) {
return 'fail';
}
if(is_null($mid)){
$getMerchantInfo = MerchantService::instance()->db()->whereLike('other_param', '%"seller_nick":"'.$datas['seller_nick'].'"%')->findOrEmpty();
}else{
$getMerchantInfo = MerchantService::instance()->get($mid);
}
if(!$getMerchantInfo) return 'fail';
if(!$mid) $mid = $getMerchantInfo['id'];
$aftersalesservice = AfterSalesOrderService::instance();
$info = $aftersalesservice->db()->where(['refund_id' => $datas['refund_id']])->findOrEmpty();
if (!$info) {
$update = [];
$update['listdata'] = json_encode($datas);
$update['mid'] = $mid;
$update['status'] = '1';
$update['merchant_order_id'] = $datas['tid'];
$update['refund_id'] = $datas['refund_id'];
$update['refund_fee'] = $datas['refund_fee'];
// $update['dispute_type'] = $datas['dispute_type'];
// $update['refund_desc'] = $datas['desc'];
$update['create_at'] = $datas['modified'];
$update['buyer_nick'] = $datas['buyer_nick'];
$update['buyer_open_uid'] = $datas['buyer_open_uid'];
$update['refund_phase'] = $datas['refund_phase'];
$up = $aftersalesservice->up(['refund_id' => $datas['refund_id']], $update);
return 'ok';
}
return 'error';
}
protected function getOrder($order_id, $merchant_order_id = false ,$mid = false)
{
if(str_ends_with($merchant_order_id, '-00')){
$merchant_order_id = substr($merchant_order_id, 0, -3);
}
$orderService = OrderService::instance();
$order = $orderService->get($order_id, $merchant_order_id ,$mid);
if (!$order) {
$orderHistoryService = OrderLastweekHistoryService::instance();
$order = $orderHistoryService->get($order_id, $merchant_order_id ,$mid);
}
return $order;
}
public function uphuidiao($order_id)
{
$order = $this->getOrder($order_id);
if(isset($order['channel_callback_msg'])){
$msg = json_decode($order['channel_callback_msg'],true);
if(isset($msg['kami'])){
return 'ok';
}else{
return 'error';
}
}else{
$response = json_decode($order['response'],true);
//
if(isset($response['kami'])){
// var_dump($response['kami']);die;
$kami = [
'cardno' =>$response['kami']['cardno'],
'cardpwd' =>$response['kami']['cardpwd'],
'expire_time' =>$response['kami']['expired'],
];
$where = [
'order_id' => $order_id
];
$result = Kami91OrderService::instance()->up($where,$kami);
}else{
return 'error';
}
}
return 'ok';
}
public function test_notify()
{
// $input = input();
$getMerchantInfo = MerchantService::instance()->get(12);
$param = [
'order_id' => 'GC202502212399457180392259',
'merchant_order_id'=>'2474652326141058778',
'status' => 2,
];
$kami91server = Kami91OrderService::instance();
$info = $kami91server->db()->where(['order_id' => $param['order_id']])->find();
$info_param = json_decode($info['param'],true);
$param['uid'] = $info_param['buyer_open_uid'];
$param['pid'] = $info['pid'];
$kami = [
'cardno' => $info['cardno'],
'cardpwd' => $info['cardpwd'],
'expire_time' => $info['expire_time']
];
$kami['expired'] = $kami['expire_time'];
$param['kami'] = $kami;
$up_msg = $this->notify($info['notifyurl'], $param,$getMerchantInfo);
// return $this->notify('https://mai.91kami.com/AldsSupplierTest/2025011935557114401/CreateRechargeCallback', $input,$getMerchantInfo);
}
public function notify_template($pid,$mid,$tid,$card)
{
#临时模板
$cardNo = $card['cardNo'];
$cardPwd = $card['cardPwd']??null;
$expireTime = $card['expireTime']??'';
$template = "==
您好!感谢光临小店,订单{$tid}
卡号:{$cardNo}
密码:{$cardPwd}
过期时间:{$expireTime}
注意:【本店卡密】不可充值话费、不可兑换游戏皮肤、不可代充校园卡开水卡等,让你来买的一定是骗子、!!!!!!“切勿在商品详情页指定官方以外渠道提交使用卡密“!!!!!!!
=============================
其他平台让你来购买的一定是骗子某红书、某Q、某音等全是骗子本店不跟任何人合作。请注意
注意:卡密就是您的钱,非自用,请勿把卡密发给别人
【再三提醒,被骗,自行负责】
本店仅出售未使用卡密,游戏充值不在本店服务范围,请官网使用!
===【已发卡密,后使用不支持任何理由退款,请合规使用】===
记得再来哦~~^0^
==";
// 将换行符转为\n
$escapedText = str_replace(["\r\n", "\n", "\r"], "\n", $template);
return $escapedText;
#把$template中的回车转为\n
}
# 通知处理
public function notify($url,$param,$merchant = [])
{
$log['type'] = 'maSuDa_notify';
$log['request'] =$param;
if (!isset($log['request']['merchant_order_id'])) {
return 'error';
}
$merchant_order_id = $log['request']['merchant_order_id'];
$param_data = [
'tid' =>$merchant_order_id,
'uid' => $param['uid']??'',
'method'=>'trade_message_deliver',
'timestamp' => time(),
];
// var_dump($log);die;
if (isset($log['request']['status']) && ($log['request']['status'] == 2 || $log['request']['status'] == 3)) {
$other_param = json_decode($merchant['other_param'],true);
if(!is_array($other_param) || !isset($other_param['maSuDa_secret_key'])){
$secretKey = 'ez8bfsrgefga5nkx5zgccegrb25mct7w';
}else{
$secretKey = $other_param['maSuDa_secret_key'];
$param_data['uid'] = $other_param['maSuDa_uid']??$param['uid']??'';
}
if ($log['request']['status'] == 2) {
if(isset($param['kami'])){
$cards=[
'cardNo' => $param['kami']['cardno'],
'cardPwd' => $param['kami']['cardpwd']??null,
'expireTime' => $param['kami']['expired']??null,
];
$param_data['content']=$this->notify_template($param['pid'],$merchant['id'],$merchant_order_id,$cards);
$param_data['sign'] = $this->_sign($param_data,$secretKey);
$response = $this->curl('post',$url, $param_data);
// var_dump($response);die;
if ($response) {
$response = json_decode($response, true);
if (isset($response['code']) && $response['code'] == '10000') {
return 'success';
}else{
return $response['message']??'error';
}
}
}
}
}
return 'error';
}
public function _sign($request, $secretKey)
{
ksort($request);
$str = '';
foreach ($request as $k => $v){
$str .= $k . $v ;
}
$str = $secretKey.$str.$secretKey;
// var_dump($str);die;
return md5($str);
}
# 提交接口 一般用于提交数据,异步执行
public function trade_buyer_pay($datas,$mid=null)
{
#注意修改id
// $this->mid = '2';
if (is_string($datas)) {
$decodedData = json_decode($datas, true);
if (json_last_error() === JSON_ERROR_NONE) {
$datas = $decodedData;
} else {
return 'fail';
}
} elseif (!is_array($datas)) {
return 'fail';
}
$data = [
'api_key' =>'maSuDa'
];
if(is_null($mid)){
$getMerchantInfo = MerchantService::instance()->db()->whereLike('other_param', '%"seller_nick":"'.$datas['seller_nick'].'"%')->findOrEmpty();
}else{
$getMerchantInfo = MerchantService::instance()->get($mid);
}
if(!$getMerchantInfo) return 'fail';
$data['mid'] = $getMerchantInfo['id'];
$other_param = json_decode($getMerchantInfo['other_param'],true);
if(is_array($other_param) && isset($other_param['maSuDa_secret_key'])){
$secret_key = $other_param['maSuDa_secret_key'];
}else{
$secret_key = 'maSuDa';
}
$order = '';
$merchant_order = $datas['tid'];
#使用redis记录每笔订单详情进行限单或者退款处理
if(is_array($other_param) && str_contains($getMerchantInfo['other_param'], 'limitbuy_')){
if(isset($other_param['limitbuy_min_num'])){
# 使用redis记录并按分钟限制订单
$min = $array['limitbuy_min_num'][0]??0; #每隔几分钟
$num = $array['limitbuy_min_num'][1]??0; #限制规则
$By_OpenUid = $datas['buyer_open_uid'];
if($min && $num){
$redis = RedisService::getInstance();
$redis_key = $this->merchant['id'].'_['.$By_OpenUid.']_LimitM_MSD';
$countS = $redis->get($redis_key);
if(!$countS){
$redis->set($redis_key,1,$min*60);
}else{
# 检测是否超过限制
$new_num = $countS + 1;
if($new_num >$num){
return 'fail';
}else{
#未触发,设置redis继续发货
$redis->set($redis_key,$new_num,$min*60);
}
}
}
}
}
# 根据订单号获取订单信息,先从数据库中获取
$orderData = $this->getOrder($order, $merchant_order ,$getMerchantInfo['id']);
$buyer_open_uid = $datas['buyer_open_uid'];
if(!$orderData){
#从码速达获取订单信息
#优化为等待处理
$data['cash'] =$datas['payment'] ??1;
$data['pid'] = '999999';#设置默认pid
$data['status'] = '1';
$data['param'] = json_encode($datas);
$where = [
'mid' => $data['mid'],
'merchant_order_id' => $merchant_order
];
$data['merchant_order_id'] = $merchant_order;
$data['notifyurl'] = $this->host_url;
$result = Kami91OrderService::instance()->up($where,$data);
if(!is_numeric($result)){
$this->no(-1000);
}
$response = [
'orderNo' => $merchant_order,
'orderStatus' => 10,
'outTradeNo'=>'T'.$merchant_order,
];
$this->yes($response);
}else{
$data['product_key'] = $orderData['product_key'];
#判断是否为非卡密
if(!str_contains($orderData['product_key'], '_cardbuy'))return '暂时不处理非卡密订单';
$data['cash'] = $orderData['cash'] ;
$data['pid'] = $orderData['pid'];
$data['status'] = '4';
$data['order_id'] = $orderData['order_id'];
try{
$redis = RedisService::getInstance();
$redis_key = 'Kami_wait_'.$orderData['order_id'];
$getRedisData = $redis->get($redis_key);
if($getRedisData){
$redis->delete($redis_key);
$redis->push('submit', $getRedisData);
}
}catch (\Exception $e){
}
$data['param'] = json_encode($datas);
$where = [
'mid' => $data['mid'],
'merchant_order_id' => $merchant_order
];
$data['merchant_order_id'] = $merchant_order;
$data['notifyurl'] = $this->host_url;
$result = Kami91OrderService::instance()->up($where,$data);
if(!is_numeric($result)){
$this->no(-1000);
}
$response = [
'orderNo' => $merchant_order,
'orderStatus' => 10,
'outTradeNo'=>$orderData['order_id']??'D'.$merchant_order,
];
$this->yes($response);
}
}
#获取订单信息-从码速达
public function get_Order($uid, $merchant_order ,$secret_key)
{
$request = [
'uid' =>$uid,
'method'=>'trade_detail',
'tid' => $merchant_order,
'timestamp'=>time()
];
$request['sign'] = $this->_sign($request,$secret_key);
$response = $this->curl('post', $this->host_url,$request);
$response = json_decode($response,true);
if(is_array($response) && $response['code'] == 10000){
return $response['data'];
}else{
return false;
}
}
protected static function log($data, $type = 'request'):void
{
\dever\Log::write('masuda', $type, $data);
}
public function mapping($proid)
{
if($proid == '5438110079611'){
return '10091';
}else{
return $proid;
}
}
public function queryFaka($merchant_order,$uid,$secretKey){
$param = [
'uid'=>$uid,
'method'=>'trade_message_deliver_search',
'timestamp'=>time(),
'tid'=>$merchant_order,
];
$param['sign'] =$this->_sign($param,$secretKey);
$response = $this->curl('post', $this->host_url,$param);
// var_dump($response);die;
$msg = json_decode($response,true);
$this->log($msg,'queryFaka');
if(is_array($msg) && isset($msg['code']) && $msg['code'] == '10000'){
if(isset($msg['data']['status'])){
if($msg['data']['status'] == '1'){
return 'ok';
}elseif ($msg['data']['status'] == '0'){
return 'wait';
}elseif($msg['data']['status'] == '2'){
return 'fail';
}
}
}
return false;
}
public function huidiao($order_id)
{
// var_dump(123);die;
$order = $this->getOrder($order_id);
if(isset($order['channel_callback_msg'])){
$msg = json_decode($order['channel_callback_msg'],true);
if(isset($msg['kami'])){
OrderService::instance()->upStatus($order_id);
}else{
return 'error';
}
}else{
$response = json_decode($order['response'],true);
if(isset($response['kami'])){
$kami = [
'cardno' =>$response['kami']['cardno'],
'cardpwd' =>$response['kami']['cardpwd'],
'expire_time' =>$response['kami']['expired'],
];
$where = [
'order_id' => $order_id
];
OrderService::instance()->upChannelMsg($order_id,'2',['kami' => $response['kami'],'s_number'=>$response['kami']['cardno']]);
}else{
return 'error';
}
}
if ( $order['merchant_callback_error'] != 1) {
$data['merchant_callback_error'] = 2;
$where = [
'order_id' => $order_id
];
OrderService::instance()->db()->where($where)->update($data);
}
return 'ok';
}
# 备注
public function send_post($notify_url, $post_data, $type): mixed
{
$postdate = json_encode($post_data);
$options = array(
'http' => array(
'method' => $type,
'header' => 'Content-type:application/json',
'content' => $postdate,
'timeout' => 15 * 60 // 超时时间(单位:s
)
);
$context = stream_context_create($options);
return file_get_contents($notify_url, false, $context);
}
protected function curl($method, $url, $param = array(), $json = false, $header = false):mixed
{
if ($param) {
$log['type'] = 'request';
$log['url'] = $url;
$log['param'] = $param;
$this->log($log);
}
$curl = CurlService::getInstance($url, $param, $method, $json, $header);
$curl->setTimeOut(3600);
return $curl->result();
}
/**
* 返回成功的消息
* @param mixed $info
* @param string $data
* @param integer $code
*/
protected function yes($data = '{-null-}', $info = 'ok', $code = 200)
{
if (is_string($data) && $data != 'ok' && $data != 'success') {
if ($data == '订单号重复') {
return $this->no(-102);
}
return $this->no(-100, $data);
}
$response = [
'code' => $code,
'message' => $info,
'data' => $data
];
throw new HttpResponseException(json($response));
}
/**
* 返回失败的消息
* @param mixed $info
* @param string $data
* @param integer $code
*/
protected function no($code = 0, $info = '', $data = null)
{
$msg = '失败原因'.$this->code[$code] ?? 'error';
if ($info) {
$msg .= ':' . $info;
}
$response = [
'code' => $code,
'message' => $msg,
'data' => $data
];
throw new HttpResponseException(json($response));
}
#订阅消息
public function message_config($mid,$topics,$status){
$merchant = $this->getMid_info($mid);
$host = sysconf('system_host');
if (!$host) {
if (isset($_SERVER['SERVER_PORT']) && isset($_SERVER['HTTP_HOST'])) {
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
$host = $protocol.$_SERVER['HTTP_HOST'];
} else {
$host = 'https://reapi.gcdat.com';
}
}
$param = [
'uid'=>$this->uid,
'method'=>'message_config',
'timestamp'=>time(),
'status'=>$status,
'message_url'=>$host.'/openapi/maSuDaApi/Order/message?mid='.$mid,
'topics'=>$topics
];
$param['sign'] =$this->_sign($param,$this->secretKey );
$response = $this->curl('post', $this->host_url,$param);
// var_dump($param);die;
$msg = json_decode($response,true);
if(is_array($msg) && isset($msg['code']) && $msg['code'] == '10000'){
return 'ok';
}else{
return 'fail';
}
}
public function test_dy_message(){
$param = input();
return $this->message_config($param['mid'],$param['tops'],$param['status']);
}
public function getMid_info($mid){
$merchantService = MerchantService::instance();
$merchant = $merchantService->getInfo($mid);
if(!$merchant){
return $this->no(-100,'商户不存在');
}
$array = json_decode($merchant['other_param'],true);
$this->uid = $array['maSuDa_uid']??'';
$this->secretKey = $array['maSuDa_secret_key']??'';
return $merchant;
}
}