Skip to content

Commit

Permalink
feat: 新增 v3 付款码服务商模式 (#1010)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: yansongda <[email protected]>
  • Loading branch information
majiameng and yansongda authored Jul 10, 2024
1 parent da3bf50 commit b7cad54
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 15 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
## 3.7.7
## v3.7.8

### added

- feat: 新增 v3 付款码服务商模式(#1010)

## v3.7.7

### added

Expand Down
21 changes: 20 additions & 1 deletion src/Plugin/Wechat/V3/Pay/Pos/CancelPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@
use Yansongda\Artful\Logger;
use Yansongda\Artful\Rocket;
use Yansongda\Pay\Exception\Exception;
use Yansongda\Pay\Pay;
use Yansongda\Supports\Collection;

use function Yansongda\Pay\get_provider_config;
use function Yansongda\Pay\get_wechat_type_key;

/**
* @see https://pay.weixin.qq.com/docs/merchant/apis/code-payment-v3/direct/reverse.html
* @see https://pay.weixin.qq.com/docs/partner/apis/partner-code-payment-v3/partner/partner-reverse.html
*/
class CancelPlugin implements PluginInterface
{
Expand All @@ -41,12 +44,17 @@ public function assembly(Rocket $rocket, Closure $next): Rocket
throw new InvalidParamsException(Exception::PARAMS_NECESSARY_PARAMS_MISSING, '参数异常: 付款码支付撤销订单,参数缺少 `out_trade_no`');
}

if (Pay::MODE_SERVICE === ($config['mode'] ?? Pay::MODE_NORMAL)) {
$data = $this->service($payload, $params, $config);
}

$rocket->setPayload(array_merge(
[
'_method' => 'POST',
'_url' => 'v3/pay/transactions/out-trade-no/'.$outTradeNo.'/reverse',
'_service_url' => 'v3/pay/partner/transactions/out-trade-no/'.$outTradeNo.'/reverse',
],
$this->normal($params, $config)
$data ?? $this->normal($params, $config)
));

Logger::info('[Wechat][V3][Pay][Pos][CancelPlugin] 插件装载完毕', ['rocket' => $rocket]);
Expand All @@ -61,4 +69,15 @@ protected function normal(array $params, array $config): array
'mchid' => $config['mch_id'] ?? '',
];
}

protected function service(Collection $payload, array $params, array $config): array
{
$configKey = get_wechat_type_key($params);

return [
'sp_appid' => $config[$configKey] ?? '',
'sp_mchid' => $config['mch_id'] ?? '',
'sub_mchid' => $payload->get('sub_mchid', $config['sub_mch_id'] ?? ''),
];
}
}
28 changes: 27 additions & 1 deletion src/Plugin/Wechat/V3/Pay/Pos/PayPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@
use Throwable;
use Yansongda\Artful\Contract\PluginInterface;
use Yansongda\Artful\Exception\ContainerException;
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\Pay;
use Yansongda\Supports\Collection;

use function Yansongda\Pay\get_provider_config;
use function Yansongda\Pay\get_wechat_type_key;

/**
* @see https://pay.weixin.qq.com/docs/merchant/apis/code-payment-v3/direct/code-pay.html
* @see https://pay.weixin.qq.com/docs/partner/apis/partner-code-payment-v3/partner/partner-code-pay.html
*/
class PayPlugin implements PluginInterface
{
Expand All @@ -29,15 +34,25 @@ public function assembly(Rocket $rocket, Closure $next): Rocket
{
Logger::debug('[Wechat][V3][Pay][Pos][PayPlugin] 插件开始装载', ['rocket' => $rocket]);

$payload = $rocket->getPayload();
$params = $rocket->getParams();
$config = get_provider_config('wechat', $params);

if (is_null($payload)) {
throw new InvalidParamsException(Exception::PARAMS_NECESSARY_PARAMS_MISSING, '参数异常: 付款码支付,参数为空');
}

if (Pay::MODE_SERVICE === ($config['mode'] ?? Pay::MODE_NORMAL)) {
$data = $this->service($payload, $params, $config);
}

$rocket->mergePayload(array_merge(
[
'_method' => 'POST',
'_url' => 'v3/pay/transactions/codepay',
'_service_url' => 'v3/pay/partner/transactions/codepay',
],
$this->normal($params, $config)
$data ?? $this->normal($params, $config)
));

Logger::info('[Wechat][V3][Pay][Pos][PayPlugin] 插件装载完毕', ['rocket' => $rocket]);
Expand All @@ -52,4 +67,15 @@ protected function normal(array $params, array $config): array
'mchid' => $config['mch_id'] ?? '',
];
}

