From 76a4f47c582452ed12eabba658438877b139ef20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sammy=20Nordstr=C3=B6m?= Date: Tue, 14 May 2019 13:53:14 +0200 Subject: [PATCH] [RELEASE] First release of new PayEx Checkin module for Magento 2 --- .gitignore | 2 + Block/Widget/CheckinWidget.php | 197 ++++++++++++ .../Index/OnBillingDetailsAvailable.php | 145 +++++++++ Controller/Index/OnConsumerIdentified.php | 116 ++++++++ Controller/Index/OnConsumerReidentified.php | 93 ++++++ Controller/Index/OnError.php | 93 ++++++ .../Index/OnShippingDetailsAvailable.php | 142 +++++++++ Helper/Config.php | 10 + Model/Checkout/AdditionalConfigVars.php | 52 ++++ Model/ConsumerSession.php | 141 +++++++++ composer.json | 33 ++ etc/adminhtml/system.xml | 23 ++ etc/config.xml | 11 + etc/di.xml | 14 + etc/frontend/di.xml | 10 + etc/frontend/routes.xml | 7 + etc/module.xml | 8 + etc/widget.xml | 8 + registration.php | 7 + view/frontend/layout/default.xml | 11 + view/frontend/layout/payex_checkout_index.xml | 37 +++ view/frontend/requirejs-config.js | 7 + .../templates/widget/checkin-script.phtml | 5 + .../templates/widget/checkin-widget.phtml | 31 ++ view/frontend/web/css/payex_checkin.css | 47 +++ .../js/action/open-shipping-information.js | 13 + view/frontend/web/js/checkin-styling.js | 55 ++++ view/frontend/web/js/view/checkin.js | 281 ++++++++++++++++++ view/frontend/web/template/checkin.html | 20 ++ 29 files changed, 1619 insertions(+) create mode 100644 .gitignore create mode 100644 Block/Widget/CheckinWidget.php create mode 100644 Controller/Index/OnBillingDetailsAvailable.php create mode 100644 Controller/Index/OnConsumerIdentified.php create mode 100644 Controller/Index/OnConsumerReidentified.php create mode 100644 Controller/Index/OnError.php create mode 100644 Controller/Index/OnShippingDetailsAvailable.php create mode 100644 Helper/Config.php create mode 100644 Model/Checkout/AdditionalConfigVars.php create mode 100644 Model/ConsumerSession.php create mode 100644 composer.json create mode 100644 etc/adminhtml/system.xml create mode 100644 etc/config.xml create mode 100644 etc/di.xml create mode 100644 etc/frontend/di.xml create mode 100644 etc/frontend/routes.xml create mode 100644 etc/module.xml create mode 100644 etc/widget.xml create mode 100644 registration.php create mode 100644 view/frontend/layout/default.xml create mode 100644 view/frontend/layout/payex_checkout_index.xml create mode 100644 view/frontend/requirejs-config.js create mode 100644 view/frontend/templates/widget/checkin-script.phtml create mode 100644 view/frontend/templates/widget/checkin-widget.phtml create mode 100644 view/frontend/web/css/payex_checkin.css create mode 100644 view/frontend/web/js/action/open-shipping-information.js create mode 100644 view/frontend/web/js/checkin-styling.js create mode 100644 view/frontend/web/js/view/checkin.js create mode 100644 view/frontend/web/template/checkin.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..987e2a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +composer.lock +vendor diff --git a/Block/Widget/CheckinWidget.php b/Block/Widget/CheckinWidget.php new file mode 100644 index 0000000..d836b7f --- /dev/null +++ b/Block/Widget/CheckinWidget.php @@ -0,0 +1,197 @@ +consumerSession = $consumerSession; + $this->customerSession = $customerSession; + $this->customerRepository = $customerRepository; + $this->addressRepository = $addressRepository; + $this->eventManager = $eventManager; + $this->service = $service; + $this->logger = $logger; + $this->config = $config; + parent::__construct($context, $data); + } + + public function isActive() + { + return $this->config->isActive(); + } + + public function isConsumerIdentified() + { + return $this->consumerSession->isIdentified(); + } + + /** + * Get default country + * + * @return string + */ + public function getDefaultCountry() + { + $configPath = 'general/country/default'; + $scope = ScopeInterface::SCOPE_STORE; + return $this->_scopeConfig->getValue($configPath, $scope); + } + + /** + * @param ConsumerSessionResource $consumerSessionData + * @return ResponseInterface|false + * @throws \PayEx\Client\Exception\ServiceException + */ + public function initiateConsumerSession(ConsumerSessionResource $consumerSessionData) + { + /** @var RequestInterface $consumerSession */ + $consumerSession = $this->service->init('Consumer', 'InitiateConsumerSession', $consumerSessionData); + + /** @var ResponseInterface $response */ + $response = $consumerSession->send(); + + if (!($response instanceof ResponseInterface) || !($response->getResponseResource() instanceof ResponseResourceInterface)) { + $this->logger->error(sprintf('Invalid InitiateConsumerSession response: %s', print_r($response, true))); + return false; + } + + $this->consumerSession->isInitiated(true); + + return $response; + } + + /** + * @return string|false + */ + public function getCheckinScript() + { + if ($this->consumerSession->getViewOperation()) { + $viewOperation = $this->consumerSession->getViewOperation(); + return $viewOperation['href']; + } + + $consumerSessionData = new ConsumerSessionResource(); + $consumerSessionData->setConsumerCountryCode($this->getDefaultCountry()); + + if ($this->customerSession->isLoggedIn()) { + $customerId = $this->customerSession->getCustomerId(); + $customer = $this->customerRepository->getById($customerId); + $email = $customer->getEmail(); + try { + $billingAddress = $this->addressRepository->getById($customer->getDefaultBilling()); + } catch (LocalizedException $e) { + $this->logger->error($e->getMessage()); + return false; + } + $msisdn = $billingAddress->getTelephone(); + $countryCode = $billingAddress->getCountryId(); + $this->eventManager->dispatch('payex_checkin_before_initiate_consumer_session'); + + $nationalIdentifierData = new ConsumerNationalIdentifier(); + $nationalIdentifierData->setCountryCode($countryCode); + + $consumerSessionData->setMsisdn($msisdn) + ->setEmail($email) + ->setConsumerCountryCode($countryCode) + ->setNationalIdentifier($nationalIdentifierData); + } + + /** @var ResponseInterface|false $response */ + try { + $response = $this->initiateConsumerSession($consumerSessionData); + } catch (ServiceException $e) { + $this->logger->error($e->getMessage()); + return false; + } + + if ($response instanceof ResponseInterface) { + $viewOperation = $response->getOperationByRel('view-consumer-identification'); + $this->consumerSession->setViewOperation($viewOperation); + return $viewOperation['href']; + } + + return false; + } + + protected function _toHtml() + { + if (!$this->isActive()) { + return ''; + } + + return parent::_toHtml(); + } +} diff --git a/Controller/Index/OnBillingDetailsAvailable.php b/Controller/Index/OnBillingDetailsAvailable.php new file mode 100644 index 0000000..ca78026 --- /dev/null +++ b/Controller/Index/OnBillingDetailsAvailable.php @@ -0,0 +1,145 @@ +resultPageFactory = $resultPageFactory; + $this->resultJsonFactory = $resultJsonFactory; + $this->customerSession = $customerSession; + $this->consumerSession = $consumerSession; + $this->eventManager = $eventManager; + $this->logger = $logger; + $this->service = $service; + $this->config = $config; + $this->cookieManager = $cookieManager; + $this->cookieMetadataFactory = $cookieMetadataFactory; + } + + /** + * @return ResponseInterface|Json|ResultInterface + * @throws \Exception + */ + public function execute() + { + if (!$this->config->isActive()) { + $result = $this->resultJsonFactory->create(); + $result->setData(['data' => 'Forbidden! Module is not enabled']); + $result->setHttpResponseCode(403); + + return $result; + } + + /** @var HttpRequest $request */ + $request = $this->getRequest(); + $requestBody = json_decode($request->getContent()); + + $this->eventManager->dispatch('payex_checkin_before_billing_details_available', (array) $requestBody); + + try { + $url = $requestBody->url; + + /** @var \PayEx\Api\Service\Data\RequestInterface $session */ + $session = $this->service->init('Consumer', 'GetBillingDetails'); + $session->setRequestMethod('GET'); + $session->setRequestEndpoint($url); + $response = $session->send()->getResponseData(); + + $metadata = $this->cookieMetadataFactory + ->createPublicCookieMetadata() + ->setDuration(self::COOKIE_DURATION) + ->setPath($this->consumerSession->getCookiePath()) + ->setDomain($this->consumerSession->getCookieDomain()); + + $this->cookieManager + ->setPublicCookie('billingDetails', json_encode($response), $metadata); + + $result = $this->resultJsonFactory->create(); + $result->setData(['data' => $response]); + $result->setHttpResponseCode(200); + } catch (\Exception $exception) { + $this->logger->Error($exception->getMessage()); + $result = $this->resultJsonFactory->create(); + $result->setHttpResponseCode(400); + } + + return $result; + } +} diff --git a/Controller/Index/OnConsumerIdentified.php b/Controller/Index/OnConsumerIdentified.php new file mode 100644 index 0000000..dc73263 --- /dev/null +++ b/Controller/Index/OnConsumerIdentified.php @@ -0,0 +1,116 @@ +resultPageFactory = $resultPageFactory; + $this->resultJsonFactory = $resultJsonFactory; + $this->consumerSession = $consumerSession; + $this->eventManager = $eventManager; + $this->logger = $logger; + $this->config = $config; + } + + /** + * @return ResponseInterface|\Magento\Framework\Controller\Result\Json|\Magento\Framework\Controller\ResultInterface + * @throws \Exception + */ + public function execute() + { + if (!$this->config->isActive()) { + $result = $this->resultJsonFactory->create(); + $result->setData(['data' => 'Forbidden! Module is not enabled']); + $result->setHttpResponseCode(403); + + return $result; + } + /** @var HttpRequest $request */ + $request = $this->getRequest(); + $requestBody = json_decode($request->getContent()); + + $this->eventManager->dispatch('payex_checkin_before_consumer_identified', (array)$requestBody); + + try { + $actionType = $requestBody->actionType; + switch ($actionType) { + case 'OnConsumerIdentified': +// $this->consumerSession->isIdentified(true); +// $this->consumerSession->setConsumerProfileRef($requestBody->consumerProfileRef); +// $this->consumerSession->setActionType($actionType); + $this->eventManager->dispatch( + 'payex_checkin_identified', + ['consumerProfileRef' => $requestBody->consumerProfileRef] + ); + break; + default: +// $this->consumerSession->setCheckinUrl($requestBody->url); +// $this->consumerSession->setActionType($actionType); + $this->eventManager->dispatch( + 'payex_checkin_complete', + ['url' => $requestBody->url] + ); + break; + } + } catch (\Exception $exception) { + $result = $this->resultJsonFactory->create(); + $result->setData(['data' => 'Wrong request body']); + $result->setHttpResponseCode(400); + $this->logger->Error('Wrong request body passed to OnConsumerIdentifiedController', (array)$requestBody); + return $result; + } + + $result = $this->resultJsonFactory->create(); + $result->setData(['data' => 'Status changed']); + return $result; + } +} diff --git a/Controller/Index/OnConsumerReidentified.php b/Controller/Index/OnConsumerReidentified.php new file mode 100644 index 0000000..2938840 --- /dev/null +++ b/Controller/Index/OnConsumerReidentified.php @@ -0,0 +1,93 @@ +resultPageFactory = $resultPageFactory; + $this->resultJsonFactory = $resultJsonFactory; + $this->eventManager = $eventManager; + $this->logger = $logger; + $this->config = $config; + $this->consumerSession = $consumerSession; + $this->cookieManager = $cookieManager; + } + + /** + * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\Result\Json|\Magento\Framework\Controller\ResultInterface + */ + public function execute() + { + $result = $this->resultJsonFactory->create(); + + if (!$this->config->isActive()) { + $result->setData(['data' => 'Forbidden! Module is not enabled']); + $result->setHttpResponseCode(403); + + return $result; + } + + $result->setData( + [ + 'billing_details' => json_decode($this->cookieManager->getCookie('billingDetails')), + 'shipping_details' => json_decode($this->cookieManager->getCookie('shippingDetails')) + ] + ); + $result->setHttpResponseCode(200); + return $result; + } +} diff --git a/Controller/Index/OnError.php b/Controller/Index/OnError.php new file mode 100644 index 0000000..fc908dc --- /dev/null +++ b/Controller/Index/OnError.php @@ -0,0 +1,93 @@ +resultPageFactory = $resultPageFactory; + $this->resultJsonFactory = $resultJsonFactory; + $this->customerSession = $customerSession; + $this->eventManager = $eventManager; + $this->logger = $logger; + $this->config = $config; + } + + /** + * @return ResponseInterface|\Magento\Framework\Controller\Result\Json|\Magento\Framework\Controller\ResultInterface + * @throws \Exception + */ + public function execute() + { + if (!$this->config->isActive()) { + $result = $this->resultJsonFactory->create(); + $result->setData(['data' => 'Forbidden! Module is not enabled']); + $result->setHttpResponseCode(403); + + return $result; + } + + /** @var HttpRequest $request */ + $request = $this->getRequest(); + $requestBody = json_decode($request->getContent()); + + $this->eventManager->dispatch('payex_checkin_before_error', (array) $requestBody); + + $details = $requestBody->details; + + $this->logger->Error($details, $requestBody); + + $result = $this->resultJsonFactory->create(); + $result->setData(['data' => $details]); + $result->setHttpResponseCode(400); + return $result; + } +} diff --git a/Controller/Index/OnShippingDetailsAvailable.php b/Controller/Index/OnShippingDetailsAvailable.php new file mode 100644 index 0000000..4aa4d39 --- /dev/null +++ b/Controller/Index/OnShippingDetailsAvailable.php @@ -0,0 +1,142 @@ +resultPageFactory = $resultPageFactory; + $this->resultJsonFactory = $resultJsonFactory; + $this->customerSession = $customerSession; + $this->consumerSession = $consumerSession; + $this->eventManager = $eventManager; + $this->logger = $logger; + $this->service = $service; + $this->config = $config; + $this->cookieManager = $cookieManager; + $this->cookieMetadataFactory = $cookieMetadataFactory; + } + + /** + * @return ResponseInterface|\Magento\Framework\Controller\Result\Json|\Magento\Framework\Controller\ResultInterface + * @throws \Exception + */ + public function execute() + { + if (!$this->config->isActive()) { + $result = $this->resultJsonFactory->create(); + $result->setData(['data' => 'Forbidden! Module is not enabled']); + $result->setHttpResponseCode(403); + + return $result; + } + + /** @var HttpRequest $request */ + $request = $this->getRequest(); + $requestBody = json_decode($request->getContent()); + + $this->eventManager->dispatch('payex_checkin_before_shipping_details_available', (array)$requestBody); + + try { + //$actionType = $requestBody->actionType; // TO DO: Do we need this variable? + $url = $requestBody->url; + + $session = $this->service->init('Consumer', 'GetShippingDetails'); + $session->setRequestMethod('GET'); + $session->setRequestEndpoint($url); + $response = $session->send()->getResponseData(); + + $metadata = $this->cookieMetadataFactory + ->createPublicCookieMetadata() + ->setDuration(self::COOKIE_DURATION) + ->setPath($this->consumerSession->getCookiePath()) + ->setDomain($this->consumerSession->getCookieDomain()); + + $this->cookieManager + ->setPublicCookie('shippingDetails', json_encode($response), $metadata); + + $result = $this->resultJsonFactory->create(); + $result->setData(['data' => $response]); + $result->setHttpResponseCode(200); + } catch (\Exception $exception) { + $this->logger->Error($exception->getMessage()); + $result = $this->resultJsonFactory->create(); + $result->setHttpResponseCode(400); + } + return $result; + } +} diff --git a/Helper/Config.php b/Helper/Config.php new file mode 100644 index 0000000..a733cdd --- /dev/null +++ b/Helper/Config.php @@ -0,0 +1,10 @@ +config = $config; + $this->urlBuilder = $urlBuilder; + } + + /** + * @return array + */ + public function getConfig() + { + return [ + 'PayEx_Checkin' => [ + 'isEnabled' => $this->config->getValue('active'), + 'isRequired' => $this->config->getValue('required'), + 'OnConsumerIdentifiedUrl' => $this->urlBuilder->getUrl('PayExCheckin/Index/OnConsumerIdentified'), + 'OnConsumerReidentifiedUrl' => $this->urlBuilder->getUrl('PayExCheckin/Index/OnConsumerReidentified'), + 'OnBillingDetailsAvailableUrl' => $this->urlBuilder->getUrl('PayExCheckin/Index/OnBillingDetailsAvailable'), + 'OnShippingDetailsAvailableUrl' => $this->urlBuilder->getUrl('PayExCheckin/Index/OnShippingDetailsAvailable') + ] + ]; + } +} diff --git a/Model/ConsumerSession.php b/Model/ConsumerSession.php new file mode 100644 index 0000000..9f1dcf6 --- /dev/null +++ b/Model/ConsumerSession.php @@ -0,0 +1,141 @@ +storage->setData(self::IS_INITIATED, $flag); + + return $this; + } + + return (bool) $this->getData(self::IS_INITIATED); + } + + /** + * @param bool|null $flag + * @return bool|ConsumerSession + */ + public function isIdentified($flag = null) + { + if (!is_null($flag)) { + $this->storage->setData(self::IS_IDENTIFIED, $flag); + + return $this; + } + + return (bool) $this->getData(self::IS_IDENTIFIED); + } + + /** + * @return mixed + */ + public function getViewOperation() + { + return $this->getData(self::VIEW_OPERATION); + } + + /** + * @param $viewOperation + */ + public function setViewOperation($viewOperation) + { + $this->storage->setData(self::VIEW_OPERATION, $viewOperation); + } + + /** + * @return mixed + */ + public function getBillingDetails() + { + return $this->getData(self::BILLING_DETAILS); + } + + /** + * @param $billingDetails + */ + public function setBillingDetails($billingDetails) + { + $this->storage->setData(self::BILLING_DETAILS, $billingDetails); + } + + /** + * @return mixed + */ + public function getShippingDetails() + { + return $this->getData(self::SHIPPING_DETAILS); + } + + /** + * @param $shippingDetails + */ + public function setShippingDetails($shippingDetails) + { + $this->storage->setData(self::SHIPPING_DETAILS, $shippingDetails); + } + + /** + * @return mixed + */ + public function getConsumerProfileRef() + { + return $this->getData(self::CONSUMER_PROFILE_REF); + } + + /** + * @param $consumerProfileRef + */ + public function setConsumerProfileRef($consumerProfileRef) + { + $this->storage->setData(self::CONSUMER_PROFILE_REF, $consumerProfileRef); + } + /** + * @return mixed + */ + public function getCheckinUrl() + { + return $this->getData(self::CHECKIN_URL); + } + + /** + * @param $checkinUrl + */ + public function setCheckinUrl($checkinUrl) + { + $this->storage->setData(self::CHECKIN_URL, $checkinUrl); + } + /** + * @return mixed + */ + public function getActionType() + { + return $this->getData(self::ACTION_TYPE); + } + + /** + * @param $actionType + */ + public function setActionType($actionType) + { + $this->storage->setData(self::ACTION_TYPE, $actionType); + } + + +} diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..01e6427 --- /dev/null +++ b/composer.json @@ -0,0 +1,33 @@ +{ + "name": "payex/magento2-checkin", + "type": "magento2-module", + "version": "1.0.0", + "description": "PayEx Checkin module for Magento 2", + "license": "Apache-2.0", + "authors": [ + { + "name": "Sammy Nordström", + "email": "sammy.nordstrom@visma.com" + } + ], + "keywords": ["magento", "payment", "payex"], + "require": { + "ext-curl": "*", + "ext-json": "*", + "payex/magento2-client": "^1.0" + }, + "repositories": { + "magento": { + "type": "composer", + "url": "https://repo.magento.com/" + } + }, + "autoload": { + "files" : [ + "registration.php" + ], + "psr-4": { + "PayEx\\Checkin\\": "" + } + } +} diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml new file mode 100644 index 0000000..f65c578 --- /dev/null +++ b/etc/adminhtml/system.xml @@ -0,0 +1,23 @@ + + + +
+ + + + + + payex/checkin/active + Magento\Config\Model\Config\Source\Yesno + + + + payex/checkin/required + Magento\Config\Model\Config\Source\Yesno + Require login through checkin widget + + + +
+
+
\ No newline at end of file diff --git a/etc/config.xml b/etc/config.xml new file mode 100644 index 0000000..8ad5bd2 --- /dev/null +++ b/etc/config.xml @@ -0,0 +1,11 @@ + + + + + + 0 + 0 + + + + \ No newline at end of file diff --git a/etc/di.xml b/etc/di.xml new file mode 100644 index 0000000..2ebff7f --- /dev/null +++ b/etc/di.xml @@ -0,0 +1,14 @@ + + + + + PayEx_Checkin + + + + + PayEx\Checkin\Model\ConsumerSession\Storage + + + \ No newline at end of file diff --git a/etc/frontend/di.xml b/etc/frontend/di.xml new file mode 100644 index 0000000..3c0211c --- /dev/null +++ b/etc/frontend/di.xml @@ -0,0 +1,10 @@ + + + + + PayEx\Checkin\Model\Checkout\AdditionalConfigVars + + + + \ No newline at end of file diff --git a/etc/frontend/routes.xml b/etc/frontend/routes.xml new file mode 100644 index 0000000..fe113ee --- /dev/null +++ b/etc/frontend/routes.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/etc/module.xml b/etc/module.xml new file mode 100644 index 0000000..7114c4e --- /dev/null +++ b/etc/module.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/etc/widget.xml b/etc/widget.xml new file mode 100644 index 0000000..cd77316 --- /dev/null +++ b/etc/widget.xml @@ -0,0 +1,8 @@ + + + + + PayEx Checkin Widget + + \ No newline at end of file diff --git a/registration.php b/registration.php new file mode 100644 index 0000000..a657fad --- /dev/null +++ b/registration.php @@ -0,0 +1,7 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/view/frontend/layout/payex_checkout_index.xml b/view/frontend/layout/payex_checkout_index.xml new file mode 100644 index 0000000..5c79180 --- /dev/null +++ b/view/frontend/layout/payex_checkout_index.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + PayEx_Checkin/checkin + + 0 + PayEx_Checkin/js/view/checkin + + + + PayEx_Checkout/shipping + + + + + + + + + + + + + + diff --git a/view/frontend/requirejs-config.js b/view/frontend/requirejs-config.js new file mode 100644 index 0000000..096c43f --- /dev/null +++ b/view/frontend/requirejs-config.js @@ -0,0 +1,7 @@ +var config = { + map: { + "*": { + "checkinStyling": "PayEx_Checkin/js/checkin-styling" + } + } +}; diff --git a/view/frontend/templates/widget/checkin-script.phtml b/view/frontend/templates/widget/checkin-script.phtml new file mode 100644 index 0000000..73d1990 --- /dev/null +++ b/view/frontend/templates/widget/checkin-script.phtml @@ -0,0 +1,5 @@ +isActive()):?> + + \ No newline at end of file diff --git a/view/frontend/templates/widget/checkin-widget.phtml b/view/frontend/templates/widget/checkin-widget.phtml new file mode 100644 index 0000000..55e32ed --- /dev/null +++ b/view/frontend/templates/widget/checkin-widget.phtml @@ -0,0 +1,31 @@ +isActive() && !$block->isConsumerIdentified()):?> +
+

+
+
+ + + \ No newline at end of file diff --git a/view/frontend/web/css/payex_checkin.css b/view/frontend/web/css/payex_checkin.css new file mode 100644 index 0000000..0ce5545 --- /dev/null +++ b/view/frontend/web/css/payex_checkin.css @@ -0,0 +1,47 @@ +.payex-checkin__wrapper { + display: flex; + align-items: center; + flex-direction: column; + padding-bottom: 2rem; +} +.payex-checkin__wrapper .payex-checkin__subtitle { + width: 100%; + max-width: 500px; + margin: 0; + padding: 12px 0 0; + font-size: 16px; + font-weight: bold; + color: #333333; +} + +.payex-checkin__wrapper .payex-checkin__iframe { + width: 100%; +} + +.payex-checkin__wrapper .payex-checkin__loggedIn-info { + font-size: 20px; +} + +.payex-checkin__wrapper .payex-checkin__loggedIn-info .value { + font-weight: bold; +} + +.payex-checkin__wrapper .payex-checkin__actions { + display: flex; + margin-top: 1.5rem; +} + +.payex-checkin__wrapper .payex-checkin__actions button { + margin: 0 1rem; + padding: 1rem 1.5rem; + box-shadow: none; + border: 1px solid #2da944; + background: transparent; + color: #404040; + transition: background 0.1s ease, color 0.1s ease; +} + +.payex-checkin__wrapper .payex-checkin__actions button:hover { + background-color: #2da944; + color: white; +} \ No newline at end of file diff --git a/view/frontend/web/js/action/open-shipping-information.js b/view/frontend/web/js/action/open-shipping-information.js new file mode 100644 index 0000000..714576f --- /dev/null +++ b/view/frontend/web/js/action/open-shipping-information.js @@ -0,0 +1,13 @@ +define([ + 'jquery', + 'ko', +], function ($, _) { + 'use strict'; + + return { + open: function(){ + // Function not hooked into anything + // This function get overridden by checkin initialization + } + } +}); \ No newline at end of file diff --git a/view/frontend/web/js/checkin-styling.js b/view/frontend/web/js/checkin-styling.js new file mode 100644 index 0000000..fc61d7f --- /dev/null +++ b/view/frontend/web/js/checkin-styling.js @@ -0,0 +1,55 @@ +define([],function(){ + return { + "body": { + "backgroundColor": "white", + "font": "15px Arial, Verdana, Helvetica, sans-serif", + "color": "#333333", + "validColor": "green", + "noticeColor": "yellow", + "invalidColor": "red" + }, + "formGroup": { + "margin": "0px 0px 15px 0px" + }, + "label": { + "font": "11px Verdana, Arial, Helvetica, sans-serif", + "padding": "0px 5px", + "borderRadius": "8px", + "margin": "15px 0px 0px 11px", + "color": "grey", + "backgroundColor": "white" + }, + "input": { + "border": "1px solid #cccccc", + "backgroundColor": "white", + "color": "#333333", + "padding": "15px", + "focus": { + "border": "1px solid #2DA944" + }, + "invalid": { + "color": "#E9516D", + "border": "1px solid #E9516D" + } + }, + "button": { + "backgroundColor": "#2DA944", + "borderRadius": "3px", + "border": "0px", + "font": "bold 18px Arial, Verdana, Helvetica, sans-serif", + "color": "white", + "padding": "15px" + }, + "infoBox": { + "border": "0", + "borderRadius": "0px" + }, + "link": { + "color": "#2DA944" + }, + "header": { + "font": "16px Arial, Verdana, Helvetica, sans-serif", + "margin": "10px 0px 10px 0px" + } + } +}); \ No newline at end of file diff --git a/view/frontend/web/js/view/checkin.js b/view/frontend/web/js/view/checkin.js new file mode 100644 index 0000000..31f276f --- /dev/null +++ b/view/frontend/web/js/view/checkin.js @@ -0,0 +1,281 @@ +define([ + 'uiComponent', + 'jquery', + 'ko', + 'underscore', + 'mage/translate', + 'mage/storage', + 'Magento_Checkout/js/model/step-navigator', + 'Magento_Checkout/js/model/quote', + 'uiRegistry', + 'Magento_Checkout/js/model/new-customer-address', + 'Magento_Checkout/js/action/set-shipping-information', + 'PayEx_Checkin/js/action/open-shipping-information', + 'PayEx_Checkout/js/action/trigger-shipping-information-validation', + 'Magento_Checkout/js/model/address-converter', + 'Magento_Checkout/js/checkout-data', + 'checkinStyling', + 'mage/cookies' +], function (Component, $, ko, _, $t, storage, stepNavigator, quote, registry, newCustomerAddress, setShippingInformationAction, openShippingInformation, triggerShippingInformationValidation, addressConverter, checkoutData, checkinStyling) { + 'use strict'; + + var PayEx = window.payex, + onConsumerIdentifiedDelay = ko.observable(false), + isVisible = ko.observable(false), + isShippingSectionVisible = ko.observable(false), + isRequired = ko.observable(false), + isCheckedIn = ko.observable(false); + + return Component.extend({ + config: { + data: { + element: 'checkin-widget', + shippingDetails: ko.observable({}), + billingDetails: ko.observable({}) + } + }, + isVisible: isVisible, + isShippingSectionVisible: isShippingSectionVisible, + isRequired: isRequired, + isCheckedIn: isCheckedIn, + initialize: function(config){ + var self = this; + + self._super(); + + // Check if data comes from widget config or checkout config + config.isCheckout = !config.hasOwnProperty('data'); + + if(config.isCheckout) { + Object.assign(self.config.data, window.checkoutConfig.PayEx_Checkin); + self.config.isCheckout = config.isCheckout; + + self.isRequired((this.config.data.isRequired == true)); + + stepNavigator.steps.subscribe(function(section){ + stepNavigator.hideSection('shipping'); + isShippingSectionVisible(false); + }); + + } else { + Object.assign(self.config, config); + } + + openShippingInformation.open = function(){ + self.proceedAsGuest(); + }; + + // Make request to get consumer info if user logged in through checkin in current session + self.checkIsCheckedIn(); + }, + checkIsCheckedIn: function(){ + var self = this; + + storage.post( + this.config.data.OnConsumerReidentifiedUrl, + "", + true + ).done(function(response){ + self.isVisible((self.config.data.isEnabled)); + + // If previously logged in, autofill shipping and billing and don't load checkin window + if(response.shipping_details || response.billing_details) { + if (self.config.isCheckout) { + setTimeout(function () { + self.autofillShippingDetails(response.shipping_details); + self.autofillBillingDetails(response.billing_details); + self.onCheckinValidation(); + }, 500) + } + } else { + if(!self.config.isCheckout) { + self.payexSetupHostedView(); + } + } + + }).fail(function(message){ + console.log(message); + + self.isVisible((self.config.data.isEnabled)); + self.payexSetupHostedView(); + }); + }, + onCheckinValidation: function(){ + var self = this, + consumerProfileRef = $.cookie('consumerProfileRef'); + + if(consumerProfileRef){ + self.isCheckedIn(true); + + triggerShippingInformationValidation.trigger(function(result) { + if(!result.success) { + self.proceedAsGuest(); + } + }); + } + }, + proceedAsGuest: function(element, event){ + stepNavigator.showSection('shipping'); + this.isShippingSectionVisible(true); + }, + payexSetupHostedView: function(){ + PayEx.hostedView.consumer({ + container: this.config.data.element, + onConsumerIdentified: this.onConsumerIdentified.bind(this), + onShippingDetailsAvailable: this.onShippingDetailsAvailable.bind(this), + onBillingDetailsAvailable: this.onBillingDetailsAvailable.bind(this), + style: checkinStyling + }).open(); + }, + onConsumerIdentified: function(data){ + let self = this; + + if (data.hasOwnProperty('consumerProfileRef')) { + $.cookie('consumerProfileRef', data.consumerProfileRef); + } + + storage.post( + this.config.data.OnConsumerIdentifiedUrl, + JSON.stringify(data), + true + ).done(function(response){ + onConsumerIdentifiedDelay(true); + self.isCheckedIn(true); + }).fail(function(message){ + console.error(message); + }); + }, + onShippingDetailsAvailable: function(data){ + let self = this; + + if (data.hasOwnProperty('url')) { + $.cookie('shippingDetailsAvailableUrl', data.url); + } + + onConsumerIdentifiedDelay.subscribe(function(value) { + if(value) { + storage.post( + self.config.data.OnShippingDetailsAvailableUrl, + JSON.stringify(data), + true + ).done(function (response) { + if (self.config.isCheckout) { + self.autofillShippingDetails(response.data); + } + }).fail(function (message) { + console.error(message); + }); + } + }); + + }, + onBillingDetailsAvailable: function(data){ + let self = this; + + if (data.hasOwnProperty('url')) { + $.cookie('billingDetailsAvailableUrl', data.url); + } + + onConsumerIdentifiedDelay.subscribe(function(value) { + if (value) { + storage.post( + self.config.data.OnBillingDetailsAvailableUrl, + JSON.stringify(data), + true + ).done(function (response) { + if (self.config.isCheckout) { + self.autofillBillingDetails(response.data); + } + }).fail(function (message) { + console.error(message); + }); + } + }); + + }, + separateAddressee: function(addressee) { + var lastSpaceIndex = addressee.lastIndexOf(' '); + + return { + firstname: addressee.substring(0, lastSpaceIndex), + middlename: '', + lastname: addressee.substring(lastSpaceIndex + 1) + } + }, + setEmailInputValue: function(email){ + var emailSelector = 'form[data-role=email-with-possible-login] input[type=email]'; + $(emailSelector).val(email).trigger('change'); + }, + getStreetAddressObject: function(streetAddressString){ + return {0: streetAddressString, 1: "", 2: "", 3: ""}; + }, + createAddressObject: function(payexAddress, addressKey) { + + if(!payexAddress[addressKey]){ return false; } + + var names = this.separateAddressee(payexAddress[addressKey].addressee); + + return { + firstname: names.firstname, + middlename: names.middlename, + lastname: names.lastname, + email: payexAddress.email, + postcode: payexAddress[addressKey].zip_code, + city: payexAddress[addressKey].city, + street: this.getStreetAddressObject(payexAddress[addressKey].street_address), + country_id: payexAddress[addressKey].country_code, + company: '', + canUseForBilling: ko.observable(true), + telephone: payexAddress.msisdn + } + }, + autofillShippingDetails: function(payexShippingInformation){ + if(!payexShippingInformation) { + return; + } + + // Create new address object + var shippingAddress = this.createAddressObject(payexShippingInformation, 'shipping_address'); + + if(shippingAddress) { + this.config.data.shippingDetails(shippingAddress); + + // Create new address object + var address = newCustomerAddress(shippingAddress); + address.street = this.getStreetAddressObject(payexShippingInformation['shipping_address'].street_address); + + // Set email input to logged in customer email + this.setEmailInputValue(shippingAddress.email); + + // Update quote with logged in address object + quote.shippingAddress(address); + + // Prepare address for auto-filling + var addressFormPrepared = addressConverter.quoteAddressToFormAddressData(address); + + // Autofill fields + registry.async('checkoutProvider')(function (checkoutProvider) { + checkoutProvider.set('shippingAddress', addressFormPrepared); + }); + } + }, + autofillBillingDetails: function(payexBillingInformation){ + if(!payexBillingInformation) { + return; + } + + // Create new address object + var billingAddress = this.createAddressObject(payexBillingInformation, 'billing_address'); + + if(billingAddress) { + this.config.data.billingDetails(billingAddress); + + // Create new address object + var address = newCustomerAddress(billingAddress); + + // Update quote with logged in address object + quote.billingAddress(address); + } + } + }); +}); \ No newline at end of file diff --git a/view/frontend/web/template/checkin.html b/view/frontend/web/template/checkin.html new file mode 100644 index 0000000..4d9c290 --- /dev/null +++ b/view/frontend/web/template/checkin.html @@ -0,0 +1,20 @@ + +
+

+ +
+
+ + + + + + + + + + + +
+
+ \ No newline at end of file