This commit is contained in:
youda 2025-05-23 15:46:19 +08:00
parent 783a04dae6
commit 7cbef78015
9 changed files with 388 additions and 8 deletions

View File

@ -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);
}
}

View File

@ -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); // 返回成功避免重复通知

View File

@ -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']);
}

View File

@ -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福利屋
#============================

View File

@ -0,0 +1,303 @@
<?php
namespace app\common\server\platform;
use Alipay\EasySDK\Kernel\Factory;
use Alipay\EasySDK\Kernel\Config;
use app\common\model\User;
use think\App;
use think\facade\Db;
use think\facade\Log;
use app\common\model\Order;
use app\common\model\OrderNotify;
use app\common\helper\EnvHelper;
use think\facade\Request;
/**
* 多端平台支付抽象基类
*/
class AppPlatform extends BasePlatform
{
public function __construct()
{
parent::__construct();
$this->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;
}
}

View File

@ -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;
/**
* 普通方法(子类自动继承)
*/

View File

@ -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) {

View File

@ -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;
}
/**
* 实际加载商户信息

View File

@ -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('订单号错误');
}
}