Browse Source

feat:版本

super-yimizi 2 months ago
parent
commit
0d3f264dd3
100 changed files with 4118 additions and 60 deletions
  1. 1 1
      addons/epay/.addonrc
  2. 15 3
      addons/epay/Epay.php
  3. 54 54
      addons/epay/config.php
  4. 2 2
      addons/epay/info.ini
  5. 1 0
      addons/epay/library/v2/version.txt
  6. 1 0
      addons/epay/library/v3/version.txt
  7. 342 0
      addons/epay/library/v3new/Yansongda/Artful/Artful.php
  8. 14 0
      addons/epay/library/v3new/Yansongda/Artful/Contract/ConfigInterface.php
  9. 12 0
      addons/epay/library/v3new/Yansongda/Artful/Contract/ContainerInterface.php
  10. 12 0
      addons/epay/library/v3new/Yansongda/Artful/Contract/DirectionInterface.php
  11. 7 0
      addons/epay/library/v3new/Yansongda/Artful/Contract/EventDispatcherInterface.php
  12. 12 0
      addons/epay/library/v3new/Yansongda/Artful/Contract/HttpClientFactoryInterface.php
  13. 9 0
      addons/epay/library/v3new/Yansongda/Artful/Contract/HttpClientInterface.php
  14. 7 0
      addons/epay/library/v3new/Yansongda/Artful/Contract/LoggerInterface.php
  15. 14 0
      addons/epay/library/v3new/Yansongda/Artful/Contract/PackerInterface.php
  16. 13 0
      addons/epay/library/v3new/Yansongda/Artful/Contract/PluginInterface.php
  17. 15 0
      addons/epay/library/v3new/Yansongda/Artful/Contract/ServiceProviderInterface.php
  18. 13 0
      addons/epay/library/v3new/Yansongda/Artful/Contract/ShortcutInterface.php
  19. 33 0
      addons/epay/library/v3new/Yansongda/Artful/Direction/CollectionDirection.php
  20. 17 0
      addons/epay/library/v3new/Yansongda/Artful/Direction/NoHttpRequestDirection.php
  21. 26 0
      addons/epay/library/v3new/Yansongda/Artful/Direction/OriginResponseDirection.php
  22. 7 0
      addons/epay/library/v3new/Yansongda/Artful/Direction/ResponseDirection.php
  23. 39 0
      addons/epay/library/v3new/Yansongda/Artful/Event.php
  24. 7 0
      addons/epay/library/v3new/Yansongda/Artful/Event/ArtfulEnd.php
  25. 10 0
      addons/epay/library/v3new/Yansongda/Artful/Event/ArtfulStart.php
  26. 12 0
      addons/epay/library/v3new/Yansongda/Artful/Event/Event.php
  27. 7 0
      addons/epay/library/v3new/Yansongda/Artful/Event/HttpEnd.php
  28. 7 0
      addons/epay/library/v3new/Yansongda/Artful/Event/HttpStart.php
  29. 16 0
      addons/epay/library/v3new/Yansongda/Artful/Exception/ContainerException.php
  30. 15 0
      addons/epay/library/v3new/Yansongda/Artful/Exception/ContainerNotFoundException.php
  31. 69 0
      addons/epay/library/v3new/Yansongda/Artful/Exception/Exception.php
  32. 18 0
      addons/epay/library/v3new/Yansongda/Artful/Exception/InvalidConfigException.php
  33. 15 0
      addons/epay/library/v3new/Yansongda/Artful/Exception/InvalidParamsException.php
  34. 23 0
      addons/epay/library/v3new/Yansongda/Artful/Exception/InvalidResponseException.php
  35. 16 0
      addons/epay/library/v3new/Yansongda/Artful/Exception/ServiceNotFoundException.php
  36. 93 0
      addons/epay/library/v3new/Yansongda/Artful/Functions.php
  37. 39 0
      addons/epay/library/v3new/Yansongda/Artful/HttpClientFactory.php
  38. 49 0
      addons/epay/library/v3new/Yansongda/Artful/Logger.php
  39. 26 0
      addons/epay/library/v3new/Yansongda/Artful/Packer/JsonPacker.php
  40. 22 0
      addons/epay/library/v3new/Yansongda/Artful/Packer/QueryPacker.php
  41. 22 0
      addons/epay/library/v3new/Yansongda/Artful/Packer/XmlPacker.php
  42. 33 0
      addons/epay/library/v3new/Yansongda/Artful/Plugin/AddPayloadBodyPlugin.php
  43. 45 0
      addons/epay/library/v3new/Yansongda/Artful/Plugin/AddRadarPlugin.php
  44. 45 0
      addons/epay/library/v3new/Yansongda/Artful/Plugin/ParserPlugin.php
  45. 24 0
      addons/epay/library/v3new/Yansongda/Artful/Plugin/StartPlugin.php
  46. 180 0
      addons/epay/library/v3new/Yansongda/Artful/Rocket.php
  47. 42 0
      addons/epay/library/v3new/Yansongda/Artful/Service/ConfigServiceProvider.php
  48. 108 0
      addons/epay/library/v3new/Yansongda/Artful/Service/ContainerServiceProvider.php
  49. 24 0
      addons/epay/library/v3new/Yansongda/Artful/Service/EventServiceProvider.php
  50. 24 0
      addons/epay/library/v3new/Yansongda/Artful/Service/HttpServiceProvider.php
  51. 71 0
      addons/epay/library/v3new/Yansongda/Artful/Service/LoggerServiceProvider.php
  52. 28 0
      addons/epay/library/v3new/Yansongda/Pay/Contract/ProviderInterface.php
  53. 27 0
      addons/epay/library/v3new/Yansongda/Pay/Event/CallbackReceived.php
  54. 26 0
      addons/epay/library/v3new/Yansongda/Pay/Event/MethodCalled.php
  55. 9 0
      addons/epay/library/v3new/Yansongda/Pay/Event/PayEnd.php
  56. 27 0
      addons/epay/library/v3new/Yansongda/Pay/Event/PayStart.php
  57. 19 0
      addons/epay/library/v3new/Yansongda/Pay/Exception/DecryptException.php
  58. 92 0
      addons/epay/library/v3new/Yansongda/Pay/Exception/Exception.php
  59. 23 0
      addons/epay/library/v3new/Yansongda/Pay/Exception/InvalidSignException.php
  60. 656 0
      addons/epay/library/v3new/Yansongda/Pay/Functions.php
  61. 108 0
      addons/epay/library/v3new/Yansongda/Pay/Pay.php
  62. 68 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/AddPayloadSignaturePlugin.php
  63. 55 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/AddRadarPlugin.php
  64. 55 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/AppCallbackPlugin.php
  65. 48 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/CallbackPlugin.php
  66. 33 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/FormatPayloadBizContentPlugin.php
  67. 32 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/PCreditPayInstallment/AppPayPlugin.php
  68. 48 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/PCreditPayInstallment/H5PayPlugin.php
  69. 47 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/PCreditPayInstallment/PosPayPlugin.php
  70. 41 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/PCreditPayInstallment/ScanPayPlugin.php
  71. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Royalty/Query/OnsettlePlugin.php
  72. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Royalty/Query/RatePlugin.php
  73. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Royalty/Query/SettlePlugin.php
  74. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Royalty/Relation/BindPlugin.php
  75. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Royalty/Relation/QueryPlugin.php
  76. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Royalty/Relation/UnbindPlugin.php
  77. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Royalty/Request/SettleOrderPlugin.php
  78. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Transfer/ApplyReceiptPlugin.php
  79. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Transfer/Bill/QueryUrlPlugin.php
  80. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Transfer/Fund/QueryPlugin.php
  81. 37 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Transfer/Fund/TransferPlugin.php
  82. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Transfer/QueryAccountPlugin.php
  83. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Transfer/QueryReceiptPlugin.php
  84. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Transfer/RefundPlugin.php
  85. 38 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Marketing/Redpack/AppPayPlugin.php
  86. 37 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Marketing/Redpack/WebPayPlugin.php
  87. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/Authorization/AuthPlugin.php
  88. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/Authorization/QueryPlugin.php
  89. 32 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/Authorization/TokenPlugin.php
  90. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/Certification/CertifyPlugin.php
  91. 35 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/Certification/InitPlugin.php
  92. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/Certification/QueryPlugin.php
  93. 33 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/DetailPlugin.php
  94. 35 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/FaceCheck/AppInitPlugin.php
  95. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/FaceCheck/AppQueryPlugin.php
  96. 36 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/FaceVerification/AppInitPlugin.php
  97. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/FaceVerification/AppQueryPlugin.php
  98. 35 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/FaceVerification/H5InitPlugin.php
  99. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/FaceVerification/H5QueryPlugin.php
  100. 30 0
      addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/FaceVerification/H5VerifyPlugin.php

+ 1 - 1
addons/epay/.addonrc

@@ -1 +1 @@
-{"files":["application\/admin\/controller\/Epay.php","public\/assets\/addons\/epay\/css\/common.css","public\/assets\/addons\/epay\/less\/common.less","public\/assets\/addons\/epay\/images\/paid.png","public\/assets\/addons\/epay\/images\/logo-wechat.png","public\/assets\/addons\/epay\/images\/logo-alipay.png","public\/assets\/addons\/epay\/images\/screenshot-alipay.png","public\/assets\/addons\/epay\/images\/alipay.png","public\/assets\/addons\/epay\/images\/screenshot-wechat.png","public\/assets\/addons\/epay\/images\/wechat.png","public\/assets\/addons\/epay\/images\/scan.png","public\/assets\/addons\/epay\/images\/expired.png","public\/assets\/addons\/epay\/js\/jquery.qrcode.min.js","public\/assets\/addons\/epay\/js\/common.js"],"license":"regular","licenseto":"9671","licensekey":"AMGWSLFhxsvpKy9E j+5KbEzsYwu\/qtJpUU2lFA==","domains":["thinkphp_fastadmin_tailored.test"],"licensecodes":[],"validations":["849901681e419b30a3ed3e4629b8f4ac"]}
+{"files":["application\/admin\/controller\/Epay.php","public\/assets\/addons\/epay\/css\/common.css","public\/assets\/addons\/epay\/less\/common.less","public\/assets\/addons\/epay\/images\/paid.png","public\/assets\/addons\/epay\/images\/logo-wechat.png","public\/assets\/addons\/epay\/images\/logo-alipay.png","public\/assets\/addons\/epay\/images\/screenshot-alipay.png","public\/assets\/addons\/epay\/images\/alipay.png","public\/assets\/addons\/epay\/images\/screenshot-wechat.png","public\/assets\/addons\/epay\/images\/wechat.png","public\/assets\/addons\/epay\/images\/scan.png","public\/assets\/addons\/epay\/images\/expired.png","public\/assets\/addons\/epay\/js\/jquery.qrcode.min.js","public\/assets\/addons\/epay\/js\/common.js"],"license":"regular","licenseto":"9671","licensekey":"fY2u0NovbBezQWUn vj6BNKi5JAcnHiwqWlIMgA==","domains":[],"licensecodes":[],"validations":[]}

+ 15 - 3
addons/epay/Epay.php

@@ -71,7 +71,19 @@ class Epay extends Addons
             $version = Service::getSdkVersion();
 
             $libraryDir = ADDON_PATH . 'epay' . DS . 'library' . DS;
-            Loader::addNamespace('Yansongda\Pay', $libraryDir . $version . DS . 'Yansongda' . DS . 'Pay' . DS);
+
+            if (PHP_VERSION_ID >= 80000 && $version == Service::SDK_VERSION_V3) {
+                $yansongdaDir = $libraryDir . $version . 'new' . DS . 'Yansongda' . DS;
+
+                // PHP 8.0+ 版本且为V3接口,需要加载 Artful 的命名空间
+                Loader::addNamespace('Yansongda\Artful', $yansongdaDir . 'Artful' . DS);
+                require_once $yansongdaDir . 'Artful' . DS . 'Functions.php';
+            } else {
+                $yansongdaDir = $libraryDir . $version . DS . 'Yansongda' . DS;
+            }
+
+            // 注册Pay命名空间
+            Loader::addNamespace('Yansongda\Pay', $yansongdaDir . 'Pay' . DS);
 
             $checkArr = [
                 '\Hyperf\Context\Context'     => 'context',
@@ -88,12 +100,12 @@ class Epay extends Addons
             }
 
             if (!class_exists('\Yansongda\Supports\Logger')) {
-                Loader::addNamespace('Yansongda\Supports', $libraryDir . $version . DS . 'Yansongda' . DS . 'Supports' . DS);
+                Loader::addNamespace('Yansongda\Supports', $yansongdaDir . 'Supports' . DS);
             }
 
             // V3需载入辅助函数
             if ($version == Service::SDK_VERSION_V3) {
-                require_once $libraryDir . $version . DS . 'Yansongda' . DS . 'Pay' . DS . 'Functions.php';
+                require_once $yansongdaDir . 'Pay' . DS . 'Functions.php';
             }
         }
     }

+ 54 - 54
addons/epay/config.php

