diff --git a/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/FraudDetails.php b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/FraudDetails.php index a7a670d64d7ce..c693ebe95d52b 100644 --- a/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/FraudDetails.php +++ b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/FraudDetails.php @@ -3,13 +3,18 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Block\Adminhtml\Order\View\Info; use Magento\Authorizenet\Model\Directpost; /** + * Fraud information block for Authorize.net payment method + * * @api * @since 100.0.2 + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class FraudDetails extends \Magento\Backend\Block\Template { @@ -33,6 +38,8 @@ public function __construct( } /** + * Return payment method model + * * @return \Magento\Sales\Model\Order\Payment */ public function getPayment() @@ -42,6 +49,8 @@ public function getPayment() } /** + * Produce and return the block's HTML output + * * @return string */ protected function _toHtml() diff --git a/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php index fb9c74d2f0ab1..23034270640dd 100644 --- a/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php +++ b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php @@ -12,6 +12,7 @@ /** * Payment information block for Authorize.net payment method + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class PaymentDetails extends ConfigurableInfo { diff --git a/app/code/Magento/Authorizenet/Block/Transparent/Iframe.php b/app/code/Magento/Authorizenet/Block/Transparent/Iframe.php index 296d22d6f61b2..65161413cb18f 100644 --- a/app/code/Magento/Authorizenet/Block/Transparent/Iframe.php +++ b/app/code/Magento/Authorizenet/Block/Transparent/Iframe.php @@ -3,13 +3,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Block\Transparent; use Magento\Payment\Block\Transparent\Iframe as TransparentIframe; /** + * Transparent Iframe block for Authorize.net payments * @api * @since 100.0.2 + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Iframe extends TransparentIframe { diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/AddConfigured.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/AddConfigured.php index 46d395b978eba..f71314613fc1f 100644 --- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/AddConfigured.php +++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/AddConfigured.php @@ -4,8 +4,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Directpost\Payment; -class AddConfigured extends \Magento\Sales\Controller\Adminhtml\Order\Create\AddConfigured +use Magento\Framework\App\Action\HttpPutActionInterface; +use Magento\Sales\Controller\Adminhtml\Order\Create\AddConfigured as BaseAddConfigured; + +/** + * Class AddConfigured + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ +class AddConfigured extends BaseAddConfigured implements HttpPutActionInterface { } diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Cancel.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Cancel.php index 3432e14d77b9e..3ebea4704db7e 100644 --- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Cancel.php +++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Cancel.php @@ -4,8 +4,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Directpost\Payment; -class Cancel extends \Magento\Sales\Controller\Adminhtml\Order\Create\Cancel +use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Sales\Controller\Adminhtml\Order\Create\Cancel as BaseCancel; + +/** + * Class Cancel + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ +class Cancel extends BaseCancel implements HttpPostActionInterface { } diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ConfigureProductToAdd.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ConfigureProductToAdd.php index 9fa3c7dd19b88..19eb4571a852e 100644 --- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ConfigureProductToAdd.php +++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ConfigureProductToAdd.php @@ -4,8 +4,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Directpost\Payment; -class ConfigureProductToAdd extends \Magento\Sales\Controller\Adminhtml\Order\Create\ConfigureProductToAdd +use Magento\Framework\App\Action\HttpPutActionInterface; +use Magento\Sales\Controller\Adminhtml\Order\Create\ConfigureProductToAdd as BaseConfigureProductToAdd; + +/** + * Class ConfigureProductToAdd + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ +class ConfigureProductToAdd extends BaseConfigureProductToAdd implements HttpPutActionInterface { } diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ConfigureQuoteItems.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ConfigureQuoteItems.php index c1ea98aea2382..d314149059c72 100644 --- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ConfigureQuoteItems.php +++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ConfigureQuoteItems.php @@ -4,8 +4,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Directpost\Payment; -class ConfigureQuoteItems extends \Magento\Sales\Controller\Adminhtml\Order\Create\ConfigureQuoteItems +use Magento\Framework\App\Action\HttpPutActionInterface; +use Magento\Sales\Controller\Adminhtml\Order\Create\ConfigureQuoteItems as BaseConfigureQuoteItems; + +/** + * Class ConfigureQuoteItems + * @deprecated 2.3 Authorize.net is removing all support for this payment method + */ +class ConfigureQuoteItems extends BaseConfigureQuoteItems implements HttpPutActionInterface { } diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Index.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Index.php index b206f89ab8bf5..33ac620499e71 100644 --- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Index.php +++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Index.php @@ -4,8 +4,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Directpost\Payment; +/** + * Class Index + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ class Index extends \Magento\Sales\Controller\Adminhtml\Order\Create\Index { } diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/LoadBlock.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/LoadBlock.php index 43e456e766932..577840c0a9ba4 100644 --- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/LoadBlock.php +++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/LoadBlock.php @@ -4,8 +4,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Directpost\Payment; +/** + * Class LoadBlock + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ class LoadBlock extends \Magento\Sales\Controller\Adminhtml\Order\Create\LoadBlock { } diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Place.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Place.php index b393015ce1231..fc4cce07bd08f 100644 --- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Place.php +++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Place.php @@ -3,21 +3,26 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Directpost\Payment; -use Magento\Framework\Escaper; -use Magento\Catalog\Helper\Product; +use Magento\Authorizenet\Helper\Backend\Data as DataHelper; use Magento\Backend\App\Action\Context; -use Magento\Framework\View\Result\PageFactory; use Magento\Backend\Model\View\Result\ForwardFactory; -use Magento\Authorizenet\Helper\Backend\Data as DataHelper; +use Magento\Catalog\Helper\Product; +use Magento\Framework\Escaper; +use Magento\Framework\View\Result\PageFactory; +use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Sales\Controller\Adminhtml\Order\Create; /** * Class Place * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ -class Place extends \Magento\Sales\Controller\Adminhtml\Order\Create +class Place extends Create implements HttpPostActionInterface { /** * @var DataHelper diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ProcessData.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ProcessData.php index 35720249be359..3d0d572bd6265 100644 --- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ProcessData.php +++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ProcessData.php @@ -4,8 +4,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Directpost\Payment; -class ProcessData extends \Magento\Sales\Controller\Adminhtml\Order\Create\ProcessData +use Magento\Sales\Controller\Adminhtml\Order\Create\ProcessData as BaseProcessData; +use Magento\Framework\App\Action\HttpPostActionInterface; + +/** + * Class ProcessData + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ +class ProcessData extends BaseProcessData implements HttpPostActionInterface { } diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Redirect.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Redirect.php index bd9de956dc647..333751f93653a 100644 --- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Redirect.php +++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Redirect.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Directpost\Payment; use Magento\Backend\App\Action; @@ -10,11 +12,16 @@ use Magento\Framework\View\Result\LayoutFactory; use Magento\Framework\View\Result\PageFactory; use Magento\Payment\Block\Transparent\Iframe; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Sales\Controller\Adminhtml\Order\Create; /** + * Class Redirect * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ -class Redirect extends \Magento\Sales\Controller\Adminhtml\Order\Create +class Redirect extends Create implements HttpGetActionInterface, HttpPostActionInterface { /** * Core registry diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Reorder.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Reorder.php index 80b9f54524f00..06a6403915ff1 100644 --- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Reorder.php +++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Reorder.php @@ -4,8 +4,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Directpost\Payment; -class Reorder extends \Magento\Sales\Controller\Adminhtml\Order\Create\Reorder +use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Sales\Controller\Adminhtml\Order\Create\Reorder as BaseReorder; + +/** + * Class Reorder + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ +class Reorder extends BaseReorder implements HttpPostActionInterface { } diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ReturnQuote.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ReturnQuote.php index 82a5ee08f7ce8..c42e7ecbeef00 100644 --- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ReturnQuote.php +++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ReturnQuote.php @@ -4,9 +4,19 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Directpost\Payment; -class ReturnQuote extends \Magento\Sales\Controller\Adminhtml\Order\Create +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Sales\Controller\Adminhtml\Order\Create; + +/** + * Class ReturnQuote + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ +class ReturnQuote extends Create implements HttpPostActionInterface, HttpGetActionInterface { /** * Return quote diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Save.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Save.php index 7519f3415c40b..cc93ce5daedeb 100644 --- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Save.php +++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Save.php @@ -4,8 +4,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Directpost\Payment; +/** + * Class Save + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ class Save extends \Magento\Sales\Controller\Adminhtml\Order\Create\Save { } diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ShowUpdateResult.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ShowUpdateResult.php index b55da878b2e39..af80bde10831a 100644 --- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ShowUpdateResult.php +++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/ShowUpdateResult.php @@ -4,8 +4,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Directpost\Payment; +/** + * Class ShowUpdateResult + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ class ShowUpdateResult extends \Magento\Sales\Controller\Adminhtml\Order\Create\ShowUpdateResult { } diff --git a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Start.php b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Start.php index f0ac5f80c11ab..689b30d63be68 100644 --- a/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Start.php +++ b/app/code/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/Start.php @@ -4,8 +4,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Adminhtml\Authorizenet\Directpost\Payment; -abstract class Start extends \Magento\Sales\Controller\Adminhtml\Order\Create +use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Sales\Controller\Adminhtml\Order\Create; + +/** + * Class Start + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ +abstract class Start extends Create implements HttpPostActionInterface { } diff --git a/app/code/Magento/Authorizenet/Controller/Directpost/Payment.php b/app/code/Magento/Authorizenet/Controller/Directpost/Payment.php index fc9e7807cd99e..cfaa5f1cfcd08 100644 --- a/app/code/Magento/Authorizenet/Controller/Directpost/Payment.php +++ b/app/code/Magento/Authorizenet/Controller/Directpost/Payment.php @@ -3,16 +3,22 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Directpost; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Payment\Block\Transparent\Iframe; +use Magento\Framework\App\Action\Action; /** * DirectPost Payment Controller * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ -abstract class Payment extends \Magento\Framework\App\Action\Action +abstract class Payment extends Action implements HttpGetActionInterface, HttpPostActionInterface { /** * Core registry @@ -44,6 +50,8 @@ public function __construct( } /** + * Get checkout model + * * @return \Magento\Checkout\Model\Session */ protected function _getCheckout() @@ -63,6 +71,7 @@ protected function _getDirectPostSession() /** * Response action. + * * Action for Authorize.net SIM Relay Request. * * @param string $area diff --git a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponse.php b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponse.php index 70565ea8ac65f..e0610a92feb6a 100644 --- a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponse.php +++ b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponse.php @@ -4,6 +4,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Directpost\Payment; use Magento\Authorizenet\Helper\DataFactory; @@ -16,9 +18,18 @@ use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Registry; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; use Psr\Log\LoggerInterface; -class BackendResponse extends \Magento\Authorizenet\Controller\Directpost\Payment implements CsrfAwareActionInterface +/** + * Class BackendResponse + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ +class BackendResponse extends \Magento\Authorizenet\Controller\Directpost\Payment implements + CsrfAwareActionInterface, + HttpGetActionInterface, + HttpPostActionInterface { /** * @var LoggerInterface @@ -70,6 +81,7 @@ public function validateForCsrf(RequestInterface $request): ?bool /** * Response action. + * * Action for Authorize.net SIM Relay Request. * * @return \Magento\Framework\Controller\ResultInterface diff --git a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Place.php b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Place.php index 3c1cb90e0c0a5..7d672a75f5b17 100644 --- a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Place.php +++ b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Place.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Authorizenet\Controller\Directpost\Payment; @@ -25,6 +26,7 @@ * Class Place * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Place extends Payment implements HttpPostActionInterface { diff --git a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Redirect.php b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Redirect.php index 028b90bf7da50..8c9510243f610 100644 --- a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Redirect.php +++ b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Redirect.php @@ -4,15 +4,20 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Directpost\Payment; -use Magento\Framework\App\ObjectManager; +use Magento\Authorizenet\Controller\Directpost\Payment; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Payment\Block\Transparent\Iframe; /** * Class Redirect + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ -class Redirect extends \Magento\Authorizenet\Controller\Directpost\Payment +class Redirect extends Payment implements HttpGetActionInterface, HttpPostActionInterface { /** * Retrieve params and put javascript into iframe diff --git a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Response.php b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Response.php index d562df9fb24a9..17fc3cb72e454 100644 --- a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Response.php +++ b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Response.php @@ -4,13 +4,22 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Directpost\Payment; use Magento\Framework\App\CsrfAwareActionInterface; use Magento\Framework\App\Request\InvalidRequestException; use Magento\Framework\App\RequestInterface; +use Magento\Authorizenet\Controller\Directpost\Payment; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; -class Response extends \Magento\Authorizenet\Controller\Directpost\Payment implements CsrfAwareActionInterface +/** + * Class Response + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ +class Response extends Payment implements CsrfAwareActionInterface, HttpGetActionInterface, HttpPostActionInterface { /** * @inheritDoc @@ -31,6 +40,7 @@ public function validateForCsrf(RequestInterface $request): ?bool /** * Response action. + * * Action for Authorize.net SIM Relay Request. * * @return \Magento\Framework\Controller\ResultInterface diff --git a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/ReturnQuote.php b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/ReturnQuote.php index 3030a75055b7e..c974632f584b0 100644 --- a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/ReturnQuote.php +++ b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/ReturnQuote.php @@ -4,9 +4,19 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Controller\Directpost\Payment; -class ReturnQuote extends \Magento\Authorizenet\Controller\Directpost\Payment +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Authorizenet\Controller\Directpost\Payment; + +/** + * Class ReturnQuote + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ +class ReturnQuote extends Payment implements HttpPostActionInterface, HttpGetActionInterface { /** * Return customer quote by ajax diff --git a/app/code/Magento/Authorizenet/Helper/Backend/Data.php b/app/code/Magento/Authorizenet/Helper/Backend/Data.php index 24bdb23873265..d291125ccae06 100644 --- a/app/code/Magento/Authorizenet/Helper/Backend/Data.php +++ b/app/code/Magento/Authorizenet/Helper/Backend/Data.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Helper\Backend; use Magento\Authorizenet\Helper\Data as FrontendDataHelper; @@ -16,6 +18,7 @@ * * @api * @since 100.0.2 + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Data extends FrontendDataHelper { diff --git a/app/code/Magento/Authorizenet/Helper/Data.php b/app/code/Magento/Authorizenet/Helper/Data.php index 8bcc1f3f3f03c..e240cd692a13f 100644 --- a/app/code/Magento/Authorizenet/Helper/Data.php +++ b/app/code/Magento/Authorizenet/Helper/Data.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Helper; use Magento\Framework\App\Helper\AbstractHelper; @@ -17,6 +19,7 @@ * * @api * @since 100.0.2 + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Data extends AbstractHelper { @@ -153,6 +156,7 @@ public function getSuccessOrderUrl($params) /** * Update all child and parent order's edit increment numbers. + * * Needed for Admin area. * * @param \Magento\Sales\Model\Order $order @@ -255,6 +259,7 @@ protected function getOperation($requestType) /** * Format price with currency sign + * * @param \Magento\Payment\Model\InfoInterface $payment * @param float $amount * @return string diff --git a/app/code/Magento/Authorizenet/Helper/DataFactory.php b/app/code/Magento/Authorizenet/Helper/DataFactory.php index f3ccf16e7d396..71f16ab4af646 100644 --- a/app/code/Magento/Authorizenet/Helper/DataFactory.php +++ b/app/code/Magento/Authorizenet/Helper/DataFactory.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Helper; use Magento\Framework\Exception\LocalizedException; @@ -10,6 +12,7 @@ /** * Class DataFactory + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class DataFactory { diff --git a/app/code/Magento/Authorizenet/Model/Authorizenet.php b/app/code/Magento/Authorizenet/Model/Authorizenet.php index ae9ac833a4395..9370b649a23c7 100644 --- a/app/code/Magento/Authorizenet/Model/Authorizenet.php +++ b/app/code/Magento/Authorizenet/Model/Authorizenet.php @@ -3,15 +3,20 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model; use Magento\Authorizenet\Model\TransactionService; use Magento\Framework\HTTP\ZendClientFactory; /** + * Model for Authorize.net payment method + * * @SuppressWarnings(PHPMD.TooManyFields) * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ abstract class Authorizenet extends \Magento\Payment\Model\Method\Cc { diff --git a/app/code/Magento/Authorizenet/Model/Debug.php b/app/code/Magento/Authorizenet/Model/Debug.php index 255c2e3aba444..93d508cc744e1 100644 --- a/app/code/Magento/Authorizenet/Model/Debug.php +++ b/app/code/Magento/Authorizenet/Model/Debug.php @@ -3,9 +3,13 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model; /** + * Authorize.net debug payment method model + * * @method string getRequestBody() * @method \Magento\Authorizenet\Model\Debug setRequestBody(string $value) * @method string getResponseBody() @@ -18,10 +22,13 @@ * @method \Magento\Authorizenet\Model\Debug setRequestDump(string $value) * @method string getResultDump() * @method \Magento\Authorizenet\Model\Debug setResultDump(string $value) + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Debug extends \Magento\Framework\Model\AbstractModel { /** + * Construct debug class + * * @return void */ protected function _construct() diff --git a/app/code/Magento/Authorizenet/Model/Directpost.php b/app/code/Magento/Authorizenet/Model/Directpost.php index aeaa0cd9a3ad1..5bc9335d24439 100644 --- a/app/code/Magento/Authorizenet/Model/Directpost.php +++ b/app/code/Magento/Authorizenet/Model/Directpost.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model; use Magento\Framework\App\ObjectManager; @@ -14,6 +16,7 @@ * @SuppressWarnings(PHPMD.TooManyFields) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Directpost extends \Magento\Authorizenet\Model\Authorizenet implements TransparentInterface, ConfigInterface { @@ -651,7 +654,7 @@ public function checkResponseCode() case self::RESPONSE_CODE_ERROR: $errorMessage = $this->dataHelper->wrapGatewayError($this->getResponse()->getXResponseReasonText()); $order = $this->getOrderFromResponse(); - $this->paymentFailures->handle((int)$order->getQuoteId(), $errorMessage); + $this->paymentFailures->handle((int)$order->getQuoteId(), (string)$errorMessage); throw new \Magento\Framework\Exception\LocalizedException($errorMessage); default: throw new \Magento\Framework\Exception\LocalizedException( diff --git a/app/code/Magento/Authorizenet/Model/Directpost/Request.php b/app/code/Magento/Authorizenet/Model/Directpost/Request.php index fc78d836b6080..357385e5c8c79 100644 --- a/app/code/Magento/Authorizenet/Model/Directpost/Request.php +++ b/app/code/Magento/Authorizenet/Model/Directpost/Request.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Authorizenet\Model\Directpost; @@ -10,6 +11,7 @@ /** * Authorize.net request model for DirectPost model + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Request extends AuthorizenetRequest { @@ -20,6 +22,7 @@ class Request extends AuthorizenetRequest /** * Return merchant transaction key. + * * Needed to generate sign. * * @return string @@ -31,6 +34,7 @@ protected function _getTransactionKey() /** * Set merchant transaction key. + * * Needed to generate sign. * * @param string $transKey @@ -162,6 +166,7 @@ public function setDataFromOrder( /** * Set sign hash into the request object. + * * All needed fields should be placed in the object fist. * * @return $this diff --git a/app/code/Magento/Authorizenet/Model/Directpost/Request/Factory.php b/app/code/Magento/Authorizenet/Model/Directpost/Request/Factory.php index 2cdd02d7f8488..6036935f57be1 100644 --- a/app/code/Magento/Authorizenet/Model/Directpost/Request/Factory.php +++ b/app/code/Magento/Authorizenet/Model/Directpost/Request/Factory.php @@ -3,12 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model\Directpost\Request; use Magento\Authorizenet\Model\Request\Factory as AuthorizenetRequestFactory; /** * Factory class for @see \Magento\Authorizenet\Model\Directpost\Request + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Factory extends AuthorizenetRequestFactory { diff --git a/app/code/Magento/Authorizenet/Model/Directpost/Response.php b/app/code/Magento/Authorizenet/Model/Directpost/Response.php index dc62c1e990dc3..1c713a159c3ad 100644 --- a/app/code/Magento/Authorizenet/Model/Directpost/Response.php +++ b/app/code/Magento/Authorizenet/Model/Directpost/Response.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model\Directpost; use Magento\Authorizenet\Model\Response as AuthorizenetResponse; @@ -10,6 +12,7 @@ /** * Authorize.net response model for DirectPost model + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Response extends AuthorizenetResponse { diff --git a/app/code/Magento/Authorizenet/Model/Directpost/Response/Factory.php b/app/code/Magento/Authorizenet/Model/Directpost/Response/Factory.php index c2a24ef386ab0..4fda5ac62b498 100644 --- a/app/code/Magento/Authorizenet/Model/Directpost/Response/Factory.php +++ b/app/code/Magento/Authorizenet/Model/Directpost/Response/Factory.php @@ -3,12 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model\Directpost\Response; use Magento\Authorizenet\Model\Response\Factory as AuthorizenetResponseFactory; /** * Factory class for @see \Magento\Authorizenet\Model\Directpost\Response + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Factory extends AuthorizenetResponseFactory { diff --git a/app/code/Magento/Authorizenet/Model/Directpost/Session.php b/app/code/Magento/Authorizenet/Model/Directpost/Session.php index 7ddedac161399..26c5ff0cb7e36 100644 --- a/app/code/Magento/Authorizenet/Model/Directpost/Session.php +++ b/app/code/Magento/Authorizenet/Model/Directpost/Session.php @@ -3,12 +3,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model\Directpost; use Magento\Framework\Session\SessionManager; /** * Authorize.net DirectPost session model + * + * @SuppressWarnings(PHPMD.CookieAndSessionMisuse) + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Session extends SessionManager { diff --git a/app/code/Magento/Authorizenet/Model/Request.php b/app/code/Magento/Authorizenet/Model/Request.php index dc52f84baecee..552439fc8bb9b 100644 --- a/app/code/Magento/Authorizenet/Model/Request.php +++ b/app/code/Magento/Authorizenet/Model/Request.php @@ -3,12 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model; use Magento\Framework\DataObject; /** * Request object + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Request extends DataObject { diff --git a/app/code/Magento/Authorizenet/Model/Request/Factory.php b/app/code/Magento/Authorizenet/Model/Request/Factory.php index e60bbd0c88e83..a7a636280e28d 100644 --- a/app/code/Magento/Authorizenet/Model/Request/Factory.php +++ b/app/code/Magento/Authorizenet/Model/Request/Factory.php @@ -3,10 +3,13 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model\Request; /** * Factory class for @see \Magento\Authorizenet\Model\Request + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Factory { diff --git a/app/code/Magento/Authorizenet/Model/ResourceModel/Debug.php b/app/code/Magento/Authorizenet/Model/ResourceModel/Debug.php index ee6ec6783bb06..2c21d0e2e28e0 100644 --- a/app/code/Magento/Authorizenet/Model/ResourceModel/Debug.php +++ b/app/code/Magento/Authorizenet/Model/ResourceModel/Debug.php @@ -3,10 +3,13 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model\ResourceModel; /** * Resource Authorize.net debug model + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Debug extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb { diff --git a/app/code/Magento/Authorizenet/Model/ResourceModel/Debug/Collection.php b/app/code/Magento/Authorizenet/Model/ResourceModel/Debug/Collection.php index 095ac5a91dd7c..b84ee1e72a2d4 100644 --- a/app/code/Magento/Authorizenet/Model/ResourceModel/Debug/Collection.php +++ b/app/code/Magento/Authorizenet/Model/ResourceModel/Debug/Collection.php @@ -3,10 +3,13 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model\ResourceModel\Debug; /** * Resource Authorize.net debug collection model + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection { diff --git a/app/code/Magento/Authorizenet/Model/Response.php b/app/code/Magento/Authorizenet/Model/Response.php index 52b43c251dca2..c552663a15373 100644 --- a/app/code/Magento/Authorizenet/Model/Response.php +++ b/app/code/Magento/Authorizenet/Model/Response.php @@ -3,12 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model; use Magento\Framework\DataObject; /** * Response object + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Response extends DataObject { diff --git a/app/code/Magento/Authorizenet/Model/Response/Factory.php b/app/code/Magento/Authorizenet/Model/Response/Factory.php index 74bf8953471d2..4578095566004 100644 --- a/app/code/Magento/Authorizenet/Model/Response/Factory.php +++ b/app/code/Magento/Authorizenet/Model/Response/Factory.php @@ -3,10 +3,13 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model\Response; /** * Factory class for @see \Magento\Authorizenet\Model\Response + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Factory { diff --git a/app/code/Magento/Authorizenet/Model/Source/Cctype.php b/app/code/Magento/Authorizenet/Model/Source/Cctype.php index 0a5fe8ab9b341..ffb3584722450 100644 --- a/app/code/Magento/Authorizenet/Model/Source/Cctype.php +++ b/app/code/Magento/Authorizenet/Model/Source/Cctype.php @@ -3,16 +3,21 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model\Source; use Magento\Payment\Model\Source\Cctype as PaymentCctype; /** * Authorize.net Payment CC Types Source Model + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class Cctype extends PaymentCctype { /** + * Return all supported credit card types + * * @return string[] */ public function getAllowedTypes() diff --git a/app/code/Magento/Authorizenet/Model/Source/PaymentAction.php b/app/code/Magento/Authorizenet/Model/Source/PaymentAction.php index 9943e1001da56..c6e57557f65c5 100644 --- a/app/code/Magento/Authorizenet/Model/Source/PaymentAction.php +++ b/app/code/Magento/Authorizenet/Model/Source/PaymentAction.php @@ -3,18 +3,20 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Model\Source; use Magento\Framework\Option\ArrayInterface; /** - * * Authorize.net Payment Action Dropdown source + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class PaymentAction implements ArrayInterface { /** - * {@inheritdoc} + * @inheritdoc */ public function toOptionArray() { diff --git a/app/code/Magento/Authorizenet/Model/TransactionService.php b/app/code/Magento/Authorizenet/Model/TransactionService.php index 693a5b890faba..af0b02e94cf45 100644 --- a/app/code/Magento/Authorizenet/Model/TransactionService.php +++ b/app/code/Magento/Authorizenet/Model/TransactionService.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Authorizenet\Model; @@ -15,7 +16,7 @@ /** * Class TransactionService - * @package Magento\Authorizenet\Model + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method */ class TransactionService { @@ -74,6 +75,7 @@ public function __construct( /** * Get transaction information + * * @param \Magento\Authorizenet\Model\Authorizenet $context * @param string $transactionId * @return \Magento\Framework\Simplexml\Element @@ -142,6 +144,7 @@ protected function loadTransactionDetails(Authorizenet $context, $transactionId) /** * Create request body to get transaction details + * * @param string $login * @param string $transactionKey * @param string $transactionId diff --git a/app/code/Magento/Authorizenet/Observer/AddFieldsToResponseObserver.php b/app/code/Magento/Authorizenet/Observer/AddFieldsToResponseObserver.php index 03846dddfdee3..bdd10437927c8 100644 --- a/app/code/Magento/Authorizenet/Observer/AddFieldsToResponseObserver.php +++ b/app/code/Magento/Authorizenet/Observer/AddFieldsToResponseObserver.php @@ -3,11 +3,19 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Sales\Model\Order; +/** + * Class AddFieldsToResponseObserver + * + * @SuppressWarnings(PHPMD.CookieAndSessionMisuse) + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ class AddFieldsToResponseObserver implements ObserverInterface { /** diff --git a/app/code/Magento/Authorizenet/Observer/SaveOrderAfterSubmitObserver.php b/app/code/Magento/Authorizenet/Observer/SaveOrderAfterSubmitObserver.php index 8426d004c2037..45f0adfa96f4f 100644 --- a/app/code/Magento/Authorizenet/Observer/SaveOrderAfterSubmitObserver.php +++ b/app/code/Magento/Authorizenet/Observer/SaveOrderAfterSubmitObserver.php @@ -3,11 +3,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Sales\Model\Order; +/** + * Class SaveOrderAfterSubmitObserver + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ class SaveOrderAfterSubmitObserver implements ObserverInterface { /** diff --git a/app/code/Magento/Authorizenet/Observer/UpdateAllEditIncrementsObserver.php b/app/code/Magento/Authorizenet/Observer/UpdateAllEditIncrementsObserver.php index 3e62fe2278d3b..d6cc51eb63c01 100644 --- a/app/code/Magento/Authorizenet/Observer/UpdateAllEditIncrementsObserver.php +++ b/app/code/Magento/Authorizenet/Observer/UpdateAllEditIncrementsObserver.php @@ -3,11 +3,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Sales\Model\Order; +/** + * Class UpdateAllEditIncrementsObserver + * @deprecated 2.3.1 Authorize.net is removing all support for this payment method + */ class UpdateAllEditIncrementsObserver implements ObserverInterface { /** diff --git a/app/code/Magento/Authorizenet/etc/adminhtml/system.xml b/app/code/Magento/Authorizenet/etc/adminhtml/system.xml index 1319fa102d0d8..28bf6945c8b81 100644 --- a/app/code/Magento/Authorizenet/etc/adminhtml/system.xml +++ b/app/code/Magento/Authorizenet/etc/adminhtml/system.xml @@ -9,7 +9,7 @@
- + Magento\Config\Model\Config\Source\Yesno diff --git a/app/code/Magento/Authorizenet/etc/config.xml b/app/code/Magento/Authorizenet/etc/config.xml index a960e96a288ea..02dca74023e22 100644 --- a/app/code/Magento/Authorizenet/etc/config.xml +++ b/app/code/Magento/Authorizenet/etc/config.xml @@ -19,7 +19,7 @@ processing authorize 1 - Credit Card Direct Post (Authorize.net) + Credit Card Direct Post (Authorize.Net) 0 diff --git a/app/code/Magento/Authorizenet/etc/payment.xml b/app/code/Magento/Authorizenet/etc/payment.xml index 8f92d5fba3aef..1d2cac374d8dc 100644 --- a/app/code/Magento/Authorizenet/etc/payment.xml +++ b/app/code/Magento/Authorizenet/etc/payment.xml @@ -9,7 +9,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Payment:etc/payment.xsd"> - + diff --git a/app/code/Magento/Authorizenet/i18n/en_US.csv b/app/code/Magento/Authorizenet/i18n/en_US.csv index 6228d5102b13c..d724bd960d310 100644 --- a/app/code/Magento/Authorizenet/i18n/en_US.csv +++ b/app/code/Magento/Authorizenet/i18n/en_US.csv @@ -45,7 +45,7 @@ void,void "Fraud Filters","Fraud Filters" "Place Order","Place Order" "Sorry, but something went wrong. Please contact the seller.","Sorry, but something went wrong. Please contact the seller." -"Authorize.net Direct Post","Authorize.net Direct Post" +"Authorize.Net Direct Post (Deprecated)","Authorize.Net Direct Post (Deprecated)" Enabled,Enabled "Payment Action","Payment Action" Title,Title diff --git a/app/code/Magento/AuthorizenetAcceptjs/Block/Form.php b/app/code/Magento/AuthorizenetAcceptjs/Block/Form.php new file mode 100644 index 0000000000000..9f10b2df40e9f --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Block/Form.php @@ -0,0 +1,62 @@ +config = $config; + $this->sessionQuote = $sessionQuote; + } + + /** + * Check if cvv validation is available + * + * @return boolean + */ + public function isCvvEnabled(): bool + { + return $this->config->isCvvEnabled($this->sessionQuote->getStoreId()); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Block/Info.php b/app/code/Magento/AuthorizenetAcceptjs/Block/Info.php new file mode 100644 index 0000000000000..ea476eaa55716 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Block/Info.php @@ -0,0 +1,31 @@ +config = $config; + $this->json = $json; + } + + /** + * Retrieves the config that should be used by the block + * + * @return string + */ + public function getPaymentConfig(): string + { + $payment = $this->config->getConfig()['payment']; + $config = $payment[$this->getMethodCode()]; + $config['code'] = $this->getMethodCode(); + + return $this->json->serialize($config); + } + + /** + * Returns the method code for this payment method + * + * @return string + */ + public function getMethodCode(): string + { + return Config::METHOD; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/AcceptPaymentStrategyCommand.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/AcceptPaymentStrategyCommand.php new file mode 100644 index 0000000000000..a72435644d23c --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/AcceptPaymentStrategyCommand.php @@ -0,0 +1,74 @@ +commandPool = $commandPool; + $this->subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function execute(array $commandSubject): void + { + if ($this->shouldAcceptInGateway($commandSubject)) { + $this->commandPool->get(self::ACCEPT_FDS) + ->execute($commandSubject); + } + } + + /** + * Determines if the transaction needs to be accepted in the gateway + * + * @param array $commandSubject + * @return bool + * @throws CommandException + */ + private function shouldAcceptInGateway(array $commandSubject): bool + { + $details = $this->commandPool->get('get_transaction_details') + ->execute($commandSubject) + ->get(); + + return in_array($details['transaction']['transactionStatus'], self::NEEDS_APPROVAL_STATUSES); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/CaptureStrategyCommand.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/CaptureStrategyCommand.php new file mode 100644 index 0000000000000..a4d895d4daae0 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/CaptureStrategyCommand.php @@ -0,0 +1,140 @@ +commandPool = $commandPool; + $this->transactionRepository = $repository; + $this->filterBuilder = $filterBuilder; + $this->searchCriteriaBuilder = $searchCriteriaBuilder; + $this->subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function execute(array $commandSubject): void + { + /** @var PaymentDataObjectInterface $paymentDO */ + $paymentDO = $this->subjectReader->readPayment($commandSubject); + + $command = $this->getCommand($paymentDO); + $this->commandPool->get($command) + ->execute($commandSubject); + } + + /** + * Get execution command name. + * + * @param PaymentDataObjectInterface $paymentDO + * @return string + */ + private function getCommand(PaymentDataObjectInterface $paymentDO): string + { + $payment = $paymentDO->getPayment(); + ContextHelper::assertOrderPayment($payment); + + // If auth transaction does not exist then execute authorize&capture command + $captureExists = $this->captureTransactionExists($payment); + if (!$payment->getAuthorizationTransaction() && !$captureExists) { + return self::SALE; + } + + return self::CAPTURE; + } + + /** + * Check if capture transaction already exists + * + * @param OrderPaymentInterface $payment + * @return bool + */ + private function captureTransactionExists(OrderPaymentInterface $payment): bool + { + $this->searchCriteriaBuilder->addFilters( + [ + $this->filterBuilder + ->setField('payment_id') + ->setValue($payment->getId()) + ->create(), + ] + ); + + $this->searchCriteriaBuilder->addFilters( + [ + $this->filterBuilder + ->setField('txn_type') + ->setValue(TransactionInterface::TYPE_CAPTURE) + ->create(), + ] + ); + + $searchCriteria = $this->searchCriteriaBuilder->create(); + $count = $this->transactionRepository->getList($searchCriteria) + ->getTotalCount(); + + return $count > 0; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/FetchTransactionInfoCommand.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/FetchTransactionInfoCommand.php new file mode 100644 index 0000000000000..bb9e7c26a45b1 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/FetchTransactionInfoCommand.php @@ -0,0 +1,87 @@ +commandPool = $commandPool; + $this->subjectReader = $subjectReader; + $this->config = $config; + $this->handler = $handler; + } + + /** + * @inheritdoc + */ + public function execute(array $commandSubject): array + { + $paymentDO = $this->subjectReader->readPayment($commandSubject); + $order = $paymentDO->getOrder(); + + $command = $this->commandPool->get('get_transaction_details'); + $result = $command->execute($commandSubject); + $response = $result->get(); + + if ($this->handler) { + $this->handler->handle($commandSubject, $response); + } + + $additionalInformationKeys = $this->config->getTransactionInfoSyncKeys($order->getStoreId()); + $rawDetails = []; + foreach ($additionalInformationKeys as $key) { + if (isset($response['transaction'][$key])) { + $rawDetails[$key] = $response['transaction'][$key]; + } + } + + return $rawDetails; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/GatewayQueryCommand.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/GatewayQueryCommand.php new file mode 100644 index 0000000000000..f8975ef38eed1 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/GatewayQueryCommand.php @@ -0,0 +1,100 @@ +requestBuilder = $requestBuilder; + $this->transferFactory = $transferFactory; + $this->client = $client; + $this->validator = $validator; + $this->logger = $logger; + } + + /** + * @inheritdoc + * + * @throws Exception + */ + public function execute(array $commandSubject): ResultInterface + { + $transferO = $this->transferFactory->create( + $this->requestBuilder->build($commandSubject) + ); + + try { + $response = $this->client->placeRequest($transferO); + } catch (Exception $e) { + $this->logger->critical($e); + + throw new CommandException(__('There was an error while trying to process the request.')); + } + + $result = $this->validator->validate( + array_merge($commandSubject, ['response' => $response]) + ); + if (!$result->isValid()) { + throw new CommandException(__('There was an error while trying to process the request.')); + } + + return new ArrayResult($response); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/RefundTransactionStrategyCommand.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/RefundTransactionStrategyCommand.php new file mode 100644 index 0000000000000..53a1f13fa8786 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Command/RefundTransactionStrategyCommand.php @@ -0,0 +1,77 @@ +commandPool = $commandPool; + $this->subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function execute(array $commandSubject): void + { + $command = $this->getCommand($commandSubject); + + $this->commandPool->get($command) + ->execute($commandSubject); + } + + /** + * Determines the command that should be used based on the status of the transaction + * + * @param array $commandSubject + * @return string + * @throws CommandException + */ + private function getCommand(array $commandSubject): string + { + $details = $this->commandPool->get('get_transaction_details') + ->execute($commandSubject) + ->get(); + + if ($details['transaction']['transactionStatus'] === 'capturedPendingSettlement') { + return self::VOID; + } elseif ($details['transaction']['transactionStatus'] !== 'settledSuccessfully') { + throw new CommandException(__('This transaction cannot be refunded with its current status.')); + } + + return self::REFUND; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Config.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Config.php new file mode 100644 index 0000000000000..2a28945d98359 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Config.php @@ -0,0 +1,199 @@ +getValue(Config::KEY_LOGIN_ID, $storeId); + } + + /** + * Gets the current environment + * + * @param int|null $storeId + * @return string + */ + public function getEnvironment($storeId = null): string + { + return $this->getValue(Config::KEY_ENVIRONMENT, $storeId); + } + + /** + * Gets the transaction key + * + * @param int|null $storeId + * @return string + */ + public function getTransactionKey($storeId = null): ?string + { + return $this->getValue(Config::KEY_TRANSACTION_KEY, $storeId); + } + + /** + * Gets the API endpoint URL + * + * @param int|null $storeId + * @return string + */ + public function getApiUrl($storeId = null): string + { + $environment = $this->getValue(Config::KEY_ENVIRONMENT, $storeId); + + return $environment === Environment::ENVIRONMENT_SANDBOX + ? self::ENDPOINT_URL_SANDBOX + : self::ENDPOINT_URL_PRODUCTION; + } + + /** + * Gets the configured signature key + * + * @param int|null $storeId + * @return string + */ + public function getTransactionSignatureKey($storeId = null): ?string + { + return $this->getValue(Config::KEY_SIGNATURE_KEY, $storeId); + } + + /** + * Gets the configured legacy transaction hash + * + * @param int|null $storeId + * @return string + */ + public function getLegacyTransactionHash($storeId = null): ?string + { + return $this->getValue(Config::KEY_LEGACY_TRANSACTION_HASH, $storeId); + } + + /** + * Gets the configured payment action + * + * @param int|null $storeId + * @return string + */ + public function getPaymentAction($storeId = null): ?string + { + return $this->getValue(Config::KEY_PAYMENT_ACTION, $storeId); + } + + /** + * Gets the configured client key + * + * @param int|null $storeId + * @return string + */ + public function getClientKey($storeId = null): ?string + { + return $this->getValue(Config::KEY_CLIENT_KEY, $storeId); + } + + /** + * Should authorize.net email the customer their receipt. + * + * @param int|null $storeId + * @return bool + */ + public function shouldEmailCustomer($storeId = null): bool + { + return (bool)$this->getValue(Config::KEY_SHOULD_EMAIL_CUSTOMER, $storeId); + } + + /** + * Should the cvv field be shown + * + * @param int|null $storeId + * @return bool + */ + public function isCvvEnabled($storeId = null): bool + { + return (bool)$this->getValue(Config::KEY_CVV_ENABLED, $storeId); + } + + /** + * Retrieves the solution id for the given store based on environment + * + * @param int|null $storeId + * @return string + */ + public function getSolutionId($storeId = null): ?string + { + $environment = $this->getValue(Config::KEY_ENVIRONMENT, $storeId); + + return $environment === Environment::ENVIRONMENT_SANDBOX + ? self::SOLUTION_ID_SANDBOX + : self::SOLUTION_ID_PRODUCTION; + } + + /** + * Returns the keys to be pulled from the transaction and displayed + * + * @param int|null $storeId + * @return string[] + */ + public function getAdditionalInfoKeys($storeId = null): array + { + return explode(',', $this->getValue(Config::KEY_ADDITIONAL_INFO_KEYS, $storeId) ?? ''); + } + + /** + * Returns the keys to be pulled from the transaction and displayed when syncing the transaction + * + * @param int|null $storeId + * @return string[] + */ + public function getTransactionInfoSyncKeys($storeId = null): array + { + return explode(',', $this->getValue(Config::KEY_TRANSACTION_SYNC_KEYS, $storeId) ?? ''); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Http/Client.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Http/Client.php new file mode 100644 index 0000000000000..1b2efbb85721a --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Http/Client.php @@ -0,0 +1,126 @@ +httpClientFactory = $httpClientFactory; + $this->config = $config; + $this->paymentLogger = $paymentLogger; + $this->logger = $logger; + $this->json = $json; + } + + /** + * Places request to gateway. Returns result as ENV array + * + * @param TransferInterface $transferObject + * @return array + * @throws \Magento\Payment\Gateway\Http\ClientException + */ + public function placeRequest(TransferInterface $transferObject) + { + $request = $transferObject->getBody(); + $log = [ + 'request' => $request, + ]; + $client = $this->httpClientFactory->create(); + $url = $this->config->getApiUrl(); + + $type = $request['payload_type']; + unset($request['payload_type']); + $request = [$type => $request]; + + try { + $client->setUri($url); + $client->setConfig(['maxredirects' => 0, 'timeout' => 30]); + $client->setRawData($this->json->serialize($request), 'application/json'); + $client->setMethod(ZendClient::POST); + + $responseBody = $client->request() + ->getBody(); + + // Strip BOM because Authorize.net sends it in the response + if ($responseBody && substr($responseBody, 0, 3) === pack('CCC', 0xef, 0xbb, 0xbf)) { + $responseBody = substr($responseBody, 3); + } + + $log['response'] = $responseBody; + + try { + $data = $this->json->unserialize($responseBody); + } catch (InvalidArgumentException $e) { + throw new \Exception('Invalid JSON was returned by the gateway'); + } + + return $data; + } catch (\Exception $e) { + $this->logger->critical($e); + + throw new ClientException( + __('Something went wrong in the payment gateway.') + ); + } finally { + $this->paymentLogger->debug($log); + } + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Http/Payload/Filter/RemoveFieldsFilter.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Http/Payload/Filter/RemoveFieldsFilter.php new file mode 100644 index 0000000000000..a23397c09189a --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Http/Payload/Filter/RemoveFieldsFilter.php @@ -0,0 +1,42 @@ +fields = $fields; + } + + /** + * @inheritdoc + */ + public function filter(array $data): array + { + foreach ($this->fields as $field) { + unset($data[$field]); + } + + return $data; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Http/Payload/FilterInterface.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Http/Payload/FilterInterface.php new file mode 100644 index 0000000000000..35e563eacb0cd --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Http/Payload/FilterInterface.php @@ -0,0 +1,23 @@ +transferBuilder = $transferBuilder; + $this->payloadFilters = $payloadFilters; + } + + /** + * Builds gateway transfer object + * + * @param array $request + * @return TransferInterface + */ + public function create(array $request) + { + foreach ($this->payloadFilters as $filter) { + $request = $filter->filter($request); + } + + return $this->transferBuilder + ->setBody($request) + ->build(); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AcceptFdsDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AcceptFdsDataBuilder.php new file mode 100644 index 0000000000000..6883d63397be0 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AcceptFdsDataBuilder.php @@ -0,0 +1,65 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $payment = $paymentDO->getPayment(); + $data = []; + + if ($payment instanceof Payment) { + $authorizationTransaction = $payment->getAuthorizationTransaction(); + + if (empty($authorizationTransaction)) { + $transactionId = $payment->getLastTransId(); + } else { + $transactionId = $authorizationTransaction->getParentTxnId(); + + if (empty($transactionId)) { + $transactionId = $authorizationTransaction->getTxnId(); + } + } + + $data = [ + 'heldTransactionRequest' => [ + 'action' => 'approve', + 'refTransId' => $transactionId, + ] + ]; + } + + return $data; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AddressDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AddressDataBuilder.php new file mode 100644 index 0000000000000..e9c42e864440c --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AddressDataBuilder.php @@ -0,0 +1,77 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $order = $paymentDO->getOrder(); + $billingAddress = $order->getBillingAddress(); + $shippingAddress = $order->getShippingAddress(); + $result = [ + 'transactionRequest' => [] + ]; + + if ($billingAddress) { + $result['transactionRequest']['billTo'] = [ + 'firstName' => $billingAddress->getFirstname(), + 'lastName' => $billingAddress->getLastname(), + 'company' => $billingAddress->getCompany() ?? '', + 'address' => $billingAddress->getStreetLine1(), + 'city' => $billingAddress->getCity(), + 'state' => $billingAddress->getRegionCode(), + 'zip' => $billingAddress->getPostcode(), + 'country' => $billingAddress->getCountryId() + ]; + } + + if ($shippingAddress) { + $result['transactionRequest']['shipTo'] = [ + 'firstName' => $shippingAddress->getFirstname(), + 'lastName' => $shippingAddress->getLastname(), + 'company' => $shippingAddress->getCompany() ?? '', + 'address' => $shippingAddress->getStreetLine1(), + 'city' => $shippingAddress->getCity(), + 'state' => $shippingAddress->getRegionCode(), + 'zip' => $shippingAddress->getPostcode(), + 'country' => $shippingAddress->getCountryId() + ]; + } + + if ($order->getRemoteIp()) { + $result['transactionRequest']['customerIP'] = $order->getRemoteIp(); + } + + return $result; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AmountDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AmountDataBuilder.php new file mode 100644 index 0000000000000..601c329fe4f76 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AmountDataBuilder.php @@ -0,0 +1,46 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + return [ + 'transactionRequest' => [ + 'amount' => $this->formatPrice($this->subjectReader->readAmount($buildSubject)), + ] + ]; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AuthenticationDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AuthenticationDataBuilder.php new file mode 100644 index 0000000000000..2387ab0ab89f3 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AuthenticationDataBuilder.php @@ -0,0 +1,59 @@ +subjectReader = $subjectReader; + $this->config = $config; + } + + /** + * Adds authentication information to the request + * + * @param array $buildSubject + * @return array + */ + public function build(array $buildSubject): array + { + $storeId = $this->subjectReader->readStoreId($buildSubject); + + return [ + 'merchantAuthentication' => [ + 'name' => $this->config->getLoginId($storeId), + 'transactionKey' => $this->config->getTransactionKey($storeId) + ] + ]; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AuthorizeDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AuthorizeDataBuilder.php new file mode 100644 index 0000000000000..226175f74d55a --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/AuthorizeDataBuilder.php @@ -0,0 +1,69 @@ +subjectReader = $subjectReader; + $this->passthroughData = $passthroughData; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $payment = $paymentDO->getPayment(); + $data = []; + + if ($payment instanceof Payment) { + $data = [ + 'transactionRequest' => [ + 'transactionType' => self::REQUEST_AUTH_ONLY, + ] + ]; + + $this->passthroughData->setData( + 'transactionType', + $data['transactionRequest']['transactionType'] + ); + } + + return $data; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/CaptureDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/CaptureDataBuilder.php new file mode 100644 index 0000000000000..0b17d10fb0d68 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/CaptureDataBuilder.php @@ -0,0 +1,73 @@ +subjectReader = $subjectReader; + $this->passthroughData = $passthroughData; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $payment = $paymentDO->getPayment(); + $data = []; + + if ($payment instanceof Payment) { + $authTransaction = $payment->getAuthorizationTransaction(); + $refId = $authTransaction->getAdditionalInformation('real_transaction_id'); + + $data = [ + 'transactionRequest' => [ + 'transactionType' => self::REQUEST_TYPE_PRIOR_AUTH_CAPTURE, + 'refTransId' => $refId + ] + ]; + + $this->passthroughData->setData( + 'transactionType', + $data['transactionRequest']['transactionType'] + ); + } + + return $data; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/CustomSettingsBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/CustomSettingsBuilder.php new file mode 100644 index 0000000000000..e5b4472c098c8 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/CustomSettingsBuilder.php @@ -0,0 +1,62 @@ +subjectReader = $subjectReader; + $this->config = $config; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $result = []; + + if ($this->config->shouldEmailCustomer($this->subjectReader->readStoreId($buildSubject))) { + $result['transactionRequest'] = [ + 'transactionSettings' => [ + 'setting' => [ + [ + 'settingName' => 'emailCustomer', + 'settingValue' => 'true' + ] + ] + ] + ]; + } + + return $result; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/CustomerDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/CustomerDataBuilder.php new file mode 100644 index 0000000000000..7cd0426e93dd7 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/CustomerDataBuilder.php @@ -0,0 +1,52 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $order = $paymentDO->getOrder(); + $billingAddress = $order->getBillingAddress(); + $result = [ + 'transactionRequest' => [ + 'customer' => [ + 'id' => $order->getCustomerId(), + 'email' => $billingAddress->getEmail() + ] + ] + ]; + + return $result; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/OrderDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/OrderDataBuilder.php new file mode 100644 index 0000000000000..b0e33c9ca9615 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/OrderDataBuilder.php @@ -0,0 +1,48 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $order = $paymentDO->getOrder(); + + return [ + 'transactionRequest' => [ + 'order' => [ + 'invoiceNumber' => $order->getOrderIncrementId() + ] + ] + ]; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/PassthroughDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/PassthroughDataBuilder.php new file mode 100644 index 0000000000000..0301d08ad42c5 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/PassthroughDataBuilder.php @@ -0,0 +1,58 @@ +passthroughData = $passthroughData; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $fields = []; + + foreach ($this->passthroughData->getData() as $key => $value) { + $fields[] = [ + 'name' => $key, + 'value' => $value + ]; + } + + if (!empty($fields)) { + return [ + 'transactionRequest' => [ + 'userFields' => [ + 'userField' => $fields + ] + ] + ]; + } + + return []; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/PaymentDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/PaymentDataBuilder.php new file mode 100644 index 0000000000000..1ad73f6236616 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/PaymentDataBuilder.php @@ -0,0 +1,56 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $payment = $paymentDO->getPayment(); + $data = []; + + if ($payment instanceof Payment) { + $dataDescriptor = $payment->getAdditionalInformation('opaqueDataDescriptor'); + $dataValue = $payment->getAdditionalInformation('opaqueDataValue'); + + $data['transactionRequest']['payment'] = [ + 'opaqueData' => [ + 'dataDescriptor' => $dataDescriptor, + 'dataValue' => $dataValue + ] + ]; + } + + return $data; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/PoDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/PoDataBuilder.php new file mode 100644 index 0000000000000..ad8f8c2b05d91 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/PoDataBuilder.php @@ -0,0 +1,52 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $payment = $paymentDO->getPayment(); + $data = []; + + if ($payment instanceof Payment) { + $data = [ + 'transactionRequest' => [ + 'poNumber' => $payment->getPoNumber() + ] + ]; + } + + return $data; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/RefundPaymentDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/RefundPaymentDataBuilder.php new file mode 100644 index 0000000000000..96f3e67720fea --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/RefundPaymentDataBuilder.php @@ -0,0 +1,58 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + * @throws \Exception + */ + public function build(array $buildSubject): array + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $payment = $paymentDO->getPayment(); + $data = []; + + if ($payment instanceof Payment) { + $data = [ + 'transactionRequest' => [ + 'payment' => [ + 'creditCard' => [ + 'cardNumber' => $payment->getAdditionalInformation('ccLast4'), + 'expirationDate' => 'XXXX' + ] + ] + ] + ]; + } + + return $data; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/RefundReferenceTransactionDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/RefundReferenceTransactionDataBuilder.php new file mode 100644 index 0000000000000..b8cb5f858d05d --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/RefundReferenceTransactionDataBuilder.php @@ -0,0 +1,53 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $payment = $paymentDO->getPayment(); + $data = []; + + if ($payment instanceof Payment) { + $transactionId = $payment->getAuthorizationTransaction()->getParentTxnId(); + $data = [ + 'transactionRequest' => [ + 'refTransId' => $transactionId + ] + ]; + } + + return $data; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/RefundTransactionTypeDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/RefundTransactionTypeDataBuilder.php new file mode 100644 index 0000000000000..752be05f6b576 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/RefundTransactionTypeDataBuilder.php @@ -0,0 +1,31 @@ + [ + 'transactionType' => self::REQUEST_TYPE_REFUND + ] + ]; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/RequestTypeBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/RequestTypeBuilder.php new file mode 100644 index 0000000000000..16c3f9556de27 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/RequestTypeBuilder.php @@ -0,0 +1,45 @@ +type = $type; + } + + /** + * Adds the type of the request to the build subject + * + * @param array $buildSubject + * @return array + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function build(array $buildSubject): array + { + return [ + 'payload_type' => $this->type + ]; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/SaleDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/SaleDataBuilder.php new file mode 100644 index 0000000000000..6ec27b105615b --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/SaleDataBuilder.php @@ -0,0 +1,69 @@ +subjectReader = $subjectReader; + $this->passthroughData = $passthroughData; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $payment = $paymentDO->getPayment(); + $data = []; + + if ($payment instanceof Payment) { + $data = [ + 'transactionRequest' => [ + 'transactionType' => self::REQUEST_AUTH_AND_CAPTURE, + ] + ]; + + $this->passthroughData->setData( + 'transactionType', + $data['transactionRequest']['transactionType'] + ); + } + + return $data; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/ShippingDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/ShippingDataBuilder.php new file mode 100644 index 0000000000000..390714579f0b3 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/ShippingDataBuilder.php @@ -0,0 +1,56 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $payment = $paymentDO->getPayment(); + $order = $paymentDO->getOrder(); + $data = []; + + if ($payment instanceof Payment && $order instanceof Order) { + $data = [ + 'transactionRequest' => [ + 'shipping' => [ + 'amount' => $order->getBaseShippingAmount() + ] + ] + ]; + } + + return $data; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/SolutionDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/SolutionDataBuilder.php new file mode 100644 index 0000000000000..0c89a0116defe --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/SolutionDataBuilder.php @@ -0,0 +1,53 @@ +config = $config; + $this->subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + return [ + 'transactionRequest' => [ + 'solution' => [ + 'id' => $this->config->getSolutionId($this->subjectReader->readStoreId($buildSubject)), + ] + ] + ]; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/StoreConfigBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/StoreConfigBuilder.php new file mode 100644 index 0000000000000..f44b1e5de9a28 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/StoreConfigBuilder.php @@ -0,0 +1,43 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $order = $paymentDO->getOrder(); + + return [ + 'store_id' => $order->getStoreId() + ]; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/TransactionDetailsDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/TransactionDetailsDataBuilder.php new file mode 100644 index 0000000000000..e3a17e9636846 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/TransactionDetailsDataBuilder.php @@ -0,0 +1,69 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $data = []; + + if (!empty($buildSubject['transactionId'])) { + $data = [ + 'transId' => $buildSubject['transactionId'] + ]; + } else { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $payment = $paymentDO->getPayment(); + + if ($payment instanceof Payment) { + $authorizationTransaction = $payment->getAuthorizationTransaction(); + + if (empty($authorizationTransaction)) { + $transactionId = $payment->getLastTransId(); + } else { + $transactionId = $authorizationTransaction->getParentTxnId(); + + if (empty($transactionId)) { + $transactionId = $authorizationTransaction->getTxnId(); + } + } + + $data = [ + 'transId' => $transactionId + ]; + } + } + + return $data; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/VoidDataBuilder.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/VoidDataBuilder.php new file mode 100644 index 0000000000000..ef0cb96774e62 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Request/VoidDataBuilder.php @@ -0,0 +1,60 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject): array + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $payment = $paymentDO->getPayment(); + $transactionData = []; + + if ($payment instanceof Payment) { + $authorizationTransaction = $payment->getAuthorizationTransaction(); + $refId = $authorizationTransaction->getAdditionalInformation('real_transaction_id'); + if (empty($refId)) { + $refId = $authorizationTransaction->getParentTxnId(); + } + + $transactionData['transactionRequest'] = [ + 'transactionType' => self::REQUEST_TYPE_VOID, + 'refTransId' => $refId + ]; + } + + return $transactionData; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/CloseParentTransactionHandler.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/CloseParentTransactionHandler.php new file mode 100644 index 0000000000000..30b1ce88b083a --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/CloseParentTransactionHandler.php @@ -0,0 +1,45 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function handle(array $handlingSubject, array $response): void + { + $paymentDO = $this->subjectReader->readPayment($handlingSubject); + $payment = $paymentDO->getPayment(); + + if ($payment instanceof Payment) { + $payment->setShouldCloseParentTransaction(true); + } + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/CloseTransactionHandler.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/CloseTransactionHandler.php new file mode 100644 index 0000000000000..f0dff200e802b --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/CloseTransactionHandler.php @@ -0,0 +1,46 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function handle(array $handlingSubject, array $response): void + { + $paymentDO = $this->subjectReader->readPayment($handlingSubject); + $payment = $paymentDO->getPayment(); + + if ($payment instanceof Payment) { + $payment->setIsTransactionClosed(true); + $payment->setShouldCloseParentTransaction(true); + } + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/PaymentResponseHandler.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/PaymentResponseHandler.php new file mode 100644 index 0000000000000..16e8fbabb214a --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/PaymentResponseHandler.php @@ -0,0 +1,55 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function handle(array $handlingSubject, array $response): void + { + $paymentDO = $this->subjectReader->readPayment($handlingSubject); + $payment = $paymentDO->getPayment(); + $transactionResponse = $response['transactionResponse']; + + if ($payment instanceof Payment) { + $payment->setCcLast4($payment->getAdditionalInformation('ccLast4')); + $payment->setCcAvsStatus($transactionResponse['avsResultCode']); + $payment->setIsTransactionClosed(false); + + if ($transactionResponse['responseCode'] == self::RESPONSE_CODE_HELD) { + $payment->setIsTransactionPending(true) + ->setIsFraudDetected(true); + } + } + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/PaymentReviewStatusHandler.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/PaymentReviewStatusHandler.php new file mode 100644 index 0000000000000..9f7c62873669f --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/PaymentReviewStatusHandler.php @@ -0,0 +1,63 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function handle(array $handlingSubject, array $response): void + { + $paymentDO = $this->subjectReader->readPayment($handlingSubject); + $payment = $paymentDO->getPayment(); + + if ($payment instanceof Payment) { + $paymentDO = $this->subjectReader->readPayment($handlingSubject); + $payment = $paymentDO->getPayment(); + + $status = $response['transaction']['transactionStatus']; + // This data is only used when updating the order payment via Get Payment Update + if (!in_array($status, self::REVIEW_PENDING_STATUSES)) { + $denied = in_array($status, self::REVIEW_DECLINED_STATUSES); + $payment->setData('is_transaction_denied', $denied); + $payment->setData('is_transaction_approved', !$denied); + } + } + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/TransactionDetailsResponseHandler.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/TransactionDetailsResponseHandler.php new file mode 100644 index 0000000000000..0dab641452136 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/TransactionDetailsResponseHandler.php @@ -0,0 +1,65 @@ +subjectReader = $subjectReader; + $this->config = $config; + } + + /** + * @inheritdoc + */ + public function handle(array $handlingSubject, array $response): void + { + $storeId = $this->subjectReader->readStoreId($handlingSubject); + $paymentDO = $this->subjectReader->readPayment($handlingSubject); + $payment = $paymentDO->getPayment(); + $transactionResponse = $response['transactionResponse']; + + if ($payment instanceof Payment) { + // Add the keys that should show in the transaction details interface + $additionalInformationKeys = $this->config->getAdditionalInfoKeys($storeId); + $rawDetails = []; + foreach ($additionalInformationKeys as $paymentInfoKey) { + if (isset($transactionResponse[$paymentInfoKey])) { + $rawDetails[$paymentInfoKey] = $transactionResponse[$paymentInfoKey]; + $payment->setAdditionalInformation($paymentInfoKey, $transactionResponse[$paymentInfoKey]); + } + } + $payment->setTransactionAdditionalInfo(Payment\Transaction::RAW_DETAILS, $rawDetails); + } + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/TransactionIdHandler.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/TransactionIdHandler.php new file mode 100644 index 0000000000000..bf5257f95dad6 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/TransactionIdHandler.php @@ -0,0 +1,54 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function handle(array $handlingSubject, array $response): void + { + $paymentDO = $this->subjectReader->readPayment($handlingSubject); + $payment = $paymentDO->getPayment(); + $transactionResponse = $response['transactionResponse']; + + if ($payment instanceof Payment) { + if (!$payment->getParentTransactionId() + || $transactionResponse['transId'] != $payment->getParentTransactionId() + ) { + $payment->setTransactionId($transactionResponse['transId']); + } + $payment->setTransactionAdditionalInfo( + 'real_transaction_id', + $transactionResponse['transId'] + ); + } + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/VoidResponseHandler.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/VoidResponseHandler.php new file mode 100644 index 0000000000000..06b16b37278ba --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Response/VoidResponseHandler.php @@ -0,0 +1,49 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function handle(array $handlingSubject, array $response): void + { + $paymentDO = $this->subjectReader->readPayment($handlingSubject); + $payment = $paymentDO->getPayment(); + $transactionId = $response['transactionResponse']['transId']; + + if ($payment instanceof Payment) { + $payment->setIsTransactionClosed(true); + $payment->setShouldCloseParentTransaction(true); + $payment->setTransactionAdditionalInfo('real_transaction_id', $transactionId); + } + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/SubjectReader.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/SubjectReader.php new file mode 100644 index 0000000000000..855d48e27968e --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/SubjectReader.php @@ -0,0 +1,96 @@ +readPayment($subject) + ->getOrder() + ->getStoreId(); + } catch (\InvalidArgumentException $e) { + // No store id is current set + } + } + + return $storeId ? (int)$storeId : null; + } + + /** + * Reads amount from subject + * + * @param array $subject + * @return string + */ + public function readAmount(array $subject): string + { + return (string)Helper\SubjectReader::readAmount($subject); + } + + /** + * Reads response from subject + * + * @param array $subject + * @return array + */ + public function readResponse(array $subject): ?array + { + return Helper\SubjectReader::readResponse($subject); + } + + /** + * Reads login id from subject + * + * @param array $subject + * @return string|null + */ + public function readLoginId(array $subject): ?string + { + return $subject['merchantAuthentication']['name'] ?? null; + } + + /** + * Reads transaction key from subject + * + * @param array $subject + * @return string|null + */ + public function readTransactionKey(array $subject): ?string + { + return $subject['merchantAuthentication']['transactionKey'] ?? null; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Validator/GeneralResponseValidator.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Validator/GeneralResponseValidator.php new file mode 100644 index 0000000000000..7ad4647b421a1 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Validator/GeneralResponseValidator.php @@ -0,0 +1,79 @@ +resultFactory = $resultFactory; + $this->subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function validate(array $validationSubject): ResultInterface + { + $response = $this->subjectReader->readResponse($validationSubject); + $isValid = (isset($response['messages']['resultCode']) + && $response['messages']['resultCode'] === self::RESULT_CODE_SUCCESS); + $errorCodes = []; + $errorMessages = []; + + if (!$isValid) { + if (isset($response['messages']['message']['code'])) { + $errorCodes[] = $response['messages']['message']['code']; + $errorMessages[] = $response['messages']['message']['text']; + } elseif (isset($response['messages']['message'])) { + foreach ($response['messages']['message'] as $message) { + $errorCodes[] = $message['code']; + $errorMessages[] = $message['text']; + } + } elseif (isset($response['errors']['error'])) { + foreach ($response['errors']['error'] as $message) { + $errorCodes[] = $message['errorCode']; + $errorMessages[] = $message['errorText']; + } + } + } + + return $this->createResult($isValid, $errorMessages, $errorCodes); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Validator/TransactionHashValidator.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Validator/TransactionHashValidator.php new file mode 100644 index 0000000000000..0d1c2ad033d87 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Validator/TransactionHashValidator.php @@ -0,0 +1,197 @@ +subjectReader = $subjectReader; + $this->config = $config; + } + + /** + * Validates the transaction hash matches the configured hash + * + * @param array $validationSubject + * @return ResultInterface + */ + public function validate(array $validationSubject): ResultInterface + { + $response = $this->subjectReader->readResponse($validationSubject); + $storeId = $this->subjectReader->readStoreId($validationSubject); + + if (!empty($response['transactionResponse']['transHashSha2'])) { + return $this->validateHash( + $validationSubject, + $this->config->getTransactionSignatureKey($storeId), + 'transHashSha2', + 'generateSha512Hash' + ); + } elseif (!empty($response['transactionResponse']['transHash'])) { + return $this->validateHash( + $validationSubject, + $this->config->getLegacyTransactionHash($storeId), + 'transHash', + 'generateMd5Hash' + ); + } + + return $this->createResult( + false, + [ + __('The authenticity of the gateway response could not be verified.') + ], + [self::ERROR_TRANSACTION_HASH] + ); + } + + /** + * Validates the response again the legacy MD5 spec + * + * @param array $validationSubject + * @param string $storedHash + * @param string $hashField + * @param string $generateFunction + * @return ResultInterface + */ + private function validateHash( + array $validationSubject, + string $storedHash, + string $hashField, + string $generateFunction + ): ResultInterface { + $storeId = $this->subjectReader->readStoreId($validationSubject); + $response = $this->subjectReader->readResponse($validationSubject); + $transactionResponse = $response['transactionResponse']; + + /* + * Authorize.net is inconsistent with how they hash and heuristically trying to detect whether or not they used + * the amount to calculate the hash is risky because their responses are incorrect in some cases. + * Refund uses the amount when referencing a transaction but will use 0 when refunding without a reference. + * Non-refund reference transactions such as (void/capture) don't use the amount. Authorize/auth&capture + * transactions will use amount but if there is an AVS error the response will indicate the transaction was a + * reference transaction so this can't be heuristically detected by looking at combinations of refTransID + * and transId (yes they also mixed the letter casing for "id"). Their documentation doesn't talk about this + * and to make this even better, none of their official SDKs support the new hash field to compare + * implementations. Therefore the only way to safely validate this hash without failing for even more + * unexpected corner cases we simply need to validate with and without the amount. + */ + try { + $amount = $this->subjectReader->readAmount($validationSubject); + } catch (\InvalidArgumentException $e) { + $amount = 0; + } + + $hash = $this->{$generateFunction}( + $storedHash, + $this->config->getLoginId($storeId), + sprintf('%.2F', $amount), + $transactionResponse['transId'] ?? '' + ); + $valid = Security::compareStrings($hash, $transactionResponse[$hashField]); + + if (!$valid && $amount > 0) { + $hash = $this->{$generateFunction}( + $storedHash, + $this->config->getLoginId($storeId), + '0.00', + $transactionResponse['transId'] ?? '' + ); + $valid = Security::compareStrings($hash, $transactionResponse[$hashField]); + } + + if ($valid) { + return $this->createResult(true); + } + + return $this->createResult( + false, + [ + __('The authenticity of the gateway response could not be verified.') + ], + [self::ERROR_TRANSACTION_HASH] + ); + } + + /** + * Generates a Md5 hash to compare against AuthNet's. + * + * @param string $merchantMd5 + * @param string $merchantApiLogin + * @param string $amount + * @param string $transactionId + * @return string + * @SuppressWarnings(PHPMD.UnusedPrivateMethod) + */ + private function generateMd5Hash( + $merchantMd5, + $merchantApiLogin, + $amount, + $transactionId + ) { + return strtoupper(md5($merchantMd5 . $merchantApiLogin . $transactionId . $amount)); + } + + /** + * Generates a SHA-512 hash to compare against AuthNet's. + * + * @param string $merchantKey + * @param string $merchantApiLogin + * @param string $amount + * @param string $transactionId + * @return string + * @SuppressWarnings(PHPMD.UnusedPrivateMethod) + */ + private function generateSha512Hash( + $merchantKey, + $merchantApiLogin, + $amount, + $transactionId + ) { + $message = '^' . $merchantApiLogin . '^' . $transactionId . '^' . $amount . '^'; + + return strtoupper(hash_hmac('sha512', $message, pack('H*', $merchantKey))); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Gateway/Validator/TransactionResponseValidator.php b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Validator/TransactionResponseValidator.php new file mode 100644 index 0000000000000..93b5f2bb62a7d --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Gateway/Validator/TransactionResponseValidator.php @@ -0,0 +1,99 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function validate(array $validationSubject): ResultInterface + { + $response = $this->subjectReader->readResponse($validationSubject); + $transactionResponse = $response['transactionResponse']; + + if ($this->isResponseCodeAnError($transactionResponse)) { + $errorCodes = []; + $errorMessages = []; + + if (isset($transactionResponse['messages']['message']['code'])) { + $errorCodes[] = $transactionResponse['messages']['message']['code']; + $errorMessages[] = $transactionResponse['messages']['message']['text']; + } elseif ($transactionResponse['messages']['message']) { + foreach ($transactionResponse['messages']['message'] as $message) { + $errorCodes[] = $message['code']; + $errorMessages[] = $message['description']; + } + } elseif (isset($transactionResponse['errors'])) { + foreach ($transactionResponse['errors'] as $message) { + $errorCodes[] = $message['errorCode']; + $errorMessages[] = $message['errorCode']; + } + } + + return $this->createResult(false, $errorMessages, $errorCodes); + } + + return $this->createResult(true); + } + + /** + * Determines if the response code is actually an error + * + * @param array $transactionResponse + * @return bool + */ + private function isResponseCodeAnError(array $transactionResponse): bool + { + $code = $transactionResponse['messages']['message']['code'] + ?? $transactionResponse['messages']['message'][0]['code'] + ?? $transactionResponse['errors'][0]['errorCode'] + ?? null; + + return in_array($transactionResponse['responseCode'], [self::RESPONSE_CODE_APPROVED, self::RESPONSE_CODE_HELD]) + && $code + && !in_array( + $code, + [ + self::RESPONSE_REASON_CODE_APPROVED, + self::RESPONSE_REASON_CODE_PENDING_REVIEW, + self::RESPONSE_REASON_CODE_PENDING_REVIEW_AUTHORIZED + ] + ); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/LICENSE.txt b/app/code/Magento/AuthorizenetAcceptjs/LICENSE.txt new file mode 100644 index 0000000000000..49525fd99da9c --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/LICENSE.txt @@ -0,0 +1,48 @@ + +Open Software License ("OSL") v. 3.0 + +This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Open Software License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/AuthorizenetAcceptjs/LICENSE_AFL.txt b/app/code/Magento/AuthorizenetAcceptjs/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/AuthorizenetAcceptjs/Model/Adminhtml/Source/Cctype.php b/app/code/Magento/AuthorizenetAcceptjs/Model/Adminhtml/Source/Cctype.php new file mode 100644 index 0000000000000..046907ebb88cc --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Model/Adminhtml/Source/Cctype.php @@ -0,0 +1,25 @@ + self::ENVIRONMENT_SANDBOX, + 'label' => 'Sandbox', + ], + [ + 'value' => self::ENVIRONMENT_PRODUCTION, + 'label' => 'Production' + ] + ]; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Model/Adminhtml/Source/PaymentAction.php b/app/code/Magento/AuthorizenetAcceptjs/Model/Adminhtml/Source/PaymentAction.php new file mode 100644 index 0000000000000..907a1b2a51b85 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Model/Adminhtml/Source/PaymentAction.php @@ -0,0 +1,32 @@ + 'authorize', + 'label' => __('Authorize Only'), + ], + [ + 'value' => 'authorize_capture', + 'label' => __('Authorize and Capture') + ] + ]; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Model/PassthroughDataObject.php b/app/code/Magento/AuthorizenetAcceptjs/Model/PassthroughDataObject.php new file mode 100644 index 0000000000000..b49ef7e622506 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Model/PassthroughDataObject.php @@ -0,0 +1,19 @@ +config = $config; + $this->cart = $cart; + } + + /** + * Retrieve assoc array of checkout configuration + * + * @return array + */ + public function getConfig() + { + $storeId = $this->cart->getStoreId(); + + return [ + 'payment' => [ + Config::METHOD => [ + 'clientKey' => $this->config->getClientKey($storeId), + 'apiLoginID' => $this->config->getLoginId($storeId), + 'environment' => $this->config->getEnvironment($storeId), + 'useCvv' => $this->config->isCvvEnabled($storeId), + ] + ] + ]; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Observer/DataAssignObserver.php b/app/code/Magento/AuthorizenetAcceptjs/Observer/DataAssignObserver.php new file mode 100644 index 0000000000000..c7490ad0c80c3 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Observer/DataAssignObserver.php @@ -0,0 +1,52 @@ +readDataArgument($observer); + + $additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA); + if (!is_array($additionalData)) { + return; + } + + $paymentInfo = $this->readPaymentModelArgument($observer); + + foreach ($this->additionalInformationList as $additionalInformationKey) { + if (isset($additionalData[$additionalInformationKey])) { + $paymentInfo->setAdditionalInformation( + $additionalInformationKey, + $additionalData[$additionalInformationKey] + ); + } + } + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/README.md b/app/code/Magento/AuthorizenetAcceptjs/README.md new file mode 100644 index 0000000000000..b066f8a2d7509 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/README.md @@ -0,0 +1 @@ +The Magento_AuthorizenetAcceptjs module implements the integration with the Authorize.Net payment gateway and makes the latter available as a payment method in Magento. diff --git a/app/code/Magento/AuthorizenetAcceptjs/Setup/Patch/Data/CopyCurrentConfig.php b/app/code/Magento/AuthorizenetAcceptjs/Setup/Patch/Data/CopyCurrentConfig.php new file mode 100644 index 0000000000000..0675bd94b6200 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Setup/Patch/Data/CopyCurrentConfig.php @@ -0,0 +1,230 @@ +scopeConfig = $scopeConfig; + $this->resourceConfig = $resourceConfig; + $this->encryptor = $encryptor; + $this->moduleDataSetup = $moduleDataSetup; + $this->storeManager = $storeManager; + } + + /** + * @inheritdoc + */ + public function apply(): void + { + $this->moduleDataSetup->startSetup(); + $this->migrateDefaultValues(); + $this->migrateWebsiteValues(); + $this->moduleDataSetup->endSetup(); + } + + /** + * Migrate configuration values from DirectPost to Accept.js on default scope + * + * @return void + */ + private function migrateDefaultValues(): void + { + foreach ($this->configFieldsToMigrate as $field) { + $configValue = $this->getOldConfigValue($field); + + if (!empty($configValue)) { + $this->saveNewConfigValue($field, $configValue); + } + } + + foreach ($this->encryptedConfigFieldsToMigrate as $field) { + $configValue = $this->getOldConfigValue($field); + + if (!empty($configValue)) { + $this->saveNewConfigValue( + $field, + $configValue, + ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + 0, + true + ); + } + } + } + + /** + * Migrate configuration values from DirectPost to Accept.js on all website scopes + * + * @return void + */ + private function migrateWebsiteValues(): void + { + foreach ($this->storeManager->getWebsites() as $website) { + $websiteID = (int) $website->getId(); + + foreach ($this->configFieldsToMigrate as $field) { + $configValue = $this->getOldConfigValue($field, ScopeInterface::SCOPE_WEBSITES, $websiteID); + + if (!empty($configValue)) { + $this->saveNewConfigValue($field, $configValue, ScopeInterface::SCOPE_WEBSITES, $websiteID); + } + } + + foreach ($this->encryptedConfigFieldsToMigrate as $field) { + $configValue = $this->getOldConfigValue($field, ScopeInterface::SCOPE_WEBSITES, $websiteID); + + if (!empty($configValue)) { + $this->saveNewConfigValue($field, $configValue, ScopeInterface::SCOPE_WEBSITES, $websiteID, true); + } + } + } + } + + /** + * Get old configuration value from the DirectPost module's configuration on the store scope + * + * @param string $field + * @param string $scope + * @param int $scopeID + * @return mixed + */ + private function getOldConfigValue( + string $field, + string $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + int $scopeID = null + ) { + return $this->scopeConfig->getValue( + sprintf(self::PAYMENT_PATH_FORMAT, self::DIRECTPOST_PATH, $field), + $scope, + $scopeID + ); + } + + /** + * Save configuration value for AcceptJS + * + * @param string $field + * @param mixed $value + * @param string $scope + * @param int $scopeID + * @param bool $isEncrypted + * @return void + */ + private function saveNewConfigValue( + string $field, + $value, + string $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + int $scopeID = 0, + bool $isEncrypted = false + ): void { + $value = $isEncrypted ? $this->encryptor->encrypt($value) : $value; + + $this->resourceConfig->saveConfig( + sprintf(self::PAYMENT_PATH_FORMAT, self::ACCEPTJS_PATH, $field), + $value, + $scope, + $scopeID + ); + } + + /** + * @inheritdoc + */ + public static function getDependencies() + { + return []; + } + + /** + * @inheritdoc + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/ActionGroup/ConfigureAuthorizenetAcceptjsActionGroup.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/ActionGroup/ConfigureAuthorizenetAcceptjsActionGroup.xml new file mode 100644 index 0000000000000..e9a194435e3eb --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/ActionGroup/ConfigureAuthorizenetAcceptjsActionGroup.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/ActionGroup/FillPaymentInformationActionGroup.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/ActionGroup/FillPaymentInformationActionGroup.xml new file mode 100644 index 0000000000000..d06bf996a1f25 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/ActionGroup/FillPaymentInformationActionGroup.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/ActionGroup/ViewAndValidateOrderActionGroup.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/ActionGroup/ViewAndValidateOrderActionGroup.xml new file mode 100644 index 0000000000000..ba0e49d1876f0 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/ActionGroup/ViewAndValidateOrderActionGroup.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Data/AuthorizenetAcceptjsOrderValidationData.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Data/AuthorizenetAcceptjsOrderValidationData.xml new file mode 100644 index 0000000000000..59d4be98d450c --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Data/AuthorizenetAcceptjsOrderValidationData.xml @@ -0,0 +1,18 @@ + + + + + + $24.68 + $128.00 + Processing + Capture + No + + diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/LICENSE.txt b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/LICENSE.txt new file mode 100644 index 0000000000000..49525fd99da9c --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/LICENSE.txt @@ -0,0 +1,48 @@ + +Open Software License ("OSL") v. 3.0 + +This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Open Software License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/LICENSE_AFL.txt b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/README.md b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/README.md new file mode 100644 index 0000000000000..aba235e2cfad9 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/README.md @@ -0,0 +1,3 @@ +# AuthorizenetAcceptjs Functional Tests + +The Functional Test Module for **Magento AuthorizenetAcceptjs** module. diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/AdminMenuSection.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/AdminMenuSection.xml new file mode 100644 index 0000000000000..defb91339ea8f --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/AdminMenuSection.xml @@ -0,0 +1,25 @@ + + + + +
+ + + + + + + + + + + + +
+
diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/AuthorizenetAcceptjsConfigurationSection.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/AuthorizenetAcceptjsConfigurationSection.xml new file mode 100644 index 0000000000000..31be865ea2678 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/AuthorizenetAcceptjsConfigurationSection.xml @@ -0,0 +1,24 @@ + + + + +
+ + + + + + + + + + + +
+
diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/AuthorizenetCheckoutSection.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/AuthorizenetCheckoutSection.xml new file mode 100644 index 0000000000000..5d97842de374c --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/AuthorizenetCheckoutSection.xml @@ -0,0 +1,19 @@ + + + + +
+ + + + + + +
+
diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/ConfigurationMainActionsSection.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/ConfigurationMainActionsSection.xml new file mode 100644 index 0000000000000..344330c4bc052 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/ConfigurationMainActionsSection.xml @@ -0,0 +1,14 @@ + + + + +
+ +
+
diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/GuestAuthorizenetCheckoutSection.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/GuestAuthorizenetCheckoutSection.xml new file mode 100644 index 0000000000000..b5f2ecf641162 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/GuestAuthorizenetCheckoutSection.xml @@ -0,0 +1,22 @@ + + + + +
+ + + + + + + + + +
+
diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/OrdersGridSection.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/OrdersGridSection.xml new file mode 100644 index 0000000000000..7ae3dd0ffee89 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/OrdersGridSection.xml @@ -0,0 +1,14 @@ + + + + +
+ +
+
diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/StoresConfigurationListSection.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/StoresConfigurationListSection.xml new file mode 100644 index 0000000000000..f9f1bef38d17d --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/StoresConfigurationListSection.xml @@ -0,0 +1,15 @@ + + + + +
+ + +
+
diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/StoresSubmenuSection.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/StoresSubmenuSection.xml new file mode 100644 index 0000000000000..e54f9808fd49e --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/StoresSubmenuSection.xml @@ -0,0 +1,14 @@ + + + + +
+ +
+
diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/ViewOrderSection.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/ViewOrderSection.xml new file mode 100644 index 0000000000000..608067d7d31a1 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Section/ViewOrderSection.xml @@ -0,0 +1,25 @@ + + + + +
+ + + + + + + + + + + + +
+
diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Test/FullCaptureAuthorizenetAcceptjsTest.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Test/FullCaptureAuthorizenetAcceptjsTest.xml new file mode 100644 index 0000000000000..42a78291436ed --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Test/FullCaptureAuthorizenetAcceptjsTest.xml @@ -0,0 +1,74 @@ + + + + + + + + + <description value="Capture an order placed using Authorize.net Accept.js"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-12255"/> + <skip> + <issueId value="DEVOPS-4604"/> + </skip> + <group value="AuthorizenetAcceptjs"/> + <group value="ThirdPartyPayments"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + + <createData stepKey="createCustomer" entity="Simple_US_Customer"/> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + + <!--Configure Auth.net--> + <actionGroup ref="ConfigureAuthorizenetAcceptjs" stepKey="configureAuthorizenetAcceptjs"> + <argument name="paymentAction" value="Authorize Only"/> + </actionGroup> + + </before> + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <actionGroup ref="DisableAuthorizenetAcceptjs" stepKey="DisableAuthorizenetAcceptjs"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Storefront Login--> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginStorefront"> + <argument name="Customer" value="$$createCustomer$$"/> + </actionGroup> + + <!--Add product to cart--> + <amOnPage url="$$createProduct.name$$.html" stepKey="goToProductPage"/> + <waitForPageLoad stepKey="waitForProductPage"/> + <click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addProductToCart"/> + <waitForPageLoad stepKey="waitForCartToFill"/> + + <!--Checkout steps--> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="GoToCheckoutFromMinicartActionGroup"/> + <waitForPageLoad stepKey="waitForCheckoutLoad"/> + <actionGroup ref="CheckoutSelectFlatRateShippingMethodActionGroup" stepKey="selectFlatRateShipping"/> + <click selector="{{CheckoutShippingMethodsSection.next}}" stepKey="submitShippingSelection"/> + <waitForPageLoad stepKey="waitForShippingToFinish"/> + <actionGroup ref="FillPaymentInformation" stepKey="fillPaymentInfo"/> + + <!--View and validate order--> + <actionGroup ref="ViewAndValidateOrderActionGroup" stepKey="viewAndValidateOrder"> + <argument name="amount" value="{{AuthorizenetAcceptjsOrderValidationData.twoSimpleProductsOrderAmount}}"/> + <argument name="status" value="{{AuthorizenetAcceptjsOrderValidationData.processingStatusProcessing}}"/> + <argument name="captureStatus" value="{{AuthorizenetAcceptjsOrderValidationData.captureStatusCapture}}"/> + <argument name="closedStatus" value="{{AuthorizenetAcceptjsOrderValidationData.closedStatusNo}}"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Test/GuestCheckoutVirtualProductAuthorizenetAcceptjsTest.xml b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Test/GuestCheckoutVirtualProductAuthorizenetAcceptjsTest.xml new file mode 100644 index 0000000000000..95c2436905212 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Mftf/Test/GuestCheckoutVirtualProductAuthorizenetAcceptjsTest.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="GuestCheckoutVirtualProductAuthorizenetAcceptjsTest"> + <annotations> + <stories value="Authorize.net Accept.js"/> + <title value="Guest Checkout of Virtual Product using Authorize.net Accept.js"/> + <description value="Checkout a virtual product with a guest using Authorize.net Accept.js"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-12712"/> + <skip> + <issueId value="DEVOPS-4604"/> + </skip> + <group value="AuthorizenetAcceptjs"/> + <group value="ThirdPartyPayments"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + + <!-- Create virtual product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <waitForPageLoad stepKey="waitForProductIndexPage"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateProduct"> + <argument name="product" value="defaultVirtualProduct"/> + </actionGroup> + <actionGroup ref="fillMainProductFormNoWeight" stepKey="fillProductForm"> + <argument name="product" value="defaultVirtualProduct"/> + </actionGroup> + <actionGroup ref="saveProductForm" stepKey="saveProductForm"/> + + <!--Configure Auth.net--> + <actionGroup ref="ConfigureAuthorizenetAcceptjs" stepKey="configureAuthorizenetAcceptjs"> + <argument name="paymentAction" value="Authorize and Capture"/> + </actionGroup> + + </before> + <after> + <actionGroup ref="DisableAuthorizenetAcceptjs" stepKey="DisableAuthorizenetAcceptjs"/> + <!-- Delete virtual product --> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteProduct"> + <argument name="product" value="defaultVirtualProduct"/> + </actionGroup> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Add product to cart twice--> + <amOnPage url="{{defaultVirtualProduct.sku}}.html" stepKey="goToProductPage"/> + <waitForPageLoad stepKey="waitForProductPage"/> + <click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addProductToCart"/> + <waitForPageLoad stepKey="waitForCartToFill"/> + <click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addProductToCartAgain"/> + <waitForPageLoad stepKey="waitForCartToFillAgain"/> + + <!--Checkout steps--> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="GoToCheckoutFromMinicartActionGroup"/> + <waitForPageLoad stepKey="waitForCheckoutLoad"/> + + <fillField selector="{{CheckoutShippingSection.email}}" userInput="{{Simple_US_Customer.email}}" stepKey="enterEmail"/> + <click stepKey="clickOnAuthorizenetToggle" selector="{{AuthorizenetCheckoutSection.selectAuthorizenet}}"/> + <waitForPageLoad stepKey="waitForBillingInfoLoad"/> + <actionGroup ref="GuestCheckoutAuthorizenetFillBillingAddress" stepKey="fillAddressForm"> + <argument name="customer" value="Simple_US_Customer"/> + <argument name="customerAddress" value="CustomerAddressSimple"/> + </actionGroup> + <actionGroup ref="FillPaymentInformation" stepKey="fillPaymentInfo"/> + + <!--View and validate order--> + <actionGroup ref="ViewAndValidateOrderActionGroupNoSubmit" stepKey="viewAndValidateOrder"> + <argument name="amount" value="{{AuthorizenetAcceptjsOrderValidationData.virtualProductOrderAmount}}"/> + <argument name="status" value="{{AuthorizenetAcceptjsOrderValidationData.processingStatusProcessing}}"/> + <argument name="captureStatus" value="{{AuthorizenetAcceptjsOrderValidationData.captureStatusCapture}}"/> + <argument name="closedStatus" value="{{AuthorizenetAcceptjsOrderValidationData.closedStatusNo}}"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Block/FormTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Block/FormTest.php new file mode 100644 index 0000000000000..020b651aaaf17 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Block/FormTest.php @@ -0,0 +1,59 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Block; + +use Magento\AuthorizenetAcceptjs\Block\Form; +use PHPUnit\Framework\MockObject\Builder\InvocationMocker; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; +use Magento\AuthorizenetAcceptjs\Gateway\Config; +use Magento\Backend\Model\Session\Quote; +use Magento\Framework\View\Element\Template\Context; +use Magento\Payment\Model\Config as PaymentConfig; + +class FormTest extends TestCase +{ + /** + * @var Form + */ + private $block; + + /** + * @var Config|MockObject|InvocationMocker + */ + private $configMock; + + protected function setUp() + { + $contextMock = $this->createMock(Context::class); + $this->configMock = $this->createMock(Config::class); + $quoteMock = $this->getMockBuilder(Quote::class) + ->disableOriginalConstructor() + ->setMethods(['getStoreId']) + ->getMock(); + $quoteMock->method('getStoreId') + ->willReturn('123'); + $paymentConfig = $this->createMock(PaymentConfig::class); + + $this->block = new Form( + $contextMock, + $paymentConfig, + $this->configMock, + $quoteMock + ); + } + + public function testIsCvvEnabled() + { + $this->configMock->method('isCvvEnabled') + ->with('123') + ->willReturn(true); + $this->assertTrue($this->block->isCvvEnabled()); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Block/InfoTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Block/InfoTest.php new file mode 100644 index 0000000000000..70dfb140e1576 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Block/InfoTest.php @@ -0,0 +1,80 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Block; + +use Magento\AuthorizenetAcceptjs\Block\Info; +use Magento\AuthorizenetAcceptjs\Gateway\Config; +use Magento\Framework\Phrase; +use Magento\Framework\Phrase\RendererInterface; +use Magento\Framework\View\Element\Template\Context; +use Magento\Payment\Gateway\ConfigInterface; +use Magento\Payment\Model\InfoInterface; +use PHPUnit\Framework\MockObject\Builder\InvocationMocker; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class InfoTest extends TestCase +{ + public function testLabelsAreTranslated() + { + /** @var Context|MockObject|InvocationMocker $contextMock */ + $contextMock = $this->createMock(Context::class); + /** @var Config|MockObject|InvocationMocker $configMock */ + $configMock = $this->createMock(ConfigInterface::class); + $block = new Info($contextMock, $configMock); + /** @var InfoInterface|MockObject|InvocationMocker $payment */ + $payment = $this->createMock(InfoInterface::class); + /** @var RendererInterface|MockObject|InvocationMocker $translationRenderer */ + $translationRenderer = $this->createMock(RendererInterface::class); + + // only foo should be used + $configMock->method('getValue') + ->willReturnMap([ + ['paymentInfoKeys', null, 'foo'], + ['privateInfoKeys', null, ''] + ]); + + // Give more info to ensure only foo is translated + $payment->method('getAdditionalInformation') + ->willReturnCallback(function ($name = null) { + $info = [ + 'foo' => 'bar', + 'baz' => 'bash' + ]; + + if (empty($name)) { + return $info; + } + + return $info[$name]; + }); + + // Foo should be translated to Super Cool String + $translationRenderer->method('render') + ->with(['foo'], []) + ->willReturn('Super Cool String'); + + $previousRenderer = Phrase::getRenderer(); + Phrase::setRenderer($translationRenderer); + + try { + $block->setData('info', $payment); + + $info = $block->getSpecificInformation(); + } finally { + // No matter what, restore the renderer + Phrase::setRenderer($previousRenderer); + } + + // Assert the label was correctly translated + $this->assertSame($info['Super Cool String'], 'bar'); + $this->assertArrayNotHasKey('foo', $info); + $this->assertArrayNotHasKey('baz', $info); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Block/PaymentTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Block/PaymentTest.php new file mode 100644 index 0000000000000..11ae27f9d2ea7 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Block/PaymentTest.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Block; + +use Magento\AuthorizenetAcceptjs\Block\Payment; +use Magento\AuthorizenetAcceptjs\Model\Ui\ConfigProvider; +use Magento\Framework\Serialize\Serializer\Json; +use Magento\Framework\View\Element\Template\Context; +use PHPUnit\Framework\MockObject\Builder\InvocationMocker; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class PaymentTest extends TestCase +{ + /** + * @var ConfigProvider|MockObject|InvocationMocker + */ + private $configMock; + + /** + * @var Payment + */ + private $block; + + protected function setUp() + { + $contextMock = $this->createMock(Context::class); + $this->configMock = $this->createMock(ConfigProvider::class); + $this->block = new Payment($contextMock, $this->configMock, new Json()); + } + + public function testConfigIsCreated() + { + $this->configMock->method('getConfig') + ->willReturn([ + 'payment' => [ + 'authorizenet_acceptjs' => [ + 'foo' => 'bar' + ] + ] + ]); + + $result = $this->block->getPaymentConfig(); + $expected = '{"foo":"bar","code":"authorizenet_acceptjs"}'; + $this->assertEquals($expected, $result); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/AcceptPaymentStrategyCommandTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/AcceptPaymentStrategyCommandTest.php new file mode 100644 index 0000000000000..316fef5443360 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/AcceptPaymentStrategyCommandTest.php @@ -0,0 +1,131 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Command; + +use Magento\AuthorizenetAcceptjs\Gateway\Command\AcceptPaymentStrategyCommand; +use Magento\AuthorizenetAcceptjs\Gateway\Command\RefundTransactionStrategyCommand; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Command\CommandPoolInterface; +use Magento\Payment\Gateway\Command\ResultInterface; +use Magento\Payment\Gateway\CommandInterface; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class AcceptPaymentStrategyCommandTest extends TestCase +{ + /** + * @var CommandInterface|MockObject + */ + private $commandMock; + + /** + * @var CommandInterface|MockObject + */ + private $transactionDetailsCommandMock; + + /** + * @var CommandPoolInterface|MockObject + */ + private $commandPoolMock; + + /** + * @var RefundTransactionStrategyCommand + */ + private $command; + + /** + * @var ResultInterface|MockObject + */ + private $transactionResultMock; + + protected function setUp() + { + $this->transactionDetailsCommandMock = $this->createMock(CommandInterface::class); + $this->commandMock = $this->createMock(CommandInterface::class); + $this->transactionResultMock = $this->createMock(ResultInterface::class); + $this->commandPoolMock = $this->createMock(CommandPoolInterface::class); + $this->command = new AcceptPaymentStrategyCommand( + $this->commandPoolMock, + new SubjectReader() + ); + } + + /** + * @param string $status + * @dataProvider inReviewStatusesProvider + */ + public function testCommandWillAcceptInTheGatewayWhenInFDSReview(string $status) + { + // Assert command is executed + $this->commandMock->expects($this->once()) + ->method('execute'); + + $this->commandPoolMock->method('get') + ->willReturnMap([ + ['get_transaction_details', $this->transactionDetailsCommandMock], + ['accept_fds', $this->commandMock] + ]); + + $this->transactionResultMock->method('get') + ->willReturn([ + 'transaction' => [ + 'transactionStatus' => $status + ] + ]); + + $buildSubject = [ + 'foo' => '123' + ]; + + $this->transactionDetailsCommandMock->expects($this->once()) + ->method('execute') + ->with($buildSubject) + ->willReturn($this->transactionResultMock); + + $this->command->execute($buildSubject); + } + + public function testCommandWillDoNothingWhenTransactionHasAlreadyBeenAuthorized() + { + // Assert command is never executed + $this->commandMock->expects($this->never()) + ->method('execute'); + + $this->commandPoolMock->method('get') + ->willReturnMap([ + ['get_transaction_details', $this->transactionDetailsCommandMock], + ]); + + $this->transactionResultMock->method('get') + ->willReturn([ + 'transaction' => [ + 'transactionStatus' => 'anythingelseisfine' + ] + ]); + + $buildSubject = [ + 'foo' => '123' + ]; + + $this->transactionDetailsCommandMock->expects($this->once()) + ->method('execute') + ->with($buildSubject) + ->willReturn($this->transactionResultMock); + + $this->command->execute($buildSubject); + } + + public function inReviewStatusesProvider() + { + return [ + ['FDSPendingReview'], + ['FDSAuthorizedPendingReview'] + ]; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/CaptureStrategyCommandTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/CaptureStrategyCommandTest.php new file mode 100644 index 0000000000000..4cbded9764793 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/CaptureStrategyCommandTest.php @@ -0,0 +1,181 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Command; + +use Magento\AuthorizenetAcceptjs\Gateway\Command\CaptureStrategyCommand; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\Api\Search\SearchCriteria; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Payment\Gateway\Command\CommandPoolInterface; +use Magento\Payment\Gateway\Command\GatewayCommand; +use Magento\Payment\Gateway\Data\PaymentDataObject; +use Magento\Sales\Api\Data\TransactionSearchResultInterface; +use Magento\Sales\Api\TransactionRepositoryInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class CaptureStrategyCommandTest extends TestCase +{ + /** + * @var CaptureStrategyCommand + */ + private $strategyCommand; + + /** + * @var CommandPoolInterface|MockObject + */ + private $commandPoolMock; + + /** + * @var TransactionRepositoryInterface|MockObject + */ + private $transactionRepositoryMock; + + /** + * @var FilterBuilder|MockObject + */ + private $filterBuilderMock; + + /** + * @var SearchCriteriaBuilder|MockObject + */ + private $searchCriteriaBuilderMock; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var PaymentDataObject|MockObject + */ + private $paymentDOMock; + + /** + * @var GatewayCommand|MockObject + */ + private $commandMock; + + /** + * @var TransactionSearchResultInterface|MockObject + */ + private $transactionsResult; + + protected function setUp() + { + // Simple mocks + $this->paymentDOMock = $this->createMock(PaymentDataObject::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + $this->commandMock = $this->createMock(GatewayCommand::class); + $this->commandPoolMock = $this->createMock(CommandPoolInterface::class); + $this->searchCriteriaBuilderMock = $this->createMock(SearchCriteriaBuilder::class); + $this->transactionRepositoryMock = $this->createMock(TransactionRepositoryInterface::class); + + // The search criteria builder should return the criteria with the specified filters + $this->filterBuilderMock = $this->createMock(FilterBuilder::class); + // We aren't coupling the implementation to the test. The test only cares how the result is processed + $this->filterBuilderMock->method('setField') + ->willReturnSelf(); + $this->filterBuilderMock->method('setValue') + ->willReturnSelf(); + $searchCriteria = new SearchCriteria(); + $this->searchCriteriaBuilderMock->method('addFilters') + ->willReturnSelf(); + $this->searchCriteriaBuilderMock->method('create') + ->willReturn($searchCriteria); + // The transaction result can be customized per test to simulate different scenarios + $this->transactionsResult = $this->createMock(TransactionSearchResultInterface::class); + $this->transactionRepositoryMock->method('getList') + ->with($searchCriteria) + ->willReturn($this->transactionsResult); + + $this->strategyCommand = new CaptureStrategyCommand( + $this->commandPoolMock, + $this->transactionRepositoryMock, + $this->filterBuilderMock, + $this->searchCriteriaBuilderMock, + new SubjectReader() + ); + } + + public function testExecuteWillAuthorizeWhenNotAuthorizedAndNotCaptured() + { + $subject = ['payment' => $this->paymentDOMock]; + + // Hasn't been authorized + $this->paymentMock->method('getAuthorizationTransaction') + ->willReturn(false); + // Hasn't been captured + $this->transactionsResult->method('getTotalCount') + ->willReturn(0); + // Assert authorize command was used + $this->commandPoolMock->expects($this->once()) + ->method('get') + ->with('sale') + ->willReturn($this->commandMock); + // Assert execute was called and with correct data + $this->commandMock->expects($this->once()) + ->method('execute') + ->with($subject); + + $this->strategyCommand->execute($subject); + // Assertions are performed via mock expects above + } + + public function testExecuteWillAuthorizeAndCaptureWhenAlreadyCaptured() + { + $subject = ['payment' => $this->paymentDOMock]; + + // Already authorized + $this->paymentMock->method('getAuthorizationTransaction') + ->willReturn(true); + // And already captured + $this->transactionsResult->method('getTotalCount') + ->willReturn(1); + // Assert authorize command was used + $this->commandPoolMock->expects($this->once()) + ->method('get') + ->with('settle') + ->willReturn($this->commandMock); + // Assert execute was called and with correct data + $this->commandMock->expects($this->once()) + ->method('execute') + ->with($subject); + + $this->strategyCommand->execute($subject); + // Assertions are performed via mock expects above + } + + public function testExecuteWillCaptureWhenAlreadyAuthorizedButNotCaptured() + { + $subject = ['payment' => $this->paymentDOMock]; + + // Was already authorized + $this->paymentMock->method('getAuthorizationTransaction') + ->willReturn(true); + // But, hasn't been captured + $this->transactionsResult->method('getTotalCount') + ->willReturn(0); + // Assert authorize command was used + $this->commandPoolMock->expects($this->once()) + ->method('get') + ->with('settle') + ->willReturn($this->commandMock); + // Assert execute was called and with correct data + $this->commandMock->expects($this->once()) + ->method('execute') + ->with($subject); + + $this->strategyCommand->execute($subject); + // Assertions are performed via mock expects above + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/FetchTransactionInfoCommandTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/FetchTransactionInfoCommandTest.php new file mode 100644 index 0000000000000..757500c7e50eb --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/FetchTransactionInfoCommandTest.php @@ -0,0 +1,132 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Command; + +use Magento\AuthorizenetAcceptjs\Gateway\Command\FetchTransactionInfoCommand; +use Magento\AuthorizenetAcceptjs\Gateway\Config; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Command\CommandPoolInterface; +use Magento\Payment\Gateway\Command\ResultInterface; +use Magento\Payment\Gateway\CommandInterface; +use Magento\Payment\Gateway\Data\PaymentDataObject; +use Magento\Payment\Gateway\Response\HandlerInterface; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class FetchTransactionInfoCommandTest extends TestCase +{ + /** + * @var CommandInterface|MockObject + */ + private $transactionDetailsCommandMock; + + /** + * @var CommandPoolInterface|MockObject + */ + private $commandPoolMock; + + /** + * @var FetchTransactionInfoCommand + */ + private $command; + + /** + * @var ResultInterface|MockObject + */ + private $transactionResultMock; + + /** + * @var PaymentDataObject|MockObject + */ + private $paymentDOMock; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Config + */ + private $configMock; + + /** + * @var HandlerInterface + */ + private $handlerMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObject::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + $this->configMock = $this->createMock(Config::class); + $this->configMock->method('getTransactionInfoSyncKeys') + ->willReturn(['foo', 'bar']); + $orderMock = $this->createMock(Order::class); + $this->paymentDOMock->method('getOrder') + ->willReturn($orderMock); + $this->transactionDetailsCommandMock = $this->createMock(CommandInterface::class); + $this->transactionResultMock = $this->createMock(ResultInterface::class); + $this->commandPoolMock = $this->createMock(CommandPoolInterface::class); + $this->handlerMock = $this->createMock(HandlerInterface::class); + $this->command = new FetchTransactionInfoCommand( + $this->commandPoolMock, + new SubjectReader(), + $this->configMock, + $this->handlerMock + ); + } + + public function testCommandWillMarkTransactionAsApprovedWhenNotVoid() + { + $response = [ + 'transaction' => [ + 'transactionStatus' => 'authorizedPendingCapture', + 'foo' => 'abc', + 'bar' => 'cba', + 'dontreturnme' => 'justdont' + ] + ]; + + $this->commandPoolMock->method('get') + ->willReturnMap([ + ['get_transaction_details', $this->transactionDetailsCommandMock], + ]); + + $this->transactionResultMock->method('get') + ->willReturn($response); + + $buildSubject = [ + 'payment' => $this->paymentDOMock + ]; + + $this->transactionDetailsCommandMock->expects($this->once()) + ->method('execute') + ->with($buildSubject) + ->willReturn($this->transactionResultMock); + + $this->handlerMock->expects($this->once()) + ->method('handle') + ->with($buildSubject, $response) + ->willReturn($this->transactionResultMock); + + $result = $this->command->execute($buildSubject); + + $expected = [ + 'foo' => 'abc', + 'bar' => 'cba' + ]; + + $this->assertSame($expected, $result); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/GatewayQueryCommandTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/GatewayQueryCommandTest.php new file mode 100644 index 0000000000000..e37db34936385 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/GatewayQueryCommandTest.php @@ -0,0 +1,196 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Command; + +use Magento\AuthorizenetAcceptjs\Gateway\Command\GatewayQueryCommand; +use Magento\Payment\Gateway\Command\Result\ArrayResult; +use Magento\Payment\Gateway\Http\ClientInterface; +use Magento\Payment\Gateway\Http\TransferFactoryInterface; +use Magento\Payment\Gateway\Http\TransferInterface; +use Magento\Payment\Gateway\Request\BuilderInterface; +use Magento\Payment\Gateway\Validator\Result; +use Magento\Payment\Gateway\Validator\ValidatorInterface; +use PHPUnit\Framework\MockObject\Builder\InvocationMocker; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; + +class GatewayQueryCommandTest extends TestCase +{ + /** + * @var GatewayQueryCommand + */ + private $command; + + /** + * @var BuilderInterface|MockObject|InvocationMocker + */ + private $requestBuilderMock; + + /** + * @var TransferFactoryInterface|MockObject|InvocationMocker + */ + private $transferFactoryMock; + + /** + * @var ClientInterface|MockObject|InvocationMocker + */ + private $clientMock; + + /** + * @var LoggerInterface|MockObject|InvocationMocker + */ + private $loggerMock; + + /** + * @var ValidatorInterface|MockObject|InvocationMocker + */ + private $validatorMock; + + /** + * @var TransferInterface|MockObject|InvocationMocker + */ + private $transferMock; + + protected function setUp() + { + $this->requestBuilderMock = $this->createMock(BuilderInterface::class); + $this->transferFactoryMock = $this->createMock(TransferFactoryInterface::class); + $this->transferMock = $this->createMock(TransferInterface::class); + $this->clientMock = $this->createMock(ClientInterface::class); + $this->loggerMock = $this->createMock(LoggerInterface::class); + $this->validatorMock = $this->createMock(ValidatorInterface::class); + + $this->command = new GatewayQueryCommand( + $this->requestBuilderMock, + $this->transferFactoryMock, + $this->clientMock, + $this->loggerMock, + $this->validatorMock + ); + } + + public function testNormalExecution() + { + $buildSubject = [ + 'foo' => '123' + ]; + + $request = [ + 'bar' => '321' + ]; + + $response = [ + 'transaction' => [ + 'transactionType' => 'foo', + 'transactionStatus' => 'bar', + 'responseCode' => 'baz' + ] + ]; + + $validationSubject = $buildSubject; + $validationSubject['response'] = $response; + + $this->requestBuilderMock->method('build') + ->with($buildSubject) + ->willReturn($request); + + $this->transferFactoryMock->method('create') + ->with($request) + ->willReturn($this->transferMock); + + $this->clientMock->method('placeRequest') + ->with($this->transferMock) + ->willReturn($response); + + $this->validatorMock->method('validate') + ->with($validationSubject) + ->willReturn(new Result(true)); + + $result = $this->command->execute($buildSubject); + + $this->assertInstanceOf(ArrayResult::class, $result); + $this->assertEquals($response, $result->get()); + } + + /** + * @expectedExceptionMessage There was an error while trying to process the request. + * @expectedException \Magento\Payment\Gateway\Command\CommandException + */ + public function testExceptionIsThrownAndLoggedWhenRequestFails() + { + $buildSubject = [ + 'foo' => '123' + ]; + + $request = [ + 'bar' => '321' + ]; + + $this->requestBuilderMock->method('build') + ->with($buildSubject) + ->willReturn($request); + + $this->transferFactoryMock->method('create') + ->with($request) + ->willReturn($this->transferMock); + + $e = new \Exception('foobar'); + + $this->clientMock->method('placeRequest') + ->with($this->transferMock) + ->willThrowException($e); + + // assert the exception is logged + $this->loggerMock->expects($this->once()) + ->method('critical') + ->with($e); + + $this->command->execute($buildSubject); + } + /** + * @expectedExceptionMessage There was an error while trying to process the request. + * @expectedException \Magento\Payment\Gateway\Command\CommandException + */ + public function testExceptionIsThrownWhenResponseIsInvalid() + { + $buildSubject = [ + 'foo' => '123' + ]; + + $request = [ + 'bar' => '321' + ]; + + $response = [ + 'baz' => '456' + ]; + + $validationSubject = $buildSubject; + $validationSubject['response'] = $response; + + $this->requestBuilderMock->method('build') + ->with($buildSubject) + ->willReturn($request); + + $this->transferFactoryMock->method('create') + ->with($request) + ->willReturn($this->transferMock); + + $this->clientMock->method('placeRequest') + ->with($this->transferMock) + ->willReturn($response); + + $this->validatorMock->method('validate') + ->with($validationSubject) + ->willReturn(new Result(false)); + + $this->command->execute($buildSubject); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/RefundTransactionStrategyCommandTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/RefundTransactionStrategyCommandTest.php new file mode 100644 index 0000000000000..df6d89d7bc585 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Command/RefundTransactionStrategyCommandTest.php @@ -0,0 +1,153 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Command; + +use Magento\AuthorizenetAcceptjs\Gateway\Command\RefundTransactionStrategyCommand; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Command\CommandPoolInterface; +use Magento\Payment\Gateway\Command\ResultInterface; +use Magento\Payment\Gateway\CommandInterface; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class RefundTransactionStrategyCommandTest extends TestCase +{ + /** + * @var CommandInterface|MockObject + */ + private $commandMock; + + /** + * @var CommandInterface|MockObject + */ + private $transactionDetailsCommandMock; + + /** + * @var CommandPoolInterface|MockObject + */ + private $commandPoolMock; + + /** + * @var RefundTransactionStrategyCommand + */ + private $command; + + /** + * @var ResultInterface|MockObject + */ + private $transactionResultMock; + + protected function setUp() + { + $this->transactionDetailsCommandMock = $this->createMock(CommandInterface::class); + $this->commandMock = $this->createMock(CommandInterface::class); + $this->transactionResultMock = $this->createMock(ResultInterface::class); + $this->commandPoolMock = $this->createMock(CommandPoolInterface::class); + $this->command = new RefundTransactionStrategyCommand( + $this->commandPoolMock, + new SubjectReader() + ); + } + + public function testCommandWillVoidWhenTransactionIsPendingSettlement() + { + // Assert command is executed + $this->commandMock->expects($this->once()) + ->method('execute'); + + $this->commandPoolMock->method('get') + ->willReturnMap([ + ['get_transaction_details', $this->transactionDetailsCommandMock], + ['void', $this->commandMock] + ]); + + $this->transactionResultMock->method('get') + ->willReturn([ + 'transaction' => [ + 'transactionStatus' => 'capturedPendingSettlement' + ] + ]); + + $buildSubject = [ + 'foo' => '123' + ]; + + $this->transactionDetailsCommandMock->expects($this->once()) + ->method('execute') + ->with($buildSubject) + ->willReturn($this->transactionResultMock); + + $this->command->execute($buildSubject); + } + + public function testCommandWillRefundWhenTransactionIsSettled() + { + // Assert command is executed + $this->commandMock->expects($this->once()) + ->method('execute'); + + $this->commandPoolMock->method('get') + ->willReturnMap([ + ['get_transaction_details', $this->transactionDetailsCommandMock], + ['refund_settled', $this->commandMock] + ]); + + $this->transactionResultMock->method('get') + ->willReturn([ + 'transaction' => [ + 'transactionStatus' => 'settledSuccessfully' + ] + ]); + + $buildSubject = [ + 'foo' => '123' + ]; + + $this->transactionDetailsCommandMock->expects($this->once()) + ->method('execute') + ->with($buildSubject) + ->willReturn($this->transactionResultMock); + + $this->command->execute($buildSubject); + } + + /** + * @expectedException \Magento\Payment\Gateway\Command\CommandException + * @expectedExceptionMessage This transaction cannot be refunded with its current status. + */ + public function testCommandWillThrowExceptionWhenTransactionIsInInvalidState() + { + // Assert command is never executed + $this->commandMock->expects($this->never()) + ->method('execute'); + + $this->commandPoolMock->method('get') + ->willReturnMap([ + ['get_transaction_details', $this->transactionDetailsCommandMock], + ]); + + $this->transactionResultMock->method('get') + ->willReturn([ + 'transaction' => [ + 'transactionStatus' => 'somethingIsWrong' + ] + ]); + + $buildSubject = [ + 'foo' => '123' + ]; + + $this->transactionDetailsCommandMock->expects($this->once()) + ->method('execute') + ->with($buildSubject) + ->willReturn($this->transactionResultMock); + + $this->command->execute($buildSubject); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/ConfigTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/ConfigTest.php new file mode 100644 index 0000000000000..da2b953d843b1 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/ConfigTest.php @@ -0,0 +1,126 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway; + +use Magento\AuthorizenetAcceptjs\Gateway\Config; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Store\Model\ScopeInterface; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class ConfigTest extends TestCase +{ + /** + * @var Config + */ + private $model; + + /** + * @var ScopeConfigInterface|MockObject + */ + private $scopeConfigMock; + + protected function setUp() + { + $this->scopeConfigMock = $this->createMock(ScopeConfigInterface::class); + + $objectManager = new ObjectManager($this); + $this->model = $objectManager->getObject( + Config::class, + [ + 'scopeConfig' => $this->scopeConfigMock, + 'methodCode' => Config::METHOD, + ] + ); + } + + /** + * @param $getterName + * @param $configField + * @param $configValue + * @param $expectedValue + * @dataProvider configMapProvider + */ + public function testConfigGetters($getterName, $configField, $configValue, $expectedValue) + { + $this->scopeConfigMock->method('getValue') + ->with($this->getPath($configField), ScopeInterface::SCOPE_STORE, 123) + ->willReturn($configValue); + $this->assertEquals($expectedValue, $this->model->{$getterName}(123)); + } + + /** + * @dataProvider environmentUrlProvider + * @param $environment + * @param $expectedUrl + */ + public function testGetApiUrl($environment, $expectedUrl) + { + $this->scopeConfigMock->method('getValue') + ->with($this->getPath('environment'), ScopeInterface::SCOPE_STORE, 123) + ->willReturn($environment); + $this->assertEquals($expectedUrl, $this->model->getApiUrl(123)); + } + + /** + * @dataProvider environmentSolutionProvider + * @param $environment + * @param $expectedSolution + */ + public function testGetSolutionIdSandbox($environment, $expectedSolution) + { + $this->scopeConfigMock->method('getValue') + ->with($this->getPath('environment'), ScopeInterface::SCOPE_STORE, 123) + ->willReturn($environment); + $this->assertEquals($expectedSolution, $this->model->getSolutionId(123)); + } + + public function configMapProvider() + { + return [ + ['getLoginId', 'login', 'username', 'username'], + ['getEnvironment', 'environment', 'production', 'production'], + ['getClientKey', 'public_client_key', 'abc', 'abc'], + ['getTransactionKey', 'trans_key', 'password', 'password'], + ['getLegacyTransactionHash', 'trans_md5', 'abc123', 'abc123'], + ['getTransactionSignatureKey', 'trans_signature_key', 'abc123', 'abc123'], + ['getPaymentAction', 'payment_action', 'authorize', 'authorize'], + ['shouldEmailCustomer', 'email_customer', true, true], + ['isCvvEnabled', 'cvv_enabled', true, true], + ['getAdditionalInfoKeys', 'paymentInfoKeys', 'a,b,c', ['a', 'b', 'c']], + ['getTransactionInfoSyncKeys', 'transactionSyncKeys', 'a,b,c', ['a', 'b', 'c']], + ]; + } + public function environmentUrlProvider() + { + return [ + ['sandbox', 'https://apitest.authorize.net/xml/v1/request.api'], + ['production', 'https://api.authorize.net/xml/v1/request.api'], + ]; + } + + public function environmentSolutionProvider() + { + return [ + ['sandbox', 'AAA102993'], + ['production', 'AAA175350'], + ]; + } + + /** + * Return config path + * + * @param string $field + * @return string + */ + private function getPath($field) + { + return sprintf(Config::DEFAULT_PATH_PATTERN, Config::METHOD, $field); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Http/ClientTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Http/ClientTest.php new file mode 100644 index 0000000000000..4086195ff4c95 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Http/ClientTest.php @@ -0,0 +1,218 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Http; + +use Magento\AuthorizenetAcceptjs\Gateway\Http\Client; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\HTTP\ZendClientFactory; +use Magento\Framework\Serialize\Serializer\Json; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Payment\Gateway\Http\TransferInterface; +use Magento\Payment\Model\Method\Logger; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Zend_Http_Client; +use Zend_Http_Response; + +class ClientTest extends TestCase +{ + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var Logger + */ + private $paymentLogger; + + /** + * @var ZendClientFactory + */ + private $httpClientFactory; + + /** + * @var Zend_Http_Client + */ + private $httpClient; + + /** + * @var Zend_Http_Response + */ + private $httpResponse; + + /** + * @var LoggerInterface + */ + private $logger; + + protected function setUp() + { + $this->objectManager = new ObjectManager($this); + $this->paymentLogger = $this->createMock(Logger::class); + $this->httpClientFactory = $this->createMock(ZendClientFactory::class); + $this->httpClient = $this->createMock(Zend_Http_Client::class); + $this->httpResponse = $this->createMock(Zend_Http_Response::class); + $this->httpClientFactory->method('create')->will($this->returnValue($this->httpClient)); + $this->httpClient->method('request') + ->willReturn($this->httpResponse); + /** @var MockObject $logger */ + $this->logger = $this->createMock(LoggerInterface::class); + } + + public function testCanSendRequest() + { + // Assert the raw data was set on the client + $this->httpClient->expects($this->once()) + ->method('setRawData') + ->with( + '{"doSomeThing":{"foobar":"baz"}}', + 'application/json' + ); + + $request = [ + 'payload_type' => 'doSomeThing', + 'foobar' => 'baz' + ]; + // Authorize.net returns a BOM and refuses to fix it + $response = pack('CCC', 0xef, 0xbb, 0xbf) . '{"foo":{"bar":"baz"}}'; + + $this->httpResponse->method('getBody') + ->willReturn($response); + + // Assert the logger was given the data + $this->paymentLogger->expects($this->once()) + ->method('debug') + ->with(['request' => $request, 'response' => '{"foo":{"bar":"baz"}}']); + + /** + * @var $apiClient Client + */ + $apiClient = $this->objectManager->getObject(Client::class, [ + 'httpClientFactory' => $this->httpClientFactory, + 'paymentLogger' => $this->paymentLogger, + 'json' => new Json() + ]); + + $result = $apiClient->placeRequest($this->getTransferObjectMock($request)); + + $this->assertSame('baz', $result['foo']['bar']); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Something went wrong in the payment gateway. + */ + public function testExceptionIsThrownWhenEmptyResponseIsReceived() + { + // Assert the client has the raw data set + $this->httpClient->expects($this->once()) + ->method('setRawData') + ->with( + '{"doSomeThing":{"foobar":"baz"}}', + 'application/json' + ); + + $this->httpResponse->method('getBody') + ->willReturn(''); + + // Assert the exception is given to the logger + $this->logger->expects($this->once()) + ->method('critical') + ->with($this->callback(function ($e) { + return $e instanceof \Exception + && $e->getMessage() === 'Invalid JSON was returned by the gateway'; + })); + + $request = [ + 'payload_type' => 'doSomeThing', + 'foobar' => 'baz' + ]; + + // Assert the logger was given the data + $this->paymentLogger->expects($this->once()) + ->method('debug') + ->with(['request' => $request, 'response' => '']); + + /** + * @var $apiClient Client + */ + $apiClient = $this->objectManager->getObject(Client::class, [ + 'httpClientFactory' => $this->httpClientFactory, + 'paymentLogger' => $this->paymentLogger, + 'logger' => $this->logger, + 'json' => new Json() + ]); + + $apiClient->placeRequest($this->getTransferObjectMock($request)); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Something went wrong in the payment gateway. + */ + public function testExceptionIsThrownWhenInvalidResponseIsReceived() + { + // Assert the client was given the raw data + $this->httpClient->expects($this->once()) + ->method('setRawData') + ->with( + '{"doSomeThing":{"foobar":"baz"}}', + 'application/json' + ); + + $this->httpResponse->method('getBody') + ->willReturn('bad'); + + $request = [ + 'payload_type' => 'doSomeThing', + 'foobar' => 'baz' + ]; + + // Assert the logger was given the data + $this->paymentLogger->expects($this->once()) + ->method('debug') + ->with(['request' => $request, 'response' => 'bad']); + + // Assert the exception was given to the logger + $this->logger->expects($this->once()) + ->method('critical') + ->with($this->callback(function ($e) { + return $e instanceof \Exception + && $e->getMessage() === 'Invalid JSON was returned by the gateway'; + })); + + /** + * @var $apiClient Client + */ + $apiClient = $this->objectManager->getObject(Client::class, [ + 'httpClientFactory' => $this->httpClientFactory, + 'paymentLogger' => $this->paymentLogger, + 'logger' => $this->logger, + 'json' => new Json() + ]); + + $apiClient->placeRequest($this->getTransferObjectMock($request)); + } + + /** + * Creates mock object for TransferInterface. + * + * @return TransferInterface|MockObject + */ + private function getTransferObjectMock(array $data) + { + $transferObjectMock = $this->createMock(TransferInterface::class); + $transferObjectMock->method('getBody') + ->willReturn($data); + + return $transferObjectMock; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Http/Payload/Filter/RemoveFieldsFilterTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Http/Payload/Filter/RemoveFieldsFilterTest.php new file mode 100644 index 0000000000000..bcc6279f5b1fe --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Http/Payload/Filter/RemoveFieldsFilterTest.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Http\Payload\Filter; + +use Magento\AuthorizenetAcceptjs\Gateway\Http\Payload\Filter\RemoveFieldsFilter; +use PHPUnit\Framework\TestCase; + +class RemoveFieldsFilterTest extends TestCase +{ + public function testFilterRemovesFields() + { + $filter = new RemoveFieldsFilter(['foo', 'bar']); + + $actual = $filter->filter([ + 'some' => 123, + 'data' => 321, + 'foo' => 'to', + 'filter' => ['blah'], + 'bar' => 'fields from' + ]); + + $expected = [ + 'some' => 123, + 'data' => 321, + 'filter' => ['blah'], + ]; + + $this->assertEquals($expected, $actual); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Http/TransferFactoryTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Http/TransferFactoryTest.php new file mode 100644 index 0000000000000..954fd9782bd3f --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Http/TransferFactoryTest.php @@ -0,0 +1,73 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Http; + +use Magento\AuthorizenetAcceptjs\Gateway\Http\Payload\Filter\RemoveFieldsFilter; +use Magento\AuthorizenetAcceptjs\Gateway\Http\TransferFactory; +use Magento\Payment\Gateway\Http\TransferBuilder; +use Magento\Payment\Gateway\Http\TransferInterface; +use Magento\AuthorizenetAcceptjs\Gateway\Http\Payload\FilterInterface; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class TransferFactoryTest extends TestCase +{ + /** + * @var TransferFactory + */ + private $transferFactory; + + /** + * @var TransferFactory + */ + private $transferMock; + + /** + * @var TransferBuilder|MockObject + */ + private $transferBuilder; + + /** + * @var FilterInterface|MockObject + */ + private $filterMock; + + protected function setUp() + { + $this->transferBuilder = $this->createMock(TransferBuilder::class); + $this->transferMock = $this->createMock(TransferInterface::class); + $this->filterMock = $this->createMock(RemoveFieldsFilter::class); + + $this->transferFactory = new TransferFactory( + $this->transferBuilder, + [$this->filterMock] + ); + } + + public function testCreate() + { + $request = ['data1', 'data2']; + + // Assert the filter was created + $this->filterMock->expects($this->once()) + ->method('filter') + ->with($request) + ->willReturn($request); + + // Assert the body of the transfer was set + $this->transferBuilder->expects($this->once()) + ->method('setBody') + ->with($request) + ->willReturnSelf(); + + $this->transferBuilder->method('build') + ->willReturn($this->transferMock); + + $this->assertEquals($this->transferMock, $this->transferFactory->create($request)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AcceptFdsDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AcceptFdsDataBuilderTest.php new file mode 100644 index 0000000000000..00bb7ee84f98b --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AcceptFdsDataBuilderTest.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\AcceptFdsDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Sales\Model\Order\Payment\Transaction; +use PHPUnit\Framework\TestCase; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; + +class AcceptFdsDataBuilderTest extends TestCase +{ + /** + * @var AcceptFdsDataBuilder + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->orderMock = $this->createMock(Order::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + + $this->builder = new AcceptFdsDataBuilder(new SubjectReader()); + } + + public function testBuild() + { + $transactionMock = $this->createMock(Transaction::class); + + $this->paymentMock->method('getAuthorizationTransaction') + ->willReturn($transactionMock); + + $transactionMock->method('getTxnId') + ->willReturn('foo'); + + $expected = [ + 'heldTransactionRequest' => [ + 'action' => 'approve', + 'refTransId' => 'foo' + ] + ]; + + $buildSubject = [ + 'payment' => $this->paymentDOMock, + ]; + + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AddressDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AddressDataBuilderTest.php new file mode 100644 index 0000000000000..6ddb30a64af96 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AddressDataBuilderTest.php @@ -0,0 +1,129 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\AddressDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\AddressAdapterInterface; +use Magento\Payment\Gateway\Data\OrderAdapterInterface; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class AddressDataBuilderTest extends TestCase +{ + /** + * @var AddressDataBuilder + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var PaymentDataObjectInterface|MockObject + */ + private $paymentDOMock; + + /** + * @var OrderAdapterInterface|MockObject + */ + private $orderMock; + + private $mockAddressData = [ + 'firstName' => [ + 'method' => 'getFirstname', + 'sampleData' => 'John' + ], + 'lastName' => [ + 'method' => 'getLastname', + 'sampleData' => 'Doe' + ], + 'company' => [ + 'method' => 'getCompany', + 'sampleData' => 'Magento' + ], + 'address' => [ + 'method' => 'getStreetLine1', + 'sampleData' => '11501 Domain Dr' + ], + 'city' => [ + 'method' => 'getCity', + 'sampleData' => 'Austin' + ], + 'state' => [ + 'method' => 'getRegionCode', + 'sampleData' => 'TX' + ], + 'zip' => [ + 'method' => 'getPostcode', + 'sampleData' => '78758' + ], + 'country' => [ + 'method' => 'getCountryId', + 'sampleData' => 'US' + ], + ]; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + $this->orderMock = $this->createMock(OrderAdapterInterface::class); + $this->paymentDOMock->method('getOrder') + ->willReturn($this->orderMock); + + $this->builder = new AddressDataBuilder(new SubjectReader()); + } + + public function testBuildWithBothAddresses() + { + $billingAddress = $this->createAddressMock('billing'); + $shippingAddress = $this->createAddressMock('shipping'); + $this->orderMock->method('getBillingAddress') + ->willReturn($billingAddress); + $this->orderMock->method('getShippingAddress') + ->willReturn($shippingAddress); + $this->orderMock->method('getRemoteIp') + ->willReturn('abc'); + + $buildSubject = [ + 'payment' => $this->paymentDOMock + ]; + + $result = $this->builder->build($buildSubject); + + $this->validateAddressData($result['transactionRequest']['billTo'], 'billing'); + $this->validateAddressData($result['transactionRequest']['shipTo'], 'shipping'); + $this->assertEquals('abc', $result['transactionRequest']['customerIP']); + } + + private function validateAddressData($responseData, $addressPrefix) + { + foreach ($this->mockAddressData as $fieldValue => $field) { + $this->assertEquals($addressPrefix . $field['sampleData'], $responseData[$fieldValue]); + } + } + + private function createAddressMock($prefix) + { + $addressAdapterMock = $this->createMock(AddressAdapterInterface::class); + + foreach ($this->mockAddressData as $field) { + $addressAdapterMock->method($field['method']) + ->willReturn($prefix . $field['sampleData']); + } + + return $addressAdapterMock; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AmountDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AmountDataBuilderTest.php new file mode 100644 index 0000000000000..9da0139302a30 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AmountDataBuilderTest.php @@ -0,0 +1,42 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\AmountDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use PHPUnit\Framework\TestCase; + +class AmountDataBuilderTest extends TestCase +{ + /** + * @var AmountDataBuilder + */ + private $builder; + + protected function setUp() + { + $this->builder = new AmountDataBuilder( + new SubjectReader() + ); + } + + public function testBuild() + { + $expected = [ + 'transactionRequest' => [ + 'amount' => '123.45', + ] + ]; + + $buildSubject = [ + 'amount' => 123.45 + ]; + + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AuthenticationDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AuthenticationDataBuilderTest.php new file mode 100644 index 0000000000000..e9588e51b0fc8 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AuthenticationDataBuilderTest.php @@ -0,0 +1,78 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Config; +use Magento\AuthorizenetAcceptjs\Gateway\Request\AuthenticationDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class AuthenticationDataBuilderTest extends TestCase +{ + /** + * @var AuthenticationDataBuilder + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + /** + * @var SubjectReader|MockObject + */ + private $subjectReaderMock; + + /** + * @var Config|MockObject + */ + private $configMock; + + protected function setUp() + { + $this->configMock = $this->createMock(Config::class); + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + /** @var MockObject|SubjectReader subjectReaderMock */ + $this->subjectReaderMock = $this->createMock(SubjectReader::class); + + $this->builder = new AuthenticationDataBuilder($this->subjectReaderMock, $this->configMock); + } + + public function testBuild() + { + $this->configMock->method('getLoginId') + ->willReturn('myloginid'); + $this->configMock->method('getTransactionKey') + ->willReturn('mytransactionkey'); + + $expected = [ + 'merchantAuthentication' => [ + 'name' => 'myloginid', + 'transactionKey' => 'mytransactionkey' + ] + ]; + + $buildSubject = []; + + $this->subjectReaderMock->method('readStoreId') + ->with($buildSubject) + ->willReturn(123); + + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AuthorizationDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AuthorizationDataBuilderTest.php new file mode 100644 index 0000000000000..438d681a2b5b2 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/AuthorizationDataBuilderTest.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\AuthorizeDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\AuthorizenetAcceptjs\Model\PassthroughDataObject; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class AuthorizationDataBuilderTest extends TestCase +{ + /** + * @var AuthorizeDataBuilder + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + /** + * @var PassthroughDataObject + */ + private $passthroughData; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + $this->passthroughData = new PassthroughDataObject(); + + $this->builder = new AuthorizeDataBuilder( + new SubjectReader(), + $this->passthroughData + ); + } + + public function testBuildWillAddTransactionType() + { + $expected = [ + 'transactionRequest' => [ + 'transactionType' => 'authOnlyTransaction' + ] + ]; + + $buildSubject = [ + 'store_id' => 123, + 'payment' => $this->paymentDOMock, + ]; + + $this->assertEquals($expected, $this->builder->build($buildSubject)); + $this->assertEquals('authOnlyTransaction', $this->passthroughData->getData('transactionType')); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/CaptureDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/CaptureDataBuilderTest.php new file mode 100644 index 0000000000000..537a685f1ff7f --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/CaptureDataBuilderTest.php @@ -0,0 +1,77 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\CaptureDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\AuthorizenetAcceptjs\Model\PassthroughDataObject; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class CaptureDataBuilderTest extends TestCase +{ + /** + * @var CaptureDataBuilder + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + /** + * @var PassthroughDataObject + */ + private $passthroughData; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + $this->passthroughData = new PassthroughDataObject(); + + $this->builder = new CaptureDataBuilder( + new SubjectReader(), + $this->passthroughData + ); + } + + public function testBuildWillCaptureWhenAuthorizeTransactionExists() + { + $transactionMock = $this->createMock(Payment\Transaction::class); + $transactionMock->method('getAdditionalInformation') + ->with('real_transaction_id') + ->willReturn('prevtrans'); + $this->paymentMock->method('getAuthorizationTransaction') + ->willReturn($transactionMock); + + $expected = [ + 'transactionRequest' => [ + 'transactionType' => 'priorAuthCaptureTransaction', + 'refTransId' => 'prevtrans' + ] + ]; + + $buildSubject = [ + 'payment' => $this->paymentDOMock, + ]; + + $this->assertEquals($expected, $this->builder->build($buildSubject)); + $this->assertEquals('priorAuthCaptureTransaction', $this->passthroughData->getData('transactionType')); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/CustomSettingsBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/CustomSettingsBuilderTest.php new file mode 100644 index 0000000000000..be7dd7eca1761 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/CustomSettingsBuilderTest.php @@ -0,0 +1,74 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Config; +use Magento\AuthorizenetAcceptjs\Gateway\Request\CustomSettingsBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class CustomSettingsBuilderTest extends TestCase +{ + /** + * @var CustomSettingsBuilder + */ + private $builder; + + /** + * @var SubjectReader|MockObject + */ + private $subjectReaderMock; + + /** + * @var Config|MockObject + */ + private $configMock; + + protected function setUp() + { + $this->configMock = $this->createMock(Config::class); + /** @var MockObject|SubjectReader subjectReaderMock */ + $this->subjectReaderMock = $this->createMock(SubjectReader::class); + $this->subjectReaderMock->method('readStoreId') + ->willReturn('123'); + + $this->builder = new CustomSettingsBuilder($this->subjectReaderMock, $this->configMock); + } + + public function testBuildWithEmailCustomerDisabled() + { + $this->configMock->method('shouldEmailCustomer') + ->with('123') + ->willReturn(false); + + $this->assertEquals([], $this->builder->build([])); + } + + public function testBuildWithEmailCustomerEnabled() + { + $this->configMock->method('shouldEmailCustomer') + ->with('123') + ->willReturn(true); + + $expected = [ + 'transactionRequest' => [ + 'transactionSettings' => [ + 'setting' => [ + [ + 'settingName' => 'emailCustomer', + 'settingValue' => 'true' + ] + ] + ] + ] + ]; + + $this->assertEquals($expected, $this->builder->build([])); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/CustomerDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/CustomerDataBuilderTest.php new file mode 100644 index 0000000000000..7c9116cad54b1 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/CustomerDataBuilderTest.php @@ -0,0 +1,79 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\CustomerDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\AddressAdapterInterface; +use Magento\Payment\Gateway\Data\OrderAdapterInterface; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class CustomerDataBuilderTest extends TestCase +{ + /** + * @var CustomerDataBuilder + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + /** + * @var OrderAdapterInterface|MockObject + */ + private $orderMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + $this->orderMock = $this->createMock(OrderAdapterInterface::class); + $this->paymentDOMock->method('getOrder') + ->willReturn($this->orderMock); + + $this->builder = new CustomerDataBuilder(new SubjectReader()); + } + + public function testBuild() + { + $addressAdapterMock = $this->createMock(AddressAdapterInterface::class); + $addressAdapterMock->method('getEmail') + ->willReturn('foo@bar.com'); + $this->orderMock->method('getBillingAddress') + ->willReturn($addressAdapterMock); + $this->orderMock->method('getCustomerId') + ->willReturn('123'); + + $expected = [ + 'transactionRequest' => [ + 'customer' => [ + 'id' => '123', + 'email' => 'foo@bar.com' + ] + ] + ]; + + $buildSubject = [ + 'payment' => $this->paymentDOMock, + ]; + + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/OrderDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/OrderDataBuilderTest.php new file mode 100644 index 0000000000000..d66421d48ca8b --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/OrderDataBuilderTest.php @@ -0,0 +1,74 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\OrderDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Payment\Model\InfoInterface; +use Magento\Payment\Gateway\Data\OrderAdapterInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class OrderDataBuilderTest extends TestCase +{ + /** + * @var OrderDataBuilder + */ + private $builder; + + /** + * @var InfoInterface|MockObject + */ + private $paymentMock; + + /** + * @var PaymentDataObjectInterface|MockObject + */ + private $paymentDOMock; + + /** + * @var OrderAdapterInterface|MockObject + */ + private $orderMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + $this->orderMock = $this->createMock(OrderAdapterInterface::class); + $this->paymentDOMock->method('getOrder') + ->willReturn($this->orderMock); + + $this->builder = new OrderDataBuilder(new SubjectReader()); + } + + public function testBuild() + { + $this->orderMock->method('getOrderIncrementId') + ->willReturn('10000015'); + + $expected = [ + 'transactionRequest' => [ + 'order' => [ + 'invoiceNumber' => '10000015' + ] + ] + ]; + + $buildSubject = [ + 'payment' => $this->paymentDOMock, + 'order' => $this->orderMock, + ]; + + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/PassthroughDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/PassthroughDataBuilderTest.php new file mode 100644 index 0000000000000..f4c5f56efe890 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/PassthroughDataBuilderTest.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\PassthroughDataBuilder; +use Magento\AuthorizenetAcceptjs\Model\PassthroughDataObject; +use PHPUnit\Framework\TestCase; + +class PassthroughDataBuilderTest extends TestCase +{ + public function testBuild() + { + $passthroughData = new PassthroughDataObject([ + 'foo' => 'bar', + 'baz' => 'bash' + ]); + $builder = new PassthroughDataBuilder($passthroughData); + + $expected = [ + 'transactionRequest' => [ + 'userFields' => [ + 'userField' => [ + [ + 'name' => 'foo', + 'value' => 'bar' + ], + [ + 'name' => 'baz', + 'value' => 'bash' + ], + ] + ] + ] + ]; + + $this->assertEquals($expected, $builder->build([])); + } + + public function testBuildWithNoData() + { + $passthroughData = new PassthroughDataObject(); + $builder = new PassthroughDataBuilder($passthroughData); + $expected = []; + + $this->assertEquals($expected, $builder->build([])); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/PaymentDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/PaymentDataBuilderTest.php new file mode 100644 index 0000000000000..cf3842b8947bb --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/PaymentDataBuilderTest.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\PaymentDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class PaymentDataBuilderTest extends TestCase +{ + /** + * @var PaymentDataBuilder + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->orderMock = $this->createMock(Order::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + + $this->builder = new PaymentDataBuilder(new SubjectReader()); + } + + public function testBuild() + { + $this->paymentMock->method('getAdditionalInformation') + ->willReturnMap([ + ['opaqueDataDescriptor', 'foo'], + ['opaqueDataValue', 'bar'] + ]); + + $expected = [ + 'transactionRequest' => [ + 'payment' => [ + 'opaqueData' => [ + 'dataDescriptor' => 'foo', + 'dataValue' => 'bar' + ] + ] + ] + ]; + + $buildSubject = [ + 'payment' => $this->paymentDOMock, + 'amount' => 123.45 + ]; + + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/PoDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/PoDataBuilderTest.php new file mode 100644 index 0000000000000..97b51c1e1807c --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/PoDataBuilderTest.php @@ -0,0 +1,61 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\PoDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Payment\Model\InfoInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class PoDataBuilderTest extends TestCase +{ + /** + * @var PoDataBuilder + */ + private $builder; + + /** + * @var InfoInterface|MockObject + */ + private $paymentMock; + + /** + * @var PaymentDataObjectInterface|MockObject + */ + private $paymentDOMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + + $this->builder = new PoDataBuilder(new SubjectReader()); + } + + public function testBuild() + { + $this->paymentMock->method('getPoNumber') + ->willReturn('abc'); + + $expected = [ + 'transactionRequest' => [ + 'poNumber' => 'abc' + ] + ]; + + $buildSubject = [ + 'payment' => $this->paymentDOMock, + ]; + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/RefundPaymentDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/RefundPaymentDataBuilderTest.php new file mode 100644 index 0000000000000..c1879b3df83a3 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/RefundPaymentDataBuilderTest.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\RefundPaymentDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class RefundPaymentDataBuilderTest extends TestCase +{ + /** + * @var RefundPaymentDataBuilder + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + + $this->builder = new RefundPaymentDataBuilder( + new SubjectReader() + ); + } + + public function testBuild() + { + $this->paymentMock->method('getAdditionalInformation') + ->with('ccLast4') + ->willReturn('1111'); + + $expected = [ + 'transactionRequest' => [ + 'payment' => [ + 'creditCard' => [ + 'cardNumber' => '1111', + 'expirationDate' => 'XXXX' + ] + ] + ] + ]; + + $buildSubject = [ + 'payment' => $this->paymentDOMock, + 'amount' => 123.45 + ]; + + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/RefundReferenceTransactionDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/RefundReferenceTransactionDataBuilderTest.php new file mode 100644 index 0000000000000..cf1803005acee --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/RefundReferenceTransactionDataBuilderTest.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\RefundReferenceTransactionDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Sales\Model\Order\Payment\Transaction; +use PHPUnit\Framework\TestCase; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; + +class RefundReferenceTransactionDataBuilderTest extends TestCase +{ + /** + * @var RefundReferenceTransactionDataBuilder + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->orderMock = $this->createMock(Order::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + + $this->builder = new RefundReferenceTransactionDataBuilder(new SubjectReader()); + } + + public function testBuild() + { + $transactionMock = $this->createMock(Transaction::class); + + $this->paymentMock->method('getAuthorizationTransaction') + ->willReturn($transactionMock); + + $transactionMock->method('getParentTxnId') + ->willReturn('foo'); + + $expected = [ + 'transactionRequest' => [ + 'refTransId' => 'foo' + ] + ]; + + $buildSubject = [ + 'payment' => $this->paymentDOMock, + ]; + + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/RefundTransactionTypeDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/RefundTransactionTypeDataBuilderTest.php new file mode 100644 index 0000000000000..4e0f5f75fb944 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/RefundTransactionTypeDataBuilderTest.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\RefundTransactionTypeDataBuilder; +use PHPUnit\Framework\TestCase; + +class RefundTransactionTypeDataBuilderTest extends TestCase +{ + private const REQUEST_TYPE_REFUND = 'refundTransaction'; + + public function testBuild() + { + $builder = new RefundTransactionTypeDataBuilder(); + + $expected = [ + 'transactionRequest' => [ + 'transactionType' => self::REQUEST_TYPE_REFUND + ] + ]; + + $this->assertEquals($expected, $builder->build([])); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/RequestTypeBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/RequestTypeBuilderTest.php new file mode 100644 index 0000000000000..cb03dfc3dac5e --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/RequestTypeBuilderTest.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\AuthenticationDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\Request\RequestTypeBuilder; +use PHPUnit\Framework\TestCase; + +class RequestTypeBuilderTest extends TestCase +{ + /** + * @var AuthenticationDataBuilder + */ + private $builder; + + protected function setUp() + { + $this->builder = new RequestTypeBuilder('foo'); + } + + public function testBuild() + { + $expected = [ + 'payload_type' => 'foo' + ]; + + $buildSubject = []; + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/SaleDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/SaleDataBuilderTest.php new file mode 100644 index 0000000000000..407b9bc85a2c5 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/SaleDataBuilderTest.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\SaleDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\AuthorizenetAcceptjs\Model\PassthroughDataObject; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class SaleDataBuilderTest extends TestCase +{ + /** + * @var SaleDataBuilder + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + /** + * @var PassthroughDataObject + */ + private $passthroughData; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + $this->passthroughData = new PassthroughDataObject(); + + $this->builder = new SaleDataBuilder( + new SubjectReader(), + $this->passthroughData + ); + } + + public function testBuildWillAddTransactionType() + { + $expected = [ + 'transactionRequest' => [ + 'transactionType' => 'authCaptureTransaction' + ] + ]; + + $buildSubject = [ + 'store_id' => 123, + 'payment' => $this->paymentDOMock, + ]; + + $this->assertEquals($expected, $this->builder->build($buildSubject)); + $this->assertEquals('authCaptureTransaction', $this->passthroughData->getData('transactionType')); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/ShippingDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/ShippingDataBuilderTest.php new file mode 100644 index 0000000000000..d6525e610a285 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/ShippingDataBuilderTest.php @@ -0,0 +1,75 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\ShippingDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class ShippingDataBuilderTest extends TestCase +{ + /** + * @var v + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + /** + * @var Order + */ + private $orderMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->orderMock = $this->createMock(Order::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + $this->paymentDOMock->method('getOrder') + ->willReturn($this->orderMock); + + $this->builder = new ShippingDataBuilder( + new SubjectReader() + ); + } + + public function testBuild() + { + $this->orderMock->method('getBaseShippingAmount') + ->willReturn('43.12'); + + $expected = [ + 'transactionRequest' => [ + 'shipping' => [ + 'amount' => '43.12' + ] + ] + ]; + + $buildSubject = [ + 'payment' => $this->paymentDOMock, + 'order' => $this->orderMock, + ]; + + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/SolutionDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/SolutionDataBuilderTest.php new file mode 100644 index 0000000000000..1b06546c2ea8f --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/SolutionDataBuilderTest.php @@ -0,0 +1,75 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Config; +use Magento\AuthorizenetAcceptjs\Gateway\Request\SolutionDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class SolutionDataBuilderTest extends TestCase +{ + /** + * @var SolutionDataBuilder + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + /** + * @var SubjectReader|MockObject + */ + private $subjectReaderMock; + + /** + * @var Config|MockObject + */ + private $configMock; + + protected function setUp() + { + $this->configMock = $this->createMock(Config::class); + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + /** @var MockObject|SubjectReader subjectReaderMock */ + $this->subjectReaderMock = $this->createMock(SubjectReader::class); + + $this->builder = new SolutionDataBuilder($this->subjectReaderMock, $this->configMock); + } + + public function testBuild() + { + $this->subjectReaderMock->method('readStoreId') + ->willReturn('123'); + $this->configMock->method('getSolutionId') + ->with('123') + ->willReturn('solutionid'); + + $expected = [ + 'transactionRequest' => [ + 'solution' => [ + 'id' => 'solutionid', + ] + ] + ]; + + $buildSubject = []; + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/StoreConfigBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/StoreConfigBuilderTest.php new file mode 100644 index 0000000000000..2ed0cb13ed624 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/StoreConfigBuilderTest.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\StoreConfigBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Payment\Model\InfoInterface; +use Magento\Payment\Gateway\Data\OrderAdapterInterface; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class StoreConfigBuilderTest extends TestCase +{ + /** + * @var StoreConfigBuilder + */ + private $builder; + + /** + * @var InfoInterface|MockObject + */ + private $paymentMock; + + /** + * @var PaymentDataObjectInterface|MockObject + */ + private $paymentDOMock; + + /** + * @var OrderAdapterInterface|MockObject + */ + private $orderMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(InfoInterface::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + $this->orderMock = $this->createMock(OrderAdapterInterface::class); + $this->paymentDOMock->method('getOrder') + ->willReturn($this->orderMock); + + $this->builder = new StoreConfigBuilder(new SubjectReader()); + } + + public function testBuild() + { + $this->orderMock->method('getStoreID') + ->willReturn(123); + + $expected = [ + 'store_id' => 123 + ]; + + $buildSubject = [ + 'payment' => $this->paymentDOMock, + ]; + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/TransactionDetailsDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/TransactionDetailsDataBuilderTest.php new file mode 100644 index 0000000000000..03c036c027147 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/TransactionDetailsDataBuilderTest.php @@ -0,0 +1,89 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\TransactionDetailsDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Sales\Model\Order\Payment\Transaction; +use PHPUnit\Framework\TestCase; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; + +class TransactionDetailsDataBuilderTest extends TestCase +{ + /** + * @var TransactionDetailsDataBuilder + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->orderMock = $this->createMock(Order::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + + $this->builder = new TransactionDetailsDataBuilder(new SubjectReader()); + } + + public function testBuild() + { + $transactionMock = $this->createMock(Transaction::class); + + $this->paymentMock->method('getAuthorizationTransaction') + ->willReturn($transactionMock); + + $transactionMock->method('getParentTxnId') + ->willReturn('foo'); + + $expected = [ + 'transId' => 'foo' + ]; + + $buildSubject = [ + 'payment' => $this->paymentDOMock, + ]; + + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } + + public function testBuildWithIncludedTransactionId() + { + $transactionMock = $this->createMock(Transaction::class); + + $this->paymentMock->expects($this->never()) + ->method('getAuthorizationTransaction'); + + $transactionMock->expects($this->never()) + ->method('getParentTxnId'); + + $expected = [ + 'transId' => 'foo' + ]; + + $buildSubject = [ + 'payment' => $this->paymentDOMock, + 'transactionId' => 'foo' + ]; + + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/VoidDataBuilderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/VoidDataBuilderTest.php new file mode 100644 index 0000000000000..84460a1c744b9 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Request/VoidDataBuilderTest.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Request; + +use Magento\AuthorizenetAcceptjs\Gateway\Request\VoidDataBuilder; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order\Payment; +use Magento\Sales\Model\Order\Payment\Transaction; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class VoidDataBuilderTest extends TestCase +{ + private const REQUEST_TYPE_VOID = 'voidTransaction'; + + /** + * @var VoidDataBuilder + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + + $this->builder = new VoidDataBuilder(new SubjectReader()); + } + + public function testBuild() + { + $transactionMock = $this->createMock(Transaction::class); + $this->paymentMock->method('getAuthorizationTransaction') + ->willReturn($transactionMock); + $transactionMock->method('getParentTxnId') + ->willReturn('myref'); + + $buildSubject = [ + 'payment' => $this->paymentDOMock + ]; + + $expected = [ + 'transactionRequest' => [ + 'transactionType' => self::REQUEST_TYPE_VOID, + 'refTransId' => 'myref', + ] + ]; + $this->assertEquals($expected, $this->builder->build($buildSubject)); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/CloseParentTransactionHandlerTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/CloseParentTransactionHandlerTest.php new file mode 100644 index 0000000000000..e9929c631eb15 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/CloseParentTransactionHandlerTest.php @@ -0,0 +1,62 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Response; + +use Magento\AuthorizenetAcceptjs\Gateway\Response\CloseParentTransactionHandler; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Payment\Model\InfoInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class CloseParentTransactionHandlerTest extends TestCase +{ + /** + * @var CloseParentTransactionHandler + */ + private $handler; + + /** + * @var InfoInterface|MockObject + */ + private $paymentMock; + + /** + * @var PaymentDataObjectInterface|MockObject + */ + private $paymentDOMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + + $this->handler = new CloseParentTransactionHandler(new SubjectReader()); + } + + public function testHandleClosesTransactionByDefault() + { + $subject = [ + 'payment' => $this->paymentDOMock + ]; + $response = [ + 'transactionResponse' => [] + ]; + + // Assert the parent transaction i closed + $this->paymentMock->expects($this->once()) + ->method('setShouldCloseParentTransaction') + ->with(true); + + $this->handler->handle($subject, $response); + // Assertions are via mock expects above + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/CloseTransactionHandlerTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/CloseTransactionHandlerTest.php new file mode 100644 index 0000000000000..a7093f0dac889 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/CloseTransactionHandlerTest.php @@ -0,0 +1,62 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Response; + +use Magento\AuthorizenetAcceptjs\Gateway\Response\CloseTransactionHandler; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Payment\Model\InfoInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class CloseTransactionHandlerTest extends TestCase +{ + /** + * @var CloseTransactionHandler + */ + private $handler; + + /** + * @var InfoInterface|MockObject + */ + private $paymentMock; + + /** + * @var PaymentDataObjectInterface|MockObject + */ + private $paymentDOMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + + $this->handler = new CloseTransactionHandler(new SubjectReader()); + } + + public function testHandleClosesTransactionByDefault() + { + $subject = [ + 'payment' => $this->paymentDOMock + ]; + $response = [ + 'transactionResponse' => [] + ]; + + // Assert the transaction is closed + $this->paymentMock->expects($this->once()) + ->method('setIsTransactionClosed') + ->with(true); + + $this->handler->handle($subject, $response); + // Assertions are via mock expects above + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/PaymentResponseHandlerTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/PaymentResponseHandlerTest.php new file mode 100644 index 0000000000000..d051c7d2910a5 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/PaymentResponseHandlerTest.php @@ -0,0 +1,112 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Response; + +use Magento\AuthorizenetAcceptjs\Gateway\Response\PaymentResponseHandler; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class PaymentResponseHandlerTest extends TestCase +{ + private const RESPONSE_CODE_APPROVED = 1; + private const RESPONSE_CODE_HELD = 4; + + /** + * @var PaymentResponseHandler + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + + $this->builder = new PaymentResponseHandler(new SubjectReader()); + } + + public function testHandleDefaultResponse() + { + $this->paymentMock->method('getAdditionalInformation') + ->with('ccLast4') + ->willReturn('1234'); + // Assert the avs code is saved + $this->paymentMock->expects($this->once()) + ->method('setCcAvsStatus') + ->with('avshurray'); + $this->paymentMock->expects($this->once()) + ->method('setCcLast4') + ->with('1234'); + $this->paymentMock->expects($this->once()) + ->method('setIsTransactionClosed') + ->with(false); + + $response = [ + 'transactionResponse' => [ + 'avsResultCode' => 'avshurray', + 'responseCode' => self::RESPONSE_CODE_APPROVED, + ] + ]; + $subject = [ + 'payment' => $this->paymentDOMock + ]; + + $this->builder->handle($subject, $response); + // Assertions are part of mocking above + } + + public function testHandleHeldResponse() + { + // Assert the avs code is saved + $this->paymentMock->expects($this->once()) + ->method('setCcAvsStatus') + ->with('avshurray'); + $this->paymentMock->expects($this->once()) + ->method('setIsTransactionClosed') + ->with(false); + // opaque data wasn't provided + $this->paymentMock->expects($this->never()) + ->method('setAdditionalInformation'); + // Assert the payment is flagged for review + $this->paymentMock->expects($this->once()) + ->method('setIsTransactionPending') + ->with(true) + ->willReturnSelf(); + $this->paymentMock->expects($this->once()) + ->method('setIsFraudDetected') + ->with(true); + + $response = [ + 'transactionResponse' => [ + 'avsResultCode' => 'avshurray', + 'responseCode' => self::RESPONSE_CODE_HELD, + ] + ]; + $subject = [ + 'payment' => $this->paymentDOMock + ]; + + $this->builder->handle($subject, $response); + // Assertions are part of mocking above + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/PaymentReviewStatusHandlerTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/PaymentReviewStatusHandlerTest.php new file mode 100644 index 0000000000000..a52a1b317fbb7 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/PaymentReviewStatusHandlerTest.php @@ -0,0 +1,130 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Response; + +use Magento\AuthorizenetAcceptjs\Gateway\Response\PaymentReviewStatusHandler; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Payment\Model\InfoInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class PaymentReviewStatusHandlerTest extends TestCase +{ + /** + * @var PaymentReviewStatusHandler + */ + private $handler; + + /** + * @var InfoInterface|MockObject + */ + private $paymentMock; + + /** + * @var PaymentDataObjectInterface|MockObject + */ + private $paymentDOMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + + $this->handler = new PaymentReviewStatusHandler(new SubjectReader()); + } + + public function testApprovesPayment() + { + $subject = [ + 'payment' => $this->paymentDOMock + ]; + $response = [ + 'transaction' => [ + 'transactionStatus' => 'approvedOrSomething', + ] + ]; + + // Assert payment is handled correctly + $this->paymentMock->expects($this->exactly(2)) + ->method('setData') + ->withConsecutive( + ['is_transaction_denied', false], + ['is_transaction_approved', true] + ); + + $this->handler->handle($subject, $response); + // Assertions are via mock expects above + } + + /** + * @param string $status + * @dataProvider declinedTransactionStatusesProvider + */ + public function testDeniesPayment(string $status) + { + $subject = [ + 'payment' => $this->paymentDOMock + ]; + $response = [ + 'transaction' => [ + 'transactionStatus' => $status, + ] + ]; + + // Assert payment is handled correctly + $this->paymentMock->expects($this->exactly(2)) + ->method('setData') + ->withConsecutive( + ['is_transaction_denied', true], + ['is_transaction_approved', false] + ); + $this->handler->handle($subject, $response); + } + + /** + * @param string $status + * @dataProvider pendingTransactionStatusesProvider + */ + public function testDoesNothingWhenPending(string $status) + { + $subject = [ + 'payment' => $this->paymentDOMock + ]; + $response = [ + 'transaction' => [ + 'transactionStatus' => $status, + ] + ]; + + // Assert payment is handled correctly + $this->paymentMock->expects($this->never()) + ->method('setData'); + + $this->handler->handle($subject, $response); + } + + public function pendingTransactionStatusesProvider() + { + return [ + ['FDSPendingReview'], + ['FDSAuthorizedPendingReview'] + ]; + } + + public function declinedTransactionStatusesProvider() + { + return [ + ['void'], + ['declined'] + ]; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/TransactionDetailsResponseHandlerTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/TransactionDetailsResponseHandlerTest.php new file mode 100644 index 0000000000000..016e3a1e95383 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/TransactionDetailsResponseHandlerTest.php @@ -0,0 +1,82 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Response; + +use Magento\AuthorizenetAcceptjs\Gateway\Config; +use Magento\AuthorizenetAcceptjs\Gateway\Response\TransactionDetailsResponseHandler; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Payment\Model\InfoInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class TransactionDetailsResponseHandlerTest extends TestCase +{ + /** + * @var TransactionDetailsResponseHandler + */ + private $handler; + + /** + * @var InfoInterface|MockObject + */ + private $paymentMock; + + /** + * @var PaymentDataObjectInterface|MockObject + */ + private $paymentDOMock; + + /** + * @var Config|MockObject + */ + private $configMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->configMock = $this->createMock(Config::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + + $this->handler = new TransactionDetailsResponseHandler(new SubjectReader(), $this->configMock); + } + + public function testHandle() + { + $subject = [ + 'payment' => $this->paymentDOMock, + 'store_id' => 123, + ]; + $response = [ + 'transactionResponse' => [ + 'dontsaveme' => 'dontdoti', + 'abc' => 'foobar', + ] + ]; + + // Assert the information comes from the right store config + $this->configMock->method('getAdditionalInfoKeys') + ->with(123) + ->willReturn(['abc']); + + // Assert the payment has the most recent information always set on it + $this->paymentMock->expects($this->once()) + ->method('setAdditionalInformation') + ->with('abc', 'foobar'); + // Assert the transaction has the raw details from the transaction + $this->paymentMock->expects($this->once()) + ->method('setTransactionAdditionalInfo') + ->with('raw_details_info', ['abc' => 'foobar']); + + $this->handler->handle($subject, $response); + // Assertions are via mock expects above + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/TransactionIdHandlerTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/TransactionIdHandlerTest.php new file mode 100644 index 0000000000000..710f995918495 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/TransactionIdHandlerTest.php @@ -0,0 +1,92 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Response; + +use Magento\AuthorizenetAcceptjs\Gateway\Response\TransactionIdHandler; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class TransactionIdHandlerTest extends TestCase +{ + /** + * @var TransactionIdHandler + */ + private $builder; + + /** + * @var Payment|MockObject + */ + private $paymentMock; + + /** + * @var Payment|MockObject + */ + private $paymentDOMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + + $this->builder = new TransactionIdHandler(new SubjectReader()); + } + + public function testHandleDefaultResponse() + { + $this->paymentMock->method('getParentTransactionId') + ->willReturn(null); + // Assert the id is set + $this->paymentMock->expects($this->once()) + ->method('setTransactionId') + ->with('thetransid'); + // Assert the id is set in the additional info for later + $this->paymentMock->expects($this->once()) + ->method('setTransactionAdditionalInfo') + ->with('real_transaction_id', 'thetransid'); + + $response = [ + 'transactionResponse' => [ + 'transId' => 'thetransid', + ] + ]; + $subject = [ + 'payment' => $this->paymentDOMock + ]; + + $this->builder->handle($subject, $response); + // Assertions are part of mocking above + } + + public function testHandleDifferenceInTransactionId() + { + $this->paymentMock->method('getParentTransactionId') + ->willReturn('somethingElse'); + // Assert the id is set + $this->paymentMock->expects($this->once()) + ->method('setTransactionId') + ->with('thetransid'); + + $response = [ + 'transactionResponse' => [ + 'transId' => 'thetransid', + ] + ]; + $subject = [ + 'payment' => $this->paymentDOMock + ]; + + $this->builder->handle($subject, $response); + // Assertions are part of mocking above + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/VoidResponseHandlerTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/VoidResponseHandlerTest.php new file mode 100644 index 0000000000000..f99da2b2ec90b --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Response/VoidResponseHandlerTest.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Response; + +use Magento\AuthorizenetAcceptjs\Gateway\Response\VoidResponseHandler; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Magento\Payment\Model\InfoInterface; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class VoidResponseHandlerTest extends TestCase +{ + /** + * @var VoidResponseHandler + */ + private $handler; + + /** + * @var InfoInterface|MockObject + */ + private $paymentMock; + + /** + * @var PaymentDataObjectInterface|MockObject + */ + private $paymentDOMock; + + protected function setUp() + { + $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentMock = $this->createMock(Payment::class); + $this->paymentDOMock->method('getPayment') + ->willReturn($this->paymentMock); + + $this->handler = new VoidResponseHandler(new SubjectReader()); + } + + public function testHandle() + { + $subject = [ + 'payment' => $this->paymentDOMock + ]; + $response = [ + 'transactionResponse' => [ + 'transId' => 'abc123', + ] + ]; + + // Assert the transaction is closed + $this->paymentMock->expects($this->once()) + ->method('setIsTransactionClosed') + ->with(true); + // Assert the parent transaction is closed + $this->paymentMock->expects($this->once()) + ->method('setShouldCloseParentTransaction') + ->with(true); + // Assert the authorize.net transaction id is saved + $this->paymentMock->expects($this->once()) + ->method('setTransactionAdditionalInfo') + ->with('real_transaction_id', 'abc123'); + + $this->handler->handle($subject, $response); + // Assertions are via mock expects above + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/SubjectReaderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/SubjectReaderTest.php new file mode 100644 index 0000000000000..42219024badbf --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/SubjectReaderTest.php @@ -0,0 +1,119 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway; + +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\Payment\Gateway\Data\OrderAdapterInterface; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use PHPUnit\Framework\TestCase; + +class SubjectReaderTest extends TestCase +{ + /** + * @var SubjectReader + */ + private $subjectReader; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->subjectReader = new SubjectReader(); + } + + public function testReadPayment(): void + { + $paymentDO = $this->createMock(PaymentDataObjectInterface::class); + + $this->assertSame($paymentDO, $this->subjectReader->readPayment(['payment' => $paymentDO])); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Payment data object should be provided + */ + public function testReadPaymentThrowsExceptionWhenNotAPaymentObject(): void + { + $this->subjectReader->readPayment(['payment' => 'nope']); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Payment data object should be provided + */ + public function testReadPaymentThrowsExceptionWhenNotSet(): void + { + $this->subjectReader->readPayment([]); + } + + public function testReadResponse(): void + { + $expected = ['foo' => 'bar']; + + $this->assertSame($expected, $this->subjectReader->readResponse(['response' => $expected])); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Response does not exist + */ + public function testReadResponseThrowsExceptionWhenNotAvailable(): void + { + $this->subjectReader->readResponse([]); + } + + public function testReadStoreId(): void + { + $this->assertEquals(123, $this->subjectReader->readStoreId(['store_id' => '123'])); + } + + public function testReadStoreIdFromOrder(): void + { + $paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); + $orderMock = $this->createMock(OrderAdapterInterface::class); + $paymentDOMock->method('getOrder') + ->willReturn($orderMock); + $orderMock->method('getStoreID') + ->willReturn('123'); + + $result = $this->subjectReader->readStoreId([ + 'payment' => $paymentDOMock + ]); + + $this->assertEquals(123, $result); + } + + public function testReadLoginId(): void + { + $this->assertEquals('abc', $this->subjectReader->readLoginId([ + 'merchantAuthentication' => ['name' => 'abc'] + ])); + } + + public function testReadTransactionKey(): void + { + $this->assertEquals('abc', $this->subjectReader->readTransactionKey([ + 'merchantAuthentication' => ['transactionKey' => 'abc'] + ])); + } + + public function testReadAmount(): void + { + $this->assertSame('123.12', $this->subjectReader->readAmount(['amount' => 123.12])); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Amount should be provided + */ + public function testReadAmountThrowsExceptionWhenNotAvailable(): void + { + $this->subjectReader->readAmount([]); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Validator/GeneralResponseValidatorTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Validator/GeneralResponseValidatorTest.php new file mode 100644 index 0000000000000..347cd071acc3a --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Validator/GeneralResponseValidatorTest.php @@ -0,0 +1,161 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Validator; + +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\AuthorizenetAcceptjs\Gateway\Validator\GeneralResponseValidator; +use Magento\Payment\Gateway\Validator\ResultInterface; +use Magento\Payment\Gateway\Validator\ResultInterfaceFactory; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class GeneralResponseValidatorTest extends TestCase +{ + /** + * @var ResultInterfaceFactory|MockObject + */ + private $resultFactoryMock; + + /** + * @var GeneralResponseValidator + */ + private $validator; + + protected function setUp() + { + $this->resultFactoryMock = $this->createMock(ResultInterfaceFactory::class); + $this->validator = new GeneralResponseValidator($this->resultFactoryMock, new SubjectReader()); + } + + public function testValidateParsesSuccess() + { + $args = []; + + $this->resultFactoryMock->method('create') + ->with($this->callback(function ($a) use (&$args) { + // Spy on method call + $args = $a; + + return true; + })) + ->willReturn($this->createMock(ResultInterface::class)); + + $this->validator->validate([ + 'response' => [ + 'messages' => [ + 'resultCode' => 'Ok', + 'message' => [ + [ + 'code' => 'foo', + 'text' => 'bar' + ] + ] + ] + ] + ]); + + $this->assertTrue($args['isValid']); + $this->assertEmpty($args['errorCodes']); + $this->assertEmpty($args['failsDescription']); + } + + public function testValidateParsesErrors() + { + $args = []; + + $this->resultFactoryMock->method('create') + ->with($this->callback(function ($a) use (&$args) { + // Spy on method call + $args = $a; + + return true; + })) + ->willReturn($this->createMock(ResultInterface::class)); + + $this->validator->validate([ + 'response' => [ + 'errors' => [ + 'resultCode' => 'Error', + 'error' => [ + [ + 'errorCode' => 'foo', + 'errorText' => 'bar' + ] + ] + ] + ] + ]); + + $this->assertFalse($args['isValid']); + $this->assertSame(['foo'], $args['errorCodes']); + $this->assertSame(['bar'], $args['failsDescription']); + } + + public function testValidateParsesMessages() + { + $args = []; + + $this->resultFactoryMock->method('create') + ->with($this->callback(function ($a) use (&$args) { + // Spy on method call + $args = $a; + + return true; + })) + ->willReturn($this->createMock(ResultInterface::class)); + + $this->validator->validate([ + 'response' => [ + 'messages' => [ + 'resultCode' => 'Error', + 'message' => [ + [ + 'code' => 'foo', + 'text' => 'bar' + ] + ] + ] + ] + ]); + + $this->assertFalse($args['isValid']); + $this->assertSame(['foo'], $args['errorCodes']); + $this->assertSame(['bar'], $args['failsDescription']); + } + + public function testValidateParsesErrorsWhenOnlyOneIsReturned() + { + $args = []; + + $this->resultFactoryMock->method('create') + ->with($this->callback(function ($a) use (&$args) { + // Spy on method call + $args = $a; + + return true; + })) + ->willReturn($this->createMock(ResultInterface::class)); + + $this->validator->validate([ + 'response' => [ + 'messages' => [ + 'resultCode' => 'Error', + 'message' => [ + 'code' => 'foo', + 'text' => 'bar' + ] + ] + ] + ]); + + $this->assertFalse($args['isValid']); + $this->assertSame(['foo'], $args['errorCodes']); + $this->assertSame(['bar'], $args['failsDescription']); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Validator/TransactionHashValidatorTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Validator/TransactionHashValidatorTest.php new file mode 100644 index 0000000000000..fb3f9d0520d49 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Validator/TransactionHashValidatorTest.php @@ -0,0 +1,280 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Validator; + +use Magento\AuthorizenetAcceptjs\Gateway\Config; +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\AuthorizenetAcceptjs\Gateway\Validator\TransactionHashValidator; +use Magento\Payment\Gateway\Validator\ResultInterface; +use Magento\Payment\Gateway\Validator\ResultInterfaceFactory; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class TransactionHashValidatorTest extends TestCase +{ + /** + * @var ResultInterfaceFactory|MockObject + */ + private $resultFactoryMock; + + /** + * @var TransactionHashValidator + */ + private $validator; + + /** + * @var Config|MockObject + */ + private $configMock; + + /** + * @var ResultInterface + */ + private $resultMock; + + protected function setUp() + { + $this->resultFactoryMock = $this->createMock(ResultInterfaceFactory::class); + $this->configMock = $this->createMock(Config::class); + $this->resultMock = $this->createMock(ResultInterface::class); + + $this->validator = new TransactionHashValidator( + $this->resultFactoryMock, + new SubjectReader(), + $this->configMock + ); + } + + /** + * @param $response + * @param $isValid + * @param $errorCodes + * @param $errorDescriptions + * @dataProvider sha512ResponseProvider + */ + public function testValidateSha512HashScenarios( + $response, + $isValid, + $errorCodes, + $errorDescriptions + ) { + $args = []; + + $this->resultFactoryMock->method('create') + ->with($this->callback(function ($a) use (&$args) { + // Spy on method call + $args = $a; + + return true; + })) + ->willReturn($this->resultMock); + + $this->configMock->method('getTransactionSignatureKey') + ->willReturn('abc'); + $this->configMock->method('getLoginId') + ->willReturn('username'); + + $this->validator->validate($response); + + $this->assertSame($isValid, $args['isValid']); + $this->assertEquals($errorCodes, $args['errorCodes']); + $this->assertEquals($errorDescriptions, $args['failsDescription']); + } + + /** + * @param $response + * @param $isValid + * @param $errorCodes + * @param $errorDescriptions + * @dataProvider md5ResponseProvider + */ + public function testValidateMd5HashScenarios( + $response, + $isValid, + $errorCodes, + $errorDescriptions + ) { + $args = []; + + $this->resultFactoryMock->method('create') + ->with($this->callback(function ($a) use (&$args) { + // Spy on method call + $args = $a; + + return true; + })) + ->willReturn($this->resultMock); + + $this->configMock->method('getLegacyTransactionHash') + ->willReturn('abc'); + $this->configMock->method('getLoginId') + ->willReturn('username'); + + $this->validator->validate($response); + + $this->assertSame($isValid, $args['isValid']); + $this->assertEquals($errorCodes, $args['errorCodes']); + $this->assertEquals($errorDescriptions, $args['failsDescription']); + } + + public function md5ResponseProvider() + { + return [ + [ + [ + 'response' => [ + 'transactionResponse' => [ + 'transId' => '123', + 'transHash' => 'C8675D9F7BE7BE4A04C18EA1B6F7B6FD' + ] + ] + ], + true, + [], + [] + ], + [ + [ + 'response' => [ + 'transactionResponse' => [ + 'transId' => '123', + 'transHash' => 'C8675D9F7BE7BE4A04C18EA1B6F7B6FD' + ] + ] + ], + true, + [], + [] + ], + [ + [ + 'amount' => '123.00', + 'response' => [ + 'transactionResponse' => [ + 'transHash' => 'bad' + ] + ] + ], + false, + ['ETHV'], + ['The authenticity of the gateway response could not be verified.'] + ], + [ + [ + 'amount' => '123.00', + 'response' => [ + 'transactionResponse' => [ + 'refTransID' => '123', + 'transId' => '123', + 'transHash' => 'C8675D9F7BE7BE4A04C18EA1B6F7B6FD' + ] + ] + ], + true, + [], + [] + ], + ]; + } + + public function sha512ResponseProvider() + { + return [ + [ + [ + 'response' => [ + 'transactionResponse' => [ + 'transId' => '123', + 'refTransID' => '123', + 'transHashSha2' => 'CC0FF465A081D98FFC6E502C40B2DCC7655ACF591F859135B6E66558D' + . '41E3A2C654D5A2ACF4749104F3133711175C232C32676F79F70211C2984B21A33D30DEE' + ] + ] + ], + true, + [], + [] + ], + [ + [ + 'response' => [ + 'transactionResponse' => [ + 'transId' => '0', + 'refTransID' => '123', + 'transHashSha2' => '563D42F4A5189F74334088EF6A02E84F320CD8C005FB0DC436EF96084D' + . 'FAC0C76DE081DFC58A3BF825465C63B7F38E4D463025EAC44597A68C024CBBCE7A3159' + ] + ] + ], + true, + [], + [] + ], + [ + [ + 'amount' => '123.00', + 'response' => [ + 'transactionResponse' => [ + 'transId' => '0', + 'transHashSha2' => 'DEE5309078D9F7A68BA4F706FB3E58618D3991A6A5E4C39DCF9C49E693' + . '673C38BD6BB15C235263C549A6B5F0B6D7019EC729E0C275C9FEA37FB91F8B612D0A5D' + ] + ] + ], + true, + [], + [] + ], + [ + [ + 'amount' => '123.00', + 'response' => [ + 'transactionResponse' => [ + 'transId' => '123', + 'transHashSha2' => '1DBD16DED0DA02F52A22A9AD71A49F70BD2ECD42437552889912DD5CE' + . 'CBA0E09A5E8E6221DA74D98A46E5F77F7774B6D9C39CADF3E9A33D85870A6958DA7C8B2' + ] + ] + ], + true, + [], + [] + ], + [ + [ + 'amount' => '123.00', + 'response' => [ + 'transactionResponse' => [ + 'transId' => '123', + 'refTransID' => '0', + 'transHashSha2' => '1DBD16DED0DA02F52A22A9AD71A49F70BD2ECD42437552889912DD5CE' + . 'CBA0E09A5E8E6221DA74D98A46E5F77F7774B6D9C39CADF3E9A33D85870A6958DA7C8B2' + ] + ] + ], + true, + [], + [] + ], + [ + [ + 'amount' => '123.00', + 'response' => [ + 'transactionResponse' => [ + 'transHashSha2' => 'bad' + ] + ] + ], + false, + ['ETHV'], + ['The authenticity of the gateway response could not be verified.'] + ], + ]; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Validator/TransactionResponseValidatorTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Validator/TransactionResponseValidatorTest.php new file mode 100644 index 0000000000000..cef7883bd5dbc --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Gateway/Validator/TransactionResponseValidatorTest.php @@ -0,0 +1,213 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Gateway\Validator; + +use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader; +use Magento\AuthorizenetAcceptjs\Gateway\Validator\TransactionResponseValidator; +use Magento\Payment\Gateway\Validator\ResultInterface; +use Magento\Payment\Gateway\Validator\ResultInterfaceFactory; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class TransactionResponseValidatorTest extends TestCase +{ + private const RESPONSE_CODE_APPROVED = 1; + private const RESPONSE_CODE_HELD = 4; + private const RESPONSE_REASON_CODE_APPROVED = 1; + private const RESPONSE_REASON_CODE_PENDING_REVIEW_AUTHORIZED = 252; + private const RESPONSE_REASON_CODE_PENDING_REVIEW = 253; + + /** + * @var ResultInterfaceFactory|MockObject + */ + private $resultFactoryMock; + + /** + * @var TransactionResponseValidator + */ + private $validator; + + /** + * @var ResultInterface + */ + private $resultMock; + + protected function setUp() + { + $this->resultFactoryMock = $this->createMock(ResultInterfaceFactory::class); + $this->resultMock = $this->createMock(ResultInterface::class); + + $this->validator = new TransactionResponseValidator( + $this->resultFactoryMock, + new SubjectReader() + ); + } + + /** + * @param $transactionResponse + * @param $isValid + * @param $errorCodes + * @param $errorMessages + * @dataProvider scenarioProvider + */ + public function testValidateScenarios($transactionResponse, $isValid, $errorCodes, $errorMessages) + { + $args = []; + + $this->resultFactoryMock->method('create') + ->with($this->callback(function ($a) use (&$args) { + // Spy on method call + $args = $a; + + return true; + })) + ->willReturn($this->resultMock); + + $this->validator->validate([ + 'response' => [ + 'transactionResponse' => $transactionResponse + ] + ]); + + $this->assertEquals($isValid, $args['isValid']); + $this->assertEquals($errorCodes, $args['errorCodes']); + $this->assertEquals($errorMessages, $args['failsDescription']); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function scenarioProvider() + { + return [ + // This validator only cares about successful edge cases so test for default behavior + [ + [ + 'responseCode' => 'foo', + ], + true, + [], + [] + ], + + // Test for acceptable reason codes + [ + [ + 'responseCode' => self::RESPONSE_CODE_APPROVED, + 'messages' => [ + 'message' => [ + 'code' => self::RESPONSE_REASON_CODE_APPROVED, + ] + ] + ], + true, + [], + [] + ], + [ + [ + 'responseCode' => self::RESPONSE_CODE_APPROVED, + 'messages' => [ + 'message' => [ + 'code' => self::RESPONSE_REASON_CODE_PENDING_REVIEW, + ] + ] + ], + true, + [], + [] + ], + [ + [ + 'responseCode' => self::RESPONSE_CODE_APPROVED, + 'messages' => [ + 'message' => [ + 'code' => self::RESPONSE_REASON_CODE_PENDING_REVIEW_AUTHORIZED, + ] + ] + ], + true, + [], + [] + ], + [ + [ + 'responseCode' => self::RESPONSE_CODE_HELD, + 'messages' => [ + 'message' => [ + 'code' => self::RESPONSE_REASON_CODE_APPROVED, + ] + ] + ], + true, + [], + [] + ], + [ + [ + 'responseCode' => self::RESPONSE_CODE_HELD, + 'messages' => [ + 'message' => [ + 'code' => self::RESPONSE_REASON_CODE_PENDING_REVIEW, + ] + ] + ], + true, + [], + [] + ], + [ + [ + 'responseCode' => self::RESPONSE_CODE_HELD, + 'messages' => [ + 'message' => [ + 'code' => self::RESPONSE_REASON_CODE_PENDING_REVIEW_AUTHORIZED, + ] + ] + ], + true, + [], + [] + ], + + // Test for reason codes that aren't acceptable + [ + [ + 'responseCode' => self::RESPONSE_CODE_APPROVED, + 'messages' => [ + 'message' => [ + [ + 'description' => 'bar', + 'code' => 'foo', + ] + ] + ] + ], + false, + ['foo'], + ['bar'] + ], + [ + [ + 'responseCode' => self::RESPONSE_CODE_APPROVED, + 'messages' => [ + 'message' => [ + // Alternate, non-array sytax + 'text' => 'bar', + 'code' => 'foo', + ] + ] + ], + false, + ['foo'], + ['bar'] + ], + ]; + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Model/Ui/ConfigProviderTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Model/Ui/ConfigProviderTest.php new file mode 100644 index 0000000000000..dea4557fd584c --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Model/Ui/ConfigProviderTest.php @@ -0,0 +1,76 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Model\Ui; + +use Magento\AuthorizenetAcceptjs\Gateway\Config; +use Magento\AuthorizenetAcceptjs\Model\Ui\ConfigProvider; +use Magento\Quote\Api\Data\CartInterface; +use PHPUnit\Framework\MockObject\Builder\InvocationMocker; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class ConfigProviderTest extends TestCase +{ + /** + * @var CartInterface|MockObject|InvocationMocker + */ + private $cart; + + /** + * @var Config|MockObject|InvocationMocker + */ + private $config; + + /** + * @var ConfigProvider + */ + private $provider; + + protected function setUp() + { + $this->cart = $this->createMock(CartInterface::class); + $this->config = $this->createMock(Config::class); + $this->provider = new ConfigProvider($this->config, $this->cart); + } + + public function testProviderRetrievesValues() + { + $this->cart->method('getStoreId') + ->willReturn('123'); + + $this->config->method('getClientKey') + ->with('123') + ->willReturn('foo'); + + $this->config->method('getLoginId') + ->with('123') + ->willReturn('bar'); + + $this->config->method('getEnvironment') + ->with('123') + ->willReturn('baz'); + + $this->config->method('isCvvEnabled') + ->with('123') + ->willReturn(false); + + $expected = [ + 'payment' => [ + Config::METHOD => [ + 'clientKey' => 'foo', + 'apiLoginID' => 'bar', + 'environment' => 'baz', + 'useCvv' => false, + ] + ] + ]; + + $this->assertEquals($expected, $this->provider->getConfig()); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Observer/DataAssignObserverTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Observer/DataAssignObserverTest.php new file mode 100644 index 0000000000000..ebb95263f54d2 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Observer/DataAssignObserverTest.php @@ -0,0 +1,79 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Observer; + +use Magento\Framework\DataObject; +use Magento\Framework\Event; +use Magento\Framework\Event\Observer; +use Magento\Payment\Model\InfoInterface; +use Magento\Payment\Observer\AbstractDataAssignObserver; +use Magento\AuthorizenetAcceptjs\Observer\DataAssignObserver; +use Magento\Quote\Api\Data\PaymentInterface; +use PHPUnit\Framework\TestCase; + +class DataAssignObserverTest extends TestCase +{ + public function testExecuteSetsProperData() + { + $additionalInfo = [ + 'opaqueDataDescriptor' => 'foo', + 'opaqueDataValue' => 'bar', + 'ccLast4' => '1234' + ]; + + $observerContainer = $this->createMock(Observer::class); + $event = $this->createMock(Event::class); + $paymentInfoModel = $this->createMock(InfoInterface::class); + $dataObject = new DataObject([ + PaymentInterface::KEY_ADDITIONAL_DATA => $additionalInfo + ]); + $observerContainer->method('getEvent') + ->willReturn($event); + $event->method('getDataByKey') + ->willReturnMap( + [ + [AbstractDataAssignObserver::MODEL_CODE, $paymentInfoModel], + [AbstractDataAssignObserver::DATA_CODE, $dataObject] + ] + ); + $paymentInfoModel->expects($this->at(0)) + ->method('setAdditionalInformation') + ->with('opaqueDataDescriptor', 'foo'); + $paymentInfoModel->expects($this->at(1)) + ->method('setAdditionalInformation') + ->with('opaqueDataValue', 'bar'); + $paymentInfoModel->expects($this->at(2)) + ->method('setAdditionalInformation') + ->with('ccLast4', '1234'); + + $observer = new DataAssignObserver(); + $observer->execute($observerContainer); + } + + public function testDoestSetDataWhenEmpty() + { + $observerContainer = $this->createMock(Observer::class); + $event = $this->createMock(Event::class); + $paymentInfoModel = $this->createMock(InfoInterface::class); + $observerContainer->method('getEvent') + ->willReturn($event); + $event->method('getDataByKey') + ->willReturnMap( + [ + [AbstractDataAssignObserver::MODEL_CODE, $paymentInfoModel], + [AbstractDataAssignObserver::DATA_CODE, new DataObject()] + ] + ); + $paymentInfoModel->expects($this->never()) + ->method('setAdditionalInformation'); + + $observer = new DataAssignObserver(); + $observer->execute($observerContainer); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Setup/Patch/Data/CopyCurrentConfigTest.php b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Setup/Patch/Data/CopyCurrentConfigTest.php new file mode 100644 index 0000000000000..5ac8a6ca9b3f6 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/Test/Unit/Setup/Patch/Data/CopyCurrentConfigTest.php @@ -0,0 +1,149 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\AuthorizenetAcceptjs\Test\Unit\Setup\Patch\Data; + +use Magento\AuthorizenetAcceptjs\Setup\Patch\Data\CopyCurrentConfig; +use Magento\Config\Model\ResourceModel\Config as ResourceConfig; +use Magento\Framework\App\Config; +use Magento\Framework\Encryption\Encryptor; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Setup\Module\DataSetup; +use Magento\Setup\Model\ModuleContext; +use Magento\Store\Model\StoreManagerInterface; +use Magento\Store\Model\Website; +use PHPUnit\Framework\TestCase; + +class CopyCurrentConfigTest extends TestCase +{ + /** + * @var \Magento\Framework\App\Config + */ + private $scopeConfig; + + /** + * @var \Magento\Config\Model\ResourceModel\Config + */ + private $resourceConfig; + + /** + * @var \Magento\Framework\Encryption\Encryptor + */ + private $encryptor; + + /** + * @var \Magento\Setup\Module\DataSetup + */ + private $setup; + + /** + * @var \Magento\Setup\Model\ModuleContext + */ + private $context; + + /** + * @var \Magento\Store\Model\StoreManager + */ + private $storeManager; + + /** + * @var \Magento\Store\Model\Website + */ + private $website; + + protected function setUp(): void + { + $this->scopeConfig = $this->createMock(Config::class); + $this->resourceConfig = $this->createMock(ResourceConfig::class); + $this->encryptor = $this->createMock(Encryptor::class); + $this->setup = $this->createMock(DataSetup::class); + + $this->setup->expects($this->once()) + ->method('startSetup') + ->willReturn(null); + + $this->setup->expects($this->once()) + ->method('endSetup') + ->willReturn(null); + + $this->context = $this->createMock(ModuleContext::class); + $this->storeManager = $this->createMock(StoreManagerInterface::class); + $this->website = $this->createMock(Website::class); + } + + public function testMigrateData(): void + { + $this->scopeConfig->expects($this->exactly(26)) + ->method('getValue') + ->willReturn('TestValue'); + + $this->resourceConfig->expects($this->exactly(26)) + ->method('saveConfig') + ->willReturn(null); + + $this->encryptor->expects($this->exactly(6)) + ->method('encrypt') + ->willReturn('TestValue'); + + $this->website->expects($this->once()) + ->method('getId') + ->willReturn(1); + + $this->storeManager->expects($this->once()) + ->method('getWebsites') + ->willReturn([$this->website]); + + $objectManager = new ObjectManager($this); + + $installer = $objectManager->getObject( + CopyCurrentConfig::class, + [ + 'moduleDataSetup' => $this->setup, + 'scopeConfig' => $this->scopeConfig, + 'resourceConfig' => $this->resourceConfig, + 'encryptor' => $this->encryptor, + 'storeManager' => $this->storeManager + ] + ); + + $installer->apply($this->context); + } + + public function testMigrateDataNullFields(): void + { + $this->scopeConfig->expects($this->exactly(13)) + ->method('getValue') + ->will($this->onConsecutiveCalls(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); + + $this->resourceConfig->expects($this->exactly(10)) + ->method('saveConfig') + ->willReturn(null); + + $this->encryptor->expects($this->never()) + ->method('encrypt'); + + $this->storeManager->expects($this->once()) + ->method('getWebsites') + ->willReturn([]); + + $objectManager = new ObjectManager($this); + + $installer = $objectManager->getObject( + CopyCurrentConfig::class, + [ + 'moduleDataSetup' => $this->setup, + 'scopeConfig' => $this->scopeConfig, + 'resourceConfig' => $this->resourceConfig, + 'encryptor' => $this->encryptor, + 'storeManager' => $this->storeManager + ] + ); + + $installer->apply($this->context); + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/composer.json b/app/code/Magento/AuthorizenetAcceptjs/composer.json new file mode 100644 index 0000000000000..be2cd6d4e70f8 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/composer.json @@ -0,0 +1,31 @@ +{ + "name": "magento/module-authorizenet-acceptjs", + "description": "N/A", + "config": { + "sort-packages": true + }, + "require": { + "php": "~7.1.3||~7.2.0", + "magento/framework": "*", + "magento/module-payment": "*", + "magento/module-sales": "*", + "magento/module-config": "*", + "magento/module-backend": "*", + "magento/module-checkout": "*", + "magento/module-store": "*", + "magento/module-quote": "*" + }, + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\AuthorizenetAcceptjs\\": "" + } + } +} diff --git a/app/code/Magento/AuthorizenetAcceptjs/etc/adminhtml/di.xml b/app/code/Magento/AuthorizenetAcceptjs/etc/adminhtml/di.xml new file mode 100644 index 0000000000000..320f8f79ee28a --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/etc/adminhtml/di.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <type name="Magento\AuthorizenetAcceptjs\Block\Payment"> + <arguments> + <argument name="config" xsi:type="object">Magento\AuthorizenetAcceptjs\Model\Ui\ConfigProvider</argument> + </arguments> + </type> +</config> diff --git a/app/code/Magento/AuthorizenetAcceptjs/etc/adminhtml/system.xml b/app/code/Magento/AuthorizenetAcceptjs/etc/adminhtml/system.xml new file mode 100644 index 0000000000000..279a904d916a2 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/etc/adminhtml/system.xml @@ -0,0 +1,118 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd"> + <system> + <section id="payment"> + <group id="authorizenet_acceptjs" translate="label" type="text" sortOrder="34" showInDefault="1" showInWebsite="1" showInStore="1"> + <label>Authorize.Net</label> + <field id="active" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0" canRestore="1"> + <label>Enabled</label> + <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> + <requires> + <group id="authorizenet_acceptjs_required"/> + </requires> + </field> + <group id="required" translate="label" showInDefault="1" showInWebsite="1" showInStore="1" sortOrder="5"> + <label>Basic Authorize.Net Settings</label> + <attribute type="expanded">1</attribute> + <frontend_model>Magento\Config\Block\System\Config\Form\Fieldset</frontend_model> + <field id="title" translate="label" type="text" sortOrder="10" showInDefault="10" showInWebsite="1" showInStore="1" canRestore="1"> + <label>Title</label> + <config_path>payment/authorizenet_acceptjs/title</config_path> + </field> + <field id="environment" translate="label" type="select" sortOrder="15" showInDefault="1" showInWebsite="1" showInStore="0"> + <label>Environment</label> + <source_model>Magento\AuthorizenetAcceptjs\Model\Adminhtml\Source\Environment</source_model> + <config_path>payment/authorizenet_acceptjs/environment</config_path> + </field> + <field id="payment_action" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="0" canRestore="1"> + <label>Payment Action</label> + <source_model>Magento\AuthorizenetAcceptjs\Model\Adminhtml\Source\PaymentAction</source_model> + <config_path>payment/authorizenet_acceptjs/payment_action</config_path> + </field> + <field id="login" translate="label" type="obscure" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="0"> + <label>API Login ID</label> + <backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model> + <config_path>payment/authorizenet_acceptjs/login</config_path> + </field> + <field id="trans_key" translate="label" type="obscure" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="0"> + <label>Transaction Key</label> + <backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model> + <config_path>payment/authorizenet_acceptjs/trans_key</config_path> + </field> + <field id="public_client_key" translate="label" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="0"> + <label>Public Client Key</label> + <config_path>payment/authorizenet_acceptjs/public_client_key</config_path> + </field> + <field id="trans_signature_key" translate="label" type="obscure" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="0"> + <label>Signature Key</label> + <backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model> + <config_path>payment/authorizenet_acceptjs/trans_signature_key</config_path> + </field> + <field id="trans_md5" translate="label" type="obscure" sortOrder="70" showInDefault="1" showInWebsite="1" showInStore="0"> + <label>Merchant MD5 (deprecated)</label> + <backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model> + <config_path>payment/authorizenet_acceptjs/trans_md5</config_path> + </field> + </group> + <group id="advanced" translate="label" showInDefault="1" showInWebsite="1" showInStore="0" sortOrder="20"> + <label>Advanced Authorize.Net Settings</label> + <attribute type="expanded">0</attribute> + <field id="currency" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0" canRestore="1"> + <label>Accepted Currency</label> + <source_model>Magento\Config\Model\Config\Source\Locale\Currency</source_model> + <config_path>payment/authorizenet_acceptjs/currency</config_path> + </field> + <field id="debug" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="0" canRestore="1"> + <label>Debug</label> + <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> + <config_path>payment/authorizenet_acceptjs/debug</config_path> + </field> + <field id="email_customer" translate="label" type="select" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="0" canRestore="1"> + <label>Email Customer</label> + <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> + <config_path>payment/authorizenet_acceptjs/email_customer</config_path> + </field> + <field id="cvv_enabled" translate="label" type="select" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="0" canRestore="1"> + <label>Enable Credit Card Verification Field</label> + <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> + <config_path>payment/authorizenet_acceptjs/cvv_enabled</config_path> + </field> + <field id="cctypes" translate="label" type="multiselect" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="0" canRestore="1"> + <label>Credit Card Types</label> + <source_model>Magento\AuthorizenetAcceptjs\Model\Adminhtml\Source\Cctype</source_model> + <config_path>payment/authorizenet_acceptjs/cctypes</config_path> + </field> + <field id="allowspecific" translate="label" type="allowspecific" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="0" canRestore="1"> + <label>Payment from Applicable Countries</label> + <source_model>Magento\Payment\Model\Config\Source\Allspecificcountries</source_model> + <config_path>payment/authorizenet_acceptjs/allowspecific</config_path> + </field> + <field id="specificcountry" translate="label" type="multiselect" sortOrder="70" showInDefault="1" showInWebsite="1" showInStore="0"> + <label>Payment from Specific Countries</label> + <source_model>Magento\Directory\Model\Config\Source\Country</source_model> + <config_path>payment/authorizenet_acceptjs/specificcountry</config_path> + </field> + <field id="min_order_total" translate="label" type="text" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="0"> + <label>Minimum Order Total</label> + <config_path>payment/authorizenet_acceptjs/min_order_total</config_path> + </field> + <field id="max_order_total" translate="label" type="text" sortOrder="90" showInDefault="1" showInWebsite="1" showInStore="0"> + <label>Maximum Order Total</label> + <config_path>payment/authorizenet_acceptjs/max_order_total</config_path> + </field> + <field id="sort_order" translate="label" type="text" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="0"> + <label>Sort Order</label> + <frontend_class>validate-number</frontend_class> + <config_path>payment/authorizenet_acceptjs/sort_order</config_path> + </field> + </group> + </group> + </section> + </system> +</config> diff --git a/app/code/Magento/AuthorizenetAcceptjs/etc/authorizenet_acceptjs_error_mapping.xml b/app/code/Magento/AuthorizenetAcceptjs/etc/authorizenet_acceptjs_error_mapping.xml new file mode 100644 index 0000000000000..507a9b14f917b --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/etc/authorizenet_acceptjs_error_mapping.xml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Payment:etc/error_mapping.xsd"> + <message_list> + <message code="E00003" translate="true">Invalid request to gateway.</message> + <message code="E00007" translate="true">Invalid gateway credentials.</message> + <message code="E00027" translate="true">Transaction has been declined. Please try again later.</message> + <message code="ETHV" translate="true">The authenticity of the gateway response could not be verified.</message> + </message_list> +</mapping> diff --git a/app/code/Magento/AuthorizenetAcceptjs/etc/config.xml b/app/code/Magento/AuthorizenetAcceptjs/etc/config.xml new file mode 100644 index 0000000000000..24291187c0584 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/etc/config.xml @@ -0,0 +1,49 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd"> + <default> + <payment> + <authorizenet_acceptjs> + <active>0</active> + <cctypes>AE,VI,MC,DI,JCB,DN</cctypes> + <debug>0</debug> + <can_use_checkout>1</can_use_checkout> + <can_use_internal>1</can_use_internal> + <can_capture_partial>0</can_capture_partial> + <can_authorize>1</can_authorize> + <can_refund>1</can_refund> + <can_capture>1</can_capture> + <can_void>1</can_void> + <can_accept_payment>1</can_accept_payment> + <can_deny_payment>1</can_deny_payment> + <can_cancel>1</can_cancel> + <can_review_payment>1</can_review_payment> + <can_edit>1</can_edit> + <can_fetch_transaction_info>1</can_fetch_transaction_info> + <can_fetch_transaction_information>1</can_fetch_transaction_information> + <model>AuthorizenetAcceptjsFacade</model> + <email_customer>0</email_customer> + <login backend_model="Magento\Config\Model\Config\Backend\Encrypted" /> + <order_status>processing</order_status> + <payment_action>authorize</payment_action> + <title>Credit Card (Authorize.Net) + 1 + + + + + 0 + USD + production + authCode,avsResultCode,cvvResultCode,cavvResultCode + accountType,ccLast4,authCode,avsResultCode,cvvResultCode,cavvResultCode + transactionStatus,responseCode,responseReasonCode,authCode,AVSResponse,cardCodeResponse,CAVVResponse + + + + diff --git a/app/code/Magento/AuthorizenetAcceptjs/etc/di.xml b/app/code/Magento/AuthorizenetAcceptjs/etc/di.xml new file mode 100644 index 0000000000000..cf10557d3869a --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/etc/di.xml @@ -0,0 +1,428 @@ + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Config::METHOD + + + + + authorizenet_acceptjs + Magento\AuthorizenetAcceptjs\Block\Form + AuthorizenetAcceptjsInfoBlock + AuthorizenetAcceptjsValueHandlerPool + AuthorizenetAcceptjsValidatorPool + AuthorizenetAcceptjsCommandPool + + + + + + AuthorizenetAcceptjsAuthorizeCommand + AuthorizenetAcceptjsCaptureCommand + AuthorizenetAcceptjsSaleCommand + AuthorizenetAcceptjsSettleCommand + AuthorizenetAcceptjsVoidCommand + AuthorizenetAcceptjsRefundCommand + AuthorizenetAcceptjsRefundSettledCommand + AuthorizenetAcceptjsCancelCommand + AuthorizenetAcceptjsAcceptPaymentCommand + AuthorizenetAcceptjsAcceptFdsCommand + AuthorizenetAcceptjsCancelCommand + AuthorizenetAcceptjsTransactionDetailsCommand + AuthorizenetAcceptjsFetchTransactionInfoCommand + + + + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Validator\GeneralResponseValidator + + + + + + + true + + + Magento\AuthorizenetAcceptjs\Gateway\Validator\GeneralResponseValidator + Magento\AuthorizenetAcceptjs\Gateway\Validator\TransactionResponseValidator + Magento\AuthorizenetAcceptjs\Gateway\Validator\TransactionHashValidator + + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Validator\GeneralResponseValidator + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Config + + + + + + AuthorizenetAcceptjsCountryValidator + + + + + + + + + AuthorizenetAcceptjsCommandPool + + + + + AuthorizenetAcceptjsTransactionDetailsRequest + AuthorizenetAcceptjsDefaultTransferFactory + Magento\AuthorizenetAcceptjs\Gateway\Http\Client + AuthorizenetAcceptjsTransactionDetailsValidator + + + + + AuthorizenetAcceptjsAuthorizeRequest + AuthorizenetAcceptjsDefaultTransferFactory + Magento\AuthorizenetAcceptjs\Gateway\Http\Client + AuthorizenetAcceptjsAuthorizationHandler + AuthorizenetAcceptjsTransactionValidator + AuthorizenetAcceptjsVirtualErrorMessageMapper + + + + + AuthorizenetAcceptjsAcceptsFdsRequest + AuthorizenetAcceptjsDefaultTransferFactory + Magento\AuthorizenetAcceptjs\Gateway\Http\Client + AuthorizenetAcceptjsAcceptsFdsRequestValidator + + + + + AuthorizenetAcceptjsCommandPool + + + + + AuthorizenetAcceptjsSaleRequest + AuthorizenetAcceptjsSaleHandler + + + + + AuthorizenetAcceptjsCommandPool + + + + + AuthorizenetAcceptjsRefundRequest + AuthorizenetAcceptjsRefundSettledHandler + + + + + AuthorizenetAcceptjsCommandPool + + + + + AuthorizenetAcceptjsCaptureRequest + AuthorizenetAcceptjsCaptureTransactionHandler + + + + + AuthorizenetAcceptjsVoidRequest + AuthorizenetAcceptjsDefaultTransferFactory + Magento\AuthorizenetAcceptjs\Gateway\Http\Client + AuthorizenetAcceptjsVoidHandler + AuthorizenetAcceptjsTransactionValidator + AuthorizenetAcceptjsVirtualErrorMessageMapper + + + + + AuthorizenetAcceptjsCancelHandler + + + + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Response\PaymentReviewStatusHandler + + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Response\TransactionIdHandler + Magento\AuthorizenetAcceptjs\Gateway\Response\PaymentResponseHandler + Magento\AuthorizenetAcceptjs\Gateway\Response\TransactionDetailsResponseHandler + + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Response\CloseParentTransactionHandler + + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Response\CloseParentTransactionHandler + + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Response\TransactionIdHandler + Magento\AuthorizenetAcceptjs\Gateway\Response\CloseParentTransactionHandler + Magento\AuthorizenetAcceptjs\Gateway\Response\CloseTransactionHandler + + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Response\VoidResponseHandler + + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Response\CloseTransactionHandler + Magento\AuthorizenetAcceptjs\Gateway\Response\CloseParentTransactionHandler + + + + + + + + + + + AuthorizenetAcceptjsTransactionDetailsRequestTypeBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\StoreConfigBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\AuthenticationDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\TransactionDetailsDataBuilder + + + + + + + AuthorizenetAcceptjsAcceptsFdsRequestTypeBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\StoreConfigBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\AuthenticationDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\AcceptFdsDataBuilder + + + + + + + AuthorizenetAcceptjsTransactionRequestTypeBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\StoreConfigBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\AuthenticationDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\AuthorizeDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\AmountDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\PaymentDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\ShippingDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\SolutionDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\OrderDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\PoDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\CustomerDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\AddressDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\CustomSettingsBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\PassthroughDataBuilder + + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Request\SaleDataBuilder + + + + + + + AuthorizenetAcceptjsTransactionRequestTypeBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\StoreConfigBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\AuthenticationDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\RefundTransactionTypeDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\AmountDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\RefundPaymentDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\ShippingDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\RefundReferenceTransactionDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\OrderDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\PoDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\CustomerDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\AddressDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\CustomSettingsBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\PassthroughDataBuilder + + + + + + + AuthorizenetAcceptjsTransactionRequestTypeBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\StoreConfigBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\AuthenticationDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\CaptureDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\PassthroughDataBuilder + + + + + + + AuthorizenetAcceptjsTransactionRequestTypeBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\StoreConfigBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\AuthenticationDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\VoidDataBuilder + Magento\AuthorizenetAcceptjs\Gateway\Request\PassthroughDataBuilder + + + + + + + + + createTransactionRequest + + + + + getTransactionDetailsRequest + + + + + updateHeldTransactionRequest + + + + + + + + authorizenet_acceptjs_error_mapping.xml + + + + + AuthorizenetAcceptjsErrorMappingConfigReader + authorizenet_acceptjs_error_mapper + + + + + AuthorizenetAcceptjsErrorMappingData + + + + + + + AuthorizenetAcceptjsPaymentReviewStatusHandler + + + + + + AuthorizenetAcceptjsCommandManager + + + + + + + 1 + 1 + 1 + 1 + 1 + 1 + + + 1 + 1 + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Config + + + + + + AuthorizenetAcceptjsDefaultValueHandler + + + + + + AuthorizenetAcceptjsCommandPool + + + + + Magento\AuthorizenetAcceptjs\Gateway\Config + + + + + AuthorizenetAcceptjsLogger + + + + + + store_id + + + + + + + AuthorizenetAcceptjsRemoveStoreConfigFilter + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Config + + + diff --git a/app/code/Magento/AuthorizenetAcceptjs/etc/events.xml b/app/code/Magento/AuthorizenetAcceptjs/etc/events.xml new file mode 100644 index 0000000000000..93dc448d1d895 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/etc/events.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/app/code/Magento/AuthorizenetAcceptjs/etc/frontend/di.xml b/app/code/Magento/AuthorizenetAcceptjs/etc/frontend/di.xml new file mode 100644 index 0000000000000..8b0e570abbd2e --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/etc/frontend/di.xml @@ -0,0 +1,30 @@ + + + + + + + 1 + + + + + + + Magento\AuthorizenetAcceptjs\Model\Ui\ConfigProvider + + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Config::METHOD + + + + diff --git a/app/code/Magento/AuthorizenetAcceptjs/etc/module.xml b/app/code/Magento/AuthorizenetAcceptjs/etc/module.xml new file mode 100644 index 0000000000000..6bc8fe3c4daee --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/etc/module.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + diff --git a/app/code/Magento/AuthorizenetAcceptjs/etc/payment.xml b/app/code/Magento/AuthorizenetAcceptjs/etc/payment.xml new file mode 100644 index 0000000000000..b8292839c3bd1 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/etc/payment.xml @@ -0,0 +1,15 @@ + + + + + + 1 + + + diff --git a/app/code/Magento/AuthorizenetAcceptjs/i18n/en_US.csv b/app/code/Magento/AuthorizenetAcceptjs/i18n/en_US.csv new file mode 100644 index 0000000000000..da518301652f4 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/i18n/en_US.csv @@ -0,0 +1,21 @@ +Authorize.net,Authorize.net +"Gateway URL","Gateway URL" +"Invalid payload type.","Invalid payload type." +"Something went wrong in the payment gateway.","Something went wrong in the payment gateway." +"Merchant MD5 (deprecated","Merchant MD5 (deprecated" +"Signature Key","Signature Key" +"Basic Authorize.Net Settings","Basic Authorize.Net Settings" +"Advanced Authorie.Net Settings","Advanced Authorie.Net Settings" +"Public Client Key","Public Client Key" +"Environment","Environment" +"Production","Production" +"Sandbox","Sandbox" +"accountType","Account Type" +"authCode", "Processor Response Text" +"avsResultCode", "AVS Response Code" +"cvvResultCode","CVV Response Code" +"cavvResultCode","CAVV Response Code" +"Enable Credit Card Verification Field","Enable Credit Card Verification Field" +"ccLast4","Last 4 Digits of Card" +"There was an error while trying to process the refund.","There was an error while trying to process the refund." +"This transaction cannot be refunded with its current status.","This transaction cannot be refunded with its current status." diff --git a/app/code/Magento/AuthorizenetAcceptjs/registration.php b/app/code/Magento/AuthorizenetAcceptjs/registration.php new file mode 100644 index 0000000000000..5338c9a4ddc80 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/registration.php @@ -0,0 +1,11 @@ + + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Config::METHOD + Magento_AuthorizenetAcceptjs::form/cc.phtml + + + + + + + diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml b/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml new file mode 100644 index 0000000000000..13f6d38e2b81a --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml @@ -0,0 +1,17 @@ + + + + + + + Magento\AuthorizenetAcceptjs\Gateway\Config::METHOD + Magento_AuthorizenetAcceptjs::form/cc.phtml + + + + diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/templates/form/cc.phtml b/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/templates/form/cc.phtml new file mode 100644 index 0000000000000..045bd5cfd81b2 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/templates/form/cc.phtml @@ -0,0 +1,93 @@ +escapeHtml($block->getMethodCode()); +$ccType = $block->getInfoData('cc_type'); +$ccExpMonth = $block->getInfoData('cc_exp_month'); +$ccExpYear = $block->getInfoData('cc_exp_year'); +?> + diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/templates/payment/script.phtml b/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/templates/payment/script.phtml new file mode 100644 index 0000000000000..6960bddf696af --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/templates/payment/script.phtml @@ -0,0 +1,17 @@ + + \ No newline at end of file diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/web/js/authorizenet.js b/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/web/js/authorizenet.js new file mode 100644 index 0000000000000..0eb865d7666b3 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/web/js/authorizenet.js @@ -0,0 +1,196 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'jquery', + 'uiComponent', + 'Magento_Ui/js/modal/alert', + 'Magento_AuthorizenetAcceptjs/js/view/payment/acceptjs-client' +], function ($, Class, alert, AcceptjsClient) { + 'use strict'; + + return Class.extend({ + defaults: { + acceptjsClient: null, + $selector: null, + selector: 'edit_form', + container: 'payment_form_authorizenet_acceptjs', + active: false, + imports: { + onActiveChange: 'active' + } + }, + + /** + * @{inheritdoc} + */ + initConfig: function (config) { + this._super(); + + this.acceptjsClient = AcceptjsClient({ + environment: config.environment + }); + + return this; + }, + + /** + * @{inheritdoc} + */ + initObservable: function () { + this.$selector = $('#' + this.selector); + this._super() + .observe('active'); + + // re-init payment method events + this.$selector.off('changePaymentMethod.' + this.code) + .on('changePaymentMethod.' + this.code, this.changePaymentMethod.bind(this)); + + return this; + }, + + /** + * Enable/disable current payment method + * + * @param {Object} event + * @param {String} method + * @returns {Object} + */ + changePaymentMethod: function (event, method) { + this.active(method === this.code); + + return this; + }, + + /** + * Triggered when payment changed + * + * @param {Boolean} isActive + */ + onActiveChange: function (isActive) { + if (!isActive) { + + return; + } + + this.disableEventListeners(); + + window.order.addExcludedPaymentMethod(this.code); + + this.enableEventListeners(); + }, + + /** + * Sets the payment details on the form + * + * @param {Object} tokens + */ + setPaymentDetails: function (tokens) { + var $ccNumber = $(this.getSelector('cc_number')), + ccLast4 = $ccNumber.val().replace(/[^\d]/g, '').substr(-4); + + $(this.getSelector('opaque_data_descriptor')).val(tokens.opaqueDataDescriptor); + $(this.getSelector('opaque_data_value')).val(tokens.opaqueDataValue); + $(this.getSelector('cc_last_4')).val(ccLast4); + $ccNumber.val(''); + $(this.getSelector('cc_exp_month')).val(''); + $(this.getSelector('cc_exp_year')).val(''); + + if (this.useCvv) { + $(this.getSelector('cc_cid')).val(''); + } + }, + + /** + * Trigger order submit + */ + submitOrder: function () { + var authData = {}, + cardData = {}, + secureData = {}; + + this.$selector.validate().form(); + this.$selector.trigger('afterValidate.beforeSubmit'); + + authData.clientKey = this.clientKey; + authData.apiLoginID = this.apiLoginID; + + cardData.cardNumber = $(this.getSelector('cc_number')).val(); + cardData.month = $(this.getSelector('cc_exp_month')).val(); + cardData.year = $(this.getSelector('cc_exp_year')).val(); + + if (this.useCvv) { + cardData.cardCode = $(this.getSelector('cc_cid')).val(); + } + + secureData.authData = authData; + secureData.cardData = cardData; + + this.disableEventListeners(); + + this.acceptjsClient.createTokens(secureData) + .always(function () { + $('body').trigger('processStop'); + this.enableEventListeners(); + }.bind(this)) + .done(function (tokens) { + this.setPaymentDetails(tokens); + this.placeOrder(); + }.bind(this)) + .fail(function (messages) { + this.tokens = null; + + if (messages.length > 0) { + this._showError(messages[0]); + } + }.bind(this)); + + return false; + }, + + /** + * Place order + */ + placeOrder: function () { + this.$selector.trigger('realOrder'); + }, + + /** + * Get jQuery selector + * + * @param {String} field + * @returns {String} + */ + getSelector: function (field) { + return '#' + this.code + '_' + field; + }, + + /** + * Show alert message + * + * @param {String} message + */ + _showError: function (message) { + alert({ + content: message + }); + }, + + /** + * Enable form event listeners + */ + enableEventListeners: function () { + this.$selector.on('submitOrder.authorizenetacceptjs', this.submitOrder.bind(this)); + }, + + /** + * Disable form event listeners + */ + disableEventListeners: function () { + this.$selector.off('submitOrder'); + this.$selector.off('submit'); + } + + }); +}); diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/web/js/payment-form.js b/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/web/js/payment-form.js new file mode 100644 index 0000000000000..68c2f22f6ed44 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/view/adminhtml/web/js/payment-form.js @@ -0,0 +1,18 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'Magento_AuthorizenetAcceptjs/js/authorizenet', + 'jquery' +], function (AuthorizenetAcceptjs, $) { + 'use strict'; + + return function (data, element) { + var $form = $(element), + config = data.config; + + config.active = $form.length > 0 && !$form.is(':hidden'); + new AuthorizenetAcceptjs(config); + }; +}); diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/base/requirejs-config.js b/app/code/Magento/AuthorizenetAcceptjs/view/base/requirejs-config.js new file mode 100644 index 0000000000000..83ddd1094ea1a --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/view/base/requirejs-config.js @@ -0,0 +1,19 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +var config = { + shim: { + acceptjs: { + exports: 'Accept' + }, + acceptjssandbox: { + exports: 'Accept' + } + }, + paths: { + acceptjssandbox: 'https://jstest.authorize.net/v1/Accept', + acceptjs: 'https://js.authorize.net/v1/Accept' + } +}; diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/acceptjs-client.js b/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/acceptjs-client.js new file mode 100644 index 0000000000000..935465f5298eb --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/acceptjs-client.js @@ -0,0 +1,73 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'jquery', + 'uiClass', + 'Magento_AuthorizenetAcceptjs/js/view/payment/acceptjs-factory', + 'Magento_AuthorizenetAcceptjs/js/view/payment/validator-handler' +], function ($, Class, acceptjsFactory, validatorHandler) { + 'use strict'; + + return Class.extend({ + defaults: { + environment: 'production' + }, + + /** + * @{inheritdoc} + */ + initialize: function () { + validatorHandler.initialize(); + + this._super(); + + return this; + }, + + /** + * Creates the token pair with the provided data + * + * @param {Object} data + * @return {jQuery.Deferred} + */ + createTokens: function (data) { + var deferred = $.Deferred(); + + if (this.acceptjsClient) { + this._createTokens(deferred, data); + } else { + acceptjsFactory(this.environment) + .done(function (client) { + this.acceptjsClient = client; + this._createTokens(deferred, data); + }.bind(this)); + } + + return deferred.promise(); + }, + + /** + * Creates a token from the payment information in the form + * + * @param {jQuery.Deferred} deferred + * @param {Object} data + */ + _createTokens: function (deferred, data) { + this.acceptjsClient.dispatchData(data, function (response) { + validatorHandler.validate(response, function (valid, messages) { + if (valid) { + deferred.resolve({ + opaqueDataDescriptor: response.opaqueData.dataDescriptor, + opaqueDataValue: response.opaqueData.dataValue + }); + } else { + deferred.reject(messages); + } + }); + }); + } + }); +}); diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/acceptjs-factory.js b/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/acceptjs-factory.js new file mode 100644 index 0000000000000..e98a204e36cee --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/acceptjs-factory.js @@ -0,0 +1,38 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'jquery' +], function ($) { + 'use strict'; + + return function (environment) { + var deferred = $.Deferred(), + dependency = 'acceptjs'; + + if (environment === 'sandbox') { + dependency = 'acceptjssandbox'; + } + + require([dependency], function (accept) { + var $body = $('body'); + + /* + * Acceptjs doesn't safely load dependent files which leads to a race condition when trying to use + * the sdk right away. + * @see https://community.developer.authorize.net/t5/Integration-and-Testing/ + * Dynamically-loading-Accept-js-E-WC-03-Accept-js-is-not-loaded/td-p/63283 + */ + $body.on('handshake.acceptjs', function () { + deferred.resolve(accept); + $body.off('handshake.acceptjs'); + }); + }, + deferred.reject + ); + + return deferred.promise(); + }; +}); diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/response-validator.js b/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/response-validator.js new file mode 100644 index 0000000000000..3c44ca2f9e490 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/response-validator.js @@ -0,0 +1,38 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'jquery', + 'mage/translate' +], function ($, $t) { + 'use strict'; + + return { + /** + * Validate Authorizenet-Acceptjs response + * + * @param {Object} context + * @returns {jQuery.Deferred} + */ + validate: function (context) { + var state = $.Deferred(), + messages = []; + + if (context.messages.resultCode === 'Ok') { + state.resolve(); + } else { + if (context.messages.message.length > 0) { + $.each(context.messages.message, function (index, element) { + messages.push($t(element.text)); + }); + } + state.reject(messages); + } + + return state.promise(); + } + }; +}); + diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/validator-handler.js b/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/validator-handler.js new file mode 100644 index 0000000000000..109f159c9a77c --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/view/base/web/js/view/payment/validator-handler.js @@ -0,0 +1,59 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'jquery', + 'Magento_AuthorizenetAcceptjs/js/view/payment/response-validator' +], function ($, responseValidator) { + 'use strict'; + + return { + validators: [], + + /** + * Init list of validators + */ + initialize: function () { + this.add(responseValidator); + }, + + /** + * Add new validator + * @param {Object} validator + */ + add: function (validator) { + this.validators.push(validator); + }, + + /** + * Run pull of validators + * @param {Object} context + * @param {Function} callback + */ + validate: function (context, callback) { + var self = this, + deferred; + + // no available validators + if (!self.validators.length) { + callback(true); + + return; + } + + // get list of deferred validators + deferred = $.map(self.validators, function (current) { + return current.validate(context); + }); + + $.when.apply($, deferred) + .done(function () { + callback(true); + }).fail(function (error) { + callback(false, error); + }); + } + }; +}); diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/AuthorizenetAcceptjs/view/frontend/layout/checkout_index_index.xml new file mode 100644 index 0000000000000..f31b06c9be9b9 --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/view/frontend/layout/checkout_index_index.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + uiComponent + + + + + + + + Magento_AuthorizenetAcceptjs/js/view/payment/authorizenet + + + true + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/frontend/web/js/view/payment/authorizenet.js b/app/code/Magento/AuthorizenetAcceptjs/view/frontend/web/js/view/payment/authorizenet.js new file mode 100644 index 0000000000000..a05fe739a444a --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/view/frontend/web/js/view/payment/authorizenet.js @@ -0,0 +1,20 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'uiComponent', + 'Magento_Checkout/js/model/payment/renderer-list' +], +function (Component, rendererList) { + 'use strict'; + + rendererList.push({ + type: 'authorizenet_acceptjs', + component: 'Magento_AuthorizenetAcceptjs/js/view/payment/method-renderer/authorizenet-accept' + }); + + /** Add view logic here if needed */ + return Component.extend({}); +}); diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/frontend/web/js/view/payment/method-renderer/authorizenet-accept.js b/app/code/Magento/AuthorizenetAcceptjs/view/frontend/web/js/view/payment/method-renderer/authorizenet-accept.js new file mode 100644 index 0000000000000..983318c4cdaaf --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/view/frontend/web/js/view/payment/method-renderer/authorizenet-accept.js @@ -0,0 +1,146 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'jquery', + 'Magento_Payment/js/view/payment/cc-form', + 'Magento_AuthorizenetAcceptjs/js/view/payment/acceptjs-client', + 'Magento_Checkout/js/model/full-screen-loader', + 'Magento_Ui/js/model/messageList', + 'Magento_Payment/js/model/credit-card-validation/validator' +], function ($, Component, AcceptjsClient, fullScreenLoader, globalMessageList) { + 'use strict'; + + return Component.extend({ + defaults: { + active: false, + template: 'Magento_AuthorizenetAcceptjs/payment/authorizenet-acceptjs', + tokens: null, + ccForm: 'Magento_Payment/payment/cc-form', + acceptjsClient: null + }, + + /** + * Set list of observable attributes + * + * @returns {exports.initObservable} + */ + initObservable: function () { + this._super() + .observe(['active']); + + return this; + }, + + /** + * @returns {String} + */ + getCode: function () { + return 'authorizenet_acceptjs'; + }, + + /** + * Initialize form elements for validation + */ + initFormElement: function (element) { + this.formElement = element; + this.acceptjsClient = AcceptjsClient({ + environment: window.checkoutConfig.payment[this.getCode()].environment + }); + $(this.formElement).validation(); + }, + + /** + * @returns {Object} + */ + getData: function () { + return { + method: this.getCode(), + 'additional_data': { + opaqueDataDescriptor: this.tokens ? this.tokens.opaqueDataDescriptor : null, + opaqueDataValue: this.tokens ? this.tokens.opaqueDataValue : null, + ccLast4: this.creditCardNumber().substr(-4) + } + }; + }, + + /** + * Check if payment is active + * + * @returns {Boolean} + */ + isActive: function () { + var active = this.getCode() === this.isChecked(); + + this.active(active); + + return active; + }, + + /** + * Prepare data to place order + */ + beforePlaceOrder: function () { + var authData = {}, + cardData = {}, + secureData = {}; + + if (!$(this.formElement).valid()) { + return; + } + + authData.clientKey = window.checkoutConfig.payment[this.getCode()].clientKey; + authData.apiLoginID = window.checkoutConfig.payment[this.getCode()].apiLoginID; + + cardData.cardNumber = this.creditCardNumber(); + cardData.month = this.creditCardExpMonth(); + cardData.year = this.creditCardExpYear(); + + if (this.hasVerification()) { + cardData.cardCode = this.creditCardVerificationNumber(); + } + + secureData.authData = authData; + secureData.cardData = cardData; + + fullScreenLoader.startLoader(); + + this.acceptjsClient.createTokens(secureData) + .always(function () { + fullScreenLoader.stopLoader(); + }) + .done(function (tokens) { + this.tokens = tokens; + this.placeOrder(); + }.bind(this)) + .fail(function (messages) { + this.tokens = null; + this._showErrors(messages); + }.bind(this)); + }, + + /** + * Should the cvv field be used + * + * @return {Boolean} + */ + hasVerification: function () { + return window.checkoutConfig.payment[this.getCode()].useCvv; + }, + + /** + * Show error messages + * + * @param {String[]} errorMessages + */ + _showErrors: function (errorMessages) { + $.each(errorMessages, function (index, message) { + globalMessageList.addErrorMessage({ + message: message + }); + }); + } + }); +}); diff --git a/app/code/Magento/AuthorizenetAcceptjs/view/frontend/web/template/payment/authorizenet-acceptjs.html b/app/code/Magento/AuthorizenetAcceptjs/view/frontend/web/template/payment/authorizenet-acceptjs.html new file mode 100644 index 0000000000000..6db52a2b1025e --- /dev/null +++ b/app/code/Magento/AuthorizenetAcceptjs/view/frontend/web/template/payment/authorizenet-acceptjs.html @@ -0,0 +1,45 @@ + +
+
+ + +
+
+ +
+ +
+
+ + +
+ +
+
+
+ +
+
+
+
diff --git a/app/code/Magento/Payment/Gateway/Validator/AbstractValidator.php b/app/code/Magento/Payment/Gateway/Validator/AbstractValidator.php index f1a8950514152..110fe10ee5c3b 100644 --- a/app/code/Magento/Payment/Gateway/Validator/AbstractValidator.php +++ b/app/code/Magento/Payment/Gateway/Validator/AbstractValidator.php @@ -3,11 +3,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + +declare(strict_types=1); + namespace Magento\Payment\Gateway\Validator; /** - * Class AbstractValidator - * @package Magento\Payment\Gateway\Validator + * Represents a basic validator shell that can create a result + * * @api * @since 100.0.2 */ @@ -33,7 +36,7 @@ public function __construct( * @param bool $isValid * @param array $fails * @param array $errorCodes - * @return void + * @return \Magento\Payment\Gateway\Validator\ResultInterface */ protected function createResult($isValid, array $fails = [], array $errorCodes = []) { diff --git a/app/code/Magento/Payment/Gateway/Validator/ValidatorComposite.php b/app/code/Magento/Payment/Gateway/Validator/ValidatorComposite.php index b7f1368ddabce..8ea97d31ed4d9 100644 --- a/app/code/Magento/Payment/Gateway/Validator/ValidatorComposite.php +++ b/app/code/Magento/Payment/Gateway/Validator/ValidatorComposite.php @@ -10,10 +10,9 @@ use Magento\Payment\Gateway\Validator\ResultInterfaceFactory; /** - * Class ValidatorComposite - * @package Magento\Payment\Gateway\Validator + * Compiles a result using the results of multiple validators + * * @api - * @since 100.0.2 */ class ValidatorComposite extends AbstractValidator { @@ -22,15 +21,22 @@ class ValidatorComposite extends AbstractValidator */ private $validators; + /** + * @var array + */ + private $chainBreakingValidators; + /** * @param ResultInterfaceFactory $resultFactory * @param TMapFactory $tmapFactory * @param array $validators + * @param array $chainBreakingValidators */ public function __construct( ResultInterfaceFactory $resultFactory, TMapFactory $tmapFactory, - array $validators = [] + array $validators = [], + array $chainBreakingValidators = [] ) { $this->validators = $tmapFactory->create( [ @@ -38,6 +44,7 @@ public function __construct( 'type' => ValidatorInterface::class ] ); + $this->chainBreakingValidators = $chainBreakingValidators; parent::__construct($resultFactory); } @@ -51,7 +58,8 @@ public function validate(array $validationSubject) { $isValid = true; $failsDescriptionAggregate = []; - foreach ($this->validators as $validator) { + $errorCodesAggregate = []; + foreach ($this->validators as $key => $validator) { $result = $validator->validate($validationSubject); if (!$result->isValid()) { $isValid = false; @@ -59,9 +67,16 @@ public function validate(array $validationSubject) $failsDescriptionAggregate, $result->getFailsDescription() ); + $errorCodesAggregate = array_merge( + $errorCodesAggregate, + $result->getErrorCodes() + ); + if (!empty($this->chainBreakingValidators[$key])) { + break; + } } } - return $this->createResult($isValid, $failsDescriptionAggregate); + return $this->createResult($isValid, $failsDescriptionAggregate, $errorCodesAggregate); } } diff --git a/app/code/Magento/Payment/Test/Unit/Gateway/Validator/ValidatorCompositeTest.php b/app/code/Magento/Payment/Test/Unit/Gateway/Validator/ValidatorCompositeTest.php index 7352cb7a4ac6d..5dec99e2a4b1b 100644 --- a/app/code/Magento/Payment/Test/Unit/Gateway/Validator/ValidatorCompositeTest.php +++ b/app/code/Magento/Payment/Test/Unit/Gateway/Validator/ValidatorCompositeTest.php @@ -13,9 +13,9 @@ class ValidatorCompositeTest extends \PHPUnit\Framework\TestCase public function testValidate() { $validationSubject = []; - $validator1 = $this->getMockBuilder(\Magento\Payment\Gateway\Validator\ValidatorInterface::class) + $validator1 = $this->getMockBuilder(ValidatorInterface::class) ->getMockForAbstractClass(); - $validator2 = $this->getMockBuilder(\Magento\Payment\Gateway\Validator\ValidatorInterface::class) + $validator2 = $this->getMockBuilder(ValidatorInterface::class) ->getMockForAbstractClass(); $tMapFactory = $this->getMockBuilder(\Magento\Framework\ObjectManager\TMapFactory::class) ->disableOriginalConstructor() @@ -30,8 +30,8 @@ public function testValidate() ->with( [ 'array' => [ - 'validator1' => \Magento\Payment\Gateway\Validator\ValidatorInterface::class, - 'validator2' => \Magento\Payment\Gateway\Validator\ValidatorInterface::class + 'validator1' => ValidatorInterface::class, + 'validator2' => ValidatorInterface::class ], 'type' => ValidatorInterface::class ] @@ -54,6 +54,9 @@ public function testValidate() $resultFail->expects(static::once()) ->method('getFailsDescription') ->willReturn(['Fail']); + $resultFail->expects(static::once()) + ->method('getErrorCodes') + ->willReturn(['abc123']); $validator1->expects(static::once()) ->method('validate') @@ -76,7 +79,7 @@ public function testValidate() [ 'isValid' => false, 'failsDescription' => ['Fail'], - 'errorCodes' => [] + 'errorCodes' => ['abc123'] ] ) ->willReturn($compositeResult); @@ -85,10 +88,91 @@ public function testValidate() $resultFactory, $tMapFactory, [ - 'validator1' => \Magento\Payment\Gateway\Validator\ValidatorInterface::class, - 'validator2' => \Magento\Payment\Gateway\Validator\ValidatorInterface::class + 'validator1' => ValidatorInterface::class, + 'validator2' => ValidatorInterface::class ] ); static::assertSame($compositeResult, $validatorComposite->validate($validationSubject)); } + + public function testValidateChainBreaksCorrectly() + { + $validationSubject = []; + $validator1 = $this->getMockBuilder(ValidatorInterface::class) + ->getMockForAbstractClass(); + $validator2 = $this->getMockBuilder(ValidatorInterface::class) + ->getMockForAbstractClass(); + $tMapFactory = $this->getMockBuilder(\Magento\Framework\ObjectManager\TMapFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $tMap = $this->getMockBuilder(\Magento\Framework\ObjectManager\TMap::class) + ->disableOriginalConstructor() + ->getMock(); + + $tMapFactory->expects($this->once()) + ->method('create') + ->with( + [ + 'array' => [ + 'validator1' => ValidatorInterface::class, + 'validator2' => ValidatorInterface::class + ], + 'type' => ValidatorInterface::class + ] + ) + ->willReturn($tMap); + $tMap->expects($this->once()) + ->method('getIterator') + ->willReturn(new \ArrayIterator([$validator1, $validator2])); + + $resultFail = $this->getMockBuilder(\Magento\Payment\Gateway\Validator\ResultInterface::class) + ->getMockForAbstractClass(); + $resultFail->expects($this->once()) + ->method('isValid') + ->willReturn(false); + $resultFail->expects($this->once()) + ->method('getFailsDescription') + ->willReturn(['Fail']); + $resultFail->expects($this->once()) + ->method('getErrorCodes') + ->willReturn(['abc123']); + + $validator1->expects($this->once()) + ->method('validate') + ->with($validationSubject) + ->willReturn($resultFail); + + // Assert this is never called + $validator2->expects($this->never()) + ->method('validate'); + + $compositeResult = $this->getMockBuilder(\Magento\Payment\Gateway\Validator\ResultInterface::class) + ->getMockForAbstractClass(); + $resultFactory = $this->getMockBuilder(\Magento\Payment\Gateway\Validator\ResultInterfaceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $resultFactory->expects($this->once()) + ->method('create') + ->with( + [ + 'isValid' => false, + 'failsDescription' => ['Fail'], + 'errorCodes' => ['abc123'] + ] + ) + ->willReturn($compositeResult); + + $validatorComposite = new ValidatorComposite( + $resultFactory, + $tMapFactory, + [ + 'validator1' => ValidatorInterface::class, + 'validator2' => ValidatorInterface::class + ], + ['validator1'] + ); + $this->assertSame($compositeResult, $validatorComposite->validate($validationSubject)); + } } diff --git a/composer.json b/composer.json index 3222de2d1fe0f..17e32e88442e7 100644 --- a/composer.json +++ b/composer.json @@ -104,6 +104,7 @@ "magento/module-asynchronous-operations": "*", "magento/module-authorization": "*", "magento/module-authorizenet": "*", + "magento/module-authorizenet-acceptjs": "*", "magento/module-advanced-search": "*", "magento/module-backend": "*", "magento/module-backup": "*", diff --git a/composer.lock b/composer.lock index 697e7df3e19aa..1f09fc746d60b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3f58ddc5609e6a934ee3706006357646", + "content-hash": "4b6f2eede23af2202078a4c3043616c6", "packages": [ { "name": "braintree/braintree_php", @@ -2165,7 +2165,7 @@ }, { "name": "Gert de Pagter", - "email": "backendtea@gmail.com" + "email": "BackEndTea@gmail.com" } ], "description": "Symfony polyfill for ctype functions", diff --git a/dev/tests/integration/testsuite/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponseTest.php b/dev/tests/integration/testsuite/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponseTest.php index 28d4395e7e413..7ab55dc7fd928 100644 --- a/dev/tests/integration/testsuite/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponseTest.php +++ b/dev/tests/integration/testsuite/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponseTest.php @@ -23,7 +23,7 @@ public function testUnauthorizedRequest() $data = [ 'x_response_code' => 1, 'x_response_reason_code' => 1, - 'x_invoice_num' => 1, + 'x_invoice_num' => '1', 'x_amount' => 16, 'x_trans_id' => '32iiw5ve', 'x_card_type' => 'American Express', @@ -48,7 +48,7 @@ public function testSuccess() $data = [ 'x_response_code' => 1, 'x_response_reason_code' => 1, - 'x_invoice_num' => 1, + 'x_invoice_num' => '1', 'x_amount' => 16, 'x_trans_id' => '32iiw5ve', 'x_card_type' => 'American Express', diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/full_order_with_capture.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/full_order_with_capture.php new file mode 100644 index 0000000000000..4ef5a4dd14c08 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/full_order_with_capture.php @@ -0,0 +1,45 @@ +getPayment(); +$payment->setMethod(Config::METHOD); +$payment->setAuthorizationTransaction(false); +$payment->setParentTransactionId(4321); + + +/** @var OrderRepository $orderRepo */ +$orderRepo = $objectManager->get(OrderRepository::class); +$orderRepo->save($order); + +/** @var TransactionBuilder $transactionBuilder */ +$transactionBuilder = $objectManager->create(TransactionBuilder::class); +$transactionAuthorize = $transactionBuilder->setPayment($payment) + ->setOrder($order) + ->setTransactionId(1234) + ->build(Transaction::TYPE_AUTH); +$transactionCapture = $transactionBuilder->setPayment($payment) + ->setOrder($order) + ->setTransactionId(4321) + ->build(Transaction::TYPE_CAPTURE); + +$transactionRepository = $objectManager->create(TransactionRepositoryInterface::class); +$transactionRepository->save($transactionAuthorize); +$transactionRepository->save($transactionCapture); diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/full_order_with_capture_rollback.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/full_order_with_capture_rollback.php new file mode 100644 index 0000000000000..1a2cb2532fe52 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/full_order_with_capture_rollback.php @@ -0,0 +1,28 @@ +get(SearchCriteriaBuilder::class); +$searchCriteria = $searchCriteriaBuilder->addFilter('increment_id', '100000001') + ->create(); + +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +$items = $orderRepository->getList($searchCriteria) + ->getItems(); + +foreach ($items as $item) { + $orderRepository->delete($item); +} + +require __DIR__ . '/../../../Magento/Catalog/_files/product_simple_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/order_auth_only.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/order_auth_only.php new file mode 100644 index 0000000000000..b1d0521c9c610 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/order_auth_only.php @@ -0,0 +1,74 @@ +create(Address::class, ['data' => $addressData]); +$billingAddress->setAddressType('billing'); + +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null) + ->setAddressType('shipping'); + +/** @var OrderItem $orderItem */ +$orderItem = $objectManager->create(OrderItem::class); +$orderItem->setProductId($product->getId()) + ->setQtyOrdered(2) + ->setBasePrice($product->getPrice()) + ->setPrice($product->getPrice()) + ->setRowTotal($product->getPrice()) + ->setProductType('simple'); + +require __DIR__ . '/payment.php'; + +$order = $objectManager->create(Order::class); +$order->setIncrementId('100000002') + ->setSubtotal($product->getPrice() * 2) + ->setBaseSubtotal($product->getPrice() * 2) + ->setCustomerEmail('admin@example.com') + ->setCustomerIsGuest(true) + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->setStoreId( + $objectManager->get(StoreManagerInterface::class)->getStore() + ->getId() + ) + ->addItem($orderItem) + ->setPayment($payment); + +$payment->setParentTransactionId(1234); + +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +$orderRepository->save($order); + +/** @var TransactionBuilder $transactionBuilder */ +$transactionBuilder = $objectManager->create(TransactionBuilder::class); +$transactionAuthorize = $transactionBuilder->setPayment($payment) + ->setOrder($order) + ->setTransactionId(1234) + ->build(Transaction::TYPE_AUTH); + +$transactionAuthorize->setAdditionalInformation('real_transaction_id', '1234'); + +$transactionRepository = $objectManager->create(TransactionRepositoryInterface::class); +$transactionRepository->save($transactionAuthorize); diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/order_auth_only_rollback.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/order_auth_only_rollback.php new file mode 100644 index 0000000000000..5a65a1fc0d0c7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/order_auth_only_rollback.php @@ -0,0 +1,9 @@ +create(Address::class, ['data' => $addressData]); +$billingAddress->setAddressType('billing'); + +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null) + ->setAddressType('shipping'); + +/** @var OrderItem $orderItem */ +$orderItem = $objectManager->create(OrderItem::class); +$orderItem->setProductId($product->getId()) + ->setQtyOrdered(2) + ->setBasePrice($product->getPrice()) + ->setPrice($product->getPrice()) + ->setRowTotal($product->getPrice()) + ->setProductType('simple'); + +require __DIR__ . '/payment.php'; + +$order = $objectManager->create(Order::class); +$order->setIncrementId('100000002') + ->setSubtotal($product->getPrice() * 2) + ->setBaseSubtotal($product->getPrice() * 2) + ->setCustomerEmail('admin@example.com') + ->setCustomerIsGuest(true) + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->setStoreId( + $objectManager->get(StoreManagerInterface::class)->getStore() + ->getId() + ) + ->addItem($orderItem) + ->setPayment($payment); + +$payment->setParentTransactionId(4321); + +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +$orderRepository->save($order); + +/** @var TransactionBuilder $transactionBuilder */ +$transactionBuilder = $objectManager->create(TransactionBuilder::class); +$transactionAuthorize = $transactionBuilder->setPayment($payment) + ->setOrder($order) + ->setTransactionId(1234) + ->build(Transaction::TYPE_AUTH); +$transactionCapture = $transactionBuilder->setPayment($payment) + ->setOrder($order) + ->setTransactionId(4321) + ->build(Transaction::TYPE_CAPTURE); + +$transactionRepository = $objectManager->create(TransactionRepositoryInterface::class); +$transactionRepository->save($transactionAuthorize); +$transactionRepository->save($transactionCapture); diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/order_captured_rollback.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/order_captured_rollback.php new file mode 100644 index 0000000000000..a2da0b639e98d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/order_captured_rollback.php @@ -0,0 +1,28 @@ +get(SearchCriteriaBuilder::class); +$searchCriteria = $searchCriteriaBuilder->addFilter('increment_id', '100000002') + ->create(); + +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +$items = $orderRepository->getList($searchCriteria) + ->getItems(); + +foreach ($items as $item) { + $orderRepository->delete($item); +} + +require __DIR__ . '/../../../Magento/Catalog/_files/product_simple_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/payment.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/payment.php new file mode 100644 index 0000000000000..5b15e356a7d8d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Fixture/payment.php @@ -0,0 +1,19 @@ +create(Payment::class); +$payment->setMethod(Config::METHOD); +$payment->setAuthorizationTransaction(true); diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/AbstractTest.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/AbstractTest.php new file mode 100644 index 0000000000000..f1458a19012f3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/AbstractTest.php @@ -0,0 +1,91 @@ +loadArea(Area::AREA_FRONTEND); + $this->objectManager = Bootstrap::getObjectManager(); + $this->clientMock = $this->createMock(ZendClient::class); + $this->responseMock = $this->createMock(Zend_Http_Response::class); + $this->clientMock->method('request') + ->willReturn($this->responseMock); + $this->clientMock->method('setUri') + ->with('https://apitest.authorize.net/xml/v1/request.api'); + $clientFactoryMock = $this->createMock(ZendClientFactory::class); + $clientFactoryMock->method('create') + ->willReturn($this->clientMock); + /** @var PaymentDataObjectFactory $paymentFactory */ + $this->paymentFactory = $this->objectManager->get(PaymentDataObjectFactory::class); + $this->objectManager->addSharedInstance($clientFactoryMock, ZendClientFactory::class); + } + + protected function tearDown() + { + $this->objectManager->removeSharedInstance(ZendClientFactory::class); + parent::tearDown(); + } + + protected function getOrderWithIncrementId(string $incrementId): Order + { + /** @var OrderRepositoryInterface $orderRepository */ + $orderRepository = $this->objectManager->get(OrderRepositoryInterface::class); + $searchCriteria = $this->objectManager->get(SearchCriteriaBuilder::class) + ->addFilter('increment_id', $incrementId) + ->create(); + /** @var Order $order */ + $order = current( + $orderRepository->getList($searchCriteria) + ->getItems() + ); + + return $order; + } +} diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/AcceptFdsCommandTest.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/AcceptFdsCommandTest.php new file mode 100644 index 0000000000000..394d9de6684c4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/AcceptFdsCommandTest.php @@ -0,0 +1,49 @@ +objectManager->get('AuthorizenetAcceptjsCommandPool'); + $command = $commandPool->get('accept_fds'); + + $order = $this->getOrderWithIncrementId('100000002'); + $payment = $order->getPayment(); + $paymentDO = $this->paymentFactory->create($payment); + + $expectedRequest = include __DIR__ . '/../../_files/expected_request/accept_fds.php'; + $response = include __DIR__ . '/../../_files/response/generic_success.php'; + + $this->clientMock->expects($this->once()) + ->method('setRawData') + ->with(json_encode($expectedRequest), 'application/json'); + + $this->responseMock->expects($this->once()) + ->method('getBody') + ->willReturn(json_encode($response)); + + $command->execute([ + 'payment' => $paymentDO + ]); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/AuthorizeCommandTest.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/AuthorizeCommandTest.php new file mode 100644 index 0000000000000..9affd80be0600 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/AuthorizeCommandTest.php @@ -0,0 +1,70 @@ +objectManager->get('AuthorizenetAcceptjsCommandPool'); + $command = $commandPool->get('authorize'); + + $order = include __DIR__ . '/../../_files/full_order.php'; + $payment = $order->getPayment(); + + $paymentDO = $this->paymentFactory->create($payment); + + $expectedRequest = include __DIR__ . '/../../_files/expected_request/authorize.php'; + $response = include __DIR__ . '/../../_files/response/authorize.php'; + + $this->clientMock->method('setRawData') + ->with(json_encode($expectedRequest), 'application/json'); + + $this->responseMock->method('getBody') + ->willReturn(json_encode($response)); + + $command->execute([ + 'payment' => $paymentDO, + 'amount' => 100.00 + ]); + + /** @var Payment $payment */ + $rawDetails = [ + 'authCode' => 'abc123', + 'avsResultCode' => 'Y', + 'cvvResultCode' => 'P', + 'cavvResultCode' => '2', + 'accountType' => 'Visa', + ]; + $this->assertSame('1111', $payment->getCcLast4()); + $this->assertSame('Y', $payment->getCcAvsStatus()); + $this->assertFalse($payment->getData('is_transaction_closed')); + + $transactionDetails = $payment->getTransactionAdditionalInfo(); + foreach ($rawDetails as $key => $value) { + $this->assertSame($value, $payment->getAdditionalInformation($key)); + $this->assertSame($value, $transactionDetails[Transaction::RAW_DETAILS][$key]); + } + + $this->assertSame('123456', $payment->getTransactionId()); + $this->assertSame('123456', $transactionDetails['real_transaction_id']); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/CancelCommandTest.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/CancelCommandTest.php new file mode 100644 index 0000000000000..aa606a50ae67a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/CancelCommandTest.php @@ -0,0 +1,62 @@ +objectManager->get('AuthorizenetAcceptjsCommandPool'); + $command = $commandPool->get($commandName); + + $order = $this->getOrderWithIncrementId('100000002'); + $payment = $order->getPayment(); + $paymentDO = $this->paymentFactory->create($payment); + + $expectedRequest = include __DIR__ . '/../../_files/expected_request/void.php'; + $response = include __DIR__ . '/../../_files/response/void.php'; + + $this->clientMock->method('setRawData') + ->with(json_encode($expectedRequest), 'application/json'); + + $this->responseMock->method('getBody') + ->willReturn(json_encode($response)); + + $command->execute([ + 'payment' => $paymentDO + ]); + + /** @var Payment $payment */ + + $this->assertTrue($payment->getIsTransactionClosed()); + $this->assertTrue($payment->getShouldCloseParentTransaction()); + $this->assertArrayNotHasKey('real_transaction_id', $payment->getTransactionAdditionalInfo()); + } + + public function aliasesProvider() + { + return [ + ['cancel'], + ['deny_payment'] + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/FetchTransactionInfoCommandTest.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/FetchTransactionInfoCommandTest.php new file mode 100644 index 0000000000000..1651dfc7db3d9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/FetchTransactionInfoCommandTest.php @@ -0,0 +1,184 @@ +objectManager->get('AuthorizenetAcceptjsCommandPool'); + $command = $commandPool->get('fetch_transaction_information'); + + $order = $this->getOrderWithIncrementId('100000002'); + $payment = $order->getPayment(); + $paymentDO = $this->paymentFactory->create($payment); + + $expectedRequest = include __DIR__ . '/../../_files/expected_request/transaction_details_authorized.php'; + $response = include __DIR__ . '/../../_files/response/transaction_details_authorized.php'; + + $this->clientMock->method('setRawData') + ->with(json_encode($expectedRequest), 'application/json'); + + $this->responseMock->method('getBody') + ->willReturn(json_encode($response)); + + $result = $command->execute([ + 'payment' => $paymentDO + ]); + + $expected = [ + 'transId' => '1234', + 'transactionType' => 'authOnlyTransaction' + ]; + $this->assertSame($expected, $result); + + /** @var Payment $payment */ + $this->assertTrue($payment->getIsTransactionApproved()); + $this->assertFalse($payment->getIsTransactionDenied()); + } + + /** + * @magentoConfigFixture default_store payment/authorizenet_acceptjs/environment sandbox + * @magentoConfigFixture default_store payment/authorizenet_acceptjs/login someusername + * @magentoConfigFixture default_store payment/authorizenet_acceptjs/trans_key somepassword + * @magentoConfigFixture default_store payment/authorizenet_acceptjs/trans_signature_key abc + * * @magentoConfigFixture default_store payment/authorizenet_acceptjs/transactionSyncKeys transId,transactionType + * @magentoDataFixture Magento/AuthorizenetAcceptjs/Fixture/order_auth_only.php + */ + public function testTransactionVoided() + { + /** @var CommandPoolInterface $commandPool */ + $commandPool = $this->objectManager->get('AuthorizenetAcceptjsCommandPool'); + $command = $commandPool->get('fetch_transaction_information'); + + $order = $this->getOrderWithIncrementId('100000002'); + $payment = $order->getPayment(); + $paymentDO = $this->paymentFactory->create($payment); + + $expectedRequest = include __DIR__ . '/../../_files/expected_request/transaction_details_authorized.php'; + $response = include __DIR__ . '/../../_files/response/transaction_details_voided.php'; + + $this->clientMock->method('setRawData') + ->with(json_encode($expectedRequest), 'application/json'); + + $this->responseMock->method('getBody') + ->willReturn(json_encode($response)); + + $result = $command->execute([ + 'payment' => $paymentDO + ]); + + $expected = [ + 'transId' => '1234', + 'transactionType' => 'authOnlyTransaction' + ]; + $this->assertSame($expected, $result); + + /** @var Payment $payment */ + $this->assertFalse($payment->getIsTransactionApproved()); + $this->assertTrue($payment->getIsTransactionDenied()); + } + + /** + * @magentoConfigFixture default_store payment/authorizenet_acceptjs/environment sandbox + * @magentoConfigFixture default_store payment/authorizenet_acceptjs/login someusername + * @magentoConfigFixture default_store payment/authorizenet_acceptjs/trans_key somepassword + * @magentoConfigFixture default_store payment/authorizenet_acceptjs/trans_signature_key abc + * @magentoConfigFixture default_store payment/authorizenet_acceptjs/transactionSyncKeys transId,transactionType + * @magentoDataFixture Magento/AuthorizenetAcceptjs/Fixture/order_auth_only.php + */ + public function testTransactionDenied() + { + /** @var CommandPoolInterface $commandPool */ + $commandPool = $this->objectManager->get('AuthorizenetAcceptjsCommandPool'); + $command = $commandPool->get('fetch_transaction_information'); + + $order = $this->getOrderWithIncrementId('100000002'); + $payment = $order->getPayment(); + $paymentDO = $this->paymentFactory->create($payment); + + $expectedRequest = include __DIR__ . '/../../_files/expected_request/transaction_details_authorized.php'; + $response = include __DIR__ . '/../../_files/response/transaction_details_voided.php'; + + $this->clientMock->method('setRawData') + ->with(json_encode($expectedRequest), 'application/json'); + + $this->responseMock->method('getBody') + ->willReturn(json_encode($response)); + + $result = $command->execute([ + 'payment' => $paymentDO + ]); + + $expected = [ + 'transId' => '1234', + 'transactionType' => 'authOnlyTransaction' + ]; + $this->assertSame($expected, $result); + + /** @var Payment $payment */ + $this->assertFalse($payment->getIsTransactionApproved()); + $this->assertTrue($payment->getIsTransactionDenied()); + } + + /** + * @magentoConfigFixture default_store payment/authorizenet_acceptjs/environment sandbox + * @magentoConfigFixture default_store payment/authorizenet_acceptjs/login someusername + * @magentoConfigFixture default_store payment/authorizenet_acceptjs/trans_key somepassword + * @magentoConfigFixture default_store payment/authorizenet_acceptjs/trans_signature_key abc + * @magentoConfigFixture default_store payment/authorizenet_acceptjs/transactionSyncKeys transId,transactionType + * @magentoDataFixture Magento/AuthorizenetAcceptjs/Fixture/order_auth_only.php + */ + public function testTransactionPending() + { + /** @var CommandPoolInterface $commandPool */ + $commandPool = $this->objectManager->get('AuthorizenetAcceptjsCommandPool'); + $command = $commandPool->get('fetch_transaction_information'); + + $order = $this->getOrderWithIncrementId('100000002'); + $payment = $order->getPayment(); + $paymentDO = $this->paymentFactory->create($payment); + + $expectedRequest = include __DIR__ . '/../../_files/expected_request/transaction_details_authorized.php'; + $response = include __DIR__ . '/../../_files/response/transaction_details_fds_pending.php'; + + $this->clientMock->method('setRawData') + ->with(json_encode($expectedRequest), 'application/json'); + + $this->responseMock->method('getBody') + ->willReturn(json_encode($response)); + + $result = $command->execute([ + 'payment' => $paymentDO + ]); + + $expected = [ + 'transId' => '1234', + 'transactionType' => 'authOnlyTransaction' + ]; + $this->assertSame($expected, $result); + + /** @var Payment $payment */ + $this->assertNull($payment->getIsTransactionApproved()); + $this->assertNull($payment->getIsTransactionDenied()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/RefundSettledCommandTest.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/RefundSettledCommandTest.php new file mode 100644 index 0000000000000..6e06d749f3906 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/RefundSettledCommandTest.php @@ -0,0 +1,53 @@ +objectManager->get('AuthorizenetAcceptjsCommandPool'); + $command = $commandPool->get('refund_settled'); + + $order = $this->getOrderWithIncrementId('100000001'); + $payment = $order->getPayment(); + + $paymentDO = $this->paymentFactory->create($payment); + + $expectedRequest = include __DIR__ . '/../../_files/expected_request/refund.php'; + $response = include __DIR__ . '/../../_files/response/refund.php'; + + $this->clientMock->method('setRawData') + ->with(json_encode($expectedRequest), 'application/json'); + + $this->responseMock->method('getBody') + ->willReturn(json_encode($response)); + + $command->execute([ + 'payment' => $paymentDO, + 'amount' => 100.00 + ]); + + /** @var Payment $payment */ + $this->assertTrue($payment->getIsTransactionClosed()); + $this->assertSame('5678', $payment->getTransactionId()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/SaleCommandTest.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/SaleCommandTest.php new file mode 100644 index 0000000000000..7ae03d36cb752 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/SaleCommandTest.php @@ -0,0 +1,71 @@ +objectManager->get('AuthorizenetAcceptjsCommandPool'); + $command = $commandPool->get('sale'); + + $order = include __DIR__ . '/../../_files/full_order.php'; + $payment = $order->getPayment(); + + $paymentDO = $this->paymentFactory->create($payment); + + $expectedRequest = include __DIR__ . '/../../_files/expected_request/sale.php'; + $response = include __DIR__ . '/../../_files/response/sale.php'; + + $this->clientMock->method('setRawData') + ->with(json_encode($expectedRequest), 'application/json'); + + $this->responseMock->method('getBody') + ->willReturn(json_encode($response)); + + $command->execute([ + 'payment' => $paymentDO, + 'amount' => 100.00 + ]); + + /** @var Payment $payment */ + $rawDetails = [ + 'authCode' => 'abc123', + 'avsResultCode' => 'Y', + 'cvvResultCode' => 'P', + 'cavvResultCode' => '2', + 'accountType' => 'Visa', + ]; + $this->assertSame('1111', $payment->getCcLast4()); + $this->assertSame('Y', $payment->getCcAvsStatus()); + + $transactionDetails = $payment->getTransactionAdditionalInfo(); + foreach ($rawDetails as $key => $value) { + $this->assertSame($value, $payment->getAdditionalInformation($key)); + $this->assertSame($value, $transactionDetails[Transaction::RAW_DETAILS][$key]); + } + + $this->assertSame('123456', $payment->getTransactionId()); + $this->assertSame('123456', $transactionDetails['real_transaction_id']); + $this->assertTrue($payment->getShouldCloseParentTransaction()); + $this->assertFalse($payment->getData('is_transaction_closed')); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/SettleCommandTest.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/SettleCommandTest.php new file mode 100644 index 0000000000000..bb0a259b165bf --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/SettleCommandTest.php @@ -0,0 +1,52 @@ +objectManager->get('AuthorizenetAcceptjsCommandPool'); + $command = $commandPool->get('settle'); + + $order = $this->getOrderWithIncrementId('100000002'); + $payment = $order->getPayment(); + + $paymentDO = $this->paymentFactory->create($payment); + + $expectedRequest = include __DIR__ . '/../../_files/expected_request/settle.php'; + $response = include __DIR__ . '/../../_files/response/settle.php'; + + $this->clientMock->method('setRawData') + ->with(json_encode($expectedRequest), 'application/json'); + + $this->responseMock->method('getBody') + ->willReturn(json_encode($response)); + + $command->execute([ + 'payment' => $paymentDO, + 'amount' => 100.00 + ]); + + /** @var Payment $payment */ + $this->assertTrue($payment->getShouldCloseParentTransaction()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/TransactionDetailsCommandTest.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/TransactionDetailsCommandTest.php new file mode 100644 index 0000000000000..d81cffc413b59 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/TransactionDetailsCommandTest.php @@ -0,0 +1,50 @@ +objectManager->get('AuthorizenetAcceptjsCommandPool'); + $command = $commandPool->get('get_transaction_details'); + + $order = $this->getOrderWithIncrementId('100000002'); + $payment = $order->getPayment(); + $paymentDO = $this->paymentFactory->create($payment); + + $expectedRequest = include __DIR__ . '/../../_files/expected_request/transaction_details.php'; + $response = include __DIR__ . '/../../_files/response/transaction_details_settled_capture.php'; + + $this->clientMock->method('setRawData') + ->with(json_encode($expectedRequest), 'application/json'); + + $this->responseMock->method('getBody') + ->willReturn(json_encode($response)); + + $result = $command->execute([ + 'payment' => $paymentDO + ]); + + $resultData = $result->get(); + + $this->assertEquals($response, $resultData); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/VoidCommandTest.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/VoidCommandTest.php new file mode 100644 index 0000000000000..f74f8542bfdc3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/Command/VoidCommandTest.php @@ -0,0 +1,53 @@ +objectManager->get('AuthorizenetAcceptjsCommandPool'); + $command = $commandPool->get('void'); + + $order = $this->getOrderWithIncrementId('100000002'); + $payment = $order->getPayment(); + $paymentDO = $this->paymentFactory->create($payment); + + $expectedRequest = include __DIR__ . '/../../_files/expected_request/void.php'; + $response = include __DIR__ . '/../../_files/response/void.php'; + + $this->clientMock->method('setRawData') + ->with(json_encode($expectedRequest), 'application/json'); + + $this->responseMock->method('getBody') + ->willReturn(json_encode($response)); + + $command->execute([ + 'payment' => $paymentDO + ]); + + /** @var Payment $payment */ + + $this->assertTrue($payment->getIsTransactionClosed()); + $this->assertTrue($payment->getShouldCloseParentTransaction()); + $this->assertEquals('1234', $payment->getTransactionAdditionalInfo()['real_transaction_id']); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/ConfigTest.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/ConfigTest.php new file mode 100644 index 0000000000000..7e6aeda5a7a6d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/Gateway/ConfigTest.php @@ -0,0 +1,44 @@ +objectManager = Bootstrap::getObjectManager(); + } + + public function testVerifyConfiguration() + { + /** @var Adapter $paymentAdapter */ + $paymentAdapter = $this->objectManager->get('AuthorizenetAcceptjsFacade'); + + $this->assertEquals('authorizenet_acceptjs', $paymentAdapter->getCode()); + $this->assertTrue($paymentAdapter->canAuthorize()); + $this->assertTrue($paymentAdapter->canCapture()); + $this->assertFalse($paymentAdapter->canCapturePartial()); + $this->assertTrue($paymentAdapter->canRefund()); + $this->assertTrue($paymentAdapter->canUseCheckout()); + $this->assertTrue($paymentAdapter->canVoid()); + $this->assertTrue($paymentAdapter->canUseInternal()); + $this->assertTrue($paymentAdapter->canEdit()); + $this->assertTrue($paymentAdapter->canFetchTransactionInfo()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/accept_fds.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/accept_fds.php new file mode 100644 index 0000000000000..d843de1c2cac0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/accept_fds.php @@ -0,0 +1,20 @@ + [ + 'merchantAuthentication' => [ + 'name' => 'someusername', + 'transactionKey' => 'somepassword' + ], + 'heldTransactionRequest' => [ + 'action' => 'approve', + 'refTransId' => '1234', + ] + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/authorize.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/authorize.php new file mode 100644 index 0000000000000..16debdb2ef820 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/authorize.php @@ -0,0 +1,66 @@ + [ + 'merchantAuthentication' =>[ + 'name' => 'someusername', + 'transactionKey' => 'somepassword', + ], + 'transactionRequest' => [ + 'transactionType' => 'authOnlyTransaction', + 'amount' => '100.00', + 'payment' => [ + 'opaqueData' => [ + 'dataDescriptor' => 'mydescriptor', + 'dataValue' => 'myvalue', + ], + ], + 'solution' => [ + 'id' => 'AAA102993', + ], + 'order' => [ + 'invoiceNumber' => '100000001', + ], + 'poNumber' => null, + 'customer' => [ + 'id' => 1, + 'email' => 'admin@example.com', + ], + 'billTo' => [ + 'firstName' => 'firstname', + 'lastName' => 'lastname', + 'company' => '', + 'address' => 'street', + 'city' => 'Los Angeles', + 'state' => 'CA', + 'zip' => '11111', + 'country' => 'US', + ], + 'shipTo' => [ + 'firstName' => 'John', + 'lastName' => 'Doe', + 'company' => '', + 'address' => '6161 West Centinela Avenue', + 'city' => 'Los Angeles', + 'state' => 'CA', + 'zip' => '11111', + 'country' => 'US', + ], + 'customerIP' => '127.0.0.1', + 'userFields' => [ + 'userField' => [ + [ + 'name' => 'transactionType', + 'value' => 'authOnlyTransaction', + ], + ], + ], + ], + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/refund.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/refund.php new file mode 100644 index 0000000000000..5ed331d076f66 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/refund.php @@ -0,0 +1,56 @@ + [ + 'merchantAuthentication' =>[ + 'name' => 'someusername', + 'transactionKey' => 'somepassword', + ], + 'transactionRequest' => [ + 'transactionType' => 'refundTransaction', + 'amount' => '100.00', + 'payment' => [ + 'creditCard' => [ + 'cardNumber' => '1111', + 'expirationDate' => 'XXXX' + ] + ], + 'refTransId' => '4321', + 'order' => [ + 'invoiceNumber' => '100000001', + ], + 'poNumber' => null, + 'customer' => [ + 'id' => '1', + 'email' => 'admin@example.com', + ], + 'billTo' => [ + 'firstName' => 'firstname', + 'lastName' => 'lastname', + 'company' => '', + 'address' => 'street', + 'city' => 'Los Angeles', + 'state' => 'CA', + 'zip' => '11111', + 'country' => 'US', + ], + 'shipTo' => [ + 'firstName' => 'John', + 'lastName' => 'Doe', + 'company' => '', + 'address' => '6161 West Centinela Avenue', + 'city' => 'Los Angeles', + 'state' => 'CA', + 'zip' => '11111', + 'country' => 'US', + ], + 'customerIP' => '127.0.0.1' + ], + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/sale.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/sale.php new file mode 100644 index 0000000000000..4514acbcb6646 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/sale.php @@ -0,0 +1,66 @@ + [ + 'merchantAuthentication' =>[ + 'name' => 'someusername', + 'transactionKey' => 'somepassword', + ], + 'transactionRequest' => [ + 'transactionType' => 'authCaptureTransaction', + 'amount' => '100.00', + 'payment' => [ + 'opaqueData' => [ + 'dataDescriptor' => 'mydescriptor', + 'dataValue' => 'myvalue', + ], + ], + 'solution' => [ + 'id' => 'AAA102993', + ], + 'order' => [ + 'invoiceNumber' => '100000001', + ], + 'poNumber' => null, + 'customer' => [ + 'id' => 1, + 'email' => 'admin@example.com', + ], + 'billTo' => [ + 'firstName' => 'firstname', + 'lastName' => 'lastname', + 'company' => '', + 'address' => 'street', + 'city' => 'Los Angeles', + 'state' => 'CA', + 'zip' => '11111', + 'country' => 'US', + ], + 'shipTo' => [ + 'firstName' => 'John', + 'lastName' => 'Doe', + 'company' => '', + 'address' => '6161 West Centinela Avenue', + 'city' => 'Los Angeles', + 'state' => 'CA', + 'zip' => '11111', + 'country' => 'US', + ], + 'customerIP' => '127.0.0.1', + 'userFields' => [ + 'userField' => [ + [ + 'name' => 'transactionType', + 'value' => 'authCaptureTransaction', + ], + ], + ], + ], + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/settle.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/settle.php new file mode 100644 index 0000000000000..b4fa88cc1e5a9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/settle.php @@ -0,0 +1,28 @@ + [ + 'merchantAuthentication' =>[ + 'name' => 'someusername', + 'transactionKey' => 'somepassword', + ], + 'transactionRequest' => [ + 'transactionType' => 'priorAuthCaptureTransaction', + 'refTransId' => '1234', + 'userFields' => [ + 'userField' => [ + [ + 'name' => 'transactionType', + 'value' => 'priorAuthCaptureTransaction', + ], + ], + ], + ], + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/transaction_details.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/transaction_details.php new file mode 100644 index 0000000000000..110333866766e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/transaction_details.php @@ -0,0 +1,17 @@ + [ + 'merchantAuthentication' => [ + 'name' => 'someusername', + 'transactionKey' => 'somepassword' + ], + 'transId' => '4321' + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/transaction_details_authorized.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/transaction_details_authorized.php new file mode 100644 index 0000000000000..c3ffdedba6851 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/transaction_details_authorized.php @@ -0,0 +1,17 @@ + [ + 'merchantAuthentication' => [ + 'name' => 'someusername', + 'transactionKey' => 'somepassword' + ], + 'transId' => '1234' + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/void.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/void.php new file mode 100644 index 0000000000000..a1d3dade74ff1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/expected_request/void.php @@ -0,0 +1,20 @@ + [ + 'merchantAuthentication' => [ + 'name' => 'someusername', + 'transactionKey' => 'somepassword', + ], + 'transactionRequest' =>[ + 'transactionType' => 'voidTransaction', + 'refTransId' => '1234', + ], + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/full_order.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/full_order.php new file mode 100644 index 0000000000000..cac7c38971ae5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/full_order.php @@ -0,0 +1,125 @@ +create(Product::class); +$product->isObjectNew(true); +$product->setTypeId(Type::TYPE_SIMPLE) + ->setId(1) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Simple Product') + ->setSku('simple') + ->setPrice(10) + ->setWeight(1) + ->setShortDescription('Short description') + ->setTaxClassId(0) + ->setDescription('Description with html tag') + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData([ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ])->setCanSaveCustomOptions(true) + ->setHasOptions(false); + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(ProductRepositoryInterface::class); +$productRepository->save($product); + + +$billingAddress = $objectManager->create(Address::class, ['data' => $addressData]); +$billingAddress->setAddressType('billing'); + +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null) + ->setAddressType('shipping') + ->setStreet(['6161 West Centinela Avenue']) + ->setFirstname('John') + ->setLastname('Doe') + ->setShippingMethod('flatrate_flatrate'); + +$payment = $objectManager->create(Payment::class); +$payment->setAdditionalInformation('ccLast4', '1111'); +$payment->setAdditionalInformation('opaqueDataDescriptor', 'mydescriptor'); +$payment->setAdditionalInformation('opaqueDataValue', 'myvalue'); + +/** @var Item $orderItem */ +$orderItem1 = $objectManager->create(Item::class); +$orderItem1->setProductId($product->getId()) + ->setSku($product->getSku()) + ->setName($product->getName()) + ->setQtyOrdered(1) + ->setBasePrice($product->getPrice()) + ->setPrice($product->getPrice()) + ->setRowTotal($product->getPrice()) + ->setProductType($product->getTypeId()); + +/** @var Item $orderItem */ +$orderItem2 = $objectManager->create(Item::class); +$orderItem2->setProductId($product->getId()) + ->setSku('simple2') + ->setName('Simple product') + ->setPrice(100) + ->setQtyOrdered(2) + ->setBasePrice($product->getPrice()) + ->setPrice($product->getPrice()) + ->setRowTotal($product->getPrice()) + ->setProductType($product->getTypeId()); + +$orderAmount = 100; +$customerEmail = $billingAddress->getEmail(); + +/** @var Order $order */ +$order = $objectManager->create(Order::class); +$order->setIncrementId('100000001') + ->setState(Order::STATE_PROCESSING) + ->setStatus(Order::STATE_PROCESSING) + ->setCustomerId($customer->getId()) + ->setCustomerIsGuest(false) + ->setRemoteIp('127.0.0.1') + ->setCreatedAt(date('Y-m-d 00:00:55')) + ->setOrderCurrencyCode('USD') + ->setBaseCurrencyCode('USD') + ->setSubtotal($orderAmount) + ->setGrandTotal($orderAmount) + ->setBaseSubtotal($orderAmount) + ->setBaseGrandTotal($orderAmount) + ->setCustomerEmail($customerEmail) + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->setShippingDescription('Flat Rate - Fixed') + ->setShippingAmount(10) + ->setStoreId(1) + ->addItem($orderItem1) + ->addItem($orderItem2) + ->setQuoteId(1) + ->setPayment($payment); + +return $order; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/authorize.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/authorize.php new file mode 100644 index 0000000000000..f80495137ca29 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/authorize.php @@ -0,0 +1,47 @@ + [ + 'responseCode' => '1', + 'authCode' => 'abc123', + 'avsResultCode' => 'Y', + 'cvvResultCode' => 'P', + 'cavvResultCode' => '2', + 'transId' => '123456', + 'refTransID' => '', + 'transHash' => 'foobar', + 'testRequest' => '0', + 'accountNumber' => 'XXXX1111', + 'accountType' => 'Visa', + 'messages' => [ + [ + 'code' => '1', + 'description' => 'This transaction has been approved.' + ] + ], + 'userFields' => [ + [ + 'name' => 'transactionType', + 'value' => 'authOnlyTransaction' + ] + ], + 'transHashSha2' => 'CD1E57FB1B5C876FDBD536CB16F8BBBA687580EDD78DD881C7F14DC4467C32BF6C' + . '808620FBD59E5977DF19460B98CCFC0DA0D90755992C0D611CABB8E2BA52B0', + 'SupplementalDataQualificationIndicator' => 0 + ], + 'messages' => [ + 'resultCode' => 'Ok', + 'message' => [ + [ + 'code' => 'I00001', + 'text' => 'Successful.' + ] + ] + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/generic_success.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/generic_success.php new file mode 100644 index 0000000000000..ea7662e319376 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/generic_success.php @@ -0,0 +1,17 @@ + [ + 'resultCode' => 'Ok', + 'message' => [ + 'code' => 'I00001', + 'text' => 'Successful' + ] + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/refund.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/refund.php new file mode 100644 index 0000000000000..536f51d659ad8 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/refund.php @@ -0,0 +1,40 @@ + [ + 'responseCode' => '1', + 'authCode' => '', + 'avsResultCode' => 'P', + 'cvvResultCode' => '', + 'cavvResultCode' => '', + 'transId' => '5678', + 'refTransID' => '4321', + 'testRequest' => '0', + 'accountNumber' => 'XXXX1111', + 'accountType' => 'Visa', + 'messages' => [ + [ + 'code' => '1', + 'description' => 'This transaction has been approved.' + ] + ], + 'transHashSha2' => '78BD31BA5BCDF3C3FA3C8373D8DF80EF07FC7E02C3545FCF18A408E2F76ED4F20D' + . 'FF007221374B576FDD1BFD953B3E5CF37249CEC4C135EEF975F7B478D8452C', + 'SupplementalDataQualificationIndicator' => 0 + ], + 'messages' => [ + 'resultCode' => 'Ok', + 'message' => [ + [ + 'code' => 'I00001', + 'text' => 'Successful.' + ] + ] + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/sale.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/sale.php new file mode 100644 index 0000000000000..74a80110adece --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/sale.php @@ -0,0 +1,47 @@ + [ + 'responseCode' => '1', + 'authCode' => 'abc123', + 'avsResultCode' => 'Y', + 'cvvResultCode' => 'P', + 'cavvResultCode' => '2', + 'transId' => '123456', + 'refTransID' => '', + 'transHash' => 'foobar', + 'testRequest' => '0', + 'accountNumber' => 'XXXX1111', + 'accountType' => 'Visa', + 'messages' => [ + [ + 'code' => '1', + 'description' => 'This transaction has been approved.' + ] + ], + 'userFields' => [ + [ + 'name' => 'transactionType', + 'value' => 'authCaptureTransaction' + ] + ], + 'transHashSha2' => 'CD1E57FB1B5C876FDBD536CB16F8BBBA687580EDD78DD881C7F14DC4467C32BF6C' + . '808620FBD59E5977DF19460B98CCFC0DA0D90755992C0D611CABB8E2BA52B0', + 'SupplementalDataQualificationIndicator' => 0 + ], + 'messages' => [ + 'resultCode' => 'Ok', + 'message' => [ + [ + 'code' => 'I00001', + 'text' => 'Successful.' + ] + ] + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/settle.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/settle.php new file mode 100644 index 0000000000000..5e54c30198741 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/settle.php @@ -0,0 +1,40 @@ + [ + 'responseCode' => '1', + 'authCode' => '', + 'avsResultCode' => 'P', + 'cvvResultCode' => '', + 'cavvResultCode' => '', + 'transId' => '1234', + 'refTransID' => '1234', + 'testRequest' => '0', + 'accountNumber' => 'XXXX1111', + 'accountType' => 'Visa', + 'messages' => [ + [ + 'code' => '1', + 'description' => 'This transaction has been approved.' + ] + ], + 'transHashSha2' => '1B22AB4E4DF750CF2E0D1944BB6903537C145545C7313C87B6FD4A6384' + . '709EA2609CE9A9788C128F2F2EAEEE474F6010418904648C6D000BE3AF7BCD98A5AD8F', + 'SupplementalDataQualificationIndicator' => 0 + ], + 'messages' => [ + 'resultCode' => 'Ok', + 'message' => [ + [ + 'code' => 'I00001', + 'text' => 'Successful.' + ] + ] + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_authorized.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_authorized.php new file mode 100644 index 0000000000000..80fd24a5c601a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_authorized.php @@ -0,0 +1,22 @@ + [ + 'resultCode' => 'Ok', + 'message' => [ + 'code' => 'I00001', + 'text' => 'Successful' + ] + ], + 'transaction' => [ + 'transId' => '1234', + 'transactionType' => 'authOnlyTransaction', + 'transactionStatus' => 'authorizedPendingCapture' + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_declined.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_declined.php new file mode 100644 index 0000000000000..24c9353e4088a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_declined.php @@ -0,0 +1,22 @@ + [ + 'resultCode' => 'Ok', + 'message' => [ + 'code' => 'I00001', + 'text' => 'Successful' + ] + ], + 'transaction' => [ + 'transId' => '1234', + 'transactionType' => 'authOnlyTransaction', + 'transactionStatus' => 'declined' + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_fds_pending.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_fds_pending.php new file mode 100644 index 0000000000000..de045f30ab22e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_fds_pending.php @@ -0,0 +1,22 @@ + [ + 'resultCode' => 'Ok', + 'message' => [ + 'code' => 'I00001', + 'text' => 'Successful' + ] + ], + 'transaction' => [ + 'transId' => '1234', + 'transactionType' => 'authOnlyTransaction', + 'transactionStatus' => 'FDSPendingReview' + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_settled_capture.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_settled_capture.php new file mode 100644 index 0000000000000..5df2f03a943a6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_settled_capture.php @@ -0,0 +1,22 @@ + [ + 'resultCode' => 'Ok', + 'message' => [ + 'code' => 'I00001', + 'text' => 'Successful' + ] + ], + 'transaction' => [ + 'transId' => '4321', + 'transactionType' => 'captureOnlyTransaction', + 'transactionStatus' => 'settledSuccessfully' + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_voided.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_voided.php new file mode 100644 index 0000000000000..7ee735cd8cf36 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/transaction_details_voided.php @@ -0,0 +1,22 @@ + [ + 'resultCode' => 'Ok', + 'message' => [ + 'code' => 'I00001', + 'text' => 'Successful' + ] + ], + 'transaction' => [ + 'transId' => '1234', + 'transactionType' => 'authOnlyTransaction', + 'transactionStatus' => 'void' + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/void.php b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/void.php new file mode 100644 index 0000000000000..eb71de4dd9667 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AuthorizenetAcceptjs/_files/response/void.php @@ -0,0 +1,30 @@ + [ + 'resultCode' => 'Ok', + 'message' => [ + 'code' => 'I00001', + 'text' => 'Successful' + ] + ], + 'transactionResponse' => [ + 'responseCode' => '1', + 'messages' => [ + 'message' => [ + [ + 'code' => 1 + ] + ] + ], + 'transHashSha2' => '1B22AB4E4DF750CF2E0D1944BB6903537C145545C7313C87B6FD4A6384709E' + . 'A2609CE9A9788C128F2F2EAEEE474F6010418904648C6D000BE3AF7BCD98A5AD8F', + 'transId' => '1234' + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/EncryptionKey/Setup/Patch/Data/SodiumChachaPatchTest.php b/dev/tests/integration/testsuite/Magento/EncryptionKey/Setup/Patch/Data/SodiumChachaPatchTest.php index 3a47692bdb932..a563641a4f874 100644 --- a/dev/tests/integration/testsuite/Magento/EncryptionKey/Setup/Patch/Data/SodiumChachaPatchTest.php +++ b/dev/tests/integration/testsuite/Magento/EncryptionKey/Setup/Patch/Data/SodiumChachaPatchTest.php @@ -41,6 +41,9 @@ public function testChangeEncryptionKey() $structureMock->expects($this->once()) ->method('getFieldPathsByAttribute') ->will($this->returnValue([$testPath])); + $structureMock->expects($this->once()) + ->method('getFieldPaths') + ->willReturn([]); /** @var \Magento\Config\Model\ResourceModel\Config $configModel */ $configModel = $this->objectManager->create(\Magento\Config\Model\ResourceModel\Config::class); diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/unsecure_php_functions.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/unsecure_php_functions.php index 1c23f8d8ccf8a..10c0da47cb2d2 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/unsecure_php_functions.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/unsecure_php_functions.php @@ -63,6 +63,16 @@ 'type' => 'module', 'name' => 'Magento_AsynchronousOperations', 'path' => 'Model/ResourceModel/System/Message/Collection/Synchronized/Plugin.php' + ], + [ + 'type' => 'module', + 'name' => 'Magento_AuthorizenetAcceptjs', + 'path' => 'Gateway/Validator/TransactionHashValidator.php' + ], + [ + 'type' => 'module', + 'name' => 'Magento_Authorizenet', + 'path' => 'Model/Directpost/Response.php' ] ] ],