From 7cbef7801510b007a1948035de27a944391267f9 Mon Sep 17 00:00:00 2001 From: youda Date: Fri, 23 May 2025 15:46:19 +0800 Subject: [PATCH] 222 --- app/api/controller/Config.php | 12 +- app/api/controller/Notify.php | 4 +- app/api/controller/Order.php | 2 +- app/api/route/app.php | 2 + app/common/server/platform/AppPlatform.php | 303 ++++++++++++++++++ app/common/server/platform/BasePlatform.php | 14 + app/common/server/platform/H5Platform.php | 10 +- .../server/platform/MiniProgramPlatform.php | 19 +- .../server/platform/PlatformFactory.php | 30 ++ 9 files changed, 388 insertions(+), 8 deletions(-) create mode 100644 app/common/server/platform/AppPlatform.php diff --git a/app/api/controller/Config.php b/app/api/controller/Config.php index 7729fe6..131d688 100755 --- a/app/api/controller/Config.php +++ b/app/api/controller/Config.php @@ -29,5 +29,15 @@ class Config extends Base 'version' => '111' ]); } - + /** + * 获取平台配置 + * @return \think\response\Json + */ + public function getPlatformConfig() + { + $platform = \app\common\server\platform\PlatformFactory::create(); + $config = $platform->get_config(); + return $this->renderSuccess("", $config); + } + } \ No newline at end of file diff --git a/app/api/controller/Notify.php b/app/api/controller/Notify.php index 6a0c2be..9d354c0 100755 --- a/app/api/controller/Notify.php +++ b/app/api/controller/Notify.php @@ -2716,8 +2716,8 @@ class Notify extends Base } if ($payment_type == "zfbpay") { $postData = request()->post(); - $h5 = new \app\common\server\platform\H5Platform(); - $zfb_result = $h5->verify($order_num, $postData); + $platform = \app\common\server\platform\PlatformFactory::getOrderNumPlatform($order_num); + $zfb_result = $platform->verify($order_num, $postData); if (!$zfb_result) { writelog('pay_notify_error', "支付宝支付验证失败: " . $order_num); $this->CallbackSuccess_new($payment_type); // 返回成功避免重复通知 diff --git a/app/api/controller/Order.php b/app/api/controller/Order.php index ec84c53..c473af7 100644 --- a/app/api/controller/Order.php +++ b/app/api/controller/Order.php @@ -151,7 +151,7 @@ class Order extends Base $platform = \app\common\server\platform\PlatformFactory::create(); $res = $platform->sendCustomerServiceMessage($user, $orderNum); if ($res['status'] == 1) { - return $this->renderSuccess('发送成功'); + return $this->renderSuccess('发送成功',$res['data']); } else { return $this->renderError($res['msg']); } diff --git a/app/api/route/app.php b/app/api/route/app.php index b69e577..46a6bf2 100755 --- a/app/api/route/app.php +++ b/app/api/route/app.php @@ -181,6 +181,8 @@ Route::rule('goods_receive_sync', 'Goods/receive_sync', 'POST'); // 配置信息接口 Route::rule('config', 'Config/index', 'GET'); +Route::rule('getPlatformConfig', 'Config/getPlatformConfig', 'GET'); + #============================ #WelfareHouse.php福利屋 #============================ diff --git a/app/common/server/platform/AppPlatform.php b/app/common/server/platform/AppPlatform.php new file mode 100644 index 0000000..d30f8df --- /dev/null +++ b/app/common/server/platform/AppPlatform.php @@ -0,0 +1,303 @@ +code = 'APP_ANDROID'; + $this->env = 'app'; + Factory::setOptions($this->getOptions()); + } + + /** + * 获取系统配置 + * @return void + */ + public function get_config(): array + { + return ['isWebPay' => false]; + } + /** + * 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 + + 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 = "AD"; + if ($price <= 0) { + //生成订单号,订单号为:ML_DRAYDMP02025018.... ML_ 前缀(固定3位),DRA 商户号(固定3位),YD 项目,固定2位,MP0 表示微信小程序支付 + $order_no = create_order_no_new($pre, "MON", $project_prefix, "APP"); + return [ + 'status' => 1, + 'data' => [ + 'order_no' => $order_no, + 'res' => [] + ] + ]; + } + + $prefix = "ZFA";//$this->GetPrefix(); + $config = $this->get_config(); + if ($config['isWebPay']) { + $domain = Request::domain(); + // Request::param('return_url') + $host = parse_url($domain, PHP_URL_HOST); + $order_no = create_order_no_new($pre, "ZFA", 'H5', "ZFB"); + $extend = [ + 'orderType' => $attach, + ]; + $extend_str = json_encode($extend, JSON_UNESCAPED_UNICODE); + // 将通知URL和随机字符串保存到order_notify表中 + Db::name('order_notify')->insert([ + 'order_no' => $order_no, + 'notify_url' => '', + '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'), + 'extend' => $extend_str, + 'title' => $title, + ]); + return [ + 'status' => 1, + 'data' => [ + 'order_no' => $order_no, + 'res' => ['data' => ['order_num' => $order_no], 'requestPay' => $domain . '/api/send_web_pay_order', 'tips' => ''] + ] + ]; + } + $title = mb_substr($title, 0, 30); + + + //生成订单号,订单号为: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; + // 回调使用的随机数(与支付随机数分离) + $callback_nonce_str = $this->genRandomString(); + // 生成新的支付通知URL + $notifyUrl = generatePayNotifyUrl($payment_type, $order_type, $user_id, $order_no, $callback_nonce_str); + $is_env_test = EnvHelper::getIsTest(); + if ($is_env_test) { + $is_test = $user['istest']; + if ($is_test == 2) { + $price = 0.01; + } + } + $returnUrl = urldecode($returnUrl); + //2. 发起API调用(以支付能力下的统一收单交易创建接口为例) + $result = Factory::payment() + ->app() + ->asyncNotify($notifyUrl) + ->pay( + $title, // 支付标题 + $order_no, // 商户订单号(唯一) + $price, // 金额 + $quitUrl,// 取消地址 + $returnUrl// 支付后返回地址 + ); + //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'), + 'title' => $title, + ]); + 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' => '支付失败:']; + } + + + /** + * 客服发送消息 + * @param mixed $user_id + * @param mixed $order_num + * @return array{status: int, data: array, msg: string} + */ + public function sendCustomerServiceMessage($user, $order_num): array + { + // 获取订单编号 + $return_url = Request::param('return_url', ''); + + + $message = "用户ID:{$user['id']},订单号:{$order_num}"; + $order_title = ''; + $order_price = 0; + if ($user['openid'] == null) { + return ['status' => 0, 'msg' => '用户openid为空']; + } + $orderNotify = OrderNotify::where([ + 'order_no' => $order_num, + ])->find(); + $extend = []; + if ($orderNotify) { + if ($orderNotify['extend'] != '') { + $extend = json_decode($orderNotify['extend'], true); + } + $order_title = $orderNotify['title']; + $order_price = $orderNotify['pay_amount']; + } + if ($order_title == "") { + return ['status' => 0, 'msg' => '订单号错误']; + } + + // $this->appid + $web_domain = EnvHelper::getWebDomain(); + $extend['returnUrl'] = $return_url; + $extend['openId'] = $user['openid']; + $extend['userId'] = $user['id']; + $extend_str = json_encode($extend, JSON_UNESCAPED_UNICODE); + OrderNotify::where('order_no', $order_num)->update(['extend' => $extend_str]); + return ['status' => 1, 'data' => $web_domain . '/pages/other/web-pay-order?order_num=' . $order_num]; + + } + + /** + * 发货 + * @param mixed $openid + * @param mixed $access_token + * @param mixed $order_num + * @param mixed $title + * @return int + */ + public function post_order($user, $order_num): int + { + + return 1; + } + + public function verify($order_no, $data): bool + { + $result = Factory::payment()->common()->verifyNotify($data); + if ($result) { + return true; + } + return false; + } + + /** + * 生成URL链接 + * @param int $userId 用户ID + * @return array + */ + public function generateUrlLink($userId): array + { + + return ['status' => 1, 'data' => ""]; + } + + /** + * 获取手机号 + * @param string $code 手机号获取凭证 + * @return array + */ + public function getMobile($code = ''): array + { + + + return ['status' => 1, 'data' => ""]; + } + + /** + * 获取openid + * @param string $code 登录凭证 + * @return array + */ + public function getOpenid($code): array + { + + return ['status' => 1, 'data' => ""]; + } + + + + public function getOptions() + { + $options = new Config(); + $options->protocol = 'https'; + $options->gatewayHost = 'openapi.alipay.com'; + $options->signType = 'RSA2'; + + $options->appId = '2021005153608270'; + + // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中 + $options->merchantPrivateKey = 'MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDt4poXku4KIym89gds3U6nbzLUxky1x47G8cgloYdIObXDV8oDPiPVf7kaJGcVU5R3eU7myJHEkurlAnSzb40oyg2xV5qsHjjV4AO/9v5VPCQNl5qbL83PYC79eh7z4vGOwitSK3AjHilQJkeD8WNaX6D/UMZKz4KcXbcNbBjnu9FvwpiVwY6HZPxrTlR5QTxxuPWVUAbnMkBP9nLys0jMrIShns+PA4GD7Jhx32SUwMPwmjTmv93CR1KTgKe1I0WQgkCG2/5nyD2j+hm1SFC/5rnF0dElZbJcZxIXgvyyTEdbNuf2mzaVYpFZNSc6v/kQKCevL3sNPfHy5XWqFydxAgMBAAECggEBANyV6rN/cLH/xz1MmrgNQ1kpWOZK92j8ol3CaAjVDuAfe3enWVDGd24LYLZoGRqChUKAP3TreZfhcGVpcJPPFgND0YyoImoGIEfa0T9Zpp+dBAWClj/fBSaOFyS+8CLRR5NMY+VvGC3IUyDaTiiAVtO/p0f5O9a1M3URxaNxoGqISlMxpn/LIyWc1elpT2/RY0nkKQCXk2rav3yZZe9+td1ESHtKOFE4l9qPAP6H9AaE401qKhASa8vuLm1nUE35XqoGSxASLnckAq3Z+v6WnO2rli59DMiFFB45+XJxMSwumdfpKxsI/OO/VXBwpgNaLGXBO47op8SxqswYZiVRyVECgYEA9xK1SmCbGjyUJAiJI77zF3SQotz39PK2pe1l+5YUXTGRx5D9iOR9o2zMfHwlgGpPWB9XJU23ZOjPhNsz0pGXTfEelp0VJtmbX1SqKjGhAZ+sJxMmY5iP72MFfu+aIsfPnWPh3G9s2fDGxlmoXnCKbptrgM7T3TRsRPPx+7zvZ+0CgYEA9nrpGIipOn0n2lxHH1eSlLVYMvRT/gt1EWePlWXK/7D71iCL09SdbY1DKvZxRwcd+c3LBuTI+zWJiW+8b78B7Z/mMntoQokbB3EMM/C3voVfsuCOSea5ARDNbgQ0pRFw9Qov/dLlliDdYrSKiYJYwjnfXKE+qTX9dXNOAK2cBRUCgYEA7mAwZSg7vN6BlxpdJg3O/+xIt7k1yjB6JDCdWlR8JUXz/nVXB8JbrVcFG32zuOfY0Y67R5RpwoQT43yRzTEGp/5gorO/epIso5dN7hOf4a8qKzEAssq45B/HZ6bIMZJSLun1OfaPMN5rCWfrV+KAzSJKYCYsppkzdHtgFp885CkCgYEA9Kf0D+I2+FOa52iJQFcQrIOE1K8pYBXHUktVfpnX8g2fLGCJ6u40hbWeYlrU/gfWfUsEqAcYaCIwLze198XFCDWbrahJSSIGrlBMKJJcEMUaxNeY5UobgS9Iele6Wc8CLHi8QlrAgVCF75/9k5jKuZ/wUmXLaPKqb5bQamPpZjECgYEAuSTyMwJmOTLJ/LRGCzVKOUEetfjQU+RhDvp7K/9zAuhUx9iY869lzIdCV9gzrk92+inhmTxXBxxM+zcml7VfHxbsNoG0jnlMtC7f4jdzg1qMhk3vPlRDIC+TIB/kaNu+lAScg3BzYSniKVBu9zwZ1OIlVWFwAKNvBGXtRSdUN7k='; + + // $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/BasePlatform.php b/app/common/server/platform/BasePlatform.php index 8577e22..9b7d17f 100644 --- a/app/common/server/platform/BasePlatform.php +++ b/app/common/server/platform/BasePlatform.php @@ -14,6 +14,11 @@ abstract class BasePlatform $this->code = ''; $this->env = ''; } + /** + * 获取系统配置 + * @return void + */ + abstract public function get_config(): array; /** * 抽象方法:支付(子类必须实现) @@ -47,6 +52,15 @@ abstract class BasePlatform * @return void */ abstract public function getMobile($code = ''): array; + /** + * 验证加签 + * @param mixed $order_no + * @param mixed $data + * @return void + */ + abstract function verify($order_no, $data): bool; + + /** * 普通方法(子类自动继承) */ diff --git a/app/common/server/platform/H5Platform.php b/app/common/server/platform/H5Platform.php index ca86f55..4eec5c1 100644 --- a/app/common/server/platform/H5Platform.php +++ b/app/common/server/platform/H5Platform.php @@ -22,6 +22,14 @@ class H5Platform extends BasePlatform $this->env = 'h5'; Factory::setOptions($this->getOptions()); } + /** + * 获取系统配置 + * @return void + */ + public function get_config(): array + { + return ['isWebPay' => false]; + } /** * Summary of pay @@ -136,7 +144,7 @@ class H5Platform extends BasePlatform return 1; } - public function verify($order_no, $data) + public function verify($order_no, $data): bool { $result = Factory::payment()->common()->verifyNotify($data); if ($result) { diff --git a/app/common/server/platform/MiniProgramPlatform.php b/app/common/server/platform/MiniProgramPlatform.php index 68a3342..7aeabef 100644 --- a/app/common/server/platform/MiniProgramPlatform.php +++ b/app/common/server/platform/MiniProgramPlatform.php @@ -61,6 +61,14 @@ class MiniProgramPlatform extends BasePlatform $this->wx_secret = $this->mp_miniprogram['app_secret']; } } + /** + * 获取系统配置 + * @return void + */ + public function get_config(): array + { + return ['isWebPay' => true]; + } /** * Summary of pay [$user,$price,title,attach] * @param mixed $data @@ -114,11 +122,12 @@ class MiniProgramPlatform extends BasePlatform $title = mb_substr($title, 0, 30); $prefix = $this->GetPrefix(); - if (true) { + $mp_config = $this->get_config(); + if ($mp_config['isWebPay']) { $domain = Request::domain(); // Request::param('return_url') $host = parse_url($domain, PHP_URL_HOST); - $order_no = create_order_no_new($pre, "ZFA", 'MP', "ZFB"); + $order_no = create_order_no_new($pre, "ZFA", 'H5', "ZFB"); $extend = [ 'orderType' => $attach, ]; @@ -353,7 +362,7 @@ class MiniProgramPlatform extends BasePlatform //发送成功,退出循环 $extend_str = json_encode($extend, JSON_UNESCAPED_UNICODE); OrderNotify::where('order_no', $order_num)->update(['extend' => $extend_str]); - return ['status' => 1, 'data' => $result]; + return ['status' => 1, 'data' => '']; } // 记录响应结果日志 @@ -831,6 +840,10 @@ class MiniProgramPlatform extends BasePlatform return $this->mp_merchant['order_prefix']; } + public function verify($order_no, $data): bool + { + return true; + } /** * 实际加载商户信息 diff --git a/app/common/server/platform/PlatformFactory.php b/app/common/server/platform/PlatformFactory.php index 33d4af7..cb1f1b8 100644 --- a/app/common/server/platform/PlatformFactory.php +++ b/app/common/server/platform/PlatformFactory.php @@ -22,6 +22,12 @@ class PlatformFactory if ($client == "WEB_APP") { return new H5Platform(); } + if ($client == "APP_ANDROID") { + return new AppPlatform(); + } + if ($client == "APP_IOS") { + return new AppPlatform(); + } if ($client == "MP-WEIXIN") { return new MiniProgramPlatform(); } @@ -57,4 +63,28 @@ class PlatformFactory } return $platform->pay($data); } + + /** + * 根据订单号获取平台实例 + * @param string $order_num 订单号 + * @return BasePlatform 平台实例 + */ + public static function getOrderNumPlatform($order_num = null): BasePlatform + { + + if ($order_num == null) { + throw new \Exception('订单号不能为空'); + } + $platform = substr($order_num, 6, 2); + if ($platform == "H5") { + return new H5Platform(); + } + if ($platform == "MP") { + return new MiniProgramPlatform(); + } + if ($platform == "AD") { + return new AppPlatform(); + } + throw new \Exception('订单号错误'); + } } \ No newline at end of file