Merge pull request #479 from kanghuli/release

add: 支持服务商模式收款(2)
This commit is contained in:
yansongda 2021-08-28 18:38:33 +08:00 committed by GitHub
commit 722d19850b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 441 additions and 16 deletions

View File

@ -8,6 +8,7 @@ use Closure;
use Psr\Http\Message\RequestInterface;
use Yansongda\Pay\Contract\PluginInterface;
use Yansongda\Pay\Logger;
use Yansongda\Pay\Pay;
use Yansongda\Pay\Request;
use Yansongda\Pay\Rocket;
@ -56,15 +57,18 @@ abstract class GeneralPlugin implements PluginInterface
*/
protected function getUrl(Rocket $rocket): string
{
return get_wechat_base_uri($rocket->getParams()).
$this->getUri($rocket);
$params = $rocket->getParams();
$mode = get_wechat_config($params)->get('mode');
return get_wechat_base_uri($params).
(Pay::MODE_SERVICE == $mode ? $this->getPartnerUri($rocket) : $this->getUri($rocket));
}
protected function getHeaders(): array
{
return [
'Accept' => 'application/json, text/plain, application/x-gzip',
'User-Agent' => 'yansongda/pay-v3.0.0',
'User-Agent' => 'yansongda/pay-v3.0',
'Content-Type' => 'application/json; charset=utf-8',
];
}
@ -72,4 +76,9 @@ abstract class GeneralPlugin implements PluginInterface
abstract protected function doSomething(Rocket $rocket): void;
abstract protected function getUri(Rocket $rocket): string;
protected function getPartnerUri(Rocket $rocket): string
{
return $this->getUri($rocket);
}
}

View File

