diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..779cf88 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +*.bak diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..9ee856f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,168 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "Launch Current File", + "request": "launch", + "mainClass": "${file}" + }, + { + "args": [ + " + " + ], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "name": "Yeoman + ", + "program": "${workspaceFolder}/node_modules/yo/lib/cli.js", + "request": "launch", + "skipFiles": [ + "/**" + ], + "type": "pwa-node" + }, + + { + "name": "Attach", + "port": 9229, + "request": "attach", + "skipFiles": [ + "/**" + ], + "type": "pwa-node" + }, + { + "type": "java", + "name": "Launch with Arguments Prompt", + "request": "launch", + "mainClass": "", + "args": "${command:SpecifyProgramArgs}" + }, + { + "args": [ + "-u", + "tdd", + "--timeout", + "999999", + "--colors", + "${workspaceFolder}/test" + ], + "internalConsoleOptions": "openOnSessionStart", + "name": "Mocha Tests", + "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "request": "launch", + "skipFiles": [ + "/**" + ], + "type": "pwa-node" + }, + { + "name": "Launch Program", + "program": "${workspaceFolder}/app.js", + "request": "launch", + "skipFiles": [ + "/**" + ], + "type": "pwa-node" + }, + { + "name": "Launch Chrome", + "request": "launch", + "type": "pwa-chrome", + "url": "http://localhost:8080", + "webRoot": "${workspaceFolder}" + }, + + { + "type": "java", + "name": "Attach to Remote Program", + "request": "attach", + "hostName": "", + "port": "" + }, + { + "name": "Launch Chrome", + "request": "launch", + "type": "pwa-chrome", + "url": "http://localhost:8080", + "webRoot": "${workspaceFolder}" + }, + { + "type": "java", + "name": "Launch External Terminal", + "request": "launch", + "console": "externalTerminal", + "mainClass": "" + }, + { + "type": "java", + "request": "attach", + "name": "Attach by Process ID", + "processId": "${command:PickJavaProcess}" + }, + { + "type": "java", + "request": "attach", + "name": "Attach by Process ID", + "processId": "${command:PickJavaProcess}" + }, + { + "type": "java", + "request": "attach", + "name": "Attach by Process ID", + "processId": "${command:PickJavaProcess}" + }, + { + "type": "java", + "request": "attach", + "name": "Attach by Process ID", + "processId": "${command:PickJavaProcess}" + }, + { + "type": "java", + "name": "Attach to Remote Program", + "request": "attach", + "hostName": "", + "port": "" + }, + { + "name": "Launch Chrome", + "request": "launch", + "type": "pwa-chrome", + "url": "http://localhost:8080", + "webRoot": "${workspaceFolder}" + }, + { + "type": "java", + "name": "Attach to Remote Program", + "request": "attach", + "hostName": "", + "port": "" + }, + { + "type": "java", + "name": "Attach to Remote Program", + "request": "attach", + "hostName": "", + "port": "" + }, + { + "type": "java", + "request": "attach", + "name": "Attach by Process ID", + "processId": "${command:PickJavaProcess}" + }, + { + "type": "pwa-msedge", + "request": "launch", + "name": "Launch Chrome against localhost", + "url": "http://localhost:8080", + "webRoot": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..ed46e28 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,19 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "verify", + "type": "shell", + "command": "mvn -B verify", + "group": "build" + }, + { + "label": "test", + "type": "shell", + "command": "mvn -B test", + "group": "test" + } + ] +} \ No newline at end of file diff --git a/Api/InvoiceInterface.php b/Api/InvoiceInterface.php new file mode 100644 index 0000000..014b852 --- /dev/null +++ b/Api/InvoiceInterface.php @@ -0,0 +1,27 @@ +>>>>>> Stashed changes +namespace Coinpayments\CoinPayments\Api; + +interface InvoiceInterface +{ + + /** + * @param $clientId + * @param $invoiceParams + * @return mixed + */ + public function createSimple($clientId, $invoiceParams); + + /** + * @param $clientId + * @param $clientSecret + * @param $invoiceParams + * @return mixed + */ + public function createMerchant($clientId, $clientSecret, $invoiceParams); + +} diff --git a/Api/WebHookInterface.php b/Api/WebHookInterface.php new file mode 100644 index 0000000..0214241 --- /dev/null +++ b/Api/WebHookInterface.php @@ -0,0 +1,22 @@ + - */ - -namespace Firebear\CoinPayments\Block\Form; - -use Magento\Customer\Helper\Session\CurrentCustomer; - -class Coinpayments extends \Magento\Payment\Block\Form -{ - /** - * Payment method code - * - * @var string - */ - protected $_methodCode = 'coin_payments'; - - /** - * @var null - */ - protected $_config; - - /** - * @var CurrentCustomer - */ - protected $currentCustomer; - - protected function _construct() - { - $template = 'Firebear_CoinPayments::coinpayments/form/coinpayments.phtml'; - $this->setTemplate($template); - - parent::__construct(); - } -} diff --git a/Block/Iframe.php b/Block/Iframe.php deleted file mode 100644 index f4b23d4..0000000 --- a/Block/Iframe.php +++ /dev/null @@ -1,124 +0,0 @@ - - */ - -namespace Firebear\CoinPayments\Block; - -class Iframe extends \Magento\Framework\View\Element\Template -{ - const PATH_TO_PAYMENT_CONFIG = 'payment/coin_payments/'; - - /** - * @var \Magento\Framework\Registry - */ - protected $_coreRegistry; - - - /** - * @var \Magento\Quote\Model\QuoteRepository - */ - protected $quoteRepository; - - /** - * Iframe constructor. - * @param \Magento\Framework\View\Element\Template\Context $context - * @param \Magento\Framework\Registry $coreRegistry - * @param \Magento\Quote\Model\QuoteRepository $quoteRepository - * @param array $data - */ - public function __construct( - \Magento\Framework\View\Element\Template\Context $context, - \Magento\Framework\Registry $coreRegistry, - \Magento\Quote\Model\QuoteRepository $quoteRepository, - array $data = [] - ) { - $this->quoteRepository = $quoteRepository; - $this->_coreRegistry = $coreRegistry; - parent::__construct($context, $data); - } - - /** - * @return mixed - */ - public function getLastOrderId() - { - $lastSuccessOrderId = $this->_coreRegistry->registry('last_success_order_id'); - return $lastSuccessOrderId; - } - - /** - * create an invoice and return the url so that iframe.phtml can display it - * - * @return string - */ - public function getFrameActionUrl() - { - return $this->getUrl('coinpayments/form/index', ['_secure' => true]); - } - - /** - * @return string - */ - public function getIpnUrl() - { - $quoteModel = $this->getQuote(); - return $this->getUrl('coinpayments/ipn/index'); - } - - /** - * @return array - */ - public function getPaymentData() - { - $storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE; - $data = [ - 'merchant_id' => $this->_scopeConfig->getValue(self::PATH_TO_PAYMENT_CONFIG . "merchant_id", $storeScope), - 'ipn_secret' => $this->_scopeConfig->getValue(self::PATH_TO_PAYMENT_CONFIG . "ipn_secret", $storeScope), - 'item_name' => $this->_scopeConfig->getValue('general/store_information/name', $storeScope), - 'store_id' => $this->_storeManager->getStore()->getId(), - 'currency_code' => $this->_storeManager->getStore()->getCurrentCurrencyCode(), - ]; - return $data; - } - - /** - * @return \Magento\Quote\Api\Data\CartInterface|\Magento\Quote\Model\Quote - */ - public function getQuote() - { - $quoteModel = $this->quoteRepository->get($this->_coreRegistry->registry('last_success_quote_id')); - return $quoteModel; - } - - /** - * @return int - */ - public function getShippingAmount() - { - $quoteModel = $this->quoteRepository->get($this->_coreRegistry->registry('last_success_quote_id')); - $shippingAmount = $quoteModel->getShippingAddress()->getShippingAmount(); - if ($quoteModel->getShippingAddress()->getShippingDiscountAmount()) { - $shippingAmount = $shippingAmount - $quoteModel->getShippingAddress()->getShippingDiscountAmount(); - } - - return $shippingAmount; - } - - /** - * @return string - */ - public function getSuccessUrl() - { - return $this->getUrl('checkout/onepage/success'); - } - - /** - * @return string - */ - public function getFailUrl() - { - return $this->getUrl('coinpayments/checkout/failure'); - } -} diff --git a/Block/Info.php b/Block/Info.php deleted file mode 100644 index eac6e9f..0000000 --- a/Block/Info.php +++ /dev/null @@ -1,26 +0,0 @@ - - */ - -namespace Firebear\CoinPayments\Block; - -/** - * Base payment iformation block - */ -class Info extends \Magento\Framework\View\Element\Template -{ - /** - * @var string - */ - protected $_template = 'Firebear_CoinPayments::coinpayments/info/default.phtml'; - - /** - * @return mixed - */ - public function getCoinPaymentsInvoiceUrl() - { - return true; - } -} diff --git a/Block/Redirect.php b/Block/Redirect.php deleted file mode 100644 index a617b68..0000000 --- a/Block/Redirect.php +++ /dev/null @@ -1,60 +0,0 @@ - - */ - -namespace Firebear\CoinPayments\Block; - -class Redirect extends \Magento\Framework\View\Element\Template -{ - /** - * @var \Magento\Checkout\Model\Session - */ - protected $checkoutSession; - - /** - * @var \Magento\Sales\Model\OrderFactory - */ - protected $orderFactory; - - /** - * Redirect constructor. - * @param \Magento\Framework\View\Element\Template\Context $context - * @param \Magento\Checkout\Model\Session $checkoutSession - * @param \Magento\Sales\Model\OrderFactory $orderFactory - */ - public function __construct( - \Magento\Framework\View\Element\Template\Context $context, - \Magento\Checkout\Model\Session $checkoutSession, - \Magento\Sales\Model\OrderFactory $orderFactory - ) { - $this->checkoutSession = $checkoutSession; - $this->orderFactory = $orderFactory; - parent::__construct($context); - } - - /** - * @return mixed - */ - public function getRealOrderId() - { - $lastorderId = $this->checkoutSession->getLastOrderId(); - - return $lastorderId; - } - - /** - * @return bool - */ - public function getOrder() - { - if ($this->checkoutSession->getLastRealOrderId()) { - $order = $this->orderFactory->create()->loadByIncrementId($this->checkoutSession->getLastRealOrderId()); - - return $order; - } - - return false; - } -} diff --git a/Controller/Adminhtml/Validation/Invoice.php b/Controller/Adminhtml/Validation/Invoice.php new file mode 100644 index 0000000..27705b1 --- /dev/null +++ b/Controller/Adminhtml/Validation/Invoice.php @@ -0,0 +1,57 @@ +getRequest()->getParams(); + + $response = []; + if (!empty($params['client_id']) && $this->helper->getConfig('validated') != $params['client_id']) { + $clientId = $params['client_id']; + + $invoiceParams = array( + 'currencyId' => 5057, + 'invoiceId' => 'Validate invoice', + 'amount' => 1, + 'displayValue' => '0.01', + 'notesLink' => '', + ); + + $invoice = $this->invoiceModel->createSimple($clientId, $invoiceParams); + + if ($invoice) { + $this->helper->setConfig('validated', $params['client_id']); + $response = [ + 'success' => $invoice + ]; + } else { + $response = [ + 'success' => false, + 'errorText' => sprintf('Failed to create validation invoice!'), + ]; + } + } elseif ($this->helper->getConfig('validated') == $params['client_id']) { + $response = [ + 'success' => $params['client_id'] + ]; + } else { + $response = [ + 'success' => false, + 'errorText' => sprintf('Enter Coinpayments.NET credentials!'), + ]; + } + + + $result = $this->jsonResultFactory->create(); + $result->setData($response); + return $result; + } +} diff --git a/Controller/Adminhtml/Validation/Validation.php b/Controller/Adminhtml/Validation/Validation.php new file mode 100644 index 0000000..c12ed22 --- /dev/null +++ b/Controller/Adminhtml/Validation/Validation.php @@ -0,0 +1,61 @@ +jsonResultFactory = $jsonResultFactory; + $this->webHookModel = $webHook; + $this->invoiceModel = $invoice; + $this->helper = $helper; + } + + abstract public function execute(); +} \ No newline at end of file diff --git a/Controller/Adminhtml/Validation/WebHook.php b/Controller/Adminhtml/Validation/WebHook.php new file mode 100644 index 0000000..65758ca --- /dev/null +++ b/Controller/Adminhtml/Validation/WebHook.php @@ -0,0 +1,87 @@ +getRequest()->getParams(); + $response = []; + + if (!empty($params['client_id']) && !empty($params['client_secret'])) { + if ($this->helper->getConfig('validated') != ($params['client_id'] . $params['client_secret'])) { + + $clientId = $params['client_id']; + $clientSecret = $params['client_secret']; + + $webHooksList = $this->webHookModel->getList($clientId, $clientSecret); + + if (!empty($webHooksList)) { + + $webHooksUrlsList = []; + if (!empty($webHooksList['items'])) { + $webHooksUrlsList = array_map(function ($webHook) { + return $webHook['notificationsUrl']; + }, $webHooksList['items']); + } + + if ( + !in_array($this->helper->getNotificationUrl($clientId, DATA::PAID_EVENT), $webHooksUrlsList) || + !in_array($this->helper->getNotificationUrl($clientId, DATA::CANCELLED_EVENT), $webHooksUrlsList) + ) { + if ( + !empty($this->webHookModel->createWebHook($clientId, $clientSecret, DATA::PAID_EVENT)) && + !empty($this->webHookModel->createWebHook($clientId, $clientSecret, DATA::CANCELLED_EVENT)) + + ) { + $this->helper->setConfig('validated', $params['client_id'] . $params['client_secret']); + $response = [ + 'success' => true, + ]; + } else { + $response = [ + 'success' => false, + 'errorText' => sprintf('Failed to create WebHook!'), + ]; + } + } else { + $this->helper->setConfig('validated', $params['client_id'] . $params['client_secret']); + $response = [ + 'success' => true, + ]; + } + } else { + $response = [ + 'success' => false, + 'errorText' => sprintf('Failed to get WebHooks list!'), + ]; + } + } else { + $response = [ + 'success' => true, + ]; + } + } else { + $response = [ + 'success' => false, + 'errorText' => sprintf('Enter Coinpayments.NET credentials!'), + ]; + } + + + $result = $this->jsonResultFactory->create(); + $result->setData($response); + return $result; + } +} \ No newline at end of file diff --git a/Controller/Checkout/Failure.php b/Controller/Checkout/Failure.php index b876a10..83197be 100644 --- a/Controller/Checkout/Failure.php +++ b/Controller/Checkout/Failure.php @@ -1,38 +1,46 @@ checkoutSession = $checkoutSession; - $this->orderFactory = $orderFactory; $this->orderRepository = $orderRepository; $this->resultPageFactory = $resultPageFactory; - $this->logger = $logger; - $this->cacheTypeList = $cacheTypeList; - $this->cacheFrontendPool = $cacheFrontendPool; parent::__construct($context); } @@ -40,31 +48,15 @@ public function __construct( public function execute() { $lastOrderId = $this->getRealOrderId(); - $order = $this->orderRepository->get($lastOrderId); + $order = $this->orderRepository->get($lastOrderId); $order->setStatus(Order::STATE_CANCELED)->setState(Order::STATE_CANCELED); $this->orderRepository->save($order); - $this->logger->info('ORDER INFO kjgjkgjkghjgjhggjh: ' . $order->getStatus() . $order->getState()); - return $this->resultPageFactory->create(); } - - // Use this method to get ID public function getRealOrderId() { - $lastorderId = $this->checkoutSession->getLastOrderId(); - - return $lastorderId; + return $this->checkoutSession->getLastOrderId(); } - public function getOrder() - { - if ($this->checkoutSession->getLastOrderId()) { - $order = $this->orderFactory->create()->loadByIncrementId($this->checkoutSession->getLastRealOrderId()); - - return $order; - } - - return false; - } } diff --git a/Controller/Iframe/Index.php b/Controller/Iframe/Index.php deleted file mode 100644 index d3679ad..0000000 --- a/Controller/Iframe/Index.php +++ /dev/null @@ -1,62 +0,0 @@ - - */ - -namespace Firebear\CoinPayments\Controller\Iframe; - -class Index extends \Magento\Framework\App\Action\Action -{ - private $configResource; - - /** - * @var \Magento\Quote\Model\QuoteFactory - */ - private $quoteFactory; - - /** - * @var \Magento\Checkout\Model\Session - */ - private $cart; - - /** - * @var \Magento\Framework\App\Config\ScopeConfigInterface - */ - private $scopeConfig; - - /** - * Index constructor. - * - * @param \Magento\Framework\App\Action\Context $context - * @param \Magento\Framework\App\Config\MutableScopeConfigInterface $config - * @param \Magento\Checkout\Model\Cart $cart - * @param \Magento\Quote\Model\QuoteFactory $quoteFactory - */ - public function __construct( - \Magento\Framework\App\Action\Context $context, - \Magento\Framework\App\Config\MutableScopeConfigInterface $config, - \Magento\Checkout\Model\Cart $cart, - \Magento\Quote\Model\QuoteFactory $quoteFactory, - \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig - ) { - $this->config = $config; - $this->cart = $cart; - $this->quoteFactory = $quoteFactory; - $this->scopeConfig = $scopeConfig; - parent::__construct($context); - } - - /** - * @route coinpayments/iframe/index - */ - public function execute() - { - $coinpaymentUrl = $this->scopeConfig->getValue( - 'coinpayment/conf/url_payment', - \Magento\Store\Model\ScopeInterface::SCOPE_STORE - ); - $html = 'You will be transfered to coinpayments.net to complete your purchase when using this payment method.'; - $this->getResponse()->setBody(json_encode(['html' => $html])); - } -} diff --git a/Controller/Invoice/Create.php b/Controller/Invoice/Create.php new file mode 100644 index 0000000..94a28a7 --- /dev/null +++ b/Controller/Invoice/Create.php @@ -0,0 +1,187 @@ +urlBuilder = $urlBuilder; + $this->invoiceModel = $invoice; + $this->helper = $helper; + $this->scopeConfig = $scopeConfig; + $this->checkoutSession = $checkoutSession; + $this->jsonResultFactory = $jsonResultFactory; + $this->backendUrl = $backendUrl; + parent::__construct($context); + } + + public function execute() + { + + $response = [ + 'successUrl' => $this->urlBuilder->getUrl('checkout/onepage/success'), + 'cancelUrl' => $this->urlBuilder->getUrl('coinpayments/checkout/failure'), + ]; + + $order = $this->checkoutSession->getLastRealOrder(); + + if ($order->getIncrementId()) { + + $coinInvoiceCacheId = Data::INVOICE_CACHE_PREFIX . $order->getIncrementId(); + $coinInvoiceId = $this->checkoutSession->{'get' . $coinInvoiceCacheId}(); + + if (empty($coinInvoiceId)) { + + $currencyCode = $order->getBaseCurrencyCode(); + $coinCurrency = $this->getCoinCurrency($currencyCode); + $amount = number_format($order->getGrandTotal(), $coinCurrency['decimalPlaces'], '', ''); + + if (!empty($coinCurrency)) { + + $clientId = $this->helper->getConfig(Data::CLIENT_ID_KEY); + $clientSecret = $this->helper->getConfig(Data::CLIENT_SECRET_KEY); + $merchantWebHooks = $this->helper->getConfig(Data::CLIENT_WEBHOOKS_KEY); + $invoiceId = sprintf('%s|%s|%s', md5($this->helper->getHostUrl()), $order->getId(), $order->getPayment()->getId()); + + try { + $notesLink = sprintf( + "%s|Store name: %s|Order #%s", + $this->backendUrl->getUrl('sales/order/view', ['order_id' => $order->getId(), '_nosecret' => true]), + $this->helper->getGeneralConfig('store_information/name'), + $order->getId() + ); + + $invoiceParams = array( + 'invoiceId' => $invoiceId, + 'currencyId' => $coinCurrency['id'], + 'displayValue' => $order->getGrandTotal(), + 'amount' => intval($amount), + 'billingData' => $order->getBillingAddress(), + 'notesLink' => $notesLink, + ); + + if ($merchantWebHooks) { + $invoicesData = $this->invoiceModel->createMerchant($clientId, $clientSecret, $invoiceParams); + $invoiceData = array_shift($invoicesData['invoices']); + } else { + $invoiceData = $this->invoiceModel->createSimple($clientId, $invoiceParams); + } + } catch (\Exception $e) { + } + + if (!empty($invoiceData['id'])) { + $this->checkoutSession->{'set' . $coinInvoiceCacheId}($invoiceData['id']); + $coinInvoiceId = $invoiceData['id']; + $this->invoiceModel->createOrderTransaction($order, $coinInvoiceId); + } + } + + } + + if (!empty($coinInvoiceId)) { + $response['coinInvoiceId'] = $coinInvoiceId; + $response['redirectUrl'] = $this->helper->getCoinCheckoutRedirectUrl($coinInvoiceId, $response['successUrl'], $response['cancelUrl']); + } + } + + $result = $this->jsonResultFactory->create(); + $result->setData($response); + return $result; + } + + /** + * @param string $name + * @return array|mixed + */ + protected function getCoinCurrency(string $name) + { + + $params = [ + 'types' => Data::FIAT_TYPE, + 'q' => $name, + ]; + $items = []; + + $listData = $this->invoiceModel->getCurrencies($params); + if (!empty($listData['items'])) { + $items = $listData['items']; + } + + return array_shift($items); + } + + public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException + { + return null; + } + + public function validateForCsrf(RequestInterface $request): ?bool + { + return true; + } + +} diff --git a/Controller/Invoice/Index.php b/Controller/Invoice/Index.php deleted file mode 100644 index 1376a0d..0000000 --- a/Controller/Invoice/Index.php +++ /dev/null @@ -1,105 +0,0 @@ - - */ - -namespace Firebear\CoinPayments\Controller\Invoice; - -use Magento\Framework\App\Action\Context; -use Magento\Framework\Controller\ResultFactory; -use Magento\Sales\Model\Order; - -class Index extends \Magento\Framework\App\Action\Action -{ - /** - * Core registry - * - * @var \Magento\Framework\Registry - */ - private $_coreRegistry; - - private $configResource; - - /** - * @var \Magento\Framework\View\Result\PageFactory - */ - private $resultPageFactory; - - /** - * @var \Magento\Framework\App\Config\MutableScopeConfigInterface - */ - private $config; - - /** - * @var \Magento\Checkout\Model\Session - */ - private $checkoutSession; - - /** - * @var \Psr\Log\LoggerInterface - */ - private $log; - - /** - * @var \Magento\Sales\Model\OrderRepository - */ - private $orderRepository; - - /** - * @var \Firebear\CoinPayments\Helper\Data - */ - private $coinPayemtnsHelper; - - /** - * Index constructor. - * @param Context $context - * @param \Magento\Framework\Registry $coreRegistry - * @param \Magento\Framework\App\Config\MutableScopeConfigInterface $config - * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory - * @param \Magento\Checkout\Model\Session $checkoutSession - * @param \Psr\Log\LoggerInterface $logger - * @param \Magento\Sales\Model\OrderRepository $orderRepository - * @param \Firebear\CoinPayments\Helper\Data $coinPayemtnsHelper - */ - public function __construct( - \Magento\Framework\App\Action\Context $context, - \Magento\Framework\Registry $coreRegistry, - \Magento\Framework\App\Config\MutableScopeConfigInterface $config, - \Magento\Framework\View\Result\PageFactory $resultPageFactory, - \Magento\Checkout\Model\Session $checkoutSession, - \Psr\Log\LoggerInterface $logger, - \Magento\Sales\Model\OrderRepository $orderRepository, - \Firebear\CoinPayments\Helper\Data $coinPayemtnsHelper - ) { - $this->_coreRegistry = $coreRegistry; - $this->config = $config; - $this->resultPageFactory = $resultPageFactory; - $this->checkoutSession = $checkoutSession; - $this->log = $logger; - $this->orderRepository = $orderRepository; - $this->coinPayemtnsHelper = $coinPayemtnsHelper; - parent::__construct($context); - } - - /** - * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\View\Result\Page - */ - public function execute() - { - if (empty($this->checkoutSession->getData('last_success_quote_id'))) { - return $this->_redirect('checkout/cart'); - } - - $this->log->info('ORDER_ID: ' . $this->checkoutSession->getLastRealOrder()->getId()); - $this->_coreRegistry->register('last_success_quote_id', $this->checkoutSession->getData('last_success_quote_id')); - $this->_coreRegistry->register('last_success_order_id', $this->checkoutSession->getLastRealOrder()->getId()); - $orderModel = $this->orderRepository->get($this->checkoutSession->getLastRealOrder()->getId()); - $orderModel->setState(Order::STATE_NEW) - ->setStatus($this->coinPayemtnsHelper->getGeneralConfig('status_order_placed')); - $resultPage = $this->resultPageFactory->create(); - $resultPage->getConfig()->getTitle()->set(__('Pay with CoinPayments')); - - return $resultPage; - } -} diff --git a/Controller/Ipn/Index.php b/Controller/Ipn/Index.php deleted file mode 100644 index f664589..0000000 --- a/Controller/Ipn/Index.php +++ /dev/null @@ -1,264 +0,0 @@ - - */ - -namespace Firebear\CoinPayments\Controller\Ipn; - -use Magento\Sales\Model\Order; -use Magento\Framework\App\Action\Context; -use Firebear\CoinPayments\Logger\Logger; -use Firebear\CoinPayments\Helper\Data as CoinPaymentHelper; - -/** - * Class Index - * - * @package Firebear\CoinPayments\Controller\Ipn - */ -class Index extends \Magento\Framework\App\Action\Action -{ - /** - * @var \Magento\Sales\Model\OrderRepository - */ - private $orderRepository; - - /** - * @var Logger - */ - private $log; - - /** - * @var CoinPaymentHelper - */ - private $helper; - - /** - * Index constructor. - * - * @param Context $context - * @param \Magento\Sales\Model\OrderRepository $orderRepository - * @param Logger $logger - * @param CoinPaymentHelper $helper - */ - public function __construct( - Context $context, - \Magento\Sales\Model\OrderRepository $orderRepository, - Logger $logger, - CoinPaymentHelper $helper - ) { - $this->orderRepository = $orderRepository; - $this->log = $logger; - $this->helper = $helper; - parent::__construct($context); - } - - public function execute() - { - if ($this->getRequest()->getParams()) { - if ($this->is_ipn_valid()) { - // Payment was successful, so update the order's state, send order email and move to the success page - $order_id = (int)$this->getRequest()->getParam('invoice'); - if ($order = $this->orderRepository->get($order_id)) { - if ($order->getState() == Order::STATE_NEW) { - if ($this->getRequest()->getParam('ipn_type') == 'button') { - if ($this->getRequest()->getParam('currency1') == $order->getBaseCurrencyCode()) { - if ($this->getRequest()->getParam('amount1') >= $order->getBaseGrandTotal()) { - $status = (int)$this->getRequest()->getParam('status'); - $this->log->info("STATUS: " . $status); - $this->checkStatus($status, $order); - $order->save(); - - return 'IPN OK'; - } else { - $this->logAndDie('Amount paid is less than order total!', $order); - } - } else { - $this->logAndDie('Original currency does not match!', $order); - } - } else { - $this->logAndDie('Invalid IPN type!', $order); - } - } else { - $this->logAndDie('Order is no longer new. (most likely IPN has already been processed)'); - } - } else { - $this->logAndDie('Could not load order with ID: ' . $order_id); - } - } - } else { - $this->logAndDie('Request is EMPTY'); - } - } - - /** - * @param $status - * @param $order - */ - private function checkStatus($status, $order) - { - if ($status < 0) { - //canceled or timed out - $order->cancel(); - $order->setState( - ORDER::STATE_CANCELED, - true, - 'CoinPayments.net Payment Status: ' . $this->getRequest()->getParam( - 'status_text' - ) - )->setStatus(ORDER::STATE_CANCELED); - } else { - if ($status >= 100 || $status == 2) { - //order complete or queued for nightly payout - $str = 'CoinPayments.net Payment Status: ' . $this->getRequest()->geпtParam('status_text') - . '
'; - $str .= 'Transaction ID: ' . $this->getRequest()->getParam('txn_id') - . '
'; - $str .= 'Original Amount: ' . sprintf('%.08f', $this->getRequest()->getParam('amount1')) - . ' ' . $this->getRequest()->getParam('currency1') . '
'; - $str .= 'Received Amount: ' . sprintf('%.08f', $this->getRequest()->getParam('amount2')) - . ' ' . $this->getRequest()->getParam('currency2'); - $order->setState( - $this->helper->getGeneralConfig('status_order_paid'), - true, - $str - )->setStatus($this->helper->getGeneralConfig('status_order_paid')); - $this->_objectManager->create('\Magento\Sales\Model\OrderNotifier') - ->notify($order); - } else { - //order pending - $order->setState( - Order::STATE_NEW, - true, - 'CoinPayments.net Payment Status: ' . $this->getRequest()->getParam( - 'status_text' - ) - )->setStatus(Order::STATE_PROCESSING); - } - $order->save(); - } - } - - /** - * @param $msg - * @param null $order - */ - private function logAndDie($msg, $order = null) - { - if ($this->helper->getGeneralConfig('debug')) { - $messsageString = ''; - if ($order !== null) { - $messsageString = 'Order ID: ' . $order->getId() . '
'; - } - $messsageString .= $msg; - $this->log->info($messsageString); - } - - return; - } - - /** - * @return bool - */ - private function is_ipn_valid() - { - $ipn = $this->getRequest()->getParams(); - if (!isset($ipn['ipn_mode'])) { - $this->logAndDie('IPN received with no ipn_mode.'); - } - if ($ipn['ipn_mode'] == 'hmac') { - if ($this->checkHmacIpn($ipn)) { - return true; - } - } else { - if ($ipn['ipn_mode'] == 'httpauth' && $this->helper->getGeneralConfig('ipn_mode') == 1) { - if ($this->checkHttpauthIpn($ipn)) { - return true; - } - } else { - $this->logAndDie('Unknown ipn_mode.'); - } - } - - return false; - } - - /** - * @return bool - */ - private function checkHmacIpn($ipn) - { - if (!isset($_SERVER['HTTP_HMAC']) || empty($_SERVER['HTTP_HMAC'])) { - $this->logAndDie('No HMAC signature sent.'); - - return false; - } - - $request = file_get_contents('php://input'); - if ($request === false || empty($request)) { - $this->logAndDie( - 'Error reading POST data: ' . print_r($_SERVER, true) . '/' . print_r( - $this->getRequest()->getParams(), - true - ) - ); - - return false; - } - - $merchant = isset($ipn['merchant']) ? $ipn['merchant'] : ''; - if (empty($merchant)) { - $this->logAndDie('No Merchant ID passed'); - - return false; - } - if ($merchant != trim($this->helper->getGeneralConfig('merchant_id'))) { - $this->logAndDie('Invalid Merchant ID'); - - return false; - } - - $hmac = hash_hmac("sha512", $request, trim($this->helper->getGeneralConfig('ipn_secret'))); - if ($hmac != $_SERVER['HTTP_HMAC']) { - $this->logAndDie('HMAC signature does not match'); - - return false; - } - - return true; - } - - private function checkHttpauthIpn($ipn) - { - if (isset($_SERVER['PHP_AUTH_USER']) - && $_SERVER['PHP_AUTH_USER'] == trim( - $this->helper->getGeneralConfig('merchant_id') - ) - ) { - if (isset($_SERVER['PHP_AUTH_PW']) - && $_SERVER['PHP_AUTH_PW'] == trim( - $this->helper->getGeneralConfig('ipn_secret') - ) - ) { - $merchant = isset($ipn['merchant']) ? $ipn['merchant'] : ''; - if (empty($merchant)) { - $this->logAndDie('No Merchant ID passed'); - } - if ($merchant != trim($this->helper->getGeneralConfig('merchant_id'))) { - $this->logAndDie('Invalid Merchant ID'); - } - - return true; - } else { - $this->logAndDie( - 'IPN Secret not correct or no HTTP Auth variables passed. If you are using PHP in CGI mode try the HMAC method.' - ); - } - } else { - $this->logAndDie( - 'Merchant ID not correct or no HTTP Auth variables passed. If you are using PHP in CGI mode try the HMAC method.' - ); - } - return false; - } -} diff --git a/Controller/WebHooks/Notification.php b/Controller/WebHooks/Notification.php new file mode 100644 index 0000000..2d9c951 --- /dev/null +++ b/Controller/WebHooks/Notification.php @@ -0,0 +1,86 @@ +urlBuilder = $urlBuilder; + $this->webHookModel = $webHookModel; + $this->helper = $helper; + $this->scopeConfig = $scopeConfig; + parent::__construct($context); + } + + + public function execute() + { + if (!empty($this->helper->getConfig(Data::CLIENT_WEBHOOKS_KEY)) && !empty($this->getRequest()->getHeaders()->get('X-CoinPayments-Signature'))) { + $content = $this->getRequest()->getContent(); + $signature = $this->getRequest()->getHeaders()->get('X-CoinPayments-Signature')->getFieldValue(); + $requestData = json_decode($content, true); + if ($this->checkDataSignature($signature, $content)) { + $this->webHookModel->receiveNotification($requestData); + } + } + + } + + /** + * @param $signature + * @param $content + * @return bool + */ + protected function checkDataSignature($signature, $content) + { + + $requestUrl = $this->urlBuilder->getCurrentUrl(); + $clientSecret = $this->helper->getConfig(Data::CLIENT_SECRET_KEY); + $encodedPure = $this->webHookModel->generateHmac([$requestUrl, $content], $clientSecret); + return $signature == $encodedPure; + } + + public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException + { + return null; + } + + public function validateForCsrf(RequestInterface $request): ?bool + { + return true; + } +} diff --git a/Helper/Data.php b/Helper/Data.php index 8c47e9a..9cb1d53 100644 --- a/Helper/Data.php +++ b/Helper/Data.php @@ -1,52 +1,160 @@ - */ -namespace Firebear\CoinPayments\Helper; +namespace Coinpayments\CoinPayments\Helper; use Magento\Framework\App\Helper\AbstractHelper; use Magento\Framework\App\Helper\Context; -use Magento\Store\Model\ScopeInterface; +use Magento\Config\Model\ResourceModel\Config; +use Magento\Framework\App\Config\ConfigResource\ConfigInterface; +/** + * Class Data + * @package Coinpayments\CoinPayments\Helper + */ class Data extends AbstractHelper { + + + const FIAT_TYPE = 'fiat'; + const INVOICE_CACHE_PREFIX = 'CoinpaymentsInvoice'; + const XML_PATH_CONFIG_COINPAYMENTS = 'payment/coin_payments/'; + const XML_PATH_CONFIG_GENERAL = 'general/'; + + const CLIENT_ID_KEY = 'client_id'; + const CLIENT_SECRET_KEY = 'client_secret'; + const CLIENT_WEBHOOKS_KEY = 'webhooks'; + const CLIENT_ORDER_STATUS_KEY = 'status_order_paid'; + const PACKAGE_VERSION = 'package_version'; + + const API_WEBHOOK_ACTION = 'merchant/clients/%s/webhooks'; + const API_SIMPLE_INVOICE_ACTION = 'invoices'; + const API_MERCHANT_INVOICE_ACTION = 'merchant/invoices'; + + const VALIDATE_SIMPLE_URL = 'coinpayments/validation/invoice'; + const VALIDATE_MERCHANT_URL = 'coinpayments/validation/webhook'; + + const CREATE_INVOICE_URL = 'coinpayments/invoice/create'; + const WEBHOOK_NOTIFICATION_URL = 'coinpayments/webhooks/notification'; + + const PAID_EVENT = 'Paid'; + const CANCELLED_EVENT = 'Cancelled'; + + /** + * @var Config + */ + protected $resourceConfig; + protected $baseConf; /** * Data constructor. * * @param Context $context + * @param Config $resourceConfig */ - public function __construct(Context $context) + public function __construct(Context $context, + ConfigInterface $resourceConfig) { parent::__construct($context); + $this->resourceConfig = $resourceConfig; + $this->baseConf = $this->getBaseConfig(); } /** - * @param $field - * @param null $storeId - * + * @param $param * @return mixed */ - private function getConfigValue($field, $storeId = null) + public function getConfig($param) { - return $this->scopeConfig->getValue( - $field, - ScopeInterface::SCOPE_STORE, - $storeId - ); + return $this->scopeConfig->getValue(self::XML_PATH_CONFIG_COINPAYMENTS . $param); } /** - * @param $code - * @param null $storeId - * + * @param $param + * @return mixed + */ + public function getGeneralConfig($param) + { + return $this->scopeConfig->getValue(self::XML_PATH_CONFIG_GENERAL . $param); + } + + /** + * @param $param + * @param $value * @return mixed */ - public function getGeneralConfig($code, $storeId = null) + public function setConfig($param, $value) { - return $this->getConfigValue(self::XML_PATH_CONFIG_COINPAYMENTS . $code, $storeId); + return $this->resourceConfig->saveConfig(self::XML_PATH_CONFIG_COINPAYMENTS . $param, $value); + } + + /** + * @return mixed + */ + public function getBaseConfig() + { + return $this->scopeConfig->getValue('coinpayment/conf'); + } + + /** + * @param $action + * @return string + */ + public function getApiUrl($action) + { + return sprintf('%s/api/v%s/%s', $this->baseConf['api_host'], $this->baseConf['api_version'], $action); + } + + /** + * @param $param + * @return mixed + */ + public function getBaseConfigParam($param) + { + $value = null; + if (isset($this->baseConf[$param])) { + $value = $this->baseConf[$param]; + } + return $value; + } + + /** + * @param string $route + * @return string + */ + public function getHostUrl($route = '') + { + return $this->_getUrl($route, ['_direct' => null]); + } + + /** + * @param $clientId + * @param $event + * @return string + */ + public function getNotificationUrl($clientId, $event) + { + $query = http_build_query(array( + 'event' => $event, + 'clientId' => $clientId, + )); + return $this->getHostUrl(DATA::WEBHOOK_NOTIFICATION_URL) . '?' . $query; + } + + /** + * @param $coinInvoiceId + * @param $successUrl + * @param $cancelUrl + * @return string + */ + public function getCoinCheckoutRedirectUrl($coinInvoiceId, $successUrl, $cancelUrl) + { + return sprintf( + '%s/checkout/?invoice-id=%s&success-url=%s&cancel-url=%s', + $this->baseConf['checkout_host'], + $coinInvoiceId, + $successUrl, + $cancelUrl + ); } } diff --git a/Logger/Handler.php b/Logger/Handler.php deleted file mode 100644 index 6059fac..0000000 --- a/Logger/Handler.php +++ /dev/null @@ -1,24 +0,0 @@ - - */ - -namespace Firebear\CoinPayments\Logger; - -use \Monolog\Logger as MonologLogger; - -class Handler extends \Magento\Framework\Logger\Handler\Base -{ - /** - * Logging level - * @var int - */ - protected $loggerType = MonologLogger::INFO; - - /** - * File name - * @var string - */ - protected $fileName = '/var/log/CoinPaymentDebug.log'; -} diff --git a/Logger/Logger.php b/Logger/Logger.php deleted file mode 100644 index 3b62945..0000000 --- a/Logger/Logger.php +++ /dev/null @@ -1,12 +0,0 @@ - - */ - -namespace Firebear\CoinPayments\Logger; - -class Logger extends \Monolog\Logger -{ - -} diff --git a/Model/AbstractApi.php b/Model/AbstractApi.php new file mode 100644 index 0000000..3005fb2 --- /dev/null +++ b/Model/AbstractApi.php @@ -0,0 +1,186 @@ + 'application/json;' + ]; + /** + * @var Order + */ + protected $orderModel; + /** + * @var Coinpayments + */ + protected $coinPaymentsMethod; + /** + * @var BuilderInterface + */ + protected $transactionBuilder; + /** + * @var Data + */ + protected $helper; + /** + * @var Repository + */ + protected $transactionRepository; + + /** + * AbstractApi constructor. + * @param Curl $curl + * @param Data $helper + * @param ScopeConfigInterface $scopeConfig + * @param Order $orderModel + * @param Coinpayments $coinPaymentsMethod + * @param BuilderInterface $transactionBuilder + * @param Repository $transactionRepository + */ + public function __construct( + Curl $curl, + Data $helper, + ScopeConfigInterface $scopeConfig, + Order $orderModel, + Coinpayments $coinPaymentsMethod, + BuilderInterface $transactionBuilder, + Repository $transactionRepository + ) + { + $this->curl = $curl; + $this->helper = $helper; + $this->scopeConfig = $scopeConfig; + $this->orderModel = $orderModel; + $this->coinPaymentsMethod = $coinPaymentsMethod; + $this->transactionBuilder = $transactionBuilder; + $this->transactionRepository = $transactionRepository; + + } + + /** + * @param $requestParams + * @param array $requestData + * @return array + * @throws \Exception + */ + public function getRequestHeaders($requestParams, $requestData = []) + { + + $date = new \Datetime(); + + $headerData = [ + 'method' => $requestParams['method'], + 'url' => $this->helper->getApiUrl($requestParams['action']), + 'clientId' => $requestParams['clientId'], + 'timestamp' => $date->format('c'), + ]; + + if (!empty($requestData)) { + $headerData['params'] = json_encode($requestData); + } + + return [ + 'X-CoinPayments-Client' => $requestParams['clientId'], + 'X-CoinPayments-Timestamp' => $date->format('c'), + 'X-CoinPayments-Signature' => $this->generateHmac($headerData, $requestParams['clientSecret'], true), + ]; + } + + /** + * @param $action + * @param $headers + * @param $requestData + * @return mixed + */ + public function sendPostRequest($action, $headers, $requestData) + { + + $headers = array_merge($headers, $this->defaultHeaders); + foreach ($headers as $name => $value) { + $this->curl->addHeader($name, $value); + } + + $this->curl->setOption(CURLOPT_SSL_VERIFYHOST, 0); + $this->curl->setOption(CURLOPT_SSL_VERIFYPEER, 0); + + $requestUrl = $this->helper->getApiUrl($action); + $this->curl->post($requestUrl, json_encode($requestData)); + return json_decode($this->curl->getBody(), true); + } + + /** + * @param $action + * @param $headers + * @param array $requestData + * @return mixed + */ + public function sendGetRequest($action, $headers, $requestData = []) + { + + $headers = array_merge($headers, $this->defaultHeaders); + foreach ($headers as $name => $value) { + $this->curl->addHeader($name, $value); + } + + $this->curl->setOption(CURLOPT_SSL_VERIFYHOST, 0); + $this->curl->setOption(CURLOPT_SSL_VERIFYPEER, 0); + + $requestUrl = $this->helper->getApiUrl($action); + if (!empty($requestData)) { + $requestUrl .= '?' . http_build_query($requestData); + } + + $this->curl->get($requestUrl); + return json_decode($this->curl->getBody(), true); + } + + /** + * @param $requestData + * @param null $secretKey + * @param bool $useAdditional + * @return string + */ + public function generateHmac($requestData, $secretKey = null, $useAdditional = false) + { + if ($useAdditional) { + $requestData = array_merge([chr(239), chr(187), chr(191)], $requestData); + } + + return base64_encode( + hash_hmac( + 'sha256', + implode('', $requestData), + $secretKey, + true + ) + ); + } + + /** + * @param array $params + * @return mixed + */ + public function getCurrencies($params = []) + { + return $this->sendGetRequest('currencies', [], $params); + } +} diff --git a/Model/CoinPaymentsConfigProvider.php b/Model/CoinPaymentsConfigProvider.php new file mode 100644 index 0000000..711715e --- /dev/null +++ b/Model/CoinPaymentsConfigProvider.php @@ -0,0 +1,112 @@ +_curl = $curl; + $this->_scopeConfig = $scopeConfig; + $this->_assetRepo = $assetRepo; + } + + /** + * @return array + */ + public function getConfig() + { + $scope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE; + $secretKey = $this->_scopeConfig->getValue('payment/coin_payments/secret_key', $scope); + $publicKey = $this->_scopeConfig->getValue('payment/coin_payments/public_key', $scope); + $isDirect = $this->_scopeConfig->getValue('payment/coin_payments/is_direct', $scope); + $coinpaymentsDomain = $this->_scopeConfig->getValue('coinpayment/conf/url_payment', $scope); + $coinpaymentsApi = $this->_scopeConfig->getValue('coinpayment/conf/api_payment', $scope); + + $data = [ + 'version' => 1, + 'cmd' => 'rates', + 'key' => $publicKey, + 'accepted' => 2, + ]; + + $this->_curl->addHeader('HMAC', hash_hmac('sha512', http_build_query($data), $secretKey)); + $this->_curl->addHeader('Content-Type', 'application/x-www-form-urlencoded'); + $this->_curl->post($coinpaymentsApi, $data); + $response = json_decode($this->_curl->getBody()); + + $currencies = ['error' => $response->error]; + $acceptedCurrencies = ['error' => $response->error]; + if ($response->error == 'ok') { + $currencies = []; + $acceptedCurrencies = []; + foreach ($response->result as $key => $item) { + $elm = [ + 'value' => $key, + 'body' => $item, + 'name' => $item->name + ]; + $currencies[] = $elm; + if (isset($item->accepted) && $item->accepted == '1') { + $acceptedCurrencies[] = $elm; + } + } + } + + return [ + 'payment' => [ + 'coinpayments' => [ +<<<<<<< HEAD +<<<<<<< HEAD + 'logo' => $this->_assetRepo->getUrl('Coinpayments_CoinPayments::images/logo.png'), +======= +======= +>>>>>>> bongacam + 'available_currencies' => $currencies, + 'accepted_currencies' => $acceptedCurrencies, + 'logo' => $this->_assetRepo->getUrl('Coinpayments_CoinPayments::images/logo.png'), + 'direct_mode' => (int)$isDirect, + 'url' => $coinpaymentsDomain, + 'api_url' => $coinpaymentsApi +<<<<<<< HEAD +>>>>>>> revert-10-master +======= +>>>>>>> bongacam + ] + ] + ]; + } +} \ No newline at end of file diff --git a/Model/Invoice.php b/Model/Invoice.php new file mode 100644 index 0000000..bac1a09 --- /dev/null +++ b/Model/Invoice.php @@ -0,0 +1,152 @@ + 'POST', + 'action' => $action, + 'clientId' => $clientId, + 'clientSecret' => $clientSecret, + ]; + + $requestData = [ + 'invoiceId' => $invoiceParams['invoiceId'], + 'amount' => [ + 'currencyId' => $invoiceParams['currencyId'], + 'displayValue' => $invoiceParams['displayValue'], + 'value' => $invoiceParams['amount'] + ], + 'notesToRecipient' => $invoiceParams['notesLink'], + ]; + + if (isset($invoiceParams['billingData'])) { + $requestData['buyer'] = $this->appendBillingData($invoiceParams['billingData']); + } + + $requestData = $this->appendInvoiceMetadata($requestData); + $headers = $this->getRequestHeaders($requestParams, $requestData); + return $this->sendPostRequest($action, $headers, $requestData); + } + + /** + * @param $clientId + * @param $invoiceParams + * @return mixed + */ + public function createSimple($clientId, $invoiceParams) + { + + $action = Data::API_SIMPLE_INVOICE_ACTION; + + $requestData = [ + 'clientId' => $clientId, + 'invoiceId' => $invoiceParams['invoiceId'], + 'amount' => [ + 'currencyId' => $invoiceParams['currencyId'], + 'displayValue' => $invoiceParams['displayValue'], + 'value' => $invoiceParams['amount'], + ], + 'notesToRecipient' => $invoiceParams['notesLink'], + ]; + + if (isset($invoiceParams['billingData'])) { + $requestData['buyer'] = $this->appendBillingData($invoiceParams['billingData']); + } + + $requestData = $this->appendInvoiceMetadata($requestData); + return $this->sendPostRequest($action, [], $requestData); + } + + /** + * @param $order + * @param $coinInvoiceId + * @return int + */ + public function createOrderTransaction($order, $coinInvoiceId) + { + $payment = $order->getPayment(); + /* @var Order\Payment\Transaction\BuilderInterface */ + $transaction = $this->transactionBuilder + ->setPayment($payment) + ->setOrder($order) + ->setTransactionId($coinInvoiceId) + ->setFailSafe(true) + ->build(\Magento\Sales\Model\Order\Payment\Transaction::TYPE_CAPTURE); + $transaction->save(); + return $transaction->getTransactionId(); + } + + /** + * @param $requestData + * @return mixed + */ + protected function appendInvoiceMetadata($requestData) + { + + $requestData['metadata'] = [ + 'integration' => sprintf('Magento_v%s', $this->helper->getBaseConfigParam(Data::PACKAGE_VERSION)), + 'hostname' => $this->helper->getHostUrl(), + ]; + + return $requestData; + } + + /** + * @param $billingData + * @return array + */ + function appendBillingData($billingData) + { + $params = array( + 'companyName' => $billingData->getCompany(), + 'name' => array( + 'firstName' => $billingData->getFirstname(), + 'lastName' => $billingData->getLastname(), + ), + 'phoneNumber' => $billingData->getTelephone(), + ); + + if (preg_match('/^.*@.*$/', $billingData->getEmail())) { + $params['emailAddress'] = $billingData->getEmail(); + } + + if (!empty($billingData->getStreetLine(1)) && + !empty($billingData->getCity()) && + preg_match('/^([A-Z]{2})$/', $billingData->getCountryId()) + ) { + $params['address'] = array( + 'address1' => $billingData->getStreetLine(1), + 'address2' => $billingData->getStreetLine(2), + 'provinceOrState' => $billingData->getRegionCode(), + 'city' => $billingData->getCity(), + 'countryCode' => $billingData->getCountryId(), + 'postalCode' => $billingData->getPostcode() + ); + } + + return $params; + } +} diff --git a/Model/Methods/Coinpayments.php b/Model/Methods/Coinpayments.php index 8109914..8a131d5 100644 --- a/Model/Methods/Coinpayments.php +++ b/Model/Methods/Coinpayments.php @@ -4,17 +4,15 @@ * @author : Firebear Studio */ -namespace Firebear\CoinPayments\Model\Methods; +namespace Coinpayments\CoinPayments\Model\Methods; -use Magento\Framework\Pricing\PriceCurrencyInterface; -use Magento\Framework\HTTP\ZendClientFactory; -use Magento\Payment\Model\Method\ConfigInterface; -use Magento\Payment\Model\Method\TransparentInterface; -use Magento\Sales\Model\Order\Email\Sender\OrderSender; use Magento\Quote\Api\Data\CartInterface; use Magento\Payment\Model\Method\AbstractMethod; -use Magento\Sales\Model\Order; +/** + * Class Coinpayments + * @package Coinpayments\CoinPayments\Model\Methods + */ class Coinpayments extends AbstractMethod { @@ -28,19 +26,11 @@ class Coinpayments extends AbstractMethod */ protected $_code = self::CODE; - - /* Uncomment if need using blocks - - protected $_formBlockType = 'Firebear\CoinPayments\Block\Form\Coinpayments'; - - protected $_infoBlockType = 'Firebear\CoinPayments\Block\Info';*/ - - /** * @param CartInterface|null $quote * @return bool */ - public function isAvailable(\Magento\Quote\Api\Data\CartInterface $quote = null) + public function isAvailable(CartInterface $quote = null) { return parent::isAvailable($quote); } @@ -53,4 +43,12 @@ public function isActive($storeId = null) { return (bool)(int)$this->getConfigData('active', $storeId); } + + /** + * @return string + */ + public function getCode() + { + return $this->_code; + } } diff --git a/Model/WebHook.php b/Model/WebHook.php new file mode 100644 index 0000000..5d3a0be --- /dev/null +++ b/Model/WebHook.php @@ -0,0 +1,166 @@ + 'POST', + 'action' => $action, + 'clientId' => $clientId, + 'clientSecret' => $clientSecret, + ]; + + $requestData = [ + "notificationsUrl" => $this->helper->getNotificationUrl($clientId, $event), + "notifications" => [ + sprintf("invoice%s", $event), + ], + ]; + + $headers = $this->getRequestHeaders($requestParams, $requestData); + return $this->sendPostRequest($action, $headers, $requestData); + } + + /** + * @param $clientId + * @param $clientSecret + * @return mixed + * @throws \Exception + */ + public function getList($clientId, $clientSecret) + { + + $action = sprintf(Data::API_WEBHOOK_ACTION, $clientId); + + $requestParams = [ + 'method' => 'GET', + 'action' => $action, + 'clientId' => $clientId, + 'clientSecret' => $clientSecret, + ]; + + $headers = $this->getRequestHeaders($requestParams); + return $this->sendGetRequest($action, $headers); + } + + /** + * @param $requestData + * @throws \Magento\Framework\Exception\InputException + */ + public function receiveNotification($requestData) + { + + $orderData = explode('|', $requestData['invoice']['invoiceId']); + $host = array_shift($orderData); + if ($host == md5($this->helper->getHostUrl())) { + $orderId = array_shift($orderData); + $paymentId = array_shift($orderData); + $coinInvoiceId = $requestData['invoice']['id']; + $transaction = $this->transactionRepository->getByTransactionId( + $coinInvoiceId, + $paymentId, + $orderId + ); + + if (!empty($transaction)) { + /** @var Order $order */ + $order = $transaction->getOrder(); + if ($requestData['invoice']['status'] == Data::PAID_EVENT) { + $this->completeOrder($requestData['invoice'], $order, $transaction); + } elseif ($requestData['invoice']['status'] == Data::CANCELLED_EVENT) { + $this->cancelOrder($order); + } + } + } + + } + + /** + * @param $rawDetails + * @param $order + * @param $transaction + * @return bool + */ + public function completeOrder($rawDetails, $order, $transaction) + { + + $rawDetails['amount'] = $rawDetails['amount']['displayValue']; + $rawDetails['currency'] = $rawDetails['currency']['symbol']; + + + $order->setTotalPaid($rawDetails['amount']); + $order + ->setState($this->helper->getConfig(Data::CLIENT_ORDER_STATUS_KEY)) + ->setStatus($this->helper->getConfig(Data::CLIENT_ORDER_STATUS_KEY)); + + $str = 'CoinPayments.net Payment Status: ' . $rawDetails['status'] . ' ' . $rawDetails['status'] . '
'; + $str .= 'Transaction ID: ' . $rawDetails['id'] . '
'; + $str .= 'Received Amount: ' . sprintf('%s %s', $rawDetails['amount'], $rawDetails['currency']); + $order->addStatusToHistory($order->getStatus(), $str); + + + $transaction->setAdditionalInformation(Order\Payment\Transaction::RAW_DETAILS, $rawDetails); + + try { + $formatedPrice = $order->getBaseCurrency()->formatTxt($order->getGrandTotal()); + + $payment = $order->getPayment(); + $payment->setMethod($this->coinPaymentsMethod->getCode()); + $payment->setLastTransId($transaction->getId()); + $payment->setTransactionId($transaction->getTransactionId()); + $payment->setAdditionalInformation([Order\Payment\Transaction::RAW_DETAILS => $rawDetails]); + $payment->addTransactionCommentsToOrder($transaction, __('The authorized amount is %1.', $formatedPrice)); + $payment->setParentTransactionId(null); + + $invoice = $order->prepareInvoice()->register(); + $invoice->setOrder($order); + $invoice->setOrder($order); + $invoice->pay(); + + $order->addRelatedObject($invoice); + $payment->setCreatedInvoice($invoice); + + $payment->save(); + $order->save(); + $transaction->save(); + return $transaction->getTransactionId(); + } catch (\Exception $e) { + } + return true; + } + + /** + * @param Order $order + * @throws \Exception + */ + public function cancelOrder($order) + { + $order + ->setStatus(Order::STATE_CANCELED) + ->setState(Order::STATE_CANCELED) + ->save(); + } + +} diff --git a/README.md b/README.md index e326299..a01c083 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,30 @@ - -

Live demo | Extension manualCoinPayments 

-

Meet the best way to accept cryptocurrency on Magento 2. With Firebear CoinPayments Magento 2 extension, you will easily integrate your ecommerce store with the popular cryptocurrency gateway accepting over 70 altcoins, including Bitcoin and Ethereum. Thus, Magento 2 cryptocurrency trading is no longer an unattainable goal - it is a new way of business dealing.

-

Features

-

- Magento 2 cryptocurrency integration: accept Bitcoin, Ethereum, and other altcoins as payment for products and services you sell;

-

- Use Magento 2 cryptocurrency wallets (based on CoinPayments) to store crypto: Ethereum, BitCoin or any altocoin wallet;

-

- Magento 2 Cryptocurrency PayPal integration: send payments to PayPal without any fees;

-

- Transparent transaction history: view separate logs for deposits, transfers, withdrawals, and conversions.

-

- Supported coins : Bitcoin, Litecoin, AudioCoin, BitConnect, Bitcoin Cash, BitBean, BlackCoin, Breakout, CloakCoin, Crown, CureCoin, Dash, Decred, DigiByte, Dogecoin, Ether Classic, Ethereum, Expanse, FLASH, GameCredits, GCRCoin, Goldcoin, Gridcoin, Groestlcoin, LeoCoin, LeoCoin (Old Chain), LISK, MaidSafeCoin, MonetaryUnit, NAV Coin, NoLimitCoin, Namecoin, NVO Token, Nexus, NXT, OMNI, PinkCoin, PIVX, PoSW Coin, PotCoin, Peercoin, ProCurrency, Quark, Steem Dollars, SibCoin, STEEM, Stratis, Syscoin, TetherUSD, Voxels, Vertcoin, Waves, Counterparty, NEM, Monero, VERGE, ZCash, ZenCash, Litecoin Testnet

-

CoinPayments is a popular online platform that allows accepting, storing, converting, and withdrawing altcoins. Currently it supports 70+ cryptocurrencies and provides a unique $tag to receive payments from all of them. Thus, you can easily accept payments in such popular altcoins as Bitcoin and Ethereum on your Magento 2 ecommerce website. Bitcoin is a number one cryptocurrency that has become the first decentralized digital currency that uses peer-to-peer transactions, so users interact directly without any intermediary. Ethereum is based on the same technology, blockchain, and provides a cryptocurrency token transferable between accounts as well. To view current Magento 2 cryptocurrency prices, visit CoinMarketCup.

-

-

Besides, CoinPayments offers an integration with PayPal. For all United States and Euro merchants, the platform, and our Magento 2 cryptocurrency extension, provides the ability to have a fiat settlement directly to a bank account. And since there are more than 70 altcoins are supported, CoinPayments offers autoconversion for them that is free of fees. As a result, you save lots of time and effort.

-

With the Firebear CoinPayments Magento 2 cryptocurrency extension, you can not only accept altcoins on your Magento 2 website, but also store cryptocurrency in a secure online wallet as well as protect altcoins in the vault that requires a time amount before being able to spend them. Almost 400 thousand vendors all over the world already use CoinPayments, so don't waste your chance to implement the new technology on your ecommerce storefront with the Firebear CoinPayments Magento 2 extension.

-

The Magento 2 CoinPyament cryptocurrency module is easy to configure. The integration of your store with CoinPayments (and the desired ability to accept crypto on Magento 2) won't take much time. Simply go to Stores -> Settings -> Configuration -> Sales -> Payment Methods -> Other Payment Methods. Here, you can find the 'Coin Payments' section that allows enabling the integration (specify such parameters as your CoinPayments.net Merchant ID and IPN secret), specifying countries to enable the new payment method for, and selecting order statuses for two cases: CoinPayments didn't receive funds and funds are received. You can find a more detailed Magento 2 payment gateway tutorial in the extension manual.

-

magento 2 bitcoin

-

magento 2 ethereum

-

From the frontend perspective, you should add a product to cart and proceed to checkout. Complete the first step in order to be able to select a payment method. Select "Coin Payments" and you will see the following message:

-

magento 2 bitcoin checkout

-

Now, you are on the CoinPayments platform. Specify your first name, last name, and email, choose your altcoin, and complete the checkout. Alternatively, you can cancel it and return to seller's store, contact seller directly from the cryptocurrency payment gateway page, or view profile.

-

magento 2 coin payments checkout - bitcoin & ethereum

-

send bitcoin magento 2

+IMPORTANT NOTE: + +This is only for use with: https://alpha.coinpayments.net/ + +NOT for use with https://coinpayments.net + +Demonstration Website Disclaimer: The information presented on alpha.coinpayments.net (the "Demo Site") is for demonstration purposes only. All content on the Demo Site is considered “in development” and should be used at your own risk. CoinPayments Inc. assumes no responsibility or liability for any errors or omissions in the content of the Demo Site. The information contained in the Demo Site is provided on an "as is" basis with no guarantees of completeness, accuracy, usefulness or timeliness and without any warranties of any kind whatsoever, express or implied. CoinPayments Inc. does not warrant that the Demo Site and any information or material downloaded from the Demo Site, will be uninterrupted, error-free, omission-free or free of viruses or other harmful items. + +In no event will CoinPayments Inc. or its directors, officers, employees, shareholders, service providers or agents, be liable to you, or anyone else, for any decision(s) made or action(s) taken in reliance upon the information contained in the Demo Site, nor for any direct, indirect, incidental, special, exemplary, punitive, consequential, or other damages whatsoever (including, but not limited to, liability for loss of use, funds, data or profits) whether in an action of contract, statute, tort or otherwise, relating to the use of the Demo Site." + +# Coinpayments_CoinPayments Module + +The Coinpayments_CoinPayments module provides the "Coinpayments.NET" payment method. + +## About CoinPayments Module + +CoinPayments module provides integration of your Magento 2 store with Coinpaymnets.NET services. This helps your customers shop quickly, safely and securely. +Your customers can pay on your website without re-entering their payment and address details. +All CoinPayments module transactions are protected. + +## Dependencies + +You can find a list of modules in the require section of the `composer.json` file located in the +same directory as this `README.md` file. + +## Extension Points + +There are no extension points or service contracts for this module. + +## Additional Information diff --git a/composer.json b/composer.json index 7e20972..e339362 100644 --- a/composer.json +++ b/composer.json @@ -1,11 +1,11 @@ { - "name": "firebear/coinpayments", - "description": "Add new payment method for coinpayments.com", + "name": "coinpaymentsnet/magento2", + "description": "Add new payment method for CoinPayments.net", "require": { - "php": "~5.5.0|~5.6.0|~7.0.0|~7.1" + "php": "~7.3.0||~7.4.0" }, "type": "magento2-module", - "version": "1.1.0", + "version": "2.0.0", "license": [ "OSL-3.0" ], @@ -14,7 +14,7 @@ "registration.php" ], "psr-4": { - "Firebear\\CoinPayments\\": "" + "coinpaymentsnet\\magento2\\": "" } } } diff --git a/etc/acl.xml b/etc/acl.xml new file mode 100644 index 0000000..2350630 --- /dev/null +++ b/etc/acl.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/etc/adminhtml/routes.xml b/etc/adminhtml/routes.xml new file mode 100644 index 0000000..bff2f1a --- /dev/null +++ b/etc/adminhtml/routes.xml @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 03d2e14..58f0925 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -1,73 +1,75 @@ - - +
- - + + complex coin-payment-section + Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Payment + - + Magento\Config\Model\Config\Source\Yesno - - - - - - - Account Settings -> Basic Settings -> Your Merchant ID.]]> - - - - - + + + + required-entry validate-length minimum-length-22 maximum-length-32 coin-invoice-validate + + + 1 + - - - + + Magento\Config\Model\Config\Source\Yesno + + 1 + - - - + + + + required-entry validate-length minimum-length-22 maximum-length-44 coin-webhooks-validate + + + 1 + 1 + - - - Magento\Payment\Model\Config\Source\Allspecificcountries - - - - - Magento\Directory\Model\Config\Source\Country - 1 - - - - - Magento\Sales\Model\Config\Source\Order\Status\NewStatus - - - - + Magento\Sales\Model\Config\Source\Order\Status - + required-entry + + + + + 1 + 1 + - - - Magento\Config\Model\Config\Source\Yesno -
-
\ No newline at end of file +
diff --git a/etc/config.xml b/etc/config.xml index ab46a61..8a8183a 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -1,18 +1,11 @@ - - 1 - Firebear\CoinPayments\Model\Methods\Coinpayments - pending + 0 + Coinpayments\CoinPayments\Model\Methods\Coinpayments Coin Payments 0 coinpayments @@ -20,8 +13,11 @@ - https://www.coinpayments.net + https://api.coinpayments.net + https://checkout.coinpayments.net + 1 + 2.0.0 - ` + \ No newline at end of file diff --git a/etc/di.xml b/etc/di.xml index f284408..2b0a1b9 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -1,23 +1,6 @@ - - - - - Magento\Framework\Filesystem\Driver\File - - - - - CoinPaymentDebug - - Firebear\CoinPayments\Logger\Handler - - - + + \ No newline at end of file diff --git a/etc/frontend/di.xml b/etc/frontend/di.xml new file mode 100644 index 0000000..fca8dd9 --- /dev/null +++ b/etc/frontend/di.xml @@ -0,0 +1,13 @@ + + + + + + + Coinpayments\CoinPayments\Model\CoinPaymentsConfigProvider + + + + + \ No newline at end of file diff --git a/etc/frontend/routes.xml b/etc/frontend/routes.xml index 310c7ae..e4e6805 100644 --- a/etc/frontend/routes.xml +++ b/etc/frontend/routes.xml @@ -1,14 +1,9 @@ - - + - + \ No newline at end of file diff --git a/etc/module.xml b/etc/module.xml index d66de55..70b380d 100644 --- a/etc/module.xml +++ b/etc/module.xml @@ -1,17 +1,13 @@ - - - + + - - - - - - + + + + + + + \ No newline at end of file diff --git a/etc/payment.xml b/etc/payment.xml index 4ae7aec..34905c1 100644 --- a/etc/payment.xml +++ b/etc/payment.xml @@ -1,10 +1,4 @@ - diff --git a/registration.php b/registration.php index a2abac6..cb2090d 100644 --- a/registration.php +++ b/registration.php @@ -1,11 +1,7 @@ - */ \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, - 'Firebear_CoinPayments', + 'Coinpayments_CoinPayments', __DIR__ ); diff --git a/view/adminhtml/layout/adminhtml_system_config_edit.xml b/view/adminhtml/layout/adminhtml_system_config_edit.xml new file mode 100644 index 0000000..af483a5 --- /dev/null +++ b/view/adminhtml/layout/adminhtml_system_config_edit.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/view/adminhtml/requirejs-config.js b/view/adminhtml/requirejs-config.js new file mode 100644 index 0000000..281fef8 --- /dev/null +++ b/view/adminhtml/requirejs-config.js @@ -0,0 +1,6 @@ +var config = { + 'paths': { + 'coin-invoice-validate': 'Coinpayments_CoinPayments/js/invoice-validate', + 'coin-webhooks-validate': 'Coinpayments_CoinPayments/js/webhooks-validate' + } +}; diff --git a/view/adminhtml/templates/coinpayments/info/default.phtml b/view/adminhtml/templates/coinpayments/info/default.phtml deleted file mode 100644 index 1466665..0000000 --- a/view/adminhtml/templates/coinpayments/info/default.phtml +++ /dev/null @@ -1,11 +0,0 @@ - - */ - -echo '

