Skip to content

Commit

Permalink
Merge pull request #102 from swlodarski-sumoheavy/9.3.x
Browse files Browse the repository at this point in the history
 SP-1069 Add option to redirect to standard checkout success
  • Loading branch information
p-maguire authored Sep 20, 2024
2 parents 742c2fa + 6716b27 commit e264454
Show file tree
Hide file tree
Showing 12 changed files with 161 additions and 32 deletions.
10 changes: 10 additions & 0 deletions Model/BPCheckout.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
64 changes: 49 additions & 15 deletions Model/BPRedirect.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -34,6 +35,7 @@ class BPRedirect
protected Client $client;
protected OrderRepository $orderRepository;
protected BitpayInvoiceRepository $bitpayInvoiceRepository;
protected EncryptorInterface $encryptor;

/**
* @param Session $checkoutSession
Expand All @@ -49,6 +51,7 @@ class BPRedirect
* @param Client $client
* @param OrderRepository $orderRepository
* @param BitpayInvoiceRepository $bitpayInvoiceRepository
* @param EncryptorInterface $encryptor
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
Expand All @@ -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;
Expand All @@ -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) {
Expand All @@ -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);
Expand All @@ -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(
Expand Down Expand Up @@ -234,16 +268,16 @@ 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();
$this->registry->unregister('isSecureArea');
$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'));
}
}
13 changes: 12 additions & 1 deletion Model/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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';
Expand Down Expand Up @@ -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
*
Expand Down
25 changes: 25 additions & 0 deletions Model/Config/Source/CheckoutSuccess.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);

namespace Bitpay\BPCheckout\Model\Config\Source;

use Magento\Framework\Option\ArrayInterface;

/**
* CheckoutSuccess Model
*/
class CheckoutSuccess implements ArrayInterface
{
/**
* Return array of Checkout Success options
*
* @return string[]
*/
public function toOptionArray()
{
return [
'module' => 'Module',
'standard' => 'Standard',
];
}
}
2 changes: 1 addition & 1 deletion Plugin/Onepage/SuccessPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'));
}
}
48 changes: 38 additions & 10 deletions Test/Unit/Model/BPRedirectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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();
}

Expand All @@ -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');
Expand Down Expand Up @@ -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);
}

/**
Expand All @@ -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
Expand All @@ -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));
}

/**
Expand All @@ -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');
Expand All @@ -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
Expand Down Expand Up @@ -340,7 +367,8 @@ private function getClass(): BPRedirect
$this->resultFactory,
$this->client,
$this->orderRepository,
$this->bitpayInvoiceRepository
$this->bitpayInvoiceRepository,
$this->encryptor
);
}

Expand Down
5 changes: 5 additions & 0 deletions Test/Unit/Plugin/Onepage/SuccessPluginTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "",
"type": "magento2-module",
"license": "mit",
"version":"9.2.2",
"version":"9.3.0",
"authors": [
{
"email": "[email protected]",
Expand Down
5 changes: 5 additions & 0 deletions etc/adminhtml/system.xml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@
<source_model>Bitpay\BPCheckout\Model\Config\Source\Ux</source_model>
</field>

<field id="bitpay_checkout_success" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Checkout Success</label>
<comment><![CDATA[Note: Using the standard checkout success page may require updates to your theme.]]></comment>
<source_model>Bitpay\BPCheckout\Model\Config\Source\CheckoutSuccess</source_model>
</field>

<field id="specificcountry" translate="label" type="multiselect" sortOrder="41" showInDefault="1"
showInWebsite="1" showInStore="0">
Expand Down
1 change: 1 addition & 0 deletions etc/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<model>Bitpay\BPCheckout\Model\BPCheckout</model>
<group>offline</group>
<send_order_email>0</send_order_email>
<bitpay_checkout_success>module</bitpay_checkout_success>
</bpcheckout>
<!-- payment-config -->
</payment>
Expand Down
Loading

0 comments on commit e264454

Please sign in to comment.