@@ -2,69 +2,69 @@
 
 return [
     [
-        'name'    => 'version',
-        'title'   => 'API版本(请勿修改该值)',
-        'type'    => 'radio',
+        'name' => 'version',
+        'title' => 'API版本(请勿修改该值)',
+        'type' => 'radio',
         'content' => [],
-        'value'   => 'v2',
-        'rule'    => '',
-        'msg'     => '',
-        'tip'     => 'V2版本只支持微信支付V2密钥,V3版本只支持微信支付V3密钥,请勿修改该值!!!',
-        'ok'      => '',
-        'extend'  => '',
+        'value' => 'v2',
+        'rule' => '',
+        'msg' => '',
+        'tip' => 'V2版本只支持微信支付V2密钥,V3版本只支持微信支付V3密钥,请勿修改该值!!!',
+        'ok' => '',
+        'extend' => '',
     ],
     [
-        'name'    => 'wechat',
-        'title'   => '微信',
-        'type'    => 'array',
+        'name' => 'wechat',
+        'title' => '微信',
+        'type' => 'array',
         'content' => [],
-        'value'   => [
-            'appid'          => '',
-            'app_id'         => '',
-            'app_secret'     => '',
-            'miniapp_id'     => '',
-            'mch_id'         => '',
-            'key'            => '',
-            'key_v3'         => '',
-            'mode'           => 'normal',
-            'sub_mch_id'     => '',
-            'sub_appid'      => '',
-            'sub_app_id'     => '',
+        'value' => [
+            'appid' => '',
+            'app_id' => '',
+            'app_secret' => '',
+            'miniapp_id' => '',
+            'mch_id' => '',
+            'key' => '',
+            'key_v3' => '',
+            'mode' => 'normal',
+            'sub_mch_id' => '',
+            'sub_appid' => '',
+            'sub_app_id' => '',
             'sub_miniapp_id' => '',
-            'notify_url'     => '',
-            'cert_client'    => '/addons/epay/certs/apiclient_cert.pem',
-            'cert_key'       => '/addons/epay/certs/apiclient_key.pem',
-            'log'            => '1',
+            'notify_url' => '',
+            'cert_client' => '/addons/epay/certs/apiclient_cert.pem',
+            'cert_key' => '/addons/epay/certs/apiclient_key.pem',
+            'log' => '1',
         ],
-        'rule'    => 'required',
-        'msg'     => '',
-        'tip'     => '微信参数配置',
-        'ok'      => '',
-        'extend'  => '',
+        'rule' => 'required',
+        'msg' => '',
+        'tip' => '微信参数配置',
+        'ok' => '',
+        'extend' => '',
     ],
     [
-        'name'    => 'alipay',
-        'title'   => '支付宝',
-        'type'    => 'array',
+        'name' => 'alipay',
+        'title' => '支付宝',
+        'type' => 'array',
         'content' => [],
-        'value'   => [
-            'app_id'              => '',
-            'mode'                => 'normal',
-            'notify_url'          => '/addons/epay/api/notifyx/type/alipay',
-            'return_url'          => '/addons/epay/api/returnx/type/alipay',
-            'private_key'         => '',
-            'signtype'            => 'cert',
-            'pid'                 => '',
-            'ali_public_key'      => '',
+        'value' => [
+            'app_id' => '',
+            'mode' => 'normal',
+            'notify_url' => '/addons/epay/api/notifyx/type/alipay',
+            'return_url' => '/addons/epay/api/returnx/type/alipay',
+            'private_key' => '',
+            'signtype' => 'cert',
+            'pid' => '',
+            'ali_public_key' => '',
             'app_cert_public_key' => '',
-            'alipay_root_cert'    => '',
-            'log'                 => '1',
-            'scanpay'             => '0',
+            'alipay_root_cert' => '',
+            'log' => '1',
+            'scanpay' => '0',
         ],
-        'rule'    => 'required',
-        'msg'     => '',
-        'tip'     => '支付宝参数配置',
-        'ok'      => '',
-        'extend'  => '',
-    ]
+        'rule' => 'required',
+        'msg' => '',
+        'tip' => '支付宝参数配置',
+        'ok' => '',
+        'extend' => '',
+    ],
 ];

+ 2 - 2
addons/epay/info.ini

@@ -3,8 +3,8 @@ title = 微信支付宝整合
 intro = 可用于快速整合企业微信、支付宝支付功能
 author = FastAdmin
 website = https://www.fastadmin.net
-version = 1.3.9
-state = 0
+version = 1.3.10
+state = 1
 url = /addons/epay
 license = regular
 licenseto = 9671

+ 1 - 0
addons/epay/library/v2/version.txt

@@ -0,0 +1 @@
+v2.10.6

+ 1 - 0
addons/epay/library/v3/version.txt

@@ -0,0 +1 @@
+v3.4.1

+ 342 - 0
addons/epay/library/v3new/Yansongda/Artful/Artful.php

@@ -0,0 +1,342 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful;
+
+use Closure;
+use Illuminate\Container\Container as LaravelContainer;
+use Psr\Container\ContainerInterface;
+use Psr\Container\NotFoundExceptionInterface;
+use Psr\Http\Message\MessageInterface;
+use Throwable;
+use Yansongda\Artful\Contract\ConfigInterface;
+use Yansongda\Artful\Contract\DirectionInterface;
+use Yansongda\Artful\Contract\HttpClientFactoryInterface;
+use Yansongda\Artful\Contract\PackerInterface;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Contract\ServiceProviderInterface;
+use Yansongda\Artful\Contract\ShortcutInterface;
+use Yansongda\Artful\Direction\CollectionDirection;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\ContainerNotFoundException;
+use Yansongda\Artful\Exception\Exception;
+use Yansongda\Artful\Exception\InvalidParamsException;
+use Yansongda\Artful\Exception\InvalidResponseException;
+use Yansongda\Artful\Exception\ServiceNotFoundException;
+use Yansongda\Artful\Packer\JsonPacker;
+use Yansongda\Artful\Service\ConfigServiceProvider;
+use Yansongda\Artful\Service\ContainerServiceProvider;
+use Yansongda\Artful\Service\EventServiceProvider;
+use Yansongda\Artful\Service\HttpServiceProvider;
+use Yansongda\Artful\Service\LoggerServiceProvider;
+use Yansongda\Supports\Collection;
+use Yansongda\Supports\Config;
+use Yansongda\Supports\Pipeline;
+
+class Artful
+{
+    /**
+     * @var string[]
+     */
+    private array $coreService = [
+        ContainerServiceProvider::class,
+        ConfigServiceProvider::class,
+        LoggerServiceProvider::class,
+        EventServiceProvider::class,
+        HttpServiceProvider::class,
+    ];
+
+    private static null|Closure|ContainerInterface $container = null;
+
+    /**
+     * @throws ContainerException
+     */
+    private function __construct(array $config, null|Closure|ContainerInterface $container = null)
+    {
+        $this->registerServices($config, $container);
+
+        Artful::set(DirectionInterface::class, CollectionDirection::class);
+        Artful::set(PackerInterface::class, JsonPacker::class);
+    }
+
+    /**
+     * @return mixed
+     *
+     * @throws ContainerException
+     * @throws ServiceNotFoundException
+     */
+    public static function __callStatic(string $service, array $config)
+    {
+        if (!empty($config)) {
+            self::config(...$config);
+        }
+
+        return self::get($service);
+    }
+
+    /**
+     * @throws ContainerException
+     */
+    public static function config(array $config = [], null|Closure|ContainerInterface $container = null): bool
+    {
+        if (self::hasContainer() && !($config['_force'] ?? false)) {
+            return false;
+        }
+
+        new self($config, $container);
+
+        return true;
+    }
+
+    /**
+     * @codeCoverageIgnore
+     *
+     * @throws ContainerException
+     */
+    public static function set(string $name, mixed $value): void
+    {
+        try {
+            $container = Artful::getContainer();
+
+            if ($container instanceof LaravelContainer) {
+                $container->singleton($name, $value instanceof Closure ? $value : static fn () => $value);
+
+                return;
+            }
+
+            if (method_exists($container, 'set')) {
+                $container->set(...func_get_args());
+
+                return;
+            }
+        } catch (ContainerNotFoundException $e) {
+            throw $e;
+        } catch (Throwable $e) {
+            throw new ContainerException('容器异常: '.$e->getMessage());
+        }
+
+        throw new ContainerException('容器异常: 当前容器类型不支持 `set` 方法');
+    }
+
+    /**
+     * @codeCoverageIgnore
+     *
+     * @throws ContainerException
+     */
+    public static function make(string $service, array $parameters = []): mixed
+    {
+        try {
+            $container = Artful::getContainer();
+
+            if (method_exists($container, 'make')) {
+                return $container->make(...func_get_args());
+            }
+        } catch (ContainerNotFoundException $e) {
+            throw $e;
+        } catch (Throwable $e) {
+            throw new ContainerException('容器异常: '.$e->getMessage());
+        }
+
+        $parameters = array_values($parameters);
+
+        return new $service(...$parameters);
+    }
+
+    /**
+     * @throws ServiceNotFoundException
+     * @throws ContainerException
+     */
+    public static function get(string $service): mixed
+    {
+        try {
+            return Artful::getContainer()->get($service);
+        } catch (NotFoundExceptionInterface $e) {
+            throw new ServiceNotFoundException('服务未找到: '.$e->getMessage());
+        } catch (ContainerNotFoundException $e) {
+            throw $e;
+        } catch (Throwable $e) {
+            throw new ContainerException('容器异常: '.$e->getMessage());
+        }
+    }
+
+    /**
+     * @throws ContainerNotFoundException
+     */
+    public static function has(string $service): bool
+    {
+        return Artful::getContainer()->has($service);
+    }
+
+    public static function setContainer(null|Closure|ContainerInterface $container): void
+    {
+        self::$container = $container;
+    }
+
+    /**
+     * @throws ContainerNotFoundException
+     */
+    public static function getContainer(): ContainerInterface
+    {
+        if (self::$container instanceof ContainerInterface) {
+            return self::$container;
+        }
+
+        if (self::$container instanceof Closure) {
+            return (self::$container)();
+        }
+
+        throw new ContainerNotFoundException('容器未找到: `getContainer()` 方法调用失败! 或许你应该先 `setContainer()`');
+    }
+
+    public static function hasContainer(): bool
+    {
+        return self::$container instanceof ContainerInterface || self::$container instanceof Closure;
+    }
+
+    public static function clear(): void
+    {
+        self::$container = null;
+    }
+
+    /**
+     * @throws ContainerException
+     */
+    public static function load(string $service, mixed $data = null): void
+    {
+        self::registerService($service, $data);
+    }
+
+    /**
+     * @throws ContainerException
+     */
+    public static function registerService(string $service, mixed $data = null): void
+    {
+        $var = new $service();
+
+        if ($var instanceof ServiceProviderInterface) {
+            $var->register($data);
+        }
+    }
+
+    /**
+     * @throws ContainerException
+     * @throws InvalidParamsException
+     * @throws ServiceNotFoundException
+     */
+    public static function shortcut(string $shortcut, array $params = []): null|Collection|MessageInterface|Rocket
+    {
+        if (!class_exists($shortcut) || !in_array(ShortcutInterface::class, class_implements($shortcut))) {
+            throw new InvalidParamsException(Exception::PARAMS_SHORTCUT_INVALID, "参数异常: [{$shortcut}] 未实现 `ShortcutInterface`");
+        }
+
+        /* @var ShortcutInterface $shortcutInstance */
+        $shortcutInstance = self::get($shortcut);
+
+        return self::artful($shortcutInstance->getPlugins($params), $params);
+    }
+
+    /**
+     * @throws ContainerException
+     * @throws InvalidParamsException
+     */
+    public static function artful(array $plugins, array $params): null|Collection|MessageInterface|Rocket
+    {
+        Event::dispatch(new Event\ArtfulStart($plugins, $params));
+
+        self::verifyPlugin($plugins);
+
+        /* @var Pipeline $pipeline */
+        $pipeline = self::make(Pipeline::class);
+
+        /* @var Rocket $rocket */
+        $rocket = $pipeline
+            ->send((new Rocket())->setParams($params)->setPayload(new Collection()))
+            ->through($plugins)
+            ->via('assembly')
+            ->then(static fn ($rocket) => self::ignite($rocket));
+
+        Event::dispatch(new Event\ArtfulEnd($rocket));
+
+        if (!empty($params['_return_rocket'])) {
+            return $rocket;
+        }
+
+        return $rocket->getDestination();
+    }
+
+    /**
+     * @throws ContainerException
+     * @throws InvalidParamsException
+     * @throws InvalidResponseException
+     * @throws ServiceNotFoundException
+     */
+    public static function ignite(Rocket $rocket): Rocket
+    {
+        if (!should_do_http_request($rocket->getDirection())) {
+            return $rocket;
+        }
+
+        /* @var HttpClientFactoryInterface $httpFactory */
+        $httpFactory = self::get(HttpClientFactoryInterface::class);
+        /* @var Config $config */
+        $config = self::get(ConfigInterface::class);
+
+        if (!$httpFactory instanceof HttpClientFactoryInterface) {
+            throw new InvalidParamsException(Exception::PARAMS_HTTP_CLIENT_FACTORY_INVALID, '参数异常: 配置的 `HttpClientFactoryInterface` 不符合规范');
+        }
+
+        Logger::info('[Artful] 准备请求第三方 API', $rocket->toArray());
+
+        $http = $httpFactory->create(array_merge($config->get('http', []), $rocket->getPayload()?->get('_http') ?? []));
+
+        Event::dispatch(new Event\HttpStart($rocket));
+
+        try {
+            $response = $http->sendRequest($rocket->getRadar());
+
+            $rocket->setDestination(clone $response)
+                ->setDestinationOrigin(clone $response);
+        } catch (Throwable $e) {
+            Logger::error('[Artful] 请求第三方 API 出错', ['message' => $e->getMessage(), 'rocket' => $rocket->toArray(), 'trace' => $e->getTrace()]);
+
+            throw new InvalidResponseException(Exception::REQUEST_RESPONSE_ERROR, '响应异常: 请求第三方 API 出错 - '.$e->getMessage(), [], $e);
+        }
+
+        Logger::info('[Artful] 请求第三方 API 成功', ['rocket' => $rocket->toArray()]);
+
+        Event::dispatch(new Event\HttpEnd($rocket));
+
+        return $rocket;
+    }
+
+    /**
+     * @throws InvalidParamsException
+     */
+    protected static function verifyPlugin(array $plugins): void
+    {
+        foreach ($plugins as $plugin) {
+            if (is_callable($plugin)) {
+                continue;
+            }
+
+            if ((is_object($plugin)
+                    || (is_string($plugin) && class_exists($plugin)))
+                && in_array(PluginInterface::class, class_implements($plugin))) {
+                continue;
+            }
+
+            throw new InvalidParamsException(Exception::PARAMS_PLUGIN_INCOMPATIBLE, "参数异常: [{$plugin}] 插件未实现 `PluginInterface`");
+        }
+    }
+
+    /**
+     * @throws ContainerException
+     */
+    private function registerServices(array $config, null|Closure|ContainerInterface $container = null): void
+    {
+        foreach ($this->coreService as $service) {
+            self::registerService($service, ContainerServiceProvider::class == $service ? $container : $config);
+        }
+    }
+}

+ 14 - 0
addons/epay/library/v3new/Yansongda/Artful/Contract/ConfigInterface.php

@@ -0,0 +1,14 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Contract;
+
+interface ConfigInterface
+{
+    public function get(string $key, mixed $default = null): mixed;
+
+    public function has(string $key): bool;
+
+    public function set(string $key, mixed $value): void;
+}

+ 12 - 0
addons/epay/library/v3new/Yansongda/Artful/Contract/ContainerInterface.php

@@ -0,0 +1,12 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Contract;
+
+interface ContainerInterface extends \Psr\Container\ContainerInterface
+{
+    public function make(string $name, array $parameters = []): mixed;
+
+    public function set(string $name, mixed $entry): mixed;
+}

+ 12 - 0
addons/epay/library/v3new/Yansongda/Artful/Contract/DirectionInterface.php

@@ -0,0 +1,12 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Contract;
+
+use Psr\Http\Message\ResponseInterface;
+
+interface DirectionInterface
+{
+    public function guide(PackerInterface $packer, ?ResponseInterface $response, array $params = []): mixed;
+}

+ 7 - 0
addons/epay/library/v3new/Yansongda/Artful/Contract/EventDispatcherInterface.php

@@ -0,0 +1,7 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Contract;
+
+interface EventDispatcherInterface extends \Psr\EventDispatcher\EventDispatcherInterface {}

+ 12 - 0
addons/epay/library/v3new/Yansongda/Artful/Contract/HttpClientFactoryInterface.php

@@ -0,0 +1,12 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Contract;
+
+use Psr\Http\Client\ClientInterface;
+
+interface HttpClientFactoryInterface
+{
+    public function create(array $options = []): ClientInterface;
+}

+ 9 - 0
addons/epay/library/v3new/Yansongda/Artful/Contract/HttpClientInterface.php

@@ -0,0 +1,9 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Contract;
+
+use Psr\Http\Client\ClientInterface;
+
+interface HttpClientInterface extends ClientInterface {}

+ 7 - 0
addons/epay/library/v3new/Yansongda/Artful/Contract/LoggerInterface.php

@@ -0,0 +1,7 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Contract;
+
+interface LoggerInterface extends \Psr\Log\LoggerInterface {}

+ 14 - 0
addons/epay/library/v3new/Yansongda/Artful/Contract/PackerInterface.php

@@ -0,0 +1,14 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Contract;
+
+use Yansongda\Supports\Collection;
+
+interface PackerInterface
+{
+    public function pack(null|array|Collection $payload, ?array $params = null): string;
+
+    public function unpack(string $payload, ?array $params = null): ?array;
+}

+ 13 - 0
addons/epay/library/v3new/Yansongda/Artful/Contract/PluginInterface.php

@@ -0,0 +1,13 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Contract;
+
+use Closure;
+use Yansongda\Artful\Rocket;
+
+interface PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket;
+}

