From a2652c6209b32d4247dc1fe58597bef7aab1ce2a Mon Sep 17 00:00:00 2001 From: youda Date: Sat, 3 May 2025 15:05:08 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/controller/Order.php | 4 +- app/api/controller/Goods.php | 107 +++++----- app/api/controller/Infinite.php | 3 +- app/api/controller/Notify.php | 33 +-- app/api/controller/User.php | 2 + app/api/controller/Warehouse.php | 23 +- app/common.php | 8 +- app/common/server/platform/H5Platform.php | 133 +++++++++++- .../server/platform/MiniProgramPlatform.php | 197 +++++++++++++++++- .../server/platform/PlatformFactory.php | 13 +- 10 files changed, 437 insertions(+), 86 deletions(-) diff --git a/app/admin/controller/Order.php b/app/admin/controller/Order.php index dac41ba..1750aca 100755 --- a/app/admin/controller/Order.php +++ b/app/admin/controller/Order.php @@ -1018,8 +1018,8 @@ class Order extends Base $end_time = input('end_time', ''); $where = []; - $where[] = ['u.status', '=', 1]; - $where[] = ['u.istest', '=', 0]; + // $where[] = ['u.status', '=', 1]; + // $where[] = ['u.istest', '=', 0]; if ($user_id) { $where[] = ['o.user_id', '=', $user_id]; diff --git a/app/api/controller/Goods.php b/app/api/controller/Goods.php index 6c4d66b..1091c23 100755 --- a/app/api/controller/Goods.php +++ b/app/api/controller/Goods.php @@ -819,7 +819,7 @@ class Goods extends Base $coupon_id = request()->param('coupon_id/d', 0); //优惠券 #盒子信息 - $goods = Goodsmodel::field('id,title,imgurl_detail,type,price,status,is_shou_zhe,quanju_xiangou,lock_is,choujiang_xianzhi,lock_time,flw_start_time,flw_end_time,daily_xiangou')->where(['id' => $goods_id]) + $goods = Goodsmodel::field('*')->where(['id' => $goods_id]) ->find(); if (!$goods) { return $this->renderError("盒子不存在"); @@ -839,9 +839,6 @@ class Goods extends Base if (RegInt($num)) { return $this->renderError("箱号选择错误"); } - // if ($goods['type'] == 10) { - // return $this->renderError("商城未开放"); - // } // 使用PaymentCalculator验证抽奖限制(限购、消费门槛等) $paymentCalculator = new \app\common\service\PaymentCalculator(); @@ -1031,10 +1028,57 @@ class Goods extends Base } } #===================================================*********** + if ($goods['quanju_xiangou'] > 0) { + // 查看一天内有没有未支付的订单,未支付的订单要先作废 + Order::where('goods_id', '=', $goods_id) + ->where('user_id', '=', $user['id']) + ->where('status', '=', 0) + // ->where('addtime', '>=', time() - 86400) + // ->where('order_num', '!=', $order_num) + ->update(['status' => 2]); + + } + if ($goods['daily_xiangou'] > 0) { + + // 查看一天内有没有未支付的订单,未支付的订单要先作废 + Order::where('goods_id', '=', $goods_id) + ->where('user_id', '=', $user['id']) + ->where('status', '=', 0) + ->where('addtime', '>=', time() - 86400) + // ->where('order_num', '!=', $order_num) + ->update(['status' => 2]); + + } + $attach = ""; + if ($goods['type'] == 1) { + $attach = 'order_yfs'; + } elseif ($goods['type'] == 3) { + $attach = 'order_lts'; + } elseif ($goods['type'] == 5) { + $attach = 'order_jfs'; + } elseif ($goods['type'] == 6) { + $attach = 'order_lts'; + } elseif ($goods['type'] == 11) { + $attach = 'order_zzs'; + } elseif ($goods['type'] == 10) { + $attach = 'order_scs'; + } elseif ($goods['type'] == 15) { + $attach = 'order_flw'; + } else { + $attach = 'order_qts'; + } + $title = '购买盒子' . $goods['title']; + $payRes = \app\common\server\platform\PlatformFactory::createPay($user, $paymentResult['price'], $title, $attach, "MH_"); + if ($payRes['status'] !== 1) { + Db::rollback(); + #删除redis + $redis->del($redis_key); + return $this->renderError("购买失败,请刷新重试"); + } + $order_num = $payRes['data']['order_no']; $res = []; - $order_num = create_order_no('MH_', 'order', 'order_num'); #创建订单 $res[] = $order_id = Order::insertGetId([ 'user_id' => $user['id'], @@ -1063,64 +1107,15 @@ class Goods extends Base 'ad_id' => $ad_id, 'click_id' => $user['click_id'] ]); - if ($goods['quanju_xiangou'] > 0) { - // 查看一天内有没有未支付的订单,未支付的订单要先作废 - Order::where('goods_id', '=', $goods_id) - ->where('user_id', '=', $user['id']) - ->where('status', '=', 0) - // ->where('addtime', '>=', time() - 86400) - ->where('order_num', '!=', $order_num) - ->update(['status' => 2]); - - } - if ($goods['daily_xiangou'] > 0) { - - // 查看一天内有没有未支付的订单,未支付的订单要先作废 - Order::where('goods_id', '=', $goods_id) - ->where('user_id', '=', $user['id']) - ->where('status', '=', 0) - ->where('addtime', '>=', time() - 86400) - ->where('order_num', '!=', $order_num) - ->update(['status' => 2]); - - } #微信支付金额大于0 if ($paymentResult['price'] > 0) { - $body = '购买盒子' . $goods['title']; - if ($goods['type'] == 1) { - $attach = 'order_yfs'; - } elseif ($goods['type'] == 3) { - $attach = 'order_lts'; - } elseif ($goods['type'] == 5) { - $attach = 'order_jfs'; - } elseif ($goods['type'] == 6) { - $attach = 'order_lts'; - } elseif ($goods['type'] == 11) { - $attach = 'order_zzs'; - } elseif ($goods['type'] == 10) { - $attach = 'order_scs'; - } elseif ($goods['type'] == 15) { - $attach = 'order_flw'; - } else { - $attach = 'order_qts'; - } - - - // $isTest = \app\common\helper\ConfigHelper::getSystemTestKey("disable_wechat_pay"); - // if ($isTest == "1") { - // Db::rollback(); - // #删除redis - // $redis->del($redis_key); - // return $this->renderError("支付未开放"); - // } - $payRes = (new Pay())->wxCreateOrder($order_num, $paymentResult['price'], $user['id'], $body, $attach); if ($payRes['status'] == 1) { #结果集 $new_data = [ 'status' => 1, 'order_num' => $order_num, - 'res' => $payRes['data'], + 'res' => $payRes['data']['res'], ]; } else { Db::rollback(); @@ -1130,7 +1125,7 @@ class Goods extends Base } } else { try { - #开盒子 infinite_drawprize_notice + #开盒子 $res[] = (new Notify($this->app))->drawprize_notice($user['id'], $order_id, $goods_id, $num); } catch (\Throwable $e) { Db::rollback(); diff --git a/app/api/controller/Infinite.php b/app/api/controller/Infinite.php index de37cd0..e57e0f9 100755 --- a/app/api/controller/Infinite.php +++ b/app/api/controller/Infinite.php @@ -731,7 +731,7 @@ class Infinite extends Base $is_mibao = request()->param('is_mibao/d', 0); //连击赏下 是否是抽的秘宝池 1是 0否 #盒子信息 - $goods = Goodsmodel::field('id,title,imgurl_detail,type,price,status,choujiang_xianzhi')->where(['id' => $goods_id]) + $goods = Goodsmodel::field('*')->where(['id' => $goods_id]) ->find(); if (!$goods) { return $this->renderError("盒子不存在"); @@ -794,6 +794,7 @@ class Infinite extends Base } Db::startTrans(); $res = []; + $order_num = create_order_no('MH_', 'order', 'order_num'); #创建订单 $res[] = $order_id = Order::insertGetId([ diff --git a/app/api/controller/Notify.php b/app/api/controller/Notify.php index 9f37570..d714e44 100755 --- a/app/api/controller/Notify.php +++ b/app/api/controller/Notify.php @@ -1453,7 +1453,7 @@ class Notify extends Base { // 记录抽奖总开始时间 $total_start_time = microtime(true); - + // 记录抽奖出货总金额 $total_prize_money = 0; @@ -1462,14 +1462,14 @@ class Notify extends Base $order_num = $order['order_num'];//订单编号 $res = []; // 保存每次抽奖结果 $multiple = ConfigHelper::getInfiniteMultiple(); // 获取随机倍数(例如100000) - + // 将赏品列表转换为map格式,以id为键,便于快速查找 $shang_list_array = Shang::field('id,title')->select()->toArray(); $shang_list = []; foreach ($shang_list_array as $shang) { $shang_list[$shang['id']] = $shang['title']; } - + $lingzhu_shang_id = 0; // 初始化领主赏上级ID if (!$infinite_goods) { $infinite_goods = Goods::getInfo(['id' => $goods_id], '*'); @@ -1485,7 +1485,7 @@ class Notify extends Base for ($i = 0; $i < $prize_num; $i++) { // 记录单次抽奖开始时间 $single_start_time = microtime(true); - + // 用于记录日志的数据 $log_data = [ 'draw_num' => $i + 1, @@ -1588,9 +1588,9 @@ class Notify extends Base $log_data_collection[] = $log_data; continue; } - + // 累加中奖金额到总金额 - $total_prize_money += (float)$prize_info['money']; + $total_prize_money += (float) $prize_info['money']; $log_data['prize_money'] = $prize_info['money']; // 5. 处理编号 @@ -1701,7 +1701,7 @@ class Notify extends Base \think\facade\Log::error('记录抽奖日志异常:' . $e->getMessage()); } } - + // 将总金额添加到返回结果中,以便递归调用时能够累加子抽奖的金额 $res['total_prize_money'] = $total_prize_money; @@ -1830,13 +1830,13 @@ class Notify extends Base $shang_id = $range['shang_id'] ?? 0; $shang_title = $range['shang_title'] ?? '未知'; $money = $range['money'] ?? 0; - + // 判断是否是中奖奖品,如果是,则把名称变成红色 $title = $range['title']; if ($winning_prize_id && $winning_prize_id == $range['id']) { $title = "{$title}"; } - + $full_log_content .= "| {$range['id']} | {$title} | {$range['price']} | {$money} | {$range['real_pro']} | {$start} ~ {$end} | {$shang_id} | {$shang_title} |" . PHP_EOL; } } @@ -2549,13 +2549,16 @@ class Notify extends Base public function wx_gf_fahuo($user_id, $order_num) { - //微信官方发货 - $wxServer = new \app\common\server\Wx($this->app); + $user = Db::name('user')->where('id', $user_id)->find(); + $mp = new \app\common\server\platform\MiniProgramPlatform(); + $mp->post_order($user, $order_num); + // //微信官方发货 + // $wxServer = new \app\common\server\Wx($this->app); - $access_token = $wxServer->get_access_token(); - $open_id = Db::name('user')->where('id', $user_id)->value('openid'); - $pay = new \app\api\controller\Pay(); - $pay->post_order($open_id, $access_token, $order_num); + // $access_token = $wxServer->get_access_token(); + // $open_id = Db::name('user')->where('id', $user_id)->value('openid'); + // $pay = new \app\api\controller\Pay(); + // $pay->post_order($open_id, $access_token, $order_num); // $wxServer->post_order($open_id, $access_token, $order_num); } diff --git a/app/api/controller/User.php b/app/api/controller/User.php index a9fa9fe..f8ada5c 100755 --- a/app/api/controller/User.php +++ b/app/api/controller/User.php @@ -1253,4 +1253,6 @@ class User extends Base return $this->renderError('创建用户失败:' . $e->getMessage()); } } + + } \ No newline at end of file diff --git a/app/api/controller/Warehouse.php b/app/api/controller/Warehouse.php index 4b89f80..9a5aa85 100755 --- a/app/api/controller/Warehouse.php +++ b/app/api/controller/Warehouse.php @@ -760,7 +760,7 @@ class Warehouse extends Base $post_money = $post_money <= 0 ? 0 : $post_money; } #发货订单 - $send_num = create_order_no('FH_', 'order_list_send', 'send_num'); + // $send_num = create_order_no('FH_', 'order_list_send', 'send_num'); $redis = (new \app\common\server\RedisHelper())->getRedis(); $redis_key = "kpw_warehouse_send" . '_' . $user['id']; $redis_key_info = $redis->get($redis_key); @@ -770,6 +770,20 @@ class Warehouse extends Base $redis->set($redis_key, 1, 10); } Db::startTrans(); + $title = '背包发货' . $count . '件'; + $attach = 'order_list_send'; + $fa_money = $post_money; + if ($free_post <= $count || $post_money == 0) { + $fa_money = 0; + } + $payRes = \app\common\server\platform\PlatformFactory::createPay($user, $fa_money, $title, $attach, "FH_"); + if ($payRes['status'] !== 1) { + Db::rollback(); + #删除redis + $redis->del($redis_key); + return $this->renderError("支付失败,请刷新重试"); + } + $send_num = $payRes['data']['order_no']; #改变赏品信息 $res[] = OrderList::field('id,send_num') ->where('id', 'in', $order_list_id) @@ -780,6 +794,7 @@ class Warehouse extends Base ->update([ 'send_num' => $send_num, ]); + #生成订单 $res[] = $end_order_id = OrderListSend::insertGetId([ 'user_id' => $user_id, @@ -797,15 +812,13 @@ class Warehouse extends Base // // dd($free_post,$count); if ($free_post > $count && $post_money > 0) { - $body = '背包发货' . $count . '件'; - $attach = 'order_list_send'; - $payRes = (new Pay())->wxCreateOrder($send_num, $post_money, $user['id'], $body, $attach); + // $payRes = (new Pay())->wxCreateOrder($send_num, $post_money, $user['id'], $body, $attach); if ($payRes['status'] == 1) { #结果集 $new_data = [ 'status' => 1, 'order_no' => $send_num, - 'res' => $payRes['data'], + 'res' => $payRes['data']['res'], ]; } else { Db::rollback(); diff --git a/app/common.php b/app/common.php index 3206639..05141c2 100755 --- a/app/common.php +++ b/app/common.php @@ -328,8 +328,12 @@ if (!function_exists('create_order_no_new')) { function create_order_no_new($pre = "", $merchant_prefix = "", $project_prefix = "", $pay_type = "") { $pre = $pre . $merchant_prefix . $project_prefix . $pay_type; - $order_no = $pre . date('Ymd') . substr(implode('', array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8) . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT); - $r = Db::name('order')->field('id')->where(['order_num' => $order_no])->find(); + $order_no = $pre . date('Ymd') . substr(implode('', array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8) . str_pad(mt_rand(1, 999), 3, '0', STR_PAD_LEFT); + if ($pre == "FH_") { + $r = Db::name('order_list_send')->field('id')->where(['send_num' => $order_no])->find(); + } else { + $r = Db::name('order')->field('id')->where(['order_num' => $order_no])->find(); + } if ($r) { $order_no = create_order_no_new($pre, $merchant_prefix, $project_prefix, $pay_type); } diff --git a/app/common/server/platform/H5Platform.php b/app/common/server/platform/H5Platform.php index 26bd09c..eb9402d 100644 --- a/app/common/server/platform/H5Platform.php +++ b/app/common/server/platform/H5Platform.php @@ -1,5 +1,11 @@ code = 'WEB_H5'; $this->env = 'h5'; + Factory::setOptions($this->getOptions()); } + /** + * Summary of pay + * @param array $data + * @throws \Exception + * @return array|array{data: array, status: int} + */ public function pay(array $data): array { // echo "H5支付:{$amount}分,订单号:{$orderId}\n"; // 实际项目中这里调用支付SDK - return []; + + try { + $data += ['user' => null, 'price' => 0, 'title' => '', 'attach' => 'order_wxs', 'pre' => 'MH_']; + [ + 'user' => $user, + 'price' => $price, + 'title' => $title, + 'attach' => $attach, + 'pre' => $pre, + 'quitUrl' => $quitUrl, + 'returnUrl' => $returnUrl + ] = $data; + if ($user == null) { + //抛出异常 + throw new \Exception('用户信息为空'); + } + $project_prefix = "H5"; + if ($price <= 0) { + //生成订单号,订单号为:ML_DRAYDMP02025018.... ML_ 前缀(固定3位),DRA 商户号(固定3位),YD 项目,固定2位,MP0 表示微信小程序支付 + $order_no = create_order_no_new($pre, "MON", $project_prefix, "MP0"); + return [ + 'status' => 1, + 'data' => [ + 'order_no' => $order_no, + 'res' => [] + ] + ]; + } + $title = mb_substr($title, 0, 30); + + $prefix = "ZFA";//$this->GetPrefix(); + //生成订单号,订单号为:ML_DRAYDMP02025018.... ML_ 前缀(固定3位),DRA 商户号(固定3位),YD 项目,固定2位,MP0 表示微信小程序支付 + $order_no = create_order_no_new($pre, $prefix, $project_prefix, "ZFB"); + $openid = $user['openid']; + $payment_type = 'zfbpay'; + $order_type = $attach; + $user_id = $user ? $user['id'] : 0; + // 支付使用的随机数 + $nonce_str = $this->genRandomString(); + // 回调使用的随机数(与支付随机数分离) + $callback_nonce_str = $this->genRandomString(); + // 生成新的支付通知URL + $notifyUrl = generatePayNotifyUrl($payment_type, $order_type, $user_id, $order_no, $callback_nonce_str); + $is_test = $user['istest']; + if ($is_test == 2) { + $price = 0.01; + } + $returnUrl .= "&order_no=" . $order_no; + //2. 发起API调用(以支付能力下的统一收单交易创建接口为例) + $result = Factory::payment() + ->wap()->optional('notify_url', $notifyUrl) + ->pay( + $title, // 支付标题 + $order_no, // 商户订单号(唯一) + $price, // 金额 + $quitUrl,// 取消地址 + $returnUrl// 支付后返回地址 + ); + + // $result = Factory::payment()->faceToFace()->asyncNotify($notifyUrl)->common()->create("iPhone6 16G", "2020******5526001", $price, "2088******718920"); + + //3. 处理响应或异常 + if (!empty($result->body)) { + // echo "调用成功" . PHP_EOL; + // 将通知URL和随机字符串保存到order_notify表中 + Db::name('order_notify')->insert([ + 'order_no' => $order_no, + 'notify_url' => $notifyUrl, + 'nonce_str' => $callback_nonce_str, + 'pay_time' => date('Y-m-d H:i:s'), + 'pay_amount' => $price, + 'status' => 0, + 'retry_count' => 0, + 'create_time' => date('Y-m-d H:i:s'), + 'update_time' => date('Y-m-d H:i:s') + ]); + return [ + 'status' => 1, + 'data' => [ + 'order_no' => $order_no, + 'res' => $result->body + ] + ]; + } else { + return ['status' => 0, 'msg' => '支付失败:' . $result]; + } + } catch (\Exception $e) { + // echo "调用失败," . $e->getMessage() . PHP_EOL; + // ; + } + return ['status' => 0, 'msg' => '支付失败:']; } /** * 发货 @@ -67,4 +170,32 @@ class H5Platform extends BasePlatform return ['status' => 1, 'data' => ""]; } + + public function getOptions() + { + $options = new Config(); + $options->protocol = 'https'; + $options->gatewayHost = 'openapi.alipay.com'; + $options->signType = 'RSA2'; + + $options->appId = '2021005141643914'; + + // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中 + $options->merchantPrivateKey = 'MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCaFFYCEuN7z8DMToMI5j7dI+nQzsH3l/DCfKD6kMVQk1lOuwAtsOYu9dkfHUEcjygng9eFYVxv6xAmCLBaf4JeZQk+dObP31VYIRN+lyiec/zZHDwiuLWIJsoIEos9BIWhtbayeNWfhFgNcR0K6KLx4j7M+F02GOkmXTDVpQC1whcafM2ASm3WJvYabpTpqnRnIbUltOIU5a0HluHXz6Q29jQXg0aCeB3R2rkHZIGNj3GuY9vFey6yFKc4EvKpc/BaFnhS46W8J6dRa2pcHQehGNX+tI/7clScf2+Ccj6K94r0PxFbzTUTS0zCoeZY5jDmVr7rxzXZzVrJmK+MgLdBAgMBAAECggEBAILwy1MB2F8s5Ez8X/FdMolebuMsAr02W738ihXGmFjskBYPZ4xs7IF2HumJQ/9QTbCfI7ZPUm4uVs/rzGtsN0+fD6cLU+fOhUna+iU3sqZOLdAYZaagUG1/gWwwzjGxuRr/QV8Uv37LysTJnwPZRjjHq9UnMJe7vdADnG/DxQGws+XfF0/6ysnzWwJGs/F/yQPJgmhanvfub6XnenYGzsYQTFevU4SqtEkM729FRTgC1OYkZKAMY1FwYmEIwfwb4Ay9PRhUDU7EKsnkeQWYT1HeqdnA6/5qKyDSAyow+0QF25iEbvEFrTri993rRkIf5c37Meusb7FvBv6CYjtWIm0CgYEA7ywWcylyo+YzJ1HJvldyc7aWz1s3WEWYJVGZHgLaNTxh+hp90iiD5Zae/7K1n69w52685fSv4ZS0MEluww5M+POkwv8wjcbwixd4MOuZ6aLaj5TK38NZ8GSHXdKxv6Vg6d1mQ6ryOJiSSTBKqzBXvMbPgjP20ra4LJ08F/8to4MCgYEApOuT4BrsRryv9tIWG5hm+ecRaFl7SzQS53eq0MXvrf4JBCQQr/Qo4a0wEwQamSCZA2Ec89ZLygBesh5xpdPkP34spIKvF3w6xpNazSySAWgrOCrYh+pxH6rCrAtET5qS1GlgUaKC+NYeLI3hq8+xPEDy+7qvZr7w3ciFKon9iusCgYAgePnrVNtNyXl0gzRC9ZiCgW3kZVwUTg6kMnn5iyWZSMN8s5AVso6F43de/CKQtb88jNp01k3y8L+uNqolLZHh0yKxnvg2p6YNHHijG7nf8M5/5BHPY7SYYO3IHU0o2glYd0jlMxaD/KMP8NCSgZPH+6483VVLsqc613ZLQ8gshQKBgQCc9AJo3taMv5hruycFHjaqkMkVWUuol6eCGHY9eJMRMNod0cD7489gb7V384jowIg/GhY2zXSVi2KT+7tHCXCJKKiN7D18iWNahvR8nXVa12uCaexm9ayxaY8ZsyNQ6xfgBWWAa7xf208eMe1a2S+g22MkRVgW3ZNYTzTE9kyQ/wKBgQDjErfoFCFawa0qJvP+mHgtR+hcypc6rdYskcqzp6oOaBIjk87Rip+ZT1CRO6vyfo7DCKZGLAT4UTGVgx4tHyuxVsHbNgpuQ7IXmB6uM+g569VAJtfciGwf+rVblw6CJxlFF/2WhuszhCmqlX2/Ddboob62g5rF/2RQYwUpRBI7TA=='; + + // $options->alipayCertPath = '<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->'; + // $options->alipayRootCertPath = '<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt" -->'; + // $options->merchantCertPath = '<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->'; + + //注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可 + $options->alipayPublicKey = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlAGEC6+urK0+aC3HGy1KqxqK2lD8G+0/oNN3AcZpsXrztMNHbSpfw9zdea1jldF5HZsFD5JH/mb3ngMaepry/DnEyTpxqVfeBfWDhXgM+isQqm8mc/SpX4W1uh0edXh984U0YHNabg+HKdc4EdXpIW/0bRBUjmDQJPLDl6vjn7aFU1KTFSo06+e5PsVAwZuYZTEsgqn05zZxh+nccLVsjO64Kywv6NbbZRFRG3Dxequ35gRHtZOUvzt5o8bzpEnH0/8lNJqVtfpu41tFxinSdH8R4WFa8YKPqLqRnxCw7o5pTuznS2akOhPQ7ElO5tvotgFwOfVUGc/7yXxizGVgMwIDAQAB'; + //可设置异步通知接收服务地址(可选) + //如果需要使用文件上传接口,请不要设置该参数 + $options->notifyUrl = ""; + + //可设置AES密钥,调用AES加解密相关接口时需要(可选) + // $options->encryptKey = "<-- 请填写您的AES密钥,例如:aa4BtZ4tspm2wnXLb1ThQA== -->"; + return $options; + } + } \ No newline at end of file diff --git a/app/common/server/platform/MiniProgramPlatform.php b/app/common/server/platform/MiniProgramPlatform.php index 9ca8fbc..e8c329a 100644 --- a/app/common/server/platform/MiniProgramPlatform.php +++ b/app/common/server/platform/MiniProgramPlatform.php @@ -159,7 +159,10 @@ class MiniProgramPlatform extends BasePlatform } else { $error_message = '微信支付接口返回异常'; } - // $redis = (new \app\common\server\RedisHelper())->getRedis(); + + // 获取Redis实例 + $redis = (new \app\common\server\RedisHelper())->getRedis(); + // 记录到ThinkPHP的日志系统中 Log::error('微信支付失败: ' . json_encode([ 'order_no' => $order_no, @@ -170,6 +173,58 @@ class MiniProgramPlatform extends BasePlatform 'result' => $result, 'time' => date('Y-m-d H:i:s') ], JSON_UNESCAPED_UNICODE)); + + // 获取当前商户ID + $merchant_id = $this->getMchId(); + + // 记录支付失败信息到Redis + if ($merchant_id) { + // 商户支付失败计数的key,使用12小时过期时间 + $merchant_fail_key = 'merchant:payment:fail:' . $merchant_id; + + // 将失败信息存入列表 + $fail_info = [ + 'merchant_id' => $merchant_id, + 'order_no' => $order_no, + 'time' => time(), + 'error' => $error_message + ]; + + // 添加到失败列表 + $redis->rPush($merchant_fail_key, json_encode($fail_info)); + + // 设置过期时间为12小时 + $redis->expire($merchant_fail_key, 12 * 3600); + + // 获取当前列表长度 + $fail_count = $redis->lLen($merchant_fail_key); + + // 如果12小时内失败次数达到10次,临时停用该商户 + if ($fail_count >= 10) { + // 商户临时停用标记 + $disable_key = 'merchant:payment:disabled:' . $merchant_id; + + // 记录停用信息 + $disable_info = [ + 'merchant_id' => $merchant_id, + 'disable_time' => time(), + 'disable_reason' => '12小时内支付失败次数超过10次,系统自动临时停用', + 'auto_disabled' => true + ]; + + // 设置商户停用标记,默认停用12小时 + $redis->set($disable_key, json_encode($disable_info)); + $redis->expire($disable_key, 12 * 3600); + + // 记录停用日志 + Log::warning('商户支付功能临时停用: ' . json_encode([ + 'merchant_id' => $merchant_id, + 'fail_count' => $fail_count, + 'disable_time' => date('Y-m-d H:i:s'), + 'expire_time' => date('Y-m-d H:i:s', time() + 12 * 3600) + ], JSON_UNESCAPED_UNICODE)); + } + } return ['status' => 0, 'msg' => '支付失败:' . $error_message]; } @@ -517,6 +572,68 @@ class MiniProgramPlatform extends BasePlatform return $this->mch_id; } + /** + * 切换到备选商户 + * 当当前商户被停用时调用此方法 + */ + private function switchToAlternativeMerchant(): void + { + if (empty($this->mp_miniprogram) || + empty($this->mp_miniprogram['merchants']) || + !is_array($this->mp_miniprogram['merchants'])) { + return; + } + + $weixinpay_setting = getConfig('weixinpay_setting'); + if (empty($weixinpay_setting['merchants']) || !is_array($weixinpay_setting['merchants'])) { + return; + } + + // 当前被停用的商户ID + $current_disabled_mch_id = $this->mch_id; + $redis = (new \app\common\server\RedisHelper())->getRedis(); + + // 过滤出启用且未被临时停用的商户 + $available_merchants = array_values(array_filter($weixinpay_setting['merchants'], function ($merchant) use ($redis, $current_disabled_mch_id) { + // 跳过当前被停用的商户 + if ($merchant['mch_id'] == $current_disabled_mch_id) { + return false; + } + + // 检查商户是否被启用且在小程序配置中 + if (isset($merchant['is_enabled'], $merchant['mch_id']) && + $merchant['is_enabled'] === "1" && + in_array($merchant['mch_id'], $this->mp_miniprogram['merchants'])) { + + // 检查商户是否被临时停用 + $disable_key = 'merchant:payment:disabled:' . $merchant['mch_id']; + if (!$redis->exists($disable_key)) { + return true; // 商户可用 + } + } + + return false; // 商户不可用 + })); + + // 如果有可用商户,随机选择一个 + if (!empty($available_merchants)) { + $merchant = WxPayHelper::getRandomMerchant($available_merchants); + $this->mp_merchant = $merchant; + $this->mch_id = $merchant['mch_id']; + $this->key = $merchant['keys']; + + // 记录商户切换日志 + Log::info('成功切换到备选商户: ' . json_encode([ + 'from_merchant' => $current_disabled_mch_id, + 'to_merchant' => $this->mch_id, + 'switch_time' => date('Y-m-d H:i:s') + ], JSON_UNESCAPED_UNICODE)); + } else { + // 没有可用的备选商户,记录警告日志 + Log::warning('没有可用的备选商户,将继续使用当前商户: ' . $current_disabled_mch_id); + } + } + /** * 获取 key(延迟加载) */ @@ -555,17 +672,91 @@ class MiniProgramPlatform extends BasePlatform return; } - $associatedMerchants = array_values(array_filter($weixinpay_setting['merchants'], function ($merchant) { - return isset($merchant['is_enabled'], $merchant['mch_id']) && + // 获取Redis实例检查临时禁用状态 + $redis = (new \app\common\server\RedisHelper())->getRedis(); + + // 过滤掉被禁用的商户 + $associatedMerchants = array_values(array_filter($weixinpay_setting['merchants'], function ($merchant) use ($redis) { + // 基本条件:商户已启用且在小程序配置中 + $basicCondition = isset($merchant['is_enabled'], $merchant['mch_id']) && $merchant['is_enabled'] === "1" && in_array($merchant['mch_id'], $this->mp_miniprogram['merchants']); + + // 如果不满足基本条件,直接排除 + if (!$basicCondition) { + return false; + } + + // 检查商户是否被临时禁用 + $disable_key = 'merchant:payment:disabled:' . $merchant['mch_id']; + if ($redis->exists($disable_key)) { + // 商户被临时禁用,记录日志 + $disabled_info = $redis->get($disable_key); + $disabled_info = $disabled_info ? json_decode($disabled_info, true) : []; + + Log::info('加载商户时跳过被临时禁用的商户: ' . json_encode([ + 'merchant_id' => $merchant['mch_id'], + 'disabled_time' => isset($disabled_info['disable_time']) ? date('Y-m-d H:i:s', $disabled_info['disable_time']) : '未知', + 'reason' => $disabled_info['disable_reason'] ?? '未知原因' + ], JSON_UNESCAPED_UNICODE)); + + return false; // 商户被禁用,排除 + } + + return true; // 商户可用 })); + // 如果没有可用的未禁用商户,则使用所有启用的商户(忽略临时禁用状态) + if (empty($associatedMerchants)) { + Log::warning('没有未禁用的可用商户,将加载所有启用的商户(忽略临时禁用状态)'); + + // 重新筛选商户,只考虑是否启用,忽略临时禁用状态 + $associatedMerchants = array_values(array_filter($weixinpay_setting['merchants'], function ($merchant) { + return isset($merchant['is_enabled'], $merchant['mch_id']) && + $merchant['is_enabled'] === "1" && + in_array($merchant['mch_id'], $this->mp_miniprogram['merchants']); + })); + + // 记录被禁用但仍将使用的商户 + foreach ($associatedMerchants as $merchant) { + $disable_key = 'merchant:payment:disabled:' . $merchant['mch_id']; + $redis = (new \app\common\server\RedisHelper())->getRedis(); + + if ($redis->exists($disable_key)) { + $disabled_info = $redis->get($disable_key); + $disabled_info = $disabled_info ? json_decode($disabled_info, true) : []; + + Log::warning('由于没有可用商户,将使用被临时禁用的商户: ' . json_encode([ + 'merchant_id' => $merchant['mch_id'], + 'disabled_time' => isset($disabled_info['disable_time']) ? date('Y-m-d H:i:s', $disabled_info['disable_time']) : '未知', + 'reason' => $disabled_info['disable_reason'] ?? '未知原因', + 'time' => date('Y-m-d H:i:s') + ], JSON_UNESCAPED_UNICODE)); + } + } + } + if (!empty($associatedMerchants)) { $merchant = WxPayHelper::getRandomMerchant($associatedMerchants); $this->mp_merchant = $merchant; $this->mch_id = $merchant['mch_id']; $this->key = $merchant['keys']; + + // 检查选中的商户是否被临时禁用 + $disable_key = 'merchant:payment:disabled:' . $this->mch_id; + $redis = (new \app\common\server\RedisHelper())->getRedis(); + $isDisabled = $redis->exists($disable_key); + + // 记录选择的商户 + Log::debug('已选择支付商户: ' . json_encode([ + 'merchant_id' => $this->mch_id, + 'order_prefix' => $merchant['order_prefix'] ?? '', + 'is_disabled' => $isDisabled ? '是(临时禁用被忽略)' : '否', + 'time' => date('Y-m-d H:i:s') + ], JSON_UNESCAPED_UNICODE)); + } else { + // 没有可用商户,记录警告 + Log::warning('没有可用的支付商户,请检查商户配置或临时禁用状态'); } } diff --git a/app/common/server/platform/PlatformFactory.php b/app/common/server/platform/PlatformFactory.php index 0adaa4c..660cfbb 100644 --- a/app/common/server/platform/PlatformFactory.php +++ b/app/common/server/platform/PlatformFactory.php @@ -32,15 +32,26 @@ class PlatformFactory */ public static function createPay($user, $price, $title, $attach, $pre = "MH_", $pay_type = 1, $client = null): array { + if (!isset($client)) { + $client = request()->header('client', 'MP-WEIXIN'); + } $data = [ 'user' => $user, 'price' => $price, 'title' => $title, 'attach' => $attach, 'pre' => $pre, - 'pay_type' => $pay_type + 'pay_type' => $pay_type, + 'quitUrl' => '', + 'returnUrl' => '' ]; $platform = self::create($client); + if ($client == "WEB_H5") { + $quitUrl = request()->param('quitUrl', ''); + $returnUrl = request()->param('returnUrl', ''); + $data['quitUrl'] = $quitUrl; + $data['returnUrl'] = $returnUrl; + } return $platform->pay($data); } } \ No newline at end of file