Wechat.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <?php
  2. declare(strict_types=1);
  3. namespace Yansongda\Pay\Provider;
  4. use GuzzleHttp\Psr7\Response;
  5. use GuzzleHttp\Psr7\ServerRequest;
  6. use Psr\Http\Message\MessageInterface;
  7. use Psr\Http\Message\ResponseInterface;
  8. use Psr\Http\Message\ServerRequestInterface;
  9. use Yansongda\Artful\Artful;
  10. use Yansongda\Artful\Event;
  11. use Yansongda\Artful\Exception\ContainerException;
  12. use Yansongda\Artful\Exception\InvalidParamsException;
  13. use Yansongda\Artful\Exception\ServiceNotFoundException;
  14. use Yansongda\Artful\Plugin\AddPayloadBodyPlugin;
  15. use Yansongda\Artful\Plugin\ParserPlugin;
  16. use Yansongda\Artful\Plugin\StartPlugin;
  17. use Yansongda\Artful\Rocket;
  18. use Yansongda\Pay\Contract\ProviderInterface;
  19. use Yansongda\Pay\Event\CallbackReceived;
  20. use Yansongda\Pay\Event\MethodCalled;
  21. use Yansongda\Pay\Exception\Exception;
  22. use Yansongda\Pay\Pay;
  23. use Yansongda\Pay\Plugin\Wechat\AddRadarPlugin;
  24. use Yansongda\Pay\Plugin\Wechat\ResponsePlugin;
  25. use Yansongda\Pay\Plugin\Wechat\V3\AddPayloadSignaturePlugin;
  26. use Yansongda\Pay\Plugin\Wechat\V3\CallbackPlugin;
  27. use Yansongda\Pay\Plugin\Wechat\V3\VerifySignaturePlugin;
  28. use Yansongda\Supports\Collection;
  29. use Yansongda\Supports\Str;
  30. /**
  31. * @method Collection|Rocket app(array $order) APP 支付
  32. * @method Collection|Rocket mini(array $order) 小程序支付
  33. * @method Collection|Rocket mp(array $order) 公众号支付
  34. * @method Collection|Rocket scan(array $order) 扫码支付(摄像头,主动扫)
  35. * @method Collection|Rocket h5(array $order) H5 支付
  36. * @method Collection|Rocket transfer(array $order) 帐户转账
  37. */
  38. class Wechat implements ProviderInterface
  39. {
  40. public const AUTH_TAG_LENGTH_BYTE = 16;
  41. public const MCH_SECRET_KEY_LENGTH_BYTE = 32;
  42. public const URL = [
  43. Pay::MODE_NORMAL => 'https://api.mch.weixin.qq.com/',
  44. Pay::MODE_SANDBOX => 'https://api.mch.weixin.qq.com/sandboxnew/',
  45. Pay::MODE_SERVICE => 'https://api.mch.weixin.qq.com/',
  46. ];
  47. /**
  48. * @throws ContainerException
  49. * @throws InvalidParamsException
  50. * @throws ServiceNotFoundException
  51. */
  52. public function __call(string $shortcut, array $params): null|Collection|MessageInterface|Rocket
  53. {
  54. $plugin = '\Yansongda\Pay\Shortcut\Wechat\\'.Str::studly($shortcut).'Shortcut';
  55. return Artful::shortcut($plugin, ...$params);
  56. }
  57. /**
  58. * @throws ContainerException
  59. * @throws InvalidParamsException
  60. */
  61. public function pay(array $plugins, array $params): null|Collection|MessageInterface|Rocket
  62. {
  63. return Artful::artful($plugins, $params);
  64. }
  65. /**
  66. * @throws ContainerException
  67. * @throws InvalidParamsException
  68. * @throws ServiceNotFoundException
  69. */
  70. public function query(array $order): Collection|Rocket
  71. {
  72. Event::dispatch(new MethodCalled('wechat', __METHOD__, $order, null));
  73. return $this->__call('query', [$order]);
  74. }
  75. /**
  76. * @throws InvalidParamsException
  77. */
  78. public function cancel(array $order): Collection|Rocket
  79. {
  80. throw new InvalidParamsException(Exception::PARAMS_METHOD_NOT_SUPPORTED, '参数异常: 微信不支持 cancel API');
  81. }
  82. /**
  83. * @throws ContainerException
  84. * @throws InvalidParamsException
  85. * @throws ServiceNotFoundException
  86. */
  87. public function close(array $order): Collection|Rocket
  88. {
  89. Event::dispatch(new MethodCalled('wechat', __METHOD__, $order, null));
  90. $this->__call('close', [$order]);
  91. return new Collection();
  92. }
  93. /**
  94. * @throws ContainerException
  95. * @throws InvalidParamsException
  96. * @throws ServiceNotFoundException
  97. */
  98. public function refund(array $order): Collection|Rocket
  99. {
  100. Event::dispatch(new MethodCalled('wechat', __METHOD__, $order, null));
  101. return $this->__call('refund', [$order]);
  102. }
  103. /**
  104. * @throws ContainerException
  105. * @throws InvalidParamsException
  106. */
  107. public function callback(null|array|ServerRequestInterface $contents = null, ?array $params = null): Collection|Rocket
  108. {
  109. $request = $this->getCallbackParams($contents);
  110. Event::dispatch(new CallbackReceived('wechat', clone $request, $params, null));
  111. return $this->pay(
  112. [CallbackPlugin::class],
  113. ['_request' => $request, '_params' => $params]
  114. );
  115. }
  116. public function success(): ResponseInterface
  117. {
  118. return new Response(
  119. 200,
  120. ['Content-Type' => 'application/json'],
  121. json_encode(['code' => 'SUCCESS', 'message' => '成功']),
  122. );
  123. }
  124. public function mergeCommonPlugins(array $plugins): array
  125. {
  126. return array_merge(
  127. [StartPlugin::class],
  128. $plugins,
  129. [AddPayloadBodyPlugin::class, AddPayloadSignaturePlugin::class, AddRadarPlugin::class, VerifySignaturePlugin::class, ResponsePlugin::class, ParserPlugin::class],
  130. );
  131. }
  132. protected function getCallbackParams(null|array|ServerRequestInterface $contents = null): ServerRequestInterface
  133. {
  134. if (is_array($contents) && isset($contents['body'], $contents['headers'])) {
  135. return new ServerRequest('POST', 'http://localhost', $contents['headers'], $contents['body']);
  136. }
  137. if (is_array($contents)) {
  138. return new ServerRequest('POST', 'http://localhost', [], json_encode($contents));
  139. }
  140. if ($contents instanceof ServerRequestInterface) {
  141. return $contents;
  142. }
  143. return ServerRequest::fromGlobals();
  144. }
  145. }