diff --git a/Model/BPCheckout.php b/Model/BPCheckout.php index d06434e..e9590e9 100755 --- a/Model/BPCheckout.php +++ b/Model/BPCheckout.php @@ -27,4 +27,14 @@ class BPCheckout extends AbstractMethod * @var bool */ protected $_isOffline = true; + + /** + * Get config payment action, do nothing if status is pending + * + * @return string|null + */ + public function getConfigPaymentAction() + { + return $this->getConfigData('order_status') == 'pending' ? null : parent::getConfigPaymentAction(); + } } diff --git a/Model/BPRedirect.php b/Model/BPRedirect.php index 288756c..0eeb638 100755 --- a/Model/BPRedirect.php +++ b/Model/BPRedirect.php @@ -13,6 +13,7 @@ use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Controller\ResultInterface; use Magento\Sales\Model\OrderRepository; +use Magento\Framework\Encryption\EncryptorInterface; /** * @SuppressWarnings(PHPMD.TooManyFields) @@ -34,6 +35,7 @@ class BPRedirect protected Client $client; protected OrderRepository $orderRepository; protected BitpayInvoiceRepository $bitpayInvoiceRepository; + protected EncryptorInterface $encryptor; /** * @param Session $checkoutSession @@ -49,6 +51,7 @@ class BPRedirect * @param Client $client * @param OrderRepository $orderRepository * @param BitpayInvoiceRepository $bitpayInvoiceRepository + * @param EncryptorInterface $encryptor * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -64,7 +67,8 @@ public function __construct( ResultFactory $resultFactory, Client $client, OrderRepository $orderRepository, - BitpayInvoiceRepository $bitpayInvoiceRepository + BitpayInvoiceRepository $bitpayInvoiceRepository, + EncryptorInterface $encryptor, ) { $this->checkoutSession = $checkoutSession; $this->orderInterface = $orderInterface; @@ -79,16 +83,19 @@ public function __construct( $this->client = $client; $this->orderRepository = $orderRepository; $this->bitpayInvoiceRepository = $bitpayInvoiceRepository; + $this->encryptor = $encryptor; } /** * Create bitpay invoice after order creation during redirect to success page * + * @param ResultInterface $defaultResult + * @param string|null $returnId * @return ResultInterface * @throws LocalizedException * @throws NoSuchEntityException|\Exception */ - public function execute(): ResultInterface + public function execute(ResultInterface $defaultResult, string $returnId = null): ResultInterface { $orderId = $this->checkoutSession->getData('last_order_id'); if (!$orderId) { @@ -102,17 +109,36 @@ public function execute(): ResultInterface return $this->resultFactory->create(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT) ->setUrl($this->url->getUrl('checkout/cart')); } - $baseUrl = $this->config->getBaseUrl(); if ($order->getPayment()->getMethodInstance()->getCode() !== Config::BITPAY_PAYMENT_METHOD_NAME) { - return $this->resultFactory->create( - \Magento\Framework\Controller\ResultFactory::TYPE_PAGE - ); + return $defaultResult; + } + + $isStandardCheckoutSuccess = $this->config->getBitpayCheckoutSuccess() === 'standard'; + $returnHash = $this->encryptor->hash("$incrementId:{$order->getCustomerEmail()}:{$order->getProtectCode()}"); + if ($isStandardCheckoutSuccess && $returnId) { + if ($returnId !== $returnHash) { + $this->checkoutSession->clearHelperData(); + + return $this->resultFactory->create(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT) + ->setUrl($this->url->getUrl('checkout/cart')); + } + + return $defaultResult; } try { + $baseUrl = $this->config->getBaseUrl(); $order = $this->setToPendingAndOverrideMagentoStatus($order); $modal = $this->config->getBitpayUx() === 'modal'; - $redirectUrl = $baseUrl .'bitpay-invoice/?order_id='. $incrementId; + $redirectUrl = $this->url->getUrl('bitpay-invoice', ['_query' => ['order_id' => $incrementId]]); + if ($isStandardCheckoutSuccess) { + $this->checkoutSession->setLastSuccessQuoteId($order->getQuoteId()); + if (!$modal) { + $redirectUrl = $this->url->getUrl('checkout/onepage/success', [ + '_query' => ['return_id' => $returnHash] + ]); + } + } $params = $this->getParams($order, $incrementId, $modal, $redirectUrl, $baseUrl); $billingAddressData = $order->getBillingAddress()->getData(); $this->setSessionCustomerData($billingAddressData, $order->getCustomerEmail(), $incrementId); @@ -134,12 +160,20 @@ public function execute(): ResultInterface #set some info for guest checkout $this->setSessionCustomerData($billingAddressData, $order->getCustomerEmail(), $incrementId); - $redirectUrl = $this->url->getUrl('bitpay-invoice', ['_query' => ['invoiceID' => $invoiceID, 'order_id' => $incrementId, 'm' => 1]]); + $redirectParams = [ + 'invoiceID' => $invoiceID, + 'order_id' => $incrementId, + 'm' => 1, + ]; + if ($isStandardCheckoutSuccess) { + $redirectParams['return_id'] = $returnHash; + } + $redirectUrl = $this->url->getUrl('bitpay-invoice', ['_query' => $redirectParams]); return $this->resultFactory->create( - \Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT - ) - ->setUrl($redirectUrl); + \Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT + ) + ->setUrl($redirectUrl); case false: default: return $this->resultFactory->create( @@ -234,6 +268,7 @@ private function getParams( */ private function deleteOrderAndRedirectToCart($exception, OrderInterface $order): ResultInterface { + $this->checkoutSession->clearHelperData(); $this->logger->error($exception->getMessage()); $this->registry->register('isSecureArea', 'true'); $order->delete(); @@ -241,9 +276,8 @@ private function deleteOrderAndRedirectToCart($exception, OrderInterface $order) $this->messageManager->addErrorMessage('We are unable to place your Order at this time'); return $this->resultFactory->create( - \Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT - ) - ->setUrl($this->url->getUrl('checkout/cart')); - + \Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT + ) + ->setUrl($this->url->getUrl('checkout/cart')); } } diff --git a/Model/Config.php b/Model/Config.php index dbe6848..b6157dc 100755 --- a/Model/Config.php +++ b/Model/Config.php @@ -19,6 +19,7 @@ class Config public const BITPAY_PAYMENT_ACTIVE = 'payment/bpcheckout/active'; public const BPCHECKOUT_ORDER_STATUS = 'payment/bpcheckout/order_status'; public const BITPAY_UX = 'payment/bpcheckout/bitpay_ux'; + public const BITPAY_CHECKOUT_SUCCESS = 'payment/bpcheckout/bitpay_checkout_success'; public const BITPAY_MERCHANT_TOKEN_DATA = 'bitpay_merchant_facade/authenticate/token_data'; public const BITPAY_MERCHANT_PRIVATE_KEY_PATH = 'bitpay_merchant_facade/authenticate/private_key_path'; public const BITPAY_MERCHANT_PASSWORD = 'bitpay_merchant_facade/authenticate/password'; @@ -27,7 +28,7 @@ class Config public const BITPAY_PROD_TOKEN_URL = 'https://bitpay.com/tokens'; public const API_HOST_DEV = 'test.bitpay.com'; public const API_HOST_PROD = 'bitpay.com'; - public const EXTENSION_VERSION = 'Bitpay_BPCheckout_Magento2_9.2.2'; + public const EXTENSION_VERSION = 'Bitpay_BPCheckout_Magento2_9.3.0'; public const BITPAY_PAYMENT_METHOD_NAME = 'bpcheckout'; public const BITPAY_PAYMENT_ICON = 'Pay-with-BitPay-CardGroup.svg'; public const BITPAY_PAYMENT_DIR_IMAGES = 'images'; @@ -109,6 +110,16 @@ public function getBitpayUx():? string return $this->scopeConfig->getValue(self::BITPAY_UX, ScopeInterface::SCOPE_STORE); } + /** + * Get BitPay CheckoutSuccess + * + * @return string|null + */ + public function getBitpayCheckoutSuccess():? string + { + return $this->scopeConfig->getValue(self::BITPAY_CHECKOUT_SUCCESS, ScopeInterface::SCOPE_STORE); + } + /** * Get token * diff --git a/Model/Config/Source/CheckoutSuccess.php b/Model/Config/Source/CheckoutSuccess.php new file mode 100644 index 0000000..d25f868 --- /dev/null +++ b/Model/Config/Source/CheckoutSuccess.php @@ -0,0 +1,25 @@ + 'Module', + 'standard' => 'Standard', + ]; + } +} diff --git a/Plugin/Onepage/SuccessPlugin.php b/Plugin/Onepage/SuccessPlugin.php index 07a4e3a..b040f9a 100755 --- a/Plugin/Onepage/SuccessPlugin.php +++ b/Plugin/Onepage/SuccessPlugin.php @@ -28,6 +28,6 @@ public function afterExecute( \Magento\Checkout\Controller\Onepage\Success $subject, \Magento\Framework\Controller\ResultInterface $result ) { - return $this->bpRedirect->execute(); + return $this->bpRedirect->execute($result, $subject->getRequest()->getParam('return_id')); } } diff --git a/Test/Unit/Model/BPRedirectTest.php b/Test/Unit/Model/BPRedirectTest.php index d116d48..fa99cbe 100755 --- a/Test/Unit/Model/BPRedirectTest.php +++ b/Test/Unit/Model/BPRedirectTest.php @@ -20,6 +20,7 @@ use Magento\Sales\Api\Data\OrderInterface; use \Magento\Framework\Controller\Result\Redirect; use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\Encryption\EncryptorInterface; use Magento\Sales\Model\Order; use Magento\Payment\Model\MethodInterface; use Magento\Sales\Model\OrderRepository; @@ -102,6 +103,11 @@ class BPRedirectTest extends TestCase */ private $resultFactory; + /** + * @var EncryptorInterface|MockObject $encryptor + */ + private $encryptor; + public function setUp(): void { $this->checkoutSession = $this->getMock(Session::class); @@ -112,11 +118,12 @@ public function setUp(): void $this->invoice = $this->getMock(Invoice::class); $this->messageManager = $this->getMock(Manager::class); $this->registry = $this->getMock(Registry::class); - $this->url = $this->getMock(UrlInterface::class); + $this->url = $this->getMockBuilder(UrlInterface::class)->getMock(); $this->logger = $this->getMock(Logger::class); $this->resultFactory = $this->getMock(ResultFactory::class); $this->orderRepository = $this->getMock(OrderRepository::class); $this->bitpayInvoiceRepository = $this->getMock(BitpayInvoiceRepository::class); + $this->encryptor = $this->getMock(EncryptorInterface::class); $this->bpRedirect = $this->getClass(); } @@ -142,6 +149,14 @@ public function testExecute($ux): void ->with('last_order_id') ->willReturn($lastOrderId); + $this->url->expects( + $this->any() + )->method( + 'getUrl' + ) + ->withConsecutive(['bitpay-invoice', ['_query' => ['order_id' => $incrementId]]], ['checkout/cart']) + ->willReturnOnConsecutiveCalls('http://localhost/bitpay-invoice?order_id=' . $incrementId, 'http://localhost/checkout/cart'); + $billingAddress->expects($this->once())->method('getData') ->willReturn(['first_name' => 'test', 'last_name' => 'test1']); $billingAddress->expects($this->once())->method('getFirstName')->willReturn('test'); @@ -171,7 +186,9 @@ public function testExecute($ux): void $this->resultFactory->expects($this->once())->method('create')->willReturn($result); } - $this->bpRedirect->execute(); + $page = $this->getMock(\Magento\Framework\View\Result\Page::class); + + $this->bpRedirect->execute($page); } /** @@ -195,7 +212,9 @@ public function testExecuteNoOrderId(): void $result->expects($this->once())->method('setUrl')->willReturnSelf(); $this->resultFactory->expects($this->once())->method('create')->willReturn($result); - $this->bpRedirect->execute(); + $page = $this->getMock(\Magento\Framework\View\Result\Page::class); + + $this->bpRedirect->execute($page); } public function testExecuteNoBitpayPaymentMethod(): void @@ -217,12 +236,10 @@ public function testExecuteNoBitpayPaymentMethod(): void $order->expects($this->once())->method('getIncrementId')->willReturn($incrementId); $order->expects($this->once())->method('getPayment')->willReturn($payment); $this->order->expects($this->once())->method('load')->with($lastOrderId)->willReturn($order); - $this->config->expects($this->once())->method('getBaseUrl')->willReturn($baseUrl); - - $result = $this->getMock(\Magento\Framework\Controller\Result\Redirect::class); - $this->resultFactory->expects($this->once())->method('create')->willReturn($result); - $this->bpRedirect->execute(); + $page = $this->getMock(\Magento\Framework\View\Result\Page::class); + + $this->assertSame($page, $this->bpRedirect->execute($page)); } /** @@ -245,6 +262,14 @@ public function testExecuteException($exceptionType): void ->with('last_order_id') ->willReturn($lastOrderId); + $this->url->expects( + $this->any() + )->method( + 'getUrl' + ) + ->withConsecutive(['bitpay-invoice', ['_query' => ['order_id' => $incrementId]]], ['checkout/cart']) + ->willReturnOnConsecutiveCalls('http://localhost/bitpay-invoice?order_id=' . $incrementId, 'http://localhost/checkout/cart'); + $billingAddress->expects($this->once())->method('getData') ->willReturn(['first_name' => 'test', 'last_name' => 'test1']); $billingAddress->expects($this->once())->method('getFirstName')->willReturn('test'); @@ -263,7 +288,9 @@ public function testExecuteException($exceptionType): void ->method('BPCCreateInvoice') ->willThrowException(new $exceptionType('something went wrong')); - $this->bpRedirect->execute(); + $page = $this->getMock(\Magento\Framework\View\Result\Page::class); + + $this->bpRedirect->execute($page); } public function exceptionTypeDataProvider(): array @@ -340,7 +367,8 @@ private function getClass(): BPRedirect $this->resultFactory, $this->client, $this->orderRepository, - $this->bitpayInvoiceRepository + $this->bitpayInvoiceRepository, + $this->encryptor ); } diff --git a/Test/Unit/Plugin/Onepage/SuccessPluginTest.php b/Test/Unit/Plugin/Onepage/SuccessPluginTest.php index bad3f84..8d8b38b 100644 --- a/Test/Unit/Plugin/Onepage/SuccessPluginTest.php +++ b/Test/Unit/Plugin/Onepage/SuccessPluginTest.php @@ -5,6 +5,7 @@ use Bitpay\BPCheckout\Plugin\Onepage\SuccessPlugin; use Bitpay\BPCheckout\Model\BPRedirect; use Magento\Checkout\Controller\Onepage\Success; +use Magento\Framework\App\RequestInterface; use Magento\Framework\Controller\ResultInterface; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -15,6 +16,10 @@ public function testAfterExecute(): void { $bpRedirect = $this->getMockBuilder(BPRedirect::class)->disableOriginalConstructor()->getMock(); $subject = $this->getMockBuilder(Success::class)->disableOriginalConstructor()->getMock(); + $subject = $this->getMockBuilder(Success::class)->disableOriginalConstructor()->getMock(); + $request = $this->getMockBuilder(RequestInterface::class)->disableOriginalConstructor()->getMock(); + $request->expects($this->once())->method('getParam')->willReturn(null); + $subject->expects($this->once())->method('getRequest')->willReturn($request); $result = $this->getMockBuilder(ResultInterface::class)->disableOriginalConstructor()->getMock(); $testedClass = new SuccessPlugin($bpRedirect); diff --git a/composer.json b/composer.json index 01ac4de..1074c51 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "", "type": "magento2-module", "license": "mit", - "version":"9.2.2", + "version":"9.3.0", "authors": [ { "email": "integrations@bitpay.com", diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 7f40803..332e396 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -128,6 +128,11 @@ Bitpay\BPCheckout\Model\Config\Source\Ux + + + + Bitpay\BPCheckout\Model\Config\Source\CheckoutSuccess + diff --git a/etc/config.xml b/etc/config.xml index 12dd4ea..611c9ad 100755 --- a/etc/config.xml +++ b/etc/config.xml @@ -19,6 +19,7 @@ Bitpay\BPCheckout\Model\BPCheckout offline 0 + module diff --git a/etc/module.xml b/etc/module.xml index 15e9571..a87827b 100755 --- a/etc/module.xml +++ b/etc/module.xml @@ -6,5 +6,5 @@ --> - - \ No newline at end of file + + diff --git a/view/frontend/web/js/bitpay/checkout/index.js b/view/frontend/web/js/bitpay/checkout/index.js index b031260..adef717 100755 --- a/view/frontend/web/js/bitpay/checkout/index.js +++ b/view/frontend/web/js/bitpay/checkout/index.js @@ -9,6 +9,7 @@ define([ var orderId = getParams()['order_id'] var env = config.env var baseUrl = config.baseUrl + var returnId = getParams()["return_id"] if(env == "test"){ bitpay.enableTestMode() } @@ -22,8 +23,17 @@ define([ deleteCookie('env') deleteCookie('invoicedata') deleteCookie('modal') - document.getElementById("bitpay-header").innerHTML = 'Thank you for your purchase.'; - document.getElementById("success-bitpay-page").style.display = 'block'; + + if (returnId) { + window.location.replace( + baseUrl + "checkout/onepage/success/?return_id=" + returnId + ); + } else { + document.getElementById("bitpay-header").innerHTML = + "Thank you for your purchase."; + document.getElementById("success-bitpay-page").style.display = + "block"; + } return; }