6
0
Fork 0
jiqu-library-server/app/Services/Payment/WxpayService.php

295 lines
8.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Services\Payment;
use App\Enums\WxpayTradeType;
use App\Exceptions\WeChatPayException;
use EasyWeChat\Factory;
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
use EasyWeChat\Payment\Application;
use GuzzleHttp\Exception\GuzzleException;
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'])) {
$params['notify_url'] = route('wxpay.paid_notify', ['payment' => $payment ?: 'default']);
}
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
* @throws WeChatPayException
*/
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 $order_sn string 商户订单号
* @param $share_sn string 分账订单号
* @param $receivers array 接收方{}
* @return mixed
*/
public function share(string $order_sn, string $share_sn, array $receivers): mixed
{
$app = $this->payment();
// 服务商模式 (子商户)
$appId = config('wechat.payment.sub.app_id');
$mchId = config('wechat.payment.sub.mch_id');
if ($appId && $mchId) {
$app->setSubMerchant($mchId, $appId);
}
// 添加分账接收方
foreach ($receivers as $receiver) {
$app->profit_sharing->addReceiver([
"type" => $receiver['type'],
"account" => $receiver['account'],
"relation_type" => "DISTRIBUTOR"
]);
}
$result = $app->profit_sharing->share($order_sn, $share_sn, $receivers);
$this->validateResult($result);
return $result;
}
/**
* 微信支付-查询分账结果
*
* @param string $transaction_id
* @param string $share_sn
* @return mixed
*/
public function queryShare(string $transaction_id, string $share_sn)
{
$app = $this->payment();
// 服务商模式 (子商户)
$appId = config('wechat.payment.sub.app_id');
$mchId = config('wechat.payment.sub.mch_id');
if ($appId && $mchId) {
$app->setSubMerchant($mchId, $appId);
}
return $app->profit_sharing->query($transaction_id, $share_sn);
}
/**
* 微信支付-完结分账, 解冻订单剩余资金
*
* @param string $transaction_id 微信支付流水号
* @param string $out_trade_sn 分账订单号, 自动生成
* @return mixed
*/
public function finishShare(string $transaction_id, string $out_trade_sn)
{
$app = $this->payment();
// 服务商模式 (子商户)
$appId = config('wechat.payment.sub.app_id');
$mchId = config('wechat.payment.sub.mch_id');
if ($appId && $mchId) {
$app->setSubMerchant($mchId, $appId);
}
return $app->profit_sharing->markOrderAsFinished([
'transaction_id' => $transaction_id,
'out_order_no' => $out_trade_sn,
'description' => '订单分账完结, 解冻资金'
]);
}
/**
* 根据商户订单号退款
*
* @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);
}
}
}