目录
3.2 APP客户端用3-1-1中返回的参数去调起支付宝和微信支付进行支付
1.composer安装yansongda SDK
composer require yansongda/pay:~3.7.0 -vvv
composer require guzzlehttp/guzzle:^7.0
composer require hyperf/pimple:~2.2.0 # 或者 composer require illuminate/container
2.支付所需参数配置文件内容参考
文件位置 "根目录/config/pay.php"
<?php
use think\facade\Request;
use Yansongda\Pay\Pay;
return [
'wechat'=> [
'default' => [
// 必填-商户号,服务商模式下为服务商商户号
// 可在 https://pay.weixin.qq.com/ 账户中心->商户信息 查看
'mch_id' => 'zzz',
// 选填-v2商户私钥
'mch_secret_key_v2' => '',
// 必填-v3 商户秘钥
// 即 API v3 密钥(32字节,形如md5值),可在 账户中心->API安全 中设置
'mch_secret_key' => '',
// 必填-商户私钥 字符串或路径
// 即 API证书 PRIVATE KEY,可在 账户中心->API安全->申请API证书 里获得
// 文件名形如:apiclient_key.pem
'mch_secret_cert' => realpath(app()->getRootPath().'public/cert/alipayCertPublicKey_RSA2.crt'),
// 必填-商户公钥证书路径
// 即 API证书 CERTIFICATE,可在 账户中心->API安全->申请API证书 里获得
// 文件名形如:apiclient_cert.pem
'mch_public_cert_path' => '',
// 必填-微信回调url
// 不能有参数,如?号,空格等,否则会无法正确回调
'notify_url' => Request::domain(). '/api/pay/notifyWxPay',
// 选填-公众号 的 app_id
// 可在 mp.weixin.qq.com 设置与开发->基本配置->开发者ID(AppID) 查看
'mp_app_id' => '2016082000291234',
// 选填-小程序 的 app_id
'mini_app_id' => '',
// 选填-app 的 app_id
'app_id' => '',
// 选填-服务商模式下,子公众号 的 app_id
'sub_mp_app_id' => '',
// 选填-服务商模式下,子 app 的 app_id
'sub_app_id' => '',
// 选填-服务商模式下,子小程序 的 app_id
'sub_mini_app_id' => '',
// 选填-服务商模式下,子商户id
'sub_mch_id' => '',
// 选填-微信平台公钥证书路径, optional,强烈建议 php-fpm 模式下配置此参数
'wechat_public_cert_path' => [
'45F59D4DABF31918AFCEC556D5D2C6E376675D57' => __DIR__.'/Cert/wechatPublicKey.crt',
],
// 选填-默认为正常模式。可选为: MODE_NORMAL, MODE_SERVICE
'mode' => Pay::MODE_NORMAL,
]
],
'alipay'=>[
'default' => [
// 必填-支付宝分配的 app_id
'app_id' => '你的实际app_id',
// 必填-应用私钥 字符串或路径
// 在 https://open.alipay.com/develop/manage 《应用详情->开发设置->接口加签方式》中设置
'app_secret_cert' => 'MIIEvQIBADANBgkqhkiaaG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCCFUrQVV244Zfygo8FqMMCc7on6o585o98CephLgNWlBrXwbn1nIILNPfCsm+j6zmV9hhdlbuDXvVHyLFLx/MexzOap5RcKhOg2xURE/Rmze3GrOFjGlmxldkt4QVbS2C3P8Kqes5cGHpYaHxmq7AkQ1gILVhOTE8aBMlBh7Zt8CDuBO17kEBPJLpl/Dr+//khOOvB0pxX4hJk6KBR8aiBq66K2GZ3Z8EcAwnUaYdBkEqc7rWGLNUk+Zk9l4PfFdJRJLz5h8bPpTIzo1bNTSUw4bDVwhCT5AprLw7vt3Gl9RxcgvHP37tsdz0FsXGtNlmNArvavrSC94OQx8tQF7s9AgMBAAECggEAF9SavgvFfacmVPECDoFaKErXIZTgwZTjWE/gtijdx7CeMkR1Mr+XO0Ja2TojJZ5kEErjL9HMZkaxHJNxl3Zr3YmUtJJapX+31NINy/Eh5ut20dy99Y/QOq4++R6uAomOkEOH//87are5QhTyJUTyodIMgIL+GGn2W8fgrraT/xOpnBBvCLPlV2RNy6tF3DDSfAgS4yYlcRmoaCyXSEMMCUWhrQJxAKZ6pR1UmgMXh/y+YiymomyOyrZMmtjaISbzsB4H1UHVIM68bN3j8tKM79cvtZ0gyR23bSGMsjOYH6MgO8G7YTpv8H8ws7a6SXVlnCn2/NKlWMatCIh/nIjFaQKBgQDBOL1efuYqCyAKwsLQ5wQzLDVTC4bL2IJFdbphzUzzNumY/pO7CRagIOLnL1MdkuM9aUNbaW26Va1Zjv8OwgMEpj8PMtWvXPmxopsgdXyWDAniyXCPlB2PaQiV4bhlX0+uXa94Gbf968RRRRa1tHivJYutSfENhyufmgkeW9IzB+PwKBgQCsWP570KJz2ELWcggKiXK9SCka1vDBCIp01SVM3x/TuLyQ7VMd890e9RGkqZBxYY9xbRUMTkMMeKKQHUJrGl2k5XdfXC2yvu4dXkrTHjmWCIishoeYI5GQVo7whF5+sF0WAWLtmQRBZ6D8g4iSRRIrsF8WYATUf1e+l+eNtKKfgwKBgHlT55UumdhMpBIdubbzWO/JErLSyhG2Ihb7lc1T1sPcKUGK+ZRVvHSrNgRBCN66LkNidwTDZ1FiTmZcIekUaaHX6trQAwoZmpQT9ghpqxdIOzebquhuFGUt3Knr8I2j/jFAuWGrKXGO7vMxNl/2H7cXmetH6KIhpV3uPxRExG6BAoGAdQW8Ta+9DnGR+G/W++iV6uXbWykEsd0tveSX/hkmUCkIiFNMc3MI+iMmxqqHtCStNDP/7aoaJpamsrnbRkPRv8w7AJnjQZIYtgI3RiAos7G5s4NpACluhhXv2mnWi6kOm4l3daLHW+2URsC886xIiTepaNTrkqmgl34nMHWtUicCgYEAnVP9FogNzu+M3Kw5PvUKbnyn5g5asKICsybEa4eCFJjre90EMZO2/sPWNF7W2m6xJXSo6MwM2N3asVNyvpXcHnYb/c/OjRnYsdV2umWDrofxpboqeQMMHF+xHPyAxlt87kV1oLj9Omp6STb3gU+sl6VwPQQbWIJOkHJGhYJm1LQ=',
// 设置应用私钥后,即可下载得到以下3个证书
// 必填-应用公钥证书 路径
'app_public_cert_path' => realpath(app()->getRootPath().'/public/cert/appCertPublicKey_2021004144642003.crt'),
// 必填-支付宝公钥证书 路径
'alipay_public_cert_path' => realpath(app()->getRootPath().'public/cert/alipayCertPublicKey_RSA2.crt'),
// 必填-支付宝根证书 路径
'alipay_root_cert_path' => realpath(app()->getRootPath().'public/cert/alipayRootCert.crt'),
'return_url' => '',
'notify_url' => Request::domain().'/api/pay/notifyAliPay',
// 选填-第三方应用授权token
'app_auth_token' => '',
// 选填-服务商模式下的服务商 id,当 mode 为 Pay::MODE_SERVICE 时使用该参数
'service_provider_id' => '',
// 选填-默认为正常模式。可选为: MODE_NORMAL, MODE_SANDBOX, MODE_SERVICE
'mode' => Pay::MODE_NORMAL,
]
// 'default' => [
// // 必填-支付宝分配的 app_id
// 'app_id' => '9021000139627530', //沙箱
// // 必填-应用私钥 字符串或路径
// // 在 https://open.alipay.com/develop/manage 《应用详情->开发设置->接口加签方式》中设置
// 'app_secret_cert' => 'MIIEowIBAAKCAQEAl4ZZMKaXHGtKbvk1q80op/kw9vC8kXGmnNwkXdEVJIxiVE6GDD6qGHiKRrctGRvsr3qZ4YgFUAHRyefiZ04LDB8CFrUTcfWnzP+uGvQ93AB18OOGVeWUPzN2Q0eHsb3l9ZF5Fx6u7voKVnWf1Eh7oYMx7/5i/V6SBqBZ0H8HvpGoXXx+ejIL69IuudzsHTqlmsj3Za8+1h83Z/VFWPNP4rGRfAhqv+YEgDKFg0q6GSMRp+PoAwBzVEdkzPIju+gHLtJXdeuXNIFNdYRLI2UlkKf8PYbMo15JQh+6OBGGYj8ivIKfreptDbYvqTVWozP6G7Zy4s16TW90O+P5Uma/9wIDAQABAoIBABkqEr3lrMrndqEfei5iEBJ1bBBWwrpU6Zq7ZL6/7ob3WY0uzUxTS+RsgGpmGXNGE/TAo7W05Uz4QGMLw6nsaCFHNQ2YXPZcGdYN0Fhhn7RdzziGUNULH6evYECkLID0TLCPzFBupBbEJ9tcBYM31nBoXW7CDKaPgijfkIrzzdF0FCefRYD/lYUiXRtQHdGO8dMU+MAfClqxXGpn8naorCo6m/hAGQS2BBJBsBNvbBw8Oj6I5w8wTkOOcDx539CHUwMK7lCY4+AF2OwAAfIzImR8Ikb0TkrxUtwUeBzZ2Av2aJE/mHct1OoJMQkRGVIZg6eb8SVLXNHoxgqDjaney0ECgYEA90UMG/lkQksqd5EaLtJ950l1r0kxE5NcKUyCGYqK95qdA8A+ry34m3u5LiRVGGZKdVMmsUDY5NnzMHYSum7ZKcaY04URSX5M8jx2rMHllULcsVGoYo0ywho2RyR1kATr1uPVBRA4ywN2wlaD7Y8oOaRzLFrmnr7wBbPAVKGAh1kCgYEAnN/omLBKS1noTD3OeSLsFOumXGhUJlPkSZK9GZZCpSxayC+aSPU1LVzGz5Upw6uwGLzovKLvEpLeOqsfGUYdvaU9JxeKIjlQ11559OKmH7IG+G6VYGnpuLRkybIv7xPiAf/QF5ZNJmsCe6oj2nec+YxAt68HRD28rlY82nkY588CgYEA12sRBKH9hX/EjIweOmJpC4FFBKOIHNzJcrVTtnqrXNEXL3hhY+5x4ssj5h4DAJHFFneNgujSzHVQV4zV/hOqH6oD5GrOR6+/y11/qjv2DlZEvDo+rzUB3nZFiS8rOIABEqJEJ/gc8kifQulqYCDS030AVckPl4cSxnT1/wUAW2kCgYBr7lm3g8L56Ne8bOG70l0fX6pL9bO/0wRD4mOcURd1UPj8tlOuUpbNqQFYHMZpS5ySyJZQAsH9w3KGZum0l9sqeZ+DX9y4AzstkmDSLYYiVHgbQOohNX2KiQK3CpOUJ9fdjEV9lPlrr0A8GSklzBoCT47PUerr9pX0VHz1y09pXQKBgEs8F5zBFE746UARvfVuw8bRhVbpgexAjQtr2h2pqtmgp+hpfWJ/AF7LKJe1LXpAO8F53/BkDmtgeCsxFMtj4PrcZ3GmjSV2rij5O7YPhyrypBn8z8RuQ+u1G/GW05K0PCaTKOKzvSJwP+m/LcLLQKR6plY8Ouq/FZThNfyrgz9u',
// // 设置应用私钥后,即可下载得到以下3个证书
// // 必填-应用公钥证书 路径
// 'app_public_cert_path' => realpath(app()->getRootPath().'/public/certsx/appPublicCert.crt'),
// // 必填-支付宝公钥证书 路径
// 'alipay_public_cert_path' => realpath(app()->getRootPath().'public/certsx/alipayPublicCert.crt'),
// // 必填-支付宝根证书 路径
// 'alipay_root_cert_path' => realpath(app()->getRootPath().'public/certsx/alipayRootCert.crt'),
//
// 'return_url' => 'https://yansongda.cn/alipay/return',
// 'notify_url' => 'http://'.$_SERVER['HTTP_HOST'].'/api/pay/notifyAliPay',
// // 选填-第三方应用授权token
// 'app_auth_token' => '',
// // 选填-服务商模式下的服务商 id,当 mode 为 Pay::MODE_SERVICE 时使用该参数
// 'service_provider_id' => '',
// // 选填-默认为正常模式。可选为: MODE_NORMAL, MODE_SANDBOX, MODE_SERVICE
// 'mode' => Pay::MODE_SANDBOX,
// ]
],
'http' => [ // optional
'timeout' => 5.0,
'connect_timeout' => 5.0,
// 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
],
];
3.具体业务代码实现
3.1 下单
3.1.1 控制器
/**
* @return \think\response\Json
* @notes 下单
* @author ssx
*/
public function pay()
{
$param = request()->param();
$result = PayLogic::pay($this->userId,$this->userInfo,$param);
if (false === $result) {
return $this->fail(PayLogic::getError());
}
return $this->success('下单成功。', $result->getBody()->getContents());
}
3.1.2 业务层
public static function pay(int $userId,array $userInfo,array $param)
{
Db::startTrans();
try {
$payType = $param['pay_type']??1;
$money = $param['money'];
//根据自己的实际项目需求去生成订单以及处理一些其它相关业务
$sn = "c".date('mdHis').$userId.rand(100,999);
$id = Db::table('ap_charge')->insertGetId([
"sn"=>$sn,
//。。。
]);
if ($id) {
switch ($payType) {
case 1: //微信
$res = self::wxPay($sn,$money);
break;
case 2: //支付宝
$res = self::aliPay($sn,$money);
break;
default:
self::$error = "变量payType值有误。";
// 回滚事务
Db::rollback();
return false;
}
// 提交事务
Db::commit();
return $res;
}
self::$error = "订单生成失败。";
// 回滚事务
Db::rollback();
return false;
} catch (\Exception $e) {
self::setError($e->getMessage());
// 回滚事务
Db::rollback();
return false;
}
}
protected static function wxPay($sn,$money){
Pay::config(Config::get("pay"));
$order = [
'out_trade_no' => $sn,
'description' => '充值',
'amount' => [
'total' => $money * 100,
],
];
// 将返回 json 格式,供后续 APP 调用,调用方式不在本文档讨论范围内,请参考官方文档。
return Pay::wechat()->app($order);
}
protected static function aliPay($sn,$money){
Pay::config(Config::get("pay"));
// 注意返回类型为 Response,具体见详细文档
return Pay::alipay()->app([
'out_trade_no' => $sn,
'total_amount' => $money,
'subject' => '充值',
]);
}
3.2 APP客户端用3-1-1中返回的参数去调起支付宝和微信支付进行支付
3.3退款
3.3.1 控制器
/**
* @return \think\response\Json
* @notes 退款
* @author ssx
*/
public function refund(){
$param = request()->param();
$result = RechargeLogic::refund($this->adminId,$param);
if (false === $result) {
return $this->fail(RechargeLogic::getError());
}
return $this->success('请求成功', $result);
}
3.3.2 业务层
public static function refund(int $adminId,array $param){
// 启动事务
Db::startTrans();
try {
if(empty($param['id'])){
throw new \Exception("id参数不能为空。");
}
$orderInfo = Recharge::where(['ap_charge.id'=>$param['id'],'status'=>2])
->leftJoin('ap_mini_program amp','ap_charge.source = amp.code')
->field("ap_charge.id,sn,money,pay_type,amp.type")->find();
if(!$orderInfo){
throw new \Exception("id参数有误。");
}
$outsn = "o" . date('YmdHis') . $adminId . rand(100,999);
Recharge::where('id',$orderInfo['id'])->update(['outsn' => $outsn,'out_status'=>1]); //out_status 1退款中 2已退款
switch ($orderInfo['pay_type']) {
case 1: //微信
throw new \Exception("app微信退款-待开发");
case 2: //支付宝
self::aliPayRefund($orderInfo,$outsn);
break;
default:
throw new \Exception("pay_type值有误");
}
// 提交事务
Db::commit();
return true;
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
self::$error = $e->getMessage();
return false;
}
}
protected static function aliPayRefund($orderInfo,$outsn):void
{
Pay::config(Config::get("pay"));
$result = Pay::alipay()->refund([
'out_trade_no' => $orderInfo['sn'],
'refund_amount' => $orderInfo['money'],
'out_request_no' => $outsn,
'_action' => 'app', // 退款 APP 订单
])->toArray();
if($result['code'] != 10000 || $result['msg'] != "Success"){
throw new \Exception($result['sub_msg']);
}
}
3.4 异步回调处理
3.4.1 控制器代码
/**
* @return \Psr\Http\Message\ResponseInterface
* @throws \Yansongda\Artful\Exception\ContainerException
* @notes 微信回调
* @author ssx
*/
public function notifyWxPay()
{
Pay::config(Config::get("pay"));
PayLogic::notifyWxPay();
return Pay::wechat()->success();
}
/**
* @return \Psr\Http\Message\ResponseInterface
* @throws \Yansongda\Artful\Exception\ContainerException
* @notes 支付宝回调
* @author ssx
*/
public function notifyAliPay()
{
try {
Pay::config(Config::get("pay"));
PayLogic::notifyAliPay();
echo 'success';die;
} catch (\Exception $e) {
Log::channel('pay')->write("支付宝异步回调发生错误: " . $e->getMessage(),'error');
return false;
}
}
3.4.2 业务层代码
public static function notifyAliPay(): bool
{
try {
Pay::config(Config::get("pay"));
$data = Pay::alipay()->callback()->toArray();
if ($data['trade_status'] == 'TRADE_SUCCESS') {//交易成功
Log::channel('pay')->write("支付宝支付-支付成功-回调数据: " . json_encode($data,JSON_UNESCAPED_UNICODE));
return self::extracted($data); //处理具体的业务
}elseif($data['trade_status'] == 'TRADE_CLOSED'){//交易关闭
Log::channel('pay')->write("支付宝支付-退款成功-回调数据: " . json_encode($data,JSON_UNESCAPED_UNICODE));
if(isset($data['refund_fee']) && isset($data['gmt_refund'])){//退款
//含有refund_fee(总退款金额)、gmt_refund(交易退款时间)参数
return self::notifyAliPayRefund($data); //处理具体的业务
}
}
Log::channel('pay')->write("支付宝支付-其它-回调数据: " . json_encode($data,JSON_UNESCAPED_UNICODE));
Db::table('ap_charge')->where(['sn' => $data['out_trade_no']])->update(['status' => 0]);
// CouponLogic::setUsedCouponLog($data['out_trade_no'], 0);
return true;
}catch (\Exception $e) {
Log::channel('pay')->write("支付宝异步回调发生错误: " . $e->getMessage(),'error');
return false;
}
}