|
|
@@ -0,0 +1,132 @@
|
|
|
+<?php
|
|
|
+declare(strict_types=1);
|
|
|
+
|
|
|
+namespace SixShop\WechatPay\Trait;
|
|
|
+
|
|
|
+use app\xyz\exception\ApiException;
|
|
|
+use GuzzleHttp\Promise\PromiseInterface;
|
|
|
+use SixShop\Payment\Entity\ExtensionPaymentEntity;
|
|
|
+use SixShop\WechatPay\Config;
|
|
|
+use think\exception\ErrorException;
|
|
|
+use think\facade\Log;
|
|
|
+use WeChatPay\Builder;
|
|
|
+use WeChatPay\BuilderChainable;
|
|
|
+
|
|
|
+trait ApiTrait
|
|
|
+{
|
|
|
+ public function __construct(
|
|
|
+ private readonly Config $config,
|
|
|
+ private readonly ExtensionPaymentEntity $extensionPaymentEntity,
|
|
|
+ private ?BuilderChainable $builderChainable = null,
|
|
|
+ )
|
|
|
+ {
|
|
|
+ }
|
|
|
+ private function getBuilderChainable(): BuilderChainable
|
|
|
+ {
|
|
|
+ if ($this->builderChainable === null) {
|
|
|
+ $this->builderChainable = Builder::factory([
|
|
|
+ 'mchid' => $this->config->mchid,
|
|
|
+ 'serial' => $this->config->serial_no,
|
|
|
+ 'privateKey' => $this->config->apiclient_key,
|
|
|
+ 'certs' => [
|
|
|
+ $this->config->wechatpay_serial => $this->config->public_key,
|
|
|
+ ],
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ return $this->builderChainable;
|
|
|
+ }
|
|
|
+
|
|
|
+ private function handleAsyncRequest(PromiseInterface $promise)
|
|
|
+ {
|
|
|
+ return $promise
|
|
|
+ ->then(function ($response) {
|
|
|
+ Log::info('微信支付异步回调返回数据:' . $response->getBody());
|
|
|
+ return json_decode((string)$response->getBody());
|
|
|
+ })
|
|
|
+ ->otherwise(function ($e) {
|
|
|
+ if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
|
|
|
+ $errorBody = json_decode((string)$e->getResponse()->getBody());
|
|
|
+ throw new ErrorException(message: trim($errorBody->message));
|
|
|
+ }
|
|
|
+ throw $e;
|
|
|
+ })
|
|
|
+ ->wait();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 微信支付
|
|
|
+ */
|
|
|
+ private function wechatPay(string $openid, string $outTradeNo, int $total, string $description, string $notifyUrl, int $expireTime)
|
|
|
+ {
|
|
|
+
|
|
|
+ // https://pay.weixin.qq.com/doc/v3/merchant/4012791856
|
|
|
+ // 【POST】/v3/pay/transactions/jsapi
|
|
|
+ return $this->handleAsyncRequest($this->getBuilderChainable()->v3->pay->transactions->jsapi->postAsync([
|
|
|
+ 'json' => [
|
|
|
+ 'mchid' => $this->config->mchid,
|
|
|
+ 'out_trade_no' => $outTradeNo,
|
|
|
+ 'appid' => $this->config->appid,
|
|
|
+ 'description' => $description,
|
|
|
+ 'notify_url' => $notifyUrl,
|
|
|
+ // yyyy-MM-DDTHH:mm:ss+TIMEZONE
|
|
|
+ 'time_expire' => date('Y-m-d\TH:i:s+08:00', $expireTime),
|
|
|
+ 'attach' => 'actor',
|
|
|
+ 'amount' => [
|
|
|
+ 'total' => $total,
|
|
|
+ 'currency' => 'CNY'
|
|
|
+ ],
|
|
|
+ 'payer' => [
|
|
|
+ 'openid' => $openid
|
|
|
+ ]
|
|
|
+ ],]));
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 退款申请
|
|
|
+ */
|
|
|
+ private function domesticRefunds(string $outRefundNo, string $outTradeNo, array $amount, string $reason)
|
|
|
+ {
|
|
|
+ // https://pay.weixin.qq.com/doc/v3/merchant/4012791862
|
|
|
+ // 【POST】/v3/refund/domestic/refunds
|
|
|
+ return $this->handleAsyncRequest($this->getBuilderChainable()->v3->refund->domestic->refunds->postAsync([
|
|
|
+ 'json' => [
|
|
|
+ 'out_refund_no' => $outRefundNo,
|
|
|
+ 'out_trade_no' => $outTradeNo,
|
|
|
+ 'reason' => $reason,
|
|
|
+ 'amount' => $amount,
|
|
|
+ 'notify_url' => $this->notifyUrl
|
|
|
+ ]
|
|
|
+ ]));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发起转账
|
|
|
+ */
|
|
|
+ private function transferBills(int $uid, string $orderSn, string $amount)
|
|
|
+ {
|
|
|
+ // https://pay.weixin.qq.com/doc/v3/merchant/4012716434
|
|
|
+ //【POST】/v3/fund-app/mch-transfer/transfer-bills
|
|
|
+ return $this->handleAsyncRequest($this->getBuilderChainable()->v3->fundApp->mchTransfer->transferBills->postAsync([
|
|
|
+ 'json' => [
|
|
|
+ 'appid' => $this->appId,
|
|
|
+ 'openid' => $this->getOpenId($uid, 'routine'),
|
|
|
+ 'out_bill_no' => $orderSn,
|
|
|
+ 'transfer_amount' => (int)($amount * 100),
|
|
|
+ 'notify_url' => $this->notifyUrl,
|
|
|
+ 'transfer_scene_id' => '1005', // 佣金报酬
|
|
|
+ 'transfer_scene_report_infos' => [
|
|
|
+ [
|
|
|
+ 'info_type' => '岗位类型',
|
|
|
+ 'info_content' => '合作运营'
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ 'info_type' => '报酬说明',
|
|
|
+ 'info_content' => sprintf('提现到账%.2f元', $amount)
|
|
|
+ ],
|
|
|
+ ],
|
|
|
+ 'transfer_remark' => sprintf('提现%s元到零钱', $amount),
|
|
|
+ ]
|
|
|
+ ]));
|
|
|
+ }
|
|
|
+}
|