@ -4,7 +4,9 @@ declare(strict_types=1);
namespace Yansongda\Pay\Plugin\Wechat\Pay\App;
use Yansongda\Pay\Pay;
use Yansongda\Pay\Rocket;
use Yansongda\Supports\Collection;
use Yansongda\Supports\Config;
class PrepayPlugin extends \Yansongda\Pay\Plugin\Wechat\Pay\Common\PrepayPlugin
@ -14,8 +16,22 @@ class PrepayPlugin extends \Yansongda\Pay\Plugin\Wechat\Pay\Common\PrepayPlugin
return 'v3/pay/transactions/app';
}
protected function getWechatId(Config $config): array
protected function getPartnerUri(Rocket $rocket): string
{
return 'v3/pay/partner/transactions/app';
}
protected function getWechatId(Config $config, Collection $payload): array
{
if (Pay::MODE_SERVICE == $config->get('mode')) {
return [
'sp_appid' => $config->get('app_id', ''),
'sp_mchid' => $config->get('mch_id', ''),
'sub_appid' => $payload->get('sub_appid', $config->get('sub_app_id')),
'sub_mchid' => $payload->get('sub_mchid', $config->get('sub_mch_id')),
];
}
return [
'appid' => $config->get('app_id', ''),
'mchid' => $config->get('mch_id', ''),

View File

@ -7,6 +7,7 @@ namespace Yansongda\Pay\Plugin\Wechat\Pay\Common;
use Yansongda\Pay\Exception\Exception;
use Yansongda\Pay\Exception\InvalidParamsException;
use Yansongda\Pay\Parser\OriginResponseParser;
use Yansongda\Pay\Pay;
use Yansongda\Pay\Plugin\Wechat\GeneralPlugin;
use Yansongda\Pay\Rocket;
use Yansongda\Supports\Collection;
@ -29,6 +30,22 @@ class ClosePlugin extends GeneralPlugin
'/close';
}
/**
* @throws \Yansongda\Pay\Exception\InvalidParamsException
*/
protected function getPartnerUri(Rocket $rocket): string
{
$payload = $rocket->getPayload();
if (is_null($payload->get('out_trade_no'))) {
throw new InvalidParamsException(Exception::MISSING_NECESSARY_PARAMS);
}
return 'v3/pay/partner/transactions/out-trade-no/'.
$payload->get('out_trade_no').
'/close';
}
/**
* @throws \Yansongda\Pay\Exception\ContainerDependencyException
* @throws \Yansongda\Pay\Exception\ContainerException
@ -40,8 +57,17 @@ class ClosePlugin extends GeneralPlugin
$config = get_wechat_config($rocket->getParams());
$rocket->setPayload(new Collection([
$body = [
'mchid' => $config->get('mch_id', ''),
]));
];
if (Pay::MODE_SERVICE == $config->get('mode')) {
$body = [
'sp_mchid' => $config->get('mch_id', ''),
'sub_mchid' => $rocket->getPayload()->get('sub_mchid', $config->get('sub_mch_id', '')),
];
}
$rocket->setPayload(new Collection($body));
}
}

View File

@ -27,7 +27,7 @@ class CombinePrepayPlugin extends GeneralPlugin
$payload = $this->getWechatId($config);
if (!$rocket->getPayload()->has('notify_url')) {
$payload['notify_url'] = $config->get('notify_url');
$payload['notify_url'] = $config->get('notify_url', '');
}
if (!$rocket->getPayload()->has('combine_out_trade_no')) {

View File

@ -4,8 +4,10 @@ declare(strict_types=1);
namespace Yansongda\Pay\Plugin\Wechat\Pay\Common;
use Yansongda\Pay\Pay;
use Yansongda\Pay\Plugin\Wechat\GeneralPlugin;
use Yansongda\Pay\Rocket;
use Yansongda\Supports\Collection;
use Yansongda\Supports\Config;
class PrepayPlugin extends GeneralPlugin
@ -15,6 +17,11 @@ class PrepayPlugin extends GeneralPlugin
return 'v3/pay/transactions/jsapi';
}
protected function getPartnerUri(Rocket $rocket): string
{
return 'v3/pay/partner/transactions/jsapi';
}
/**
* @throws \Yansongda\Pay\Exception\ContainerDependencyException
* @throws \Yansongda\Pay\Exception\ContainerException
@ -23,18 +30,28 @@ class PrepayPlugin extends GeneralPlugin
protected function doSomething(Rocket $rocket): void
{
$config = get_wechat_config($rocket->getParams());
$payload = $rocket->getPayload();
$payload = $this->getWechatId($config);
$wechatId = $this->getWechatId($config, $payload);
if (!$rocket->getPayload()->has('notify_url')) {
$payload['notify_url'] = $config->get('notify_url');
if (!$payload->has('notify_url')) {
$wechatId['notify_url'] = $config->get('notify_url');
}
$rocket->mergePayload($payload);
$rocket->mergePayload($wechatId);
}
protected function getWechatId(Config $config): array
protected function getWechatId(Config $config, Collection $payload): array
{
if (Pay::MODE_SERVICE == $config->get('mode')) {
return [
'sp_appid' => $config->get('mp_app_id', ''),
'sp_mchid' => $config->get('mch_id', ''),
'sub_appid' => $payload->get('sub_appid', $config->get('sub_mp_app_id')),
'sub_mchid' => $payload->get('sub_mchid', $config->get('sub_mch_id')),
];
}
return [
'appid' => $config->get('mp_app_id', ''),
'mchid' => $config->get('mch_id', ''),

View File

@ -37,6 +37,32 @@ class QueryPlugin extends GeneralPlugin
throw new InvalidParamsException(Exception::MISSING_NECESSARY_PARAMS);
}
/**
* @throws \Yansongda\Pay\Exception\ContainerDependencyException
* @throws \Yansongda\Pay\Exception\ContainerException
* @throws \Yansongda\Pay\Exception\ServiceNotFoundException
* @throws \Yansongda\Pay\Exception\InvalidParamsException
*/
protected function getPartnerUri(Rocket $rocket): string
{
$config = get_wechat_config($rocket->getParams());
$payload = $rocket->getPayload();
if (!is_null($payload->get('transaction_id'))) {
return 'v3/pay/partner/transactions/id/'.
$payload->get('transaction_id').
'?mchid='.$config->get('mch_id', '');
}
if (!is_null($payload->get('out_trade_no'))) {
return 'v3/pay/partner/transactions/out-trade-no/'.
$payload->get('out_trade_no').
'?mchid='.$config->get('mch_id', '');
}
throw new InvalidParamsException(Exception::MISSING_NECESSARY_PARAMS);
}
protected function getMethod(): string
{
return 'GET';

View File

@ -12,4 +12,9 @@ class PrepayPlugin extends \Yansongda\Pay\Plugin\Wechat\Pay\Common\PrepayPlugin
{
return 'v3/pay/transactions/h5';
}
protected function getPartnerUri(Rocket $rocket): string
{
return 'v3/pay/partner/transactions/h5';
}
}

View File

@ -4,12 +4,23 @@ declare(strict_types=1);
namespace Yansongda\Pay\Plugin\Wechat\Pay\Mini;
use Yansongda\Pay\Pay;
use Yansongda\Supports\Collection;
use Yansongda\Supports\Config;
class PrepayPlugin extends \Yansongda\Pay\Plugin\Wechat\Pay\Common\PrepayPlugin
{
protected function getWechatId(Config $config): array
protected function getWechatId(Config $config, Collection $payload): array
{
if (Pay::MODE_SERVICE == $config->get('mode')) {
return [
'sp_appid' => $config->get('app_id', ''),
'sp_mchid' => $config->get('mch_id', ''),
'sub_appid' => $payload->get('sub_appid', $config->get('sub_mini_app_id')),
'sub_mchid' => $payload->get('sub_mchid', $config->get('sub_mch_id')),
];
}
return [
'appid' => $config->get('mini_app_id', ''),
'mchid' => $config->get('mch_id', ''),

View File

@ -12,4 +12,9 @@ class PrepayPlugin extends \Yansongda\Pay\Plugin\Wechat\Pay\Common\PrepayPlugin
{
return 'v3/pay/transactions/native';
}
protected function getPartnerUri(Rocket $rocket): string
{
return 'v3/pay/partner/transactions/native';
}
}

View File

@ -27,4 +27,20 @@ class GeneralPluginTest extends TestCase
self::assertEquals('POST', $radar->getMethod());
self::assertEquals(new Uri(Wechat::URL[Pay::MODE_NORMAL].'yansongda/pay'), $radar->getUri());
}
public function testPartner()
{
$rocket = new Rocket();
$rocket->setParams(['_config' => 'service_provider']);
$plugin = new WechatGeneralPluginStub();
$result = $plugin->assembly($rocket, function ($rocket) { return $rocket; });
$radar = $result->getRadar();
self::assertInstanceOf(RequestInterface::class, $radar);
self::assertEquals('POST', $radar->getMethod());
self::assertEquals(new Uri(Wechat::URL[Pay::MODE_SERVICE].'yansongda/pay/partner'), $radar->getUri());
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace Yansongda\Pay\Tests\Plugin\Wechat\App;
namespace Yansongda\Pay\Tests\Plugin\Wechat\Pay\App;
use Yansongda\Pay\Plugin\Wechat\Pay\App\InvokePrepayPlugin;
use Yansongda\Pay\Rocket;

View File

@ -0,0 +1,56 @@
<?php
namespace Yansongda\Pay\Tests\Plugin\Wechat\Pay\App;
use Yansongda\Pay\Plugin\Wechat\Pay\App\PrepayPlugin;
use Yansongda\Pay\Rocket;
use Yansongda\Pay\Tests\TestCase;
use Yansongda\Supports\Collection;
class PrepayPluginTest extends TestCase
{
public function testWechatIdNormal()
{
$rocket = new Rocket();
$rocket->setParams([])->setPayload(new Collection());
$plugin = new PrepayPlugin();
$result = $plugin->assembly($rocket, function ($rocket) { return $rocket; });
$payload = $result->getPayload();
self::assertEquals('yansongda', $payload->get('appid'));
self::assertEquals('1600314069', $payload->get('mchid'));
}
public function testWechatIdPartner()
{
$rocket = new Rocket();
$rocket->setParams(['_config' => 'service_provider'])->setPayload(new Collection());
$plugin = new PrepayPlugin();
$result = $plugin->assembly($rocket, function ($rocket) { return $rocket; });
$payload = $result->getPayload();
self::assertEquals('wx55955316af4ef16', $payload->get('sub_appid'));
self::assertEquals('1600314070', $payload->get('sub_mchid'));
}
public function testWechatIdPartnerDirect()
{
$rocket = new Rocket();
$rocket->setParams(['_config' => 'service_provider'])->setPayload(new Collection(['sub_appid' => '123']));
$plugin = new PrepayPlugin();
$result = $plugin->assembly($rocket, function ($rocket) { return $rocket; });
$payload = $result->getPayload();
self::assertEquals('123', $payload->get('sub_appid'));
self::assertEquals('1600314070', $payload->get('sub_mchid'));
}
}

View File

@ -0,0 +1,79 @@
<?php
namespace Yansongda\Pay\Tests\Plugin\Wechat\Pay\Common;
use GuzzleHttp\Psr7\Uri;
use Yansongda\Pay\Exception\Exception;
use Yansongda\Pay\Exception\InvalidParamsException;
use Yansongda\Pay\Pay;
use Yansongda\Pay\Plugin\Wechat\Pay\Common\ClosePlugin;
use Yansongda\Pay\Provider\Wechat;
use Yansongda\Pay\Rocket;
use Yansongda\Pay\Tests\TestCase;
use Yansongda\Supports\Collection;
class ClosePluginTest extends TestCase
{
public function testNormal()
{
$rocket = new Rocket();
$rocket->setParams([])->setPayload(new Collection(['out_trade_no' => '123']));
$plugin = new ClosePlugin();
$result = $plugin->assembly($rocket, function ($rocket) { return $rocket; });
$radar = $result->getRadar();
$payload = $result->getPayload();
self::assertEquals(new Uri(Wechat::URL[Pay::MODE_NORMAL].'v3/pay/transactions/out-trade-no/123/close'), $radar->getUri());
self::assertEquals('1600314069', $payload->get('mchid'));
self::assertArrayNotHasKey('sp_mchid', $payload->all());
self::assertArrayNotHasKey('sub_mchid', $payload->all());
}
public function testNormalNoOutTradeNo()
{
$rocket = new Rocket();
$rocket->setParams([])->setPayload(new Collection());
$plugin = new ClosePlugin();
self::expectException(InvalidParamsException::class);
self::expectExceptionCode(Exception::MISSING_NECESSARY_PARAMS);
$plugin->assembly($rocket, function ($rocket) { return $rocket; });
}
public function testPartner()
{
$rocket = new Rocket();
$rocket->setParams(['_config' => 'service_provider'])->setPayload(new Collection(['out_trade_no' => '123']));
$plugin = new ClosePlugin();
$result = $plugin->assembly($rocket, function ($rocket) { return $rocket; });
$radar = $result->getRadar();
$payload = $result->getPayload();
self::assertEquals(new Uri(Wechat::URL[Pay::MODE_NORMAL].'v3/pay/partner/transactions/out-trade-no/123/close'), $radar->getUri());
self::assertEquals('1600314069', $payload->get('sp_mchid'));
self::assertEquals('1600314070', $payload->get('sub_mchid'));
self::assertArrayNotHasKey('mchid', $payload->all());
}
public function testPartnerDirectPayload()
{
$rocket = new Rocket();
$rocket->setParams(['_config' => 'service_provider'])->setPayload(new Collection(['out_trade_no' => '123', 'sub_mchid' => '123']));
$plugin = new ClosePlugin();
$result = $plugin->assembly($rocket, function ($rocket) { return $rocket; });
$payload = $result->getPayload();
self::assertEquals('123', $payload->get('sub_mchid'));
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace Yansongda\Pay\Tests\Plugin\Wechat\Common;
namespace Yansongda\Pay\Tests\Plugin\Wechat\Pay\Common;
use Yansongda\Pay\Exception\InvalidResponseException;
use Yansongda\Pay\Plugin\Wechat\Pay\Common\InvokePrepayPlugin;

View File

@ -0,0 +1,80 @@
<?php
namespace Yansongda\Pay\Tests\Plugin\Wechat\Pay\Common;
use GuzzleHttp\Psr7\Uri;
use Psr\Http\Message\RequestInterface;
use Yansongda\Pay\Pay;
use Yansongda\Pay\Plugin\Wechat\Pay\Common\PrepayPlugin;
use Yansongda\Pay\Provider\Wechat;
use Yansongda\Pay\Rocket;
use Yansongda\Pay\Tests\TestCase;
use Yansongda\Supports\Collection;
class PrepayPluginTest extends TestCase
{
public function testNormal()
{
$rocket = new Rocket();
$rocket->setParams([])->setPayload(new Collection());
$plugin = new PrepayPlugin();
$result = $plugin->assembly($rocket, function ($rocket) { return $rocket; });
$radar = $result->getRadar();
$payload = $result->getPayload();
self::assertInstanceOf(RequestInterface::class, $radar);
self::assertEquals('POST', $radar->getMethod());
self::assertEquals(new Uri(Wechat::URL[Pay::MODE_NORMAL].'v3/pay/transactions/jsapi'), $radar->getUri());
self::assertArrayHasKey('appid', $payload->all());
self::assertArrayHasKey('mchid', $payload->all());
self::assertArrayNotHasKey('sp_appid', $payload->all());
self::assertArrayNotHasKey('sp_mchid', $payload->all());
self::assertArrayNotHasKey('sub_appid', $payload->all());
self::assertArrayNotHasKey('sub_mchid', $payload->all());
self::assertEquals('wx55955316af4ef13', $payload->get('appid'));
self::assertEquals('1600314069', $payload->get('mchid'));
}
public function testPartner()
{
$rocket = new Rocket();
$rocket->setParams(['_config' => 'service_provider'])->setPayload(new Collection());
$plugin = new PrepayPlugin();
$result = $plugin->assembly($rocket, function ($rocket) { return $rocket; });
$radar = $result->getRadar();
$payload = $result->getPayload();
self::assertInstanceOf(RequestInterface::class, $radar);
self::assertEquals('POST', $radar->getMethod());
self::assertEquals(new Uri(Wechat::URL[Pay::MODE_SERVICE].'v3/pay/partner/transactions/jsapi'), $radar->getUri());
self::assertArrayNotHasKey('appid', $payload->all());
self::assertArrayNotHasKey('mchid', $payload->all());
self::assertArrayHasKey('sp_appid', $payload->all());
self::assertArrayHasKey('sp_mchid', $payload->all());
self::assertArrayHasKey('sub_appid', $payload->all());
self::assertArrayHasKey('sub_mchid', $payload->all());
self::assertEquals('wx55955316af4ef15', $payload->get('sub_appid'));
self::assertEquals('1600314070', $payload->get('sub_mchid'));
}
public function testPartnerDirectPayload()
{
$rocket = new Rocket();
$rocket->setParams(['_config' => 'service_provider'])->setPayload(new Collection(['sub_appid' => '123']));
$plugin = new PrepayPlugin();
$result = $plugin->assembly($rocket, function ($rocket) { return $rocket; });
$payload = $result->getPayload();
self::assertEquals('123', $payload->get('sub_appid'));
self::assertEquals('1600314070', $payload->get('sub_mchid'));
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace Yansongda\Pay\Tests\Plugin\Wechat\Mini;
namespace Yansongda\Pay\Tests\Plugin\Wechat\Pay\Mini;
use Yansongda\Pay\Plugin\Wechat\Pay\Mini\InvokePrepayPlugin;
use Yansongda\Pay\Rocket;

View File

@ -0,0 +1,56 @@
<?php
namespace Yansongda\Pay\Tests\Plugin\Wechat\Pay\Mini;
use Yansongda\Pay\Plugin\Wechat\Pay\Mini\PrepayPlugin;
use Yansongda\Pay\Rocket;
use Yansongda\Pay\Tests\TestCase;
use Yansongda\Supports\Collection;
class PrepayPluginTest extends TestCase
{
public function testWechatIdNormal()
{
$rocket = new Rocket();
$rocket->setParams([])->setPayload(new Collection());
$plugin = new PrepayPlugin();
$result = $plugin->assembly($rocket, function ($rocket) { return $rocket; });
$payload = $result->getPayload();
self::assertEquals('wx55955316af4ef14', $payload->get('appid'));
self::assertEquals('1600314069', $payload->get('mchid'));
}
public function testWechatIdPartner()
{
$rocket = new Rocket();
$rocket->setParams(['_config' => 'service_provider'])->setPayload(new Collection());
$plugin = new PrepayPlugin();
$result = $plugin->assembly($rocket, function ($rocket) { return $rocket; });
$payload = $result->getPayload();
self::assertEquals('wx55955316af4ef17', $payload->get('sub_appid'));
self::assertEquals('1600314070', $payload->get('sub_mchid'));
}
public function testWechatIdPartnerDirect()
{
$rocket = new Rocket();
$rocket->setParams(['_config' => 'service_provider'])->setPayload(new Collection(['sub_appid' => '123']));
$plugin = new PrepayPlugin();
$result = $plugin->assembly($rocket, function ($rocket) { return $rocket; });
$payload = $result->getPayload();
self::assertEquals('123', $payload->get('sub_appid'));
self::assertEquals('1600314070', $payload->get('sub_mchid'));
}
}

View File

@ -15,4 +15,9 @@ class WechatGeneralPluginStub extends GeneralPlugin
{
return 'yansongda/pay';
}
protected function getPartnerUri(Rocket $rocket): string
{
return 'yansongda/pay/partner';
}
}

View File

@ -20,6 +20,7 @@ class TestCase extends \PHPUnit\Framework\TestCase
],
'wechat' => [
'default' => [
'app_id' => 'yansongda',
'mp_app_id' => 'wx55955316af4ef13',
'mch_id' => '1600314069',
'mini_app_id' => 'wx55955316af4ef14',
@ -29,6 +30,23 @@ class TestCase extends \PHPUnit\Framework\TestCase
'wechat_public_cert_path' => [
'45F59D4DABF31918AFCEC556D5D2C6E376675D57' => __DIR__.'/Cert/wechatPublicKey.crt',
],
'mode' => Pay::MODE_NORMAL,
],
'service_provider' => [
'mp_app_id' => 'wx55955316af4ef13',
'mch_id' => '1600314069',
'mini_app_id' => 'wx55955316af4ef14',
'mch_secret_key' => '53D67FCB97E68F9998CBD17ED7A8D1E2',
'mch_secret_cert' => __DIR__.'/Cert/wechatAppPrivateKey.pem',
'mch_public_cert_path' => __DIR__.'/Cert/wechatAppPublicKey.pem',
'wechat_public_cert_path' => [
'45F59D4DABF31918AFCEC556D5D2C6E376675D57' => __DIR__.'/Cert/wechatPublicKey.crt',
],
'sub_mp_app_id' => 'wx55955316af4ef15',
'sub_app_id' => 'wx55955316af4ef16',
'sub_mini_app_id' => 'wx55955316af4ef17',
'sub_mch_id' => '1600314070',
'mode' => Pay::MODE_SERVICE,
]
]
];