protected function service(Collection $payload, array $params, array $config): array
{
$configKey = get_wechat_type_key($params);

return [
'sp_appid' => $config[$configKey] ?? '',
'sp_mchid' => $config['mch_id'] ?? '',
'sub_mchid' => $payload->get('sub_mchid', $config['sub_mch_id'] ?? ''),
];
}
}
59 changes: 47 additions & 12 deletions tests/Plugin/Wechat/V3/Pay/Pos/CancelPluginTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ protected function setUp(): void
$this->plugin = new CancelPlugin();
}

public function testMissingOut()
{
$rocket = new Rocket();
$rocket->setPayload(new Collection([
'aaa' => 'aaa'
]));

self::expectException(InvalidParamsException::class);
self::expectExceptionCode(Exception::PARAMS_NECESSARY_PARAMS_MISSING);
self::expectExceptionMessage('参数异常: 付款码支付撤销订单,参数缺少 `out_trade_no`');

$this->plugin->assembly($rocket, function ($rocket) { return $rocket; });
}

public function testNormal()
{
$rocket = new Rocket();
Expand All @@ -31,25 +45,46 @@ public function testNormal()
$result = $this->plugin->assembly($rocket, function ($rocket) { return $rocket; });
$payload = $result->getPayload();

self::assertEqualsCanonicalizing([
'_method' => 'POST',
'_url' => 'v3/pay/transactions/out-trade-no/111/reverse',
'appid' => 'wx55955316af4ef13',
'mchid' => '1600314069'
], $payload->all());
self::assertEquals('POST', $payload->get('_method'));
self::assertEquals('v3/pay/transactions/out-trade-no/111/reverse', $payload->get('_url'));
self::assertEquals('wx55955316af4ef13', $payload->get('appid'));
self::assertEquals('1600314069', $payload->get('mchid'));
}

