Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

退款通知处理及相关单元测试 #863

Merged
merged 1 commit into from
Aug 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/Payment/Notify.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use EasyWeChat\Kernel\Support\Collection;
use EasyWeChat\Kernel\Support\XML;
use Symfony\Component\HttpFoundation\Request;
use EasyWeChat\Kernel\Support\AES;

/**
* Class Notify.
Expand Down Expand Up @@ -69,6 +70,29 @@ public function isValid()
return $localSign === $this->getNotify()->get('sign');
}

/**
* Decrypt req_info in refund Notify.
*
* @return $this
* @throws Exception
*/
public function decryptReqInfo()
{
if ($reqInfo = $this->getNotify()->get('req_info')) {
$decrypted = AES::decrypt(
base64_decode($reqInfo, true),
md5($this->merchant->key),
substr(md5($this->merchant->key), 0, 16)
);

$this->notify->req_info = $decrypted;

return $this;
} else {
throw new Exception('req_info does not exist.', 400);
}
}

/**
* Return the notify body from request.
*
Expand Down
34 changes: 34 additions & 0 deletions src/Payment/Traits/HandleNotify.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,40 @@ public function handleNotify(callable $callback)
return new Response(Support\XML::build($response));
}

/**
* Handle refund notify.
*
* @param callable $callback
*
* @return \EasyWeChat\Kernel\Http\Response
*
* @throws \Exception
*/
public function handleRefundNotify(callable $callback)
{
// please notice that the 'req_info' has been decrypted here
$notify = $this->getNotify()->decryptReqInfo();

$notify = $notify->getNotify();
$successful = $notify->get('result_code') === 'SUCCESS';

$handleResult = call_user_func_array($callback, [$notify, $successful]);

if (is_bool($handleResult) && $handleResult) {
$response = [
'return_code' => 'SUCCESS',
'return_msg' => 'OK',
];
} else {
$response = [
'return_code' => 'FAIL',
'return_msg' => $handleResult,
];
}

return new Response(Support\XML::build($response));
}

/**
* Handle native scan notify.
*
Expand Down
50 changes: 45 additions & 5 deletions tests/Payment/NotifyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,49 @@ public function testIsValid()
$this->assertTrue($notify->isValid());
}

public function testDecryptReqInfo()
{
$merchant = new Merchant([
'merchant_id' => '123456',
'key' => 'foo',
]);

$notify = \Mockery::mock(DummnyClassForNotiryTest::class.'[getNotify, decryptReqInfo]', [$merchant])->makePartial();

// build a collection vithout req_info
$mockInvalidResult = new Collection([
'foo' => 'bar',
'bax' => 123,
]);

$notify->expects()->getNotify()->andReturn($mockInvalidResult);

try {
$this->assertFalse($notify->decryptReqInfo());

$this->fail('No eaception is thrown.');
} catch (\Exception $e) {
$this->assertSame('req_info does not exist.', $e->getMessage());
}

// build a collection vith valid req_info
$mockValidResult = new Collection([
'foo' => 'bar',
'bax' => 123,
'req_info' => base64_encode(Support\AES::encrypt('foo-req-info', md5($merchant->key), substr(md5($merchant->key), 0, 16))),
]);

$notify->notify = $mockValidResult;

$notify->expects()->getNotify()->andReturn($mockValidResult);

// get the notify with its req_info decrypted
$notifyWithDecryptedReqInfo = $notify->decryptReqInfo();

$this->assertInstanceOf(Notify::class, $notifyWithDecryptedReqInfo);
$this->assertSame('foo-req-info', $notifyWithDecryptedReqInfo->notify->req_info);
}

public function testGetNotify()
{
$merchant = new Merchant([
Expand All @@ -62,7 +105,7 @@ public function testGetNotify()

// test notify already has non-empty value.
$notify = new DummnyClassForNotiryTest($merchant);
$notify->setNotify(new Collection(['foo' => 'bar']));
$notify->notify = new Collection(['foo' => 'bar']);

$notifyResult = $notify->getNotify();

Expand Down Expand Up @@ -116,8 +159,5 @@ public function testGetNotify()

class DummnyClassForNotiryTest extends Notify
{
public function setNotify(Collection $notify)
{
$this->notify = $notify;
}
public $notify;
}
51 changes: 44 additions & 7 deletions tests/Payment/Traits/HandleNotiryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,21 @@ public function handleNotifyCallback($notify, $successful)
return $successful;
}

/**
* A callback for handleRefundNotify().
*
* @param $notify
* @param $successful
*
* @return mixed
*/
public function handleRefundNotifyCallback($notify, $successful)
{
return $successful;
}



/**
* A callback for handleScanNotify().
*
Expand Down Expand Up @@ -80,19 +95,15 @@ public function testHandleNotify()

// mock Notify.
$mockNotify->shouldReceive('isValid')
->times(3)
->andReturn(false, true, true);

$mockNotify->shouldReceive('getNotify')
->twice()
->andReturn(
new Collection(['result_code' => 'SUCCESS']),
new Collection(['result_code' => 'FAILURE'])
new Collection(['result_code' => 'FAIL'])
);

$mock->shouldReceive('getNotify')
->times(3)
->andReturn($mockNotify);
$mock->shouldReceive('getNotify')->andReturn($mockNotify);

// $notify->isValid() === false
try {
Expand All @@ -106,10 +117,36 @@ public function testHandleNotify()
// result_code === 'SUCCESS'
$this->assertInstanceOf(Response::class, $mock->handleNotify([$this, 'handleNotifyCallback']));

// result_code === 'SUCCESS'
// result_code === 'FAIL'
$this->assertInstanceOf(Response::class, $mock->handleNotify([$this, 'handleNotifyCallback']));
}

public function testRefundHandleNotify()
{
$app = $this->makeApp();

$mock = \Mockery::mock(DummnyClassForHandleNotifyTest::class.'[getNotify, handleRefundNotify]', [$app])->shouldAllowMockingProtectedMethods()->makePartial();

$mockNotify = \Mockery::mock(Notify::class, [$app['merchant']]);

$mockNotify->shouldReceive('decryptReqInfo')
->andReturn($mockNotify);

$mockNotify->shouldReceive('getNotify')
->andReturn(
new Collection(['result_code' => 'SUCCESS']),
new Collection(['result_code' => 'FAIL'])
);

$mock->shouldReceive('getNotify')->andReturn($mockNotify);

// result_code === 'SUCCESS'
$this->assertInstanceOf(Response::class, $mock->handleRefundNotify([$this, 'handleRefundNotifyCallback']));

// result_code === 'FAIL'
$this->assertInstanceOf(Response::class, $mock->handleRefundNotify([$this, 'handleRefundNotifyCallback']));
}

public function testHandleScanNotify()
{
$app = $this->makeApp();
Expand Down