From b62021f13bcaa8774e4f4bb6ce8c63a7b5491ddd Mon Sep 17 00:00:00 2001 From: Adam Wysocki Date: Thu, 14 Nov 2024 10:39:14 +0100 Subject: [PATCH] Add Blik one click payment variant --- Api/TpayInterface.php | 1 + Controller/Tpay/Create.php | 29 ++- Controller/Tpay/Notification.php | 182 +----------------- Model/Alias.php | 38 +++- Model/AliasRepository.php | 48 +++++ Model/Api/AliasRepositoryInterface.php | 23 +++ Model/Api/Data/AliasInterface.php | 12 ++ Model/ApiFacade/OpenApi.php | 23 ++- .../Transaction/TransactionApiFacade.php | 5 + .../Transaction/TransactionOriginApi.php | 5 + Model/ResourceModel/Alias/Collection.php | 15 ++ Model/TpayConfigProvider.php | 23 ++- Model/TpayPayment.php | 1 + Notification/NotificationProcessor.php | 20 +- .../BlikAliasNotificationProcessor.php | 22 +++ .../Strategy/CardNotificationProcessor.php | 56 ++++++ .../Strategy/DefaultNotificationProcessor.php | 56 +++++- .../Factory/NotificationProcessorFactory.php | 2 +- Service/TpayAliasService.php | 70 +++++++ Service/TpayAliasServiceInterface.php | 17 ++ Service/TpayAliasesService.php | 10 - Setup/InstallSchema.php | 46 +++++ Setup/Uninstall.php | 1 + Validator/AdditionalPaymentInfoValidator.php | 2 +- view/base/web/js/open_render_channels.js | 18 ++ .../payment/method-renderer/tpay-method.js | 1 + .../web/template/payment/tpay-form.html | 9 + 27 files changed, 526 insertions(+), 209 deletions(-) create mode 100644 Model/AliasRepository.php create mode 100644 Model/Api/AliasRepositoryInterface.php create mode 100644 Model/Api/Data/AliasInterface.php create mode 100644 Model/ResourceModel/Alias/Collection.php create mode 100644 Service/TpayAliasService.php create mode 100644 Service/TpayAliasServiceInterface.php delete mode 100644 Service/TpayAliasesService.php diff --git a/Api/TpayInterface.php b/Api/TpayInterface.php index 21a1834..b4e8c7a 100644 --- a/Api/TpayInterface.php +++ b/Api/TpayInterface.php @@ -11,6 +11,7 @@ interface TpayInterface public const GROUP = 'group'; public const CHANNEL = 'channel'; public const BLIK_CODE = 'blik_code'; + public const BLIK_ALIAS = 'blik_alias'; public const TERMS_ACCEPT = 'accept_tos'; public const CARDDATA = 'card_data'; public const CARD_SAVE = 'card_save'; diff --git a/Controller/Tpay/Create.php b/Controller/Tpay/Create.php index 7e08925..609006a 100644 --- a/Controller/Tpay/Create.php +++ b/Controller/Tpay/Create.php @@ -98,7 +98,7 @@ public function execute(): ResultInterface return $this->redirectFactory->redirectSuccess(); } - $result = $this->blikPay($transaction['title'], $additionalPaymentInformation['blik_code']); + $result = $this->blikPay($transaction['title'], $additionalPaymentInformation['blik_code'] ?? '', $additionalPaymentInformation['blik_alias'] ?? ''); $this->checkoutSession->unsQuoteId(); if (!$result) { @@ -125,9 +125,13 @@ public function execute(): ResultInterface * @param string $blikTransactionId * @param string $blikCode */ - protected function blikPay($blikTransactionId, $blikCode): bool + protected function blikPay($blikTransactionId, $blikCode, $blikAlias): bool { - $apiResult = $this->transaction->blik($blikTransactionId, $blikCode); + if ($blikAlias) { + $apiResult = $this->transaction->blikAlias($blikTransactionId, $blikAlias); + } else { + $apiResult = $this->transaction->blik($blikTransactionId, $blikCode); + } return isset($apiResult['result']) && 1 === $apiResult['result']; } @@ -139,7 +143,7 @@ private function prepareTransaction($orderId, array $additionalPaymentInformatio if ($this->additionalPaymentInfoValidator->validateBlikIfPresent($additionalPaymentInformation)) { $data['group'] = TransactionOriginApi::BLIK_CHANNEL; $data['channel'] = null; - $this->handleBlikData($data, $additionalPaymentInformation['blik_code']); + $this->handleBlikData($data, $additionalPaymentInformation['blik_code'] ?? '', $additionalPaymentInformation['blik_alias'] ?? ''); } else { $data['group'] = (int) ($additionalPaymentInformation['group'] ?? null); $data['channel'] = (int) ($additionalPaymentInformation['channel'] ?? null); @@ -159,12 +163,21 @@ private function prepareTransaction($orderId, array $additionalPaymentInformatio return $this->transaction->create($data); } - private function handleBlikData(array &$data, string $blikCode) + private function handleBlikData(array &$data, string $blikCode, string $blikAlias) { if ($this->transaction->isOpenApiUse() && $this->tpay->checkBlikLevel0Settings()) { - $data['blikPaymentData'] = [ - 'blikToken' => $blikCode, - ]; + if ($blikCode) { + $data['blikPaymentData'] = [ + 'blikToken' => $blikCode, + ]; + } + + if ($blikAlias) { + $data['blikPaymentData']['aliases'] = [ + 'type' => 'UID', + 'value' => $blikAlias, + ]; + } } if (!$this->transaction->isOpenApiUse()) { unset($data['channel']); diff --git a/Controller/Tpay/Notification.php b/Controller/Tpay/Notification.php index fa5eb1b..73bea83 100644 --- a/Controller/Tpay/Notification.php +++ b/Controller/Tpay/Notification.php @@ -4,78 +4,37 @@ namespace Tpay\Magento2\Controller\Tpay; -use Exception; use Laminas\Http\Response; use Magento\Framework\App\CsrfAwareActionInterface; use Magento\Framework\App\Request\InvalidRequestException; use Magento\Framework\App\RequestInterface; use Magento\Framework\App\ResponseInterface; -use Magento\Sales\Model\Order; -use Tpay\Magento2\Api\TpayConfigInterface; -use Tpay\Magento2\Api\TpayInterface; -use Tpay\Magento2\Notification\Strategy\Factory\NotificationProcessorFactoryInterface; -use Tpay\Magento2\Service\TpayService; -use Tpay\Magento2\Service\TpayTokensService; -use Tpay\OpenApi\Webhook\JWSVerifiedPaymentNotification; -use Tpay\OriginApi\Utilities\Util; -use Tpay\OriginApi\Webhook\JWSVerifiedPaymentNotification as OriginJWSVerifiedPaymentNotification; +use Throwable; +use Tpay\Magento2\Notification\NotificationProcessor; class Notification implements CsrfAwareActionInterface { - /** @var TpayInterface */ - protected $tpay; - - /** @var TpayConfigInterface */ - protected $tpayConfig; - - /** @var TpayService */ - protected $tpayService; - - /** @var NotificationProcessorFactoryInterface */ - protected $notificationProcessorFactory; - - /** @var TpayTokensService */ - private $tokensService; + /** @var NotificationProcessor */ + protected $notificationProcessor; /** @var ResponseInterface */ private $response; public function __construct( - TpayInterface $tpayModel, - TpayConfigInterface $tpayConfig, - TpayService $tpayService, - TpayTokensService $tokensService, ResponseInterface $response, - NotificationProcessorFactoryInterface $notificationProcessorFactory + NotificationProcessor $notificationProcessor ) { - $this->tpay = $tpayModel; - $this->tpayConfig = $tpayConfig; - $this->tpayService = $tpayService; - $this->tokensService = $tokensService; $this->response = $response; - $this->notificationProcessorFactory = $notificationProcessorFactory; - Util::$loggingEnabled = false; + $this->notificationProcessor = $notificationProcessor; } public function execute(): ?Response { try { - if (isset($_POST['card'])) { - $orderId = base64_decode($_POST['order_id']); - - return $this->extractCardNotification($this->getOrderStore($orderId)); - } - - if (isset($_POST['event'])) { - return $this->response->setStatusCode(Response::STATUS_CODE_400)->setContent('kurwa mac'); - } - - $orderId = base64_decode($_POST['tr_crc']); + $orderId = isset($_POST['order_id']) ? base64_decode($_POST['order_id']) : base64_decode($_POST['tr_crc']); - $strategy = $this->notificationProcessorFactory->create($_POST); - - $strategy->process($this->getOrderStore($orderId)); - } catch (\Throwable $e) { + $this->notificationProcessor->process($orderId); + } catch (Throwable $e) { return $this->response->setStatusCode(Response::STATUS_CODE_400)->setContent($e->getMessage()); } @@ -91,127 +50,4 @@ public function validateForCsrf(RequestInterface $request): ?bool { return true; } - - /** - * Check if the order has been canceled and get response to Tpay server. - * - * @throws Exception - */ - protected function getPaidTransactionResponse(string $orderId): string - { - $order = $this->tpayService->getOrderById($orderId); - - if (!$order->getId()) { - throw new Exception(sprintf('Unable to get order by orderId %s', $orderId)); - } - - if (Order::STATE_CANCELED === $order->getState()) { - return 'FALSE'; - } - - return 'TRUE'; - } - - private function saveCard(array $notification, string $orderId) - { - $order = $this->tpayService->getOrderById($orderId); - - if (isset($notification['card_token']) && !$this->tpay->isCustomerGuest($orderId)) { - $token = $this->tokensService->getWithoutAuthCustomerTokens( - (string) $order->getCustomerId(), - $notification['tr_crc'] - ); - - if (!empty($token)) { - $this->tokensService->updateTokenById((int) $token['tokenId'], $notification['card_token']); - } - } - } - - private function saveOriginCard(array $notification, string $orderId) - { - $order = $this->tpayService->getOrderById($orderId); - - $payment = $this->tpayService->getPayment($orderId); - $additionalPaymentInformation = $payment->getData()['additional_information']; - - if (isset($notification['cli_auth']) && $this->tpayConfig->getCardSaveEnabled() && !$this->tpay->isCustomerGuest($orderId)) { - $this->tokensService->setCustomerToken( - (string) $order->getCustomerId(), - $notification['cli_auth'], - $notification['card'], - $additionalPaymentInformation['card_vendor'] - ); - } - } - - private function extractNotification(?int $storeId = null): Response - { - try { - $notification = (new JWSVerifiedPaymentNotification( - $this->tpayConfig->getSecurityCode($storeId), - !$this->tpayConfig->useSandboxMode($storeId) - ))->getNotification(); - - $notification = $notification->getNotificationAssociative(); - $orderId = base64_decode($notification['tr_crc']); - - if ('PAID' === $notification['tr_status']) { - $response = $this->getPaidTransactionResponse($orderId); - - return $this->response->setStatusCode(Response::STATUS_CODE_200)->setContent($response); - } - - $this->saveCard($notification, $orderId); - $this->tpayService->setOrderStatus($orderId, $notification, $this->tpayConfig); - - return $this->response->setStatusCode(Response::STATUS_CODE_200)->setContent('TRUE'); - } catch (Exception $e) { - $this->handleException($e); - - return $this->response->setStatusCode(Response::STATUS_CODE_400)->setContent('FALSE'); - } - } - - private function extractCardNotification(?int $storeId = null): ?Response - { - try { - $notification = (new OriginJWSVerifiedPaymentNotification( - $this->tpayConfig->getSecurityCode($storeId), - !$this->tpayConfig->useSandboxMode($storeId) - ))->getNotification(); - - $orderId = base64_decode($notification['order_id']); - - $this->tpayService->setCardOrderStatus($orderId, $notification, $this->tpayConfig); - $this->saveOriginCard($notification, $orderId); - - return $this->response->setStatusCode(Response::STATUS_CODE_200)->setContent('TRUE'); - } catch (Exception $e) { - $this->handleException($e); - - return $this->response->setStatusCode(Response::STATUS_CODE_400)->setContent('FALSE'); - } - } - - private function handleException(Exception $e) - { - Util::log( - 'Notification exception', - sprintf( - '%s in file %s line: %d \n\n %s', - $e->getMessage(), - $e->getFile(), - $e->getLine(), - $e->getTraceAsString() - ) - ); - } - - private function getOrderStore(string $orderId): ?int - { - $order = $this->tpayService->getOrderById($orderId); - - return $order->getStoreId() ? (int) $order->getStoreId() : null; - } } diff --git a/Model/Alias.php b/Model/Alias.php index 9c84a64..2f0647c 100644 --- a/Model/Alias.php +++ b/Model/Alias.php @@ -2,12 +2,44 @@ namespace Tpay\Magento2\Model; +use Magento\Framework\Data\Collection\AbstractDb; use Magento\Framework\Model\AbstractModel; +use Magento\Framework\Model\Context; +use Magento\Framework\Model\ResourceModel\AbstractResource; +use Magento\Framework\Registry; +use Tpay\Magento2\Model\Api\Data\AliasInterface; -class Alias extends AbstractModel +class Alias extends AbstractModel implements AliasInterface { - public function __construct() - { + public function __construct( + Context $context, + Registry $registry, + AbstractResource $resource = null, + AbstractDb $resourceCollection = null, + array $data = [] + ) { + parent::__construct($context, $registry, $resource, $resourceCollection, $data); $this->_init(ResourceModel\Alias::class); } + + public function setCustomerId(int $id): AliasInterface + { + $this->setData('cli_id', $id); + + return $this; + } + + public function setAlias(string $alias): AliasInterface + { + $this->setData('alias', $alias); + + return $this; + } + + public function created(): AliasInterface + { + $this->setData('created_at', date('Y-m-d H:i:s')); + + return $this; + } } diff --git a/Model/AliasRepository.php b/Model/AliasRepository.php new file mode 100644 index 0000000..aba53e2 --- /dev/null +++ b/Model/AliasRepository.php @@ -0,0 +1,48 @@ +aliasFactory = $aliasFactory; + $this->aliasResourceModel = $aliasResourceModel; + } + + public function findByCustomerId(int $customerId): ?AliasInterface + { + $alias = $this->aliasFactory->create(); + $this->aliasResourceModel->load($alias, $customerId, 'cli_id'); + + return $alias; + } + + /** + * @inheritDoc + */ + public function save(AliasInterface $alias): void + { + $this->aliasResourceModel->save($alias); + } + + /** + * @inheritDoc + */ + public function remove(AliasInterface $alias): void + { + $this->aliasResourceModel->delete($alias); + } +} diff --git a/Model/Api/AliasRepositoryInterface.php b/Model/Api/AliasRepositoryInterface.php new file mode 100644 index 0000000..4e86c26 --- /dev/null +++ b/Model/Api/AliasRepositoryInterface.php @@ -0,0 +1,23 @@ +createBlikZero($data); } @@ -47,7 +47,7 @@ public function create(array $data): array public function createTransaction(array $data): array { - if (!empty($data['blikPaymentData'])) { + if (!empty($data['blikPaymentData']) && empty($data['blikPaymentData']['aliases'])) { return $this->createBlikZeroTransaction($data); } @@ -91,6 +91,25 @@ public function blik(string $transactionId, string $blikCode): array return $this->updateRedirectUrl($this->waitForBlikAccept($result)); } + public function blikAlias(string $transactionId, string $blikAlias): array + { + $additional_payment_data = [ + 'channelId' => 64, + 'method' => 'pay_by_link', + 'blikPaymentData' => [ + 'type' => 0, + 'aliases' => [ + 'value' => $blikAlias, + 'type' => 'UID' + ], + ], + ]; + + $result = $this->tpayApi->transactions()->createInstantPaymentByTransactionId($additional_payment_data, $transactionId); + + return $this->updateRedirectUrl($this->waitForBlikAccept($result)); + } + public function createBlikZero(array $data): array { $transaction = $this->createBlikZeroTransaction($data); diff --git a/Model/ApiFacade/Transaction/TransactionApiFacade.php b/Model/ApiFacade/Transaction/TransactionApiFacade.php index 77d378c..a0e131e 100755 --- a/Model/ApiFacade/Transaction/TransactionApiFacade.php +++ b/Model/ApiFacade/Transaction/TransactionApiFacade.php @@ -69,6 +69,11 @@ public function blik($blikTransactionId, $blikCode): array return $this->getCurrentApi()->blik($blikTransactionId, $blikCode); } + public function blikAlias($blikAliasTransactionId, $blikAlias): array + { + return $this->getCurrentApi()->blikAlias($blikAliasTransactionId, $blikAlias); + } + /** @return list */ public function channels(): array { diff --git a/Model/ApiFacade/Transaction/TransactionOriginApi.php b/Model/ApiFacade/Transaction/TransactionOriginApi.php index 5329086..a389414 100755 --- a/Model/ApiFacade/Transaction/TransactionOriginApi.php +++ b/Model/ApiFacade/Transaction/TransactionOriginApi.php @@ -31,4 +31,9 @@ public function createTransaction(array $data): array { return $this->create($data); } + + public function blikAlias(string $transactionId, string $blikAlias): array + { + return $this->blik($transactionId, '', $blikAlias); + } } diff --git a/Model/ResourceModel/Alias/Collection.php b/Model/ResourceModel/Alias/Collection.php new file mode 100644 index 0000000..92b1a19 --- /dev/null +++ b/Model/ResourceModel/Alias/Collection.php @@ -0,0 +1,15 @@ +_init(Alias::class, AliasResourceModel::class); + } +} diff --git a/Model/TpayConfigProvider.php b/Model/TpayConfigProvider.php index e9c3946..9e3ba1e 100644 --- a/Model/TpayConfigProvider.php +++ b/Model/TpayConfigProvider.php @@ -5,12 +5,15 @@ namespace Tpay\Magento2\Model; use Magento\Checkout\Model\ConfigProviderInterface; +use Magento\Customer\Model\Session; use Magento\Framework\View\Asset\Repository; use Magento\Payment\Helper\Data as PaymentHelper; use Tpay\Magento2\Api\TpayConfigInterface; use Tpay\Magento2\Api\TpayInterface; +use Tpay\Magento2\Model\Api\AliasRepositoryInterface; use Tpay\Magento2\Model\ApiFacade\TpayConfig\ConfigFacade; use Tpay\Magento2\Model\ApiFacade\Transaction\TransactionApiFacade; +use Tpay\Magento2\Service\TpayAliasServiceInterface; use Tpay\Magento2\Service\TpayService; use Tpay\Magento2\Service\TpayTokensService; @@ -28,17 +31,27 @@ class TpayConfigProvider implements ConfigProviderInterface /** @var TransactionApiFacade */ protected $transactionApi; + /** @var Session */ + protected $customerSession; + + /** @var TpayAliasServiceInterface */ + protected $aliasService; + public function __construct( PaymentHelper $paymentHelper, Repository $assetRepository, TpayTokensService $tokensService, TransactionApiFacade $transactionApiFacade, TpayService $tpayService, - TpayConfigInterface $tpayConfig + TpayConfigInterface $tpayConfig, + Session $customerSession, + TpayAliasServiceInterface $aliasService ) { $this->paymentHelper = $paymentHelper; $this->transactionApi = $transactionApiFacade; $this->configFacade = new ConfigFacade($this->getPaymentMethodInstance(), $tpayConfig, $assetRepository, $tokensService, $tpayService); + $this->customerSession = $customerSession; + $this->aliasService = $aliasService; } public function getConfig(): array @@ -46,6 +59,14 @@ public function getConfig(): array $config = $this->configFacade->getConfig(); $channels = $this->transactionApi->channels(); + if ($this->customerSession->getCustomerId()) { + $alias = $this->aliasService->getCustomerAlias((int) $this->customerSession->getCustomerId()); + + if ($alias) { + $config['blik_alias'] = $alias['alias']; + } + } + foreach ($channels as $channel) { $config['generic'][$channel->id] = [ 'id' => $channel->id, diff --git a/Model/TpayPayment.php b/Model/TpayPayment.php index 42456bf..ccca4dd 100755 --- a/Model/TpayPayment.php +++ b/Model/TpayPayment.php @@ -242,6 +242,7 @@ public function assignData(DataObject $data) $additionalData = array_merge($info->getAdditionalInformation(), $data->getData('additional_data')); $info->setAdditionalInformation(static::GROUP, array_key_exists(static::GROUP, $additionalData) ? $additionalData[static::GROUP] : ''); $info->setAdditionalInformation(static::BLIK_CODE, array_key_exists(static::BLIK_CODE, $additionalData) ? $additionalData[static::BLIK_CODE] : ''); + $info->setAdditionalInformation(static::BLIK_ALIAS, array_key_exists(static::BLIK_ALIAS, $additionalData) ? $additionalData[static::BLIK_ALIAS] : ''); $info->setAdditionalInformation(static::CHANNEL, $additionalData[static::CHANNEL] ?? null); $info->setAdditionalInformation(static::TERMS_ACCEPT, isset($additionalData[static::TERMS_ACCEPT]) ? (bool) ($additionalData[static::TERMS_ACCEPT]) : false); $info->setAdditionalInformation(static::CARDDATA, $additionalData[static::CARDDATA] ?? ''); diff --git a/Notification/NotificationProcessor.php b/Notification/NotificationProcessor.php index 4894b77..4fad778 100644 --- a/Notification/NotificationProcessor.php +++ b/Notification/NotificationProcessor.php @@ -3,21 +3,33 @@ namespace Tpay\Magento2\Notification; use Tpay\Magento2\Notification\Strategy\Factory\NotificationProcessorFactoryInterface; +use Tpay\Magento2\Service\TpayService; class NotificationProcessor { /** @var NotificationProcessorFactoryInterface */ protected $factory; - public function __construct(NotificationProcessorFactoryInterface $factory) + /** @var TpayService */ + protected $tpayService; + + public function __construct(NotificationProcessorFactoryInterface $factory, TpayService $tpayService) { $this->factory = $factory; + $this->tpayService = $tpayService; + } + + public function process(string $orderId) + { + $strategy = $this->factory->create($_POST); + + $strategy->process($this->getOrderStore($orderId)); } - public function process() + private function getOrderStore(string $orderId): ?int { - $strategy = $this->factory->create(); + $order = $this->tpayService->getOrderById($orderId); - return $strategy->process(); + return $order->getStoreId() ? (int) $order->getStoreId() : null; } } diff --git a/Notification/Strategy/BlikAliasNotificationProcessor.php b/Notification/Strategy/BlikAliasNotificationProcessor.php index dba4974..822d96c 100644 --- a/Notification/Strategy/BlikAliasNotificationProcessor.php +++ b/Notification/Strategy/BlikAliasNotificationProcessor.php @@ -1,10 +1,32 @@ aliasService = $aliasService; + } + public function process(?int $storeId) { + $response = $_POST; + $userId = (int) explode('_', $response['value'])[1]; + + if ($response['event'] === 'ALIAS_REGISTER') { + $this->aliasService->saveCustomerAlias($userId, $response['value']); + } + + if ($response['event'] === 'ALIAS_UNREGISTER') { + $this->aliasService->removeCustomerAlias($userId, $response['value']); + } } } diff --git a/Notification/Strategy/CardNotificationProcessor.php b/Notification/Strategy/CardNotificationProcessor.php index e5c0251..a8f7081 100644 --- a/Notification/Strategy/CardNotificationProcessor.php +++ b/Notification/Strategy/CardNotificationProcessor.php @@ -2,9 +2,65 @@ namespace Tpay\Magento2\Notification\Strategy; +use Tpay\Magento2\Api\TpayConfigInterface; +use Tpay\Magento2\Api\TpayInterface; +use Tpay\Magento2\Service\TpayService; +use Tpay\Magento2\Service\TpayTokensService; +use Tpay\OriginApi\Webhook\JWSVerifiedPaymentNotification; + class CardNotificationProcessor implements NotificationProcessorInterface { + /** @var TpayConfigInterface */ + protected $tpayConfig; + + /** @var TpayService */ + protected $tpayService; + + /** @var TpayTokensService */ + protected $tokensService; + + /** @var TpayInterface */ + protected $tpay; + + public function __construct( + TpayConfigInterface $tpayConfig, + TpayService $tpayService, + TpayTokensService $tokensService, + TpayInterface $tpayModel + ) { + $this->tpayConfig = $tpayConfig; + $this->tpayService = $tpayService; + $this->tokensService = $tokensService; + $this->tpay = $tpayModel; + } + public function process(?int $storeId) { + $notification = (new JWSVerifiedPaymentNotification( + $this->tpayConfig->getSecurityCode($storeId), + !$this->tpayConfig->useSandboxMode($storeId) + ))->getNotification(); + + $orderId = base64_decode($notification['order_id']); + + $this->tpayService->setCardOrderStatus($orderId, $notification, $this->tpayConfig); + $this->saveOriginCard($notification, $orderId); + } + + private function saveOriginCard(array $notification, string $orderId) + { + $order = $this->tpayService->getOrderById($orderId); + + $payment = $this->tpayService->getPayment($orderId); + $additionalPaymentInformation = $payment->getData()['additional_information']; + + if (isset($notification['cli_auth']) && $this->tpayConfig->getCardSaveEnabled() && !$this->tpay->isCustomerGuest($orderId)) { + $this->tokensService->setCustomerToken( + (string) $order->getCustomerId(), + $notification['cli_auth'], + $notification['card'], + $additionalPaymentInformation['card_vendor'] + ); + } } } diff --git a/Notification/Strategy/DefaultNotificationProcessor.php b/Notification/Strategy/DefaultNotificationProcessor.php index 413984a..31d9d42 100644 --- a/Notification/Strategy/DefaultNotificationProcessor.php +++ b/Notification/Strategy/DefaultNotificationProcessor.php @@ -2,9 +2,12 @@ namespace Tpay\Magento2\Notification\Strategy; -use Laminas\Http\Response; +use Exception; +use Magento\Sales\Model\Order; use Tpay\Magento2\Api\TpayConfigInterface; +use Tpay\Magento2\Api\TpayInterface; use Tpay\Magento2\Service\TpayService; +use Tpay\Magento2\Service\TpayTokensService; use Tpay\OpenApi\Webhook\JWSVerifiedPaymentNotification; class DefaultNotificationProcessor implements NotificationProcessorInterface @@ -15,10 +18,22 @@ class DefaultNotificationProcessor implements NotificationProcessorInterface /** @var TpayService */ protected $tpayService; - public function __construct(TpayConfigInterface $tpayConfig, TpayService $tpayService) - { + /** @var TpayTokensService */ + protected $tokensService; + + /** @var TpayInterface */ + protected $tpay; + + public function __construct( + TpayConfigInterface $tpayConfig, + TpayService $tpayService, + TpayTokensService $tokensService, + TpayInterface $tpayModel + ) { $this->tpayConfig = $tpayConfig; $this->tpayService = $tpayService; + $this->tokensService = $tokensService; + $this->tpay = $tpayModel; } public function process(?int $storeId) @@ -32,12 +47,41 @@ public function process(?int $storeId) $orderId = base64_decode($notification['tr_crc']); if ('PAID' === $notification['tr_status']) { - $response = $this->getPaidTransactionResponse($orderId); - - return $this->response->setStatusCode(Response::STATUS_CODE_200)->setContent($response); + return $this->getPaidTransactionResponse($orderId); } $this->saveCard($notification, $orderId); $this->tpayService->setOrderStatus($orderId, $notification, $this->tpayConfig); } + + protected function getPaidTransactionResponse(string $orderId): string + { + $order = $this->tpayService->getOrderById($orderId); + + if (!$order->getId()) { + throw new Exception(sprintf('Unable to get order by orderId %s', $orderId)); + } + + if (Order::STATE_CANCELED === $order->getState()) { + return 'FALSE'; + } + + return 'TRUE'; + } + + private function saveCard(array $notification, string $orderId) + { + $order = $this->tpayService->getOrderById($orderId); + + if (isset($notification['card_token']) && !$this->tpay->isCustomerGuest($orderId)) { + $token = $this->tokensService->getWithoutAuthCustomerTokens( + (string) $order->getCustomerId(), + $notification['tr_crc'] + ); + + if (!empty($token)) { + $this->tokensService->updateTokenById((int) $token['tokenId'], $notification['card_token']); + } + } + } } diff --git a/Notification/Strategy/Factory/NotificationProcessorFactory.php b/Notification/Strategy/Factory/NotificationProcessorFactory.php index 29e44b0..0807d7a 100644 --- a/Notification/Strategy/Factory/NotificationProcessorFactory.php +++ b/Notification/Strategy/Factory/NotificationProcessorFactory.php @@ -6,7 +6,7 @@ class NotificationProcessorFactory implements NotificationProcessorFactoryInterface { - /** @var NotificationProcessorInterface[] */ + /** @var list */ protected $strategies; public function __construct(array $strategies = []) diff --git a/Service/TpayAliasService.php b/Service/TpayAliasService.php new file mode 100644 index 0000000..d45cd33 --- /dev/null +++ b/Service/TpayAliasService.php @@ -0,0 +1,70 @@ +resourceConnection = $resourceConnection; + $this->collection = $collection; + $this->aliasRepository = $aliasRepository; + } + + public function getCustomerAlias(int $customerId) + { + $connection = $this->resourceConnection->getConnection(); + $tableName = $connection->getTableName('tpay_blik_aliases'); + + $select = $connection->select() + ->from($tableName) + ->where('cli_id = ?', $customerId); + + return $connection->fetchRow($select); + } + + public function saveCustomerAlias(int $customerId, string $alias): void + { + $aliasEntity = $this->aliasRepository->findByCustomerId($customerId); + + if (!$aliasEntity->getId()) { + $aliasEntity->setCustomerId($customerId) + ->setAlias($alias) + ->created(); + + $this->aliasRepository->save($aliasEntity); + } + } + + /** + * @inheritDoc + */ + public function removeCustomerAlias(int $customerId, string $alias): void + { + $aliasEntity = $this->aliasRepository->findByCustomerId($customerId); + + if (!$aliasEntity->getId()) { + throw new \Exception("Alias for customerId {$customerId} not found"); + } + + $this->aliasRepository->remove($aliasEntity); + } +} diff --git a/Service/TpayAliasServiceInterface.php b/Service/TpayAliasServiceInterface.php new file mode 100644 index 0000000..e0680df --- /dev/null +++ b/Service/TpayAliasServiceInterface.php @@ -0,0 +1,17 @@ +getConnection()->createTable($table); } + // Get tpay blik aliases table + $tableName = $installer->getTable('tpay_blik_aliases'); + // Check if the table already exists + if (true != $installer->getConnection()->isTableExists($tableName)) { + // Create table + $table = $installer->getConnection() + ->newTable($tableName) + ->addColumn( + 'id', + Table::TYPE_INTEGER, + null, + [ + 'identity' => true, + 'unsigned' => true, + 'nullable' => false, + 'primary' => true, + ], + 'ID' + ) + ->addColumn( + 'cli_id', + Table::TYPE_TEXT, + null, + ['nullable' => false, 'default' => ''], + 'Customer Identifier' + ) + ->addColumn( + 'alias', + Table::TYPE_TEXT, + null, + ['nullable' => false, 'default' => ''], + 'Blik alias' + ) + ->addColumn( + 'created_at', + Table::TYPE_DATETIME, + null, + ['nullable' => false], + 'Created At' + ) + ->setComment('Tpay blik aliases') + ->setOption('type', 'InnoDB') + ->setOption('charset', 'utf8'); + $installer->getConnection()->createTable($table); + } + $installer->endSetup(); } } diff --git a/Setup/Uninstall.php b/Setup/Uninstall.php index 92d64a8..00a201f 100644 --- a/Setup/Uninstall.php +++ b/Setup/Uninstall.php @@ -14,6 +14,7 @@ public function uninstall(SchemaSetupInterface $setup, ModuleContextInterface $c $installer->startSetup(); $installer->getConnection()->dropTable($installer->getTable('tpay_credit_cards')); + $installer->getConnection()->dropTable($installer->getTable('tpay_blik_aliases')); $installer->endSetup(); } diff --git a/Validator/AdditionalPaymentInfoValidator.php b/Validator/AdditionalPaymentInfoValidator.php index 3de32b1..f91a9bd 100644 --- a/Validator/AdditionalPaymentInfoValidator.php +++ b/Validator/AdditionalPaymentInfoValidator.php @@ -15,7 +15,7 @@ public function validateCardData(array $data): bool public function validateBlikIfPresent(array $data): bool { - return 6 === strlen($data[TpayInterface::BLIK_CODE]); + return 6 === strlen($data[TpayInterface::BLIK_CODE]) || !empty($data[TpayInterface::BLIK_ALIAS]); } public function validatePresenceOfGroupOrChannel(array $data): bool diff --git a/view/base/web/js/open_render_channels.js b/view/base/web/js/open_render_channels.js index 589e1a1..1c3e7ad 100644 --- a/view/base/web/js/open_render_channels.js +++ b/view/base/web/js/open_render_channels.js @@ -113,6 +113,10 @@ require(['jquery', 'mage/translate'], function ($, $t) { if (window.checkoutConfig.tpay.payment.blikStatus !== true) { $(".blik").hide(); } + + if (!window.checkoutConfig.blik_alias) { + $(".blik-alias").hide(); + } } function setBlikInputAction() { @@ -120,19 +124,33 @@ require(['jquery', 'mage/translate'], function ($, $t) { $('#blik_code').on(TRIGGER_EVENTS, function () { var that = $(this); + if (that.val().length > 0) { $('#tpay-basic-main-payment').css('display', 'none'); } else { $('#tpay-basic-main-payment').css('display', 'block'); } + if ( (that.val().length === 6 || (that.val().length === 0 && $('#tpay-channel-input').val() > 0)) ) { payButton.removeClass('disabled'); } + if (that.val().length > 0 && that.val().length !== 6) { payButton.addClass('disabled'); } + + $('#blik_alias').prop('checked', false); + }); + + $('#blik_alias').on('change', function () { + if ($('#blik_code').val().length > 0) { + $('#blik_alias').prop('checked', false); + } + + $("#blik_alias_value").val(window.checkoutConfig.blik_alias); + payButton.removeClass('disabled'); }); } diff --git a/view/frontend/web/js/view/payment/method-renderer/tpay-method.js b/view/frontend/web/js/view/payment/method-renderer/tpay-method.js index 5b36ce2..9e87094 100644 --- a/view/frontend/web/js/view/payment/method-renderer/tpay-method.js +++ b/view/frontend/web/js/view/payment/method-renderer/tpay-method.js @@ -66,6 +66,7 @@ define( paymentData['blik_code'] = $('#blik_code').val(); paymentData['accept_tos'] = true; paymentData['channel'] = ""; + paymentData['blik_alias'] = $('#blik_alias_value').val(); return $.extend(true, parent, {'additional_data': paymentData}); }, diff --git a/view/frontend/web/template/payment/tpay-form.html b/view/frontend/web/template/payment/tpay-form.html index 76c7b98..6dd2d84 100644 --- a/view/frontend/web/template/payment/tpay-form.html +++ b/view/frontend/web/template/payment/tpay-form.html @@ -37,6 +37,15 @@ /> +
+
+

+ + +

+ +
+