Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/10.0.x' into 10.0.x
Browse files Browse the repository at this point in the history
  • Loading branch information
swlodarski committed Dec 19, 2024
2 parents 1421e86 + 6e518c4 commit f9e17bd
Show file tree
Hide file tree
Showing 21 changed files with 751 additions and 174 deletions.
140 changes: 140 additions & 0 deletions Block/Checkout/Onepage/Success/PayButton.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?php
declare(strict_types=1);

namespace Bitpay\BPCheckout\Block\Checkout\Onepage\Success;

use Bitpay\BPCheckout\Model\Client;
use Bitpay\BPCheckout\Model\Config;
use Bitpay\BPCheckout\Model\TransactionRepository;
use BitPaySDK\Model\Invoice\Invoice;
use Magento\Checkout\Block\Onepage\Success as MagentoSuccess;
use Magento\Checkout\Model\Session;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Config as OrderConfig;
use Magento\Framework\App\Http\Context as HttpContext;
use Magento\Framework\UrlInterface;
use Magento\Framework\View\Element\Template\Context;

class PayButton extends MagentoSuccess
{
/**
* @var TransactionRepository
*/
protected TransactionRepository $transactionRepository;

/**
* @var Client
*/
protected Client $client;

/**
* @var Config
*/
protected Config $config;

/**
* @var UrlInterface
*/
protected UrlInterface $url;

/**
* @var Invoice|null
*/
protected ?Invoice $invoice = null;

/**
* @param Context $context
* @param Session $checkoutSession
* @param OrderConfig $orderConfig
* @param HttpContext $httpContext
* @param TransactionRepository $transactionRepository
* @param Client $client
* @param Config $config
* @param UrlInterface $url
* @param array $data
*/
public function __construct(
Context $context,
Session $checkoutSession,
OrderConfig $orderConfig,
HttpContext $httpContext,
TransactionRepository $transactionRepository,
Client $client,
Config $config,
UrlInterface $url,
array $data = []
) {
parent::__construct($context, $checkoutSession, $orderConfig, $httpContext, $data);

$this->transactionRepository = $transactionRepository;
$this->client = $client;
$this->config = $config;
$this->url = $url;
}

/**
* Returns true when Pay button be displayed
*
* @return bool
*/
public function canViewPayButton(): bool
{
if ($this->config->getBitpayCheckoutSuccess() === 'standard'
&& $this->config->getBitpayInvoiceCloseHandling() === 'keep_order') {
$invoice = $this->getBitpayInvoice();

return $invoice !== null;
}

return false;
}

/**
* Returns button url
*
* @return string
*/
public function getButtonUrl(): string
{
return $this->url->getUrl('bpcheckout/invoice/pay', [
'_query' => [
'order_id' => $this->getOrder()->getId(), 'invoice_id' => $this->getBitpayInvoice()->getId()
]
]);
}

/**
* Get BitPay invoice by last order
*
* @return Invoice|null
*/
protected function getBitpayInvoice(): ?Invoice
{
if (!$this->invoice) {
$order = $this->getOrder();
if ($order->canInvoice()) {
$transactions = $this->transactionRepository
->findByOrderIdAndTransactionStatus($order->getIncrementId(), 'new');
if (!empty($transactions)) {
$lastTransaction = array_pop($transactions);
$client = $this->client->initialize();
$invoice = $client->getInvoice($lastTransaction['transaction_id']);

$this->invoice = $invoice;
}
}
}

return $this->invoice;
}

/**
* Get order instance based on last order ID
*
* @return Order
*/
protected function getOrder(): Order
{
return $this->_checkoutSession->getLastRealOrder();
}
}
139 changes: 139 additions & 0 deletions Controller/Invoice/Pay.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php
declare(strict_types=1);

namespace Bitpay\BPCheckout\Controller\Invoice;

use Bitpay\BPCheckout\Model\Client;
use Bitpay\BPCheckout\Model\Config;
use Bitpay\BPCheckout\Model\TransactionRepository;
use Magento\Checkout\Model\Session;
use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Controller\Result\RedirectFactory;
use Magento\Framework\Controller\ResultInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Message\Manager;
use Magento\Framework\Phrase;
use Magento\Sales\Api\OrderRepositoryInterface;