+ 15 - 0
addons/epay/library/v3new/Yansongda/Artful/Contract/ServiceProviderInterface.php

@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Contract;
+
+use Yansongda\Artful\Exception\ContainerException;
+
+interface ServiceProviderInterface
+{
+    /**
+     * @throws ContainerException
+     */
+    public function register(mixed $data = null): void;
+}

+ 13 - 0
addons/epay/library/v3new/Yansongda/Artful/Contract/ShortcutInterface.php

@@ -0,0 +1,13 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Contract;
+
+interface ShortcutInterface
+{
+    /**
+     * @return PluginInterface[]|string[]
+     */
+    public function getPlugins(array $params): array;
+}

+ 33 - 0
addons/epay/library/v3new/Yansongda/Artful/Direction/CollectionDirection.php

@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Direction;
+
+use Psr\Http\Message\ResponseInterface;
+use Yansongda\Artful\Contract\DirectionInterface;
+use Yansongda\Artful\Contract\PackerInterface;
+use Yansongda\Artful\Exception\Exception;
+use Yansongda\Artful\Exception\InvalidResponseException;
+use Yansongda\Supports\Collection;
+
+class CollectionDirection implements DirectionInterface
+{
+    /**
+     * @throws InvalidResponseException
+     */
+    public function guide(PackerInterface $packer, ?ResponseInterface $response, array $params = []): Collection
+    {
+        if (is_null($response)) {
+            throw new InvalidResponseException(Exception::RESPONSE_EMPTY, '响应异常: 响应为空,不能进行 direction');
+        }
+
+        $body = (string) $response->getBody();
+
+        if (!is_null($result = $packer->unpack($body, $params))) {
+            return new Collection($result);
+        }
+
+        throw new InvalidResponseException(Exception::RESPONSE_UNPACK_ERROR, '响应异常: 解包错误', ['body' => $body, 'response' => $response]);
+    }
+}

+ 17 - 0
addons/epay/library/v3new/Yansongda/Artful/Direction/NoHttpRequestDirection.php

@@ -0,0 +1,17 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Direction;
+
+use Psr\Http\Message\ResponseInterface;
+use Yansongda\Artful\Contract\DirectionInterface;
+use Yansongda\Artful\Contract\PackerInterface;
+
+class NoHttpRequestDirection implements DirectionInterface
+{
+    public function guide(PackerInterface $packer, ?ResponseInterface $response, array $params = []): ?ResponseInterface
+    {
+        return $response;
+    }
+}

+ 26 - 0
addons/epay/library/v3new/Yansongda/Artful/Direction/OriginResponseDirection.php

@@ -0,0 +1,26 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Direction;
+
+use Psr\Http\Message\ResponseInterface;
+use Yansongda\Artful\Contract\DirectionInterface;
+use Yansongda\Artful\Contract\PackerInterface;
+use Yansongda\Artful\Exception\Exception;
+use Yansongda\Artful\Exception\InvalidResponseException;
+
+class OriginResponseDirection implements DirectionInterface
+{
+    /**
+     * @throws InvalidResponseException
+     */
+    public function guide(PackerInterface $packer, ?ResponseInterface $response, array $params = []): ?ResponseInterface
+    {
+        if (is_null($response)) {
+            throw new InvalidResponseException(Exception::RESPONSE_EMPTY, '响应异常: 响应为空,不能进行 direction');
+        }
+
+        return $response;
+    }
+}

+ 7 - 0
addons/epay/library/v3new/Yansongda/Artful/Direction/ResponseDirection.php

@@ -0,0 +1,7 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Direction;
+
+class ResponseDirection extends NoHttpRequestDirection {}

+ 39 - 0
addons/epay/library/v3new/Yansongda/Artful/Event.php

@@ -0,0 +1,39 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful;
+
+use Yansongda\Artful\Contract\EventDispatcherInterface;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\Exception;
+use Yansongda\Artful\Exception\InvalidParamsException;
+use Yansongda\Artful\Exception\ServiceNotFoundException;
+
+/**
+ * @method static Event\Event dispatch(object $event)
+ */
+class Event
+{
+    /**
+     * @throws ContainerException
+     * @throws ServiceNotFoundException
+     * @throws InvalidParamsException
+     */
+    public static function __callStatic(string $method, array $args): void
+    {
+        if (!Artful::hasContainer() || !Artful::has(EventDispatcherInterface::class)) {
+            return;
+        }
+
+        $class = Artful::get(EventDispatcherInterface::class);
+
+        if ($class instanceof \Psr\EventDispatcher\EventDispatcherInterface) {
+            $class->{$method}(...$args);
+
+            return;
+        }
+
+        throw new InvalidParamsException(Exception::PARAMS_EVENT_DRIVER_INVALID, '参数异常: 配置的 `EventDispatcherInterface` 不符合 PSR 规范');
+    }
+}

+ 7 - 0
addons/epay/library/v3new/Yansongda/Artful/Event/ArtfulEnd.php

@@ -0,0 +1,7 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Event;
+
+class ArtfulEnd extends Event {}

+ 10 - 0
addons/epay/library/v3new/Yansongda/Artful/Event/ArtfulStart.php

@@ -0,0 +1,10 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Event;
+
+class ArtfulStart extends Event
+{
+    public function __construct(public array $plugins, public array $params) {}
+}

+ 12 - 0
addons/epay/library/v3new/Yansongda/Artful/Event/Event.php

@@ -0,0 +1,12 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Event;
+
+use Yansongda\Artful\Rocket;
+
+class Event
+{
+    public function __construct(public ?Rocket $rocket = null) {}
+}

+ 7 - 0
addons/epay/library/v3new/Yansongda/Artful/Event/HttpEnd.php

@@ -0,0 +1,7 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Event;
+
+class HttpEnd extends Event {}

+ 7 - 0
addons/epay/library/v3new/Yansongda/Artful/Event/HttpStart.php

@@ -0,0 +1,7 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Event;
+
+class HttpStart extends Event {}

+ 16 - 0
addons/epay/library/v3new/Yansongda/Artful/Exception/ContainerException.php

@@ -0,0 +1,16 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Exception;
+
+use Psr\Container\ContainerExceptionInterface;
+use Throwable;
+
+class ContainerException extends Exception implements ContainerExceptionInterface
+{
+    public function __construct(string $message = '容器异常', int $code = self::CONTAINER_ERROR, mixed $extra = null, ?Throwable $previous = null)
+    {
+        parent::__construct($message, $code, $extra, $previous);
+    }
+}

+ 15 - 0
addons/epay/library/v3new/Yansongda/Artful/Exception/ContainerNotFoundException.php

@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Exception;
+
+use Throwable;
+
+class ContainerNotFoundException extends ContainerException
+{
+    public function __construct(string $message = '容器未找到', int $code = self::CONTAINER_NOT_FOUND, mixed $extra = null, ?Throwable $previous = null)
+    {
+        parent::__construct($message, $code, $extra, $previous);
+    }
+}

+ 69 - 0
addons/epay/library/v3new/Yansongda/Artful/Exception/Exception.php

@@ -0,0 +1,69 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Exception;
+
+use Throwable;
+
+class Exception extends \Exception
+{
+    public const UNKNOWN_ERROR = 9999;
+
+    /**
+     * 关于容器.
+     */
+    public const CONTAINER_ERROR = 9100;
+
+    public const CONTAINER_NOT_FOUND = 9101;
+
+    public const CONTAINER_SERVICE_NOT_FOUND = 9102;
+
+    /**
+     * 关于参数.
+     */
+    public const PARAMS_ERROR = 9200;
+
+    public const PARAMS_DIRECTION_INVALID = 9201;
+
+    public const PARAMS_PACKER_INVALID = 9202;
+
+    public const PARAMS_EVENT_DRIVER_INVALID = 9203;
+
+    public const PARAMS_HTTP_CLIENT_INVALID = 9204;
+
+    public const PARAMS_LOGGER_DRIVER_INVALID = 9205;
+
+    public const PARAMS_HTTP_CLIENT_FACTORY_INVALID = 9206;
+
+    public const PARAMS_PLUGIN_INCOMPATIBLE = 9207;
+
+    public const PARAMS_PARSER_DIRECTION_INVALID = 9208;
+
+    public const PARAMS_SHORTCUT_INVALID = 9209;
+
+    /**
+     * 关于响应.
+     */
+    public const RESPONSE_ERROR = 9300;
+
+    public const REQUEST_RESPONSE_ERROR = 9301;
+
+    public const RESPONSE_UNPACK_ERROR = 9302;
+
+    public const RESPONSE_EMPTY = 9303;
+
+    /**
+     * 关于配置.
+     */
+    public const CONFIG_ERROR = 9400;
+
+    public mixed $extra;
+
+    public function __construct(string $message = '未知异常', int $code = self::UNKNOWN_ERROR, mixed $extra = null, ?Throwable $previous = null)
+    {
+        $this->extra = $extra;
+
+        parent::__construct($message, $code, $previous);
+    }
+}

+ 18 - 0
addons/epay/library/v3new/Yansongda/Artful/Exception/InvalidConfigException.php

@@ -0,0 +1,18 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Exception;
+
+use Throwable;
+
+/**
+ * @codeCoverageIgnore
+ */
+class InvalidConfigException extends Exception
+{
+    public function __construct(int $code = self::CONFIG_ERROR, string $message = '配置异常', mixed $extra = null, ?Throwable $previous = null)
+    {
+        parent::__construct($message, $code, $extra, $previous);
+    }
+}

+ 15 - 0
addons/epay/library/v3new/Yansongda/Artful/Exception/InvalidParamsException.php

@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Exception;
+
+use Throwable;
+
+class InvalidParamsException extends Exception
+{
+    public function __construct(int $code = self::PARAMS_ERROR, string $message = '参数异常', mixed $extra = null, ?Throwable $previous = null)
+    {
+        parent::__construct($message, $code, $extra, $previous);
+    }
+}

+ 23 - 0
addons/epay/library/v3new/Yansongda/Artful/Exception/InvalidResponseException.php

@@ -0,0 +1,23 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Exception;
+
+use Throwable;
+
+class InvalidResponseException extends Exception
+{
+    public mixed $response;
+
+    public function __construct(
+        int $code = self::RESPONSE_ERROR,
+        string $message = '响应异常',
+        mixed $extra = null,
+        ?Throwable $previous = null
+    ) {
+        $this->response = $extra;
+
+        parent::__construct($message, $code, $extra, $previous);
+    }
+}

+ 16 - 0
addons/epay/library/v3new/Yansongda/Artful/Exception/ServiceNotFoundException.php

@@ -0,0 +1,16 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Exception;
+
+use Psr\Container\NotFoundExceptionInterface;
+use Throwable;
+
+class ServiceNotFoundException extends Exception implements NotFoundExceptionInterface
+{
+    public function __construct(string $message = '服务未找到', int $code = self::CONTAINER_SERVICE_NOT_FOUND, mixed $extra = null, ?Throwable $previous = null)
+    {
+        parent::__construct($message, $code, $extra, $previous);
+    }
+}

+ 93 - 0
addons/epay/library/v3new/Yansongda/Artful/Functions.php

@@ -0,0 +1,93 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful;
+
+use Closure;
+use Yansongda\Artful\Contract\DirectionInterface;
+use Yansongda\Artful\Contract\PackerInterface;
+use Yansongda\Artful\Direction\NoHttpRequestDirection;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\Exception;
+use Yansongda\Artful\Exception\InvalidParamsException;
+use Yansongda\Artful\Exception\ServiceNotFoundException;
+use Yansongda\Supports\Collection;
+use Yansongda\Supports\Str;
+
+function should_do_http_request(string $direction): bool
+{
+    return NoHttpRequestDirection::class !== $direction
+        && !in_array(NoHttpRequestDirection::class, class_parents($direction));
+}
+
+/**
+ * @throws InvalidParamsException
+ */
+function get_direction(mixed $direction): DirectionInterface
+{
+    try {
+        $direction = Artful::get($direction);
+
+        $direction = is_string($direction) ? Artful::get($direction) : $direction;
+    } catch (ContainerException|ServiceNotFoundException) {
+    }
+
+    if (!$direction instanceof DirectionInterface) {
+        throw new InvalidParamsException(Exception::PARAMS_DIRECTION_INVALID, '参数异常: 配置的 `DirectionInterface` 未实现 `DirectionInterface`');
+    }
+
+    return $direction;
+}
+
+/**
+ * @throws InvalidParamsException
+ */
+function get_packer(mixed $packer): PackerInterface
+{
+    try {
+        $packer = Artful::get($packer);
+
+        $packer = is_string($packer) ? Artful::get($packer) : $packer;
+    } catch (ContainerException|ServiceNotFoundException) {
+    }
+
+    if (!$packer instanceof PackerInterface) {
+        throw new InvalidParamsException(Exception::PARAMS_PACKER_INVALID, '参数异常: 配置的 `PackerInterface` 未实现 `PackerInterface`');
+    }
+
+    return $packer;
+}
+
+function filter_params(null|array|Collection $params, ?Closure $closure = null): Collection
+{
+    $params = Collection::wrap($params);
+
+    return $params->filter(static fn ($v, $k) => !Str::startsWith($k, '_') && !is_null($v) && (empty($closure) || $closure($k, $v)));
+}
+
+function get_radar_method(?Collection $payload): ?string
+{
+    $string = $payload?->get('_method') ?? null;
+
+    if (is_null($string)) {
+        return null;
+    }
+
+    return strtoupper($string);
+}
+
+function get_radar_url(?Collection $payload): ?string
+{
+    return $payload?->get('_url') ?? null;
+}
+
+function get_radar_body(?Collection $payload): mixed
+{
+    return $payload?->get('_body') ?? null;
+}
+
+function get_radar_headers(?Collection $payload): mixed
+{
+    return $payload?->get('_headers') ?? null;
+}

+ 39 - 0
addons/epay/library/v3new/Yansongda/Artful/HttpClientFactory.php