Ordered with CoinPayments

'; -if ($url = $block->getCoinPaymentsInvoiceUrl()) { - echo '

View Invoice

'; -} -?> \ No newline at end of file diff --git a/view/adminhtml/templates/js_vars.phtml b/view/adminhtml/templates/js_vars.phtml new file mode 100644 index 0000000..d876cdc --- /dev/null +++ b/view/adminhtml/templates/js_vars.phtml @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/view/adminhtml/web/images/logo.png b/view/adminhtml/web/images/logo.png new file mode 100644 index 0000000..eefad06 Binary files /dev/null and b/view/adminhtml/web/images/logo.png differ diff --git a/view/adminhtml/web/js/invoice-validate.js b/view/adminhtml/web/js/invoice-validate.js new file mode 100644 index 0000000..904f287 --- /dev/null +++ b/view/adminhtml/web/js/invoice-validate.js @@ -0,0 +1,38 @@ +require([ + 'jquery', + 'jquery/ui', + 'jquery/validate', + 'mage/translate' +], function ($) { + + $.validator.addMethod( + "coin-invoice-validate", + function (client_id) { + + var web_hooks = $('[data-ui-id="select-groups-coin-payments-fields-webhooks-value"]'); + var is_success = false; + + if (web_hooks.length && web_hooks.val() === '1') { + is_success = true; + } else { + var params = { + client_id: client_id, + }; + $.ajax({ + showLoader: true, + url: coin_validate_invoice, + data: params, + async: false, + type: "POST", + dataType: 'json' + }).done(function (data) { + is_success = data.success; + }); + } + + return is_success; + }, + $.mage.__("Please enter a valid Coinpayments.NET credentials.") + ); + +}); \ No newline at end of file diff --git a/view/adminhtml/web/js/webhooks-validate.js b/view/adminhtml/web/js/webhooks-validate.js new file mode 100644 index 0000000..292d3f7 --- /dev/null +++ b/view/adminhtml/web/js/webhooks-validate.js @@ -0,0 +1,48 @@ +require([ + 'jquery', + 'jquery/ui', + 'jquery/validate', + 'mage/translate' +], function ($) { + + var validationError = "Please enter a valid Coinpayments.NET credentials."; + + $.validator.addMethod( + "coin-webhooks-validate", + function (client_secret, elem) { + + var is_success = false; + var validator = this; + var client_id_field = $('[data-ui-id="text-groups-coin-payments-fields-client-id-value"]'); + var client_secret_field = $('[data-ui-id="text-groups-coin-payments-fields-client-secret-value"]'); + var web_hooks = $('[data-ui-id="select-groups-coin-payments-fields-webhooks-value"]'); + + if (client_id_field.length && web_hooks.length && client_secret_field.length) { + + var params = { + client_id: client_id_field.val(), + client_secret: client_secret_field.val(), + }; + + $.ajax({ + showLoader: true, + url: coin_validate_webhooks, + data: params, + async: false, + type: "POST", + dataType: 'json' + }).done(function (data) { + is_success = data.success; + if (!is_success) { + var errors = {}; + errors[client_id_field.attr('name').replace(/[.*+?^${}()|[\]\\]/g, '\\$&')] = validationError; + validator.showErrors(errors); + } + }); + } + + return is_success; + }, + $.mage.__(validationError) + ); +}); \ No newline at end of file diff --git a/view/adminhtml/web/styles.css b/view/adminhtml/web/styles.css new file mode 100644 index 0000000..22a17cd --- /dev/null +++ b/view/adminhtml/web/styles.css @@ -0,0 +1,30 @@ +.complex.coin-payment-section .coin-payment-logo { + display: inline-block; + vertical-align: middle; + margin: 0 20px 0 0px; + width: 180px; + height: 60px; + background-repeat: no-repeat, no-repeat, no-repeat; + background-size: 100% auto; + background-position: center top; + background-image: url('images/logo.png'); +} + +.section-config.with-button.coin-payment-section .config-heading strong { + font-weight: normal; +} + +.complex.coin-payment-section .button-container { + float: right; +} + +.complex.coin-payment-section .coin-payment-description { + display: inline-block; + vertical-align: middle; + width: 50%; +} + +.coin-payment-section.section-config.active > .admin__collapsible-block + input + fieldset { + margin-left: 40px; +} + diff --git a/view/frontend/layout/checkout_index_index.xml b/view/frontend/layout/checkout_index_index.xml index 0736117..5a7494b 100644 --- a/view/frontend/layout/checkout_index_index.xml +++ b/view/frontend/layout/checkout_index_index.xml @@ -1,49 +1,53 @@ - - - - - - - - - - - - - - uiComponent - - - - - - - - Firebear_CoinPayments/js/view/payment/coin_payments - - - true - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + uiComponent + + + + + + + + Coinpayments_CoinPayments/js/view/payment/coin_payments + + + + true + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/view/frontend/layout/coinpayments_checkout_failure.xml b/view/frontend/layout/coinpayments_checkout_failure.xml index 71e3b5b..7831f24 100644 --- a/view/frontend/layout/coinpayments_checkout_failure.xml +++ b/view/frontend/layout/coinpayments_checkout_failure.xml @@ -5,7 +5,8 @@ * See COPYING.txt for license details. */ --> - + @@ -13,7 +14,8 @@ - + diff --git a/view/frontend/layout/coinpayments_invoice_index.xml b/view/frontend/layout/coinpayments_invoice_index.xml deleted file mode 100644 index 38e09d2..0000000 --- a/view/frontend/layout/coinpayments_invoice_index.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/view/frontend/templates/coinpayments/form/coinpayments.phtml b/view/frontend/templates/coinpayments/form/coinpayments.phtml deleted file mode 100644 index 4f5a28f..0000000 --- a/view/frontend/templates/coinpayments/form/coinpayments.phtml +++ /dev/null @@ -1,14 +0,0 @@ - - */ - -$_code = $block->getMethodCode(); -$coinpaymentsScope = \Magento\Framework\App\ObjectManager::getInstance()->get('\Magento\Framework\App\Config\ScopeConfigInterface'); -if ($coinpaymentsScope->getValue('payment/coinpayments/fullscreen')) { - echo ''; -} -?> \ No newline at end of file diff --git a/view/frontend/templates/coinpayments/iframe.phtml b/view/frontend/templates/coinpayments/iframe.phtml deleted file mode 100644 index 39b9b22..0000000 --- a/view/frontend/templates/coinpayments/iframe.phtml +++ /dev/null @@ -1,53 +0,0 @@ - - */ -// Retrieve order -$orderId = $block->getLastOrderId(); -$payemntData = $block->getPaymentData(); -$quoteData = $block->getQuote(); -$successUrl = $block->getSuccessUrl(); -$failUrl = $block->getFailUrl(); -?> -
- - - - - - - - - - - - - - - - - - - - -
- \ No newline at end of file diff --git a/view/frontend/templates/coinpayments/redirect.phtml b/view/frontend/templates/coinpayments/redirect.phtml deleted file mode 100644 index c923ce6..0000000 --- a/view/frontend/templates/coinpayments/redirect.phtml +++ /dev/null @@ -1,36 +0,0 @@ - - */ - -// Retrieve order -$_order = $block->getOrder(); -$orderId = $block->getRealOrderId(); -var_dump($orderId); -?> - diff --git a/view/frontend/templates/js_vars.phtml b/view/frontend/templates/js_vars.phtml new file mode 100644 index 0000000..a0ff978 --- /dev/null +++ b/view/frontend/templates/js_vars.phtml @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/view/frontend/web/images/logo.png b/view/frontend/web/images/logo.png new file mode 100644 index 0000000..3467c9d Binary files /dev/null and b/view/frontend/web/images/logo.png differ diff --git a/view/frontend/web/js/action/set-payment-method.js b/view/frontend/web/js/action/set-payment-method.js index f50b662..332081c 100644 --- a/view/frontend/web/js/action/set-payment-method.js +++ b/view/frontend/web/js/action/set-payment-method.js @@ -1,56 +1,56 @@ -/** - * @copyright: Copyright © 2017 Firebear Studio. All rights reserved. - * @author : Firebear Studio - */ -define( - [ - 'jquery', - 'Magento_Checkout/js/model/quote', - 'Magento_Checkout/js/model/url-builder', - 'mage/storage', - 'Magento_Checkout/js/model/error-processor', - 'Magento_Customer/js/model/customer', - 'Magento_Checkout/js/model/full-screen-loader' - ], - function ($, quote, urlBuilder, storage, errorProcessor, customer, fullScreenLoader) { - 'use strict'; - - return function (messageContainer) { - var serviceUrl, - payload, - method = 'put', - paymentData = quote.paymentMethod(); - - /** - * Checkout for guest and registered customer. - */ - if (!customer.isLoggedIn()) { - serviceUrl = urlBuilder.createUrl('/guest-carts/:cartId/set-payment-information', { - cartId: quote.getQuoteId() - }); - payload = { - cartId: quote.getQuoteId(), - email: quote.guestEmail, - paymentMethod: paymentData - }; - method = 'post'; - } else { - serviceUrl = urlBuilder.createUrl('/carts/mine/selected-payment-method', {}); - payload = { - cartId: quote.getQuoteId(), - method: paymentData - }; - } - fullScreenLoader.startLoader(); - - return storage[method]( - serviceUrl, JSON.stringify(payload) - ).fail( - function (response) { - errorProcessor.process(response, messageContainer); - fullScreenLoader.stopLoader(); - } - ); - }; - } +/** + * @copyright: Copyright © 2017 Firebear Studio. All rights reserved. + * @author : Firebear Studio + */ +define( + [ + 'jquery', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/model/url-builder', + 'mage/storage', + 'Magento_Checkout/js/model/error-processor', + 'Magento_Customer/js/model/customer', + 'Magento_Checkout/js/model/full-screen-loader' + ], + function ($, quote, urlBuilder, storage, errorProcessor, customer, fullScreenLoader) { + 'use strict'; + + return function (messageContainer) { + var serviceUrl, + payload, + method = 'put', + paymentData = quote.paymentMethod(); + + /** + * Checkout for guest and registered customer. + */ + if (!customer.isLoggedIn()) { + serviceUrl = urlBuilder.createUrl('/guest-carts/:cartId/set-payment-information', { + cartId: quote.getQuoteId() + }); + payload = { + cartId: quote.getQuoteId(), + email: quote.guestEmail, + paymentMethod: paymentData + }; + method = 'post'; + } else { + serviceUrl = urlBuilder.createUrl('/carts/mine/selected-payment-method', {}); + payload = { + cartId: quote.getQuoteId(), + method: paymentData + }; + } + fullScreenLoader.startLoader(); + + return storage[method]( + serviceUrl, JSON.stringify(payload) + ).fail( + function (response) { + errorProcessor.process(response, messageContainer); + fullScreenLoader.stopLoader(); + } + ); + }; + } ); \ No newline at end of file diff --git a/view/frontend/web/js/view/payment/coin_payments.js b/view/frontend/web/js/view/payment/coin_payments.js index f44c385..0d2585d 100644 --- a/view/frontend/web/js/view/payment/coin_payments.js +++ b/view/frontend/web/js/view/payment/coin_payments.js @@ -1,20 +1,18 @@ -/** - * @copyright: Copyright © 2017 Firebear Studio. All rights reserved. - * @author : Firebear Studio - */ - define( [ 'uiComponent', 'Magento_Checkout/js/model/payment/renderer-list' ], - function (Component, - rendererList) { + function ( + Component, + rendererList + ) { 'use strict'; + rendererList.push( { type: 'coin_payments', - component: 'Firebear_CoinPayments/js/view/payment/method-renderer/coin-method' + component: 'Coinpayments_CoinPayments/js/view/payment/method-renderer/coin-method' } ); return Component.extend({}); diff --git a/view/frontend/web/js/view/payment/method-renderer/coin-method.js b/view/frontend/web/js/view/payment/method-renderer/coin-method.js index 4d8adcb..9104cff 100644 --- a/view/frontend/web/js/view/payment/method-renderer/coin-method.js +++ b/view/frontend/web/js/view/payment/method-renderer/coin-method.js @@ -1,8 +1,3 @@ - /** - * @copyright: Copyright © 2017 Firebear Studio. All rights reserved. - * @author : Firebear Studio - */ - define( [ 'ko', @@ -15,44 +10,59 @@ define( 'Magento_Checkout/js/checkout-data', 'Magento_Checkout/js/model/payment/additional-validators', 'mage/url', - 'Firebear_CoinPayments/js/action/set-payment-method', - 'Magento_Checkout/js/model/full-screen-loader' + 'Magento_Checkout/js/model/full-screen-loader', + 'Magento_Checkout/js/model/error-processor', + 'Magento_Checkout/js/model/totals', ], - function (ko,Component, quote,$,placeOrderAction,selectPaymentMethodAction,customer, checkoutData, additionalValidators, url,setPaymentMethodAction,fullScreenLoader) { + function (ko, + Component, + quote, + $, + placeOrderAction, + selectPaymentMethodAction, + customer, + checkoutData, + additionalValidators, + url, + fullScreenLoader, + errorProcessor, + totals + ) { 'use strict'; - return Component.extend({ + + window.fullScreenLoader = fullScreenLoader; + window.url = url; + + var a = Component.extend({ defaults: { - template: 'Firebear_CoinPayments/payment/coin_payment' + template: 'Coinpayments_CoinPayments/payment/coin_payment' }, - getCode: function() { + /** + * @returns {string} + */ + getCode: function () { return 'coin_payments'; }, - isActive: function() { - return true; - }, afterPlaceOrder: function () { - window.location.replace(url.build('coinpayments/invoice/index/')); + this.createInvoice(); }, - getRedirectionText: function () { - - var iframeHtml; - jQuery.ajax( { - url: url.build('coinpayments/iframe/index/'), - async: false , - dataType: "json", - success: function(a) { - iframeHtml = a.html; - } - - }); - return iframeHtml; - }, - selectPaymentMethod: function() { + /** + * + * @returns {boolean} + */ + selectPaymentMethod: function () { selectPaymentMethodAction(this.getData()); checkoutData.setSelectedPaymentMethod(this.item.method); return true; }, + /** + * + * @param data + * @param event + * @returns {boolean} + */ placeOrder: function (data, event) { + if (event) { event.preventDefault(); } @@ -64,6 +74,7 @@ define( $(loginFormSelector).validation(); emailValidationResult = Boolean($(loginFormSelector + ' input[name=username]').valid()); } + if (emailValidationResult && this.validate() && additionalValidators.validate()) { this.isPlaceOrderActionAllowed(false); placeOrder = placeOrderAction(this.getData(), false, this.messageContainer); @@ -75,9 +86,52 @@ define( } return false; }, - getMailingAddress: function () { - return window.checkoutConfig.payment.checkmo.mailingAddress; + getBaseGrandTotal: function () { + if (totals.totals()) { + var grandTotal = parseFloat(totals.totals()['grand_total']); + return grandTotal; + } + return window.checkoutConfig.totalsData.base_grand_total; + }, + getPaymentAcceptanceMarkSrc: function () { + return window.checkoutConfig.payment.coinpayments.logo; + }, + /** + * @returns {boolean} + */ + getAllowPlaceOrder: function () { + return this.getCode() === this.isChecked(); }, + /** + * + * @param currency + * @param value + * @param redirect + */ + createInvoice: function () { + $.ajax({ + type: "POST", + dataType: 'json', + contentType: "application/json", + url: url.build(coin_invoice_create_url), + success: function (result) { + if (result.coinInvoiceId) { + window.location.href = result.redirectUrl; + } else { + window.location.href = result.cancelUrl; + } + }, + error: function (err) { + console.log(error); + if (redirect) { + window.location.replace(redirect); + } + } + }); + } }); + window.a = a; + return a; } -); \ No newline at end of file +) +; \ No newline at end of file diff --git a/view/frontend/web/template/payment/coin_payment.html b/view/frontend/web/template/payment/coin_payment.html index 90efeef..91c7081 100644 --- a/view/frontend/web/template/payment/coin_payment.html +++ b/view/frontend/web/template/payment/coin_payment.html @@ -1,46 +1,41 @@ - -
-
- - -
-
- - - -
-
- -
-
-
- - - -
-
-
- -
-
-
+
+
+ + +
+
+ + + + +
+ + + +
+
+
+ +
+
+
\ No newline at end of file