public function testMissingOut()
public function testService()
{
$rocket = new Rocket();
$rocket->setPayload(new Collection([
$rocket->setParams(['_config' => 'service_provider'])->setPayload(new Collection([
"out_trade_no" => "111",
'aaa' => 'aaa'
]));

self::expectException(InvalidParamsException::class);
self::expectExceptionCode(Exception::PARAMS_NECESSARY_PARAMS_MISSING);
self::expectExceptionMessage('参数异常: 付款码支付撤销订单,参数缺少 `out_trade_no`');
$result = $this->plugin->assembly($rocket, function ($rocket) { return $rocket; });
$payload = $result->getPayload();

$this->plugin->assembly($rocket, function ($rocket) { return $rocket; });
self::assertEquals('POST', $payload->get('_method'));
self::assertEquals('v3/pay/partner/transactions/out-trade-no/111/reverse', $payload->get('_service_url'));
self::assertEquals('wx55955316af4ef13', $payload->get('sp_appid'));
self::assertEquals('1600314069', $payload->get('sp_mchid'));
self::assertEquals('1600314070', $payload->get('sub_mchid'));
}

public function testServiceParams()
{
$rocket = new Rocket();
$rocket->setParams(['_config' => 'service_provider'])->setPayload(new Collection([
'sub_mchid' => '1222',
"out_trade_no" => "111",
'aaa' => 'aaa'
]));

$result = $this->plugin->assembly($rocket, function ($rocket) { return $rocket; });
$payload = $result->getPayload();

self::assertEquals('POST', $payload->get('_method'));
self::assertEquals('v3/pay/partner/transactions/out-trade-no/111/reverse', $payload->get('_service_url'));
self::assertEquals('wx55955316af4ef13', $payload->get('sp_appid'));
self::assertEquals('1600314069', $payload->get('sp_mchid'));
self::assertEquals('1222', $payload->get('sub_mchid'));
}
}
80 changes: 80 additions & 0 deletions tests/Plugin/Wechat/V3/Pay/Pos/PayPluginTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace Yansongda\Pay\Tests\Plugin\Wechat\V3\Pay\Pos;

use Yansongda\Artful\Contract\PackerInterface;
use Yansongda\Artful\Exception\InvalidParamsException;
use Yansongda\Pay\Exception\Exception;
use Yansongda\Pay\Plugin\Wechat\V3\Pay\Pos\PayPlugin;
use Yansongda\Artful\Rocket;
use Yansongda\Pay\Tests\TestCase;
Expand All @@ -19,6 +21,17 @@ protected function setUp(): void
$this->plugin = new PayPlugin();
}

public function testEmptyPayload()
{
$rocket = new Rocket();

self::expectException(InvalidParamsException::class);
self::expectExceptionCode(Exception::PARAMS_NECESSARY_PARAMS_MISSING);
self::expectExceptionMessage('参数异常: 付款码支付,参数为空');

$this->plugin->assembly($rocket, function ($rocket) { return $rocket; });
}

public function testNormal()
{
$rocket = new Rocket();
Expand Down Expand Up @@ -50,4 +63,71 @@ public function testNormal()
self::assertEquals(1, $payload->get('amount')['total']);
self::assertEquals('5678', $payload->get('scene_info')['id']);
}

public function testService()
{
$rocket = new Rocket();
$rocket->setParams(['_config' => 'service_provider'])->setPayload(new Collection([
'description' => 'test',
"out_trade_no" => "111",
'payer' => [
'auth_code' => '1234'
],
'amount' => [
'total' => 1,
],
'scene_info' => [
'id' => '5678'
],
]));

$result = $this->plugin->assembly($rocket, function ($rocket) { return $rocket; });
$payload = $result->getPayload();

self::assertEquals(PackerInterface::class, $result->getPacker());
self::assertEquals('v3/pay/partner/transactions/codepay', $payload->get('_service_url'));
self::assertEquals('POST', $payload->get('_method'));
self::assertEquals('wx55955316af4ef13', $payload->get('sp_appid'));
self::assertEquals('1600314069', $payload->get('sp_mchid'));
self::assertEquals('1600314070', $payload->get('sub_mchid'));
self::assertEquals('111', $payload->get('out_trade_no'));
self::assertEquals('test', $payload->get('description'));
self::assertEquals('1234', $payload->get('payer')['auth_code']);
self::assertEquals(1, $payload->get('amount')['total']);
self::assertEquals('5678', $payload->get('scene_info')['id']);
}

public function testServiceParams()
{
$rocket = new Rocket();
$rocket->setParams(['_config' => 'service_provider'])->setPayload(new Collection([
'sub_mchid' => 'aaaa',
'description' => 'test',
"out_trade_no" => "111",
'payer' => [
'auth_code' => '1234'
],
'amount' => [
'total' => 1,
],
'scene_info' => [
'id' => '5678'
],
]));

$result = $this->plugin->assembly($rocket, function ($rocket) { return $rocket; });
$payload = $result->getPayload();

self::assertEquals(PackerInterface::class, $result->getPacker());
self::assertEquals('v3/pay/partner/transactions/codepay', $payload->get('_service_url'));
self::assertEquals('POST', $payload->get('_method'));
self::assertEquals('wx55955316af4ef13', $payload->get('sp_appid'));
self::assertEquals('1600314069', $payload->get('sp_mchid'));
self::assertEquals('aaaa', $payload->get('sub_mchid'));
self::assertEquals('111', $payload->get('out_trade_no'));
self::assertEquals('test', $payload->get('description'));
self::assertEquals('1234', $payload->get('payer')['auth_code']);
self::assertEquals(1, $payload->get('amount')['total']);
self::assertEquals('5678', $payload->get('scene_info')['id']);
}
}

0 comments on commit b7cad54

Please sign in to comment.