course/app/common/service/PayService.php

180 lines
6.3 KiB
PHP
Raw Normal View History

<?php
namespace app\common\service;
use app\common\service\Channel\wechat\WechatConstants;
use app\constant\ResponseCode;
use GuzzleHttp\Exception\RequestException;
use think\Exception;
use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;
use WeChatPay\Util\PemUtil;
class PayService
{
protected $config;
protected $instance;
protected $platformPublicKeyInstance;
protected $merchantPrivateKeyInstance;
public function __construct()
{
// 服务商 商户号
$merchantId = getenv('MERCHANT_ID');
// 从本地文件中加载「商户API私钥」「商户API私钥」会用来生成请求的签名
$merchantPrivateKeyFilePath = 'file://' . base_path() . '/certificate/apiclient_key.pem';
$this->merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
// 「商户API证书」的「证书序列号」
$merchantCertificateSerial = '3297EB3A1132A39DAFFD70A6C4A6C3078CD346F7';
// 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名
$platformCertificateFilePath = 'file://' . base_path() . '/certificate/wechatpay_660FAD2D6E804E37BE9D77EF5882718CC1E3399F.pem';
$this->platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
// 从「微信支付平台证书」中获取「证书序列号」
$platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
// 构造一个 APIv3 客户端实例
$this->instance = Builder::factory([
'mchid' => $merchantId,
'serial' => $merchantCertificateSerial,
'privateKey' => $this->merchantPrivateKeyInstance,
'certs' => [
$platformCertificateSerial => $this->platformPublicKeyInstance,
],
]);
}
/**
* @desc jsapi支付
* @param array $pay_data
* @param $seller_channel
* @return array
*/
public function payment(array $pay_data)
{
try {
$request_data = [
'appid' => getenv('APP_ID'),// 公众号ID
'mchid' => getenv('MERCHANT_ID'),//直连商户号
'description' => $pay_data['desc'],//商品描述
'out_trade_no' => $pay_data['out_trade_no'],//商户订单号
'notify_url' => $pay_data['notify_url'],//通知地址
'amount' => [
'total' => round($pay_data['total_amount'] * 100),//总金额 单位为分
],
'payer' => [
'openid' => $pay_data['openid'],// 用户在服务商AppID下的唯一标识
]
];
$resp = $this->instance
->chain('/v3/pay/transactions/jsapi')
->post([
'json' => $request_data,
// 'debug' => true
]);
$result = json_decode($resp->getBody(), true);
raw_log('wechat_pay/transactions_jsapi', ['request_data' => $request_data, 'result' => $result]);
$pay_data = [
'appId' => getenv('APP_ID'), //微信小程序appid
'timeStamp' => strval(Formatter::timestamp()),
'nonceStr' => Formatter::nonce(),
'package' => 'prepay_id=' . $result['prepay_id'],
];
$pay_data['paySign'] = Rsa::sign(
Formatter::joinedByLineFeed(...array_values($pay_data)),
$this->merchantPrivateKeyInstance
);
$pay_data['signType'] = 'RSA';
return $pay_data;
} catch (RequestException $exception) {
$response = $exception->getResponse();
$result = json_decode($response->getBody()->getContents(), true);
raw_log('wechat_pay/transactions_jsapi_failed', ['pay_data' => $pay_data, 'result' => $result]);
return [
'code' => ResponseCode::FAIL,
'msg' => $result['message']
];
}
}
/**
* @desc 退款
* @param $refund_data
* @return array
*/
public function refundPayment($refund_data)
{
try {
//退款数据
$request_data = [
'out_trade_no' => $refund_data['out_trade_no'],//微信支付订单号
'out_refund_no' => $refund_data['out_refund_no'],//商户退款单号
'reason' => $refund_data['refund_desc'],//退款原因
'notify_url' => $refund_data['notify_url'],//通知地址
'amount' => [
'refund' => round($refund_data['refund_amount'] * 100),//退款金额
'total' => round($refund_data['total'] * 100),//原订单金额
'currency' => 'CNY',//退款币种
]
];
$resp = $this->instance
->chain('/v3/refund/domestic/refunds')
->post([
'json' => $request_data,
// 'debug' => true
]);
$result = json_decode($resp->getBody(), true);
raw_log('wechat_pay/refund', ['request_data' => $request_data, 'result' => $result]);
return [
'transaction_id' => $result['transaction_id'],
'out_transaction_id' => $result['refund_id'],
'out_trade_no' => $result['out_refund_no'],
];
} catch (RequestException $exception) {
$response = $exception->getResponse();
$result = json_decode($response->getBody()->getContents(), true);
raw_log('wechat_pay/refund_failed', ['request_data' => $request_data, 'result' => $result]);
return [
'code' => ResponseCode::FAIL,
'msg' => $result['message']
];
}
}
/**
* @desc 余额查询 微信没有余额查询接口,返回假数据
* @param $seller_channel
* @return array
*/
public function queryBalanceAmount($seller_channel)
{
return [
'code'=>ResponseCode::SUCCESS,
'data'=>[
'total_amount'=>0.00,
'settled_amount'=>0.00,
'not_settled_amount'=>0.00
]
];
}
}