@@ -0,0 +1,39 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful;
+
+use GuzzleHttp\Client;
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Container\ContainerInterface;
+use Psr\Container\NotFoundExceptionInterface;
+use Psr\Http\Client\ClientInterface;
+use Yansongda\Artful\Contract\HttpClientInterface;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\Exception;
+use Yansongda\Artful\Exception\InvalidParamsException;
+
+class HttpClientFactory implements Contract\HttpClientFactoryInterface
+{
+    public function __construct(private ContainerInterface $container) {}
+
+    /**
+     * @throws ContainerExceptionInterface
+     * @throws ContainerException
+     * @throws InvalidParamsException
+     * @throws NotFoundExceptionInterface
+     */
+    public function create(?array $options = []): ClientInterface
+    {
+        if ($this->container->has(HttpClientInterface::class)) {
+            if (($http = $this->container->get(HttpClientInterface::class)) instanceof ClientInterface) {
+                return $http;
+            }
+
+            throw new InvalidParamsException(Exception::PARAMS_HTTP_CLIENT_INVALID, '参数异常: `HttpClient` 不符合 PSR 规范');
+        }
+
+        return new Client($options);
+    }
+}

+ 49 - 0
addons/epay/library/v3new/Yansongda/Artful/Logger.php

@@ -0,0 +1,49 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful;
+
+use Yansongda\Artful\Contract\ConfigInterface;
+use Yansongda\Artful\Contract\LoggerInterface;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\Exception;
+use Yansongda\Artful\Exception\InvalidParamsException;
+use Yansongda\Artful\Exception\ServiceNotFoundException;
+
+/**
+ * @method static void emergency($message, array $context = [])
+ * @method static void alert($message, array $context = [])
+ * @method static void critical($message, array $context = [])
+ * @method static void error($message, array $context = [])
+ * @method static void warning($message, array $context = [])
+ * @method static void notice($message, array $context = [])
+ * @method static void info($message, array $context = [])
+ * @method static void debug($message, array $context = [])
+ * @method static void log($message, array $context = [])
+ */
+class Logger
+{
+    /**
+     * @throws ContainerException
+     * @throws ServiceNotFoundException
+     * @throws InvalidParamsException
+     */
+    public static function __callStatic(string $method, array $args): void
+    {
+        if (!Artful::hasContainer() || !Artful::has(LoggerInterface::class)
+            || false === Artful::get(ConfigInterface::class)->get('logger.enable', false)) {
+            return;
+        }
+
+        $class = Artful::get(LoggerInterface::class);
+
+        if ($class instanceof \Psr\Log\LoggerInterface) {
+            $class->{$method}(...$args);
+
+            return;
+        }
+
+        throw new InvalidParamsException(Exception::PARAMS_LOGGER_DRIVER_INVALID, '配置异常: 配置的 `LoggerInterface` 不符合 PSR 规范');
+    }
+}

+ 26 - 0
addons/epay/library/v3new/Yansongda/Artful/Packer/JsonPacker.php

@@ -0,0 +1,26 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Packer;
+
+use Yansongda\Artful\Contract\PackerInterface;
+use Yansongda\Supports\Arr;
+use Yansongda\Supports\Collection;
+
+class JsonPacker implements PackerInterface
+{
+    public function pack(null|array|Collection $payload, ?array $params = null): string
+    {
+        if (($payload instanceof Collection && $payload->isEmpty()) || empty($payload)) {
+            return '';
+        }
+
+        return Collection::wrap($payload)->toJson();
+    }
+
+    public function unpack(string $payload, ?array $params = null): ?array
+    {
+        return Arr::wrapJson($payload);
+    }
+}

+ 22 - 0
addons/epay/library/v3new/Yansongda/Artful/Packer/QueryPacker.php

@@ -0,0 +1,22 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Packer;
+
+use Yansongda\Artful\Contract\PackerInterface;
+use Yansongda\Supports\Arr;
+use Yansongda\Supports\Collection;
+
+class QueryPacker implements PackerInterface
+{
+    public function pack(null|array|Collection $payload, ?array $params = null): string
+    {
+        return Collection::wrap($payload)->query();
+    }
+
+    public function unpack(string $payload, ?array $params = null): array
+    {
+        return Arr::wrapQuery($payload, !empty($params['_unpack_raw']));
+    }
+}

+ 22 - 0
addons/epay/library/v3new/Yansongda/Artful/Packer/XmlPacker.php

@@ -0,0 +1,22 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Packer;
+
+use Yansongda\Artful\Contract\PackerInterface;
+use Yansongda\Supports\Arr;
+use Yansongda\Supports\Collection;
+
+class XmlPacker implements PackerInterface
+{
+    public function pack(null|array|Collection $payload, ?array $params = null): string
+    {
+        return Collection::wrap($payload)->toXml();
+    }
+
+    public function unpack(string $payload, ?array $params = null): array
+    {
+        return Arr::wrapXml($payload);
+    }
+}

+ 33 - 0
addons/epay/library/v3new/Yansongda/Artful/Plugin/AddPayloadBodyPlugin.php

