diff --git a/upload/admin/controller/extension/payment/paypal.php b/upload/admin/controller/extension/payment/paypal.php index a8a18bb1f3a..4d68577ff6d 100644 --- a/upload/admin/controller/extension/payment/paypal.php +++ b/upload/admin/controller/extension/payment/paypal.php @@ -5,7 +5,7 @@ class ControllerExtensionPaymentPayPal extends Controller { public function __construct($registry) { parent::__construct($registry); - if (empty($this->config->get('paypal_version')) || (!empty($this->config->get('paypal_version')) && ($this->config->get('paypal_version') < '2.2.0'))) { + if (empty($this->config->get('paypal_version')) || (!empty($this->config->get('paypal_version')) && ($this->config->get('paypal_version') < '3.0.0'))) { $this->uninstall(); $this->install(); } @@ -25,17 +25,21 @@ public function index() { $config_setting = $_config->get('paypal_setting'); - if (!empty($this->session->data['environment']) && !empty($this->session->data['authorization_code']) && !empty($this->session->data['shared_id']) && !empty($this->session->data['seller_nonce']) && !empty($this->request->get['merchantIdInPayPal'])) { + $cache_data = $this->cache->get('paypal'); + + $this->cache->delete('paypal'); + + if (!empty($cache_data['environment']) && !empty($cache_data['authorization_code']) && !empty($cache_data['shared_id']) && !empty($cache_data['seller_nonce']) && !empty($this->request->get['merchantIdInPayPal'])) { $this->load->language('extension/payment/paypal'); $this->load->model('extension/payment/paypal'); - $environment = $this->session->data['environment']; + $environment = $cache_data['environment']; require_once DIR_SYSTEM . 'library/paypal/paypal.php'; $paypal_info = array( - 'client_id' => $this->session->data['shared_id'], + 'client_id' => $cache_data['shared_id'], 'environment' => $environment, 'partner_attribution_id' => $config_setting['partner'][$environment]['partner_attribution_id'] ); @@ -44,8 +48,8 @@ public function index() { $token_info = array( 'grant_type' => 'authorization_code', - 'code' => $this->session->data['authorization_code'], - 'code_verifier' => $this->session->data['seller_nonce'] + 'code' => $cache_data['authorization_code'], + 'code_verifier' => $cache_data['seller_nonce'] ); $paypal->setAccessToken($token_info); @@ -76,6 +80,7 @@ public function index() { $paypal->setAccessToken($token_info); + $callback_token = sha1(uniqid(mt_rand(), 1)); $webhook_token = sha1(uniqid(mt_rand(), 1)); $cron_token = sha1(uniqid(mt_rand(), 1)); @@ -89,7 +94,8 @@ public function index() { array('name' => 'PAYMENT.CAPTURE.PENDING'), array('name' => 'PAYMENT.CAPTURE.REFUNDED'), array('name' => 'PAYMENT.CAPTURE.REVERSED'), - array('name' => 'CHECKOUT.ORDER.COMPLETED') + array('name' => 'CHECKOUT.ORDER.COMPLETED'), + array('name' => 'VAULT.PAYMENT-TOKEN.CREATED') ) ); @@ -138,6 +144,7 @@ public function index() { $setting['payment_paypal_total'] = 0; $setting['payment_paypal_geo_zone_id'] = 0; $setting['payment_paypal_sort_order'] = 0; + $setting['payment_paypal_setting']['general']['callback_token'] = $callback_token; $setting['payment_paypal_setting']['general']['webhook_token'] = $webhook_token; $setting['payment_paypal_setting']['general']['cron_token'] = $cron_token; @@ -161,14 +168,12 @@ public function index() { } $this->model_setting_setting->editSetting('payment_paypal', $setting); - - unset($this->session->data['authorization_code']); - unset($this->session->data['shared_id']); - unset($this->session->data['seller_nonce']); + } + + if (!empty($this->request->get['merchantIdInPayPal']) && !$this->error) { + sleep(3); - if (!$this->error) { - $this->response->redirect($this->url->link('extension/payment/paypal', 'user_token=' . $this->session->data['user_token'], true)); - } + $this->response->redirect($this->url->link('extension/payment/paypal', 'user_token=' . $this->session->data['user_token'], true)); } if (!$this->config->get('payment_paypal_client_id')) { @@ -311,7 +316,8 @@ public function dashboard() { $data['href_googlepay_button'] = $this->url->link('extension/payment/paypal/googlepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_applepay_button'] = $this->url->link('extension/payment/paypal/applepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_card'] = $this->url->link('extension/payment/paypal/card', 'user_token=' . $this->session->data['user_token'], true); - $data['href_message'] = $this->url->link('extension/payment/paypal/message', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_configurator'] = $this->url->link('extension/payment/paypal/message_configurator', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_setting'] = $this->url->link('extension/payment/paypal/message_setting', 'user_token=' . $this->session->data['user_token'], true); $data['href_order_status'] = $this->url->link('extension/payment/paypal/order_status', 'user_token=' . $this->session->data['user_token'], true); $data['href_contact'] = $this->url->link('extension/payment/paypal/contact', 'user_token=' . $this->session->data['user_token'], true); @@ -442,7 +448,8 @@ public function general() { $data['href_googlepay_button'] = $this->url->link('extension/payment/paypal/googlepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_applepay_button'] = $this->url->link('extension/payment/paypal/applepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_card'] = $this->url->link('extension/payment/paypal/card', 'user_token=' . $this->session->data['user_token'], true); - $data['href_message'] = $this->url->link('extension/payment/paypal/message', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_configurator'] = $this->url->link('extension/payment/paypal/message_configurator', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_setting'] = $this->url->link('extension/payment/paypal/message_setting', 'user_token=' . $this->session->data['user_token'], true); $data['href_order_status'] = $this->url->link('extension/payment/paypal/order_status', 'user_token=' . $this->session->data['user_token'], true); $data['href_contact'] = $this->url->link('extension/payment/paypal/contact', 'user_token=' . $this->session->data['user_token'], true); @@ -562,7 +569,8 @@ public function button() { $data['href_googlepay_button'] = $this->url->link('extension/payment/paypal/googlepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_applepay_button'] = $this->url->link('extension/payment/paypal/applepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_card'] = $this->url->link('extension/payment/paypal/card', 'user_token=' . $this->session->data['user_token'], true); - $data['href_message'] = $this->url->link('extension/payment/paypal/message', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_configurator'] = $this->url->link('extension/payment/paypal/message_configurator', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_setting'] = $this->url->link('extension/payment/paypal/message_setting', 'user_token=' . $this->session->data['user_token'], true); $data['href_order_status'] = $this->url->link('extension/payment/paypal/order_status', 'user_token=' . $this->session->data['user_token'], true); $data['href_contact'] = $this->url->link('extension/payment/paypal/contact', 'user_token=' . $this->session->data['user_token'], true); @@ -713,7 +721,8 @@ public function googlepay_button() { $data['href_googlepay_button'] = $this->url->link('extension/payment/paypal/googlepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_applepay_button'] = $this->url->link('extension/payment/paypal/applepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_card'] = $this->url->link('extension/payment/paypal/card', 'user_token=' . $this->session->data['user_token'], true); - $data['href_message'] = $this->url->link('extension/payment/paypal/message', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_configurator'] = $this->url->link('extension/payment/paypal/message_configurator', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_setting'] = $this->url->link('extension/payment/paypal/message_setting', 'user_token=' . $this->session->data['user_token'], true); $data['href_order_status'] = $this->url->link('extension/payment/paypal/order_status', 'user_token=' . $this->session->data['user_token'], true); $data['href_contact'] = $this->url->link('extension/payment/paypal/contact', 'user_token=' . $this->session->data['user_token'], true); @@ -864,7 +873,8 @@ public function applepay_button() { $data['href_googlepay_button'] = $this->url->link('extension/payment/paypal/googlepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_applepay_button'] = $this->url->link('extension/payment/paypal/applepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_card'] = $this->url->link('extension/payment/paypal/card', 'user_token=' . $this->session->data['user_token'], true); - $data['href_message'] = $this->url->link('extension/payment/paypal/message', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_configurator'] = $this->url->link('extension/payment/paypal/message_configurator', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_setting'] = $this->url->link('extension/payment/paypal/message_setting', 'user_token=' . $this->session->data['user_token'], true); $data['href_order_status'] = $this->url->link('extension/payment/paypal/order_status', 'user_token=' . $this->session->data['user_token'], true); $data['href_contact'] = $this->url->link('extension/payment/paypal/contact', 'user_token=' . $this->session->data['user_token'], true); @@ -1017,7 +1027,8 @@ public function card() { $data['href_googlepay_button'] = $this->url->link('extension/payment/paypal/googlepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_applepay_button'] = $this->url->link('extension/payment/paypal/applepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_card'] = $this->url->link('extension/payment/paypal/card', 'user_token=' . $this->session->data['user_token'], true); - $data['href_message'] = $this->url->link('extension/payment/paypal/message', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_configurator'] = $this->url->link('extension/payment/paypal/message_configurator', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_setting'] = $this->url->link('extension/payment/paypal/message_setting', 'user_token=' . $this->session->data['user_token'], true); $data['href_order_status'] = $this->url->link('extension/payment/paypal/order_status', 'user_token=' . $this->session->data['user_token'], true); $data['href_contact'] = $this->url->link('extension/payment/paypal/contact', 'user_token=' . $this->session->data['user_token'], true); @@ -1125,8 +1136,8 @@ public function card() { $this->response->setOutput($this->load->view('extension/payment/paypal/card', $data)); } - - public function message() { + + public function message_configurator() { if (!$this->config->get('payment_paypal_client_id')) { $this->response->redirect($this->url->link('extension/payment/paypal', 'user_token=' . $this->session->data['user_token'], true)); } @@ -1140,8 +1151,161 @@ public function message() { $this->document->addScript('view/javascript/paypal/paypal.js'); $this->document->addScript('view/javascript/paypal/bootstrap-switch.js'); - $this->document->addScript('https://www.paypalobjects.com/merchant-library/merchant-configurator.js'); + //$this->document->addScript('https://www.paypalobjects.com/merchant-library/merchant-configurator.js'); + $this->document->addScript('https://www.paypalobjects.com/merchant-library/preview/merchant-configurator.js'); + + $this->document->setTitle($this->language->get('heading_title_main')); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_home'), + 'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'], true) + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_extensions'), + 'href' => $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=payment', true) + ); + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('heading_title_main'), + 'href' => $this->url->link('extension/payment/paypal', 'user_token=' . $this->session->data['user_token'], true) + ); + + // Action + $data['href_dashboard'] = $this->url->link('extension/payment/paypal/dashboard', 'user_token=' . $this->session->data['user_token'], true); + $data['href_general'] = $this->url->link('extension/payment/paypal/general', 'user_token=' . $this->session->data['user_token'], true); + $data['href_button'] = $this->url->link('extension/payment/paypal/button', 'user_token=' . $this->session->data['user_token'], true); + $data['href_googlepay_button'] = $this->url->link('extension/payment/paypal/googlepay_button', 'user_token=' . $this->session->data['user_token'], true); + $data['href_applepay_button'] = $this->url->link('extension/payment/paypal/applepay_button', 'user_token=' . $this->session->data['user_token'], true); + $data['href_card'] = $this->url->link('extension/payment/paypal/card', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_configurator'] = $this->url->link('extension/payment/paypal/message_configurator', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_setting'] = $this->url->link('extension/payment/paypal/message_setting', 'user_token=' . $this->session->data['user_token'], true); + $data['href_order_status'] = $this->url->link('extension/payment/paypal/order_status', 'user_token=' . $this->session->data['user_token'], true); + $data['href_contact'] = $this->url->link('extension/payment/paypal/contact', 'user_token=' . $this->session->data['user_token'], true); + + $data['action'] = $this->url->link('extension/payment/paypal/save', 'user_token=' . $this->session->data['user_token'], true); + $data['cancel'] = $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=payment', true); + $data['agree_url'] = str_replace('&', '&', $this->url->link('extension/payment/paypal/agree', 'user_token=' . $this->session->data['user_token'], true)); + + if (isset($this->request->server['HTTPS']) && (($this->request->server['HTTPS'] == 'on') || ($this->request->server['HTTPS'] == '1'))) { + $data['server'] = HTTPS_SERVER; + $data['catalog'] = HTTPS_CATALOG; + } else { + $data['server'] = HTTP_SERVER; + $data['catalog'] = HTTP_CATALOG; + } + + $_config = new Config(); + $_config->load('paypal'); + + $data['setting'] = $_config->get('paypal_setting'); + + $data['setting'] = array_replace_recursive((array)$data['setting'], (array)$this->config->get('payment_paypal_setting')); + + $data['client_id'] = $this->config->get('payment_paypal_client_id'); + $data['secret'] = $this->config->get('payment_paypal_secret'); + $data['merchant_id'] = $this->config->get('payment_paypal_merchant_id'); + $data['webhook_id'] = $this->config->get('payment_paypal_webhook_id'); + $data['environment'] = $this->config->get('payment_paypal_environment'); + $data['partner_client_id'] = $data['setting']['partner'][$data['environment']]['client_id']; + $data['partner_attribution_id'] = $data['setting']['partner'][$data['environment']]['partner_attribution_id']; + + $country = $this->model_extension_payment_paypal->getCountryByCode($data['setting']['general']['country_code']); + + $data['locale'] = preg_replace('/-(.+?)+/', '', $this->config->get('config_language')) . '_' . $country['iso_code_2']; + + $data['currency_code'] = $data['setting']['general']['currency_code']; + $data['currency_value'] = $data['setting']['general']['currency_value']; + + $data['decimal_place'] = $data['setting']['currency'][$data['currency_code']]['decimal_place']; + + if ($data['client_id'] && $data['secret']) { + require_once DIR_SYSTEM . 'library/paypal/paypal.php'; + + $paypal_info = array( + 'client_id' => $data['client_id'], + 'secret' => $data['secret'], + 'environment' => $data['environment'], + 'partner_attribution_id' => $data['setting']['partner'][$data['environment']]['partner_attribution_id'] + ); + + $paypal = new PayPal($paypal_info); + + $token_info = array( + 'grant_type' => 'client_credentials' + ); + + $paypal->setAccessToken($token_info); + + $data['client_token'] = $paypal->getClientToken(); + + if ($paypal->hasErrors()) { + $error_messages = array(); + + $errors = $paypal->getErrors(); + + foreach ($errors as $error) { + if (isset($error['name']) && ($error['name'] == 'CURLE_OPERATION_TIMEOUTED')) { + $error['message'] = $this->language->get('error_timeout'); + } + + if (isset($error['details'][0]['description'])) { + $error_messages[] = $error['details'][0]['description']; + } elseif (isset($error['message'])) { + $error_messages[] = $error['message']; + } + + $this->model_extension_payment_paypal->log($error, $error['message']); + } + + $this->error['warning'] = implode(' ', $error_messages); + } + } + + $result = $this->model_extension_payment_paypal->checkVersion(VERSION, $data['setting']['version']); + + if (!empty($result['href'])) { + $data['text_version'] = sprintf($this->language->get('text_version'), $result['href']); + } else { + $data['text_version'] = ''; + } + + $agree_status = $this->model_extension_payment_paypal->getAgreeStatus(); + + if (!$agree_status) { + $this->error['warning'] = $this->language->get('error_agree'); + } + + if (isset($this->error['warning'])) { + $data['error_warning'] = $this->error['warning']; + } else { + $data['error_warning'] = ''; + } + + $data['header'] = $this->load->controller('common/header'); + $data['column_left'] = $this->load->controller('common/column_left'); + $data['footer'] = $this->load->controller('common/footer'); + + $this->response->setOutput($this->load->view('extension/payment/paypal/message_configurator', $data)); + } + + public function message_setting() { + if (!$this->config->get('payment_paypal_client_id')) { + $this->response->redirect($this->url->link('extension/payment/paypal', 'user_token=' . $this->session->data['user_token'], true)); + } + + $this->load->language('extension/payment/paypal'); + + $this->load->model('extension/payment/paypal'); + + $this->document->addStyle('view/stylesheet/paypal/paypal.css'); + $this->document->addStyle('view/stylesheet/paypal/bootstrap-switch.css'); + + $this->document->addScript('view/javascript/paypal/paypal.js'); + $this->document->addScript('view/javascript/paypal/bootstrap-switch.js'); + $this->document->setTitle($this->language->get('heading_title_main')); $data['breadcrumbs'] = array(); @@ -1168,7 +1332,8 @@ public function message() { $data['href_googlepay_button'] = $this->url->link('extension/payment/paypal/googlepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_applepay_button'] = $this->url->link('extension/payment/paypal/applepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_card'] = $this->url->link('extension/payment/paypal/card', 'user_token=' . $this->session->data['user_token'], true); - $data['href_message'] = $this->url->link('extension/payment/paypal/message', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_configurator'] = $this->url->link('extension/payment/paypal/message_configurator', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_setting'] = $this->url->link('extension/payment/paypal/message_setting', 'user_token=' . $this->session->data['user_token'], true); $data['href_order_status'] = $this->url->link('extension/payment/paypal/order_status', 'user_token=' . $this->session->data['user_token'], true); $data['href_contact'] = $this->url->link('extension/payment/paypal/contact', 'user_token=' . $this->session->data['user_token'], true); @@ -1283,7 +1448,7 @@ public function message() { $data['column_left'] = $this->load->controller('common/column_left'); $data['footer'] = $this->load->controller('common/footer'); - $this->response->setOutput($this->load->view('extension/payment/paypal/message', $data)); + $this->response->setOutput($this->load->view('extension/payment/paypal/message_setting', $data)); } public function order_status() { @@ -1323,7 +1488,8 @@ public function order_status() { $data['href_googlepay_button'] = $this->url->link('extension/payment/paypal/googlepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_applepay_button'] = $this->url->link('extension/payment/paypal/applepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_card'] = $this->url->link('extension/payment/paypal/card', 'user_token=' . $this->session->data['user_token'], true); - $data['href_message'] = $this->url->link('extension/payment/paypal/message', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_configurator'] = $this->url->link('extension/payment/paypal/message_configurator', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_setting'] = $this->url->link('extension/payment/paypal/message_setting', 'user_token=' . $this->session->data['user_token'], true); $data['href_order_status'] = $this->url->link('extension/payment/paypal/order_status', 'user_token=' . $this->session->data['user_token'], true); $data['href_contact'] = $this->url->link('extension/payment/paypal/contact', 'user_token=' . $this->session->data['user_token'], true); @@ -1414,7 +1580,8 @@ public function contact() { $data['href_googlepay_button'] = $this->url->link('extension/payment/paypal/googlepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_applepay_button'] = $this->url->link('extension/payment/paypal/applepay_button', 'user_token=' . $this->session->data['user_token'], true); $data['href_card'] = $this->url->link('extension/payment/paypal/card', 'user_token=' . $this->session->data['user_token'], true); - $data['href_message'] = $this->url->link('extension/payment/paypal/message', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_configurator'] = $this->url->link('extension/payment/paypal/message_configurator', 'user_token=' . $this->session->data['user_token'], true); + $data['href_message_setting'] = $this->url->link('extension/payment/paypal/message_setting', 'user_token=' . $this->session->data['user_token'], true); $data['href_order_status'] = $this->url->link('extension/payment/paypal/order_status', 'user_token=' . $this->session->data['user_token'], true); $data['href_contact'] = $this->url->link('extension/payment/paypal/contact', 'user_token=' . $this->session->data['user_token'], true); @@ -1510,10 +1677,12 @@ public function disconnect() { public function callback() { if (isset($this->request->post['environment']) && isset($this->request->post['authorization_code']) && isset($this->request->post['shared_id']) && isset($this->request->post['seller_nonce'])) { - $this->session->data['environment'] = $this->request->post['environment']; - $this->session->data['authorization_code'] = $this->request->post['authorization_code']; - $this->session->data['shared_id'] = $this->request->post['shared_id']; - $this->session->data['seller_nonce'] = $this->request->post['seller_nonce']; + $cache_data['environment'] = $this->request->post['environment']; + $cache_data['authorization_code'] = $this->request->post['authorization_code']; + $cache_data['shared_id'] = $this->request->post['shared_id']; + $cache_data['seller_nonce'] = $this->request->post['seller_nonce']; + + $this->cache->set('paypal', $cache_data, 30); } $data['error'] = $this->error; @@ -1719,11 +1888,13 @@ public function install() { $this->model_setting_event->deleteEventByCode('paypal_header'); $this->model_setting_event->deleteEventByCode('paypal_extension_get_extensions'); $this->model_setting_event->deleteEventByCode('paypal_order_delete_order'); + $this->model_setting_event->deleteEventByCode('paypal_customer_delete_customer'); $this->model_setting_event->addEvent('paypal_order_info', 'admin/view/sale/order_info/before', 'extension/payment/paypal/order_info_before'); $this->model_setting_event->addEvent('paypal_header', 'catalog/controller/common/header/before', 'extension/payment/paypal/header_before'); $this->model_setting_event->addEvent('paypal_extension_get_extensions', 'catalog/model/setting/extension/getExtensions/after', 'extension/payment/paypal/extension_get_extensions_after'); $this->model_setting_event->addEvent('paypal_order_delete_order', 'catalog/model/checkout/order/deleteOrder/before', 'extension/payment/paypal/order_delete_order_before'); + $this->model_setting_event->addEvent('paypal_customer_delete_customer', 'admin/model/customer/customer/deleteCustomer/before', 'extension/payment/paypal/customer_delete_customer_before'); $_config = new Config(); $_config->load('paypal'); @@ -1748,19 +1919,28 @@ public function uninstall() { $this->model_setting_event->deleteEventByCode('paypal_header'); $this->model_setting_event->deleteEventByCode('paypal_extension_get_extensions'); $this->model_setting_event->deleteEventByCode('paypal_order_delete_order'); + $this->model_setting_event->deleteEventByCode('paypal_customer_delete_customer'); $this->load->model('setting/setting'); $this->model_setting_setting->deleteSetting('paypal_version'); } + public function customer_delete_customer_before($route, &$data) { + $this->load->model('extension/payment/paypal'); + + $customer_id = $data[0]; + + $this->model_extension_payment_paypal->deletePayPalCustomerTokens($customer_id); + } + public function order_info_before($route, &$data) { if ($this->config->get('payment_paypal_status') && !empty($this->request->get['order_id'])) { $this->load->language('extension/payment/paypal'); $this->load->model('extension/payment/paypal'); - $data['order_id'] = (int)$this->request->get['order_id']; + $data['order_id'] = $this->request->get['order_id']; $paypal_order_info = $this->model_extension_payment_paypal->getPayPalOrder($data['order_id']); @@ -1788,7 +1968,7 @@ public function order_info_before($route, &$data) { } } } - + public function getPaymentInfo() { $content = ''; @@ -1797,7 +1977,7 @@ public function getPaymentInfo() { $this->load->model('extension/payment/paypal'); - $data['order_id'] = (int)$this->request->get['order_id']; + $data['order_id'] = $this->request->get['order_id']; $paypal_order_info = $this->model_extension_payment_paypal->getPayPalOrder($data['order_id']); @@ -2262,4 +2442,4 @@ private function token($length = 32) { return $token; } -} +} \ No newline at end of file diff --git a/upload/admin/language/en-gb/extension/payment/paypal.php b/upload/admin/language/en-gb/extension/payment/paypal.php index 3a1522d47d2..4af76d8ed34 100644 --- a/upload/admin/language/en-gb/extension/payment/paypal.php +++ b/upload/admin/language/en-gb/extension/payment/paypal.php @@ -17,7 +17,8 @@ $_['text_tab_googlepay_button'] = 'Google Pay'; $_['text_tab_applepay_button'] = 'Apple Pay'; $_['text_tab_card'] = 'Advanced Cards'; -$_['text_tab_message'] = 'Pay Later messaging'; +$_['text_tab_message_configurator'] = 'Pay Later Messaging'; +$_['text_tab_message_setting'] = 'Pay Later Message placement'; $_['text_tab_order_status'] = 'Order Statuses'; $_['text_tab_contact'] = 'Contact PayPal'; $_['text_all_sales'] = 'All Sales'; @@ -126,7 +127,6 @@ $_['text_mybank'] = 'MyBank'; $_['text_p24'] = 'Przelewy24'; $_['text_sepa'] = 'SEPA-Lastschrift'; -$_['text_sofort'] = 'Sofort'; $_['text_venmo'] = 'Venmo'; $_['text_paylater'] = 'Pay Later'; $_['text_auto'] = 'Auto'; @@ -134,6 +134,8 @@ $_['text_flex'] = 'Flexible Banner'; $_['text_accept'] = 'Accept'; $_['text_decline'] = 'Decline'; +$_['text_sca_when_required'] = 'SCA When Required'; +$_['text_sca_always'] = 'SCA Always'; $_['text_recommended'] = '(recommended)'; $_['text_3ds_failed_authentication'] = 'Failed authentication.'; $_['text_3ds_rejected_authentication'] = 'Rejected authentication.'; @@ -236,20 +238,13 @@ $_['entry_applepay_button_type'] = 'Button Type'; $_['entry_card_align'] = 'Card Align'; $_['entry_card_size'] = 'Card Size'; -$_['entry_card_secure_status'] = 'Card 3D Secure Status'; +$_['entry_card_secure_method'] = 'Card 3D Secure Method'; $_['entry_card_secure_scenario'] = 'Card 3D Secure Scenarios'; $_['entry_card_number'] = 'Card Number'; $_['entry_expiration_date'] = 'Expiration Date'; $_['entry_cvv'] = 'CVV'; $_['entry_message_insert_tag'] = 'Message Insert Tag'; $_['entry_message_insert_type'] = 'Message Insert Type'; -$_['entry_message_align'] = 'Message Align'; -$_['entry_message_size'] = 'Message Size'; -$_['entry_message_layout'] = 'Message Layout'; -$_['entry_message_text_color'] = 'Message Text Color'; -$_['entry_message_text_size'] = 'Message Text Size'; -$_['entry_message_flex_color'] = 'Message Banner Color'; -$_['entry_message_flex_ratio'] = 'Message Banner Ratio'; $_['entry_contact_company'] = 'Company'; $_['entry_contact_first_name'] = 'First Name'; $_['entry_contact_last_name'] = 'Last Name'; @@ -270,7 +265,6 @@ $_['help_googlepay_button_status'] = 'PayPal verifies if you are eligible for Google Pay payment and will display this option on the checkout step if available.'; $_['help_applepay_button_status'] = 'PayPal verifies if you are eligible for Apple Pay payment and will display this option on the checkout step if available.'; $_['help_card_status'] = 'PayPal verifies if you are eligible for advanced card payment and will display this option on the checkout step if available.'; -$_['help_message_status'] = 'Add pay later messaging to your site.'; $_['help_checkout_mode'] = 'If your checkout is incompatible with this payment, then we advise you to set the \'One Button\' mode.'; $_['help_total'] = 'The checkout total the order must reach before this payment method becomes active.'; $_['help_country_code'] = 'Select the default country for PayPal.'; @@ -279,7 +273,7 @@ $_['help_card_currency_code'] = 'Select the default currency for PayPal Card.'; $_['help_card_currency_value'] = 'Set to 1.00000 if this is your default currency.'; $_['help_cron_url'] = 'Set a cron to call this URL.'; -$_['help_card_secure_status'] = '3D Secure enables you to authenticate card holders through card issuers. It reduces the likelihood of fraud when you use supported cards and improves transaction perfomance. A successful 3D Secure authentication can shift liability for chargebacks due to fraud from you -the merchant- to the card issuer.'; +$_['help_card_secure_method'] = '3D Secure enables you to authenticate card holders through card issuers. \'SCA Always\' method trigger 3D Secure for every transaction, regardless of SCA requirements. \'SCA When Required\' method returns a 3D Secure contingency when it is a mandate in the region where you operate.'; $_['help_card_secure_scenario'] = '3D Secure authentication is perfomed only if the card is enrolled for the service. In scenarios where the 3D Secure authentication has not been successful, you have the option to complete the payment at your own risk, meaning that you -the merchant- will be liable in case of a chargeback.'; // Button diff --git a/upload/admin/model/extension/payment/paypal.php b/upload/admin/model/extension/payment/paypal.php index a1eb2d89cee..272598fcf5f 100644 --- a/upload/admin/model/extension/payment/paypal.php +++ b/upload/admin/model/extension/payment/paypal.php @@ -144,12 +144,20 @@ public function getCountryByCode($code) { return $query->row; } + + public function deletePayPalCustomerTokens($customer_id) { + $query = $this->db->query("DELETE FROM `" . DB_PREFIX . "paypal_checkout_integration_customer_token` WHERE `customer_id` = '" . (int)$customer_id . "'"); + } public function editPayPalOrder($data) { $sql = "UPDATE `" . DB_PREFIX . "paypal_checkout_integration_order` SET"; $implode = array(); + if (!empty($data['paypal_order_id'])) { + $implode[] = "`paypal_order_id` = '" . $this->db->escape($data['paypal_order_id']) . "'"; + } + if (!empty($data['transaction_id'])) { $implode[] = "`transaction_id` = '" . $this->db->escape($data['transaction_id']) . "'"; } @@ -170,6 +178,22 @@ public function editPayPalOrder($data) { $implode[] = "`vault_customer_id` = '" . $this->db->escape($data['vault_customer_id']) . "'"; } + if (!empty($data['card_type'])) { + $implode[] = "`card_type` = '" . $this->db->escape($data['card_type']) . "'"; + } + + if (!empty($data['card_nice_type'])) { + $implode[] = "`card_nice_type` = '" . $this->db->escape($data['card_nice_type']) . "'"; + } + + if (!empty($data['card_last_digits'])) { + $implode[] = "`card_last_digits` = '" . $this->db->escape($data['card_last_digits']) . "'"; + } + + if (!empty($data['card_expiry'])) { + $implode[] = "`card_expiry` = '" . $this->db->escape($data['card_expiry']) . "'"; + } + if (!empty($data['environment'])) { $implode[] = "`environment` = '" . $this->db->escape($data['environment']) . "'"; } @@ -200,7 +224,7 @@ public function getPayPalOrder($order_id) { public function editOrderRecurringStatus($order_recurring_id, $status) { $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = '" . (int)$status . "' WHERE `order_recurring_id` = '" . (int)$order_recurring_id . "'"); } - + public function setAgreeStatus() { $this->db->query("UPDATE " . DB_PREFIX . "country SET status = '0' WHERE (iso_code_2 = 'CU' OR iso_code_2 = 'IR' OR iso_code_2 = 'SY' OR iso_code_2 = 'KP')"); $this->db->query("UPDATE " . DB_PREFIX . "zone SET status = '0' WHERE country_id = '220' AND (`code` = '43' OR `code` = '14' OR `code` = '09')"); @@ -282,11 +306,13 @@ public function log($data, $title = null) { } public function install() { - $this->db->query("CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "paypal_checkout_integration_order` (`order_id` INT(11) NOT NULL, `transaction_id` VARCHAR(20) NOT NULL, `transaction_status` VARCHAR(20) NULL, `payment_method` VARCHAR(20) NULL, `vault_id` VARCHAR(50) NULL, `vault_customer_id` VARCHAR(50) NULL, `environment` VARCHAR(20) NULL, PRIMARY KEY (`order_id`, `transaction_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci"); + $this->db->query("CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "paypal_checkout_integration_customer_token` (`customer_id` INT(11) NOT NULL, `payment_method` VARCHAR(20) NOT NULL, `vault_id` VARCHAR(50) NOT NULL, `vault_customer_id` VARCHAR(50) NOT NULL, `card_type` VARCHAR(40) NOT NULL, `card_nice_type` VARCHAR(40) NOT NULL, `card_last_digits` VARCHAR(4) NOT NULL, `card_expiry` VARCHAR(20) NOT NULL, `main_token_status` TINYINT(1) NOT NULL, PRIMARY KEY (`customer_id`, `payment_method`, `vault_id`), KEY `vault_customer_id` (`vault_customer_id`), KEY `main_token_status` (`main_token_status`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci"); + $this->db->query("CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "paypal_checkout_integration_order` (`order_id` INT(11) NOT NULL, `paypal_order_id` VARCHAR(20) NOT NULL, `transaction_id` VARCHAR(20) NOT NULL, `transaction_status` VARCHAR(20) NOT NULL, `payment_method` VARCHAR(20) NOT NULL, `vault_id` VARCHAR(50) NOT NULL, `vault_customer_id` VARCHAR(50) NOT NULL, `card_type` VARCHAR(40) NOT NULL, `card_nice_type` VARCHAR(40) NOT NULL, `card_last_digits` VARCHAR(4) NOT NULL, `card_expiry` VARCHAR(20) NOT NULL, `environment` VARCHAR(20) NOT NULL, PRIMARY KEY (`order_id`), KEY `paypal_order_id` (`paypal_order_id`), KEY `transaction_id` (`transaction_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci"); $this->db->query("CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "paypal_checkout_integration_order_recurring` (`paypal_order_recurring_id` INT(11) NOT NULL AUTO_INCREMENT, `order_id` INT(11) NOT NULL, `order_recurring_id` INT(11) NOT NULL, `date_added` DATETIME NOT NULL, `date_modified` DATETIME NOT NULL, `next_payment` DATETIME NOT NULL, `trial_end` DATETIME DEFAULT NULL, `subscription_end` DATETIME DEFAULT NULL, `currency_code` CHAR(3) NOT NULL, `total` DECIMAL(10, 2) NOT NULL, PRIMARY KEY (`paypal_order_recurring_id`), KEY (`order_id`), KEY (`order_recurring_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci"); } public function uninstall() { + $this->db->query("DROP TABLE IF EXISTS `" . DB_PREFIX . "paypal_checkout_integration_customer_token`"); $this->db->query("DROP TABLE IF EXISTS `" . DB_PREFIX . "paypal_checkout_integration_order`"); $this->db->query("DROP TABLE IF EXISTS `" . DB_PREFIX . "paypal_checkout_integration_order_recurring`"); } diff --git a/upload/admin/view/stylesheet/paypal/paypal.css b/upload/admin/view/stylesheet/paypal/paypal.css index 5b109abac13..24884e8a8fa 100644 --- a/upload/admin/view/stylesheet/paypal/paypal.css +++ b/upload/admin/view/stylesheet/paypal/paypal.css @@ -357,9 +357,13 @@ width: 33px; background-image: url('../../image/payment/paypal/icon-card.svg'); } -.payment-paypal .panel-default .tab .tab-icon-message { +.payment-paypal .panel-default .tab .tab-icon-message-setting { width: 37px; - background-image: url('../../image/payment/paypal/icon-message.svg'); + background-image: url('../../image/payment/paypal/icon-message-setting.svg'); +} +.payment-paypal .panel-default .tab .tab-icon-message-configurator { + width: 37px; + background-image: url('../../image/payment/paypal/icon-message-configurator.svg'); } .payment-paypal .panel-default .tab .tab-icon-order-status { width: 28px; @@ -656,10 +660,37 @@ background-size: contain; background-repeat: no-repeat; } +.payment-paypal .panel-default #messaging-configurator * { + font-size: 13px; + line-height: 1.4; + -webkit-box-sizing: revert; + -moz-box-sizing: revert; + box-sizing: revert; +} +.payment-paypal .panel-default #messaging-configurator > div { + margin: 0 !important; + justify-content: flex-start !important; +} +.payment-paypal .panel-default #configurator-eligibleContainer{ + width: 100% !important; + max-width: 110rem !important; + padding: 0 !important; +} +.payment-paypal .panel-default #messaging-configurator .headerOverride { + font-size: 15px; + font-weight: 700; + color: #000000; +} +.payment-paypal .panel-default #messaging-configurator .buttonOverride { + display: none; +} .payment-paypal .panel-default #messaging-configurator input { position: absolute; } -.payment-paypal .panel-default #messaging-configurator .css-15yf9ku { +.payment-paypal .panel-default #messaging-configurator [accordionname] button:not([id^="dropdownMenuButton"]) { + padding: 8px 16px 16px 16px; +} +.payment-paypal .card #messaging-configurator #configurator-previewSectionContainer > div + div { height: auto; } @media (max-width: 767px) { @@ -870,6 +901,11 @@ .payment-paypal .panel-dashboard .col { padding: 0px 7px; } +@media (min-width: 1200px) { + .payment-paypal .panel-dashboard .col-tab { + width: 20%; + } +} .payment-paypal .panel-dashboard .paypal-sale { padding: 11px 0px; } @@ -893,7 +929,7 @@ .payment-paypal .panel-dashboard .tab { position: relative; display: block; - padding: 37px 7px 30px 7px; + padding: 37px 10px 30px 10px; text-align: center; background: #FFFFFF; box-shadow: 0px 2px 6px #00000029; diff --git a/upload/admin/view/template/extension/payment/paypal/applepay_button.twig b/upload/admin/view/template/extension/payment/paypal/applepay_button.twig index 89b9170f078..cc7159e7992 100644 --- a/upload/admin/view/template/extension/payment/paypal/applepay_button.twig +++ b/upload/admin/view/template/extension/payment/paypal/applepay_button.twig @@ -34,7 +34,8 @@ - + + diff --git a/upload/admin/view/template/extension/payment/paypal/button.twig b/upload/admin/view/template/extension/payment/paypal/button.twig index d6cbc5c7a08..7370af441da 100644 --- a/upload/admin/view/template/extension/payment/paypal/button.twig +++ b/upload/admin/view/template/extension/payment/paypal/button.twig @@ -34,7 +34,8 @@ - + + diff --git a/upload/admin/view/template/extension/payment/paypal/card.twig b/upload/admin/view/template/extension/payment/paypal/card.twig index 042bbf35caa..421434f99ce 100644 --- a/upload/admin/view/template/extension/payment/paypal/card.twig +++ b/upload/admin/view/template/extension/payment/paypal/card.twig @@ -34,7 +34,8 @@ - + + @@ -125,11 +126,16 @@
- -
- - -
+ +

diff --git a/upload/admin/view/template/extension/payment/paypal/contact.twig b/upload/admin/view/template/extension/payment/paypal/contact.twig index 0e422f8482c..d5d196b1730 100644 --- a/upload/admin/view/template/extension/payment/paypal/contact.twig +++ b/upload/admin/view/template/extension/payment/paypal/contact.twig @@ -34,7 +34,8 @@ - + + diff --git a/upload/admin/view/template/extension/payment/paypal/dashboard.twig b/upload/admin/view/template/extension/payment/paypal/dashboard.twig index e0398f778e7..b0eb44aac29 100644 --- a/upload/admin/view/template/extension/payment/paypal/dashboard.twig +++ b/upload/admin/view/template/extension/payment/paypal/dashboard.twig @@ -78,10 +78,17 @@
- + - - {{ text_tab_message }} + + {{ text_tab_message_configurator }} + +
+
+ + + + {{ text_tab_message_setting }}
diff --git a/upload/admin/view/template/extension/payment/paypal/general.twig b/upload/admin/view/template/extension/payment/paypal/general.twig index bb7d38d16db..e2808bf301c 100644 --- a/upload/admin/view/template/extension/payment/paypal/general.twig +++ b/upload/admin/view/template/extension/payment/paypal/general.twig @@ -34,7 +34,8 @@ - + + diff --git a/upload/admin/view/template/extension/payment/paypal/googlepay_button.twig b/upload/admin/view/template/extension/payment/paypal/googlepay_button.twig index 098d2a6a543..60b8f1c3dec 100644 --- a/upload/admin/view/template/extension/payment/paypal/googlepay_button.twig +++ b/upload/admin/view/template/extension/payment/paypal/googlepay_button.twig @@ -34,7 +34,8 @@ - + + diff --git a/upload/admin/view/template/extension/payment/paypal/order_status.twig b/upload/admin/view/template/extension/payment/paypal/order_status.twig index 6f1ed8ab4af..2fda3d8c3ab 100644 --- a/upload/admin/view/template/extension/payment/paypal/order_status.twig +++ b/upload/admin/view/template/extension/payment/paypal/order_status.twig @@ -34,7 +34,8 @@ - + + diff --git a/upload/catalog/controller/extension/payment/paypal.php b/upload/catalog/controller/extension/payment/paypal.php index ddae8b02f28..9db0a2c75f8 100644 --- a/upload/catalog/controller/extension/payment/paypal.php +++ b/upload/catalog/controller/extension/payment/paypal.php @@ -10,7 +10,7 @@ public function __construct($registry) { ini_set('serialize_precision', 14); } - if (empty($this->config->get('paypal_version')) || (!empty($this->config->get('paypal_version')) && ($this->config->get('paypal_version') < '2.2.0'))) { + if (empty($this->config->get('paypal_version')) || (!empty($this->config->get('paypal_version')) && ($this->config->get('paypal_version') < '3.0.0'))) { $this->update(); } } @@ -20,7 +20,7 @@ public function index() { $agree_status = $this->model_extension_payment_paypal->getAgreeStatus(); - if ($this->config->get('payment_paypal_status') && $this->config->get('payment_paypal_client_id') && $this->config->get('payment_paypal_secret') && !$this->webhook() && !$this->cron() && $agree_status) { + if ($this->config->get('payment_paypal_status') && $this->config->get('payment_paypal_client_id') && $this->config->get('payment_paypal_secret') && !$this->callback() && !$this->webhook() && !$this->cron() && $agree_status) { $this->load->language('extension/payment/paypal'); $_config = new Config(); @@ -43,6 +43,8 @@ public function index() { $data['googlepay_button_status'] = $setting['googlepay_button']['status']; $data['applepay_button_status'] = $setting['applepay_button']['status']; $data['card_status'] = $setting['card']['status']; + + $data['logged'] = $this->customer->isLogged(); require_once DIR_SYSTEM .'library/paypal/paypal.php'; @@ -219,9 +221,6 @@ public function getData() { $data['message_status'] = $setting['message']['home']['status']; $data['message_insert_tag'] = html_entity_decode($setting['message']['home']['insert_tag']); $data['message_insert_type'] = $setting['message']['home']['insert_type']; - $data['message_align'] = $setting['message']['home']['align']; - $data['message_size'] = $setting['message']['home']['size']; - $data['message_width'] = $setting['message_width'][$data['message_size']]; $data['message_layout'] = $setting['message']['home']['layout']; $data['message_logo_type'] = $setting['message']['home']['logo_type']; $data['message_logo_position'] = $setting['message']['home']['logo_position']; @@ -268,9 +267,6 @@ public function getData() { $data['message_status'] = $setting['message']['product']['status']; $data['message_insert_tag'] = html_entity_decode($setting['message']['product']['insert_tag']); $data['message_insert_type'] = $setting['message']['product']['insert_type']; - $data['message_align'] = $setting['message']['product']['align']; - $data['message_size'] = $setting['message']['product']['size']; - $data['message_width'] = $setting['message_width'][$data['message_size']]; $data['message_layout'] = $setting['message']['product']['layout']; $data['message_logo_type'] = $setting['message']['product']['logo_type']; $data['message_logo_position'] = $setting['message']['product']['logo_position']; @@ -319,9 +315,6 @@ public function getData() { $data['message_status'] = $setting['message']['cart']['status']; $data['message_insert_tag'] = html_entity_decode($setting['message']['cart']['insert_tag']); $data['message_insert_type'] = $setting['message']['cart']['insert_type']; - $data['message_align'] = $setting['message']['cart']['align']; - $data['message_size'] = $setting['message']['cart']['size']; - $data['message_width'] = $setting['message_width'][$data['message_size']]; $data['message_layout'] = $setting['message']['cart']['layout']; $data['message_logo_type'] = $setting['message']['cart']['logo_type']; $data['message_logo_position'] = $setting['message']['cart']['logo_position']; @@ -445,20 +438,30 @@ public function getData() { } if ($setting['card']['status']) { - $data['components'][] = 'hosted-fields'; + $data['components'][] = 'card-fields'; $data['card_status'] = $setting['card']['status']; $data['card_align'] = $setting['card']['align']; $data['card_size'] = $setting['card']['size']; $data['card_width'] = $setting['card_width'][$data['card_size']]; - $data['card_secure_status'] = $setting['card']['secure_status']; + + $data['card_customer_tokens'] = array(); + + if ($this->customer->isLogged()) { + $card_customer_tokens = $this->model_extension_payment_paypal->getPayPalCustomerTokens($this->customer->getId(), 'card'); + + foreach ($card_customer_tokens as $card_customer_token) { + $data['card_customer_tokens'][] = array( + 'vault_id' => $card_customer_token['vault_id'], + 'card_type' => $card_customer_token['card_type'], + 'card_number' => sprintf($this->language->get('text_card_number'), $card_customer_token['card_nice_type'], $card_customer_token['card_last_digits']) + ); + } + } } if ($setting['message']['checkout']['status'] && ($data['currency_code'] == $setting['general']['currency_code'])) { $data['components'][] = 'messages'; $data['message_status'] = $setting['message']['checkout']['status']; - $data['message_align'] = $setting['message']['checkout']['align']; - $data['message_size'] = $setting['message']['checkout']['size']; - $data['message_width'] = $setting['message_width'][$data['message_size']]; $data['message_layout'] = $setting['message']['checkout']['layout']; $data['message_logo_type'] = $setting['message']['checkout']['logo_type']; $data['message_logo_position'] = $setting['message']['checkout']['logo_position']; @@ -502,10 +505,23 @@ public function getData() { $paypal = new PayPal($paypal_info); $token_info = array( - 'grant_type' => 'client_credentials' - ); + 'grant_type' => 'client_credentials', + ); + + if ($this->customer->isLogged()) { + $paypal_customer_token = $this->model_extension_payment_paypal->getPayPalCustomerMainToken($this->customer->getId(), 'paypal'); - $paypal->setAccessToken($token_info); + if (!empty($paypal_customer_token['vault_customer_id'])) { + $token_info['response_type'] = 'id_token'; + $token_info['target_customer_id'] = $paypal_customer_token['vault_customer_id']; + } + } + + $result = $paypal->setAccessToken($token_info); + + if (!empty($result['id_token'])) { + $data['id_token'] = $result['id_token']; + } $data['client_token'] = $paypal->getClientToken(); @@ -551,9 +567,20 @@ public function createOrder() { $page_code = $this->request->post['page_code']; $payment_type = $this->request->post['payment_type']; + $payment_method = ''; + + if ($payment_type == 'button') { + $payment_method = 'paypal'; + } + + if ($payment_type == 'card') { + $payment_method = 'card'; + } + $errors = array(); - $data['order_id'] = ''; + $data['paypal_order_id'] = ''; + $data['url'] = ''; if (!empty($this->request->post['product'])) { $this->request->post['product'] = $this->unserialize($this->request->post['product']); @@ -825,31 +852,59 @@ public function createOrder() { $paypal_order_info['application_context']['shipping_preference'] = $shipping_preference; - if ($this->cart->hasRecurringProducts()) { - $payment_method = ''; - - if ($payment_type == 'button') { - $payment_method = 'paypal'; - } - - if ($payment_type == 'card') { - $payment_method = 'card'; + if ($this->customer->isLogged() || $this->cart->hasRecurringProducts()) { + if ($payment_method == 'paypal') { + $paypal_customer_token = array(); + + if ($this->customer->isLogged()) { + $paypal_customer_token = $this->model_extension_payment_paypal->getPayPalCustomerMainToken($this->customer->getId(), $payment_method); + } + + if (empty($paypal_customer_token['vault_id'])) { + $paypal_order_info['payment_source'][$payment_method]['attributes']['vault'] = array( + 'permit_multiple_payment_tokens' => 'false', + 'store_in_vault' => 'ON_SUCCESS', + 'usage_type' => 'MERCHANT', + 'customer_type' => 'CONSUMER' + ); + } + + $paypal_order_info['payment_source'][$payment_method]['experience_context']['return_url'] = $this->url->link('extension/payment/paypal', 'callback_token=' . $setting['general']['callback_token'], true); + $paypal_order_info['payment_source'][$payment_method]['experience_context']['cancel_url'] = $this->url->link('checkout/checkout', '', true); } - if ($payment_method) { - $paypal_order_info['payment_source'][$payment_method]['attributes']['vault'] = array( - 'store_in_vault' => 'ON_SUCCESS', - 'usage_type' => 'MERCHANT', - 'customer_type' => 'CONSUMER' - ); - - $paypal_order_info['payment_source']['paypal']['experience_context'] = array( - 'return_url' => $this->url->link('checkout/success', '', true), - 'cancel_url' => $this->url->link('checkout/success', '', true) - ); + if ($payment_method == 'card') { + if (isset($this->request->post['index'])) { + $card_token_index = $this->request->post['index']; + + $card_customer_tokens = $this->model_extension_payment_paypal->getPayPalCustomerTokens($this->customer->getId(), $payment_method); + + if (!empty($card_customer_tokens[$card_token_index]['vault_id'])) { + $paypal_order_info['payment_source'][$payment_method]['vault_id'] = $card_customer_tokens[$card_token_index]['vault_id']; + $paypal_order_info['payment_source'][$payment_method]['stored_credential']['payment_initiator'] = 'CUSTOMER'; + $paypal_order_info['payment_source'][$payment_method]['stored_credential']['payment_type'] = 'ONE_TIME'; + $paypal_order_info['payment_source'][$payment_method]['stored_credential']['usage'] = 'SUBSEQUENT'; + } + } else { + if (!empty($this->request->post['card_save']) || $this->cart->hasRecurringProducts()) { + $paypal_order_info['payment_source'][$payment_method]['attributes']['vault']['store_in_vault'] = 'ON_SUCCESS'; + $paypal_order_info['payment_source'][$payment_method]['stored_credential']['payment_initiator'] = 'CUSTOMER'; + $paypal_order_info['payment_source'][$payment_method]['stored_credential']['usage'] = 'FIRST'; + + if ($this->cart->hasRecurringProducts()) { + $paypal_order_info['payment_source'][$payment_method]['stored_credential']['payment_type'] = 'UNSCHEDULED'; + } else { + $paypal_order_info['payment_source'][$payment_method]['stored_credential']['payment_type'] = 'ONE_TIME'; + } + } + } } } + $paypal_order_info['payment_source'][$payment_method]['attributes']['verification']['method'] = strtoupper($setting['card']['secure_method']); + $paypal_order_info['payment_source'][$payment_method]['experience_context']['return_url'] = $this->url->link('extension/payment/paypal', 'callback_token=' . $setting['general']['callback_token'], true); + $paypal_order_info['payment_source'][$payment_method]['experience_context']['cancel_url'] = $this->url->link('checkout/checkout', '', true); + $result = $paypal->createOrder($paypal_order_info); if ($paypal->hasErrors()) { @@ -877,19 +932,32 @@ public function createOrder() { if (!empty($this->error['warning'])) { $this->error['warning'] .= ' ' . sprintf($this->language->get('error_payment'), $this->url->link('information/contact', '', true)); } - - $data['paypal_order_id'] = ''; - + if (isset($result['id']) && isset($result['status']) && !$this->error) { $this->model_extension_payment_paypal->log($result, 'Create Order'); - + if ($result['status'] == 'VOIDED') { $this->error['warning'] = sprintf($this->language->get('error_order_voided'), $this->url->link('information/contact', '', true)); } - - if ($result['status'] == 'COMPLETED') { + + if (($result['status'] == 'COMPLETED') && empty($paypal_order_info['payment_source']['card']['vault_id'])) { $this->error['warning'] = sprintf($this->language->get('error_order_completed'), $this->url->link('information/contact', '', true)); } + + if (($result['status'] == 'COMPLETED') && !empty($paypal_order_info['payment_source']['card']['vault_id'])) { + $data['url'] = $this->url->link('checkout/success', '', true); + } + + if (($result['status'] == 'PAYER_ACTION_REQUIRED') && !empty($paypal_order_info['payment_source']['card']['vault_id'])) { + foreach ($result['links'] as $link) { + if ($link['rel'] == 'payer-action') { + $data['url'] = $link['href']; + + $this->session->data['paypal_order_id'] = $result['id']; + $this->session->data['paypal_card_token_index'] = $this->request->post['index']; + } + } + } if (!$this->error) { $data['paypal_order_id'] = $result['id']; @@ -905,7 +973,7 @@ public function createOrder() { $this->response->addHeader('Content-Type: application/json'); $this->response->setOutput(json_encode($data)); } - + public function approveOrder() { $this->load->language('extension/payment/paypal'); @@ -1110,97 +1178,89 @@ public function approveOrder() { $data['url'] = $this->url->link('extension/payment/paypal/confirmOrder', '', true); } } else { - if ((($payment_type == 'button') || ($payment_type == 'googlepay_button') || ($payment_type == 'applepay_button')) && !empty($this->request->post['paypal_order_id'])) { + if (!empty($this->request->post['paypal_order_id'])) { $paypal_order_id = $this->request->post['paypal_order_id']; } - if (($payment_type == 'card') && !empty($this->request->post['payload'])) { - $payload = json_decode(htmlspecialchars_decode($this->request->post['payload']), true); - - if (isset($payload['orderId'])) { - $paypal_order_id = $payload['orderId']; - - if ($setting['card']['secure_status']) { - $paypal_order_info = $paypal->getOrder($paypal_order_id); + if (($payment_type == 'card') && !empty($paypal_order_id)) { + $paypal_order_info = $paypal->getOrder($paypal_order_id); - if ($paypal->hasErrors()) { - $error_messages = array(); + if ($paypal->hasErrors()) { + $error_messages = array(); - $errors = $paypal->getErrors(); + $errors = $paypal->getErrors(); - foreach ($errors as $error) { - if (isset($error['name']) && ($error['name'] == 'CURLE_OPERATION_TIMEOUTED')) { - $error['message'] = $this->language->get('error_timeout'); - } - - if (isset($error['details'][0]['description'])) { - $error_messages[] = $error['details'][0]['description']; - } elseif (isset($error['message'])) { - $error_messages[] = $error['message']; - } + foreach ($errors as $error) { + if (isset($error['name']) && ($error['name'] == 'CURLE_OPERATION_TIMEOUTED')) { + $error['message'] = $this->language->get('error_timeout'); + } - $this->model_extension_payment_paypal->log($error, $error['message']); - } - - $this->error['warning'] = implode(' ', $error_messages); + if (isset($error['details'][0]['description'])) { + $error_messages[] = $error['details'][0]['description']; + } elseif (isset($error['message'])) { + $error_messages[] = $error['message']; } + + $this->model_extension_payment_paypal->log($error, $error['message']); + } + + $this->error['warning'] = implode(' ', $error_messages); + } - if (isset($paypal_order_info['payment_source']['card']) && !$this->error) { - $this->model_extension_payment_paypal->log($paypal_order_info['payment_source']['card'], 'Card'); + if (isset($paypal_order_info['payment_source']['card']) && !$this->error) { + $this->model_extension_payment_paypal->log($paypal_order_info['payment_source']['card'], 'Card'); - $liability_shift = (isset($paypal_order_info['payment_source']['card']['authentication_result']['liability_shift']) ? $paypal_order_info['payment_source']['card']['authentication_result']['liability_shift'] : ''); - $enrollment_status = (isset($paypal_order_info['payment_source']['card']['authentication_result']['three_d_secure']['enrollment_status']) ? $paypal_order_info['payment_source']['card']['authentication_result']['three_d_secure']['enrollment_status'] : ''); - $authentication_status = (isset($paypal_order_info['payment_source']['card']['authentication_result']['three_d_secure']['authentication_status']) ? $paypal_order_info['payment_source']['card']['authentication_result']['three_d_secure']['authentication_status'] : ''); + $liability_shift = (isset($paypal_order_info['payment_source']['card']['authentication_result']['liability_shift']) ? $paypal_order_info['payment_source']['card']['authentication_result']['liability_shift'] : ''); + $enrollment_status = (isset($paypal_order_info['payment_source']['card']['authentication_result']['three_d_secure']['enrollment_status']) ? $paypal_order_info['payment_source']['card']['authentication_result']['three_d_secure']['enrollment_status'] : ''); + $authentication_status = (isset($paypal_order_info['payment_source']['card']['authentication_result']['three_d_secure']['authentication_status']) ? $paypal_order_info['payment_source']['card']['authentication_result']['three_d_secure']['authentication_status'] : ''); - if ($enrollment_status == 'Y') { - if (($authentication_status == 'N') && !$setting['card']['secure_scenario']['failed_authentication']) { - $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['failed_authentication']['error']); - } + if ($enrollment_status == 'Y') { + if (($authentication_status == 'N') && !$setting['card']['secure_scenario']['failed_authentication']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['failed_authentication']['error']); + } - if (($authentication_status == 'R') && !$setting['card']['secure_scenario']['rejected_authentication']) { - $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['rejected_authentication']['error']); - } + if (($authentication_status == 'R') && !$setting['card']['secure_scenario']['rejected_authentication']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['rejected_authentication']['error']); + } - if (($authentication_status == 'A') && !$setting['card']['secure_scenario']['attempted_authentication']) { - $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['attempted_authentication']['error']); - } + if (($authentication_status == 'A') && !$setting['card']['secure_scenario']['attempted_authentication']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['attempted_authentication']['error']); + } - if (($authentication_status == 'U') && !$setting['card']['secure_scenario']['unable_authentication']) { - $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['unable_authentication']['error']); - } + if (($authentication_status == 'U') && !$setting['card']['secure_scenario']['unable_authentication']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['unable_authentication']['error']); + } - if (($authentication_status == 'C') && !$setting['card']['secure_scenario']['challenge_authentication']) { - $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['challenge_authentication']['error']); - } - } + if (($authentication_status == 'C') && !$setting['card']['secure_scenario']['challenge_authentication']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['challenge_authentication']['error']); + } + } - if (($enrollment_status == 'N') && !$setting['card']['secure_scenario']['card_ineligible']) { - $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['card_ineligible']['error']); - } + if (($enrollment_status == 'N') && !$setting['card']['secure_scenario']['card_ineligible']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['card_ineligible']['error']); + } - if (($enrollment_status == 'U') && !$setting['card']['secure_scenario']['system_unavailable']) { - $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['system_unavailable']['error']); - } + if (($enrollment_status == 'U') && !$setting['card']['secure_scenario']['system_unavailable']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['system_unavailable']['error']); + } - if (($enrollment_status == 'B') && !$setting['card']['secure_scenario']['system_bypassed']) { - $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['system_bypassed']['error']); - } - } - - if (!empty($this->error['warning'])) { - $this->error['warning'] .= ' ' . sprintf($this->language->get('error_payment'), $this->url->link('information/contact', '', true)); - } + if (($enrollment_status == 'B') && !$setting['card']['secure_scenario']['system_bypassed']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['system_bypassed']['error']); } } + + if (!empty($this->error['warning'])) { + $this->error['warning'] .= ' ' . sprintf($this->language->get('error_payment'), $this->url->link('information/contact', '', true)); + } } - - if (isset($paypal_order_id) && !$this->error) { + + if (!empty($paypal_order_id) && !$this->error) { if ($transaction_method == 'authorize') { $result = $paypal->setOrderAuthorize($paypal_order_id); } else { $result = $paypal->setOrderCapture($paypal_order_id); } - + if ($paypal->hasErrors()) { $error_messages = array(); @@ -1248,15 +1308,21 @@ public function approveOrder() { $payment_method = ''; $vault_id = ''; $vault_customer_id = ''; + $card_type = (!empty($this->request->post['card_type']) ? $this->request->post['card_type'] : ''); + $card_nice_type = (!empty($this->request->post['card_nice_type']) ? $this->request->post['card_nice_type'] : ''); + $card_last_digits = ''; + $card_expiry = ''; if (!$this->cart->hasShipping()) { $seller_protection_status = 'NOT_ELIGIBLE'; } foreach ($result['payment_source'] as $payment_source_key => $payment_source) { + $payment_method = $payment_source_key; $vault_id = (isset($payment_source['attributes']['vault']['id']) ? $payment_source['attributes']['vault']['id'] : ''); $vault_customer_id = (isset($payment_source['attributes']['vault']['customer']['id']) ? $payment_source['attributes']['vault']['customer']['id'] : ''); - $payment_method = $payment_source_key; + $card_last_digits = (isset($payment_source['last_digits']) ? $payment_source['last_digits'] : ''); + $card_expiry = (isset($payment_source['expiry']) ? $payment_source['expiry'] : ''); break; } @@ -1293,19 +1359,60 @@ public function approveOrder() { } if (($authorization_status == 'CREATED') || ($authorization_status == 'DENIED') || ($authorization_status == 'PENDING')) { + if ($payment_method == 'paypal') { + $paypal_customer_token = array(); + + if ($this->customer->isLogged()) { + $paypal_customer_token = $this->model_extension_payment_paypal->getPayPalCustomerMainToken($this->customer->getId(), $payment_method); + } + + if (!empty($paypal_customer_token['vault_id'])) { + $vault_id = $paypal_customer_token['vault_id']; + $vault_customer_id = $paypal_customer_token['vault_customer_id']; + } + } + $this->model_extension_payment_paypal->deletePayPalOrder($this->session->data['order_id']); $paypal_order_data = array( 'order_id' => $this->session->data['order_id'], + 'paypal_order_id' => $paypal_order_id, 'transaction_id' => $authorization_id, 'transaction_status' => $transaction_status, 'payment_method' => $payment_method, 'vault_id' => $vault_id, 'vault_customer_id' => $vault_customer_id, + 'card_type' => $card_type, + 'card_nice_type' => $card_nice_type, + 'card_last_digits' => $card_last_digits, + 'card_expiry' => $card_expiry, 'environment' => $environment ); $this->model_extension_payment_paypal->addPayPalOrder($paypal_order_data); + + if ($this->customer->isLogged() && $vault_id) { + $customer_id = $this->customer->getId(); + + $paypal_customer_token_info = $this->model_extension_payment_paypal->getPayPalCustomerToken($customer_id, $payment_method, $vault_id); + + if (!$paypal_customer_token_info) { + $paypal_customer_token_data = array( + 'customer_id' => $customer_id, + 'payment_method' => $payment_method, + 'vault_id' => $vault_id, + 'vault_customer_id' => $vault_customer_id, + 'card_type' => $card_type, + 'card_nice_type' => $card_nice_type, + 'card_last_digits' => $card_last_digits, + 'card_expiry' => $card_expiry + ); + + $this->model_extension_payment_paypal->addPayPalCustomerToken($paypal_customer_token_data); + } + + $this->model_extension_payment_paypal->setPayPalCustomerMainToken($customer_id, $payment_method, $vault_id); + } } if (($authorization_status == 'CREATED') || ($authorization_status == 'PENDING')) { @@ -1332,15 +1439,21 @@ public function approveOrder() { $payment_method = ''; $vault_id = ''; $vault_customer_id = ''; - + $card_type = (!empty($this->request->post['card_type']) ? $this->request->post['card_type'] : ''); + $card_nice_type = (!empty($this->request->post['card_nice_type']) ? $this->request->post['card_nice_type'] : ''); + $card_last_digits = ''; + $card_expiry = ''; + if (!$this->cart->hasShipping()) { $seller_protection_status = 'NOT_ELIGIBLE'; } foreach ($result['payment_source'] as $payment_source_key => $payment_source) { + $payment_method = $payment_source_key; $vault_id = (isset($payment_source['attributes']['vault']['id']) ? $payment_source['attributes']['vault']['id'] : ''); $vault_customer_id = (isset($payment_source['attributes']['vault']['customer']['id']) ? $payment_source['attributes']['vault']['customer']['id'] : ''); - $payment_method = $payment_source_key; + $card_last_digits = (isset($payment_source['last_digits']) ? $payment_source['last_digits'] : ''); + $card_expiry = (isset($payment_source['expiry']) ? $payment_source['expiry'] : ''); break; } @@ -1373,19 +1486,60 @@ public function approveOrder() { } if (($capture_status == 'COMPLETED') || ($capture_status == 'DECLINED') || ($capture_status == 'PENDING')) { + if ($payment_method == 'paypal') { + $paypal_customer_token = array(); + + if ($this->customer->isLogged()) { + $paypal_customer_token = $this->model_extension_payment_paypal->getPayPalCustomerMainToken($this->customer->getId(), $payment_method); + } + + if (!empty($paypal_customer_token['vault_id'])) { + $vault_id = $paypal_customer_token['vault_id']; + $vault_customer_id = $paypal_customer_token['vault_customer_id']; + } + } + $this->model_extension_payment_paypal->deletePayPalOrder($this->session->data['order_id']); $paypal_order_data = array( 'order_id' => $this->session->data['order_id'], + 'paypal_order_id' => $paypal_order_id, 'transaction_id' => $capture_id, 'transaction_status' => $transaction_status, 'payment_method' => $payment_method, 'vault_id' => $vault_id, 'vault_customer_id' => $vault_customer_id, + 'card_type' => $card_type, + 'card_nice_type' => $card_nice_type, + 'card_last_digits' => $card_last_digits, + 'card_expiry' => $card_expiry, 'environment' => $environment ); $this->model_extension_payment_paypal->addPayPalOrder($paypal_order_data); + + if ($this->customer->isLogged() && $vault_id) { + $customer_id = $this->customer->getId(); + + $paypal_customer_token_info = $this->model_extension_payment_paypal->getPayPalCustomerToken($customer_id, $payment_method, $vault_id); + + if (!$paypal_customer_token_info) { + $paypal_customer_token_data = array( + 'customer_id' => $customer_id, + 'payment_method' => $payment_method, + 'vault_id' => $vault_id, + 'vault_customer_id' => $vault_customer_id, + 'card_type' => $card_type, + 'card_nice_type' => $card_nice_type, + 'card_last_digits' => $card_last_digits, + 'card_expiry' => $card_expiry + ); + + $this->model_extension_payment_paypal->addPayPalCustomerToken($paypal_customer_token_data); + } + + $this->model_extension_payment_paypal->setPayPalCustomerMainToken($customer_id, $payment_method, $vault_id); + } } if (($capture_status == 'COMPLETED') || ($capture_status == 'PENDING')) { @@ -1411,7 +1565,7 @@ public function approveOrder() { $this->response->addHeader('Content-Type: application/json'); $this->response->setOutput(json_encode($data)); } - + public function confirmOrder() { $this->load->language('extension/payment/paypal'); $this->load->language('checkout/cart'); @@ -2390,15 +2544,21 @@ public function completeOrder() { $payment_method = ''; $vault_id = ''; $vault_customer_id = ''; + $card_type = ''; + $card_nice_type = ''; + $card_last_digits = ''; + $card_expiry = ''; if (!$this->cart->hasShipping()) { $seller_protection_status = 'NOT_ELIGIBLE'; } foreach ($result['payment_source'] as $payment_source_key => $payment_source) { + $payment_method = $payment_source_key; $vault_id = (isset($payment_source['attributes']['vault']['id']) ? $payment_source['attributes']['vault']['id'] : ''); $vault_customer_id = (isset($payment_source['attributes']['vault']['customer']['id']) ? $payment_source['attributes']['vault']['customer']['id'] : ''); - $payment_method = $payment_source_key; + $card_last_digits = (isset($payment_source['last_digits']) ? $payment_source['last_digits'] : ''); + $card_expiry = (isset($payment_source['expiry']) ? $payment_source['expiry'] : ''); break; } @@ -2435,19 +2595,60 @@ public function completeOrder() { } if (($authorization_status == 'CREATED') || ($authorization_status == 'DENIED') || ($authorization_status == 'PENDING')) { + if ($payment_method == 'paypal') { + $paypal_customer_token = array(); + + if ($this->customer->isLogged()) { + $paypal_customer_token = $this->model_extension_payment_paypal->getPayPalCustomerMainToken($this->customer->getId(), $payment_method); + } + + if (!empty($paypal_customer_token['vault_id'])) { + $vault_id = $paypal_customer_token['vault_id']; + $vault_customer_id = $paypal_customer_token['vault_customer_id']; + } + } + $this->model_extension_payment_paypal->deletePayPalOrder($this->session->data['order_id']); - + $paypal_order_data = array( 'order_id' => $this->session->data['order_id'], + 'paypal_order_id' => $paypal_order_id, 'transaction_id' => $authorization_id, 'transaction_status' => $transaction_status, 'payment_method' => $payment_method, 'vault_id' => $vault_id, 'vault_customer_id' => $vault_customer_id, + 'card_type' => $card_type, + 'card_nice_type' => $card_nice_type, + 'card_last_digits' => $card_last_digits, + 'card_expiry' => $card_expiry, 'environment' => $environment ); $this->model_extension_payment_paypal->addPayPalOrder($paypal_order_data); + + if ($this->customer->isLogged() && $vault_id) { + $customer_id = $this->customer->getId(); + + $paypal_customer_token_info = $this->model_extension_payment_paypal->getPayPalCustomerToken($customer_id, $payment_method, $vault_id); + + if (!$paypal_customer_token_info) { + $paypal_customer_token_data = array( + 'customer_id' => $customer_id, + 'payment_method' => $payment_method, + 'vault_id' => $vault_id, + 'vault_customer_id' => $vault_customer_id, + 'card_type' => $card_type, + 'card_nice_type' => $card_nice_type, + 'card_last_digits' => $card_last_digits, + 'card_expiry' => $card_expiry, + ); + + $this->model_extension_payment_paypal->addPayPalCustomerToken($paypal_customer_token_data); + } + + $this->model_extension_payment_paypal->setPayPalCustomerMainToken($customer_id, $payment_method, $vault_id); + } } if (($authorization_status == 'CREATED') || ($authorization_status == 'PENDING')) { @@ -2474,16 +2675,22 @@ public function completeOrder() { $payment_method = ''; $vault_id = ''; $vault_customer_id = ''; - + $card_type = ''; + $card_nice_type = ''; + $card_last_digits = ''; + $card_expiry = ''; + if (!$this->cart->hasShipping()) { $seller_protection_status = 'NOT_ELIGIBLE'; } foreach ($result['payment_source'] as $payment_source_key => $payment_source) { + $payment_method = $payment_source_key; $vault_id = (isset($payment_source['attributes']['vault']['id']) ? $payment_source['attributes']['vault']['id'] : ''); $vault_customer_id = (isset($payment_source['attributes']['vault']['customer']['id']) ? $payment_source['attributes']['vault']['customer']['id'] : ''); - $payment_method = $payment_source_key; - + $card_last_digits = (isset($payment_source['last_digits']) ? $payment_source['last_digits'] : ''); + $card_expiry = (isset($payment_source['expiry']) ? $payment_source['expiry'] : ''); + break; } @@ -2515,19 +2722,60 @@ public function completeOrder() { } if (($capture_status == 'COMPLETED') || ($capture_status == 'DECLINED') || ($capture_status == 'PENDING')) { + if ($payment_method == 'paypal') { + $paypal_customer_token = array(); + + if ($this->customer->isLogged()) { + $paypal_customer_token = $this->model_extension_payment_paypal->getPayPalCustomerMainToken($this->customer->getId(), $payment_method); + } + + if (!empty($paypal_customer_token['vault_id'])) { + $vault_id = $paypal_customer_token['vault_id']; + $vault_customer_id = $paypal_customer_token['vault_customer_id']; + } + } + $this->model_extension_payment_paypal->deletePayPalOrder($this->session->data['order_id']); - + $paypal_order_data = array( 'order_id' => $this->session->data['order_id'], + 'paypal_order_id' => $paypal_order_id, 'transaction_id' => $capture_id, 'transaction_status' => $transaction_status, 'payment_method' => $payment_method, 'vault_id' => $vault_id, 'vault_customer_id' => $vault_customer_id, + 'card_type' => $card_type, + 'card_nice_type' => $card_nice_type, + 'card_last_digits' => $card_last_digits, + 'card_expiry' => $card_expiry, 'environment' => $environment ); $this->model_extension_payment_paypal->addPayPalOrder($paypal_order_data); + + if ($this->customer->isLogged() && $vault_id) { + $customer_id = $this->customer->getId(); + + $paypal_customer_token_info = $this->model_extension_payment_paypal->getPayPalCustomerToken($customer_id, $payment_method, $vault_id); + + if (!$paypal_customer_token_info) { + $paypal_customer_token_data = array( + 'customer_id' => $customer_id, + 'payment_method' => $payment_method, + 'vault_id' => $vault_id, + 'vault_customer_id' => $vault_customer_id, + 'card_type' => $card_type, + 'card_nice_type' => $card_nice_type, + 'card_last_digits' => $card_last_digits, + 'card_expiry' => $card_expiry, + ); + + $this->model_extension_payment_paypal->addPayPalCustomerToken($paypal_customer_token_data); + } + + $this->model_extension_payment_paypal->setPayPalCustomerMainToken($customer_id, $payment_method, $vault_id); + } } if (($capture_status == 'COMPLETED') || ($capture_status == 'PENDING')) { @@ -2723,7 +2971,514 @@ public function confirmShippingAddress() { $this->response->addHeader('Content-Type: application/json'); $this->response->setOutput(json_encode($data)); } + + public function deleteCustomerToken() { + $this->load->language('extension/payment/paypal'); + + $this->load->model('extension/payment/paypal'); + + if ($this->customer->isLogged() && isset($this->request->post['index'])) { + $card_token_index = $this->request->post['index']; + + $card_customer_tokens = $this->model_extension_payment_paypal->getPayPalCustomerTokens($this->customer->getId(), 'card'); + + if (!empty($card_customer_tokens[$card_token_index]['vault_id'])) { + $vault_id = $card_customer_tokens[$card_token_index]['vault_id']; + + $_config = new Config(); + $_config->load('paypal'); + + $config_setting = $_config->get('paypal_setting'); + + $setting = array_replace_recursive((array)$config_setting, (array)$this->config->get('payment_paypal_setting')); + + $client_id = $this->config->get('payment_paypal_client_id'); + $secret = $this->config->get('payment_paypal_secret'); + $merchant_id = $this->config->get('payment_paypal_merchant_id'); + $environment = $this->config->get('payment_paypal_environment'); + $partner_id = $setting['partner'][$environment]['partner_id']; + $partner_attribution_id = $setting['partner'][$environment]['partner_attribution_id']; + + require_once DIR_SYSTEM . 'library/paypal/paypal.php'; + + $paypal_info = array( + 'partner_id' => $partner_id, + 'client_id' => $client_id, + 'secret' => $secret, + 'environment' => $environment, + 'partner_attribution_id' => $partner_attribution_id + ); + + $paypal = new PayPal($paypal_info); + + $token_info = array( + 'grant_type' => 'client_credentials' + ); + + $result = $paypal->setAccessToken($token_info); + + $result = $paypal->deletePaymentToken($vault_id); + + if ($paypal->hasErrors()) { + $error_messages = array(); + + $errors = $paypal->getErrors(); + + foreach ($errors as $error) { + if (isset($error['name']) && ($error['name'] == 'CURLE_OPERATION_TIMEOUTED')) { + $error['message'] = $this->language->get('error_timeout'); + } + if (isset($error['details'][0]['description'])) { + $error_messages[] = $error['details'][0]['description']; + } elseif (isset($error['message'])) { + $error_messages[] = $error['message']; + } + + $this->model_extension_payment_paypal->log($error, $error['message']); + } + + $this->error['warning'] = implode(' ', $error_messages); + } + + if (!empty($this->error['warning'])) { + $this->error['warning'] .= ' ' . sprintf($this->language->get('error_payment'), $this->url->link('information/contact', '', true)); + } + + + if (!empty($this->error['warning'])) { + $this->error['warning'] .= ' ' . sprintf($this->language->get('error_payment'), $this->url->link('information/contact', '', true)); + } + + if ($result && !$this->error) { + $this->model_extension_payment_paypal->deletePayPalCustomerToken($this->customer->getId(), 'card', $vault_id); + + $data['success'] = true; + } + } + } + + $data['error'] = $this->error; + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($data)); + } + + public function callback() { + $this->load->language('extension/payment/paypal'); + + $this->load->model('extension/payment/paypal'); + + if (!empty($this->request->get['callback_token'])) { + $_config = new Config(); + $_config->load('paypal'); + + $config_setting = $_config->get('paypal_setting'); + + $setting = array_replace_recursive((array)$config_setting, (array)$this->config->get('payment_paypal_setting')); + + if (hash_equals($setting['general']['callback_token'], $this->request->get['callback_token']) && !empty($this->session->data['order_id']) && !empty($this->session->data['paypal_order_id']) && isset($this->session->data['paypal_card_token_index'])) { + $order_id = $this->session->data['order_id']; + $paypal_order_id = $this->session->data['paypal_order_id']; + $card_token_index = $this->session->data['paypal_card_token_index']; + + $card_customer_tokens = $this->model_extension_payment_paypal->getPayPalCustomerTokens($this->customer->getId(), 'card'); + + if (!empty($card_customer_tokens[$card_token_index]['vault_id'])) { + $vault_id = $card_customer_tokens[$card_token_index]['vault_id']; + $vault_customer_id = $card_customer_tokens[$card_token_index]['vault_customer_id']; + $card_type = $card_customer_tokens[$card_token_index]['card_type']; + $card_nice_type = $card_customer_tokens[$card_token_index]['card_nice_type']; + $card_last_digits = $card_customer_tokens[$card_token_index]['card_last_digits']; + $card_expiry = $card_customer_tokens[$card_token_index]['card_expiry']; + + $client_id = $this->config->get('payment_paypal_client_id'); + $secret = $this->config->get('payment_paypal_secret'); + $environment = $this->config->get('payment_paypal_environment'); + $partner_id = $setting['partner'][$environment]['partner_id']; + $partner_attribution_id = $setting['partner'][$environment]['partner_attribution_id']; + $transaction_method = $setting['general']['transaction_method']; + + require_once DIR_SYSTEM . 'library/paypal/paypal.php'; + + $paypal_info = array( + 'partner_id' => $partner_id, + 'client_id' => $client_id, + 'secret' => $secret, + 'environment' => $environment, + 'partner_attribution_id' => $partner_attribution_id + ); + + $paypal = new PayPal($paypal_info); + + $token_info = array( + 'grant_type' => 'client_credentials' + ); + + $paypal->setAccessToken($token_info); + + $paypal_order_info = $paypal->getOrder($paypal_order_id); + + if ($paypal->hasErrors()) { + $error_messages = array(); + + $errors = $paypal->getErrors(); + + foreach ($errors as $error) { + if (isset($error['name']) && ($error['name'] == 'CURLE_OPERATION_TIMEOUTED')) { + $error['message'] = $this->language->get('error_timeout'); + } + + if (isset($error['details'][0]['description'])) { + $error_messages[] = $error['details'][0]['description']; + } elseif (isset($error['message'])) { + $error_messages[] = $error['message']; + } + + $this->model_extension_payment_paypal->log($error, $error['message']); + } + + $this->error['warning'] = implode(' ', $error_messages); + } + + if (isset($paypal_order_info['payment_source']['card']) && !$this->error) { + $this->model_extension_payment_paypal->log($paypal_order_info['payment_source']['card'], 'Card'); + + $liability_shift = (isset($paypal_order_info['payment_source']['card']['authentication_result']['liability_shift']) ? $paypal_order_info['payment_source']['card']['authentication_result']['liability_shift'] : ''); + $enrollment_status = (isset($paypal_order_info['payment_source']['card']['authentication_result']['three_d_secure']['enrollment_status']) ? $paypal_order_info['payment_source']['card']['authentication_result']['three_d_secure']['enrollment_status'] : ''); + $authentication_status = (isset($paypal_order_info['payment_source']['card']['authentication_result']['three_d_secure']['authentication_status']) ? $paypal_order_info['payment_source']['card']['authentication_result']['three_d_secure']['authentication_status'] : ''); + + if ($enrollment_status == 'Y') { + if (($authentication_status == 'N') && !$setting['card']['secure_scenario']['failed_authentication']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['failed_authentication']['error']); + } + + if (($authentication_status == 'R') && !$setting['card']['secure_scenario']['rejected_authentication']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['rejected_authentication']['error']); + } + + if (($authentication_status == 'A') && !$setting['card']['secure_scenario']['attempted_authentication']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['attempted_authentication']['error']); + } + + if (($authentication_status == 'U') && !$setting['card']['secure_scenario']['unable_authentication']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['unable_authentication']['error']); + } + + if (($authentication_status == 'C') && !$setting['card']['secure_scenario']['challenge_authentication']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['challenge_authentication']['error']); + } + } + + if (($enrollment_status == 'N') && !$setting['card']['secure_scenario']['card_ineligible']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['card_ineligible']['error']); + } + + if (($enrollment_status == 'U') && !$setting['card']['secure_scenario']['system_unavailable']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['system_unavailable']['error']); + } + + if (($enrollment_status == 'B') && !$setting['card']['secure_scenario']['system_bypassed']) { + $this->error['warning'] = $this->language->get($setting['card_secure_scenario']['system_bypassed']['error']); + } + } + + if (!empty($this->error['warning'])) { + $this->error['warning'] .= ' ' . sprintf($this->language->get('error_payment'), $this->url->link('information/contact', '', true)); + } + + if (!$this->error) { + if ($transaction_method == 'authorize') { + $result = $paypal->setOrderAuthorize($paypal_order_id); + } else { + $result = $paypal->setOrderCapture($paypal_order_id); + } + + if ($paypal->hasErrors()) { + $error_messages = array(); + + $errors = $paypal->getErrors(); + + foreach ($errors as $error) { + if (isset($error['details'][0]['issue']) && ($error['details'][0]['issue'] == 'INSTRUMENT_DECLINED')) { + $data['restart'] = true; + } + + if (isset($error['name']) && ($error['name'] == 'CURLE_OPERATION_TIMEOUTED')) { + $error['message'] = $this->language->get('error_timeout'); + } + + if (isset($error['details'][0]['description'])) { + $error_messages[] = $error['details'][0]['description']; + } elseif (isset($error['message'])) { + $error_messages[] = $error['message']; + } + + $this->model_extension_payment_paypal->log($error, $error['message']); + } + + $this->error['warning'] = implode(' ', $error_messages); + } + + if (!empty($this->error['warning'])) { + $this->error['warning'] .= ' ' . sprintf($this->language->get('error_payment'), $this->url->link('information/contact', '', true)); + } + + if (!$this->error) { + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if ($transaction_method == 'authorize') { + $this->model_extension_payment_paypal->log($result, 'Authorize Order'); + + if (isset($result['purchase_units'][0]['payments']['authorizations'][0]['status']) && isset($result['purchase_units'][0]['payments']['authorizations'][0]['seller_protection']['status'])) { + $authorization_id = $result['purchase_units'][0]['payments']['authorizations'][0]['id']; + $authorization_status = $result['purchase_units'][0]['payments']['authorizations'][0]['status']; + $seller_protection_status = $result['purchase_units'][0]['payments']['authorizations'][0]['seller_protection']['status']; + $order_status_id = 0; + $transaction_status = ''; + $payment_method = 'card'; + + if (!$this->cart->hasShipping()) { + $seller_protection_status = 'NOT_ELIGIBLE'; + } + + if ($authorization_status == 'CREATED') { + $order_status_id = $setting['order_status']['pending']['id']; + $transaction_status = 'created'; + } + + if ($authorization_status == 'CAPTURED') { + $this->error['warning'] = sprintf($this->language->get('error_authorization_captured'), $this->url->link('information/contact', '', true)); + } + + if ($authorization_status == 'DENIED') { + $order_status_id = $setting['order_status']['denied']['id']; + $transaction_status = 'denied'; + + $this->error['warning'] = $this->language->get('error_authorization_denied'); + } + + if ($authorization_status == 'EXPIRED') { + $this->error['warning'] = sprintf($this->language->get('error_authorization_expired'), $this->url->link('information/contact', '', true)); + } + + if ($authorization_status == 'PENDING') { + $order_status_id = $setting['order_status']['pending']['id']; + $transaction_status = 'pending'; + } + + if (($authorization_status == 'CREATED') || ($authorization_status == 'DENIED') || ($authorization_status == 'PENDING')) { + $message = sprintf($this->language->get('text_order_message'), $seller_protection_status); + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $order_status_id, $message); + } + + if (($authorization_status == 'CREATED') || ($authorization_status == 'DENIED') || ($authorization_status == 'PENDING')) { + $this->model_extension_payment_paypal->deletePayPalOrder($this->session->data['order_id']); + + $paypal_order_data = array( + 'order_id' => $this->session->data['order_id'], + 'paypal_order_id' => $paypal_order_id, + 'transaction_id' => $authorization_id, + 'transaction_status' => $transaction_status, + 'payment_method' => $payment_method, + 'vault_id' => $vault_id, + 'vault_customer_id' => $vault_customer_id, + 'card_type' => $card_type, + 'card_nice_type' => $card_nice_type, + 'card_last_digits' => $card_last_digits, + 'card_expiry' => $card_expiry, + 'environment' => $environment + ); + + $this->model_extension_payment_paypal->addPayPalOrder($paypal_order_data); + + if ($this->customer->isLogged() && $vault_id) { + $customer_id = $this->customer->getId(); + + $paypal_customer_token_info = $this->model_extension_payment_paypal->getPayPalCustomerToken($customer_id, $payment_method, $vault_id); + + if (!$paypal_customer_token_info) { + $paypal_customer_token_data = array( + 'customer_id' => $customer_id, + 'payment_method' => $payment_method, + 'vault_id' => $vault_id, + 'vault_customer_id' => $vault_customer_id, + 'card_type' => $card_type, + 'card_nice_type' => $card_nice_type, + 'card_last_digits' => $card_last_digits, + 'card_expiry' => $card_expiry + ); + + $this->model_extension_payment_paypal->addPayPalCustomerToken($paypal_customer_token_data); + } + + $this->model_extension_payment_paypal->setPayPalCustomerMainToken($customer_id, $payment_method, $vault_id); + } + } + + if (($authorization_status == 'CREATED') || ($authorization_status == 'PENDING')) { + $recurring_products = $this->cart->getRecurringProducts(); + + foreach ($recurring_products as $recurring_product) { + $this->model_extension_payment_paypal->recurringPayment($recurring_product, $order_info, $paypal_order_data); + } + } + + if (($authorization_status == 'CREATED') || ($authorization_status == 'PARTIALLY_CAPTURED') || ($authorization_status == 'PARTIALLY_CREATED') || ($authorization_status == 'VOIDED') || ($authorization_status == 'PENDING')) { + $this->response->redirect($this->url->link('checkout/success', '', true)); + } + } + } else { + $this->model_extension_payment_paypal->log($result, 'Capture Order'); + + if (isset($result['purchase_units'][0]['payments']['captures'][0]['status']) && isset($result['purchase_units'][0]['payments']['captures'][0]['seller_protection']['status'])) { + $capture_id = $result['purchase_units'][0]['payments']['captures'][0]['id']; + $capture_status = $result['purchase_units'][0]['payments']['captures'][0]['status']; + $seller_protection_status = $result['purchase_units'][0]['payments']['captures'][0]['seller_protection']['status']; + + $order_status_id = 0; + $transaction_status = ''; + $payment_method = 'card'; + + if (!$this->cart->hasShipping()) { + $seller_protection_status = 'NOT_ELIGIBLE'; + } + + if ($capture_status == 'COMPLETED') { + $order_status_id = $setting['order_status']['completed']['id']; + $transaction_status = 'completed'; + } + + if ($capture_status == 'DECLINED') { + $order_status_id = $setting['order_status']['denied']['id']; + $transaction_status = 'denied'; + + $this->error['warning'] = $this->language->get('error_capture_declined'); + } + + if ($capture_status == 'FAILED') { + $this->error['warning'] = sprintf($this->language->get('error_capture_failed'), $this->url->link('information/contact', '', true)); + } + + if ($capture_status == 'PENDING') { + $order_status_id = $setting['order_status']['pending']['id']; + $transaction_status = 'pending'; + } + + if (($capture_status == 'COMPLETED') || ($capture_status == 'DECLINED') || ($capture_status == 'PENDING')) { + $message = sprintf($this->language->get('text_order_message'), $seller_protection_status); + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $order_status_id, $message); + } + + if (($capture_status == 'COMPLETED') || ($capture_status == 'DECLINED') || ($capture_status == 'PENDING')) { + $this->model_extension_payment_paypal->deletePayPalOrder($this->session->data['order_id']); + + $paypal_order_data = array( + 'order_id' => $this->session->data['order_id'], + 'paypal_order_id' => $paypal_order_id, + 'transaction_id' => $capture_id, + 'transaction_status' => $transaction_status, + 'payment_method' => $payment_method, + 'vault_id' => $vault_id, + 'vault_customer_id' => $vault_customer_id, + 'card_type' => $card_type, + 'card_nice_type' => $card_nice_type, + 'card_last_digits' => $card_last_digits, + 'card_expiry' => $card_expiry, + 'environment' => $environment + ); + + $this->model_extension_payment_paypal->addPayPalOrder($paypal_order_data); + + if ($this->customer->isLogged() && $vault_id) { + $customer_id = $this->customer->getId(); + + $paypal_customer_token_info = $this->model_extension_payment_paypal->getPayPalCustomerToken($customer_id, $payment_method, $vault_id); + + if (!$paypal_customer_token_info) { + $paypal_customer_token_data = array( + 'customer_id' => $customer_id, + 'payment_method' => $payment_method, + 'vault_id' => $vault_id, + 'vault_customer_id' => $vault_customer_id, + 'card_type' => $card_type, + 'card_nice_type' => $card_nice_type, + 'card_last_digits' => $card_last_digits, + 'card_expiry' => $card_expiry + ); + + $this->model_extension_payment_paypal->addPayPalCustomerToken($paypal_customer_token_data); + } + + $this->model_extension_payment_paypal->setPayPalCustomerMainToken($customer_id, $payment_method, $vault_id); + } + } + + if (($capture_status == 'COMPLETED') || ($capture_status == 'PENDING')) { + $recurring_products = $this->cart->getRecurringProducts(); + + foreach ($recurring_products as $recurring_product) { + $this->model_extension_payment_paypal->recurringPayment($recurring_product, $order_info, $paypal_order_data); + } + } + + if (($capture_status == 'COMPLETED') || ($capture_status == 'PARTIALLY_REFUNDED') || ($capture_status == 'REFUNDED') || ($capture_status == 'PENDING')) { + $this->response->redirect($this->url->link('checkout/success', '', true)); + } + } + } + } + } + } + + $this->document->setTitle($this->language->get('text_failure_page_title')); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_home'), + 'href' => $this->url->link('common/home', '', true) + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_cart'), + 'href' => $this->url->link('checkout/cart', '', true) + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_paypal'), + 'href' => $this->url->link('extension/payment/paypal/callback', '', true) + ); + + $data['text_title'] = $this->language->get('text_failure_page_title'); + $data['text_message'] = sprintf($this->language->get('text_failure_page_message'), $this->url->link('information/contact', '', true)); + + if (!empty($this->error['warning'])) { + $data['text_message'] = $this->error['warning']; + } + + $data['continue'] = $this->url->link('common/home'); + + $data['column_left'] = $this->load->controller('common/column_left'); + $data['column_right'] = $this->load->controller('common/column_right'); + $data['content_top'] = $this->load->controller('common/content_top'); + $data['content_bottom'] = $this->load->controller('common/content_bottom'); + $data['footer'] = $this->load->controller('common/footer'); + $data['header'] = $this->load->controller('common/header'); + + $this->response->setOutput($this->load->view('extension/payment/paypal/failure', $data)); + + return true; + } + } + + return false; + } + public function webhook() { if (!empty($this->request->get['webhook_token'])) { $_config = new Config(); @@ -2737,6 +3492,7 @@ public function webhook() { if (hash_equals($setting['general']['webhook_token'], $this->request->get['webhook_token']) && !empty($webhook_info['id']) && !empty($webhook_info['event_type'])) { $this->load->model('extension/payment/paypal'); + $this->load->model('checkout/order'); $this->model_extension_payment_paypal->log($webhook_info, 'Webhook'); @@ -2789,71 +3545,127 @@ public function webhook() { } } - if (isset($webhook_event['resource']['invoice_id']) && (strpos($webhook_event['resource']['invoice_id'], '_') !== false) && !$errors) { + if (!empty($webhook_event['resource']['invoice_id']) && (strpos($webhook_event['resource']['invoice_id'], '_') !== false) && !$errors) { $invoice_id = explode('_', $webhook_event['resource']['invoice_id']); $order_id = reset($invoice_id); + + $order_info = $this->model_checkout_order->getOrder($order_id); - $order_status_id = 0; - $transaction_status = ''; + if ($order_info) { + $order_status_id = 0; + $transaction_status = ''; - if ($webhook_event['event_type'] == 'PAYMENT.AUTHORIZATION.CREATED') { - $order_status_id = $setting['order_status']['pending']['id']; - $transaction_status = 'created'; - } + if ($webhook_event['event_type'] == 'PAYMENT.AUTHORIZATION.CREATED') { + $order_status_id = $setting['order_status']['pending']['id']; + $transaction_status = 'created'; + } - if ($webhook_event['event_type'] == 'PAYMENT.AUTHORIZATION.VOIDED') { - $order_status_id = $setting['order_status']['voided']['id']; - $transaction_status = 'voided'; - } + if ($webhook_event['event_type'] == 'PAYMENT.AUTHORIZATION.VOIDED') { + $order_status_id = $setting['order_status']['voided']['id']; + $transaction_status = 'voided'; + } - if ($webhook_event['event_type'] == 'PAYMENT.CAPTURE.COMPLETED') { - $order_status_id = $setting['order_status']['completed']['id']; - $transaction_status = 'completed'; - } + if ($webhook_event['event_type'] == 'PAYMENT.CAPTURE.COMPLETED') { + $order_status_id = $setting['order_status']['completed']['id']; + $transaction_status = 'completed'; + } - if ($webhook_event['event_type'] == 'PAYMENT.CAPTURE.DENIED') { - $order_status_id = $setting['order_status']['denied']['id']; - $transaction_status = 'denied'; - } + if ($webhook_event['event_type'] == 'PAYMENT.CAPTURE.DENIED') { + $order_status_id = $setting['order_status']['denied']['id']; + $transaction_status = 'denied'; + } - if ($webhook_event['event_type'] == 'PAYMENT.CAPTURE.PENDING') { - $order_status_id = $setting['order_status']['pending']['id']; - $transaction_status = 'pending'; - } + if ($webhook_event['event_type'] == 'PAYMENT.CAPTURE.PENDING') { + $order_status_id = $setting['order_status']['pending']['id']; + $transaction_status = 'pending'; + } - if ($webhook_event['event_type'] == 'PAYMENT.CAPTURE.REFUNDED') { - $order_status_id = $setting['order_status']['refunded']['id']; - $transaction_status = 'refunded'; - } + if ($webhook_event['event_type'] == 'PAYMENT.CAPTURE.REFUNDED') { + $order_status_id = $setting['order_status']['refunded']['id']; + $transaction_status = 'refunded'; + } - if ($webhook_event['event_type'] == 'PAYMENT.CAPTURE.REVERSED') { - $order_status_id = $setting['order_status']['reversed']['id']; - $transaction_status = 'reversed'; - } + if ($webhook_event['event_type'] == 'PAYMENT.CAPTURE.REVERSED') { + $order_status_id = $setting['order_status']['reversed']['id']; + $transaction_status = 'reversed'; + } - if ($webhook_event['event_type'] == 'CHECKOUT.ORDER.COMPLETED') { - $order_status_id = $setting['order_status']['completed']['id']; - } + if ($webhook_event['event_type'] == 'CHECKOUT.ORDER.COMPLETED') { + $order_status_id = $setting['order_status']['completed']['id']; + } - if ($order_status_id) { - $this->load->model('checkout/order'); + if ($order_status_id && ($order_info['order_status_id'] != $order_status_id)) { + $this->load->model('checkout/order'); - $this->model_checkout_order->addOrderHistory($order_id, $order_status_id, '', true); - } + $this->model_checkout_order->addOrderHistory($order_id, $order_status_id, '', true); + } + + if (isset($webhook_event['resource']['id']) && $transaction_status) { + $transaction_id = $webhook_event['resource']['id']; - if (isset($webhook_event['resource']['id']) && $transaction_status) { - $transaction_id = $webhook_event['resource']['id']; + $paypal_order_data = array( + 'order_id' => $order_id, + 'transaction_status' => $transaction_status + ); + + if (($transaction_status != 'refunded') && ($transaction_status != 'reversed')) { + $paypal_order_data['transaction_id'] = $transaction_id; + } + + $this->model_extension_payment_paypal->editPayPalOrder($paypal_order_data); + } + } + } + if (($webhook_event['event_type'] == 'VAULT.PAYMENT-TOKEN.CREATED') && !empty($webhook_info['resource']['id']) && !empty($webhook_info['resource']['customer']['id']) && !empty($webhook_event['resource']['metadata']['order_id']) && !$errors) { + $paypal_order_id = $webhook_event['resource']['metadata']['order_id']; + + $paypal_order_info = $this->model_extension_payment_paypal->getPayPalOrderByPayPalOrderId($paypal_order_id); + + if ($paypal_order_info) { + $order_id = $paypal_order_info['order_id']; + $payment_method = $paypal_order_info['payment_method']; + $vault_id = $webhook_event['resource']['id']; + $vault_customer_id = $webhook_event['resource']['customer']['id']; + $card_type = $paypal_order_info['card_type']; + $card_nice_type = $paypal_order_info['card_nice_type']; + $card_last_digits = (isset($webhook_event['resource']['payment_source']['card']['last_digits']) ? $webhook_event['resource']['payment_source']['card']['last_digits'] : ''); + $card_expiry = (isset($webhook_event['resource']['payment_source']['card']['expiry']) ? $webhook_event['resource']['payment_source']['card']['expiry'] : ''); + $paypal_order_data = array( 'order_id' => $order_id, - 'transaction_status' => $transaction_status + 'vault_id' => $vault_id, + 'vault_customer_id' => $vault_customer_id, + 'card_last_digits' => $card_last_digits, + 'card_expiry' => $card_expiry ); - - if (($transaction_status != 'refunded') && ($transaction_status != 'reversed')) { - $paypal_order_data['transaction_id'] = $transaction_id; - } - + $this->model_extension_payment_paypal->editPayPalOrder($paypal_order_data); + + $order_info = $this->model_checkout_order->getOrder($order_id); + + if (!empty($order_info['customer_id']) && $vault_id) { + $customer_id = $order_info['customer_id']; + + $paypal_customer_token_info = $this->model_extension_payment_paypal->getPayPalCustomerToken($customer_id, $payment_method, $vault_id); + + if (!$paypal_customer_token_info) { + $paypal_customer_token_data = array( + 'customer_id' => $customer_id, + 'payment_method' => $payment_method, + 'vault_id' => $vault_id, + 'vault_customer_id' => $vault_customer_id, + 'card_type' => $card_type, + 'card_nice_type' => $card_nice_type, + 'card_last_digits' => $card_last_digits, + 'card_expiry' => $card_expiry + ); + + $this->model_extension_payment_paypal->addPayPalCustomerToken($paypal_customer_token_data); + } + + $this->model_extension_payment_paypal->setPayPalCustomerMainToken($customer_id, $payment_method, $vault_id); + } } } diff --git a/upload/catalog/language/en-gb/extension/payment/paypal.php b/upload/catalog/language/en-gb/extension/payment/paypal.php index 8913592ef33..08bdb9f9746 100644 --- a/upload/catalog/language/en-gb/extension/payment/paypal.php +++ b/upload/catalog/language/en-gb/extension/payment/paypal.php @@ -18,6 +18,7 @@ $_['text_semi_month'] = 'half-month'; $_['text_month'] = 'month'; $_['text_year'] = 'year'; +$_['text_card_number'] = '%s ending in %s'; $_['text_trial'] = '%s every %s %s for %s payments then '; $_['text_recurring'] = '%s every %s %s'; $_['text_recurring_item'] = 'Recurring Item'; @@ -29,6 +30,8 @@ $_['text_order_message'] = 'PayPal Seller Protection - %s'; $_['text_wait'] = 'Please wait!'; $_['text_loading'] = 'Loading...'; +$_['text_failure_page_title'] = 'Your order is failed!'; +$_['text_failure_page_message'] = 'Sorry, but the transaction failed! Please choose another payment method or contact us'; // Column $_['column_image'] = 'Image'; @@ -53,6 +56,7 @@ $_['entry_card_number'] = 'Card Number'; $_['entry_expiration_date'] = 'Expiration Date'; $_['entry_cvv'] = 'CVV'; +$_['entry_card_save'] = 'Save your card'; // Button $_['button_confirm'] = 'Confirm'; diff --git a/upload/catalog/model/extension/payment/paypal.php b/upload/catalog/model/extension/payment/paypal.php index ebd08f2ae94..1af15172cc8 100644 --- a/upload/catalog/model/extension/payment/paypal.php +++ b/upload/catalog/model/extension/payment/paypal.php @@ -52,6 +52,93 @@ public function getZoneByCode($country_id, $code) { return $query->row; } + public function addPayPalCustomerToken($data) { + $sql = "INSERT INTO `" . DB_PREFIX . "paypal_checkout_integration_customer_token` SET"; + + $implode = array(); + + if (!empty($data['customer_id'])) { + $implode[] = "`customer_id` = '" . (int)$data['customer_id'] . "'"; + } + + if (!empty($data['payment_method'])) { + $implode[] = "`payment_method` = '" . $this->db->escape($data['payment_method']) . "'"; + } + + if (!empty($data['vault_id'])) { + $implode[] = "`vault_id` = '" . $this->db->escape($data['vault_id']) . "'"; + } + + if (!empty($data['vault_customer_id'])) { + $implode[] = "`vault_customer_id` = '" . $this->db->escape($data['vault_customer_id']) . "'"; + } + + if (!empty($data['card_type'])) { + $implode[] = "`card_type` = '" . $this->db->escape($data['card_type']) . "'"; + } + + if (!empty($data['card_nice_type'])) { + $implode[] = "`card_nice_type` = '" . $this->db->escape($data['card_nice_type']) . "'"; + } + + if (!empty($data['card_last_digits'])) { + $implode[] = "`card_last_digits` = '" . $this->db->escape($data['card_last_digits']) . "'"; + } + + if (!empty($data['card_expiry'])) { + $implode[] = "`card_expiry` = '" . $this->db->escape($data['card_expiry']) . "'"; + } + + if ($implode) { + $sql .= implode(", ", $implode); + } + + $this->db->query($sql); + } + + public function deletePayPalCustomerToken($customer_id, $payment_method, $vault_id) { + $query = $this->db->query("DELETE FROM `" . DB_PREFIX . "paypal_checkout_integration_customer_token` WHERE `customer_id` = '" . (int)$customer_id . "' AND `payment_method` = '" . $this->db->escape($payment_method) . "' AND `vault_id` = '" . $this->db->escape($vault_id) . "'"); + } + + public function setPayPalCustomerMainToken($customer_id, $payment_method, $vault_id) { + $this->db->query("UPDATE `" . DB_PREFIX . "paypal_checkout_integration_customer_token` SET `main_token_status` = '0' WHERE `customer_id` = '" . (int)$customer_id . "' AND `payment_method` = '" . $this->db->escape($payment_method) . "'"); + $this->db->query("UPDATE `" . DB_PREFIX . "paypal_checkout_integration_customer_token` SET `main_token_status` = '1' WHERE `customer_id` = '" . (int)$customer_id . "' AND `payment_method` = '" . $this->db->escape($payment_method) . "' AND `vault_id` = '" . $this->db->escape($vault_id) . "'"); + } + + public function getPayPalCustomerMainToken($customer_id, $payment_method) { + $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "paypal_checkout_integration_customer_token` WHERE `customer_id` = '" . (int)$customer_id . "' AND `payment_method` = '" . $this->db->escape($payment_method) . "' AND `main_token_status` = '1'"); + + if ($query->num_rows) { + return $query->row; + } else { + return array(); + } + } + + public function getPayPalCustomerToken($customer_id, $payment_method, $vault_id) { + $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "paypal_checkout_integration_customer_token` WHERE `customer_id` = '" . (int)$customer_id . "' AND `payment_method` = '" . $this->db->escape($payment_method) . "' AND `vault_id` = '" . $this->db->escape($vault_id) . "'"); + + if ($query->num_rows) { + return $query->row; + } else { + return array(); + } + } + + public function getPayPalCustomerTokens($customer_id, $payment_method = '') { + if ($payment_method) { + $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "paypal_checkout_integration_customer_token` WHERE `customer_id` = '" . (int)$customer_id . "' AND `payment_method` = '" . $this->db->escape($payment_method) . "'"); + } else { + $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "paypal_checkout_integration_customer_token` WHERE `customer_id` = '" . (int)$customer_id . "'"); + } + + if ($query->num_rows) { + return $query->rows; + } else { + return array(); + } + } + public function addPayPalOrder($data) { $sql = "INSERT INTO `" . DB_PREFIX . "paypal_checkout_integration_order` SET"; @@ -61,6 +148,10 @@ public function addPayPalOrder($data) { $implode[] = "`order_id` = '" . (int)$data['order_id'] . "'"; } + if (!empty($data['paypal_order_id'])) { + $implode[] = "`paypal_order_id` = '" . $this->db->escape($data['paypal_order_id']) . "'"; + } + if (!empty($data['transaction_id'])) { $implode[] = "`transaction_id` = '" . $this->db->escape($data['transaction_id']) . "'"; } @@ -80,6 +171,22 @@ public function addPayPalOrder($data) { if (!empty($data['vault_customer_id'])) { $implode[] = "`vault_customer_id` = '" . $this->db->escape($data['vault_customer_id']) . "'"; } + + if (!empty($data['card_type'])) { + $implode[] = "`card_type` = '" . $this->db->escape($data['card_type']) . "'"; + } + + if (!empty($data['card_nice_type'])) { + $implode[] = "`card_nice_type` = '" . $this->db->escape($data['card_nice_type']) . "'"; + } + + if (!empty($data['card_last_digits'])) { + $implode[] = "`card_last_digits` = '" . $this->db->escape($data['card_last_digits']) . "'"; + } + + if (!empty($data['card_expiry'])) { + $implode[] = "`card_expiry` = '" . $this->db->escape($data['card_expiry']) . "'"; + } if (!empty($data['environment'])) { $implode[] = "`environment` = '" . $this->db->escape($data['environment']) . "'"; @@ -97,6 +204,10 @@ public function editPayPalOrder($data) { $implode = array(); + if (!empty($data['paypal_order_id'])) { + $implode[] = "`paypal_order_id` = '" . $this->db->escape($data['paypal_order_id']) . "'"; + } + if (!empty($data['transaction_id'])) { $implode[] = "`transaction_id` = '" . $this->db->escape($data['transaction_id']) . "'"; } @@ -117,6 +228,22 @@ public function editPayPalOrder($data) { $implode[] = "`vault_customer_id` = '" . $this->db->escape($data['vault_customer_id']) . "'"; } + if (!empty($data['card_type'])) { + $implode[] = "`card_type` = '" . $this->db->escape($data['card_type']) . "'"; + } + + if (!empty($data['card_nice_type'])) { + $implode[] = "`card_nice_type` = '" . $this->db->escape($data['card_nice_type']) . "'"; + } + + if (!empty($data['card_last_digits'])) { + $implode[] = "`card_last_digits` = '" . $this->db->escape($data['card_last_digits']) . "'"; + } + + if (!empty($data['card_expiry'])) { + $implode[] = "`card_expiry` = '" . $this->db->escape($data['card_expiry']) . "'"; + } + if (!empty($data['environment'])) { $implode[] = "`environment` = '" . $this->db->escape($data['environment']) . "'"; } @@ -144,6 +271,16 @@ public function getPayPalOrder($order_id) { } } + public function getPayPalOrderByPayPalOrderId($paypal_order_id) { + $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "paypal_checkout_integration_order` WHERE `paypal_order_id` = '" . $this->db->escape($paypal_order_id) . "'"); + + if ($query->num_rows) { + return $query->row; + } else { + return array(); + } + } + public function addPayPalOrderRecurring($data) { $this->db->query("INSERT INTO `" . DB_PREFIX . "paypal_checkout_integration_order_recurring` SET `order_recurring_id` = '" . (int)$data['order_recurring_id'] . "', `order_id` = '" . (int)$data['order_id'] . "', `date_added` = NOW(), `date_modified` = NOW(), `next_payment` = NOW(), `trial_end` = '" . $data['trial_end'] . "', `subscription_end` = '" . $data['subscription_end'] . "', `currency_code` = '" . $this->db->escape($data['currency_code']) . "', `total` = '" . $this->currency->format($data['amount'], $data['currency_code'], false, false) . "'"); } @@ -163,7 +300,7 @@ public function getPayPalOrderRecurring($order_recurring_id) { } public function addOrderRecurring($order_id, $description, $data, $reference) { - $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring` SET `order_id` = '" . (int)$order_id . "', `date_added` = NOW(), `status` = 6, `product_id` = '" . (int)$data['product_id'] . "', `product_name` = '" . $this->db->escape($data['name']) . "', `product_quantity` = '" . $this->db->escape($data['quantity']) . "', `recurring_id` = '" . (int)$data['recurring']['recurring_id'] . "', `recurring_name` = '" . $this->db->escape($data['name']) . "', `recurring_description` = '" . $this->db->escape($description) . "', `recurring_frequency` = '" . $this->db->escape($data['recurring']['frequency']) . "', `recurring_cycle` = '" . (int)$data['recurring']['cycle'] . "', `recurring_duration` = '" . (int)$data['recurring']['duration'] . "', `recurring_price` = '" . (float)$data['recurring']['price'] . "', `trial` = '" . (int)$data['recurring']['trial'] . "', `trial_frequency` = '" . $this->db->escape($data['recurring']['trial_frequency']) . "', `trial_cycle` = '" . (int)$data['recurring']['trial_cycle'] . "', `trial_duration` = '" . (int)$data['recurring']['trial_duration'] . "', `trial_price` = '" . (float)$data['recurring']['trial_price'] . "', `reference` = '" . $this->db->escape($reference) . "'"); + $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring` SET `order_id` = '" . (int)$order_id . "', `date_added` = NOW(), `status` = '1', `product_id` = '" . (int)$data['product_id'] . "', `product_name` = '" . $this->db->escape($data['name']) . "', `product_quantity` = '" . $this->db->escape($data['quantity']) . "', `recurring_id` = '" . (int)$data['recurring']['recurring_id'] . "', `recurring_name` = '" . $this->db->escape($data['name']) . "', `recurring_description` = '" . $this->db->escape($description) . "', `recurring_frequency` = '" . $this->db->escape($data['recurring']['frequency']) . "', `recurring_cycle` = '" . (int)$data['recurring']['cycle'] . "', `recurring_duration` = '" . (int)$data['recurring']['duration'] . "', `recurring_price` = '" . (float)$data['recurring']['price'] . "', `trial` = '" . (int)$data['recurring']['trial'] . "', `trial_frequency` = '" . $this->db->escape($data['recurring']['trial_frequency']) . "', `trial_cycle` = '" . (int)$data['recurring']['trial_cycle'] . "', `trial_duration` = '" . (int)$data['recurring']['trial_duration'] . "', `trial_price` = '" . (float)$data['recurring']['trial_price'] . "', `reference` = '" . $this->db->escape($reference) . "'"); return $this->db->getLastId(); } @@ -238,88 +375,90 @@ public function recurringPayment($product_data, $order_data, $paypal_order_data) $order_recurring_id = $this->addOrderRecurring($order_data['order_id'], $recurring_description, $product_data, $paypal_order_data['transaction_id']); - $next_payment = new DateTime('now'); - $trial_end = new DateTime('now'); - $subscription_end = new DateTime('now'); + $this->editOrderRecurringStatus($order_recurring_id, 1); + + if (!empty($paypal_order_data['vault_id'])) { + $next_payment = new DateTime('now'); + $trial_end = new DateTime('now'); + $subscription_end = new DateTime('now'); - if (($product_data['recurring']['trial'] == 1) && ($product_data['recurring']['trial_duration'] != 0)) { - $next_payment = $this->calculateSchedule($product_data['recurring']['trial_frequency'], $next_payment, $product_data['recurring']['trial_cycle']); - $trial_end = $this->calculateSchedule($product_data['recurring']['trial_frequency'], $trial_end, $product_data['recurring']['trial_cycle'] * $product_data['recurring']['trial_duration']); - } elseif ($product_data['recurring']['trial'] == 1) { - $next_payment = $this->calculateSchedule($product_data['recurring']['trial_frequency'], $next_payment, $product_data['recurring']['trial_cycle']); - $trial_end = new DateTime('0000-00-00'); - } + if (($product_data['recurring']['trial'] == 1) && ($product_data['recurring']['trial_duration'] != 0)) { + $next_payment = $this->calculateSchedule($product_data['recurring']['trial_frequency'], $next_payment, $product_data['recurring']['trial_cycle']); + $trial_end = $this->calculateSchedule($product_data['recurring']['trial_frequency'], $trial_end, $product_data['recurring']['trial_cycle'] * $product_data['recurring']['trial_duration']); + } elseif ($product_data['recurring']['trial'] == 1) { + $next_payment = $this->calculateSchedule($product_data['recurring']['trial_frequency'], $next_payment, $product_data['recurring']['trial_cycle']); + $trial_end = new DateTime('0000-00-00'); + } - if (date_format($trial_end, 'Y-m-d H:i:s') > date_format($subscription_end, 'Y-m-d H:i:s') && $product_data['recurring']['duration'] != 0) { - $subscription_end = new DateTime(date_format($trial_end, 'Y-m-d H:i:s')); - $subscription_end = $this->calculateSchedule($product_data['recurring']['frequency'], $subscription_end, $product_data['recurring']['cycle'] * $product_data['recurring']['duration']); - } elseif (date_format($trial_end, 'Y-m-d H:i:s') == date_format($subscription_end, 'Y-m-d H:i:s') && $product_data['recurring']['duration'] != 0) { - $next_payment = $this->calculateSchedule($product_data['recurring']['frequency'], $next_payment, $product_data['recurring']['cycle']); - $subscription_end = $this->calculateSchedule($product_data['recurring']['frequency'], $subscription_end, $product_data['recurring']['cycle'] * $product_data['recurring']['duration']); - } elseif (date_format($trial_end, 'Y-m-d H:i:s') > date_format($subscription_end, 'Y-m-d H:i:s') && $product_data['recurring']['duration'] == 0) { - $subscription_end = new DateTime('0000-00-00'); - } elseif (date_format($trial_end, 'Y-m-d H:i:s') == date_format($subscription_end, 'Y-m-d H:i:s') && $product_data['recurring']['duration'] == 0) { - $next_payment = $this->calculateSchedule($product_data['recurring']['frequency'], $next_payment, $product_data['recurring']['cycle']); - $subscription_end = new DateTime('0000-00-00'); - } + if (date_format($trial_end, 'Y-m-d H:i:s') > date_format($subscription_end, 'Y-m-d H:i:s') && $product_data['recurring']['duration'] != 0) { + $subscription_end = new DateTime(date_format($trial_end, 'Y-m-d H:i:s')); + $subscription_end = $this->calculateSchedule($product_data['recurring']['frequency'], $subscription_end, $product_data['recurring']['cycle'] * $product_data['recurring']['duration']); + } elseif (date_format($trial_end, 'Y-m-d H:i:s') == date_format($subscription_end, 'Y-m-d H:i:s') && $product_data['recurring']['duration'] != 0) { + $next_payment = $this->calculateSchedule($product_data['recurring']['frequency'], $next_payment, $product_data['recurring']['cycle']); + $subscription_end = $this->calculateSchedule($product_data['recurring']['frequency'], $subscription_end, $product_data['recurring']['cycle'] * $product_data['recurring']['duration']); + } elseif (date_format($trial_end, 'Y-m-d H:i:s') > date_format($subscription_end, 'Y-m-d H:i:s') && $product_data['recurring']['duration'] == 0) { + $subscription_end = new DateTime('0000-00-00'); + } elseif (date_format($trial_end, 'Y-m-d H:i:s') == date_format($subscription_end, 'Y-m-d H:i:s') && $product_data['recurring']['duration'] == 0) { + $next_payment = $this->calculateSchedule($product_data['recurring']['frequency'], $next_payment, $product_data['recurring']['cycle']); + $subscription_end = new DateTime('0000-00-00'); + } - $result = $this->createPayment($order_data, $paypal_order_data, $price, $order_recurring_id, $recurring_name); + $result = $this->createPayment($order_data, $paypal_order_data, $price, $order_recurring_id, $recurring_name); - $transaction_status = ''; - $transaction_id = ''; - $currency_code = ''; - $amount = ''; + $transaction_status = ''; + $transaction_id = ''; + $currency_code = ''; + $amount = ''; - if ($transaction_method == 'authorize') { - if (isset($result['purchase_units'][0]['payments']['authorizations'][0]['status']) && isset($result['purchase_units'][0]['payments']['authorizations'][0]['seller_protection']['status'])) { - $transaction_id = $result['purchase_units'][0]['payments']['authorizations'][0]['id']; - $transaction_status = $result['purchase_units'][0]['payments']['authorizations'][0]['status']; - $currency_code = $result['purchase_units'][0]['payments']['authorizations'][0]['amount']['currency_code']; - $amount = $result['purchase_units'][0]['payments']['authorizations'][0]['amount']['value']; - } - } else { - if (isset($result['purchase_units'][0]['payments']['captures'][0]['status']) && isset($result['purchase_units'][0]['payments']['captures'][0]['seller_protection']['status'])) { - $transaction_id = $result['purchase_units'][0]['payments']['captures'][0]['id']; - $transaction_status = $result['purchase_units'][0]['payments']['captures'][0]['status']; - $currency_code = $result['purchase_units'][0]['payments']['captures'][0]['amount']['currency_code']; - $amount = $result['purchase_units'][0]['payments']['captures'][0]['amount']['value']; + if ($transaction_method == 'authorize') { + if (isset($result['purchase_units'][0]['payments']['authorizations'][0]['status']) && isset($result['purchase_units'][0]['payments']['authorizations'][0]['seller_protection']['status'])) { + $transaction_id = $result['purchase_units'][0]['payments']['authorizations'][0]['id']; + $transaction_status = $result['purchase_units'][0]['payments']['authorizations'][0]['status']; + $currency_code = $result['purchase_units'][0]['payments']['authorizations'][0]['amount']['currency_code']; + $amount = $result['purchase_units'][0]['payments']['authorizations'][0]['amount']['value']; + } + } else { + if (isset($result['purchase_units'][0]['payments']['captures'][0]['status']) && isset($result['purchase_units'][0]['payments']['captures'][0]['seller_protection']['status'])) { + $transaction_id = $result['purchase_units'][0]['payments']['captures'][0]['id']; + $transaction_status = $result['purchase_units'][0]['payments']['captures'][0]['status']; + $currency_code = $result['purchase_units'][0]['payments']['captures'][0]['amount']['currency_code']; + $amount = $result['purchase_units'][0]['payments']['captures'][0]['amount']['value']; + } } - } - if ($transaction_id && $transaction_status && $currency_code && $amount) { - $this->editOrderRecurringStatus($order_recurring_id, 1); - - $paypal_order_recurring_data = array( - 'order_recurring_id' => $order_recurring_id, - 'order_id' => $order_data['order_id'], - 'trial_end' => date_format($trial_end, 'Y-m-d H:i:s'), - 'subscription_end' => date_format($subscription_end, 'Y-m-d H:i:s'), - 'currency_code' => $currency_code, - 'amount' => $amount - ); - - $this->addPayPalOrderRecurring($paypal_order_recurring_data); - - if (($transaction_status == 'CREATED') || ($transaction_status == 'COMPLETED') || ($transaction_status == 'PENDING')) { - $order_recurring_transaction_data = array( + if ($transaction_id && $transaction_status && $currency_code && $amount) { + $paypal_order_recurring_data = array( 'order_recurring_id' => $order_recurring_id, - 'reference' => $transaction_id, - 'type' => '1', + 'order_id' => $order_data['order_id'], + 'trial_end' => date_format($trial_end, 'Y-m-d H:i:s'), + 'subscription_end' => date_format($subscription_end, 'Y-m-d H:i:s'), + 'currency_code' => $currency_code, 'amount' => $amount ); + + $this->addPayPalOrderRecurring($paypal_order_recurring_data); + + if (($transaction_status == 'CREATED') || ($transaction_status == 'COMPLETED') || ($transaction_status == 'PENDING')) { + $order_recurring_transaction_data = array( + 'order_recurring_id' => $order_recurring_id, + 'reference' => $transaction_id, + 'type' => '1', + 'amount' => $amount + ); - $this->addOrderRecurringTransaction($order_recurring_transaction_data); + $this->addOrderRecurringTransaction($order_recurring_transaction_data); - $this->editPayPalOrderRecurringNextPayment($order_recurring_id, date_format($next_payment, 'Y-m-d H:i:s')); - } else { - $order_recurring_transaction_data = array( - 'order_recurring_id' => $order_recurring_id, - 'reference' => $transaction_id, - 'type' => '4', - 'amount' => $amount - ); + $this->editPayPalOrderRecurringNextPayment($order_recurring_id, date_format($next_payment, 'Y-m-d H:i:s')); + } else { + $order_recurring_transaction_data = array( + 'order_recurring_id' => $order_recurring_id, + 'reference' => $transaction_id, + 'type' => '4', + 'amount' => $amount + ); - $this->addOrderRecurringTransaction($order_recurring_transaction_data); + $this->addOrderRecurringTransaction($order_recurring_transaction_data); + } } } } @@ -352,65 +491,67 @@ public function cronPayment() { $order_info = $this->model_checkout_order->getOrder($order_recurring['order_id']); $paypal_order_info = $this->getPayPalOrder($order_recurring['order_id']); - - if ((date_format($today, 'Y-m-d H:i:s') > date_format($next_payment, 'Y-m-d H:i:s')) && (date_format($trial_end, 'Y-m-d H:i:s') > date_format($today, 'Y-m-d H:i:s') || date_format($trial_end, 'Y-m-d H:i:s') == date_format($unlimited, 'Y-m-d H:i:s'))) { - $price = $this->currency->format($order_recurring['trial_price'], $order_info['currency_code'], false, false); - $frequency = $order_recurring['trial_frequency']; - $cycle = $order_recurring['trial_cycle']; - $next_payment = $this->calculateSchedule($frequency, $next_payment, $cycle); - } elseif ((date_format($today, 'Y-m-d H:i:s') > date_format($next_payment, 'Y-m-d H:i:s')) && (date_format($subscription_end, 'Y-m-d H:i:s') > date_format($today, 'Y-m-d H:i:s') || date_format($subscription_end, 'Y-m-d H:i:s') == date_format($unlimited, 'Y-m-d H:i:s'))) { - $price = $this->currency->format($order_recurring['recurring_price'], $order_info['currency_code'], false, false); - $frequency = $order_recurring['recurring_frequency']; - $cycle = $order_recurring['recurring_cycle']; - $next_payment = $this->calculateSchedule($frequency, $next_payment, $cycle); - } else { - continue; - } + + if (!empty($paypal_order_info['vault_id'])) { + if ((date_format($today, 'Y-m-d H:i:s') > date_format($next_payment, 'Y-m-d H:i:s')) && (date_format($trial_end, 'Y-m-d H:i:s') > date_format($today, 'Y-m-d H:i:s') || date_format($trial_end, 'Y-m-d H:i:s') == date_format($unlimited, 'Y-m-d H:i:s'))) { + $price = $this->currency->format($order_recurring['trial_price'], $order_info['currency_code'], false, false); + $frequency = $order_recurring['trial_frequency']; + $cycle = $order_recurring['trial_cycle']; + $next_payment = $this->calculateSchedule($frequency, $next_payment, $cycle); + } elseif ((date_format($today, 'Y-m-d H:i:s') > date_format($next_payment, 'Y-m-d H:i:s')) && (date_format($subscription_end, 'Y-m-d H:i:s') > date_format($today, 'Y-m-d H:i:s') || date_format($subscription_end, 'Y-m-d H:i:s') == date_format($unlimited, 'Y-m-d H:i:s'))) { + $price = $this->currency->format($order_recurring['recurring_price'], $order_info['currency_code'], false, false); + $frequency = $order_recurring['recurring_frequency']; + $cycle = $order_recurring['recurring_cycle']; + $next_payment = $this->calculateSchedule($frequency, $next_payment, $cycle); + } else { + continue; + } - $result = $this->createPayment($order_info, $paypal_order_info, $price, $order_recurring['order_recurring_id'], $order_recurring['recurring_name']); + $result = $this->createPayment($order_info, $paypal_order_info, $price, $order_recurring['order_recurring_id'], $order_recurring['recurring_name']); - $transaction_status = ''; - $transaction_id = ''; - $currency_code = ''; - $amount = ''; + $transaction_status = ''; + $transaction_id = ''; + $currency_code = ''; + $amount = ''; - if ($transaction_method == 'authorize') { - if (isset($result['purchase_units'][0]['payments']['authorizations'][0]['status']) && isset($result['purchase_units'][0]['payments']['authorizations'][0]['seller_protection']['status'])) { - $transaction_id = $result['purchase_units'][0]['payments']['authorizations'][0]['id']; - $transaction_status = $result['purchase_units'][0]['payments']['authorizations'][0]['status']; - $currency_code = $result['purchase_units'][0]['payments']['authorizations'][0]['amount']['currency_code']; - $amount = $result['purchase_units'][0]['payments']['authorizations'][0]['amount']['value']; - } - } else { - if (isset($result['purchase_units'][0]['payments']['captures'][0]['status']) && isset($result['purchase_units'][0]['payments']['captures'][0]['seller_protection']['status'])) { - $transaction_id = $result['purchase_units'][0]['payments']['captures'][0]['id']; - $transaction_status = $result['purchase_units'][0]['payments']['captures'][0]['status']; - $currency_code = $result['purchase_units'][0]['payments']['captures'][0]['amount']['currency_code']; - $amount = $result['purchase_units'][0]['payments']['captures'][0]['amount']['value']; + if ($transaction_method == 'authorize') { + if (isset($result['purchase_units'][0]['payments']['authorizations'][0]['status']) && isset($result['purchase_units'][0]['payments']['authorizations'][0]['seller_protection']['status'])) { + $transaction_id = $result['purchase_units'][0]['payments']['authorizations'][0]['id']; + $transaction_status = $result['purchase_units'][0]['payments']['authorizations'][0]['status']; + $currency_code = $result['purchase_units'][0]['payments']['authorizations'][0]['amount']['currency_code']; + $amount = $result['purchase_units'][0]['payments']['authorizations'][0]['amount']['value']; + } + } else { + if (isset($result['purchase_units'][0]['payments']['captures'][0]['status']) && isset($result['purchase_units'][0]['payments']['captures'][0]['seller_protection']['status'])) { + $transaction_id = $result['purchase_units'][0]['payments']['captures'][0]['id']; + $transaction_status = $result['purchase_units'][0]['payments']['captures'][0]['status']; + $currency_code = $result['purchase_units'][0]['payments']['captures'][0]['amount']['currency_code']; + $amount = $result['purchase_units'][0]['payments']['captures'][0]['amount']['value']; + } } - } - if ($transaction_id && $transaction_status && $currency_code && $amount) { - if (($transaction_status == 'CREATED') || ($transaction_status == 'COMPLETED') || ($transaction_status == 'PENDING')) { - $order_recurring_transaction_data = array( - 'order_recurring_id' => $order_recurring['order_recurring_id'], - 'reference' => $transaction_id, - 'type' => '1', - 'amount' => $amount - ); + if ($transaction_id && $transaction_status && $currency_code && $amount) { + if (($transaction_status == 'CREATED') || ($transaction_status == 'COMPLETED') || ($transaction_status == 'PENDING')) { + $order_recurring_transaction_data = array( + 'order_recurring_id' => $order_recurring['order_recurring_id'], + 'reference' => $transaction_id, + 'type' => '1', + 'amount' => $amount + ); - $this->addOrderRecurringTransaction($order_recurring_transaction_data); + $this->addOrderRecurringTransaction($order_recurring_transaction_data); - $this->editPayPalOrderRecurringNextPayment($order_recurring['order_recurring_id'], date_format($next_payment, 'Y-m-d H:i:s')); - } else { - $order_recurring_transaction_data = array( - 'order_recurring_id' => $order_recurring['order_recurring_id'], - 'reference' => $transaction_id, - 'type' => '4', - 'amount' => $amount - ); + $this->editPayPalOrderRecurringNextPayment($order_recurring['order_recurring_id'], date_format($next_payment, 'Y-m-d H:i:s')); + } else { + $order_recurring_transaction_data = array( + 'order_recurring_id' => $order_recurring['order_recurring_id'], + 'reference' => $transaction_id, + 'type' => '4', + 'amount' => $amount + ); - $this->addOrderRecurringTransaction($order_recurring_transaction_data); + $this->addOrderRecurringTransaction($order_recurring_transaction_data); + } } } } @@ -503,6 +644,13 @@ public function createPayment($order_data, $paypal_order_data, $price, $order_re $paypal_order_info['payment_source'][$paypal_order_data['payment_method']]['vault_id'] = $paypal_order_data['vault_id']; + if ($paypal_order_data['payment_method'] == 'card') { + $paypal_order_info['payment_source'][$paypal_order_data['payment_method']]['stored_credential']['payment_initiator'] = 'MERCHANT'; + $paypal_order_info['payment_source'][$paypal_order_data['payment_method']]['stored_credential']['payment_type'] = 'UNSCHEDULED'; + $paypal_order_info['payment_source'][$paypal_order_data['payment_method']]['stored_credential']['usage'] = 'SUBSEQUENT'; + $paypal_order_info['payment_source'][$paypal_order_data['payment_method']]['stored_credential']['previous_transaction_reference'] = $paypal_order_data['transaction_id']; + } + $result = $paypal->createOrder($paypal_order_info); $errors = array(); @@ -602,21 +750,25 @@ public function log($data, $title = '') { } public function update() { + $this->db->query("DROP TABLE IF EXISTS `" . DB_PREFIX . "paypal_checkout_integration_customer_token`"); $this->db->query("DROP TABLE IF EXISTS `" . DB_PREFIX . "paypal_checkout_integration_order`"); $this->db->query("DROP TABLE IF EXISTS `" . DB_PREFIX . "paypal_checkout_integration_order_recurring`"); - $this->db->query("CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "paypal_checkout_integration_order` (`order_id` INT(11) NOT NULL, `transaction_id` VARCHAR(20) NOT NULL, `transaction_status` VARCHAR(20) NULL, `payment_method` VARCHAR(20) NULL, `vault_id` VARCHAR(50) NULL, `vault_customer_id` VARCHAR(50) NULL, `environment` VARCHAR(20) NULL, PRIMARY KEY (`order_id`, `transaction_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci"); + $this->db->query("CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "paypal_checkout_integration_customer_token` (`customer_id` INT(11) NOT NULL, `payment_method` VARCHAR(20) NOT NULL, `vault_id` VARCHAR(50) NOT NULL, `vault_customer_id` VARCHAR(50) NOT NULL, `card_type` VARCHAR(40) NOT NULL, `card_nice_type` VARCHAR(40) NOT NULL, `card_last_digits` VARCHAR(4) NOT NULL, `card_expiry` VARCHAR(20) NOT NULL, `main_token_status` TINYINT(1) NOT NULL, PRIMARY KEY (`customer_id`, `payment_method`, `vault_id`), KEY `vault_customer_id` (`vault_customer_id`), KEY `main_token_status` (`main_token_status`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci"); + $this->db->query("CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "paypal_checkout_integration_order` (`order_id` INT(11) NOT NULL, `paypal_order_id` VARCHAR(20) NOT NULL, `transaction_id` VARCHAR(20) NOT NULL, `transaction_status` VARCHAR(20) NOT NULL, `payment_method` VARCHAR(20) NOT NULL, `vault_id` VARCHAR(50) NOT NULL, `vault_customer_id` VARCHAR(50) NOT NULL, `card_type` VARCHAR(40) NOT NULL, `card_nice_type` VARCHAR(40) NOT NULL, `card_last_digits` VARCHAR(4) NOT NULL, `card_expiry` VARCHAR(20) NOT NULL, `environment` VARCHAR(20) NOT NULL, PRIMARY KEY (`order_id`), KEY `paypal_order_id` (`paypal_order_id`), KEY `transaction_id` (`transaction_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci"); $this->db->query("CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "paypal_checkout_integration_order_recurring` (`paypal_order_recurring_id` INT(11) NOT NULL AUTO_INCREMENT, `order_id` INT(11) NOT NULL, `order_recurring_id` INT(11) NOT NULL, `date_added` DATETIME NOT NULL, `date_modified` DATETIME NOT NULL, `next_payment` DATETIME NOT NULL, `trial_end` DATETIME DEFAULT NULL, `subscription_end` DATETIME DEFAULT NULL, `currency_code` CHAR(3) NOT NULL, `total` DECIMAL(10, 2) NOT NULL, PRIMARY KEY (`paypal_order_recurring_id`), KEY (`order_id`), KEY (`order_recurring_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci"); $this->db->query("DELETE FROM `" . DB_PREFIX . "event` WHERE `code` = 'paypal_order_info'"); $this->db->query("DELETE FROM `" . DB_PREFIX . "event` WHERE `code` = 'paypal_header'"); $this->db->query("DELETE FROM `" . DB_PREFIX . "event` WHERE `code` = 'paypal_extension_get_extensions'"); $this->db->query("DELETE FROM `" . DB_PREFIX . "event` WHERE `code` = 'paypal_order_delete_order'"); + $this->db->query("DELETE FROM `" . DB_PREFIX . "event` WHERE `code` = 'paypal_customer_delete_customer'"); $this->db->query("INSERT INTO `" . DB_PREFIX . "event` SET `code` = 'paypal_order_info', `trigger` = 'admin/view/sale/order_info/before', `action` = 'extension/payment/paypal/order_info_before', `sort_order` = '0', `status` = '1'"); $this->db->query("INSERT INTO `" . DB_PREFIX . "event` SET `code` = 'paypal_header', `trigger` = 'catalog/controller/common/header/before', `action` = 'extension/payment/paypal/header_before', `sort_order` = '0', `status` = '1'"); $this->db->query("INSERT INTO `" . DB_PREFIX . "event` SET `code` = 'paypal_extension_get_extensions', `trigger` = 'catalog/model/setting/extension/getExtensions/after', `action` = 'extension/payment/paypal/extension_get_extensions_after', `sort_order` = '0', `status` = '1'"); $this->db->query("INSERT INTO `" . DB_PREFIX . "event` SET `code` = 'paypal_order_delete_order', `trigger` = 'catalog/model/checkout/order/deleteOrder/before', `action` = 'extension/payment/paypal/order_delete_order_before', `sort_order` = '0', `status` = '1'"); + $this->db->query("INSERT INTO `" . DB_PREFIX . "event` SET `code` = 'paypal_customer_delete_customer', `trigger` = 'admin/model/customer/customer/deleteCustomer/before', `action` = 'extension/payment/paypal/customer_delete_customer_before', `sort_order` = '0', `status` = '1'"); // Setting $_config = new Config(); diff --git a/upload/catalog/view/javascript/paypal/paypal.js b/upload/catalog/view/javascript/paypal/paypal.js index 01f9d712837..af03284fcb5 100644 --- a/upload/catalog/view/javascript/paypal/paypal.js +++ b/upload/catalog/view/javascript/paypal/paypal.js @@ -132,8 +132,12 @@ var PayPalAPI = (function () { paypal_script[script_count].src = src; paypal_script[script_count].setAttribute('data-partner-attribution-id', paypal_data['partner_attribution_id']); paypal_script[script_count].setAttribute('data-client-token', paypal_data['client_token']); - paypal_script[script_count].setAttribute('data-namespace', 'PayPalSDK'); + paypal_script[script_count].setAttribute('data-namespace', 'PayPalSDK'); + if (paypal_data['id_token']) { + paypal_script[script_count].setAttribute('data-user-id-token', paypal_data['id_token']); + } + paypal_script[script_count].async = false; paypal_script[script_count].onload = readyPayPalSDK(); @@ -169,8 +173,7 @@ var PayPalAPI = (function () { label: paypal_data['button_label'], tagline: ((paypal_data['page_code'] != 'checkout') ? paypal_data['button_tagline'] : 'false') }, - // Set up the transaction - createOrder: function(data, actions) { + createOrder: function() { paypal_order_id = false; product_data = $('#product input[type=\'text\'], #product input[type=\'hidden\'], #product input[type=\'radio\']:checked, #product input[type=\'checkbox\']:checked, #product select, #product textarea').serialize(); @@ -178,7 +181,7 @@ var PayPalAPI = (function () { $.ajax({ method: 'post', url: 'index.php?route=extension/payment/paypal/createOrder', - data: {'page_code' : paypal_data['page_code'], 'payment_type' : 'button', 'product' : product_data}, + data: {'page_code': paypal_data['page_code'], 'payment_type': 'button', 'product': product_data}, dataType: 'json', async: false, success: function(json) { @@ -193,23 +196,15 @@ var PayPalAPI = (function () { return paypal_order_id; }, - // Finalize the transaction - onApprove: function(data, actions) { - // Call your server to save the transaction - restart = false; - + onApprove: function(data) { $.ajax({ method: 'post', url: 'index.php?route=extension/payment/paypal/approveOrder', - data: {'page_code' : paypal_data['page_code'], 'payment_type' : 'button', 'paypal_order_id': data.orderID}, + data: {'page_code': paypal_data['page_code'], 'payment_type': 'button', 'paypal_order_id': data.orderID}, dataType: 'json', async: false, success: function(json) { showPayPalAlert(json); - - if (json['restart']) { - restart = json['restart']; - } if (json['url']) { location = json['url']; @@ -219,10 +214,6 @@ var PayPalAPI = (function () { console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); } }); - - if (restart) { - return actions.restart(); - } } }; @@ -264,7 +255,87 @@ var PayPalAPI = (function () { } } - if (paypal_data['components'].includes('hosted-fields') && $('#paypal_card').length && !$('#paypal_card_form').find('iframe').length) { + if (paypal_data['card_customer_tokens'] && $('#paypal_card_tokens').length && !$('#paypal_card_tokens_container').html()) { + $('#paypal_card_tokens').css('text-align', paypal_data['card_align']); + + if (paypal_data['card_width']) { + $('#paypal_card_tokens_container').css('display', 'inline-block'); + $('#paypal_card_tokens_container').css('width', paypal_data['card_width']); + } else { + $('#paypal_card_tokens_container').css('display', 'block'); + $('#paypal_card_tokens_container').css('width', 'auto'); + } + + $.each(paypal_data['card_customer_tokens'], function(index, card_customer_token) { + html = '
' + card_customer_token['card_number'] + '
'; + + $('#paypal_card_tokens_container').append(html); + }); + + $('#paypal_card_tokens_container').delegate('.card-token-button', 'click', function(event) { + event.preventDefault(); + + var paypal_card_token = $(this).parents('.paypal-card-token'); + var card_token_index = $(this).attr('index'); + + paypal_order_id = false; + + $.ajax({ + method: 'post', + url: 'index.php?route=extension/payment/paypal/createOrder', + data: {'page_code': paypal_data['page_code'], 'payment_type': 'card', 'index': card_token_index}, + dataType: 'json', + beforeSend: function() { + paypal_card_token.addClass('paypal-spinner'); + }, + success: function(json) { + showPayPalAlert(json); + + if (json['url']) { + location = json['url']; + } + }, + complete: function() { + paypal_card_token.removeClass('paypal-spinner'); + }, + error: function(xhr, ajaxOptions, thrownError) { + console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); + } + }); + }); + + $('#paypal_card_tokens_container').delegate('.card-token-delete-button', 'click', function(event) { + event.preventDefault(); + + var paypal_card_token = $(this).parents('.paypal-card-token'); + var card_token_index = $(this).attr('index'); + + $.ajax({ + method: 'post', + url: 'index.php?route=extension/payment/paypal/deleteCustomerToken', + data: {'index': card_token_index}, + dataType: 'json', + beforeSend: function() { + paypal_card_token.addClass('paypal-spinner'); + }, + success: function(json) { + showPayPalAlert(json); + + if (json['success']) { + paypal_card_token.remove(); + } + }, + error: function(xhr, ajaxOptions, thrownError) { + console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); + }, + complete: function() { + paypal_card_token.removeClass('paypal-spinner'); + } + }); + }); + } + + if (paypal_data['components'].includes('card-fields') && $('#paypal_card').length && !$('#paypal_card_form').find('iframe').length) { $('#paypal_card').css('text-align', paypal_data['card_align']); if (paypal_data['card_width']) { @@ -276,171 +347,124 @@ var PayPalAPI = (function () { } try { - // Check if card fields are eligible to render for the buyer's country. The card fields are not eligible in all countries where buyers are located. - if (PayPalSDK.HostedFields.isEligible() === true) { - var paypal_card_form = document.querySelector('#paypal_card_form'); - var paypal_button_submit = document.querySelector('#paypal_button_submit'); - - PayPalSDK.HostedFields.render({ - styles: { - 'input': { - 'color': '#282c37', - 'transition': 'color 0.1s', - 'line-height': '3' - }, - 'input.invalid': { - 'color': '#E53A40' - }, - ':-ms-input-placeholder': { - 'color': 'rgba(0,0,0,0.6)' + var paypal_card = PayPalSDK.CardFields({ + style: { + 'input': { + 'font-size': '1rem', + 'color': '#282c37', + 'transition': 'color 0.1s', + 'padding': '0.75rem 0.75rem', + } + }, + createOrder: function() { + paypal_order_id = false; + + var card_save = ($('#paypal_card_form #paypal_card_save:checked').length ? $('#paypal_card_form #paypal_card_save:checked').val() : 0); + + $.ajax({ + method: 'post', + url: 'index.php?route=extension/payment/paypal/createOrder', + data: {'page_code': paypal_data['page_code'], 'payment_type': 'card', 'card_save': card_save}, + dataType: 'json', + async: false, + success: function(json) { + showPayPalAlert(json); + + paypal_order_id = json['paypal_order_id']; }, - ':-moz-placeholder': { - 'color': 'rgba(0,0,0,0.6)' + error: function(xhr, ajaxOptions, thrownError) { + console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); } - }, - fields: { - number: { - selector: '#card_number', - placeholder: '#### #### #### ####' + }); + + return paypal_order_id; + }, + onApprove: function(data) { + var card_save = ($('#paypal_card_form #paypal_card_save:checked').length ? $('#paypal_card_form #paypal_card_save:checked').val() : 0); + var card_type = $('#paypal_card_form').attr('card_type'); + var card_nice_type = $('#paypal_card_form').attr('card_nice_type'); + + $.ajax({ + method: 'post', + url: 'index.php?route=extension/payment/paypal/approveOrder', + data: {'page_code': paypal_data['page_code'], 'payment_type': 'card', 'card_save': card_save, 'card_type': card_type, 'card_nice_type': card_nice_type, 'paypal_order_id': data.orderID}, + dataType: 'json', + async: false, + success: function(json) { + showPayPalAlert(json); + + if (json['url']) { + location = json['url']; + } }, - cvv: { - selector: '#cvv', - placeholder: '###' + error: function(xhr, ajaxOptions, thrownError) { + console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); }, - expirationDate: { - selector: '#expiration_date', - placeholder: 'MM / YYYY' + complete: function() { + $('#paypal_card_container').removeClass('paypal-spinner'); } - }, - createOrder: function(data, actions) { - paypal_order_id = false; - - $.ajax({ - method: 'post', - url: 'index.php?route=extension/payment/paypal/createOrder', - data: {'page_code' : paypal_data['page_code'], 'payment_type' : 'card'}, - dataType: 'json', - async: false, - success: function(json) { - showPayPalAlert(json); - - paypal_order_id = json['paypal_order_id']; - }, - error: function(xhr, ajaxOptions, thrownError) { - console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); - } - }); - - return paypal_order_id; - } - }).then(function(hostedFieldsInstance) { - hostedFieldsInstance.on('blur', function (event) { - console.log('CCF Event "blur", state=' + hostedFieldsInstance.getState() + ', event=' + event); - }); - - hostedFieldsInstance.on('focus', function (event) { - console.log('CCF Event "focus", state=' + hostedFieldsInstance.getState() + ', event=' + event); }); + }, + inputEvents: { + onChange: function(data) { + console.log('CCF Event "change", state=' + paypal_card.getState() + ', event=' + data); + + $('#paypal_card_form').removeClass().addClass('well'); + $('#paypal_card_form').removeAttr(); + + if (data.cards.length === 1) { + $('#paypal_card_form').addClass(data.cards[0].type); + $('#paypal_card_form').attr('card_type', data.cards[0].type); + $('#paypal_card_form').attr('card_nice_type', data.cards[0].niceType); + } - hostedFieldsInstance.on('validityChange', function (event) { - console.log('CCF Event "validityChange", state=' + hostedFieldsInstance.getState() + ',event=' + event); - - // Check if all fields are valid, then show submit button - var formValid = Object.keys(event.fields).every(function (key) { - return event.fields[key].isValid; - }); - - if (formValid) { - $('#paypal_button_submit').addClass('show-button'); + if (data.isFormValid) { + $('#paypal_card_button').addClass('show-button'); } else { - $('#paypal_button_submit').removeClass('show-button'); + $('#paypal_card_button').removeClass('show-button'); } - }); - - hostedFieldsInstance.on('notEmpty', function (event) { - console.log('CCF Event "notEmpty", state=' + hostedFieldsInstance.getState() + ', event=' + event); - }); - - hostedFieldsInstance.on('empty', function (event) { - console.log('CCF Event "empty", state=' + hostedFieldsInstance.getState() + ',event=' + event); - - $(paypal_card_form).removeClass().addClass('well'); - $('#card_image').removeClass(); - }); - - hostedFieldsInstance.on('cardTypeChange', function (event) { - console.log('CCF Event "cardTypeChange", state=' + hostedFieldsInstance.getState() + ',event=' + event); - - $(paypal_card_form).removeClass().addClass('well'); - $('#card_image').removeClass(); - - // Change card bg depending on card type - if (event.cards.length === 1) { - $(paypal_card_form).addClass(event.cards[0].type); - $('#card_image').addClass(event.cards[0].type); - - // Change the CVV length for AmericanExpress cards - if (event.cards[0].code.size === 4) { - hostedFieldsInstance.setAttribute({ - field: 'cvv', - attribute: 'placeholder', - value: '####' - }); - } else { - hostedFieldsInstance.setAttribute({ - field: 'cvv', - attribute: 'placeholder', - value: '###' - }); - } - } else { - hostedFieldsInstance.setAttribute({ - field: 'cvv', - attribute: 'placeholder', - value: '###' - }); + }, + onFocus: function(data) { + console.log('CCF Event "focus", state=' + paypal_card.getState() + ', event=' + data); + }, + onBlur: function(data) { + console.log('CCF Event "blur", state=' + paypal_card.getState() + ', event=' + data); + }, + onInputSubmitRequest: function(data) { + console.log('CCF Event "input submit request", state=' + paypal_card.getState() + ', event=' + data); + + if (data.isFormValid) { + $('#paypal_card_button').addClass('show-button'); + } else { + $('#paypal_card_button').removeClass('show-button'); } - }); - - paypal_button_submit.addEventListener('click', function (event) { - event.preventDefault(); + } + } + }); + + if (paypal_card.isEligible()) { + paypal_card.NameField().render('#card_holder_name'); + paypal_card.NumberField().render('#card_number'); + paypal_card.ExpiryField().render('#expiration_date'); + paypal_card.CVVField().render('#cvv'); - if ($('#paypal_button_submit').hasClass('show-button')) { - console.log('CCF Event "click", state=' + hostedFieldsInstance.getState() + ',event=' + event); + var paypal_card_button = document.querySelector('#paypal_card_button'); + + paypal_card_button.addEventListener('click', function(event) { + event.preventDefault(); + + if ($('#paypal_card_button').hasClass('show-button')) { + console.log('CCF Event "click", state=' + paypal_card.getState() + ', event=' + event); - $('#paypal_card_container').addClass('paypal-spinner'); - - hostedFieldsInstance.submit({ - // Need to specify when triggering 3D Secure authentication - contingencies: (paypal_data['card_secure_status'] ? ['3D_SECURE'] : '') - - }).then(function (payload) { - console.log('PayPal CCF submitted:', payload); + $('#paypal_card_container').addClass('paypal-spinner'); - $.ajax({ - method: 'post', - url: 'index.php?route=extension/payment/paypal/approveOrder', - data: {'page_code' : paypal_data['page_code'], 'payment_type' : 'card', 'payload': JSON.stringify(payload)}, - dataType: 'json', - async: false, - success: function(json) { - showPayPalAlert(json); - - if (json['url']) { - location = json['url']; - } - }, - error: function(xhr, ajaxOptions, thrownError) { - console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); - }, - complete: function() { - $('#paypal_card_container').removeClass('paypal-spinner'); - } - }); - }); - } - }, false); - }); + paypal_card.submit().then(function() { + console.log('PayPal CCF submitted:', paypal_card); + }).catch(function(error) { + console.error('PayPal CCF submit erred:', error); + }); + } + }, false); } else { console.log('Not eligible for CCF'); } @@ -451,17 +475,7 @@ var PayPalAPI = (function () { $('#paypal_card_container').removeClass('paypal-spinner'); } - if (paypal_data['components'].includes('messages') && $('#paypal_message').length && !$('#paypal_message_container').html()) { - $('#paypal_message').css('text-align', paypal_data['message_align']); - - if (paypal_data['message_width']) { - $('#paypal_message_container').css('display', 'inline-block'); - $('#paypal_message_container').css('width', paypal_data['message_width']); - } else { - $('#paypal_message_container').css('display', 'block'); - $('#paypal_message_container').css('width', 'auto'); - } - + if (paypal_data['components'].includes('messages') && $('#paypal_message').length && !$('#paypal_message_container').html()) { var paypal_message = document.createElement('div'); paypal_message.setAttribute('data-pp-message', ''); @@ -479,7 +493,7 @@ var PayPalAPI = (function () { } if (paypal_data['page_code'] == 'checkout') { - paypal_message.setAttribute('data-pp-placement', 'checkout'); + paypal_message.setAttribute('data-pp-placement', 'payment'); } paypal_message.setAttribute('data-pp-amount', paypal_data['message_amount']); @@ -518,7 +532,7 @@ var PayPalAPI = (function () { $.ajax({ method: 'post', url: 'index.php?route=extension/payment/paypal/createOrder', - data: {'page_code' : paypal_data['page_code'], 'payment_type' : 'googlepay_button'}, + data: {'page_code': paypal_data['page_code'], 'payment_type': 'googlepay_button'}, dataType: 'json', async: false, success: function(json) { @@ -543,7 +557,7 @@ var PayPalAPI = (function () { $.ajax({ method: 'post', url: 'index.php?route=extension/payment/paypal/approveOrder', - data: {'page_code' : paypal_data['page_code'], 'payment_type' : 'googlepay_button', 'paypal_order_id': paypal_order_id}, + data: {'page_code': paypal_data['page_code'], 'payment_type': 'googlepay_button', 'paypal_order_id': paypal_order_id}, dataType: 'json', async: false, success: function(json) { @@ -566,7 +580,7 @@ var PayPalAPI = (function () { $.ajax({ method: 'post', url: 'index.php?route=extension/payment/paypal/approveOrder', - data: {'page_code' : paypal_data['page_code'], 'payment_type' : 'googlepay_button', 'paypal_order_id': paypal_order_id}, + data: {'page_code': paypal_data['page_code'], 'payment_type': 'googlepay_button', 'paypal_order_id': paypal_order_id}, dataType: 'json', async: false, success: function(json) { @@ -794,7 +808,7 @@ var PayPalAPI = (function () { $.ajax({ method: 'post', url: 'index.php?route=extension/payment/paypal/createOrder', - data: {'page_code' : paypal_data['page_code'], 'payment_type' : 'applepay_button'}, + data: {'page_code': paypal_data['page_code'], 'payment_type': 'applepay_button'}, dataType: 'json', async: false, success: function(json) { @@ -817,7 +831,7 @@ var PayPalAPI = (function () { $.ajax({ method: 'post', url: 'index.php?route=extension/payment/paypal/approveOrder', - data: {'page_code' : paypal_data['page_code'], 'payment_type' : 'applepay_button', 'paypal_order_id': paypal_order_id}, + data: {'page_code': paypal_data['page_code'], 'payment_type': 'applepay_button', 'paypal_order_id': paypal_order_id}, dataType: 'json', async: false, success: function(json) { diff --git a/upload/catalog/view/theme/default/stylesheet/paypal/card.css b/upload/catalog/view/theme/default/stylesheet/paypal/card.css index 2e30a933677..0e40f1a6dc8 100644 --- a/upload/catalog/view/theme/default/stylesheet/paypal/card.css +++ b/upload/catalog/view/theme/default/stylesheet/paypal/card.css @@ -1,38 +1,174 @@ +#paypal_card_tokens .paypal-card-token { + position: relative; + display: table; + width: 100%; + border-collapse: separate; + margin-bottom: 1em; +} +#paypal_card_tokens .card-token-button { + position: relative; + display: table-cell; + width: 100%; + height: 60px; + padding: 0px 8px 0px 80px; + color: #282c37; + background: #FFFFFF; + font-size: 15px; + text-align: left; + vertical-align: middle; + white-space: normal; + border: 1px solid #909697; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; + -webkit-appearance: none; + box-shadow: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + overflow: hidden; + z-index: 0; + outline: 0; +} +#paypal_card_tokens .card-token-delete-button { + position: relative; + display: table-cell; + width: 1%; + height: 60px; + padding: 0px 16px; + color: #282c37; + background: #FFFFFF; + font-size: 14px; + text-align: center; + vertical-align: middle; + white-space: nowrap; + border: 1px solid #909697; + border-left: none; + border-top-left-radius: 0px; + border-bottom-left-radius: 0px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + -webkit-appearance: none; + box-shadow: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + overflow: hidden; + z-index: 0; + outline: 0; +} +#paypal_card_tokens .card-token-button:hover, #paypal_card_tokens .card-token-delete-button:hover { + background: #f5f5f5; +} +#paypal_card_tokens .card-token-button:active, #paypal_card_tokens .card-token-delete-button:active { + -webkit-animation: cardIntro 200ms cubic-bezier(0.2, 1.3, 0.7, 1); + animation: cardIntro 200ms cubic-bezier(0.2, 1.3, 0.7, 1); +} +#paypal_card_tokens .card-icon { + position: absolute; + display: block; + width: 61px; + height: 36px; + left: 8px; + top: 50%; + margin-top: -18px; + background-repeat: no-repeat; + background-image: url('../../image/paypal/card.svg'); + background-size: 61px 432px; + background-position-x: left; + background-position-y: 0px; + border: none; +} +#paypal_card_tokens .card-icon-american-express { + background-position-y: -36px; +} +#paypal_card_tokens .card-icon-diners-club { + background-position-y: -72px; +} +#paypal_card_tokens .card-icon-discover { + background-position-y: -108px; +} +#paypal_card_tokens .card-icon-jcb { + background-position-y: -144px; +} +#paypal_card_tokens .card-icon-mastercard { + background-position-y: -180px; +} +#paypal_card_tokens .card-icon-maestro { + background-position-y: -216px; +} +#paypal_card_tokens .card-icon-unionpay { + background-position-y: -252px; +} +#paypal_card_tokens .card-icon-visa { + background-position-y: -288px; +} +#paypal_card_tokens .card-icon-elo { + background-position-y: -324px; +} +#paypal_card_tokens .card-icon-hiper { + background-position-y: -360px; +} +#paypal_card_tokens .card-icon-hipercard { + background-position-y: -396px; +} #paypal_card_form { color: #717171; - text-align: center; + text-align: left; transition: all 600ms cubic-bezier(0.2, 1.3, 0.7, 1); -webkit-animation: cardIntro 500ms cubic-bezier(0.2, 1.3, 0.7, 1); animation: cardIntro 500ms cubic-bezier(0.2, 1.3, 0.7, 1); z-index: 1; } -#paypal_card_form.visa { - color: #fff; - background-color: #0D4AA2; -} -#paypal_card_form.master-card { - color: #fff; - background-color: #363636; - background: linear-gradient(115deg, #d82332, #d82332 50%, #f1ad3d 50%, #f1ad3d); -} -#paypal_card_form.maestro { - color: #fff; - background-color: #363636; - background: linear-gradient(115deg, #009ddd, #009ddd 50%, #ed1c2e 50%, #ed1c2e); -} #paypal_card_form.american-express { - color: #fff; + color: #FFFFFF; background-color: #007CC3; } +#paypal_card_form.diners-club { + color: #FFFFFF; + background-color: #0079BE; +} #paypal_card_form.discover { - color: #fff; + color: #FFFFFF; background-color: #ff6000; background: linear-gradient(#d14310, #f7961e); } -#paypal_card_form.unionpay, #paypal_card_form.jcb, #paypal_card_form.diners-club { - color: #fff; +#paypal_card_form.jcb { + color: #FFFFFF; + background-color: #363636; + background: linear-gradient(90deg, #005182, #005182 33%, #BE1833 33% 67%, #00933F 67%, #00933F); +} +#paypal_card_form.mastercard { + color: #FFFFFF; + background-color: #363636; + background: linear-gradient(115deg, #D82332, #D82332 50%, #F1AD3D 50%, #F1AD3D); +} +#paypal_card_form.maestro { + color: #FFFFFF; + background-color: #363636; + background: linear-gradient(115deg, #009DDD, #009DDD 50%, #ED1C2E 50%, #ED1C2E); +} +#paypal_card_form.unionpay { + color: #FFFFFF; background-color: #363636; + background: linear-gradient(100deg, #D10429, #D10429 33%, #022E64 33% 67%, #076F74 67%, #076F74); +} +#paypal_card_form.visa { + color: #FFFFFF; + background-color: #0D4AA2; +} +#paypal_card_form.elo { + color: #FFFFFF; + background-color: #000000; +} +#paypal_card_form.hiper { + color: #FFFFFF; + background-color: #F37421; } +#paypal_card_form.hipercard { + color: #FFFFFF; + background-color: #BA1319 +} +#paypal_card_form .card-info-holder-name, #paypal_card_form .card-info-number, #paypal_card_form .card-info-date-cvv { position: relative; @@ -48,65 +184,23 @@ float: right; margin-bottom: 0.5em; } +#paypal_card_form .card-info-holder-name, #paypal_card_form .card-info-number, #paypal_card_form .card-info-date, #paypal_card_form .card-info-cvv { - transition: -webkit-transform 0.3s; - transition: transform 0.3s; - transition: transform 0.3s, -webkit-transform 0.3s; -} -#paypal_card_form .card-label { - display: block; - margin-bottom: 0.5em; - text-transform: uppercase; + transition: -webkit-transform 0.3s; + transition: transform 0.3s; + transition: transform 0.3s, -webkit-transform 0.3s; } -#paypal_card_form .card-input-container { +#paypal_card_form .card-button { position: relative; - height: 2.75em; - padding: 5px 10px; - margin-bottom: 1em; - background: rgba(255, 255, 255, 0.86); - border: 1px solid #eee; - border-radius: 2px; -} -#paypal_card_form #card_image { - position: absolute; - top: 0px; - right: 2px; - width: 44px; - height: 28px; - background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/346994/card_sprite.png); - background-size: 86px 458px; - border-radius: 4px; - background-position: -100px 0; - background-repeat: no-repeat; -} -#paypal_card_form #card_image.visa { - background-position: 0 -398px; -} -#paypal_card_form #card_image.master-card { - background-position: 0 -281px; -} -#paypal_card_form #card_image.american-express { - background-position: 0 -370px; -} -#paypal_card_form #card_image.discover { - background-position: 0 -163px; + padding: 0rem 0.6rem; } -#paypal_card_form #card_image.maestro { - background-position: 0 -251px; -} -#paypal_card_form #card_image.jcb { - background-position: 0 -221px; -} -#paypal_card_form #card_image.diners-club { - background-position: 0 -133px; -} -#paypal_card_form #paypal_button_submit { +#paypal_card_form .paypal-card-button { width: 100%; - padding: 1em 1em; - color: #fff; - background: #282c37; + padding: 16px 16px; + color: #FFFFFF; + background: #282C37; font-size: 15px; box-shadow: none; -moz-box-shadow: none; @@ -117,14 +211,21 @@ outline: 0; -webkit-appearance: none; } -#paypal_card_form #paypal_button_submit:hover { +#paypal_card_form .paypal-card-button:hover { background: #535b72; } -#paypal_card_form #paypal_button_submit:active { +#paypal_card_form.elo .paypal-card-button { + color: #000000; + background: #FFFFFF; +} +#paypal_card_form.elo .paypal-card-button:hover { + background: #F5F5F5; +} +#paypal_card_form .paypal-card-button:active { -webkit-animation: cardIntro 200ms cubic-bezier(0.2, 1.3, 0.7, 1); animation: cardIntro 200ms cubic-bezier(0.2, 1.3, 0.7, 1); } -#paypal_card_form #paypal_button_submit.show-button { +#paypal_card_form .paypal-card-button.show-button { opacity: 1; cursor: pointer; } \ No newline at end of file diff --git a/upload/catalog/view/theme/default/stylesheet/paypal/paypal.css b/upload/catalog/view/theme/default/stylesheet/paypal/paypal.css index d502481720a..435df514c59 100644 --- a/upload/catalog/view/theme/default/stylesheet/paypal/paypal.css +++ b/upload/catalog/view/theme/default/stylesheet/paypal/paypal.css @@ -34,6 +34,17 @@ width: 100% !important; } } +.paypal-card-tokens { + position: relative; +} +.paypal-card-tokens-container { + position: relative; +} +@media (max-width: 476px) { + .paypal-card-tokens-container { + width: 100% !important; + } +} .paypal-card { position: relative; } @@ -49,6 +60,9 @@ position: relative; margin-bottom: 10px; } +.paypal-message [data-pp-message] > * { + max-width: none !important; +} .paypal-spinner { position: relative; min-height: 20px; diff --git a/upload/catalog/view/theme/default/template/extension/payment/paypal/paypal.twig b/upload/catalog/view/theme/default/template/extension/payment/paypal/paypal.twig index 64aa58d107a..0ba7ef5765c 100644 --- a/upload/catalog/view/theme/default/template/extension/payment/paypal/paypal.twig +++ b/upload/catalog/view/theme/default/template/extension/payment/paypal/paypal.twig @@ -16,25 +16,38 @@ {% endif %} {% if card_status %} +
+
+
-
+
+
+
+
- -
+
-
-
- - +
+ {% if logged %} +
+ +
+ {% endif %} + +
+
+
{% endif %} diff --git a/upload/catalog/view/theme/default/template/extension/payment/paypal/paypal_modal.twig b/upload/catalog/view/theme/default/template/extension/payment/paypal/paypal_modal.twig index 5dc5a220707..0115a78ec1e 100644 --- a/upload/catalog/view/theme/default/template/extension/payment/paypal/paypal_modal.twig +++ b/upload/catalog/view/theme/default/template/extension/payment/paypal/paypal_modal.twig @@ -23,25 +23,38 @@ {% endif %} {% if card_status %} +
+
+
-
+
+
+
+
- -
+
-
-
- - +
+ {% if logged %} +
+ +
+ {% endif %} + +
+
+
{% endif %} diff --git a/upload/catalog/view/theme/default/template/extension/payment/paypal/paypal_paylater.twig b/upload/catalog/view/theme/default/template/extension/payment/paypal/paypal_paylater.twig index f0577f1233b..f3a4c3c42f8 100644 --- a/upload/catalog/view/theme/default/template/extension/payment/paypal/paypal_paylater.twig +++ b/upload/catalog/view/theme/default/template/extension/payment/paypal/paypal_paylater.twig @@ -16,7 +16,7 @@ if (typeof PayPalAPI !== 'undefined') { {% else %}
- +