213 lines
5.9 KiB
PHP
213 lines
5.9 KiB
PHP
<?php
|
||
|
||
namespace App\Services\Payment;
|
||
|
||
use App\Enums\WxpayTradeType;
|
||
use App\Exceptions\WeChatPayException;
|
||
use EasyWeChat\Factory;
|
||
use EasyWeChat\Payment\Application;
|
||
use Illuminate\Support\Arr;
|
||
|
||
class WxpayService
|
||
{
|
||
/**
|
||
* @var array<string, \EasyWeChat\Payment\Application>
|
||
*/
|
||
protected $payments = [];
|
||
|
||
/**
|
||
* 支付
|
||
*
|
||
* @param array $params
|
||
* @param string|null $payment
|
||
* @return array
|
||
*/
|
||
public function pay(array $params, ?string $payment = null): array
|
||
{
|
||
if (! isset($params['notify_url'])) {
|
||
$path = route('wxpay.paid_notify', ['payment' => $payment ?: 'default'], false);
|
||
|
||
$params['notify_url'] = url($path, [], true);
|
||
}
|
||
|
||
if (! isset($params['trade_type'])) {
|
||
$params['trade_type'] = WxpayTradeType::App->value;
|
||
}
|
||
|
||
$app = $this->payment($payment);
|
||
|
||
// 服务商模式 (子商户)
|
||
$appId = config('wechat.payment.sub.app_id');
|
||
$mchId = config('wechat.payment.sub.mch_id');
|
||
|
||
if ($appId && $mchId) {
|
||
$params['sub_openid'] = Arr::pull($params, 'openid');
|
||
}
|
||
|
||
$result = $app->order->unify($params);
|
||
|
||
$this->validateResult($result, $params);
|
||
|
||
return match ($params['trade_type']) {
|
||
WxpayTradeType::App->value => $app->jssdk->appConfig($result['prepay_id']),
|
||
WxpayTradeType::H5->value => Arr::only($result, ['mweb_url']),
|
||
default => $app->jssdk->bridgeConfig($result['prepay_id'], false),
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 微信企业付款到零钱
|
||
*
|
||
* @param array $params
|
||
* @return array
|
||
*/
|
||
public function transfer(array $params)
|
||
{
|
||
$config = config('wechat.payment.transfer');
|
||
$debug = config('app.debug');
|
||
if (!isset($params['openid']) && $debug) {
|
||
$params['openid'] = 'oU7xS5UspzVvpPEBqKZuW6N9WXDg';
|
||
}
|
||
if ($debug) {
|
||
$params['amount'] = 100;
|
||
}
|
||
$app = Factory::payment($config);
|
||
/*
|
||
'partner_trade_no' => '1233455', // 商户订单号,需保持唯一性(只能是字母或者数字,不能包含有符号)
|
||
'openid' => 'oxTWIuGaIt6gTKsQRLau2M0yL16E',
|
||
'check_name' => 'FORCE_CHECK', // NO_CHECK:不校验真实姓名, FORCE_CHECK:强校验真实姓名
|
||
're_user_name' => '王小帅', // 如果 check_name 设置为FORCE_CHECK,则必填用户真实姓名
|
||
'amount' => 10000, // 企业付款金额,单位为分
|
||
'desc' => '理赔', // 企业付款操作说明信息。必填
|
||
*/
|
||
$result = $app->transfer->toBalance($params);
|
||
$this->validateResult($result);
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* 查询 微信企业付款到零钱 的订单
|
||
*
|
||
* @param string $no 商户订单号
|
||
* @return array
|
||
*/
|
||
public function queryTransfer($no)
|
||
{
|
||
$config = config('wechat.payment.transfer');
|
||
$app = Factory::payment($config);
|
||
$result = $app->transfer->queryBalanceOrder($no);
|
||
$this->validateResult($result);
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* 根据商户订单号退款
|
||
*
|
||
* @param string $number
|
||
* @param string $refundNumber
|
||
* @param int $totalFee
|
||
* @param int $refundFee
|
||
* @param array $optional
|
||
* @return array
|
||
*/
|
||
public function refundByOutTradeNumber(array $params, ?string $payment = null)
|
||
{
|
||
$optional = Arr::get($params, 'optional', []);
|
||
|
||
if (! is_array($optional)) {
|
||
$optional = [];
|
||
}
|
||
|
||
if (! isset($optional['notify_url'])) {
|
||
$path = route('wxpay.order_refund_notify', [
|
||
'payment' => $payment ?: 'default',
|
||
], false);
|
||
|
||
$optional['notify_url'] = url($path, [], true);
|
||
}
|
||
|
||
$result = $this->payment($payment)->refund->byOutTradeNumber(
|
||
$params['number'],
|
||
$params['refund_number'],
|
||
$params['total_fee'],
|
||
$params['refund_fee'],
|
||
$optional,
|
||
);
|
||
|
||
$this->validateResult($result, $params);
|
||
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* @param string|null $name
|
||
* @return \EasyWeChat\Payment\Application
|
||
*/
|
||
public function payment(?string $name = null): Application
|
||
{
|
||
$name = $name ?: 'default';
|
||
|
||
return $this->payments[$name] = $this->get($name);
|
||
}
|
||
|
||
/**
|
||
* @param string $name
|
||
* @return \EasyWeChat\Payment\Application
|
||
*/
|
||
protected function get(string $name): Application
|
||
{
|
||
return $this->payments[$name] ?? $this->resolve($name);
|
||
}
|
||
|
||
/**
|
||
* @param string $name
|
||
* @return \EasyWeChat\Payment\Application
|
||
*
|
||
* @throws \App\Exceptions\WeChatPayException
|
||
*/
|
||
protected function resolve(string $name): Application
|
||
{
|
||
$config = config("wechat.payment.{$name}");
|
||
|
||
if (empty($config)) {
|
||
throw new WeChatPayException("支付 [{$name}] 配置未找到");
|
||
}
|
||
|
||
$app = Factory::payment($config);
|
||
|
||
// 服务商模式 (子商户)
|
||
$appId = config('wechat.payment.sub.app_id');
|
||
$mchId = config('wechat.payment.sub.mch_id');
|
||
|
||
if ($appId && $mchId) {
|
||
$app->setSubMerchant($mchId, $appId);
|
||
}
|
||
|
||
return $app;
|
||
}
|
||
|
||
/**
|
||
* 校验响应结果
|
||
*
|
||
* @param array $result
|
||
* @param array $raw
|
||
* @return void
|
||
*
|
||
* @throws \App\Exceptions\WeChatPayException
|
||
*/
|
||
protected function validateResult(array $result, array $raw = [])
|
||
{
|
||
if (Arr::get($result, 'return_code') !== 'SUCCESS') {
|
||
throw new WeChatPayException(Arr::get($result, 'return_msg', '请求失败'), $raw);
|
||
}
|
||
|
||
if (Arr::get($result, 'result_code') !== 'SUCCESS') {
|
||
throw new WeChatPayException(sprintf(
|
||
'[%s] %s',
|
||
Arr::get($result, 'err_code', '-1'),
|
||
Arr::get($result, 'err_code_des', '交易失败')
|
||
), $raw);
|
||
}
|
||
}
|
||
}
|