123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- <?php namespace App\Servers\WechatPay;
- use DateTime;
- use DateTimeZone;
- use App\Facades\Servers\Logs\Log;
- use WeChatPay\Builder;
- use WeChatPay\Crypto\Rsa;
- use WeChatPay\Util\PemUtil;
- use WeChatPay\Formatter;
- class Payment
- {
- private $appid;
- private $mchid;
- private $instance;
- private $merchantPrivateKeyInstance;
- private $merchantCertificateSerial;
- function __construct()
- {
- // 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名
- $merchantPrivateKeyFilePath = Config('wechat.pay.key');
- $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
- // 「商户API证书」的「证书序列号」
- // 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名
- $platformCertificateFilePath = Config('wechat.platformCertificate');
- $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
- // 从「微信支付平台证书」中获取「证书序列号」
- $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
- // 构造一个 APIv3 客户端实例
- $instance = Builder::factory([
- 'mchid' => Config('wechat.pay.mch_id'),
- 'serial' => Config('wechat.pay.certificate'),
- 'privateKey' => $merchantPrivateKeyInstance,
- 'certs' => [
- $platformCertificateSerial => $platformPublicKeyInstance,
- ],
- ]);
- $this->instance = $instance;
- $this->appid = Config('wechat.pay.appid');
- $this->mchid = Config('wechat.pay.mch_id');
- $this->merchantPrivateKeyInstance = $merchantPrivateKeyInstance;
- $this->merchantCertificateSerial = Config('wechat.pay.certificate');
- return;
- }
- /**
- * 拉起小程序支付
- */
- public function pay($params)
- {
- $notify_url = Config('wechat.pay.notify_url');
- //调用微信JSAPI下单获取预支付交易会话标识
- try {
- $resp = $this->instance
- ->chain('v3/pay/transactions/jsapi')
- ->post(['json' => [
- 'mchid' => $this->mchid,
- 'out_trade_no' => $params['out_trade_no'],
- 'appid' => $this->appid,
- 'description' => $params['description'],
- 'time_expire' => $this->timestampToRfc3339(time() + env('ORDER_OUT_TIME')*60),
- 'notify_url' => $notify_url,
- 'amount' => [
- 'total' => $params['total_price'],
- 'currency' => 'CNY'
- ],
- 'payer' => [
- 'openid' => $params['openid']
- ]
- ]]);
- $result = json_decode($resp->getBody(),true);
- $prepay_id = $result['prepay_id'];
- } catch (\Exception $e) {
- if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
- $r = $e->getResponse();
- // 记录错误信息
- Log::error('wechat/Payment','拉起小程序支付,出现错误'.$r->getBody().'参数'.json_encode($params));
- }
- return response()->json(['error' => '拉起支付失败'], 500);
- }
- //根据返回的预支付交易会话标识,组装调起小程序支付参数
- $data = [
- 'appId' => $this->appid,
- 'timeStamp' => (string)Formatter::timestamp(),
- 'nonceStr' => Formatter::nonce(),
- 'package' => 'prepay_id='.$prepay_id,
- ];
- $data += ['paySign' => Rsa::sign(
- Formatter::joinedByLineFeed(...array_values($data)),
- $this->merchantPrivateKeyInstance
- ), 'signType' => 'RSA'];
- return response()->json($data);
- }
- //查询订单
- public function query($params)
- {
- try {
- $promise = $this->instance
- ->chain('v3/pay/transactions/id/'.$params[''])
- ->get(['json' => [
- 'mchid' => $this->mchid,
- ]]);
- } catch (\Exception $e) {
- if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
- $r = $e->getResponse();
- // 记录错误信息
- Log::error('wechat/Payment','查询订单,出现错误'.$r->getBody().'参数'.json_encode($params));
- }
- return response()->json(['error' => '查询订单支付失败'], 500);
- }
- return response()->json($promise);
- }
- /**
- * 订单微信退款
- */
- public function refund($params)
- {
- $notify_url = Config('wechat.course_refund_notify_url');
- try {
- $resp = $this->instance
- ->chain('v3/refund/domestic/refunds')
- ->post(['json' => [
- 'transaction_id' => $params['transaction_id'],
- 'out_refund_no' => $params['out_refund_no'],
- 'reason' => $params['reason'] ?? '',
- 'notify_url' => $notify_url,
- 'amount' => [
- 'refund' => $params['refund'],
- 'total' => $params['total'],
- 'currency' => 'CNY'
- ],
- ]]);
- } catch (\Exception $e) {
- if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
- $r = $e->getResponse();
- Log::error('wechat/Payment','订单微信退款,出现错误'.$r->getBody());
- }
- return response()->json(['error' => '订单微信退款失败'], 500);
- }
- return response()->json($resp);
- }
- //Rfc3339时间日期格式
- public function timestampToRfc3339($timestamp)
- {
- // 转换为DateTime对象
- $dateTime = new DateTime();
- $dateTime->setTimestamp($timestamp);
- // 设置时区,默认为UTC
- $dateTime->setTimezone(new DateTimeZone('UTC'));
- // 格式化为RFC3339
- return $dateTime->format(DateTime::RFC3339);
- }
- }
|