diff --git a/app/code/Magento/Authorizenet/Model/Authorizenet.php b/app/code/Magento/Authorizenet/Model/Authorizenet.php index b35e4f4c39911df89d553ef98ad77eba768ccf3c..4ad08d89cc495556bd4b5b794417fb7185817d92 100644 --- a/app/code/Magento/Authorizenet/Model/Authorizenet.php +++ b/app/code/Magento/Authorizenet/Model/Authorizenet.php @@ -6,6 +6,7 @@ namespace Magento\Authorizenet\Model; use Magento\Authorizenet\Model\TransactionService; +use Magento\Framework\HTTP\ZendClientFactory; /** * @SuppressWarnings(PHPMD.TooManyFields) @@ -97,6 +98,11 @@ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc */ protected $_debugReplacePrivateDataKeys = ['merchantAuthentication', 'x_login']; + /** + * @var \Magento\Framework\HTTP\ZendClientFactory + */ + protected $httpClientFactory; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -111,6 +117,7 @@ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc * @param \Magento\Authorizenet\Model\Request\Factory $requestFactory * @param \Magento\Authorizenet\Model\Response\Factory $responseFactory * @param \Magento\Authorizenet\Model\TransactionService $transactionService + * @param \Magento\Framework\HTTP\ZendClientFactory $httpClientFactory * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection * @param array $data @@ -130,6 +137,7 @@ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc \Magento\Authorizenet\Model\Request\Factory $requestFactory, \Magento\Authorizenet\Model\Response\Factory $responseFactory, TransactionService $transactionService, + ZendClientFactory $httpClientFactory, \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, array $data = [] @@ -138,6 +146,7 @@ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc $this->requestFactory = $requestFactory; $this->responseFactory = $responseFactory; $this->transactionService = $transactionService; + $this->httpClientFactory = $httpClientFactory; parent::__construct( $context, @@ -370,7 +379,8 @@ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc protected function postRequest(\Magento\Authorizenet\Model\Request $request) { $result = $this->responseFactory->create(); - $client = new \Magento\Framework\HTTP\ZendClient(); + /** @var \Magento\Framework\HTTP\ZendClient $client */ + $client = $this->httpClientFactory->create(); $url = $this->getConfigData('cgi_url') ?: self::CGI_URL; $debugData = ['url' => $url, 'request' => $request->getData()]; $client->setUri($url); diff --git a/app/code/Magento/Authorizenet/Model/Directpost.php b/app/code/Magento/Authorizenet/Model/Directpost.php index bbfcd0f7d6e128fb7d0e5d0740223ef42282c469..68fd630f21f4593740fed6288e3821b87677d7db 100644 --- a/app/code/Magento/Authorizenet/Model/Directpost.php +++ b/app/code/Magento/Authorizenet/Model/Directpost.php @@ -6,6 +6,7 @@ namespace Magento\Authorizenet\Model; use Magento\Authorizenet\Model\TransactionService; +use Magento\Framework\HTTP\ZendClientFactory; use Magento\Payment\Model\Method\ConfigInterface; use Magento\Payment\Model\Method\TransparentInterface; use Magento\Sales\Model\Order\Email\Sender\OrderSender; @@ -132,6 +133,7 @@ class Directpost extends \Magento\Authorizenet\Model\Authorizenet implements Tra * @param Directpost\Request\Factory $requestFactory * @param Directpost\Response\Factory $responseFactory * @param \Magento\Authorizenet\Model\TransactionService $transactionService + * @param \Magento\Framework\HTTP\ZendClientFactory $httpClientFactory * @param \Magento\Sales\Model\OrderFactory $orderFactory * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Quote\Model\QuoteRepository $quoteRepository @@ -156,6 +158,7 @@ class Directpost extends \Magento\Authorizenet\Model\Authorizenet implements Tra \Magento\Authorizenet\Model\Directpost\Request\Factory $requestFactory, \Magento\Authorizenet\Model\Directpost\Response\Factory $responseFactory, TransactionService $transactionService, + ZendClientFactory $httpClientFactory, \Magento\Sales\Model\OrderFactory $orderFactory, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Quote\Model\QuoteRepository $quoteRepository, @@ -187,6 +190,7 @@ class Directpost extends \Magento\Authorizenet\Model\Authorizenet implements Tra $requestFactory, $responseFactory, $transactionService, + $httpClientFactory, $resource, $resourceCollection, $data @@ -404,9 +408,7 @@ class Directpost extends \Magento\Authorizenet\Model\Authorizenet implements Tra if ($result->getXTransId() != $payment->getParentTransactionId()) { $payment->setTransactionId($result->getXTransId()); } - $shouldCloseCaptureTransaction = $payment->getOrder()->canCreditmemo() ? 0 : 1; - $payment->setIsTransactionClosed(1) - ->setShouldCloseParentTransaction($shouldCloseCaptureTransaction) + $payment->setIsTransactionClosed(true) ->setTransactionAdditionalInfo(self::REAL_TRANSACTION_ID_KEY, $result->getXTransId()); return $this; } diff --git a/app/code/Magento/Authorizenet/Test/Unit/Model/DirectpostTest.php b/app/code/Magento/Authorizenet/Test/Unit/Model/DirectpostTest.php index 3247ed2cb9329f86e0efda4e07aeae938515f05b..f2203f2fbe1f2bcd7cefa5e2fbf9a8955b1fc24a 100644 --- a/app/code/Magento/Authorizenet/Test/Unit/Model/DirectpostTest.php +++ b/app/code/Magento/Authorizenet/Test/Unit/Model/DirectpostTest.php @@ -9,6 +9,9 @@ use Magento\Framework\Simplexml\Element; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; use Magento\Authorizenet\Model\Directpost; use Magento\Authorizenet\Model\TransactionService; +use Magento\Authorizenet\Model\Request; +use Magento\Authorizenet\Model\Directpost\Request\Factory; +use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Payment\Transaction\Repository as TransactionRepository; /** @@ -16,6 +19,10 @@ use Magento\Sales\Model\Order\Payment\Transaction\Repository as TransactionRepos */ class DirectpostTest extends \PHPUnit_Framework_TestCase { + const TOTAL_AMOUNT = 100.02; + const INVOICE_NUM = '00000001'; + const TRANSACTION_ID = '41a23x34fd124'; + /** * @var \Magento\Authorizenet\Model\Directpost */ @@ -56,6 +63,16 @@ class DirectpostTest extends \PHPUnit_Framework_TestCase */ protected $transactionServiceMock; + /** + * @var \Magento\Framework\HTTP\ZendClient|\PHPUnit_Framework_MockObject_MockObject + */ + protected $httpClientMock; + + /** + * @var \Magento\Authorizenet\Model\Directpost\Request\Factory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $requestFactory; + protected function setUp() { $this->scopeConfigMock = $this->getMockBuilder('Magento\Framework\App\Config\ScopeConfigInterface') @@ -64,7 +81,8 @@ class DirectpostTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->setMethods([ 'getOrder', 'getId', 'setAdditionalInformation', 'getAdditionalInformation', - 'setIsTransactionDenied', 'setIsTransactionClosed' + 'setIsTransactionDenied', 'setIsTransactionClosed', 'decrypt', 'getCcLast4', + 'getParentTransactionId', 'getPoNumber' ]) ->getMock(); $this->dataHelperMock = $this->getMockBuilder('Magento\Authorizenet\Helper\Data') @@ -85,15 +103,20 @@ class DirectpostTest extends \PHPUnit_Framework_TestCase ->setMethods(['getTransactionDetails']) ->getMock(); + $this->requestFactory = $this->getRequestFactoryMock(); + $httpClientFactoryMock = $this->getHttpClientFactoryMock(); + $helper = new ObjectManagerHelper($this); $this->directpost = $helper->getObject( 'Magento\Authorizenet\Model\Directpost', [ 'scopeConfig' => $this->scopeConfigMock, 'dataHelper' => $this->dataHelperMock, + 'requestFactory' => $this->requestFactory, 'responseFactory' => $this->responseFactoryMock, 'transactionRepository' => $this->transactionRepositoryMock, - 'transactionService' => $this->transactionServiceMock + 'transactionService' => $this->transactionServiceMock, + 'httpClientFactory' => $httpClientFactoryMock ] ); } @@ -376,7 +399,7 @@ class DirectpostTest extends \PHPUnit_Framework_TestCase } /** - * @covers \Magento\Authorizenet\Model\Directpost::fetchTransactionInfo + * @covers \Magento\Authorizenet\Model\Directpost::fetchTransactionInfo * * @param $transactionId * @param $resultStatus @@ -440,6 +463,72 @@ class DirectpostTest extends \PHPUnit_Framework_TestCase $this->directpost->fetchTransactionInfo($this->paymentMock, $transactionId); } + /** + * @covers \Magento\Authorizenet\Model\Directpost::refund() + * @return void + */ + public function testSuccessRefund() + { + $card = 1111; + + $this->paymentMock->expects(static::exactly(2)) + ->method('getCcLast4') + ->willReturn($card); + $this->paymentMock->expects(static::once()) + ->method('decrypt') + ->willReturn($card); + $this->paymentMock->expects(static::exactly(3)) + ->method('getParentTransactionId') + ->willReturn(self::TRANSACTION_ID . '-capture'); + $this->paymentMock->expects(static::once()) + ->method('getPoNumber') + ->willReturn(self::INVOICE_NUM); + $this->paymentMock->expects(static::once()) + ->method('setIsTransactionClosed') + ->with(true) + ->willReturnSelf(); + + $orderMock = $this->getOrderMock(); + + $this->paymentMock->expects(static::exactly(2)) + ->method('getOrder') + ->willReturn($orderMock); + + $transactionMock = $this->getMockBuilder(Order\Payment\Transaction::class) + ->disableOriginalConstructor() + ->setMethods(['getAdditionalInformation']) + ->getMock(); + $transactionMock->expects(static::once()) + ->method('getAdditionalInformation') + ->with(Directpost::REAL_TRANSACTION_ID_KEY) + ->willReturn(self::TRANSACTION_ID); + + $this->transactionRepositoryMock->expects(static::once()) + ->method('getByTransactionId') + ->willReturn($transactionMock); + + $response = $this->getRefundResponseBody( + Directpost::RESPONSE_CODE_APPROVED, + Directpost::RESPONSE_REASON_CODE_APPROVED, + 'Successful' + ); + $this->httpClientMock->expects(static::once()) + ->method('getBody') + ->willReturn($response); + + $this->responseMock->expects(static::once()) + ->method('getXResponseCode') + ->willReturn(Directpost::RESPONSE_CODE_APPROVED); + $this->responseMock->expects(static::once()) + ->method('getXResponseReasonCode') + ->willReturn(Directpost::RESPONSE_REASON_CODE_APPROVED); + + $this->dataHelperMock->expects(static::never()) + ->method('wrapGatewayError'); + + $this->directpost->refund($this->paymentMock, self::TOTAL_AMOUNT); + } + /** * Get data for tests * @return array @@ -468,14 +557,48 @@ class DirectpostTest extends \PHPUnit_Framework_TestCase $this->responseMock = $this->getMockBuilder('Magento\Authorizenet\Model\Directpost\Response') ->setMethods( [ - 'setData', 'isValidHash', 'getXTransId', - 'getXResponseCode', 'getXResponseReasonText', - 'getXAmount' + 'isValidHash', + 'getXTransId', 'getXResponseCode', 'getXResponseReasonCode', 'getXResponseReasonText', 'getXAmount', + 'setXResponseCode', 'setXResponseReasonCode', 'setXAvsCode', 'setXResponseReasonText', + 'setXTransId', 'setXInvoiceNum', 'setXAmount', 'setXMethod', 'setXType', 'setData', + 'setXAccountNumber', + '__wakeup' ] ) ->disableOriginalConstructor() ->getMock(); + $this->responseMock->expects(static::any()) + ->method('setXResponseCode') + ->willReturnSelf(); + $this->responseMock->expects(static::any()) + ->method('setXResponseReasonCode') + ->willReturnSelf(); + $this->responseMock->expects(static::any()) + ->method('setXResponseReasonText') + ->willReturnSelf(); + $this->responseMock->expects(static::any()) + ->method('setXAvsCode') + ->willReturnSelf(); + $this->responseMock->expects(static::any()) + ->method('setXTransId') + ->willReturnSelf(); + $this->responseMock->expects(static::any()) + ->method('setXInvoiceNum') + ->willReturnSelf(); + $this->responseMock->expects(static::any()) + ->method('setXAmount') + ->willReturnSelf(); + $this->responseMock->expects(static::any()) + ->method('setXMethod') + ->willReturnSelf(); + $this->responseMock->expects(static::any()) + ->method('setXType') + ->willReturnSelf(); + $this->responseMock->expects(static::any()) + ->method('setData') + ->willReturnSelf(); + $this->responseFactoryMock->expects($this->any()) ->method('create') ->willReturn($this->responseMock); @@ -530,4 +653,105 @@ class DirectpostTest extends \PHPUnit_Framework_TestCase libxml_use_internal_errors(false); return $document; } + + /** + * Get mock for authorize.net request factory + * @return \PHPUnit_Framework_MockObject_MockBuilder + */ + private function getRequestFactoryMock() + { + $requestFactory = $this->getMockBuilder(Factory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $request = $this->getMockBuilder(Request::class) + ->disableOriginalConstructor() + ->setMethods(['__wakeup']) + ->getMock(); + $requestFactory->expects(static::any()) + ->method('create') + ->willReturn($request); + return $requestFactory; + } + + /** + * Get mock for order + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function getOrderMock() + { + $orderMock = $this->getMockBuilder(Order::class) + ->disableOriginalConstructor() + ->setMethods([ + 'getId', 'getIncrementId', 'getStoreId', 'getBillingAddress', 'getShippingAddress', + 'getBaseCurrencyCode', 'getBaseTaxAmount', '__wakeup' + ]) + ->getMock(); + + $orderMock->expects(static::once()) + ->method('getId') + ->willReturn(1); + + $orderMock->expects(static::exactly(2)) + ->method('getIncrementId') + ->willReturn(self::INVOICE_NUM); + + $orderMock->expects(static::once()) + ->method('getStoreId') + ->willReturn(1); + + $orderMock->expects(static::once()) + ->method('getBaseCurrencyCode') + ->willReturn('USD'); + return $orderMock; + } + + /** + * Create and return mock for http client factory + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function getHttpClientFactoryMock() + { + $this->httpClientMock = $this->getMockBuilder(\Magento\Framework\HTTP\ZendClient::class) + ->disableOriginalConstructor() + ->setMethods(['request', 'getBody', '__wakeup']) + ->getMock(); + + $this->httpClientMock->expects(static::any()) + ->method('request') + ->willReturnSelf(); + + $httpClientFactoryMock = $this->getMockBuilder(\Magento\Framework\HTTP\ZendClientFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $httpClientFactoryMock->expects(static::any()) + ->method('create') + ->willReturn($this->httpClientMock); + return $httpClientFactoryMock; + } + + /** + * Get mocked response for refund transaction + * @param $code + * @param $reasonCode + * @param $reasonText + * @return string + */ + private function getRefundResponseBody($code, $reasonCode, $reasonText) + { + $result = array_fill(0, 50, ''); + $result[0] = $code; // XResponseCode + $result[2] = $reasonCode; // XResponseReasonCode + $result[3] = $reasonText; // XResponseReasonText + $result[6] = self::TRANSACTION_ID; // XTransId + $result[7] = self::INVOICE_NUM; // XInvoiceNum + $result[9] = self::TOTAL_AMOUNT; // XAmount + $result[10] = Directpost::REQUEST_METHOD_CC; // XMethod + $result[11] = Directpost::REQUEST_TYPE_CREDIT; // XType + $result[37] = md5(self::TRANSACTION_ID); // x_MD5_Hash + $result[50] = '48329483921'; // setXAccountNumber + return implode(Directpost::RESPONSE_DELIM_CHAR, $result); + } } diff --git a/app/code/Magento/Braintree/Model/PaymentMethod.php b/app/code/Magento/Braintree/Model/PaymentMethod.php index 45171956e87bcf8832723f7b7dffeb90ea5f1f79..7b045d5dcde6eb43b1b1cf37419728a7594fe0aa 100644 --- a/app/code/Magento/Braintree/Model/PaymentMethod.php +++ b/app/code/Magento/Braintree/Model/PaymentMethod.php @@ -657,7 +657,6 @@ class PaymentMethod extends \Magento\Payment\Model\Method\Cc : $this->braintreeTransaction->refund($transactionId, $amount); $this->_debug($this->_convertObjToArray($result)); if ($result->success) { - $payment->setTransactionId($transactionId . '-' . Transaction::TYPE_REFUND); $payment->setIsTransactionClosed(true); } else { throw new LocalizedException($this->errorHelper->parseBraintreeError($result)); diff --git a/app/code/Magento/Braintree/Test/Unit/Model/PaymentMethodTest.php b/app/code/Magento/Braintree/Test/Unit/Model/PaymentMethodTest.php index e20af765062e3b3b0713c5732d5b67f8f3c279f3..9e90e201f6b85d8062be2784947c7bef3ada301c 100644 --- a/app/code/Magento/Braintree/Test/Unit/Model/PaymentMethodTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Model/PaymentMethodTest.php @@ -2379,7 +2379,6 @@ class PaymentMethodTest extends \PHPUnit_Framework_TestCase $this->model->refund($paymentObject, $amount); $this->assertEquals(1, $paymentObject->getIsTransactionClosed()); - $this->assertEquals($refundTransactionId . '-' .Transaction::TYPE_REFUND, $paymentObject->getTransactionId()); } /** diff --git a/app/code/Magento/Paypal/Model/Payflowpro.php b/app/code/Magento/Paypal/Model/Payflowpro.php index 6efc7e7cca4ed1735aeeaaacc8deee09aaf18eb1..894c0792a99e4ab689f5c40aed6b0d29c0d334a5 100644 --- a/app/code/Magento/Paypal/Model/Payflowpro.php +++ b/app/code/Magento/Paypal/Model/Payflowpro.php @@ -500,8 +500,7 @@ class Payflowpro extends \Magento\Payment\Model\Method\Cc implements GatewayInte $this->processErrors($response); if ($response->getResultCode() == self::RESPONSE_CODE_APPROVED) { - $payment->setTransactionId($response->getPnref())->setIsTransactionClosed(1); - $payment->setShouldCloseParentTransaction(!$payment->getCreditmemo()->getInvoice()->canRefund()); + $payment->setTransactionId($response->getPnref())->setIsTransactionClosed(true); } return $this; } diff --git a/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php b/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php index 215680852225b7b3ed5b4507a223fda725b821b5..c6250a24903ee0e71b30669e762a44c00a3eb06c 100644 --- a/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php +++ b/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php @@ -175,7 +175,6 @@ class PayflowproTest extends \PHPUnit_Framework_TestCase $this->payflowpro->fetchTransactionInfo($payment, 'AD49G8N825'); } - /** * @param $response * @dataProvider setTransStatusDataProvider @@ -323,6 +322,22 @@ class PayflowproTest extends \PHPUnit_Framework_TestCase ]; } + /** + * @covers \Magento\Paypal\Model\Payflowpro::refund() + */ + public function testRefund() + { + /** @var \Magento\Sales\Model\Order\Payment $paymentMock */ + $paymentMock = $this->getPaymentMock(); + + $response = $this->execGatewayRequest(); + + $amount = 213.04; + $this->payflowpro->refund($paymentMock, $amount); + static::assertEquals($response['pnref'], $paymentMock->getTransactionId()); + static::assertTrue($paymentMock->getIsTransactionClosed()); + } + /** * Create mock object for store model * @return void @@ -399,16 +414,16 @@ class PayflowproTest extends \PHPUnit_Framework_TestCase 'year' => 18, 'cvv' => 123 ]; - $paymentMock->expects(static::once()) + $paymentMock->expects(static::any()) ->method('getCcNumber') ->willReturn($cardData['number']); - $paymentMock->expects(static::once()) + $paymentMock->expects(static::any()) ->method('getCcExpMonth') ->willReturn($cardData['month']); - $paymentMock->expects(static::once()) + $paymentMock->expects(static::any()) ->method('getCcExpYear') ->willReturn($cardData['year']); - $paymentMock->expects(static::once()) + $paymentMock->expects(static::any()) ->method('getCcCid') ->willReturn($cardData['cvv']); return $paymentMock; diff --git a/app/code/Magento/Sales/Model/Order/Payment.php b/app/code/Magento/Sales/Model/Order/Payment.php index 690bde68d5c575ece27f56d68165d1ccf31bc7d5..885838781eecfe282ba6c1889c9dcfb6b932b6ec 100644 --- a/app/code/Magento/Sales/Model/Order/Payment.php +++ b/app/code/Magento/Sales/Model/Order/Payment.php @@ -139,7 +139,8 @@ class Payment extends Info implements OrderPaymentInterface \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, array $data = [] - ) { + ) + { $this->priceCurrency = $priceCurrency; $this->creditmemoFactory = $creditmemoFactory; $this->transactionRepository = $transactionRepository; @@ -629,7 +630,7 @@ class Payment extends Info implements OrderPaymentInterface $this->getOrder()->getId() ); if ($captureTxn) { - $this->setParentTransactionId($captureTxn->getTxnId()); + $this->setTransactionIdsForRefund($captureTxn); } $this->setShouldCloseParentTransaction(true); // TODO: implement multiple refunds per capture @@ -638,10 +639,7 @@ class Payment extends Info implements OrderPaymentInterface $this->getOrder()->getStoreId() ); $this->setRefundTransactionId($invoice->getTransactionId()); - $gateway->refund( - $this, - $baseAmountToRefund - ); + $gateway->refund($this, $baseAmountToRefund); $creditmemo->setTransactionId($this->getLastTransId()); } catch (\Magento\Framework\Exception\LocalizedException $e) { @@ -2414,5 +2412,24 @@ class Payment extends Info implements OrderPaymentInterface return (bool)$this->getData('should_close_parent_transaction'); } + /** + * Set payment parent transaction id and current transaction id if it not set + * @param Transaction $transaction + * @return void + */ + private function setTransactionIdsForRefund(Transaction $transaction) + { + if (!$this->getTransactionId()) { + $this->setTransactionId( + $this->transactionManager->generateTransactionId( + $this, + Transaction::TYPE_REFUND, + $transaction + ) + ); + } + $this->setParentTransactionId($transaction->getTxnId()); + } + //@codeCoverageIgnoreEnd } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/PaymentTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/PaymentTest.php index 29757fc570f2380410376d09d3ca137062ffad9d..e9b65325df8831bfebcf4e91f033e5f297133888 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/PaymentTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/PaymentTest.php @@ -17,6 +17,8 @@ use Magento\Sales\Model\Order\Payment\Transaction; */ class PaymentTest extends \PHPUnit_Framework_TestCase { + const TRANSACTION_ID = 'ewr34fM49V0'; + private $mockContext; /** * @var Payment @@ -166,6 +168,7 @@ class PaymentTest extends \PHPUnit_Framework_TestCase 'order', 'isInitializeNeeded', 'initialize', + 'refund' ] ) ->getMock(); @@ -258,7 +261,10 @@ class PaymentTest extends \PHPUnit_Framework_TestCase 'register', 'addComment', 'save', - 'getGrandTotal' + 'getGrandTotal', + 'getBaseGrandTotal', + 'getDoTransaction', + 'getInvoice' ], [], '', @@ -268,7 +274,7 @@ class PaymentTest extends \PHPUnit_Framework_TestCase $this->payment = $this->initPayment(); $this->payment->setMethod('any'); $this->payment->setOrder($this->orderMock); - $this->transactionId = 100; + $this->transactionId = self::TRANSACTION_ID; } protected function tearDown() @@ -825,13 +831,13 @@ class PaymentTest extends \PHPUnit_Framework_TestCase */ protected function mockInvoice($transactionId, $countCall = 1) { - $this->invoiceMock->expects($this->once()) + $this->invoiceMock->expects(static::any()) ->method('getTransactionId') ->willReturn($transactionId); - $this->invoiceMock->expects($this->once()) + $this->invoiceMock->expects(static::any()) ->method('load') ->with($transactionId); - $this->invoiceMock->expects($this->once()) + $this->invoiceMock->expects(static::any()) ->method('getId') ->willReturn($transactionId); $this->orderMock->expects($this->exactly($countCall)) @@ -1314,7 +1320,8 @@ class PaymentTest extends \PHPUnit_Framework_TestCase */ public function testRegisterRefundNotification() { - $message = 'Registered notification about refunded amount of . Transaction ID: "100-refund"'; + $message = 'Registered notification about refunded amount of . Transaction ID: "' . + self::TRANSACTION_ID . '-refund"'; $amount = 50; $grandTotalCreditMemo = 50; $invoiceBaseGrandTotal = 50; @@ -1429,6 +1436,73 @@ class PaymentTest extends \PHPUnit_Framework_TestCase $this->assertEquals($canRefund, $this->payment->canRefund()); } + /** + * @covers \Magento\Sales\Model\Order\Payment::refund() + */ + public function testRefund() + { + $amount = 204.04; + $this->creditMemoMock->expects(static::once()) + ->method('getBaseGrandTotal') + ->willReturn($amount); + $this->creditMemoMock->expects(static::once()) + ->method('getGrandTotal') + ->willReturn($amount); + $this->creditMemoMock->expects(static::once()) + ->method('getDoTransaction') + ->willReturn(true); + + $this->paymentMethodMock->expects(static::once()) + ->method('canRefund') + ->willReturn(true); + + $this->mockInvoice(self::TRANSACTION_ID, 0); + $this->creditMemoMock->expects(static::once()) + ->method('getInvoice') + ->willReturn($this->invoiceMock); + + $captureTranId = self::TRANSACTION_ID . '-' . Transaction::TYPE_CAPTURE; + $captureTransaction = $this->getMockBuilder(Transaction::class) + ->disableOriginalConstructor() + ->setMethods(['getTxnId']) + ->getMock(); + + $refundTranId = $captureTranId . '-' . Transaction::TYPE_REFUND; + $this->transactionManagerMock->expects(static::once()) + ->method('generateTransactionId') + ->willReturn($refundTranId); + $captureTransaction->expects(static::once()) + ->method('getTxnId') + ->willReturn($captureTranId); + $this->transactionRepositoryMock->expects(static::once()) + ->method('getByTransactionId') + ->willReturn($captureTransaction); + + $this->paymentMethodMock->expects(static::once()) + ->method('refund') + ->with($this->payment, $amount); + + $isOnline = true; + $this->getTransactionBuilderMock([], $isOnline, Transaction::TYPE_REFUND, $refundTranId); + + $this->currencyMock->expects(static::once()) + ->method('formatTxt') + ->willReturn($amount); + $this->orderMock->expects(static::once()) + ->method('getBaseCurrency') + ->willReturn($this->currencyMock); + + $status = 'status'; + $message = 'We refunded ' . $amount . ' online. Transaction ID: "' . $refundTranId . '"'; + $this->mockGetDefaultStatus(Order::STATE_PROCESSING, $status); + $this->assertOrderUpdated(Order::STATE_PROCESSING, $status, $message); + + static::assertSame($this->payment, $this->payment->refund($this->creditMemoMock)); + static::assertEquals($amount, $this->payment->getData('amount_refunded')); + static::assertEquals($amount, $this->payment->getData('base_amount_refunded_online')); + static::assertEquals($amount, $this->payment->getData('base_amount_refunded')); + } + public function boolProvider() { return [