class Pay implements HttpGetActionInterface
{
/**
* @var RequestInterface
*/
private $request;

/**
* @var Manager
*/
protected Manager $messageManager;

/**
* @var RedirectFactory
*/
protected $resultRedirectFactory;

/**
* @var OrderRepositoryInterface
*/
protected $orderRepository;

/**
* @var TransactionRepository
*/
protected TransactionRepository $transactionRepository;

/**
* @var Session
*/
protected Session $checkoutSession;

/**
* @var Client
*/
protected Client $client;

/**
* @var Config
*/
protected Config $config;

/**
* @param RequestInterface $request
* @param Manager $messageManager
* @param RedirectFactory $resultRedirectFactory
* @param OrderRepositoryInterface $orderRepository
* @param TransactionRepository $transactionRepository
* @param Session $checkoutSession
* @param Client $client
* @param Config $config
*/
public function __construct(
RequestInterface $request,
Manager $messageManager,
RedirectFactory $resultRedirectFactory,
OrderRepositoryInterface $orderRepository,
TransactionRepository $transactionRepository,
Session $checkoutSession,
Client $client,
Config $config,
) {
$this->request = $request;
$this->messageManager = $messageManager;
$this->resultRedirectFactory = $resultRedirectFactory;
$this->orderRepository = $orderRepository;
$this->transactionRepository = $transactionRepository;
$this->checkoutSession = $checkoutSession;
$this->client = $client;
$this->config = $config;
}

/**
* Get checkout customer info
*
* @return ResultInterface
*/
public function execute()
{
$orderId = $this->request->getParam('order_id', null);
$invoiceId = $this->request->getParam('invoice_id', null);

try {
if (!$orderId || !$invoiceId || $this->config->getBitpayCheckoutSuccess() !== 'standard'
|| $this->config->getBitpayInvoiceCloseHandling() !== 'keep_order') {
throw new LocalizedException(new Phrase('Invalid request!'));
}

/** @var \Magento\Sales\Model\Order $order */
$order = $this->orderRepository->get($orderId);
if (!$order->canInvoice()) {
throw new LocalizedException(new Phrase('Order already paid!'));
}

$client = $this->client->initialize();
$invoice = $client->getInvoice($invoiceId);
$invoiceStatus = $invoice->getStatus();
if ($invoiceStatus === 'paid' || $invoiceStatus === 'confirmed' || $invoiceStatus === 'complete') {
throw new LocalizedException(new Phrase('The invoice has already been paid!'));
} elseif ($invoiceStatus === 'expired') {
throw new LocalizedException(new Phrase('The invoice has expired!'));
} elseif ($invoiceStatus !== 'new') {
throw new LocalizedException(new Phrase('The invoice is invalid or expired!'));
}

$this->checkoutSession->setLastSuccessQuoteId($order->getQuoteId())
->setLastQuoteId($order->getQuoteId())
->setLastOrderId($order->getEntityId());

return $this->resultRedirectFactory->create()->setUrl($invoice->getUrl());
} catch (\Exception $exception) {
$this->messageManager->addErrorMessage($exception->getMessage());

return $this->resultRedirectFactory->create()->setPath('checkout/cart');
} catch (\Error $error) {
$this->messageManager->addErrorMessage('Invalid request!');

return $this->resultRedirectFactory->create()->setPath('checkout/cart');
}
}
}
55 changes: 55 additions & 0 deletions Helper/ReturnHash.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php
declare(strict_types=1);

namespace Bitpay\BPCheckout\Helper;

use Magento\Framework\App\Helper\Context;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\Encryption\EncryptorInterface;
use Magento\Sales\Api\Data\OrderInterface;

class ReturnHash extends AbstractHelper
{
/**
* @var EncryptorInterface
*/
protected EncryptorInterface $encryptor;

/**
* @param Context $context
* @param EncryptorInterface $encryptor
*/
public function __construct(
Context $context,
EncryptorInterface $encryptor
) {
$this->encryptor = $encryptor;

parent::__construct($context);
}

/**
* Generates return hash
*
* @param OrderInterface $order
* @return string
*/
public function generate(OrderInterface $order): string
{
return $this->encryptor->hash(
"{$order->getIncrementId()}:{$order->getCustomerEmail()}:{$order->getProtectCode()}"
);
}

/**
* Checks if returnHash is valid
*
* @param string $returnHashToCheck
* @param OrderInterface $order
* @return bool
*/
public function isValid(string $returnHashToCheck, OrderInterface $order): bool
{
return $returnHashToCheck === $this->generate($order);
}
}
11 changes: 9 additions & 2 deletions Model/BPRedirect.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace Bitpay\BPCheckout\Model;

use Bitpay\BPCheckout\Helper\ReturnHash;
use Bitpay\BPCheckout\Logger\Logger;
use Magento\Checkout\Model\Session;
use Magento\Framework\DataObject;
Expand Down Expand Up @@ -35,6 +36,7 @@ class BPRedirect
protected Client $client;
protected OrderRepository $orderRepository;
protected BitpayInvoiceRepository $bitpayInvoiceRepository;
protected ReturnHash $returnHashHelper;
protected EncryptorInterface $encryptor;

/**
Expand All @@ -51,6 +53,7 @@ class BPRedirect
* @param Client $client
* @param OrderRepository $orderRepository
* @param BitpayInvoiceRepository $bitpayInvoiceRepository
* @param ReturnHash $returnHashHelper
* @param EncryptorInterface $encryptor
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
Expand All @@ -68,6 +71,7 @@ public function __construct(
Client $client,
OrderRepository $orderRepository,
BitpayInvoiceRepository $bitpayInvoiceRepository,
ReturnHash $returnHashHelper,
EncryptorInterface $encryptor,
) {
$this->checkoutSession = $checkoutSession;
Expand All @@ -83,6 +87,7 @@ public function __construct(
$this->client = $client;
$this->orderRepository = $orderRepository;
$this->bitpayInvoiceRepository = $bitpayInvoiceRepository;
$this->returnHashHelper = $returnHashHelper;
$this->encryptor = $encryptor;
}

Expand Down Expand Up @@ -114,9 +119,10 @@ public function execute(ResultInterface $defaultResult, string $returnId = null)
}

$isStandardCheckoutSuccess = $this->config->getBitpayCheckoutSuccess() === 'standard';
$returnHash = $this->encryptor->hash("$incrementId:{$order->getCustomerEmail()}:{$order->getProtectCode()}");

if ($isStandardCheckoutSuccess && $returnId) {
if ($returnId !== $returnHash) {
$returnHash = $this->returnHashHelper->generate($order);
if (!$this->returnHashHelper->isValid($returnId, $order)) {
$this->checkoutSession->clearHelperData();

return $this->resultFactory->create(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT)
Expand All @@ -127,6 +133,7 @@ public function execute(ResultInterface $defaultResult, string $returnId = null)
}

try {
$returnHash = $this->returnHashHelper->generate($order);
$baseUrl = $this->config->getBaseUrl();
$order = $this->setToPendingAndOverrideMagentoStatus($order);
$redirectUrl = $this->url->getUrl('bitpay-invoice', ['_query' => ['order_id' => $incrementId]]);
Expand Down
Loading

0 comments on commit f9e17bd

Please sign in to comment.