@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Plugin;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Exception\InvalidParamsException;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+use function Yansongda\Artful\filter_params;
+use function Yansongda\Artful\get_packer;
+
+class AddPayloadBodyPlugin implements PluginInterface
+{
+    /**
+     * @throws InvalidParamsException
+     */
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[AddPayloadBodyPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $packer = get_packer($rocket->getPacker());
+
+        $rocket->mergePayload(['_body' => $packer->pack(filter_params($rocket->getPayload()))]);
+
+        Logger::info('[AddPayloadBodyPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 45 - 0
addons/epay/library/v3new/Yansongda/Artful/Plugin/AddRadarPlugin.php

@@ -0,0 +1,45 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Plugin;
+
+use Closure;
+use GuzzleHttp\Psr7\Request;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+use function Yansongda\Artful\get_radar_body;
+use function Yansongda\Artful\get_radar_headers;
+use function Yansongda\Artful\get_radar_method;
+use function Yansongda\Artful\get_radar_url;
+
+class AddRadarPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[AddRadarPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $payload = $rocket->getPayload();
+
+        $rocket->setRadar(new Request(
+            get_radar_method($payload) ?? 'POST',
+            get_radar_url($payload),
+            get_radar_headers($payload) ?? $this->getHeaders(),
+            get_radar_body($payload),
+        ));
+
+        Logger::info('[AddRadarPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+
+    protected function getHeaders(): array
+    {
+        return [
+            'User-Agent' => 'yansongda/artful-v1',
+            'Content-Type' => 'application/json;charset=utf-8',
+        ];
+    }
+}

+ 45 - 0
addons/epay/library/v3new/Yansongda/Artful/Plugin/ParserPlugin.php

@@ -0,0 +1,45 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Plugin;
+
+use Closure;
+use Psr\Http\Message\ResponseInterface;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Exception\Exception;
+use Yansongda\Artful\Exception\InvalidParamsException;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+use function Yansongda\Artful\get_direction;
+use function Yansongda\Artful\get_packer;
+
+class ParserPlugin implements PluginInterface
+{
+    /**
+     * @throws InvalidParamsException
+     */
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        /* @var Rocket $rocket */
+        $rocket = $next($rocket);
+
+        Logger::debug('[ParserPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $response = $rocket->getDestination();
+        $direction = get_direction($rocket->getDirection());
+        $packer = get_packer($rocket->getPacker());
+        $payload = $rocket->getPayload();
+
+        if (!is_null($response) && !($response instanceof ResponseInterface)) {
+            throw new InvalidParamsException(Exception::PARAMS_PARSER_DIRECTION_INVALID, '参数异常: 解析插件中 `Rocket` 的 `destination` 只能是 `null` 或者 `ResponseInterface`');
+        }
+
+        $rocket->setDestination($direction->guide($packer, $response, $payload?->all() ?? []));
+
+        Logger::debug('[ParserPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $rocket;
+    }
+}

+ 24 - 0
addons/epay/library/v3new/Yansongda/Artful/Plugin/StartPlugin.php

@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Plugin;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+class StartPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[StartPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload($rocket->getParams());
+
+        Logger::info('[StartPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 180 - 0
addons/epay/library/v3new/Yansongda/Artful/Rocket.php

@@ -0,0 +1,180 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful;
+
+use ArrayAccess;
+use JsonSerializable as JsonSerializableInterface;
+use Psr\Http\Message\MessageInterface;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Yansongda\Artful\Contract\DirectionInterface;
+use Yansongda\Artful\Contract\PackerInterface;
+use Yansongda\Supports\Collection;
+use Yansongda\Supports\Traits\Accessable;
+use Yansongda\Supports\Traits\Arrayable;
+use Yansongda\Supports\Traits\Serializable;
+
+class Rocket implements JsonSerializableInterface, ArrayAccess
+{
+    use Accessable;
+    use Arrayable;
+    use Serializable;
+
+    private ?RequestInterface $radar = null;
+
+    private array $params = [];
+
+    private ?Collection $payload = null;
+
+    private string $packer = PackerInterface::class;
+
+    private string $direction = DirectionInterface::class;
+
+    private null|Collection|MessageInterface $destination = null;
+
+    private null|RequestInterface|ResponseInterface $destinationOrigin = null;
+
+    public function getRadar(): ?RequestInterface
+    {
+        return $this->radar;
+    }
+
+    public function setRadar(?RequestInterface $radar): Rocket
+    {
+        $this->radar = $radar;
+
+        return $this;
+    }
+
+    public function getParams(): array
+    {
+        return $this->params;
+    }
+
+    public function setParams(array $params): Rocket
+    {
+        $this->params = $params;
+
+        return $this;
+    }
+
+    public function mergeParams(array $params): Rocket
+    {
+        $this->params = array_merge($this->params, $params);
+
+        return $this;
+    }
+
+    public function getPayload(): ?Collection
+    {
+        return $this->payload;
+    }
+
+    public function setPayload(null|array|Collection $payload): Rocket
+    {
+        if (is_array($payload)) {
+            $payload = new Collection($payload);
+        }
+
+        $this->payload = $payload;
+
+        return $this;
+    }
+
+    public function mergePayload(array $payload): Rocket
+    {
+        if (empty($this->payload)) {
+            $this->payload = new Collection();
+        }
+
+        $this->payload = $this->payload->merge($payload);
+
+        return $this;
+    }
+
+    public function exceptPayload(mixed $key): Rocket
+    {
+        if (empty($this->payload)) {
+            return $this;
+        }
+
+        $this->payload = $this->payload->except($key);
+
+        return $this;
+    }
+
+    public function getPacker(): string
+    {
+        return $this->packer;
+    }
+
+    public function setPacker(string $packer): Rocket
+    {
+        $this->packer = $packer;
+
+        return $this;
+    }
+
+    public function getDirection(): string
+    {
+        return $this->direction;
+    }
+
+    public function setDirection(string $direction): Rocket
+    {
+        $this->direction = $direction;
+
+        return $this;
+    }
+
+    public function getDestination(): null|Collection|MessageInterface
+    {
+        return $this->destination;
+    }
+
+    public function setDestination(null|Collection|MessageInterface $destination): Rocket
+    {
+        $this->destination = $destination;
+
+        return $this;
+    }
+
+    public function getDestinationOrigin(): null|RequestInterface|ResponseInterface
+    {
+        return $this->destinationOrigin;
+    }
+
+    public function setDestinationOrigin(null|RequestInterface|ResponseInterface $destinationOrigin): Rocket
+    {
+        $this->destinationOrigin = $destinationOrigin;
+
+        return $this;
+    }
+
+    public function toArray(): array
+    {
+        $request = $this->getRadar();
+        $destination = $this->getDestinationOrigin();
+
+        return [
+            'radar' => [
+                'url' => $request?->getUri()->__toString(),
+                'method' => $request?->getMethod(),
+                'headers' => $request?->getHeaders(),
+                'body' => (string) $request?->getBody(),
+            ],
+            'params' => $this->getParams(),
+            'payload' => $this->getPayload()?->toArray(),
+            'packer' => $this->getPacker(),
+            'direction' => $this->getDirection(),
+            'destination' => $this->getDestination(),
+            'destination_origin' => [
+                'status' => $destination instanceof ResponseInterface ? $destination->getStatusCode() : null,
+                'headers' => $destination?->getHeaders(),
+                'body' => (string) $destination?->getBody(),
+            ],
+        ];
+    }
+}

+ 42 - 0
addons/epay/library/v3new/Yansongda/Artful/Service/ConfigServiceProvider.php

@@ -0,0 +1,42 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Service;
+
+use Yansongda\Artful\Artful;
+use Yansongda\Artful\Contract\ConfigInterface;
+use Yansongda\Artful\Contract\ServiceProviderInterface;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Supports\Config;
+
+class ConfigServiceProvider implements ServiceProviderInterface
+{
+    private array $config = [
+        'logger' => [
+            'enable' => false,
+            'file' => null,
+            'identify' => 'yansongda.artful',
+            'level' => 'debug',
+            'type' => 'daily',
+            'max_files' => 30,
+        ],
+        'http' => [
+            'timeout' => 5.0,
+            'connect_timeout' => 3.0,
+            'headers' => [
+                'User-Agent' => 'yansongda/artful-v1',
+            ],
+        ],
+    ];
+
+    /**
+     * @throws ContainerException
+     */
+    public function register(mixed $data = null): void
+    {
+        $config = new Config(array_replace_recursive($this->config, $data ?? []));
+
+        Artful::set(ConfigInterface::class, $config);
+    }
+}

+ 108 - 0
addons/epay/library/v3new/Yansongda/Artful/Service/ContainerServiceProvider.php

@@ -0,0 +1,108 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Service;
+
+use Closure;
+use Hyperf\Context\ApplicationContext as HyperfContainer;
+use Hyperf\Pimple\ContainerFactory as DefaultContainer;
+use Illuminate\Container\Container as LaravelContainer;
+use Psr\Container\ContainerInterface;
+use Yansongda\Artful\Artful;
+use Yansongda\Artful\Contract\ServiceProviderInterface;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\ContainerNotFoundException;
+use Yansongda\Artful\Exception\Exception;
+
+/**
+ * @codeCoverageIgnore
+ */
+class ContainerServiceProvider implements ServiceProviderInterface
+{
+    private array $detectApplication = [
+        'laravel' => LaravelContainer::class,
+        'hyperf' => HyperfContainer::class,
+    ];
+
+    /**
+     * @throws ContainerException
+     */
+    public function register(mixed $data = null): void
+    {
+        if ($data instanceof ContainerInterface || $data instanceof Closure) {
+            Artful::setContainer($data);
+
+            return;
+        }
+
+        if (Artful::hasContainer()) {
+            return;
+        }
+
+        foreach ($this->detectApplication as $framework => $application) {
+            $method = $framework.'Application';
+
+            if (class_exists($application) && method_exists($this, $method) && $this->{$method}()) {
+                return;
+            }
+        }
+
+        $this->defaultApplication();
+    }
+
+    /**
+     * @throws ContainerException
+     * @throws ContainerNotFoundException
+     */
+    protected function laravelApplication(): bool
+    {
+        Artful::setContainer(static fn () => LaravelContainer::getInstance());
+
+        Artful::set(\Yansongda\Artful\Contract\ContainerInterface::class, LaravelContainer::getInstance());
+
+        if (!Artful::has(ContainerInterface::class)) {
+            Artful::set(ContainerInterface::class, LaravelContainer::getInstance());
+        }
+
+        return true;
+    }
+
+    /**
+     * @throws ContainerException
+     * @throws ContainerNotFoundException
+     */
+    protected function hyperfApplication(): bool
+    {
+        if (!HyperfContainer::hasContainer()) {
+            return false;
+        }
+
+        Artful::setContainer(static fn () => HyperfContainer::getContainer());
+
+        Artful::set(\Yansongda\Artful\Contract\ContainerInterface::class, HyperfContainer::getContainer());
+
+        if (!Artful::has(ContainerInterface::class)) {
+            Artful::set(ContainerInterface::class, HyperfContainer::getContainer());
+        }
+
+        return true;
+    }
+
+    /**
+     * @throws ContainerException
+     * @throws ContainerNotFoundException
+     */
+    protected function defaultApplication(): void
+    {
+        if (!class_exists(DefaultContainer::class)) {
+            throw new ContainerNotFoundException('容器未找到: Init failed! Maybe you should install `hyperf/pimple` first', Exception::CONTAINER_NOT_FOUND);
+        }
+
+        $container = (new DefaultContainer())();
+
+        Artful::setContainer($container);
+
+        Artful::set(\Yansongda\Artful\Contract\ContainerInterface::class, $container);
+    }
+}

+ 24 - 0
addons/epay/library/v3new/Yansongda/Artful/Service/EventServiceProvider.php

@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Service;
+
+use Symfony\Component\EventDispatcher\EventDispatcher;
+use Yansongda\Artful\Artful;
+use Yansongda\Artful\Contract\EventDispatcherInterface;
+use Yansongda\Artful\Contract\ServiceProviderInterface;
+use Yansongda\Artful\Exception\ContainerException;
+
+class EventServiceProvider implements ServiceProviderInterface
+{
+    /**
+     * @throws ContainerException
+     */
+    public function register(mixed $data = null): void
+    {
+        if (class_exists(EventDispatcher::class)) {
+            Artful::set(EventDispatcherInterface::class, new EventDispatcher());
+        }
+    }
+}

+ 24 - 0
addons/epay/library/v3new/Yansongda/Artful/Service/HttpServiceProvider.php

@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Service;
+
+use Yansongda\Artful\Artful;
+use Yansongda\Artful\Contract\HttpClientFactoryInterface;
+use Yansongda\Artful\Contract\ServiceProviderInterface;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\HttpClientFactory;
+
+class HttpServiceProvider implements ServiceProviderInterface
+{
+    /**
+     * @throws ContainerException
+     */
+    public function register(mixed $data = null): void
+    {
+        $container = Artful::getContainer();
+
+        Artful::set(HttpClientFactoryInterface::class, new HttpClientFactory($container));
+    }
+}

+ 71 - 0
addons/epay/library/v3new/Yansongda/Artful/Service/LoggerServiceProvider.php

@@ -0,0 +1,71 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Artful\Service;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Handler\AbstractProcessingHandler;
+use Monolog\Handler\RotatingFileHandler;
+use Monolog\Handler\StreamHandler;
+use Monolog\Logger;
+use Yansongda\Artful\Artful;
+use Yansongda\Artful\Contract\ConfigInterface;
+use Yansongda\Artful\Contract\LoggerInterface;
+use Yansongda\Artful\Contract\ServiceProviderInterface;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\ServiceNotFoundException;
+
+class LoggerServiceProvider implements ServiceProviderInterface
+{
+    protected array $config = [
+        'enable' => false,
+        'file' => null,
+        'identify' => 'yansongda.artful',
+        'level' => 'DEBUG',
+        'type' => 'daily',
+        'max_files' => 30,
+        'formatter' => "%datetime% > %channel%.%level_name% > %message% %context% %extra%\n\n",
+    ];
+
+    /**
+     * @throws ContainerException
+     * @throws ServiceNotFoundException
+     */
+    public function register(mixed $data = null): void
+    {
+        /* @var ConfigInterface $config */
+        $config = Artful::get(ConfigInterface::class);
+
+        $this->config = array_merge($this->config, $config->get('logger', []));
+
+        if (class_exists(Logger::class) && (true === ($this->config['enable'] ?? false))) {
+            $logger = new Logger($this->config['identify']);
+
+            $logger->pushHandler($this->getDefaultHandler()
+                ->setFormatter($this->getDefaultFormatter()));
+
+            Artful::set(LoggerInterface::class, $logger);
+        }
+    }
+
+    protected function getDefaultFormatter(): LineFormatter
+    {
+        return new LineFormatter(
+            $this->config['formatter'],
+            null,
+            false,
+            true
+        );
+    }
+
+    protected function getDefaultHandler(): AbstractProcessingHandler
+    {
+        $file = $this->config['file'] ?? (sys_get_temp_dir().'/logs/'.$this->config['identify'].'.log');
+
+        return match ($this->config['type']) {
+            'single' => new StreamHandler($file, $this->config['level']),
+            default => new RotatingFileHandler($file, $this->config['max_files'], $this->config['level']),
+        };
+    }
+}

+ 28 - 0
addons/epay/library/v3new/Yansongda/Pay/Contract/ProviderInterface.php

@@ -0,0 +1,28 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Contract;
+
+use Psr\Http\Message\MessageInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Yansongda\Artful\Rocket;
+use Yansongda\Supports\Collection;
+
+interface ProviderInterface
+{
+    public function pay(array $plugins, array $params): null|Collection|MessageInterface|Rocket;
+
+    public function query(array $order): Collection|Rocket;
+
+    public function cancel(array $order): Collection|Rocket;
+
+    public function close(array $order): Collection|Rocket;
+
+    public function refund(array $order): Collection|Rocket;
+
+    public function callback(null|array|ServerRequestInterface $contents = null, ?array $params = null): Collection|Rocket;
+
+    public function success(): ResponseInterface;
+}

+ 27 - 0
addons/epay/library/v3new/Yansongda/Pay/Event/CallbackReceived.php

@@ -0,0 +1,27 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Event;
+
+use Psr\Http\Message\ServerRequestInterface;
+use Yansongda\Artful\Event\Event;
+use Yansongda\Artful\Rocket;
+
+class CallbackReceived extends Event
+{
+    public string $provider;
+
+    public ?array $params = null;
+
+    public null|array|ServerRequestInterface $contents;
+
+    public function __construct(string $provider, null|array|ServerRequestInterface $contents, ?array $params = null, ?Rocket $rocket = null)
+    {
+        $this->provider = $provider;
+        $this->contents = $contents;
+        $this->params = $params;
+
+        parent::__construct($rocket);
+    }
+}

+ 26 - 0
addons/epay/library/v3new/Yansongda/Pay/Event/MethodCalled.php

@@ -0,0 +1,26 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Event;
+
+use Yansongda\Artful\Event\Event;
+use Yansongda\Artful\Rocket;
+
+class MethodCalled extends Event
+{
+    public string $provider;
+
+    public string $name;
+
+    public array $params;
+
+    public function __construct(string $provider, string $name, array $params, ?Rocket $rocket = null)
+    {
+        $this->provider = $provider;
+        $this->name = $name;
+        $this->params = $params;
+
+        parent::__construct($rocket);
+    }
+}

+ 9 - 0
addons/epay/library/v3new/Yansongda/Pay/Event/PayEnd.php

@@ -0,0 +1,9 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Event;
+
+use Yansongda\Artful\Event\Event;
+
+class PayEnd extends Event {}

+ 27 - 0
addons/epay/library/v3new/Yansongda/Pay/Event/PayStart.php

@@ -0,0 +1,27 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Event;
+
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Event\Event;
+use Yansongda\Artful\Rocket;
+
+class PayStart extends Event
+{
+    /**
+     * @var PluginInterface[]
+     */
+    public array $plugins;
+
+    public array $params;
+
+    public function __construct(array $plugins, array $params, ?Rocket $rocket = null)
+    {
+        $this->plugins = $plugins;
+        $this->params = $params;
+
+        parent::__construct($rocket);
+    }
+}

+ 19 - 0
addons/epay/library/v3new/Yansongda/Pay/Exception/DecryptException.php

@@ -0,0 +1,19 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Exception;
+
+use Throwable;
+
+class DecryptException extends Exception
+{
+    public function __construct(
+        int $code = self::DECRYPT_ERROR,
+        string $message = '加解密异常',
+        mixed $extra = null,
+        ?Throwable $previous = null
+    ) {
+        parent::__construct($message, $code, $extra, $previous);
+    }
+}

+ 92 - 0
addons/epay/library/v3new/Yansongda/Pay/Exception/Exception.php

@@ -0,0 +1,92 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Exception;
+
+use Throwable;
+
+class Exception extends \Exception
+{
+    public const UNKNOWN_ERROR = 9999;
+
+    /*
+     * 关于参数.
+     */
+    public const PARAMS_SHORTCUT_ACTION_INVALID = 9210;
+
+    public const PARAMS_METHOD_NOT_SUPPORTED = 9211;
+
+    public const PARAMS_WECHAT_PAPAY_TYPE_NOT_SUPPORTED = 9212;
+
+    public const PARAMS_WECHAT_URL_MISSING = 9213;
+
+    public const PARAMS_WECHAT_BODY_MISSING = 9214;
+
+    public const PARAMS_WECHAT_SERIAL_NOT_FOUND = 9215;
+
+    public const PARAMS_UNIPAY_URL_MISSING = 9216;
+
+    public const PARAMS_UNIPAY_BODY_MISSING = 9217;
+
+    public const PARAMS_NECESSARY_PARAMS_MISSING = 9218;
+
+    public const PARAMS_PLUGIN_ONLY_SUPPORT_SERVICE_MODE = 9219;
+
+    public const PARAMS_PLUGIN_ONLY_SUPPORT_NORMAL_MODE = 9220;
+
+    public const PARAMS_CALLBACK_REQUEST_INVALID = 9221;
+
+    public const PARAMS_DOUYIN_URL_MISSING = 9222;
+
+    /**
+     * 关于响应.
+     */
+    public const RESPONSE_CODE_WRONG = 9304;
+
+    public const RESPONSE_MISSING_NECESSARY_PARAMS = 9305;
+
+    public const RESPONSE_BUSINESS_CODE_WRONG = 9306;
+
+    /*
+     * 关于配置.
+     */
+    public const CONFIG_ALIPAY_INVALID = 9401;
+
+    public const CONFIG_WECHAT_INVALID = 9402;
+
+    public const CONFIG_UNIPAY_INVALID = 9403;
+
+    public const CONFIG_JSB_INVALID = 9404;
+
+    public const CONFIG_DOUYIN_INVALID = 9405;
+
+    /**
+     * 关于签名.
+     */
+    public const SIGN_ERROR = 9500;
+
+    public const SIGN_EMPTY = 9501;
+
+    /**
+     * 关于加解密.
+     */
+    public const DECRYPT_ERROR = 9600;
+
+    public const DECRYPT_WECHAT_CIPHERTEXT_PARAMS_INVALID = 9601;
+
+    public const DECRYPT_WECHAT_ENCRYPTED_DATA_INVALID = 9602;
+
+    public const DECRYPT_WECHAT_DECRYPTED_METHOD_INVALID = 9603;
+
+    public const DECRYPT_WECHAT_ENCRYPTED_CONTENTS_INVALID = 9604;
+
+    public mixed $extra;
+
+    public function __construct(string $message = '未知异常', int $code = self::UNKNOWN_ERROR, mixed $extra = null, ?Throwable $previous = null)
+    {
+        $this->extra = $extra;
+
+        parent::__construct($message, $code, $previous);
+    }
+}

+ 23 - 0
addons/epay/library/v3new/Yansongda/Pay/Exception/InvalidSignException.php

@@ -0,0 +1,23 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Exception;
+
+use Throwable;
+
+class InvalidSignException extends Exception
+{
+    public mixed $callback;
+
+    public function __construct(
+        int $code = self::SIGN_ERROR,
+        string $message = '签名异常',
+        mixed $extra = null,
+        ?Throwable $previous = null
+    ) {
+        $this->callback = $extra;
+
+        parent::__construct($message, $code, $extra, $previous);
+    }
+}

+ 656 - 0
addons/epay/library/v3new/Yansongda/Pay/Functions.php

@@ -0,0 +1,656 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay;
+
+use JetBrains\PhpStorm\Deprecated;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Yansongda\Artful\Contract\ConfigInterface;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\InvalidConfigException;
+use Yansongda\Artful\Exception\InvalidParamsException;
+use Yansongda\Artful\Exception\ServiceNotFoundException;
+use Yansongda\Artful\Plugin\AddPayloadBodyPlugin;
+use Yansongda\Artful\Plugin\ParserPlugin;
+use Yansongda\Artful\Plugin\StartPlugin;
+use Yansongda\Pay\Exception\DecryptException;
+use Yansongda\Pay\Exception\Exception;
+use Yansongda\Pay\Exception\InvalidSignException;
+use Yansongda\Pay\Plugin\Wechat\AddRadarPlugin;
+use Yansongda\Pay\Plugin\Wechat\ResponsePlugin;
+use Yansongda\Pay\Plugin\Wechat\V3\AddPayloadSignaturePlugin;
+use Yansongda\Pay\Plugin\Wechat\V3\WechatPublicCertsPlugin;
+use Yansongda\Pay\Provider\Alipay;
+use Yansongda\Pay\Provider\Douyin;
+use Yansongda\Pay\Provider\Jsb;
+use Yansongda\Pay\Provider\Unipay;
+use Yansongda\Pay\Provider\Wechat;
+use Yansongda\Supports\Collection;
+use Yansongda\Supports\Str;
+
+use function Yansongda\Artful\get_radar_body;
+use function Yansongda\Artful\get_radar_method;
+
+function get_tenant(array $params = []): string
+{
+    return strval($params['_config'] ?? 'default');
+}
+
+function get_public_cert(string $key): string
+{
+    return is_file($key) ? file_get_contents($key) : $key;
+}
+
+function get_private_cert(string $key): string
+{
+    if (is_file($key)) {
+        return file_get_contents($key);
+    }
+
+    if (Str::startsWith($key, '-----BEGIN PRIVATE KEY-----')) {
+        return $key;
+    }
+
+    return "-----BEGIN RSA PRIVATE KEY-----\n"
+        .wordwrap($key, 64, "\n", true)
+        ."\n-----END RSA PRIVATE KEY-----";
+}
+
+function get_radar_url(array $config, ?Collection $payload): ?string
+{
+    return match ($config['mode'] ?? Pay::MODE_NORMAL) {
+        Pay::MODE_SERVICE => $payload?->get('_service_url') ?? $payload?->get('_url') ?? null,
+        Pay::MODE_SANDBOX => $payload?->get('_sandbox_url') ?? $payload?->get('_url') ?? null,
+        default => $payload?->get('_url') ?? null,
+    };
+}
+
+/**
+ * @throws ContainerException
+ * @throws ServiceNotFoundException
+ */
+function get_provider_config(string $provider, array $params = []): array
+{
+    /** @var ConfigInterface $config */
+    $config = Pay::get(ConfigInterface::class);
+
+    return $config->get($provider, [])[get_tenant($params)] ?? [];
+}
+
+/**
+ * @throws ContainerException
+ * @throws ServiceNotFoundException
+ */
+#[Deprecated(reason: '自 v3.7.5 开始废弃', replacement: 'get_provider_config')]
+function get_alipay_config(array $params = []): array
+{
+    $alipay = Pay::get(ConfigInterface::class)->get('alipay');
+
+    return $alipay[get_tenant($params)] ?? [];
+}
+
+function get_alipay_url(array $config, ?Collection $payload): string
+{
+    $url = get_radar_url($config, $payload) ?? '';
+
+    if (str_starts_with($url, 'http')) {
+        return $url;
+    }
+
+    return Alipay::URL[$config['mode'] ?? Pay::MODE_NORMAL];
+}
+
+/**
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ */
+function verify_alipay_sign(array $config, string $contents, string $sign): void
+{
+    if (empty($sign)) {
+        throw new InvalidSignException(Exception::SIGN_EMPTY, '签名异常: 验证支付宝签名失败-支付宝签名为空', func_get_args());
+    }
+
+    $public = $config['alipay_public_cert_path'] ?? null;
+
+    if (empty($public)) {
+        throw new InvalidConfigException(Exception::CONFIG_ALIPAY_INVALID, '配置异常: 缺少支付宝配置 -- [alipay_public_cert_path]');
+    }
+
+    $result = 1 === openssl_verify(
+        $contents,
+        base64_decode($sign),
+        get_public_cert($public),
+        OPENSSL_ALGO_SHA256
+    );
+
+    if (!$result) {
+        throw new InvalidSignException(Exception::SIGN_ERROR, '签名异常: 验证支付宝签名失败', func_get_args());
+    }
+}
+
+/**
+ * @throws ContainerException
+ * @throws ServiceNotFoundException
+ */
+#[Deprecated(reason: '自 v3.7.5 开始废弃', replacement: 'get_provider_config')]
+function get_wechat_config(array $params = []): array
+{
+    $wechat = Pay::get(ConfigInterface::class)->get('wechat');
+
+    return $wechat[get_tenant($params)] ?? [];
+}
+
+function get_wechat_method(?Collection $payload): string
+{
+    return get_radar_method($payload) ?? 'POST';
+}
+
+/**
+ * @throws InvalidParamsException
+ */
+function get_wechat_url(array $config, ?Collection $payload): string
+{
+    $url = get_radar_url($config, $payload);
+
+    if (empty($url)) {
+        throw new InvalidParamsException(Exception::PARAMS_WECHAT_URL_MISSING, '参数异常: 微信 `_url` 或 `_service_url` 参数缺失:你可能用错插件顺序,应该先使用 `业务插件`');
+    }
+
+    if (str_starts_with($url, 'http')) {
+        return $url;
+    }
+
+    return Wechat::URL[$config['mode'] ?? Pay::MODE_NORMAL].$url;
+}
+
+/**
+ * @throws InvalidParamsException
+ */
+function get_wechat_body(?Collection $payload): mixed
+{
+    $body = get_radar_body($payload);
+
+    if (is_null($body)) {
+        throw new InvalidParamsException(Exception::PARAMS_WECHAT_BODY_MISSING, '参数异常: 微信 `_body` 参数缺失:你可能用错插件顺序,应该先使用 `AddPayloadBodyPlugin`');
+    }
+
+    return $body;
+}
+
+function get_wechat_type_key(array $params): string
+{
+    $key = ($params['_type'] ?? 'mp').'_app_id';
+
+    if ('app_app_id' === $key) {
+        $key = 'app_id';
+    }
+
+    return $key;
+}
+
+/**
+ * @throws InvalidConfigException
+ */
+function get_wechat_sign(array $config, string $contents): string
+{
+    $privateKey = $config['mch_secret_cert'] ?? null;
+
+    if (empty($privateKey)) {
+        throw new InvalidConfigException(Exception::CONFIG_WECHAT_INVALID, '配置异常: 缺少微信配置 -- [mch_secret_cert]');
+    }
+
+    $privateKey = get_private_cert($privateKey);
+
+    openssl_sign($contents, $sign, $privateKey, 'sha256WithRSAEncryption');
+
+    return base64_encode($sign);
+}
+
+/**
+ * @throws InvalidConfigException
+ */
+function get_wechat_sign_v2(array $config, array $payload, bool $upper = true): string
+{
+    $key = $config['mch_secret_key_v2'] ?? null;
+
+    if (empty($key)) {
+        throw new InvalidConfigException(Exception::CONFIG_WECHAT_INVALID, '配置异常: 缺少微信配置 -- [mch_secret_key_v2]');
+    }
+
+    ksort($payload);
+
+    $buff = '';
+
+    foreach ($payload as $k => $v) {
+        $buff .= ('sign' != $k && '' != $v && !is_array($v)) ? $k.'='.$v.'&' : '';
+    }
+
+    $sign = md5($buff.'key='.$key);
+
+    return $upper ? strtoupper($sign) : $sign;
+}
+
+/**
+ * @throws ContainerException
+ * @throws DecryptException
+ * @throws InvalidConfigException
+ * @throws InvalidParamsException
+ * @throws InvalidSignException
+ * @throws ServiceNotFoundException
+ */
+function verify_wechat_sign(ResponseInterface|ServerRequestInterface $message, array $params): void
+{
+    if ($message instanceof ServerRequestInterface && 'localhost' === $message->getUri()->getHost()) {
+        return;
+    }
+
+    $wechatSerial = $message->getHeaderLine('Wechatpay-Serial');
+    $timestamp = $message->getHeaderLine('Wechatpay-Timestamp');
+    $random = $message->getHeaderLine('Wechatpay-Nonce');
+    $sign = $message->getHeaderLine('Wechatpay-Signature');
+    $body = (string) $message->getBody();
+
+    $content = $timestamp."\n".$random."\n".$body."\n";
+    $public = get_provider_config('wechat', $params)['wechat_public_cert_path'][$wechatSerial] ?? null;
+
+    if (empty($sign)) {
+        throw new InvalidSignException(Exception::SIGN_EMPTY, '签名异常: 微信签名为空', ['headers' => $message->getHeaders(), 'body' => $body]);
+    }
+
+    $public = get_public_cert(
+        empty($public) ? reload_wechat_public_certs($params, $wechatSerial) : $public
+    );
+
+    $result = 1 === openssl_verify(
+        $content,
+        base64_decode($sign),
+        $public,
+        'sha256WithRSAEncryption'
+    );
+
+    if (!$result) {
+        throw new InvalidSignException(Exception::SIGN_ERROR, '签名异常: 验证微信签名失败', ['headers' => $message->getHeaders(), 'body' => $body]);
+    }
+}
+
+/**
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ */
+function verify_wechat_sign_v2(array $config, array $destination): void
+{
+    $sign = $destination['sign'] ?? null;
+
+    if (empty($sign)) {
+        throw new InvalidSignException(Exception::SIGN_EMPTY, '签名异常: 微信签名为空', $destination);
+    }
+
+    $key = $config['mch_secret_key_v2'] ?? null;
+
+    if (empty($key)) {
+        throw new InvalidConfigException(Exception::CONFIG_WECHAT_INVALID, '配置异常: 缺少微信配置 -- [mch_secret_key_v2]');
+    }
+
+    if (get_wechat_sign_v2($config, $destination) !== $sign) {
+        throw new InvalidSignException(Exception::SIGN_ERROR, '签名异常: 验证微信签名失败', $destination);
+    }
+}
+
+function encrypt_wechat_contents(string $contents, string $publicKey): ?string
+{
+    if (openssl_public_encrypt($contents, $encrypted, get_public_cert($publicKey), OPENSSL_PKCS1_OAEP_PADDING)) {
+        return base64_encode($encrypted);
+    }
+
+    return null;
+}
+
+function decrypt_wechat_contents(string $encrypted, array $config): ?string
+{
+    if (openssl_private_decrypt(base64_decode($encrypted), $decrypted, get_private_cert($config['mch_secret_cert'] ?? ''), OPENSSL_PKCS1_OAEP_PADDING)) {
+        return $decrypted;
+    }
+
+    return null;
+}
+
+/**
+ * @throws ContainerException
+ * @throws DecryptException
+ * @throws InvalidConfigException
+ * @throws InvalidParamsException
+ * @throws ServiceNotFoundException
+ */
+function reload_wechat_public_certs(array $params, ?string $serialNo = null): string
+{
+    $data = Pay::wechat()->pay(
+        [StartPlugin::class, WechatPublicCertsPlugin::class, AddPayloadBodyPlugin::class, AddPayloadSignaturePlugin::class, AddRadarPlugin::class, ResponsePlugin::class, ParserPlugin::class],
+        $params
+    )->get('data', []);
+
+    $wechatConfig = get_provider_config('wechat', $params);
+
+    foreach ($data as $item) {
+        $certs[$item['serial_no']] = decrypt_wechat_resource($item['encrypt_certificate'], $wechatConfig)['ciphertext'] ?? '';
+    }
+
+    Pay::get(ConfigInterface::class)->set(
+        'wechat.'.get_tenant($params).'.wechat_public_cert_path',
+        ((array) ($wechatConfig['wechat_public_cert_path'] ?? [])) + ($certs ?? []),
+    );
+
+    if (!is_null($serialNo) && empty($certs[$serialNo])) {
+        throw new InvalidConfigException(Exception::CONFIG_WECHAT_INVALID, '配置异常: 获取微信 wechat_public_cert_path 配置失败');
+    }
+
+    return $certs[$serialNo] ?? '';
+}
+
+/**
+ * @throws ContainerException
+ * @throws DecryptException
+ * @throws InvalidConfigException
+ * @throws InvalidParamsException
+ * @throws ServiceNotFoundException
+ */
+function get_wechat_public_certs(array $params = [], ?string $path = null): void
+{
+    reload_wechat_public_certs($params);
+
+    $config = get_provider_config('wechat', $params);
+
+    if (empty($path)) {
+        var_dump($config['wechat_public_cert_path']);
+
+        return;
+    }
+
+    foreach ($config['wechat_public_cert_path'] as $serialNo => $cert) {
+        file_put_contents($path.'/'.$serialNo.'.crt', $cert);
+    }
+}
+
+/**
+ * @throws InvalidConfigException
+ * @throws DecryptException
+ */
+function decrypt_wechat_resource(array $resource, array $config): array
+{
+    $ciphertext = base64_decode($resource['ciphertext'] ?? '');
+    $secret = $config['mch_secret_key'] ?? null;
+
+    if (strlen($ciphertext) <= Wechat::AUTH_TAG_LENGTH_BYTE) {
+        throw new DecryptException(Exception::DECRYPT_WECHAT_CIPHERTEXT_PARAMS_INVALID, '加解密异常: ciphertext 位数过短');
+    }
+
+    if (is_null($secret) || Wechat::MCH_SECRET_KEY_LENGTH_BYTE != strlen($secret)) {
+        throw new InvalidConfigException(Exception::CONFIG_WECHAT_INVALID, '配置异常: 缺少微信配置 -- [mch_secret_key]');
+    }
+
+    $resource['ciphertext'] = match ($resource['algorithm'] ?? '') {
+        'AEAD_AES_256_GCM' => decrypt_wechat_resource_aes_256_gcm($ciphertext, $secret, $resource['nonce'] ?? '', $resource['associated_data'] ?? ''),
+        default => throw new DecryptException(Exception::DECRYPT_WECHAT_DECRYPTED_METHOD_INVALID, '加解密异常: algorithm 不支持'),
+    };
+
+    return $resource;
+}
+
+/**
+ * @throws DecryptException
+ */
+function decrypt_wechat_resource_aes_256_gcm(string $ciphertext, string $secret, string $nonce, string $associatedData): array|string
+{
+    $decrypted = openssl_decrypt(
+        substr($ciphertext, 0, -Wechat::AUTH_TAG_LENGTH_BYTE),
+        'aes-256-gcm',
+        $secret,
+        OPENSSL_RAW_DATA,
+        $nonce,
+        substr($ciphertext, -Wechat::AUTH_TAG_LENGTH_BYTE),
+        $associatedData
+    );
+
+    if (false === $decrypted) {
+        throw new DecryptException(Exception::DECRYPT_WECHAT_ENCRYPTED_DATA_INVALID, '加解密异常: 解密失败,请检查微信 mch_secret_key 是否正确');
+    }
+
+    if ('certificate' !== $associatedData) {
+        $decrypted = json_decode($decrypted, true);
+
+        if (JSON_ERROR_NONE !== json_last_error()) {
+            throw new DecryptException(Exception::DECRYPT_WECHAT_ENCRYPTED_DATA_INVALID, '加解密异常: 待解密数据非正常数据');
+        }
+    }
+
+    return $decrypted;
+}
+
+/**
+ * @throws ContainerException
+ * @throws DecryptException
+ * @throws InvalidConfigException
+ * @throws InvalidParamsException
+ * @throws ServiceNotFoundException
+ */
+function get_wechat_serial_no(array $params): string
+{
+    if (!empty($params['_serial_no'])) {
+        return $params['_serial_no'];
+    }
+
+    $config = get_provider_config('wechat', $params);
+
+    if (empty($config['wechat_public_cert_path'])) {
+        reload_wechat_public_certs($params);
+
+        $config = get_provider_config('wechat', $params);
+    }
+
+    mt_srand();
+
+    return strval(array_rand($config['wechat_public_cert_path']));
+}
+
+/**
+ * @throws InvalidParamsException
+ */
+function get_wechat_public_key(array $config, string $serialNo): string
+{
+    $publicKey = $config['wechat_public_cert_path'][$serialNo] ?? null;
+
+    if (empty($publicKey)) {
+        throw new InvalidParamsException(Exception::PARAMS_WECHAT_SERIAL_NOT_FOUND, '参数异常: 微信公钥序列号未找到 - '.$serialNo);
+    }
+
+    return $publicKey;
+}
+
+/**
+ * @throws InvalidConfigException
+ */
+function get_wechat_miniprogram_pay_sign(array $config, string $url, string $payload): string
+{
+    if (empty($config['mini_app_key_virtual_pay'])) {
+        throw new InvalidConfigException(Exception::CONFIG_WECHAT_INVALID, '配置异常: 缺少微信配置 -- [mini_app_key_virtual_pay]');
+    }
+
+    return hash_hmac('sha256', $url.'&'.$payload, $config['mini_app_key_virtual_pay']);
+}
+
+function get_wechat_miniprogram_user_sign(string $sessionKey, string $payload): string
+{
+    return hash_hmac('sha256', $payload, $sessionKey);
+}
+
+/**
+ * @throws ContainerException
+ * @throws ServiceNotFoundException
+ */
+#[Deprecated(reason: '自 v3.7.5 开始废弃', replacement: 'get_provider_config')]
+function get_unipay_config(array $params = []): array
+{
+    $unipay = Pay::get(ConfigInterface::class)->get('unipay');
+
+    return $unipay[get_tenant($params)] ?? [];
+}
+
+/**
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ */
+function verify_unipay_sign(array $config, string $contents, string $sign, ?string $signPublicKeyCert = null): void
+{
+    if (empty($sign)) {
+        throw new InvalidSignException(Exception::SIGN_EMPTY, '签名异常: 银联签名为空', func_get_args());
+    }
+
+    if (empty($signPublicKeyCert) && empty($public = $config['unipay_public_cert_path'] ?? null)) {
+        throw new InvalidConfigException(Exception::CONFIG_UNIPAY_INVALID, '配置异常: 缺少银联配置 -- [unipay_public_cert_path]');
+    }
+
+    $result = 1 === openssl_verify(
+        hash('sha256', $contents),
+        base64_decode($sign),
+        get_public_cert($signPublicKeyCert ?? $public ?? ''),
+        'sha256'
+    );
+
+    if (!$result) {
+        throw new InvalidSignException(Exception::SIGN_ERROR, '签名异常: 验证银联签名失败', func_get_args());
+    }
+}
+
+/**
+ * @throws InvalidParamsException
+ */
+function get_unipay_url(array $config, ?Collection $payload): string
+{
+    $url = get_radar_url($config, $payload);
+
+    if (empty($url)) {
+        throw new InvalidParamsException(Exception::PARAMS_UNIPAY_URL_MISSING, '参数异常: 银联 `_url` 参数缺失:你可能用错插件顺序,应该先使用 `业务插件`');
+    }
+
+    if (str_starts_with($url, 'http')) {
+        return $url;
+    }
+
+    return Unipay::URL[$config['mode'] ?? Pay::MODE_NORMAL].$url;
+}
+
+/**
+ * @throws InvalidParamsException
+ */
+function get_unipay_body(?Collection $payload): string
+{
+    $body = get_radar_body($payload);
+
+    if (is_null($body)) {
+        throw new InvalidParamsException(Exception::PARAMS_UNIPAY_BODY_MISSING, '参数异常: 银联 `_body` 参数缺失:你可能用错插件顺序,应该先使用 `AddPayloadBodyPlugin`');
+    }
+
+    return $body;
+}
+
+/**
+ * @throws InvalidConfigException
+ */
+function get_unipay_sign_qra(array $config, array $payload): string
+{
+    $key = $config['mch_secret_key'] ?? null;
+
+    if (empty($key)) {
+        throw new InvalidConfigException(Exception::CONFIG_UNIPAY_INVALID, '配置异常: 缺少银联配置 -- [mch_secret_key]');
+    }
+
+    ksort($payload);
+
+    $buff = '';
+
+    foreach ($payload as $k => $v) {
+        $buff .= ('sign' != $k && '' != $v && !is_array($v)) ? $k.'='.$v.'&' : '';
+    }
+
+    return strtoupper(md5($buff.'key='.$key));
+}
+
+/**
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ */
+function verify_unipay_sign_qra(array $config, array $destination): void
+{
+    $sign = $destination['sign'] ?? null;
+
+    if (empty($sign)) {
+        throw new InvalidSignException(Exception::SIGN_EMPTY, '签名异常: 银联签名为空', $destination);
+    }
+
+    $key = $config['mch_secret_key'] ?? null;
+
+    if (empty($key)) {
+        throw new InvalidConfigException(Exception::CONFIG_UNIPAY_INVALID, '配置异常: 缺少银联配置 -- [mch_secret_key]');
+    }
+
+    if (get_unipay_sign_qra($config, $destination) !== $sign) {
+        throw new InvalidSignException(Exception::SIGN_ERROR, '签名异常: 验证银联签名失败', $destination);
+    }
+}
+
+function get_jsb_url(array $config, ?Collection $payload): string
+{
+    $url = get_radar_url($config, $payload) ?? '';
+
+    if (str_starts_with($url, 'http')) {
+        return $url;
+    }
+
+    return Jsb::URL[$config['mode'] ?? Pay::MODE_NORMAL];
+}
+
+/**
+ * @throws InvalidConfigException
+ * @throws InvalidSignException
+ */
+function verify_jsb_sign(array $config, string $content, string $sign): void
+{
+    if (empty($sign)) {
+        throw new InvalidSignException(Exception::SIGN_EMPTY, '签名异常: 江苏银行签名为空', func_get_args());
+    }
+
+    $publicCert = $config['jsb_public_cert_path'] ?? null;
+
+    if (empty($publicCert)) {
+        throw new InvalidConfigException(Exception::CONFIG_JSB_INVALID, '配置异常: 缺少配置参数 -- [jsb_public_cert_path]');
+    }
+
+    $result = 1 === openssl_verify(
+        $content,
+        base64_decode($sign),
+        get_public_cert($publicCert)
+    );
+
+    if (!$result) {
+        throw new InvalidSignException(Exception::SIGN_ERROR, '签名异常: 验证江苏银行签名失败', func_get_args());
+    }
+}
+
+/**
+ * @throws InvalidParamsException
+ */
+function get_douyin_url(array $config, ?Collection $payload): string
+{
+    $url = get_radar_url($config, $payload);
+
+    if (empty($url)) {
+        throw new InvalidParamsException(Exception::PARAMS_DOUYIN_URL_MISSING, '参数异常: 抖音 `_url` 参数缺失:你可能用错插件顺序,应该先使用 `业务插件`');
+    }
+
+    if (str_starts_with($url, 'http')) {
+        return $url;
+    }
+
+    return Douyin::URL[$config['mode'] ?? Pay::MODE_NORMAL].$url;
+}

+ 108 - 0
addons/epay/library/v3new/Yansongda/Pay/Pay.php

@@ -0,0 +1,108 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay;
+
+use Closure;
+use Psr\Container\ContainerInterface;
+use Yansongda\Artful\Artful;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\ServiceNotFoundException;
+use Yansongda\Pay\Provider\Alipay;
+use Yansongda\Pay\Provider\Douyin;
+use Yansongda\Pay\Provider\Jsb;
+use Yansongda\Pay\Provider\Unipay;
+use Yansongda\Pay\Provider\Wechat;
+use Yansongda\Pay\Service\AlipayServiceProvider;
+use Yansongda\Pay\Service\DouyinServiceProvider;
+use Yansongda\Pay\Service\JsbServiceProvider;
+use Yansongda\Pay\Service\UnipayServiceProvider;
+use Yansongda\Pay\Service\WechatServiceProvider;
+
+/**
+ * @method static Alipay alipay(array $config = [], $container = null)
+ * @method static Wechat wechat(array $config = [], $container = null)
+ * @method static Unipay unipay(array $config = [], $container = null)
+ * @method static Jsb    jsb(array $config = [], $container = null)
+ * @method static Douyin douyin(array $config = [], $container = null)
+ */
+class Pay
+{
+    /**
+     * 正常模式.
+     */
+    public const MODE_NORMAL = 0;
+
+    /**
+     * 沙箱模式.
+     */
+    public const MODE_SANDBOX = 1;
+
+    /**
+     * 服务商模式.
+     */
+    public const MODE_SERVICE = 2;
+
+    protected static array $providers = [
+        AlipayServiceProvider::class,
+        WechatServiceProvider::class,
+        UnipayServiceProvider::class,
+        JsbServiceProvider::class,
+        DouyinServiceProvider::class,
+    ];
+
+    /**
+     * @throws ContainerException
+     * @throws ServiceNotFoundException
+     */
+    public static function __callStatic(string $service, array $config = [])
+    {
+        if (!empty($config)) {
+            self::config(...$config);
+        }
+
+        return Artful::get($service);
+    }
+
+    /**
+     * @throws ContainerException
+     */
+    public static function config(array $config = [], null|Closure|ContainerInterface $container = null): bool
+    {
+        $result = Artful::config($config, $container);
+
+        foreach (self::$providers as $provider) {
+            Artful::load($provider);
+        }
+
+        return $result;
+    }
+
+    /**
+     * @throws ContainerException
+     */
+    public static function set(string $name, mixed $value): void
+    {
+        Artful::set($name, $value);
+    }
+
+    /**
+     * @throws ContainerException
+     * @throws ServiceNotFoundException
+     */
+    public static function get(string $service): mixed
+    {
+        return Artful::get($service);
+    }
+
+    public static function setContainer(null|Closure|ContainerInterface $container): void
+    {
+        Artful::setContainer($container);
+    }
+
+    public static function clear(): void
+    {
+        Artful::clear();
+    }
+}

+ 68 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/AddPayloadSignaturePlugin.php

@@ -0,0 +1,68 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\InvalidConfigException;
+use Yansongda\Artful\Exception\ServiceNotFoundException;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+use Yansongda\Pay\Exception\Exception;
+
+use function Yansongda\Pay\get_private_cert;
+use function Yansongda\Pay\get_provider_config;
+
+class AddPayloadSignaturePlugin implements PluginInterface
+{
+    /**
+     * @throws ContainerException
+     * @throws InvalidConfigException
+     * @throws ServiceNotFoundException
+     */
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][AddPayloadSignaturePlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload(['sign' => $this->getSign($rocket)]);
+
+        Logger::info('[Alipay][AddPayloadSignaturePlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+
+    /**
+     * @throws ContainerException
+     * @throws InvalidConfigException
+     * @throws ServiceNotFoundException
+     */
+    protected function getSign(Rocket $rocket): string
+    {
+        $privateKey = $this->getPrivateKey($rocket->getParams());
+
+        $content = $rocket->getPayload()->sortKeys()->toString();
+
+        openssl_sign($content, $sign, $privateKey, OPENSSL_ALGO_SHA256);
+
+        return base64_encode($sign);
+    }
+
+    /**
+     * @throws ContainerException
+     * @throws InvalidConfigException
+     * @throws ServiceNotFoundException
+     */
+    protected function getPrivateKey(array $params): string
+    {
+        $privateKey = get_provider_config('alipay', $params)['app_secret_cert'] ?? null;
+
+        if (is_null($privateKey)) {
+            throw new InvalidConfigException(Exception::CONFIG_ALIPAY_INVALID, '配置异常: 缺少支付宝配置 -- [app_secret_cert]');
+        }
+
+        return get_private_cert($privateKey);
+    }
+}

+ 55 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/AddRadarPlugin.php

@@ -0,0 +1,55 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2;
+
+use Closure;
+use GuzzleHttp\Psr7\Request;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\ServiceNotFoundException;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+use Yansongda\Supports\Collection;
+
+use function Yansongda\Artful\get_radar_method;
+use function Yansongda\Pay\get_alipay_url;
+use function Yansongda\Pay\get_provider_config;
+
+class AddRadarPlugin implements PluginInterface
+{
+    /**
+     * @throws ContainerException
+     * @throws ServiceNotFoundException
+     */
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][AddRadarPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $params = $rocket->getParams();
+        $config = get_provider_config('alipay', $params);
+        $payload = $rocket->getPayload();
+
+        $rocket->setRadar(new Request(
+            // 这里因为支付宝的 payload 里不包含 _method,所以需要取 params 中的
+            get_radar_method(new Collection($params)) ?? 'POST',
+            get_alipay_url($config, $payload),
+            $this->getHeaders(),
+            // 不能用 packer,支付宝接收的是 x-www-form-urlencoded 返回的又是 json,packer 用的是返回.
+            $payload?->query() ?? '',
+        ));
+
+        Logger::info('[Alipay][AddRadarPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+
+    protected function getHeaders(): array
+    {
+        return [
+            'Content-Type' => 'application/x-www-form-urlencoded',
+            'User-Agent' => 'yansongda/pay-v3',
+        ];
+    }
+}

+ 55 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/AppCallbackPlugin.php

@@ -0,0 +1,55 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Direction\NoHttpRequestDirection;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\InvalidConfigException;
+use Yansongda\Artful\Exception\InvalidParamsException;
+use Yansongda\Artful\Exception\ServiceNotFoundException;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+use Yansongda\Pay\Exception\Exception;
+use Yansongda\Pay\Exception\InvalidSignException;
+
+use function Yansongda\Artful\filter_params;
+use function Yansongda\Pay\get_provider_config;
+use function Yansongda\Pay\verify_alipay_sign;
+
+class AppCallbackPlugin implements PluginInterface
+{
+    /**
+     * @throws ContainerException
+     * @throws InvalidConfigException
+     * @throws ServiceNotFoundException
+     * @throws InvalidSignException
+     * @throws InvalidParamsException
+     */
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][AppCallbackPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $params = $rocket->getParams();
+        $config = get_provider_config('alipay', $params);
+
+        if (empty($params['alipay_trade_app_pay_response'])) {
+            throw new InvalidParamsException(Exception::PARAMS_CALLBACK_REQUEST_INVALID);
+        }
+
+        $value = filter_params($params['alipay_trade_app_pay_response']);
+
+        verify_alipay_sign($config, $value->toJson(), $params['sign'] ?? '');
+
+        $rocket->setPayload($params)
+            ->setDirection(NoHttpRequestDirection::class)
+            ->setDestination($rocket->getPayload());
+
+        Logger::info('[Alipay][AppCallbackPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 48 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/CallbackPlugin.php

@@ -0,0 +1,48 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Direction\NoHttpRequestDirection;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\InvalidConfigException;
+use Yansongda\Artful\Exception\ServiceNotFoundException;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+use Yansongda\Pay\Exception\InvalidSignException;
+
+use function Yansongda\Artful\filter_params;
+use function Yansongda\Pay\get_provider_config;
+use function Yansongda\Pay\verify_alipay_sign;
+
+class CallbackPlugin implements PluginInterface
+{
+    /**
+     * @throws ContainerException
+     * @throws InvalidConfigException
+     * @throws ServiceNotFoundException
+     * @throws InvalidSignException
+     */
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][CallbackPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $params = $rocket->getParams();
+        $config = get_provider_config('alipay', $params);
+
+        $value = filter_params($params, fn ($k, $v) => '' !== $v && 'sign' != $k && 'sign_type' != $k);
+
+        verify_alipay_sign($config, $value->sortKeys()->toString(), $params['sign'] ?? '');
+
+        $rocket->setPayload($params)
+            ->setDirection(NoHttpRequestDirection::class)
+            ->setDestination($rocket->getPayload());
+
+        Logger::info('[Alipay][CallbackPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 33 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/FormatPayloadBizContentPlugin.php

@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+use function Yansongda\Artful\filter_params;
+
+class FormatPayloadBizContentPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][FormatPayloadBizContentPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $payload = $rocket->getPayload();
+
+        $rocket->setPayload(
+            filter_params($payload->all(), fn ($k, $v) => '' !== $v && 'sign' != $k)
+                ->merge([
+                    'biz_content' => json_encode(filter_params($payload->get('biz_content', []))),
+                ])
+        );
+
+        Logger::info('[Alipay][FormatPayloadBizContentPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 32 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/PCreditPayInstallment/AppPayPlugin.php

@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\PCreditPayInstallment;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Direction\ResponseDirection;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/02np8z?pathHash=994a1e7d&ref=api
+ */
+class AppPayPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][PCreditPayInstallment][AppPayPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->setDirection(ResponseDirection::class)
+            ->mergePayload([
+                'method' => 'alipay.trade.app.pay',
+                'biz_content' => $rocket->getParams(),
+            ]);
+
+        Logger::info('[Alipay][Fund][PCreditPayInstallment][AppPayPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 48 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/PCreditPayInstallment/H5PayPlugin.php

@@ -0,0 +1,48 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\PCreditPayInstallment;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Direction\ResponseDirection;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\ServiceNotFoundException;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+use Yansongda\Pay\Traits\SupportServiceProviderTrait;
+
+/**
+ * @see https://opendocs.alipay.com/open/02np8y?pathHash=718b8786&ref=api
+ */
+class H5PayPlugin implements PluginInterface
+{
+    use SupportServiceProviderTrait;
+
+    /**
+     * @throws ContainerException
+     * @throws ServiceNotFoundException
+     */
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][PCreditPayInstallment][H5PayPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $this->loadAlipayServiceProvider($rocket);
+
+        $rocket->setDirection(ResponseDirection::class)
+            ->mergePayload([
+                'method' => 'alipay.trade.wap.pay',
+                'biz_content' => array_merge(
+                    [
+                        'product_code' => 'QUICK_WAP_WAY',
+                    ],
+                    $rocket->getParams(),
+                ),
+            ]);
+
+        Logger::info('[Alipay][Fund][PCreditPayInstallment][H5PayPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 47 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/PCreditPayInstallment/PosPayPlugin.php

@@ -0,0 +1,47 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\PCreditPayInstallment;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\ServiceNotFoundException;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+use Yansongda\Pay\Traits\SupportServiceProviderTrait;
+
+/**
+ * @see https://opendocs.alipay.com/open/02np90?pathHash=d2a20943&ref=api&scene=32
+ */
+class PosPayPlugin implements PluginInterface
+{
+    use SupportServiceProviderTrait;
+
+    /**
+     * @throws ContainerException
+     * @throws ServiceNotFoundException
+     */
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][PCreditPayInstallment][PosPayPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $this->loadAlipayServiceProvider($rocket);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.trade.pay',
+            'biz_content' => array_merge(
+                [
+                    'product_code' => 'FACE_TO_FACE_PAYMENT',
+                    'scene' => 'bar_code',
+                ],
+                $rocket->getParams(),
+            ),
+        ]);
+
+        Logger::info('[Alipay][Fund][PCreditPayInstallment][PosPayPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 41 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/PCreditPayInstallment/ScanPayPlugin.php

@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\PCreditPayInstallment;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Exception\ContainerException;
+use Yansongda\Artful\Exception\ServiceNotFoundException;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+use Yansongda\Pay\Traits\SupportServiceProviderTrait;
+
+/**
+ * @see https://opendocs.alipay.com/open/02np92?pathHash=de4742e0&ref=api
+ */
+class ScanPayPlugin implements PluginInterface
+{
+    use SupportServiceProviderTrait;
+
+    /**
+     * @throws ContainerException
+     * @throws ServiceNotFoundException
+     */
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][PCreditPayInstallment][ScanPayPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $this->loadAlipayServiceProvider($rocket);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.trade.precreate',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Fund][PCreditPayInstallment][ScanPayPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Royalty/Query/OnsettlePlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\Royalty\Query;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/d87dc009_alipay.trade.order.onsettle.query?pathHash=53466049&ref=api&scene=common
+ */
+class OnsettlePlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][Royalty][Query][OnsettlePlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.trade.order.onsettle.query',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Fund][Royalty][Query][OnsettlePlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Royalty/Query/RatePlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\Royalty\Query;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/6f314ee9_alipay.trade.royalty.rate.query?pathHash=9118088a&ref=api&scene=common
+ */
+class RatePlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][Royalty][Query][RatePlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.trade.royalty.rate.query',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Fund][Royalty][Query][RatePlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Royalty/Query/SettlePlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\Royalty\Query;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/9ef980b7_alipay.trade.order.settle.query?pathHash=688b1c13&ref=api&scene=common
+ */
+class SettlePlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][Royalty][Query][SettlePlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.trade.order.settle.query',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Fund][Royalty][Query][SettlePlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Royalty/Relation/BindPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\Royalty\Relation;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/c21931d6_alipay.trade.royalty.relation.bind?pathHash=08a24dae&ref=api&scene=common
+ */
+class BindPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][Royalty][Relation][BindPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.trade.royalty.relation.bind',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Fund][Royalty][Relation][BindPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Royalty/Relation/QueryPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\Royalty\Relation;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/1860be54_alipay.trade.royalty.relation.batchquery?pathHash=2f733e2d&ref=api&scene=common
+ */
+class QueryPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][Royalty][Relation][QueryPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.trade.royalty.relation.batchquery',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Fund][Royalty][Relation][QueryPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Royalty/Relation/UnbindPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\Royalty\Relation;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/3613f4e1_alipay.trade.royalty.relation.unbind?pathHash=5a880175&ref=api&scene=common
+ */
+class UnbindPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][Royalty][Relation][UnbindPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.trade.royalty.relation.unbind',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Fund][Royalty][Relation][UnbindPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Royalty/Request/SettleOrderPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\Royalty\Request;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/c3b24498_alipay.trade.order.settle?pathHash=8e6acab4&ref=api&scene=common
+ */
+class SettleOrderPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][Royalty][Request][SettleOrderPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.trade.order.settle',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Fund][Royalty][Request][SettleOrderPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Transfer/ApplyReceiptPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\Transfer;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/1aad1956_alipay.data.bill.ereceipt.apply?pathHash=a2527e9c&ref=api&scene=common
+ */
+class ApplyReceiptPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][Transfer][ApplyReceiptPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.data.bill.ereceipt.apply',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Fund][Transfer][ApplyReceiptPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Transfer/Bill/QueryUrlPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\Transfer\Bill;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/76606b11_alipay.data.dataservice.bill.downloadurl.query?pathHash=425f62c6&ref=api&scene=common
+ */
+class QueryUrlPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][Transfer][Bill][QueryUrlPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.data.dataservice.bill.downloadurl.query',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Fund][Transfer][Bill][QueryUrlPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Transfer/Fund/QueryPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\Transfer\Fund;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/58a29899_alipay.fund.trans.common.query?pathHash=aad07c6d&ref=api&scene=f9fece54d41f49cbbd00dc73655a01a4
+ */
+class QueryPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][Transfer][Fund][QueryPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.fund.trans.common.query',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Fund][Transfer][Fund][QueryPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 37 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Transfer/Fund/TransferPlugin.php

@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\Transfer\Fund;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/62987723_alipay.fund.trans.uni.transfer?pathHash=66064890&ref=api&scene=ca56bca529e64125a2786703c6192d41
+ * @see https://opendocs.alipay.com/open/02byvi?pathHash=b367173b&ref=api&scene=66dd06f5a923403393b85de68d3c0055
+ */
+class TransferPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][Transfer][Fund][TransferPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.fund.trans.uni.transfer',
+            'biz_content' => array_merge(
+                [
+                    'biz_scene' => 'DIRECT_TRANSFER',
+                    'product_code' => 'TRANS_ACCOUNT_NO_PWD',
+                ],
+                $rocket->getParams(),
+            ),
+        ]);
+
+        Logger::info('[Alipay][Fund][Transfer][Fund][TransferPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Transfer/QueryAccountPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\Transfer;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/1b8a680c_alipay.fund.account.query?pathHash=ff8fc0e0&ref=api&scene=c76aa8f1c54e4b8b8ffecfafc4d3c31c
+ */
+class QueryAccountPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][Transfer][QueryAccountPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.fund.account.query',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Fund][Transfer][QueryAccountPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Transfer/QueryReceiptPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\Transfer;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/30b94a2f_alipay.data.bill.ereceipt.query?pathHash=bfe1c3f4&ref=api&scene=common
+ */
+class QueryReceiptPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][Transfer][QueryReceiptPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.data.bill.ereceipt.query',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Fund][Transfer][QueryReceiptPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Fund/Transfer/RefundPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Fund\Transfer;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/02byvd?pathHash=2dceb6d2&ref=api&scene=common
+ */
+class RefundPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Fund][Transfer][RefundPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.fund.trans.refund',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Fund][Transfer][RefundPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 38 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Marketing/Redpack/AppPayPlugin.php

@@ -0,0 +1,38 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Marketing\Redpack;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Direction\ResponseDirection;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/03rbyf?pathHash=76643847&ref=api&scene=common
+ */
+class AppPayPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Marketing][Redpack][AppPayPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->setDirection(ResponseDirection::class)
+            ->mergePayload([
+                'method' => 'alipay.fund.trans.app.pay',
+                'biz_content' => array_merge(
+                    [
+                        'product_code' => 'STD_RED_PACKET',
+                        'biz_scene' => 'PERSONAL_PAY',
+                    ],
+                    $rocket->getParams(),
+                ),
+            ]);
+
+        Logger::info('[Alipay][Marketing][Redpack][AppPayPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 37 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Marketing/Redpack/WebPayPlugin.php

@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Marketing\Redpack;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Direction\ResponseDirection;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/03rbye?pathHash=1c8d9fcb&ref=api&scene=common
+ */
+class WebPayPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Marketing][Redpack][WebPayPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->setDirection(ResponseDirection::class)
+            ->mergePayload([
+                'method' => 'alipay.fund.trans.page.pay',
+                'biz_content' => array_merge(
+                    [
+                        'product_code' => 'STD_APP_TRANSFER',
+                    ],
+                    $rocket->getParams()
+                ),
+            ]);
+
+        Logger::info('[Alipay][Marketing][Redpack][WebPayPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/Authorization/AuthPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Member\Authorization;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/02aile?pathHash=4efd837f&ref=api&scene=common
+ */
+class AuthPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Member][Authorization][AuthPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.user.info.auth',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Member][Authorization][AuthPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/Authorization/QueryPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Member\Authorization;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/6b97edd1_alipay.open.auth.userauth.relationship.query?pathHash=ac4a364e&ref=api&scene=common
+ */
+class QueryPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Member][Authorization][QueryPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.open.auth.userauth.relationship.query',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Member][Authorization][QueryPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 32 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/Authorization/TokenPlugin.php

@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Member\Authorization;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/84bc7352_alipay.system.oauth.token?pathHash=fe1502d5&ref=api&scene=common
+ */
+class TokenPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Member][Authorization][TokenPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload(array_merge(
+            [
+                'method' => 'alipay.system.oauth.token',
+            ],
+            $rocket->getParams(),
+        ));
+
+        Logger::info('[Alipay][Member][Authorization][TokenPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/Certification/CertifyPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Member\Certification;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/02ahk0?pathHash=b485c65c&ref=api&scene=common
+ */
+class CertifyPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Member][Certification][CertifyPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.user.certify.open.certify',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Member][Certification][CertifyPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 35 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/Certification/InitPlugin.php

@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Member\Certification;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/02ahjy?pathHash=ed72e8ea&ref=api&scene=common
+ */
+class InitPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Member][Certification][AppInitPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.user.certify.open.initialize',
+            'biz_content' => array_merge(
+                [
+                    'product_code' => 'FACE',
+                ],
+                $rocket->getParams(),
+            ),
+        ]);
+
+        Logger::info('[Alipay][Member][Certification][AppInitPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/Certification/QueryPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Member\Certification;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/02ahjw?pathHash=a3efadb6&ref=api&scene=common
+ */
+class QueryPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Member][Certification][QueryPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'alipay.user.certify.open.query',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Member][Certification][QueryPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 33 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/DetailPlugin.php

@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Member;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/a74a7068_alipay.user.info.share?pathHash=af2476d4&ref=api&scene=common
+ */
+class DetailPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Member][DetailPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $params = $rocket->getParams();
+
+        $rocket->mergePayload([
+            'auth_token' => $params['auth_token'] ?? $params['_auth_token'] ?? '',
+            'method' => 'alipay.user.info.share',
+            'biz_content' => [],
+        ]);
+
+        Logger::info('[Alipay][Member][DetailPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 35 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/FaceCheck/AppInitPlugin.php

@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Member\FaceCheck;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/03nisu?pathHash=43fcb08b&ref=api&scene=common
+ */
+class AppInitPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Member][FaceCheck][AppInitPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'datadigital.fincloud.generalsaas.face.check.initialize',
+            'biz_content' => array_merge(
+                [
+                    'biz_code' => 'DATA_DIGITAL_BIZ_CODE_FACE_CHECK_LIVE',
+                ],
+                $rocket->getParams(),
+            ),
+        ]);
+
+        Logger::info('[Alipay][Member][FaceCheck][AppInitPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/FaceCheck/AppQueryPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Member\FaceCheck;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/03nisv?pathHash=3f259e83&ref=api&scene=common
+ */
+class AppQueryPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Member][FaceCheck][AppQueryPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'datadigital.fincloud.generalsaas.face.check.query',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Member][FaceCheck][AppQueryPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 36 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/FaceVerification/AppInitPlugin.php

@@ -0,0 +1,36 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Member\FaceVerification;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/04jg6r?pathHash=0572cc86&ref=api&scene=common
+ */
+class AppInitPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Member][FaceVerification][AppInitPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'datadigital.fincloud.generalsaas.face.verification.initialize',
+            'biz_content' => array_merge(
+                [
+                    'biz_code' => 'DATA_DIGITAL_BIZ_CODE_FACE_VERIFICATION',
+                    'identity_type' => 'CERT_INFO',
+                ],
+                $rocket->getParams(),
+            ),
+        ]);
+
+        Logger::info('[Alipay][Member][FaceVerification][AppInitPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/FaceVerification/AppQueryPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Member\FaceVerification;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/04jg6s?pathHash=1608a398&ref=api&scene=common
+ */
+class AppQueryPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Member][FaceVerification][AppQueryPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'datadigital.fincloud.generalsaas.face.verification.query',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Member][FaceVerification][AppQueryPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 35 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/FaceVerification/H5InitPlugin.php

@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Member\FaceVerification;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/02zloa?pathHash=b0b7fece&ref=api&scene=common
+ */
+class H5InitPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Member][FaceVerification][H5InitPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'datadigital.fincloud.generalsaas.face.certify.initialize',
+            'biz_content' => array_merge(
+                [
+                    'biz_code' => 'FUTURE_TECH_BIZ_FACE_SDK',
+                ],
+                $rocket->getParams(),
+            ),
+        ]);
+
+        Logger::info('[Alipay][Member][FaceVerification][H5InitPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/FaceVerification/H5QueryPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Member\FaceVerification;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/02zloc?pathHash=b1141506&ref=api&scene=common
+ */
+class H5QueryPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Member][FaceVerification][H5QueryPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'datadigital.fincloud.generalsaas.face.certify.query',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Member][FaceVerification][H5QueryPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

+ 30 - 0
addons/epay/library/v3new/Yansongda/Pay/Plugin/Alipay/V2/Member/FaceVerification/H5VerifyPlugin.php

@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yansongda\Pay\Plugin\Alipay\V2\Member\FaceVerification;
+
+use Closure;
+use Yansongda\Artful\Contract\PluginInterface;
+use Yansongda\Artful\Logger;
+use Yansongda\Artful\Rocket;
+
+/**
+ * @see https://opendocs.alipay.com/open/02zlob?pathHash=20eba12a&ref=api&scene=common
+ */
+class H5VerifyPlugin implements PluginInterface
+{
+    public function assembly(Rocket $rocket, Closure $next): Rocket
+    {
+        Logger::debug('[Alipay][Member][FaceVerification][H5VerifyPlugin] 插件开始装载', ['rocket' => $rocket]);
+
+        $rocket->mergePayload([
+            'method' => 'datadigital.fincloud.generalsaas.face.certify.verify',
+            'biz_content' => $rocket->getParams(),
+        ]);
+
+        Logger::info('[Alipay][Member][FaceVerification][H5VerifyPlugin] 插件装载完毕', ['rocket' => $rocket]);
+
+        return $next($rocket);
+    }
+}

Some files were not shown because too many files changed in this diff