diff options
Diffstat (limited to 'public/catalog/controller/extension')
98 files changed, 21436 insertions, 0 deletions
diff --git a/public/catalog/controller/extension/advertise/google.php b/public/catalog/controller/extension/advertise/google.php new file mode 100644 index 0000000..aa42410 --- /dev/null +++ b/public/catalog/controller/extension/advertise/google.php @@ -0,0 +1,380 @@ +<?php + +use \googleshopping\traits\StoreLoader; +use \googleshopping\traits\LibraryLoader; + +class ControllerExtensionAdvertiseGoogle extends Controller { + use StoreLoader; + use LibraryLoader; + + private $store_id = 0; + + public function __construct($registry) { + parent::__construct($registry); + + if (getenv("ADVERTISE_GOOGLE_STORE_ID")) { + $this->store_id = (int)getenv("ADVERTISE_GOOGLE_STORE_ID"); + } else { + $this->store_id = (int)$this->config->get('config_store_id'); + } + + $this->loadStore($this->store_id); + } + + public function google_global_site_tag(&$route, &$data, &$output) { + // In case the extension is disabled, do nothing + if (!$this->setting->get('advertise_google_status')) { + return; + } + + // If there is no tracker, do nothing + if (!$this->setting->has('advertise_google_conversion_tracker')) { + return; + } + + $tracker = $this->setting->get('advertise_google_conversion_tracker'); + + // Insert the tags before the closing <head> tag + $output = str_replace('</head>', $tracker['google_global_site_tag'] . '</head>', $output); + } + + public function before_checkout_success(&$route, &$data) { + // In case the extension is disabled, do nothing + if (!$this->setting->get('advertise_google_status')) { + return; + } + + // If there is no tracker, do nothing + if (!$this->setting->has('advertise_google_conversion_tracker')) { + return; + } + + // In case there is no order, do nothing + if (!isset($this->session->data['order_id'])) { + return; + } + + if (!$this->registry->has('googleshopping')) { + $this->loadLibrary($this->store_id); + } + + $this->load->model('checkout/order'); + $this->load->model('extension/advertise/google'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $tracker = $this->setting->get('advertise_google_conversion_tracker'); + $currency = $order_info['currency_code']; + + $total = $this->googleshopping->convertAndFormat($order_info['total'], $currency); + + $search = array( + '{VALUE}', + '{CURRENCY}' + ); + + $replace = array( + $total, + $currency + ); + + $snippet = str_replace($search, $replace, $tracker['google_event_snippet']); + + // Store the snippet to display it in the order success view + $tax = 0; + $shipping = 0; + $coupon = $this->model_extension_advertise_google->getCoupon($order_info['order_id']); + + foreach ($this->model_checkout_order->getOrderTotals($order_info['order_id']) as $order_total) { + if ($order_total['code'] == 'shipping') { + $shipping += $this->googleshopping->convertAndFormat($order_total['value'], $currency); + } + + if ($order_total['code'] == 'tax') { + $tax += $this->googleshopping->convertAndFormat($order_total['value'], $currency); + } + } + + $order_products = $this->model_checkout_order->getOrderProducts($order_info['order_id']); + + foreach ($order_products as &$order_product) { + $order_product['option'] = $this->model_checkout_order->getOrderOptions($order_info['order_id'], $order_product['order_product_id']); + } + + $purchase_data = array( + 'transaction_id' => $order_info['order_id'], + 'value' => $total, + 'currency' => $currency, + 'tax' => $tax, + 'shipping' => $shipping, + 'items' => $this->model_extension_advertise_google->getRemarketingItems($order_products, $order_info['store_id']), + 'ecomm_prodid' => $this->model_extension_advertise_google->getRemarketingProductIds($order_products, $order_info['store_id']) + ); + + if ($coupon !== null) { + $purchase_data['coupon'] = $coupon; + } + + $this->googleshopping->setEventSnippet($snippet); + $this->googleshopping->setPurchaseData($purchase_data); + } + + public function google_dynamic_remarketing_purchase(&$route, &$data, &$output) { + // In case the extension is disabled, do nothing + if (!$this->setting->get('advertise_google_status')) { + return; + } + + // If the library has not been loaded, or if there is no snippet, do nothing + if (!$this->registry->has('googleshopping') || $this->googleshopping->getEventSnippet() === null || $this->googleshopping->getPurchaseData() === null) { + return; + } + + $data['send_to'] = $this->googleshopping->getEventSnippetSendTo(); + + $purchase_data = $this->googleshopping->getPurchaseData(); + + $data['transaction_id'] = $purchase_data['transaction_id']; + $data['value'] = $purchase_data['value']; + $data['currency'] = $purchase_data['currency']; + $data['tax'] = $purchase_data['tax']; + $data['shipping'] = $purchase_data['shipping']; + $data['items'] = json_encode($purchase_data['items']); + $data['ecomm_prodid'] = json_encode($purchase_data['ecomm_prodid']); + $data['ecomm_totalvalue'] = $purchase_data['value']; + + $purchase_snippet = $this->load->view('extension/advertise/google_dynamic_remarketing_purchase', $data); + + // Insert the snippet after the output + $output = str_replace('</body>', $this->googleshopping->getEventSnippet() . $purchase_snippet . '</body>', $output); + } + + public function google_dynamic_remarketing_home(&$route, &$data, &$output) { + // In case the extension is disabled, do nothing + if (!$this->setting->get('advertise_google_status')) { + return; + } + + // If we are not on the home page, do nothing + if (isset($this->request->get['route']) && $this->request->get['route'] != $this->config->get('action_default')) { + return; + } + + if (!$this->registry->has('googleshopping')) { + $this->loadLibrary($this->store_id); + } + + if (null === $this->googleshopping->getEventSnippetSendTo()) { + return; + } + + $data = array(); + $data['send_to'] = $this->googleshopping->getEventSnippetSendTo(); + + $snippet = $this->load->view('extension/advertise/google_dynamic_remarketing_home', $data); + + // Insert the snippet after the output + $output = str_replace('</body>', $snippet . '</body>', $output); + } + + public function google_dynamic_remarketing_searchresults(&$route, &$data, &$output) { + // In case the extension is disabled, do nothing + if (!$this->setting->get('advertise_google_status')) { + return; + } + + // If we are not on the search page, do nothing + if (!isset($this->request->get['route']) || $this->request->get['route'] != 'product/search' || !isset($this->request->get['search'])) { + return; + } + + if (!$this->registry->has('googleshopping')) { + $this->loadLibrary($this->store_id); + } + + if (null === $this->googleshopping->getEventSnippetSendTo()) { + return; + } + + $data = array(); + $data['send_to'] = $this->googleshopping->getEventSnippetSendTo(); + $data['search_term'] = $this->request->get['search']; + + $snippet = $this->load->view('extension/advertise/google_dynamic_remarketing_searchresults', $data); + + // Insert the snippet after the output + $output = str_replace('</body>', $snippet . '</body>', $output); + } + + public function google_dynamic_remarketing_category(&$route, &$data, &$output) { + // In case the extension is disabled, do nothing + if (!$this->setting->get('advertise_google_status')) { + return; + } + + // If we are not on the search page, do nothing + if (!isset($this->request->get['route']) || $this->request->get['route'] != 'product/category') { + return; + } + + if (!$this->registry->has('googleshopping')) { + $this->loadLibrary($this->store_id); + } + + if (null === $this->googleshopping->getEventSnippetSendTo()) { + return; + } + + if (isset($this->request->get['path'])) { + $parts = explode('_', $this->request->get['path']); + $category_id = (int)end($parts); + } else if (isset($this->request->get['category_id'])) { + $category_id = (int)$this->request->get['category_id']; + } else { + $category_id = 0; + } + + $this->load->model('extension/advertise/google'); + + $data = array(); + $data['send_to'] = $this->googleshopping->getEventSnippetSendTo(); + $data['description'] = str_replace('"', '\\"', $this->model_extension_advertise_google->getHumanReadableOpenCartCategory($category_id)); + + $snippet = $this->load->view('extension/advertise/google_dynamic_remarketing_category', $data); + + // Insert the snippet after the output + $output = str_replace('</body>', $snippet . '</body>', $output); + } + + public function google_dynamic_remarketing_product(&$route, &$data, &$output) { + // In case the extension is disabled, do nothing + if (!$this->setting->get('advertise_google_status')) { + return; + } + + // If we do not know the viewed product, do nothing + if (!isset($this->request->get['product_id']) || !isset($this->request->get['route']) || $this->request->get['route'] != 'product/product') { + return; + } + + $this->load->model('catalog/product'); + + $product_info = $this->model_catalog_product->getProduct((int)$this->request->get['product_id']); + + // If product does not exist, do nothing + if (!$product_info) { + return; + } + + if (!$this->registry->has('googleshopping')) { + $this->loadLibrary($this->store_id); + } + + if (null === $this->googleshopping->getEventSnippetSendTo()) { + return; + } + + $this->load->model('extension/advertise/google'); + + $category_name = $this->model_extension_advertise_google->getHumanReadableCategory($product_info['product_id'], $this->store_id); + + $option_map = $this->model_extension_advertise_google->getSizeAndColorOptionMap($product_info['product_id'], $this->store_id); + + $data = array(); + $data['send_to'] = $this->googleshopping->getEventSnippetSendTo(); + $data['option_map'] = json_encode($option_map); + $data['brand'] = $product_info['manufacturer']; + $data['name'] = $product_info['name']; + $data['category'] = str_replace('"', '\\"', $category_name); + + $snippet = $this->load->view('extension/advertise/google_dynamic_remarketing_product', $data); + + // Insert the snippet after the output + $output = str_replace('</body>', $snippet . '</body>', $output); + } + + public function google_dynamic_remarketing_cart(&$route, &$data, &$output) { + // In case the extension is disabled, do nothing + if (!$this->setting->get('advertise_google_status')) { + return; + } + + // If we are not on the cart page, do nothing + if (!isset($this->request->get['route']) || $this->request->get['route'] != 'checkout/cart') { + return; + } + + if (!$this->registry->has('googleshopping')) { + $this->loadLibrary($this->store_id); + } + + if (null === $this->googleshopping->getEventSnippetSendTo()) { + return; + } + + $this->load->model('catalog/product'); + $this->load->model('extension/advertise/google'); + + $data = array(); + $data['send_to'] = $this->googleshopping->getEventSnippetSendTo(); + $data['ecomm_totalvalue'] = $this->cart->getTotal(); + $data['ecomm_prodid'] = json_encode($this->model_extension_advertise_google->getRemarketingProductIds($this->cart->getProducts(), $this->store_id)); + $data['items'] = json_encode($this->model_extension_advertise_google->getRemarketingItems($this->cart->getProducts(), $this->store_id)); + + $snippet = $this->load->view('extension/advertise/google_dynamic_remarketing_cart', $data); + + // Insert the snippet after the output + $output = str_replace('</body>', $snippet . '</body>', $output); + } + + public function cron($cron_id = null, $code = null, $cycle = null, $date_added = null, $date_modified = null) { + $this->loadLibrary($this->store_id); + + if (!$this->validateCRON()) { + // In case this is not a CRON task + return; + } + + $this->load->language('extension/advertise/google'); + + // Reset taxes to use the store address and zone + $this->tax->setShippingAddress($this->config->get('config_country_id'), $this->config->get('config_zone_id')); + $this->tax->setPaymentAddress($this->config->get('config_country_id'), $this->config->get('config_zone_id')); + $this->tax->setStoreAddress($this->config->get('config_country_id'), $this->config->get('config_zone_id')); + + $this->googleshopping->cron(); + } + + protected function validateCRON() { + if (!$this->setting->get('advertise_google_status')) { + // In case the extension is disabled, do nothing + return false; + } + + if (!$this->setting->get('advertise_google_gmc_account_selected')) { + return false; + } + + if (!$this->setting->get('advertise_google_gmc_shipping_taxes_configured')) { + return false; + } + + try { + if (count($this->googleshopping->getTargets($this->store_id)) === 0) { + return false; + } + } catch (\RuntimeException $e) { + return false; + } + + if (isset($this->request->get['cron_token']) && $this->request->get['cron_token'] == $this->config->get('advertise_google_cron_token')) { + return true; + } + + if (defined('ADVERTISE_GOOGLE_ROUTE')) { + return true; + } + + return false; + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/analytics/google.php b/public/catalog/controller/extension/analytics/google.php new file mode 100644 index 0000000..7bb3ddd --- /dev/null +++ b/public/catalog/controller/extension/analytics/google.php @@ -0,0 +1,6 @@ +<?php +class ControllerExtensionAnalyticsGoogle extends Controller { + public function index() { + return html_entity_decode($this->config->get('analytics_google_code'), ENT_QUOTES, 'UTF-8'); + } +} diff --git a/public/catalog/controller/extension/captcha/basic.php b/public/catalog/controller/extension/captcha/basic.php new file mode 100644 index 0000000..f0f3325 --- /dev/null +++ b/public/catalog/controller/extension/captcha/basic.php @@ -0,0 +1,57 @@ +<?php +class ControllerExtensionCaptchaBasic extends Controller { + public function index($error = array()) { + $this->load->language('extension/captcha/basic'); + + if (isset($error['captcha'])) { + $data['error_captcha'] = $error['captcha']; + } else { + $data['error_captcha'] = ''; + } + + $data['route'] = $this->request->get['route']; + + return $this->load->view('extension/captcha/basic', $data); + } + + public function validate() { + $this->load->language('extension/captcha/basic'); + + if (empty($this->session->data['captcha']) || ($this->session->data['captcha'] != $this->request->post['captcha'])) { + return $this->language->get('error_captcha'); + } + } + + public function captcha() { + $this->session->data['captcha'] = substr(sha1(mt_rand()), 17, 6); + + $image = imagecreatetruecolor(150, 35); + + $width = imagesx($image); + $height = imagesy($image); + + $black = imagecolorallocate($image, 0, 0, 0); + $white = imagecolorallocate($image, 255, 255, 255); + $red = imagecolorallocatealpha($image, 255, 0, 0, 75); + $green = imagecolorallocatealpha($image, 0, 255, 0, 75); + $blue = imagecolorallocatealpha($image, 0, 0, 255, 75); + + imagefilledrectangle($image, 0, 0, $width, $height, $white); + imagefilledellipse($image, ceil(rand(5, 145)), ceil(rand(0, 35)), 30, 30, $red); + imagefilledellipse($image, ceil(rand(5, 145)), ceil(rand(0, 35)), 30, 30, $green); + imagefilledellipse($image, ceil(rand(5, 145)), ceil(rand(0, 35)), 30, 30, $blue); + imagefilledrectangle($image, 0, 0, $width, 0, $black); + imagefilledrectangle($image, $width - 1, 0, $width - 1, $height - 1, $black); + imagefilledrectangle($image, 0, 0, 0, $height - 1, $black); + imagefilledrectangle($image, 0, $height - 1, $width, $height - 1, $black); + + imagestring($image, 10, intval(($width - (strlen($this->session->data['captcha']) * 9)) / 2), intval(($height - 15) / 2), $this->session->data['captcha'], $black); + + header('Content-type: image/jpeg'); + + imagejpeg($image); + + imagedestroy($image); + exit(); + } +} diff --git a/public/catalog/controller/extension/captcha/google.php b/public/catalog/controller/extension/captcha/google.php new file mode 100644 index 0000000..ee2e60c --- /dev/null +++ b/public/catalog/controller/extension/captcha/google.php @@ -0,0 +1,38 @@ +<?php +class ControllerExtensionCaptchaGoogle extends Controller { + public function index($error = array()) { + $this->load->language('extension/captcha/google'); + + if (isset($error['captcha'])) { + $data['error_captcha'] = $error['captcha']; + } else { + $data['error_captcha'] = ''; + } + + $data['site_key'] = $this->config->get('captcha_google_key'); + + $data['route'] = $this->request->get['route']; + + return $this->load->view('extension/captcha/google', $data); + } + + public function validate() { + if (empty($this->session->data['gcapcha'])) { + $this->load->language('extension/captcha/google'); + + if (!isset($this->request->post['g-recaptcha-response'])) { + return $this->language->get('error_captcha'); + } + + $recaptcha = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret=' . urlencode($this->config->get('captcha_google_secret')) . '&response=' . $this->request->post['g-recaptcha-response'] . '&remoteip=' . $this->request->server['REMOTE_ADDR']); + + $recaptcha = json_decode($recaptcha, true); + + if ($recaptcha['success']) { + $this->session->data['gcapcha'] = true; + } else { + return $this->language->get('error_captcha'); + } + } + } +} diff --git a/public/catalog/controller/extension/credit_card/sagepay_direct.php b/public/catalog/controller/extension/credit_card/sagepay_direct.php new file mode 100644 index 0000000..f982148 --- /dev/null +++ b/public/catalog/controller/extension/credit_card/sagepay_direct.php @@ -0,0 +1,273 @@ +<?php +class ControllerExtensionCreditCardSagepayDirect extends Controller { + public function index() { + if (!$this->customer->isLogged()) { + $this->session->data['redirect'] = $this->url->link('account/account', '', true); + + $this->response->redirect($this->url->link('account/login', '', true)); + } + + $this->load->language('extension/credit_card/sagepay_direct'); + + $this->load->model('extension/payment/sagepay_direct'); + + $this->document->setTitle($this->language->get('heading_title')); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_home'), + 'href' => $this->url->link('common/home') + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_account'), + 'href' => $this->url->link('account/account', '', true) + ); + + + if (isset($this->session->data['success'])) { + $data['success'] = $this->session->data['success']; + unset($this->session->data['success']); + } else { + $data['success'] = ''; + } + + if (isset($this->session->data['error_warning'])) { + $data['error_warning'] = $this->session->data['error_warning']; + unset($this->session->data['error_warning']); + } else { + $data['error_warning'] = ''; + } + + if ($this->config->get('payment_sagepay_direct_card')) { + $data['cards'] = $this->model_extension_payment_sagepay_direct->getCards($this->customer->getId()); + $data['delete'] = $this->url->link('extension/credit_card/sagepay_direct/delete', 'card_id=', true); + + if (isset($this->request->get['page'])) { + $page = $this->request->get['page']; + } else { + $page = 1; + } + + $cards_total = count($data['cards']); + + $pagination = new Pagination(); + $pagination->total = $cards_total; + $pagination->page = $page; + $pagination->limit = 10; + $pagination->url = $this->url->link('extension/credit_card/sagepay_direct', 'page={page}', true); + + $data['pagination'] = $pagination->render(); + + $data['results'] = sprintf($this->language->get('text_pagination'), ($cards_total) ? (($page - 1) * 10) + 1 : 0, ((($page - 1) * 10) > ($cards_total - 10)) ? $cards_total : ((($page - 1) * 10) + 10), $cards_total, ceil($cards_total / 10)); + } else { + $data['cards'] = false; + $data['pagination'] = false; + $data['results'] = false; + } + + $data['back'] = $this->url->link('account/account', '', true); + $data['add'] = $this->url->link('extension/credit_card/sagepay_direct/add', '', true); + + $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/credit_card/sagepay_direct_list', $data)); + } + + public function add() { + if (!$this->customer->isLogged()) { + $this->session->data['redirect'] = $this->url->link('account/account', '', true); + + $this->response->redirect($this->url->link('account/login', '', true)); + } + + $this->load->language('extension/credit_card/sagepay_direct'); + + $this->load->model('extension/payment/sagepay_direct'); + + $this->document->setTitle($this->language->get('heading_title')); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_home'), + 'href' => $this->url->link('common/home') + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_account'), + 'href' => $this->url->link('account/account', '', true) + ); + + $data['add'] = $this->url->link('extension/credit_card/sagepay_direct/addCard', '', true); + $data['back'] = $this->url->link('extension/credit_card/sagepay_direct', '', true); + + $data['cards'] = array(); + + $data['cards'][] = array( + 'text' => 'Visa', + 'value' => 'VISA' + ); + + $data['cards'][] = array( + 'text' => 'MasterCard', + 'value' => 'MC' + ); + + $data['cards'][] = array( + 'text' => 'Visa Delta/Debit', + 'value' => 'DELTA' + ); + + $data['cards'][] = array( + 'text' => 'Solo', + 'value' => 'SOLO' + ); + + $data['cards'][] = array( + 'text' => 'Maestro', + 'value' => 'MAESTRO' + ); + + $data['cards'][] = array( + 'text' => 'Visa Electron UK Debit', + 'value' => 'UKE' + ); + + $data['cards'][] = array( + 'text' => 'American Express', + 'value' => 'AMEX' + ); + + $data['cards'][] = array( + 'text' => 'Diners Club', + 'value' => 'DC' + ); + + $data['cards'][] = array( + 'text' => 'Japan Credit Bureau', + 'value' => 'JCB' + ); + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['year_valid'] = array(); + + for ($i = $today['year'] - 10; $i < $today['year'] + 1; $i++) { + $data['year_valid'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + $data['year_expire'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['year_expire'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + $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/credit_card/sagepay_direct_form', $data)); + } + + public function delete() { + $this->load->language('extension/credit_card/sagepay_direct'); + $this->load->model('extension/payment/sagepay_direct'); + + $card = $this->model_extension_payment_sagepay_direct->getCard($this->request->get['card_id'], false); + + if (!empty($card['token'])) { + if ($this->config->get('payment_sagepay_direct_test') == 'live') { + $url = 'https://live.sagepay.com/gateway/service/removetoken.vsp'; + } else { + $url = 'https://test.sagepay.com/gateway/service/removetoken.vsp'; + } + + $payment_data['VPSProtocol'] = '3.00'; + $payment_data['Vendor'] = $this->config->get('payment_sagepay_direct_vendor'); + $payment_data['TxType'] = 'REMOVETOKEN'; + $payment_data['Token'] = $card['token']; + + $response_data = $this->model_extension_payment_sagepay_direct->sendCurl($url, $payment_data); + + if ($response_data['Status'] == 'OK') { + $this->model_extension_payment_sagepay_direct->deleteCard($this->request->get['card_id']); + + $this->session->data['success'] = $this->language->get('text_success_card'); + } else { + $this->session->data['error_warning'] = $this->language->get('text_fail_card'); + } + } else { + $this->session->data['error_warning'] = $this->language->get('text_fail_card'); + } + + $this->response->redirect($this->url->link('acredit_card/sagepay_direct', '', true)); + } + + public function addCard() { + $this->load->language('extension/credit_card/sagepay_direct'); + $this->load->model('checkout/order'); + $this->load->model('extension/payment/sagepay_direct'); + + $payment_data = array(); + + if ($this->config->get('payment_sagepay_direct_test') == 'live') { + $url = 'https://live.sagepay.com/gateway/service/directtoken.vsp'; + } else { + $url = 'https://test.sagepay.com/gateway/service/directtoken.vsp'; + } + $payment_data['VPSProtocol'] = '3.00'; + + $payment_data['ReferrerID'] = 'E511AF91-E4A0-42DE-80B0-09C981A3FB61'; + $payment_data['TxType'] = 'TOKEN'; + $payment_data['Vendor'] = $this->config->get('payment_sagepay_direct_vendor'); + $payment_data['Currency'] = $this->session->data['currency']; + $payment_data['CardHolder'] = $this->request->post['cc_owner']; + $payment_data['CardNumber'] = $this->request->post['cc_number']; + $payment_data['ExpiryDate'] = $this->request->post['cc_expire_date_month'] . substr($this->request->post['cc_expire_date_year'], 2); + $payment_data['CV2'] = $this->request->post['cc_cvv2']; + $payment_data['CardType'] = $this->request->post['cc_type']; + + $response_data = $this->model_extension_payment_sagepay_direct->sendCurl($url, $payment_data); + + if ($response_data['Status'] == 'OK') { + $card_data = array(); + $card_data['customer_id'] = $this->customer->getId(); + $card_data['Token'] = $response_data['Token']; + $card_data['Last4Digits'] = substr(str_replace(' ', '', $payment_data['CardNumber']), -4, 4); + $card_data['ExpiryDate'] = $this->request->post['cc_expire_date_month'] . '/' . substr($this->request->post['cc_expire_date_year'], 2); + $card_data['CardType'] = $payment_data['CardType']; + $this->model_extension_payment_sagepay_direct->addCard($card_data); + $this->session->data['success'] = $this->language->get('text_success_add_card'); + } else { + $this->session->data['error_warning'] = $response_data['Status'] . ': ' . $response_data['StatusDetail']; + $this->model_extension_payment_sagepay_direct->logger('Response data: ', $this->session->data['error_warning']); + } + + $this->response->redirect($this->url->link('extension/credit_card/sagepay_direct', '', true)); + } +} diff --git a/public/catalog/controller/extension/credit_card/sagepay_server.php b/public/catalog/controller/extension/credit_card/sagepay_server.php new file mode 100644 index 0000000..0e9f43a --- /dev/null +++ b/public/catalog/controller/extension/credit_card/sagepay_server.php @@ -0,0 +1,271 @@ +<?php +class ControllerExtensionCreditCardSagepayServer extends Controller { + public function index() { + if (!$this->customer->isLogged()) { + $this->session->data['redirect'] = $this->url->link('account/account', '', true); + + $this->response->redirect($this->url->link('account/login', '', true)); + } + + $this->load->language('extension/credit_card/sagepay_server'); + + $this->load->model('extension/payment/sagepay_server'); + + $this->document->setTitle($this->language->get('heading_title')); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_home'), + 'href' => $this->url->link('common/home') + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_account'), + 'href' => $this->url->link('account/account', '', true) + ); + + + if (isset($this->session->data['success'])) { + $data['success'] = $this->session->data['success']; + unset($this->session->data['success']); + } else { + $data['success'] = ''; + } + + if (isset($this->session->data['error_warning'])) { + $data['error_warning'] = $this->session->data['error_warning']; + unset($this->session->data['error_warning']); + } else { + $data['error_warning'] = ''; + } + + if ($this->config->get('payment_sagepay_server_card')) { + $data['cards'] = $this->model_extension_payment_sagepay_server->getCards($this->customer->getId()); + $data['delete'] = $this->url->link('extension/credit_card/sagepay_server/delete', 'card_id=', true); + + if (isset($this->request->get['page'])) { + $page = $this->request->get['page']; + } else { + $page = 1; + } + + $cards_total = count($data['cards']); + + $pagination = new Pagination(); + $pagination->total = $cards_total; + $pagination->page = $page; + $pagination->limit = 10; + $pagination->url = $this->url->link('extension/credit_card/sagepay_server', 'page={page}', true); + + $data['pagination'] = $pagination->render(); + + $data['results'] = sprintf($this->language->get('text_pagination'), ($cards_total) ? (($page - 1) * 10) + 1 : 0, ((($page - 1) * 10) > ($cards_total - 10)) ? $cards_total : ((($page - 1) * 10) + 10), $cards_total, ceil($cards_total / 10)); + } else { + $data['cards'] = false; + $data['pagination'] = false; + $data['results'] = false; + } + + $data['add'] = $this->url->link('extension/credit_card/sagepay_server/add', '', true); + $data['back'] = $this->url->link('account/account', '', true); + + $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/credit_card/sagepay_server_list', $data)); + } + + public function delete() { + $this->load->language('extension/credit_card/sagepay_server'); + + $this->load->model('extension/payment/sagepay_server'); + + $card = $this->model_extension_payment_sagepay_server->getCard($this->request->get['card_id'], ''); + + if (!empty($card['token'])) { + if ($this->config->get('payment_sagepay_server_test') == 'live') { + $url = 'https://live.sagepay.com/gateway/service/removetoken.vsp'; + } else { + $url = 'https://test.sagepay.com/gateway/service/removetoken.vsp'; + } + + $payment_data['VPSProtocol'] = '3.00'; + $payment_data['Vendor'] = $this->config->get('payment_sagepay_server_vendor'); + $payment_data['TxType'] = 'REMOVETOKEN'; + $payment_data['Token'] = $card['token']; + + $response_data = $this->model_extension_payment_sagepay_server->sendCurl($url, $payment_data); + + if ($response_data['Status'] == 'OK') { + $this->model_extension_payment_sagepay_server->deleteCard($this->request->get['card_id']); + $this->session->data['success'] = $this->language->get('text_success_card'); + } else { + $this->session->data['error_warning'] = $this->language->get('text_fail_card'); + } + } else { + $this->session->data['error_warning'] = $this->language->get('text_fail_card'); + } + $this->response->redirect($this->url->link('extension/credit_card/sagepay_server', '', true)); + } + + public function addCard() { + $this->load->language('extension/payment/sagepay_server'); + + $this->load->model('checkout/order'); + $this->load->model('extension/payment/sagepay_server'); + + $payment_data = array(); + + if ($this->config->get('payment_sagepay_server_test') == 'live') { + $url = 'https://live.sagepay.com/gateway/service/token.vsp'; + } else { + $url = 'https://test.sagepay.com/gateway/service/token.vsp'; + } + $payment_data['VPSProtocol'] = '3.00'; + + $payment_data['ReferrerID'] = 'E511AF91-E4A0-42DE-80B0-09C981A3FB61'; + $payment_data['TxType'] = 'TOKEN'; + $payment_data['Vendor'] = $this->config->get('payment_sagepay_server_vendor'); + $payment_data['VendorTxCode'] = 'server_card_' . strftime("%Y%m%d%H%M%S") . mt_rand(1, 999); + $payment_data['NotificationURL'] = $this->url->link('extension/credit_card/sagepay_server/callback', '', true); + $payment_data['Currency'] = $this->session->data['currency']; + + $response_data = $this->model_extension_payment_sagepay_server->sendCurl($url, $payment_data); + + $this->model_extension_payment_sagepay_server->logger('Response', $response_data); + + if ($response_data['Status'] == 'OK') { + $json['redirect'] = $response_data['NextURL']; + $json['Status'] = $response_data['Status']; + $json['StatusDetail'] = $response_data['StatusDetail']; + + $order_info['order_id'] = -1; + $order_info['VPSTxId'] = substr($response_data['VPSTxId'], 1, -1); + $order_info['SecurityKey'] = $response_data['SecurityKey']; + $order_info['VendorTxCode'] = $payment_data['VendorTxCode']; + $order_info['currency_code'] = $this->session->data['currency']; + $order_info['total'] = ''; + $this->model_extension_payment_sagepay_server->addOrder($order_info); + } else { + $json['error'] = $response_data['StatusDetail']; + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function callback() { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/sagepay_server'); + + $this->model_extension_payment_sagepay_server->logger('Callback data', $this->request->post); + + $success_page = $this->url->link('extension/credit_card/sagepay_server/success', '', true); + $error_page = $this->url->link('extension/credit_card/sagepay_server/failure', '', true); + $end_ln = chr(13) . chr(10); + + if (isset($this->request->post['VendorTxCode'])) { + $vendor_tx_code = $this->request->post['VendorTxCode']; + } else { + $vendor_tx_code = ''; + } + + if (isset($this->request->post['Status'])) { + $str_status = $this->request->post['Status']; + } else { + $str_status = ''; + } + + if (isset($this->request->post['VPSSignature'])) { + $str_vps_signature = $this->request->post['VPSSignature']; + } else { + $str_vps_signature = ''; + } + + if (isset($this->request->post['VPSTxId'])) { + $str_vps_tx_id = $this->request->post['VPSTxId']; + } else { + $str_vps_tx_id = ''; + } + + if (isset($this->request->post['ExpiryDate'])) { + $str_expiry_date = $this->request->post['ExpiryDate']; + } else { + $str_expiry_date = ''; + } + + if (isset($this->request->post['Token'])) { + $str_token = $this->request->post['Token']; + } else { + $str_token = ''; + } + + $transaction_info = $this->model_extension_payment_sagepay_server->getOrder('', $str_vps_tx_id); + + if (isset($transaction_info['SecurityKey'])) { + $str_security_key = $transaction_info['SecurityKey']; + } else { + $str_security_key = ''; + } + $this->model_extension_payment_sagepay_server->logger('$transaction_info', $transaction_info); + $this->model_extension_payment_sagepay_server->logger('$str_vps_tx_id', $str_vps_tx_id); + $this->model_extension_payment_sagepay_server->logger('$vendor_tx_code', $vendor_tx_code); + $this->model_extension_payment_sagepay_server->logger('$str_status', $str_status); + $this->model_extension_payment_sagepay_server->logger('payment_sagepay_server_vendor', $this->config->get('payment_sagepay_server_vendor')); + $this->model_extension_payment_sagepay_server->logger('$str_token', $str_token); + $this->model_extension_payment_sagepay_server->logger('$str_security_key', $str_security_key); + + $str_message = $str_vps_tx_id . $vendor_tx_code . $str_status . strtolower($this->config->get('payment_sagepay_server_vendor')) . $str_token . $str_security_key; + + $str_my_signature = strtoupper(md5($str_message)); + + /** We can now compare our MD5 Hash signature with that from Sage Pay Server * */ + if ($str_my_signature != $str_vps_signature) { + + echo "Status=INVALID" . $end_ln; + echo "StatusDetail= Cannot match the MD5 Hash. Order might be tampered with." . $end_ln; + echo "RedirectURL=" . $error_page . $end_ln; + $this->model_extension_payment_sagepay_server->logger('StatusDetail', 'Cannot match the MD5 Hash. Order might be tampered with.'); + exit; + } + + if ($str_status != "OK") { + echo "Status=INVALID" . $end_ln; + echo "StatusDetail= Either status invalid or order info was not found."; + echo "RedirectURL=" . $error_page . $end_ln; + + $this->model_extension_payment_sagepay_server->logger('StatusDetail', 'Either status invalid or order info was not found.'); + + exit; + } + + $card_data['customer_id'] = $transaction_info['customer_id']; + $card_data['Token'] = $this->request->post['Token']; + $card_data['Last4Digits'] = $this->request->post['Last4Digits']; + $card_data['ExpiryDate'] = substr_replace($this->request->post['ExpiryDate'], '/', 2, 0); + $card_data['CardType'] = $this->request->post['CardType']; + $this->model_extension_payment_sagepay_server->addCard($card_data); + + echo "Status=OK" . $end_ln; + echo "RedirectURL=" . $success_page . $end_ln; + } + + public function success() { + $this->load->model('extension/payment/sagepay_server'); + $this->model_extension_payment_sagepay_server->logger('Success', ''); + $this->session->data['success'] = 'Success'; + $this->response->redirect($this->url->link('extension/credit_card/sagepay_server', '', true)); + } + + public function failure() { + $this->load->model('extension/payment/sagepay_server'); + $this->model_extension_payment_sagepay_server->logger('Failure', ''); + $this->session->data['error_warning'] = 'Failure'; + $this->response->redirect($this->url->link('extension/credit_card/sagepay_server', '', true)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/credit_card/squareup.php b/public/catalog/controller/extension/credit_card/squareup.php new file mode 100644 index 0000000..7350d74 --- /dev/null +++ b/public/catalog/controller/extension/credit_card/squareup.php @@ -0,0 +1,105 @@ +<?php + +class ControllerExtensionCreditCardSquareup extends Controller { + public function index() { + if (!$this->customer->isLogged()) { + $this->session->data['redirect'] = $this->url->link('account/account', '', true); + + $this->response->redirect($this->url->link('account/login', '', true)); + } + + $this->load->language('extension/credit_card/squareup'); + + $this->load->model('extension/credit_card/squareup'); + + $this->document->setTitle($this->language->get('heading_title')); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_home'), + 'href' => $this->url->link('common/home') + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_account'), + 'href' => $this->url->link('account/account', '', true) + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('heading_title'), + 'href' => $this->url->link('extension/credit_card/squareup', '', true) + ); + + if (isset($this->session->data['success'])) { + $data['success'] = $this->session->data['success']; + + unset($this->session->data['success']); + } else { + $data['success'] = ''; + } + + if (isset($this->session->data['error'])) { + $data['error'] = $this->session->data['error']; + + unset($this->session->data['error']); + } else { + $data['error'] = ''; + } + + $data['back'] = $this->url->link('account/account', '', true); + + $data['cards'] = array(); + + foreach ($this->model_extension_credit_card_squareup->getCards($this->customer->getId(), $this->config->get('payment_squareup_enable_sandbox')) as $card) { + $data['cards'][] = array( + 'text' => sprintf($this->language->get('text_card_ends_in'), $card['brand'], $card['ends_in']), + 'delete' => $this->url->link('extension/credit_card/squareup/forget', 'squareup_token_id=' . $card['squareup_token_id'], true) + ); + } + + $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/credit_card/squareup', $data)); + } + + public function forget() { + if (!$this->customer->isLogged()) { + $this->session->data['redirect'] = $this->url->link('account/account', '', true); + + $this->response->redirect($this->url->link('account/login', '', true)); + } + + $this->load->language('extension/credit_card/squareup'); + + $this->load->model('extension/credit_card/squareup'); + + $this->load->library('squareup'); + + $squareup_token_id = !empty($this->request->get['squareup_token_id']) ? + $this->request->get['squareup_token_id'] : 0; + + if ($this->model_extension_credit_card_squareup->verifyCardCustomer($squareup_token_id, $this->customer->getId())) { + $card_info = $this->model_extension_credit_card_squareup->getCard($squareup_token_id); + + $customer_info = $this->model_extension_credit_card_squareup->getCustomer($this->customer->getId(), $card_info['sandbox']); + + try { + $this->squareup->deleteCard($customer_info['square_customer_id'], $card_info['token']); + + $this->model_extension_credit_card_squareup->deleteCard($squareup_token_id); + + $this->session->data['success'] = $this->language->get('text_success_card_delete'); + } catch (\Squareup\Exception $e) { + $this->session->data['error'] = $e->getMessage(); + } + } + + $this->response->redirect($this->url->link('extension/credit_card/squareup', '', true)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/feed/google_base.php b/public/catalog/controller/extension/feed/google_base.php new file mode 100644 index 0000000..a6bd427 --- /dev/null +++ b/public/catalog/controller/extension/feed/google_base.php @@ -0,0 +1,146 @@ +<?php +class ControllerExtensionFeedGoogleBase extends Controller { + public function index() { + if ($this->config->get('feed_google_base_status')) { + $output = '<?xml version="1.0" encoding="UTF-8" ?>'; + $output .= '<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">'; + $output .= ' <channel>'; + $output .= ' <title>' . $this->config->get('config_name') . '</title>'; + $output .= ' <description>' . $this->config->get('config_meta_description') . '</description>'; + $output .= ' <link>' . $this->config->get('config_url') . '</link>'; + + $this->load->model('extension/feed/google_base'); + $this->load->model('catalog/category'); + $this->load->model('catalog/product'); + + $this->load->model('tool/image'); + + $product_data = array(); + + $google_base_categories = $this->model_extension_feed_google_base->getCategories(); + + foreach ($google_base_categories as $google_base_category) { + $filter_data = array( + 'filter_category_id' => $google_base_category['category_id'], + 'filter_filter' => false + ); + + $products = $this->model_catalog_product->getProducts($filter_data); + + foreach ($products as $product) { + if (!in_array($product['product_id'], $product_data) && $product['description']) { + + $product_data[] = $product['product_id']; + + $output .= '<item>'; + $output .= '<title><![CDATA[' . $product['name'] . ']]></title>'; + $output .= '<link>' . $this->url->link('product/product', 'product_id=' . $product['product_id']) . '</link>'; + $output .= '<description><![CDATA[' . strip_tags(html_entity_decode($product['description'], ENT_QUOTES, 'UTF-8')) . ']]></description>'; + $output .= '<g:brand><![CDATA[' . html_entity_decode($product['manufacturer'], ENT_QUOTES, 'UTF-8') . ']]></g:brand>'; + $output .= '<g:condition>new</g:condition>'; + $output .= '<g:id>' . $product['product_id'] . '</g:id>'; + + if ($product['image']) { + $output .= ' <g:image_link>' . $this->model_tool_image->resize($product['image'], 500, 500) . '</g:image_link>'; + } else { + $output .= ' <g:image_link></g:image_link>'; + } + + $output .= ' <g:model_number>' . $product['model'] . '</g:model_number>'; + + if ($product['mpn']) { + $output .= ' <g:mpn><![CDATA[' . $product['mpn'] . ']]></g:mpn>' ; + } else { + $output .= ' <g:identifier_exists>false</g:identifier_exists>'; + } + + if ($product['upc']) { + $output .= ' <g:upc>' . $product['upc'] . '</g:upc>'; + } + + if ($product['ean']) { + $output .= ' <g:ean>' . $product['ean'] . '</g:ean>'; + } + + $currencies = array( + 'USD', + 'EUR', + 'GBP' + ); + + if (in_array($this->session->data['currency'], $currencies)) { + $currency_code = $this->session->data['currency']; + $currency_value = $this->currency->getValue($this->session->data['currency']); + } else { + $currency_code = 'USD'; + $currency_value = $this->currency->getValue('USD'); + } + + if ((float)$product['special']) { + $output .= ' <g:price>' . $this->currency->format($this->tax->calculate($product['special'], $product['tax_class_id']), $currency_code, $currency_value, false) . '</g:price>'; + } else { + $output .= ' <g:price>' . $this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id']), $currency_code, $currency_value, false) . '</g:price>'; + } + + $output .= ' <g:google_product_category>' . $google_base_category['google_base_category_id'] . '</g:google_product_category>'; + + $categories = $this->model_catalog_product->getCategories($product['product_id']); + + foreach ($categories as $category) { + $path = $this->getPath($category['category_id']); + + if ($path) { + $string = ''; + + foreach (explode('_', $path) as $path_id) { + $category_info = $this->model_catalog_category->getCategory($path_id); + + if ($category_info) { + if (!$string) { + $string = $category_info['name']; + } else { + $string .= ' > ' . $category_info['name']; + } + } + } + + $output .= '<g:product_type><![CDATA[' . $string . ']]></g:product_type>'; + } + } + + $output .= ' <g:quantity>' . $product['quantity'] . '</g:quantity>'; + $output .= ' <g:weight>' . $this->weight->format($product['weight'], $product['weight_class_id']) . '</g:weight>'; + $output .= ' <g:availability><![CDATA[' . ($product['quantity'] ? 'in stock' : 'out of stock') . ']]></g:availability>'; + $output .= '</item>'; + } + } + } + + $output .= ' </channel>'; + $output .= '</rss>'; + + $this->response->addHeader('Content-Type: application/rss+xml'); + $this->response->setOutput($output); + } + } + + protected function getPath($parent_id, $current_path = '') { + $category_info = $this->model_catalog_category->getCategory($parent_id); + + if ($category_info) { + if (!$current_path) { + $new_path = $category_info['category_id']; + } else { + $new_path = $category_info['category_id'] . '_' . $current_path; + } + + $path = $this->getPath($category_info['parent_id'], $new_path); + + if ($path) { + return $path; + } else { + return $new_path; + } + } + } +} diff --git a/public/catalog/controller/extension/feed/google_sitemap.php b/public/catalog/controller/extension/feed/google_sitemap.php new file mode 100644 index 0000000..7cb7d37 --- /dev/null +++ b/public/catalog/controller/extension/feed/google_sitemap.php @@ -0,0 +1,107 @@ +<?php +class ControllerExtensionFeedGoogleSitemap extends Controller { + public function index() { + if ($this->config->get('feed_google_sitemap_status')) { + $output = '<?xml version="1.0" encoding="UTF-8"?>'; + $output .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">'; + + $this->load->model('catalog/product'); + $this->load->model('tool/image'); + + $products = $this->model_catalog_product->getProducts(); + + foreach ($products as $product) { + if ($product['image']) { + $output .= '<url>'; + $output .= ' <loc>' . $this->url->link('product/product', 'product_id=' . $product['product_id']) . '</loc>'; + $output .= ' <changefreq>weekly</changefreq>'; + $output .= ' <lastmod>' . date('Y-m-d\TH:i:sP', strtotime($product['date_modified'])) . '</lastmod>'; + $output .= ' <priority>1.0</priority>'; + $output .= ' <image:image>'; + $output .= ' <image:loc>' . $this->model_tool_image->resize($product['image'], $this->config->get('theme_' . $this->config->get('config_theme') . '_image_popup_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_popup_height')) . '</image:loc>'; + $output .= ' <image:caption>' . $product['name'] . '</image:caption>'; + $output .= ' <image:title>' . $product['name'] . '</image:title>'; + $output .= ' </image:image>'; + $output .= '</url>'; + } + } + + $this->load->model('catalog/category'); + + $output .= $this->getCategories(0); + + $this->load->model('catalog/manufacturer'); + + $manufacturers = $this->model_catalog_manufacturer->getManufacturers(); + + foreach ($manufacturers as $manufacturer) { + $output .= '<url>'; + $output .= ' <loc>' . $this->url->link('product/manufacturer/info', 'manufacturer_id=' . $manufacturer['manufacturer_id']) . '</loc>'; + $output .= ' <changefreq>weekly</changefreq>'; + $output .= ' <priority>0.7</priority>'; + $output .= '</url>'; + + $products = $this->model_catalog_product->getProducts(array('filter_manufacturer_id' => $manufacturer['manufacturer_id'])); + + foreach ($products as $product) { + $output .= '<url>'; + $output .= ' <loc>' . $this->url->link('product/product', 'manufacturer_id=' . $manufacturer['manufacturer_id'] . '&product_id=' . $product['product_id']) . '</loc>'; + $output .= ' <changefreq>weekly</changefreq>'; + $output .= ' <priority>1.0</priority>'; + $output .= '</url>'; + } + } + + $this->load->model('catalog/information'); + + $informations = $this->model_catalog_information->getInformations(); + + foreach ($informations as $information) { + $output .= '<url>'; + $output .= ' <loc>' . $this->url->link('information/information', 'information_id=' . $information['information_id']) . '</loc>'; + $output .= ' <changefreq>weekly</changefreq>'; + $output .= ' <priority>0.5</priority>'; + $output .= '</url>'; + } + + $output .= '</urlset>'; + + $this->response->addHeader('Content-Type: application/xml'); + $this->response->setOutput($output); + } + } + + protected function getCategories($parent_id, $current_path = '') { + $output = ''; + + $results = $this->model_catalog_category->getCategories($parent_id); + + foreach ($results as $result) { + if (!$current_path) { + $new_path = $result['category_id']; + } else { + $new_path = $current_path . '_' . $result['category_id']; + } + + $output .= '<url>'; + $output .= ' <loc>' . $this->url->link('product/category', 'path=' . $new_path) . '</loc>'; + $output .= ' <changefreq>weekly</changefreq>'; + $output .= ' <priority>0.7</priority>'; + $output .= '</url>'; + + $products = $this->model_catalog_product->getProducts(array('filter_category_id' => $result['category_id'])); + + foreach ($products as $product) { + $output .= '<url>'; + $output .= ' <loc>' . $this->url->link('product/product', 'path=' . $new_path . '&product_id=' . $product['product_id']) . '</loc>'; + $output .= ' <changefreq>weekly</changefreq>'; + $output .= ' <priority>1.0</priority>'; + $output .= '</url>'; + } + + $output .= $this->getCategories($result['category_id'], $new_path); + } + + return $output; + } +} diff --git a/public/catalog/controller/extension/module/account.php b/public/catalog/controller/extension/module/account.php new file mode 100644 index 0000000..333b9a1 --- /dev/null +++ b/public/catalog/controller/extension/module/account.php @@ -0,0 +1,26 @@ +<?php +class ControllerExtensionModuleAccount extends Controller { + public function index() { + $this->load->language('extension/module/account'); + + $data['logged'] = $this->customer->isLogged(); + $data['register'] = $this->url->link('account/register', '', true); + $data['login'] = $this->url->link('account/login', '', true); + $data['logout'] = $this->url->link('account/logout', '', true); + $data['forgotten'] = $this->url->link('account/forgotten', '', true); + $data['account'] = $this->url->link('account/account', '', true); + $data['edit'] = $this->url->link('account/edit', '', true); + $data['password'] = $this->url->link('account/password', '', true); + $data['address'] = $this->url->link('account/address', '', true); + $data['wishlist'] = $this->url->link('account/wishlist'); + $data['order'] = $this->url->link('account/order', '', true); + $data['download'] = $this->url->link('account/download', '', true); + $data['reward'] = $this->url->link('account/reward', '', true); + $data['return'] = $this->url->link('account/return', '', true); + $data['transaction'] = $this->url->link('account/transaction', '', true); + $data['newsletter'] = $this->url->link('account/newsletter', '', true); + $data['recurring'] = $this->url->link('account/recurring', '', true); + + return $this->load->view('extension/module/account', $data); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/amazon_login.php b/public/catalog/controller/extension/module/amazon_login.php new file mode 100644 index 0000000..9b8ae65 --- /dev/null +++ b/public/catalog/controller/extension/module/amazon_login.php @@ -0,0 +1,172 @@ +<?php + +class ControllerExtensionModuleAmazonLogin extends Controller { + public function index() { + if ($this->config->get('payment_amazon_login_pay_status') && $this->config->get('module_amazon_login_status') && !$this->customer->isLogged() && !empty($this->request->server['HTTPS'])) { + + $this->load->model('extension/payment/amazon_login_pay'); + + // capital L in Amazon cookie name is required, do not alter for coding standards + if (isset($this->request->cookie['amazon_Login_state_cache'])) { + setcookie('amazon_Login_state_cache', null, -1, '/'); + } + + $amazon_payment_js = $this->model_extension_payment_amazon_login_pay->getWidgetJs(); + + $this->document->addScript($amazon_payment_js); + + $data['client_id'] = trim($this->config->get('payment_amazon_login_pay_client_id')); + $data['merchant_id'] = $this->config->get('payment_amazon_login_pay_merchant_id'); + $data['return_url'] = html_entity_decode($this->url->link('extension/module/amazon_login/login', '', true), ENT_COMPAT, "UTF-8"); + $data['button_id'] = 'AmazonLoginButton'; + + if ($this->config->get('payment_amazon_login_pay_test') == 'sandbox') { + $data['sandbox'] = isset($this->session->data['user_id']); // Require an active admin panel session to show debug messages + } + + if ($this->config->get('module_amazon_login_button_type')) { + $data['button_type'] = $this->config->get('module_amazon_login_button_type'); + } else { + $data['button_type'] = 'lwa'; + } + + if ($this->config->get('module_amazon_login_button_colour')) { + $data['button_colour'] = $this->config->get('module_amazon_login_button_colour'); + } else { + $data['button_colour'] = 'gold'; + } + + if ($this->config->get('module_amazon_login_button_size')) { + $data['button_size'] = $this->config->get('module_amazon_login_button_size'); + } else { + $data['button_size'] = 'medium'; + } + + if ($this->config->get('payment_amazon_login_pay_language')) { + $data['language'] = $this->config->get('payment_amazon_login_pay_language'); + } else { + $data['language'] = 'en-US'; + } + + return $this->load->view('extension/module/amazon_login', $data); + } + } + + public function login() { + $this->load->language('extension/payment/amazon_login_pay'); + $this->load->language('account/login'); + + $this->load->model('extension/module/amazon_login'); + + $from_amazon_pay = isset($this->request->get['from_amazon_pay']); + + unset($this->session->data['apalwa']); + + try { + if (isset($this->request->get['access_token'])) { + $access_token = $this->request->get['access_token']; + + $this->session->data['apalwa']['login']['access_token'] = $access_token; + + $this->model_extension_module_amazon_login->verifyAccessToken($access_token); + + $amazon_profile = $this->model_extension_module_amazon_login->fetchProfile($access_token); + } else { + $this->model_extension_module_amazon_login->debugLog("EXCEPTION", $this->language->get('error_login')); + + throw new \RuntimeException($this->language->get('error_login')); + } + + // No issues found, and the Amazon profile has been fetched + if ($from_amazon_pay) { + unset($this->session->data['guest']); + unset($this->session->data['account']); + + if ($this->config->get('payment_amazon_login_pay_checkout') == 'guest') { + $this->session->data['account'] = 'guest'; + + $this->session->data['guest']['customer_group_id'] = $this->config->get('config_customer_group_id'); + $this->session->data['guest']['firstname'] = (string)$amazon_profile->first_name; + $this->session->data['guest']['lastname'] = (string)$amazon_profile->last_name; + $this->session->data['guest']['email'] = (string)$amazon_profile->email; + $this->session->data['guest']['telephone'] = '0000000'; + + $this->session->data['apalwa']['pay']['profile'] = $this->session->data['guest']; + } else { + // The payment button must log in a customer + $this->session->data['account'] = 'register'; + + $profile = $this->model_extension_module_amazon_login->loginProfile($amazon_profile); + + $this->session->data['apalwa']['pay']['profile'] = $profile; + + // If a customer is already logged in, we must overwrite their data with amazon data + // Therefore, at the end of the day, we will have a + } + + $this->response->redirect($this->url->link('extension/payment/amazon_login_pay/address', '', true)); + } else { + $this->model_extension_module_amazon_login->loginProfile($amazon_profile); + + $this->response->redirect($this->url->link('account/account', '', true)); + } + } catch (\RuntimeException $e) { + $this->session->data['apalwa']['login']['error'] = $e->getMessage(); + + $this->response->redirect($this->url->link('extension/module/amazon_login/error', '', true)); + } + } + + public function error() { + $this->load->language('extension/payment/amazon_login_pay'); + + $data = array(); + + $continue = $this->url->link('common/home', '', true); + + if (isset($this->session->data['apalwa']['login']['error'])) { + $data['error'] = $this->session->data['apalwa']['login']['error']; + $data['continue'] = $continue; + $data['heading_title'] = $this->language->get('error_login'); + + $this->document->setTitle($this->language->get('error_login')); + + unset($this->session->data['apalwa']); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('common/home', '', true), + 'text' => $this->language->get('text_home') + ); + + $data['breadcrumbs'][] = array( + 'href' => null, + 'current' => true, + 'text' => $this->language->get('error_login') + ); + + $data['content_main'] = $this->load->view('extension/module/amazon_login_error', $data); + $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/amazon_login_pay_generic', $data)); + } else { + $this->response->redirect($continue); + } + } + + public function logout() { + unset($this->session->data['apalwa']); + + // capital L in Amazon cookie name is required, do not alter for coding standards + if (isset($this->request->cookie['amazon_Login_state_cache'])) { + //@todo - rework this by triggering the JavaScript logout + setcookie('amazon_Login_state_cache', null, -1, '/'); + } + } +} diff --git a/public/catalog/controller/extension/module/amazon_pay.php b/public/catalog/controller/extension/module/amazon_pay.php new file mode 100644 index 0000000..97bc3c0 --- /dev/null +++ b/public/catalog/controller/extension/module/amazon_pay.php @@ -0,0 +1,52 @@ +<?php +class ControllerExtensionModuleAmazonPay extends Controller { + public function index() { + $this->load->model('extension/payment/amazon_login_pay'); + + if ($this->config->get('payment_amazon_login_pay_status') && $this->config->get('module_amazon_pay_status') && !empty($this->request->server['HTTPS']) && !($this->config->get('payment_amazon_login_pay_minimum_total') > 0 && $this->config->get('payment_amazon_login_pay_minimum_total') > $this->cart->getSubTotal()) && $this->model_extension_payment_amazon_login_pay->isTotalPositive()) { + + // capital L in Amazon cookie name is required, do not alter for coding standards + if (!$this->customer->isLogged() && isset($this->request->cookie['amazon_Login_state_cache'])) { + setcookie('amazon_Login_state_cache', null, -1, '/'); + } + + $amazon_payment_js = $this->model_extension_payment_amazon_login_pay->getWidgetJs(); + $this->document->addScript($amazon_payment_js); + + $data['client_id'] = $this->config->get('payment_amazon_login_pay_client_id'); + $data['merchant_id'] = $this->config->get('payment_amazon_login_pay_merchant_id'); + $data['return_url'] = html_entity_decode($this->url->link('extension/module/amazon_login/login', 'from_amazon_pay=1', true), ENT_COMPAT, "UTF-8"); + $data['button_id'] = 'AmazonPayButton'; + + if ($this->config->get('payment_amazon_login_pay_test') == 'sandbox') { + $data['sandbox'] = isset($this->session->data['user_id']); // Require an active admin panel session to show debug messages + } + + if ($this->config->get('module_amazon_pay_button_type')) { + $data['button_type'] = $this->config->get('module_amazon_pay_button_type'); + } else { + $data['button_type'] = 'PwA'; + } + + if ($this->config->get('module_amazon_pay_button_colour')) { + $data['button_colour'] = $this->config->get('module_amazon_pay_button_colour'); + } else { + $data['button_colour'] = 'Gold'; + } + + if ($this->config->get('module_amazon_pay_button_size')) { + $data['button_size'] = $this->config->get('module_amazon_pay_button_size'); + } else { + $data['button_size'] = 'medium'; + } + + if ($this->config->get('payment_amazon_login_pay_language')) { + $data['language'] = $this->config->get('payment_amazon_login_pay_language'); + } else { + $data['language'] = 'en-US'; + } + + return $this->load->view('extension/module/amazon_login', $data); + } + } +} diff --git a/public/catalog/controller/extension/module/banner.php b/public/catalog/controller/extension/module/banner.php new file mode 100644 index 0000000..0e90702 --- /dev/null +++ b/public/catalog/controller/extension/module/banner.php @@ -0,0 +1,31 @@ +<?php +class ControllerExtensionModuleBanner extends Controller { + public function index($setting) { + static $module = 0; + + $this->load->model('design/banner'); + $this->load->model('tool/image'); + + $this->document->addStyle('catalog/view/javascript/jquery/swiper/css/swiper.min.css'); + $this->document->addStyle('catalog/view/javascript/jquery/swiper/css/opencart.css'); + $this->document->addScript('catalog/view/javascript/jquery/swiper/js/swiper.jquery.js'); + + $data['banners'] = array(); + + $results = $this->model_design_banner->getBanner($setting['banner_id']); + + foreach ($results as $result) { + if (is_file(DIR_IMAGE . $result['image'])) { + $data['banners'][] = array( + 'title' => $result['title'], + 'link' => $result['link'], + 'image' => $this->model_tool_image->resize($result['image'], $setting['width'], $setting['height']) + ); + } + } + + $data['module'] = $module++; + + return $this->load->view('extension/module/banner', $data); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/bestseller.php b/public/catalog/controller/extension/module/bestseller.php new file mode 100644 index 0000000..6b0a239 --- /dev/null +++ b/public/catalog/controller/extension/module/bestseller.php @@ -0,0 +1,62 @@ +<?php +class ControllerExtensionModuleBestSeller extends Controller { + public function index($setting) { + $this->load->language('extension/module/bestseller'); + + $this->load->model('catalog/product'); + + $this->load->model('tool/image'); + + $data['products'] = array(); + + $results = $this->model_catalog_product->getBestSellerProducts($setting['limit']); + + if ($results) { + foreach ($results as $result) { + if ($result['image']) { + $image = $this->model_tool_image->resize($result['image'], $setting['width'], $setting['height']); + } else { + $image = $this->model_tool_image->resize('placeholder.png', $setting['width'], $setting['height']); + } + + if ($this->customer->isLogged() || !$this->config->get('config_customer_price')) { + $price = $this->currency->format($this->tax->calculate($result['price'], $result['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']); + } else { + $price = false; + } + + if ((float)$result['special']) { + $special = $this->currency->format($this->tax->calculate($result['special'], $result['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']); + } else { + $special = false; + } + + if ($this->config->get('config_tax')) { + $tax = $this->currency->format((float)$result['special'] ? $result['special'] : $result['price'], $this->session->data['currency']); + } else { + $tax = false; + } + + if ($this->config->get('config_review_status')) { + $rating = $result['rating']; + } else { + $rating = false; + } + + $data['products'][] = array( + 'product_id' => $result['product_id'], + 'thumb' => $image, + 'name' => $result['name'], + 'description' => utf8_substr(trim(strip_tags(html_entity_decode($result['description'], ENT_QUOTES, 'UTF-8'))), 0, $this->config->get('theme_' . $this->config->get('config_theme') . '_product_description_length')) . '..', + 'price' => $price, + 'special' => $special, + 'tax' => $tax, + 'rating' => $rating, + 'href' => $this->url->link('product/product', 'product_id=' . $result['product_id']) + ); + } + + return $this->load->view('extension/module/bestseller', $data); + } + } +} diff --git a/public/catalog/controller/extension/module/carousel.php b/public/catalog/controller/extension/module/carousel.php new file mode 100644 index 0000000..f273cd1 --- /dev/null +++ b/public/catalog/controller/extension/module/carousel.php @@ -0,0 +1,31 @@ +<?php +class ControllerExtensionModuleCarousel extends Controller { + public function index($setting) { + static $module = 0; + + $this->load->model('design/banner'); + $this->load->model('tool/image'); + + $this->document->addStyle('catalog/view/javascript/jquery/swiper/css/swiper.min.css'); + $this->document->addStyle('catalog/view/javascript/jquery/swiper/css/opencart.css'); + $this->document->addScript('catalog/view/javascript/jquery/swiper/js/swiper.jquery.js'); + + $data['banners'] = array(); + + $results = $this->model_design_banner->getBanner($setting['banner_id']); + + foreach ($results as $result) { + if (is_file(DIR_IMAGE . $result['image'])) { + $data['banners'][] = array( + 'title' => $result['title'], + 'link' => $result['link'], + 'image' => $this->model_tool_image->resize($result['image'], $setting['width'], $setting['height']) + ); + } + } + + $data['module'] = $module++; + + return $this->load->view('extension/module/carousel', $data); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/category.php b/public/catalog/controller/extension/module/category.php new file mode 100644 index 0000000..e29ed4b --- /dev/null +++ b/public/catalog/controller/extension/module/category.php @@ -0,0 +1,64 @@ +<?php +class ControllerExtensionModuleCategory extends Controller { + public function index() { + $this->load->language('extension/module/category'); + + if (isset($this->request->get['path'])) { + $parts = explode('_', (string)$this->request->get['path']); + } else { + $parts = array(); + } + + if (isset($parts[0])) { + $data['category_id'] = $parts[0]; + } else { + $data['category_id'] = 0; + } + + if (isset($parts[1])) { + $data['child_id'] = $parts[1]; + } else { + $data['child_id'] = 0; + } + + $this->load->model('catalog/category'); + + $this->load->model('catalog/product'); + + $data['categories'] = array(); + + $categories = $this->model_catalog_category->getCategories(0); + + foreach ($categories as $category) { + $children_data = array(); + + if ($category['category_id'] == $data['category_id']) { + $children = $this->model_catalog_category->getCategories($category['category_id']); + + foreach($children as $child) { + $filter_data = array('filter_category_id' => $child['category_id'], 'filter_sub_category' => true); + + $children_data[] = array( + 'category_id' => $child['category_id'], + 'name' => $child['name'] . ($this->config->get('config_product_count') ? ' (' . $this->model_catalog_product->getTotalProducts($filter_data) . ')' : ''), + 'href' => $this->url->link('product/category', 'path=' . $category['category_id'] . '_' . $child['category_id']) + ); + } + } + + $filter_data = array( + 'filter_category_id' => $category['category_id'], + 'filter_sub_category' => true + ); + + $data['categories'][] = array( + 'category_id' => $category['category_id'], + 'name' => $category['name'] . ($this->config->get('config_product_count') ? ' (' . $this->model_catalog_product->getTotalProducts($filter_data) . ')' : ''), + 'children' => $children_data, + 'href' => $this->url->link('product/category', 'path=' . $category['category_id']) + ); + } + + return $this->load->view('extension/module/category', $data); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/divido_calculator.php b/public/catalog/controller/extension/module/divido_calculator.php new file mode 100644 index 0000000..40a7b3e --- /dev/null +++ b/public/catalog/controller/extension/module/divido_calculator.php @@ -0,0 +1,53 @@ +<?php +class ControllerExtensionModuleDividoCalculator extends Controller { + public function index() { + $this->load->language('extension/module/divido_calculator'); + $this->load->model('extension/payment/divido'); + $this->load->model('catalog/product'); + + $product_selection = $this->config->get('payment_divido_productselection'); + $product_threshold = $this->config->get('payment_divido_price_threshold'); + + if (!isset($this->request->get['product_id']) || !$this->config->get('payment_divido_status') || !$this->config->get('module_divido_calculator_status')) { + return false; + } + + $product_info = $this->model_catalog_product->getProduct($this->request->get['product_id']); + + $price = 0; + if (($this->config->get('config_customer_price') && $this->customer->isLogged()) || !$this->config->get('config_customer_price')) { + $base_price = !empty($product_info['special']) ? $product_info['special'] : $product_info['price']; + $price = $this->tax->calculate($base_price, $product_info['tax_class_id'], $this->config->get('config_tax')); + } + + if ($product_selection == 'threshold' && $product_threshold > $price) { + return false; + } + + $api_key = $this->config->get('payment_divido_api_key'); + $key_parts = explode('.', $api_key); + $js_key = strtolower(array_shift($key_parts)); + + $this->model_extension_payment_divido->setMerchant($api_key); + $plans = $this->model_extension_payment_divido->getProductPlans($this->request->get['product_id']); + + if (!$plans) { + return false; + } + + $plans_ids = array_map(function ($plan) { + return $plan->id; + }, $plans); + $plans_ids = array_unique($plans_ids); + $plans_list = implode(',', $plans_ids); + + $data = array( + 'merchant_script' => "//cdn.divido.com/calculator/{$js_key}.js", + 'product_price' => $price, + 'plan_list' => $plans_list, + 'generic_credit_req_error' => 'Credit request could not be initiated', + ); + + return $this->load->view('extension/module/divido_calculator', $data); + } +} diff --git a/public/catalog/controller/extension/module/ebay_listing.php b/public/catalog/controller/extension/module/ebay_listing.php new file mode 100644 index 0000000..0e763e7 --- /dev/null +++ b/public/catalog/controller/extension/module/ebay_listing.php @@ -0,0 +1,42 @@ +<?php +class ControllerExtensionModuleEbayListing extends Controller { + public function index() { + if ($this->config->get('ebay_status') == 1) { + $this->load->language('extension/module/ebay'); + + $this->load->model('tool/image'); + $this->load->model('extension/openbay/ebay_product'); + + $data['heading_title'] = $this->language->get('heading_title'); + + $data['products'] = array(); + + $products = $this->cache->get('ebay_listing.' . md5(serialize($products))); + + if (!$products) { + $products = $this->model_extension_openbay_ebay_product->getDisplayProducts(); + + $this->cache->set('ebay_listing.' . md5(serialize($products)), $products); + } + + foreach($products['products'] as $product) { + if (isset($product['pictures'][0])) { + $image = $this->model_extension_openbay_ebay_product->resize($product['pictures'][0], $this->config->get('ebay_listing_width'), $this->config->get('ebay_listing_height')); + } else { + $image = $this->model_tool_image->resize('placeholder.png', $this->config->get('ebay_listing_width'), $this->config->get('ebay_listing_height')); + } + + $data['products'][] = array( + 'thumb' => $image, + 'name' => base64_decode($product['Title']), + 'price' => $this->currency->format($product['priceGross'], $this->session->data['currency']), + 'href' => (string)$product['link'] + ); + } + + $data['tracking_pixel'] = $products['tracking_pixel']; + + return $this->load->view('extension/module/ebay', $data); + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/featured.php b/public/catalog/controller/extension/module/featured.php new file mode 100644 index 0000000..b3b14c5 --- /dev/null +++ b/public/catalog/controller/extension/module/featured.php @@ -0,0 +1,72 @@ +<?php +class ControllerExtensionModuleFeatured extends Controller { + public function index($setting) { + $this->load->language('extension/module/featured'); + + $this->load->model('catalog/product'); + + $this->load->model('tool/image'); + + $data['products'] = array(); + + if (!$setting['limit']) { + $setting['limit'] = 4; + } + + if (!empty($setting['product'])) { + $products = array_slice($setting['product'], 0, (int)$setting['limit']); + + foreach ($products as $product_id) { + $product_info = $this->model_catalog_product->getProduct($product_id); + + if ($product_info) { + if ($product_info['image']) { + $image = $this->model_tool_image->resize($product_info['image'], $setting['width'], $setting['height']); + } else { + $image = $this->model_tool_image->resize('placeholder.png', $setting['width'], $setting['height']); + } + + if ($this->customer->isLogged() || !$this->config->get('config_customer_price')) { + $price = $this->currency->format($this->tax->calculate($product_info['price'], $product_info['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']); + } else { + $price = false; + } + + if ((float)$product_info['special']) { + $special = $this->currency->format($this->tax->calculate($product_info['special'], $product_info['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']); + } else { + $special = false; + } + + if ($this->config->get('config_tax')) { + $tax = $this->currency->format((float)$product_info['special'] ? $product_info['special'] : $product_info['price'], $this->session->data['currency']); + } else { + $tax = false; + } + + if ($this->config->get('config_review_status')) { + $rating = $product_info['rating']; + } else { + $rating = false; + } + + $data['products'][] = array( + 'product_id' => $product_info['product_id'], + 'thumb' => $image, + 'name' => $product_info['name'], + 'description' => utf8_substr(strip_tags(html_entity_decode($product_info['description'], ENT_QUOTES, 'UTF-8')), 0, $this->config->get('theme_' . $this->config->get('config_theme') . '_product_description_length')) . '..', + 'price' => $price, + 'special' => $special, + 'tax' => $tax, + 'rating' => $rating, + 'href' => $this->url->link('product/product', 'product_id=' . $product_info['product_id']) + ); + } + } + } + + if ($data['products']) { + return $this->load->view('extension/module/featured', $data); + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/filter.php b/public/catalog/controller/extension/module/filter.php new file mode 100644 index 0000000..36bedce --- /dev/null +++ b/public/catalog/controller/extension/module/filter.php @@ -0,0 +1,74 @@ +<?php +class ControllerExtensionModuleFilter extends Controller { + public function index() { + if (isset($this->request->get['path'])) { + $parts = explode('_', (string)$this->request->get['path']); + } else { + $parts = array(); + } + + $category_id = end($parts); + + $this->load->model('catalog/category'); + + $category_info = $this->model_catalog_category->getCategory($category_id); + + if ($category_info) { + $this->load->language('extension/module/filter'); + + $url = ''; + + if (isset($this->request->get['sort'])) { + $url .= '&sort=' . $this->request->get['sort']; + } + + if (isset($this->request->get['order'])) { + $url .= '&order=' . $this->request->get['order']; + } + + if (isset($this->request->get['limit'])) { + $url .= '&limit=' . $this->request->get['limit']; + } + + $data['action'] = str_replace('&', '&', $this->url->link('product/category', 'path=' . $this->request->get['path'] . $url)); + + if (isset($this->request->get['filter'])) { + $data['filter_category'] = explode(',', $this->request->get['filter']); + } else { + $data['filter_category'] = array(); + } + + $this->load->model('catalog/product'); + + $data['filter_groups'] = array(); + + $filter_groups = $this->model_catalog_category->getCategoryFilters($category_id); + + if ($filter_groups) { + foreach ($filter_groups as $filter_group) { + $childen_data = array(); + + foreach ($filter_group['filter'] as $filter) { + $filter_data = array( + 'filter_category_id' => $category_id, + 'filter_filter' => $filter['filter_id'] + ); + + $childen_data[] = array( + 'filter_id' => $filter['filter_id'], + 'name' => $filter['name'] . ($this->config->get('config_product_count') ? ' (' . $this->model_catalog_product->getTotalProducts($filter_data) . ')' : '') + ); + } + + $data['filter_groups'][] = array( + 'filter_group_id' => $filter_group['filter_group_id'], + 'name' => $filter_group['name'], + 'filter' => $childen_data + ); + } + + return $this->load->view('extension/module/filter', $data); + } + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/google_hangouts.php b/public/catalog/controller/extension/module/google_hangouts.php new file mode 100644 index 0000000..5d61d87 --- /dev/null +++ b/public/catalog/controller/extension/module/google_hangouts.php @@ -0,0 +1,14 @@ +<?php +class ControllerExtensionModuleGoogleHangouts extends Controller { + public function index() { + $this->load->language('extension/module/google_hangouts'); + + if ($this->request->server['HTTPS']) { + $data['code'] = str_replace('http', 'https', html_entity_decode($this->config->get('module_google_hangouts_code'))); + } else { + $data['code'] = html_entity_decode($this->config->get('module_google_hangouts_code')); + } + + return $this->load->view('extension/module/google_hangouts', $data); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/html.php b/public/catalog/controller/extension/module/html.php new file mode 100644 index 0000000..bf32060 --- /dev/null +++ b/public/catalog/controller/extension/module/html.php @@ -0,0 +1,11 @@ +<?php +class ControllerExtensionModuleHTML extends Controller { + public function index($setting) { + if (isset($setting['module_description'][$this->config->get('config_language_id')])) { + $data['heading_title'] = html_entity_decode($setting['module_description'][$this->config->get('config_language_id')]['title'], ENT_QUOTES, 'UTF-8'); + $data['html'] = html_entity_decode($setting['module_description'][$this->config->get('config_language_id')]['description'], ENT_QUOTES, 'UTF-8'); + + return $this->load->view('extension/module/html', $data); + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/information.php b/public/catalog/controller/extension/module/information.php new file mode 100644 index 0000000..15badd3 --- /dev/null +++ b/public/catalog/controller/extension/module/information.php @@ -0,0 +1,22 @@ +<?php +class ControllerExtensionModuleInformation extends Controller { + public function index() { + $this->load->language('extension/module/information'); + + $this->load->model('catalog/information'); + + $data['informations'] = array(); + + foreach ($this->model_catalog_information->getInformations() as $result) { + $data['informations'][] = array( + 'title' => $result['title'], + 'href' => $this->url->link('information/information', 'information_id=' . $result['information_id']) + ); + } + + $data['contact'] = $this->url->link('information/contact'); + $data['sitemap'] = $this->url->link('information/sitemap'); + + return $this->load->view('extension/module/information', $data); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/klarna_checkout_module.php b/public/catalog/controller/extension/module/klarna_checkout_module.php new file mode 100644 index 0000000..079207f --- /dev/null +++ b/public/catalog/controller/extension/module/klarna_checkout_module.php @@ -0,0 +1,138 @@ +<?php +class ControllerExtensionModuleKlarnaCheckoutModule extends Controller { + public function index() { + $this->load->model('extension/payment/klarna_checkout'); + + // If Payment Method or Module is disabled + if (!$this->config->get('module_klarna_checkout_status') || !$this->config->get('klarna_checkout_status')) { + $this->model_extension_payment_klarna_checkout->log('Not shown due to Payment Method or Module being disabled'); + return false; + } + + // Validate cart has products and has stock. + if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) { + $this->model_extension_payment_klarna_checkout->log('Not shown due to empty cart'); + return false; + } + + // Validate minimum quantity requirements. + $products = $this->cart->getProducts(); + + foreach ($products as $product) { + $product_total = 0; + + foreach ($products as $product_2) { + if ($product_2['product_id'] == $product['product_id']) { + $product_total += $product_2['quantity']; + } + } + + if ($product['minimum'] > $product_total) { + $this->model_extension_payment_klarna_checkout->log('Not shown due to cart not meeting minimum quantity reqs.'); + return false; + } + } + + // Validate cart has recurring products + if ($this->cart->hasRecurringProducts()) { + $this->model_extension_payment_klarna_checkout->log('Not shown due to cart having recurring products.'); + return false; + } + + list($totals, $taxes, $total) = $this->model_extension_payment_klarna_checkout->getTotals(); + + if ($this->config->get('klarna_checkout_total') > 0 && $this->config->get('klarna_checkout_total') > $total) { + return false; + } + + if ($this->model_extension_payment_klarna_checkout->checkForPaymentTaxes($products)) { + $this->model_extension_payment_klarna_checkout->log('Payment Address based taxes used.'); + return false; + } + + $this->setShipping(); + + list($klarna_account, $connector) = $this->model_extension_payment_klarna_checkout->getConnector($this->config->get('klarna_checkout_account'), $this->session->data['currency']); + + if (!$klarna_account || !$connector) { + $this->model_extension_payment_klarna_checkout->log('Couldn\'t secure connection to Klarna API.'); + return false; + } + + $data['klarna_checkout'] = $this->url->link('extension/payment/klarna_checkout', '', true); + + return $this->load->view('extension/module/klarna_checkout_module', $data); + } + + private function setShipping() { + $this->load->model('account/address'); + $this->load->model('localisation/country'); + $this->load->model('localisation/zone'); + + if (isset($this->session->data['shipping_address']) && !empty($this->session->data['shipping_address'])) { + $this->session->data['shipping_address'] = $this->session->data['shipping_address']; + } elseif ($this->customer->isLogged() && $this->customer->getAddressId()) { + $this->session->data['shipping_address'] = $this->model_account_address->getAddress($this->customer->getAddressId()); + } else { + $country_info = $this->model_localisation_country->getCountry($this->config->get('config_country_id')); + + $zone_info = $this->model_localisation_zone->getZone($this->config->get('config_zone_id')); + + $this->session->data['shipping_address'] = array( + 'address_id' => null, + 'firstname' => null, + 'lastname' => null, + 'company' => null, + 'address_1' => null, + 'address_2' => null, + 'postcode' => null, + 'city' => null, + 'zone_id' => $zone_info['zone_id'], + 'zone' => $zone_info['name'], + 'zone_code' => $zone_info['code'], + 'country_id' => $country_info['country_id'], + 'country' => $country_info['name'], + 'iso_code_2' => $country_info['iso_code_2'], + 'iso_code_3' => $country_info['iso_code_3'], + 'address_format' => '', + 'custom_field' => null, + ); + } + + if (isset($this->session->data['shipping_address'])) { + // Shipping Methods + $method_data = array(); + + $this->load->model('setting/extension'); + + $results = $this->model_setting_extension->getExtensions('shipping'); + + foreach ($results as $result) { + if ($this->config->get('shipping_' . $result['code'] . '_status')) { + $this->load->model('extension/shipping/' . $result['code']); + + $quote = $this->{'model_extension_shipping_' . $result['code']}->getQuote($this->session->data['shipping_address']); + + if ($quote) { + $method_data[$result['code']] = array( + 'title' => $quote['title'], + 'quote' => $quote['quote'], + 'sort_order' => $quote['sort_order'], + 'error' => $quote['error'] + ); + } + } + } + + $sort_order = array(); + + foreach ($method_data as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $method_data); + + $this->session->data['shipping_methods'] = $method_data; + } + } +} diff --git a/public/catalog/controller/extension/module/latest.php b/public/catalog/controller/extension/module/latest.php new file mode 100644 index 0000000..44285de --- /dev/null +++ b/public/catalog/controller/extension/module/latest.php @@ -0,0 +1,69 @@ +<?php +class ControllerExtensionModuleLatest extends Controller { + public function index($setting) { + $this->load->language('extension/module/latest'); + + $this->load->model('catalog/product'); + + $this->load->model('tool/image'); + + $data['products'] = array(); + + $filter_data = array( + 'sort' => 'p.date_added', + 'order' => 'DESC', + 'start' => 0, + 'limit' => $setting['limit'] + ); + + $results = $this->model_catalog_product->getProducts($filter_data); + + if ($results) { + foreach ($results as $result) { + if ($result['image']) { + $image = $this->model_tool_image->resize($result['image'], $setting['width'], $setting['height']); + } else { + $image = $this->model_tool_image->resize('placeholder.png', $setting['width'], $setting['height']); + } + + if ($this->customer->isLogged() || !$this->config->get('config_customer_price')) { + $price = $this->currency->format($this->tax->calculate($result['price'], $result['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']); + } else { + $price = false; + } + + if ((float)$result['special']) { + $special = $this->currency->format($this->tax->calculate($result['special'], $result['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']); + } else { + $special = false; + } + + if ($this->config->get('config_tax')) { + $tax = $this->currency->format((float)$result['special'] ? $result['special'] : $result['price'], $this->session->data['currency']); + } else { + $tax = false; + } + + if ($this->config->get('config_review_status')) { + $rating = $result['rating']; + } else { + $rating = false; + } + + $data['products'][] = array( + 'product_id' => $result['product_id'], + 'thumb' => $image, + 'name' => $result['name'], + 'description' => utf8_substr(trim(strip_tags(html_entity_decode($result['description'], ENT_QUOTES, 'UTF-8'))), 0, $this->config->get('theme_' . $this->config->get('config_theme') . '_product_description_length')) . '..', + 'price' => $price, + 'special' => $special, + 'tax' => $tax, + 'rating' => $rating, + 'href' => $this->url->link('product/product', 'product_id=' . $result['product_id']) + ); + } + + return $this->load->view('extension/module/latest', $data); + } + } +} diff --git a/public/catalog/controller/extension/module/laybuy_layout.php b/public/catalog/controller/extension/module/laybuy_layout.php new file mode 100644 index 0000000..a586167 --- /dev/null +++ b/public/catalog/controller/extension/module/laybuy_layout.php @@ -0,0 +1,38 @@ +<?php +class ControllerExtensionModuleLaybuyLayout extends Controller { + public function index() { + $this->load->model('extension/module/laybuy_layout'); + + $status = $this->config->get('module_laybuy_layout_status'); + + if ($status && $this->config->get('payment_laybuy_status')) { + if ($this->customer->isLogged()) { + if (isset($this->request->get['order_id'])) { + $order_id = $this->request->get['order_id']; + + if ($this->model_extension_module_laybuy_layout->isLayBuyOrder($order_id)) { + $this->load->language('extension/module/laybuy_layout'); + + $transaction_info = $this->model_extension_module_laybuy_layout->getTransactionByOrderId($order_id); + + $data['transaction'] = array( + 'laybuy_ref_no' => $transaction_info['laybuy_ref_no'], + 'paypal_profile_id' => $transaction_info['paypal_profile_id'], + 'status' => $this->model_extension_module_laybuy_layout->getStatusLabel($transaction_info['status']), + 'amount' => $this->currency->format($transaction_info['amount'], $transaction_info['currency']), + 'downpayment' => $transaction_info['downpayment'], + 'months' => $transaction_info['months'], + 'downpayment_amount' => $this->currency->format($transaction_info['downpayment_amount'], $transaction_info['currency']), + 'payment_amounts' => $this->currency->format($transaction_info['payment_amounts'], $transaction_info['currency']), + 'first_payment_due' => date($this->language->get('date_format_short'), strtotime($transaction_info['first_payment_due'])), + 'last_payment_due' => date($this->language->get('date_format_short'), strtotime($transaction_info['last_payment_due'])), + 'report' => json_decode($transaction_info['report'], true) + ); + + return $this->load->view('extension/module/laybuy_layout', $data); + } + } + } + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/pilibaba_button.php b/public/catalog/controller/extension/module/pilibaba_button.php new file mode 100644 index 0000000..bd7271a --- /dev/null +++ b/public/catalog/controller/extension/module/pilibaba_button.php @@ -0,0 +1,16 @@ +<?php +class ControllerExtensionModulePilibabaButton extends Controller { + public function index() { + $status = true; + + if (!$this->cart->hasProducts() || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) { + $status = false; + } + + if ($status) { + $data['payment_url'] = $this->url->link('extension/payment/pilibaba/express', '', true); + + return $this->load->view('extension/module/pilibaba_button', $data); + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/pp_braintree_button.php b/public/catalog/controller/extension/module/pp_braintree_button.php new file mode 100644 index 0000000..32f38d8 --- /dev/null +++ b/public/catalog/controller/extension/module/pp_braintree_button.php @@ -0,0 +1,51 @@ +<?php +class ControllerExtensionModulePPBraintreeButton extends Controller { + private $gateway = null; + + public function index() { + if ($this->config->get('payment_pp_braintree_status') == 1) { + $this->initialise(); + + $status = true; + + if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout')) || (!$this->customer->isLogged() && ($this->cart->hasRecurringProducts() || $this->cart->hasDownload()))) { + $status = false; + } + + if ($status) { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/pp_braintree'); + + $create_token = array(); + + $data['client_token'] = $this->model_extension_payment_pp_braintree->generateToken($this->gateway, $create_token); + + $data['payment_pp_braintree_settlement_immediate'] = $this->config->get('payment_pp_braintree_settlement_immediate'); + $data['payment_pp_braintree_paypal_button_colour'] = $this->config->get('payment_pp_braintree_paypal_button_colour'); + $data['payment_pp_braintree_paypal_button_size'] = $this->config->get('payment_pp_braintree_paypal_button_size'); + $data['payment_pp_braintree_paypal_button_shape'] = $this->config->get('payment_pp_braintree_paypal_button_shape'); + + /* + * The auth total is just a guess as to what the end total will be since the user has not + * selected a shipping option yet. The user does not see this amount during checkout but the figure + * may be too low if buying a low value item and shipping is more than 50% of the item value. + */ + $data['auth_total'] = $this->cart->getTotal() * 1.5; + $data['currency_code'] = $this->session->data['currency']; + $data['action'] = $this->url->link('extension/payment/pp_braintree/expressConfirm', '', true); + + return $this->load->view('extension/module/pp_braintree_button', $data); + } + } + } + + private function initialise() { + $this->load->model('extension/payment/pp_braintree'); + + if ($this->config->get('payment_pp_braintree_access_token') != '') { + $this->gateway = $this->model_extension_payment_pp_braintree->setGateway($this->config->get('payment_pp_braintree_access_token')); + } else { + $this->model_extension_payment_pp_braintree->setCredentials(); + } + } +} diff --git a/public/catalog/controller/extension/module/pp_button.php b/public/catalog/controller/extension/module/pp_button.php new file mode 100644 index 0000000..a217245 --- /dev/null +++ b/public/catalog/controller/extension/module/pp_button.php @@ -0,0 +1,34 @@ +<?php +class ControllerExtensionModulePPButton extends Controller { + public function index() { + if ($this->config->get('payment_pp_express_status') == 1) { + $status = true; + + if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout')) || (!$this->customer->isLogged() && ($this->cart->hasRecurringProducts() || $this->cart->hasDownload()))) { + $status = false; + } + + if ($status) { + $this->load->model('extension/payment/pp_express'); + + if (preg_match('/Mobile|Android|BlackBerry|iPhone|Windows Phone/', $this->request->server['HTTP_USER_AGENT'])) { + $data['mobile'] = true; + } else { + $data['mobile'] = false; + } + + if ($this->config->get('payment_pp_express_test') == 1) { + $data['paypal_username'] = $this->config->get('payment_pp_express_sandbox_username'); + $data['paypal_environment'] = 'sandbox'; + } else { + $data['paypal_username'] = $this->config->get('payment_pp_express_username'); + $data['paypal_environment'] = 'production'; + } + + $data['payment_url'] = $this->url->link('extension/payment/pp_express/express', '', true); + + return $this->load->view('extension/module/pp_button', $data); + } + } + } +} diff --git a/public/catalog/controller/extension/module/pp_login.php b/public/catalog/controller/extension/module/pp_login.php new file mode 100644 index 0000000..dc581ab --- /dev/null +++ b/public/catalog/controller/extension/module/pp_login.php @@ -0,0 +1,202 @@ +<?php +class ControllerExtensionModulePPLogin extends Controller { + private $error = array(); + + public function index() { + if (!$this->customer->isLogged()) { + $data['client_id'] = $this->config->get('module_pp_login_client_id'); + $data['return_url'] = $this->url->link('extension/module/pp_login/login', '', true); + + if ($this->config->get('module_pp_login_sandbox')) { + $data['sandbox'] = 'sandbox'; + } else { + $data['sandbox'] = ''; + } + + if ($this->config->get('module_pp_login_button_colour') == 'grey') { + $data['button_colour'] = 'neutral'; + } else { + $data['button_colour'] = ''; + } + + $locale = $this->config->get('module_pp_login_locale'); + + $this->load->model('localisation/language'); + + $languages = $this->model_localisation_language->getLanguages(); + + foreach ($languages as $language) { + if ($language['status'] && ($language['code'] == $this->session->data['language']) && isset($locale[$language['language_id']])) { + $data['locale'] = $locale[$language['language_id']]; + } + } + + if (!isset($data['locale'])) { + $data['locale'] = 'en-gb'; + } + + $scopes = array( + 'profile', + 'email', + 'address', + 'phone' + ); + + if ($this->config->get('module_pp_login_seamless')) { + $scopes[] = 'https://uri.paypal.com/services/expresscheckout'; + } + + $data['scopes'] = implode(' ', $scopes); + + return $this->load->view('extension/module/pp_login', $data); + } + } + + public function login() { + $this->load->model('extension/module/pp_login'); + $this->load->model('account/customer'); + $this->load->model('account/customer_group'); + + if ($this->customer->isLogged()) { + echo '<script type="text/javascript">window.opener.location = "' . $this->url->link('account/account', '', true) . '"; window.close();</script>'; + } + + if (!isset($this->request->get['code'])) { + if (isset($this->request->get['error']) && isset($this->request->get['error_description'])) { + $this->model_extension_module_pp_login->log('No code returned. Error: ' . $this->request->get['error'] . ', Error Description: ' . $this->request->get['error_description']); + } + + echo '<script type="text/javascript">window.opener.location = "' . $this->url->link('account/login', '', true) . '"; window.close();</script>'; + } else { + $tokens = $this->model_extension_module_pp_login->getTokens($this->request->get['code']); + } + + if (isset($tokens->access_token) && !isset($tokens->error)) { + $user = $this->model_extension_module_pp_login->getUserInfo($tokens->access_token); + } + + if (isset($user)) { + $customer_info = $this->model_account_customer->getCustomerByEmail($user->email); + + if ($customer_info) { + if ($this->validate($user->email)) { + $this->completeLogin($customer_info['customer_id'], $customer_info['email'], $tokens->access_token); + } else { + $this->model_extension_module_pp_login->log('Could not login to - ID: ' . $customer_info['customer_id'] . ', Email: ' . $customer_info['email']); + echo '<script type="text/javascript">window.opener.location = "' . $this->url->link('account/login', '', true) . '"; window.close();</script>'; + } + } else { + $country = $this->db->query("SELECT `country_id` FROM `" . DB_PREFIX . "country` WHERE iso_code_2 = '" . $this->db->escape($user->address->country) . "'"); + + if ($country->num_rows) { + $country_id = $country->row['country_id']; + + $zone = $this->db->query("SELECT `zone_id` FROM `" . DB_PREFIX . "zone` WHERE country_id = '" . (int)$country_id . "' AND name = '" . $this->db->escape($user->address->region) . "'"); + + if ($zone->num_rows) { + $zone_id = $zone->row['zone_id']; + } else { + $zone_id = 0; + } + } else { + $country_id = 0; + $zone_id = 0; + } + + if ($this->config->get('module_pp_login_customer_group_id')) { + $customer_group_id = $this->config->get('module_pp_login_customer_group_id'); + } else { + $customer_group_id = $this->config->get('config_customer_group_id'); + } + + $data = array( + 'customer_group_id' => (int)$customer_group_id, + 'firstname' => $user->given_name, + 'lastname' => $user->family_name, + 'email' => $user->email, + 'telephone' => $user->phone_number, + 'password' => uniqid(rand(), true), + 'company' => '', + 'address_1' => $user->address->street_address, + 'address_2' => '', + 'city' => $user->address->locality, + 'postcode' => $user->address->postal_code, + 'country_id' => (int)$country_id, + 'zone_id' => (int)$zone_id, + ); + + $customer_id = $this->model_account_customer->addCustomer($data); + + $this->model_extension_module_pp_login->log('Customer ID date_added: ' . $customer_id); + + if ($this->validate($user->email)) { + $this->completeLogin($customer_id, $user->email, $tokens->access_token); + } else { + $this->model_extension_module_pp_login->log('Could not login to - ID: ' . $customer_id . ', Email: ' . $user->email); + echo '<script type="text/javascript">window.opener.location = "' . $this->url->link('account/login', '', true) . '"; window.close();</script>'; + } + } + } + } + + public function logout() { + if (isset($this->session->data['pp_login'])) { + unset($this->session->data['pp_login']); + } + } + + protected function completeLogin($customer_id, $email, $access_token) { + unset($this->session->data['guest']); + + // Default Shipping Address + $this->load->model('account/address'); + + if ($this->config->get('config_tax_customer') == 'payment') { + $this->session->data['payment_address'] = $this->model_account_address->getAddress($this->customer->getAddressId()); + } + + if ($this->config->get('config_tax_customer') == 'shipping') { + $this->session->data['shipping_address'] = $this->model_account_address->getAddress($this->customer->getAddressId()); + } + + if ($this->config->get('module_pp_login_seamless')) { + $this->session->data['pp_login']['seamless']['customer_id'] = $this->customer->getId(); + $this->session->data['pp_login']['seamless']['access_token'] = $access_token; + } else { + if (isset($this->session->data['pp_login']['seamless'])) { + unset($this->session->data['pp_login']['seamless']); + } + } + + $this->model_extension_module_pp_login->log('Customer logged in - ID: ' . $customer_id . ', Email: ' . $email); + echo '<script type="text/javascript">window.opener.location = "' . $this->url->link('account/account', '', true) . '"; window.close();</script>'; + } + + protected function validate($email) { + // Check how many login attempts have been made. + $login_info = $this->model_account_customer->getLoginAttempts($email); + + if ($login_info && ($login_info['total'] >= $this->config->get('config_login_attempts')) && strtotime('-1 hour') < strtotime($login_info['date_modified'])) { + $this->error['warning'] = $this->language->get('error_attempts'); + } + + // Check if customer has been approved. + $customer_info = $this->model_account_customer->getCustomerByEmail($email); + + if ($customer_info && !$customer_info['status']) { + $this->error['warning'] = $this->language->get('error_approved'); + } + + if (!$this->error) { + if (!$this->customer->login($email, '', true)) { + $this->error['warning'] = $this->language->get('error_login'); + + $this->model_account_customer->addLoginAttempt($email); + } else { + $this->model_account_customer->deleteLoginAttempts($email); + } + } + + return !$this->error; + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/sagepay_direct_cards.php b/public/catalog/controller/extension/module/sagepay_direct_cards.php new file mode 100644 index 0000000..0d4dce1 --- /dev/null +++ b/public/catalog/controller/extension/module/sagepay_direct_cards.php @@ -0,0 +1,13 @@ +<?php +class ControllerExtensionModuleSagepayDirectCards extends Controller { + public function index() { + if ($this->config->get('module_sagepay_direct_cards_status') && $this->config->get('payment_sagepay_direct_status') && $this->customer->isLogged()) { + $this->load->language('account/sagepay_direct_cards'); + + $data['card'] = $this->url->link('account/sagepay_direct_cards', '', true); + + return $this->load->view('extension/module/sagepay_direct_cards', $data); + } + } + +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/sagepay_server_cards.php b/public/catalog/controller/extension/module/sagepay_server_cards.php new file mode 100644 index 0000000..f4cc007 --- /dev/null +++ b/public/catalog/controller/extension/module/sagepay_server_cards.php @@ -0,0 +1,13 @@ +<?php +class ControllerExtensionModuleSagepayServerCards extends Controller { + public function index() { + if ($this->config->get('module_sagepay_server_cards_status') && $this->config->get('payment_sagepay_server_status') && $this->customer->isLogged()) { + $this->load->language('account/sagepay_server_cards'); + + $data['card'] = $this->url->link('account/sagepay_server_cards', '', true); + + return $this->load->view('extension/module/sagepay_server_cards', $data); + } + } + +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/slideshow.php b/public/catalog/controller/extension/module/slideshow.php new file mode 100644 index 0000000..80265d7 --- /dev/null +++ b/public/catalog/controller/extension/module/slideshow.php @@ -0,0 +1,31 @@ +<?php +class ControllerExtensionModuleSlideshow extends Controller { + public function index($setting) { + static $module = 0; + + $this->load->model('design/banner'); + $this->load->model('tool/image'); + + $this->document->addStyle('catalog/view/javascript/jquery/swiper/css/swiper.min.css'); + $this->document->addStyle('catalog/view/javascript/jquery/swiper/css/opencart.css'); + $this->document->addScript('catalog/view/javascript/jquery/swiper/js/swiper.jquery.js'); + + $data['banners'] = array(); + + $results = $this->model_design_banner->getBanner($setting['banner_id']); + + foreach ($results as $result) { + if (is_file(DIR_IMAGE . $result['image'])) { + $data['banners'][] = array( + 'title' => $result['title'], + 'link' => $result['link'], + 'image' => $this->model_tool_image->resize($result['image'], $setting['width'], $setting['height']) + ); + } + } + + $data['module'] = $module++; + + return $this->load->view('extension/module/slideshow', $data); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/special.php b/public/catalog/controller/extension/module/special.php new file mode 100644 index 0000000..6f13eed --- /dev/null +++ b/public/catalog/controller/extension/module/special.php @@ -0,0 +1,69 @@ +<?php +class ControllerExtensionModuleSpecial extends Controller { + public function index($setting) { + $this->load->language('extension/module/special'); + + $this->load->model('catalog/product'); + + $this->load->model('tool/image'); + + $data['products'] = array(); + + $filter_data = array( + 'sort' => 'pd.name', + 'order' => 'ASC', + 'start' => 0, + 'limit' => $setting['limit'] + ); + + $results = $this->model_catalog_product->getProductSpecials($filter_data); + + if ($results) { + foreach ($results as $result) { + if ($result['image']) { + $image = $this->model_tool_image->resize($result['image'], $setting['width'], $setting['height']); + } else { + $image = $this->model_tool_image->resize('placeholder.png', $setting['width'], $setting['height']); + } + + if ($this->customer->isLogged() || !$this->config->get('config_customer_price')) { + $price = $this->currency->format($this->tax->calculate($result['price'], $result['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']); + } else { + $price = false; + } + + if ((float)$result['special']) { + $special = $this->currency->format($this->tax->calculate($result['special'], $result['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']); + } else { + $special = false; + } + + if ($this->config->get('config_tax')) { + $tax = $this->currency->format((float)$result['special'] ? $result['special'] : $result['price'], $this->session->data['currency']); + } else { + $tax = false; + } + + if ($this->config->get('config_review_status')) { + $rating = $result['rating']; + } else { + $rating = false; + } + + $data['products'][] = array( + 'product_id' => $result['product_id'], + 'thumb' => $image, + 'name' => $result['name'], + 'description' => utf8_substr(trim(strip_tags(html_entity_decode($result['description'], ENT_QUOTES, 'UTF-8'))), 0, $this->config->get('theme_' . $this->config->get('config_theme') . '_product_description_length')) . '..', + 'price' => $price, + 'special' => $special, + 'tax' => $tax, + 'rating' => $rating, + 'href' => $this->url->link('product/product', 'product_id=' . $result['product_id']) + ); + } + + return $this->load->view('extension/module/special', $data); + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/module/store.php b/public/catalog/controller/extension/module/store.php new file mode 100644 index 0000000..40a0dd4 --- /dev/null +++ b/public/catalog/controller/extension/module/store.php @@ -0,0 +1,40 @@ +<?php +class ControllerExtensionModuleStore extends Controller { + public function index() { + $status = true; + + if ($this->config->get('module_store_admin')) { + $this->user = new Cart\User($this->registry); + + $status = $this->user->isLogged(); + } + + if ($status) { + $this->load->language('extension/module/store'); + + $data['store_id'] = $this->config->get('config_store_id'); + + $data['stores'] = array(); + + $data['stores'][] = array( + 'store_id' => 0, + 'name' => $this->language->get('text_default'), + 'url' => HTTP_SERVER . 'index.php?route=common/home&session_id=' . $this->session->getId() + ); + + $this->load->model('setting/store'); + + $results = $this->model_setting_store->getStores(); + + foreach ($results as $result) { + $data['stores'][] = array( + 'store_id' => $result['store_id'], + 'name' => $result['name'], + 'url' => $result['url'] . 'index.php?route=common/home&session_id=' . $this->session->getId() + ); + } + + return $this->load->view('extension/module/store', $data); + } + } +} diff --git a/public/catalog/controller/extension/openbay/amazon.php b/public/catalog/controller/extension/openbay/amazon.php new file mode 100644 index 0000000..3df7054 --- /dev/null +++ b/public/catalog/controller/extension/openbay/amazon.php @@ -0,0 +1,590 @@ +<?php +class ControllerExtensionOpenbayAmazon extends Controller { + public function order() { + if ($this->config->get('openbay_amazon_status') != '1') { + return; + } + + $this->load->model('checkout/order'); + $this->load->model('extension/openbay/amazon_order'); + $this->load->language('extension/openbay/amazon_order'); + + $logger = new Log('amazon.log'); + $logger->write('amazon/order - started'); + + $incoming_token = isset($this->request->post['token']) ? $this->request->post['token'] : ''; + + if (!hash_equals($this->config->get('openbay_amazon_token'), $incoming_token)) { + $logger->write('amazon/order - Incorrect token: ' . $incoming_token); + return; + } + + $decrypted = $this->openbay->decrypt($this->request->post['data'], $this->openbay->amazon->getEncryptionKey(), $this->openbay->amazon->getEncryptionIv(), false); + + if (!$decrypted) { + $logger->write('amazon/order Failed to decrypt data'); + return; + } + + $order_xml = simplexml_load_string($decrypted); + + $amazon_order_status = trim(strtolower((string)$order_xml->Status)); + + $amazon_order_id = (string)$order_xml->AmazonOrderId; + $order_status = $this->model_extension_openbay_amazon_order->getMappedStatus((string)$order_xml->Status); + + $logger->write('Received order ' . $amazon_order_id); + + $order_id = $this->model_extension_openbay_amazon_order->getOrderId($amazon_order_id); + + // If the order already exists on opencart, ignore it. + if ($order_id) { + $logger->write("Duplicate order $amazon_order_id. Terminating."); + $this->response->setOutput('Ok'); + return; + } + + /* Check if order comes from subscribed marketplace */ + + $currency_to = $this->config->get('config_currency'); + $order_currency = (string)$order_xml->Payment->CurrencyCode; + + $products = array(); + + $products_total = 0; + $products_shipping = 0; + $products_tax = 0; + $products_shipping_tax = 0; + $gift_wrap = 0; + $gift_wrap_tax = 0; + + $product_count = 0; + + $amazon_order_id = (string)$order_xml->AmazonOrderId; + + /* SKU => ORDER_ITEM_ID */ + $product_mapping = array(); + $product_gift_messages = array(); + + foreach ($order_xml->Items->Item as $item) { + + $total_price = $this->currency->convert((double)$item->Totals->Price, $order_currency, $currency_to); + $tax_total = (double)$item->Totals->Tax; + + if ($tax_total == 0 && $this->config->get('openbay_amazon_order_tax') > 0) { + $tax_total = (double)$item->Totals->Price * ($this->config->get('openbay_amazon_order_tax') / 100) / (1 + $this->config->get('openbay_amazon_order_tax') / 100); + } + + $tax_total = $this->currency->convert($tax_total, $order_currency, $currency_to); + + $products_total += $total_price; + $products_tax += $tax_total; + + $products_shipping += $this->currency->convert((double)$item->Totals->Shipping, $order_currency, $currency_to); + + $shipping_tax = (double)$item->Totals->ShippingTax; + + if ($shipping_tax == 0 && $this->config->get('openbay_amazon_order_tax') > 0) { + $shipping_tax = (double)$item->Totals->Shipping * ($this->config->get('openbay_amazon_order_tax') / 100) / (1 + $this->config->get('openbay_amazon_order_tax') / 100); + } + + $products_shipping_tax += $this->currency->convert($shipping_tax, $order_currency, $currency_to); + + $gift_wrap += $this->currency->convert((double)$item->Totals->GiftWrap, $order_currency, $currency_to); + + $item_gift_wrap_tax = (double)$item->Totals->GiftWrapTax; + + if ($item_gift_wrap_tax == 0 && $this->config->get('openbay_amazon_order_tax') > 0) { + $item_gift_wrap_tax = (double)$item->Totals->GiftWrap * ($this->config->get('openbay_amazon_order_tax') / 100) / (1 + $this->config->get('openbay_amazon_order_tax') / 100); + } + + $gift_wrap_tax += $this->currency->convert($item_gift_wrap_tax, $order_currency, $currency_to); + + $product_count += (int)$item->Ordered; + + if ((int)$item->Ordered == 0) { + continue; + } + + $product_id = $this->model_extension_openbay_amazon_order->getProductId((string)$item->Sku); + $product_var = $this->model_extension_openbay_amazon_order->getProductVar((string)$item->Sku); + + $products[] = array( + 'product_id' => $product_id, + 'var' => $product_var, + 'sku' => (string)$item->Sku, + 'asin' => (string)$item->Asin, + 'order_item_id' => (string)$item->OrderItemId, + 'name' => (string)$item->Title, + 'model' => (string)$item->Sku, + 'quantity' => (int)$item->Ordered, + 'price' => sprintf('%.4f', ($total_price - $tax_total) / (int)$item->Ordered), + 'total' => sprintf('%.4f', $total_price - $tax_total), + 'tax' => $tax_total / (int)$item->Ordered, + 'reward' => '0', + 'option' => $this->model_extension_openbay_amazon_order->getProductOptionsByVar($product_var), + 'download' => array(), + ); + + $product_mapping[(string)$item->Sku] = (string)$item->OrderItemId; + + if ($item->GiftMessage != '') { + $product_gift_messages[] = (string)$item->Title . ' : ' . (string)$item->GiftMessage; + } + } + + $order_comment = ''; + if (count($product_gift_messages) > 0) { + $order_comment = $this->language->get('text_gift_message') . '<br />' . implode('<br />', $product_gift_messages); + } + + $total = sprintf('%.4f', $this->currency->convert((double)$order_xml->Payment->Amount, $order_currency, $currency_to)); + + $address_line_2 = (string)$order_xml->Shipping->AddressLine2; + if ((string)$order_xml->Shipping->AddressLine3 != '') { + $address_line_2 .= ', ' . (string)$order_xml->Shipping->AddressLine3; + } + + $customer_info = $this->db->query("SELECT `customer_id` FROM " . DB_PREFIX . "customer WHERE email = '" . $this->db->escape((string)$order_xml->Payment->Email) . "'")->row; + $customer_id = '0'; + + if(isset($customer_info['customer_id'])) { + $customer_id = $customer_info['customer_id']; + } else { + /* Add a new customer */ + $customer_data = array( + 'firstname' => (string)$order_xml->Shipping->Name, + 'lastname' => '', + 'email' => (string)$order_xml->Payment->Email, + 'telephone' => (string)$order_xml->Shipping->Phone, + 'newsletter' => '0', + 'customer_group_id' => $this->config->get('openbay_amazon_order_customer_group'), + 'password' => '', + 'status' => '0', + ); + + $this->db->query(" + INSERT INTO " . DB_PREFIX . "customer + SET firstname = '" . $this->db->escape($customer_data['firstname']) . "', + lastname = '" . $this->db->escape($customer_data['lastname']) . "', + email = '" . $this->db->escape($customer_data['email']) . "', + telephone = '" . $this->db->escape($customer_data['telephone']) . "', + newsletter = '" . (int)$customer_data['newsletter'] . "', + customer_group_id = '" . (int)$customer_data['customer_group_id'] . "', + password = '', + status = '" . (int)$customer_data['status'] . "', + date_added = NOW()"); + + $customer_id = $this->db->getLastId(); + } + + $shipping_first_name = (string)$order_xml->Shipping->FirstName; + $shipping_last_name = (string)$order_xml->Shipping->LastName; + + if (empty($shipping_first_name) || empty($shipping_last_name)) { + $shipping_first_name = (string)$order_xml->Shipping->Name; + $shipping_last_name = ''; + } + + $order = array( + 'invoice_prefix' => $this->config->get('config_invoice_prefix'), + 'store_id' => $this->config->get('config_store_id'), + 'store_name' => $this->config->get('config_name') . ' / Amazon', + 'store_url' => $this->config->get('config_url'), + 'customer_id' => (int)$customer_id, + 'customer_group_id' => $this->config->get('openbay_amazon_order_customer_group'), + 'firstname' => $shipping_first_name, + 'lastname' => $shipping_last_name, + 'email' => (string)$order_xml->Payment->Email, + 'telephone' => (string)$order_xml->Shipping->Phone, + 'fax' => '', + 'shipping_firstname' => $shipping_first_name, + 'shipping_lastname' => $shipping_last_name, + 'shipping_company' => '', + 'shipping_address_1' => (string)$order_xml->Shipping->AddressLine1, + 'shipping_address_2' => $address_line_2, + 'shipping_city' => (string)$order_xml->Shipping->City, + 'shipping_postcode' => (string)$order_xml->Shipping->PostCode, + 'shipping_country' => $this->model_extension_openbay_amazon_order->getCountryName((string)$order_xml->Shipping->CountryCode), + 'shipping_country_id' => $this->model_extension_openbay_amazon_order->getCountryId((string)$order_xml->Shipping->CountryCode), + 'shipping_zone' => (string)$order_xml->Shipping->State, + 'shipping_zone_id' => $this->model_extension_openbay_amazon_order->getZoneId((string)$order_xml->Shipping->State), + 'shipping_address_format' => '', + 'shipping_method' => (string)$order_xml->Shipping->Type, + 'shipping_code' => 'amazon.' . (string)$order_xml->Shipping->Type, + 'payment_firstname' => $shipping_first_name, + 'payment_lastname' => $shipping_last_name, + 'payment_company' => '', + 'payment_address_1' => (string)$order_xml->Shipping->AddressLine1, + 'payment_address_2' => $address_line_2, + 'payment_city' => (string)$order_xml->Shipping->City, + 'payment_postcode' => (string)$order_xml->Shipping->PostCode, + 'payment_country' => $this->model_extension_openbay_amazon_order->getCountryName((string)$order_xml->Shipping->CountryCode), + 'payment_country_id' => $this->model_extension_openbay_amazon_order->getCountryId((string)$order_xml->Shipping->CountryCode), + 'payment_zone' => (string)$order_xml->Shipping->State, + 'payment_zone_id' => $this->model_extension_openbay_amazon_order->getZoneId((string)$order_xml->Shipping->State), + 'payment_address_format' => '', + 'payment_method' => $this->language->get('text_paid_amazon'), + 'payment_code' => 'amazon.amazon', + 'payment_company_id' => 0, + 'payment_tax_id' => 0, + 'comment' => $order_comment, + 'total' => $total, + 'affiliate_id' => '0', + 'commission' => '0.00', + 'language_id' => (int)$this->config->get('config_language_id'), + 'currency_id' => $this->currency->getId($order_currency), + 'currency_code' => (string)$order_currency, + 'currency_value' => $this->currency->getValue($order_currency), + 'ip' => '', + 'forwarded_ip' => '', + 'user_agent' => 'OpenBay Pro for Amazon', + 'accept_language' => '', + 'products' => $products, + 'vouchers' => array(), + 'marketing_id' => 0, + 'tracking' => 0, + 'totals' => array( + array( + 'code' => 'sub_total', + 'title' => $this->language->get('text_total_sub'), + 'value' => sprintf('%.4f', $products_total), + 'sort_order' => '1', + ), + array( + 'code' => 'shipping', + 'title' => $this->language->get('text_total_shipping'), + 'value' => sprintf('%.4f', $products_shipping), + 'sort_order' => '3', + ), + array( + 'code' => 'tax', + 'title' => $this->language->get('text_tax'), + 'value' => sprintf('%.4f', $products_tax), + 'sort_order' => '4', + ), + array( + 'code' => 'shipping_tax', + 'title' => $this->language->get('text_total_shipping_tax'), + 'value' => sprintf('%.4f', $products_shipping_tax), + 'sort_order' => '6', + ), + array( + 'code' => 'gift_wrap', + 'title' => $this->language->get('text_total_giftwrap'), + 'value' => sprintf('%.4f', $gift_wrap), + 'sort_order' => '2', + ), + array( + 'code' => 'gift_wrap_tax', + 'title' => $this->language->get('text_total_giftwrap_tax'), + 'value' => sprintf('%.4f', $gift_wrap_tax), + 'sort_order' => '5', + ), + array( + 'code' => 'total', + 'title' => $this->language->get('text_total'), + 'value' => sprintf('%.4f', $total), + 'sort_order' => '7', + ), + ), + ); + + $order_id = $this->model_checkout_order->addOrder($order); + + $this->model_extension_openbay_amazon_order->updateOrderStatus($order_id, $order_status); + $this->model_extension_openbay_amazon_order->addAmazonOrder($order_id, $amazon_order_id); + $this->model_extension_openbay_amazon_order->addAmazonOrderProducts($order_id, $product_mapping); + + foreach($products as $product) { + if($product['product_id'] != 0) { + $this->model_extension_openbay_amazon_order->decreaseProductQuantity($product['product_id'], $product['quantity'], $product['var']); + } + } + + $logger->write('Order ' . $amazon_order_id . ' was added to the database (ID: ' . $order_id . ')'); + $logger->write("Finished processing the order"); + + $this->model_extension_openbay_amazon_order->acknowledgeOrder($order_id); + + if($this->config->get('openbay_amazon_notify_admin') == 1){ + $this->openbay->newOrderAdminNotify($order_id, $order_status); + } + + $this->event->trigger('model/checkout/order/addOrderHistory/after', array('model/checkout/order/addOrderHistory/after', array($order_id, $order_status))); + + $logger->write("Ok"); + $this->response->setOutput('Ok'); + } + + public function listing() { + if ($this->config->get('openbay_amazon_status') != '1') { + return; + } + + $this->load->model('extension/openbay/amazon_listing'); + $this->load->model('extension/openbay/amazon_product'); + + $logger = new Log('amazon_listing.log'); + $logger->write('amazon/listing - started'); + + $incoming_token = isset($this->request->post['token']) ? $this->request->post['token'] : ''; + + if (!hash_equals($this->config->get('openbay_amazon_token'), $incoming_token)) { + $logger->write('amazon/listing - Incorrect token: ' . $incoming_token); + return; + } + + $decrypted = $this->openbay->decrypt($this->request->post['data'], $this->openbay->amazon->getEncryptionKey(), $this->openbay->amazon->getEncryptionIv(), false); + + if (!$decrypted) { + $logger->write('amazon/order Failed to decrypt data'); + return; + } + + $data = json_decode($decrypted, 1); + + $logger->write("Received data: " . print_r($data, 1)); + + if ($data['status']) { + $logger->write("Updating " . $data['product_id'] . ' from ' . $data['marketplace'] . ' as successful'); + $this->model_extension_openbay_amazon_listing->listingSuccessful($data['product_id'], $data['marketplace']); + $this->model_extension_openbay_amazon_product->linkProduct($data['sku'], $data['product_id']); + $logger->write("Updated successfully"); + } else { + $logger->write("Updating " . $data['product_id'] . ' from ' . $data['marketplace'] . ' as failed'); + $this->model_extension_openbay_amazon_listing->listingFailed($data['product_id'], $data['marketplace'], $data['messages']); + $logger->write("Updated successfully"); + } + } + + public function listingReport() { + if ($this->config->get('openbay_amazon_status') != '1') { + return; + } + + $this->load->model('extension/openbay/amazon_product'); + + $logger = new Log('amazon.log'); + $logger->write('amazon/listing_reports - started'); + + $incoming_token = isset($this->request->post['token']) ? $this->request->post['token'] : ''; + + if (!hash_equals($this->config->get('openbay_amazon_token'), $incoming_token)) { + $logger->write('amazon/listing_reports - Incorrect token: ' . $incoming_token); + return; + } + + $decrypted = $this->openbay->decrypt($this->request->post['data'], $this->openbay->amazon->getEncryptionKey(), $this->openbay->amazon->getEncryptionIv(), false); + + if (!$decrypted) { + $logger->write('amazon/listing_reports - Failed to decrypt data'); + return; + } + + $logger->write('Received Listing Report: ' . $decrypted); + + $request = json_decode($decrypted, 1); + + $data = array(); + + foreach ($request['products'] as $product) { + $data[] = array( + 'marketplace' => $request['marketplace'], + 'sku' => $product['sku'], + 'quantity' => $product['quantity'], + 'asin' => $product['asin'], + 'price' => $product['price'], + ); + } + + if ($data) { + $this->model_extension_openbay_amazon_product->addListingReport($data); + } + + $this->model_extension_openbay_amazon_product->removeListingReportLock($request['marketplace']); + + $logger->write('amazon/listing_reports - Finished'); + } + + public function product() { + if ($this->config->get('openbay_amazon_status') != '1') { + $this->response->setOutput("disabled"); + return; + } + + ob_start(); + + $this->load->model('extension/openbay/amazon_product'); + $logger = new Log('amazon_product.log'); + + $logger->write("AmazonProduct/inbound: incoming data"); + + $incoming_token = isset($this->request->post['token']) ? $this->request->post['token'] : ''; + + if($incoming_token != $this->config->get('openbay_amazon_token')) { + $logger->write("Error - Incorrect token: " . $this->request->post['token']); + ob_get_clean(); + $this->response->setOutput("tokens did not match"); + + return; + } + + $decrypted = $this->openbay->decrypt($this->request->post['data'], $this->openbay->amazon->getEncryptionKey(), $this->openbay->amazon->getEncryptionIv(), false); + + if(!$decrypted) { + $logger->write("Error - Failed to decrypt received data."); + ob_get_clean(); + $this->response->setOutput("failed to decrypt"); + + return; + } + + $decoded_data = (array)json_decode($decrypted); + $logger->write("Received data: " . print_r($decoded_data, true)); + $status = $decoded_data['status']; + + if($status == "submit_error") { + $message = 'Product was not submited to amazon properly. Please try again or contact OpenBay.'; + $this->model_extension_openbay_amazon_product->setSubmitError($decoded_data['insertion_id'], $message); + } else { + $status = (array)$status; + if($status['successful'] == 1) { + $this->model_extension_openbay_amazon_product->setStatus($decoded_data['insertion_id'], 'ok'); + $insertion_product = $this->model_extension_openbay_amazon_product->getProduct($decoded_data['insertion_id']); + $this->model_extension_openbay_amazon_product->linkProduct($insertion_product['sku'], $insertion_product['product_id'], $insertion_product['var']); + $this->model_extension_openbay_amazon_product->deleteErrors($decoded_data['insertion_id']); + + $quantity_data = array( + $insertion_product['sku'] => $this->model_extension_openbay_amazon_product->getProductQuantity($insertion_product['product_id'], $insertion_product['var']) + ); + $logger->write('Updating quantity with data: ' . print_r($quantity_data, true)); + $logger->write('Response: ' . print_r($this->openbay->amazon->updateQuantities($quantity_data), true)); + } else { + $msg = 'Product was not accepted by amazon. Please try again or contact OpenBay.'; + $this->model_extension_openbay_amazon_product->setSubmitError($decoded_data['insertion_id'], $msg); + + if(isset($decoded_data['error_details'])) { + foreach($decoded_data['error_details'] as $error) { + $error = (array)$error; + $error_data = array( + 'sku' => $error['sku'], + 'error_code' => $error['error_code'], + 'message' => $error['message'], + 'insertion_id' => $decoded_data['insertion_id'] + ); + $this->model_extension_openbay_amazon_product->insertError($error_data); + } + } + } + } + + $logger->write("Data processed successfully."); + ob_get_clean(); + $this->response->setOutput("ok"); + } + + public function search() { + if ($this->config->get('openbay_amazon_status') != '1') { + return; + } + + $this->load->model('extension/openbay/amazon_product'); + + $logger = new Log('amazon.log'); + $logger->write('amazon/search - started'); + + $incoming_token = isset($this->request->post['token']) ? $this->request->post['token'] : ''; + + if (!hash_equals($this->config->get('openbay_amazon_token'), $incoming_token)) { + $logger->write('amazon/search - Incorrect token: ' . $incoming_token); + return; + } + + $decrypted = $this->openbay->decrypt($this->request->post['data'], $this->openbay->amazon->getEncryptionKey(), $this->openbay->amazon->getEncryptionIv(), false); + + if (!$decrypted) { + $logger->write('amazon/search Failed to decrypt data'); + return; + } + + $logger->write($decrypted); + + $json = json_decode($decrypted, 1); + + $this->model_extension_openbay_amazon_product->updateSearch($json); + } + + public function dev() { + if ($this->config->get('openbay_amazon_status') != '1') { + $this->response->setOutput("error 001"); + return; + } + + $incoming_token = isset($this->request->post['token']) ? $this->request->post['token'] : ''; + + if ($incoming_token != $this->config->get('openbay_amazon_token')) { + $this->response->setOutput("error 002"); + return; + } + + $decrypted = $this->openbay->decrypt($this->request->post['data'], $this->openbay->amazon->getEncryptionKey(), $this->openbay->amazon->getEncryptionIv(), false); + + if (!$decrypted) { + $this->response->setOutput("error 003"); + return; + } + + $data_xml = simplexml_load_string(base64_decode($decrypted)); + + if(!isset($data_xml->action)) { + $this->response->setOutput("error 004"); + return; + } + + $action = trim((string)$data_xml->action); + + if ($action === "get_amazon_product") { + if(!isset($data_xml->product_id)) { + $this->response->setOutput("error 005"); + return; + } + + $product_id = trim((string)$data_xml->product_id); + + if ($product_id === "all") { + $all_rows = $this->db->query("SELECT * FROM `" . DB_PREFIX . "amazon_product`")->rows; + + $response = array(); + foreach ($all_rows as $row) { + unset($row['data']); + $response[] = $row; + } + + $this->response->setOutput(print_r($response, true)); + return; + } else { + $response = $this->db->query("SELECT * FROM `" . DB_PREFIX . "amazon_product` WHERE `product_id` = '" . (int)$product_id . "'")->rows; + + $this->response->setOutput(print_r($response, true)); + return; + } + } else { + $this->response->setOutput("error 999"); + return; + } + } + + public function eventAddOrderHistory($route, $data) { + $logger = new \Log('amazon.log'); + $logger->write('eventAddOrderHistory Event fired: ' . $route); + + if (isset($data[0]) && !empty($data[0])) { + $this->load->model('extension/openbay/amazon_order'); + + $logger->write('Order ID: ' . (int)$data[0]); + + $this->model_extension_openbay_amazon_order->addOrderHistory((int)$data[0]); + } + } +} diff --git a/public/catalog/controller/extension/openbay/amazonus.php b/public/catalog/controller/extension/openbay/amazonus.php new file mode 100644 index 0000000..7bdfb8b --- /dev/null +++ b/public/catalog/controller/extension/openbay/amazonus.php @@ -0,0 +1,591 @@ +<?php +class ControllerExtensionOpenbayAmazonus extends Controller { + public function order() { + if ($this->config->get('openbay_amazonus_status') != '1') { + return; + } + + $this->load->model('checkout/order'); + $this->load->model('extension/openbay/amazonus_order'); + $this->load->language('extension/openbay/amazonus_order'); + + $logger = new Log('amazonus.log'); + $logger->write('amazonus/order - started'); + + $incoming_token = isset($this->request->post['token']) ? $this->request->post['token'] : ''; + + if (!hash_equals($this->config->get('openbay_amazonus_token'), $incoming_token)) { + $logger->write('amazon/order - Incorrect token: ' . $incoming_token); + return; + } + + $decrypted = $this->openbay->decrypt($this->request->post['data'], $this->openbay->amazonus->getEncryptionKey(), $this->openbay->amazonus->getEncryptionIv(), false); + + if (!$decrypted) { + $logger->write('amazonus/order Failed to decrypt data'); + return; + } + + $order_xml = simplexml_load_string($decrypted); + + $amazonus_order_status = trim(strtolower((string)$order_xml->Status)); + + $amazonus_order_id = (string)$order_xml->AmazonOrderId; + $order_status = $this->model_extension_openbay_amazonus_order->getMappedStatus((string)$order_xml->Status); + + $logger->write('Received order ' . $amazonus_order_id); + + $order_id = $this->model_extension_openbay_amazonus_order->getOrderId($amazonus_order_id); + + // If the order already exists on opencart, ignore it. + if ($order_id) { + $logger->write("Duplicate order $amazonus_order_id. Terminating."); + $this->response->setOutput('Ok'); + return; + } + + /* Check if order comes from subscribed marketplace */ + + $currency_to = $this->config->get('config_currency'); + $order_currency = (string)$order_xml->Payment->CurrencyCode; + + $products = array(); + + $products_total = 0; + $products_shipping = 0; + $products_tax = 0; + $products_shipping_tax = 0; + $gift_wrap = 0; + $gift_wrap_tax = 0; + + $product_count = 0; + + $amazonus_order_id = (string)$order_xml->AmazonOrderId; + + /* SKU => ORDER_ITEM_ID */ + $product_mapping = array(); + $product_gift_messages = array(); + + foreach ($order_xml->Items->Item as $item) { + + $total_price = $this->currency->convert((double)$item->Totals->Price, $order_currency, $currency_to); + $tax_total = (double)$item->Totals->Tax; + + if ($tax_total == 0 && $this->config->get('openbay_amazonus_order_tax') > 0) { + $tax_total = (double)$item->Totals->Price * ($this->config->get('openbay_amazonus_order_tax') / 100) / (1 + $this->config->get('openbay_amazonus_order_tax') / 100); + } + + $tax_total = $this->currency->convert($tax_total, $order_currency, $currency_to); + + $products_total += $total_price; + $products_tax += $tax_total; + + $products_shipping += $this->currency->convert((double)$item->Totals->Shipping, $order_currency, $currency_to); + + $shipping_tax = (double)$item->Totals->ShippingTax; + + if ($shipping_tax == 0 && $this->config->get('openbay_amazonus_order_tax') > 0) { + $shipping_tax = (double)$item->Totals->Shipping * ($this->config->get('openbay_amazonus_order_tax') / 100) / (1 + $this->config->get('openbay_amazonus_order_tax') / 100); + } + + $products_shipping_tax += $this->currency->convert($shipping_tax, $order_currency, $currency_to); + + $gift_wrap += $this->currency->convert((double)$item->Totals->GiftWrap, $order_currency, $currency_to); + + $item_gift_wrap_tax = (double)$item->Totals->GiftWrapTax; + + if ($item_gift_wrap_tax == 0 && $this->config->get('openbay_amazonus_order_tax') > 0) { + $item_gift_wrap_tax = (double)$item->Totals->GiftWrap * ($this->config->get('openbay_amazonus_order_tax') / 100) / (1 + $this->config->get('openbay_amazonus_order_tax') / 100); + } + + $gift_wrap_tax += $this->currency->convert($item_gift_wrap_tax, $order_currency, $currency_to); + + $product_count += (int)$item->Ordered; + + if ((int)$item->Ordered == 0) { + continue; + } + + $product_id = $this->model_extension_openbay_amazonus_order->getProductId((string)$item->Sku); + $product_var = $this->model_extension_openbay_amazonus_order->getProductVar((string)$item->Sku); + + $products[] = array( + 'product_id' => $product_id, + 'var' => $product_var, + 'sku' => (string)$item->Sku, + 'asin' => (string)$item->Asin, + 'order_item_id' => (string)$item->OrderItemId, + 'name' => (string)$item->Title, + 'model' => (string)$item->Sku, + 'quantity' => (int)$item->Ordered, + 'price' => sprintf('%.4f', ($total_price - $tax_total) / (int)$item->Ordered), + 'total' => sprintf('%.4f', $total_price - $tax_total), + 'tax' => $tax_total / (int)$item->Ordered, + 'reward' => '0', + 'option' => $this->model_extension_openbay_amazonus_order->getProductOptionsByVar($product_var), + 'download' => array(), + ); + + $product_mapping[(string)$item->Sku] = (string)$item->OrderItemId; + + if ($item->GiftMessage != '') { + $product_gift_messages[] = (string)$item->Title . ' : ' . (string)$item->GiftMessage; + } + } + + $order_comment = ''; + if (count($product_gift_messages) > 0) { + $order_comment = $this->language->get('text_gift_message') . '<br />' . implode('<br />', $product_gift_messages); + } + + $total = sprintf('%.4f', $this->currency->convert((double)$order_xml->Payment->Amount, $order_currency, $currency_to)); + + $address_line_2 = (string)$order_xml->Shipping->AddressLine2; + if ((string)$order_xml->Shipping->AddressLine3 != '') { + $address_line_2 .= ', ' . (string)$order_xml->Shipping->AddressLine3; + } + + $customer_info = $this->db->query("SELECT `customer_id` FROM " . DB_PREFIX . "customer WHERE email = '" . $this->db->escape((string)$order_xml->Payment->Email) . "'")->row; + $customer_id = '0'; + + if(isset($customer_info['customer_id'])) { + $customer_id = $customer_info['customer_id']; + } else { + /* Add a new customer */ + $customer_data = array( + 'firstname' => (string)$order_xml->Shipping->Name, + 'lastname' => '', + 'email' => (string)$order_xml->Payment->Email, + 'telephone' => (string)$order_xml->Shipping->Phone, + 'fax' => '', + 'newsletter' => '0', + 'customer_group_id' => $this->config->get('openbay_amazonus_order_customer_group'), + 'password' => '', + 'status' => '0', + ); + + $this->db->query(" + INSERT INTO " . DB_PREFIX . "customer + SET firstname = '" . $this->db->escape($customer_data['firstname']) . "', + lastname = '" . $this->db->escape($customer_data['lastname']) . "', + email = '" . $this->db->escape($customer_data['email']) . "', + telephone = '" . $this->db->escape($customer_data['telephone']) . "', + newsletter = '" . (int)$customer_data['newsletter'] . "', + customer_group_id = '" . (int)$customer_data['customer_group_id'] . "', + password = '', + status = '" . (int)$customer_data['status'] . "', + date_added = NOW()"); + + $customer_id = $this->db->getLastId(); + } + + $shipping_first_name = (string)$order_xml->Shipping->FirstName; + $shipping_last_name = (string)$order_xml->Shipping->LastName; + + if (empty($shipping_first_name) || empty($shipping_last_name)) { + $shipping_first_name = (string)$order_xml->Shipping->Name; + $shipping_last_name = ''; + } + + $order = array( + 'invoice_prefix' => $this->config->get('config_invoice_prefix'), + 'store_id' => $this->config->get('config_store_id'), + 'store_name' => $this->config->get('config_name') . ' / Amazon US', + 'store_url' => $this->config->get('config_url'), + 'customer_id' => (int)$customer_id, + 'customer_group_id' => $this->config->get('openbay_amazonus_order_customer_group'), + 'firstname' => $shipping_first_name, + 'lastname' => $shipping_last_name, + 'email' => (string)$order_xml->Payment->Email, + 'telephone' => (string)$order_xml->Shipping->Phone, + 'shipping_firstname' => $shipping_first_name, + 'shipping_lastname' => $shipping_last_name, + 'shipping_company' => '', + 'shipping_address_1' => (string)$order_xml->Shipping->AddressLine1, + 'shipping_address_2' => $address_line_2, + 'shipping_city' => (string)$order_xml->Shipping->City, + 'shipping_postcode' => (string)$order_xml->Shipping->PostCode, + 'shipping_country' => $this->model_extension_openbay_amazonus_order->getCountryName((string)$order_xml->Shipping->CountryCode), + 'shipping_country_id' => $this->model_extension_openbay_amazonus_order->getCountryId((string)$order_xml->Shipping->CountryCode), + 'shipping_zone' => (string)$order_xml->Shipping->State, + 'shipping_zone_id' => $this->model_extension_openbay_amazonus_order->getZoneId((string)$order_xml->Shipping->State), + 'shipping_address_format' => '', + 'shipping_method' => (string)$order_xml->Shipping->Type, + 'shipping_code' => 'amazonus.' . (string)$order_xml->Shipping->Type, + 'payment_firstname' => $shipping_first_name, + 'payment_lastname' => $shipping_last_name, + 'payment_company' => '', + 'payment_address_1' => (string)$order_xml->Shipping->AddressLine1, + 'payment_address_2' => $address_line_2, + 'payment_city' => (string)$order_xml->Shipping->City, + 'payment_postcode' => (string)$order_xml->Shipping->PostCode, + 'payment_country' => $this->model_extension_openbay_amazonus_order->getCountryName((string)$order_xml->Shipping->CountryCode), + 'payment_country_id' => $this->model_extension_openbay_amazonus_order->getCountryId((string)$order_xml->Shipping->CountryCode), + 'payment_zone' => (string)$order_xml->Shipping->State, + 'payment_zone_id' => $this->model_extension_openbay_amazonus_order->getZoneId((string)$order_xml->Shipping->State), + 'payment_address_format' => '', + 'payment_method' => $this->language->get('text_paid_amazon'), + 'payment_code' => 'amazonus.amazonus', + 'payment_company_id' => 0, + 'payment_tax_id' => 0, + 'comment' => $order_comment, + 'total' => $total, + 'affiliate_id' => '0', + 'commission' => '0.00', + 'language_id' => (int)$this->config->get('config_language_id'), + 'currency_id' => $this->currency->getId($order_currency), + 'currency_code' => (string)$order_currency, + 'currency_value' => $this->currency->getValue($order_currency), + 'ip' => '', + 'forwarded_ip' => '', + 'user_agent' => 'OpenBay Pro for Amazon US', + 'accept_language' => '', + 'products' => $products, + 'vouchers' => array(), + 'marketing_id' => 0, + 'tracking' => 0, + 'totals' => array( + array( + 'code' => 'sub_total', + 'title' => $this->language->get('text_total_sub'), + 'value' => sprintf('%.4f', $products_total), + 'sort_order' => '1', + ), + array( + 'code' => 'shipping', + 'title' => $this->language->get('text_total_shipping'), + 'value' => sprintf('%.4f', $products_shipping), + 'sort_order' => '3', + ), + array( + 'code' => 'tax', + 'title' => $this->language->get('text_tax'), + 'value' => sprintf('%.4f', $products_tax), + 'sort_order' => '4', + ), + array( + 'code' => 'shipping_tax', + 'title' => $this->language->get('text_total_shipping_tax'), + 'value' => sprintf('%.4f', $products_shipping_tax), + 'sort_order' => '6', + ), + array( + 'code' => 'gift_wrap', + 'title' => $this->language->get('text_total_giftwrap'), + 'value' => sprintf('%.4f', $gift_wrap), + 'sort_order' => '2', + ), + array( + 'code' => 'gift_wrap_tax', + 'title' => $this->language->get('text_total_giftwrap_tax'), + 'value' => sprintf('%.4f', $gift_wrap_tax), + 'sort_order' => '5', + ), + array( + 'code' => 'total', + 'title' => $this->language->get('text_total'), + 'value' => sprintf('%.4f', $total), + 'sort_order' => '7', + ), + ), + ); + + $order_id = $this->model_checkout_order->addOrder($order); + + $this->model_extension_openbay_amazonus_order->updateOrderStatus($order_id, $order_status); + $this->model_extension_openbay_amazonus_order->addAmazonusOrder($order_id, $amazonus_order_id); + $this->model_extension_openbay_amazonus_order->addAmazonusOrderProducts($order_id, $product_mapping); + + foreach($products as $product) { + if($product['product_id'] != 0) { + $this->model_extension_openbay_amazonus_order->decreaseProductQuantity($product['product_id'], $product['quantity'], $product['var']); + } + } + + $logger->write('Order ' . $amazonus_order_id . ' was added to the database (ID: ' . $order_id . ')'); + $logger->write("Finished processing the order"); + + $this->model_extension_openbay_amazonus_order->acknowledgeOrder($order_id); + + //send an email to the administrator about the sale + if ($this->config->get('openbay_amazonus_notify_admin') == 1){ + $this->openbay->newOrderAdminNotify($order_id, $order_status); + } + + $this->event->trigger('model/checkout/order/addOrderHistory/after', array('model/checkout/order/addOrderHistory/after', array($order_id, $order_status))); + + $logger->write("Ok"); + $this->response->setOutput('Ok'); + } + + public function listing() { + if ($this->config->get('openbay_amazonus_status') != '1') { + return; + } + + $this->load->model('extension/openbay/amazonus_listing'); + $this->load->model('extension/openbay/amazonus_product'); + + $logger = new Log('amazonus_listing.log'); + $logger->write('amazonus/listing - started'); + + $incoming_token = isset($this->request->post['token']) ? $this->request->post['token'] : ''; + + if (!hash_equals($this->config->get('openbay_amazonus_token'), $incoming_token)) { + $logger->write('amazonus/listing - Incorrect token: ' . $incoming_token); + return; + } + + $decrypted = $this->openbay->decrypt($this->request->post['data'], $this->openbay->amazonus->getEncryptionKey(), $this->openbay->amazonus->getEncryptionIv(), false); + + if (!$decrypted) { + $logger->write('amazonus/order Failed to decrypt data'); + return; + } + + $data = json_decode($decrypted, 1); + + $logger->write("Received data: " . print_r($data, 1)); + + if ($data['status']) { + $logger->write("Updating " . $data['product_id'] . ' as successful'); + $this->model_extension_openbay_amazonus_listing->listingSuccessful($data['product_id']); + $this->model_extension_openbay_amazonus_product->linkProduct($data['sku'], $data['product_id']); + $logger->write("Updated successfully"); + } else { + $logger->write("Updating " . $data['product_id'] . ' as failed'); + $this->model_extension_openbay_amazonus_listing->listingFailed($data['product_id'], $data['messages']); + $logger->write("Updated successfully"); + } + } + + public function listingReport() { + if ($this->config->get('openbay_amazonus_status') != '1') { + return; + } + + $this->load->model('extension/openbay/amazonus_product'); + + $logger = new Log('amazonus.log'); + $logger->write('amazonus/listing_reports - started'); + + $incoming_token = isset($this->request->post['token']) ? $this->request->post['token'] : ''; + + if (!hash_equals($this->config->get('openbay_amazonus_token'), $incoming_token)) { + $logger->write('amazonus/listing_reports - Incorrect token: ' . $incoming_token); + return; + } + + $decrypted = $this->openbay->decrypt($this->request->post['data'], $this->openbay->amazonus->getEncryptionKey(), $this->openbay->amazonus->getEncryptionIv(), false); + + if (!$decrypted) { + $logger->write('amazonus/listing_reports - Failed to decrypt data'); + return; + } + + $logger->write('Received Listing Report: ' . $decrypted); + + $request = json_decode($decrypted, 1); + + $data = array(); + + foreach ($request['products'] as $product) { + $data[] = array( + 'sku' => $product['sku'], + 'quantity' => $product['quantity'], + 'asin' => $product['asin'], + 'price' => $product['price'], + ); + } + + if ($data) { + $this->model_extension_openbay_amazonus_product->addListingReport($data); + } + + $this->model_extension_openbay_amazonus_product->removeListingReportLock($request['marketplace']); + + $logger->write('amazonus/listing_reports - Finished'); + } + + public function product() { + if ($this->config->get('openbay_amazonus_status') != '1') { + $this->response->setOutput("disabled"); + return; + } + + ob_start(); + + $this->load->model('extension/openbay/amazonus_product'); + $logger = new Log('amazonus_product.log'); + + $logger->write("AmazonusProduct/inbound: incoming data"); + + $incoming_token = isset($this->request->post['token']) ? $this->request->post['token'] : ''; + + if($incoming_token != $this->config->get('openbay_amazonus_token')) { + $logger->write("Error - Incorrect token: " . $this->request->post['token']); + ob_get_clean(); + $this->response->setOutput("tokens did not match"); + return; + } + + $decrypted = $this->openbay->decrypt($this->request->post['data'], $this->openbay->amazonus->getEncryptionKey(), $this->openbay->amazonus->getEncryptionIv(), false); + + if(!$decrypted) { + $logger->write("Error - Failed to decrypt received data."); + ob_get_clean(); + $this->response->setOutput("failed to decrypt"); + return; + } + + $decoded_data = (array)json_decode($decrypted); + $logger->write("Received data: " . print_r($decoded_data, true)); + $status = $decoded_data['status']; + + if($status == "submit_error") { + $message = 'Product was not submited to amazonus properly. Please try again or contact OpenBay.'; + $this->model_extension_openbay_amazonus_product->setSubmitError($decoded_data['insertion_id'], $message); + } else { + $status = (array)$status; + if($status['successful'] == 1) { + $this->model_extension_openbay_amazonus_product->setStatus($decoded_data['insertion_id'], 'ok'); + $insertion_product = $this->model_extension_openbay_amazonus_product->getProduct($decoded_data['insertion_id']); + $this->model_extension_openbay_amazonus_product->linkProduct($insertion_product['sku'], $insertion_product['product_id'], $insertion_product['var']); + $this->model_extension_openbay_amazonus_product->deleteErrors($decoded_data['insertion_id']); + + $quantity_data = array( + $insertion_product['sku'] => $this->model_extension_openbay_amazonus_product->getProductQuantity($insertion_product['product_id'], $insertion_product['var']) + ); + $logger->write('Updating quantity with data: ' . print_r($quantity_data, true)); + $logger->write('Response: ' . print_r($this->openbay->amazonus->updateQuantities($quantity_data), true)); + } else { + $msg = 'Product was not accepted by amazonus. Please try again or contact OpenBay.'; + $this->model_extension_openbay_amazonus_product->setSubmitError($decoded_data['insertion_id'], $msg); + + if(isset($decoded_data['error_details'])) { + foreach($decoded_data['error_details'] as $error) { + $error = (array)$error; + $error_data = array( + 'sku' => $error['sku'], + 'error_code' => $error['error_code'], + 'message' => $error['message'], + 'insertion_id' => $decoded_data['insertion_id'] + ); + $this->model_extension_openbay_amazonus_product->insertError($error_data); + + } + } + } + } + + $logger->write("Data processed successfully."); + ob_get_clean(); + $this->response->setOutput("ok"); + } + + public function search() { + if ($this->config->get('openbay_amazonus_status') != '1') { + return; + } + + $this->load->model('extension/openbay/amazonus_product'); + + $logger = new Log('amazonus.log'); + $logger->write('amazonus/search - started'); + + $incoming_token = isset($this->request->post['token']) ? $this->request->post['token'] : ''; + + if (!hash_equals($this->config->get('openbay_amazonus_token'), $incoming_token)) { + $logger->write('amazonus/search - Incorrect token: ' . $incoming_token); + return; + } + + $decrypted = $this->openbay->decrypt($this->request->post['data'], $this->openbay->amazonus->getEncryptionKey(), $this->openbay->amazonus->getEncryptionIv(), false); + + if (!$decrypted) { + $logger->write('amazonus/search Failed to decrypt data'); + return; + } + + $logger->write($decrypted); + + $json = json_decode($decrypted, 1); + + $this->model_extension_openbay_amazonus_product->updateSearch($json); + } + + public function dev() { + if ($this->config->get('openbay_amazonus_status') != '1') { + $this->response->setOutput("error 001"); + return; + } + + $incoming_token = isset($this->request->post['token']) ? $this->request->post['token'] : ''; + + if ($incoming_token != $this->config->get('openbay_amazonus_token')) { + $this->response->setOutput("error 002"); + return; + } + + $decrypted = $this->openbay->decrypt($this->request->post['data'], $this->openbay->amazonus->getEncryptionKey(), $this->openbay->amazonus->getEncryptionIv(), false); + + if (!$decrypted) { + $this->response->setOutput("error 003"); + return; + } + + $data_xml = simplexml_load_string($decrypted); + + if(!isset($data_xml->action)) { + $this->response->setOutput("error 004"); + return; + } + + $action = trim((string)$data_xml->action); + + if ($action === "get_amazonus_product") { + if(!isset($data_xml->product_id)) { + $this->response->setOutput("error 005"); + return; + } + + $product_id = trim((string)$data_xml->product_id); + + if ($product_id === "all") { + $all_rows = $this->db->query("SELECT * FROM `" . DB_PREFIX . "amazonus_product`")->rows; + + $response = array(); + + foreach ($all_rows as $row) { + unset($row['data']); + $response[] = $row; + } + + $this->response->setOutput(print_r($response, true)); + + return; + } else { + $response = $this->db->query("SELECT * FROM `" . DB_PREFIX . "amazonus_product` WHERE `product_id` = '" . (int)$product_id . "'")->rows; + + $this->response->setOutput(print_r($response, true)); + return; + } + } else { + $this->response->setOutput("error 999"); + return; + } + } + + public function eventAddOrderHistory($route, $data) { + $logger = new \Log('amazonus.log'); + $logger->write('eventAddOrderHistory Event fired: ' . $route); + + if (isset($data[0]) && !empty($data[0])) { + $this->load->model('extension/openbay/amazonus_order'); + + $logger->write('Order ID: ' . (int)$data[0]); + + $this->model_extension_openbay_amazonus_order->addOrderHistory((int)$data[0]); + } + } +} diff --git a/public/catalog/controller/extension/openbay/ebay.php b/public/catalog/controller/extension/openbay/ebay.php new file mode 100644 index 0000000..1c4fecc --- /dev/null +++ b/public/catalog/controller/extension/openbay/ebay.php @@ -0,0 +1,201 @@ +<?php +class ControllerExtensionOpenbayEbay extends Controller { + public function inbound() { + $post_data = $this->request->post; + $secret = $this->config->get('ebay_secret'); + $active = $this->config->get('ebay_status'); + + $this->load->model('extension/openbay/ebay_product'); + $this->load->model('extension/openbay/ebay_order'); + + if(empty($post_data)) { + http_response_code(400); + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode(array('error' => 'Bad request'))); + $this->response->output(); + exit(); + } else { + $data = $this->openbay->decrypt($post_data['data'], $this->openbay->ebay->getEncryptionKey(), $this->openbay->ebay->getEncryptionIv()); + + if(isset($data['secret']) && $secret == $data['secret'] && $active == 1) { + if($data['action'] == 'ItemUnsold') { + $this->openbay->ebay->log('Action: Unsold Item'); + $product_id = $this->openbay->ebay->getProductId($data['itemId']); + + if($product_id != false) { + $this->openbay->ebay->log('eBay item link found with internal product'); + $rules = $this->model_extension_openbay_ebay_product->getRelistRule($data['itemId']); + + if(!empty($rules)) { + $this->openbay->ebay->log('Item is due to be automatically relisted'); + $this->db->query("INSERT INTO `" . DB_PREFIX . "ebay_listing_pending` SET `ebay_item_id` = '" . $this->db->escape($data['itemId']) . "', `product_id` = '" . (int)$product_id . "', `key` = '" . $this->db->escape($data['key']) . "'"); + $this->openbay->ebay->removeItemByItemId($data['itemId']); + } else { + $this->openbay->ebay->log('No automation rule set'); + $this->openbay->ebay->removeItemByItemId($data['itemId']); + } + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode(array('msg' => 'ok'))); + } + + if($data['action'] == 'ItemListed') { + $this->openbay->ebay->log('Action: Listed Item'); + + $product_id = $this->openbay->ebay->getProductIdFromKey($data['key']); + + if($product_id != false) { + $this->openbay->ebay->createLink($product_id, $data['itemId'], ''); + $this->db->query("DELETE FROM `" . DB_PREFIX . "ebay_listing_pending` WHERE `key` = '" . $this->db->escape($data['key']) . "' LIMIT 1"); + $this->openbay->ebay->log('A link was found with product id: ' . $product_id . ', item id: ' . $data['itemId'] . ' and key: ' . $data['key']); + } else { + $this->openbay->ebay->log('No link found to previous item'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode(array('msg' => 'ok'))); + } + + if($data['action'] == 'newOrder') { + $this->openbay->ebay->log('Action: newOrder / Order data from polling'); + $this->model_extension_openbay_ebay_order->importOrders($data['data2']); + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode(array('msg' => 'ok'))); + } + + if($data['action'] == 'notificationOrder') { + $this->openbay->ebay->log('Action: notificationOrder / Order data from notification'); + $this->model_extension_openbay_ebay_order->importOrders($data['data']); + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode(array('msg' => 'ok'))); + } + + if($data['action'] == 'outputLog') { + if (file_exists(DIR_LOGS . "ebaylog.log")) { + header('Pragma: public'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Cache-Control: private', false); + header('Content-Type: application/force-download'); + header('Content-Length: ' . filesize(DIR_LOGS . "ebaylog.log")); + header('Content-Disposition: attachment; filename="ebaylog.log"'); + header('Content-Transfer-Encoding: binary'); + header('Connection: close'); + readfile(DIR_LOGS . "ebaylog.log"); + exit(); + } else { + $this->openbay->ebay->log('Action: outputLog / No log file found'); + + http_response_code(404); + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode(array('error' => 'Log file not found'))); + } + } + + if($data['action'] == 'config') { + $this->openbay->ebay->log('Action: config / Check store php limits for import options'); + + $post_size = ini_get('post_max_size'); + $post_size = (int)str_replace(array('M','m','Mb','MB'), '', $post_size); + $version = (int)$this->config->get('feed_openbaypro_version'); + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode(array('msg' => 'ok', 'max_post' => $post_size, 'version' => $version))); + } + } else { + $this->openbay->ebay->log('Secret incorrect or module not active.'); + + http_response_code(401); + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode(array('error' => 'Authorisation failed or module inactive'))); + $this->response->output(); + exit(); + } + } + } + + public function importItems() { + set_time_limit(0); + + $data = $this->request->post; + $secret = $this->config->get('ebay_secret'); + $active = $this->config->get('ebay_status'); + + $this->response->addHeader('Content-Type: application/json'); + + if(isset($data['secret']) && $secret == $data['secret'] && $active == 1 && isset($data['data'])) { + $this->load->model('extension/openbay/ebay_order'); + $this->load->model('extension/openbay/ebay_product'); + $this->model_extension_openbay_ebay_product->importItems($data); + $this->response->setOutput(json_encode(array('msg' => 'ok', 'error' => false))); + } else { + $this->response->setOutput(json_encode(array('msg' => 'Auth failed', 'error' => true))); + } + } + + public function setup() { + @set_time_limit(0); + + $this->load->model('setting/setting'); + $settings = $this->model_setting_setting->getSetting('ebay'); + + $this->response->addHeader('Cache-Control: no-cache, must-revalidate'); + $this->response->addHeader('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); + $this->response->addHeader('Content-type: application/json; charset=utf-8'); + + if( + (isset($settings['ebay_token']) && !empty($settings['ebay_token'])) || + (isset($settings['ebay_secret']) && !empty($settings['ebay_secret'])) || + (isset($settings['ebay_encryption_key']) && !empty($settings['ebay_encryption_key'])) || + (isset($settings['ebay_encryption_iv']) && !empty($settings['ebay_encryption_iv'])) || + !isset($this->request->post['token']) || + !isset($this->request->post['secret']) || + !isset($this->request->post['encryption_key']) || + !isset($this->request->post['encryption_iv']) + ) { + $this->response->setOutput(json_encode(array('msg' => 'fail', 'reason' => 'Tokens are already setup or data missing'))); + } else { + $settings['ebay_token'] = $this->request->post['token']; + $settings['ebay_secret'] = $this->request->post['secret']; + $settings['ebay_encryption_key'] = $this->request->post['encryption_key']; + $settings['ebay_encryption_iv'] = $this->request->post['encryption_iv']; + + $this->openbay->ebay->editSetting('ebay', $settings); + + $this->response->setOutput(json_encode(array('msg' => 'ok', 'reason' => 'Auto setup has completed','version' => (int)$this->config->get('feed_openbaypro_version')))); + } + } + + public function sync() { + @set_time_limit(0); + + $this->response->addHeader('Content-Type: application/json'); + + if($this->request->post['process'] == 'categories') { + $this->response->setOutput(json_encode($this->openbay->ebay->updateCategories())); + }elseif($this->request->post['process'] == 'settings') { + $this->response->setOutput(json_encode($this->openbay->ebay->updateSettings())); + }elseif($this->request->post['process'] == 'store') { + $this->response->setOutput(json_encode($this->openbay->ebay->updateStore())); + } + } + + public function eventAddOrder($route, $data) { + + } + + public function eventAddOrderHistory($route, $data) { + $this->openbay->ebay->log('eventAddOrderHistory Event fired: ' . $route); + + if (isset($data[0]) && !empty($data[0])) { + $this->load->model('extension/openbay/ebay_order'); + + $this->openbay->ebay->log('Order ID: ' . (int)$data[0]); + + $this->model_extension_openbay_ebay_order->addOrderHistory((int)$data[0]); + } + } +} diff --git a/public/catalog/controller/extension/openbay/etsy.php b/public/catalog/controller/extension/openbay/etsy.php new file mode 100644 index 0000000..9ced310 --- /dev/null +++ b/public/catalog/controller/extension/openbay/etsy.php @@ -0,0 +1,69 @@ +<?php +class ControllerExtensionOpenbayEtsy extends Controller { + public function inbound() { + if ($this->config->get('etsy_status') != '1') { + $this->openbay->etsy->log('etsy/inbound - module inactive (503)'); + http_response_code(503); + exit(); + } + + $body = $this->request->post; + + if (!isset($body['action']) || !isset($body['auth'])) { + $this->openbay->etsy->log('etsy/inbound - action or auth data not set (401)'); + http_response_code(401); + exit(); + } + + $incoming_token = isset($body['auth']['token']) ? $body['auth']['token'] : ''; + + if (!hash_equals($this->config->get('etsy_token'), $incoming_token)) { + $this->openbay->etsy->log('etsy/inbound - Auth failed (401): ' . $incoming_token); + http_response_code(401); + exit(); + } + + $data = array(); + + if (isset($body['data']) && !empty($body['data'])) { + $decrypted = $this->openbay->decrypt($body['data'], $this->openbay->etsy->getEncryptionKey(), $this->openbay->etsy->getEncryptionIv()); + + if (!$decrypted) { + $this->openbay->etsy->log('etsy/inbound Failed to decrypt data'); + http_response_code(400); + exit(); + } + + $data = json_decode($decrypted); + } + + switch ($body['action']) { + case 'orders': + $this->load->model('extension/openbay/etsy_order'); + + $this->openbay->etsy->log('Orders action found'); + + $this->model_extension_openbay_etsy_order->inbound($data); + + break; + case 'products'; + $this->load->model('extension/openbay/etsy_product'); + + $this->model_extension_openbay_etsy_product->inbound($data); + + break; + } + } + + public function eventAddOrderHistory($route, $data) { + $this->openbay->etsy->log('eventAddOrderHistory Event fired: ' . $route); + + if (isset($data[0]) && !empty($data[0])) { + $this->load->model('extension/openbay/etsy_order'); + + $this->openbay->etsy->log('Order ID: ' . (int)$data[0]); + + $this->model_extension_openbay_etsy_order->addOrderHistory((int)$data[0]); + } + } +} diff --git a/public/catalog/controller/extension/openbay/fba.php b/public/catalog/controller/extension/openbay/fba.php new file mode 100644 index 0000000..76b5cd2 --- /dev/null +++ b/public/catalog/controller/extension/openbay/fba.php @@ -0,0 +1,119 @@ +<?php +class ControllerExtensionOpenbayFba extends Controller { + public function eventAddOrderHistory($route, $data) { + $this->openbay->fba->log('eventAddOrderHistory Event fired: ' . $route); + + if (isset($data[0]) && !empty($data[0])) { + $this->load->model('checkout/order'); + $this->load->model('account/order'); + $this->load->model('catalog/product'); + + $this->openbay->fba->log('eventAddOrderHistory Event fired for order ID: ' . $data[0]); + + $order = $this->model_checkout_order->getOrder($data[0]); + + if ($order['shipping_method']) { + if ($this->config->get('openbay_fba_order_trigger_status') == $order['order_status_id']) { + $fba_fulfillment_id = $this->openbay->fba->createFBAFulfillmentID($data[0], 0); + + $order_products = $this->model_account_order->getOrderProducts($data[0]); + + $total_order_products = count($order_products); + + $fulfillment_items = array(); + + foreach ($order_products as $order_product) { + $product = $this->model_catalog_product->getProduct($order_product['product_id']); + + if ($product['location'] == 'FBA') { + $fulfillment_items[] = array( + 'seller_sku' => $product['sku'], + 'quantity' => $order_product['quantity'], + 'seller_fulfillment_order_item_id' => $this->config->get('openbay_fba_order_prefix') . $fba_fulfillment_id . '-' . $order_product['order_product_id'], + 'per_unit_declared_value' => array( + 'currency_code' => $order['currency_code'], + 'value' => number_format($order_product['price'], 2) + ), + ); + } + } + + $total_fulfillment_items = count($fulfillment_items); + + if (($total_order_products == $total_fulfillment_items) || ($this->config->get('openbay_fba_only_fill_complete') != 1)) { + if (!empty($fulfillment_items)) { + $request = array(); + + $datetime = new DateTime($order['date_added']); + $request['displayable_order_datetime'] = $datetime->format(DateTime::ISO8601); + + $request['seller_fulfillment_order_id'] = $this->config->get('openbay_fba_order_prefix') . $data[0] . '-' . $fba_fulfillment_id; + $request['displayable_order_id'] = $data[0]; + $request['displayable_order_comment'] = 'none'; + $request['shipping_speed_category'] = $this->config->get('openbay_fba_shipping_speed'); + $request['fulfillment_action'] = ($this->config->get('openbay_fba_send_orders') == 1 ? 'Ship' : 'Hold'); + $request['fulfillment_policy'] = $this->config->get('openbay_fba_fulfill_policy'); + + $request['destination_address'] = array( + 'name' => $order['shipping_firstname'] . ' ' . $order['shipping_lastname'], + 'line_1' => (!empty($order['shipping_company']) ? $order['shipping_company'] : $order['shipping_address_1']), + 'line_2' => (!empty($order['shipping_company']) ? $order['shipping_address_1'] : $order['shipping_address_2']), + 'line_3' => (!empty($order['shipping_company']) ? $order['shipping_address_2'] : ''), + 'state_or_province_code' => $order['shipping_zone'], + 'city' => $order['shipping_city'], + 'country_code' => $order['shipping_iso_code_2'], + 'postal_code' => $order['shipping_postcode'], + ); + + $request['items'] = $fulfillment_items; + + $response = $this->openbay->fba->call("v1/fba/fulfillments/", $request, 'POST'); + + if ($response['response_http'] != 201) { + /** + * @todo notify the admin about any errors + */ + $this->openbay->fba->updateFBAOrderStatus($data[0], 1); + } else { + if ($this->config->get('openbay_fba_send_orders') == 1) { + $this->openbay->fba->updateFBAOrderStatus($data[0], 3); + } else { + $this->openbay->fba->updateFBAOrderStatus($data[0], 2); + } + + $this->openbay->fba->updateFBAOrderRef($data[0], $this->config->get('openbay_fba_order_prefix') . $data[0] . '-' . $fba_fulfillment_id); + } + + $this->openbay->fba->populateFBAFulfillment(json_encode($request), json_encode($response), $response['response_http'], $fba_fulfillment_id); + $this->openbay->fba->updateFBAOrderFulfillmentID($data[0], $fba_fulfillment_id); + } else { + $this->openbay->fba->log('No FBA items found for this order'); + } + } else { + $this->openbay->fba->log('Products:' . $total_order_products . ', Fulfillment products: ' . $total_fulfillment_items . ' - settings do not allow incomplete order fulfillment.'); + } + } + } + + // how about notifications? does the merchant want a notification that here is a new fulfillment ready to be checked over? + // alert of any missing products that were not in FBA? + // any errors returned by FBA? + } + } + + public function eventAddOrder($route, $data) { + $this->openbay->fba->log('eventAddOrder Event fired: ' . $route); + + if (isset($data[0]) && !empty($data[0])) { + $this->load->model('checkout/order'); + + $this->openbay->fba->log('Order ID: ' . (int)$data[0]); + + $order = $this->model_checkout_order->getOrder((int)$data[0]); + + if ($order['shipping_method']) { + $this->openbay->fba->createFBAOrderID((int)$data[0]); + } + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/openbay/openbay.php b/public/catalog/controller/extension/openbay/openbay.php new file mode 100644 index 0000000..3a5f335 --- /dev/null +++ b/public/catalog/controller/extension/openbay/openbay.php @@ -0,0 +1,12 @@ +<?php +class ControllerExtensionOpenbayOpenbay extends Controller { + public function index() { + $this->response->addHeader('Cache-Control: no-cache, must-revalidate'); + $this->response->addHeader('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); + $this->response->addHeader('Content-type: application/json; charset=utf-8'); + $this->response->addHeader('X-Openbay-Header: hello'); + + http_response_code(200); + $this->response->setOutput(json_encode(array('reply' => 'hello'))); + } +} diff --git a/public/catalog/controller/extension/payment/alipay.php b/public/catalog/controller/extension/payment/alipay.php new file mode 100644 index 0000000..51bd26c --- /dev/null +++ b/public/catalog/controller/extension/payment/alipay.php @@ -0,0 +1,76 @@ +<?php +class ControllerExtensionPaymentAlipay extends Controller { + public function index() { + $data['button_confirm'] = $this->language->get('button_confirm'); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $config = array ( + 'app_id' => $this->config->get('payment_alipay_app_id'), + 'merchant_private_key' => $this->config->get('payment_alipay_merchant_private_key'), + 'notify_url' => HTTPS_SERVER . "payment_callback/alipay", + 'return_url' => $this->url->link('checkout/success'), + 'charset' => "UTF-8", + 'sign_type' => "RSA2", + 'gateway_url' => $this->config->get('payment_alipay_test') == "sandbox" ? "https://openapi.alipaydev.com/gateway.do" : "https://openapi.alipay.com/gateway.do", + 'alipay_public_key' => $this->config->get('payment_alipay_alipay_public_key'), + ); + $out_trade_no = trim($order_info['order_id']); + $subject = trim($this->config->get('config_name')); + $total_amount = trim($this->currency->format($order_info['total'], 'CNY', '', false)); + $body = '';//trim($_POST['WIDbody']); + + $payRequestBuilder = array( + 'body' => $body, + 'subject' => $subject, + 'total_amount' => $total_amount, + 'out_trade_no' => $out_trade_no, + 'product_code' => 'FAST_INSTANT_TRADE_PAY' + ); + + $this->load->model('extension/payment/alipay'); + + $response = $this->model_extension_payment_alipay->pagePay($payRequestBuilder,$config); + $data['action'] = $config['gateway_url'] . "?charset=" . $this->model_extension_payment_alipay->getPostCharset(); + $data['form_params'] = $response; + + return $this->load->view('extension/payment/alipay', $data); + } + + public function callback() { + $this->log->write('alipay pay notify:'); + $arr = $_POST; + $config = array ( + 'app_id' => $this->config->get('payment_alipay_app_id'), + 'merchant_private_key' => $this->config->get('payment_alipay_merchant_private_key'), + 'notify_url' => HTTPS_SERVER . "payment_callback/alipay", + 'return_url' => $this->url->link('checkout/success'), + 'charset' => "UTF-8", + 'sign_type' => "RSA2", + 'gateway_url' => $this->config->get('payment_alipay_test') == "sandbox" ? "https://openapi.alipaydev.com/gateway.do" : "https://openapi.alipay.com/gateway.do", + 'alipay_public_key' => $this->config->get('payment_alipay_alipay_public_key'), + ); + $this->load->model('extension/payment/alipay'); + $this->log->write('POST' . var_export($_POST,true)); + $result = $this->model_extension_payment_alipay->check($arr, $config); + + if($result) {//check successed + $this->log->write('Alipay check successed'); + $order_id = $_POST['out_trade_no']; + if($_POST['trade_status'] == 'TRADE_FINISHED') { + } + else if ($_POST['trade_status'] == 'TRADE_SUCCESS') { + $this->load->model('checkout/order'); + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_alipay_order_status_id')); + } + echo "success"; //Do not modified or deleted + }else { + $this->log->write('Alipay check failed'); + //chedk failed + echo "fail"; + + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/alipay_cross.php b/public/catalog/controller/extension/payment/alipay_cross.php new file mode 100644 index 0000000..2acce97 --- /dev/null +++ b/public/catalog/controller/extension/payment/alipay_cross.php @@ -0,0 +1,87 @@ +<?php +class ControllerExtensionPaymentAlipayCross extends Controller { + var $alipay_gateway = 'https://mapi.alipay.com/gateway.do?'; + var $alipay_gateway_test = 'https://openapi.alipaydev.com/gateway.do?'; + + public function index() { + $data['button_confirm'] = $this->language->get('button_confirm'); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $out_trade_no = str_pad($order_info['order_id'], 7, "0",STR_PAD_LEFT); // Length must be greater than 7 + $subject = trim($this->config->get('config_name')); + $currency = $this->config->get('payment_alipay_cross_currency'); + $total_fee = trim($this->currency->format($order_info['total'], $currency, '', false)); + $total_fee_cny = trim($this->currency->format($order_info['total'], 'CNY', '', false)); + $body = trim($this->config->get('config_name')); + + $alipay_config = array ( + 'partner' => $this->config->get('payment_alipay_cross_app_id'), + 'key' => $this->config->get('payment_alipay_cross_merchant_private_key'), + 'notify_url' => HTTPS_SERVER . "payment_callback/alipay_cross", + 'return_url' => $this->url->link('checkout/success'), + 'sign_type' => strtoupper('MD5'), + 'input_charset' => strtolower('utf-8'), + 'cacert' => getcwd().'/cacert.pem', + 'transport' => 'https', + 'service' => 'create_forex_trade' + ); + + $parameter = array( + "service" => $alipay_config['service'], + "partner" => $alipay_config['partner'], + "notify_url" => $alipay_config['notify_url'], + "return_url" => $alipay_config['return_url'], + + "out_trade_no" => $out_trade_no, + "subject" => $subject, + "body" => $body, + "currency" => $currency, + "_input_charset" => trim(strtolower($alipay_config['input_charset'])) + ); + if ($this->session->data['currency'] == 'CNY') { + $parameter['rmb_fee'] = $total_fee_cny; + } else { + $parameter['total_fee'] = $total_fee; + } + + $this->load->model('extension/payment/alipay_cross'); + $data['params'] = $this->model_extension_payment_alipay_cross->buildRequestPara($alipay_config, $parameter); + $gateway = $this->config->get('payment_alipay_cross_test') == "sandbox" ? $this->alipay_gateway_test : $this->alipay_gateway; + $data['action'] = $gateway . "_input_charset=".trim($alipay_config['input_charset']); + + return $this->load->view('extension/payment/alipay_cross', $data); + } + + public function callback() { + $this->log->write('alipay cross payment notify:'); + $alipay_config = array ( + 'partner' => $this->config->get('payment_alipay_cross_app_id'), + 'key' => $this->config->get('payment_alipay_cross_merchant_private_key'), + 'sign_type' => strtoupper('MD5'), + 'input_charset' => strtolower('utf-8'), + 'cacert' => getcwd().'/cacert.pem' + ); + $this->load->model('extension/payment/alipay_cross'); + $this->log->write('config: ' . var_export($alipay_config,true)); + $verify_result = $this->model_extension_payment_alipay_cross->verifyNotify($alipay_config); + + if($verify_result) {//check successed + $this->log->write('Alipay cross check successed'); + $order_id = $_POST['out_trade_no']; + if($_POST['trade_status'] == 'TRADE_FINISHED') { + $this->load->model('checkout/order'); + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_alipay_cross_order_status_id')); + } else if ($_POST['trade_status'] == 'TRADE_SUCCESS') { + } + echo "success"; //Do not modified or deleted + } else { + $this->log->write('Alipay cross check failed'); + //chedk failed + echo "fail"; + + } + } +} diff --git a/public/catalog/controller/extension/payment/amazon_login_pay.php b/public/catalog/controller/extension/payment/amazon_login_pay.php new file mode 100644 index 0000000..c76844d --- /dev/null +++ b/public/catalog/controller/extension/payment/amazon_login_pay.php @@ -0,0 +1,690 @@ +<?php + +class ControllerExtensionPaymentAmazonLoginPay extends Controller { + public function session_expired() { + $this->load->language('extension/payment/amazon_login_pay'); + + $this->load->model('extension/payment/amazon_login_pay'); + + $this->model_extension_payment_amazon_login_pay->cartRedirect($this->language->get('error_session_expired')); + } + + public function address() { + $this->load->language('extension/payment/amazon_login_pay'); + + $this->load->model('extension/payment/amazon_login_pay'); + + $this->document->setTitle($this->language->get('heading_address')); + + // Verify cart + $this->model_extension_payment_amazon_login_pay->verifyCart(); + + // Verify login + $this->model_extension_payment_amazon_login_pay->verifyLogin(); + + // Verify cart total + //$this->model_extension_payment_amazon_login_pay->verifyTotal(); + + // Cancel an existing order reference + unset($this->session->data['order_id']); + + if (!empty($this->session->data['apalwa']['pay']['order_reference_id']) && !$this->model_extension_payment_amazon_login_pay->isOrderInState($this->session->data['apalwa']['pay']['order_reference_id'], array('Canceled', 'Closed', 'Draft'))) { + $this->model_extension_payment_amazon_login_pay->cancelOrder($this->session->data['apalwa']['pay']['order_reference_id'], "Shipment widget has been requested, cancelling this order reference."); + + unset($this->session->data['apalwa']['pay']['order_reference_id']); + } + + $data['text_cart'] = $this->language->get('text_cart'); + + $data['shipping_methods'] = html_entity_decode($this->url->link('extension/payment/amazon_login_pay/shipping_methods', '', true), ENT_COMPAT, "UTF-8"); + $data['shipping'] = html_entity_decode($this->url->link('extension/payment/amazon_login_pay/shipping', '', true), ENT_COMPAT, "UTF-8"); + $data['cart'] = html_entity_decode($this->url->link('checkout/cart'), ENT_COMPAT, "UTF-8"); + $data['session_expired'] = html_entity_decode($this->url->link('extension/payment/amazon_login_pay/session_expired'), ENT_COMPAT, "UTF-8"); + + $data['client_id'] = $this->config->get('payment_amazon_login_pay_client_id'); + $data['merchant_id'] = $this->config->get('payment_amazon_login_pay_merchant_id'); + + if ($this->config->get('payment_amazon_login_pay_test') == 'sandbox') { + $data['sandbox'] = isset($this->session->data['user_id']); // Require an active admin panel session to show debug messages + } + + $amazon_payment_js = $this->model_extension_payment_amazon_login_pay->getWidgetJs(); + $this->document->addScript($amazon_payment_js); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('common/home', '', true), + 'text' => $this->language->get('text_home') + ); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('checkout/cart'), + 'text' => $this->language->get('breadcrumb_cart') + ); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('extension/payment/amazon_login_pay/address'), + 'current' => true, + 'text' => $this->language->get('breadcrumb_shipping') + ); + + $data['breadcrumbs'][] = array( + 'href' => null, + 'text' => $this->language->get('breadcrumb_payment') + ); + + $data['breadcrumbs'][] = array( + 'href' => null, + 'text' => $this->language->get('breadcrumb_summary') + ); + + $data['content_main'] = $this->load->view('extension/payment/amazon_login_pay_address', $data); + $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/amazon_login_pay_generic', $data)); + } + + public function shipping_methods() { + $this->load->language('extension/payment/amazon_login_pay'); + + $json = array(); + + try { + $this->load->model('extension/payment/amazon_login_pay'); + $this->load->model('setting/extension'); + + if (!isset($this->request->get['AmazonOrderReferenceId'])) { + throw $this->model_extension_payment_amazon_login_pay->loggedException($this->language->get('error_shipping_methods'), $this->language->get('error_shipping_methods')); + } + + $order_reference_id = $this->request->get['AmazonOrderReferenceId']; + + $this->session->data['apalwa']['pay']['order_reference_id'] = $order_reference_id; + + $address = $this->model_extension_payment_amazon_login_pay->getAddress($order_reference_id); + + $quotes = array(); + + $results = $this->model_setting_extension->getExtensions('shipping'); + + foreach ($results as $result) { + if (isset($result['code'])) { + $code = $result['code']; + } else { + $code = $result['key']; + } + + if ($this->config->get('shipping_' . $code . '_status')) { + $this->load->model('extension/shipping/' . $code); + + $quote = $this->{'model_extension_shipping_' . $code}->getQuote($address); + + if ($quote && empty($quote['error'])) { + $quotes[$code] = array( + 'title' => $quote['title'], + 'quote' => $quote['quote'], + 'sort_order' => $quote['sort_order'], + 'error' => $quote['error'] + ); + } + } + } + + if (empty($quotes)) { + throw new \RuntimeException($this->language->get('error_no_shipping_methods')); + } + + $sort_order = array(); + + foreach ($quotes as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $quotes); + + $this->session->data['apalwa']['pay']['shipping_methods'] = $quotes; + $this->session->data['apalwa']['pay']['address'] = $address; + + $json['quotes'] = $quotes; + + if (!empty($this->session->data['apalwa']['pay']['shipping_method']['code'])) { + $json['selected'] = $this->session->data['apalwa']['pay']['shipping_method']['code']; + } else { + $json['selected'] = ''; + } + } catch (\RuntimeException $e) { + $json['error'] = $e->getMessage(); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function shipping() { + $this->load->language('extension/payment/amazon_login_pay'); + + $this->load->model('extension/payment/amazon_login_pay'); + $this->load->model('extension/module/amazon_login'); + + $json = array( + 'redirect' => null, + 'error' => null + ); + + try { + if (!isset($this->request->post['shipping_method'])) { + throw $this->model_extension_payment_amazon_login_pay->loggedException("No shipping method provided.", $this->language->get('error_process_order')); + } + + $shipping_method = explode('.', $this->request->post['shipping_method']); + + if (!isset($shipping_method[0]) || !isset($shipping_method[1]) || !isset($this->session->data['apalwa']['pay']['shipping_methods'][$shipping_method[0]]['quote'][$shipping_method[1]])) { + + throw $this->model_extension_payment_amazon_login_pay->loggedException("Used shipping method is not allowed.", $this->language->get('error_process_order')); + } + + $this->session->data['apalwa']['pay']['shipping_method'] = $this->session->data['apalwa']['pay']['shipping_methods'][$shipping_method[0]]['quote'][$shipping_method[1]]; + $this->session->data['shipping_method'] = $this->session->data['apalwa']['pay']['shipping_method']; + $this->session->data['payment_address'] = $this->session->data['apalwa']['pay']['address']; + $this->session->data['shipping_address'] = $this->session->data['apalwa']['pay']['address']; + $this->session->data['shipping_country_id'] = $this->session->data['apalwa']['pay']['address']['country_id']; + $this->session->data['shipping_zone_id'] = $this->session->data['apalwa']['pay']['address']['zone_id']; + + $this->model_extension_module_amazon_login->persistAddress($this->session->data['apalwa']['pay']['address']); + + $json['redirect'] = $this->url->link('extension/payment/amazon_login_pay/payment', '', true); + } catch (\RuntimeException $e) { + $json['error'] = $e->getMessage(); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function payment() { + $this->load->language('extension/payment/amazon_login_pay'); + + $this->load->model('extension/payment/amazon_login_pay'); + + $this->document->setTitle($this->language->get('heading_payment')); + + // Verify cart + $this->model_extension_payment_amazon_login_pay->verifyCart(); + + // Verify login + $this->model_extension_payment_amazon_login_pay->verifyLogin(); + + // Verify cart total + //$this->model_extension_payment_amazon_login_pay->verifyTotal(); + + $data['confirm'] = html_entity_decode($this->url->link('extension/payment/amazon_login_pay/confirm', '', true), ENT_COMPAT, "UTF-8"); + $data['back'] = html_entity_decode($this->url->link('extension/payment/amazon_login_pay/address', '', true), ENT_COMPAT, "UTF-8"); + $data['session_expired'] = html_entity_decode($this->url->link('extension/payment/amazon_login_pay/session_expired'), ENT_COMPAT, "UTF-8"); + + $data['merchant_id'] = $this->config->get('payment_amazon_login_pay_merchant_id'); + $data['client_id'] = $this->config->get('payment_amazon_login_pay_client_id'); + + $data['order_reference_id'] = !empty($this->session->data['apalwa']['pay']['order_reference_id']) ? $this->session->data['apalwa']['pay']['order_reference_id'] : null; + + if ($this->config->get('payment_amazon_login_pay_test') == 'sandbox') { + $data['sandbox'] = isset($this->session->data['user_id']); // Require an active admin panel session to show debug messages + } + + $data['error'] = ''; + if (isset($this->session->data['apalwa']['error'])) { + $data['error'] = $this->session->data['apalwa']['error']; + unset($this->session->data['apalwa']['error']); + } + + $amazon_payment_js = $this->model_extension_payment_amazon_login_pay->getWidgetJs(); + $this->document->addScript($amazon_payment_js); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('common/home', '', true), + 'text' => $this->language->get('text_home') + ); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('checkout/cart'), + 'text' => $this->language->get('breadcrumb_cart') + ); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('extension/payment/amazon_login_pay/address'), + 'text' => $this->language->get('breadcrumb_shipping') + ); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('extension/payment/amazon_login_pay/payment'), + 'current' => true, + 'text' => $this->language->get('breadcrumb_payment') + ); + + $data['breadcrumbs'][] = array( + 'href' => null, + 'text' => $this->language->get('breadcrumb_summary') + ); + + $data['content_main'] = $this->load->view('extension/payment/amazon_login_pay_payment', $data); + $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/amazon_login_pay_generic', $data)); + } + + public function persist_comment() { + if (isset($this->request->post['comment'])) { + $this->session->data['comment'] = strip_tags($this->request->post['comment']); + + $this->session->data['apalwa']['pay']['order']['comment'] = $this->session->data['comment']; + } + } + + public function coupon_discard() { + $this->load->model('extension/payment/amazon_login_pay'); + + // Verify reference + $this->model_extension_payment_amazon_login_pay->verifyReference(); + + if ($this->model_extension_payment_amazon_login_pay->isOrderInState($this->session->data['apalwa']['pay']['order_reference_id'], array('Draft'))) { + unset($this->session->data['coupon']); + } + + $this->response->redirect($this->url->link('extension/payment/amazon_login_pay/confirm', '', true)); + } + + public function standard_checkout() { + $this->load->language('extension/payment/amazon_login_pay'); + + $this->load->model('extension/payment/amazon_login_pay'); + + // Verify cart + $this->model_extension_payment_amazon_login_pay->verifyCart(); + + // Verify login + $this->model_extension_payment_amazon_login_pay->verifyLogin(); + + // Cancel an existing order reference + if (!empty($this->session->data['apalwa']['pay']['order_reference_id']) && $this->model_extension_payment_amazon_login_pay->isOrderInState($this->session->data['apalwa']['pay']['order_reference_id'], array('Open'))) { + $this->model_extension_payment_amazon_login_pay->cancelOrder($this->session->data['apalwa']['pay']['order_reference_id'], "Shipment widget has been requested, cancelling this order reference."); + } + + // Unset all payment data + unset($this->session->data['apalwa']['pay']); + unset($this->session->data['order_id']); + + // Redirect to the cart + $this->response->redirect($this->url->link('checkout/cart', '', true)); + } + + public function confirm() { + $this->load->language('extension/payment/amazon_login_pay'); + $this->load->language('checkout/checkout'); + + $this->load->model('extension/payment/amazon_login_pay'); + + $this->document->setTitle($this->language->get('heading_confirm')); + + // Verify cart + $this->model_extension_payment_amazon_login_pay->verifyCart(); + + // Verify login + $this->model_extension_payment_amazon_login_pay->verifyLogin(); + + // Verify cart total + // Not needed, as we will display an error message later on... + + // Verify reference + $this->model_extension_payment_amazon_login_pay->verifyReference(); + + // Verify shipping + $this->model_extension_payment_amazon_login_pay->verifyShipping(); + + $data['merchant_id'] = $this->config->get('payment_amazon_login_pay_merchant_id'); + $data['client_id'] = $this->config->get('payment_amazon_login_pay_client_id'); + + if ($this->config->get('payment_amazon_login_pay_test') == 'sandbox') { + $data['sandbox'] = isset($this->session->data['user_id']); // Require an active admin panel session to show debug messages + } + + $amazon_payment_js = $this->model_extension_payment_amazon_login_pay->getWidgetJs(); + $this->document->addScript($amazon_payment_js); + + try { + $order = $this->model_extension_payment_amazon_login_pay->makeOrder(); + + $this->session->data['apalwa']['pay']['order'] = $order; + + $data['order_reference_id'] = $this->session->data['apalwa']['pay']['order_reference_id']; + $data['order'] = $order; + } catch (\RuntimeException $e) { + $this->model_extension_payment_amazon_login_pay->cartRedirect($e->getMessage()); + } + + $data['success'] = ''; + + if (!empty($this->session->data['success'])) { + $data['success'] = $this->session->data['success']; + unset($this->session->data['success']); + } + + if (isset($this->session->data['coupon'])) { + $data['coupon'] = $this->session->data['coupon']; + } else { + $data['coupon'] = ''; + } + + if (isset($this->session->data['comment'])) { + $data['comment'] = $this->session->data['comment']; + } else { + $data['comment'] = ''; + } + + $data['is_order_total_positive'] = $this->model_extension_payment_amazon_login_pay->isTotalPositive(); + $data['standard_checkout'] = $this->url->link('extension/payment/amazon_login_pay/standard_checkout', '', true); + + $zero_total = $this->currency->format(0, $this->session->data['currency']); + $data['error_order_total_zero'] = sprintf($this->language->get('error_order_total_zero'), $zero_total); + + $data['process'] = html_entity_decode($this->url->link('extension/payment/amazon_login_pay/process', '', true), ENT_COMPAT, "UTF-8"); + $data['back'] = html_entity_decode($this->url->link('extension/payment/amazon_login_pay/payment', '', true), ENT_COMPAT, "UTF-8"); + $data['session_expired'] = html_entity_decode($this->url->link('extension/payment/amazon_login_pay/session_expired'), ENT_COMPAT, "UTF-8"); + $data['coupon_discard'] = html_entity_decode($this->url->link('extension/payment/amazon_login_pay/coupon_discard', '', true), ENT_COMPAT, "UTF-8"); + $data['coupon_apply'] = html_entity_decode($this->url->link('extension/total/coupon/coupon', '', true), ENT_COMPAT, "UTF-8"); + $data['persist_comment'] = html_entity_decode($this->url->link('extension/payment/amazon_login_pay/persist_comment', '', true), ENT_COMPAT, "UTF-8"); + $data['is_coupon_change_allowed'] = $this->model_extension_payment_amazon_login_pay->isOrderInState($this->session->data['apalwa']['pay']['order_reference_id'], array('Draft')); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('common/home', '', true), + 'text' => $this->language->get('text_home') + ); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('checkout/cart'), + 'text' => $this->language->get('breadcrumb_cart') + ); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('extension/payment/amazon_login_pay/address'), + 'text' => $this->language->get('breadcrumb_shipping') + ); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('extension/payment/amazon_login_pay/payment'), + 'text' => $this->language->get('breadcrumb_payment') + ); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('extension/payment/amazon_login_pay/confirm'), + 'current' => true, + 'text' => $this->language->get('breadcrumb_summary') + ); + + $location_currency = $this->config->get('payment_amazon_login_pay_payment_region'); + $rate = round($this->currency->getValue($location_currency) / $this->currency->getValue($order['currency_code']), 8); + $amount = $this->currency->format($this->currency->convert($order['total'], $this->config->get('config_currency'), $location_currency), $location_currency, 1, true); + + $data['is_amount_converted'] = $order['currency_code'] != $location_currency; + $data['text_amount_converted'] = sprintf($this->language->get('text_amount_converted'), $location_currency, $rate, $amount); + + $data['content_main'] = $this->load->view('extension/payment/amazon_login_pay_confirm', $data); + $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/amazon_login_pay_generic', $data)); + } + + public function process() { + $this->load->language('extension/payment/amazon_login_pay'); + $this->load->language('checkout/checkout'); + + $this->load->model('extension/payment/amazon_login_pay'); + $this->load->model('checkout/order'); + + // Verify cart + $this->model_extension_payment_amazon_login_pay->verifyCart(); + + // Verify login + $this->model_extension_payment_amazon_login_pay->verifyLogin(); + + // Verify cart total + // Not needed, as we will display an error message later on... + + // Verify reference + $this->model_extension_payment_amazon_login_pay->verifyReference(); + + // Verify shipping + $this->model_extension_payment_amazon_login_pay->verifyShipping(); + + // Verify order + $this->model_extension_payment_amazon_login_pay->verifyOrder(); + + try { + $order_reference_id = $this->session->data['apalwa']['pay']['order_reference_id']; + + if (empty($this->session->data['order_id'])) { + // Up to this point, everything is fine in the session. Save the order and submit it to Amazon. + $order_id = $this->model_checkout_order->addOrder($this->session->data['apalwa']['pay']['order']); + + $this->session->data['order_id'] = $order_id; + + $this->model_extension_payment_amazon_login_pay->submitOrderDetails($order_reference_id, $order_id); + } else { + $order_id = $this->session->data['order_id']; + } + + // Check constraints + $constraints = $this->model_extension_payment_amazon_login_pay->fetchOrder($order_reference_id)->Constraints; + + if (!empty($constraints->Constraint)) { + // We do not expect to fall under the other kinds of constraints. For more information, see: https://pay.amazon.com/us/developer/documentation/apireference/201752890 + $payment_page_errors = array( + 'PaymentPlanNotSet' => $this->language->get('error_constraint_payment_plan_not_set'), + 'PaymentMethodNotAllowed' => $this->language->get('error_constraint_payment_method_not_allowed'), + 'AmountNotSet' => $this->language->get('error_constraint_amount_not_set') + ); + + $constraint_id = (string)$constraints->Constraint->ConstraintID; + + if (in_array($constraint_id, array_keys($payment_page_errors))) { + $this->session->data['apalwa']['error'] = $payment_page_errors[$constraint_id]; + + $this->response->redirect($this->url->link('extension/payment/amazon_login_pay/payment', '', true)); + } else { + throw new \RuntimeException($constraints->Constraint->Description); + } + } + + // Open the order for authorization + $this->model_extension_payment_amazon_login_pay->confirmOrder($order_reference_id); + + $amazon_order = $this->model_extension_payment_amazon_login_pay->fetchOrder($order_reference_id); + + // The order has been opened for authorization. Store it in the database + $amazon_login_pay_order_id = $this->model_extension_payment_amazon_login_pay->findOrAddOrder($amazon_order); + + // Authorize the order + $authorization = $this->model_extension_payment_amazon_login_pay->authorizeOrder($amazon_order); + + // Log the authorization + $this->model_extension_payment_amazon_login_pay->addAuthorization($amazon_login_pay_order_id, $authorization); + + if ($authorization->AuthorizationStatus->State == 'Declined') { + $reason_code = (string)$authorization->AuthorizationStatus->ReasonCode; + + switch ($reason_code) { + case 'InvalidPaymentMethod' : + $this->session->data['apalwa']['error'] = $this->language->get('error_decline_invalid_payment_method'); + + $this->response->redirect($this->url->link('extension/payment/amazon_login_pay/payment', '', true)); + break; + default : + if ($this->model_extension_payment_amazon_login_pay->isOrderInState($order_reference_id, array('Open'))) { + $this->model_extension_payment_amazon_login_pay->cancelOrder($order_reference_id, "Authorization has failed with the state: " . $authorization->AuthorizationStatus->State); + } + + $cart_error_messages = array( + 'TransactionTimedOut' => $this->language->get('error_decline_transaction_timed_out'), + 'AmazonRejected' => $this->language->get('error_decline_amazon_rejected'), + 'ProcessingFailure' => $this->language->get('error_decline_processing_failure') + ); + + if (in_array($reason_code, array_keys($cart_error_messages))) { + //@todo - do the logout with amazon.Login.logout(); instead + unset($this->session->data['apalwa']); + + // capital L in Amazon cookie name is required, do not alter for coding standards + if (isset($this->request->cookie['amazon_Login_state_cache'])) { + //@todo - rework this by triggering the JavaScript logout + setcookie('amazon_Login_state_cache', null, -1, '/'); + } + + throw new \RuntimeException($cart_error_messages[$reason_code]); + } else { + // This should never occur, but just in case... + throw $this->model_extension_payment_amazon_login_pay->loggedException("Authorization has failed with code: " . $reason_code, $this->language->get('error_process_order')); + } + break; + } + } + + // Amend the billing address based on the Authorize response + if (!empty($authorization->AuthorizationBillingAddress)) { + $this->model_extension_payment_amazon_login_pay->updatePaymentAddress($order_id, $authorization->AuthorizationBillingAddress); + } + + // Clean the session and redirect to the success page + unset($this->session->data['apalwa']['pay']); + + // In case a payment has been completed, and the order is not closed, close it. + if (isset($authorization->CapturedAmount->Amount) && (float)$authorization->CapturedAmount->Amount && $this->model_extension_payment_amazon_login_pay->isOrderInState($order_reference_id, array('Open', 'Suspended'))) { + $this->model_extension_payment_amazon_login_pay->closeOrder($order_reference_id, "A capture has been performed. Closing the order."); + } + + // Log any errors triggered by addOrderHistory, but without displaying them + set_error_handler(array($this->model_extension_payment_amazon_login_pay, 'logHandler')); + + try { + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_amazon_login_pay_pending_status')); + } catch (\Exception $e) { + if ($this->config->get('error_log')) { + $this->log->write($e->getMessage()); + } + } + + $this->response->redirect($this->url->link('checkout/success', '', true)); + } catch (\RuntimeException $e) { + $this->model_extension_payment_amazon_login_pay->cartRedirect($e->getMessage()); + } + } + + public function ipn() { + $this->load->model('extension/payment/amazon_login_pay'); + + try { + if (!isset($this->request->get['token'])) { + throw new \RuntimeException('GET variable "token" is missing.'); + } + + if (trim($this->request->get['token']) == '') { + throw new \RuntimeException('GET variable "token" set, but is empty.'); + } + + if (!$this->config->get('payment_amazon_login_pay_ipn_token')) { + throw new \RuntimeException('CONFIG variable "payment_amazon_login_pay_ipn_token" is empty.'); + } + + if (!hash_equals(trim($this->config->get('payment_amazon_login_pay_ipn_token')), trim($this->request->get['token']))) { + throw new \RuntimeException('Token values are different.'); + } + + // Everything is fine. Process the IPN + $body = file_get_contents('php://input'); + + $this->model_extension_payment_amazon_login_pay->debugLog('IPN BODY', $body); + + if ($body) { + $xml = $this->model_extension_payment_amazon_login_pay->parseIpnBody($body); + + switch ($xml->getName()) { + case 'AuthorizationNotification': + $this->model_extension_payment_amazon_login_pay->authorizationIpn($xml); + break; + case 'CaptureNotification': + $this->model_extension_payment_amazon_login_pay->captureIpn($xml); + break; + case 'RefundNotification': + $this->model_extension_payment_amazon_login_pay->refundIpn($xml); + break; + } + } + } catch (\RuntimeException $e) { + $this->model_extension_payment_amazon_login_pay->debugLog('IPN ERROR', $e->getMessage()); + } + + $this->response->addHeader('HTTP/1.1 200 OK'); + $this->response->addHeader('Content-Type: application/json'); + } + + public function capture(&$route, &$args, &$output) { + $this->load->language('extension/payment/amazon_login_pay'); + + $this->load->model('extension/payment/amazon_login_pay'); + $order_id = $args[0]; + + $order_info = $this->model_checkout_order->getOrder($order_id); + + if ($order_info['order_status_id'] == $this->config->get('payment_amazon_login_pay_capture_status')) { + try { + $amazon_login_pay_order = $this->model_extension_payment_amazon_login_pay->getOrderByOrderId($order_id); + + $capture_response = $this->model_extension_payment_amazon_login_pay->captureOrder($amazon_login_pay_order['amazon_authorization_id'], $amazon_login_pay_order['total'], $amazon_login_pay_order['currency_code']); + + if (isset($capture_response->CaptureStatus->State) && in_array($capture_response->CaptureStatus->State, array('Completed', 'Pending'))) { + $order_reference_id = $amazon_login_pay_order['amazon_order_reference_id']; + + if ($this->model_extension_payment_amazon_login_pay->isOrderInState($order_reference_id, array('Open', 'Suspended'))) { + $this->model_extension_payment_amazon_login_pay->closeOrder($order_reference_id, "Captured amount: " . (string)$capture_response->CaptureAmount->Amount . " " . (string)$capture_response->CaptureAmount->CurrencyCode); + } + + $transaction = array( + 'amazon_login_pay_order_id' => $amazon_login_pay_order['amazon_login_pay_order_id'], + 'amazon_authorization_id' => $amazon_login_pay_order['amazon_authorization_id'], + 'amazon_capture_id' => $capture_response->AmazonCaptureId, + 'amazon_refund_id' => '', + 'date_added' => date('Y-m-d H:i:s', strtotime((string)$capture_response->CreationTimestamp)), + 'type' => 'capture', + 'status' => (string)$capture_response->CaptureStatus->State, + 'amount' => (float)$capture_response->CaptureAmount->Amount + ); + + $this->model_extension_payment_amazon_login_pay->addTransaction($transaction); + + $this->model_extension_payment_amazon_login_pay->updateStatus($amazon_login_pay_order['amazon_authorization_id'], 'authorization', 'Closed'); + + $this->model_extension_payment_amazon_login_pay->updateCapturedStatus($amazon_login_pay_order['amazon_login_pay_order_id'], 1); + } + } catch (\RuntimeException $e) { + // Do nothing, as the exception is logged in case of debug logging. + } + } + } +} diff --git a/public/catalog/controller/extension/payment/authorizenet_aim.php b/public/catalog/controller/extension/payment/authorizenet_aim.php new file mode 100644 index 0000000..d3355ef --- /dev/null +++ b/public/catalog/controller/extension/payment/authorizenet_aim.php @@ -0,0 +1,176 @@ +<?php +class ControllerExtensionPaymentAuthorizeNetAim extends Controller { + public function index() { + $this->load->language('extension/payment/authorizenet_aim'); + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['year_expire'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['year_expire'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + return $this->load->view('extension/payment/authorizenet_aim', $data); + } + + public function send() { + if ($this->config->get('payment_authorizenet_aim_server') == 'live') { + $url = 'https://secure.authorize.net/gateway/transact.dll'; + } elseif ($this->config->get('payment_authorizenet_aim_server') == 'test') { + $url = 'https://test.authorize.net/gateway/transact.dll'; + } + + //$url = 'https://secure.networkmerchants.com/gateway/transact.dll'; + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $data = array(); + + $data['x_login'] = $this->config->get('payment_authorizenet_aim_login'); + $data['x_tran_key'] = $this->config->get('payment_authorizenet_aim_key'); + $data['x_version'] = '3.1'; + $data['x_delim_data'] = 'true'; + $data['x_delim_char'] = '|'; + $data['x_encap_char'] = '"'; + $data['x_relay_response'] = 'false'; + $data['x_first_name'] = $order_info['payment_firstname']; + $data['x_last_name'] = $order_info['payment_lastname']; + $data['x_company'] = $order_info['payment_company']; + $data['x_address'] = $order_info['payment_address_1']; + $data['x_city'] = $order_info['payment_city']; + $data['x_state'] = $order_info['payment_zone']; + $data['x_zip'] = $order_info['payment_postcode']; + $data['x_country'] = $order_info['payment_country']; + $data['x_phone'] = $order_info['telephone']; + $data['x_customer_ip'] = $this->request->server['REMOTE_ADDR']; + $data['x_email'] = $order_info['email']; + $data['x_description'] = html_entity_decode($this->config->get('config_name'), ENT_QUOTES, 'UTF-8'); + $data['x_amount'] = $this->currency->format($order_info['total'], $order_info['currency_code'], 1.00000, false); + $data['x_currency_code'] = $this->session->data['currency']; + $data['x_method'] = 'CC'; + $data['x_type'] = ($this->config->get('payment_authorizenet_aim_method') == 'capture') ? 'AUTH_CAPTURE' : 'AUTH_ONLY'; + $data['x_card_num'] = str_replace(' ', '', $this->request->post['cc_number']); + $data['x_exp_date'] = $this->request->post['cc_expire_date_month'] . $this->request->post['cc_expire_date_year']; + $data['x_card_code'] = $this->request->post['cc_cvv2']; + $data['x_invoice_num'] = $this->session->data['order_id']; + $data['x_solution_id'] = 'A1000015'; + + /* Customer Shipping Address Fields */ + if ($order_info['shipping_method']) { + $data['x_ship_to_first_name'] = $order_info['shipping_firstname']; + $data['x_ship_to_last_name'] = $order_info['shipping_lastname']; + $data['x_ship_to_company'] = $order_info['shipping_company']; + $data['x_ship_to_address'] = $order_info['shipping_address_1'] . ' ' . $order_info['shipping_address_2']; + $data['x_ship_to_city'] = $order_info['shipping_city']; + $data['x_ship_to_state'] = $order_info['shipping_zone']; + $data['x_ship_to_zip'] = $order_info['shipping_postcode']; + $data['x_ship_to_country'] = $order_info['shipping_country']; + } else { + $data['x_ship_to_first_name'] = $order_info['payment_firstname']; + $data['x_ship_to_last_name'] = $order_info['payment_lastname']; + $data['x_ship_to_company'] = $order_info['payment_company']; + $data['x_ship_to_address'] = $order_info['payment_address_1'] . ' ' . $order_info['payment_address_2']; + $data['x_ship_to_city'] = $order_info['payment_city']; + $data['x_ship_to_state'] = $order_info['payment_zone']; + $data['x_ship_to_zip'] = $order_info['payment_postcode']; + $data['x_ship_to_country'] = $order_info['payment_country']; + } + + if ($this->config->get('payment_authorizenet_aim_mode') == 'test') { + $data['x_test_request'] = 'true'; + } + + $curl = curl_init($url); + + curl_setopt($curl, CURLOPT_PORT, 443); + curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_FORBID_REUSE, 1); + curl_setopt($curl, CURLOPT_FRESH_CONNECT, 1); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_setopt($curl, CURLOPT_TIMEOUT, 10); + curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data, '', '&')); + + $response = curl_exec($curl); + + $json = array(); + + if (curl_error($curl)) { + $json['error'] = 'CURL ERROR: ' . curl_errno($curl) . '::' . curl_error($curl); + + $this->log->write('AUTHNET AIM CURL ERROR: ' . curl_errno($curl) . '::' . curl_error($curl)); + } elseif ($response) { + $i = 1; + + $response_info = array(); + + $results = explode('|', $response); + + foreach ($results as $result) { + $response_info[$i] = trim($result, '"'); + + $i++; + } + + if ($response_info[1] == '1') { + $message = ''; + + if (isset($response_info['5'])) { + $message .= 'Authorization Code: ' . $response_info['5'] . "\n"; + } + + if (isset($response_info['6'])) { + $message .= 'AVS Response: ' . $response_info['6'] . "\n"; + } + + if (isset($response_info['7'])) { + $message .= 'Transaction ID: ' . $response_info['7'] . "\n"; + } + + if (isset($response_info['39'])) { + $message .= 'Card Code Response: ' . $response_info['39'] . "\n"; + } + + if (isset($response_info['40'])) { + $message .= 'Cardholder Authentication Verification Response: ' . $response_info['40'] . "\n"; + } + + if (!$this->config->get('payment_authorizenet_aim_hash') || (strtoupper($response_info[38]) == strtoupper(md5($this->config->get('payment_authorizenet_aim_hash') . $this->config->get('payment_authorizenet_aim_login') . $response_info[7] . $this->currency->format($order_info['total'], $order_info['currency_code'], 1.00000, false))))) { + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_authorizenet_aim_order_status_id'), $message, false); + } else { + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('config_order_status_id')); + } + + $json['redirect'] = $this->url->link('checkout/success', '', true); + } else { + $json['error'] = $response_info[4]; + } + } else { + $json['error'] = 'Empty Gateway Response'; + + $this->log->write('AUTHNET AIM CURL ERROR: Empty Gateway Response'); + } + + curl_close($curl); + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/authorizenet_sim.php b/public/catalog/controller/extension/payment/authorizenet_sim.php new file mode 100644 index 0000000..9cf7d87 --- /dev/null +++ b/public/catalog/controller/extension/payment/authorizenet_sim.php @@ -0,0 +1,141 @@ +<?php +class ControllerExtensionPaymentAuthorizeNetSim extends Controller { + public function index() { + $this->load->language('extension/payment/authorizenet_sim'); + + $data['button_confirm'] = $this->language->get('button_confirm'); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $data['x_login'] = $this->config->get('payment_authorizenet_sim_merchant'); + $data['x_fp_sequence'] = $this->session->data['order_id']; + $data['x_fp_timestamp'] = time(); + $data['x_amount'] = $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false); + $data['x_fp_hash'] = null; // calculated later, once all fields are populated + $data['x_show_form'] = 'PAYMENT_FORM'; + $data['x_test_request'] = $this->config->get('payment_authorizenet_sim_mode'); + $data['x_type'] = 'AUTH_CAPTURE'; + $data['x_currency_code'] = $this->session->data['currency']; + $data['x_invoice_num'] = $this->session->data['order_id']; + $data['x_description'] = html_entity_decode($this->config->get('config_name'), ENT_QUOTES, 'UTF-8'); + $data['x_first_name'] = $order_info['payment_firstname']; + $data['x_last_name'] = $order_info['payment_lastname']; + $data['x_company'] = $order_info['payment_company']; + $data['x_address'] = $order_info['payment_address_1'] . ' ' . $order_info['payment_address_2']; + $data['x_city'] = $order_info['payment_city']; + $data['x_state'] = $order_info['payment_zone']; + $data['x_zip'] = $order_info['payment_postcode']; + $data['x_country'] = $order_info['payment_country']; + $data['x_phone'] = $order_info['telephone']; + $data['x_ship_to_first_name'] = $order_info['shipping_firstname']; + $data['x_ship_to_last_name'] = $order_info['shipping_lastname']; + $data['x_ship_to_company'] = $order_info['shipping_company']; + $data['x_ship_to_address'] = $order_info['shipping_address_1'] . ' ' . $order_info['shipping_address_2']; + $data['x_ship_to_city'] = $order_info['shipping_city']; + $data['x_ship_to_state'] = $order_info['shipping_zone']; + $data['x_ship_to_zip'] = $order_info['shipping_postcode']; + $data['x_ship_to_country'] = $order_info['shipping_country']; + $data['x_customer_ip'] = $this->request->server['REMOTE_ADDR']; + $data['x_email'] = $order_info['email']; + $data['x_relay_response'] = 'true'; + + $to_hash = $data['x_login'] . '^' . $data['x_fp_sequence'] . '^' . $data['x_fp_timestamp'] . '^' . $data['x_amount'] . '^' . $data['x_currency_code']; + $data['x_fp_hash'] = $this->generateHash($to_hash, $this->config->get('payment_authorizenet_sim_key')); + + return $this->load->view('extension/payment/authorizenet_sim', $data); + } + + public function callback() { + if (isset($this->request->post['x_SHA2_Hash']) && ($this->request->post['x_SHA2_Hash'] == $this->generateResponseHash($this->request->post, $this->config->get('payment_authorizenet_sim_hash')))) { + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->request->post['x_invoice_num']); + + if ($order_info && $this->request->post['x_response_code'] == '1') { + $message = ''; + + if (isset($this->request->post['x_response_reason_text'])) { + $message .= 'Response Text: ' . $this->request->post['x_response_reason_text'] . "\n"; + } + + if (isset($this->request->post['exact_issname'])) { + $message .= 'Issuer: ' . $this->request->post['exact_issname'] . "\n"; + } + + if (isset($this->request->post['exact_issconf'])) { + $message .= 'Confirmation Number: ' . $this->request->post['exact_issconf']; + } + + if (isset($this->request->post['exact_ctr'])) { + $message .= 'Receipt: ' . $this->request->post['exact_ctr']; + } + + $this->model_checkout_order->addOrderHistory($this->request->post['x_invoice_num'], $this->config->get('payment_authorizenet_sim_order_status_id'), $message, true); + + $this->response->redirect($this->url->link('checkout/success')); + } else { + $this->response->redirect($this->url->link('checkout/failure')); + } + } else { + $this->response->redirect($this->url->link('checkout/failure')); + } + } + + private function generateHash($to_hash, $key) { + if ($to_hash != null && $key != null) { + $sig = hash_hmac('sha512', $to_hash, hex2bin($key)); + + return strtoupper($sig); + } else { + return false; + } + } + + private function generateResponseHash($post_fields, $signature_key) { + /** + * The following array must not be reordered or elements removed, the hash requires ALL, even if empty/not set + */ + $verify_hash_fields = [ + 'x_trans_id', + 'x_test_request', + 'x_response_code', + 'x_auth_code', + 'x_cvv2_resp_code', + 'x_cavv_response', + 'x_avs_code', + 'x_method', + 'x_account_number', + 'x_amount', + 'x_company', + 'x_first_name', + 'x_last_name', + 'x_address', + 'x_city', + 'x_state', + 'x_zip', + 'x_country', + 'x_phone', + 'x_fax', + 'x_email', + 'x_ship_to_company', + 'x_ship_to_first_name', + 'x_ship_to_last_name', + 'x_ship_to_address', + 'x_ship_to_city', + 'x_ship_to_state', + 'x_ship_to_zip', + 'x_ship_to_country', + 'x_invoice_num', + ]; + + $to_hash = '^'; + + foreach ($verify_hash_fields as $hash_field) { + $to_hash .= (isset($post_fields[$hash_field]) ? $post_fields[$hash_field] : '') . '^'; + } + + return $this->generateHash($to_hash, $signature_key); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/bank_transfer.php b/public/catalog/controller/extension/payment/bank_transfer.php new file mode 100644 index 0000000..cc385c5 --- /dev/null +++ b/public/catalog/controller/extension/payment/bank_transfer.php @@ -0,0 +1,31 @@ +<?php +class ControllerExtensionPaymentBankTransfer extends Controller { + public function index() { + $this->load->language('extension/payment/bank_transfer'); + + $data['bank'] = nl2br($this->config->get('payment_bank_transfer_bank' . $this->config->get('config_language_id'))); + + return $this->load->view('extension/payment/bank_transfer', $data); + } + + public function confirm() { + $json = array(); + + if ($this->session->data['payment_method']['code'] == 'bank_transfer') { + $this->load->language('extension/payment/bank_transfer'); + + $this->load->model('checkout/order'); + + $comment = $this->language->get('text_instruction') . "\n\n"; + $comment .= $this->config->get('payment_bank_transfer_bank' . $this->config->get('config_language_id')) . "\n\n"; + $comment .= $this->language->get('text_payment'); + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_bank_transfer_order_status_id'), $comment, true); + + $json['redirect'] = $this->url->link('checkout/success'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/bluepay_hosted.php b/public/catalog/controller/extension/payment/bluepay_hosted.php new file mode 100644 index 0000000..2a218f5 --- /dev/null +++ b/public/catalog/controller/extension/payment/bluepay_hosted.php @@ -0,0 +1,95 @@ +<?php +class ControllerExtensionPaymentBluePayHosted extends Controller { + public function index() { + $this->load->language('extension/payment/bluepay_hosted'); + $this->load->model('checkout/order'); + $this->load->model('extension/payment/bluepay_hosted'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $data['ORDER_ID'] = $this->session->data['order_id']; + $data['NAME1'] = $order_info['payment_firstname']; + $data['NAME2'] = $order_info['payment_lastname']; + $data['ADDR1'] = $order_info['payment_address_1']; + $data['ADDR2'] = $order_info['payment_address_2']; + $data['CITY'] = $order_info['payment_city']; + $data['STATE'] = $order_info['payment_zone']; + $data['ZIPCODE'] = $order_info['payment_postcode']; + $data['COUNTRY'] = $order_info['payment_country']; + $data['PHONE'] = $order_info['telephone']; + $data['EMAIL'] = $order_info['email']; + + $data['SHPF_FORM_ID'] = 'opencart01'; + $data['DBA'] = $this->config->get('payment_bluepay_hosted_account_name'); + $data['MERCHANT'] = $this->config->get('payment_bluepay_hosted_account_id'); + $data['SHPF_ACCOUNT_ID'] = $this->config->get('payment_bluepay_hosted_account_id'); + $data["TRANSACTION_TYPE"] = $this->config->get('payment_bluepay_hosted_transaction'); + $data["MODE"] = strtoupper($this->config->get('payment_bluepay_hosted_test')); + + $data['CARD_TYPES'] = 'vi-mc'; + + if ($this->config->get('payment_bluepay_hosted_discover') == 1) { + $data['CARD_TYPES'] .= '-di'; + } + + if ($this->config->get('payment_bluepay_hosted_amex') == 1) { + $data['CARD_TYPES'] .= '-am'; + } + + $data["AMOUNT"] = $this->currency->format($order_info['total'], $order_info['currency_code'], false, false); + $data['APPROVED_URL'] = $this->url->link('extension/payment/bluepay_hosted/callback', '', true); + $data['DECLINED_URL'] = $this->url->link('extension/payment/bluepay_hosted/callback', '', true); + $data['MISSING_URL'] = $this->url->link('extension/payment/bluepay_hosted/callback', '', true); + $data['REDIRECT_URL'] = $this->url->link('extension/payment/bluepay_hosted/callback', '', true); + + $data['TPS_DEF'] = "MERCHANT APPROVED_URL DECLINED_URL MISSING_URL MODE TRANSACTION_TYPE TPS_DEF AMOUNT"; + $data['TAMPER_PROOF_SEAL'] = md5($this->config->get('payment_bluepay_hosted_secret_key') . $data['MERCHANT'] . $data['APPROVED_URL'] . $data['DECLINED_URL'] . $data['MISSING_URL'] . $data['MODE'] . $data['TRANSACTION_TYPE'] . $data['TPS_DEF'] . $data['AMOUNT']); + + $data['SHPF_TPS_DEF'] = "SHPF_FORM_ID SHPF_ACCOUNT_ID DBA TAMPER_PROOF_SEAL CARD_TYPES TPS_DEF SHPF_TPS_DEF AMOUNT"; + $data['SHPF_TPS'] = md5($this->config->get('payment_bluepay_hosted_secret_key') . $data['SHPF_FORM_ID'] . $data['SHPF_ACCOUNT_ID'] . $data['DBA'] . $data['TAMPER_PROOF_SEAL'] . $data['CARD_TYPES'] . $data['TPS_DEF'] . $data['SHPF_TPS_DEF'] . $data['AMOUNT']); + + $data['button_confirm'] = $this->language->get('button_confirm'); + $data['text_loading'] = $this->language->get('text_loading'); + + return $this->load->view('extension/payment/bluepay_hosted', $data); + } + + public function callback() { + $this->load->language('extension/payment/bluepay_hosted'); + + $this->load->model('checkout/order'); + + $this->load->model('extension/payment/bluepay_hosted'); + + $response_data = $this->request->get; + + if (isset($this->session->data['order_id'])) { + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if ($response_data['Result'] == 'APPROVED') { + $bluepay_hosted_order_id = $this->model_extension_payment_bluepay_hosted->addOrder($order_info, $response_data); + + if ($this->config->get('payment_bluepay_hosted_transaction') == 'SALE') { + $this->model_extension_payment_bluepay_hosted->addTransaction($bluepay_hosted_order_id, 'payment', $order_info); + } else { + $this->model_extension_payment_bluepay_hosted->addTransaction($bluepay_hosted_order_id, 'auth', $order_info); + } + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_bluepay_hosted_order_status_id')); + + $this->response->redirect($this->url->link('checkout/success', '', true)); + } else { + $this->session->data['error'] = $response_data['Result'] . ' : ' . $response_data['MESSAGE']; + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + } else { + $this->response->redirect($this->url->link('account/login', '', true)); + } + } + + public function adminCallback() { + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($this->request->get)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/bluepay_redirect.php b/public/catalog/controller/extension/payment/bluepay_redirect.php new file mode 100644 index 0000000..03b1d7e --- /dev/null +++ b/public/catalog/controller/extension/payment/bluepay_redirect.php @@ -0,0 +1,122 @@ +<?php +class ControllerExtensionPaymentBluePayRedirect extends Controller { + public function index() { + $this->load->language('extension/payment/bluepay_redirect'); + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['year_expire'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['year_expire'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + if ($this->config->get('payment_bluepay_redirect_card') == '1') { + $data['bluepay_redirect_card'] = true; + } else { + $data['bluepay_redirect_card'] = false; + } + + $data['existing_cards'] = array(); + if ($this->customer->isLogged() && $data['bluepay_redirect_card']) { + $this->load->model('extension/payment/bluepay_redirect'); + + $cards = $this->model_extension_payment_bluepay_redirect->getCards($this->customer->getId()); + + $data['existing_cards'] = $cards; + } + + return $this->load->view('extension/payment/bluepay_redirect', $data); + } + + public function send() { + $this->load->language('extension/payment/bluepay_redirect'); + + $this->load->model('checkout/order'); + + $this->load->model('extension/payment/bluepay_redirect'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + $post_data = $this->request->post; + + $post_data['MERCHANT'] = $this->config->get('payment_bluepay_redirect_account_id'); + $post_data["TRANSACTION_TYPE"] = $this->config->get('payment_bluepay_redirect_transaction'); + $post_data["MODE"] = strtoupper($this->config->get('payment_bluepay_redirect_test')); + $post_data["AMOUNT"] = $this->currency->format($order_info['total'], $order_info['currency_code'], false, false); + + if (isset($this->request->post['RRNO'])) { + $post_data["RRNO"] = $this->request->post['RRNO']; + } else { + $post_data["RRNO"] = ''; + } + + $post_data["NAME"] = substr($order_info['payment_firstname'], 0, 20) . ' ' . substr($order_info['payment_lastname'], 0, 20); + $post_data["ADDR1"] = $post_data['BillingAddress1'] = substr($order_info['payment_address_1'], 0, 100); + $post_data["CITY"] = $order_info['payment_city']; + $post_data['STATE'] = $order_info['payment_zone_code']; + $post_data["PHONE"] = substr($order_info['telephone'], 0, 20); + $post_data["EMAIL"] = substr($order_info['email'], 0, 255); + $post_data["ORDER_ID"] = $this->session->data['order_id']; + $post_data['ZIPCODE'] = substr($order_info['payment_postcode'], 0, 10); + + $post_data['APPROVED_URL'] = $this->url->link('extension/payment/bluepay_redirect/callback', '', true); + $post_data['DECLINED_URL'] = $this->url->link('extension/payment/bluepay_redirect/callback', '', true); + $post_data['MISSING_URL'] = $this->url->link('extension/payment/bluepay_redirect/callback', '', true); + + if (isset($this->request->server["REMOTE_ADDR"])) { + $post_data["REMOTE_IP"] = $this->request->server["REMOTE_ADDR"]; + } + + $tamper_proof_data = $this->config->get('payment_bluepay_redirect_secret_key') . $post_data['MERCHANT'] . $post_data["TRANSACTION_TYPE"] . $post_data['AMOUNT'] . $post_data["RRNO"] . $post_data["MODE"]; + + $post_data["TAMPER_PROOF_SEAL"] = md5($tamper_proof_data); + + $response_data = $this->model_extension_payment_bluepay_redirect->sendCurl("https://secure.bluepay.com/interfaces/bp10emu", $post_data); + + if ($response_data['Result'] == 'APPROVED') { + $bluepay_redirect_order_id = $this->model_extension_payment_bluepay_redirect->addOrder($order_info, $response_data); + + if ($this->config->get('payment_bluepay_redirect_transaction') == 'SALE') { + $this->model_extension_payment_bluepay_redirect->addTransaction($bluepay_redirect_order_id, 'payment', $order_info); + } else { + $this->model_extension_payment_bluepay_redirect->addTransaction($bluepay_redirect_order_id, 'auth', $order_info); + } + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_bluepay_redirect_order_status_id')); + + $json['redirect'] = $this->url->link('checkout/success', '', true); + } else { + $json['error'] = $response_data['Result'] . ' : ' . $response_data['MESSAGE']; + } + + if (isset($post_data['CreateToken']) && $response_data['Result'] == 'APPROVED') { + $card_data['customer_id'] = $this->customer->getId(); + $card_data['Last4Digits'] = substr(str_replace(' ', '', $post_data['CC_NUM']), -4, 4); + $card_data['ExpiryDate'] = $post_data['CC_EXPIRES_MONTH'] . '/' . substr($post_data['CC_EXPIRES_YEAR'], 2); + $card_data['CardType'] = $response_data['CARD_TYPE']; + $card_data['Token'] = $response_data['RRNO']; + + $this->model_extension_payment_bluepay_redirect->addCard($card_data); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function callback() { + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($this->request->get)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/cardconnect.php b/public/catalog/controller/extension/payment/cardconnect.php new file mode 100644 index 0000000..c1524d4 --- /dev/null +++ b/public/catalog/controller/extension/payment/cardconnect.php @@ -0,0 +1,347 @@ +<?php +class ControllerExtensionPaymentCardConnect extends Controller { + public function index() { + $this->load->language('extension/payment/cardconnect'); + + $this->load->model('extension/payment/cardconnect'); + + $data['card_types'] = $this->model_extension_payment_cardconnect->getCardTypes(); + + $data['months'] = $this->model_extension_payment_cardconnect->getMonths(); + + $data['years'] = $this->model_extension_payment_cardconnect->getYears(); + + if ($this->customer->isLogged() && $this->config->get('cardconnect_store_cards')) { + $data['store_cards'] = true; + + $data['cards'] = $this->model_extension_payment_cardconnect->getCards($this->customer->getId()); + } else { + $data['store_cards'] = false; + + $data['cards'] = array(); + } + + $data['echeck'] = $this->config->get('cardconnect_echeck'); + + $data['action'] = $this->url->link('extension/payment/cardconnect/send', '', true); + + return $this->load->view('extension/payment/cardconnect', $data); + } + + public function send() { + $this->load->language('extension/payment/cardconnect'); + + $this->load->model('extension/payment/cardconnect'); + + $this->model_extension_payment_cardconnect->log('Posting order to CardConnect'); + + $json = array(); + + $json['error'] = ''; + + if ($this->config->get('cardconnect_status')) { + if ($this->request->server['REQUEST_METHOD'] == 'POST') { + $error = $this->validate(); + + if (!$error) { + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if ($order_info) { + $this->model_extension_payment_cardconnect->log('Order ID: ' . $order_info['order_id']); + + $accttype = $account = $expiry = $cvv2 = $profile = $capture = $bankaba = ''; + + $existing_card = false; + + if (!isset($this->request->post['method']) || $this->request->post['method'] == 'card') { + $this->model_extension_payment_cardconnect->log('Method is card'); + + if ($this->request->post['card_new'] && isset($this->request->post['card_save']) && $this->config->get('cardconnect_store_cards') && $this->customer->isLogged()) { + $profile = 'Y'; + } else if (!$this->request->post['card_new'] && $this->customer->isLogged()) { + $existing_card = $this->model_extension_payment_cardconnect->getCard($this->request->post['card_choice'], $this->customer->getId()); + + $profile = $existing_card['profileid']; + } + + if ($existing_card) { + $accttype = $existing_card['type']; + + $account = $existing_card['token']; + + $expiry = $existing_card['expiry']; + + $cvv2 = ''; + } else { + $accttype = $this->request->post['card_type']; + + $account = $this->request->post['card_number']; + + $expiry = $this->request->post['card_expiry_month'] . $this->request->post['card_expiry_year']; + + $cvv2 = $this->request->post['card_cvv2']; + } + } else { + $this->model_extension_payment_cardconnect->log('Method is Echeck'); + + $account = $this->request->post['account_number']; + + $bankaba = $this->request->post['routing_number']; + } + + if ($this->config->get('cardconnect_transaction') == 'payment') { + $capture = 'Y'; + + $type = 'payment'; + + $status = 'New'; + + $order_status_id = $this->config->get('cardconnect_order_status_id_processing'); + } else { + $capture = 'N'; + + $type = 'auth'; + + $status = 'New'; + + $order_status_id = $this->config->get('cardconnect_order_status_id_pending'); + } + + $data = array( + 'merchid' => $this->config->get('payment_cardconnect_merchant_id'), + 'accttype' => $accttype, + 'account' => $account, + 'expiry' => $expiry, + 'cvv2' => $cvv2, + 'amount' => round(floatval($order_info['total']), 2, PHP_ROUND_HALF_DOWN), + 'currency' => $order_info['currency_code'], + 'orderid' => $order_info['order_id'], + 'name' => $order_info['payment_firstname'] . ' ' . $order_info['payment_lastname'], + 'address' => $order_info['payment_address_1'], + 'city' => $order_info['payment_city'], + 'region' => $order_info['payment_zone'], + 'country' => $order_info['payment_iso_code_2'], + 'postal' => $order_info['payment_postcode'], + 'email' => $order_info['email'], + 'phone' => $order_info['telephone'], + 'ecomind' => 'E', + 'tokenize' => 'Y', + 'profile' => $profile, + 'capture' => $capture, + 'bankaba' => $bankaba, + 'userfields' => array('secret_token' => $this->config->get('cardconnect_token')), + 'frontendid' => '26' + ); + + $data_json = json_encode($data); + + $url = 'https://' . $this->config->get('cardconnect_site') . '.cardconnect.com:' . (($this->config->get('cardconnect_environment') == 'live') ? 8443 : 6443) . '/cardconnect/rest/auth'; + + $header = array(); + + $header[] = 'Content-type: application/json'; + $header[] = 'Content-length: ' . strlen($data_json); + $header[] = 'Authorization: Basic ' . base64_encode($this->config->get('cardconnect_api_username') . ':' . $this->config->get('cardconnect_api_password')); + + $this->model_extension_payment_cardconnect->log('Header: ' . print_r($header, true)); + + $this->model_extension_payment_cardconnect->log('Post Data: ' . print_r($data, true)); + + $this->model_extension_payment_cardconnect->log('URL: ' . $url); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data_json); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 30); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + $response_data = curl_exec($ch); + if (curl_errno($ch)) { + $this->model_extension_payment_cardconnect->log('cURL error: ' . curl_errno($ch)); + } + curl_close($ch); + + $response_data = json_decode($response_data, true); + + $this->model_extension_payment_cardconnect->log('Response: ' . print_r($response_data, true)); + + if (isset($response_data['respstat']) && $response_data['respstat'] == 'A') { + $this->load->model('checkout/order'); + + // if a cheque + if ($bankaba) { + $payment_method = 'echeck'; + + $type = 'payment'; + } else { + $payment_method = 'card'; + } + + $this->model_checkout_order->addOrderHistory($order_info['order_id'], $order_status_id); + + $order_info = array_merge($order_info, $response_data); + + $cardconnect_order_id = $this->model_extension_payment_cardconnect->addOrder($order_info, $payment_method); + + $this->model_extension_payment_cardconnect->addTransaction($cardconnect_order_id, $type, $status, $order_info); + + if (isset($response_data['profileid']) && $this->config->get('cardconnect_store_cards') && $this->customer->isLogged()) { + $this->model_extension_payment_cardconnect->log('Saving card'); + + $this->model_extension_payment_cardconnect->addCard($cardconnect_order_id, $this->customer->getId(), $response_data['profileid'], $response_data['token'], $this->request->post['card_type'], $response_data['account'], $this->request->post['card_expiry_month'] . $this->request->post['card_expiry_year']); + } + + $this->model_extension_payment_cardconnect->log('Success'); + + $json['success'] = $this->url->link('checkout/success', '', true); + } else { + $this->model_extension_payment_cardconnect->log($response_data['resptext']); + + $json['error']['warning'] = $response_data['resptext']; + } + } else { + $this->model_extension_payment_cardconnect->log('No matching order'); + + $json['error']['warning'] = $this->language->get('error_no_order'); + } + } else { + $this->model_extension_payment_cardconnect->log('Failed validation'); + + $json['error'] = $error; + } + } else { + $this->model_extension_payment_cardconnect->log('No $_POST data'); + + $json['error']['warning'] = $this->language->get('error_no_post_data'); + } + } else { + $this->model_extension_payment_cardconnect->log('Module not enabled'); + + $json['error']['warning'] = $this->language->get('error_not_enabled'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function delete() { + $this->load->language('extension/payment/cardconnect'); + + $this->load->model('extension/payment/cardconnect'); + + $this->model_extension_payment_cardconnect->log('Deleting card'); + + $json = array(); + + if ($this->config->get('cardconnect_status')) { + if ($this->customer->isLogged()) { + if (isset($this->request->post['card_choice'])) { + if ($this->request->post['card_choice']) { + $card = $this->model_extension_payment_cardconnect->getCard($this->request->post['card_choice'], $this->customer->getId()); + + if ($card) { + $this->model_extension_payment_cardconnect->deleteCard($this->request->post['card_choice'], $this->customer->getId()); + } else { + $this->model_extension_payment_cardconnect->log('No such card'); + + $json['error'] = $this->language->get('error_no_card'); + } + } else { + $this->model_extension_payment_cardconnect->log('No card selected'); + + $json['error'] = $this->language->get('error_select_card'); + } + } else { + $this->model_extension_payment_cardconnect->log('Data missing'); + + $json['error'] = $this->language->get('error_data_missing'); + } + } else { + $this->model_extension_payment_cardconnect->log('Not logged in'); + + $json['error'] = $this->language->get('error_not_logged_in'); + } + } else { + $this->model_extension_payment_cardconnect->log('Module not enabled'); + + $json['error']['warning'] = $this->language->get('error_not_enabled'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function cron() { + $this->load->model('extension/payment/cardconnect'); + + $this->model_extension_payment_cardconnect->log('Running cron'); + + if ($this->config->get('cardconnect_status')) { + if (isset($this->request->get['token']) && hash_equals($this->config->get('cardconnect_token'), $this->request->get['token'])) { + $date = date('md', strtotime('yesterday')); + + $responses = $this->model_extension_payment_cardconnect->getSettlementStatuses($this->config->get('payment_cardconnect_merchant_id'), $date); + + foreach($responses as $response) { + foreach($response['txns'] as $transaction) { + $this->model_extension_payment_cardconnect->updateTransactionStatusByRetref($transaction['retref'], $transaction['setlstat']); + } + } + + $this->model_extension_payment_cardconnect->updateCronRunTime(); + } else { + $this->model_extension_payment_cardconnect->log('Token does not match.'); + } + } else { + $this->model_extension_payment_cardconnect->log('Module not enabled'); + } + } + + private function validate() { + $this->load->language('extension/payment/cardconnect'); + + $this->load->model('extension/payment/cardconnect'); + + $error = array(); + + if (!isset($this->request->post['method']) || $this->request->post['method'] == 'card') { + if ($this->request->post['card_new']) { + if (!isset($this->request->post['card_number']) || utf8_strlen($this->request->post['card_number']) < 1 || utf8_strlen($this->request->post['card_number']) > 19) { + $error['card_number'] = $this->language->get('error_card_number'); + } + + if (!isset($this->request->post['card_cvv2']) || utf8_strlen($this->request->post['card_cvv2']) < 1 || utf8_strlen($this->request->post['card_cvv2']) > 4) { + $error['card_cvv2'] = $this->language->get('error_card_cvv2'); + } + } else { + if (isset($this->request->post['card_choice']) && $this->request->post['card_choice']) { + $card = $this->model_extension_payment_cardconnect->getCard($this->request->post['card_choice'], $this->customer->getId()); + + if (!$card) { + $error['card_choice'] = $this->language->get('error_no_card'); + } + } else { + $error['card_choice'] = $this->language->get('error_select_card'); + } + } + } else { + if ($this->config->get('cardconnect_echeck')) { + if (!isset($this->request->post['account_number']) || utf8_strlen($this->request->post['account_number']) < 1 || utf8_strlen($this->request->post['account_number']) > 19) { + $error['account_number'] = $this->language->get('error_account_number'); + } + + if (!isset($this->request->post['routing_number']) || utf8_strlen($this->request->post['routing_number']) < 1 || utf8_strlen($this->request->post['routing_number']) > 9) { + $error['routing_number'] = $this->language->get('error_routing_number'); + } + } else { + $error['method'] = $this->language->get('error_no_echeck'); + } + } + + return $error; + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/cardinity.php b/public/catalog/controller/extension/payment/cardinity.php new file mode 100644 index 0000000..72cdf6c --- /dev/null +++ b/public/catalog/controller/extension/payment/cardinity.php @@ -0,0 +1,294 @@ +<?php +class ControllerExtensionPaymentCardinity extends Controller { + public function index() { + $this->load->language('extension/payment/cardinity'); + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['years'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['years'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + return $this->load->view('extension/payment/cardinity', $data); + } + + public function send() { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/cardinity'); + + $this->load->language('extension/payment/cardinity'); + + $json = array(); + + $json['error'] = $json['success'] = $json['3ds'] = ''; + + $payment = false; + + $error = $this->validate(); + + if (!$error) { + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if (strlen($order_info['order_id']) < 2) { + $order_id = '0' . $order_info['order_id']; + } else { + $order_id = $order_info['order_id']; + } + + if (!empty($order_info['payment_iso_code_2'])) { + $order_country = $order_info['payment_iso_code_2']; + } else { + $order_country = $order_info['shipping_iso_code_2']; + } + + $payment_data = array( + 'amount' => (float)$this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false), + 'currency' => $order_info['currency_code'], + 'order_id' => $order_id, + 'country' => $order_country, + 'payment_method' => 'card', + 'payment_instrument' => array( + 'pan' => preg_replace('!\s+!', '', $this->request->post['pan']), + 'exp_year' => (int)$this->request->post['exp_year'], + 'exp_month' => (int)$this->request->post['exp_month'], + 'cvc' => $this->request->post['cvc'], + 'holder' => $this->request->post['holder'] + ), + ); + + try { + $payment = $this->model_extension_payment_cardinity->createPayment($this->config->get('payment_cardinity_key'), $this->config->get('payment_cardinity_secret'), $payment_data); + } catch (Cardinity\Exception\Declined $exception) { + $this->failedOrder($this->language->get('error_payment_declined'), $this->language->get('error_payment_declined')); + + $json['redirect'] = $this->url->link('checkout/checkout', '', true); + } catch (Exception $exception) { + $this->failedOrder(); + + $json['redirect'] = $this->url->link('checkout/checkout', '', true); + } + + $successful_order_statuses = array( + 'approved', + 'pending' + ); + + if ($payment) { + if (!in_array($payment->getStatus(), $successful_order_statuses)) { + $this->failedOrder($payment->getStatus()); + + $json['redirect'] = $this->url->link('checkout/checkout', '', true); + } else { + $this->model_extension_payment_cardinity->addOrder(array( + 'order_id' => $this->session->data['order_id'], + 'payment_id' => $payment->getId() + )); + + if ($payment->getStatus() == 'pending') { + //3ds + $authorization_information = $payment->getAuthorizationInformation(); + + $encryption_data = array( + 'order_id' => $this->session->data['order_id'], + 'secret' => $this->config->get('payment_cardinity_secret') + ); + + $hash = $this->encryption->encrypt($this->config->get('config_encryption'), json_encode($encryption_data)); + + $json['3ds'] = array( + 'url' => $authorization_information->getUrl(), + 'PaReq' => $authorization_information->getData(), + 'TermUrl' => $this->url->link('extension/payment/cardinity/threeDSecureCallback', '', true), + 'hash' => $hash + ); + } elseif ($payment->getStatus() == 'approved') { + $this->finalizeOrder($payment); + + $json['redirect'] = $this->url->link('checkout/success', '', true); + } + } + } + } else { + $json['error'] = $error; + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function threeDSecureForm() { + $this->load->model('extension/payment/cardinity'); + + $this->load->language('extension/payment/cardinity'); + + $success = false; + $redirect = false; + + $encryption_data = array( + 'order_id' => $this->session->data['order_id'], + 'secret' => $this->config->get('payment_cardinity_secret') + ); + + $hash = $this->encryption->encrypt($this->config->get('config_encryption'), json_encode($encryption_data)); + + if (hash_equals($hash, $this->request->post['hash'])) { + $success = true; + + $data['url'] = $this->request->post['url']; + $data['PaReq'] = $this->request->post['PaReq']; + $data['TermUrl'] = $this->request->post['TermUrl']; + $data['MD'] = $hash; + } else { + $this->failedOrder($this->language->get('error_invalid_hash')); + + $redirect = $this->url->link('checkout/checkout', '', true); + } + + $data['success'] = $success; + $data['redirect'] = $redirect; + + $this->response->setOutput($this->load->view('extension/payment/cardinity_3ds', $data)); + } + + public function threeDSecureCallback() { + $this->load->model('extension/payment/cardinity'); + + $this->load->language('extension/payment/cardinity'); + + $success = false; + + $error = ''; + + $encryption_data = array( + 'order_id' => $this->session->data['order_id'], + 'secret' => $this->config->get('payment_cardinity_secret') + ); + + $hash = $this->encryption->encrypt($this->config->get('config_encryption'), json_encode($encryption_data)); + + if (hash_equals($hash, $this->request->post['MD'])) { + $order = $this->model_extension_payment_cardinity->getOrder($encryption_data['order_id']); + + if ($order && $order['payment_id']) { + $payment = $this->model_extension_payment_cardinity->finalizePayment($this->config->get('payment_cardinity_key'), $this->config->get('payment_cardinity_secret'), $order['payment_id'], $this->request->post['PaRes']); + + if ($payment && $payment->getStatus() == 'approved') { + $success = true; + } else { + $error = $this->language->get('error_finalizing_payment'); + } + } else { + $error = $this->language->get('error_unknown_order_id'); + } + } else { + $error = $this->language->get('error_invalid_hash'); + } + + if ($success) { + $this->finalizeOrder($payment); + + $this->response->redirect($this->url->link('checkout/success', '', true)); + } else { + $this->failedOrder($error); + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + } + + private function finalizeOrder($payment) { + $this->load->model('checkout/order'); + + $this->load->language('extension/payment/cardinity'); + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_cardinity_order_status_id')); + + $this->model_extension_payment_cardinity->log($this->language->get('text_payment_success')); + $this->model_extension_payment_cardinity->log($payment); + } + + private function failedOrder($log = null, $alert = null) { + $this->load->language('extension/payment/cardinity'); + + $this->model_extension_payment_cardinity->log($this->language->get('text_payment_failed')); + + if ($log) { + $this->model_extension_payment_cardinity->log($log); + } + + if ($alert) { + $this->session->data['error'] = $alert; + } else { + $this->session->data['error'] = $this->language->get('error_process_order'); + } + } + + private function validate() { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/cardinity'); + + $error = array(); + + if (!$this->session->data['order_id']) { + $error['warning'] = $this->language->get('error_process_order'); + } + + if (!$error) { + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if (!$order_info) { + $error['warning'] = $this->language->get('error_process_order'); + } + } + + if (!in_array($order_info['currency_code'], $this->model_extension_payment_cardinity->getSupportedCurrencies())) { + $error['warning'] = $this->language->get('error_invalid_currency'); + } + + if (!isset($this->request->post['holder']) || utf8_strlen($this->request->post['holder']) < 1 || utf8_strlen($this->request->post['holder']) > 32) { + $error['holder'] = true; + } + + if (!isset($this->request->post['pan']) || utf8_strlen($this->request->post['pan']) < 1 || utf8_strlen($this->request->post['pan']) > 19) { + $error['pan'] = true; + } + + if (!isset($this->request->post['pan']) || !is_numeric(preg_replace('!\s+!', '', $this->request->post['pan']))) { + $error['pan'] = true; + } + + if (!isset($this->request->post['exp_month']) || !isset($this->request->post['exp_year'])) { + $error['expiry_date'] = true; + } else { + $expiry = new DateTime(); + $expiry->setDate($this->request->post['exp_year'], $this->request->post['exp_month'], '1'); + $expiry->modify('+1 month'); + $expiry->modify('-1 day'); + + $now = new DateTime(); + + if ($expiry < $now) { + $error['expiry_date'] = true; + } + } + + if (!isset($this->request->post['cvc']) || utf8_strlen($this->request->post['cvc']) < 1 || utf8_strlen($this->request->post['cvc']) > 4) { + $error['cvc'] = true; + } + + return $error; + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/cheque.php b/public/catalog/controller/extension/payment/cheque.php new file mode 100644 index 0000000..4fbc771 --- /dev/null +++ b/public/catalog/controller/extension/payment/cheque.php @@ -0,0 +1,34 @@ +<?php +class ControllerExtensionPaymentCheque extends Controller { + public function index() { + $this->load->language('extension/payment/cheque'); + + $data['payable'] = $this->config->get('payment_cheque_payable'); + $data['address'] = nl2br($this->config->get('config_address')); + + return $this->load->view('extension/payment/cheque', $data); + } + + public function confirm() { + $json = array(); + + if ($this->session->data['payment_method']['code'] == 'cheque') { + $this->load->language('extension/payment/cheque'); + + $this->load->model('checkout/order'); + + $comment = $this->language->get('text_payable') . "\n"; + $comment .= $this->config->get('payment_cheque_payable') . "\n\n"; + $comment .= $this->language->get('text_address') . "\n"; + $comment .= $this->config->get('config_address') . "\n\n"; + $comment .= $this->language->get('text_payment') . "\n"; + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_cheque_order_status_id'), $comment, true); + + $json['redirect'] = $this->url->link('checkout/success'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/cod.php b/public/catalog/controller/extension/payment/cod.php new file mode 100644 index 0000000..4f62182 --- /dev/null +++ b/public/catalog/controller/extension/payment/cod.php @@ -0,0 +1,21 @@ +<?php +class ControllerExtensionPaymentCod extends Controller { + public function index() { + return $this->load->view('extension/payment/cod'); + } + + public function confirm() { + $json = array(); + + if ($this->session->data['payment_method']['code'] == 'cod') { + $this->load->model('checkout/order'); + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_cod_order_status_id')); + + $json['redirect'] = $this->url->link('checkout/success'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } +} diff --git a/public/catalog/controller/extension/payment/divido.php b/public/catalog/controller/extension/payment/divido.php new file mode 100644 index 0000000..ad69ae0 --- /dev/null +++ b/public/catalog/controller/extension/payment/divido.php @@ -0,0 +1,301 @@ +<?php +class ControllerExtensionPaymentDivido extends Controller { + const + STATUS_ACCEPTED = 'ACCEPTED', + STATUS_ACTION_LENDER = 'ACTION-LENDER', + STATUS_CANCELED = 'CANCELED', + STATUS_COMPLETED = 'COMPLETED', + STATUS_DEPOSIT_PAID = 'DEPOSIT-PAID', + STATUS_DECLINED = 'DECLINED', + STATUS_DEFERRED = 'DEFERRED', + STATUS_REFERRED = 'REFERRED', + STATUS_FULFILLED = 'FULFILLED', + STATUS_SIGNED = 'SIGNED'; + + private $status_id = array( + self::STATUS_ACCEPTED => 1, + self::STATUS_ACTION_LENDER => 2, + self::STATUS_CANCELED => 0, + self::STATUS_COMPLETED => 2, + self::STATUS_DECLINED => 8, + self::STATUS_DEFERRED => 1, + self::STATUS_REFERRED => 1, + self::STATUS_DEPOSIT_PAID => 1, + self::STATUS_FULFILLED => 1, + self::STATUS_SIGNED => 2, + ); + + private $history_messages = array( + self::STATUS_ACCEPTED => 'Credit request accepted', + self::STATUS_ACTION_LENDER => 'Lender notified', + self::STATUS_CANCELED => 'Credit request canceled', + self::STATUS_COMPLETED => 'Credit application completed', + self::STATUS_DECLINED => 'Credit request declined', + self::STATUS_DEFERRED => 'Credit request deferred', + self::STATUS_REFERRED => 'Credit request referred', + self::STATUS_DEPOSIT_PAID => 'Deposit paid', + self::STATUS_FULFILLED => 'Credit request fulfilled', + self::STATUS_SIGNED => 'Contract signed', + ); + + public function index() { + $this->load->language('extension/payment/divido'); + $this->load->model('extension/payment/divido'); + $this->load->model('checkout/order'); + + $api_key = $this->config->get('payment_divido_api_key'); + $key_parts = explode('.', $api_key); + $js_key = strtolower(array_shift($key_parts)); + + list($total, $totals) = $this->model_extension_payment_divido->getOrderTotals(); + + $this->model_extension_payment_divido->setMerchant($this->config->get('payment_divido_api_key')); + + $plans = $this->model_extension_payment_divido->getCartPlans($this->cart); + foreach ($plans as $key => $plan) { + $planMinTotal = $total - ($total * ($plan->min_deposit / 100)); + if ($plan->min_amount > $planMinTotal) { + unset($plans[$key]); + } + } + + $plans_ids = array_map(function ($plan) { + return $plan->id; + }, $plans); + $plans_ids = array_unique($plans_ids); + $plans_list = implode(',', $plans_ids); + + $data = array( + 'button_confirm' => $this->language->get('divido_checkout'), + 'merchant_script' => "//cdn.divido.com/calculator/{$js_key}.js", + 'grand_total' => $total, + 'plan_list' => $plans_list, + 'generic_credit_req_error' => 'Credit request could not be initiated', + ); + + return $this->load->view('extension/payment/divido', $data); + } + + public function update() { + $this->load->language('extension/payment/divido'); + $this->load->model('extension/payment/divido'); + $this->load->model('checkout/order'); + + $data = json_decode(file_get_contents('php://input')); + + if (!isset($data->status)) { + $this->response->setOutput(''); + return; + } + + $lookup = $this->model_extension_payment_divido->getLookupByOrderId($data->metadata->order_id); + if ($lookup->num_rows != 1) { + $this->response->setOutput(''); + return; + } + + $hash = $this->model_extension_payment_divido->hashOrderId($data->metadata->order_id, $lookup->row['salt']); + if ($hash !== $data->metadata->order_hash) { + $this->response->setOutput(''); + return; + } + + $order_id = $data->metadata->order_id; + $order_info = $this->model_checkout_order->getOrder($order_id); + $status_id = $order_info['order_status_id']; + $message = "Status: {$data->status}"; + if (isset($this->history_messages[$data->status])) { + $message = $this->history_messages[$data->status]; + } + + if ($data->status == self::STATUS_SIGNED) { + $status_override = $this->config->get('payment_divido_order_status_id'); + if (!empty($status_override)) { + $this->status_id[self::STATUS_SIGNED] = $status_override; + } + } + + if (isset($this->status_id[$data->status]) && $this->status_id[$data->status] > $status_id) { + $status_id = $this->status_id[$data->status]; + } + + if ($data->status == self::STATUS_DECLINED && $order_info['order_status_id'] == 0) { + $status_id = 0; + } + + $this->model_extension_payment_divido->saveLookup($data->metadata->order_id, $lookup->row['salt'], null, $data->application); + $this->model_checkout_order->addOrderHistory($order_id, $status_id, $message, false); + $this->response->setOutput('ok'); + } + + public function confirm() { + $this->load->language('extension/payment/divido'); + + $this->load->model('extension/payment/divido'); + + ini_set('html_errors', 0); + if (!$this->session->data['payment_method']['code'] == 'divido') { + return false; + } + + $this->model_extension_payment_divido->setMerchant($this->config->get('payment_divido_api_key')); + + $api_key = $this->config->get('payment_divido_api_key'); + + $deposit = $this->request->post['deposit']; + $finance = $this->request->post['finance']; + + $address = $this->session->data['payment_address']; + if (isset($this->session->data['shipping_address'])) { + $address = $this->session->data['shipping_address']; + } + + $country = $address['iso_code_2']; + $language = strtoupper($this->language->get('code')); + $currency = strtoupper($this->session->data['currency']); + $order_id = $this->session->data['order_id']; + + if ($this->customer->isLogged()) { + $this->load->model('account/customer'); + $customer_info = $this->model_account_customer->getCustomer($this->customer->getId()); + + $firstname = $customer_info['firstname']; + $lastname = $customer_info['lastname']; + $email = $customer_info['email']; + $telephone = $customer_info['telephone']; + } elseif (isset($this->session->data['guest'])) { + $firstname = $this->session->data['guest']['firstname']; + $lastname = $this->session->data['guest']['lastname']; + $email = $this->session->data['guest']['email']; + $telephone = $this->session->data['guest']['telephone']; + } + + $postcode = $address['postcode']; + + $products = array(); + foreach ($this->cart->getProducts() as $product) { + $products[] = array( + 'type' => 'product', + 'text' => $product['name'], + 'quantity' => $product['quantity'], + 'value' => $product['price'], + ); + } + + list($total, $totals) = $this->model_extension_payment_divido->getOrderTotals(); + + $sub_total = $total; + $cart_total = $this->cart->getSubTotal(); + $shiphandle = $sub_total - $cart_total; + + $products[] = array( + 'type' => 'product', + 'text' => 'Shipping & Handling', + 'quantity' => 1, + 'value' => $shiphandle, + ); + + $deposit_amount = round(($deposit / 100) * $total, 2, PHP_ROUND_HALF_UP); + + $shop_url = $this->config->get('config_url'); + if (isset($this->request->server['HTTPS']) && (($this->request->server['HTTPS'] == 'on') || ($this->request->server['HTTPS'] == '1'))) { + $shop_url = $this->config->get('config_ssl'); + } + + $callback_url = $this->url->link('extension/payment/divido/update', '', true); + $return_url = $this->url->link('checkout/success', '', true); + $checkout_url = $this->url->link('checkout/checkout', '', true); + + $salt = uniqid('', true); + $hash = $this->model_extension_payment_divido->hashOrderId($order_id, $salt); + + $request_data = array( + 'merchant' => $api_key, + 'deposit' => $deposit_amount, + 'finance' => $finance, + 'country' => $country, + 'language' => $language, + 'currency' => $currency, + 'metadata' => array( + 'order_id' => $order_id, + 'order_hash' => $hash, + ), + 'customer' => array( + 'title' => '', + 'first_name' => $firstname, + 'middle_name' => '', + 'last_name' => $lastname, + 'country' => $country, + 'postcode' => $postcode, + 'email' => $email, + 'mobile_number' => '', + 'phone_number' => $telephone, + ), + 'products' => $products, + 'response_url' => $callback_url, + 'redirect_url' => $return_url, + 'checkout_url' => $checkout_url, + ); + + $response = Divido_CreditRequest::create($request_data); + + if ($response->status == 'ok') { + + $this->model_extension_payment_divido->saveLookup($order_id, $salt, $response->id, null, $deposit_amount); + + $data = array( + 'status' => 'ok', + 'url' => $response->url, + ); + } else { + $data = array( + 'status' => 'error', + 'message' => $this->language->get($response->error), + ); + } + + $this->response->setOutput(json_encode($data)); + } + + public function calculator($args) { + $this->load->language('extension/payment/divido'); + + $this->load->model('extension/payment/divido'); + + if (!$this->model_extension_payment_divido->isEnabled()) { + return null; + } + + $this->model_extension_payment_divido->setMerchant($this->config->get('payment_divido_api_key')); + + $product_selection = $this->config->get('payment_divido_productselection'); + $price_threshold = $this->config->get('payment_divido_price_threshold'); + $product_id = $args['product_id']; + $product_price = $args['price']; + $type = $args['type']; + + if ($product_selection == 'threshold' && $product_price < $price_threshold) { + return null; + } + + $plans = $this->model_extension_payment_divido->getProductPlans($product_id); + if (empty($plans)) { + return null; + } + + $plans_ids = array_map(function ($plan) { + return $plan->id; + }, $plans); + + $plan_list = implode(',', $plans_ids); + + $data = array( + 'planList' => $plan_list, + 'productPrice' => $product_price + ); + + $filename = ($type == 'full') ? 'extension/payment/divido_calculator' : 'extension/payment/divido_widget'; + + return $this->load->view($filename, $data); + } +} diff --git a/public/catalog/controller/extension/payment/eway.php b/public/catalog/controller/extension/payment/eway.php new file mode 100644 index 0000000..393d04a --- /dev/null +++ b/public/catalog/controller/extension/payment/eway.php @@ -0,0 +1,303 @@ +<?php +class ControllerExtensionPaymentEway extends Controller { + public function index() { + $this->load->language('extension/payment/eway'); + + $data['payment_type'] = $this->config->get('payment_eway_payment_type'); + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => sprintf('%02d', $i), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['year_expire'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['year_expire'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $amount = $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false); + + if ($this->config->get('payment_eway_test')) { + $data['text_testing'] = $this->language->get('text_testing'); + $data['Endpoint'] = 'Sandbox'; + } else { + $data['text_testing'] = ''; + $data['Endpoint'] = 'Production'; + } + + $this->load->model('localisation/zone'); + + $payment_zone_info = $this->model_localisation_zone->getZone($order_info['payment_zone_id']); + $payment_zone_code = isset($payment_zone_info['code']) ? $payment_zone_info['code'] : ''; + + $shipping_zone_info = $this->model_localisation_zone->getZone($order_info['shipping_zone_id']); + $shipping_zone_code = isset($shipping_zone_info['code']) ? $shipping_zone_info['code'] : ''; + + $request = new stdClass(); + + $request->Customer = new stdClass(); + $request->Customer->Title = 'Mr.'; + $request->Customer->FirstName = (string)substr($order_info['payment_firstname'], 0, 50); + $request->Customer->LastName = (string)substr($order_info['payment_lastname'], 0, 50); + $request->Customer->CompanyName = (string)substr($order_info['payment_company'], 0, 50); + $request->Customer->Street1 = (string)substr($order_info['payment_address_1'], 0, 50); + $request->Customer->Street2 = (string)substr($order_info['payment_address_2'], 0, 50); + $request->Customer->City = (string)substr($order_info['payment_city'], 0, 50); + $request->Customer->State = (string)substr($payment_zone_code, 0, 50); + $request->Customer->PostalCode = (string)substr($order_info['payment_postcode'], 0, 30); + $request->Customer->Country = strtolower($order_info['payment_iso_code_2']); + $request->Customer->Email = $order_info['email']; + $request->Customer->Phone = (string)substr($order_info['telephone'], 0, 32); + + $request->ShippingAddress = new stdClass(); + $request->ShippingAddress->FirstName = (string)substr($order_info['shipping_firstname'], 0, 50); + $request->ShippingAddress->LastName = (string)substr($order_info['shipping_lastname'], 0, 50); + $request->ShippingAddress->Street1 = (string)substr($order_info['shipping_address_1'], 0, 50); + $request->ShippingAddress->Street2 = (string)substr($order_info['shipping_address_2'], 0, 50); + $request->ShippingAddress->City = (string)substr($order_info['shipping_city'], 0, 50); + $request->ShippingAddress->State = (string)substr($shipping_zone_code, 0, 50); + $request->ShippingAddress->PostalCode = (string)substr($order_info['shipping_postcode'], 0, 30); + $request->ShippingAddress->Country = strtolower($order_info['shipping_iso_code_2']); + $request->ShippingAddress->Email = $order_info['email']; + $request->ShippingAddress->Phone = (string)substr($order_info['telephone'], 0, 32); + $request->ShippingAddress->ShippingMethod = "Unknown"; + + $invoice_desc = ''; + foreach ($this->cart->getProducts() as $product) { + $item_price = $this->currency->format($product['price'], $order_info['currency_code'], false, false); + $item_total = $this->currency->format($product['total'], $order_info['currency_code'], false, false); + $item = new stdClass(); + $item->SKU = (string)substr($product['product_id'], 0, 12); + $item->Description = (string)substr($product['name'], 0, 26); + $item->Quantity = strval($product['quantity']); + $item->UnitCost = strval($item_price * 100); + $item->Total = $this->lowestDenomination($item_total, $order_info['currency_code']); + + $request->Items[] = $item; + $invoice_desc .= $product['name'] . ', '; + } + $invoice_desc = (string)substr($invoice_desc, 0, -2); + if (strlen($invoice_desc) > 64) { + $invoice_desc = (string)substr($invoice_desc, 0, 61) . '...'; + } + + $shipping = $this->currency->format($order_info['total'] - $this->cart->getSubTotal(), $order_info['currency_code'], false, false); + + if ($shipping > 0) { + $item = new stdClass(); + $item->SKU = ''; + $item->Description = (string)substr($this->language->get('text_shipping'), 0, 26); + $item->Quantity = 1; + $item->UnitCost = $this->lowestDenomination($shipping, $order_info['currency_code']); + $item->Total = $this->lowestDenomination($shipping, $order_info['currency_code']); + + $request->Items[] = $item; + } + + $opt1 = new stdClass(); + $opt1->Value = $order_info['order_id']; + $request->Options = array($opt1); + + $request->Payment = new stdClass(); + $request->Payment->TotalAmount = $this->lowestDenomination($amount, $order_info['currency_code']); + $request->Payment->InvoiceNumber = $this->session->data['order_id']; + $request->Payment->InvoiceDescription = $invoice_desc; + $request->Payment->InvoiceReference = (string)substr($this->config->get('config_name'), 0, 40) . ' - #' . $order_info['order_id']; + $request->Payment->CurrencyCode = $order_info['currency_code']; + + $request->RedirectUrl = $this->url->link('extension/payment/eway/callback', '', true); + if ($this->config->get('payment_eway_transaction_method') == 'auth') { + $request->Method = 'Authorise'; + } else { + $request->Method = 'ProcessPayment'; + } + $request->TransactionType = 'Purchase'; + $request->DeviceID = 'opencart-' . VERSION . ' eway-trans-2.1.2'; + $request->CustomerIP = $this->request->server['REMOTE_ADDR']; + $request->PartnerID = '0f1bec3642814f89a2ea06e7d2800b7f'; + + $this->load->model('extension/payment/eway'); + $template = 'eway'; + if ($this->config->get('payment_eway_paymode') == 'iframe') { + $request->CancelUrl = 'http://www.example.org'; + $request->CustomerReadOnly = true; + $result = $this->model_extension_payment_eway->getSharedAccessCode($request); + + $template = 'eway_iframe'; + } else { + $result = $this->model_extension_payment_eway->getAccessCode($request); + } + + // Check if any error returns + if (isset($result->Errors)) { + $error_array = explode(",", $result->Errors); + $lbl_error = ""; + foreach ($error_array as $error) { + $error = $this->language->get('text_card_message_' . $error); + $lbl_error .= $error . "<br />\n"; + } + $this->log->write('eWAY Payment error: ' . $lbl_error); + } + + if (isset($lbl_error)) { + $data['error'] = $lbl_error; + } else { + if ($this->config->get('payment_eway_paymode') == 'iframe') { + $data['callback'] = $this->url->link('extension/payment/eway/callback', 'AccessCode=' . $result->AccessCode, true); + $data['SharedPaymentUrl'] = $result->SharedPaymentUrl; + } + $data['action'] = $result->FormActionURL; + $data['AccessCode'] = $result->AccessCode; + } + + return $this->load->view('extension/payment/' . $template, $data); + } + + public function lowestDenomination($value, $currency) { + $power = $this->currency->getDecimalPlace($currency); + + $value = (float)$value; + + return (int)($value * pow(10, $power)); + } + + public function ValidateDenomination($value, $currency) { + $power = $this->currency->getDecimalPlace($currency); + + $value = (float)$value; + + return (int)($value * pow(10, '-' . $power)); + } + + public function callback() { + $this->load->language('extension/payment/eway'); + + if (isset($this->request->get['AccessCode']) || isset($this->request->get['amp;AccessCode'])) { + + $this->load->model('extension/payment/eway'); + + if (isset($this->request->get['amp;AccessCode'])) { + $access_code = $this->request->get['amp;AccessCode']; + } else { + $access_code = $this->request->get['AccessCode']; + } + + $result = $this->model_extension_payment_eway->getAccessCodeResult($access_code); + + $is_error = false; + + // Check if any error returns + if (isset($result->Errors)) { + $error_array = explode(",", $result->Errors); + $is_error = true; + $lbl_error = ''; + foreach ($error_array as $error) { + $error = $this->language->get('text_card_message_' . $error); + $lbl_error .= $error . ", "; + } + $this->log->write('eWAY error: ' . $lbl_error); + } + if (!$is_error) { + $fraud = false; + if (!$result->TransactionStatus) { + $error_array = explode(", ", $result->ResponseMessage); + $is_error = true; + $lbl_error = ''; + $log_error = ''; + foreach ($error_array as $error) { + // Don't show fraud issues to customers + if (stripos($error, 'F') === false) { + $lbl_error .= $this->language->get('text_card_message_' . $error); + } else { + $fraud = true; + } + $log_error .= $this->language->get('text_card_message_' . $error) . ", "; + } + $log_error = substr($log_error, 0, -2); + $this->log->write('eWAY payment failed: ' . $log_error); + } + } + + $this->load->model('checkout/order'); + + if ($is_error) { + if ($fraud) { + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } else { + $this->session->data['error'] = $this->language->get('text_transaction_failed'); + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + } else { + $order_id = $result->Options[0]->Value; + + $order_info = $this->model_checkout_order->getOrder($order_id); + + $this->load->model('extension/payment/eway'); + $eway_order_data = array( + 'order_id' => $order_id, + 'transaction_id' => $result->TransactionID, + 'amount' => $this->ValidateDenomination($result->TotalAmount, $order_info['currency_code']), + 'currency_code' => $order_info['currency_code'], + 'debug_data' => json_encode($result) + ); + + $error_array = explode(", ", $result->ResponseMessage); + $log_error = ''; + foreach ($error_array as $error) { + if (stripos($error, 'F') !== false) { + $fraud = true; + $log_error .= $this->language->get('text_card_message_' . $error) . ", "; + } + } + $log_error = substr($log_error, 0, -2); + + $eway_order_id = $this->model_extension_payment_eway->addOrder($eway_order_data); + $this->model_extension_payment_eway->addTransaction($eway_order_id, $this->config->get('payment_eway_transaction_method'), $result->TransactionID, $order_info); + + if ($fraud) { + $message = 'Suspected fraud order: ' . $log_error . "\n"; + } else { + $message = "eWAY Payment accepted\n"; + } + $message .= 'Transaction ID: ' . $result->TransactionID . "\n"; + $message .= 'Authorisation Code: ' . $result->AuthorisationCode . "\n"; + $message .= 'Card Response Code: ' . $result->ResponseCode . "\n"; + + if ($fraud) { + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_eway_order_status_fraud_id'), $message); + } elseif ($this->config->get('payment_eway_transaction_method') == 'payment') { + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_eway_order_status_id'), $message); + } else { + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_eway_order_status_auth_id'), $message); + } + + if (!empty($result->Customer->TokenCustomerID) && $this->customer->isLogged() && !$this->model_checkout_order->checkToken($result->Customer->TokenCustomerID)) { + $card_data = array(); + $card_data['customer_id'] = $this->customer->getId(); + $card_data['Token'] = $result->Customer->TokenCustomerID; + $card_data['Last4Digits'] = substr(str_replace(' ', '', $result->Customer->CardDetails->Number), -4, 4); + $card_data['ExpiryDate'] = $result->Customer->CardDetails->ExpiryMonth . '/' . $result->Customer->CardDetails->ExpiryYear; + $card_data['CardType'] = ''; + $this->model_extension_payment_eway->addFullCard($this->session->data['order_id'], $card_data); + } + + $this->response->redirect($this->url->link('checkout/success', '', true)); + } + } + } + +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/firstdata.php b/public/catalog/controller/extension/payment/firstdata.php new file mode 100644 index 0000000..a7fde03 --- /dev/null +++ b/public/catalog/controller/extension/payment/firstdata.php @@ -0,0 +1,243 @@ +<?php +class ControllerExtensionPaymentFirstdata extends Controller { + public function index() { + $this->load->language('extension/payment/firstdata'); + + $this->load->model('checkout/order'); + $this->load->model('extension/payment/firstdata'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if ($this->config->get('payment_firstdata_live_demo') == 1) { + $data['action'] = $this->config->get('payment_firstdata_live_url'); + } else { + $data['action'] = $this->config->get('payment_firstdata_demo_url'); + } + + $data['amount'] = $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false); + $data['currency'] = $this->model_extension_payment_firstdata->mapCurrency($order_info['currency_code']); + $data['merchant_id'] = $this->config->get('payment_firstdata_merchant_id'); + $data['timestamp'] = date('Y:m:d-H:i:s'); + $data['order_id'] = 'CON-' . $this->session->data['order_id'] . 'T' . $data['timestamp'] . mt_rand(1, 999); + $data['url_success'] = $this->url->link('checkout/success', '', true); + $data['url_fail'] = $this->url->link('extension/payment/firstdata/fail', '', true); + $data['url_notify'] = $this->url->link('extension/payment/firstdata/notify', '', true); + + if (preg_match("/Mobile|Android|BlackBerry|iPhone|Windows Phone/", $this->request->server['HTTP_USER_AGENT'])) { + $data['mobile'] = true; + } else { + $data['mobile'] = false; + } + + if ($this->config->get('payment_firstdata_auto_settle') == 1) { + $data['txntype'] = 'sale'; + } else { + $data['txntype'] = 'preauth'; + } + + $tmp = $data['merchant_id'] . $data['timestamp'] . $data['amount'] . $data['currency'] . $this->config->get('payment_firstdata_secret'); + $ascii = bin2hex($tmp); + $data['hash'] = sha1($ascii); + + $data['version'] = 'OPENCART-C-' . VERSION; + + $data['bcompany'] = $order_info['payment_company']; + $data['bname'] = $order_info['payment_firstname'] . ' ' . $order_info['payment_lastname']; + $data['baddr1'] = substr($order_info['payment_address_1'], 0, 30); + $data['baddr2'] = substr($order_info['payment_address_2'], 0, 30); + $data['bcity'] = substr($order_info['payment_city'], 0, 30); + $data['bstate'] = substr($order_info['payment_zone'], 0, 30); + $data['bcountry'] = $order_info['payment_iso_code_2']; + $data['bzip'] = $order_info['payment_postcode']; + $data['email'] = $order_info['email']; + + if ($this->cart->hasShipping()) { + $data['sname'] = $order_info['shipping_firstname'] . ' ' . $order_info['shipping_lastname']; + $data['saddr1'] = substr($order_info['shipping_address_1'], 0, 30); + $data['saddr2'] = substr($order_info['shipping_address_2'], 0, 30); + $data['scity'] = substr($order_info['shipping_city'], 0, 30); + $data['sstate'] = substr($order_info['shipping_zone'], 0, 30); + $data['scountry'] = $order_info['shipping_iso_code_2']; + $data['szip'] = $order_info['shipping_postcode']; + } else { + $data['sname'] = $order_info['payment_firstname'] . ' ' . $order_info['payment_lastname']; + $data['saddr1'] = substr($order_info['payment_address_1'], 0, 30); + $data['saddr2'] = substr($order_info['payment_address_2'], 0, 30); + $data['scity'] = substr($order_info['payment_city'], 0, 30); + $data['sstate'] = substr($order_info['payment_zone'], 0, 30); + $data['scountry'] = $order_info['payment_iso_code_2']; + $data['szip'] = $order_info['payment_postcode']; + } + + if ($this->config->get('payment_firstdata_card_storage') == 1 && $this->customer->isLogged()) { + $data['card_storage'] = 1; + $data['stored_cards'] = $this->model_extension_payment_firstdata->getStoredCards(); + $data['new_hosted_id'] = sha1($this->customer->getId() . '-' . date("Y-m-d-H-i-s") . rand(10, 500)); + } else { + $data['card_storage'] = 0; + $data['stored_cards'] = array(); + } + + return $this->load->view('extension/payment/firstdata', $data); + } + + public function notify() { + $this->load->model('extension/payment/firstdata'); + + $this->load->model('checkout/order'); + + $this->load->language('extension/payment/firstdata'); + + $message = ''; + + if ($this->config->get('payment_firstdata_debug') == 1) { + $this->model_extension_payment_firstdata->logger(print_r($this->request->post, 1)); + } + + if (isset($this->request->post['txntype']) && isset($this->request->post['notification_hash']) && isset($this->request->post['oid'])) { + $local_hash = $this->model_extension_payment_firstdata->responseHash($this->request->post['chargetotal'], $this->request->post['currency'], $this->request->post['txndatetime'], $this->request->post['approval_code']); + + if ($local_hash == $this->request->post['notification_hash']) { + $order_id_parts = explode('T', $this->request->post['oid']); + + $order_id = str_replace("CON-","",$order_id_parts[0]); + + $order_info = $this->model_checkout_order->getOrder($order_id); + + if ($this->request->post['txntype'] == 'preauth' || $this->request->post['txntype'] == 'sale') { + if (isset($this->request->post['approval_code'])) { + $response_parts = explode(':', $this->request->post['approval_code']); + + $address_codes = array( + 'PPX' => $this->language->get('text_address_ppx'), + 'YYY' => $this->language->get('text_address_yyy'), + 'YNA' => $this->language->get('text_address_yna'), + 'NYZ' => $this->language->get('text_address_nyz'), + 'NNN' => $this->language->get('text_address_nnn'), + 'YPX' => $this->language->get('text_address_ypx'), + 'PYX' => $this->language->get('text_address_pyx'), + 'XXU' => $this->language->get('text_address_xxu') + ); + + $cvv_codes = array( + 'M' => $this->language->get('text_card_code_m'), + 'N' => $this->language->get('text_card_code_n'), + 'P' => $this->language->get('text_card_code_p'), + 'S' => $this->language->get('text_card_code_s'), + 'U' => $this->language->get('text_card_code_u'), + 'X' => $this->language->get('text_card_code_x'), + 'NONE' => $this->language->get('text_card_code_blank') + ); + + $card_types = array( + 'M' => $this->language->get('text_card_type_m'), + 'V' => $this->language->get('text_card_type_v'), + 'C' => $this->language->get('text_card_type_c'), + 'A' => $this->language->get('text_card_type_a'), + 'MA' => $this->language->get('text_card_type_ma'), + 'MAESTROUK' => $this->language->get('text_card_type_mauk') + ); + + if ($response_parts[0] == 'Y') { + if (isset($response_parts[3])) { + if (strlen($response_parts[3]) == 4) { + $address_pass = strtoupper(substr($response_parts[3], 0, 3)); + $cvv_pass = strtoupper(substr($response_parts[3], -1)); + + if (!array_key_exists($cvv_pass, $cvv_codes)) { + $cvv_pass = 'NONE'; + } + } else { + $address_pass = $response_parts[3]; + $cvv_pass = 'NONE'; + } + + $message .= $this->language->get('text_address_response') . $address_codes[$address_pass] . '<br />'; + $message .= $this->language->get('text_card_code_verify') . $cvv_codes[$cvv_pass] . '<br />'; + $message .= $this->language->get('text_response_code_full') . $this->request->post['approval_code'] . '<br />'; + $message .= $this->language->get('text_response_code') . $response_parts[1] . '<br />'; + + if (isset($this->request->post['cardnumber'])) { + $message .= $this->language->get('text_response_card') . $this->request->post['cardnumber'] . '<br />'; + } + + if (isset($this->request->post['processor_response_code'])) { + $message .= $this->language->get('text_response_proc_code') . $this->request->post['processor_response_code'] . '<br />'; + } + + if (isset($this->request->post['refnumber'])) { + $message .= $this->language->get('text_response_ref') . $this->request->post['refnumber'] . '<br />'; + } + + if (isset($this->request->post['paymentMethod'])) { + $message .= $this->language->get('text_response_card_type') . $card_types[strtoupper($this->request->post['paymentMethod'])] . '<br />'; + } + } + + if (isset($this->request->post['hosteddataid']) && $order_info['customer_id'] != 0) { + $this->model_extension_payment_firstdata->storeCard($this->request->post['hosteddataid'], $order_info['customer_id'], $this->request->post['expmonth'], $this->request->post['expyear'], $this->request->post['cardnumber']); + } + + $fd_order_id = $this->model_extension_payment_firstdata->addOrder($order_info, $this->request->post['oid'], $this->request->post['tdate']); + + if ($this->config->get('payment_firstdata_auto_settle') == 1) { + $this->model_extension_payment_firstdata->addTransaction($fd_order_id, 'payment', $order_info); + + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_firstdata_order_status_success_settled_id'), $message, false); + } else { + $this->model_extension_payment_firstdata->addTransaction($fd_order_id, 'auth'); + + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_firstdata_order_status_success_unsettled_id'), $message, false); + } + } else { + $message = $this->request->post['fail_reason'] . '<br />'; + $message .= $this->language->get('text_response_code_full') . $this->request->post['approval_code']; + + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_firstdata_order_status_decline_id'), $message); + } + } + } + + if ($this->request->post['txntype'] == 'void') { + if ($this->request->post['status'] == 'DECLINED') { + $fd_order = $this->model_extension_payment_firstdata->getOrder($order_id); + + $this->model_extension_payment_firstdata->updateVoidStatus($order_id, 1); + + $this->model_extension_payment_firstdata->addTransaction($fd_order['firstdata_order_id'], 'void'); + + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_firstdata_order_status_void_id'), $message, false); + } + } + + if ($this->request->post['txntype'] == 'postauth') { + if ($this->request->post['status'] == 'APPROVED') { + $fd_order = $this->model_extension_payment_firstdata->getOrder($order_id); + + $this->model_extension_payment_firstdata->updateCaptureStatus($order_id, 1); + + $this->model_extension_payment_firstdata->addTransaction($fd_order['firstdata_order_id'], 'payment', $order_info); + + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_firstdata_order_status_success_settled_id'), $message, false); + } + } + } else { + $this->model_extension_payment_firstdata->logger('Hash does not match! Received: ' . $this->request->post['notification_hash'] . ', calculated: ' . $local_hash); + } + } else { + $this->model_extension_payment_firstdata->logger('Data is missing from request . '); + } + } + + public function fail() { + $this->load->language('extension/payment/firstdata'); + + if (isset($this->request->post['fail_reason']) && !empty($this->request->post['fail_reason'])) { + $this->session->data['error'] = $this->request->post['fail_reason']; + } else { + $this->session->data['error'] = $this->language->get('error_failed'); + } + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/firstdata_remote.php b/public/catalog/controller/extension/payment/firstdata_remote.php new file mode 100644 index 0000000..1ad6352 --- /dev/null +++ b/public/catalog/controller/extension/payment/firstdata_remote.php @@ -0,0 +1,138 @@ +<?php +class ControllerExtensionPaymentFirstdataRemote extends Controller { + public function index() { + $this->load->language('extension/payment/firstdata_remote'); + $this->load->model('extension/payment/firstdata_remote'); + + if ($this->config->get('firstdata_remote_card_storage') == 1 && $this->customer->isLogged()) { + $data['card_storage'] = 1; + $data['stored_cards'] = $this->model_extension_payment_firstdata_remote->getStoredCards(); + } else { + $data['card_storage'] = 0; + $data['stored_cards'] = array(); + } + + $data['accepted_cards'] = $this->config->get('firstdata_remote_cards_accepted'); + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['year_expire'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['year_expire'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + return $this->load->view('extension/payment/firstdata_remote', $data); + } + + public function send() { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/firstdata_remote'); + $this->load->language('extension/payment/firstdata_remote'); + + $address_codes = array( + 'PPX' => $this->language->get('text_address_ppx'), + 'YYY' => $this->language->get('text_address_yyy'), + 'YNA' => $this->language->get('text_address_yna'), + 'NYZ' => $this->language->get('text_address_nyz'), + 'NNN' => $this->language->get('text_address_nnn'), + 'YPX' => $this->language->get('text_address_ypx'), + 'PYX' => $this->language->get('text_address_pyx'), + 'XXU' => $this->language->get('text_address_xxu') + ); + + $cvv_codes = array( + 'M' => $this->language->get('text_card_code_m'), + 'N' => $this->language->get('text_card_code_n'), + 'P' => $this->language->get('text_card_code_p'), + 'S' => $this->language->get('text_card_code_s'), + 'U' => $this->language->get('text_card_code_u'), + 'X' => $this->language->get('text_card_code_x'), + 'NONE' => $this->language->get('text_card_code_blank') + ); + + if (!isset($this->request->post['cc_choice']) || (isset($this->request->post['cc_choice']) && $this->request->post['cc_choice'] == 'new')) { + if ($this->request->post['cc_number'] == '') { + $json['error'] = $this->language->get('error_card_number'); + } + + if ($this->request->post['cc_name'] == '') { + $json['error'] = $this->language->get('error_card_name'); + } + } + + if (strlen($this->request->post['cc_cvv2']) != 3 && strlen($this->request->post['cc_cvv2']) != 4) { + $json['error'] = $this->language->get('error_card_cvv'); + } + + if (empty($json['error'])) { + $order_id = $this->session->data['order_id']; + $order_info = $this->model_checkout_order->getOrder($order_id); + + $capture_result = $this->model_extension_payment_firstdata_remote->capturePayment($this->request->post, $order_id); + + $message = ''; + + if (isset($capture_result['transaction_result']) && strtoupper($capture_result['transaction_result']) == 'APPROVED') { + $json['success'] = $this->url->link('checkout/success'); + + $message .= $this->language->get('text_result') . $capture_result['transaction_result'] . '<br />'; + $message .= $this->language->get('text_avs') . $address_codes[$capture_result['avs']] . ' (' . $capture_result['avs'] . ')<br />'; + + if (!empty($capture_result['ccv'])) { + $message .= $this->language->get('text_card_code_verify') . $cvv_codes[$capture_result['ccv']] . ' (' . $capture_result['ccv'] . ')<br />'; + } + + $message .= $this->language->get('text_approval_code') . $capture_result['approval_code'] . '<br />'; + $message .= $this->language->get('text_reference_number') . $capture_result['reference_number'] . '<br />'; + $message .= $this->language->get('text_card_brand') . $capture_result['brand'] . '<br />'; + $message .= $this->language->get('text_card_number_ref') . $capture_result['card_number_ref'] . '<br />'; + $message .= $this->language->get('text_response_code') . $capture_result['response_code'] . '<br />'; + + $fd_order_id = $this->model_extension_payment_firstdata_remote->addOrder($order_info, $capture_result); + + if ($this->config->get('firstdata_remote_auto_settle') == 1) { + $this->model_extension_payment_firstdata_remote->addTransaction($fd_order_id, 'payment', $order_info); + + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('firstdata_remote_order_status_success_settled_id'), $message, false); + } else { + $this->model_extension_payment_firstdata_remote->addTransaction($fd_order_id, 'auth'); + + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('firstdata_remote_order_status_success_unsettled_id'), $message, false); + } + } else { + if (isset($capture_result['error']) && !empty($capture_result['error'])) { + $json['error'] = $capture_result['error']; + } else { + $json['error'] = $this->language->get('error_failed'); + } + + if (isset($capture_result['fault']) && !empty($capture_result['fault'])) { + $message .= $this->language->get('text_fault') . $capture_result['fault'] . '<br />'; + } + + $message .= $this->language->get('text_result') . $capture_result['transaction_result'] . '<br />'; + $message .= $this->language->get('text_error') . $capture_result['error'] . '<br />'; + $message .= $this->language->get('text_card_brand') . $capture_result['brand'] . '<br />'; + $message .= $this->language->get('text_card_number_ref') . $capture_result['card_number_ref'] . '<br />'; + + $this->model_extension_payment_firstdata_remote->addHistory($order_id, $this->config->get('firstdata_remote_order_status_decline_id'), $message); + } + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/free_checkout.php b/public/catalog/controller/extension/payment/free_checkout.php new file mode 100644 index 0000000..f4674c4 --- /dev/null +++ b/public/catalog/controller/extension/payment/free_checkout.php @@ -0,0 +1,16 @@ +<?php +class ControllerExtensionPaymentFreeCheckout extends Controller { + public function index() { + $data['continue'] = $this->url->link('checkout/success'); + + return $this->load->view('extension/payment/free_checkout', $data); + } + + public function confirm() { + if ($this->session->data['payment_method']['code'] == 'free_checkout') { + $this->load->model('checkout/order'); + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_free_checkout_order_status_id')); + } + } +} diff --git a/public/catalog/controller/extension/payment/g2apay.php b/public/catalog/controller/extension/payment/g2apay.php new file mode 100644 index 0000000..fe66b9b --- /dev/null +++ b/public/catalog/controller/extension/payment/g2apay.php @@ -0,0 +1,189 @@ +<?php +class ControllerExtensionPaymentG2APay extends Controller { + public function index() { + $this->load->language('extension/payment/g2apay'); + + $data['action'] = $this->url->link('extension/payment/g2apay/checkout', '', true); + + return $this->load->view('extension/payment/g2apay', $data); + } + + public function checkout() { + $this->load->model('checkout/order'); + $this->load->model('account/order'); + $this->load->model('extension/payment/g2apay'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $order_data = array(); + + $this->load->model('setting/extension'); + + $totals = array(); + $taxes = $this->cart->getTaxes(); + $total = 0; + + // Because __call can not keep var references so we put them into an array. + $total_data = array( + 'totals' => &$totals, + 'taxes' => &$taxes, + 'total' => &$total + ); + + $i = 0; + + $results = $this->model_setting_extension->getExtensions('total'); + + foreach ($results as $result) { + if ($this->config->get('total_' . $result['code'] . '_status')) { + $this->load->model('extension/total/' . $result['code']); + + // We have to put the totals in an array so that they pass by reference. + $this->{'model_extension_total_' . $result['code']}->getTotal($total_data); + + if (isset($order_data['totals'][$i])) { + if (strstr(strtolower($order_data['totals'][$i]['code']), 'total') === false) { + $item = new stdClass(); + $item->sku = $order_data['totals'][$i]['code']; + $item->name = $order_data['totals'][$i]['title']; + $item->amount = number_format($order_data['totals'][$i]['value'], 2); + $item->qty = 1; + $item->id = $order_data['totals'][$i]['code']; + $item->price = $order_data['totals'][$i]['value']; + $item->url = $this->url->link('common/home', '', true); + $items[] = $item; + } + + $i++; + } + } + } + + $ordered_products = $this->model_account_order->getOrderProducts($this->session->data['order_id']); + + foreach ($ordered_products as $product) { + $item = new stdClass(); + $item->sku = $product['product_id']; + $item->name = $product['name']; + $item->amount = $product['price'] * $product['quantity']; + $item->qty = $product['quantity']; + $item->id = $product['product_id']; + $item->price = $product['price']; + $item->url = $this->url->link('product/product', 'product_id=' . $product['product_id'], true); + $items[] = $item; + } + + if ($this->config->get('payment_g2apay_environment') == 1) { + $url = 'https://checkout.pay.g2a.com/index/createQuote'; + } else { + $url = 'https://checkout.test.pay.g2a.com/index/createQuote'; + } + + $order_total = number_format($order_info['total'], 2); + + $string = $this->session->data['order_id'] . $order_total . $order_info['currency_code'] . html_entity_decode($this->config->get('payment_g2apay_secret')); + + $fields = array( + 'api_hash' => $this->config->get('payment_g2apay_api_hash'), + 'hash' => hash('sha256', $string), + 'order_id' => $this->session->data['order_id'], + 'amount' => $order_total, + 'currency' => $order_info['currency_code'], + 'email' => $order_info['email'], + 'url_failure' => $this->url->link('checkout/failure'), + 'url_ok' => $this->url->link('extension/payment/g2apay/success'), + 'items' => json_encode($items) + ); + + $response_data = $this->model_extension_payment_g2apay->sendCurl($url, $fields); + + $this->model_extension_payment_g2apay->logger($order_total); + $this->model_extension_payment_g2apay->logger($items); + $this->model_extension_payment_g2apay->logger($fields); + + if ($response_data === false) { + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + + if (strtolower($response_data->status) != 'ok') { + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + + $this->model_extension_payment_g2apay->addG2aOrder($order_info); + + if ($this->config->get('payment_g2apay_environment') == 1) { + $this->response->redirect('https://checkout.pay.g2a.com/index/gateway?token=' . $response_data->token); + } else { + $this->response->redirect('https://checkout.test.pay.g2a.com/index/gateway?token=' . $response_data->token); + } + } + + public function success() { + $order_id = $this->session->data['order_id']; + + if (isset($this->request->post['transaction_id'])) { + $g2apay_transaction_id = $this->request->post['transaction_id']; + } elseif (isset($this->request->get['transaction_id'])) { + $g2apay_transaction_id = $this->request->get['transaction_id']; + } else { + $g2apay_transaction_id = ''; + } + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($order_id); + + if ($order_info) { + $this->load->model('extension/payment/g2apay'); + + $g2apay_order_info = $this->model_extension_payment_g2apay->getG2aOrder($order_id); + + $this->model_extension_payment_g2apay->updateOrder($g2apay_order_info['g2apay_order_id'], $g2apay_transaction_id, 'payment', $order_info); + + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_g2apay_order_status_id')); + } + + $this->response->redirect($this->url->link('checkout/success')); + } + + public function ipn() { + $this->load->model('extension/payment/g2apay'); + $this->model_extension_payment_g2apay->logger('ipn'); + + if (isset($this->request->get['token']) && hash_equals($this->config->get('payment_g2apay_secret_token'), $this->request->get['token'])) { + $this->model_extension_payment_g2apay->logger('token success'); + + if (isset($this->request->post['userOrderId'])) { + $g2apay_order = $this->model_extension_payment_g2apay->getG2aOrder($this->request->post['userOrderId']); + + $string = $g2apay_order['g2apay_transaction_id'] . $g2apay_order['order_id'] . round($g2apay_order['total'], 2) . html_entity_decode($this->config->get('payment_g2apay_secret')); + $hash = hash('sha256', $string); + if($hash != $this->request->post['hash']){ + $this->model_extension_payment_g2apay->logger('Hashes do not match, possible tampering!'); + return; + } + + switch ($this->request->post['status']) { + case 'complete': + $order_status_id = $this->config->get('payment_g2apay_complete_status_id'); + break; + case 'rejected': + $order_status_id = $this->config->get('payment_g2apay_rejected_status_id'); + break; + case 'canceled': + $order_status_id = $this->config->get('payment_g2apay_cancelled_status_id'); + break; + case 'partial_refunded': + $order_status_id = $this->config->get('payment_g2apay_partially_refunded_status_id'); + break; + case 'refunded': + $order_status_id = $this->config->get('payment_g2apay_refunded_status_id'); + break; + } + + $this->load->model('checkout/order'); + $this->model_checkout_order->addOrderHistory($this->request->post['userOrderId'], $order_status_id); + } + } + } +} diff --git a/public/catalog/controller/extension/payment/globalpay.php b/public/catalog/controller/extension/payment/globalpay.php new file mode 100644 index 0000000..5e8989c --- /dev/null +++ b/public/catalog/controller/extension/payment/globalpay.php @@ -0,0 +1,252 @@ +<?php +class ControllerExtensionPaymentGlobalpay extends Controller { + public function index() { + $this->load->language('extension/payment/globalpay'); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if ($this->config->get('payment_globalpay_live_demo') == 1) { + $data['action'] = $this->config->get('payment_globalpay_live_url'); + } else { + $data['action'] = $this->config->get('payment_globalpay_demo_url'); + } + + if ($this->config->get('payment_globalpay_card_select') == 1) { + $card_types = array( + 'visa' => $this->language->get('text_card_visa'), + 'mc' => $this->language->get('text_card_mc'), + 'amex' => $this->language->get('text_card_amex'), + 'switch' => $this->language->get('text_card_switch'), + 'laser' => $this->language->get('text_card_laser'), + 'diners' => $this->language->get('text_card_diners'), + ); + + $data['cards'] = array(); + + $accounts = $this->config->get('payment_globalpay_account'); + + foreach ($accounts as $card => $account) { + if (isset($account['enabled']) && $account['enabled'] == 1) { + $data['cards'][] = array( + 'type' => $card_types[$card], + 'account' => (isset($account['default']) && $account['default'] == 1 ? $this->config->get('payment_globalpay_merchant_id') : $account['merchant_id']), + ); + } + } + + $data['card_select'] = true; + } else { + $data['card_select'] = false; + } + + if ($this->config->get('payment_globalpay_auto_settle') == 0) { + $data['settle'] = 0; + } elseif ($this->config->get('payment_globalpay_auto_settle') == 1) { + $data['settle'] = 1; + } elseif ($this->config->get('payment_globalpay_auto_settle') == 2) { + $data['settle'] = 'MULTI'; + } + + $data['tss'] = (int)$this->config->get('payment_globalpay_tss_check'); + $data['merchant_id'] = $this->config->get('payment_globalpay_merchant_id'); + + $data['timestamp'] = strftime("%Y%m%d%H%M%S"); + $data['order_id'] = $this->session->data['order_id'] . 'T' . $data['timestamp'] . mt_rand(1, 999); + + $data['amount'] = round($this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false)*100); + $data['currency'] = $order_info['currency_code']; + + $tmp = $data['timestamp'] . '.' . $data['merchant_id'] . '.' . $data['order_id'] . '.' . $data['amount'] . '.' . $data['currency']; + $hash = sha1($tmp); + $tmp = $hash . '.' . $this->config->get('payment_globalpay_secret'); + $data['hash'] = sha1($tmp); + + $data['billing_code'] = filter_var(str_replace('-', '', $order_info['payment_postcode']), FILTER_SANITIZE_NUMBER_INT) . '|' . filter_var(str_replace('-', '', $order_info['payment_address_1']), FILTER_SANITIZE_NUMBER_INT); + $data['payment_country'] = $order_info['payment_iso_code_2']; + + if ($this->cart->hasShipping()) { + $data['shipping_code'] = filter_var(str_replace('-', '', $order_info['shipping_postcode']), FILTER_SANITIZE_NUMBER_INT) . '|' . filter_var(str_replace('-', '', $order_info['shipping_address_1']), FILTER_SANITIZE_NUMBER_INT); + $data['shipping_country'] = $order_info['shipping_iso_code_2']; + } else { + $data['shipping_code'] = filter_var(str_replace('-', '', $order_info['payment_postcode']), FILTER_SANITIZE_NUMBER_INT) . '|' . filter_var(str_replace('-', '', $order_info['payment_address_1']), FILTER_SANITIZE_NUMBER_INT); + $data['shipping_country'] = $order_info['payment_iso_code_2']; + } + + $data['response_url'] = HTTPS_SERVER . 'index.php?route=extension/payment/globalpay/notify'; + + return $this->load->view('extension/payment/globalpay', $data); + } + + public function notify() { + $this->load->model('extension/payment/globalpay'); + + $this->model_extension_payment_globalpay->logger(print_r($this->request->post, 1)); + + $this->load->language('extension/payment/globalpay'); + + $hash = sha1($this->request->post['TIMESTAMP'] . '.' . $this->config->get('payment_globalpay_merchant_id') . '.' . $this->request->post['ORDER_ID'] . '.' . $this->request->post['RESULT'] . '.' . $this->request->post['MESSAGE'] . '.' . $this->request->post['PASREF'] . '.' . $this->request->post['AUTHCODE']); + $tmp = $hash . '.' . $this->config->get('payment_globalpay_secret'); + $hash = sha1($tmp); + + //Check to see if hashes match or not + if ($hash != $this->request->post['SHA1HASH']) { + $data['text_response'] = $this->language->get('text_hash_failed'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } else { + $this->load->model('checkout/order'); + + $order_id_parts = explode('T', $this->request->post['ORDER_ID']); + $order_id = (int)$order_id_parts[0]; + + $order_info = $this->model_checkout_order->getOrder($order_id); + + $auto_settle = (int)$this->config->get('payment_globalpay_auto_settle'); + $tss = (int)$this->config->get('payment_globalpay_tss_check'); + + $message = '<strong>' . $this->language->get('text_result') . ':</strong> ' . $this->request->post['RESULT']; + $message .= '<br /><strong>' . $this->language->get('text_message') . ':</strong> ' . $this->request->post['MESSAGE']; + + if (isset($this->request->post['ORDER_ID'])) { + $message .= '<br /><strong>' . $this->language->get('text_order_ref') . ':</strong> ' . $this->request->post['ORDER_ID']; + } + + if (isset($this->request->post['CVNRESULT'])) { + $message .= '<br /><strong>' . $this->language->get('text_cvn_result') . ':</strong> ' . $this->request->post['CVNRESULT']; + } + + if (isset($this->request->post['AVSPOSTCODERESULT'])) { + $message .= '<br /><strong>' . $this->language->get('text_avs_postcode') . ':</strong> ' . $this->request->post['AVSPOSTCODERESULT']; + } + + if (isset($this->request->post['AVSADDRESSRESULT'])) { + $message .= '<br /><strong>' . $this->language->get('text_avs_address') . ':</strong> ' . $this->request->post['AVSADDRESSRESULT']; + } + + //3D Secure message + if (isset($this->request->post['ECI']) && isset($this->request->post['CAVV']) && isset($this->request->post['XID'])) { + $eci = $this->request->post['ECI']; + + if (($this->request->post['ECI'] == 6 || $this->request->post['ECI'] == 1) && empty($this->request->post['CAVV']) && empty($this->request->post['XID'])) { + $scenario_id = 1; + } + + if (($this->request->post['ECI'] == 5 || $this->request->post['ECI'] == 0) && !empty($this->request->post['CAVV']) && !empty($this->request->post['XID'])) { + $scenario_id = 5; + } + + if (($this->request->post['ECI'] == 6 || $this->request->post['ECI'] == 1) && !empty($this->request->post['CAVV']) && !empty($this->request->post['XID'])) { + $scenario_id = 6; + } + + if (isset($scenario_id)) { + $scenario_message = $this->language->get('text_3d_s' . $scenario_id); + } else { + if (isset($this->request->post['CARDTYPE'])) { + if ($this->request->post['CARDTYPE'] == 'VISA') { + $eci = 7; + } else { + $eci = 2; + } + } + + $scenario_message = $this->language->get('text_3d_liability'); + } + + $message .= '<br /><strong>' . $this->language->get('text_eci') . ':</strong> (' . $eci . ') ' . $scenario_message; + } + + if ($tss == 1 && isset($this->request->post['TSS'])) { + $message .= '<br /><strong>' . $this->language->get('text_tss') . ':</strong> ' . $this->request->post['TSS']; + } + + if (isset($this->request->post['TIMESTAMP'])) { + $message .= '<br /><strong>' . $this->language->get('text_timestamp') . ':</strong> ' . $this->request->post['TIMESTAMP']; + } + + if (isset($this->request->post['CARDDIGITS'])) { + $message .= '<br /><strong>' . $this->language->get('text_card_digits') . ':</strong> ' . $this->request->post['CARDDIGITS']; + } + + if (isset($this->request->post['CARDTYPE'])) { + $message .= '<br /><strong>' . $this->language->get('text_card_type') . ':</strong> ' . $this->request->post['CARDTYPE']; + } + + if (isset($this->request->post['EXPDATE'])) { + $message .= '<br /><strong>' . $this->language->get('text_card_exp') . ':</strong> ' . $this->request->post['EXPDATE']; + } + + if (isset($this->request->post['CARDNAME'])) { + $message .= '<br /><strong>' . $this->language->get('text_card_name') . ':</strong> ' . $this->request->post['CARDNAME']; + } + + if (isset($this->request->post['DCCAUTHCARDHOLDERAMOUNT']) && isset($this->request->post['DCCAUTHRATE'])) { + $message .= '<br /><strong>DCCAUTHCARDHOLDERAMOUNT:</strong> ' . $this->request->post['DCCAUTHCARDHOLDERAMOUNT']; + $message .= '<br /><strong>DCCAUTHRATE:</strong> ' . $this->request->post['DCCAUTHRATE']; + $message .= '<br /><strong>DCCAUTHCARDHOLDERCURRENCY:</strong> ' . $this->request->post['DCCAUTHCARDHOLDERCURRENCY']; + $message .= '<br /><strong>DCCAUTHMERCHANTCURRENCY:</strong> ' . $this->request->post['DCCAUTHMERCHANTCURRENCY']; + $message .= '<br /><strong>DCCAUTHMERCHANTAMOUNT:</strong> ' . $this->request->post['DCCAUTHMERCHANTAMOUNT']; + $message .= '<br /><strong>DCCCCP:</strong> ' . $this->request->post['DCCCCP']; + $message .= '<br /><strong>DCCRATE:</strong> ' . $this->request->post['DCCRATE']; + $message .= '<br /><strong>DCCMARGINRATEPERCENTAGE:</strong> ' . $this->request->post['DCCMARGINRATEPERCENTAGE']; + $message .= '<br /><strong>DCCEXCHANGERATESOURCENAME:</strong> ' . $this->request->post['DCCEXCHANGERATESOURCENAME']; + $message .= '<br /><strong>DCCCOMMISSIONPERCENTAGE:</strong> ' . $this->request->post['DCCCOMMISSIONPERCENTAGE']; + $message .= '<br /><strong>DCCEXCHANGERATESOURCETIMESTAMP:</strong> ' . $this->request->post['DCCEXCHANGERATESOURCETIMESTAMP']; + $message .= '<br /><strong>DCCCHOICE:</strong> ' . $this->request->post['DCCCHOICE']; + } + + if ($this->request->post['RESULT'] == "00") { + $globalpay_order_id = $this->model_extension_payment_globalpay->addOrder($order_info, $this->request->post['PASREF'], $this->request->post['AUTHCODE'], $this->request->post['ACCOUNT'], $this->request->post['ORDER_ID']); + + if ($auto_settle == 1) { + $this->model_extension_payment_globalpay->addTransaction($globalpay_order_id, 'payment', $order_info); + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('globalpay_order_status_success_settled_id'), $message, false); + } else { + $this->model_extension_payment_globalpay->addTransaction($globalpay_order_id, 'auth', 0.00); + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_globalpay_order_status_success_unsettled_id'), $message, false); + } + + $data['text_response'] = $this->language->get('text_success'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/success', '', true)); + } elseif ($this->request->post['RESULT'] == "101") { + // Decline + $this->model_extension_payment_globalpay->addHistory($order_id, $this->config->get('payment_globalpay_order_status_decline_id'), $message); + $data['text_response'] = $this->language->get('text_decline'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } elseif ($this->request->post['RESULT'] == "102") { + // Referal B + $this->model_extension_payment_globalpay->addHistory($order_id, $this->config->get('payment_globalpay_order_status_decline_pending_id'), $message); + $data['text_response'] = $this->language->get('text_decline'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } elseif ($this->request->post['RESULT'] == "103") { + // Referal A + $this->model_extension_payment_globalpay->addHistory($order_id, $this->config->get('payment_globalpay_order_status_decline_stolen_id'), $message); + $data['text_response'] = $this->language->get('text_decline'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } elseif ($this->request->post['RESULT'] == "200") { + // Error Connecting to Bank + $this->model_extension_payment_globalpay->addHistory($order_id, $this->config->get('payment_globalpay_order_status_decline_bank_id'), $message); + $data['text_response'] = $this->language->get('text_bank_error'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } elseif ($this->request->post['RESULT'] == "204") { + // Error Connecting to Bank + $this->model_extension_payment_globalpay->addHistory($order_id, $this->config->get('payment_globalpay_order_status_decline_bank_id'), $message); + $data['text_response'] = $this->language->get('text_bank_error'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } elseif ($this->request->post['RESULT'] == "205") { + // Comms Error + $this->model_extension_payment_globalpay->addHistory($order_id, $this->config->get('payment_globalpay_order_status_decline_bank_id'), $message); + $data['text_response'] = $this->language->get('text_bank_error'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } else { + // Other error + $this->model_extension_payment_globalpay->addHistory($order_id, $this->config->get('payment_globalpay_order_status_decline_id'), $message); + $data['text_response'] = $this->language->get('text_generic_error'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } + } + + $this->response->setOutput($this->load->view('extension/payment/globalpay_response', $data)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/globalpay_remote.php b/public/catalog/controller/extension/payment/globalpay_remote.php new file mode 100644 index 0000000..fb0afb7 --- /dev/null +++ b/public/catalog/controller/extension/payment/globalpay_remote.php @@ -0,0 +1,335 @@ +<?php +class ControllerExtensionPaymentGlobalpayRemote extends Controller { + public function index() { + $this->load->language('extension/payment/globalpay_remote'); + + $accounts = $this->config->get('payment_globalpay_remote_account'); + + $card_types = array( + 'visa' => $this->language->get('text_card_visa'), + 'mc' => $this->language->get('text_card_mc'), + 'amex' => $this->language->get('text_card_amex'), + 'switch' => $this->language->get('text_card_switch'), + 'laser' => $this->language->get('text_card_laser'), + 'diners' => $this->language->get('text_card_diners'), + ); + + $data['cards'] = array(); + + foreach ($accounts as $card => $account) { + if (isset($account['enabled']) && $account['enabled'] == 1) { + $data['cards'][] = array( + 'code' => $card, + 'text' => $card_types[$card], + ); + } + } + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['year_expire'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['year_expire'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + return $this->load->view('extension/payment/globalpay_remote', $data); + } + + public function send() { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/globalpay_remote'); + + $this->load->language('extension/payment/globalpay_remote'); + + if ($this->request->post['cc_number'] == '') { + $json['error'] = $this->language->get('error_card_number'); + } + + if ($this->request->post['cc_name'] == '') { + $json['error'] = $this->language->get('error_card_name'); + } + + if (strlen($this->request->post['cc_cvv2']) != 3 && strlen($this->request->post['cc_cvv2']) != 4) { + $json['error'] = $this->language->get('error_card_cvv'); + } + + if (isset($json['error'])) { + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + die(); + } + + $order_id = $this->session->data['order_id']; + + $order_ref = $order_id . 'T' . strftime("%Y%m%d%H%M%S") . mt_rand(1, 999); + + $order_info = $this->model_checkout_order->getOrder($order_id); + + $amount = round($this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false) * 100); + $currency = $order_info['currency_code']; + + $accounts = $this->config->get('payment_globalpay_remote_account'); + + if (isset($accounts[$this->request->post['cc_type']]['default']) && $accounts[$this->request->post['cc_type']]['default'] == 1) { + $account = $this->config->get('payment_globalpay_remote_merchant_id'); + } else { + $account = $accounts[$this->request->post['cc_type']]['merchant_id']; + } + + $eci_ref = ''; + $eci = ''; + $cavv = ''; + $xid = ''; + + if ($this->config->get('payment_globalpay_remote_3d') == 1) { + if ($this->request->post['cc_type'] == 'visa' || $this->request->post['cc_type'] == 'mc' || $this->request->post['cc_type'] == 'amex') { + $verify_3ds = $this->model_extension_payment_globalpay_remote->checkEnrollment($account, $amount, $currency, $order_ref); + + $this->model_extension_payment_globalpay_remote->logger('Verify 3DS result:\r\n' . print_r($verify_3ds, 1)); + + // Proceed to 3D secure + if (isset($verify_3ds->result) && $verify_3ds->result == '00') { + $enc_data = array( + 'account' => $account, + 'amount' => $amount, + 'currency' => $currency, + 'order_id' => $order_id, + 'order_ref' => $order_ref, + 'cc_number' => $this->request->post['cc_number'], + 'cc_expire' => $this->request->post['cc_expire_date_month'] . $this->request->post['cc_expire_date_year'], + 'cc_name' => $this->request->post['cc_name'], + 'cc_type' => $this->request->post['cc_type'], + 'cc_cvv2' => $this->request->post['cc_cvv2'], + 'cc_issue' => $this->request->post['cc_issue'] + ); + + $md = $this->encryption->encrypt($this->config->get('config_encryption'), json_encode($enc_data)); + + $json = array(); + $json['ACSURL'] = (string)$verify_3ds->url; + $json['MD'] = $md; + $json['PaReq'] = (string)$verify_3ds->pareq; + $json['TermUrl'] = $this->url->link('extension/payment/globalpay_remote/acsReturn', '', true); + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + $this->response->output(); + die(); + } + + // Cardholder Not Enrolled. Shift in liability. ECI = 6 + if (isset($verify_3ds->result) && $verify_3ds->result == '110' && isset($verify_3ds->enrolled) && $verify_3ds->enrolled == 'N') { + $eci_ref = 1; + $xid = ''; + $cavv = ''; + if ($this->request->post['cc_type'] == 'mc') { + $eci = 1; + } else { + $eci = 6; + } + } + + // Unable to Verify Enrollment. No shift in liability. ECI = 7 + if (isset($verify_3ds->result) && $verify_3ds->result == '110' && isset($verify_3ds->enrolled) && $verify_3ds->enrolled == 'U') { + if ($this->config->get('payment_globalpay_remote_liability') != 1) { + $this->load->language('extension/payment/globalpay_remote'); + + $json['error'] = $this->language->get('error_3d_unable'); + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + $this->response->output(); + die(); + } else { + $eci_ref = 2; + $xid = ''; + $cavv = ''; + if ($this->request->post['cc_type'] == 'mc') { + $eci = 0; + } else { + $eci = 7; + } + } + } + + // Invalid response from Enrollment Server. No shift in liability. ECI = 7 + if (isset($verify_3ds->result) && $verify_3ds->result >= 500 && $verify_3ds->result < 600) { + if ($this->config->get('payment_globalpay_remote_liability') != 1) { + $this->load->language('extension/payment/globalpay_remote'); + + $json['error'] = (string)$verify_3ds->message; + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + $this->response->output(); + die(); + } else { + $eci_ref = 3; + if ($this->request->post['cc_type'] == 'mc') { + $eci = 0; + } else { + $eci = 7; + } + } + } + } + } + + $capture_result = $this->model_extension_payment_globalpay_remote->capturePayment( + $account, + $amount, + $currency, + $order_id, + $order_ref, + $this->request->post['cc_number'], + $this->request->post['cc_expire_date_month'] . $this->request->post['cc_expire_date_year'], + $this->request->post['cc_name'], + $this->request->post['cc_type'], + $this->request->post['cc_cvv2'], + $this->request->post['cc_issue'], + $eci_ref, + $eci, + $cavv, + $xid + ); + + $this->model_extension_payment_globalpay_remote->logger('Capture result:\r\n' . print_r($capture_result, 1)); + + if ($capture_result->result != '00') { + $json['error'] = (string)$capture_result->message . ' (' . (int)$capture_result->result . ')'; + } else { + $json['success'] = $this->url->link('checkout/success'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function acsReturn() { + if (isset($this->session->data['order_id'])) { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/globalpay_remote'); + + $post = $this->request->post; + + $md = json_decode($this->encryption->decrypt($this->config->get('config_encryption'), $post['MD']), true); + + $signature_result = $this->model_extension_payment_globalpay_remote->enrollmentSignature($md['account'], $md['amount'], $md['currency'], $md['order_ref'], $md['cc_number'], $md['cc_expire'], $md['cc_type'], $md['cc_name'], $post['PaRes']); + + $this->model_extension_payment_globalpay_remote->logger('Signature result:\r\n' . print_r($signature_result, 1)); + + if ($signature_result->result == '00' && (strtoupper($signature_result->threedsecure->status) == 'Y' || strtoupper($signature_result->threedsecure->status) == 'A')) { + if (strtoupper($signature_result->threedsecure->status) == 'Y') { + $eci_ref = 5; + } else { + $eci_ref = 6; + } + + $eci = (string)$signature_result->threedsecure->eci; + $cavv = (string)$signature_result->threedsecure->cavv; + $xid = (string)$signature_result->threedsecure->xid; + } else { + if ($md['cc_type'] == 'mc') { + $eci = 0; + } else { + $eci = 7; + } + + // Enrolled but invalid response from ACS. No shift in liability. ECI = 7 + if ($signature_result->result == '110' && strtoupper($signature_result->threedsecure->status) == 'Y') { + $eci_ref = 4; + $cavv = (string)$signature_result->threedsecure->cavv; + $xid = (string)$signature_result->threedsecure->xid; + } + + // Incorrect password entered. No shift in liability. ECI = 7 + if ($signature_result->result == '00' && strtoupper($signature_result->threedsecure->status) == 'N') { + $eci_ref = 7; + $xid = (string)$signature_result->threedsecure->xid; + $cavv = ''; + } + + // Authentication Unavailable. No shift in liability. ECI = 7 + if ($signature_result->result == '00' && strtoupper($signature_result->threedsecure->status) == 'U') { + $eci_ref = 8; + $xid = (string)$signature_result->threedsecure->xid; + $cavv = ''; + } + + // Invalid response from ACS. No shift in liability. ECI = 7 + if (isset($signature_result->result) && $signature_result->result >= 500 && $signature_result->result < 600) { + $eci_ref = 9; + $xid = ''; + $cavv = ''; + } + + if ($this->config->get('payment_globalpay_remote_liability') != 1) { + // this is the check for liability shift - if the merchant does not want to accept, redirect to checkout with message + $this->load->language('extension/payment/globalpay_remote'); + + $message = $this->language->get('error_3d_unsuccessful'); + $message .= '<br /><strong>' . $this->language->get('text_eci') . ':</strong> (' . $eci . ') ' . $this->language->get('text_3d_s' . (int)$eci_ref); + $message .= '<br /><strong>' . $this->language->get('text_timestamp') . ':</strong> ' . (string)strftime("%Y%m%d%H%M%S"); + $message .= '<br /><strong>' . $this->language->get('text_order_ref') . ':</strong> ' . (string)$md['order_ref']; + + if ($this->config->get('payment_globalpay_remote_card_data_status') == 1) { + $message .= '<br /><strong>' . $this->language->get('entry_cc_type') . ':</strong> ' . (string)$md['cc_type']; + $message .= '<br /><strong>' . $this->language->get('text_last_digits') . ':</strong> ' . (string)substr($md['cc_number'], -4); + $message .= '<br /><strong>' . $this->language->get('entry_cc_expire_date') . ':</strong> ' . (string)$md['cc_expire']; + $message .= '<br /><strong>' . $this->language->get('entry_cc_name') . ':</strong> ' . (string)$md['cc_name']; + } + + $this->model_extension_payment_globalpay_remote->addHistory($md['order_id'], $this->config->get('payment_globalpay_remote_order_status_decline_id'), $message); + + $this->session->data['error'] = $this->language->get('error_3d_unsuccessful'); + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + die(); + } + } + + $capture_result = $this->model_extension_payment_globalpay_remote->capturePayment( + $md['account'], + $md['amount'], + $md['currency'], + $md['order_id'], + $md['order_ref'], + $md['cc_number'], + $md['cc_expire'], + $md['cc_name'], + $md['cc_type'], + $md['cc_cvv2'], + $md['cc_issue'], + $eci_ref, + $eci, + $cavv, + $xid + ); + + $this->model_extension_payment_globalpay_remote->logger('Capture result:\r\n' . print_r($capture_result, 1)); + + if ($capture_result->result != '00') { + $this->session->data['error'] = (string)$capture_result->message . ' (' . (int)$capture_result->result . ')'; + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } else { + $this->response->redirect($this->url->link('checkout/success')); + } + } else { + $this->response->redirect($this->url->link('account/login', '', true)); + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/klarna_account.php b/public/catalog/controller/extension/payment/klarna_account.php new file mode 100644 index 0000000..f6400ac --- /dev/null +++ b/public/catalog/controller/extension/payment/klarna_account.php @@ -0,0 +1,687 @@ +<?php +class ControllerExtensionPaymentKlarnaAccount extends Controller { + public function index() { + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if ($order_info) { + $this->load->language('extension/payment/klarna_account'); + + $data['days'] = array(); + + for ($i = 1; $i <= 31; $i++) { + $data['days'][] = array( + 'text' => sprintf('%02d', $i), + 'value' => $i + ); + } + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => sprintf('%02d', $i), + 'value' => $i + ); + } + + $data['years'] = array(); + + for ($i = date('Y'); $i >= 1900; $i--) { + $data['years'][] = array( + 'text' => $i, + 'value' => $i + ); + } + + // Store Taxes to send to Klarna + $totals = array(); + $taxes = $this->cart->getTaxes(); + $total = 0; + + // Because __call can not keep var references so we put them into an array. + $total_data = array( + 'totals' => &$totals, + 'taxes' => &$taxes, + 'total' => &$total + ); + + $this->load->model('setting/extension'); + + $sort_order = array(); + + $results = $this->model_setting_extension->getExtensions('total'); + + foreach ($results as $key => $value) { + $sort_order[$key] = $this->config->get('total_' . $value['code'] . '_sort_order'); + } + + array_multisort($sort_order, SORT_ASC, $results); + + $klarna_tax = array(); + + foreach ($results as $result) { + if ($this->config->get('total_' . $result['code'] . '_status')) { + $this->load->model('extension/total/' . $result['code']); + + $taxes = array(); + + // We have to put the totals in an array so that they pass by reference. + $this->{'model_extension_total_' . $result['code']}->getTotal($total_data); + + $amount = 0; + + foreach ($taxes as $tax_id => $value) { + $amount += $value; + } + + $klarna_tax[$result['code']] = $amount; + } + } + + foreach ($totals as $key => $value) { + $sort_order[$key] = $value['sort_order']; + + if (isset($klarna_tax[$value['code']])) { + if ($klarna_tax[$value['code']]) { + $totals[$key]['tax_rate'] = abs($klarna_tax[$value['code']] / $value['value'] * 100); + } else { + $totals[$key]['tax_rate'] = 0; + } + } else { + $totals[$key]['tax_rate'] = '0'; + } + } + + $this->session->data['klarna'][$this->session->data['order_id']] = $totals; + + // Order must have identical shipping and billing address or have no shipping address at all + if ($this->cart->hasShipping() && !($order_info['payment_firstname'] == $order_info['shipping_firstname'] && $order_info['payment_lastname'] == $order_info['shipping_lastname'] && $order_info['payment_address_1'] == $order_info['shipping_address_1'] && $order_info['payment_address_2'] == $order_info['shipping_address_2'] && $order_info['payment_postcode'] == $order_info['shipping_postcode'] && $order_info['payment_city'] == $order_info['shipping_city'] && $order_info['payment_zone_id'] == $order_info['shipping_zone_id'] && $order_info['payment_zone_code'] == $order_info['shipping_zone_code'] && $order_info['payment_country_id'] == $order_info['shipping_country_id'] && $order_info['payment_country'] == $order_info['shipping_country'] && $order_info['payment_iso_code_3'] == $order_info['shipping_iso_code_3'])) { + $data['error_warning'] = $this->language->get('error_address_match'); + } else { + $data['error_warning'] = ''; + } + + $klarna_account = $this->config->get('payment_klarna_account'); + + $data['merchant'] = $klarna_account[$order_info['payment_iso_code_3']]['merchant']; + $data['phone_number'] = $order_info['telephone']; + + $country_to_currency = array( + 'NOR' => 'NOK', + 'SWE' => 'SEK', + 'FIN' => 'EUR', + 'DNK' => 'DKK', + 'DEU' => 'EUR', + 'NLD' => 'EUR' + ); + + if ($order_info['payment_iso_code_3'] == 'DEU' || $order_info['payment_iso_code_3'] == 'NLD') { + $address = $this->splitAddress($order_info['payment_address_1']); + + $data['street'] = $address[0]; + $data['street_number'] = $address[1]; + $data['street_extension'] = $address[2]; + + if ($order_info['payment_iso_code_3'] == 'DEU') { + $data['street_number'] = trim($address[1] . ' ' . $address[2]); + } + } else { + $data['street'] = ''; + $data['street_number'] = ''; + $data['street_extension'] = ''; + } + + $data['company'] = $order_info['payment_company']; + $data['iso_code_2'] = $order_info['payment_iso_code_2']; + $data['iso_code_3'] = $order_info['payment_iso_code_3']; + + $payment_option = array(); + + $total = $this->currency->format($order_info['total'], $country_to_currency[$order_info['payment_iso_code_3']], '', false); + + $pclasses = $this->config->get('klarna_account_pclasses'); + + if (isset($pclasses[$order_info['payment_iso_code_3']])) { + $pclasses = $pclasses[$order_info['payment_iso_code_3']]; + } else { + $pclasses = array(); + } + + foreach ($pclasses as $pclass) { + // 0 - Campaign + // 1 - Account + // 2 - Special + // 3 - Fixed + if (!in_array($pclass['type'], array(0, 1, 3))) { + continue; + } + + if ($pclass['type'] == 2) { + $monthly_cost = -1; + } else { + if ($total < $pclass['minamount']) { + continue; + } + + if ($pclass['type'] == 3) { + continue; + } else { + $sum = $total; + + $lowest_payment = $this->getLowestPaymentAccount($order_info['payment_iso_code_3']); + $monthly_cost = 0; + + $monthly_fee = $pclass['invoicefee']; + $start_fee = $pclass['startfee']; + + $sum += $start_fee; + + $base = ($pclass['type'] == 1); + + $minimum_payment = ($pclass['type'] === 1) ? $this->getLowestPaymentAccount($order_info['payment_iso_code_3']) : 0; + + if ($pclass['months'] == 0) { + $payment = $sum; + } elseif ($pclass['interestrate'] == 0) { + $payment = $sum / $pclass['months']; + } else { + $interest = $pclass['interestrate'] / (100.0 * 12); + $payment = $sum * $interest / (1 - pow((1 + $interest), -$pclass['months'])); + } + + $payment += $monthly_fee; + + $balance = $sum; + $pay_data = array(); + + $months = $pclass['months']; + + while (($months != 0) && ($balance > 0.01)) { + $interest = $balance * $pclass['interestrate'] / (100.0 * 12); + $new_balance = $balance + $interest + $monthly_fee; + + if ($minimum_payment >= $new_balance || $payment >= $new_balance) { + $pay_data[] = $new_balance; + break; + } + + $new_payment = max($payment, $minimum_payment); + + if ($base) { + $new_payment = max($new_payment, $balance / 24.0 + $monthly_fee + $interest); + } + + $balance = $new_balance - $new_payment; + + $pay_data[] = $new_payment; + + $months -= 1; + } + + $monthly_cost = round(isset($pay_data[0]) ? ($pay_data[0]) : 0, 2); + + if ($monthly_cost < 0.01) { + continue; + } + + if ($pclass['type'] == 1 && $monthly_cost < $lowest_payment) { + $monthly_cost = $lowest_payment; + } + + if ($pclass['type'] == 0 && $monthly_cost < $lowest_payment) { + continue; + } + } + } + + $payment_option[$pclass['id']]['pclass_id'] = $pclass['id']; + $payment_option[$pclass['id']]['title'] = $pclass['description']; + $payment_option[$pclass['id']]['months'] = $pclass['months']; + $payment_option[$pclass['id']]['monthly_cost'] = $monthly_cost; + } + + $sort_order = array(); + + foreach ($payment_option as $key => $value) { + $sort_order[$key] = $value['pclass_id']; + } + + array_multisort($sort_order, SORT_ASC, $payment_option); + + $data['payment_options'] = array(); + + foreach ($payment_option as $payment_option) { + $data['payment_options'][] = array( + 'code' => $payment_option['pclass_id'], + 'title' => sprintf($this->language->get('text_monthly_payment'), $payment_option['title'], $this->currency->format($this->currency->convert($payment_option['monthly_cost'], $country_to_currency[$order_info['payment_iso_code_3']], $this->session->data['currency']), $this->session->data['currency'], 1)) + ); + } + + return $this->load->view('extension/payment/klarna_account', $data); + } + } + + public function send() { + $this->load->language('extension/payment/klarna_account'); + + $json = array(); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + // Order must have identical shipping and billing address or have no shipping address at all + if ($order_info) { + if ($order_info['payment_iso_code_3'] == 'DEU' && empty($this->request->post['deu_terms'])) { + $json['error'] = $this->language->get('error_deu_terms'); + } + + if ($this->cart->hasShipping() && !($order_info['payment_firstname'] == $order_info['shipping_firstname'] && $order_info['payment_lastname'] == $order_info['shipping_lastname'] && $order_info['payment_address_1'] == $order_info['shipping_address_1'] && $order_info['payment_address_2'] == $order_info['shipping_address_2'] && $order_info['payment_postcode'] == $order_info['shipping_postcode'] && $order_info['payment_city'] == $order_info['shipping_city'] && $order_info['payment_zone_id'] == $order_info['shipping_zone_id'] && $order_info['payment_zone_code'] == $order_info['shipping_zone_code'] && $order_info['payment_country_id'] == $order_info['shipping_country_id'] && $order_info['payment_country'] == $order_info['shipping_country'] && $order_info['payment_iso_code_3'] == $order_info['shipping_iso_code_3'])) { + $json['error'] = $this->language->get('error_address_match'); + } + + if (!$json) { + $klarna_account = $this->config->get('payment_klarna_account'); + + if ($klarna_account[$order_info['payment_iso_code_3']]['server'] == 'live') { + $url = 'https://payment.klarna.com/'; + } else { + $url = 'https://payment.testdrive.klarna.com/'; + } + + $country_to_currency = array( + 'NOR' => 'NOK', + 'SWE' => 'SEK', + 'FIN' => 'EUR', + 'DNK' => 'DKK', + 'DEU' => 'EUR', + 'NLD' => 'EUR' + ); + + switch ($order_info['payment_iso_code_3']) { + // Sweden + case 'SWE': + $country = 209; + $language = 138; + $encoding = 2; + $currency = 0; + break; + // Finland + case 'FIN': + $country = 73; + $language = 37; + $encoding = 4; + $currency = 2; + break; + // Denmark + case 'DNK': + $country = 59; + $language = 27; + $encoding = 5; + $currency = 3; + break; + // Norway + case 'NOR': + $country = 164; + $language = 97; + $encoding = 3; + $currency = 1; + break; + // Germany + case 'DEU': + $country = 81; + $language = 28; + $encoding = 6; + $currency = 2; + break; + // Netherlands + case 'NLD': + $country = 154; + $language = 101; + $encoding = 7; + $currency = 2; + break; + } + + if (isset($this->request->post['street'])) { + $street = $this->request->post['street']; + } else { + $street = $order_info['payment_address_1']; + } + + if (isset($this->request->post['house_no'])) { + $house_no = $this->request->post['house_no']; + } else { + $house_no = ''; + } + + if (isset($this->request->post['house_ext'])) { + $house_ext = $this->request->post['house_ext']; + } else { + $house_ext = ''; + } + + $address = array( + 'email' => $order_info['email'], + 'telno' => $this->request->post['phone_no'], + 'cellno' => '', + 'fname' => $order_info['payment_firstname'], + 'lname' => $order_info['payment_lastname'], + 'company' => $order_info['payment_company'], + 'careof' => '', + 'street' => $street, + 'house_number' => $house_no, + 'house_extension' => $house_ext, + 'zip' => $order_info['payment_postcode'], + 'city' => $order_info['payment_city'], + 'country' => $country + ); + + $product_query = $this->db->query("SELECT `name`, `model`, `price`, `quantity`, `tax` / `price` * 100 AS 'tax_rate' FROM `" . DB_PREFIX . "order_product` WHERE `order_id` = " . (int)$order_info['order_id'] . " UNION ALL SELECT '', `code`, `amount`, '1', 0.00 FROM `" . DB_PREFIX . "order_voucher` WHERE `order_id` = " . (int)$order_info['order_id']); + + foreach ($product_query->rows as $product) { + $goods_list[] = array( + 'qty' => (int)$product['quantity'], + 'goods' => array( + 'artno' => $product['model'], + 'title' => $product['name'], + 'price' => (int)str_replace('.', '', $this->currency->format($product['price'], $country_to_currency[$order_info['payment_iso_code_3']], '', false)), + 'vat' => (float)$product['tax_rate'], + 'discount' => 0.0, + 'flags' => 0 + ) + ); + } + + if (isset($this->session->data['klarna'][$this->session->data['order_id']])) { + $totals = $this->session->data['klarna'][$this->session->data['order_id']]; + } else { + $totals = array(); + } + + foreach ($totals as $total) { + if ($total['code'] != 'sub_total' && $total['code'] != 'tax' && $total['code'] != 'total') { + $goods_list[] = array( + 'qty' => 1, + 'goods' => array( + 'artno' => '', + 'title' => $total['title'], + 'price' => (int)str_replace('.', '', $this->currency->format($total['value'], $country_to_currency[$order_info['payment_iso_code_3']], '', false)), + 'vat' => (float)$total['tax_rate'], + 'discount' => 0.0, + 'flags' => 0 + ) + ); + } + } + + $digest = ''; + + foreach ($goods_list as $goods) { + $digest .= utf8_decode(htmlspecialchars(html_entity_decode($goods['goods']['title'], ENT_COMPAT, 'UTF-8'))) . ':'; + } + + $digest = base64_encode(pack('H*', hash('sha256', $digest . $klarna_account[$order_info['payment_iso_code_3']]['secret']))); + + if (isset($this->request->post['pno'])) { + $pno = $this->request->post['pno']; + } else { + $pno = sprintf('%02d', (int)$this->request->post['pno_day']) . sprintf('%02d', (int)$this->request->post['pno_month']) . (int)$this->request->post['pno_year']; + } + + if (isset($this->request->post['code'])) { + $pclass = (int)$this->request->post['code']; + } else { + $pclass = ''; + } + + if (isset($this->request->post['gender']) && ($order_info['payment_iso_code_3'] == 'DEU' || $order_info['payment_iso_code_3'] == 'NLD')) { + $gender = (int)$this->request->post['gender']; + } else { + $gender = ''; + } + + $transaction = array( + '4.1', + 'API:OPENCART:' . VERSION, + $pno, + $gender, + '', + '', + (string)$order_info['order_id'], + '', + $address, + $address, + $order_info['ip'], + 0, + $currency, + $country, + $language, + (int)$klarna_account[$order_info['payment_iso_code_3']]['merchant'], + $digest, + $encoding, + $pclass, + $goods_list, + $order_info['comment'], + array('delay_adjust' => 1), + array(), + array(), + array(), + array(), + array(), + ); + + $xml = '<methodCall>'; + $xml .= ' <methodName>add_invoice</methodName>'; + $xml .= ' <params>'; + + foreach ($transaction as $parameter) { + $xml .= ' <param><value>' . $this->constructXmlrpc($parameter) . '</value></param>'; + } + + $xml .= ' </params>'; + $xml .= '</methodCall>'; + + $header = array(); + + $header[] = 'Content-Type: text/xml'; + $header[] = 'Content-Length: ' . strlen($xml); + + $curl = curl_init(); + + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST'); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_HTTPHEADER, $header); + curl_setopt($curl, CURLOPT_POSTFIELDS, $xml); + + $response = curl_exec($curl); + + if (curl_errno($curl)) { + $log = new Log('klarna_account.log'); + $log->write('HTTP Error for order #' . $order_info['order_id'] . '. Code: ' . curl_errno($curl) . ' message: ' . curl_error($curl)); + + $json['error'] = $this->language->get('error_network'); + } else { + preg_match('/<member><name>faultString<\/name><value><string>(.+)<\/string><\/value><\/member>/', $response, $match); + + if (isset($match[1])) { + preg_match('/<member><name>faultCode<\/name><value><int>([0-9]+)<\/int><\/value><\/member>/', $response, $match2); + + $log = new Log('klarna_account.log'); + $log->write('Failed to create an invoice for order #' . $order_info['order_id'] . '. Message: ' . utf8_encode($match[1]) . ' Code: ' . $match2[1]); + + $json['error'] = utf8_encode($match[1]); + } else { + $xml = new DOMDocument(); + $xml->loadXML($response); + + $invoice_number = $xml->getElementsByTagName('string')->item(0)->nodeValue; + $klarna_order_status = $xml->getElementsByTagName('int')->item(0)->nodeValue; + + if ($klarna_order_status == '1') { + $order_status = $klarna_account[$order_info['payment_iso_code_3']]['accepted_status_id']; + } elseif ($klarna_order_status == '2') { + $order_status = $klarna_account[$order_info['payment_iso_code_3']]['pending_status_id']; + } else { + $order_status = $this->config->get('config_order_status_id'); + } + + $comment = sprintf($this->language->get('text_comment'), $invoice_number, $this->config->get('config_currency'), $country_to_currency[$order_info['payment_iso_code_3']], $this->currency->getValue($country_to_currency[$order_info['payment_iso_code_3']])); + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $order_status, $comment, 1); + + $json['redirect'] = $this->url->link('checkout/success'); + } + } + + curl_close($curl); + } + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + private function constructXmlrpc($data) { + $type = gettype($data); + + switch ($type) { + case 'boolean': + if ($data == true) { + $value = 1; + } else { + $value = false; + } + + $xml = '<boolean>' . $value . '</boolean>'; + break; + case 'integer': + $xml = '<int>' . (int)$data . '</int>'; + break; + case 'double': + $xml = '<double>' . (float)$data . '</double>'; + break; + case 'string': + $xml = '<string>' . htmlspecialchars($data) . '</string>'; + break; + case 'array': + if ($data === array_values($data)) { + $xml = '<array><data>'; + + foreach ($data as $value) { + $xml .= '<value>' . $this->constructXmlrpc($value) . '</value>'; + } + + $xml .= '</data></array>'; + } else { + $xml = '<struct>'; + + foreach ($data as $key => $value) { + $xml .= '<member>'; + $xml .= ' <name>' . htmlspecialchars($key) . '</name>'; + $xml .= ' <value>' . $this->constructXmlrpc($value) . '</value>'; + $xml .= '</member>'; + } + + $xml .= '</struct>'; + } + break; + default: + $xml = '<nil/>'; + break; + } + + return $xml; + } + + private function getLowestPaymentAccount($country) { + switch ($country) { + case 'SWE': + $amount = 50.0; + break; + case 'NOR': + $amount = 95.0; + break; + case 'FIN': + $amount = 8.95; + break; + case 'DNK': + $amount = 89.0; + break; + case 'DEU': + case 'NLD': + $amount = 5.00; + break; + + default: + $log = new Log('klarna.log'); + $log->write('Unknown country ' . $country); + + $amount = null; + break; + } + + return $amount; + } + + private function splitAddress($address) { + $numbers = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + $characters = array('-', '/', ' ', '#', '.', 'a', 'b', 'c', 'd', 'e', + 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', + 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', + 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z'); + + $specialchars = array('-', '/', ' ', '#', '.'); + + $num_pos = $this->strposArr($address, $numbers, 2); + + $street_name = substr($address, 0, $num_pos); + + $street_name = trim($street_name); + + $number_part = substr($address, $num_pos); + + $number_part = trim($number_part); + + $ext_pos = $this->strposArr($number_part, $characters, 0); + + if ($ext_pos != '') { + $house_number = substr($number_part, 0, $ext_pos); + + $house_extension = substr($number_part, $ext_pos); + + $house_extension = str_replace($specialchars, '', $house_extension); + } else { + $house_number = $number_part; + $house_extension = ''; + } + + return array($street_name, $house_number, $house_extension); + } + + private function strposArr($haystack, $needle, $where) { + $defpos = 10000; + + if (!is_array($needle)) { + $needle = array($needle); + } + + foreach ($needle as $what) { + if (($pos = strpos($haystack, $what, $where)) !== false) { + if ($pos < $defpos) { + $defpos = $pos; + } + } + } + + return $defpos; + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/klarna_checkout.php b/public/catalog/controller/extension/payment/klarna_checkout.php new file mode 100644 index 0000000..675ea81 --- /dev/null +++ b/public/catalog/controller/extension/payment/klarna_checkout.php @@ -0,0 +1,1963 @@ +<?php +class ControllerExtensionPaymentKlarnaCheckout extends Controller { + public function index() { + $this->load->language('extension/payment/klarna_checkout'); + + $this->load->model('extension/payment/klarna_checkout'); + $this->load->model('localisation/country'); + + $this->document->setTitle($this->language->get('heading_title')); + + $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/klarna_checkout', $data)); + } + + public function main() { + $this->load->language('extension/payment/klarna_checkout'); + + $this->load->model('extension/payment/klarna_checkout'); + $this->load->model('localisation/country'); + + $redirect = false; + $html_snippet = ''; + + // Validate cart has products and has stock. + if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) { + $redirect = $this->url->link('checkout/cart'); + } + + // Validate minimum quantity requirements. + $products = $this->cart->getProducts(); + + foreach ($products as $product) { + $product_total = 0; + + foreach ($products as $product_2) { + if ($product_2['product_id'] == $product['product_id']) { + $product_total += $product_2['quantity']; + } + } + + if ($product['minimum'] > $product_total) { + $redirect = $this->url->link('checkout/cart'); + } + } + + // Validate cart has recurring products + if ($this->cart->hasRecurringProducts()) { + $redirect = $this->url->link('checkout/cart'); + } + + list($totals, $taxes, $total) = $this->model_extension_payment_klarna_checkout->getTotals(); + + if ($this->config->get('klarna_checkout_total') > 0 && $this->config->get('klarna_checkout_total') > $total) { + $redirect = $this->url->link('checkout/cart'); + } + + if (!$this->config->get('klarna_checkout_status')) { + $redirect = $this->url->link('checkout/cart'); + } + + if ($this->model_extension_payment_klarna_checkout->checkForPaymentTaxes($products)) { + $redirect = $this->url->link('checkout/cart'); + } + + $text_title = $this->language->get('text_title'); + + unset($this->session->data['success']); + + $this->setPayment(); + $this->setShipping(); + + $this->session->data['payment_method'] = array( + 'code' => 'klarna_checkout', + 'title' => $text_title, + 'terms' => $this->url->link('information/information', 'information_id=' . $this->config->get('klarna_checkout_terms'), true), + 'sort_order' => '1' + ); + + // Shipping + $unset_shipping_method = true; + if (isset($this->session->data['shipping_method']) && isset($this->session->data['shipping_methods'])) { + foreach ($this->session->data['shipping_methods'] as $shipping_method) { + if ($shipping_method['quote']) { + foreach ($shipping_method['quote'] as $quote) { + if ($quote['code'] == $this->session->data['shipping_method']['code']) { + $unset_shipping_method = false; + break 2; + } + } + } + } + } + + if ($unset_shipping_method) { + unset($this->session->data['shipping_method']); + } + + if ((!isset($this->session->data['shipping_method']) || empty($this->session->data['shipping_method'])) && (isset($this->session->data['shipping_methods']) && !empty($this->session->data['shipping_methods']))) { + $this->session->data['shipping_method'] = $this->model_extension_payment_klarna_checkout->getDefaultShippingMethod($this->session->data['shipping_methods']); + } + + //Klarna Connector + list($klarna_account, $connector) = $this->model_extension_payment_klarna_checkout->getConnector($this->config->get('klarna_checkout_account'), $this->session->data['currency']); + + if (!$klarna_account || !$connector) { + $redirect = $this->url->link('checkout/cart'); + } + + if (!$redirect) { + // Get currency code and currency value to use to calculate taxes + + // Build order_lines + $create_order = true; + $klarna_checkout = false; + + $this->createOrder(); + + list($klarna_order_data, $encrypted_order_data) = $this->klarnaOrderData($klarna_account); + + if (isset($this->session->data['klarna_checkout_currency']) && $this->session->data['klarna_checkout_currency'] != $this->session->data['currency']) { + $this->model_extension_payment_klarna_checkout->log('Currency changed, unsetting kc order id'); + unset($this->session->data['klarna_checkout_order_id']); + unset($this->session->data['klarna_checkout_data']); + } + + $this->session->data['klarna_checkout_currency'] = $this->session->data['currency']; + + // Fetch or create order + if (isset($this->session->data['klarna_checkout_order_id'])) { + $retrieve = $this->model_extension_payment_klarna_checkout->orderRetrieve($connector, $this->session->data['klarna_checkout_order_id']); + + if ($retrieve) { + //If address has changed, unset klarna_checkout_order_id and create new order + $address_change = false; + + if (isset($this->session->data['klarna_checkout_data']) && $this->session->data['klarna_checkout_data']) { + if (isset($this->session->data['klarna_checkout_data']['zone_code'])) { + $kc_region = $this->session->data['klarna_checkout_data']['zone_code']; + } else { + $kc_region = ''; + } + + if (isset($this->session->data['klarna_checkout_data']['iso_code_2'])) { + $kc_country = $this->session->data['klarna_checkout_data']['iso_code_2']; + } else { + $kc_country = ''; + } + + if (isset($this->session->data['shipping_address']['zone_code'])) { + $oc_region = $this->session->data['shipping_address']['zone_code']; + } else { + $oc_region = ''; + } + + if (isset($this->session->data['shipping_address']['iso_code_2'])) { + $oc_country = $this->session->data['shipping_address']['iso_code_2']; + } else { + $oc_country = ''; + } + + $kc_address = array( + 'region' => $kc_region, + 'country' => $kc_country, + ); + + $oc_address = array( + 'region' => $oc_region, + 'country' => $oc_country, + ); + + //If address has changed, dont use retrieved order, create new one instead + if (array_diff(array_map('strtolower', $kc_address), array_map('strtolower', $oc_address))) { + $address_change = true; + } + } + + if (!$address_change) { + $this->model_extension_payment_klarna_checkout->log('Order Updated'); + $this->model_extension_payment_klarna_checkout->log($klarna_order_data); + + $create_order = false; + + $update = $this->model_extension_payment_klarna_checkout->orderUpdate($connector, $this->session->data['klarna_checkout_order_id'], $klarna_order_data); + + if ($update) { + $klarna_checkout = $update->fetch(); + + $this->model_extension_payment_klarna_checkout->updateOrder($this->session->data['order_id'], $klarna_checkout['order_id'], $encrypted_order_data); + } + } + } + } + + if ($create_order) { + $this->model_extension_payment_klarna_checkout->log('Order Created'); + $this->model_extension_payment_klarna_checkout->log($klarna_order_data); + + unset($this->session->data['klarna_checkout_data']); + + $create = $this->model_extension_payment_klarna_checkout->orderCreate($connector, $klarna_order_data); + + if ($create) { + $klarna_checkout = $create->fetch(); + + $this->model_extension_payment_klarna_checkout->addOrder($this->session->data['order_id'], $klarna_checkout['order_id'], $encrypted_order_data); + } + } + + if ($klarna_checkout) { + $this->session->data['klarna_checkout_order_id'] = $klarna_checkout['order_id']; + + $html_snippet = $klarna_checkout['html_snippet']; + } + } + + if (isset($this->request->post['response']) && $this->request->post['response'] == 'template') { + $data['redirect'] = $redirect; + + $data['klarna_checkout'] = $html_snippet; + + $this->response->setOutput($this->load->view('extension/payment/klarna_checkout_main', $data)); + } elseif (isset($this->request->post['response']) && $this->request->post['response'] == 'json') { + $json['redirect'] = $redirect; + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + } + + public function sidebar() { + $this->load->language('checkout/checkout'); + $this->load->language('extension/payment/klarna_checkout'); + + $this->load->model('extension/payment/klarna_checkout'); + + if (!$this->config->get('klarna_checkout_status')) { + return false; + } + + $this->setPayment(); + $this->setShipping(); + + // Shipping + $unset_shipping_method = true; + if (isset($this->session->data['shipping_method']) && isset($this->session->data['shipping_methods'])) { + foreach ($this->session->data['shipping_methods'] as $shipping_method) { + if ($shipping_method['quote']) { + foreach ($shipping_method['quote'] as $quote) { + if ($quote['code'] == $this->session->data['shipping_method']['code']) { + $unset_shipping_method = false; + break 2; + } + } + } + } + } + + if ($unset_shipping_method) { + unset($this->session->data['shipping_method']); + } + + if ((!isset($this->session->data['shipping_method']) || empty($this->session->data['shipping_method'])) && (isset($this->session->data['shipping_methods']) && !empty($this->session->data['shipping_methods']))) { + $this->session->data['shipping_method'] = $this->model_extension_payment_klarna_checkout->getDefaultShippingMethod($this->session->data['shipping_methods']); + } + + $data['shipping_required'] = $this->cart->hasShipping(); + + if (isset($this->session->data['shipping_methods'])) { + $data['shipping_methods'] = $this->session->data['shipping_methods']; + } else { + unset($data['shipping_method']); + + $data['shipping_methods'] = array(); + } + + if (isset($this->session->data['shipping_method']['code'])) { + $data['code'] = $this->session->data['shipping_method']['code']; + } else { + $data['code'] = ''; + } + + $this->load->model('tool/image'); + $this->load->model('tool/upload'); + + $data['products'] = array(); + + foreach ($this->cart->getProducts() as $product) { + if ($product['image']) { + $image = $this->model_tool_image->resize($product['image'], $this->config->get('theme_' . $this->config->get('config_theme') . '_image_cart_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_cart_height')); + } else { + $image = ''; + } + + $option_data = array(); + + foreach ($product['option'] as $option) { + if ($option['type'] != 'file') { + $value = $option['value']; + } else { + $upload_info = $this->model_tool_upload->getUploadByCode($option['value']); + + if ($upload_info) { + $value = $upload_info['name']; + } else { + $value = ''; + } + } + + $option_data[] = array( + 'name' => $option['name'], + 'value' => (utf8_strlen($value) > 20 ? utf8_substr($value, 0, 20) . '..' : $value), + 'type' => $option['type'] + ); + } + + // Display prices + if (($this->config->get('config_customer_price') && $this->customer->isLogged()) || !$this->config->get('config_customer_price')) { + $price = $this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']); + } else { + $price = false; + } + + // Display prices + if (($this->config->get('config_customer_price') && $this->customer->isLogged()) || !$this->config->get('config_customer_price')) { + $total = $this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')) * $product['quantity'], $this->session->data['currency']); + } else { + $total = false; + } + + $data['products'][] = array( + 'cart_id' => $product['cart_id'], + 'thumb' => $image, + 'name' => $product['name'], + 'model' => $product['model'], + 'option' => $option_data, + 'recurring' => ($product['recurring'] ? $product['recurring']['name'] : ''), + 'quantity' => $product['quantity'], + 'price' => $price, + 'total' => $total, + 'href' => $this->url->link('product/product', 'product_id=' . $product['product_id']) + ); + } + + // Gift Voucher + $data['vouchers'] = array(); + + if (!empty($this->session->data['vouchers'])) { + foreach ($this->session->data['vouchers'] as $key => $voucher) { + $data['vouchers'][] = array( + 'key' => $key, + 'description' => $voucher['description'], + 'amount' => $this->currency->format($voucher['amount'], $this->session->data['currency']) + ); + } + } + + $totals = array(); + $taxes = $this->cart->getTaxes(); + $total = 0; + + // Because __call can not keep var references so we put them into an array. + $total_data = array( + 'totals' => &$totals, + 'taxes' => &$taxes, + 'total' => &$total + ); + + $this->load->model('setting/extension'); + + $sort_order = array(); + + $results = $this->model_setting_extension->getExtensions('total'); + + foreach ($results as $key => $value) { + $sort_order[$key] = $this->config->get('total_' . $value['code'] . '_sort_order'); + } + + array_multisort($sort_order, SORT_ASC, $results); + + foreach ($results as $result) { + if ($this->config->get($result['code'] . '_status')) { + $this->load->model('extension/total/' . $result['code']); + + // We have to put the totals in an array so that they pass by reference. + $this->{'model_extension_total_' . $result['code']}->getTotal($total_data); + } + } + + $sort_order = array(); + + foreach ($totals as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $totals); + + $data['totals'] = array(); + + foreach ($totals as $total) { + $data['totals'][] = array( + 'title' => $total['title'], + 'text' => $this->currency->format($total['value'], $this->session->data['currency']) + ); + } + + $this->response->setOutput($this->load->view('extension/payment/klarna_checkout_sidebar', $data)); + } + + public function shippingAddress() { + $this->load->model('extension/payment/klarna_checkout'); + $this->load->model('localisation/zone'); + + if (!$this->config->get('klarna_checkout_status')) { + return false; + } + + $json = array(); + + unset($this->session->data['shipping_address']); + unset($this->session->data['shipping_methods']); + + if (($this->request->server['REQUEST_METHOD'] == 'POST') && isset($this->request->post['country'])) { + $country_info = $this->model_extension_payment_klarna_checkout->getCountryByIsoCode3($this->request->post['country']); + + if ($country_info) { + // Set default zone for shipping calculations. Get overwritten by correct data when order is confirmed + $zones = $this->model_localisation_zone->getZonesByCountryId($country_info['country_id']); + + $zone = array(); + if (isset($this->request->post['region']) && !empty($this->request->post['region'])) { + $zone = $this->model_extension_payment_klarna_checkout->getZoneByCode($this->request->post['region'], $country_info['country_id']); + } + + if ($zone || $zones) { + $this->session->data['shipping_address'] = array( + 'address_id' => null, + 'firstname' => utf8_substr($this->request->post['given_name'], 0, 32), + 'lastname' => utf8_substr($this->request->post['family_name'], 0, 32), + 'company' => null, + 'address_1' => utf8_substr($this->request->post['street_address'], 0, 128), + 'address_2' => utf8_substr($this->request->post['street_address'], 129, 256), + 'postcode' => utf8_substr($this->request->post['postal_code'], 0, 10), + 'city' => utf8_substr($this->request->post['city'], 0, 128), + 'zone_id' => ($zone ? $zone['zone_id'] : $zones[0]['zone_id']), + 'zone' => ($zone ? $zone['name'] : $zones[0]['name']), + 'zone_code' => ($zone ? $zone['code'] : $zones[0]['code']), + 'country_id' => $country_info['country_id'], + 'country' => $country_info['name'], + 'iso_code_2' => $country_info['iso_code_2'], + 'iso_code_3' => $country_info['iso_code_3'], + 'address_format' => $country_info['address_format'], + 'custom_field' => array(), + ); + + $this->tax->unsetRates(); + $this->tax->setShippingAddress($this->session->data['shipping_address']['country_id'], $this->session->data['shipping_address']['zone_id']); + $this->tax->setStoreAddress($this->config->get('config_country_id'), $this->config->get('config_zone_id')); + } + } else { + $this->model_extension_payment_klarna_checkout->log('Couldnt find country: ' . $this->request->post['country']); + } + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function cartTotal() { + $this->load->language('checkout/cart'); + + if (!$this->config->get('klarna_checkout_status')) { + return false; + } + + // Totals + $this->load->model('setting/extension'); + + $totals = array(); + $taxes = $this->cart->getTaxes(); + $total = 0; + + // Because __call can not keep var references so we put them into an array. + $total_data = array( + 'totals' => &$totals, + 'taxes' => &$taxes, + 'total' => &$total + ); + + // Display prices + if (($this->config->get('config_customer_price') && $this->customer->isLogged()) || !$this->config->get('config_customer_price')) { + $sort_order = array(); + + $results = $this->model_setting_extension->getExtensions('total'); + + foreach ($results as $key => $value) { + $sort_order[$key] = $this->config->get('total_' . $value['code'] . '_sort_order'); + } + + array_multisort($sort_order, SORT_ASC, $results); + + foreach ($results as $result) { + if ($this->config->get($result['code'] . '_status')) { + $this->load->model('extension/total/' . $result['code']); + + // We have to put the totals in an array so that they pass by reference. + $this->{'model_extension_total_' . $result['code']}->getTotal($total_data); + } + } + + $sort_order = array(); + + foreach ($totals as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $totals); + + $total = sprintf($this->language->get('text_items'), $this->cart->countProducts() + (isset($this->session->data['vouchers']) ? count($this->session->data['vouchers']) : 0), $this->currency->format($total, $this->session->data['currency'])); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($total)); + } + + public function addressUpdate() { + $this->load->language('extension/payment/klarna_checkout'); + + $this->load->model('account/customer'); + $this->load->model('checkout/order'); + $this->load->model('extension/payment/klarna_checkout'); + $this->load->model('localisation/zone'); + + if (!$this->config->get('klarna_checkout_status')) { + return false; + } + + $process = true; + + $request = json_decode(file_get_contents('php://input')); + + $json = array(); + + $http_response_code = 400; + + // Check to see if request data is complete + if (!$request || !isset($request->order_lines) || empty($request->order_lines) || !isset($request->shipping_address) || empty($request->shipping_address)) { + $this->model_extension_payment_klarna_checkout->log('Request data incomplete. Full request below:'); + $this->model_extension_payment_klarna_checkout->log($request); + $process = false; + } + + // Get Klarna order info from db + if ($process) { + $order_id = null; + + foreach ($request->order_lines as $order_line) { + if ($order_line->type == 'physical' || $order_line->type == 'digital' || $order_line->type == 'gift_card') { + $order_id = $this->encryption->decrypt($this->config->get('config_encryption'), $order_line->merchant_data); + break; + } + } + + if ($order_id) { + // Get klarna order data from db + $klarna_checkout_order = $this->model_extension_payment_klarna_checkout->getOrderByOrderId($order_id); + + if (!$klarna_checkout_order || !$klarna_checkout_order['data']) { + $this->model_extension_payment_klarna_checkout->log('No klarna order found using order_id: ' . $order_id); + $process = false; + } + } else { + $process = false; + } + } + + if ($process) { + $klarna_checkout_order_data = json_decode($this->encryption->decrypt($this->config->get('config_encryption'), $klarna_checkout_order['data']), true); + + // Check credentials in request with ones stored in db + $valid_request = false; + foreach ($this->config->get('klarna_checkout_account') as $account) { + if (($account['merchant_id'] == $klarna_checkout_order_data['merchant_id']) && ($account['secret'] == $klarna_checkout_order_data['secret'])) { + $valid_request = true; + break; + } + } + + if (!$valid_request) { + $this->model_extension_payment_klarna_checkout->log('Cannot validate request. Terminating.'); + $process = false; + } + } + + // Request is valid, we can spoof/simulate the customer to calculate shipping + if ($process) { + session_destroy(); + session_id($klarna_checkout_order_data['session_id']); + session_start(); + $this->session->start('default', $klarna_checkout_order_data['session_key']); + + if ($klarna_checkout_order_data['customer_id']) { + $customer_info = $this->model_account_customer->getCustomer($klarna_checkout_order_data['customer_id']); + + if ($customer_info) { + $this->customer->login($customer_info['email'], '', true); + } + } + + $order_info = $this->model_checkout_order->getOrder($order_id); + + if (!$order_info) { + $this->model_extension_payment_klarna_checkout->log('No order found using order_id: ' . $order_id . '. Full request below:'); + $this->model_extension_payment_klarna_checkout->log($request); + $process = false; + } + + // Set more session data from the order + $this->session->data['currency'] = $order_info['currency_code']; + $this->session->data['language'] = $order_info['language_code']; + + $country_info = $this->model_extension_payment_klarna_checkout->getCountryByIsoCode2($request->shipping_address->country); + + if (!$country_info) { + $this->model_extension_payment_klarna_checkout->log('No country found using: ' . $request->shipping_address->country . '. Full request below:'); + $this->model_extension_payment_klarna_checkout->log($request); + } + + if ($order_info && $country_info) { + $zones = $this->model_localisation_zone->getZonesByCountryId($country_info['country_id']); + + $zone = array(); + if (isset($request->shipping_address->region) && !empty($request->shipping_address->region)) { + $zone = $this->model_extension_payment_klarna_checkout->getZoneByCode($request->shipping_address->region, $country_info['country_id']); + } + + if ($zone || $zones) { + $this->session->data['shipping_address'] = array( + 'address_id' => null, + 'firstname' => null, + 'lastname' => null, + 'company' => null, + 'address_1' => null, + 'address_2' => null, + 'postcode' => null, + 'city' => null, + 'zone_id' => ($zone ? $zone['zone_id'] : $zones[0]['zone_id']), + 'zone' => ($zone ? $zone['name'] : $zones[0]['name']), + 'zone_code' => ($zone ? $zone['code'] : $zones[0]['code']), + 'country_id' => $country_info['country_id'], + 'country' => $country_info['name'], + 'iso_code_2' => $country_info['iso_code_2'], + 'iso_code_3' => $country_info['iso_code_3'], + 'address_format' => '', + 'custom_field' => array() + ); + + $this->session->data['klarna_checkout_data'] = array( + 'email' => $request->billing_address->email, + 'firstname' => $request->billing_address->given_name, + 'lastname' => $request->billing_address->family_name, + 'telephone' => $request->billing_address->phone, + 'iso_code_2' => $this->session->data['shipping_address']['iso_code_2'], + 'zone_code' => $this->session->data['shipping_address']['zone_code'] + ); + + // Unset $tax_rates + $this->tax->unsetRates(); + $this->tax->setShippingAddress($country_info['country_id'], ($zone ? $zone['zone_id'] : $zones[0]['zone_id'])); + $this->tax->setStoreAddress($this->config->get('config_country_id'), $this->config->get('config_zone_id')); + + //Check if customer is US. If so, send taxes differently + if ($this->session->data['shipping_address']['iso_code_2'] === 'US') { + $include_taxes = false; + } else { + $include_taxes = true; + } + + $method_data = array(); + + $this->load->model('setting/extension'); + + $results = $this->model_setting_extension->getExtensions('shipping'); + + foreach ($results as $result) { + if ($this->config->get('shipping_' . $result['code'] . '_status')) { + $this->load->model('extension/shipping/' . $result['code']); + + $quote = $this->{'model_extension_shipping_' . $result['code']}->getQuote($this->session->data['shipping_address']); + + if ($quote) { + $method_data[$result['code']] = array( + 'title' => $quote['title'], + 'quote' => $quote['quote'], + 'sort_order' => $quote['sort_order'], + 'error' => $quote['error'] + ); + } + } + } + + $sort_order = array(); + + foreach ($method_data as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $method_data); + + $shipping_methods = $method_data; + + if ($shipping_methods) { + list($klarna_account, $connector) = $this->model_extension_payment_klarna_checkout->getConnector($this->config->get('klarna_checkout_account'), $this->session->data['currency']); + + if ($klarna_account && $connector) { + list($klarna_order_data, $encrypted_order_data) = $this->klarnaOrderData($klarna_account); + + if ($this->cart->hasShipping()) { + $shipping_method = array(); + + if (isset($this->session->data['shipping_method']) && !empty($this->session->data['shipping_method'])) { + foreach ($shipping_methods as $individual_shipping_method) { + if ($individual_shipping_method['quote']) { + foreach ($individual_shipping_method['quote'] as $quote) { + if (($this->session->data['shipping_method']['code'] == $quote['code']) && ($this->session->data['shipping_method']['title'] == $quote['title']) && ($this->session->data['shipping_method']['cost'] == $quote['cost']) && ($this->session->data['shipping_method']['tax_class_id'] == $quote['tax_class_id'])) { + $shipping_method = $quote; + break 2; + } + } + } + } + } + + // If the current shipping method isn't in the available shipping methods, assign default + if (!$shipping_method) { + $this->session->data['shipping_method'] = $this->model_extension_payment_klarna_checkout->getDefaultShippingMethod($shipping_methods); + } + + $total_amount = $this->currency->format($this->tax->calculate($this->session->data['shipping_method']['cost'], $this->session->data['shipping_method']['tax_class_id'], $include_taxes), $order_info['currency_code'], $order_info['currency_value'], false) * 100; + + if ($include_taxes) { + $total_tax_amount = $this->currency->format($this->tax->getTax($this->session->data['shipping_method']['cost'], $this->session->data['shipping_method']['tax_class_id']), $order_info['currency_code'], $order_info['currency_value'], false) * 100; + } else { + $total_tax_amount = 0; + } + + $total_sub_amount = $this->currency->format($this->tax->calculate($this->session->data['shipping_method']['cost'], $this->session->data['shipping_method']['tax_class_id'], false), $order_info['currency_code'], $order_info['currency_value'], false) * 100; + + $tax_rate = 0; + + if ($include_taxes && $total_tax_amount && $total_sub_amount) { + $tax_rate = ($total_tax_amount / $total_sub_amount) * 100; + } + + foreach ($klarna_order_data['order_lines'] as $key => $order_line) { + if ($order_line['type'] == 'shipping_fee') { + unset($klarna_order_data['order_lines'][$key]); + break; + } + } + + $klarna_order_data['order_lines'][] = array( + 'type' => 'shipping_fee', + 'name' => $this->session->data['shipping_method']['title'], + 'quantity' => '1', + 'unit_price' => round($this->currency->format($this->tax->calculate($this->session->data['shipping_method']['cost'], $this->session->data['shipping_method']['tax_class_id'], $include_taxes), $order_info['currency_code'], $order_info['currency_value'], false) * 100), + 'tax_rate' => round($tax_rate * 100), + 'total_amount' => round($total_amount), + 'total_tax_amount' => round($total_tax_amount), + 'total_discount_amount' => 0 + ); + } + + list($totals, $taxes, $total) = $this->model_extension_payment_klarna_checkout->getTotals(); + + //If $include_taxes is false, means customer is US so we add a new sales_tax order line with all the tax + if (!$include_taxes) { + foreach ($klarna_order_data['order_lines'] as $key => $order_line) { + if ($order_line['type'] == 'sales_tax') { + unset($klarna_order_data['order_lines'][$key]); + break; + } + } + + $klarna_order_data['order_lines'][] = array( + 'type' => 'sales_tax', + 'name' => $this->language->get('text_sales_tax'), + 'quantity' => '1', + 'unit_price' => round($this->currency->format(array_sum($taxes), $order_info['currency_code'], $order_info['currency_value'], false) * 100), + 'tax_rate' => 0, + 'total_amount' => round($this->currency->format(array_sum($taxes), $order_info['currency_code'], $order_info['currency_value'], false) * 100), + 'total_tax_amount' => 0, + 'total_discount_amount' => 0 + ); + } + + $http_response_code = 200; + + $json = array( + 'order_amount' => round($this->currency->format($total, $order_info['currency_code'], $order_info['currency_value'], false) * 100), + 'order_tax_amount' => round($this->currency->format(array_sum($taxes), $order_info['currency_code'], $order_info['currency_value'], false) * 100), + 'order_lines' => array_values($klarna_order_data['order_lines']) + ); + } + } + } + } + } + + $this->model_extension_payment_klarna_checkout->log($http_response_code); + $this->model_extension_payment_klarna_checkout->log($json); + + http_response_code($http_response_code); + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function notification() { + $this->load->model('extension/payment/klarna_checkout'); + $this->load->model('checkout/order'); + + if (!$this->config->get('klarna_checkout_status')) { + return false; + } + + $request = json_decode(file_get_contents('php://input')); + + if (isset($request->order_id)) { + $klarna_checkout_order = $this->model_extension_payment_klarna_checkout->getOrder($request->order_id); + + if ($klarna_checkout_order) { + $order_info = $this->model_checkout_order->getOrder($klarna_checkout_order['order_id']); + + if ($order_info) { + list($klarna_account, $connector) = $this->model_extension_payment_klarna_checkout->getConnector($this->config->get('klarna_checkout_account'), $order_info['currency_code']); + + if (!$klarna_account || !$connector) { + $this->model_extension_payment_klarna_checkout->log('Could not getConnector'); + } + + $retrieve = $this->model_extension_payment_klarna_checkout->omOrderRetrieve($connector, $request->order_id); + + $order_status_id = false; + if ($retrieve) { + switch ($request->event_type) { + case 'FRAUD_RISK_ACCEPTED': + $order_status_id = $this->config->get('klarna_checkout_order_status_fraud_accepted_id'); + break; + case 'FRAUD_RISK_REJECTED': + $order_status_id = $this->config->get('klarna_checkout_order_status_fraud_rejected_id'); + break; + } + } + + if ($order_status_id) { + $this->model_checkout_order->addOrderHistory($klarna_checkout_order['order_id'], $order_status_id); + } + } + } else { + $this->model_extension_payment_klarna_checkout->log('Could not find order id using ' . $request->order_id); + } + } else { + $this->model_extension_payment_klarna_checkout->log('$request->order_id is not set'); + } + } + + public function validation() { + $this->load->model('account/customer'); + $this->load->model('checkout/order'); + $this->load->model('extension/payment/klarna_checkout'); + + if (!$this->config->get('klarna_checkout_status')) { + return false; + } + + $validate = true; + + $request = json_decode(file_get_contents('php://input')); + + $json = array(); + + // Check to see if request data is complete + if (!$request || !isset($request->order_lines) || empty($request->order_lines) || !isset($request->shipping_address) || empty($request->shipping_address) || !isset($request->billing_address) || empty($request->billing_address)) { + $this->model_extension_payment_klarna_checkout->log('Request data incomplete. Full request below:'); + $this->model_extension_payment_klarna_checkout->log($request); + $validate = false; + } + + // Get Klarna order info from db + if ($validate) { + $order_id = null; + + foreach ($request->order_lines as $order_line) { + if ($order_line->type == 'physical' || $order_line->type == 'digital' || $order_line->type == 'gift_card') { + $order_id = $this->encryption->decrypt($this->config->get('config_encryption'), $order_line->merchant_data); + break; + } + } + + if ($order_id) { + // Get klarna order data from db + $klarna_checkout_order = $this->model_extension_payment_klarna_checkout->getOrderByOrderId($order_id); + + if (!$klarna_checkout_order || !$klarna_checkout_order['data']) { + $this->model_extension_payment_klarna_checkout->log('No klarna order found using order_id: ' . $order_id); + $validate = false; + } + } else { + $this->model_extension_payment_klarna_checkout->log('Cannot get decrypted order_id'); + $validate = false; + } + } + + if ($validate) { + $klarna_checkout_order_data = json_decode($this->encryption->decrypt($klarna_checkout_order['data']), true); + + // Check credentials in request with ones stored in db + $valid_request = false; + foreach ($this->config->get('klarna_checkout_account') as $account) { + if (($account['merchant_id'] == $klarna_checkout_order_data['merchant_id']) && ($account['secret'] == $klarna_checkout_order_data['secret'])) { + $valid_request = true; + break; + } + } + + if (!$valid_request) { + $this->model_extension_payment_klarna_checkout->log('Cannot validate request. Terminating.'); + $validate = false; + } + } + + // Spoof/simulate the customer to calculate shipping + if ($validate) { + session_destroy(); + session_id($klarna_checkout_order_data['session_id']); + session_start(); + $this->session->start('default', $klarna_checkout_order_data['session_key']); + + if ($klarna_checkout_order_data['customer_id']) { + $customer_info = $this->model_account_customer->getCustomer($klarna_checkout_order_data['customer_id']); + + if ($customer_info) { + $this->customer->login($customer_info['email'], '', true); + } + } + + // Validate cart has products and has stock. + if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) { + $this->model_extension_payment_klarna_checkout->log('Cart has no products or cart has no stock'); + $validate = false; + } + + // Validate minimum quantity requirements. + $products = $this->cart->getProducts(); + + foreach ($products as $product) { + $product_total = 0; + + foreach ($products as $product_2) { + if ($product_2['product_id'] == $product['product_id']) { + $product_total += $product_2['quantity']; + } + } + + if ($product['minimum'] > $product_total) { + $this->model_extension_payment_klarna_checkout->log('Cart doesnt meet minimum quantities'); + $validate = false; + } + } + + // Validate cart has recurring products + if ($this->cart->hasRecurringProducts()) { + $this->model_extension_payment_klarna_checkout->log('Cart has recurring products'); + $validate = false; + } + } + + // Check order total to see if session matches post data + if ($validate) { + $order_info = $this->model_checkout_order->getOrder($order_id); + + if ($order_info) { + // Unset $tax_rates and set them again using correct shipping data + $this->tax->unsetRates(); + $this->tax->setShippingAddress($this->session->data['shipping_address']['country_id'], $this->session->data['shipping_address']['zone_id']); + $this->tax->setStoreAddress($this->config->get('config_country_id'), $this->config->get('config_zone_id')); + + list($totals, $taxes, $total) = $this->model_extension_payment_klarna_checkout->getTotals(); + + // Check order_amount + if (round($this->currency->format($total, $order_info['currency_code'], $order_info['currency_value'], false) * 100) != $request->order_amount) { + $this->model_extension_payment_klarna_checkout->log('Klarna Checkout order_amount does not match session order total. Klarna Request: ' . $request->order_amount . '. OpenCart: ' . round($this->currency->format($total, $order_info['currency_code'], $order_info['currency_value'], false) * 100)); + $this->model_extension_payment_klarna_checkout->log($order_info); + $this->model_extension_payment_klarna_checkout->log($this->cart->getTaxes()); + $validate = false; + } + + // Check order_tax_amount + if (round($this->currency->format(array_sum($taxes), $order_info['currency_code'], $order_info['currency_value'], false) * 100) != $request->order_tax_amount) { + $this->model_extension_payment_klarna_checkout->log('Klarna Checkout order_tax_amount does not match session tax total. Totals below:'); + $this->model_extension_payment_klarna_checkout->log('Session taxes:'); + $this->model_extension_payment_klarna_checkout->log(round($this->currency->format(array_sum($taxes), $order_info['currency_code'], $order_info['currency_value'], false) * 100)); + $this->model_extension_payment_klarna_checkout->log('Request taxes:'); + $this->model_extension_payment_klarna_checkout->log($request->order_tax_amount); + $validate = false; + } + } else { + $this->model_extension_payment_klarna_checkout->log('Cannot find order using: ' . $order_id); + $validate = false; + } + } + + // If validates, add customer's email (if guest checkout) and then send 200 response + if ($validate) { + if (!$this->customer->isLogged()) { + $this->model_extension_payment_klarna_checkout->updateOcOrderEmail($order_id, utf8_substr($request->shipping_address->email, 0, 96)); + } + + // Update OpenCart order with payment and shipping details + $payment_country_info = $this->model_extension_payment_klarna_checkout->getCountryByIsoCode2($request->billing_address->country); + $shipping_country_info = $this->model_extension_payment_klarna_checkout->getCountryByIsoCode2($request->shipping_address->country); + + //If region is passed, try to update OpenCart order with correct region/zone + $payment_zone_info = array(); + if ($payment_country_info && isset($request->billing_address->region)) { + $payment_zone_info = $this->model_extension_payment_klarna_checkout->getZoneByCode($request->billing_address->region, $payment_country_info['country_id']); + } + + $shipping_zone_info = array(); + if ($shipping_country_info && isset($request->shipping_address->region)) { + $shipping_zone_info = $this->model_extension_payment_klarna_checkout->getZoneByCode($request->shipping_address->region, $shipping_country_info['country_id']); + } + + $order_data = array( + 'firstname' => utf8_substr($request->billing_address->given_name, 0, 32), + 'lastname' => utf8_substr($request->billing_address->family_name, 0, 32), + 'telephone' => utf8_substr($request->billing_address->phone, 0, 32), + 'payment_firstname' => utf8_substr($request->billing_address->given_name, 0, 32), + 'payment_lastname' => utf8_substr($request->billing_address->family_name, 0, 32), + 'payment_address_1' => utf8_substr($request->billing_address->street_address, 0, 128), + 'payment_address_2' => (isset($request->billing_address->street_address2) ? utf8_substr($request->billing_address->street_address2, 0, 128) : ''), + 'payment_city' => utf8_substr($request->billing_address->city, 0, 128), + 'payment_postcode' => utf8_substr($request->billing_address->postal_code, 0, 10), + 'payment_zone' => ($payment_zone_info ? $payment_zone_info['name'] : ''), + 'payment_zone_id' => ($payment_zone_info ? $payment_zone_info['zone_id'] : ''), + 'payment_country' => ($payment_country_info ? $payment_country_info['name'] : ''), + 'payment_country_id' => ($payment_country_info ? $payment_country_info['country_id'] : ''), + 'payment_address_format' => ($payment_country_info ? $payment_country_info['address_format'] : ''), + 'shipping_firstname' => utf8_substr($request->shipping_address->given_name, 0, 32), + 'shipping_lastname' => utf8_substr($request->shipping_address->family_name, 0, 32), + 'shipping_address_1' => utf8_substr($request->shipping_address->street_address, 0, 128), + 'shipping_address_2' => (isset($request->shipping_address->street_address2) ? utf8_substr($request->shipping_address->street_address2, 0, 128) : ''), + 'shipping_city' => utf8_substr($request->shipping_address->city, 0, 128), + 'shipping_postcode' => utf8_substr($request->shipping_address->postal_code, 0, 10), + 'shipping_zone' => ($shipping_zone_info ? $shipping_zone_info['name'] : ''), + 'shipping_zone_id' => ($shipping_zone_info ? $shipping_zone_info['zone_id'] : ''), + 'shipping_country' => ($shipping_country_info ? $shipping_country_info['name'] : ''), + 'shipping_country_id' => ($shipping_country_info ? $shipping_country_info['country_id'] : ''), + 'shipping_address_format' => ($shipping_country_info ? $shipping_country_info['address_format'] : '') + ); + + $this->model_extension_payment_klarna_checkout->updateOcOrder($order_id, $order_data); + + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('config_order_status_id')); + + http_response_code(200); + } else { + http_response_code(303); + $this->response->addHeader('Location: ' . $this->url->link('checkout/failure', '', true)); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function confirmation() { + $this->load->language('extension/payment/klarna_checkout'); + + if (!$this->config->get('klarna_checkout_status')) { + return false; + } + + if (isset($this->session->data['order_id'])) { + $this->cart->clear(); + + unset($this->session->data['shipping_method']); + unset($this->session->data['shipping_methods']); + unset($this->session->data['payment_method']); + unset($this->session->data['payment_methods']); + unset($this->session->data['guest']); + unset($this->session->data['comment']); + unset($this->session->data['order_id']); + unset($this->session->data['coupon']); + unset($this->session->data['reward']); + unset($this->session->data['voucher']); + unset($this->session->data['vouchers']); + unset($this->session->data['totals']); + + unset($this->session->data['klarna_checkout_order_id']); + unset($this->session->data['klarna_checkout_data']); + } + + $this->document->setTitle($this->language->get('heading_title_success')); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_home'), + 'href' => $this->url->link('common/home') + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_basket'), + 'href' => $this->url->link('checkout/cart') + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_checkout'), + 'href' => $this->url->link('checkout/checkout', '', true) + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_success'), + 'href' => $this->url->link('checkout/success') + ); + + $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->load->model('extension/payment/klarna_checkout'); + $this->load->model('checkout/order'); + + $klarna_checkout = false; + $html_snippet = ''; + + if (isset($this->request->get['klarna_order_id'])) { + $klarna_checkout_order = $this->model_extension_payment_klarna_checkout->getOrder($this->request->get['klarna_order_id']); + + if ($klarna_checkout_order) { + $order_info = $this->model_checkout_order->getOrder($klarna_checkout_order['order_id']); + + if ($order_info) { + list($klarna_account, $connector) = $this->model_extension_payment_klarna_checkout->getConnector($this->config->get('klarna_checkout_account'), $order_info['currency_code']); + + if (!$klarna_account || !$connector) { + $this->model_extension_payment_klarna_checkout->log('Could not getConnector'); + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + + $retrieve = $this->model_extension_payment_klarna_checkout->orderRetrieve($connector, $this->request->get['klarna_order_id']); + + if ($retrieve) { + $klarna_checkout = $retrieve->fetch(); + + if ($klarna_checkout && $klarna_checkout['html_snippet']) { + $html_snippet = $klarna_checkout['html_snippet']; + } + } else { + $this->response->redirect($this->url->link('checkout/cart', '', true)); + } + } + } else { + $this->model_extension_payment_klarna_checkout->log('Could not find order id using ' . $this->request->get['klarna_order_id']); + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + } else { + $this->model_extension_payment_klarna_checkout->log('$this->request->get[\'klarna_order_id\'] is not set'); + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + + $data['klarna_checkout'] = $html_snippet; + + $this->response->setOutput($this->load->view('extension/payment/klarna_checkout_success', $data)); + } + + public function push() { + $this->load->model('extension/payment/klarna_checkout'); + $this->load->model('checkout/order'); + + if (!$this->config->get('klarna_checkout_status')) { + return false; + } + + if (isset($this->request->get['klarna_order_id'])) { + $klarna_checkout_order = $this->model_extension_payment_klarna_checkout->getOrder($this->request->get['klarna_order_id']); + + if ($klarna_checkout_order) { + $order_info = $this->model_checkout_order->getOrder($klarna_checkout_order['order_id']); + + if ($order_info) { + list($klarna_account, $connector) = $this->model_extension_payment_klarna_checkout->getConnector($this->config->get('klarna_checkout_account'), $order_info['currency_code']); + + if ($klarna_account && $connector) { + $order = $this->model_extension_payment_klarna_checkout->omOrderRetrieve($connector, $this->request->get['klarna_order_id']); + + $this->model_extension_payment_klarna_checkout->log('Order details from push:'); + $this->model_extension_payment_klarna_checkout->log($order); + + if ($order) { + if ($order->acknowledge()) { + // Update OpenCart order with payment and shipping details + $payment_country_info = $this->model_extension_payment_klarna_checkout->getCountryByIsoCode2($order['billing_address']['country']); + $shipping_country_info = $this->model_extension_payment_klarna_checkout->getCountryByIsoCode2($order['shipping_address']['country']); + + //If region is passed, try to update OpenCart order with correct region/zone + $payment_zone_info = array(); + if ($payment_country_info && isset($order['billing_address']['region'])) { + $payment_zone_info = $this->model_extension_payment_klarna_checkout->getZoneByCode($order['billing_address']['region'], $payment_country_info['country_id']); + } + + $shipping_zone_info = array(); + if ($shipping_country_info && isset($order['shipping_address']['region'])) { + $shipping_zone_info = $this->model_extension_payment_klarna_checkout->getZoneByCode($order['shipping_address']['region'], $shipping_country_info['country_id']); + } + + $order_data = array( + 'firstname' => utf8_substr($order['billing_address']['given_name'], 0, 32), + 'lastname' => utf8_substr($order['billing_address']['family_name'], 0, 32), + 'telephone' => utf8_substr($order['billing_address']['phone'], 0, 32), + 'payment_firstname' => utf8_substr($order['billing_address']['given_name'], 0, 32), + 'payment_lastname' => utf8_substr($order['billing_address']['family_name'], 0, 32), + 'payment_address_1' => utf8_substr($order['billing_address']['street_address'], 0, 128), + 'payment_address_2' => (isset($order['billing_address']['street_address2']) ? utf8_substr($order['billing_address']['street_address2'], 0, 128) : ''), + 'payment_city' => utf8_substr($order['billing_address']['city'], 0, 128), + 'payment_postcode' => utf8_substr($order['billing_address']['postal_code'], 0, 10), + 'payment_zone' => ($payment_zone_info ? $payment_zone_info['name'] : ''), + 'payment_zone_id' => ($payment_zone_info ? $payment_zone_info['zone_id'] : ''), + 'payment_country' => ($payment_country_info ? $payment_country_info['name'] : ''), + 'payment_country_id' => ($payment_country_info ? $payment_country_info['country_id'] : ''), + 'payment_address_format' => ($payment_country_info ? $payment_country_info['address_format'] : ''), + 'shipping_firstname' => utf8_substr($order['shipping_address']['given_name'], 0, 32), + 'shipping_lastname' => utf8_substr($order['shipping_address']['family_name'], 0, 32), + 'shipping_address_1' => utf8_substr($order['shipping_address']['street_address'], 0, 128), + 'shipping_address_2' => (isset($order['shipping_address']['street_address2']) ? utf8_substr($order['shipping_address']['street_address2'], 0, 128) : ''), + 'shipping_city' => utf8_substr($order['shipping_address']['city'], 0, 128), + 'shipping_postcode' => utf8_substr($order['shipping_address']['postal_code'], 0, 10), + 'shipping_zone' => ($shipping_zone_info ? $shipping_zone_info['name'] : ''), + 'shipping_zone_id' => ($shipping_zone_info ? $shipping_zone_info['zone_id'] : ''), + 'shipping_country' => ($shipping_country_info ? $shipping_country_info['name'] : ''), + 'shipping_country_id' => ($shipping_country_info ? $shipping_country_info['country_id'] : ''), + 'shipping_address_format' => ($shipping_country_info ? $shipping_country_info['address_format'] : '') + ); + + $this->model_extension_payment_klarna_checkout->updateOcOrder($klarna_checkout_order['order_id'], $order_data); + + $order_status_id = false; + switch ($order['status']) { + case 'AUTHORIZED': + $order_status_id = $this->config->get('klarna_checkout_order_status_authorised_id'); + + if ($order['fraud_status'] == 'PENDING') { + $order_status_id = $this->config->get('klarna_checkout_order_status_fraud_pending_id'); + } elseif ($order['fraud_status'] == 'REJECTED') { + $order_status_id = $this->config->get('klarna_checkout_order_status_fraud_rejected_id'); + } + break; + case 'PART_CAPTURED': + $order_status_id = $this->config->get('klarna_checkout_order_status_part_captured_id'); + break; + case 'CAPTURED': + $order_status_id = $this->config->get('klarna_checkout_order_status_captured_id'); + break; + case 'CANCELLED': + $order_status_id = $this->config->get('klarna_checkout_order_status_cancelled_id'); + break; + } + + if ($order_status_id) { + $this->model_checkout_order->addOrderHistory($klarna_checkout_order['order_id'], $order_status_id); + } + } + } else { + $this->model_extension_payment_klarna_checkout->log('Cannot retrieve KC order using order_id: ' . $this->request->get['klarna_order_id']); + } + } + } + } else { + $this->model_extension_payment_klarna_checkout->log('Cannot find KC order using order_id: ' . $this->request->get['klarna_order_id']); + } + } + } + + private function setPayment() { + $this->load->model('account/address'); + $this->load->model('localisation/country'); + $this->load->model('localisation/zone'); + + if (isset($this->session->data['payment_address']) && !empty($this->session->data['payment_address'])) { + $this->session->data['payment_address'] = $this->session->data['payment_address']; + } elseif ($this->customer->isLogged() && $this->customer->getAddressId()) { + $this->session->data['payment_address'] = $this->model_account_address->getAddress($this->customer->getAddressId()); + } else { + $country_info = $this->model_localisation_country->getCountry($this->config->get('config_country_id')); + + $zone_info = $this->model_localisation_zone->getZone($this->config->get('config_zone_id')); + + $this->session->data['payment_address'] = array( + 'address_id' => null, + 'firstname' => null, + 'lastname' => null, + 'company' => null, + 'address_1' => null, + 'address_2' => null, + 'postcode' => null, + 'city' => null, + 'zone_id' => $zone_info['zone_id'], + 'zone' => $zone_info['name'], + 'zone_code' => $zone_info['code'], + 'country_id' => $country_info['country_id'], + 'country' => $country_info['name'], + 'iso_code_2' => $country_info['iso_code_2'], + 'iso_code_3' => $country_info['iso_code_3'], + 'address_format' => '', + 'custom_field' => array() + ); + } + + $this->tax->setPaymentAddress($this->session->data['payment_address']['country_id'], $this->session->data['payment_address']['zone_id']); + $this->tax->setStoreAddress($this->config->get('config_country_id'), $this->config->get('config_zone_id')); + } + + private function setShipping() { + $this->load->model('account/address'); + $this->load->model('localisation/country'); + $this->load->model('localisation/zone'); + + if (isset($this->session->data['shipping_address']) && !empty($this->session->data['shipping_address'])) { + $this->session->data['shipping_address'] = $this->session->data['shipping_address']; + } elseif ($this->customer->isLogged() && $this->customer->getAddressId()) { + $this->session->data['shipping_address'] = $this->model_account_address->getAddress($this->customer->getAddressId()); + } else { + $country_info = $this->model_localisation_country->getCountry($this->config->get('config_country_id')); + + $zone_info = $this->model_localisation_zone->getZone($this->config->get('config_zone_id')); + + $this->session->data['shipping_address'] = array( + 'address_id' => null, + 'firstname' => null, + 'lastname' => null, + 'company' => null, + 'address_1' => null, + 'address_2' => null, + 'postcode' => null, + 'city' => null, + 'zone_id' => $zone_info['zone_id'], + 'zone' => $zone_info['name'], + 'zone_code' => $zone_info['code'], + 'country_id' => $country_info['country_id'], + 'country' => $country_info['name'], + 'iso_code_2' => $country_info['iso_code_2'], + 'iso_code_3' => $country_info['iso_code_3'], + 'address_format' => '', + 'custom_field' => array() + ); + } + + $this->tax->unsetRates(); + $this->tax->setShippingAddress($this->session->data['shipping_address']['country_id'], $this->session->data['shipping_address']['zone_id']); + $this->tax->setStoreAddress($this->config->get('config_country_id'), $this->config->get('config_zone_id')); + + if (isset($this->session->data['shipping_address'])) { + // Shipping Methods + $method_data = array(); + + $this->load->model('setting/extension'); + + $results = $this->model_setting_extension->getExtensions('shipping'); + + foreach ($results as $result) { + if ($this->config->get('shipping_' . $result['code'] . '_status')) { + $this->load->model('extension/shipping/' . $result['code']); + + $quote = $this->{'model_extension_shipping_' . $result['code']}->getQuote($this->session->data['shipping_address']); + + if ($quote) { + $method_data[$result['code']] = array( + 'title' => $quote['title'], + 'quote' => $quote['quote'], + 'sort_order' => $quote['sort_order'], + 'error' => $quote['error'] + ); + } + } + } + + $sort_order = array(); + + foreach ($method_data as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $method_data); + + $this->session->data['shipping_methods'] = $method_data; + } + } + + private function createOrder() { + //Klarna defaults: + $this->session->data['comment'] = ''; + + if (!$this->customer->isLogged()) { + $this->session->data['guest'] = array( + 'customer_group_id' => $this->config->get('config_customer_group_id'), + 'firstname' => '', + 'lastname' => '', + 'email' => '', + 'telephone' => '', + 'fax' => '', + 'custom_field' => array(), + ); + } + + //OpenCart: + $order_data = array(); + + list($totals, $taxes, $total) = $this->model_extension_payment_klarna_checkout->getTotals(); + + $order_data['totals'] = $totals; + + $this->load->language('checkout/checkout'); + + $order_data['invoice_prefix'] = $this->config->get('config_invoice_prefix'); + $order_data['store_id'] = $this->config->get('config_store_id'); + $order_data['store_name'] = $this->config->get('config_name'); + + if ($order_data['store_id']) { + $order_data['store_url'] = $this->config->get('config_url'); + } else { + $order_data['store_url'] = HTTP_SERVER; + } + + if ($this->customer->isLogged()) { + $this->load->model('account/customer'); + + $customer_info = $this->model_account_customer->getCustomer($this->customer->getId()); + + $order_data['customer_id'] = $this->customer->getId(); + $order_data['customer_group_id'] = $customer_info['customer_group_id']; + $order_data['firstname'] = $customer_info['firstname']; + $order_data['lastname'] = $customer_info['lastname']; + $order_data['email'] = $customer_info['email']; + $order_data['telephone'] = $customer_info['telephone']; + $order_data['custom_field'] = json_decode($customer_info['custom_field'], true); + } elseif (isset($this->session->data['guest'])) { + $order_data['customer_id'] = 0; + $order_data['customer_group_id'] = $this->session->data['guest']['customer_group_id']; + $order_data['firstname'] = $this->session->data['guest']['firstname']; + $order_data['lastname'] = $this->session->data['guest']['lastname']; + $order_data['email'] = $this->session->data['guest']['email']; + $order_data['telephone'] = $this->session->data['guest']['telephone']; + $order_data['custom_field'] = $this->session->data['guest']['custom_field']; + } + + $order_data['payment_firstname'] = $this->session->data['payment_address']['firstname']; + $order_data['payment_lastname'] = $this->session->data['payment_address']['lastname']; + $order_data['payment_company'] = $this->session->data['payment_address']['company']; + $order_data['payment_address_1'] = $this->session->data['payment_address']['address_1']; + $order_data['payment_address_2'] = $this->session->data['payment_address']['address_2']; + $order_data['payment_city'] = $this->session->data['payment_address']['city']; + $order_data['payment_postcode'] = $this->session->data['payment_address']['postcode']; + $order_data['payment_zone'] = $this->session->data['payment_address']['zone']; + $order_data['payment_zone_id'] = $this->session->data['payment_address']['zone_id']; + $order_data['payment_country'] = $this->session->data['payment_address']['country']; + $order_data['payment_country_id'] = $this->session->data['payment_address']['country_id']; + $order_data['payment_address_format'] = $this->session->data['payment_address']['address_format']; + $order_data['payment_custom_field'] = (isset($this->session->data['payment_address']['custom_field']) ? $this->session->data['payment_address']['custom_field'] : array()); + + if (isset($this->session->data['payment_method']['title'])) { + $order_data['payment_method'] = $this->session->data['payment_method']['title']; + } else { + $order_data['payment_method'] = ''; + } + + if (isset($this->session->data['payment_method']['code'])) { + $order_data['payment_code'] = $this->session->data['payment_method']['code']; + } else { + $order_data['payment_code'] = ''; + } + + if ($this->cart->hasShipping()) { + $order_data['shipping_firstname'] = $this->session->data['shipping_address']['firstname']; + $order_data['shipping_lastname'] = $this->session->data['shipping_address']['lastname']; + $order_data['shipping_company'] = $this->session->data['shipping_address']['company']; + $order_data['shipping_address_1'] = $this->session->data['shipping_address']['address_1']; + $order_data['shipping_address_2'] = $this->session->data['shipping_address']['address_2']; + $order_data['shipping_city'] = $this->session->data['shipping_address']['city']; + $order_data['shipping_postcode'] = $this->session->data['shipping_address']['postcode']; + $order_data['shipping_zone'] = $this->session->data['shipping_address']['zone']; + $order_data['shipping_zone_id'] = $this->session->data['shipping_address']['zone_id']; + $order_data['shipping_country'] = $this->session->data['shipping_address']['country']; + $order_data['shipping_country_id'] = $this->session->data['shipping_address']['country_id']; + $order_data['shipping_address_format'] = $this->session->data['shipping_address']['address_format']; + $order_data['shipping_custom_field'] = (isset($this->session->data['shipping_address']['custom_field']) ? $this->session->data['shipping_address']['custom_field'] : array()); + + if (isset($this->session->data['shipping_method']['title'])) { + $order_data['shipping_method'] = $this->session->data['shipping_method']['title']; + } else { + $order_data['shipping_method'] = ''; + } + + if (isset($this->session->data['shipping_method']['code'])) { + $order_data['shipping_code'] = $this->session->data['shipping_method']['code']; + } else { + $order_data['shipping_code'] = ''; + } + } else { + $order_data['shipping_firstname'] = ''; + $order_data['shipping_lastname'] = ''; + $order_data['shipping_company'] = ''; + $order_data['shipping_address_1'] = ''; + $order_data['shipping_address_2'] = ''; + $order_data['shipping_city'] = ''; + $order_data['shipping_postcode'] = ''; + $order_data['shipping_zone'] = ''; + $order_data['shipping_zone_id'] = ''; + $order_data['shipping_country'] = ''; + $order_data['shipping_country_id'] = ''; + $order_data['shipping_address_format'] = ''; + $order_data['shipping_custom_field'] = array(); + $order_data['shipping_method'] = ''; + $order_data['shipping_code'] = ''; + } + + $order_data['products'] = array(); + + foreach ($this->cart->getProducts() as $product) { + $option_data = array(); + + foreach ($product['option'] as $option) { + $option_data[] = array( + 'product_option_id' => $option['product_option_id'], + 'product_option_value_id' => $option['product_option_value_id'], + 'option_id' => $option['option_id'], + 'option_value_id' => $option['option_value_id'], + 'name' => $option['name'], + 'value' => $option['value'], + 'type' => $option['type'] + ); + } + + $order_data['products'][] = array( + 'product_id' => $product['product_id'], + 'name' => $product['name'], + 'model' => $product['model'], + 'option' => $option_data, + 'download' => $product['download'], + 'quantity' => $product['quantity'], + 'subtract' => $product['subtract'], + 'price' => $product['price'], + 'total' => $product['total'], + 'tax' => $this->tax->getTax($product['price'], $product['tax_class_id']), + 'reward' => $product['reward'] + ); + } + + // Gift Voucher + $order_data['vouchers'] = array(); + + if (!empty($this->session->data['vouchers'])) { + foreach ($this->session->data['vouchers'] as $voucher) { + $order_data['vouchers'][] = array( + 'description' => $voucher['description'], + 'code' => token(10), + 'to_name' => $voucher['to_name'], + 'to_email' => $voucher['to_email'], + 'from_name' => $voucher['from_name'], + 'from_email' => $voucher['from_email'], + 'voucher_theme_id' => $voucher['voucher_theme_id'], + 'message' => $voucher['message'], + 'amount' => $voucher['amount'] + ); + } + } + + $order_data['comment'] = $this->session->data['comment']; + $order_data['total'] = $total; + + if (isset($this->request->cookie['tracking'])) { + $order_data['tracking'] = $this->request->cookie['tracking']; + + $subtotal = $this->cart->getSubTotal(); + + // Affiliate + $this->load->model('affiliate/affiliate'); + + $affiliate_info = $this->model_affiliate_affiliate->getAffiliateByCode($this->request->cookie['tracking']); + + if ($affiliate_info) { + $order_data['affiliate_id'] = $affiliate_info['affiliate_id']; + $order_data['commission'] = ($subtotal / 100) * $affiliate_info['commission']; + } else { + $order_data['affiliate_id'] = 0; + $order_data['commission'] = 0; + } + + // Marketing + $this->load->model('checkout/marketing'); + + $marketing_info = $this->model_checkout_marketing->getMarketingByCode($this->request->cookie['tracking']); + + if ($marketing_info) { + $order_data['marketing_id'] = $marketing_info['marketing_id']; + } else { + $order_data['marketing_id'] = 0; + } + } else { + $order_data['affiliate_id'] = 0; + $order_data['commission'] = 0; + $order_data['marketing_id'] = 0; + $order_data['tracking'] = ''; + } + + $order_data['language_id'] = $this->config->get('config_language_id'); + $order_data['currency_id'] = $this->currency->getId($this->session->data['currency']); + $order_data['currency_code'] = $this->session->data['currency']; + $order_data['currency_value'] = $this->currency->getValue($this->session->data['currency']); + $order_data['ip'] = $this->request->server['REMOTE_ADDR']; + + if (!empty($this->request->server['HTTP_X_FORWARDED_FOR'])) { + $order_data['forwarded_ip'] = $this->request->server['HTTP_X_FORWARDED_FOR']; + } elseif (!empty($this->request->server['HTTP_CLIENT_IP'])) { + $order_data['forwarded_ip'] = $this->request->server['HTTP_CLIENT_IP']; + } else { + $order_data['forwarded_ip'] = ''; + } + + if (isset($this->request->server['HTTP_USER_AGENT'])) { + $order_data['user_agent'] = $this->request->server['HTTP_USER_AGENT']; + } else { + $order_data['user_agent'] = ''; + } + + if (isset($this->request->server['HTTP_ACCEPT_LANGUAGE'])) { + $order_data['accept_language'] = $this->request->server['HTTP_ACCEPT_LANGUAGE']; + } else { + $order_data['accept_language'] = ''; + } + + $this->load->model('checkout/order'); + + $this->session->data['order_id'] = $this->model_checkout_order->addOrder($order_data); + } + + private function klarnaOrderData($klarna_account) { + $this->load->language('extension/payment/klarna_checkout'); + + $this->load->model('extension/payment/klarna_checkout'); + $this->load->model('localisation/country'); + + $currency_code = $this->session->data['currency']; + $currency_value = $this->currency->getValue($this->session->data['currency']); + + // Shipping + $unset_shipping_method = true; + if (isset($this->session->data['shipping_method']) && isset($this->session->data['shipping_methods'])) { + foreach ($this->session->data['shipping_methods'] as $shipping_method) { + if ($shipping_method['quote']) { + foreach ($shipping_method['quote'] as $quote) { + if ($quote == $this->session->data['shipping_method']) { + $unset_shipping_method = false; + break 2; + } + } + } + } + } + + if ($unset_shipping_method) { + unset($this->session->data['shipping_method']); + } + + if ((!isset($this->session->data['shipping_method']) || empty($this->session->data['shipping_method'])) && (isset($this->session->data['shipping_methods']) && !empty($this->session->data['shipping_methods']))) { + $this->session->data['shipping_method'] = $this->model_extension_payment_klarna_checkout->getDefaultShippingMethod($this->session->data['shipping_methods']); + } + + //Check if customer is US. If so, send taxes differently + if ($this->session->data['shipping_address']['iso_code_2'] === 'US') { + $include_taxes = false; + } else { + $include_taxes = true; + } + + if ($this->cart->hasShipping() && isset($this->session->data['shipping_method']) && !empty($this->session->data['shipping_method'])) { + $total_amount = $this->currency->format($this->tax->calculate($this->session->data['shipping_method']['cost'], $this->session->data['shipping_method']['tax_class_id'], $include_taxes), $currency_code, $currency_value, false) * 100; + + if ($include_taxes) { + $total_tax_amount = $this->currency->format($this->tax->getTax($this->session->data['shipping_method']['cost'], $this->session->data['shipping_method']['tax_class_id']), $currency_code, $currency_value, false) * 100; + } else { + $total_tax_amount = 0; + } + + $total_sub_amount = $this->currency->format($this->tax->calculate($this->session->data['shipping_method']['cost'], $this->session->data['shipping_method']['tax_class_id'], false), $currency_code, $currency_value, false) * 100; + + $tax_rate = 0; + + if ($include_taxes && $total_tax_amount && $total_sub_amount) { + $tax_rate = ($total_tax_amount / $total_sub_amount) * 100; + } + + $klarna_order_data['order_lines'][] = array( + 'type' => 'shipping_fee', + 'name' => $this->session->data['shipping_method']['title'], + 'quantity' => '1', + 'unit_price' => round($this->currency->format($this->tax->calculate($this->session->data['shipping_method']['cost'], $this->session->data['shipping_method']['tax_class_id'], $include_taxes), $currency_code, $currency_value, false) * 100), + 'tax_rate' => round($tax_rate * 100), + 'total_amount' => round($total_amount), + 'total_tax_amount' => round($total_tax_amount), + 'total_discount_amount' => 0 + ); + } + + // Billing Address + if (isset($this->session->data['klarna_checkout_data'])) { + $klarna_order_data['billing_address'] = array( + 'given_name' => $this->session->data['klarna_checkout_data']['firstname'], + 'family_name' => $this->session->data['klarna_checkout_data']['lastname'], + 'email' => $this->session->data['klarna_checkout_data']['email'], + 'phone' => $this->session->data['klarna_checkout_data']['telephone'], + 'postal_code' => $this->session->data['shipping_address']['postcode'], + 'region' => $this->session->data['shipping_address']['zone_code'], + 'country' => $this->session->data['shipping_address']['iso_code_2'], + ); + } else { + $klarna_order_data['billing_address'] = array( + 'given_name' => $this->session->data['shipping_address']['firstname'], + 'family_name' => $this->session->data['shipping_address']['lastname'], + 'email' => ($this->customer->isLogged() ? $this->customer->getEmail() : null), + 'phone' => ($this->customer->isLogged() ? $this->customer->getTelephone() : null) + ); + } + + // Order Total + list($totals, $taxes, $total) = $this->model_extension_payment_klarna_checkout->getTotals(); + + $merchant_urls = array( + 'checkout' => html_entity_decode($this->url->link('extension/payment/klarna_checkout', 'klarna_order_id={checkout.order.id}', true)), + 'confirmation' => html_entity_decode($this->url->link('extension/payment/klarna_checkout/confirmation', 'klarna_order_id={checkout.order.id}', true)), + 'push' => html_entity_decode($this->url->link('extension/payment/klarna_checkout/push', 'klarna_order_id={checkout.order.id}', true)), + 'validation' => html_entity_decode($this->url->link('extension/payment/klarna_checkout/validation', 'klarna_order_id={checkout.order.id}', true)), + 'address_update' => html_entity_decode($this->url->link('extension/payment/klarna_checkout/addressUpdate', 'klarna_order_id={checkout.order.id}', true)), + 'notification' => html_entity_decode($this->url->link('extension/payment/klarna_checkout/notification', 'klarna_order_id={checkout.order.id}', true)), + ); + + if ($this->config->get('klarna_checkout_terms')) { + $merchant_urls['terms'] = html_entity_decode($this->url->link('information/information', 'information_id=' . $this->config->get('klarna_checkout_terms'), true)); + } + + $country_info = $this->model_localisation_country->getCountry($klarna_account['country']); + + if ($country_info) { + $klarna_order_data['purchase_country'] = $country_info['iso_code_2']; + } + + $klarna_order_data['purchase_currency'] = $currency_code; + $klarna_order_data['locale'] = $klarna_account['locale']; + + $klarna_order_data['order_amount'] = round($this->currency->format($total, $currency_code, $currency_value, false) * 100); + $klarna_order_data['order_tax_amount'] = round($this->currency->format(array_sum($taxes), $currency_code, $currency_value, false) * 100); + + $klarna_order_data['merchant_urls'] = $merchant_urls; + + // Callback data to be used to spoof/simulate customer to accurately calculate shipping + $encrypted_order_data = $this->encryption->encrypt($this->config->get('config_encryption'), json_encode(array( + 'session_id' => session_id(), + 'session_key' => $this->session->getId(), + 'customer_id' => $this->customer->getId(), + 'order_id' => $this->session->data['order_id'], + 'merchant_id' => $klarna_account['merchant_id'], + 'secret' => $klarna_account['secret'] + ))); + + $encrypted_order_id = $this->encryption->encrypt($this->config->get('config_encryption'), $this->session->data['order_id']); + + $klarna_order_data['merchant_reference1'] = $this->session->data['order_id']; + + $klarna_order_data['options'] = array(); + + if ($this->config->get('klarna_checkout_colour_button')) { + $klarna_order_data['options']['color_button'] = $this->config->get('klarna_checkout_colour_button'); + } + + if ($this->config->get('klarna_checkout_colour_button_text')) { + $klarna_order_data['options']['color_button_text'] = $this->config->get('klarna_checkout_colour_button_text'); + } + + if ($this->config->get('klarna_checkout_colour_checkbox')) { + $klarna_order_data['options']['color_checkbox'] = $this->config->get('klarna_checkout_colour_checkbox'); + } + + if ($this->config->get('klarna_checkout_colour_checkbox_checkmark')) { + $klarna_order_data['options']['color_checkbox_checkmark'] = $this->config->get('klarna_checkout_colour_checkbox_checkmark'); + } + + if ($this->config->get('klarna_checkout_colour_header')) { + $klarna_order_data['options']['color_header'] = $this->config->get('klarna_checkout_colour_header'); + } + + if ($this->config->get('klarna_checkout_colour_link')) { + $klarna_order_data['options']['color_link'] = $this->config->get('klarna_checkout_colour_link'); + } + + if ($this->config->get('klarna_checkout_separate_shipping_address')) { + $klarna_order_data['options']['allow_separate_shipping_address'] = true; + } + + // Only pass DOB/title mandatory for UK stores + if ($country_info['iso_code_2'] == 'GB') { + if ($this->config->get('klarna_checkout_dob_mandatory')) { + $klarna_order_data['options']['date_of_birth_mandatory'] = true; + } + + if ($this->config->get('klarna_checkout_title_mandatory')) { + $klarna_order_data['options']['title_mandatory'] = true; + } + } + + if ($this->config->get('klarna_checkout_additional_text_box') && $this->customer->isLogged() && !$this->customer->getNewsletter()) { + $klarna_order_data['options']['additional_checkbox'] = array( + 'text' => $this->language->get('text_newsletter'), + 'checked' => false, + 'required' => false + ); + } + + $shipping_countries = $this->model_extension_payment_klarna_checkout->getCountriesByGeoZone($klarna_account['shipping']); + + $klarna_shipping_countries = array(); + foreach ($shipping_countries as $shipping_country) { + $country_info = $this->model_localisation_country->getCountry($shipping_country['country_id']); + + if ($country_info && $country_info['iso_code_2']) { + $klarna_shipping_countries[] = $country_info['iso_code_2']; + } + } + + $klarna_order_data['shipping_countries'] = $klarna_shipping_countries; + + $average_product_tax_rate = array(); + + // Products (Add these last because we send encrypted session order_id) + foreach ($this->cart->getProducts() as $product) { + $total_amount = $this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id'], $include_taxes) * $product['quantity'], $currency_code, $currency_value, false) * 100; + + if ($include_taxes) { + $total_tax_amount = $this->currency->format($this->tax->getTax($product['price'], $product['tax_class_id']) * $product['quantity'], $currency_code, $currency_value, false) * 100; + } else { + $total_tax_amount = 0; + } + + $total_sub_amount = $this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id'], false) * $product['quantity'], $currency_code, $currency_value, false) * 100; + + $tax_rate = 0; + + if ($include_taxes && $total_tax_amount && $total_sub_amount) { + $tax_rate = ($total_tax_amount / $total_sub_amount) * 100; + } + + $average_product_tax_rate[] = round($tax_rate * 100); + + $klarna_order_data['order_lines'][] = array( + 'type' => ($product['shipping'] ? 'physical' : 'digital'), + 'reference' => $product['model'], + 'name' => $product['name'], + 'quantity' => $product['quantity'], + 'quantity_unit' => 'pcs', + 'unit_price' => round($this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id'], $include_taxes), $currency_code, $currency_value, false) * 100), + 'tax_rate' => round($tax_rate * 100), + 'total_amount' => round($total_amount), + 'total_tax_amount' => round($total_tax_amount), + 'merchant_data' => $encrypted_order_id, + 'total_discount_amount' => 0 + ); + } + + // Gift Voucher + if (!empty($this->session->data['vouchers'])) { + foreach ($this->session->data['vouchers'] as $key => $voucher) { + $klarna_order_data['order_lines'][] = array( + 'type' => 'gift_card', + 'reference' => '', + 'name' => $voucher['description'], + 'quantity' => 1, + 'quantity_unit' => 'pcs', + 'unit_price' => round($this->currency->format($voucher['amount'], $currency_code, $currency_value, false) * 100), + 'tax_rate' => 0, + 'total_amount' => round($this->currency->format($voucher['amount'], $currency_code, $currency_value, false) * 100), + 'total_tax_amount' => 0, + 'merchant_data' => $encrypted_order_id, + 'total_discount_amount' => 0 + ); + } + } + + foreach ($totals as $result) { + if ($result['code'] == 'coupon') { + $discount_total_price = 0; + $discount_sub_total_price = 0; + foreach ($this->cart->getProducts() as $product) { + $discount_total_price += $this->tax->calculate($result['value'], $product['tax_class_id'], $include_taxes); + $discount_sub_total_price += $result['value']; + } + + $average_discount_total_price = $discount_total_price / count($average_product_tax_rate); + + $average_discount_sub_total_price = $discount_sub_total_price / count($average_product_tax_rate); + + $total_tax_amount = ($average_discount_sub_total_price / 100) * (array_sum($average_product_tax_rate) / count($average_product_tax_rate)); + + $klarna_order_data['order_lines'][] = array( + 'type' => 'discount', + 'name' => $result['title'], + 'quantity' => '1', + 'unit_price' => round($this->currency->format($average_discount_total_price, $currency_code, $currency_value, false) * 100), + 'tax_rate' => array_sum($average_product_tax_rate) / count($average_product_tax_rate), + 'total_amount' => round($this->currency->format($average_discount_total_price, $currency_code, $currency_value, false) * 100), + 'total_tax_amount' => round($total_tax_amount), + 'total_discount_amount' => 0 + ); + } + + if ($result['code'] == 'voucher') { + $klarna_order_data['order_lines'][] = array( + 'type' => 'discount', + 'name' => $result['title'], + 'quantity' => '1', + 'unit_price' => round($this->currency->format($result['value'], $currency_code, $currency_value, false) * 100), + 'tax_rate' => 0, + 'total_amount' => round($this->currency->format($result['value'], $currency_code, $currency_value, false) * 100), + 'total_tax_amount' => 0, + 'total_discount_amount' => 0 + ); + } + } + + //If $include_taxes is false, means customer is US so we add a new sales_tax order line with all the tax + if (!$include_taxes) { + $klarna_order_data['order_lines'][] = array( + 'type' => 'sales_tax', + 'name' => $this->language->get('text_sales_tax'), + 'quantity' => '1', + 'unit_price' => round($this->currency->format(array_sum($taxes), $currency_code, $currency_value, false) * 100), + 'tax_rate' => 0, + 'total_amount' => round($this->currency->format(array_sum($taxes), $currency_code, $currency_value, false) * 100), + 'total_tax_amount' => 0, + 'total_discount_amount' => 0 + ); + } + + return array($klarna_order_data, $encrypted_order_data); + } +} diff --git a/public/catalog/controller/extension/payment/klarna_invoice.php b/public/catalog/controller/extension/payment/klarna_invoice.php new file mode 100644 index 0000000..8b3feae --- /dev/null +++ b/public/catalog/controller/extension/payment/klarna_invoice.php @@ -0,0 +1,527 @@ +<?php +class ControllerExtensionPaymentKlarnaInvoice extends Controller { + public function index() { + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if ($order_info) { + $this->load->language('extension/payment/klarna_invoice'); + + $data['days'] = array(); + + for ($i = 1; $i <= 31; $i++) { + $data['days'][] = array( + 'text' => sprintf('%02d', $i), + 'value' => $i + ); + } + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => sprintf('%02d', $i), + 'value' => $i + ); + } + + $data['years'] = array(); + + for ($i = date('Y'); $i >= 1900; $i--) { + $data['years'][] = array( + 'text' => $i, + 'value' => $i + ); + } + + // Store Taxes to send to Klarna + $total_data = array(); + $total = 0; + + $this->load->model('setting/extension'); + + $sort_order = array(); + + $results = $this->model_setting_extension->getExtensions('total'); + + foreach ($results as $key => $value) { + $sort_order[$key] = $this->config->get('total_' . $value['code'] . '_sort_order'); + } + + array_multisort($sort_order, SORT_ASC, $results); + + $klarna_tax = array(); + + foreach ($results as $result) { + if ($this->config->get($result['code'] . '_status')) { + $this->load->model('extension/total/' . $result['code']); + + $taxes = array(); + + // We have to put the totals in an array so that they pass by reference. + $this->{'model_extension_total_' . $result['code']}->getTotal(array("totals"=>$total_data, "total"=>$total, "taxes"=>$taxes)); + + $amount = 0; + + foreach ($taxes as $tax_id => $value) { + $amount += $value; + } + + $klarna_tax[$result['code']] = $amount; + } + } + + foreach ($total_data as $key => $value) { + $sort_order[$key] = $value['sort_order']; + + if (isset($klarna_tax[$value['code']])) { + if ($klarna_tax[$value['code']]) { + $total_data[$key]['tax_rate'] = abs($klarna_tax[$value['code']] / $value['value'] * 100); + } else { + $total_data[$key]['tax_rate'] = 0; + } + } else { + $total_data[$key]['tax_rate'] = '0'; + } + } + + $this->session->data['klarna'][$this->session->data['order_id']] = $total_data; + + // Order must have identical shipping and billing address or have no shipping address at all + if ($this->cart->hasShipping() && !($order_info['payment_firstname'] == $order_info['shipping_firstname'] && $order_info['payment_lastname'] == $order_info['shipping_lastname'] && $order_info['payment_address_1'] == $order_info['shipping_address_1'] && $order_info['payment_address_2'] == $order_info['shipping_address_2'] && $order_info['payment_postcode'] == $order_info['shipping_postcode'] && $order_info['payment_city'] == $order_info['shipping_city'] && $order_info['payment_zone_id'] == $order_info['shipping_zone_id'] && $order_info['payment_zone_code'] == $order_info['shipping_zone_code'] && $order_info['payment_country_id'] == $order_info['shipping_country_id'] && $order_info['payment_country'] == $order_info['shipping_country'] && $order_info['payment_iso_code_3'] == $order_info['shipping_iso_code_3'])) { + $data['error_warning'] = $this->language->get('error_address_match'); + } else { + $data['error_warning'] = ''; + } + + $klarna_invoice = $this->config->get('payment_klarna_invoice'); + + $data['merchant'] = $klarna_invoice[$order_info['payment_iso_code_3']]['merchant']; + $data['phone_number'] = $order_info['telephone']; + + if ($order_info['payment_iso_code_3'] == 'DEU' || $order_info['payment_iso_code_3'] == 'NLD') { + $address = $this->splitAddress($order_info['payment_address_1']); + + $data['street'] = $address[0]; + $data['street_number'] = $address[1]; + $data['street_extension'] = $address[2]; + + if ($order_info['payment_iso_code_3'] == 'DEU') { + $data['street_number'] = trim($address[1] . ' ' . $address[2]); + } + } else { + $data['street'] = ''; + $data['street_number'] = ''; + $data['street_extension'] = ''; + } + + $data['company'] = $order_info['payment_company']; + $data['iso_code_2'] = $order_info['payment_iso_code_2']; + $data['iso_code_3'] = $order_info['payment_iso_code_3']; + + // Get the invoice fee + $query = $this->db->query("SELECT `value` FROM `" . DB_PREFIX . "order_total` WHERE `order_id` = " . (int)$order_info['order_id'] . " AND `code` = 'klarna_fee'"); + + if ($query->num_rows && !$query->row['value']) { + $data['klarna_fee'] = $query->row['value']; + } else { + $data['klarna_fee'] = ''; + } + + return $this->load->view('extension/payment/klarna_invoice', $data); + } + } + + public function send() { + $this->load->language('extension/payment/klarna_invoice'); + + $json = array(); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + // Order must have identical shipping and billing address or have no shipping address at all + if ($order_info) { + if ($order_info['payment_iso_code_3'] == 'DEU' && empty($this->request->post['deu_terms'])) { + $json['error'] = $this->language->get('error_deu_terms'); + } + + if ($this->cart->hasShipping() && !($order_info['payment_firstname'] == $order_info['shipping_firstname'] && $order_info['payment_lastname'] == $order_info['shipping_lastname'] && $order_info['payment_address_1'] == $order_info['shipping_address_1'] && $order_info['payment_address_2'] == $order_info['shipping_address_2'] && $order_info['payment_postcode'] == $order_info['shipping_postcode'] && $order_info['payment_city'] == $order_info['shipping_city'] && $order_info['payment_zone_id'] == $order_info['shipping_zone_id'] && $order_info['payment_zone_code'] == $order_info['shipping_zone_code'] && $order_info['payment_country_id'] == $order_info['shipping_country_id'] && $order_info['payment_country'] == $order_info['shipping_country'] && $order_info['payment_iso_code_3'] == $order_info['shipping_iso_code_3'])) { + $json['error'] = $this->language->get('error_address_match'); + } + + if (!$json) { + $klarna_invoice = $this->config->get('payment_klarna_invoice'); + + if ($klarna_invoice[$order_info['payment_iso_code_3']]['server'] == 'live') { + $url = 'https://payment.klarna.com/'; + } else { + $url = 'https://payment.testdrive.klarna.com/'; + } + + $country_to_currency = array( + 'NOR' => 'NOK', + 'SWE' => 'SEK', + 'FIN' => 'EUR', + 'DNK' => 'DKK', + 'DEU' => 'EUR', + 'NLD' => 'EUR' + ); + + switch ($order_info['payment_iso_code_3']) { + // Sweden + case 'SWE': + $country = 209; + $language = 138; + $encoding = 2; + $currency = 0; + break; + // Finland + case 'FIN': + $country = 73; + $language = 37; + $encoding = 4; + $currency = 2; + break; + // Denmark + case 'DNK': + $country = 59; + $language = 27; + $encoding = 5; + $currency = 3; + break; + // Norway + case 'NOR': + $country = 164; + $language = 97; + $encoding = 3; + $currency = 1; + break; + // Germany + case 'DEU': + $country = 81; + $language = 28; + $encoding = 6; + $currency = 2; + break; + // Netherlands + case 'NLD': + $country = 154; + $language = 101; + $encoding = 7; + $currency = 2; + break; + } + + if (isset($this->request->post['street'])) { + $street = $this->request->post['street']; + } else { + $street = $order_info['payment_address_1']; + } + + if (isset($this->request->post['house_no'])) { + $house_no = $this->request->post['house_no']; + } else { + $house_no = ''; + } + + if (isset($this->request->post['house_ext'])) { + $house_ext = $this->request->post['house_ext']; + } else { + $house_ext = ''; + } + + $address = array( + 'email' => $order_info['email'], + 'telno' => $this->request->post['phone_no'], + 'cellno' => '', + 'fname' => $order_info['payment_firstname'], + 'lname' => $order_info['payment_lastname'], + 'company' => $order_info['payment_company'], + 'careof' => '', + 'street' => $street, + 'house_number' => $house_no, + 'house_extension' => $house_ext, + 'zip' => $order_info['payment_postcode'], + 'city' => $order_info['payment_city'], + 'country' => $country, + ); + + $product_query = $this->db->query("SELECT `name`, `model`, `price`, `quantity`, `tax` / `price` * 100 AS 'tax_rate' FROM `" . DB_PREFIX . "order_product` WHERE `order_id` = " . (int)$order_info['order_id'] . " UNION ALL SELECT '', `code`, `amount`, '1', 0.00 FROM `" . DB_PREFIX . "order_voucher` WHERE `order_id` = " . (int)$order_info['order_id']); + + foreach ($product_query->rows as $product) { + $goods_list[] = array( + 'qty' => (int)$product['quantity'], + 'goods' => array( + 'artno' => $product['model'], + 'title' => $product['name'], + 'price' => (int)str_replace('.', '', $this->currency->format($product['price'], $country_to_currency[$order_info['payment_iso_code_3']], '', false)), + 'vat' => (float)$product['tax_rate'], + 'discount' => 0.0, + 'flags' => 0 + ) + ); + } + + if (isset($this->session->data['klarna'][$this->session->data['order_id']])) { + $totals = $this->session->data['klarna'][$this->session->data['order_id']]; + } else { + $totals = array(); + } + + foreach ($totals as $total) { + if ($total['code'] != 'sub_total' && $total['code'] != 'tax' && $total['code'] != 'total') { + $goods_list[] = array( + 'qty' => 1, + 'goods' => array( + 'artno' => '', + 'title' => $total['title'], + 'price' => (int)str_replace('.', '', $this->currency->format($total['value'], $country_to_currency[$order_info['payment_iso_code_3']], '', false)), + 'vat' => (float)$total['tax_rate'], + 'discount' => 0.0, + 'flags' => 0 + ) + ); + } + } + + $digest = ''; + + foreach ($goods_list as $goods) { + $digest .= utf8_decode(htmlspecialchars(html_entity_decode($goods['goods']['title'], ENT_COMPAT, 'UTF-8'))) . ':'; + } + + $digest = base64_encode(pack('H*', hash('sha256', $digest . $klarna_invoice[$order_info['payment_iso_code_3']]['secret']))); + + if (isset($this->request->post['pno'])) { + $pno = $this->request->post['pno']; + } else { + $pno = sprintf('%02d', (int)$this->request->post['pno_day']) . sprintf('%02d', (int)$this->request->post['pno_month']) . (int)$this->request->post['pno_year']; + } + + $pclass = -1; + + if (isset($this->request->post['gender']) && ($order_info['payment_iso_code_3'] == 'DEU' || $order_info['payment_iso_code_3'] == 'NLD')) { + $gender = (int)$this->request->post['gender']; + } else { + $gender = ''; + } + + $transaction = array( + '4.1', + 'API:OPENCART:' . VERSION, + $pno, + $gender, + '', + '', + (string)$order_info['order_id'], + '', + $address, + $address, + $order_info['ip'], + 0, + $currency, + $country, + $language, + (int)$klarna_invoice[$order_info['payment_iso_code_3']]['merchant'], + $digest, + $encoding, + $pclass, + $goods_list, + $order_info['comment'], + array('delay_adjust' => 1), + array(), + array(), + array(), + array(), + array() + ); + + $xml = '<methodCall>'; + $xml .= ' <methodName>add_invoice</methodName>'; + $xml .= ' <params>'; + + foreach ($transaction as $parameter) { + $xml .= ' <param><value>' . $this->constructXmlrpc($parameter) . '</value></param>'; + } + + $xml .= ' </params>'; + $xml .= '</methodCall>'; + + $header = array(); + + $header[] = 'Content-Type: text/xml'; + $header[] = 'Content-Length: ' . strlen($xml); + + $curl = curl_init(); + + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST'); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_HTTPHEADER, $header); + curl_setopt($curl, CURLOPT_POSTFIELDS, $xml); + + $response = curl_exec($curl); + + if (curl_errno($curl)) { + $log = new Log('klarna_invoice.log'); + $log->write('HTTP Error for order #' . $order_info['order_id'] . '. Code: ' . curl_errno($curl) . ' message: ' . curl_error($curl)); + + $json['error'] = $this->language->get('error_network'); + } else { + preg_match('/<member><name>faultString<\/name><value><string>(.+)<\/string><\/value><\/member>/', $response, $match); + + if (isset($match[1])) { + preg_match('/<member><name>faultCode<\/name><value><int>([0-9]+)<\/int><\/value><\/member>/', $response, $match2); + + $log = new Log('klarna_invoice.log'); + $log->write('Failed to create an invoice for order #' . $order_info['order_id'] . '. Message: ' . utf8_encode($match[1]) . ' Code: ' . $match2[1]); + + $json['error'] = utf8_encode($match[1]); + } else { + $xml = new DOMDocument(); + $xml->loadXML($response); + + $invoice_number = $xml->getElementsByTagName('string')->item(0)->nodeValue; + $klarna_order_status = $xml->getElementsByTagName('int')->item(0)->nodeValue; + + if ($klarna_order_status == '1') { + $order_status = $klarna_invoice[$order_info['payment_iso_code_3']]['accepted_status_id']; + } elseif ($klarna_order_status == '2') { + $order_status = $klarna_invoice[$order_info['payment_iso_code_3']]['pending_status_id']; + } else { + $order_status = $this->config->get('config_order_status_id'); + } + + $comment = sprintf($this->language->get('text_comment'), $invoice_number, $this->config->get('config_currency'), $country_to_currency[$order_info['payment_iso_code_3']], $this->currency->getValue($country_to_currency[$order_info['payment_iso_code_3']])); + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $order_status, $comment, 1); + + $json['redirect'] = $this->url->link('checkout/success'); + } + } + + curl_close($curl); + } + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + private function constructXmlrpc($data) { + $type = gettype($data); + + switch ($type) { + case 'boolean': + if ($data == true) { + $value = 1; + } else { + $value = false; + } + + $xml = '<boolean>' . $value . '</boolean>'; + break; + case 'integer': + $xml = '<int>' . (int)$data . '</int>'; + break; + case 'double': + $xml = '<double>' . (float)$data . '</double>'; + break; + case 'string': + $xml = '<string>' . htmlspecialchars($data) . '</string>'; + break; + case 'array': + // is numeric ? + if ($data === array_values($data)) { + $xml = '<array><data>'; + + foreach ($data as $value) { + $xml .= '<value>' . $this->constructXmlrpc($value) . '</value>'; + } + + $xml .= '</data></array>'; + + } else { + // array is associative + $xml = '<struct>'; + + foreach ($data as $key => $value) { + $xml .= '<member>'; + $xml .= ' <name>' . htmlspecialchars($key) . '</name>'; + $xml .= ' <value>' . $this->constructXmlrpc($value) . '</value>'; + $xml .= '</member>'; + } + + $xml .= '</struct>'; + } + + break; + default: + $xml = '<nil/>'; + break; + } + + return $xml; + } + + private function splitAddress($address) { + $numbers = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + $characters = array('-', '/', ' ', '#', '.', 'a', 'b', 'c', 'd', 'e', + 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', + 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', + 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z'); + + $specialchars = array('-', '/', ' ', '#', '.'); + + $num_pos = $this->strposArr($address, $numbers, 2); + + $street_name = substr($address, 0, $num_pos); + + $street_name = trim($street_name); + + $number_part = substr($address, $num_pos); + + $number_part = trim($number_part); + + $ext_pos = $this->strposArr($number_part, $characters, 0); + + if ($ext_pos != '') { + $house_number = substr($number_part, 0, $ext_pos); + + $house_extension = substr($number_part, $ext_pos); + + $house_extension = str_replace($specialchars, '', $house_extension); + } else { + $house_number = $number_part; + $house_extension = ''; + } + + return array($street_name, $house_number, $house_extension); + } + + private function strposArr($haystack, $needle, $where) { + $defpos = 10000; + + if (!is_array($needle)) { + $needle = array($needle); + } + + foreach ($needle as $what) { + if (($pos = strpos($haystack, $what, $where)) !== false) { + if ($pos < $defpos) { + $defpos = $pos; + } + } + } + + return $defpos; + } +} diff --git a/public/catalog/controller/extension/payment/laybuy.php b/public/catalog/controller/extension/payment/laybuy.php new file mode 100644 index 0000000..433aaf0 --- /dev/null +++ b/public/catalog/controller/extension/payment/laybuy.php @@ -0,0 +1,478 @@ +<?php +class ControllerExtensionPaymentLaybuy extends Controller { + public function index() { + $this->load->language('extension/payment/laybuy'); + + $this->load->model('extension/payment/laybuy'); + + $this->load->model('checkout/order'); + + $data['action'] = $this->url->link('extension/payment/laybuy/postToLaybuy', '', true); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $data['order_info'] = $order_info; + + $data['total'] = $order_info['total']; + + $data['currency_symbol_left'] = $this->currency->getSymbolLeft($this->session->data['currency']); + + $data['currency_symbol_right'] = $this->currency->getSymbolRight($this->session->data['currency']); + + $data['initial_payments'] = $this->model_extension_payment_laybuy->getInitialPayments(); + + $data['months'] = $this->model_extension_payment_laybuy->getMonths(); + + return $this->load->view('extension/payment/laybuy', $data); + } + + public function postToLaybuy() { + $this->load->model('extension/payment/laybuy'); + + $this->model_extension_payment_laybuy->log('Posting to Laybuy'); + + if ($this->request->server['REQUEST_METHOD'] == 'POST') { + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if ($order_info) { + $this->model_extension_payment_laybuy->log('Order ID: ' . $order_info['order_id']); + + $data = array(); + + $data['VERSION'] = '0.2'; + $data['MEMBER'] = $this->config->get('payment_laybuys_membership_id'); + $data['RETURNURL'] = $this->url->link('extension/payment/laybuy/callback', '', true); + $data['CANCELURL'] = $this->url->link('extension/payment/laybuy/cancel', '', true); + $data['AMOUNT'] = round(floatval($order_info['total']), 2, PHP_ROUND_HALF_DOWN); + $data['CURRENCY'] = $order_info['currency_code']; + $data['INIT'] = (int)$this->request->post['INIT']; + $data['MONTHS'] = (int)$this->request->post['MONTHS']; + $data['MIND'] = ((int)$this->config->get('payment_laybuy_min_deposit')) ? (int)$this->config->get('payment_laybuy_min_deposit') : 20; + $data['MAXD'] = ((int)$this->config->get('payment_laybuy_max_deposit')) ? (int)$this->config->get('payment_laybuy_max_deposit') : 50; + $data['CUSTOM'] = $order_info['order_id'] . ':' . md5($this->config->get('payment_laybuy_token')); + $data['EMAIL'] = $order_info['email']; + + $data_string = ''; + + foreach ($data as $param => $value) { + $data_string .= $param . '=' . $value . '&'; + } + + $data_string = rtrim($data_string, '&'); + + $this->model_extension_payment_laybuy->log('Data String: ' . $data_string); + + $this->model_extension_payment_laybuy->log('Gateway URL: ' . $this->config->get('payment_laybuy_gateway_url')); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $this->config->get('payment_laybuy_gateway_url')); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HEADER, false); + curl_setopt($ch, CURLOPT_TIMEOUT, 30); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + $result = curl_exec($ch); + if (curl_errno($ch)) { + $this->model_extension_payment_laybuy->log('cURL error: ' . curl_errno($ch)); + } + curl_close($ch); + + $result = json_decode($result, true); + + $this->model_extension_payment_laybuy->log('Response: ' . print_r($result, true)); + + if (isset($result['ACK']) && isset($result['TOKEN']) && $result['ACK'] == 'SUCCESS') { + $this->model_extension_payment_laybuy->log('Success response. Redirecting to PayPal.'); + + $this->response->redirect($this->config->get('payment_laybuy_gateway_url') . '?TOKEN=' . $result['TOKEN']); + } else { + $this->model_extension_payment_laybuy->log('Failure response. Redirecting to checkout/failure.'); + + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + } else { + $this->model_extension_payment_laybuy->log('No matching order. Redirecting to checkout/failure.'); + + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + } else { + $this->model_extension_payment_laybuy->log('No $_POST data. Redirecting to checkout/failure.'); + + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + } + + public function callback() { + $this->load->model('extension/payment/laybuy'); + + $this->model_extension_payment_laybuy->log('Receiving callback'); + + if ($this->request->server['REQUEST_METHOD'] == 'POST' && isset($this->request->post['RESULT']) && $this->request->post['RESULT'] == 'SUCCESS') { + $this->load->model('checkout/order'); + + $custom = $this->request->post['CUSTOM']; + + $custom = explode(':', $custom); + + $order_id = $custom[0]; + + $token = $custom[1]; + + $this->model_extension_payment_laybuy->log('Received Token: ' . $token); + + $this->model_extension_payment_laybuy->log('Actual Token: ' . md5($this->config->get('payment_laybuy_token'))); + + if (hash_equals(md5($this->config->get('payment_laybuy_token')), $token)) { + $this->model_extension_payment_laybuy->log('Order ID: ' . $order_id); + + $order_info = $this->model_checkout_order->getOrder($order_id); + + if ($order_info) { + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_laybuy_order_status_id_pending')); + + $transaction_report = $this->model_extension_payment_laybuy->prepareTransactionReport($this->request->post); + + $this->model_extension_payment_laybuy->addTransaction($transaction_report, 1); + + $this->model_extension_payment_laybuy->log('Success. Redirecting to checkout/success.'); + + $this->response->redirect($this->url->link('checkout/success', '', true)); + } else { + $this->model_extension_payment_laybuy->log('No matching order. Redirecting to checkout/failure.'); + + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + } else { + $this->model_extension_payment_laybuy->log('Token does not match. Redirecting to checkout/failure.'); + + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + } elseif ($this->request->server['REQUEST_METHOD'] == 'POST' && isset($this->request->post['RESULT']) && $this->request->post['RESULT'] == 'FAILURE') { + $this->model_extension_payment_laybuy->log('Failure Response: ' . $this->request->post); + + $this->model_extension_payment_laybuy->log('Redirecting to checkout/failure.'); + + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } else { + $this->model_extension_payment_laybuy->log('Either no $_POST data or unknown response. Redirecting to checkout/failure.'); + + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + } + + public function cancel() { + $this->load->model('extension/payment/laybuy'); + + $this->model_extension_payment_laybuy->log('Transaction canceled by user. Redirecting to checkout/checkout.'); + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + + public function reviseCallback() { + $this->load->model('extension/payment/laybuy'); + + $this->load->language('extension/payment/laybuy'); + + $this->model_extension_payment_laybuy->log('Receiving callback'); + + if ($this->request->server['REQUEST_METHOD'] == 'POST') { + if (isset($this->request->post['RESULT']) && $this->request->post['RESULT'] == 'SUCCESS') { + $this->load->model('checkout/order'); + + $custom = $this->request->post['CUSTOM']; + + $custom = explode(':', $custom); + + $order_id = $custom[0]; + + $token = $custom[1]; + + $this->model_extension_payment_laybuy->log('Received Token: ' . $token); + + $this->model_extension_payment_laybuy->log('Actual Token: ' . md5($this->config->get('payment_laybuy_token'))); + + if (hash_equals(md5($this->config->get('payment_laybuy_token')), $token)) { + $this->model_extension_payment_laybuy->log('Order ID: ' . $order_id); + + $order_info = $this->model_checkout_order->getOrder($order_id); + + if ($order_info) { + $response = $this->request->post; + + $this->model_extension_payment_laybuy->log('Response: ' . print_r($response, true)); + + $revised_transaction_id = $response['MERCHANTS_REF_NO']; + + $revised_transaction = $this->model_extension_payment_laybuy->getRevisedTransaction($revised_transaction_id); + + $this->model_extension_payment_laybuy->log('Revised transaction: ' . print_r($revised_transaction, true)); + + $status = 1; + + $current_date = date('Y-m-d h:i:s'); + + if (!isset($response['DOWNPAYMENT']) && !$revised_transaction['payment_type']) { + $this->model_extension_payment_laybuy->log('Buy-Now'); + + $response['DOWNPAYMENT'] = 100; + $response['MONTHS'] = 0; + $response['DOWNPAYMENT_AMOUNT'] = $response['AMOUNT']; + $response['PAYMENT_AMOUNTS'] = 0; + $response['FIRST_PAYMENT_DUE'] = $current_date; + $response['LAST_PAYMENT_DUE'] = $current_date; + $response['PAYPAL_PROFILE_ID'] = ''; + + $status = 5; + + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_laybuy_order_status_id_processing'), $this->language->get('text_comment')); + } else { + $this->model_extension_payment_laybuy->log('Lay-Buy'); + } + + $this->session->data['order_id'] = $order_id; + + $transaction_report = $this->model_extension_payment_laybuy->prepareTransactionReport($response); + + $transaction_report['order_id'] = $order_id; + + $this->model_extension_payment_laybuy->addTransaction($transaction_report, $status); + + $old_transaction = $this->model_extension_payment_laybuy->getTransaction($revised_transaction['laybuy_transaction_id']); + + $report_content = json_decode($old_transaction['report'], true); + + foreach ($report_content as &$array) { + $array['status'] = str_replace('Pending', 'Canceled', $array['status']); + } + + $report_content = json_encode($report_content); + + if ($old_transaction['paypal_profile_id']) { + $this->model_extension_payment_laybuy->log('Canceling transaction'); + + $data_string = 'mid=' . $this->config->get('payment_laybuys_membership_id') . '&' . 'paypal_profile_id=' . $old_transaction['paypal_profile_id']; + + $this->model_extension_payment_laybuy->log('Data String: ' . $data_string); + + $ch = curl_init(); + $url = 'https://lay-buys.com/vtmob/deal5cancel.php'; + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HEADER, false); + curl_setopt($ch, CURLOPT_TIMEOUT, 30); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + $result = curl_exec($ch); + if (curl_errno($ch)) { + $this->model_extension_payment_laybuy->log('cURL error: ' . curl_errno($ch)); + } + curl_close($ch); + + $this->model_extension_payment_laybuy->log('Response: ' . $result); + + if ($result == 'success') { + $this->model_extension_payment_laybuy->log('Success'); + } else { + $this->model_extension_payment_laybuy->log('Failure'); + } + } else { + $this->model_extension_payment_laybuy->log('Transaction has no paypal_profile_id'); + } + + $this->model_extension_payment_laybuy->updateTransaction($old_transaction['laybuy_transaction_id'], '51', $report_content, $old_transaction['transaction']); + + $this->model_extension_payment_laybuy->deleteRevisedTransaction($revised_transaction['laybuy_revise_request_id']); + + $this->response->redirect($this->url->link('checkout/success', '', true)); + } else { + $this->model_extension_payment_laybuy->log('No matching order. Redirecting to checkout/failure.'); + + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + } else { + $this->model_extension_payment_laybuy->log('Token does not match. Redirecting to checkout/failure.'); + + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + } else { + $this->model_extension_payment_laybuy->log('No success response'); + + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + } else { + $this->model_extension_payment_laybuy->log('No $_POST data'); + + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + } + + public function reviseCancel() { + $this->load->model('extension/payment/laybuy'); + + $this->model_extension_payment_laybuy->log('Revise canceled. Redirecting to checkout/checkout.'); + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + + public function deleteOrder($route = '', $output = '', $order_id = 0, $order_status_id = 0) { + $this->load->model('extension/payment/laybuy'); + + if (isset($this->session->data['api_id'])) { + $this->model_extension_payment_laybuy->log('Deleting order #' . $order_id); + + $this->model_extension_payment_laybuy->deleteTransactionByOrderId($order_id); + } else { + $this->model_extension_payment_laybuy->log('No API ID in session'); + } + } + + public function cron() { + $this->load->model('extension/payment/laybuy'); + + $this->load->language('extension/payment/laybuy'); + + $this->model_extension_payment_laybuy->log('Running cron'); + + if (isset($this->request->get['token']) && hash_equals($this->config->get('payment_laybuy_token'), $this->request->get['token'])) { + $paypal_profile_id_array = $this->model_extension_payment_laybuy->getPayPalProfileIds(); + + if ($paypal_profile_id_array) { + $paypal_profile_ids = ''; + + foreach ($paypal_profile_id_array as $profile_id) { + $paypal_profile_ids .= $profile_id['paypal_profile_id'] . ','; + } + + $paypal_profile_ids = rtrim($paypal_profile_ids, ','); + + $data_string = 'mid=' . $this->config->get('payment_laybuys_membership_id') . '&' . 'profileIds=' . $paypal_profile_ids; + + $this->model_extension_payment_laybuy->log('Data String: ' . $data_string); + + $this->model_extension_payment_laybuy->log('API URL: ' . $this->config->get('payment_laybuy_api_url')); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $this->config->get('payment_laybuy_api_url')); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HEADER, false); + curl_setopt($ch, CURLOPT_TIMEOUT, 30); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + $result = curl_exec($ch); + if (curl_errno($ch)) { + $this->model_extension_payment_laybuy->log('cURL error: ' . curl_errno($ch)); + } + curl_close($ch); + + $results = json_decode($result, true); + + $this->model_extension_payment_laybuy->log('Response: ' . print_r($results, true)); + + if ($results) { + $this->load->model('checkout/order'); + + foreach ($results as $laybuy_ref_id => $reports) { + $status = $reports['status']; + + $report = $reports['report']; + + $transaction = array(); + + $transaction = $this->model_extension_payment_laybuy->getTransactionByLayBuyRefId($laybuy_ref_id); + + $order_id = $transaction['order_id']; + + $paypal_profile_id = $transaction['paypal_profile_id']; + + $months = $transaction['months']; + + $report_content = array(); + + $pending_flag = false; + + $next_payment_status = $this->language->get('text_status_1'); + + foreach ($report as $month => $payment) { + $payment['paymentDate'] = date('Y-m-d h:i:s', strtotime(str_replace('/', '-', $payment['paymentDate']))); + $date = date($this->language->get('date_format_short'), strtotime($payment['paymentDate'])); + $next_payment_date = $payment['paymentDate']; + + if ($payment['type'] == 'd') { + $report_content[] = array( + 'instalment' => 0, + 'amount' => $this->currency->format($payment['amount'], $transaction['currency']), + 'date' => $date, + 'pp_trans_id' => $payment['txnID'], + 'status' => $payment['paymentStatus'] + ); + } elseif ($payment['type'] == 'p') { + $pending_flag = true; + + $report_content[] = array( + 'instalment' => $month, + 'amount' => $this->currency->format($payment['amount'], $transaction['currency']), + 'date' => $date, + 'pp_trans_id' => $payment['txnID'], + 'status' => $payment['paymentStatus'] + ); + + $next_payment_status = $payment['paymentStatus']; + } + } + + if ($pending_flag) { + $start_index = $month + 1; + } else { + $start_index = $month + 2; + } + + if ($month < $months) { + for ($month = 1; $month <= $months; $month++) { + $next_payment_date = date("Y-m-d h:i:s", strtotime($next_payment_date . " +1 month")); + $date = date($this->language->get('date_format_short'), strtotime($next_payment_date)); + + $report_content[] = array( + 'instalment' => $month, + 'amount' => $this->currency->format($transaction['payment_amounts'], $transaction['currency']), + 'date' => $date, + 'pp_trans_id' => '', + 'status' => $next_payment_status + ); + } + } + + $report_content = json_encode($report_content); + + switch ($status) { + case -1: // Cancel + $this->model_extension_payment_laybuy->log('Transaction #' . $transaction['laybuy_transaction_id'] . ' canceled'); + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_laybuy_order_status_id_canceled'), $this->language->get('text_comment'), false, false); + $this->model_extension_payment_laybuy->updateTransaction($transaction['laybuy_transaction_id'], '7', $report_content, $start_index); + break; + case 0: // Pending + $this->model_extension_payment_laybuy->log('Transaction #' . $transaction['laybuy_transaction_id'] . ' still pending'); + $this->model_extension_payment_laybuy->updateTransaction($transaction['laybuy_transaction_id'], $transaction['status'], $report_content, $start_index); + break; + case 1: // Paid + $this->model_extension_payment_laybuy->log('Transaction #' . $transaction['laybuy_transaction_id'] . ' paid'); + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_laybuy_order_status_id_processing'), $this->language->get('text_comment'), false, false); + $this->model_extension_payment_laybuy->updateTransaction($transaction['laybuy_transaction_id'], '5', $report_content, $start_index); + break; + } + } + } + } else { + $this->model_extension_payment_laybuy->log('No PayPal Profile IDs to update'); + } + + $this->model_extension_payment_laybuy->updateCronRunTime(); + } else { + $this->model_extension_payment_laybuy->log('Token does not match.'); + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/liqpay.php b/public/catalog/controller/extension/payment/liqpay.php new file mode 100644 index 0000000..a2c7171 --- /dev/null +++ b/public/catalog/controller/extension/payment/liqpay.php @@ -0,0 +1,46 @@ +<?php +class ControllerExtensionPaymentLiqPay extends Controller { + public function index() { + $data['button_confirm'] = $this->language->get('button_confirm'); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $data['action'] = 'https://liqpay.com/?do=clickNbuy'; + + $xml = '<request>'; + $xml .= ' <version>1.2</version>'; + $xml .= ' <result_url>' . $this->url->link('checkout/success', '', true) . '</result_url>'; + $xml .= ' <server_url>' . $this->url->link('extension/payment/liqpay/callback', '', true) . '</server_url>'; + $xml .= ' <merchant_id>' . $this->config->get('payment_liqpay_merchant') . '</merchant_id>'; + $xml .= ' <order_id>' . $this->session->data['order_id'] . '</order_id>'; + $xml .= ' <amount>' . $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false) . '</amount>'; + $xml .= ' <currency>' . $order_info['currency_code'] . '</currency>'; + $xml .= ' <description>' . $this->config->get('config_name') . ' ' . $order_info['payment_firstname'] . ' ' . $order_info['payment_address_1'] . ' ' . $order_info['payment_address_2'] . ' ' . $order_info['payment_city'] . ' ' . $order_info['email'] . '</description>'; + $xml .= ' <default_phone></default_phone>'; + $xml .= ' <pay_way>' . $this->config->get('payment_liqpay_type') . '</pay_way>'; + $xml .= '</request>'; + + $data['xml'] = base64_encode($xml); + $data['signature'] = base64_encode(sha1($this->config->get('payment_liqpay_signature') . $xml . $this->config->get('payment_liqpay_signature'), true)); + + return $this->load->view('extension/payment/liqpay', $data); + } + + public function callback() { + $xml = base64_decode($this->request->post['operation_xml']); + $signature = base64_encode(sha1($this->config->get('payment_liqpay_signature') . $xml . $this->config->get('payment_liqpay_signature'), true)); + + $posleft = strpos($xml, 'order_id'); + $posright = strpos($xml, '/order_id'); + + $order_id = substr($xml, $posleft + 9, $posright - $posleft - 10); + + if ($signature == $this->request->post['signature']) { + $this->load->model('checkout/order'); + + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('config_order_status_id')); + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/nochex.php b/public/catalog/controller/extension/payment/nochex.php new file mode 100644 index 0000000..7e42536 --- /dev/null +++ b/public/catalog/controller/extension/payment/nochex.php @@ -0,0 +1,125 @@ +<?php +// Nochex via form will work for both simple "Seller" account and "Merchant" account holders +// Nochex via APC maybe only avaiable to "Merchant" account holders only - site docs a bit vague on this point +class ControllerExtensionPaymentNochex extends Controller { + public function index() { + $this->load->language('extension/payment/nochex'); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $data['action'] = 'https://secure.nochex.com/'; + + // Nochex minimum requirements + // The merchant ID is usually your Nochex registered email address but can be altered for "Merchant" accounts see below + if ($this->config->get('payment_nochex_email') != $this->config->get('payment_nochex_merchant')) { + // This MUST be changed on your Nochex account!!!! + $data['merchant_id'] = $this->config->get('payment_nochex_merchant'); + } else { + $data['merchant_id'] = $this->config->get('payment_nochex_email'); + } + + $data['amount'] = $this->currency->format($order_info['total'], 'GBP', false, false); + $data['order_id'] = $this->session->data['order_id']; + $data['description'] = $this->config->get('config_name'); + + $data['billing_fullname'] = $order_info['payment_firstname'] . ' ' . $order_info['payment_lastname']; + + if ($order_info['payment_address_2']) { + $data['billing_address'] = $order_info['payment_address_1'] . "\r\n" . $order_info['payment_address_2'] . "\r\n" . $order_info['payment_city'] . "\r\n" . $order_info['payment_zone'] . "\r\n"; + } else { + $data['billing_address'] = $order_info['payment_address_1'] . "\r\n" . $order_info['payment_city'] . "\r\n" . $order_info['payment_zone'] . "\r\n"; + } + + $data['billing_postcode'] = $order_info['payment_postcode']; + + if ($this->cart->hasShipping()) { + $data['delivery_fullname'] = $order_info['shipping_firstname'] . ' ' . $order_info['shipping_lastname']; + + if ($order_info['shipping_address_2']) { + $data['delivery_address'] = $order_info['shipping_address_1'] . "\r\n" . $order_info['shipping_address_2'] . "\r\n" . $order_info['shipping_city'] . "\r\n" . $order_info['shipping_zone'] . "\r\n"; + } else { + $data['delivery_address'] = $order_info['shipping_address_1'] . "\r\n" . $order_info['shipping_city'] . "\r\n" . $order_info['shipping_zone'] . "\r\n"; + } + + $data['delivery_postcode'] = $order_info['shipping_postcode']; + } else { + $data['delivery_fullname'] = $order_info['payment_firstname'] . ' ' . $order_info['payment_lastname']; + + if ($order_info['payment_address_2']) { + $data['delivery_address'] = $order_info['payment_address_1'] . "\r\n" . $order_info['payment_address_2'] . "\r\n" . $order_info['payment_city'] . "\r\n" . $order_info['payment_zone'] . "\r\n"; + } else { + $data['delivery_address'] = $order_info['shipping_address_1'] . "\r\n" . $order_info['payment_city'] . "\r\n" . $order_info['payment_zone'] . "\r\n"; + } + + $data['delivery_postcode'] = $order_info['payment_postcode']; + } + + $data['email_address'] = $order_info['email']; + $data['customer_phone_number']= $order_info['telephone']; + $data['test'] = $this->config->get('payment_nochex_test'); + $data['success_url'] = $this->url->link('checkout/success', '', true); + $data['cancel_url'] = $this->url->link('checkout/payment', '', true); + $data['declined_url'] = $this->url->link('extension/payment/nochex/callback', 'method=decline', true); + $data['callback_url'] = $this->url->link('extension/payment/nochex/callback', 'order=' . $this->session->data['order_id'], true); + + return $this->load->view('extension/payment/nochex', $data); + } + + public function callback() { + $this->load->language('extension/payment/nochex'); + + if (isset($this->request->get['method']) && $this->request->get['method'] == 'decline') { + $this->session->data['error'] = $this->language->get('error_declined'); + + $this->response->redirect($this->url->link('checkout/cart')); + } + + if (isset($this->request->post['order_id'])) { + $order_id = $this->request->post['order_id']; + } else { + $order_id = 0; + } + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($order_id); + + if (!$order_info) { + $this->session->data['error'] = $this->language->get('error_no_order'); + + $this->response->redirect($this->url->link('checkout/cart')); + } + + // Fraud Verification Step. + $request = ''; + + foreach ($this->request->post as $key => $value) { + $request .= '&' . $key . '=' . urlencode(stripslashes($value)); + } + + $curl = curl_init('https://www.nochex.com/nochex.dll/apc/apc'); + + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, trim($request, '&')); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HEADER, false); + curl_setopt($curl, CURLOPT_TIMEOUT, 30); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + + $response = curl_exec($curl); + + curl_close($curl); + + if (strcmp($response, 'AUTHORISED') == 0) { + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_nochex_order_status_id')); + } else { + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('config_order_status_id'), 'Auto-Verification step failed. Manually check the transaction.'); + } + + // Since it returned, the customer should see success. + // It's up to the store owner to manually verify payment. + $this->response->redirect($this->url->link('checkout/success', '', true)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/paymate.php b/public/catalog/controller/extension/payment/paymate.php new file mode 100644 index 0000000..e35ae3a --- /dev/null +++ b/public/catalog/controller/extension/payment/paymate.php @@ -0,0 +1,105 @@ +<?php +class ControllerExtensionPaymentPaymate extends Controller { + public function index() { + if (!$this->config->get('payment_paymate_test')) { + $data['action'] = 'https://www.paymate.com/PayMate/ExpressPayment'; + } else { + $data['action'] = 'https://www.paymate.com.au/PayMate/TestExpressPayment'; + } + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $data['mid'] = $this->config->get('payment_paymate_username'); + $data['amt'] = $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false); + + $data['currency'] = $order_info['currency_code']; + $data['ref'] = $order_info['order_id']; + + $data['pmt_sender_email'] = $order_info['email']; + $data['pmt_contact_firstname'] = $order_info['payment_firstname']; + $data['pmt_contact_surname'] = $order_info['payment_lastname']; + $data['pmt_contact_phone'] = $order_info['telephone']; + $data['pmt_country'] = $order_info['payment_iso_code_2']; + + $data['regindi_address1'] = $order_info['payment_address_1']; + $data['regindi_address2'] = $order_info['payment_address_2']; + $data['regindi_sub'] = $order_info['payment_city']; + $data['regindi_state'] = $order_info['payment_zone']; + $data['regindi_pcode'] = $order_info['payment_postcode']; + + $data['return'] = $this->url->link('extension/payment/paymate/callback', 'hash=' . md5($order_info['order_id'] . $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false) . $order_info['currency_code'] . $this->config->get('payment_paymate_password'))); + + return $this->load->view('extension/payment/paymate', $data); + } + + public function callback() { + $this->load->language('extension/payment/paymate'); + + if (isset($this->request->post['ref'])) { + $order_id = $this->request->post['ref']; + } else { + $order_id = 0; + } + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($order_id); + + if ($order_info) { + $error = ''; + + if (!isset($this->request->post['responseCode']) || !isset($this->request->get['hash'])) { + $error = $this->language->get('text_unable'); + } elseif ($this->request->get['hash'] != md5($order_info['order_id'] . $this->currency->format($this->request->post['paymentAmount'], $this->request->post['currency'], 1.0000000, false) . $this->request->post['currency'] . $this->config->get('payment_paymate_password'))) { + $error = $this->language->get('text_unable'); + } elseif ($this->request->post['responseCode'] != 'PA' && $this->request->post['responseCode'] != 'PP') { + $error = $this->language->get('text_declined'); + } + } else { + $error = $this->language->get('text_unable'); + } + + if ($error) { + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_home'), + 'href' => $this->url->link('common/home') + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_basket'), + 'href' => $this->url->link('checkout/cart') + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_checkout'), + 'href' => $this->url->link('checkout/checkout', '', true) + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_failed'), + 'href' => $this->url->link('checkout/success') + ); + + $data['text_message'] = sprintf($this->language->get('text_failed_message'), $error, $this->url->link('information/contact')); + + $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('common/success', $data)); + } else { + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_paymate_order_status_id')); + + $this->response->redirect($this->url->link('checkout/success')); + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/paypoint.php b/public/catalog/controller/extension/payment/paypoint.php new file mode 100644 index 0000000..06f7a92 --- /dev/null +++ b/public/catalog/controller/extension/payment/paypoint.php @@ -0,0 +1,161 @@ +<?php +class ControllerExtensionPaymentPaypoint extends Controller { + public function index() { + $data['button_confirm'] = $this->language->get('button_confirm'); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $data['merchant'] = $this->config->get('payment_paypoint_merchant'); + $data['trans_id'] = $this->session->data['order_id']; + $data['amount'] = $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false); + + if ($this->config->get('payment_paypoint_password')) { + $data['digest'] = md5($this->session->data['order_id'] . $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false) . $this->config->get('payment_paypoint_password')); + } else { + $data['digest'] = ''; + } + + $data['bill_name'] = $order_info['payment_firstname'] . ' ' . $order_info['payment_lastname']; + $data['bill_addr_1'] = $order_info['payment_address_1']; + $data['bill_addr_2'] = $order_info['payment_address_2']; + $data['bill_city'] = $order_info['payment_city']; + $data['bill_state'] = $order_info['payment_zone']; + $data['bill_post_code'] = $order_info['payment_postcode']; + $data['bill_country'] = $order_info['payment_country']; + $data['bill_tel'] = $order_info['telephone']; + $data['bill_email'] = $order_info['email']; + + if ($this->cart->hasShipping()) { + $data['ship_name'] = $order_info['shipping_firstname'] . ' ' . $order_info['shipping_lastname']; + $data['ship_addr_1'] = $order_info['shipping_address_1']; + $data['ship_addr_2'] = $order_info['shipping_address_2']; + $data['ship_city'] = $order_info['shipping_city']; + $data['ship_state'] = $order_info['shipping_zone']; + $data['ship_post_code'] = $order_info['shipping_postcode']; + $data['ship_country'] = $order_info['shipping_country']; + } else { + $data['ship_name'] = ''; + $data['ship_addr_1'] = ''; + $data['ship_addr_2'] = ''; + $data['ship_city'] = ''; + $data['ship_state'] = ''; + $data['ship_post_code'] = ''; + $data['ship_country'] = ''; + } + + $data['currency'] = $this->session->data['currency']; + $data['callback'] = $this->url->link('extension/payment/paypoint/callback', '', true); + + switch ($this->config->get('payment_paypoint_test')) { + case 'live': + $status = 'live'; + break; + case 'successful': + default: + $status = 'true'; + break; + case 'fail': + $status = 'false'; + break; + } + + $data['options'] = 'test_status=' . $status . ',dups=false,cb_post=false'; + + return $this->load->view('extension/payment/paypoint', $data); + } + + public function callback() { + if (isset($this->request->get['trans_id'])) { + $order_id = $this->request->get['trans_id']; + } else { + $order_id = 0; + } + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($order_id); + + // Validate the request is from PayPoint + if ($this->config->get('payment_paypoint_password')) { + if (!empty($this->request->get['hash'])) { + $status = ($this->request->get['hash'] == md5(str_replace('hash=' . $this->request->get['hash'], '', htmlspecialchars_decode($this->request->server['REQUEST_URI'], ENT_COMPAT)) . $this->config->get('payment_paypoint_password'))); + } else { + $status = false; + } + } else { + $status = true; + } + + if ($order_info) { + $this->load->language('extension/payment/paypoint'); + + $data['title'] = sprintf($this->language->get('heading_title'), $this->config->get('config_name')); + + if (!$this->request->server['HTTPS']) { + $data['base'] = HTTP_SERVER; + } else { + $data['base'] = HTTPS_SERVER; + } + + $data['language'] = $this->language->get('code'); + $data['direction'] = $this->language->get('direction'); + + $data['heading_title'] = sprintf($this->language->get('heading_title'), $this->config->get('config_name')); + + $data['text_success_wait'] = sprintf($this->language->get('text_success_wait'), $this->url->link('checkout/success')); + $data['text_failure_wait'] = sprintf($this->language->get('text_failure_wait'), $this->url->link('checkout/cart')); + + if (isset($this->request->get['code']) && $this->request->get['code'] == 'A' && $status) { + $message = ''; + + if (isset($this->request->get['code'])) { + $message .= 'code: ' . $this->request->get['code'] . "\n"; + } + + if (isset($this->request->get['auth_code'])) { + $message .= 'auth_code: ' . $this->request->get['auth_code'] . "\n"; + } + + if (isset($this->request->get['ip'])) { + $message .= 'ip: ' . $this->request->get['ip'] . "\n"; + } + + if (isset($this->request->get['cv2avs'])) { + $message .= 'cv2avs: ' . $this->request->get['cv2avs'] . "\n"; + } + + if (isset($this->request->get['valid'])) { + $message .= 'valid: ' . $this->request->get['valid'] . "\n"; + } + + $this->load->model('checkout/order'); + + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_paypoint_order_status_id'), $message, false); + + $data['continue'] = $this->url->link('checkout/success'); + + $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/paypoint_success', $data)); + } else { + $data['continue'] = $this->url->link('checkout/cart'); + + $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/paypoint_failure', $data)); + } + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/payza.php b/public/catalog/controller/extension/payment/payza.php new file mode 100644 index 0000000..15b3434 --- /dev/null +++ b/public/catalog/controller/extension/payment/payza.php @@ -0,0 +1,31 @@ +<?php +class ControllerExtensionPaymentPayza extends Controller { + public function index() { + $data['button_confirm'] = $this->language->get('button_confirm'); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $data['action'] = 'https://secure.payza.com/checkout'; + + $data['ap_merchant'] = $this->config->get('payment_payza_merchant'); + $data['ap_amount'] = $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false); + $data['ap_currency'] = $order_info['currency_code']; + $data['ap_purchasetype'] = 'Item'; + $data['ap_itemname'] = $this->config->get('config_name') . ' - #' . $this->session->data['order_id']; + $data['ap_itemcode'] = $this->session->data['order_id']; + $data['ap_returnurl'] = $this->url->link('checkout/success'); + $data['ap_cancelurl'] = $this->url->link('checkout/checkout', '', true); + + return $this->load->view('extension/payment/payza', $data); + } + + public function callback() { + if (isset($this->request->post['ap_securitycode']) && ($this->request->post['ap_securitycode'] == $this->config->get('payment_payza_security'))) { + $this->load->model('checkout/order'); + + $this->model_checkout_order->addOrderHistory($this->request->post['ap_itemcode'], $this->config->get('payment_payza_order_status_id')); + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/perpetual_payments.php b/public/catalog/controller/extension/payment/perpetual_payments.php new file mode 100644 index 0000000..a0cb9f5 --- /dev/null +++ b/public/catalog/controller/extension/payment/perpetual_payments.php @@ -0,0 +1,115 @@ +<?php +class ControllerExtensionPaymentPerpetualPayments extends Controller { + public function index() { + $this->load->language('extension/payment/perpetual_payments'); + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['year_valid'] = array(); + + for ($i = $today['year'] - 10; $i < $today['year'] + 1; $i++) { + $data['year_valid'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + $data['year_expire'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['year_expire'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + return $this->load->view('extension/payment/perpetual_payments', $data); + } + + public function send() { + $this->load->language('extension/payment/perpetual_payments'); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $payment_data = array( + 'auth_id' => $this->config->get('payment_perpetual_payments_auth_id'), + 'auth_pass' => $this->config->get('payment_perpetual_payments_auth_pass'), + 'card_num' => str_replace(' ', '', $this->request->post['cc_number']), + 'card_cvv' => $this->request->post['cc_cvv2'], + 'card_start' => $this->request->post['cc_start_date_month'] . substr($this->request->post['cc_start_date_year'], 2), + 'card_expiry' => $this->request->post['cc_expire_date_month'] . substr($this->request->post['cc_expire_date_year'], 2), + 'cust_name' => $order_info['payment_firstname'] . ' ' . $order_info['payment_lastname'], + 'cust_address' => $order_info['payment_address_1'] . ' ' . $order_info['payment_city'], + 'cust_country' => $order_info['payment_iso_code_2'], + 'cust_postcode' => $order_info['payment_postcode'], + 'cust_tel' => $order_info['telephone'], + 'cust_ip' => $this->request->server['REMOTE_ADDR'], + 'cust_email' => $order_info['email'], + 'tran_ref' => $order_info['order_id'], + 'tran_amount' => $this->currency->format($order_info['total'], $order_info['currency_code'], 1.00000, false), + 'tran_currency' => $order_info['currency_code'], + 'tran_testmode' => $this->config->get('payment_perpetual_payments_test'), + 'tran_type' => 'Sale', + 'tran_class' => 'MoTo', + ); + + $curl = curl_init('https://secure.voice-pay.com/gateway/remote'); + + curl_setopt($curl, CURLOPT_PORT, 443); + curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_FORBID_REUSE, 1); + curl_setopt($curl, CURLOPT_FRESH_CONNECT, 1); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($payment_data)); + + $response = curl_exec($curl); + + curl_close($curl); + + if ($response) { + $data = explode('|', $response); + + if (isset($data[0]) && $data[0] == 'A') { + $message = ''; + + if (isset($data[1])) { + $message .= $this->language->get('text_transaction') . ' ' . $data[1] . "\n"; + } + + if (isset($data[2])) { + if ($data[2] == '232') { + $message .= $this->language->get('text_avs') . ' ' . $this->language->get('text_avs_full_match') . "\n"; + } elseif ($data[2] == '400') { + $message .= $this->language->get('text_avs') . ' ' . $this->language->get('text_avs_not_match') . "\n"; + } + } + + if (isset($data[3])) { + $message .= $this->language->get('text_authorisation') . ' ' . $data[3] . "\n"; + } + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_perpetual_payments_order_status_id'), $message, false); + + $json['redirect'] = $this->url->link('checkout/success'); + } else { + $json['error'] = end($data); + } + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/pilibaba.php b/public/catalog/controller/extension/payment/pilibaba.php new file mode 100644 index 0000000..ae7829a --- /dev/null +++ b/public/catalog/controller/extension/payment/pilibaba.php @@ -0,0 +1,416 @@ +<?php +class ControllerExtensionPaymentPilibaba extends Controller { + public function index() { + $this->load->language('extension/payment/pilibaba'); + + $this->load->model('checkout/order'); + $this->load->model('extension/payment/pilibaba'); + + $this->model_extension_payment_pilibaba->log('Regular called'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $data['version'] = 'V2.0.01'; + $data['merchantNo'] = $this->config->get('payment_pilibaba_merchant_number'); + $data['currencyType'] = $order_info['currency_code']; + $data['orderNo'] = $order_info['order_id']; + $data['orderAmount'] = intval(round($order_info['total'], 2) * 100); + $data['orderTime'] = date('Y-m-d H:i:s'); + $data['pageUrl'] = $this->url->link('checkout/checkout', '', true); + $data['serverUrl'] = $this->url->link('extension/payment/pilibaba/callback', '', true); + $data['redirectUrl'] = $this->url->link('checkout/success', '', true); + $data['notifyType'] = 'json'; + $data['shipper'] = 0; + $data['tax'] = ($this->config->get('config_tax')) ? 0 : $this->model_extension_payment_pilibaba->getOrderTaxAmount($order_info['order_id']); + $data['signType'] = 'MD5'; + $data['signMsg'] = strtoupper(md5($data['version'] . $data['merchantNo'] . $data['currencyType'] . $data['orderNo'] . $data['orderAmount'] . $data['orderTime'] . $data['pageUrl'] . $data['serverUrl'] . $data['redirectUrl'] . $data['notifyType'] . $data['shipper'] . $data['tax'] . $data['signType'] . $this->config->get('payment_pilibaba_secret_key'))); + + $products = array(); + + foreach ($this->cart->getProducts() as $product) { + // kilograms + if ($product['weight_class_id'] == '1') { + $weight = intval(round($product['weight'], 2) * 1000); + } else { + $weight = intval($product['weight']); + } + + $products[] = array_map('strval', array( + 'name' => $product['name'], + 'pictureUrl' => $this->config->get('config_url') . 'image/' . $product['image'], + 'price' => intval(round($this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax'), $this->session->data['currency']), 2) * 100), + 'productUrl' => str_replace('&', '&', $this->url->link('product/product', 'product_id=' . $product['product_id'])), + 'productId' => $product['product_id'], + 'quantity' => $product['quantity'], + 'weight' => $weight + )); + } + + $data['products'] = $products; + + $data['goodsList'] = urlencode(json_encode($products)); + + if ($this->config->get('payment_pilibaba_environment') == 'live') { + $data['url'] = 'https://www.pilibaba.com/pilipay/payreq'; + } else { + $data['url'] = 'http://pre.pilibaba.com/pilipay/payreq'; + } + + $data['auto_submit'] = false; + + $this->model_extension_payment_pilibaba->log('Request: ' . print_r($data, true)); + + return $this->load->view('extension/payment/pilibaba', $data); + } + + public function express() { + $this->load->language('extension/shipping/pilibaba'); + + $this->load->language('extension/payment/pilibaba'); + + $this->load->model('extension/payment/pilibaba'); + + $this->model_extension_payment_pilibaba->log('Express called'); + + if ($this->config->get('payment_pilibaba_status')) { + if (!$this->cart->hasProducts() || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) { + $this->model_extension_payment_pilibaba->log('No physical products. Redirecting to checkout/cart'); + + $this->response->redirect($this->url->link('checkout/cart')); + } else { + $order_data = array(); + + $totals = array(); + $taxes = $this->cart->getTaxes(); + $total = 0; + + // Because __call can not keep var references so we put them into an array. + $total_data = array( + 'totals' => &$totals, + 'taxes' => &$taxes, + 'total' => &$total + ); + + $this->load->model('setting/extension'); + + $sort_order = array(); + + $results = $this->model_setting_extension->getExtensions('total'); + + foreach ($results as $key => $value) { + $sort_order[$key] = $this->config->get('total_' . $value['code'] . '_sort_order'); + } + + array_multisort($sort_order, SORT_ASC, $results); + + foreach ($results as $result) { + if ($this->config->get('total_' . $result['code'] . '_status')) { + $this->load->model('extension/total/' . $result['code']); + + // We have to put the totals in an array so that they pass by reference. + $this->{'model_extension_total_' . $result['code']}->getTotal($total_data); + } + } + + $sort_order = array(); + + foreach ($totals as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $totals); + + $order_data['totals'] = $totals; + + $this->load->language('checkout/checkout'); + + $order_data['invoice_prefix'] = $this->config->get('config_invoice_prefix'); + $order_data['store_id'] = $this->config->get('config_store_id'); + $order_data['store_name'] = $this->config->get('config_name'); + + if ($order_data['store_id']) { + $order_data['store_url'] = $this->config->get('config_url'); + } else { + $order_data['store_url'] = HTTP_SERVER; + } + + $order_data['customer_id'] = 0; + $order_data['customer_group_id'] = $this->config->get('config_customer_group_id'); + $order_data['firstname'] = ''; + $order_data['lastname'] = ''; + $order_data['email'] = ''; + $order_data['telephone'] = ''; + $order_data['custom_field'] = null; + + $order_data['payment_firstname'] = ''; + $order_data['payment_lastname'] = ''; + $order_data['payment_company'] = ''; + $order_data['payment_address_1'] = ''; + $order_data['payment_address_2'] = ''; + $order_data['payment_city'] = ''; + $order_data['payment_postcode'] = ''; + $order_data['payment_zone'] = ''; + $order_data['payment_zone_id'] = 0; + $order_data['payment_country'] = ''; + $order_data['payment_country_id'] = 0; + $order_data['payment_address_format'] = ''; + $order_data['payment_custom_field'] = array(); + $order_data['payment_method'] = $this->language->get('text_title'); + $order_data['payment_code'] = 'pilibaba'; + + $order_data['shipping_firstname'] = ''; + $order_data['shipping_lastname'] = ''; + $order_data['shipping_company'] = ''; + $order_data['shipping_address_1'] = ''; + $order_data['shipping_address_2'] = ''; + $order_data['shipping_city'] = ''; + $order_data['shipping_postcode'] = ''; + $order_data['shipping_zone'] = ''; + $order_data['shipping_zone_id'] = 0; + $order_data['shipping_country'] = ''; + $order_data['shipping_country_id'] = 0; + $order_data['shipping_address_format'] = ''; + $order_data['shipping_custom_field'] = array(); + $order_data['shipping_method'] = $this->language->get('text_description'); + $order_data['shipping_code'] = 'pilibaba.pilibaba'; + + $this->session->data['guest']['customer_group_id'] = $this->config->get('config_customer_group_id'); + $this->session->data['guest']['firstname'] = ''; + $this->session->data['guest']['lastname'] = ''; + $this->session->data['guest']['email'] = ''; + $this->session->data['guest']['telephone'] = ''; + $this->session->data['guest']['custom_field'] = array(); + + $order_data['products'] = array(); + + foreach ($this->cart->getProducts() as $product) { + $option_data = array(); + + foreach ($product['option'] as $option) { + $option_data[] = array( + 'product_option_id' => $option['product_option_id'], + 'product_option_value_id' => $option['product_option_value_id'], + 'option_id' => $option['option_id'], + 'option_value_id' => $option['option_value_id'], + 'name' => $option['name'], + 'value' => $option['value'], + 'type' => $option['type'] + ); + } + + $order_data['products'][] = array( + 'product_id' => $product['product_id'], + 'name' => $product['name'], + 'model' => $product['model'], + 'option' => $option_data, + 'download' => $product['download'], + 'quantity' => $product['quantity'], + 'subtract' => $product['subtract'], + 'price' => $product['price'], + 'total' => $product['total'], + 'tax' => $this->tax->getTax($product['price'], $product['tax_class_id']), + 'reward' => $product['reward'] + ); + } + + // Gift Voucher + $order_data['vouchers'] = array(); + + if (!empty($this->session->data['vouchers'])) { + foreach ($this->session->data['vouchers'] as $voucher) { + $order_data['vouchers'][] = array( + 'description' => $voucher['description'], + 'code' => token(10), + 'to_name' => $voucher['to_name'], + 'to_email' => $voucher['to_email'], + 'from_name' => $voucher['from_name'], + 'from_email' => $voucher['from_email'], + 'voucher_theme_id' => $voucher['voucher_theme_id'], + 'message' => $voucher['message'], + 'amount' => $voucher['amount'] + ); + } + } + + $order_data['comment'] = ''; + $order_data['total'] = $total_data['total']; + + if (isset($this->request->cookie['tracking'])) { + $order_data['tracking'] = $this->request->cookie['tracking']; + + $subtotal = $this->cart->getSubTotal(); + + // Affiliate + $this->load->model('affiliate/affiliate'); + + $affiliate_info = $this->model_affiliate_affiliate->getAffiliateByCode($this->request->cookie['tracking']); + + if ($affiliate_info) { + $order_data['affiliate_id'] = $affiliate_info['affiliate_id']; + $order_data['commission'] = ($subtotal / 100) * $affiliate_info['commission']; + } else { + $order_data['affiliate_id'] = 0; + $order_data['commission'] = 0; + } + + // Marketing + $this->load->model('checkout/marketing'); + + $marketing_info = $this->model_checkout_marketing->getMarketingByCode($this->request->cookie['tracking']); + + if ($marketing_info) { + $order_data['marketing_id'] = $marketing_info['marketing_id']; + } else { + $order_data['marketing_id'] = 0; + } + } else { + $order_data['affiliate_id'] = 0; + $order_data['commission'] = 0; + $order_data['marketing_id'] = 0; + $order_data['tracking'] = ''; + } + + $order_data['language_id'] = $this->config->get('config_language_id'); + $order_data['currency_id'] = $this->currency->getId($this->session->data['currency']); + $order_data['currency_code'] = $this->session->data['currency']; + $order_data['currency_value'] = $this->currency->getValue($this->session->data['currency']); + $order_data['ip'] = $this->request->server['REMOTE_ADDR']; + + if (!empty($this->request->server['HTTP_X_FORWARDED_FOR'])) { + $order_data['forwarded_ip'] = $this->request->server['HTTP_X_FORWARDED_FOR']; + } elseif (!empty($this->request->server['HTTP_CLIENT_IP'])) { + $order_data['forwarded_ip'] = $this->request->server['HTTP_CLIENT_IP']; + } else { + $order_data['forwarded_ip'] = ''; + } + + if (isset($this->request->server['HTTP_USER_AGENT'])) { + $order_data['user_agent'] = $this->request->server['HTTP_USER_AGENT']; + } else { + $order_data['user_agent'] = ''; + } + + if (isset($this->request->server['HTTP_ACCEPT_LANGUAGE'])) { + $order_data['accept_language'] = $this->request->server['HTTP_ACCEPT_LANGUAGE']; + } else { + $order_data['accept_language'] = ''; + } + + $this->load->model('checkout/order'); + + $this->session->data['order_id'] = $this->model_checkout_order->addOrder($order_data); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $data['version'] = 'V2.0.01'; + $data['merchantNo'] = $this->config->get('payment_pilibaba_merchant_number'); + $data['currencyType'] = $order_info['currency_code']; + $data['orderNo'] = $order_info['order_id']; + $data['orderAmount'] = intval(round($order_info['total'], 2) * 100); + $data['orderTime'] = date('Y-m-d H:i:s'); + $data['pageUrl'] = $this->url->link('checkout/checkout', '', true); + $data['serverUrl'] = $this->url->link('extension/payment/pilibaba/callback', '', true); + $data['redirectUrl'] = $this->url->link('checkout/success', '', true); + $data['notifyType'] = 'json'; + $data['shipper'] = intval(round($this->config->get('payment_pilibaba_shipping_fee'), 2) * 100); + $data['tax'] = ($this->config->get('config_tax')) ? 0 : $this->model_extension_payment_pilibaba->getOrderTaxAmount($order_info['order_id']); + $data['signType'] = 'MD5'; + $data['signMsg'] = strtoupper(md5($data['version'] . $data['merchantNo'] . $data['currencyType'] . $data['orderNo'] . $data['orderAmount'] . $data['orderTime'] . $data['pageUrl'] . $data['serverUrl'] . $data['redirectUrl'] . $data['notifyType'] . $data['shipper'] . $data['tax'] . $data['signType'] . $this->config->get('payment_pilibaba_secret_key'))); + + $products = array(); + + foreach ($this->cart->getProducts() as $product) { + // kilograms + if ($product['weight_class_id'] == '1') { + $weight = intval(round($product['weight'], 2) * 1000); + } else { + $weight = intval($product['weight']); + } + + $products[] = array_map('strval', array( + 'name' => $product['name'], + 'pictureUrl' => $this->config->get('config_url') . 'image/' . $product['image'], + 'price' => intval(round($this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax'), $this->session->data['currency']), 2) * 100), + 'productUrl' => str_replace('&', '&', $this->url->link('product/product', 'product_id=' . $product['product_id'])), + 'productId' => $product['product_id'], + 'quantity' => $product['quantity'], + 'weight' => $weight + )); + } + + $data['products'] = $products; + + $data['goodsList'] = urlencode(json_encode($products)); + + if ($this->config->get('payment_pilibaba_environment') == 'live') { + $data['url'] = 'https://www.pilibaba.com/pilipay/payreq'; + } else { + $data['url'] = 'http://pre.pilibaba.com/pilipay/payreq'; + } + + $data['text_redirecting'] = $this->language->get('text_redirecting'); + + $data['auto_submit'] = true; + + $this->model_extension_payment_pilibaba->log('Request: ' . print_r($data, true)); + + $this->response->setOutput($this->load->view('extension/payment/pilibaba', $data)); + } + } else { + $this->model_extension_payment_pilibaba->log('Module disabled'); + } + } + + public function callback() { + $this->load->language('extension/payment/pilibaba'); + + $this->load->model('checkout/order'); + $this->load->model('extension/payment/pilibaba'); + + $this->model_extension_payment_pilibaba->log('Receiving callback'); + + $response_data = $this->request->get; + + $this->model_extension_payment_pilibaba->log('Response: ' . print_r($response_data, true)); + + $sign_msg = strtoupper(md5($this->config->get('payment_pilibaba_merchant_number') . $response_data['orderNo'] . $response_data['orderAmount'] . 'MD5' . $response_data['fee'] . $response_data['orderTime'] . $response_data['customerMail'] . $this->config->get('payment_pilibaba_secret_key'))); + + $this->model_extension_payment_pilibaba->log('signMsg: ' . $sign_msg); + + if (hash_equals($sign_msg, $response_data['signMsg'])) { + $this->model_extension_payment_pilibaba->log('Adding Pilibaba order'); + + $this->model_extension_payment_pilibaba->addPilibabaOrder($response_data); + + $this->model_extension_payment_pilibaba->log('Pilibaba order added'); + + $this->model_extension_payment_pilibaba->log('Getting consumer info'); + + $consumer_info = $this->model_extension_payment_pilibaba->getConsumerInfo($response_data['orderNo']); + + if (isset($consumer_info['message']) && $consumer_info['message'] == 'success') { + $this->model_extension_payment_pilibaba->log('Updating order info'); + + $this->model_extension_payment_pilibaba->updateOrderInfo($consumer_info, $response_data['orderNo']); + + $this->model_extension_payment_pilibaba->log('Order info updated'); + + $this->model_extension_payment_pilibaba->log('Adding order history'); + + $this->model_checkout_order->addOrderHistory($response_data['orderNo'], $this->config->get('payment_pilibaba_order_status_id')); + + $this->model_extension_payment_pilibaba->log('Order history added'); + } else { + $this->model_extension_payment_pilibaba->log('Invalid consumer info response'); + } + + $this->model_extension_payment_pilibaba->log('Outputting "OK"'); + + echo 'OK'; + + $this->model_extension_payment_pilibaba->log('"OK" outputted'); + } else { + $this->model_extension_payment_pilibaba->log('Invalid callback response'); + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/pp_braintree.php b/public/catalog/controller/extension/payment/pp_braintree.php new file mode 100644 index 0000000..de2f965 --- /dev/null +++ b/public/catalog/controller/extension/payment/pp_braintree.php @@ -0,0 +1,1635 @@ +<?php +class ControllerExtensionPaymentPPBraintree extends Controller { + private $customer_id_prefix = 'braintree_oc_'; + private $gateway = null; + + public function index() { + $this->initialise(); + + $this->load->language('extension/payment/pp_braintree'); + + $data['payment_url'] = $this->url->link('extension/payment/pp_braintree/payment', '', true); + $data['vaulted_url'] = $this->url->link('extension/payment/pp_braintree/vaulted', '', true); + + $data['payment_pp_braintree_3ds_status'] = $this->config->get('payment_pp_braintree_3ds_status'); + $data['payment_pp_braintree_vault_cvv_3ds'] = $this->config->get('payment_pp_braintree_vault_cvv_3ds'); + $data['payment_pp_braintree_paypal_option'] = $this->config->get('payment_pp_braintree_paypal_option'); + $data['payment_pp_braintree_vault_cvv'] = $this->config->get('payment_pp_braintree_vault_cvv'); + $data['payment_pp_braintree_settlement_immediate'] = $this->config->get('payment_pp_braintree_settlement_immediate'); + $data['payment_pp_braintree_paypal_button_colour'] = $this->config->get('payment_pp_braintree_paypal_button_colour'); + $data['payment_pp_braintree_paypal_button_size'] = $this->config->get('payment_pp_braintree_paypal_button_size'); + $data['payment_pp_braintree_paypal_button_shape'] = $this->config->get('payment_pp_braintree_paypal_button_shape'); + + if (!$this->session->data['order_id']) { + return false; + } + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $create_token = array(); + $merchant_id = $this->config->get('payment_pp_braintree_merchant_id'); + + if ($this->gateway == '') { + $merchant_accounts = $this->config->get('payment_pp_braintree_account'); + + foreach ($merchant_accounts as $merchant_account_currency => $merchant_account) { + if (($merchant_account_currency == $order_info['currency_code']) && !empty($merchant_account['merchant_account_id'])) { + $create_token['merchantAccountId'] = $merchant_account['merchant_account_id']; + + $merchant_id = $merchant_account['merchant_account_id']; + + break; + } + } + } + + $data['merchant_id'] = $merchant_id; + + if ($this->customer->isLogged() && ($this->config->get('payment_pp_braintree_card_vault') || $this->config->get('payment_pp_braintree_paypal_vault'))) { + $data['payment_pp_braintree_card_vault'] = $this->config->get('payment_pp_braintree_card_vault'); + $data['payment_pp_braintree_paypal_vault'] = $this->config->get('payment_pp_braintree_paypal_vault'); + $data['payment_pp_braintree_card_check_vault'] = $this->config->get('payment_pp_braintree_card_check_vault'); + $data['payment_pp_braintree_paypal_check_vault'] = $this->config->get('payment_pp_braintree_paypal_check_vault'); + $vaulted_customer_info = $this->model_extension_payment_pp_braintree->getCustomer($this->gateway, $this->customer_id_prefix . $this->customer->getId(), false); + } else { + $data['payment_pp_braintree_card_vault'] = 0; + $data['payment_pp_braintree_paypal_vault'] = 0; + $data['payment_pp_braintree_card_check_vault'] = 0; + $data['payment_pp_braintree_paypal_check_vault'] = 0; + $vaulted_customer_info = false; + } + + $data['client_token'] = $this->model_extension_payment_pp_braintree->generateToken($this->gateway, $create_token); + $data['total'] = $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false); + + $data['currency_code'] = $order_info['currency_code']; + + // disable paypal option if currency is not in supported array + if (!in_array($order_info['currency_code'], array('USD', 'EUR', 'GBP', 'CAD', 'AUD', 'DKK', 'NOK', 'PLN', 'SEK', 'CHF', 'TRY'))) { + $data['payment_pp_braintree_paypal_option'] = false; + } + + // pass shipping info to paypal if set + if ($data['payment_pp_braintree_paypal_option'] && $this->cart->hasShipping()) { + $data['customer_shipping_address'] = array( + 'name' => addslashes($order_info['shipping_firstname']) . ' ' . addslashes($order_info['shipping_lastname']), + 'line_1' => addslashes($order_info['shipping_address_1']), + 'line_2' => addslashes($order_info['shipping_address_2']), + 'city' => addslashes($order_info['shipping_city']), + 'state' => addslashes($order_info['shipping_zone_code']), + 'post_code' => addslashes($order_info['shipping_postcode']), + 'country_code' => addslashes($order_info['shipping_iso_code_2']), + 'phone' => addslashes($order_info['telephone']), + ); + } + + $vaulted_payment_methods = array('cards', 'paypal'); + $vaulted_payment_count = 0; + + if ($vaulted_customer_info) { + $vaulted_card_count = 0; + $vaulted_paypal_count = 0; + + if ($vaulted_customer_info->creditCards && $this->config->get('payment_pp_braintree_card_vault') == 1) { + $vaulted_card_count = count($vaulted_customer_info->creditCards); + + foreach ($vaulted_customer_info->creditCards as $credit_card) { + $vaulted_payment_methods['cards'][] = array( + 'image' => $credit_card->imageUrl, + 'name' => sprintf($this->language->get('text_vaulted_payment_method_name'), $credit_card->cardType, $credit_card->last4, $credit_card->expirationDate), + 'token' => $credit_card->token, + 'expired' => $credit_card->expired, + 'default' => $credit_card->default + ); + } + } + + if ($vaulted_customer_info->paypalAccounts && $this->config->get('payment_pp_braintree_paypal_vault') == 1) { + $vaulted_paypal_count = count($vaulted_customer_info->paypalAccounts); + + foreach ($vaulted_customer_info->paypalAccounts as $paypal_account) { + $vaulted_payment_methods['paypal'][] = array( + 'image' => $paypal_account->imageUrl, + 'name' => $paypal_account->email, + 'token' => $paypal_account->token, + 'default' => $paypal_account->default + ); + } + } + + $vaulted_payment_count = $vaulted_card_count + $vaulted_paypal_count; + } + + $data['vaulted_payment_methods'] = $vaulted_payment_methods; + $data['vaulted_payment_count'] = $vaulted_payment_count; + + $data['form_styles'] = json_encode("{ + 'input': { 'font-size': '12px', 'font-family': 'Source Sans Pro, sans-serif', 'color': '#7A8494' }, + 'input.invalid': { 'color': 'red' }, + 'input.valid': { 'color': 'green' } + }"); + + if ($this->customer->isLogged()) { + $data['guest'] = false; + } else { + $data['guest'] = true; + } + + return $this->load->view('extension/payment/pp_braintree', $data); + } + + public function payment() { + //set_time_limit(120); + + $this->initialise(); + + $this->load->language('extension/payment/pp_braintree'); + + $this->load->model('checkout/order'); + $this->load->model('extension/payment/pp_braintree'); + + $this->model_extension_payment_pp_braintree->log('Starting payment'); + $this->model_extension_payment_pp_braintree->log($this->request->post); + + $success = true; + + if (!$this->session->data['order_id']) { + $this->model_extension_payment_pp_braintree->log('Session data: order_id not found'); + + $success = false; + } + + if (isset($this->request->post['device_data'])) { + $device_data = $this->request->post['device_data']; + } else { + $this->model_extension_payment_pp_braintree->log('Post data: device_data not found'); + + $device_data = ''; + + $success = false; + } + + if (isset($this->request->post['payment_method_token'])) { + $payment_method_token = $this->request->post['payment_method_token']; + } else { + $this->model_extension_payment_pp_braintree->log('Post data: payment_method_token not found'); + $payment_method_token = ''; + } + + if (isset($this->request->post['payment_method_nonce'])) { + $payment_method_nonce = $this->request->post['payment_method_nonce']; + } else { + $this->model_extension_payment_pp_braintree->log('Post data: payment_method_nonce not found'); + $payment_method_nonce = ''; + } + + if ($payment_method_nonce == '' && $payment_method_token == '') { + $success = false; + } + + //Start creating transaction array + if ($success) { + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $create_sale = array( + 'amount' => $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false), + 'channel' => 'OpenCart_Cart_vzero', + 'orderId' => $order_info['order_id'], + 'deviceData' => $device_data, + 'customer' => array( + 'firstName' => $order_info['firstname'], + 'lastName' => $order_info['lastname'], + 'phone' => $order_info['telephone'], + 'email' => $order_info['email'] + ), + 'billing' => array( + 'firstName' => $order_info['payment_firstname'], + 'lastName' => $order_info['payment_lastname'], + 'company' => $order_info['payment_company'], + 'streetAddress' => $order_info['payment_address_1'], + 'extendedAddress' => $order_info['payment_address_2'], + 'locality' => $order_info['payment_city'], + 'countryCodeAlpha2' => $order_info['payment_iso_code_2'], + 'postalCode' => $order_info['payment_postcode'], + 'region' => $order_info['payment_zone_code'] + ), + 'options' => array('three_d_secure' => array('required' => false)) + ); + + //Add shipping details + if ($this->cart->hasShipping()) { + $create_sale['shipping'] = array( + 'firstName' => $order_info['shipping_firstname'], + 'lastName' => $order_info['shipping_lastname'], + 'company' => $order_info['shipping_company'], + 'streetAddress' => $order_info['shipping_address_1'], + 'extendedAddress' => $order_info['shipping_address_2'], + 'locality' => $order_info['shipping_city'], + 'countryCodeAlpha2' => $order_info['shipping_iso_code_2'], + 'postalCode' => $order_info['shipping_postcode'], + 'region' => $order_info['shipping_zone_code'] + ); + } + + if ($this->customer->isLogged() && ($this->config->get('payment_pp_braintree_card_vault') || $this->config->get('payment_pp_braintree_paypal_vault'))) { + $customer_id = $this->customer_id_prefix . $this->customer->getId(); + + $vaulted_customer_info = $this->model_extension_payment_pp_braintree->getCustomer($this->gateway, $customer_id, false); + + if ($vaulted_customer_info) { + $create_sale['customerId'] = $customer_id; + } else { + $create_sale['customer']['id'] = $customer_id; + } + + if (isset($this->request->post['vault_method']) && $this->request->post['vault_method'] == '1') { + $create_sale['options']['storeInVaultOnSuccess'] = true; + } + } + + if ($payment_method_token != '') { + $create_sale['paymentMethodToken'] = $payment_method_token; + + // unset the billing info for a vaulted payment + $create_sale['billing'] = array(); + } + + if ($payment_method_nonce != '') { + $create_sale['paymentMethodNonce'] = $payment_method_nonce; + } + + if ($this->gateway == '') { + $merchant_accounts = $this->config->get('payment_pp_braintree_account'); + + foreach ($merchant_accounts as $merchant_account_currency => $merchant_account) { + if (($merchant_account_currency == $order_info['currency_code']) && !empty($merchant_account['merchant_account_id'])) { + $create_sale['merchantAccountId'] = $merchant_account['merchant_account_id']; + } + } + } + + if ($this->config->get('payment_pp_braintree_settlement_immediate') == 1) { + $create_sale['options']['submitForSettlement'] = true; + } else { + $create_sale['options']['submitForSettlement'] = false; + } + } + + // If the $payment_method_token is not empty it indicates the vaulted payment used CVV or was set to none + if ($success && (($this->config->get('payment_pp_braintree_3ds_status') == 1 && $payment_method_token == '') || ($this->config->get('payment_pp_braintree_vault_cvv_3ds') == '3ds' && $payment_method_token != ''))) { + $nonce_info = $this->model_extension_payment_pp_braintree->getPaymentMethodNonce($this->gateway, $payment_method_nonce); + + $this->model_extension_payment_pp_braintree->log($nonce_info); + + if ($nonce_info->type == 'CreditCard' && $this->config->get('payment_pp_braintree_3ds_status') == 1) { + $create_sale['options']['three_d_secure'] = array( + 'required' => true + ); + + $three_ds_info = array(); + + if (isset($nonce_info->threeDSecureInfo) && !empty($nonce_info->threeDSecureInfo)) { + $three_ds_info = $nonce_info->threeDSecureInfo; + } + + if (!empty($three_ds_info)) { + $success = false; + + switch ($three_ds_info->status) { + case 'unsupported_card': + if ($nonce_info->details['cardType'] == 'American Express') { + $success = true; + } else { + $success = $this->config->get('payment_pp_braintree_3ds_unsupported_card'); + } + break; + case 'lookup_error': + $success = $this->config->get('payment_pp_braintree_3ds_lookup_error'); + break; + case 'lookup_enrolled': + $success = $this->config->get('payment_pp_braintree_3ds_lookup_enrolled'); + break; + case 'lookup_not_enrolled': + $success = $this->config->get('payment_pp_braintree_3ds_lookup_not_enrolled'); + break; + case 'authenticate_successful_issuer_not_participating': + $success = $this->config->get('payment_pp_braintree_3ds_not_participating'); + break; + case 'authentication_unavailable': + $success = $this->config->get('payment_pp_braintree_3ds_unavailable'); + break; + case 'authenticate_signature_verification_failed': + $success = $this->config->get('payment_pp_braintree_3ds_signature_failed'); + break; + case 'authenticate_successful': + $success = $this->config->get('payment_pp_braintree_3ds_successful'); + break; + case 'authenticate_attempt_successful': + $success = $this->config->get('payment_pp_braintree_3ds_attempt_successful'); + break; + case 'authenticate_failed': + $success = $this->config->get('payment_pp_braintree_3ds_failed'); + break; + case 'authenticate_unable_to_authenticate': + $success = $this->config->get('payment_pp_braintree_3ds_unable_to_auth'); + break; + case 'authenticate_error': + $success = $this->config->get('payment_pp_braintree_3ds_error'); + break; + } + } else { + $this->model_extension_payment_pp_braintree->log('Liability shift failed, nonce was not 3D Secured'); + + $success = false; + } + } + } + $this->model_extension_payment_pp_braintree->log("Success:" . (int)$success); + + //Create transaction + if ($success) { + $transaction = $this->model_extension_payment_pp_braintree->addTransaction($this->gateway, $create_sale); + + $order_status_id = 0; + switch ($transaction->transaction->status) { + case 'authorization_expired': + $order_status_id = $this->config->get('payment_pp_braintree_authorization_expired_id'); + break; + case 'authorized': + $order_status_id = $this->config->get('payment_pp_braintree_authorized_id'); + break; + case 'authorizing': + $order_status_id = $this->config->get('payment_pp_braintree_authorizing_id'); + break; + case 'settlement_pending': + $order_status_id = $this->config->get('payment_pp_braintree_settlement_pending_id'); + break; + case 'failed': + $order_status_id = $this->config->get('payment_pp_braintree_failed_id'); + break; + case 'gateway_rejected': + $order_status_id = $this->config->get('payment_pp_braintree_gateway_rejected_id'); + break; + case 'processor_declined': + $order_status_id = $this->config->get('payment_pp_braintree_processor_declined_id'); + break; + case 'settled': + $order_status_id = $this->config->get('payment_pp_braintree_settled_id'); + break; + case 'settling': + $order_status_id = $this->config->get('payment_pp_braintree_settling_id'); + break; + case 'submitted_for_settlement': + $order_status_id = $this->config->get('payment_pp_braintree_submitted_for_settlement_id'); + break; + case 'voided': + $order_status_id = $this->config->get('payment_pp_braintree_voided_id'); + break; + } + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $order_status_id); + + if ($transaction->success) { + $this->model_extension_payment_pp_braintree->log('Transaction success, details below'); + $this->model_extension_payment_pp_braintree->log($transaction); + + $this->response->redirect($this->url->link('checkout/success', '', true)); + } else { + $this->model_extension_payment_pp_braintree->log('Transaction failed, details below'); + $this->model_extension_payment_pp_braintree->log($transaction); + + $this->session->data['error'] = $this->language->get('error_process_order'); + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + } + + //If this is reached, transaction has failed + $this->model_extension_payment_pp_braintree->log('Transaction reached end of method without being handled, failure'); + + if (isset($this->session->data['order_id'])) { + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_pp_braintree_failed_id')); + } + + $this->response->redirect($this->url->link('checkout/failure', '', true)); + } + + public function nonce() { + $this->initialise(); + + $this->load->language('extension/payment/pp_braintree'); + + $this->load->model('extension/payment/pp_braintree'); + + $this->model_extension_payment_pp_braintree->log('Starting vaulted'); + $this->model_extension_payment_pp_braintree->log($this->request->post); + + $json = array(); + + $json['payment_method'] = ''; + + $success = true; + + if (!isset($this->request->post['vaulted_payment_token'])) { + $success = false; + } + + if ($success) { + $payment_method = $this->model_extension_payment_pp_braintree->createPaymentMethodNonce($this->gateway, $this->request->post['vaulted_payment_token']); + + if ($payment_method && $payment_method->success) { + $json['payment_method'] = array( + 'type' => $payment_method->paymentMethodNonce->type, + 'nonce' => $payment_method->paymentMethodNonce->nonce + ); + } else { + $success = false; + } + } + + $json['success'] = $success; + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function remove() { + $this->initialise(); + + $this->load->language('extension/payment/pp_braintree'); + + $this->load->model('extension/payment/pp_braintree'); + + $json = array(); + + $json['success'] = false; + + if (isset($this->request->post['vaulted_payment_method'])) { + $vaulted_payment_method = $this->request->post['vaulted_payment_method']; + } else { + $vaulted_payment_method = ''; + } + + $delete_payment_method = $this->model_extension_payment_pp_braintree->deletePaymentMethod($this->gateway, $vaulted_payment_method); + + if ($delete_payment_method) { + $json['success'] = $this->language->get('text_method_removed'); + } else { + $json['error'] = $this->language->get('text_method_not_removed'); + } + + $vaulted_customer_info = $this->model_extension_payment_pp_braintree->getCustomer($this->gateway, $this->customer_id_prefix . $this->customer->getId()); + + $vaulted_card_count = 0; + $vaulted_paypal_count = 0; + + if ($vaulted_customer_info->creditCards && $this->config->get('payment_pp_braintree_card_vault') == 1) { + $vaulted_card_count = count($vaulted_customer_info->creditCards); + } + + if ($vaulted_customer_info->paypalAccounts && $this->config->get('payment_pp_braintree_paypal_vault') == 1) { + $vaulted_paypal_count = count($vaulted_customer_info->paypalAccounts); + } + + $json['vaulted_payment_count'] = $vaulted_card_count + $vaulted_paypal_count; + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function expressSetup() { + // check checkout can continue due to stock checks or vouchers + if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) { + $json = array(); + $json['error'] = true; + $json['url'] = $this->url->link('checkout/cart'); + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + // if user not logged in check that the guest checkout is allowed + if (!$this->customer->isLogged() && (!$this->config->get('config_checkout_guest') || $this->config->get('config_customer_price') || $this->cart->hasDownload() || $this->cart->hasRecurringProducts())) { + $json = array(); + $json['error'] = true; + $json['url'] = $this->url->link('checkout/checkout'); + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } else { + unset($this->session->data['guest']); + } + + unset($this->session->data['shipping_method']); + unset($this->session->data['shipping_methods']); + unset($this->session->data['payment_method']); + unset($this->session->data['payment_methods']); + + if (!$this->customer->isLogged()) { + $this->session->data['paypal_braintree']['guest'] = true; + + $this->session->data['guest']['customer_group_id'] = $this->config->get('config_customer_group_id'); + $this->session->data['guest']['firstname'] = $this->request->post['details']['firstName']; + $this->session->data['guest']['lastname'] = $this->request->post['details']['lastName']; + $this->session->data['guest']['email'] = $this->request->post['details']['email']; + + if (isset($this->request->post['details']['phone'])) { + $this->session->data['guest']['telephone'] = $this->request->post['details']['phone']; + } else { + $this->session->data['guest']['telephone'] = ''; + } + + $this->session->data['guest']['payment']['company'] = ''; + + $this->session->data['guest']['payment']['firstname'] = $this->request->post['details']['firstName']; + $this->session->data['guest']['payment']['lastname'] = $this->request->post['details']['lastName']; + + $this->session->data['guest']['payment']['company_id'] = ''; + $this->session->data['guest']['payment']['tax_id'] = ''; + + if ($this->cart->hasShipping()) { + $shipping_name = explode(' ', $this->request->post['details']['shippingAddress']['recipientName']); + $shipping_first_name = $shipping_name[0]; + unset($shipping_name[0]); + $shipping_last_name = implode(' ', $shipping_name); + + $this->session->data['guest']['payment']['address_1'] = $this->request->post['details']['shippingAddress']['line1']; + if (isset($this->request->post['details']['shippingAddress']['line2'])) { + $this->session->data['guest']['payment']['address_2'] = $this->request->post['details']['shippingAddress']['line2']; + } else { + $this->session->data['guest']['payment']['address_2'] = ''; + } + + $this->session->data['guest']['payment']['postcode'] = $this->request->post['details']['shippingAddress']['postalCode']; + $this->session->data['guest']['payment']['city'] = $this->request->post['details']['shippingAddress']['city']; + + $this->session->data['guest']['shipping']['firstname'] = $shipping_first_name; + $this->session->data['guest']['shipping']['lastname'] = $shipping_last_name; + $this->session->data['guest']['shipping']['company'] = ''; + $this->session->data['guest']['shipping']['address_1'] = $this->request->post['details']['shippingAddress']['line1']; + + if (isset($this->request->post['details']['shippingAddress']['line2'])) { + $this->session->data['guest']['shipping']['address_2'] =$this->request->post['details']['shippingAddress']['line2']; + } else { + $this->session->data['guest']['shipping']['address_2'] = ''; + } + + $this->session->data['guest']['shipping']['postcode'] = $this->request->post['details']['shippingAddress']['postalCode']; + $this->session->data['guest']['shipping']['city'] = $this->request->post['details']['shippingAddress']['city']; + + $this->session->data['shipping_postcode'] = $this->request->post['details']['shippingAddress']['postalCode']; + + $country_info = $this->db->query("SELECT * FROM `" . DB_PREFIX . "country` WHERE `iso_code_2` = '" . $this->db->escape($this->request->post['details']['shippingAddress']['countryCode']) . "' AND `status` = '1' LIMIT 1")->row; + + if ($country_info) { + $this->session->data['guest']['shipping']['country_id'] = $country_info['country_id']; + $this->session->data['guest']['shipping']['country'] = $country_info['name']; + $this->session->data['guest']['shipping']['iso_code_2'] = $country_info['iso_code_2']; + $this->session->data['guest']['shipping']['iso_code_3'] = $country_info['iso_code_3']; + $this->session->data['guest']['shipping']['address_format'] = $country_info['address_format']; + $this->session->data['guest']['payment']['country_id'] = $country_info['country_id']; + $this->session->data['guest']['payment']['country'] = $country_info['name']; + $this->session->data['guest']['payment']['iso_code_2'] = $country_info['iso_code_2']; + $this->session->data['guest']['payment']['iso_code_3'] = $country_info['iso_code_3']; + $this->session->data['guest']['payment']['address_format'] = $country_info['address_format']; + $this->session->data['shipping_country_id'] = $country_info['country_id']; + + if (isset($this->request->post['details']['shippingAddress']['state'])) { + $returned_shipping_zone = $this->request->post['details']['shippingAddress']['state']; + } else { + $returned_shipping_zone = ''; + } + + $zone_info = $this->db->query("SELECT * FROM `" . DB_PREFIX . "zone` WHERE (`name` = '" . $this->db->escape($returned_shipping_zone) . "' OR `code` = '" . $this->db->escape($returned_shipping_zone) . "') AND `status` = '1' AND `country_id` = '" . (int)$country_info['country_id'] . "' LIMIT 1")->row; + } else { + $this->session->data['guest']['shipping']['country_id'] = ''; + $this->session->data['guest']['shipping']['country'] = ''; + $this->session->data['guest']['shipping']['iso_code_2'] = ''; + $this->session->data['guest']['shipping']['iso_code_3'] = ''; + $this->session->data['guest']['shipping']['address_format'] = ''; + $this->session->data['guest']['payment']['country_id'] = ''; + $this->session->data['guest']['payment']['country'] = ''; + $this->session->data['guest']['payment']['iso_code_2'] = ''; + $this->session->data['guest']['payment']['iso_code_3'] = ''; + $this->session->data['guest']['payment']['address_format'] = ''; + $this->session->data['shipping_country_id'] = ''; + + $zone_info = array(); + } + + if ($zone_info) { + $this->session->data['guest']['shipping']['zone'] = $zone_info['name']; + $this->session->data['guest']['shipping']['zone_code'] = $zone_info['code']; + $this->session->data['guest']['shipping']['zone_id'] = $zone_info['zone_id']; + $this->session->data['guest']['payment']['zone'] = $zone_info['name']; + $this->session->data['guest']['payment']['zone_code'] = $zone_info['code']; + $this->session->data['guest']['payment']['zone_id'] = $zone_info['zone_id']; + $this->session->data['shipping_zone_id'] = $zone_info['zone_id']; + } else { + $this->session->data['guest']['shipping']['zone'] = ''; + $this->session->data['guest']['shipping']['zone_code'] = ''; + $this->session->data['guest']['shipping']['zone_id'] = ''; + $this->session->data['guest']['payment']['zone'] = ''; + $this->session->data['guest']['payment']['zone_code'] = ''; + $this->session->data['guest']['payment']['zone_id'] = ''; + $this->session->data['shipping_zone_id'] = ''; + } + + $this->session->data['guest']['shipping_address'] = true; + } else { + $this->session->data['guest']['payment']['address_1'] = ''; + $this->session->data['guest']['payment']['address_2'] = ''; + $this->session->data['guest']['payment']['postcode'] = ''; + $this->session->data['guest']['payment']['city'] = ''; + $this->session->data['guest']['payment']['country_id'] = ''; + $this->session->data['guest']['payment']['country'] = ''; + $this->session->data['guest']['payment']['iso_code_2'] = ''; + $this->session->data['guest']['payment']['iso_code_3'] = ''; + $this->session->data['guest']['payment']['address_format'] = ''; + $this->session->data['guest']['payment']['zone'] = ''; + $this->session->data['guest']['payment']['zone_code'] = ''; + $this->session->data['guest']['payment']['zone_id'] = ''; + $this->session->data['guest']['shipping_address'] = false; + } + + $this->session->data['account'] = 'guest'; + + unset($this->session->data['shipping_method']); + unset($this->session->data['shipping_methods']); + unset($this->session->data['payment_method']); + unset($this->session->data['payment_methods']); + } else { + $this->session->data['paypal_braintree']['guest'] = false; + + unset($this->session->data['guest']); + /** + * if the user is logged in, add the address to the account and set the ID. + */ + + if ($this->cart->hasShipping()) { + $this->load->model('account/address'); + + $addresses = $this->model_account_address->getAddresses(); + + /** + * Compare all of the user addresses and see if there is a match + */ + $match = false; + foreach($addresses as $address) { + if (trim(strtolower($address['address_1'])) == trim(strtolower($this->request->post['details']['shippingAddress']['line1'])) && trim(strtolower($address['postcode'])) == trim(strtolower($this->request->post['details']['shippingAddress']['postalCode']))) { + $match = true; + + $this->session->data['payment_address_id'] = $address['address_id']; + $this->session->data['payment_country_id'] = $address['country_id']; + $this->session->data['payment_zone_id'] = $address['zone_id']; + + $this->session->data['shipping_address_id'] = $address['address_id']; + $this->session->data['shipping_country_id'] = $address['country_id']; + $this->session->data['shipping_zone_id'] = $address['zone_id']; + $this->session->data['shipping_postcode'] = $address['postcode']; + + break; + } + } + + /** + * If there is no address match add the address and set the info. + */ + if ($match == false) { + $shipping_name = explode(' ', trim($this->request->post['details']['shippingAddress']['recipientName'])); + $shipping_first_name = $shipping_name[0]; + unset($shipping_name[0]); + $shipping_last_name = implode(' ', $shipping_name); + + $country_info = $this->db->query("SELECT * FROM `" . DB_PREFIX . "country` WHERE `iso_code_2` = '" . $this->db->escape($this->request->post['details']['shippingAddress']['countryCode']) . "' AND `status` = '1' LIMIT 1")->row; + $zone_info = $this->db->query("SELECT * FROM `" . DB_PREFIX . "zone` WHERE (`name` = '" . $this->db->escape($this->request->post['details']['shippingAddress']['state']) . "' OR `code` = '" . $this->db->escape($this->request->post['details']['shippingAddress']['state']) . "') AND `status` = '1' AND `country_id` = '" . (int)$country_info['country_id'] . "'")->row; + + $address_data = array( + 'firstname' => $shipping_first_name, + 'lastname' => $shipping_last_name, + 'company' => '', + 'company_id' => '', + 'tax_id' => '', + 'address_1' => $this->request->post['details']['shippingAddress']['line1'], + 'address_2' => (isset($this->request->post['details']['shippingAddress']['line2']) ? $this->request->post['details']['shippingAddress']['line2'] : ''), + 'postcode' => $this->request->post['details']['shippingAddress']['postalCode'], + 'city' => $this->request->post['details']['shippingAddress']['city'], + 'zone_id' => (isset($zone_info['zone_id']) ? $zone_info['zone_id'] : 0), + 'country_id' => (isset($country_info['country_id']) ? $country_info['country_id'] : 0) + ); + + $address_id = $this->model_account_address->addAddress($this->customer->getId(), $address_data); + + $this->session->data['payment_address_id'] = $address_id; + $this->session->data['payment_country_id'] = $address_data['country_id']; + $this->session->data['payment_zone_id'] = $address_data['zone_id']; + + $this->session->data['shipping_address_id'] = $address_id; + $this->session->data['shipping_country_id'] = $address_data['country_id']; + $this->session->data['shipping_zone_id'] = $address_data['zone_id']; + $this->session->data['shipping_postcode'] = $address_data['postcode']; + } + } else { + $this->session->data['payment_address_id'] = ''; + $this->session->data['payment_country_id'] = ''; + $this->session->data['payment_zone_id'] = ''; + } + } + + $this->session->data['paypal_braintree'] = $this->request->post; + + $json = array( + 'error' => false, + 'url' => '' + ); + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function expressConfirm() { + if (!isset($this->session->data['paypal_braintree']) || !isset($this->session->data['paypal_braintree']['nonce'])) { + $this->response->redirect($this->url->link('checkout/cart', '', true)); + } + + $this->load->language('extension/payment/pp_braintree'); + $this->load->language('checkout/cart'); + + $this->load->model('tool/image'); + $this->load->model('extension/payment/pp_braintree'); + + // Coupon + if (isset($this->request->post['coupon']) && $this->validateCoupon()) { + $this->session->data['coupon'] = $this->request->post['coupon']; + + $this->session->data['success'] = $this->language->get('text_coupon'); + + $this->response->redirect($this->url->link('extension/payment/pp_braintree/expressConfirm', '', true)); + } + + // Voucher + if (isset($this->request->post['voucher']) && $this->validateVoucher()) { + $this->session->data['voucher'] = $this->request->post['voucher']; + + $this->session->data['success'] = $this->language->get('text_voucher'); + + $this->response->redirect($this->url->link('extension/payment/pp_braintree/expressConfirm', '', true)); + } + + // Reward + if (isset($this->request->post['reward']) && $this->validateReward()) { + $this->session->data['reward'] = abs($this->request->post['reward']); + + $this->session->data['success'] = $this->language->get('text_reward'); + + $this->response->redirect($this->url->link('extension/payment/pp_braintree/expressConfirm', '', true)); + } + + $this->document->setTitle($this->language->get('text_express_title')); + + $data['heading_title'] = $this->language->get('text_express_title'); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('common/home'), + 'text' => $this->language->get('text_home') + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_cart'), + 'href' => $this->url->link('checkout/cart') + ); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('extension/payment/pp_braintree/expressConfirm'), + 'text' => $this->language->get('text_express_title') + ); + + $points_total = 0; + + foreach ($this->cart->getProducts() as $product) { + if ($product['points']) { + $points_total += $product['points']; + } + } + + $data['column_name'] = $this->language->get('column_name'); + $data['column_model'] = $this->language->get('column_model'); + $data['column_quantity'] = $this->language->get('column_quantity'); + $data['column_price'] = $this->language->get('column_price'); + $data['column_total'] = $this->language->get('column_total'); + + $data['button_shipping'] = $this->language->get('button_express_shipping'); + $data['button_confirm'] = $this->language->get('button_express_confirm'); + + if (isset($this->request->post['next'])) { + $data['next'] = $this->request->post['next']; + } else { + $data['next'] = ''; + } + + $data['action'] = $this->url->link('extension/payment/pp_braintree/expressConfirm', '', true); + + $this->load->model('tool/upload'); + + $products = $this->cart->getProducts(); + + if (empty($products)) { + $this->response->redirect($this->url->link('checkout/cart', '', true)); + } + + foreach ($products as $product) { + $product_total = 0; + + foreach ($products as $product_2) { + if ($product_2['product_id'] == $product['product_id']) { + $product_total += $product_2['quantity']; + } + } + + if ($product['minimum'] > $product_total) { + $data['error_warning'] = sprintf($this->language->get('error_minimum'), $product['name'], $product['minimum']); + } + + if ($product['image']) { + $image = $this->model_tool_image->resize($product['image'], $this->config->get('theme_' . $this->config->get('config_theme') . '_image_cart_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_cart_height')); + } else { + $image = ''; + } + + $option_data = array(); + + foreach ($product['option'] as $option) { + if ($option['type'] != 'file') { + $value = $option['value']; + } else { + $upload_info = $this->model_tool_upload->getUploadByCode($option['value']); + + if ($upload_info) { + $value = $upload_info['name']; + } else { + $value = ''; + } + } + + $option_data[] = array( + 'name' => $option['name'], + 'value' => (utf8_strlen($value) > 20 ? utf8_substr($value, 0, 20) . '..' : $value) + ); + } + + // Display prices + if ($this->customer->isLogged() || !$this->config->get('config_customer_price')) { + $unit_price = $this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')); + + $price = $this->currency->format($unit_price, $this->session->data['currency']); + $total = $this->currency->format($unit_price * $product['quantity'], $this->session->data['currency']); + } else { + $price = false; + $total = false; + } + + $data['products'][] = array( + 'cart_id' => $product['cart_id'], + 'thumb' => $image, + 'name' => $product['name'], + 'model' => $product['model'], + 'option' => $option_data, + 'quantity' => $product['quantity'], + 'stock' => $product['stock'] ? true : !(!$this->config->get('config_stock_checkout') || $this->config->get('config_stock_warning')), + 'reward' => ($product['reward'] ? sprintf($this->language->get('text_points'), $product['reward']) : ''), + 'price' => $price, + 'total' => $total, + 'href' => $this->url->link('product/product', 'product_id=' . $product['product_id']), + 'remove' => $this->url->link('checkout/cart', 'remove=' . $product['cart_id']), + ); + } + + $data['vouchers'] = array(); + + if ($this->cart->hasShipping()) { + $data['has_shipping'] = true; + /** + * Shipping services + */ + if ($this->customer->isLogged()) { + $this->load->model('account/address'); + $shipping_address = $this->model_account_address->getAddress($this->session->data['shipping_address_id']); + } elseif (isset($this->session->data['guest'])) { + $shipping_address = $this->session->data['guest']['shipping']; + } + + if (!empty($shipping_address)) { + // Shipping Methods + $quote_data = array(); + + $this->load->model('setting/extension'); + + $results = $this->model_setting_extension->getExtensions('shipping'); + + if (!empty($results)) { + foreach ($results as $result) { + if ($this->config->get('shipping_' . $result['code'] . '_status')) { + $this->load->model('extension/shipping/' . $result['code']); + + $quote = $this->{'model_extension_shipping_' . $result['code']}->getQuote($shipping_address); + + if ($quote) { + $quote_data[$result['code']] = array( + 'title' => $quote['title'], + 'quote' => $quote['quote'], + 'sort_order' => $quote['sort_order'], + 'error' => $quote['error'] + ); + } + } + } + + if (!empty($quote_data)) { + $sort_order = array(); + + foreach ($quote_data as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $quote_data); + + $this->session->data['shipping_methods'] = $quote_data; + $data['shipping_methods'] = $quote_data; + + if (!isset($this->session->data['shipping_method'])) { + //default the shipping to the very first option. + $key1 = key($quote_data); + $key2 = key($quote_data[$key1]['quote']); + $this->session->data['shipping_method'] = $quote_data[$key1]['quote'][$key2]; + } + + $data['code'] = $this->session->data['shipping_method']['code']; + $data['action_shipping'] = $this->url->link('extension/payment/pp_braintree/shipping', '', true); + } else { + unset($this->session->data['shipping_methods']); + unset($this->session->data['shipping_method']); + $data['error_no_shipping'] = $this->language->get('error_no_shipping'); + } + } else { + unset($this->session->data['shipping_methods']); + unset($this->session->data['shipping_method']); + $data['error_no_shipping'] = $this->language->get('error_no_shipping'); + } + } + } else { + $data['has_shipping'] = false; + } + + // Totals + $this->load->model('setting/extension'); + + $totals = array(); + $taxes = $this->cart->getTaxes(); + $total = 0; + + // Because __call can not keep var references so we put them into an array. + $total_data = array( + 'totals' => &$totals, + 'taxes' => &$taxes, + 'total' => &$total + ); + + // Display prices + if ($this->customer->isLogged() || !$this->config->get('config_customer_price')) { + $sort_order = array(); + + $results = $this->model_setting_extension->getExtensions('total'); + + foreach ($results as $key => $value) { + $sort_order[$key] = $this->config->get('total_' . $value['code'] . '_sort_order'); + } + + array_multisort($sort_order, SORT_ASC, $results); + + foreach ($results as $result) { + if ($this->config->get('total_' . $result['code'] . '_status')) { + $this->load->model('extension/total/' . $result['code']); + + // We have to put the totals in an array so that they pass by reference. + $this->{'model_extension_total_' . $result['code']}->getTotal($total_data); + } + } + + $sort_order = array(); + + foreach ($totals as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $totals); + } + + $data['totals'] = array(); + + foreach ($totals as $total) { + $data['totals'][] = array( + 'title' => $total['title'], + 'text' => $this->currency->format($total['value'], $this->session->data['currency']), + ); + } + + /** + * Payment methods + */ + if ($this->customer->isLogged() && isset($this->session->data['payment_address_id'])) { + $this->load->model('account/address'); + $payment_address = $this->model_account_address->getAddress($this->session->data['payment_address_id']); + } elseif (isset($this->session->data['guest'])) { + $payment_address = $this->session->data['guest']['payment']; + } + + $method_data = array(); + + $this->load->model('setting/extension'); + + $results = $this->model_setting_extension->getExtensions('payment'); + + $this->model_extension_payment_pp_braintree->log("Payment methods returned based on new data"); + $this->model_extension_payment_pp_braintree->log($results); + + foreach ($results as $result) { + if ($this->config->get('payment_' . $result['code'] . '_status')) { + $this->load->model('extension/payment/' . $result['code']); + + $method = $this->{'model_extension_payment_' . $result['code']}->getMethod($payment_address, $total); + + if ($method) { + $method_data[$result['code']] = $method; + } + } + } + + $sort_order = array(); + + foreach ($method_data as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $method_data); + + $this->model_extension_payment_pp_braintree->log("Payment methods again - sorted"); + $this->model_extension_payment_pp_braintree->log($method_data); + + if (!isset($method_data['pp_braintree'])) { + $this->model_extension_payment_pp_braintree->log("Braintree module was no longer an option. Check configured zones or minimum order amount based on user address info"); + $this->session->data['error_warning'] = $this->language->get('error_unavailable'); + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + + $this->session->data['payment_methods'] = $method_data; + $this->session->data['payment_method'] = $method_data['pp_braintree']; + + $data['action_confirm'] = $this->url->link('extension/payment/pp_braintree/expressComplete', '', true); + + if (isset($this->session->data['error_warning'])) { + $data['error_warning'] = $this->session->data['error_warning']; + unset($this->session->data['error_warning']); + } else { + $data['error_warning'] = ''; + } + + if (isset($this->session->data['success'])) { + $data['success'] = $this->session->data['success']; + unset($this->session->data['success']); + } else { + $data['success'] = ''; + } + + if (isset($this->session->data['attention'])) { + $data['attention'] = $this->session->data['attention']; + unset($this->session->data['attention']); + } else { + $data['attention'] = ''; + } + + $data['coupon'] = $this->load->controller('extension/total/coupon'); + $data['voucher'] = $this->load->controller('extension/total/voucher'); + $data['reward'] = $this->load->controller('extension/total/reward'); + $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/pp_braintree_confirm', $data)); + } + + public function expressComplete() { + if (!isset($this->session->data['paypal_braintree']) || !isset($this->session->data['paypal_braintree']['nonce'])) { + $this->response->redirect($this->url->link('checkout/cart', '', true)); + } + + $this->load->language('extension/payment/pp_braintree'); + $redirect = ''; + + if ($this->cart->hasShipping()) { + // Validate if shipping address has been set. + $this->load->model('account/address'); + + if ($this->customer->isLogged() && isset($this->session->data['shipping_address_id'])) { + $shipping_address = $this->model_account_address->getAddress($this->session->data['shipping_address_id']); + } elseif (isset($this->session->data['guest'])) { + $shipping_address = $this->session->data['guest']['shipping']; + } + + if (empty($shipping_address)) { + $redirect = $this->url->link('checkout/checkout', '', true); + } + + // Validate if shipping method has been set. + if (!isset($this->session->data['shipping_method'])) { + $redirect = $this->url->link('checkout/checkout', '', true); + } + } else { + unset($this->session->data['shipping_method']); + unset($this->session->data['shipping_methods']); + } + + // Validate if payment address has been set. + $this->load->model('account/address'); + + if ($this->customer->isLogged() && isset($this->session->data['payment_address_id'])) { + $payment_address = $this->model_account_address->getAddress($this->session->data['payment_address_id']); + } elseif (isset($this->session->data['guest'])) { + $payment_address = $this->session->data['guest']['payment']; + } + + // Validate if payment method has been set. + if (!isset($this->session->data['payment_method'])) { + $redirect = $this->url->link('checkout/checkout', '', true); + } + + // Validate cart has products and has stock. + if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) { + $redirect = $this->url->link('checkout/cart'); + } + + // Validate minimum quantity requirements. + $products = $this->cart->getProducts(); + + foreach ($products as $product) { + $product_total = 0; + + foreach ($products as $product_2) { + if ($product_2['product_id'] == $product['product_id']) { + $product_total += $product_2['quantity']; + } + } + + if ($product['minimum'] > $product_total) { + $redirect = $this->url->link('checkout/cart'); + + break; + } + } + + if ($redirect == '') { + $totals = array(); + $taxes = $this->cart->getTaxes(); + $total = 0; + + // Because __call can not keep var references so we put them into an array. + $total_data = array( + 'totals' => &$totals, + 'taxes' => &$taxes, + 'total' => &$total + ); + + $this->load->model('setting/extension'); + + $sort_order = array(); + + $results = $this->model_setting_extension->getExtensions('total'); + + foreach ($results as $key => $value) { + $sort_order[$key] = $this->config->get('total_' . $value['code'] . '_sort_order'); + } + + array_multisort($sort_order, SORT_ASC, $results); + + foreach ($results as $result) { + if ($this->config->get('total_' . $result['code'] . '_status')) { + $this->load->model('extension/total/' . $result['code']); + + // We have to put the totals in an array so that they pass by reference. + $this->{'model_extension_total_' . $result['code']}->getTotal($total_data); + } + } + + $sort_order = array(); + + foreach ($totals as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $totals); + + $this->load->language('checkout/checkout'); + + $data = array(); + + $data['invoice_prefix'] = $this->config->get('config_invoice_prefix'); + $data['store_id'] = $this->config->get('config_store_id'); + $data['store_name'] = $this->config->get('config_name'); + + if ($data['store_id']) { + $data['store_url'] = $this->config->get('config_url'); + } else { + $data['store_url'] = HTTP_SERVER; + } + + if ($this->customer->isLogged() && isset($this->session->data['payment_address_id'])) { + $data['customer_id'] = $this->customer->getId(); + $data['customer_group_id'] = $this->config->get('config_customer_group_id'); + $data['firstname'] = $this->customer->getFirstName(); + $data['lastname'] = $this->customer->getLastName(); + $data['email'] = $this->customer->getEmail(); + $data['telephone'] = $this->customer->getTelephone(); + + $this->load->model('account/address'); + + $payment_address = $this->model_account_address->getAddress($this->session->data['payment_address_id']); + } elseif (isset($this->session->data['guest'])) { + $data['customer_id'] = 0; + $data['customer_group_id'] = $this->session->data['guest']['customer_group_id']; + $data['firstname'] = $this->session->data['guest']['firstname']; + $data['lastname'] = $this->session->data['guest']['lastname']; + $data['email'] = $this->session->data['guest']['email']; + $data['telephone'] = $this->session->data['guest']['telephone']; + + $payment_address = $this->session->data['guest']['payment']; + } + + $data['payment_firstname'] = isset($payment_address['firstname']) ? $payment_address['firstname'] : ''; + $data['payment_lastname'] = isset($payment_address['lastname']) ? $payment_address['lastname'] : ''; + $data['payment_company'] = isset($payment_address['company']) ? $payment_address['company'] : ''; + $data['payment_company_id'] = isset($payment_address['company_id']) ? $payment_address['company_id'] : ''; + $data['payment_tax_id'] = isset($payment_address['tax_id']) ? $payment_address['tax_id'] : ''; + $data['payment_address_1'] = isset($payment_address['address_1']) ? $payment_address['address_1'] : ''; + $data['payment_address_2'] = isset($payment_address['address_2']) ? $payment_address['address_2'] : ''; + $data['payment_city'] = isset($payment_address['city']) ? $payment_address['city'] : ''; + $data['payment_postcode'] = isset($payment_address['postcode']) ? $payment_address['postcode'] : ''; + $data['payment_zone'] = isset($payment_address['zone']) ? $payment_address['zone'] : ''; + $data['payment_zone_id'] = isset($payment_address['zone_id']) ? $payment_address['zone_id'] : ''; + $data['payment_country'] = isset($payment_address['country']) ? $payment_address['country'] : ''; + $data['payment_country_id'] = isset($payment_address['country_id']) ? $payment_address['country_id'] : ''; + $data['payment_address_format'] = isset($payment_address['address_format']) ? $payment_address['address_format'] : ''; + + $data['payment_method'] = ''; + if (isset($this->session->data['payment_method']['title'])) { + $data['payment_method'] = $this->session->data['payment_method']['title']; + } + + $data['payment_code'] = ''; + if (isset($this->session->data['payment_method']['code'])) { + $data['payment_code'] = $this->session->data['payment_method']['code']; + } + + if ($this->cart->hasShipping()) { + if ($this->customer->isLogged()) { + $this->load->model('account/address'); + + $shipping_address = $this->model_account_address->getAddress($this->session->data['shipping_address_id']); + } elseif (isset($this->session->data['guest'])) { + $shipping_address = $this->session->data['guest']['shipping']; + } + + $data['shipping_firstname'] = $shipping_address['firstname']; + $data['shipping_lastname'] = $shipping_address['lastname']; + $data['shipping_company'] = $shipping_address['company']; + $data['shipping_address_1'] = $shipping_address['address_1']; + $data['shipping_address_2'] = $shipping_address['address_2']; + $data['shipping_city'] = $shipping_address['city']; + $data['shipping_postcode'] = $shipping_address['postcode']; + $data['shipping_zone'] = $shipping_address['zone']; + $data['shipping_zone_id'] = $shipping_address['zone_id']; + $data['shipping_country'] = $shipping_address['country']; + $data['shipping_country_id'] = $shipping_address['country_id']; + $data['shipping_address_format'] = $shipping_address['address_format']; + + $data['shipping_method'] = ''; + if (isset($this->session->data['shipping_method']['title'])) { + $data['shipping_method'] = $this->session->data['shipping_method']['title']; + } + + $data['shipping_code'] = ''; + if (isset($this->session->data['shipping_method']['code'])) { + $data['shipping_code'] = $this->session->data['shipping_method']['code']; + } + } else { + $data['shipping_firstname'] = ''; + $data['shipping_lastname'] = ''; + $data['shipping_company'] = ''; + $data['shipping_address_1'] = ''; + $data['shipping_address_2'] = ''; + $data['shipping_city'] = ''; + $data['shipping_postcode'] = ''; + $data['shipping_zone'] = ''; + $data['shipping_zone_id'] = ''; + $data['shipping_country'] = ''; + $data['shipping_country_id'] = ''; + $data['shipping_address_format'] = ''; + $data['shipping_method'] = ''; + $data['shipping_code'] = ''; + } + + $product_data = array(); + + foreach ($this->cart->getProducts() as $product) { + $option_data = array(); + + foreach ($product['option'] as $option) { + $option_data[] = array( + 'product_option_id' => $option['product_option_id'], + 'product_option_value_id' => $option['product_option_value_id'], + 'option_id' => $option['option_id'], + 'option_value_id' => $option['option_value_id'], + 'name' => $option['name'], + 'value' => $option['value'], + 'type' => $option['type'] + ); + } + + $product_data[] = array( + 'product_id' => $product['product_id'], + 'name' => $product['name'], + 'model' => $product['model'], + 'option' => $option_data, + 'download' => $product['download'], + 'quantity' => $product['quantity'], + 'subtract' => $product['subtract'], + 'price' => $product['price'], + 'total' => $product['total'], + 'tax' => $this->tax->getTax($product['price'], $product['tax_class_id']), + 'reward' => $product['reward'] + ); + } + + // Gift Voucher + $voucher_data = array(); + + if (!empty($this->session->data['vouchers'])) { + foreach ($this->session->data['vouchers'] as $voucher) { + $voucher_data[] = array( + 'description' => $voucher['description'], + 'code' => token(10), + 'to_name' => $voucher['to_name'], + 'to_email' => $voucher['to_email'], + 'from_name' => $voucher['from_name'], + 'from_email' => $voucher['from_email'], + 'voucher_theme_id' => $voucher['voucher_theme_id'], + 'message' => $voucher['message'], + 'amount' => $voucher['amount'] + ); + } + } + + $data['products'] = $product_data; + $data['vouchers'] = $voucher_data; + $data['totals'] = $totals; + $data['total'] = $total; + $data['comment'] = ''; + + if (isset($this->request->cookie['tracking'])) { + $data['tracking'] = $this->request->cookie['tracking']; + + $subtotal = $this->cart->getSubTotal(); + + // Affiliate + $this->load->model('affiliate/affiliate'); + + $affiliate_info = $this->model_affiliate_affiliate->getAffiliateByCode($this->request->cookie['tracking']); + + if ($affiliate_info) { + $data['affiliate_id'] = $affiliate_info['affiliate_id']; + $data['commission'] = ($subtotal / 100) * $affiliate_info['commission']; + } else { + $data['affiliate_id'] = 0; + $data['commission'] = 0; + } + + // Marketing + $this->load->model('checkout/marketing'); + + $marketing_info = $this->model_checkout_marketing->getMarketingByCode($this->request->cookie['tracking']); + + if ($marketing_info) { + $data['marketing_id'] = $marketing_info['marketing_id']; + } else { + $data['marketing_id'] = 0; + } + } else { + $data['affiliate_id'] = 0; + $data['commission'] = 0; + $data['marketing_id'] = 0; + $data['tracking'] = ''; + } + + $data['language_id'] = $this->config->get('config_language_id'); + $data['currency_id'] = $this->currency->getId($this->session->data['currency']); + $data['currency_code'] = $this->session->data['currency']; + $data['currency_value'] = $this->currency->getValue($this->session->data['currency']); + $data['ip'] = $this->request->server['REMOTE_ADDR']; + + if (!empty($this->request->server['HTTP_X_FORWARDED_FOR'])) { + $data['forwarded_ip'] = $this->request->server['HTTP_X_FORWARDED_FOR']; + } elseif (!empty($this->request->server['HTTP_CLIENT_IP'])) { + $data['forwarded_ip'] = $this->request->server['HTTP_CLIENT_IP']; + } else { + $data['forwarded_ip'] = ''; + } + + if (isset($this->request->server['HTTP_USER_AGENT'])) { + $data['user_agent'] = $this->request->server['HTTP_USER_AGENT']; + } else { + $data['user_agent'] = ''; + } + + if (isset($this->request->server['HTTP_ACCEPT_LANGUAGE'])) { + $data['accept_language'] = $this->request->server['HTTP_ACCEPT_LANGUAGE']; + } else { + $data['accept_language'] = ''; + } + + $this->load->model('account/custom_field'); + $this->load->model('checkout/order'); + + $order_id = $this->model_checkout_order->addOrder($data); + $this->session->data['order_id'] = $order_id; + + $this->load->model('extension/payment/pp_braintree'); + + $this->initialise(); + + $create_sale = [ + "amount" => $this->currency->format($data['total'], $data['currency_code'], $data['currency_value'], false), + "paymentMethodNonce" => $this->session->data['paypal_braintree']['nonce'], + "orderId" => $order_id, + 'channel' => 'OpenCart_Cart_vzero', + ]; + + $transaction = $this->model_extension_payment_pp_braintree->addTransaction($this->gateway, $create_sale); + + //handle order status + + $order_status_id = 0; + switch ($transaction->transaction->status) { + case 'authorization_expired': + $order_status_id = $this->config->get('payment_pp_braintree_authorization_expired_id'); + break; + case 'authorized': + $order_status_id = $this->config->get('payment_pp_braintree_authorized_id'); + break; + case 'authorizing': + $order_status_id = $this->config->get('payment_pp_braintree_authorizing_id'); + break; + case 'settlement_pending': + $order_status_id = $this->config->get('payment_pp_braintree_settlement_pending_id'); + break; + case 'failed': + $order_status_id = $this->config->get('payment_pp_braintree_failed_id'); + break; + case 'gateway_rejected': + $order_status_id = $this->config->get('payment_pp_braintree_gateway_rejected_id'); + break; + case 'processor_declined': + $order_status_id = $this->config->get('payment_pp_braintree_processor_declined_id'); + break; + case 'settled': + $order_status_id = $this->config->get('payment_pp_braintree_settled_id'); + break; + case 'settling': + $order_status_id = $this->config->get('payment_pp_braintree_settling_id'); + break; + case 'submitted_for_settlement': + $order_status_id = $this->config->get('payment_pp_braintree_submitted_for_settlement_id'); + break; + case 'voided': + $order_status_id = $this->config->get('payment_pp_braintree_voided_id'); + break; + } + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $order_status_id); + + if ($transaction->success) { + $this->model_extension_payment_pp_braintree->log('Transaction success, details below'); + $this->model_extension_payment_pp_braintree->log($transaction); + + $this->response->redirect($this->url->link('checkout/success', '', true)); + } else { + $this->model_extension_payment_pp_braintree->log('Transaction failed, details below'); + $this->model_extension_payment_pp_braintree->log($transaction); + + $this->session->data['error'] = $this->language->get('error_process_order'); + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + } else { + $this->response->redirect($redirect); + } + } + + private function initialise() { + $this->load->model('extension/payment/pp_braintree'); + + if ($this->config->get('payment_pp_braintree_access_token') != '') { + $this->gateway = $this->model_extension_payment_pp_braintree->setGateway($this->config->get('payment_pp_braintree_access_token')); + } else { + $this->model_extension_payment_pp_braintree->setCredentials(); + } + } + + public function shipping() { + $this->shippingValidate($this->request->post['shipping_method']); + + $this->response->redirect($this->url->link('extension/payment/pp_braintree/expressConfirm')); + } + + protected function shippingValidate($code) { + $this->load->language('checkout/cart'); + $this->load->language('extension/payment/pp_braintree'); + + if (empty($code)) { + $this->session->data['error_warning'] = $this->language->get('error_shipping'); + return false; + } else { + $shipping = explode('.', $code); + + if (!isset($shipping[0]) || !isset($shipping[1]) || !isset($this->session->data['shipping_methods'][$shipping[0]]['quote'][$shipping[1]])) { + $this->session->data['error_warning'] = $this->language->get('error_shipping'); + return false; + } else { + $this->session->data['shipping_method'] = $this->session->data['shipping_methods'][$shipping[0]]['quote'][$shipping[1]]; + $this->session->data['success'] = $this->language->get('text_shipping_updated'); + return true; + } + } + } + + protected function validateCoupon() { + $this->load->model('extension/total/coupon'); + + $coupon_info = $this->model_extension_total_coupon->getCoupon($this->request->post['coupon']); + + if ($coupon_info) { + return true; + } else { + $this->session->data['error_warning'] = $this->language->get('error_coupon'); + return false; + } + } + + protected function validateVoucher() { + $this->load->model('extension/total/coupon'); + + $voucher_info = $this->model_extension_total_voucher->getVoucher($this->request->post['voucher']); + + if ($voucher_info) { + return true; + } else { + $this->session->data['error_warning'] = $this->language->get('error_voucher'); + return false; + } + } + + protected function validateReward() { + $points = $this->customer->getRewardPoints(); + + $points_total = 0; + + foreach ($this->cart->getProducts() as $product) { + if ($product['points']) { + $points_total += $product['points']; + } + } + + $error = ''; + + if (empty($this->request->post['reward'])) { + $error = $this->language->get('error_reward'); + } + + if ($this->request->post['reward'] > $points) { + $error = sprintf($this->language->get('error_points'), $this->request->post['reward']); + } + + if ($this->request->post['reward'] > $points_total) { + $error = sprintf($this->language->get('error_maximum'), $points_total); + } + + if (!$error) { + return true; + } else { + $this->session->data['error_warning'] = $error; + return false; + } + } +} diff --git a/public/catalog/controller/extension/payment/pp_express.php b/public/catalog/controller/extension/payment/pp_express.php new file mode 100644 index 0000000..9081cfe --- /dev/null +++ b/public/catalog/controller/extension/payment/pp_express.php @@ -0,0 +1,1963 @@ +<?php +class ControllerExtensionPaymentPPExpress extends Controller { + public function index() { + $this->load->language('extension/payment/pp_express'); + + if ($this->config->get('payment_pp_express_test') == 1) { + $data['paypal_environment'] = "sandbox"; + } else { + $data['paypal_environment'] = "production"; + } + + $data['payment_pp_express_style_layout'] = $this->config->get('payment_pp_express_style_layout') != null ? $this->config->get('payment_pp_express_style_layout') : "vertical"; + $data['payment_pp_express_style_size'] = $this->config->get('payment_pp_express_style_size') != null ? $this->config->get('payment_pp_express_style_size') : "medium"; + $data['payment_pp_express_style_shape'] = $this->config->get('payment_pp_express_style_shape') != null ? $this->config->get('payment_pp_express_style_shape') : "rect"; + $data['payment_pp_express_style_color'] = $this->config->get('payment_pp_express_style_color') != null ? $this->config->get('payment_pp_express_style_color') : "blue"; + + $data['payment_pp_express_pp_credit'] = $this->config->get('payment_pp_express_pp_credit'); + $data['payment_pp_express_pp_cards'] = $this->config->get('payment_pp_express_pp_cards'); + $data['payment_pp_express_pp_elv'] = $this->config->get('payment_pp_express_pp_elv'); + + $disallowed_payment_methods = array(); + $allowed_payment_methods = array(); + + if ($this->config->get('payment_pp_express_pp_credit') == 1) { + $allowed_payment_methods[] = "paypal.FUNDING.CREDIT"; + } else { + $disallowed_payment_methods[] = "paypal.FUNDING.CREDIT"; + } + + if ($this->config->get('payment_pp_express_pp_cards') == 1) { + $allowed_payment_methods[] = "paypal.FUNDING.CARD"; + } else { + $disallowed_payment_methods[] = "paypal.FUNDING.CARD"; + } + + if ($this->config->get('payment_pp_express_pp_elv') == 1) { + $allowed_payment_methods[] = "paypal.FUNDING.ELV"; + } else { + $disallowed_payment_methods[] = "paypal.FUNDING.ELV"; + } + + $data['allowed_payment_methods'] = implode(",", $allowed_payment_methods); + $data['disallowed_payment_methods'] = implode(",", $disallowed_payment_methods); + + $data['continue'] = $this->url->link('extension/payment/pp_express/checkout', '', true); + + unset($this->session->data['paypal']); + + return $this->load->view('extension/payment/pp_express', $data); + } + + public function eventLoadCheckoutJs($route, &$data) { + $this->document->addScript('https://www.paypalobjects.com/api/checkout.js'); + } + + public function express() { + $this->load->model('extension/payment/pp_express'); + + if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) { + $this->response->redirect($this->url->link('checkout/cart')); + } + + if ($this->customer->isLogged()) { + /** + * If the customer is already logged in + */ + $this->session->data['paypal']['guest'] = false; + + unset($this->session->data['guest']); + } else { + if ($this->config->get('config_checkout_guest') && !$this->config->get('config_customer_price') && !$this->cart->hasDownload() && !$this->cart->hasRecurringProducts()) { + /** + * If the guest checkout is allowed (config ok, no login for price and doesn't have downloads) + */ + $this->session->data['paypal']['guest'] = true; + } else { + /** + * If guest checkout disabled or login is required before price or order has downloads + * + * Send them to the normal checkout flow. + */ + unset($this->session->data['guest']); + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + } + + unset($this->session->data['shipping_method']); + unset($this->session->data['shipping_methods']); + unset($this->session->data['payment_method']); + unset($this->session->data['payment_methods']); + + $this->load->model('tool/image'); + + if ($this->cart->hasShipping()) { + $shipping = 2; + } else { + $shipping = 1; + } + + $max_amount = $this->cart->getTotal() * 1.5; + $max_amount = $this->currency->format($max_amount, $this->session->data['currency'], '', false); + + $data = array( + 'METHOD' => 'SetExpressCheckout', + 'MAXAMT' => $max_amount, + 'RETURNURL' => $this->url->link('extension/payment/pp_express/expressReturn', '', true), + 'CANCELURL' => $this->url->link('checkout/cart', '', true), + 'REQCONFIRMSHIPPING' => 0, + 'NOSHIPPING' => $shipping, + 'LANDINGPAGE' => 'Login', + 'LOGOIMG' => $this->model_tool_image->resize($this->config->get('payment_pp_express_logo'), 750, 90), + 'CHANNELTYPE' => 'Merchant' + ); + + if (isset($this->session->data['pp_login']['seamless']['access_token']) && (isset($this->session->data['pp_login']['seamless']['customer_id']) && $this->session->data['pp_login']['seamless']['customer_id'] == $this->customer->getId()) && $this->config->get('module_pp_login_seamless')) { + $data['IDENTITYACCESSTOKEN'] = $this->session->data['pp_login']['seamless']['access_token']; + } + + $data = array_merge($data, $this->model_extension_payment_pp_express->paymentRequestInfo()); + + $result = $this->model_extension_payment_pp_express->call($data); + + /** + * If a failed PayPal setup happens, handle it. + */ + if (!isset($result['TOKEN'])) { + $this->session->data['error'] = $result['L_LONGMESSAGE0']; + /** + * Unable to add error message to user as the session errors/success are not + * used on the cart or checkout pages - need to be added? + * If PayPal debug log is off then still log error to normal error log. + */ + + $this->log->write('Unable to create PayPal call: ' . json_encode($result)); + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + + $this->session->data['paypal']['token'] = $result['TOKEN']; + + if ($this->config->get('payment_pp_express_test') == 1) { + header('Location: https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $result['TOKEN']); + } else { + header('Location: https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $result['TOKEN']); + } + } + + public function expressReturn() { + /** + * This is the url when PayPal has completed the auth. + * + * It has no output, instead it sets the data and locates to checkout + */ + $this->load->model('extension/payment/pp_express'); + $data = array( + 'METHOD' => 'GetExpressCheckoutDetails', + 'TOKEN' => $this->session->data['paypal']['token'] + ); + + $result = $this->model_extension_payment_pp_express->call($data); + $this->session->data['paypal']['payerid'] = $result['PAYERID']; + $this->session->data['paypal']['result'] = $result; + + $this->session->data['comment'] = ''; + if (isset($result['PAYMENTREQUEST_0_NOTETEXT'])) { + $this->session->data['comment'] = $result['PAYMENTREQUEST_0_NOTETEXT']; + } + + if ($this->session->data['paypal']['guest'] == true) { + $this->session->data['guest']['customer_group_id'] = $this->config->get('config_customer_group_id'); + $this->session->data['guest']['firstname'] = trim($result['FIRSTNAME']); + $this->session->data['guest']['lastname'] = trim($result['LASTNAME']); + $this->session->data['guest']['email'] = trim($result['EMAIL']); + + if (isset($result['PHONENUM'])) { + $this->session->data['guest']['telephone'] = $result['PHONENUM']; + } else { + $this->session->data['guest']['telephone'] = ''; + } + + $this->session->data['guest']['payment']['firstname'] = trim($result['FIRSTNAME']); + $this->session->data['guest']['payment']['lastname'] = trim($result['LASTNAME']); + + if (isset($result['BUSINESS'])) { + $this->session->data['guest']['payment']['company'] = $result['BUSINESS']; + } else { + $this->session->data['guest']['payment']['company'] = ''; + } + + $this->session->data['guest']['payment']['company_id'] = ''; + $this->session->data['guest']['payment']['tax_id'] = ''; + + if ($this->cart->hasShipping()) { + $shipping_name = explode(' ', trim($result['PAYMENTREQUEST_0_SHIPTONAME'])); + $shipping_first_name = $shipping_name[0]; + unset($shipping_name[0]); + $shipping_last_name = implode(' ', $shipping_name); + + $this->session->data['guest']['payment']['address_1'] = $result['PAYMENTREQUEST_0_SHIPTOSTREET']; + if (isset($result['PAYMENTREQUEST_0_SHIPTOSTREET2'])) { + $this->session->data['guest']['payment']['address_2'] = $result['PAYMENTREQUEST_0_SHIPTOSTREET2']; + } else { + $this->session->data['guest']['payment']['address_2'] = ''; + } + + $this->session->data['guest']['payment']['postcode'] = $result['PAYMENTREQUEST_0_SHIPTOZIP']; + $this->session->data['guest']['payment']['city'] = $result['PAYMENTREQUEST_0_SHIPTOCITY']; + + $this->session->data['guest']['shipping']['firstname'] = $shipping_first_name; + $this->session->data['guest']['shipping']['lastname'] = $shipping_last_name; + $this->session->data['guest']['shipping']['company'] = ''; + $this->session->data['guest']['shipping']['address_1'] = $result['PAYMENTREQUEST_0_SHIPTOSTREET']; + + if (isset($result['PAYMENTREQUEST_0_SHIPTOSTREET2'])) { + $this->session->data['guest']['shipping']['address_2'] = $result['PAYMENTREQUEST_0_SHIPTOSTREET2']; + } else { + $this->session->data['guest']['shipping']['address_2'] = ''; + } + + $this->session->data['guest']['shipping']['postcode'] = $result['PAYMENTREQUEST_0_SHIPTOZIP']; + $this->session->data['guest']['shipping']['city'] = $result['PAYMENTREQUEST_0_SHIPTOCITY']; + + $this->session->data['shipping_postcode'] = $result['PAYMENTREQUEST_0_SHIPTOZIP']; + + $country_info = $this->db->query("SELECT * FROM `" . DB_PREFIX . "country` WHERE `iso_code_2` = '" . $this->db->escape($result['PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE']) . "' AND `status` = '1' LIMIT 1")->row; + + if ($country_info) { + $this->session->data['guest']['shipping']['country_id'] = $country_info['country_id']; + $this->session->data['guest']['shipping']['country'] = $country_info['name']; + $this->session->data['guest']['shipping']['iso_code_2'] = $country_info['iso_code_2']; + $this->session->data['guest']['shipping']['iso_code_3'] = $country_info['iso_code_3']; + $this->session->data['guest']['shipping']['address_format'] = $country_info['address_format']; + $this->session->data['guest']['payment']['country_id'] = $country_info['country_id']; + $this->session->data['guest']['payment']['country'] = $country_info['name']; + $this->session->data['guest']['payment']['iso_code_2'] = $country_info['iso_code_2']; + $this->session->data['guest']['payment']['iso_code_3'] = $country_info['iso_code_3']; + $this->session->data['guest']['payment']['address_format'] = $country_info['address_format']; + $this->session->data['shipping_country_id'] = $country_info['country_id']; + } else { + $this->session->data['guest']['shipping']['country_id'] = ''; + $this->session->data['guest']['shipping']['country'] = ''; + $this->session->data['guest']['shipping']['iso_code_2'] = ''; + $this->session->data['guest']['shipping']['iso_code_3'] = ''; + $this->session->data['guest']['shipping']['address_format'] = ''; + $this->session->data['guest']['payment']['country_id'] = ''; + $this->session->data['guest']['payment']['country'] = ''; + $this->session->data['guest']['payment']['iso_code_2'] = ''; + $this->session->data['guest']['payment']['iso_code_3'] = ''; + $this->session->data['guest']['payment']['address_format'] = ''; + $this->session->data['shipping_country_id'] = ''; + } + + if (isset($result['PAYMENTREQUEST_0_SHIPTOSTATE'])) { + $returned_shipping_zone = $result['PAYMENTREQUEST_0_SHIPTOSTATE']; + } else { + $returned_shipping_zone = ''; + } + + $zone_info = $this->db->query("SELECT * FROM `" . DB_PREFIX . "zone` WHERE (`name` = '" . $this->db->escape($returned_shipping_zone) . "' OR `code` = '" . $this->db->escape($returned_shipping_zone) . "') AND `status` = '1' AND `country_id` = '" . (int)$country_info['country_id'] . "' LIMIT 1")->row; + + if ($zone_info) { + $this->session->data['guest']['shipping']['zone'] = $zone_info['name']; + $this->session->data['guest']['shipping']['zone_code'] = $zone_info['code']; + $this->session->data['guest']['shipping']['zone_id'] = $zone_info['zone_id']; + $this->session->data['guest']['payment']['zone'] = $zone_info['name']; + $this->session->data['guest']['payment']['zone_code'] = $zone_info['code']; + $this->session->data['guest']['payment']['zone_id'] = $zone_info['zone_id']; + $this->session->data['shipping_zone_id'] = $zone_info['zone_id']; + } else { + $this->session->data['guest']['shipping']['zone'] = ''; + $this->session->data['guest']['shipping']['zone_code'] = ''; + $this->session->data['guest']['shipping']['zone_id'] = ''; + $this->session->data['guest']['payment']['zone'] = ''; + $this->session->data['guest']['payment']['zone_code'] = ''; + $this->session->data['guest']['payment']['zone_id'] = ''; + $this->session->data['shipping_zone_id'] = ''; + } + + $this->session->data['guest']['shipping_address'] = true; + } else { + $this->session->data['guest']['payment']['address_1'] = ''; + $this->session->data['guest']['payment']['address_2'] = ''; + $this->session->data['guest']['payment']['postcode'] = ''; + $this->session->data['guest']['payment']['city'] = ''; + $this->session->data['guest']['payment']['country_id'] = ''; + $this->session->data['guest']['payment']['country'] = ''; + $this->session->data['guest']['payment']['iso_code_2'] = ''; + $this->session->data['guest']['payment']['iso_code_3'] = ''; + $this->session->data['guest']['payment']['address_format'] = ''; + $this->session->data['guest']['payment']['zone'] = ''; + $this->session->data['guest']['payment']['zone_code'] = ''; + $this->session->data['guest']['payment']['zone_id'] = ''; + $this->session->data['guest']['shipping_address'] = false; + } + + $this->session->data['account'] = 'guest'; + + unset($this->session->data['shipping_method']); + unset($this->session->data['shipping_methods']); + unset($this->session->data['payment_method']); + unset($this->session->data['payment_methods']); + } else { + unset($this->session->data['guest']); + /** + * if the user is logged in, add the address to the account and set the ID. + */ + + if ($this->cart->hasShipping()) { + $this->load->model('account/address'); + + $addresses = $this->model_account_address->getAddresses(); + + /** + * Compare all of the user addresses and see if there is a match + */ + $match = false; + foreach($addresses as $address) { + if (trim(strtolower($address['address_1'])) == trim(strtolower($result['PAYMENTREQUEST_0_SHIPTOSTREET'])) && trim(strtolower($address['postcode'])) == trim(strtolower($result['PAYMENTREQUEST_0_SHIPTOZIP']))) { + $match = true; + + $this->session->data['payment_address_id'] = $address['address_id']; + $this->session->data['payment_country_id'] = $address['country_id']; + $this->session->data['payment_zone_id'] = $address['zone_id']; + + $this->session->data['shipping_address_id'] = $address['address_id']; + $this->session->data['shipping_country_id'] = $address['country_id']; + $this->session->data['shipping_zone_id'] = $address['zone_id']; + $this->session->data['shipping_postcode'] = $address['postcode']; + + break; + } + } + + /** + * If there is no address match add the address and set the info. + */ + if ($match == false) { + + $shipping_name = explode(' ', trim($result['PAYMENTREQUEST_0_SHIPTONAME'])); + $shipping_first_name = $shipping_name[0]; + unset($shipping_name[0]); + $shipping_last_name = implode(' ', $shipping_name); + + $country_info = $this->db->query("SELECT * FROM `" . DB_PREFIX . "country` WHERE `iso_code_2` = '" . $this->db->escape($result['PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE']) . "' AND `status` = '1' LIMIT 1")->row; + + if (isset($result['PAYMENTREQUEST_0_SHIPTOSTATE'])) { + $zone_info = $this->db->query("SELECT * FROM `" . DB_PREFIX . "zone` WHERE (`name` = '" . $this->db->escape($result['PAYMENTREQUEST_0_SHIPTOSTATE']) . "' OR `code` = '" . $this->db->escape($result['PAYMENTREQUEST_0_SHIPTOSTATE']) . "') AND `status` = '1' AND `country_id` = '" . (int)$country_info['country_id'] . "'")->row; + } else { + $zone_info = array(); + } + + $address_data = array( + 'firstname' => $shipping_first_name, + 'lastname' => $shipping_last_name, + 'company' => '', + 'company_id' => '', + 'tax_id' => '', + 'address_1' => $result['PAYMENTREQUEST_0_SHIPTOSTREET'], + 'address_2' => (isset($result['PAYMENTREQUEST_0_SHIPTOSTREET2']) ? $result['PAYMENTREQUEST_0_SHIPTOSTREET2'] : ''), + 'postcode' => $result['PAYMENTREQUEST_0_SHIPTOZIP'], + 'city' => $result['PAYMENTREQUEST_0_SHIPTOCITY'], + 'zone_id' => (isset($zone_info['zone_id']) ? $zone_info['zone_id'] : 0), + 'country_id' => (isset($country_info['country_id']) ? $country_info['country_id'] : 0) + ); + + $address_id = $this->model_account_address->addAddress($this->customer->getId(), $address_data); + + $this->session->data['payment_address_id'] = $address_id; + $this->session->data['payment_country_id'] = $address_data['country_id']; + $this->session->data['payment_zone_id'] = $address_data['zone_id']; + + $this->session->data['shipping_address_id'] = $address_id; + $this->session->data['shipping_country_id'] = $address_data['country_id']; + $this->session->data['shipping_zone_id'] = $address_data['zone_id']; + $this->session->data['shipping_postcode'] = $address_data['postcode']; + } + } else { + $this->session->data['payment_address_id'] = ''; + $this->session->data['payment_country_id'] = ''; + $this->session->data['payment_zone_id'] = ''; + } + } + + $this->response->redirect($this->url->link('extension/payment/pp_express/expressConfirm', '', true)); + } + + public function expressConfirm() { + $this->load->language('extension/payment/pp_express'); + $this->load->language('checkout/cart'); + + $this->load->model('tool/image'); + + // Coupon + if (isset($this->request->post['coupon']) && $this->validateCoupon()) { + $this->session->data['coupon'] = $this->request->post['coupon']; + + $this->session->data['success'] = $this->language->get('text_coupon'); + + $this->response->redirect($this->url->link('extension/payment/pp_express/expressConfirm', '', true)); + } + + // Voucher + if (isset($this->request->post['voucher']) && $this->validateVoucher()) { + $this->session->data['voucher'] = $this->request->post['voucher']; + + $this->session->data['success'] = $this->language->get('text_voucher'); + + $this->response->redirect($this->url->link('extension/payment/pp_express/expressConfirm', '', true)); + } + + // Reward + if (isset($this->request->post['reward']) && $this->validateReward()) { + $this->session->data['reward'] = abs($this->request->post['reward']); + + $this->session->data['success'] = $this->language->get('text_reward'); + + $this->response->redirect($this->url->link('extension/payment/pp_express/expressConfirm', '', true)); + } + + $this->document->setTitle($this->language->get('express_text_title')); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('common/home'), + 'text' => $this->language->get('text_home') + ); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('extension/payment/pp_express/express'), + 'text' => $this->language->get('text_title') + ); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('extension/payment/pp_express/expressConfirm'), + 'text' => $this->language->get('express_text_title') + ); + + $points = $this->customer->getRewardPoints(); + + $points_total = 0; + + foreach ($this->cart->getProducts() as $product) { + if ($product['points']) { + $points_total += $product['points']; + } + } + + $data['button_shipping'] = $this->language->get('button_express_shipping'); + $data['button_confirm'] = $this->language->get('button_express_confirm'); + + if (isset($this->request->post['next'])) { + $data['next'] = $this->request->post['next']; + } else { + $data['next'] = ''; + } + + $data['action'] = $this->url->link('extension/payment/pp_express/expressConfirm', '', true); + + $this->load->model('tool/upload'); + + $products = $this->cart->getProducts(); + + foreach ($products as $product) { + $product_total = 0; + + foreach ($products as $product_2) { + if ($product_2['product_id'] == $product['product_id']) { + $product_total += $product_2['quantity']; + } + } + + if ($product['minimum'] > $product_total) { + $data['error_warning'] = sprintf($this->language->get('error_minimum'), $product['name'], $product['minimum']); + } + + if ($product['image']) { + $image = $this->model_tool_image->resize($product['image'], $this->config->get('theme_' . $this->config->get('config_theme') . '_image_cart_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_cart_height')); + } else { + $image = ''; + } + + $option_data = array(); + + foreach ($product['option'] as $option) { + if ($option['type'] != 'file') { + $value = $option['value']; + } else { + $upload_info = $this->model_tool_upload->getUploadByCode($option['value']); + + if ($upload_info) { + $value = $upload_info['name']; + } else { + $value = ''; + } + } + + $option_data[] = array( + 'name' => $option['name'], + 'value' => (utf8_strlen($value) > 20 ? utf8_substr($value, 0, 20) . '..' : $value) + ); + } + + // Display prices + if ($this->customer->isLogged() || !$this->config->get('config_customer_price')) { + $unit_price = $this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')); + + $price = $this->currency->format($unit_price, $this->session->data['currency']); + $total = $this->currency->format($unit_price * $product['quantity'], $this->session->data['currency']); + } else { + $price = false; + $total = false; + } + + $recurring_description = ''; + + if ($product['recurring']) { + $frequencies = array( + 'day' => $this->language->get('text_day'), + 'week' => $this->language->get('text_week'), + 'semi_month' => $this->language->get('text_semi_month'), + 'month' => $this->language->get('text_month'), + 'year' => $this->language->get('text_year'), + ); + + if ($product['recurring']['trial']) { + $recurring_price = $this->currency->format($this->tax->calculate($product['recurring']['trial_price'] * $product['quantity'], $product['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']); + $recurring_description = sprintf($this->language->get('text_trial_description'), $recurring_price, $product['recurring']['trial_cycle'], $frequencies[$product['recurring']['trial_frequency']], $product['recurring']['trial_duration']) . ' '; + } + + $recurring_price = $this->currency->format($this->tax->calculate($product['recurring']['price'] * $product['quantity'], $product['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']); + + if ($product['recurring']['duration']) { + $recurring_description .= sprintf($this->language->get('text_payment_description'), $recurring_price, $product['recurring']['cycle'], $frequencies[$product['recurring']['frequency']], $product['recurring']['duration']); + } else { + $recurring_description .= sprintf($this->language->get('text_payment_cancel'), $recurring_price, $product['recurring']['cycle'], $frequencies[$product['recurring']['frequency']], $product['recurring']['duration']); + } + } + + $data['products'][] = array( + 'cart_id' => $product['cart_id'], + 'thumb' => $image, + 'name' => $product['name'], + 'model' => $product['model'], + 'option' => $option_data, + 'quantity' => $product['quantity'], + 'stock' => $product['stock'] ? true : !(!$this->config->get('config_stock_checkout') || $this->config->get('config_stock_warning')), + 'reward' => ($product['reward'] ? sprintf($this->language->get('text_points'), $product['reward']) : ''), + 'price' => $price, + 'total' => $total, + 'href' => $this->url->link('product/product', 'product_id=' . $product['product_id']), + 'remove' => $this->url->link('checkout/cart', 'remove=' . $product['cart_id']), + 'recurring' => $product['recurring'], + 'recurring_name' => (isset($product['recurring']['recurring_name']) ? $product['recurring']['recurring_name'] : ''), + 'recurring_description' => $recurring_description + ); + } + + $data['vouchers'] = array(); + + if ($this->cart->hasShipping()) { + + $data['has_shipping'] = true; + /** + * Shipping services + */ + if ($this->customer->isLogged()) { + $this->load->model('account/address'); + $shipping_address = $this->model_account_address->getAddress($this->session->data['shipping_address_id']); + } elseif (isset($this->session->data['guest'])) { + $shipping_address = $this->session->data['guest']['shipping']; + } + + if (!empty($shipping_address)) { + // Shipping Methods + $quote_data = array(); + + $this->load->model('setting/extension'); + + $results = $this->model_setting_extension->getExtensions('shipping'); + + if (!empty($results)) { + foreach ($results as $result) { + if ($this->config->get('shipping_' . $result['code'] . '_status')) { + $this->load->model('extension/shipping/' . $result['code']); + + $quote = $this->{'model_extension_shipping_' . $result['code']}->getQuote($shipping_address); + + if ($quote) { + $quote_data[$result['code']] = array( + 'title' => $quote['title'], + 'quote' => $quote['quote'], + 'sort_order' => $quote['sort_order'], + 'error' => $quote['error'] + ); + } + } + } + + if (!empty($quote_data)) { + $sort_order = array(); + + foreach ($quote_data as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $quote_data); + + $this->session->data['shipping_methods'] = $quote_data; + $data['shipping_methods'] = $quote_data; + + if (!isset($this->session->data['shipping_method'])) { + //default the shipping to the very first option. + $key1 = key($quote_data); + $key2 = key($quote_data[$key1]['quote']); + $this->session->data['shipping_method'] = $quote_data[$key1]['quote'][$key2]; + } + + $data['code'] = $this->session->data['shipping_method']['code']; + $data['action_shipping'] = $this->url->link('extension/payment/pp_express/shipping', '', true); + } else { + unset($this->session->data['shipping_methods']); + unset($this->session->data['shipping_method']); + $data['error_no_shipping'] = $this->language->get('error_no_shipping'); + } + } else { + unset($this->session->data['shipping_methods']); + unset($this->session->data['shipping_method']); + $data['error_no_shipping'] = $this->language->get('error_no_shipping'); + } + } + } else { + $data['has_shipping'] = false; + } + + // Totals + $this->load->model('setting/extension'); + + $totals = array(); + $taxes = $this->cart->getTaxes(); + $total = 0; + + // Because __call can not keep var references so we put them into an array. + $total_data = array( + 'totals' => &$totals, + 'taxes' => &$taxes, + 'total' => &$total + ); + + // Display prices + if ($this->customer->isLogged() || !$this->config->get('config_customer_price')) { + $sort_order = array(); + + $results = $this->model_setting_extension->getExtensions('total'); + + foreach ($results as $key => $value) { + $sort_order[$key] = $this->config->get('total_' . $value['code'] . '_sort_order'); + } + + array_multisort($sort_order, SORT_ASC, $results); + + foreach ($results as $result) { + if ($this->config->get('total_' . $result['code'] . '_status')) { + $this->load->model('extension/total/' . $result['code']); + + // We have to put the totals in an array so that they pass by reference. + $this->{'model_extension_total_' . $result['code']}->getTotal($total_data); + } + } + + $sort_order = array(); + + foreach ($totals as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $totals); + } + + $data['totals'] = array(); + + foreach ($totals as $total) { + $data['totals'][] = array( + 'title' => $total['title'], + 'text' => $this->currency->format($total['value'], $this->session->data['currency']), + ); + } + + /** + * Payment methods + */ + if ($this->customer->isLogged() && isset($this->session->data['payment_address_id'])) { + $this->load->model('account/address'); + $payment_address = $this->model_account_address->getAddress($this->session->data['payment_address_id']); + } elseif (isset($this->session->data['guest'])) { + $payment_address = $this->session->data['guest']['payment']; + } + + $method_data = array(); + + $this->load->model('setting/extension'); + + $results = $this->model_setting_extension->getExtensions('payment'); + + foreach ($results as $result) { + if ($this->config->get('payment_' . $result['code'] . '_status')) { + $this->load->model('extension/payment/' . $result['code']); + + $method = $this->{'model_extension_payment_' . $result['code']}->getMethod($payment_address, $total); + + if ($method) { + $method_data[$result['code']] = $method; + } + } + } + + $sort_order = array(); + + foreach ($method_data as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $method_data); + + if (!isset($method_data['pp_express'])) { + $this->session->data['error_warning'] = $this->language->get('error_unavailable'); + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + + $this->session->data['payment_methods'] = $method_data; + $this->session->data['payment_method'] = $method_data['pp_express']; + + $data['action_confirm'] = $this->url->link('extension/payment/pp_express/expressComplete', '', true); + + if (isset($this->session->data['error_warning'])) { + $data['error_warning'] = $this->session->data['error_warning']; + unset($this->session->data['error_warning']); + } else { + $data['error_warning'] = ''; + } + + if (isset($this->session->data['success'])) { + $data['success'] = $this->session->data['success']; + unset($this->session->data['success']); + } else { + $data['success'] = ''; + } + + if (isset($this->session->data['attention'])) { + $data['attention'] = $this->session->data['attention']; + unset($this->session->data['attention']); + } else { + $data['attention'] = ''; + } + + $data['coupon'] = $this->load->controller('extension/total/coupon'); + $data['voucher'] = $this->load->controller('extension/total/voucher'); + $data['reward'] = $this->load->controller('extension/total/reward'); + $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/pp_express_confirm', $data)); + } + + public function expressComplete() { + $this->load->language('extension/payment/pp_express'); + $redirect = ''; + + if ($this->cart->hasShipping()) { + // Validate if shipping address has been set. + $this->load->model('account/address'); + + if ($this->customer->isLogged() && isset($this->session->data['shipping_address_id'])) { + $shipping_address = $this->model_account_address->getAddress($this->session->data['shipping_address_id']); + } elseif (isset($this->session->data['guest'])) { + $shipping_address = $this->session->data['guest']['shipping']; + } + + if (empty($shipping_address)) { + $redirect = $this->url->link('checkout/checkout', '', true); + } + + // Validate if shipping method has been set. + if (!isset($this->session->data['shipping_method'])) { + $redirect = $this->url->link('checkout/checkout', '', true); + } + } else { + unset($this->session->data['shipping_method']); + unset($this->session->data['shipping_methods']); + } + + // Validate if payment address has been set. + $this->load->model('account/address'); + + if ($this->customer->isLogged() && isset($this->session->data['payment_address_id'])) { + $payment_address = $this->model_account_address->getAddress($this->session->data['payment_address_id']); + } elseif (isset($this->session->data['guest'])) { + $payment_address = $this->session->data['guest']['payment']; + } + + // Validate if payment method has been set. + if (!isset($this->session->data['payment_method'])) { + $redirect = $this->url->link('checkout/checkout', '', true); + } + + // Validate cart has products and has stock. + if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) { + $redirect = $this->url->link('checkout/cart'); + } + + // Validate minimum quantity requirements. + $products = $this->cart->getProducts(); + + foreach ($products as $product) { + $product_total = 0; + + foreach ($products as $product_2) { + if ($product_2['product_id'] == $product['product_id']) { + $product_total += $product_2['quantity']; + } + } + + if ($product['minimum'] > $product_total) { + $redirect = $this->url->link('checkout/cart'); + + break; + } + } + + if ($redirect == '') { + $totals = array(); + $taxes = $this->cart->getTaxes(); + $total = 0; + + // Because __call can not keep var references so we put them into an array. + $total_data = array( + 'totals' => &$totals, + 'taxes' => &$taxes, + 'total' => &$total + ); + + $this->load->model('setting/extension'); + + $sort_order = array(); + + $results = $this->model_setting_extension->getExtensions('total'); + + foreach ($results as $key => $value) { + $sort_order[$key] = $this->config->get('total_' . $value['code'] . '_sort_order'); + } + + array_multisort($sort_order, SORT_ASC, $results); + + foreach ($results as $result) { + if ($this->config->get('total_' . $result['code'] . '_status')) { + $this->load->model('extension/total/' . $result['code']); + + // We have to put the totals in an array so that they pass by reference. + $this->{'model_extension_total_' . $result['code']}->getTotal($total_data); + } + } + + $sort_order = array(); + + foreach ($totals as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $totals); + + $this->load->language('checkout/checkout'); + + $data = array(); + + $data['invoice_prefix'] = $this->config->get('config_invoice_prefix'); + $data['store_id'] = $this->config->get('config_store_id'); + $data['store_name'] = $this->config->get('config_name'); + + if ($data['store_id']) { + $data['store_url'] = $this->config->get('config_url'); + } else { + $data['store_url'] = HTTP_SERVER; + } + + if ($this->customer->isLogged() && isset($this->session->data['payment_address_id'])) { + $data['customer_id'] = $this->customer->getId(); + $data['customer_group_id'] = $this->config->get('config_customer_group_id'); + $data['firstname'] = $this->customer->getFirstName(); + $data['lastname'] = $this->customer->getLastName(); + $data['email'] = $this->customer->getEmail(); + $data['telephone'] = $this->customer->getTelephone(); + + $this->load->model('account/address'); + + $payment_address = $this->model_account_address->getAddress($this->session->data['payment_address_id']); + } elseif (isset($this->session->data['guest'])) { + $data['customer_id'] = 0; + $data['customer_group_id'] = $this->session->data['guest']['customer_group_id']; + $data['firstname'] = $this->session->data['guest']['firstname']; + $data['lastname'] = $this->session->data['guest']['lastname']; + $data['email'] = $this->session->data['guest']['email']; + $data['telephone'] = $this->session->data['guest']['telephone']; + + $payment_address = $this->session->data['guest']['payment']; + } + + $data['payment_firstname'] = isset($payment_address['firstname']) ? $payment_address['firstname'] : ''; + $data['payment_lastname'] = isset($payment_address['lastname']) ? $payment_address['lastname'] : ''; + $data['payment_company'] = isset($payment_address['company']) ? $payment_address['company'] : ''; + $data['payment_company_id'] = isset($payment_address['company_id']) ? $payment_address['company_id'] : ''; + $data['payment_tax_id'] = isset($payment_address['tax_id']) ? $payment_address['tax_id'] : ''; + $data['payment_address_1'] = isset($payment_address['address_1']) ? $payment_address['address_1'] : ''; + $data['payment_address_2'] = isset($payment_address['address_2']) ? $payment_address['address_2'] : ''; + $data['payment_city'] = isset($payment_address['city']) ? $payment_address['city'] : ''; + $data['payment_postcode'] = isset($payment_address['postcode']) ? $payment_address['postcode'] : ''; + $data['payment_zone'] = isset($payment_address['zone']) ? $payment_address['zone'] : ''; + $data['payment_zone_id'] = isset($payment_address['zone_id']) ? $payment_address['zone_id'] : ''; + $data['payment_country'] = isset($payment_address['country']) ? $payment_address['country'] : ''; + $data['payment_country_id'] = isset($payment_address['country_id']) ? $payment_address['country_id'] : ''; + $data['payment_address_format'] = isset($payment_address['address_format']) ? $payment_address['address_format'] : ''; + + $data['payment_method'] = ''; + if (isset($this->session->data['payment_method']['title'])) { + $data['payment_method'] = $this->session->data['payment_method']['title']; + } + + $data['payment_code'] = ''; + if (isset($this->session->data['payment_method']['code'])) { + $data['payment_code'] = $this->session->data['payment_method']['code']; + } + + if ($this->cart->hasShipping()) { + if ($this->customer->isLogged()) { + $this->load->model('account/address'); + + $shipping_address = $this->model_account_address->getAddress($this->session->data['shipping_address_id']); + } elseif (isset($this->session->data['guest'])) { + $shipping_address = $this->session->data['guest']['shipping']; + } + + $data['shipping_firstname'] = $shipping_address['firstname']; + $data['shipping_lastname'] = $shipping_address['lastname']; + $data['shipping_company'] = $shipping_address['company']; + $data['shipping_address_1'] = $shipping_address['address_1']; + $data['shipping_address_2'] = $shipping_address['address_2']; + $data['shipping_city'] = $shipping_address['city']; + $data['shipping_postcode'] = $shipping_address['postcode']; + $data['shipping_zone'] = $shipping_address['zone']; + $data['shipping_zone_id'] = $shipping_address['zone_id']; + $data['shipping_country'] = $shipping_address['country']; + $data['shipping_country_id'] = $shipping_address['country_id']; + $data['shipping_address_format'] = $shipping_address['address_format']; + + $data['shipping_method'] = ''; + if (isset($this->session->data['shipping_method']['title'])) { + $data['shipping_method'] = $this->session->data['shipping_method']['title']; + } + + $data['shipping_code'] = ''; + if (isset($this->session->data['shipping_method']['code'])) { + $data['shipping_code'] = $this->session->data['shipping_method']['code']; + } + } else { + $data['shipping_firstname'] = ''; + $data['shipping_lastname'] = ''; + $data['shipping_company'] = ''; + $data['shipping_address_1'] = ''; + $data['shipping_address_2'] = ''; + $data['shipping_city'] = ''; + $data['shipping_postcode'] = ''; + $data['shipping_zone'] = ''; + $data['shipping_zone_id'] = ''; + $data['shipping_country'] = ''; + $data['shipping_country_id'] = ''; + $data['shipping_address_format'] = ''; + $data['shipping_method'] = ''; + $data['shipping_code'] = ''; + } + + $product_data = array(); + + foreach ($this->cart->getProducts() as $product) { + $option_data = array(); + + foreach ($product['option'] as $option) { + $option_data[] = array( + 'product_option_id' => $option['product_option_id'], + 'product_option_value_id' => $option['product_option_value_id'], + 'option_id' => $option['option_id'], + 'option_value_id' => $option['option_value_id'], + 'name' => $option['name'], + 'value' => $option['value'], + 'type' => $option['type'] + ); + } + + $product_data[] = array( + 'product_id' => $product['product_id'], + 'name' => $product['name'], + 'model' => $product['model'], + 'option' => $option_data, + 'download' => $product['download'], + 'quantity' => $product['quantity'], + 'subtract' => $product['subtract'], + 'price' => $product['price'], + 'total' => $product['total'], + 'tax' => $this->tax->getTax($product['price'], $product['tax_class_id']), + 'reward' => $product['reward'] + ); + } + + // Gift Voucher + $voucher_data = array(); + + if (!empty($this->session->data['vouchers'])) { + foreach ($this->session->data['vouchers'] as $voucher) { + $voucher_data[] = array( + 'description' => $voucher['description'], + 'code' => token(10), + 'to_name' => $voucher['to_name'], + 'to_email' => $voucher['to_email'], + 'from_name' => $voucher['from_name'], + 'from_email' => $voucher['from_email'], + 'voucher_theme_id' => $voucher['voucher_theme_id'], + 'message' => $voucher['message'], + 'amount' => $voucher['amount'] + ); + } + } + + $data['products'] = $product_data; + $data['vouchers'] = $voucher_data; + $data['totals'] = $totals; + $data['comment'] = $this->session->data['comment']; + $data['total'] = $total; + + if (isset($this->request->cookie['tracking'])) { + $data['tracking'] = $this->request->cookie['tracking']; + + $subtotal = $this->cart->getSubTotal(); + + // Affiliate + $this->load->model('affiliate/affiliate'); + + $affiliate_info = $this->model_affiliate_affiliate->getAffiliateByCode($this->request->cookie['tracking']); + + if ($affiliate_info) { + $data['affiliate_id'] = $affiliate_info['affiliate_id']; + $data['commission'] = ($subtotal / 100) * $affiliate_info['commission']; + } else { + $data['affiliate_id'] = 0; + $data['commission'] = 0; + } + + // Marketing + $this->load->model('checkout/marketing'); + + $marketing_info = $this->model_checkout_marketing->getMarketingByCode($this->request->cookie['tracking']); + + if ($marketing_info) { + $data['marketing_id'] = $marketing_info['marketing_id']; + } else { + $data['marketing_id'] = 0; + } + } else { + $data['affiliate_id'] = 0; + $data['commission'] = 0; + $data['marketing_id'] = 0; + $data['tracking'] = ''; + } + + $data['language_id'] = $this->config->get('config_language_id'); + $data['currency_id'] = $this->currency->getId($this->session->data['currency']); + $data['currency_code'] = $this->session->data['currency']; + $data['currency_value'] = $this->currency->getValue($this->session->data['currency']); + $data['ip'] = $this->request->server['REMOTE_ADDR']; + + if (!empty($this->request->server['HTTP_X_FORWARDED_FOR'])) { + $data['forwarded_ip'] = $this->request->server['HTTP_X_FORWARDED_FOR']; + } elseif (!empty($this->request->server['HTTP_CLIENT_IP'])) { + $data['forwarded_ip'] = $this->request->server['HTTP_CLIENT_IP']; + } else { + $data['forwarded_ip'] = ''; + } + + if (isset($this->request->server['HTTP_USER_AGENT'])) { + $data['user_agent'] = $this->request->server['HTTP_USER_AGENT']; + } else { + $data['user_agent'] = ''; + } + + if (isset($this->request->server['HTTP_ACCEPT_LANGUAGE'])) { + $data['accept_language'] = $this->request->server['HTTP_ACCEPT_LANGUAGE']; + } else { + $data['accept_language'] = ''; + } + + $this->load->model('account/custom_field'); + $this->load->model('checkout/order'); + + $order_id = $this->model_checkout_order->addOrder($data); + $this->session->data['order_id'] = $order_id; + + $this->load->model('extension/payment/pp_express'); + + $paypal_data = array( + 'TOKEN' => $this->session->data['paypal']['token'], + 'PAYERID' => $this->session->data['paypal']['payerid'], + 'METHOD' => 'DoExpressCheckoutPayment', + 'PAYMENTREQUEST_0_NOTIFYURL' => $this->url->link('extension/payment/pp_express/ipn', '', true), + 'RETURNFMFDETAILS' => 1 + ); + + $paypal_data = array_merge($paypal_data, $this->model_extension_payment_pp_express->paymentRequestInfo()); + + $result = $this->model_extension_payment_pp_express->call($paypal_data); + + if ($result['ACK'] == 'Success') { + //handle order status + switch($result['PAYMENTINFO_0_PAYMENTSTATUS']) { + case 'Canceled_Reversal': + $order_status_id = $this->config->get('payment_pp_express_canceled_reversal_status_id'); + break; + case 'Completed': + $order_status_id = $this->config->get('payment_pp_express_completed_status_id'); + break; + case 'Denied': + $order_status_id = $this->config->get('payment_pp_express_denied_status_id'); + break; + case 'Expired': + $order_status_id = $this->config->get('payment_pp_express_expired_status_id'); + break; + case 'Failed': + $order_status_id = $this->config->get('payment_pp_express_failed_status_id'); + break; + case 'Pending': + $order_status_id = $this->config->get('payment_pp_express_pending_status_id'); + break; + case 'Processed': + $order_status_id = $this->config->get('payment_pp_express_processed_status_id'); + break; + case 'Refunded': + $order_status_id = $this->config->get('payment_pp_express_refunded_status_id'); + break; + case 'Reversed': + $order_status_id = $this->config->get('payment_pp_express_reversed_status_id'); + break; + case 'Voided': + $order_status_id = $this->config->get('payment_pp_express_voided_status_id'); + break; + } + + $this->model_checkout_order->addOrderHistory($order_id, $order_status_id); + + //add order to paypal table + $paypal_order_data = array( + 'order_id' => $order_id, + 'capture_status' => ($this->config->get('payment_pp_express_transaction') == 'Sale' ? 'Complete' : 'NotComplete'), + 'currency_code' => $result['PAYMENTINFO_0_CURRENCYCODE'], + 'authorization_id' => $result['PAYMENTINFO_0_TRANSACTIONID'], + 'total' => $result['PAYMENTINFO_0_AMT'] + ); + + $paypal_order_id = $this->model_extension_payment_pp_express->addOrder($paypal_order_data); + + //add transaction to paypal transaction table + $paypal_transaction_data = array( + 'paypal_order_id' => $paypal_order_id, + 'transaction_id' => $result['PAYMENTINFO_0_TRANSACTIONID'], + 'parent_id' => '', + 'note' => '', + 'msgsubid' => '', + 'receipt_id' => (isset($result['PAYMENTINFO_0_RECEIPTID']) ? $result['PAYMENTINFO_0_RECEIPTID'] : ''), + 'payment_type' => $result['PAYMENTINFO_0_PAYMENTTYPE'], + 'payment_status' => $result['PAYMENTINFO_0_PAYMENTSTATUS'], + 'pending_reason' => $result['PAYMENTINFO_0_PENDINGREASON'], + 'transaction_entity' => ($this->config->get('payment_pp_express_transaction') == 'Sale' ? 'payment' : 'auth'), + 'amount' => $result['PAYMENTINFO_0_AMT'], + 'debug_data' => json_encode($result) + ); + + $this->model_extension_payment_pp_express->addTransaction($paypal_transaction_data); + + $recurring_products = $this->cart->getRecurringProducts(); + + //loop through any products that are recurring items + if ($recurring_products) { + $this->load->language('extension/payment/pp_express'); + + $this->load->model('checkout/recurring'); + + $billing_period = array( + 'day' => 'Day', + 'week' => 'Week', + 'semi_month' => 'SemiMonth', + 'month' => 'Month', + 'year' => 'Year' + ); + + foreach($recurring_products as $item) { + $data = array( + 'METHOD' => 'CreateRecurringPaymentsProfile', + 'TOKEN' => $this->session->data['paypal']['token'], + 'PROFILESTARTDATE' => gmdate("Y-m-d\TH:i:s\Z", gmmktime(gmdate("H"), gmdate("i")+5, gmdate("s"), gmdate("m"), gmdate("d"), gmdate("y"))), + 'BILLINGPERIOD' => $billing_period[$item['recurring']['frequency']], + 'BILLINGFREQUENCY' => $item['recurring']['cycle'], + 'TOTALBILLINGCYCLES' => $item['recurring']['duration'], + 'AMT' => $this->currency->format($this->tax->calculate($item['recurring']['price'], $item['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency'], false, false) * $item['quantity'], + 'CURRENCYCODE' => $this->session->data['currency'] + ); + + //trial information + if ($item['recurring']['trial']) { + $data_trial = array( + 'TRIALBILLINGPERIOD' => $billing_period[$item['recurring']['trial_frequency']], + 'TRIALBILLINGFREQUENCY' => $item['recurring']['trial_cycle'], + 'TRIALTOTALBILLINGCYCLES' => $item['recurring']['trial_duration'], + 'TRIALAMT' => $this->currency->format($this->tax->calculate($item['recurring']['trial_price'], $item['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency'], false, false) * $item['quantity'] + ); + + $trial_amt = $this->currency->format($this->tax->calculate($item['recurring']['trial_price'], $item['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency'], false, false) * $item['quantity'] . ' ' . $this->session->data['currency']; + $trial_text = sprintf($this->language->get('text_trial'), $trial_amt, $item['recurring']['trial_cycle'], $item['recurring']['trial_frequency'], $item['recurring']['trial_duration']); + + $data = array_merge($data, $data_trial); + } else { + $trial_text = ''; + } + + $recurring_amt = $this->currency->format($this->tax->calculate($item['recurring']['price'], $item['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency'], false, false) * $item['quantity'] . ' ' . $this->session->data['currency']; + $recurring_description = $trial_text . sprintf($this->language->get('text_recurring'), $recurring_amt, $item['recurring']['cycle'], $item['recurring']['frequency']); + + if ($item['recurring']['duration'] > 0) { + $recurring_description .= sprintf($this->language->get('text_length'), $item['recurring']['duration']); + } + + //create new recurring and set to pending status as no payment has been made yet. + $recurring_id = $this->model_checkout_recurring->addRecurring($order_id, $recurring_description, $item['recurring']); + + $data['PROFILEREFERENCE'] = $recurring_id; + $data['DESC'] = $recurring_description; + + $result = $this->model_extension_payment_pp_express->call($data); + + if (isset($result['PROFILEID'])) { + $this->model_checkout_recurring->addReference($recurring_id, $result['PROFILEID']); + } else { + // there was an error creating the recurring, need to log and also alert admin / user + + } + } + } + + $this->response->redirect($this->url->link('checkout/success')); + + if (isset($result['REDIRECTREQUIRED']) && $result['REDIRECTREQUIRED'] == true) { + //- handle german redirect here + $this->response->redirect('https://www.paypal.com/cgi-bin/webscr?cmd=_complete-express-checkout&token=' . $this->session->data['paypal']['token']); + } + } else { + if ($result['L_ERRORCODE0'] == '10486') { + if (isset($this->session->data['paypal_redirect_count'])) { + + if ($this->session->data['paypal_redirect_count'] == 2) { + $this->session->data['paypal_redirect_count'] = 0; + $this->session->data['error'] = $this->language->get('error_too_many_failures'); + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } else { + $this->session->data['paypal_redirect_count']++; + } + } else { + $this->session->data['paypal_redirect_count'] = 1; + } + + if ($this->config->get('payment_pp_express_test') == 1) { + $this->response->redirect('https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $this->session->data['paypal']['token']); + } else { + $this->response->redirect('https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $this->session->data['paypal']['token']); + } + } + + $this->session->data['error_warning'] = $result['L_LONGMESSAGE0']; + $this->response->redirect($this->url->link('extension/payment/pp_express/expressConfirm', '', true)); + } + } else { + $this->response->redirect($redirect); + } + } + + public function checkout() { + if ((!$this->cart->hasProducts() && empty($this->session->data['vouchers'])) || (!$this->cart->hasStock() && !$this->config->get('config_stock_checkout'))) { + $this->response->redirect($this->url->link('checkout/cart')); + } + + $this->load->model('extension/payment/pp_express'); + $this->load->model('tool/image'); + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $max_amount = $this->cart->getTotal() * 1.5; + $max_amount = $this->currency->format($max_amount, $this->session->data['currency'], '', false); + + if ($this->cart->hasShipping()) { + $shipping = 0; + + // PayPal requires some countries to use zone code (not name) to be sent in SHIPTOSTATE + $ship_to_state_codes = array( + '30', // Brazil + '38', // Canada + '105', // Italy + '138', // Mexico + '223', // USA + ); + + if (in_array($order_info['shipping_country_id'], $ship_to_state_codes)) { + $ship_to_state = $order_info['shipping_zone_code']; + } else { + $ship_to_state = $order_info['shipping_zone']; + } + + $data_shipping = array( + 'PAYMENTREQUEST_0_SHIPTONAME' => html_entity_decode($order_info['shipping_firstname'] . ' ' . $order_info['shipping_lastname'], ENT_QUOTES, 'UTF-8'), + 'PAYMENTREQUEST_0_SHIPTOSTREET' => html_entity_decode($order_info['shipping_address_1'], ENT_QUOTES, 'UTF-8'), + 'PAYMENTREQUEST_0_SHIPTOSTREET2' => html_entity_decode($order_info['shipping_address_2'], ENT_QUOTES, 'UTF-8'), + 'PAYMENTREQUEST_0_SHIPTOCITY' => html_entity_decode($order_info['shipping_city'], ENT_QUOTES, 'UTF-8'), + 'PAYMENTREQUEST_0_SHIPTOSTATE' => html_entity_decode($ship_to_state, ENT_QUOTES, 'UTF-8'), + 'PAYMENTREQUEST_0_SHIPTOZIP' => html_entity_decode($order_info['shipping_postcode'], ENT_QUOTES, 'UTF-8'), + 'PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE' => $order_info['shipping_iso_code_2'], + 'ADDROVERRIDE' => 1, + ); + } else { + $shipping = 1; + $data_shipping = array(); + } + + $data = array( + 'METHOD' => 'SetExpressCheckout', + 'MAXAMT' => $max_amount, + 'RETURNURL' => $this->url->link('extension/payment/pp_express/checkoutReturn', '', true), + 'CANCELURL' => $this->url->link('checkout/checkout', '', true), + 'REQCONFIRMSHIPPING' => 0, + 'NOSHIPPING' => $shipping, + 'LANDINGPAGE' => 'Login', + 'LOGOIMG' => $this->model_tool_image->resize($this->config->get('payment_pp_express_logo'), 750, 90), + 'CHANNELTYPE' => 'Merchant', + ); + + $data = array_merge($data, $data_shipping); + + if (isset($this->session->data['pp_login']['seamless']['access_token']) && (isset($this->session->data['pp_login']['seamless']['customer_id']) && $this->session->data['pp_login']['seamless']['customer_id'] == $this->customer->getId()) && $this->config->get('module_pp_login_seamless')) { + $data['IDENTITYACCESSTOKEN'] = $this->session->data['pp_login']['seamless']['access_token']; + } + + $data = array_merge($data, $this->model_extension_payment_pp_express->paymentRequestInfo()); + + $result = $this->model_extension_payment_pp_express->call($data); + + /** + * If a failed PayPal setup happens, handle it. + */ + if (!isset($result['TOKEN'])) { + $this->session->data['error'] = $result['L_LONGMESSAGE0']; + /** + * Unable to add error message to user as the session errors/success are not + * used on the cart or checkout pages - need to be added? + * If PayPal debug log is off then still log error to normal error log. + */ + $this->log->write('Unable to create Paypal session' . json_encode($result)); + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + + $this->session->data['paypal']['token'] = $result['TOKEN']; + + $json = array("token" => $result['TOKEN']); + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function checkoutReturn() { + $this->load->language('extension/payment/pp_express'); + + $this->load->model('extension/payment/pp_express'); + $this->load->model('checkout/order'); + + $data = array( + 'METHOD' => 'GetExpressCheckoutDetails', + 'TOKEN' => $this->session->data['paypal']['token'] + ); + + $result = $this->model_extension_payment_pp_express->call($data); + + $this->session->data['paypal']['payerid'] = $result['PAYERID']; + $this->session->data['paypal']['result'] = $result; + + $order_id = $this->session->data['order_id']; + + $paypal_data = array( + 'TOKEN' => $this->session->data['paypal']['token'], + 'PAYERID' => $this->session->data['paypal']['payerid'], + 'METHOD' => 'DoExpressCheckoutPayment', + 'PAYMENTREQUEST_0_NOTIFYURL' => $this->url->link('extension/payment/pp_express/ipn', '', true), + 'RETURNFMFDETAILS' => 1 + ); + + $paypal_data = array_merge($paypal_data, $this->model_extension_payment_pp_express->paymentRequestInfo()); + + $result = $this->model_extension_payment_pp_express->call($paypal_data); + + if ($result['ACK'] == 'Success') { + //handle order status + switch($result['PAYMENTINFO_0_PAYMENTSTATUS']) { + case 'Canceled_Reversal': + $order_status_id = $this->config->get('payment_pp_express_canceled_reversal_status_id'); + break; + case 'Completed': + $order_status_id = $this->config->get('payment_pp_express_completed_status_id'); + break; + case 'Denied': + $order_status_id = $this->config->get('payment_pp_express_denied_status_id'); + break; + case 'Expired': + $order_status_id = $this->config->get('payment_pp_express_expired_status_id'); + break; + case 'Failed': + $order_status_id = $this->config->get('payment_pp_express_failed_status_id'); + break; + case 'Pending': + $order_status_id = $this->config->get('payment_pp_express_pending_status_id'); + break; + case 'Processed': + $order_status_id = $this->config->get('payment_pp_express_processed_status_id'); + break; + case 'Refunded': + $order_status_id = $this->config->get('payment_pp_express_refunded_status_id'); + break; + case 'Reversed': + $order_status_id = $this->config->get('payment_pp_express_reversed_status_id'); + break; + case 'Voided': + $order_status_id = $this->config->get('payment_pp_express_voided_status_id'); + break; + } + + $this->model_checkout_order->addOrderHistory($order_id, $order_status_id); + + //add order to paypal table + $paypal_order_data = array( + 'order_id' => $order_id, + 'capture_status' => ($this->config->get('payment_pp_express_transaction') == 'Sale' ? 'Complete' : 'NotComplete'), + 'currency_code' => $result['PAYMENTINFO_0_CURRENCYCODE'], + 'authorization_id' => $result['PAYMENTINFO_0_TRANSACTIONID'], + 'total' => $result['PAYMENTINFO_0_AMT'] + ); + + $paypal_order_id = $this->model_extension_payment_pp_express->addOrder($paypal_order_data); + + //add transaction to paypal transaction table + $paypal_transaction_data = array( + 'paypal_order_id' => $paypal_order_id, + 'transaction_id' => $result['PAYMENTINFO_0_TRANSACTIONID'], + 'parent_id' => '', + 'note' => '', + 'msgsubid' => '', + 'receipt_id' => (isset($result['PAYMENTINFO_0_RECEIPTID']) ? $result['PAYMENTINFO_0_RECEIPTID'] : ''), + 'payment_type' => $result['PAYMENTINFO_0_PAYMENTTYPE'], + 'payment_status' => $result['PAYMENTINFO_0_PAYMENTSTATUS'], + 'pending_reason' => $result['PAYMENTINFO_0_PENDINGREASON'], + 'transaction_entity' => ($this->config->get('payment_pp_express_transaction') == 'Sale' ? 'payment' : 'auth'), + 'amount' => $result['PAYMENTINFO_0_AMT'], + 'debug_data' => json_encode($result) + ); + $this->model_extension_payment_pp_express->addTransaction($paypal_transaction_data); + + $recurring_products = $this->cart->getRecurringProducts(); + + //loop through any products that are recurring items + if ($recurring_products) { + $this->load->model('checkout/recurring'); + + $billing_period = array( + 'day' => 'Day', + 'week' => 'Week', + 'semi_month' => 'SemiMonth', + 'month' => 'Month', + 'year' => 'Year' + ); + + foreach ($recurring_products as $item) { + $data = array( + 'METHOD' => 'CreateRecurringPaymentsProfile', + 'TOKEN' => $this->session->data['paypal']['token'], + 'PROFILESTARTDATE' => gmdate("Y-m-d\TH:i:s\Z", gmmktime(gmdate('H'), gmdate('i') + 5, gmdate('s'), gmdate('m'), gmdate('d'), gmdate('y'))), + 'BILLINGPERIOD' => $billing_period[$item['recurring']['frequency']], + 'BILLINGFREQUENCY' => $item['recurring']['cycle'], + 'TOTALBILLINGCYCLES' => $item['recurring']['duration'], + 'AMT' => $this->currency->format($this->tax->calculate($item['recurring']['price'], $item['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency'], false, false) * $item['quantity'], + 'CURRENCYCODE' => $this->session->data['currency'] + ); + + //trial information + if ($item['recurring']['trial'] == 1) { + $data_trial = array( + 'TRIALBILLINGPERIOD' => $billing_period[$item['recurring']['trial_frequency']], + 'TRIALBILLINGFREQUENCY' => $item['recurring']['trial_cycle'], + 'TRIALTOTALBILLINGCYCLES' => $item['recurring']['trial_duration'], + 'TRIALAMT' => $this->currency->format($this->tax->calculate($item['recurring']['trial_price'], $item['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency'], false, false) * $item['quantity'] + ); + + $trial_amt = $this->currency->format($this->tax->calculate($item['recurring']['trial_price'], $item['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency'], false, false) * $item['quantity'] . ' ' . $this->session->data['currency']; + $trial_text = sprintf($this->language->get('text_trial'), $trial_amt, $item['recurring']['trial_cycle'], $item['recurring']['trial_frequency'], $item['recurring']['trial_duration']); + + $data = array_merge($data, $data_trial); + } else { + $trial_text = ''; + } + + $recurring_amt = $this->currency->format($this->tax->calculate($item['recurring']['price'], $item['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency'], false, false) * $item['quantity'] . ' ' . $this->session->data['currency']; + $recurring_description = $trial_text . sprintf($this->language->get('text_recurring'), $recurring_amt, $item['recurring']['cycle'], $item['recurring']['frequency']); + + if ($item['recurring']['duration'] > 0) { + $recurring_description .= sprintf($this->language->get('text_length'), $item['recurring']['duration']); + } + + //create new recurring and set to pending status as no payment has been made yet. + $recurring_id = $this->model_checkout_recurring->addRecurring($order_id, $recurring_description, $item['recurring']); + + $data['PROFILEREFERENCE'] = $recurring_id; + $data['DESC'] = $recurring_description; + + $result = $this->model_extension_payment_pp_express->call($data); + + if (isset($result['PROFILEID'])) { + $this->model_checkout_recurring->editReference($recurring_id, $result['PROFILEID']); + } else { + // there was an error creating the recurring, need to log and also alert admin / user + + } + } + } + + if (isset($result['REDIRECTREQUIRED']) && $result['REDIRECTREQUIRED'] == true) { + //- handle german redirect here + $this->response->redirect('https://www.paypal.com/cgi-bin/webscr?cmd=_complete-express-checkout&token=' . $this->session->data['paypal']['token']); + } else { + $this->response->redirect($this->url->link('checkout/success')); + } + } else { + if ($result['L_ERRORCODE0'] == '10486') { + if (isset($this->session->data['paypal_redirect_count'])) { + + if ($this->session->data['paypal_redirect_count'] == 2) { + $this->session->data['paypal_redirect_count'] = 0; + $this->session->data['error'] = $this->language->get('error_too_many_failures'); + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } else { + $this->session->data['paypal_redirect_count']++; + } + } else { + $this->session->data['paypal_redirect_count'] = 1; + } + + if ($this->config->get('payment_pp_express_test') == 1) { + $this->response->redirect('https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $this->session->data['paypal']['token']); + } else { + $this->response->redirect('https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $this->session->data['paypal']['token']); + } + } + + $this->load->language('extension/payment/pp_express'); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('common/home'), + 'text' => $this->language->get('text_home') + ); + + $data['breadcrumbs'][] = array( + 'href' => $this->url->link('checkout/cart'), + 'text' => $this->language->get('text_cart') + ); + + $data['heading_title'] = $this->language->get('error_heading_title'); + + $data['text_error'] = '<div class="warning">' . $result['L_ERRORCODE0'] . ' : ' . $result['L_LONGMESSAGE0'] . '</div>'; + + $data['button_continue'] = $this->language->get('button_continue'); + + $data['continue'] = $this->url->link('checkout/cart'); + + unset($this->session->data['success']); + + $this->response->addHeader($this->request->server['SERVER_PROTOCOL'] . ' 404 Not Found'); + + $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('error/not_found', $data)); + } + } + + public function ipn() { + $this->load->model('extension/payment/pp_express'); + $this->load->model('account/recurring'); + + $request = 'cmd=_notify-validate'; + + foreach ($_POST as $key => $value) { + $request .= '&' . $key . '=' . urlencode(html_entity_decode($value, ENT_QUOTES, 'UTF-8')); + } + + if ($this->config->get('payment_pp_express_test') == 1) { + $curl = curl_init('https://www.sandbox.paypal.com/cgi-bin/webscr'); + } else { + $curl = curl_init('https://www.paypal.com/cgi-bin/webscr'); + } + + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, $request); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HEADER, false); + curl_setopt($curl, CURLOPT_TIMEOUT, 30); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + + $response = trim(curl_exec($curl)); + + if (!$response) { + $this->model_extension_payment_pp_express->log(array('error' => curl_error($curl),'error_no' => curl_errno($curl)), 'Curl failed'); + } + + $this->model_extension_payment_pp_express->log(array('request' => $request,'response' => $response), 'IPN data'); + + if ((string)$response == "VERIFIED") { + if (isset($this->request->post['transaction_entity'])) { + $this->log->write($this->request->post['transaction_entity']); + } + + if (isset($this->request->post['txn_id'])) { + $transaction = $this->model_extension_payment_pp_express->getTransactionRow($this->request->post['txn_id']); + } else { + $transaction = false; + } + + if (isset($this->request->post['parent_txn_id'])) { + $parent_transaction = $this->model_extension_payment_pp_express->getTransactionRow($this->request->post['parent_txn_id']); + } else { + $parent_transaction = false; + } + + if ($transaction) { + //transaction exists, check for cleared payment or updates etc + $this->model_extension_payment_pp_express->log('Transaction exists', 'IPN data'); + + //if the transaction is pending but the new status is completed + if ($transaction['payment_status'] != $this->request->post['payment_status']) { + $this->db->query("UPDATE `" . DB_PREFIX . "paypal_order_transaction` SET `payment_status` = '" . $this->db->escape($this->request->post['payment_status']) . "' WHERE `transaction_id` = '" . $this->db->escape($transaction['transaction_id']) . "' LIMIT 1"); + } elseif ($transaction['payment_status'] == 'Pending' && ($transaction['pending_reason'] != $this->request->post['pending_reason'])) { + //payment is still pending but the pending reason has changed, update it. + $this->db->query("UPDATE `" . DB_PREFIX . "paypal_order_transaction` SET `pending_reason` = '" . $this->db->escape($this->request->post['pending_reason']) . "' WHERE `transaction_id` = '" . $this->db->escape($transaction['transaction_id']) . "' LIMIT 1"); + } + } else { + $this->model_extension_payment_pp_express->log('Transaction does not exist', 'IPN data'); + + if ($parent_transaction) { + //parent transaction exists + $this->model_extension_payment_pp_express->log('Parent transaction exists', 'IPN data'); + + //add new related transaction + $transaction = array( + 'paypal_order_id' => $parent_transaction['paypal_order_id'], + 'transaction_id' => $this->request->post['txn_id'], + 'parent_id' => $this->request->post['parent_txn_id'], + 'note' => '', + 'msgsubid' => '', + 'receipt_id' => (isset($this->request->post['receipt_id']) ? $this->request->post['receipt_id'] : ''), + 'payment_type' => (isset($this->request->post['payment_type']) ? $this->request->post['payment_type'] : ''), + 'payment_status' => (isset($this->request->post['payment_status']) ? $this->request->post['payment_status'] : ''), + 'pending_reason' => (isset($this->request->post['pending_reason']) ? $this->request->post['pending_reason'] : ''), + 'amount' => $this->request->post['mc_gross'], + 'debug_data' => json_encode($this->request->post), + 'transaction_entity' => (isset($this->request->post['transaction_entity']) ? $this->request->post['transaction_entity'] : '') + ); + + $this->model_extension_payment_pp_express->addTransaction($transaction); + + /** + * If there has been a refund, log this against the parent transaction. + */ + if (isset($this->request->post['payment_status']) && $this->request->post['payment_status'] == 'Refunded') { + if (($this->request->post['mc_gross'] * -1) == $parent_transaction['amount']) { + $this->db->query("UPDATE `" . DB_PREFIX . "paypal_order_transaction` SET `payment_status` = 'Refunded' WHERE `transaction_id` = '" . $this->db->escape($parent_transaction['transaction_id']) . "' LIMIT 1"); + } else { + $this->db->query("UPDATE `" . DB_PREFIX . "paypal_order_transaction` SET `payment_status` = 'Partially-Refunded' WHERE `transaction_id` = '" . $this->db->escape($parent_transaction['transaction_id']) . "' LIMIT 1"); + } + } + + /** + * If the capture payment is now complete + */ + if (isset($this->request->post['auth_status']) && $this->request->post['auth_status'] == 'Completed' && $parent_transaction['payment_status'] == 'Pending') { + $captured = $this->currency->format($this->model_extension_payment_pp_express->getTotalCaptured($parent_transaction['paypal_order_id']), $this->session->data['currency'], false, false); + $refunded = $this->currency->format($this->model_extension_payment_pp_express->getRefundedTotal($parent_transaction['paypal_order_id']), $this->session->data['currency'], false, false); + $remaining = $this->currency->format($parent_transaction['amount'] - $captured + $refunded, $this->session->data['currency'], false, false); + + $this->model_extension_payment_pp_express->log('Captured: ' . $captured, 'IPN data'); + $this->model_extension_payment_pp_express->log('Refunded: ' . $refunded, 'IPN data'); + $this->model_extension_payment_pp_express->log('Remaining: ' . $remaining, 'IPN data'); + + if ($remaining > 0.00) { + $transaction = array( + 'paypal_order_id' => $parent_transaction['paypal_order_id'], + 'transaction_id' => '', + 'parent_id' => $this->request->post['parent_txn_id'], + 'note' => '', + 'msgsubid' => '', + 'receipt_id' => '', + 'payment_type' => '', + 'payment_status' => 'Void', + 'pending_reason' => '', + 'amount' => '', + 'debug_data' => 'Voided after capture', + 'transaction_entity' => 'auth' + ); + + $this->model_extension_payment_pp_express->addTransaction($transaction); + } + + $this->model_extension_payment_pp_express->updateOrder('Complete', $parent_transaction['order_id']); + } + + } else { + //parent transaction doesn't exists, need to investigate? + $this->model_extension_payment_pp_express->log('Parent transaction not found', 'IPN data'); + } + } + + /* + * Subscription payments + * + * recurring ID should always exist if its a recurring payment transaction. + * + * also the reference will match a recurring payment ID + */ + if (isset($this->request->post['txn_type'])) { + $this->model_extension_payment_pp_express->log($this->request->post['txn_type'], 'IPN data'); + + //payment + if ($this->request->post['txn_type'] == 'recurring_payment') { + $recurring = $this->model_account_recurring->getOrderRecurringByReference($this->request->post['recurring_payment_id']); + + $this->model_extension_payment_pp_express->log($recurring, 'IPN data'); + + if ($recurring != false) { + $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `amount` = '" . (float)$this->request->post['amount'] . "', `type` = '1'"); + + //as there was a payment the recurring is active, ensure it is set to active (may be been suspended before) + if ($recurring['status'] != 1) { + $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 2 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "'"); + } + } + } + + //suspend + if ($this->request->post['txn_type'] == 'recurring_payment_suspended') { + $recurring = $this->model_account_recurring->getOrderRecurringByReference($this->request->post['recurring_payment_id']); + + if ($recurring != false) { + $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '6'"); + $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 3 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "' LIMIT 1"); + } + } + + //suspend due to max failed + if ($this->request->post['txn_type'] == 'recurring_payment_suspended_due_to_max_failed_payment') { + $recurring = $this->model_account_recurring->getOrderRecurringByReference($this->request->post['recurring_payment_id']); + + if ($recurring != false) { + $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '7'"); + $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 3 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "' LIMIT 1"); + } + } + + //payment failed + if ($this->request->post['txn_type'] == 'recurring_payment_failed') { + $recurring = $this->model_account_recurring->getOrderRecurringByReference($this->request->post['recurring_payment_id']); + + if ($recurring != false) { + $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '4'"); + } + } + + //outstanding payment failed + if ($this->request->post['txn_type'] == 'recurring_payment_outstanding_payment_failed') { + $recurring = $this->model_account_recurring->getOrderRecurringByReference($this->request->post['recurring_payment_id']); + + if ($recurring != false) { + $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '8'"); + } + } + + //outstanding payment + if ($this->request->post['txn_type'] == 'recurring_payment_outstanding_payment') { + $recurring = $this->model_account_recurring->getOrderRecurringByReference($this->request->post['recurring_payment_id']); + + if ($recurring != false) { + $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `amount` = '" . (float)$this->request->post['amount'] . "', `type` = '2'"); + + //as there was a payment the recurring is active, ensure it is set to active (may be been suspended before) + if ($recurring['status'] != 1) { + $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 2 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "'"); + } + } + } + + //date_added + if ($this->request->post['txn_type'] == 'recurring_payment_profile_date_added') { + $recurring = $this->model_account_recurring->getOrderRecurringByReference($this->request->post['recurring_payment_id']); + + if ($recurring != false) { + $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '0'"); + + if ($recurring['status'] != 1) { + $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 2 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "'"); + } + } + } + + //cancelled + if ($this->request->post['txn_type'] == 'recurring_payment_profile_cancel') { + $recurring = $this->model_account_recurring->getOrderRecurringByReference($this->request->post['recurring_payment_id']); + + if ($recurring != false && $recurring['status'] != 3) { + $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '5'"); + $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 4 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "' LIMIT 1"); + } + } + + //skipped + if ($this->request->post['txn_type'] == 'recurring_payment_skipped') { + $recurring = $this->model_account_recurring->getOrderRecurringByReference($this->request->post['recurring_payment_id']); + + if ($recurring != false) { + $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '3'"); + } + } + + //expired + if ($this->request->post['txn_type'] == 'recurring_payment_expired') { + $recurring = $this->model_account_recurring->getOrderRecurringByReference($this->request->post['recurring_payment_id']); + + if ($recurring != false) { + $this->db->query("INSERT INTO `" . DB_PREFIX . "order_recurring_transaction` SET `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "', `date_added` = NOW(), `type` = '9'"); + $this->db->query("UPDATE `" . DB_PREFIX . "order_recurring` SET `status` = 5 WHERE `order_recurring_id` = '" . (int)$recurring['order_recurring_id'] . "' LIMIT 1"); + } + } + } + } elseif ((string)$response == "INVALID") { + $this->model_extension_payment_pp_express->log(array('IPN was invalid'), 'IPN fail'); + } else { + $this->model_extension_payment_pp_express->log('Response string unknown: ' . (string)$response, 'IPN data'); + } + + header("HTTP/1.1 200 Ok"); + } + + public function shipping() { + $this->shippingValidate($this->request->post['shipping_method']); + + $this->response->redirect($this->url->link('extension/payment/pp_express/expressConfirm')); + } + + protected function shippingValidate($code) { + $this->load->language('checkout/cart'); + $this->load->language('extension/payment/pp_express'); + + if (empty($code)) { + $this->session->data['error_warning'] = $this->language->get('error_shipping'); + return false; + } else { + $shipping = explode('.', $code); + + if (!isset($shipping[0]) || !isset($shipping[1]) || !isset($this->session->data['shipping_methods'][$shipping[0]]['quote'][$shipping[1]])) { + $this->session->data['error_warning'] = $this->language->get('error_shipping'); + return false; + } else { + $this->session->data['shipping_method'] = $this->session->data['shipping_methods'][$shipping[0]]['quote'][$shipping[1]]; + $this->session->data['success'] = $this->language->get('text_shipping_updated'); + return true; + } + } + } + + protected function validateCoupon() { + $this->load->model('extension/total/coupon'); + + $coupon_info = $this->model_extension_total_coupon->getCoupon($this->request->post['coupon']); + + if ($coupon_info) { + return true; + } else { + $this->session->data['error_warning'] = $this->language->get('error_coupon'); + return false; + } + } + + protected function validateVoucher() { + $this->load->model('extension/total/coupon'); + + $voucher_info = $this->model_extension_total_voucher->getVoucher($this->request->post['voucher']); + + if ($voucher_info) { + return true; + } else { + $this->session->data['error_warning'] = $this->language->get('error_voucher'); + return false; + } + } + + protected function validateReward() { + $points = $this->customer->getRewardPoints(); + + $points_total = 0; + + foreach ($this->cart->getProducts() as $product) { + if ($product['points']) { + $points_total += $product['points']; + } + } + + $error = ''; + + if (empty($this->request->post['reward'])) { + $error = $this->language->get('error_reward'); + } + + if ($this->request->post['reward'] > $points) { + $error = sprintf($this->language->get('error_points'), $this->request->post['reward']); + } + + if ($this->request->post['reward'] > $points_total) { + $error = sprintf($this->language->get('error_maximum'), $points_total); + } + + if (!$error) { + return true; + } else { + $this->session->data['error_warning'] = $error; + return false; + } + } +} diff --git a/public/catalog/controller/extension/payment/pp_payflow.php b/public/catalog/controller/extension/payment/pp_payflow.php new file mode 100644 index 0000000..6f65897 --- /dev/null +++ b/public/catalog/controller/extension/payment/pp_payflow.php @@ -0,0 +1,191 @@ +<?php +class ControllerExtensionPaymentPPPayflow extends Controller { + public function index() { + $this->load->language('extension/payment/pp_payflow'); + + $data['text_credit_card'] = $this->language->get('text_credit_card'); + $data['text_start_date'] = $this->language->get('text_start_date'); + $data['text_issue'] = $this->language->get('text_issue'); + $data['text_loading'] = $this->language->get('text_loading'); + + $data['entry_cc_owner'] = $this->language->get('entry_cc_owner'); + $data['entry_cc_type'] = $this->language->get('entry_cc_type'); + $data['entry_cc_number'] = $this->language->get('entry_cc_number'); + $data['entry_cc_start_date'] = $this->language->get('entry_cc_start_date'); + $data['entry_cc_expire_date'] = $this->language->get('entry_cc_expire_date'); + $data['entry_cc_cvv2'] = $this->language->get('entry_cc_cvv2'); + $data['entry_cc_issue'] = $this->language->get('entry_cc_issue'); + + $data['button_confirm'] = $this->language->get('button_confirm'); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $data['owner'] = $order_info['payment_firstname'] . ' ' . $order_info['payment_lastname']; + + $data['cards'] = array(); + + $data['cards'][] = array( + 'text' => 'Visa', + 'value' => '0' + ); + + $data['cards'][] = array( + 'text' => 'MasterCard', + 'value' => '1' + ); + + $data['cards'][] = array( + 'text' => 'Maestro', + 'value' => '9' + ); + + $data['cards'][] = array( + 'text' => 'Solo', + 'value' => 'S' + ); + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['year_valid'] = array(); + + for ($i = $today['year'] - 10; $i < $today['year'] + 1; $i++) { + $data['year_valid'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + $data['year_expire'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['year_expire'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + return $this->load->view('extension/payment/pp_payflow', $data); + } + + public function send() { + $this->load->language('extension/payment/pp_payflow'); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if (!$this->config->get('payment_pp_payflow_transaction')) { + $payment_type = 'A'; + } else { + $payment_type = 'S'; + } + + $request = 'USER=' . urlencode($this->config->get('payment_pp_payflow_user')); + $request .= '&VENDOR=' . urlencode($this->config->get('payment_pp_payflow_vendor')); + $request .= '&PARTNER=' . urlencode($this->config->get('payment_pp_payflow_partner')); + $request .= '&PWD=' . urlencode($this->config->get('payment_pp_payflow_password')); + $request .= '&TENDER=C'; + $request .= '&TRXTYPE=' . $payment_type; + $request .= '&AMT=' . $this->currency->format($order_info['total'], $order_info['currency_code'], false, false); + $request .= '&CURRENCY=' . urlencode($order_info['currency_code']); + $request .= '&NAME=' . urlencode($this->request->post['cc_owner']); + $request .= '&STREET=' . urlencode($order_info['payment_address_1']); + $request .= '&CITY=' . urlencode($order_info['payment_city']); + $request .= '&STATE=' . urlencode(($order_info['payment_iso_code_2'] != 'US') ? $order_info['payment_zone'] : $order_info['payment_zone_code']); + $request .= '&COUNTRY=' . urlencode($order_info['payment_iso_code_2']); + $request .= '&ZIP=' . urlencode(str_replace(' ', '', $order_info['payment_postcode'])); + $request .= '&CLIENTIP=' . urlencode($this->request->server['REMOTE_ADDR']); + $request .= '&EMAIL=' . urlencode($order_info['email']); + $request .= '&ACCT=' . urlencode(str_replace(' ', '', $this->request->post['cc_number'])); + $request .= '&ACCTTYPE=' . urlencode($this->request->post['cc_type']); + $request .= '&CARDSTART=' . urlencode($this->request->post['cc_start_date_month'] . substr($this->request->post['cc_start_date_year'], - 2, 2)); + $request .= '&EXPDATE=' . urlencode($this->request->post['cc_expire_date_month'] . substr($this->request->post['cc_expire_date_year'], - 2, 2)); + $request .= '&CVV2=' . urlencode($this->request->post['cc_cvv2']); + $request .= '&CARDISSUE=' . urlencode($this->request->post['cc_issue']); + $request .= '&BUTTONSOURCE=' . urlencode('OpenCart_2.0_PFP'); + + if (!$this->config->get('payment_pp_payflow_test')) { + $curl = curl_init('https://payflowpro.paypal.com'); + } else { + $curl = curl_init('https://pilot-payflowpro.paypal.com'); + } + + curl_setopt($curl, CURLOPT_PORT, 443); + curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_FORBID_REUSE, 1); + curl_setopt($curl, CURLOPT_FRESH_CONNECT, 1); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, $request); + curl_setopt($curl, CURLOPT_HTTPHEADER, array('X-VPS-REQUEST-ID: ' . md5($this->session->data['order_id'] . mt_rand()))); + + $response = curl_exec($curl); + + curl_close($curl); + + if (!$response) { + $this->log->write('DoDirectPayment failed: ' . curl_error($curl) . '(' . curl_errno($curl) . ')'); + } + + $response_info = array(); + + parse_str($response, $response_info); + + $json = array(); + + if ($response_info['RESULT'] == '0') { + $message = ''; + + if (isset($response_info['AVSCODE'])) { + $message .= 'AVSCODE: ' . $response_info['AVSCODE'] . "\n"; + } + + if (isset($response_info['CVV2MATCH'])) { + $message .= 'CVV2MATCH: ' . $response_info['CVV2MATCH'] . "\n"; + } + + if (isset($response_info['TRANSACTIONID'])) { + $message .= 'TRANSACTIONID: ' . $response_info['TRANSACTIONID'] . "\n"; + } + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_pp_payflow_order_status_id'), $message, false); + + $json['success'] = $this->url->link('checkout/success'); + } else { + switch ($response_info['RESULT']) { + case '1': + case '26': + $json['error'] = $this->language->get('error_config'); + break; + case '7': + $json['error'] = $this->language->get('error_address'); + break; + case '12': + $json['error'] = $this->language->get('error_declined'); + break; + case '23': + case '24': + $json['error'] = $this->language->get('error_invalid'); + break; + default: + $json['error'] = $this->language->get('error_general'); + break; + } + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/pp_payflow_iframe.php b/public/catalog/controller/extension/payment/pp_payflow_iframe.php new file mode 100644 index 0000000..6a3102b --- /dev/null +++ b/public/catalog/controller/extension/payment/pp_payflow_iframe.php @@ -0,0 +1,154 @@ +<?php +class ControllerExtensionPaymentPPPayflowIframe extends Controller { + public function index() { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/pp_payflow_iframe'); + $this->load->model('localisation/country'); + $this->load->model('localisation/zone'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if ($this->config->get('payment_pp_payflow_iframe_test')) { + $mode = 'TEST'; + } else { + $mode = 'LIVE'; + } + + $payflow_url = 'https://payflowlink.paypal.com'; + + if ($this->config->get('payment_pp_payflow_iframe_transaction_method') == 'sale') { + $transaction_type = 'S'; + } else { + $transaction_type = 'A'; + } + + $secure_token_id = md5($this->session->data['order_id'] . mt_rand() . microtime()); + + $this->model_extension_payment_pp_payflow_iframe->addOrder($order_info['order_id'], $secure_token_id); + + $shipping_country = $this->model_localisation_country->getCountry($order_info['shipping_country_id']); + $shipping_zone = $this->model_localisation_zone->getZone($order_info['shipping_zone_id']); + + $payment_country = $this->model_localisation_country->getCountry($order_info['payment_country_id']); + $payment_zone = $this->model_localisation_zone->getZone($order_info['payment_zone_id']); + + $url_params = array( + 'TENDER' => 'C', + 'TRXTYPE' => $transaction_type, + 'AMT' => $this->currency->format($order_info['total'], $order_info['currency_code'], false, false), + 'CURRENCY' => $order_info['currency_code'], + 'CREATESECURETOKEN' => 'Y', + 'SECURETOKENID' => $secure_token_id, + 'BILLTOFIRSTNAME' => $order_info['payment_firstname'], + 'BILLTOLASTNAME' => $order_info['payment_lastname'], + 'BILLTOSTREET' => trim($order_info['payment_address_1'] . ' ' . $order_info['payment_address_2']), + 'BILLTOCITY' => $order_info['payment_city'], + 'BILLTOSTATE' => $payment_zone['code'], + 'BILLTOZIP' => $order_info['payment_postcode'], + 'BILLTOCOUNTRY' => $payment_country['iso_code_2'], + ); + + if ($shipping_country) { + $url_params['SHIPTOFIRSTNAME'] = $order_info['shipping_firstname']; + $url_params['SHIPTOLASTNAME'] = $order_info['shipping_lastname']; + $url_params['SHIPTOSTREET'] = trim($order_info['shipping_address_1'] . ' ' . $order_info['shipping_address_2']); + $url_params['SHIPTOCITY'] = $order_info['shipping_city']; + $url_params['SHIPTOSTATE'] = $shipping_zone['code']; + $url_params['SHIPTOZIP'] = $order_info['shipping_postcode']; + $url_params['SHIPTOCOUNTRY'] = $shipping_country['iso_code_2']; + } + + $response_params = $this->model_extension_payment_pp_payflow_iframe->call($url_params); + + if (isset($response_params['SECURETOKEN'])) { + $secure_token = $response_params['SECURETOKEN']; + } else { + $secure_token = ''; + } + + $iframe_params = array( + 'MODE' => $mode, + 'SECURETOKENID' => $secure_token_id, + 'SECURETOKEN' => $secure_token, + ); + + $data['iframe_url'] = $payflow_url . '?' . http_build_query($iframe_params, '', "&"); + $data['checkout_method'] = $this->config->get('payment_pp_payflow_iframe_checkout_method'); + $data['button_confirm'] = $this->language->get('button_confirm'); + $data['create'] = HTTPS_SERVER . 'index.php?route=extension/payment/pp_pro_iframe/create'; + + return $this->load->view('extension/payment/pp_payflow_iframe', $data); + } + + public function paymentReturn() { + $data['url'] = $this->url->link('checkout/success'); + + $this->response->setOutput($this->load->view('extension/payment/pp_payflow_iframe_return', $data)); + } + + public function paymentCancel() { + $data['url'] = $this->url->link('checkout/checkout'); + + $this->response->setOutput($this->load->view('extension/payment/pp_payflow_iframe_return', $data)); + } + + public function paymentError() { + $data['url'] = $this->url->link('checkout/checkout'); + + $this->response->setOutput($this->load->view('extension/payment/pp_payflow_iframe_return', $data)); + } + + public function paymentIpn() { + $this->load->model('extension/payment/pp_payflow_iframe'); + $this->load->model('checkout/order'); + + if ($this->config->get('payment_pp_pro_iframe_debug')) { + $log = new Log('pp_pro_iframe.log'); + $log->write('POST: ' . print_r($this->request->post, 1)); + } + + $order_id = $this->model_extension_payment_pp_payflow_iframe->getOrderId($this->request->post['SECURETOKENID']); + + if ($order_id) { + $order_info = $this->model_checkout_order->getOrder($order_id); + + $url_params = array( + 'TENDER' => 'C', + 'TRXTYPE' => 'I', + 'ORIGID' => $this->request->post['PNREF'], + ); + + $response_params = $this->model_extension_payment_pp_payflow_iframe->call($url_params); + + if ($order_info['order_status_id'] == 0 && $response_params['RESULT'] == '0' && $this->request->post['RESULT'] == 0) { + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_pp_payflow_iframe_order_status_id')); + + if ($this->request->post['TYPE'] == 'S') { + $complete = 1; + } else { + $complete = 0; + } + + $data = array( + 'secure_token_id' => $this->request->post['SECURETOKENID'], + 'transaction_reference' => $this->request->post['PNREF'], + 'transaction_type' => $this->request->post['TYPE'], + 'complete' => $complete, + ); + + $this->model_extension_payment_pp_payflow_iframe->updateOrder($data); + + $data = array( + 'order_id' => $order_id, + 'type' => $this->request->post['TYPE'], + 'transaction_reference' => $this->request->post['PNREF'], + 'amount' => $this->request->post['AMT'], + ); + + $this->model_extension_payment_pp_payflow_iframe->addTransaction($data); + } + } + + $this->response->setOutput('Ok'); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/pp_pro.php b/public/catalog/controller/extension/payment/pp_pro.php new file mode 100644 index 0000000..cafc44e --- /dev/null +++ b/public/catalog/controller/extension/payment/pp_pro.php @@ -0,0 +1,182 @@ +<?php +class ControllerExtensionPaymentPPPro extends Controller { + public function index() { + $this->load->language('extension/payment/pp_pro'); + + $data['cards'] = array(); + + $data['cards'][] = array( + 'text' => 'Visa', + 'value' => 'VISA' + ); + + $data['cards'][] = array( + 'text' => 'MasterCard', + 'value' => 'MASTERCARD' + ); + + $data['cards'][] = array( + 'text' => 'Discover Card', + 'value' => 'DISCOVER' + ); + + $data['cards'][] = array( + 'text' => 'American Express', + 'value' => 'AMEX' + ); + + $data['cards'][] = array( + 'text' => 'Maestro', + 'value' => 'SWITCH' + ); + + $data['cards'][] = array( + 'text' => 'Solo', + 'value' => 'SOLO' + ); + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['year_valid'] = array(); + + for ($i = $today['year'] - 10; $i < $today['year'] + 1; $i++) { + $data['year_valid'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + $data['year_expire'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['year_expire'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + return $this->load->view('extension/payment/pp_pro', $data); + } + + public function send() { + if (!$this->config->get('payment_pp_pro_transaction')) { + $payment_type = 'Authorization'; + } else { + $payment_type = 'Sale'; + } + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $request = 'METHOD=DoDirectPayment'; + $request .= '&VERSION=51.0'; + $request .= '&USER=' . urlencode($this->config->get('payment_pp_pro_username')); + $request .= '&PWD=' . urlencode($this->config->get('payment_pp_pro_password')); + $request .= '&SIGNATURE=' . urlencode($this->config->get('payment_pp_pro_signature')); + $request .= '&CUSTREF=' . (int)$order_info['order_id']; + $request .= '&PAYMENTACTION=' . $payment_type; + $request .= '&AMT=' . $this->currency->format($order_info['total'], $order_info['currency_code'], false, false); + $request .= '&CREDITCARDTYPE=' . $this->request->post['cc_type']; + $request .= '&ACCT=' . urlencode(str_replace(' ', '', $this->request->post['cc_number'])); + $request .= '&CARDSTART=' . urlencode($this->request->post['cc_start_date_month'] . $this->request->post['cc_start_date_year']); + $request .= '&EXPDATE=' . urlencode($this->request->post['cc_expire_date_month'] . $this->request->post['cc_expire_date_year']); + $request .= '&CVV2=' . urlencode($this->request->post['cc_cvv2']); + + if ($this->request->post['cc_type'] == 'SWITCH' || $this->request->post['cc_type'] == 'SOLO') { + $request .= '&ISSUENUMBER=' . urlencode($this->request->post['cc_issue']); + } + + $request .= '&FIRSTNAME=' . urlencode($order_info['payment_firstname']); + $request .= '&LASTNAME=' . urlencode($order_info['payment_lastname']); + $request .= '&EMAIL=' . urlencode($order_info['email']); + $request .= '&PHONENUM=' . urlencode($order_info['telephone']); + $request .= '&IPADDRESS=' . urlencode($this->request->server['REMOTE_ADDR']); + $request .= '&STREET=' . urlencode($order_info['payment_address_1']); + $request .= '&CITY=' . urlencode($order_info['payment_city']); + $request .= '&STATE=' . urlencode(($order_info['payment_iso_code_2'] != 'US') ? $order_info['payment_zone'] : $order_info['payment_zone_code']); + $request .= '&ZIP=' . urlencode($order_info['payment_postcode']); + $request .= '&COUNTRYCODE=' . urlencode($order_info['payment_iso_code_2']); + $request .= '&CURRENCYCODE=' . urlencode($order_info['currency_code']); + $request .= '&BUTTONSOURCE=' . urlencode('OpenCart_2.0_WPP'); + + if ($this->cart->hasShipping()) { + $request .= '&SHIPTONAME=' . urlencode($order_info['shipping_firstname'] . ' ' . $order_info['shipping_lastname']); + $request .= '&SHIPTOSTREET=' . urlencode($order_info['shipping_address_1']); + $request .= '&SHIPTOCITY=' . urlencode($order_info['shipping_city']); + $request .= '&SHIPTOSTATE=' . urlencode(($order_info['shipping_iso_code_2'] != 'US') ? $order_info['shipping_zone'] : $order_info['shipping_zone_code']); + $request .= '&SHIPTOCOUNTRYCODE=' . urlencode($order_info['shipping_iso_code_2']); + $request .= '&SHIPTOZIP=' . urlencode($order_info['shipping_postcode']); + } else { + $request .= '&SHIPTONAME=' . urlencode($order_info['payment_firstname'] . ' ' . $order_info['payment_lastname']); + $request .= '&SHIPTOSTREET=' . urlencode($order_info['payment_address_1']); + $request .= '&SHIPTOCITY=' . urlencode($order_info['payment_city']); + $request .= '&SHIPTOSTATE=' . urlencode(($order_info['payment_iso_code_2'] != 'US') ? $order_info['payment_zone'] : $order_info['payment_zone_code']); + $request .= '&SHIPTOCOUNTRYCODE=' . urlencode($order_info['payment_iso_code_2']); + $request .= '&SHIPTOZIP=' . urlencode($order_info['payment_postcode']); + } + + if (!$this->config->get('payment_pp_pro_test')) { + $curl = curl_init('https://api-3t.paypal.com/nvp'); + } else { + $curl = curl_init('https://api-3t.sandbox.paypal.com/nvp'); + } + + curl_setopt($curl, CURLOPT_PORT, 443); + curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_FORBID_REUSE, 1); + curl_setopt($curl, CURLOPT_FRESH_CONNECT, 1); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, $request); + + $response = curl_exec($curl); + + curl_close($curl); + + if (!$response) { + $this->log->write('DoDirectPayment failed: ' . curl_error($curl) . '(' . curl_errno($curl) . ')'); + } + + $response_info = array(); + + parse_str($response, $response_info); + + $json = array(); + + if (($response_info['ACK'] == 'Success') || ($response_info['ACK'] == 'SuccessWithWarning')) { + $message = ''; + + if (isset($response_info['AVSCODE'])) { + $message .= 'AVSCODE: ' . $response_info['AVSCODE'] . "\n"; + } + + if (isset($response_info['CVV2MATCH'])) { + $message .= 'CVV2MATCH: ' . $response_info['CVV2MATCH'] . "\n"; + } + + if (isset($response_info['TRANSACTIONID'])) { + $message .= 'TRANSACTIONID: ' . $response_info['TRANSACTIONID'] . "\n"; + } + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_pp_pro_order_status_id'), $message, false); + + $json['success'] = $this->url->link('checkout/success'); + } else { + $json['error'] = $response_info['L_LONGMESSAGE0']; + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/pp_pro_iframe.php b/public/catalog/controller/extension/payment/pp_pro_iframe.php new file mode 100644 index 0000000..30b6a5d --- /dev/null +++ b/public/catalog/controller/extension/payment/pp_pro_iframe.php @@ -0,0 +1,302 @@ +<?php +class ControllerExtensionPaymentPPProIframe extends Controller { + public function index() { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/pp_pro_iframe'); + + $this->load->language('extension/payment/pp_pro_iframe'); + + if ($this->config->get('payment_pp_pro_iframe_checkout_method') == 'redirect') { + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $hosted_button_id = $this->constructButtonData($order_info); + + if ($this->config->get('payment_pp_pro_iframe_test')) { + $data['url'] = 'https://securepayments.sandbox.paypal.com/webapps/HostedSoleSolutionApp/webflow/sparta/hostedSoleSolutionProcess'; + } else { + $data['url'] = 'https://securepayments.paypal.com/webapps/HostedSoleSolutionApp/webflow/sparta/hostedSoleSolutionProcess'; + } + + if ($hosted_button_id) { + $data['code'] = $hosted_button_id; + $data['error_connection'] = ''; + } else { + $data['error_connection'] = $this->language->get('error_connection'); + } + } + + $data['create'] = HTTPS_SERVER.'index.php?route=extension/payment/pp_pro_iframe/create'; + + $data['checkout_method'] = $this->config->get('payment_pp_pro_iframe_checkout_method'); + + return $this->load->view('extension/payment/pp_pro_iframe', $data); + } + + public function create() { + $this->load->language('extension/payment/pp_pro_iframe'); + $this->load->model('checkout/order'); + $this->load->model('extension/payment/pp_pro_iframe'); + + $data['text_secure_connection'] = $this->language->get('text_secure_connection'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $hosted_button_id = $this->constructButtonData($order_info); + + if ($hosted_button_id) { + $data['code'] = $hosted_button_id; + + if ($this->config->get('payment_pp_pro_iframe_test')) { + $data['url'] = 'https://securepayments.sandbox.paypal.com/webapps/HostedSoleSolutionApp/webflow/sparta/hostedSoleSolutionProcess'; + } else { + $data['url'] = 'https://securepayments.paypal.com/webapps/HostedSoleSolutionApp/webflow/sparta/hostedSoleSolutionProcess'; + } + + $data['error_connection'] = ''; + } else { + $data['error_connection'] = $this->language->get('error_connection'); + } + + if (file_exists(DIR_APPLICATION . 'view/theme/' . $this->config->get('config_template') . '/stylesheet/stylesheet.css')) { + $data['stylesheet'] = '/catalog/view/theme/' . $this->config->get('config_template') . '/stylesheet/stylesheet.css'; + } else { + $data['stylesheet'] = '/catalog/view/theme/default/stylesheet/stylesheet.css'; + } + + $this->response->setOutput($this->load->view('extension/payment/pp_pro_iframe_body', $data)); + } + + public function notify() { + $this->load->model('extension/payment/pp_pro_iframe'); + + if (isset($this->request->post['custom'])) { + $order_id = $this->encryption->decrypt($this->config->get('config_encryption'), $this->request->post['custom']); + } else { + $order_id = 0; + } + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($order_id); + + if ($order_info) { + $request = 'cmd=_notify-validate'; + + foreach ($this->request->post as $key => $value) { + $request .= '&' . $key . '=' . urlencode(html_entity_decode($value, ENT_QUOTES, 'UTF-8')); + } + + if (!$this->config->get('pp_pro_iframe')) { + $curl = curl_init('https://www.paypal.com/cgi-bin/webscr'); + } else { + $curl = curl_init('https://www.sandbox.paypal.com/cgi-bin/webscr'); + } + + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, $request); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HEADER, false); + curl_setopt($curl, CURLOPT_TIMEOUT, 30); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + + $response = curl_exec($curl); + + if (curl_errno($curl)) { + if ($this->config->get('payment_pp_pro_iframe_debug')) { + $log = new Log('pp_pro_iframe.log'); + $log->write('pp_pro_iframe :: CURL failed ' . curl_error($curl) . '(' . curl_errno($curl) . ')'); + } + } else { + if ($this->config->get('payment_pp_pro_iframe_debug')) { + $log = new Log('pp_pro_iframe.log'); + $log->write('pp_pro_iframe :: IPN REQUEST: ' . $request); + $log->write('pp_pro_iframe :: IPN RESPONSE: ' . $response); + } + + if ((strcmp($response, 'VERIFIED') == 0 || strcmp($response, 'UNVERIFIED') == 0) && isset($this->request->post['payment_status'])) { + $order_status_id = $this->config->get('payment_pp_pro_iframe_canceled_reversal_status_id'); + + switch ($this->request->post['payment_status']) { + case 'Canceled_Reversal': + $order_status_id = $this->config->get('payment_pp_pro_iframe_canceled_reversal_status_id'); + break; + case 'Completed': + $order_status_id = $this->config->get('payment_pp_pro_iframe_completed_status_id'); + break; + case 'Denied': + $order_status_id = $this->config->get('payment_pp_pro_iframe_denied_status_id'); + break; + case 'Expired': + $order_status_id = $this->config->get('payment_pp_pro_iframe_expired_status_id'); + break; + case 'Failed': + $order_status_id = $this->config->get('payment_pp_pro_iframe_failed_status_id'); + break; + case 'Pending': + $order_status_id = $this->config->get('payment_pp_pro_iframe_pending_status_id'); + break; + case 'Processed': + $order_status_id = $this->config->get('payment_pp_pro_iframe_processed_status_id'); + break; + case 'Refunded': + $order_status_id = $this->config->get('payment_pp_pro_iframe_processed_status_id'); + break; + case 'Reversed': + $order_status_id = $this->config->get('payment_pp_pro_iframe_reversed_status_id'); + break; + case 'Voided': + $order_status_id = $this->config->get('payment_pp_pro_iframe_voided_status_id'); + break; + } + + if (!$order_info['order_status_id']) { + $paypal_order_data = array( + 'order_id' => $order_id, + 'capture_status' => ($this->config->get('payment_pp_pro_iframe_transaction_method') == 'sale' ? 'Complete' : 'NotComplete'), + 'currency_code' => $this->request->post['mc_currency'], + 'authorization_id' => $this->request->post['txn_id'], + 'total' => $this->request->post['mc_gross'], + ); + + $paypal_iframe_order_id = $this->model_extension_payment_pp_pro_iframe->addOrder($paypal_order_data); + + $paypal_transaction_data = array( + 'paypal_iframe_order_id' => $paypal_iframe_order_id, + 'transaction_id' => $this->request->post['txn_id'], + 'parent_id' => '', + 'note' => '', + 'msgsubid' => '', + 'receipt_id' => $this->request->post['receipt_id'], + 'payment_type' => $this->request->post['payment_type'], + 'payment_status' => $this->request->post['payment_status'], + 'pending_reason' => (isset($this->request->post['pending_reason']) ? $this->request->post['pending_reason'] : ''), + 'transaction_entity' => ($this->config->get('payment_pp_pro_iframe_transaction_method') == 'sale' ? 'payment' : 'auth'), + 'amount' => $this->request->post['mc_gross'], + 'debug_data' => json_encode($this->request->post), + ); + + $this->model_extension_payment_pp_pro_iframe->addTransaction($paypal_transaction_data); + + $this->model_checkout_order->addOrderHistory($order_id, $order_status_id); + } else { + $this->model_checkout_order->addOrderHistory($order_id, $order_status_id); + } + } else { + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('config_order_status_id')); + } + } + + curl_close($curl); + } + } + + private function constructButtonData($order_info) { + $s_data = array(); + $s_data['METHOD'] = 'BMCreateButton'; + $s_data['VERSION'] = '65.2'; + $s_data['BUTTONCODE'] = 'TOKEN'; + + $s_data['BUTTONLANGUAGE'] = 'en'; + $s_data['BUTTONSOURCE'] = 'OpenCart_2.0_HSS'; + + $s_data['USER'] = $this->config->get('payment_pp_pro_iframe_user'); + $s_data['SIGNATURE'] = $this->config->get('payment_pp_pro_iframe_sig'); + $s_data['PWD'] = $this->config->get('payment_pp_pro_iframe_password'); + + $s_data['BUTTONTYPE'] = 'PAYMENT'; + $s_data['L_BUTTONVAR0'] = 'subtotal=' . $this->currency->format($order_info['total'], $order_info['currency_code'], false, false); + $s_data['L_BUTTONVAR1'] = 'tax=0.00'; + $s_data['L_BUTTONVAR2'] = 'shipping=0.00'; + $s_data['L_BUTTONVAR3'] = 'handling=0.00'; + + if ($this->cart->hasShipping()) { + $s_data['L_BUTTONVAR4'] = 'first_name=' . urlencode($order_info['shipping_firstname']); + $s_data['L_BUTTONVAR5'] = 'last_name=' . urlencode($order_info['shipping_lastname']); + $s_data['L_BUTTONVAR6'] = 'address1=' . urlencode($order_info['shipping_address_1']); + $s_data['L_BUTTONVAR7'] = 'address2=' . urlencode($order_info['shipping_address_2']); + $s_data['L_BUTTONVAR8'] = 'city=' . urlencode($order_info['shipping_city']); + $s_data['L_BUTTONVAR9'] = 'state=' . urlencode($order_info['shipping_zone']); + $s_data['L_BUTTONVAR10'] = 'zip=' . urlencode($order_info['shipping_postcode']); + $s_data['L_BUTTONVAR11'] = 'country=' . urlencode($order_info['shipping_iso_code_2']); + } else { + $s_data['L_BUTTONVAR4'] = 'first_name=' . urlencode($order_info['payment_firstname']); + $s_data['L_BUTTONVAR5'] = 'last_name=' . urlencode($order_info['payment_lastname']); + $s_data['L_BUTTONVAR6'] = 'address1=' . urlencode($order_info['payment_address_1']); + $s_data['L_BUTTONVAR7'] = 'address2=' . urlencode($order_info['payment_address_2']); + $s_data['L_BUTTONVAR8'] = 'city=' . urlencode($order_info['payment_city']); + $s_data['L_BUTTONVAR9'] = 'state=' . urlencode($order_info['payment_zone']); + $s_data['L_BUTTONVAR10'] = 'zip=' . urlencode($order_info['payment_postcode']); + $s_data['L_BUTTONVAR11'] = 'country=' . urlencode($order_info['payment_iso_code_2']); + } + + $s_data['L_BUTTONVAR12'] = 'billing_first_name=' . urlencode($order_info['payment_firstname']); + $s_data['L_BUTTONVAR13'] = 'billing_last_name=' . urlencode($order_info['payment_lastname']); + $s_data['L_BUTTONVAR14'] = 'billing_address1=' . urlencode($order_info['payment_address_1']); + $s_data['L_BUTTONVAR15'] = 'billing_address2=' . urlencode($order_info['payment_address_2']); + $s_data['L_BUTTONVAR16'] = 'billing_city=' . urlencode($order_info['payment_city']); + $s_data['L_BUTTONVAR17'] = 'billing_state=' . urlencode($order_info['payment_zone']); + $s_data['L_BUTTONVAR18'] = 'billing_zip=' . urlencode($order_info['payment_postcode']); + $s_data['L_BUTTONVAR19'] = 'billing_country=' . urlencode($order_info['payment_iso_code_2']); + + $s_data['L_BUTTONVAR20'] = 'notify_url=' . $this->url->link('extension/payment/pp_pro_iframe/notify', '', true); + $s_data['L_BUTTONVAR21'] = 'cancel_return=' . $this->url->link('checkout/checkout', '', true); + $s_data['L_BUTTONVAR22'] = 'paymentaction=' . $this->config->get('payment_pp_pro_iframe_transaction_method'); + $s_data['L_BUTTONVAR23'] = 'currency_code=' . urlencode($order_info['currency_code']); + $s_data['L_BUTTONVAR26'] = 'showBillingAddress=false'; + $s_data['L_BUTTONVAR27'] = 'showShippingAddress=false'; + $s_data['L_BUTTONVAR28'] = 'showBillingEmail=false'; + $s_data['L_BUTTONVAR29'] = 'showBillingPhone=false'; + $s_data['L_BUTTONVAR30'] = 'showCustomerName=true'; + $s_data['L_BUTTONVAR31'] = 'showCardInfo=true'; + $s_data['L_BUTTONVAR32'] = 'showHostedThankyouPage=false'; + $s_data['L_BUTTONVAR33'] = 'bn=GBD'; + $s_data['L_BUTTONVAR35'] = 'address_override=true'; + $s_data['L_BUTTONVAR36'] = 'cpp_header_image=Red'; + $s_data['L_BUTTONVAR44'] = 'bodyBgColor=#AEAEAE'; + $s_data['L_BUTTONVAR47'] = 'PageTitleTextColor=Blue'; + $s_data['L_BUTTONVAR48'] = 'PageCollapseBgColor=#AEAEAE'; + $s_data['L_BUTTONVAR49'] = 'PageCollapseTextColor=#AEAEAE'; + $s_data['L_BUTTONVAR50'] = 'PageButtonBgColor=#AEAEAE'; + $s_data['L_BUTTONVAR51'] = 'orderSummaryBgColor=#AEAEAE'; + $s_data['L_BUTTONVAR55'] = 'template=templateD'; + $s_data['L_BUTTONVAR56'] = 'return=' . $this->url->link('checkout/success', '', true); + $s_data['L_BUTTONVAR57'] = 'custom=' . $this->encryption->encrypt($this->config->get('config_encryption'), $order_info['order_id']); + + if ($this->config->get('payment_pp_pro_iframe_test')) { + $url = 'https://api-3t.sandbox.paypal.com/nvp'; + } else { + $url = 'https://api-3t.paypal.com/nvp'; + } + + $curl = curl_init($url); + + curl_setopt($curl, CURLOPT_PORT, 443); + curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_FORBID_REUSE, 1); + curl_setopt($curl, CURLOPT_FRESH_CONNECT, 1); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($s_data, '', "&")); + curl_setopt($curl, CURLOPT_HTTPHEADER, array('X-VPS-REQUEST-ID: ' . md5($order_info['order_id'] . mt_rand()))); + + $response = curl_exec($curl); + + $response_data = array(); + + parse_str($response, $response_data); + + if ($this->config->get('payment_pp_pro_iframe_debug')) { + $log = new Log('pp_pro_iframe.log'); + $log->write(print_r(json_encode($response_data), 1)); + } + + curl_close($curl); + + if (!$response || !isset($response_data['HOSTEDBUTTONID'])) { + return false; + } else { + return $response_data['HOSTEDBUTTONID']; + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/pp_standard.php b/public/catalog/controller/extension/payment/pp_standard.php new file mode 100644 index 0000000..c055672 --- /dev/null +++ b/public/catalog/controller/extension/payment/pp_standard.php @@ -0,0 +1,203 @@ +<?php +class ControllerExtensionPaymentPPStandard extends Controller { + public function index() { + $this->load->language('extension/payment/pp_standard'); + + $data['text_testmode'] = $this->language->get('text_testmode'); + $data['button_confirm'] = $this->language->get('button_confirm'); + + $data['testmode'] = $this->config->get('payment_pp_standard_test'); + + if (!$this->config->get('payment_pp_standard_test')) { + $data['action'] = 'https://www.paypal.com/cgi-bin/webscr&pal=V4T754QB63XXL'; + } else { + $data['action'] = 'https://www.sandbox.paypal.com/cgi-bin/webscr&pal=V4T754QB63XXL'; + } + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if ($order_info) { + $data['business'] = $this->config->get('payment_pp_standard_email'); + $data['item_name'] = html_entity_decode($this->config->get('config_name'), ENT_QUOTES, 'UTF-8'); + + $data['products'] = array(); + + foreach ($this->cart->getProducts() as $product) { + $option_data = array(); + + foreach ($product['option'] as $option) { + if ($option['type'] != 'file') { + $value = $option['value']; + } else { + $upload_info = $this->model_tool_upload->getUploadByCode($option['value']); + + if ($upload_info) { + $value = $upload_info['name']; + } else { + $value = ''; + } + } + + $option_data[] = array( + 'name' => $option['name'], + 'value' => (utf8_strlen($value) > 20 ? utf8_substr($value, 0, 20) . '..' : $value) + ); + } + + $data['products'][] = array( + 'name' => htmlspecialchars($product['name']), + 'model' => htmlspecialchars($product['model']), + 'price' => $this->currency->format($product['price'], $order_info['currency_code'], false, false), + 'quantity' => $product['quantity'], + 'option' => $option_data, + 'weight' => $product['weight'] + ); + } + + $data['discount_amount_cart'] = 0; + + $total = $this->currency->format($order_info['total'] - $this->cart->getSubTotal(), $order_info['currency_code'], false, false); + + if ($total > 0) { + $data['products'][] = array( + 'name' => $this->language->get('text_total'), + 'model' => '', + 'price' => $total, + 'quantity' => 1, + 'option' => array(), + 'weight' => 0 + ); + } else { + $data['discount_amount_cart'] -= $total; + } + + $data['currency_code'] = $order_info['currency_code']; + $data['first_name'] = $order_info['payment_firstname']; + $data['last_name'] = $order_info['payment_lastname']; + $data['address1'] = $order_info['payment_address_1']; + $data['address2'] = $order_info['payment_address_2']; + $data['city'] = $order_info['payment_city']; + $data['zip'] = $order_info['payment_postcode']; + $data['country'] = $order_info['payment_iso_code_2']; + $data['email'] = $order_info['email']; + $data['invoice'] = $this->session->data['order_id'] . ' - ' . $order_info['payment_firstname'] . ' ' . $order_info['payment_lastname']; + $data['lc'] = $this->session->data['language']; + $data['return'] = $this->url->link('checkout/success'); + $data['notify_url'] = $this->url->link('extension/payment/pp_standard/callback', '', true); + $data['cancel_return'] = $this->url->link('checkout/checkout', '', true); + + if (!$this->config->get('payment_pp_standard_transaction')) { + $data['paymentaction'] = 'authorization'; + } else { + $data['paymentaction'] = 'sale'; + } + + $data['custom'] = $this->session->data['order_id']; + + return $this->load->view('extension/payment/pp_standard', $data); + } + } + + public function callback() { + if (isset($this->request->post['custom'])) { + $order_id = $this->request->post['custom']; + } else { + $order_id = 0; + } + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($order_id); + + if ($order_info) { + $request = 'cmd=_notify-validate'; + + foreach ($this->request->post as $key => $value) { + $request .= '&' . $key . '=' . urlencode(html_entity_decode($value, ENT_QUOTES, 'UTF-8')); + } + + if (!$this->config->get('payment_pp_standard_test')) { + $curl = curl_init('https://www.paypal.com/cgi-bin/webscr'); + } else { + $curl = curl_init('https://www.sandbox.paypal.com/cgi-bin/webscr'); + } + + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, $request); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HEADER, false); + curl_setopt($curl, CURLOPT_TIMEOUT, 30); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + + $response = curl_exec($curl); + + if (!$response) { + $this->log->write('PP_STANDARD :: CURL failed ' . curl_error($curl) . '(' . curl_errno($curl) . ')'); + } + + if ($this->config->get('payment_pp_standard_debug')) { + $this->log->write('PP_STANDARD :: IPN REQUEST: ' . $request); + $this->log->write('PP_STANDARD :: IPN RESPONSE: ' . $response); + } + + if ((strcmp($response, 'VERIFIED') == 0 || strcmp($response, 'UNVERIFIED') == 0) && isset($this->request->post['payment_status'])) { + $order_status_id = $this->config->get('config_order_status_id'); + + switch($this->request->post['payment_status']) { + case 'Canceled_Reversal': + $order_status_id = $this->config->get('payment_pp_standard_canceled_reversal_status_id'); + break; + case 'Completed': + $receiver_match = (strtolower($this->request->post['receiver_email']) == strtolower($this->config->get('payment_pp_standard_email'))); + + $total_paid_match = ((float)$this->request->post['mc_gross'] == $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false)); + + if ($receiver_match && $total_paid_match) { + $order_status_id = $this->config->get('payment_pp_standard_completed_status_id'); + } + + if (!$receiver_match) { + $this->log->write('PP_STANDARD :: RECEIVER EMAIL MISMATCH! ' . strtolower($this->request->post['receiver_email'])); + } + + if (!$total_paid_match) { + $this->log->write('PP_STANDARD :: TOTAL PAID MISMATCH! ' . $this->request->post['mc_gross']); + } + break; + case 'Denied': + $order_status_id = $this->config->get('payment_pp_standard_denied_status_id'); + break; + case 'Expired': + $order_status_id = $this->config->get('payment_pp_standard_expired_status_id'); + break; + case 'Failed': + $order_status_id = $this->config->get('payment_pp_standard_failed_status_id'); + break; + case 'Pending': + $order_status_id = $this->config->get('payment_pp_standard_pending_status_id'); + break; + case 'Processed': + $order_status_id = $this->config->get('payment_pp_standard_processed_status_id'); + break; + case 'Refunded': + $order_status_id = $this->config->get('payment_pp_standard_refunded_status_id'); + break; + case 'Reversed': + $order_status_id = $this->config->get('payment_pp_standard_reversed_status_id'); + break; + case 'Voided': + $order_status_id = $this->config->get('payment_pp_standard_voided_status_id'); + break; + } + + $this->model_checkout_order->addOrderHistory($order_id, $order_status_id); + } else { + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('config_order_status_id')); + } + + curl_close($curl); + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/realex.php b/public/catalog/controller/extension/payment/realex.php new file mode 100644 index 0000000..62da983 --- /dev/null +++ b/public/catalog/controller/extension/payment/realex.php @@ -0,0 +1,258 @@ +<?php +class ControllerExtensionPaymentRealex extends Controller { + public function index() { + $this->load->language('extension/payment/realex'); + + $data['entry_cc_type'] = $this->language->get('entry_cc_type'); + + $data['help_select_card'] = $this->language->get('help_select_card'); + + $data['button_confirm'] = $this->language->get('button_confirm'); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if ($this->config->get('payment_realex_live_demo') == 1) { + $data['action'] = $this->config->get('payment_realex_live_url'); + } else { + $data['action'] = $this->config->get('payment_realex_demo_url'); + } + + if ($this->config->get('payment_realex_card_select') == 1) { + $card_types = array( + 'visa' => $this->language->get('text_card_visa'), + 'mc' => $this->language->get('text_card_mc'), + 'amex' => $this->language->get('text_card_amex'), + 'switch' => $this->language->get('text_card_switch'), + 'laser' => $this->language->get('text_card_laser'), + 'diners' => $this->language->get('text_card_diners'), + ); + + $data['cards'] = array(); + + $accounts = $this->config->get('payment_realex_account'); + + foreach ($accounts as $card => $account) { + if (isset($account['enabled']) && $account['enabled'] == 1) { + $data['cards'][] = array( + 'type' => $card_types[$card], + 'account' => (isset($account['default']) && $account['default'] == 1 ? $this->config->get('payment_realex_merchant_id') : $account['merchant_id']), + ); + } + } + + $data['card_select'] = true; + } else { + $data['card_select'] = false; + } + + if ($this->config->get('payment_realex_auto_settle') == 0) { + $data['settle'] = 0; + } elseif ($this->config->get('payment_realex_auto_settle') == 1) { + $data['settle'] = 1; + } elseif ($this->config->get('payment_realex_auto_settle') == 2) { + $data['settle'] = 'MULTI'; + } + + $data['tss'] = (int)$this->config->get('payment_realex_tss_check'); + $data['merchant_id'] = $this->config->get('payment_realex_merchant_id'); + + $data['timestamp'] = strftime("%Y%m%d%H%M%S"); + $data['order_id'] = $this->session->data['order_id'] . 'T' . $data['timestamp'] . mt_rand(1, 999); + + $data['amount'] = round($this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false) * 100); + $data['currency'] = $order_info['currency_code']; + + $tmp = $data['timestamp'] . '.' . $data['merchant_id'] . '.' . $data['order_id'] . '.' . $data['amount'] . '.' . $data['currency']; + $hash = sha1($tmp); + $tmp = $hash . '.' . $this->config->get('payment_realex_secret'); + $data['hash'] = sha1($tmp); + + $data['billing_code'] = filter_var(str_replace('-', '', $order_info['payment_postcode']), FILTER_SANITIZE_NUMBER_INT) . '|' . filter_var(str_replace('-', '', $order_info['payment_address_1']), FILTER_SANITIZE_NUMBER_INT); + $data['payment_country'] = $order_info['payment_iso_code_2']; + + if ($this->cart->hasShipping()) { + $data['shipping_code'] = filter_var(str_replace('-', '', $order_info['shipping_postcode']), FILTER_SANITIZE_NUMBER_INT) . '|' . filter_var(str_replace('-', '', $order_info['shipping_address_1']), FILTER_SANITIZE_NUMBER_INT); + $data['shipping_country'] = $order_info['shipping_iso_code_2']; + } else { + $data['shipping_code'] = filter_var(str_replace('-', '', $order_info['payment_postcode']), FILTER_SANITIZE_NUMBER_INT) . '|' . filter_var(str_replace('-', '', $order_info['payment_address_1']), FILTER_SANITIZE_NUMBER_INT); + $data['shipping_country'] = $order_info['payment_iso_code_2']; + } + + $data['response_url'] = HTTPS_SERVER . 'index.php?route=extension/payment/realex/notify'; + + return $this->load->view('extension/payment/realex', $data); + } + + public function notify() { + $this->load->model('extension/payment/realex'); + + $this->model_extension_payment_realex->logger(print_r($this->request->post, 1)); + + $this->load->language('extension/payment/realex'); + + $hash = sha1($this->request->post['TIMESTAMP'] . '.' . $this->config->get('payment_realex_merchant_id') . '.' . $this->request->post['ORDER_ID'] . '.' . $this->request->post['RESULT'] . '.' . $this->request->post['MESSAGE'] . '.' . $this->request->post['PASREF'] . '.' . $this->request->post['AUTHCODE']); + $tmp = $hash . '.' . $this->config->get('payment_realex_secret'); + $hash = sha1($tmp); + + //Check to see if hashes match or not + if ($hash != $this->request->post['SHA1HASH']) { + $data['text_response'] = $this->language->get('text_hash_failed'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } else { + $this->load->model('checkout/order'); + + $order_id_parts = explode('T', $this->request->post['ORDER_ID']); + $order_id = (int)$order_id_parts[0]; + + $order_info = $this->model_checkout_order->getOrder($order_id); + + $auto_settle = (int)$this->config->get('payment_realex_auto_settle'); + $tss = (int)$this->config->get('payment_realex_tss_check'); + + $message = '<strong>' . $this->language->get('text_result') . ':</strong> ' . $this->request->post['RESULT']; + $message .= '<br /><strong>' . $this->language->get('text_message') . ':</strong> ' . $this->request->post['MESSAGE']; + + if (isset($this->request->post['ORDER_ID'])) { + $message .= '<br /><strong>' . $this->language->get('text_order_ref') . ':</strong> ' . $this->request->post['ORDER_ID']; + } + + if (isset($this->request->post['CVNRESULT'])) { + $message .= '<br /><strong>' . $this->language->get('text_cvn_result') . ':</strong> ' . $this->request->post['CVNRESULT']; + } + + if (isset($this->request->post['AVSPOSTCODERESULT'])) { + $message .= '<br /><strong>' . $this->language->get('text_avs_postcode') . ':</strong> ' . $this->request->post['AVSPOSTCODERESULT']; + } + + if (isset($this->request->post['AVSADDRESSRESULT'])) { + $message .= '<br /><strong>' . $this->language->get('text_avs_address') . ':</strong> ' . $this->request->post['AVSADDRESSRESULT']; + } + + //3D Secure message + if (isset($this->request->post['ECI']) && isset($this->request->post['CAVV']) && isset($this->request->post['XID'])) { + $eci = $this->request->post['ECI']; + + if (($this->request->post['ECI'] == 6 || $this->request->post['ECI'] == 1) && empty($this->request->post['CAVV']) && empty($this->request->post['XID'])) { + $scenario_id = 1; + } + + if (($this->request->post['ECI'] == 5 || $this->request->post['ECI'] == 0) && !empty($this->request->post['CAVV']) && !empty($this->request->post['XID'])) { + $scenario_id = 5; + } + + if (($this->request->post['ECI'] == 6 || $this->request->post['ECI'] == 1) && !empty($this->request->post['CAVV']) && !empty($this->request->post['XID'])) { + $scenario_id = 6; + } + + if (isset($scenario_id)) { + $scenario_message = $this->language->get('text_3d_s' . $scenario_id); + } else { + if (isset($this->request->post['CARDTYPE'])) { + if ($this->request->post['CARDTYPE'] == 'VISA') { + $eci = 7; + } else { + $eci = 2; + } + } + + $scenario_message = $this->language->get('text_3d_liability'); + } + + $message .= '<br /><strong>' . $this->language->get('text_eci') . ':</strong> (' . $eci . ') ' . $scenario_message; + } + + if ($tss == 1 && isset($this->request->post['TSS'])) { + $message .= '<br /><strong>' . $this->language->get('text_tss') . ':</strong> ' . $this->request->post['TSS']; + } + + if (isset($this->request->post['TIMESTAMP'])) { + $message .= '<br /><strong>' . $this->language->get('text_timestamp') . ':</strong> ' . $this->request->post['TIMESTAMP']; + } + + if (isset($this->request->post['CARDDIGITS'])) { + $message .= '<br /><strong>' . $this->language->get('text_card_digits') . ':</strong> ' . $this->request->post['CARDDIGITS']; + } + + if (isset($this->request->post['CARDTYPE'])) { + $message .= '<br /><strong>' . $this->language->get('text_card_type') . ':</strong> ' . $this->request->post['CARDTYPE']; + } + + if (isset($this->request->post['EXPDATE'])) { + $message .= '<br /><strong>' . $this->language->get('text_card_exp') . ':</strong> ' . $this->request->post['EXPDATE']; + } + + if (isset($this->request->post['CARDNAME'])) { + $message .= '<br /><strong>' . $this->language->get('text_card_name') . ':</strong> ' . $this->request->post['CARDNAME']; + } + + if (isset($this->request->post['DCCAUTHCARDHOLDERAMOUNT']) && isset($this->request->post['DCCAUTHRATE'])) { + $message .= '<br /><strong>DCCAUTHCARDHOLDERAMOUNT:</strong> ' . $this->request->post['DCCAUTHCARDHOLDERAMOUNT']; + $message .= '<br /><strong>DCCAUTHRATE:</strong> ' . $this->request->post['DCCAUTHRATE']; + $message .= '<br /><strong>DCCAUTHCARDHOLDERCURRENCY:</strong> ' . $this->request->post['DCCAUTHCARDHOLDERCURRENCY']; + $message .= '<br /><strong>DCCAUTHMERCHANTCURRENCY:</strong> ' . $this->request->post['DCCAUTHMERCHANTCURRENCY']; + $message .= '<br /><strong>DCCAUTHMERCHANTAMOUNT:</strong> ' . $this->request->post['DCCAUTHMERCHANTAMOUNT']; + $message .= '<br /><strong>DCCCCP:</strong> ' . $this->request->post['DCCCCP']; + $message .= '<br /><strong>DCCRATE:</strong> ' . $this->request->post['DCCRATE']; + $message .= '<br /><strong>DCCMARGINRATEPERCENTAGE:</strong> ' . $this->request->post['DCCMARGINRATEPERCENTAGE']; + $message .= '<br /><strong>DCCEXCHANGERATESOURCENAME:</strong> ' . $this->request->post['DCCEXCHANGERATESOURCENAME']; + $message .= '<br /><strong>DCCCOMMISSIONPERCENTAGE:</strong> ' . $this->request->post['DCCCOMMISSIONPERCENTAGE']; + $message .= '<br /><strong>DCCEXCHANGERATESOURCETIMESTAMP:</strong> ' . $this->request->post['DCCEXCHANGERATESOURCETIMESTAMP']; + $message .= '<br /><strong>DCCCHOICE:</strong> ' . $this->request->post['DCCCHOICE']; + } + + if ($this->request->post['RESULT'] == "00") { + $realex_order_id = $this->model_extension_payment_realex->addOrder($order_info, $this->request->post['PASREF'], $this->request->post['AUTHCODE'], $this->request->post['ACCOUNT'], $this->request->post['ORDER_ID']); + + if ($auto_settle == 1) { + $this->model_extension_payment_realex->addTransaction($realex_order_id, 'payment', $order_info); + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_realex_order_status_success_settled_id'), $message, false); + } else { + $this->model_extension_payment_realex->addTransaction($realex_order_id, 'auth', 0.00); + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_realex_order_status_success_unsettled_id'), $message, false); + } + + $data['text_response'] = $this->language->get('text_success'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/success', '', true)); + } elseif ($this->request->post['RESULT'] == "101") { + // Decline + $this->model_extension_payment_realex->addHistory($order_id, $this->config->get('payment_realex_order_status_decline_id'), $message); + $data['text_response'] = $this->language->get('text_decline'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } elseif ($this->request->post['RESULT'] == "102") { + // Referal B + $this->model_extension_payment_realex->addHistory($order_id, $this->config->get('payment_realex_order_status_decline_pending_id'), $message); + $data['text_response'] = $this->language->get('text_decline'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } elseif ($this->request->post['RESULT'] == "103") { + // Referal A + $this->model_extension_payment_realex->addHistory($order_id, $this->config->get('payment_realex_order_status_decline_stolen_id'), $message); + $data['text_response'] = $this->language->get('text_decline'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } elseif ($this->request->post['RESULT'] == "200") { + // Error Connecting to Bank + $this->model_extension_payment_realex->addHistory($order_id, $this->config->get('payment_realex_order_status_decline_bank_id'), $message); + $data['text_response'] = $this->language->get('text_bank_error'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } elseif ($this->request->post['RESULT'] == "204") { + // Error Connecting to Bank + $this->model_extension_payment_realex->addHistory($order_id, $this->config->get('payment_realex_order_status_decline_bank_id'), $message); + $data['text_response'] = $this->language->get('text_bank_error'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } elseif ($this->request->post['RESULT'] == "205") { + // Comms Error + $this->model_extension_payment_realex->addHistory($order_id, $this->config->get('payment_realex_order_status_decline_bank_id'), $message); + $data['text_response'] = $this->language->get('text_bank_error'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } else { + // Other error + $this->model_extension_payment_realex->addHistory($order_id, $this->config->get('payment_realex_order_status_decline_id'), $message); + $data['text_response'] = $this->language->get('text_generic_error'); + $data['text_link'] = sprintf($this->language->get('text_link'), $this->url->link('checkout/checkout', '', true)); + } + } + + $this->response->setOutput($this->load->view('extension/payment/realex_response', $data)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/realex_remote.php b/public/catalog/controller/extension/payment/realex_remote.php new file mode 100644 index 0000000..ba08fd3 --- /dev/null +++ b/public/catalog/controller/extension/payment/realex_remote.php @@ -0,0 +1,349 @@ +<?php +class ControllerExtensionPaymentRealexRemote extends Controller { + public function index() { + $this->load->language('extension/payment/realex_remote'); + + $data['text_credit_card'] = $this->language->get('text_credit_card'); + $data['text_loading'] = $this->language->get('text_loading'); + $data['text_wait'] = $this->language->get('text_wait'); + $data['entry_cc_type'] = $this->language->get('entry_cc_type'); + $data['entry_cc_number'] = $this->language->get('entry_cc_number'); + $data['entry_cc_name'] = $this->language->get('entry_cc_name'); + $data['entry_cc_expire_date'] = $this->language->get('entry_cc_expire_date'); + $data['entry_cc_cvv2'] = $this->language->get('entry_cc_cvv2'); + $data['entry_cc_issue'] = $this->language->get('entry_cc_issue'); + $data['help_start_date'] = $this->language->get('help_start_date'); + $data['help_issue'] = $this->language->get('help_issue'); + $data['button_confirm'] = $this->language->get('button_confirm'); + + $accounts = $this->config->get('payment_realex_remote_account'); + + $card_types = array( + 'visa' => $this->language->get('text_card_visa'), + 'mc' => $this->language->get('text_card_mc'), + 'amex' => $this->language->get('text_card_amex'), + 'switch' => $this->language->get('text_card_switch'), + 'laser' => $this->language->get('text_card_laser'), + 'diners' => $this->language->get('text_card_diners'), + ); + + $data['cards'] = array(); + + foreach ($accounts as $card => $account) { + if (isset($account['enabled']) && $account['enabled'] == 1) { + $data['cards'][] = array( + 'code' => $card, + 'text' => $card_types[$card], + ); + } + } + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['year_expire'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['year_expire'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + return $this->load->view('extension/payment/realex_remote', $data); + } + + public function send() { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/realex_remote'); + + $this->load->language('extension/payment/realex_remote'); + + if ($this->request->post['cc_number'] == '') { + $json['error'] = $this->language->get('error_card_number'); + } + + if ($this->request->post['cc_name'] == '') { + $json['error'] = $this->language->get('error_card_name'); + } + + if (strlen($this->request->post['cc_cvv2']) != 3 && strlen($this->request->post['cc_cvv2']) != 4) { + $json['error'] = $this->language->get('error_card_cvv'); + } + + if (isset($json['error'])) { + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + $this->response->output(); + die(); + } + + $order_id = $this->session->data['order_id']; + + $order_ref = $order_id . 'T' . strftime("%Y%m%d%H%M%S") . mt_rand(1, 999); + + $order_info = $this->model_checkout_order->getOrder($order_id); + + $amount = round($this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false) * 100); + $currency = $order_info['currency_code']; + + $accounts = $this->config->get('payment_realex_remote_account'); + + if (isset($accounts[$this->request->post['cc_type']]['default']) && $accounts[$this->request->post['cc_type']]['default'] == 1) { + $account = $this->config->get('payment_realex_remote_merchant_id'); + } else { + $account = $accounts[$this->request->post['cc_type']]['merchant_id']; + } + + $eci_ref = ''; + $eci = ''; + $cavv = ''; + $xid = ''; + + if ($this->config->get('payment_realex_remote_3d') == 1) { + if ($this->request->post['cc_type'] == 'visa' || $this->request->post['cc_type'] == 'mc' || $this->request->post['cc_type'] == 'amex') { + $verify_3ds = $this->model_extension_payment_realex_remote->checkEnrollment($account, $amount, $currency, $order_ref); + + $this->model_extension_payment_realex_remote->logger('Verify 3DS result:\r\n' . print_r($verify_3ds, 1)); + + // Proceed to 3D secure + if (isset($verify_3ds->result) && $verify_3ds->result == '00') { + $enc_data = array( + 'account' => $account, + 'amount' => $amount, + 'currency' => $currency, + 'order_id' => $order_id, + 'order_ref' => $order_ref, + 'cc_number' => $this->request->post['cc_number'], + 'cc_expire' => $this->request->post['cc_expire_date_month'] . $this->request->post['cc_expire_date_year'], + 'cc_name' => $this->request->post['cc_name'], + 'cc_type' => $this->request->post['cc_type'], + 'cc_cvv2' => $this->request->post['cc_cvv2'], + 'cc_issue' => $this->request->post['cc_issue'] + ); + + $md = $this->encryption->encrypt($this->config->get('config_encryption'), json_encode($enc_data)); + + $json = array(); + $json['ACSURL'] = (string)$verify_3ds->url; + $json['MD'] = $md; + $json['PaReq'] = (string)$verify_3ds->pareq; + $json['TermUrl'] = $this->url->link('extension/payment/realex_remote/acsReturn', '', true); + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + $this->response->output(); + die(); + } + + // Cardholder Not Enrolled. Shift in liability. ECI = 6 + if (isset($verify_3ds->result) && $verify_3ds->result == '110' && isset($verify_3ds->enrolled) && $verify_3ds->enrolled == 'N') { + $eci_ref = 1; + $xid = ''; + $cavv = ''; + if ($this->request->post['cc_type'] == 'mc') { + $eci = 1; + } else { + $eci = 6; + } + } + + // Unable to Verify Enrollment. No shift in liability. ECI = 7 + if (isset($verify_3ds->result) && $verify_3ds->result == '110' && isset($verify_3ds->enrolled) && $verify_3ds->enrolled == 'U') { + if ($this->config->get('payment_realex_remote_liability') != 1) { + $this->load->language('extension/payment/realex_remote'); + + $json['error'] = $this->language->get('error_3d_unable'); + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + $this->response->output(); + die(); + } else { + $eci_ref = 2; + $xid = ''; + $cavv = ''; + if ($this->request->post['cc_type'] == 'mc') { + $eci = 0; + } else { + $eci = 7; + } + } + } + + // Invalid response from Enrollment Server. No shift in liability. ECI = 7 + if (isset($verify_3ds->result) && $verify_3ds->result >= 500 && $verify_3ds->result < 600) { + if ($this->config->get('payment_realex_remote_liability') != 1) { + $this->load->language('extension/payment/realex_remote'); + + $json['error'] = (string)$verify_3ds->message; + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + $this->response->output(); + die(); + } else { + $eci_ref = 3; + if ($this->request->post['cc_type'] == 'mc') { + $eci = 0; + } else { + $eci = 7; + } + } + } + } + } + + $capture_result = $this->model_extension_payment_realex_remote->capturePayment( + $account, + $amount, + $currency, + $order_id, + $order_ref, + $this->request->post['cc_number'], + $this->request->post['cc_expire_date_month'] . $this->request->post['cc_expire_date_year'], + $this->request->post['cc_name'], + $this->request->post['cc_type'], + $this->request->post['cc_cvv2'], + $this->request->post['cc_issue'], + $eci_ref, + $eci, + $cavv, + $xid + ); + + $this->model_extension_payment_realex_remote->logger('Capture result:\r\n' . print_r($capture_result, 1)); + + if ($capture_result->result != '00') { + $json['error'] = (string)$capture_result->message . ' (' . (int)$capture_result->result . ')'; + } else { + $json['success'] = $this->url->link('checkout/success'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function acsReturn() { + if (isset($this->session->data['order_id'])) { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/realex_remote'); + + $post = $this->request->post; + + $md = json_decode($this->encryption->decrypt($this->config->get('config_encryption'), $post['MD']), true); + + $signature_result = $this->model_extension_payment_realex_remote->enrollmentSignature($md['account'], $md['amount'], $md['currency'], $md['order_ref'], $md['cc_number'], $md['cc_expire'], $md['cc_type'], $md['cc_name'], $post['PaRes']); + + $this->model_extension_payment_realex_remote->logger('Signature result:\r\n' . print_r($signature_result, 1)); + + if ($signature_result->result == '00' && (strtoupper($signature_result->threedsecure->status) == 'Y' || strtoupper($signature_result->threedsecure->status) == 'A')) { + if (strtoupper($signature_result->threedsecure->status) == 'Y') { + $eci_ref = 5; + } else { + $eci_ref = 6; + } + + $eci = (string)$signature_result->threedsecure->eci; + $cavv = (string)$signature_result->threedsecure->cavv; + $xid = (string)$signature_result->threedsecure->xid; + } else { + if ($md['cc_type'] == 'mc') { + $eci = 0; + } else { + $eci = 7; + } + + // Enrolled but invalid response from ACS. No shift in liability. ECI = 7 + if ($signature_result->result == '110' && strtoupper($signature_result->threedsecure->status) == 'Y') { + $eci_ref = 4; + $cavv = (string)$signature_result->threedsecure->cavv; + $xid = (string)$signature_result->threedsecure->xid; + } + + // Incorrect password entered. No shift in liability. ECI = 7 + if ($signature_result->result == '00' && strtoupper($signature_result->threedsecure->status) == 'N') { + $eci_ref = 7; + $xid = (string)$signature_result->threedsecure->xid; + $cavv = ''; + } + + // Authentication Unavailable. No shift in liability. ECI = 7 + if ($signature_result->result == '00' && strtoupper($signature_result->threedsecure->status) == 'U') { + $eci_ref = 8; + $xid = (string)$signature_result->threedsecure->xid; + $cavv = ''; + } + + // Invalid response from ACS. No shift in liability. ECI = 7 + if (isset($signature_result->result) && $signature_result->result >= 500 && $signature_result->result < 600) { + $eci_ref = 9; + $xid = ''; + $cavv = ''; + } + + if ($this->config->get('payment_realex_remote_liability') != 1) { + // this is the check for liability shift - if the merchant does not want to accept, redirect to checkout with message + $this->load->language('extension/payment/realex_remote'); + + $message = $this->language->get('error_3d_unsuccessful'); + $message .= '<br /><strong>' . $this->language->get('text_eci') . ':</strong> (' . $eci . ') ' . $this->language->get('text_3d_s' . (int)$eci_ref); + $message .= '<br /><strong>' . $this->language->get('text_timestamp') . ':</strong> ' . (string)strftime("%Y%m%d%H%M%S"); + $message .= '<br /><strong>' . $this->language->get('text_order_ref') . ':</strong> ' . (string)$md['order_ref']; + + if ($this->config->get('payment_realex_remote_card_data_status') == 1) { + $message .= '<br /><strong>' . $this->language->get('entry_cc_type') . ':</strong> ' . (string)$md['cc_type']; + $message .= '<br /><strong>' . $this->language->get('text_last_digits') . ':</strong> ' . (string)substr($md['cc_number'], -4); + $message .= '<br /><strong>' . $this->language->get('entry_cc_expire_date') . ':</strong> ' . (string)$md['cc_expire']; + $message .= '<br /><strong>' . $this->language->get('entry_cc_name') . ':</strong> ' . (string)$md['cc_name']; + } + + $this->model_extension_payment_realex_remote->addHistory($md['order_id'], $this->config->get('payment_realex_remote_order_status_decline_id'), $message); + + $this->session->data['error'] = $this->language->get('error_3d_unsuccessful'); + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + die(); + } + } + + $capture_result = $this->model_extension_payment_realex_remote->capturePayment( + $md['account'], + $md['amount'], + $md['currency'], + $md['order_id'], + $md['order_ref'], + $md['cc_number'], + $md['cc_expire'], + $md['cc_name'], + $md['cc_type'], + $md['cc_cvv2'], + $md['cc_issue'], + $eci_ref, + $eci, + $cavv, + $xid + ); + + $this->model_extension_payment_realex_remote->logger('Capture result:\r\n' . print_r($capture_result, 1)); + + if ($capture_result->result != '00') { + $this->session->data['error'] = (string)$capture_result->message . ' (' . (int)$capture_result->result . ')'; + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } else { + $this->response->redirect($this->url->link('checkout/success')); + } + } else { + $this->response->redirect($this->url->link('account/login', '', true)); + } + } +} diff --git a/public/catalog/controller/extension/payment/sagepay_direct.php b/public/catalog/controller/extension/payment/sagepay_direct.php new file mode 100644 index 0000000..3462a1e --- /dev/null +++ b/public/catalog/controller/extension/payment/sagepay_direct.php @@ -0,0 +1,470 @@ +<?php +class ControllerExtensionPaymentSagepayDirect extends Controller { + public function index() { + $this->load->language('extension/payment/sagepay_direct'); + + if (isset($this->session->data['success'])) { + $data['success'] = $this->session->data['success']; + unset($this->session->data['success']); + } else { + $data['success'] = ''; + } + + $data['cards'] = array(); + + $data['cards'][] = array( + 'text' => 'Visa', + 'value' => 'VISA' + ); + + $data['cards'][] = array( + 'text' => 'MasterCard', + 'value' => 'MC' + ); + + $data['cards'][] = array( + 'text' => 'Visa Delta/Debit', + 'value' => 'DELTA' + ); + + $data['cards'][] = array( + 'text' => 'Solo', + 'value' => 'SOLO' + ); + + $data['cards'][] = array( + 'text' => 'Maestro', + 'value' => 'MAESTRO' + ); + + $data['cards'][] = array( + 'text' => 'Visa Electron UK Debit', + 'value' => 'UKE' + ); + + $data['cards'][] = array( + 'text' => 'American Express', + 'value' => 'AMEX' + ); + + $data['cards'][] = array( + 'text' => 'Diners Club', + 'value' => 'DC' + ); + + $data['cards'][] = array( + 'text' => 'Japan Credit Bureau', + 'value' => 'JCB' + ); + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['year_valid'] = array(); + + for ($i = $today['year'] - 10; $i < $today['year'] + 1; $i++) { + $data['year_valid'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + $data['year_expire'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['year_expire'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + if ($this->config->get('payment_sagepay_direct_card') == '1') { + $data['sagepay_direct_card'] = true; + } else { + $data['sagepay_direct_card'] = false; + } + + $data['existing_cards'] = array(); + if ($this->customer->isLogged() && $data['sagepay_direct_card']) { + $this->load->model('extension/payment/sagepay_direct'); + $data['existing_cards'] = $this->model_extension_payment_sagepay_direct->getCards($this->customer->getId()); + } + + return $this->load->view('extension/payment/sagepay_direct', $data); + } + + public function send() { + $this->load->language('extension/payment/sagepay_direct'); + $this->load->model('checkout/order'); + $this->load->model('extension/payment/sagepay_direct'); + $this->load->model('account/order'); + + $payment_data = array(); + + if ($this->config->get('payment_sagepay_direct_test') == 'live') { + $url = 'https://live.sagepay.com/gateway/service/vspdirect-register.vsp'; + $payment_data['VPSProtocol'] = '3.00'; + } elseif ($this->config->get('payment_sagepay_direct_test') == 'test') { + $url = 'https://test.sagepay.com/gateway/service/vspdirect-register.vsp'; + $payment_data['VPSProtocol'] = '3.00'; + } elseif ($this->config->get('payment_sagepay_direct_test') == 'sim') { + $url = 'https://test.sagepay.com/Simulator/VSPDirectGateway.asp'; + $payment_data['VPSProtocol'] = '2.23'; + } + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $payment_data['ReferrerID'] = 'E511AF91-E4A0-42DE-80B0-09C981A3FB61'; + $payment_data['Vendor'] = $this->config->get('payment_sagepay_direct_vendor'); + $payment_data['VendorTxCode'] = $this->session->data['order_id'] . 'SD' . strftime("%Y%m%d%H%M%S") . mt_rand(1, 999); + $payment_data['Amount'] = $this->currency->format($order_info['total'], $order_info['currency_code'], false, false); + $payment_data['Currency'] = $this->session->data['currency']; + $payment_data['Description'] = substr($this->config->get('config_name'), 0, 100); + $payment_data['TxType'] = $this->config->get('payment_sagepay_direct_transaction'); + + $payment_data['CV2'] = $this->request->post['cc_cvv2']; + + if (isset($this->request->post['Token'])) { + $payment_data['Token'] = $this->request->post['Token']; + $payment_data['StoreToken'] = 1; + } else { + $payment_data['CardHolder'] = $this->request->post['cc_owner']; + $payment_data['CardNumber'] = $this->request->post['cc_number']; + $payment_data['ExpiryDate'] = $this->request->post['cc_expire_date_month'] . substr($this->request->post['cc_expire_date_year'], 2); + $payment_data['CardType'] = $this->request->post['cc_type']; + } + + if (isset($this->request->post['CreateToken'])) { + $payment_data['CreateToken'] = $this->request->post['CreateToken']; + $payment_data['StoreToken'] = 1; + } + + $payment_data['BillingSurname'] = substr($order_info['payment_lastname'], 0, 20); + $payment_data['BillingFirstnames'] = substr($order_info['payment_firstname'], 0, 20); + $payment_data['BillingAddress1'] = substr($order_info['payment_address_1'], 0, 100); + + if ($order_info['payment_address_2']) { + $payment_data['BillingAddress2'] = $order_info['payment_address_2']; + } + + $payment_data['BillingCity'] = substr($order_info['payment_city'], 0, 40); + $payment_data['BillingPostCode'] = substr($order_info['payment_postcode'], 0, 10); + $payment_data['BillingCountry'] = $order_info['payment_iso_code_2']; + + if ($order_info['payment_iso_code_2'] == 'US') { + $payment_data['BillingState'] = $order_info['payment_zone_code']; + } + + $payment_data['BillingPhone'] = substr($order_info['telephone'], 0, 20); + + if ($this->cart->hasShipping()) { + $payment_data['DeliverySurname'] = substr($order_info['shipping_lastname'], 0, 20); + $payment_data['DeliveryFirstnames'] = substr($order_info['shipping_firstname'], 0, 20); + $payment_data['DeliveryAddress1'] = substr($order_info['shipping_address_1'], 0, 100); + + if ($order_info['shipping_address_2']) { + $payment_data['DeliveryAddress2'] = $order_info['shipping_address_2']; + } + + $payment_data['DeliveryCity'] = substr($order_info['shipping_city'], 0, 40); + $payment_data['DeliveryPostCode'] = substr($order_info['shipping_postcode'], 0, 10); + $payment_data['DeliveryCountry'] = $order_info['shipping_iso_code_2']; + + if ($order_info['shipping_iso_code_2'] == 'US') { + $payment_data['DeliveryState'] = $order_info['shipping_zone_code']; + } + + $payment_data['CustomerName'] = substr($order_info['firstname'] . ' ' . $order_info['lastname'], 0, 100); + $payment_data['DeliveryPhone'] = substr($order_info['telephone'], 0, 20); + } else { + $payment_data['DeliveryFirstnames'] = $order_info['payment_firstname']; + $payment_data['DeliverySurname'] = $order_info['payment_lastname']; + $payment_data['DeliveryAddress1'] = $order_info['payment_address_1']; + + if ($order_info['payment_address_2']) { + $payment_data['DeliveryAddress2'] = $order_info['payment_address_2']; + } + + $payment_data['DeliveryCity'] = $order_info['payment_city']; + $payment_data['DeliveryPostCode'] = $order_info['payment_postcode']; + $payment_data['DeliveryCountry'] = $order_info['payment_iso_code_2']; + + if ($order_info['payment_iso_code_2'] == 'US') { + $payment_data['DeliveryState'] = $order_info['payment_zone_code']; + } + + $payment_data['DeliveryPhone'] = $order_info['telephone']; + } + + $order_products = $this->model_account_order->getOrderProducts($this->session->data['order_id']); + $cart_rows = 0; + $str_basket = ""; + foreach ($order_products as $product) { + $str_basket .= + ":" . str_replace(":", " ", $product['name'] . " " . $product['model']) . + ":" . $product['quantity'] . + ":" . $this->currency->format($product['price'], $order_info['currency_code'], false, false) . + ":" . $this->currency->format($product['tax'], $order_info['currency_code'], false, false) . + ":" . $this->currency->format(($product['price'] + $product['tax']), $order_info['currency_code'], false, false) . + ":" . $this->currency->format(($product['price'] + $product['tax']) * $product['quantity'], $order_info['currency_code'], false, false); + $cart_rows++; + } + + $order_totals = $this->model_account_order->getOrderTotals($this->session->data['order_id']); + foreach ($order_totals as $total) { + $str_basket .= ":" . str_replace(":", " ", $total['title']) . ":::::" . $this->currency->format($total['value'], $order_info['currency_code'], false, false); + $cart_rows++; + } + $str_basket = $cart_rows . $str_basket; + + $payment_data['Basket'] = $str_basket; + + $payment_data['CustomerEMail'] = substr($order_info['email'], 0, 255); + $payment_data['Apply3DSecure'] = '0'; + + $response_data = $this->model_extension_payment_sagepay_direct->sendCurl($url, $payment_data); + + $json = array(); + + if ($response_data['Status'] == '3DAUTH') { + $json['ACSURL'] = $response_data['ACSURL']; + $json['MD'] = $response_data['MD']; + $json['PaReq'] = $response_data['PAReq']; + + $response_data['VPSTxId'] = ''; + $response_data['SecurityKey'] = ''; + $response_data['TxAuthNo'] = ''; + + $card_id = ''; + if (!empty($payment_data['CreateToken']) && $this->customer->isLogged()) { + $card_data = array(); + $card_data['customer_id'] = $this->customer->getId(); + $card_data['Token'] = ''; + $card_data['Last4Digits'] = substr(str_replace(' ', '', $payment_data['CardNumber']), -4, 4); + $card_data['ExpiryDate'] = $this->request->post['cc_expire_date_month'] . '/' . substr($this->request->post['cc_expire_date_year'], 2); + $card_data['CardType'] = $payment_data['CardType']; + $card_id = $this->model_extension_payment_sagepay_direct->addCard($card_data); + } elseif (isset($payment_data['Token'])) { + $card = $this->model_extension_payment_sagepay_direct->getCard(false, $payment_data['Token']); + $card_id = $card['card_id']; + } + + $this->model_extension_payment_sagepay_direct->addOrder($this->session->data['order_id'], $response_data, $payment_data, $card_id); + $this->model_extension_payment_sagepay_direct->logger('Response data', $response_data); + $this->model_extension_payment_sagepay_direct->logger('$payment_data', $payment_data); + $this->model_extension_payment_sagepay_direct->logger('order_id', $this->session->data['order_id']); + + $json['TermUrl'] = $this->url->link('extension/payment/sagepay_direct/callback', '', true); + } elseif ($response_data['Status'] == 'OK' || $response_data['Status'] == 'AUTHENTICATED' || $response_data['Status'] == 'REGISTERED') { + $message = ''; + + if (isset($response_data['TxAuthNo'])) { + $message .= 'TxAuthNo: ' . $response_data['TxAuthNo'] . "\n"; + } else { + $response_data['TxAuthNo'] = ''; + } + + if (isset($response_data['AVSCV2'])) { + $message .= 'AVSCV2: ' . $response_data['AVSCV2'] . "\n"; + } + + if (isset($response_data['AddressResult'])) { + $message .= 'AddressResult: ' . $response_data['AddressResult'] . "\n"; + } + + if (isset($response_data['PostCodeResult'])) { + $message .= 'PostCodeResult: ' . $response_data['PostCodeResult'] . "\n"; + } + + if (isset($response_data['CV2Result'])) { + $message .= 'CV2Result: ' . $response_data['CV2Result'] . "\n"; + } + + if (isset($response_data['3DSecureStatus'])) { + $message .= '3DSecureStatus: ' . $response_data['3DSecureStatus'] . "\n"; + } + + if (isset($response_data['CAVV'])) { + $message .= 'CAVV: ' . $response_data['CAVV'] . "\n"; + } + + $card_id = ''; + if (!empty($payment_data['CreateToken']) && !empty($response_data['Token']) && $this->customer->isLogged()) { + $card_data = array(); + $card_data['customer_id'] = $this->customer->getId(); + $card_data['Token'] = $response_data['Token']; + $card_data['Last4Digits'] = substr(str_replace(' ', '', $payment_data['CardNumber']), -4, 4); + $card_data['ExpiryDate'] = $this->request->post['cc_expire_date_month'] . '/' . substr($this->request->post['cc_expire_date_year'], 2); + $card_data['CardType'] = $payment_data['CardType']; + $card_id = $this->model_extension_payment_sagepay_direct->addCard($card_data); + } elseif (isset($payment_data['Token'])) { + $card = $this->model_extension_payment_sagepay_direct->getCard(false, $payment_data['Token']); + $card_id = $card['card_id']; + } + + $sagepay_direct_order_id = $this->model_extension_payment_sagepay_direct->addOrder($order_info['order_id'], $response_data, $payment_data, $card_id); + $this->model_extension_payment_sagepay_direct->logger('Response data', $response_data); + $this->model_extension_payment_sagepay_direct->logger('$payment_data', $payment_data); + $this->model_extension_payment_sagepay_direct->logger('order_id', $this->session->data['order_id']); + + $this->model_extension_payment_sagepay_direct->addTransaction($sagepay_direct_order_id, $this->config->get('payment_sagepay_direct_transaction'), $order_info); + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_sagepay_direct_order_status_id'), $message, false); + + if ($this->config->get('payment_sagepay_direct_transaction') == 'PAYMENT') { + $recurring_products = $this->cart->getRecurringProducts(); + //loop through any products that are recurring items + foreach ($recurring_products as $item) { + $this->model_extension_payment_sagepay_direct->recurringPayment($item, $payment_data['VendorTxCode']); + } + } + + $json['redirect'] = $this->url->link('checkout/success', '', true); + } else { + $json['error'] = $response_data['Status'] . ': ' . $response_data['StatusDetail']; + $this->model_extension_payment_sagepay_direct->logger('Response data', $json['error']); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function callback() { + $this->load->model('extension/payment/sagepay_direct'); + $this->load->language('extension/payment/sagepay_direct'); + $this->load->model('checkout/order'); + + if (isset($this->session->data['order_id'])) { + if ($this->config->get('payment_sagepay_direct_test') == 'live') { + $url = 'https://live.sagepay.com/gateway/service/direct3dcallback.vsp'; + } elseif ($this->config->get('payment_sagepay_direct_test') == 'test') { + $url = 'https://test.sagepay.com/gateway/service/direct3dcallback.vsp'; + } elseif ($this->config->get('payment_sagepay_direct_test') == 'sim') { + $url = 'https://test.sagepay.com/Simulator/VSPDirectCallback.asp'; + } + + $response_data = $this->model_extension_payment_sagepay_direct->sendCurl($url, $this->request->post); + $this->model_extension_payment_sagepay_direct->logger('$response_data', $response_data); + + if ($response_data['Status'] == 'OK' || $response_data['Status'] == 'AUTHENTICATED' || $response_data['Status'] == 'REGISTERED') { + $message = ''; + + if (isset($response_data['TxAuthNo'])) { + $message .= 'TxAuthNo: ' . $response_data['TxAuthNo'] . "\n"; + } else { + $response_data['TxAuthNo'] = ''; + } + + if (isset($response_data['AVSCV2'])) { + $message .= 'AVSCV2: ' . $response_data['AVSCV2'] . "\n"; + } + + if (isset($response_data['AddressResult'])) { + $message .= 'AddressResult: ' . $response_data['AddressResult'] . "\n"; + } + + if (isset($response_data['PostCodeResult'])) { + $message .= 'PostCodeResult: ' . $response_data['PostCodeResult'] . "\n"; + } + + if (isset($response_data['CV2Result'])) { + $message .= 'CV2Result: ' . $response_data['CV2Result'] . "\n"; + } + + if (isset($response_data['3DSecureStatus'])) { + $message .= '3DSecureStatus: ' . $response_data['3DSecureStatus'] . "\n"; + } + + if (isset($response_data['CAVV'])) { + $message .= 'CAVV: ' . $response_data['CAVV'] . "\n"; + } + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + $sagepay_order_info = $this->model_extension_payment_sagepay_direct->getOrder($this->session->data['order_id']); + + $this->model_extension_payment_sagepay_direct->logger('$order_info', $order_info); + $this->model_extension_payment_sagepay_direct->logger('$sagepay_order_info', $sagepay_order_info); + + $this->model_extension_payment_sagepay_direct->updateOrder($order_info, $response_data); + $this->model_extension_payment_sagepay_direct->addTransaction($sagepay_order_info['sagepay_direct_order_id'], $this->config->get('payment_sagepay_direct_transaction'), $order_info); + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_sagepay_direct_order_status_id'), $message, false); + + if (!empty($response_data['Token']) && $this->customer->isLogged()) { + $this->model_extension_payment_sagepay_direct->updateCard($sagepay_order_info['card_id'], $response_data['Token']); + } else { + $this->model_extension_payment_sagepay_direct->deleteCard($sagepay_order_info['card_id']); + } + + if ($this->config->get('payment_sagepay_direct_transaction') == 'PAYMENT') { + $recurring_products = $this->cart->getRecurringProducts(); + //loop through any products that are recurring items + foreach ($recurring_products as $item) { + $this->model_extension_payment_sagepay_direct->recurringPayment($item, $sagepay_order_info['VendorTxCode']); + } + } + + $this->response->redirect($this->url->link('checkout/success', '', true)); + } else { + $this->session->data['error'] = $response_data['StatusDetail']; + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + } else { + $this->response->redirect($this->url->link('account/login', '', true)); + } + } + + public function delete() { + + $this->load->language('account/sagepay_direct_cards'); + + $this->load->model('extension/payment/sagepay_direct'); + + $card = $this->model_extension_payment_sagepay_direct->getCard(false, $this->request->post['Token']); + + if (!empty($card['token'])) { + if ($this->config->get('payment_sagepay_direct_test') == 'live') { + $url = 'https://live.sagepay.com/gateway/service/removetoken.vsp'; + } else { + $url = 'https://test.sagepay.com/gateway/service/removetoken.vsp'; + } + $payment_data['VPSProtocol'] = '3.00'; + $payment_data['Vendor'] = $this->config->get('payment_sagepay_direct_vendor'); + $payment_data['TxType'] = 'REMOVETOKEN'; + $payment_data['Token'] = $card['token']; + + $response_data = $this->model_extension_payment_sagepay_direct->sendCurl($url, $payment_data); + if ($response_data['Status'] == 'OK') { + $this->model_extension_payment_sagepay_direct->deleteCard($card['card_id']); + $this->session->data['success'] = $this->language->get('text_success_card'); + $json['success'] = true; + } else { + $json['error'] = $this->language->get('text_fail_card'); + } + } else { + $json['error'] = $this->language->get('text_fail_card'); + } + $this->response->setOutput(json_encode($json)); + } + + public function cron() { + if (isset($this->request->get['token']) && hash_equals($this->config->get('payment_sagepay_direct_cron_job_token'), $this->request->get['token'])) { + $this->load->model('extension/payment/sagepay_direct'); + + $orders = $this->model_extension_payment_sagepay_direct->cronPayment(); + + $this->model_extension_payment_sagepay_direct->updateCronJobRunTime(); + + $this->model_extension_payment_sagepay_direct->logger('Repeat Orders', $orders); + } + } + +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/sagepay_server.php b/public/catalog/controller/extension/payment/sagepay_server.php new file mode 100644 index 0000000..9f886a2 --- /dev/null +++ b/public/catalog/controller/extension/payment/sagepay_server.php @@ -0,0 +1,503 @@ +<?php +class ControllerExtensionPaymentSagepayServer extends Controller { + public function index() { + $this->load->language('extension/payment/sagepay_server'); + $data['text_credit_card'] = $this->language->get('text_credit_card'); + $data['text_card_name'] = $this->language->get('text_card_name'); + $data['text_card_type'] = $this->language->get('text_card_type'); + $data['text_card_digits'] = $this->language->get('text_card_digits'); + $data['text_card_expiry'] = $this->language->get('text_card_expiry'); + $data['text_loading'] = $this->language->get('text_loading'); + $data['text_confirm_delete'] = $this->language->get('text_confirm_delete'); + + $data['entry_card'] = $this->language->get('entry_card'); + $data['entry_card_existing'] = $this->language->get('entry_card_existing'); + $data['entry_card_new'] = $this->language->get('entry_card_new'); + $data['entry_card_save'] = $this->language->get('entry_card_save'); + $data['entry_cc_choice'] = $this->language->get('entry_cc_choice'); + + $data['button_confirm'] = $this->language->get('button_confirm'); + $data['button_delete_card'] = $this->language->get('button_delete_card'); + + $data['action'] = $this->url->link('extension/payment/sagepay_server/send', '', true); + + if ($this->config->get('payment_sagepay_server_card') == '1') { + $data['sagepay_server_card'] = true; + } else { + $data['sagepay_server_card'] = false; + } + + $data['cards'] = array(); + + if ($this->customer->isLogged() && $data['sagepay_server_card']) { + $this->load->model('extension/payment/sagepay_server'); + + $data['cards'] = $this->model_extension_payment_sagepay_server->getCards($this->customer->getId()); + } + + return $this->load->view('extension/payment/sagepay_server', $data); + } + + public function send() { + + $payment_data = array(); + + if ($this->config->get('payment_sagepay_server_test') == 'live') { + $url = 'https://live.sagepay.com/gateway/service/vspserver-register.vsp'; + + $payment_data['VPSProtocol'] = '3.00'; + } elseif ($this->config->get('payment_sagepay_server_test') == 'test') { + $url = 'https://test.sagepay.com/gateway/service/vspserver-register.vsp'; + + $payment_data['VPSProtocol'] = '3.00'; + } elseif ($this->config->get('payment_sagepay_server_test') == 'sim') { + $url = 'https://test.sagepay.com/Simulator/VSPServerGateway.asp?Service=VendorRegisterTx'; + + $payment_data['VPSProtocol'] = '2.23'; + } + + $this->load->model('checkout/order'); + $this->load->model('extension/payment/sagepay_server'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $payment_data['ReferrerID'] = 'E511AF91-E4A0-42DE-80B0-09C981A3FB61'; + $payment_data['Vendor'] = $this->config->get('payment_sagepay_server_vendor'); + $payment_data['VendorTxCode'] = $this->session->data['order_id'] . 'T' . strftime("%Y%m%d%H%M%S") . mt_rand(1, 999); + $payment_data['Amount'] = $this->currency->format($order_info['total'], $order_info['currency_code'], false, false); + $payment_data['Currency'] = $this->session->data['currency']; + $payment_data['Description'] = substr($this->config->get('config_name'), 0, 100); + $payment_data['NotificationURL'] = $this->url->link('extension/payment/sagepay_server/callback', '', true); + $payment_data['TxType'] = $this->config->get('payment_sagepay_server_transaction'); + + $payment_data['BillingSurname'] = substr($order_info['payment_lastname'], 0, 20); + $payment_data['BillingFirstnames'] = substr($order_info['payment_firstname'], 0, 20); + $payment_data['BillingAddress1'] = substr($order_info['payment_address_1'], 0, 100); + + if ($order_info['payment_address_2']) { + $payment_data['BillingAddress2'] = $order_info['payment_address_2']; + } + + $payment_data['BillingCity'] = substr($order_info['payment_city'], 0, 40); + $payment_data['BillingPostCode'] = substr($order_info['payment_postcode'], 0, 10); + $payment_data['BillingCountry'] = $order_info['payment_iso_code_2']; + + if ($order_info['payment_iso_code_2'] == 'US') { + $payment_data['BillingState'] = $order_info['payment_zone_code']; + } + + $payment_data['BillingPhone'] = substr($order_info['telephone'], 0, 20); + + if ($this->cart->hasShipping()) { + $payment_data['DeliverySurname'] = substr($order_info['shipping_lastname'], 0, 20); + $payment_data['DeliveryFirstnames'] = substr($order_info['shipping_firstname'], 0, 20); + $payment_data['DeliveryAddress1'] = substr($order_info['shipping_address_1'], 0, 100); + + if ($order_info['shipping_address_2']) { + $payment_data['DeliveryAddress2'] = $order_info['shipping_address_2']; + } + + $payment_data['DeliveryCity'] = substr($order_info['shipping_city'], 0, 40); + $payment_data['DeliveryPostCode'] = substr($order_info['shipping_postcode'], 0, 10); + $payment_data['DeliveryCountry'] = $order_info['shipping_iso_code_2']; + + if ($order_info['shipping_iso_code_2'] == 'US') { + $payment_data['DeliveryState'] = $order_info['shipping_zone_code']; + } + + $payment_data['CustomerName'] = substr($order_info['firstname'] . ' ' . $order_info['lastname'], 0, 100); + $payment_data['DeliveryPhone'] = substr($order_info['telephone'], 0, 20); + } else { + $payment_data['DeliveryFirstnames'] = $order_info['payment_firstname']; + $payment_data['DeliverySurname'] = $order_info['payment_lastname']; + $payment_data['DeliveryAddress1'] = $order_info['payment_address_1']; + + if ($order_info['payment_address_2']) { + $payment_data['DeliveryAddress2'] = $order_info['payment_address_2']; + } + + $payment_data['DeliveryCity'] = $order_info['payment_city']; + $payment_data['DeliveryPostCode'] = $order_info['payment_postcode']; + $payment_data['DeliveryCountry'] = $order_info['payment_iso_code_2']; + + if ($order_info['payment_iso_code_2'] == 'US') { + $payment_data['DeliveryState'] = $order_info['payment_zone_code']; + } + + $payment_data['DeliveryPhone'] = $order_info['telephone']; + } + + $order_products = $this->model_checkout_order->getOrderProducts($this->session->data['order_id']); + $cart_rows = 0; + $str_basket = ""; + foreach ($order_products as $product) { + $str_basket .= + ":" . str_replace(":", " ", $product['name'] . " " . $product['model']) . + ":" . $product['quantity'] . + ":" . $this->currency->format($product['price'], $order_info['currency_code'], false, false) . + ":" . $this->currency->format($product['tax'], $order_info['currency_code'], false, false) . + ":" . $this->currency->format(($product['price'] + $product['tax']), $order_info['currency_code'], false, false) . + ":" . $this->currency->format(($product['price'] + $product['tax']) * $product['quantity'], $order_info['currency_code'], false, false); + $cart_rows++; + } + + $order_totals = $this->model_checkout_order->getOrderTotals($this->session->data['order_id']); + + foreach ($order_totals as $total) { + $str_basket .= ":" . str_replace(":", " ", $total['title']) . ":::::" . $this->currency->format($total['value'], $order_info['currency_code'], false, false); + $cart_rows++; + } + + $str_basket = $cart_rows . $str_basket; + + $payment_data['Basket'] = $str_basket; + + $payment_data['CustomerEMail'] = substr($order_info['email'], 0, 255); + $payment_data['Apply3DSecure'] = '0'; + + if (isset($this->request->post['CreateToken'])) { + $payment_data['CreateToken'] = $this->request->post['CreateToken']; + $payment_data['StoreToken'] = 1; + } + + if (isset($this->request->post['Token'])) { + $payment_data['Token'] = $this->request->post['Token']; + $payment_data['StoreToken'] = 1; + } + + $response_data = $this->model_extension_payment_sagepay_server->sendCurl($url, $payment_data); + + $json = array(); + + if ((substr($response_data['Status'], 0, 2) == "OK") || $response_data['Status'] == 'AUTHENTICATED' || $response_data['Status'] == 'REGISTERED') { + $json['redirect'] = $response_data['NextURL']; + $json['Status'] = $response_data['Status']; + $json['StatusDetail'] = $response_data['StatusDetail']; + + $response_data['order_id'] = $this->session->data['order_id']; + $response_data['VendorTxCode'] = $payment_data['VendorTxCode']; + + $order_info = array_merge($order_info, $response_data); + + $this->model_extension_payment_sagepay_server->addOrder($order_info); + + if ($this->config->get('payment_sagepay_server_transaction') == 'PAYMENT') { + $recurring_products = $this->cart->getRecurringProducts(); + + //loop through any products that are recurring items + foreach ($recurring_products as $item) { + $this->model_extension_payment_sagepay_server->addRecurringPayment($item, $payment_data['VendorTxCode']); + } + } + } else { + $json['error'] = $response_data['StatusDetail']; + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function callback() { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/sagepay_server'); + + $success_page = $this->url->link('extension/payment/sagepay_server/success', '', true); + $error_page = $this->url->link('extension/payment/sagepay_server/failure', '', true); + $end_ln = chr(13) . chr(10); + + if (isset($this->request->post['VendorTxCode'])) { + $vendor_tx_code = $this->request->post['VendorTxCode']; + $order_id_parts = explode('T', $this->request->post['VendorTxCode']); + $order_id = (int)$order_id_parts[0]; + } else { + $vendor_tx_code = ''; + $order_id = ''; + } + + if (isset($this->request->post['Status'])) { + $str_status = $this->request->post['Status']; + } else { + $str_status = ''; + } + + if (isset($this->request->post['VPSSignature'])) { + $str_vps_signature = $this->request->post['VPSSignature']; + } else { + $str_vps_signature = ''; + } + if (isset($this->request->post['StatusDetail'])) { + $str_status_detail = $this->request->post['StatusDetail']; + } else { + $str_status_detail = ''; + } + + if (isset($this->request->post['VPSTxId'])) { + $str_vps_tx_id = $this->request->post['VPSTxId']; + } else { + $str_vps_tx_id = ''; + } + + if (isset($this->request->post['TxAuthNo'])) { + $str_tx_auth_no = $this->request->post['TxAuthNo']; + } else { + $str_tx_auth_no = ''; + } + + if (isset($this->request->post['AVSCV2'])) { + $str_avs_cv2 = $this->request->post['AVSCV2']; + } else { + $str_avs_cv2 = ''; + } + + if (isset($this->request->post['AddressResult'])) { + $str_address_result = $this->request->post['AddressResult']; + } else { + $str_address_result = ''; + } + + if (isset($this->request->post['PostCodeResult'])) { + $str_postcode_result = $this->request->post['PostCodeResult']; + } else { + $str_postcode_result = ''; + } + + if (isset($this->request->post['CV2Result'])) { + $str_cv2_result = $this->request->post['CV2Result']; + } else { + $str_cv2_result = ''; + } + + if (isset($this->request->post['GiftAid'])) { + $str_gift_aid = $this->request->post['GiftAid']; + } else { + $str_gift_aid = ''; + } + + if (isset($this->request->post['3DSecureStatus'])) { + $str_3d_secure_status = $this->request->post['3DSecureStatus']; + } else { + $str_3d_secure_status = ''; + } + + if (isset($this->request->post['CAVV'])) { + $str_cavv = $this->request->post['CAVV']; + } else { + $str_cavv = ''; + } + + if (isset($this->request->post['AddressStatus'])) { + $str_address_status = $this->request->post['AddressStatus']; + } else { + $str_address_status = ''; + } + + if (isset($this->request->post['PayerStatus'])) { + $str_payer_status = $this->request->post['PayerStatus']; + } else { + $str_payer_status = ''; + } + + if (isset($this->request->post['CardType'])) { + $str_card_type = $this->request->post['CardType']; + } else { + $str_card_type = ''; + } + + if (isset($this->request->post['Last4Digits'])) { + $str_last_4_digits = $this->request->post['Last4Digits']; + } else { + $str_last_4_digits = ''; + } + + if (isset($this->request->post['ExpiryDate'])) { + $str_expiry_date = $this->request->post['ExpiryDate']; + } else { + $str_expiry_date = ''; + } + + if (isset($this->request->post['Token'])) { + $str_token = $this->request->post['Token']; + } else { + $str_token = ''; + } + + if (isset($this->request->post['DeclineCode'])) { + $str_decline_code = $this->request->post['DeclineCode']; + } else { + $str_decline_code = ''; + } + + if (isset($this->request->post['BankAuthCode'])) { + $str_bank_auth_code = $this->request->post['BankAuthCode']; + } else { + $str_bank_auth_code = ''; + } + + $order_info = $this->model_checkout_order->getOrder($order_id); + + $transaction_info = $this->model_extension_payment_sagepay_server->getOrder($order_id); + + $this->model_extension_payment_sagepay_server->logger('$order_id', $order_id); + $this->model_extension_payment_sagepay_server->logger('$order_info', $order_info); + $this->model_extension_payment_sagepay_server->logger('$transaction_info', $transaction_info); + $this->model_extension_payment_sagepay_server->logger('$strStatus', $str_status); + + //Check if order we have saved in database maches with callback sagepay does + if (!isset($transaction_info['order_id']) || $transaction_info['order_id'] != $order_id) { + echo "Status=INVALID" . $end_ln; + echo "StatusDetail= Order IDs could not be matched. Order might be tampered with." . $end_ln; + echo "RedirectURL=" . $error_page . $end_ln; + + $this->model_extension_payment_sagepay_server->logger('StatusDetail', 'Order IDs could not be matched. Order might be tampered with'); + + exit; + } + + if (isset($transaction_info['SecurityKey'])) { + $str_security_key = $transaction_info['SecurityKey']; + } else { + $str_security_key = ''; + } + + /** Now we rebuilt the POST message, including our security key, and use the MD5 Hash ** + * * component that is included to create our own signature to compare with ** + * * the contents of the VPSSignature field in the POST. Check the Sage Pay Server protocol ** + * * if you need clarification on this process * */ + $str_message = $str_vps_tx_id . $vendor_tx_code . $str_status . $str_tx_auth_no . $this->config->get('payment_sagepay_server_vendor') . urldecode($str_avs_cv2) . $str_security_key + . $str_address_result . $str_postcode_result . $str_cv2_result . $str_gift_aid . $str_3d_secure_status . $str_cavv + . $str_address_status . $str_payer_status . $str_card_type . $str_last_4_digits . $str_decline_code . $str_expiry_date . $str_bank_auth_code; + + $str_my_signature = strtoupper(md5($str_message)); + + /** We can now compare our MD5 Hash signature with that from Sage Pay Server * */ + if ($str_my_signature != $str_vps_signature) { + $this->model_extension_payment_sagepay_server->deleteOrder($order_id); + + echo "Status=INVALID" . $end_ln; + echo "StatusDetail= Cannot match the MD5 Hash. Order might be tampered with." . $end_ln; + echo "RedirectURL=" . $error_page . $end_ln; + + $this->model_extension_payment_sagepay_server->logger('StatusDetail', 'Cannot match the MD5 Hash. Order might be tampered with'); + exit; + } + + if (($str_status != "OK" && $str_status != "REGISTERED" && $str_status != "AUTHENTICATED") || !$order_info) { + $this->model_extension_payment_sagepay_server->deleteOrder($order_id); + + echo "Status=INVALID" . $end_ln; + echo "StatusDetail= Either status invalid or order info was not found."; + echo "RedirectURL=" . $error_page . $end_ln; + + $this->model_extension_payment_sagepay_server->logger('StatusDetail', 'Either status invalid or order info was not found'); + exit; + } + + $comment = "Paid with Sagepay Server<br><br>"; + $comment .= "<b>Transaction details</b><br>"; + $comment .= "Status: " . $str_status . "<br>"; + $comment .= "AVS and CV2 checks: " . $str_avs_cv2 . "<br>"; + $comment .= "3D Secure checks: " . $str_3d_secure_status . "<br>"; + $comment .= "Card type: " . $str_card_type . "<br>"; + + if ($str_card_type == "PAYPAL") { + $comment .= "Paypal address status: " . $str_address_status . "<br>"; + $comment .= "Paypal payer status: " . $str_payer_status . "<br>"; + } + $comment .= "Last 4 digits: " . $str_last_4_digits . "<br>"; + + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_sagepay_server_order_status_id'), $comment); + + $this->model_extension_payment_sagepay_server->updateOrder($order_info, $str_vps_tx_id, $str_tx_auth_no); + + $this->model_extension_payment_sagepay_server->addTransaction($transaction_info['sagepay_server_order_id'], $this->config->get('payment_sagepay_server_transaction'), $order_info); + + if (!empty($str_token)) { + $data['customer_id'] = $order_info['customer_id']; + $data['ExpiryDate'] = substr($str_expiry_date, -4, 2) . '/' . substr($str_expiry_date, 2); + $data['Token'] = $str_token; + $data['CardType'] = $str_card_type; + $data['Last4Digits'] = $str_last_4_digits; + + $this->model_extension_payment_sagepay_server->addCard($data); + } + + echo "Status=OK" . $end_ln; + echo "RedirectURL=" . $success_page . $end_ln; + } + + public function success() { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/sagepay_server'); + $this->load->model('checkout/recurring'); + + if (isset($this->session->data['order_id'])) { + $order_details = $this->model_extension_payment_sagepay_server->getOrder($this->session->data['order_id']); + + if ($this->config->get('payment_sagepay_server_transaction') == 'PAYMENT') { + $recurring_products = $this->model_extension_payment_sagepay_server->getRecurringOrders($this->session->data['order_id']); + + //loop through any products that are recurring items + foreach ($recurring_products as $item) { + $this->model_extension_payment_sagepay_server->updateRecurringPayment($item, $order_details); + } + } + + $this->response->redirect($this->url->link('checkout/success', '', true)); + } else { + $this->response->redirect($this->url->link('account/login', '', true)); + } + } + + public function failure() { + $this->load->language('extension/payment/sagepay_server'); + + $this->session->data['error'] = $this->language->get('text_generic_error'); + + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + + public function delete() { + $this->load->language('account/sagepay_server_cards'); + + $this->load->model('extension/payment/sagepay_server'); + + $card = $this->model_extension_payment_sagepay_server->getCard(false, $this->request->post['Token']); + + if (!empty($card['token'])) { + if ($this->config->get('payment_sagepay_server_test') == 'live') { + $url = 'https://live.sagepay.com/gateway/service/removetoken.vsp'; + } else { + $url = 'https://test.sagepay.com/gateway/service/removetoken.vsp'; + } + $payment_data['VPSProtocol'] = '3.00'; + $payment_data['Vendor'] = $this->config->get('payment_sagepay_server_vendor'); + $payment_data['TxType'] = 'REMOVETOKEN'; + $payment_data['Token'] = $card['token']; + + $response_data = $this->model_extension_payment_sagepay_server->sendCurl($url, $payment_data); + if ($response_data['Status'] == 'OK') { + $this->model_extension_payment_sagepay_server->deleteCard($card['card_id']); + $this->session->data['success'] = $this->language->get('text_success_card'); + $json['success'] = true; + } else { + $json['error'] = $this->language->get('text_fail_card'); + } + } else { + $json['error'] = $this->language->get('text_fail_card'); + } + $this->response->setOutput(json_encode($json)); + } + + public function cron() { + if (isset($this->request->get['token']) && hash_equals($this->config->get('payment_sagepay_server_cron_job_token'), $this->request->get['token'])) { + $this->load->model('extension/payment/sagepay_server'); + + $orders = $this->model_extension_payment_sagepay_server->cronPayment(); + + $this->model_extension_payment_sagepay_server->updateCronJobRunTime(); + + $this->model_extension_payment_sagepay_server->logger('Repeat Orders', $orders); + } + } + +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/sagepay_us.php b/public/catalog/controller/extension/payment/sagepay_us.php new file mode 100644 index 0000000..366ddf1 --- /dev/null +++ b/public/catalog/controller/extension/payment/sagepay_us.php @@ -0,0 +1,95 @@ +<?php +class ControllerExtensionPaymentSagepayUS extends Controller { + public function index() { + $this->load->language('extension/payment/sagepay_us'); + + $data['text_credit_card'] = $this->language->get('text_credit_card'); + $data['text_loading'] = $this->language->get('text_loading'); + + $data['entry_cc_owner'] = $this->language->get('entry_cc_owner'); + $data['entry_cc_number'] = $this->language->get('entry_cc_number'); + $data['entry_cc_expire_date'] = $this->language->get('entry_cc_expire_date'); + $data['entry_cc_cvv2'] = $this->language->get('entry_cc_cvv2'); + + $data['button_confirm'] = $this->language->get('button_confirm'); + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['year_expire'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['year_expire'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + return $this->load->view('extension/payment/sagepay_us', $data); + } + + public function send() { + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $url = 'https://www.sagepayments.net/cgi-bin/eftbankcard.dll?transaction'; + + $data = 'm_id=' . $this->config->get('payment_sagepay_us_merchant_id'); + $data .= '&m_key=' . $this->config->get('payment_sagepay_us_merchant_key'); + $data .= '&T_amt=' . urlencode($this->currency->format($order_info['total'], $order_info['currency_code'], 1.00000, false)); + $data .= '&T_ordernum=' . $this->session->data['order_id']; + $data .= '&C_name=' . urlencode($this->request->post['cc_owner']); + $data .= '&C_address=' . urlencode($order_info['payment_address_1']); + $data .= '&C_state=' . urlencode($order_info['payment_zone']); + $data .= '&C_city=' . urlencode($order_info['payment_city']); + $data .= '&C_cardnumber=' . urlencode($this->request->post['cc_number']); + $data .= '&C_exp=' . urlencode($this->request->post['cc_expire_date_month'] . substr($this->request->post['cc_expire_date_year'], '2')); + $data .= '&C_cvv=' . urlencode($this->request->post['cc_cvv2']); + $data .= '&C_zip=' . urlencode($order_info['payment_postcode']); + $data .= '&C_email=' . urlencode($order_info['email']); + $data .= '&T_code=02'; + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + + $response = curl_exec($ch); + + curl_close($ch); + + $json = array(); + + if ($response[1] == 'A') { + $message = 'Approval Indicator: ' . $response[1] . "\n"; + $message .= 'Approval/Error Code: ' . substr($response, 2, 6) . "\n"; + $message .= 'Approval/Error Message: ' . substr($response, 8, 32) . "\n"; + $message .= 'Front-End Indicator: ' . substr($response, 40, 2) . "\n"; + $message .= 'CVV Indicator: ' . $response[42] . "\n"; + $message .= 'AVS Indicator: ' . $response[43] . "\n"; + $message .= 'Risk Indicator: ' . substr($response, 44, 2) . "\n"; + $message .= 'Reference: ' . substr($response, 46, 10) . "\n"; + $message .= 'Order Number: ' . substr($response, strpos($response, chr(28)) + 1, strrpos($response, chr(28) - 1)) . "\n"; + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_sagepay_us_order_status_id'), $message, false); + + $json['redirect'] = $this->url->link('checkout/success'); + } else { + $json['error'] = substr($response, 8, 32); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/securetrading_pp.php b/public/catalog/controller/extension/payment/securetrading_pp.php new file mode 100644 index 0000000..823a161 --- /dev/null +++ b/public/catalog/controller/extension/payment/securetrading_pp.php @@ -0,0 +1,170 @@ +<?php +class ControllerExtensionPaymentSecureTradingPp extends Controller { + public function index() { + $this->load->model('checkout/order'); + $this->load->model('localisation/country'); + $this->load->model('localisation/zone'); + $this->load->language('extension/payment/securetrading_pp'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if ($order_info) { + $data['order_info'] = $order_info; + $data['site_reference'] = $this->config->get('payment_securetrading_pp_site_reference'); + $data['parent_css'] = $this->config->get('payment_securetrading_pp_parent_css'); + $data['child_css'] = $this->config->get('payment_securetrading_pp_child_css'); + $data['currency'] = $order_info['currency_code']; + $data['total'] = $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false); + $data['settle_due_date'] = date('Y-m-d', strtotime(date('Y-m-d') . ' +' . $this->config->get('payment_securetrading_pp_settle_due_date') . ' days')); + $data['settle_status'] = $this->config->get('payment_securetrading_pp_settle_status'); + + $payment_country = $this->model_localisation_country->getCountry($order_info['payment_country_id']); + $payment_zone = $this->model_localisation_zone->getZone($order_info['payment_zone_id']); + + $shipping_country = $this->model_localisation_country->getCountry($order_info['shipping_country_id']); + $shipping_zone = $this->model_localisation_zone->getZone($order_info['shipping_zone_id']); + + if ($payment_country['iso_code_3'] == 'USA') { + $data['billing_county'] = $payment_zone['code']; + } else { + $data['billing_county'] = $order_info['payment_zone']; + } + + if (isset($shipping_country['iso_code_3']) && $shipping_country['iso_code_3'] == 'USA') { + $data['shipping_county'] = $shipping_zone['code']; + } else { + $data['shipping_county'] = $order_info['shipping_zone']; + } + + if (!isset($shipping_country['iso_code_2'])) { + $shipping_country['iso_code_2'] = $payment_country['iso_code_2']; + } + + $data['payment_country'] = $payment_country; + $data['shipping_country'] = $shipping_country; + + if ($this->config->get('payment_securetrading_pp_site_security_status')) { + $data['site_security'] = hash('sha256', $order_info['currency_code'] . $data['total'] . $data['site_reference'] . $data['settle_status'] . $data['settle_due_date'] . $order_info['order_id'] . $this->config->get('payment_securetrading_pp_site_security_password')); + } else { + $data['site_security'] = false; + } + + $cards = array( + 'AMEX' => 'American Express', + 'VISA' => 'Visa', + 'DELTA' => 'Visa Debit', + 'ELECTRON' => 'Visa Electron', + 'PURCHASING' => 'Visa Purchasing', + 'VPAY' => 'V Pay', + 'MASTERCARD' => 'MasterCard', + 'MASTERCARDDEBIT' => 'MasterCard Debit', + 'MAESTRO' => 'Maestro', + 'PAYPAL' => 'PayPal', + ); + + $data['cards'] = array(); + + foreach ($cards as $key => $value) { + if (in_array($key, $this->config->get('payment_securetrading_pp_cards_accepted'))) { + $data['cards'][$key] = $value; + } + } + + $data['button_confirm'] = $this->language->get('button_confirm'); + $data['text_payment_details'] = $this->language->get('text_payment_details'); + $data['entry_card_type'] = $this->language->get('entry_card_type'); + + return $this->load->view('extension/payment/securetrading_pp', $data); + } + } + + public function ipn() { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/securetrading_pp'); + $this->load->language('extension/payment/securetrading_pp'); + + $keys = array_keys($this->request->post); + sort($keys); + + $keys_ignore = array('notificationreference', 'responsesitesecurity'); + + $string_to_hash = ''; + + foreach ($keys as $key) { + if (!in_array($key, $keys_ignore)) { + $string_to_hash .= $this->request->post[$key]; + } + } + + $string_to_hash .= $this->config->get('payment_securetrading_pp_notification_password'); + + if (hash_equals(hash('sha256', $string_to_hash), $this->request->post['responsesitesecurity']) && $this->request->post['sitereference'] == $this->config->get('payment_securetrading_pp_site_reference')) { + $order_info = $this->model_checkout_order->getOrder($this->request->post['orderreference']); + + if ($order_info) { + $order_total = $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false); + + if ($order_total == $this->request->post['mainamount'] && $order_info['currency_code'] == $this->request->post['currencyiso3a'] && $order_info['payment_code'] == 'securetrading_pp') { + $status_code_mapping = array( + 0 => $this->language->get('text_not_given'), + 1 => $this->language->get('text_not_checked'), + 2 => $this->language->get('text_match'), + 4 => $this->language->get('text_not_match'), + ); + $shipping_country = $this->model_extension_payment_securetrading_pp->getCountry($this->request->post['customercountryiso2a']); + $payment_country = $this->model_extension_payment_securetrading_pp->getCountry($this->request->post['billingcountryiso2a']); + + $order_info['payment_firstname'] = $this->request->post['billingfirstname']; + $order_info['payment_lastname'] = $this->request->post['billinglastname']; + $order_info['payment_address_1'] = $this->request->post['billingpremise']; + $order_info['payment_address_2'] = $this->request->post['billingstreet']; + $order_info['payment_city'] = $this->request->post['billingtown']; + $order_info['payment_zone'] = $this->request->post['billingcounty']; + $order_info['payment_zone_id'] = 0; + $order_info['payment_country'] = $payment_country['name']; + $order_info['payment_country_id'] = $payment_country['country_id']; + $order_info['payment_postcode'] = $this->request->post['billingpostcode']; + + $order_info['shipping_firstname'] = $this->request->post['customerfirstname']; + $order_info['shipping_lastname'] = $this->request->post['customerlastname']; + $order_info['shipping_address_1'] = $this->request->post['customerpremise']; + $order_info['shipping_address_2'] = $this->request->post['customerstreet']; + $order_info['shipping_city'] = $this->request->post['customertown']; + $order_info['shipping_zone'] = $this->request->post['customercounty']; + $order_info['shipping_zone_id'] = 0; + $order_info['shipping_country'] = $shipping_country['name']; + $order_info['shipping_country_id'] = $shipping_country['country_id']; + $order_info['shipping_postcode'] = $this->request->post['customerpostcode']; + + $this->model_extension_payment_securetrading_pp->editOrder($order_info['order_id'], $order_info); + + $postcode_status = $this->request->post['securityresponsepostcode']; + $security_code_status = $this->request->post['securityresponsesecuritycode']; + $address_status = $this->request->post['securityresponseaddress']; + + $message = sprintf($this->language->get('text_postcode_check'), $status_code_mapping[$postcode_status]) . "\n"; + $message .= sprintf($this->language->get('text_security_code_check'), $status_code_mapping[$security_code_status]) . "\n"; + $message .= sprintf($this->language->get('text_address_check'), $status_code_mapping[$address_status]) . "\n"; + + if (isset($this->request->post['transactionreference'])) { + $transactionreference = $this->request->post['transactionreference']; + } else { + $transactionreference = ''; + } + $this->model_extension_payment_securetrading_pp->addReference($order_info['order_id'], $transactionreference); + + if ($this->request->post['errorcode'] == '0') { + $order_status_id = $this->config->get('payment_securetrading_pp_order_status_id'); + + $this->model_extension_payment_securetrading_pp->confirmOrder($order_info['order_id'], $order_status_id); + $this->model_extension_payment_securetrading_pp->updateOrder($order_info['order_id'], $order_status_id, $message); + } elseif ($this->request->post['errorcode'] == '70000') { + $order_status_id = $this->config->get('payment_securetrading_pp_declined_order_status_id'); + + $this->model_extension_payment_securetrading_pp->updateOrder($order_info['order_id'], $order_status_id, $message); + } + } + } + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/securetrading_ws.php b/public/catalog/controller/extension/payment/securetrading_ws.php new file mode 100644 index 0000000..82d8bbc --- /dev/null +++ b/public/catalog/controller/extension/payment/securetrading_ws.php @@ -0,0 +1,359 @@ +<?php +class ControllerExtensionPaymentSecureTradingWs extends Controller { + public function index() { + $this->load->model('checkout/order'); + $this->load->language('extension/payment/securetrading_ws'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if ($order_info) { + $data['entry_type'] = $this->language->get('entry_type'); + $data['entry_number'] = $this->language->get('entry_number'); + $data['entry_expire_date'] = $this->language->get('entry_expire_date'); + $data['entry_cvv2'] = $this->language->get('entry_cvv2'); + + $data['text_card_details'] = $this->language->get('text_card_details'); + $data['text_wait'] = $this->language->get('text_wait'); + + $data['button_confirm'] = $this->language->get('button_confirm'); + + $cards = array( + 'AMEX' => 'American Express', + 'VISA' => 'Visa', + 'DELTA' => 'Visa Debit', + 'ELECTRON' => 'Visa Electron', + 'PURCHASING' => 'Visa Purchasing', + 'VPAY' => 'V Pay', + 'MASTERCARD' => 'MasterCard', + 'MASTERCARDDEBIT' => 'MasterCard Debit', + 'MAESTRO' => 'Maestro', + 'PAYPAL' => 'PayPal', + ); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['year_expire'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['year_expire'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + $data['cards'] = array(); + + foreach ($this->config->get('payment_securetrading_ws_cards_accepted') as $card_type) { + $data['cards'][$card_type] = $cards[$card_type]; + } + + return $this->load->view('extension/payment/securetrading_ws', $data); + } + } + + public function process() { + $this->load->model('checkout/order'); + $this->load->model('localisation/country'); + $this->load->model('extension/payment/securetrading_ws'); + $this->load->language('extension/payment/securetrading_ws'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + if ($order_info) { + if ($this->config->get('payment_securetrading_ws_3d_secure')) { + $requestblock_xml = new SimpleXMLElement('<requestblock></requestblock>'); + $requestblock_xml->addAttribute('version', '3.67'); + $requestblock_xml->addChild('alias', $this->config->get('payment_securetrading_ws_username')); + + $request_node = $requestblock_xml->addChild('request'); + $request_node->addAttribute('type', 'THREEDQUERY'); + + $merchant_node = $request_node->addChild('merchant'); + $merchant_node->addChild('orderreference', $order_info['order_id']); + $merchant_node->addChild('termurl', $this->url->link('extension/payment/securetrading_ws/threedreturn', '', true)); + + $settlement_node = $request_node->addChild('settlement'); + $settlement_date = date('Y-m-d', strtotime(date('Y-m-d') . ' +' . $this->config->get('payment_securetrading_ws_settle_due_date') . ' days')); + $settlement_node->addChild('settleduedate', $settlement_date); + $settlement_node->addChild('settlestatus', $this->config->get('payment_securetrading_ws_settle_status')); + + $customer_node = $request_node->addChild('customer'); + $customer_node->addChild('useragent', $order_info['user_agent']); + $customer_node->addChild('accept', $this->request->server['HTTP_ACCEPT']); + + $billing_node = $request_node->addChild('billing'); + $amount_node = $billing_node->addChild('amount', str_replace('.', '', $this->model_extension_payment_securetrading_ws->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value']))); + $amount_node->addAttribute('currencycode', $order_info['currency_code']); + + $billing_node->addChild('premise', $order_info['payment_address_1']); + $billing_node->addChild('postcode', $order_info['payment_postcode']); + + $name_node = $billing_node->addChild('name'); + $name_node->addChild('first', $order_info['payment_firstname']); + $name_node->addChild('last', $order_info['payment_lastname']); + + $payment_node = $billing_node->addChild('payment'); + $payment_node->addAttribute('type', $this->request->post['type']); + $payment_node->addChild('pan', $this->request->post['number']); + $payment_node->addChild('expirydate', $this->request->post['expire_month'] . '/' . $this->request->post['expire_year']); + $payment_node->addChild('securitycode', $this->request->post['cvv2']); + + $operation_node = $request_node->addChild('operation'); + $operation_node->addChild('sitereference', $this->config->get('payment_securetrading_ws_site_reference')); + $operation_node->addChild('accounttypedescription', 'ECOM'); + + $response = $this->model_extension_payment_securetrading_ws->call($requestblock_xml->asXML()); + + if ($response !== false) { + $response_xml = simplexml_load_string($response); + + if ($response_xml->response['type'] == 'THREEDQUERY') { + $error_code = (int)$response_xml->response->error->code; + + if ($error_code == 0) { + $enrolled = (string)$response_xml->response->threedsecure->enrolled; + + if ($enrolled == 'Y') { + $acs_url = (string)$response_xml->response->threedsecure->acsurl; + $md = (string)$response_xml->response->threedsecure->md; + $pareq = (string)$response_xml->response->threedsecure->pareq; + + $this->model_extension_payment_securetrading_ws->addMd($order_info['order_id'], $md); + + $json['status'] = 1; + $json['acs_url'] = $acs_url; + $json['md'] = $md; + $json['pareq'] = $pareq; + $json['term_url'] = $this->url->link('extension/payment/securetrading_ws/threedreturn', '', true); + } else { + $requestblock_xml = new SimpleXMLElement('<requestblock></requestblock>'); + $requestblock_xml->addAttribute('version', '3.67'); + $requestblock_xml->addChild('alias', $this->config->get('payment_securetrading_ws_username')); + + $request_node = $requestblock_xml->addChild('request'); + $request_node->addAttribute('type', 'AUTH'); + + $request_node->addChild('merchant')->addChild('orderreference', $order_info['order_id']); + + $operation_node = $request_node->addChild('operation'); + $operation_node->addChild('parenttransactionreference', (string)$response_xml->response->transactionreference); + $operation_node->addChild('sitereference', $this->config->get('payment_securetrading_ws_site_reference')); + + $response = $this->model_extension_payment_securetrading_ws->call($requestblock_xml->asXML()); + + $json = $this->processAuthResponse($response, $order_info['order_id']); + } + } else { + $json['message'] = $this->language->get('text_transaction_declined'); + $json['status'] = 0; + } + } else { + $json['message'] = $this->language->get('text_transaction_failed'); + $json['status'] = 0; + } + } else { + $json['message'] = $this->language->get('text_connection_error'); + $json['status'] = 0; + } + } else { + $country = $this->model_localisation_country->getCountry($order_info['payment_country_id']); + + $json = array(); + + $requestblock_xml = new SimpleXMLElement('<requestblock></requestblock>'); + $requestblock_xml->addAttribute('version', '3.67'); + $requestblock_xml->addChild('alias', $this->config->get('payment_securetrading_ws_username')); + + $request_node = $requestblock_xml->addChild('request'); + $request_node->addAttribute('type', 'AUTH'); + $operation_node = $request_node->addChild('operation'); + $operation_node->addChild('sitereference', $this->config->get('payment_securetrading_ws_site_reference')); + $operation_node->addChild('accounttypedescription', 'ECOM'); + + $merchant_node = $request_node->addChild('merchant'); + $merchant_node->addChild('orderreference', $order_info['order_id']); + + $settlement_node = $request_node->addChild('settlement'); + $settlement_date = date('Y-m-d', strtotime(date('Y-m-d') . ' +' . $this->config->get('payment_securetrading_ws_settle_due_date') . ' days')); + $settlement_node->addChild('settleduedate', $settlement_date); + $settlement_node->addChild('settlestatus', $this->config->get('payment_securetrading_ws_settle_status')); + + $billing_node = $request_node->addChild('billing'); + $billing_node->addChild('premise', $order_info['payment_address_1']); + $billing_node->addChild('street', $order_info['payment_address_2']); + $billing_node->addChild('town', $order_info['payment_city']); + $billing_node->addChild('county', $order_info['payment_zone']); + $billing_node->addChild('country', $country['iso_code_2']); + $billing_node->addChild('postcode', $order_info['payment_postcode']); + $billing_node->addChild('email', $order_info['email']); + $name_node = $billing_node->addChild('name'); + + $name_node->addChild('first', $order_info['payment_firstname']); + $name_node->addChild('last', $order_info['payment_lastname']); + + $amount_node = $billing_node->addChild('amount', str_replace('.', '', $this->model_extension_payment_securetrading_ws->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value']))); + $amount_node->addAttribute('currencycode', $order_info['currency_code']); + + $payment_node = $billing_node->addChild('payment'); + $payment_node->addAttribute('type', $this->request->post['type']); + $payment_node->addChild('pan', $this->request->post['number']); + $payment_node->addChild('expirydate', $this->request->post['expire_month'] . '/' . $this->request->post['expire_year']); + $payment_node->addChild('securitycode', $this->request->post['cvv2']); + + $response = $this->model_extension_payment_securetrading_ws->call($requestblock_xml->asXML()); + + $json = $this->processAuthResponse($response, $order_info['order_id']); + } + $this->response->setOutput(json_encode($json)); + } + } + + public function threedreturn() { + $this->load->model('checkout/order'); + $this->load->model('extension/payment/securetrading_ws'); + $this->load->language('extension/payment/securetrading_ws'); + + // Using unmodified $_POST to access values as per Secure Trading's requirements + if (isset($_POST['PaRes']) && !empty($_POST['PaRes']) && isset($_POST['MD']) && !empty($_POST['MD'])) { + $md = $_POST['MD']; + $pares = $_POST['PaRes']; + + $order_id = $this->model_extension_payment_securetrading_ws->getOrderId($md); + + if ($order_id) { + $requestblock_xml = new SimpleXMLElement('<requestblock></requestblock>'); + $requestblock_xml->addAttribute('version', '3.67'); + $requestblock_xml->addChild('alias', $this->config->get('payment_securetrading_ws_username')); + + $request_node = $requestblock_xml->addChild('request'); + $request_node->addAttribute('type', 'AUTH'); + + $request_node->addChild('merchant')->addChild('orderreference', $order_id); + + $operation_node = $request_node->addChild('operation'); + $operation_node->addChild('md', $md); + $operation_node->addChild('pares', $pares); + + $response = $this->model_extension_payment_securetrading_ws->call($requestblock_xml->asXML()); + + if ($response) { + $response_xml = simplexml_load_string($response); + + $error_code = (int)$response_xml->response->error->code; + + if ($error_code == 0) { + $postcode_status = (int)$response_xml->response->security->postcode; + $security_code_status = (int)$response_xml->response->security->securitycode; + $address_status = (int)$response_xml->response->security->address; + $authcode = (string)$response_xml->response->authcode; + $threed_status = (string)$response_xml->response->threedsecure->status; + + $status_code_mapping = array( + 0 => $this->language->get('text_not_given'), + 1 => $this->language->get('text_not_checked'), + 2 => $this->language->get('text_match'), + 4 => $this->language->get('text_not_match'), + ); + + $threed_status_mapping = array( + 'Y' => $this->language->get('text_authenticated'), + 'N' => $this->language->get('text_not_authenticated'), + 'A' => $this->language->get('text_authentication_not_completed'), + 'U' => $this->language->get('text_unable_to_perform'), + ); + + $message = sprintf($this->language->get('text_auth_code'), $authcode) . "\n"; + $message .= sprintf($this->language->get('text_postcode_check'), $status_code_mapping[$postcode_status]) . "\n"; + $message .= sprintf($this->language->get('text_security_code_check'), $status_code_mapping[$security_code_status]) . "\n"; + $message .= sprintf($this->language->get('text_address_check'), $status_code_mapping[$address_status]) . "\n"; + $message .= sprintf($this->language->get('text_3d_secure_check'), $threed_status_mapping[$threed_status]) . "\n"; + + $transaction_reference = (string)$response_xml->response->transactionreference; + $this->model_extension_payment_securetrading_ws->updateReference($order_id, $transaction_reference); + + $this->model_extension_payment_securetrading_ws->confirmOrder($order_id, $this->config->get('payment_securetrading_ws_order_status_id')); + $this->model_extension_payment_securetrading_ws->updateOrder($order_id, $this->config->get('payment_securetrading_ws_order_status_id'), $message); + + $this->response->redirect($this->url->link('checkout/success', '', true)); + } else { + $this->model_extension_payment_securetrading_ws->updateOrder($order_id, $this->config->get('payment_securetrading_ws_declined_order_status_id')); + + $this->session->data['error'] = $this->language->get('text_transaction_declined'); + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + } else { + $this->session->data['error'] = $this->language->get('error_failure'); + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + } else { + $this->session->data['error'] = $this->language->get('error_failure'); + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + } else { + $this->session->data['error'] = $this->language->get('error_failure'); + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + } + + private function processAuthResponse($response, $order_id) { + $json = array(); + + if ($response !== false) { + $response_xml = simplexml_load_string($response); + + if ($response_xml->response['type'] == 'AUTH') { + $error_code = (int)$response_xml->response->error->code; + + if ($error_code == 0) { + $postcode_status = (int)$response_xml->response->security->postcode; + $security_code_status = (int)$response_xml->response->security->securitycode; + $address_status = (int)$response_xml->response->security->address; + $authcode = (string)$response_xml->response->authcode; + + $status_code_mapping = array( + 0 => $this->language->get('text_not_given'), + 1 => $this->language->get('text_not_checked'), + 2 => $this->language->get('text_match'), + 4 => $this->language->get('text_not_match'), + ); + + $message = sprintf($this->language->get('text_auth_code'), $authcode) . "\n"; + $message .= sprintf($this->language->get('text_postcode_check'), $status_code_mapping[$postcode_status]) . "\n"; + $message .= sprintf($this->language->get('text_security_code_check'), $status_code_mapping[$security_code_status]) . "\n"; + $message .= sprintf($this->language->get('text_address_check'), $status_code_mapping[$address_status]) . "\n"; + + $transaction_reference = (string)$response_xml->response->transactionreference; + $this->model_extension_payment_securetrading_ws->updateReference($order_id, $transaction_reference); + + $this->model_extension_payment_securetrading_ws->confirmOrder($order_id, $this->config->get('payment_securetrading_ws_order_status_id')); + $this->model_extension_payment_securetrading_ws->updateOrder($order_id, $this->config->get('payment_securetrading_ws_order_status_id'), $message); + + $json['redirect'] = $this->url->link('checkout/success'); + $json['status'] = 1; + } else { + $this->model_extension_payment_securetrading_ws->updateOrder($order_id, $this->config->get('payment_securetrading_ws_declined_order_status_id')); + + $json['message'] = $this->language->get('text_transaction_declined'); + $json['status'] = 0; + } + } else { + $this->model_extension_payment_securetrading_ws->updateOrder($order_id, $this->config->get('payment_securetrading_ws_failed_order_status_id')); + + $json['message'] = $this->language->get('text_transaction_failed'); + $json['status'] = 0; + } + } else { + $json['message'] = $this->language->get('text_connection_error'); + $json['status'] = 0; + } + + return $json; + } +} diff --git a/public/catalog/controller/extension/payment/skrill.php b/public/catalog/controller/extension/payment/skrill.php new file mode 100644 index 0000000..1038ee9 --- /dev/null +++ b/public/catalog/controller/extension/payment/skrill.php @@ -0,0 +1,106 @@ +<?php +class ControllerExtensionPaymentSkrill extends Controller { + public function index() { + $this->load->model('checkout/order'); + + $this->load->language('extension/payment/skrill'); + + $data['button_confirm'] = $this->language->get('button_confirm'); + + $data['action'] = 'https://www.moneybookers.com/app/payment.pl?p=OpenCart'; + + $data['pay_to_email'] = $this->config->get('payment_skrill_email'); + $data['platform'] = '31974336'; + $data['description'] = $this->config->get('config_name'); + $data['transaction_id'] = $this->session->data['order_id']; + $data['return_url'] = $this->url->link('checkout/success'); + $data['cancel_url'] = $this->url->link('checkout/checkout', '', true); + $data['status_url'] = $this->url->link('extension/payment/skrill/callback'); + $data['language'] = $this->session->data['language']; + $data['logo'] = $this->config->get('config_url') . 'image/' . $this->config->get('config_logo'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $data['pay_from_email'] = $order_info['email']; + $data['firstname'] = $order_info['payment_firstname']; + $data['lastname'] = $order_info['payment_lastname']; + $data['address'] = $order_info['payment_address_1']; + $data['address2'] = $order_info['payment_address_2']; + $data['phone_number'] = $order_info['telephone']; + $data['postal_code'] = $order_info['payment_postcode']; + $data['city'] = $order_info['payment_city']; + $data['state'] = $order_info['payment_zone']; + $data['country'] = $order_info['payment_iso_code_3']; + $data['amount'] = $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false); + $data['currency'] = $order_info['currency_code']; + + $products = ''; + + foreach ($this->cart->getProducts() as $product) { + $products .= $product['quantity'] . ' x ' . $product['name'] . ', '; + } + + $data['detail1_text'] = $products; + + $data['order_id'] = $this->session->data['order_id']; + + return $this->load->view('extension/payment/skrill', $data); + } + + public function callback() { + if (isset($this->request->post['order_id'])) { + $order_id = $this->request->post['order_id']; + } else { + $order_id = 0; + } + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($order_id); + + if ($order_info) { + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('config_order_status_id')); + + $verified = true; + + // md5sig validation + if ($this->config->get('payment_skrill_secret')) { + $hash = $this->request->post['merchant_id']; + $hash .= $this->request->post['transaction_id']; + $hash .= strtoupper(md5($this->config->get('payment_skrill_secret'))); + $hash .= $this->request->post['mb_amount']; + $hash .= $this->request->post['mb_currency']; + $hash .= $this->request->post['status']; + + $md5hash = strtoupper(md5($hash)); + $md5sig = $this->request->post['md5sig']; + + if (($md5hash != $md5sig) || (strtolower($this->request->post['pay_to_email']) != strtolower($this->config->get('config_moneybookers_email'))) || ((float)$this->request->post['amount'] != $this->currency->format((float)$order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false))) { + $verified = false; + } + } + + if ($verified) { + switch($this->request->post['status']) { + case '2': + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_skrill_order_status_id'), '', true); + break; + case '0': + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_skrill_pending_status_id'), '', true); + break; + case '-1': + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_skrill_canceled_status_id'), '', true); + break; + case '-2': + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_skrill_failed_status_id'), '', true); + break; + case '-3': + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_skrill_chargeback_status_id'), '', true); + break; + } + } else { + $this->log->write('md5sig returned (' + $md5sig + ') does not match generated (' + $md5hash + '). Verify Manually. Current order state: ' . $this->config->get('config_order_status_id')); + } + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/squareup.php b/public/catalog/controller/extension/payment/squareup.php new file mode 100644 index 0000000..0b7205e --- /dev/null +++ b/public/catalog/controller/extension/payment/squareup.php @@ -0,0 +1,251 @@ +<?php + +class ControllerExtensionPaymentSquareup extends Controller { + public function index() { + $this->load->language('extension/payment/squareup'); + + $this->load->library('squareup'); + + $data['action'] = $this->url->link('extension/payment/squareup/checkout', '', true); + $data['squareup_js_api'] = Squareup::PAYMENT_FORM_URL; + + if (!empty($this->session->data['payment_address']['postcode'])) { + $data['payment_zip'] = $this->session->data['payment_address']['postcode']; + } else { + $data['payment_zip'] = ''; + } + + if ($this->config->get('payment_squareup_enable_sandbox')) { + $data['app_id'] = $this->config->get('payment_squareup_sandbox_client_id'); + $data['sandbox_message'] = $this->language->get('warning_test_mode'); + } else { + $data['app_id'] = $this->config->get('payment_squareup_client_id'); + $data['sandbox_message'] = ''; + } + + $data['cards'] = array(); + + if ($this->customer->isLogged()) { + $data['is_logged'] = true; + + $this->load->model('extension/credit_card/squareup'); + + $cards = $this->model_extension_credit_card_squareup->getCards($this->customer->getId(), $this->config->get('payment_squareup_enable_sandbox')); + + foreach ($cards as $card) { + $data['cards'][] = array( + 'id' => $card['squareup_token_id'], + 'text' => sprintf($this->language->get('text_card_ends_in'), $card['brand'], $card['ends_in']) + ); + } + } else { + $data['is_logged'] = false; + } + + return $this->load->view('extension/payment/squareup', $data); + } + + public function checkout() { + $this->load->language('extension/payment/squareup'); + + $this->load->model('extension/payment/squareup'); + $this->load->model('extension/credit_card/squareup'); + $this->load->model('checkout/order'); + $this->load->model('localisation/country'); + + $this->load->library('squareup'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $shipping_country_info = $this->model_localisation_country->getCountry($order_info['shipping_country_id']); + + $billing_country_info = $this->model_localisation_country->getCountry($order_info['payment_country_id']); + + if (!empty($billing_country_info)) { + $billing_address = array( + 'first_name' => $order_info['payment_firstname'], + 'last_name' => $order_info['payment_lastname'], + 'address_line_1' => $order_info['payment_address_1'], + 'address_line_2' => $order_info['payment_address_2'], + 'locality' => $order_info['payment_city'], + 'sublocality' => $order_info['payment_zone'], + 'postal_code' => $order_info['payment_postcode'], + 'country' => $billing_country_info['iso_code_2'], + 'organization' => $order_info['payment_company'] + ); + } else { + $billing_address = array(); + } + + if (!empty($shipping_country_info)) { + $shipping_address = array( + 'first_name' => $order_info['shipping_firstname'], + 'last_name' => $order_info['shipping_lastname'], + 'address_line_1' => $order_info['shipping_address_1'], + 'address_line_2' => $order_info['shipping_address_2'], + 'locality' => $order_info['shipping_city'], + 'sublocality' => $order_info['shipping_zone'], + 'postal_code' => $order_info['shipping_postcode'], + 'country' => $shipping_country_info['iso_code_2'], + 'organization' => $order_info['shipping_company'] + ); + } else { + $shipping_address = array(); + } + + $json = array(); + + try { + // Ensure we have registered the customer with Square + $square_customer = $this->model_extension_credit_card_squareup->getCustomer($this->customer->getId(), $this->config->get('payment_squareup_enable_sandbox')); + + if (!$square_customer && $this->customer->isLogged()) { + $square_customer = $this->squareup->addLoggedInCustomer(); + + $this->model_extension_credit_card_squareup->addCustomer($square_customer); + } + + $use_saved = false; + $square_card_id = null; + + // check if user is logged in and wanted to save this card + if ($this->customer->isLogged() && !empty($this->request->post['squareup_select_card'])) { + $card_verified = $this->model_extension_credit_card_squareup->verifyCardCustomer($this->request->post['squareup_select_card'], $this->customer->getId()); + + if (!$card_verified) { + throw new \Squareup\Exception($this->registry, $this->language->get('error_card_invalid')); + } + + $card = $this->model_extension_credit_card_squareup->getCard($this->request->post['squareup_select_card']); + + $use_saved = true; + $square_card_id = $card['token']; + } else if ($this->customer->isLogged() && isset($this->request->post['squareup_save_card'])) { + // Save the card + $card_data = array( + 'card_nonce' => $this->request->post['squareup_nonce'], + 'billing_address' => $billing_address, + 'cardholder_name' => $order_info['payment_firstname'] . ' ' . $order_info['payment_lastname'] + ); + + $square_card = $this->squareup->addCard($square_customer['square_customer_id'], $card_data); + + if (!$this->model_extension_credit_card_squareup->cardExists($this->customer->getId(), $square_card)) { + $this->model_extension_credit_card_squareup->addCard($this->customer->getId(), $this->config->get('payment_squareup_enable_sandbox'), $square_card); + } + + $use_saved = true; + $square_card_id = $square_card['id']; + } + + // Prepare Transaction + $transaction_data = array( + 'idempotency_key' => uniqid(), + 'amount_money' => array( + 'amount' => $this->squareup->lowestDenomination($order_info['total'], $order_info['currency_code']), + 'currency' => $order_info['currency_code'] + ), + 'billing_address' => $billing_address, + 'buyer_email_address' => $order_info['email'], + 'delay_capture' => !$this->cart->hasRecurringProducts() && $this->config->get('payment_squareup_delay_capture'), + 'integration_id' => Squareup::SQUARE_INTEGRATION_ID + ); + + if (!empty($shipping_address)) { + $transaction_data['shipping_address'] = $shipping_address; + } + + if ($use_saved) { + $transaction_data['customer_card_id'] = $square_card_id; + $transaction_data['customer_id'] = $square_customer['square_customer_id']; + } else { + $transaction_data['card_nonce'] = $this->request->post['squareup_nonce']; + } + + $transaction = $this->squareup->addTransaction($transaction_data); + + if (isset($this->request->server['HTTP_USER_AGENT'])) { + $user_agent = $this->request->server['HTTP_USER_AGENT']; + } else { + $user_agent = ''; + } + + if (isset($this->request->server['REMOTE_ADDR'])) { + $ip = $this->request->server['REMOTE_ADDR']; + } else { + $ip = ''; + } + + $this->model_extension_payment_squareup->addTransaction($transaction, $this->config->get('payment_squareup_merchant_id'), $billing_address, $this->session->data['order_id'], $user_agent, $ip); + + if (!empty($transaction['tenders'][0]['card_details']['status'])) { + $transaction_status = strtolower($transaction['tenders'][0]['card_details']['status']); + } else { + $transaction_status = ''; + } + + $order_status_id = $this->config->get('payment_squareup_status_' . $transaction_status); + + if ($order_status_id) { + if ($this->cart->hasRecurringProducts() && $transaction_status == 'captured') { + foreach ($this->cart->getRecurringProducts() as $item) { + if ($item['recurring']['trial']) { + $trial_price = $this->tax->calculate($item['recurring']['trial_price'] * $item['quantity'], $item['tax_class_id']); + $trial_amt = $this->currency->format($trial_price, $this->session->data['currency']); + $trial_text = sprintf($this->language->get('text_trial'), $trial_amt, $item['recurring']['trial_cycle'], $item['recurring']['trial_frequency'], $item['recurring']['trial_duration']); + + $item['recurring']['trial_price'] = $trial_price; + } else { + $trial_text = ''; + } + + $recurring_price = $this->tax->calculate($item['recurring']['price'] * $item['quantity'], $item['tax_class_id']); + $recurring_amt = $this->currency->format($recurring_price, $this->session->data['currency']); + $recurring_description = $trial_text . sprintf($this->language->get('text_recurring'), $recurring_amt, $item['recurring']['cycle'], $item['recurring']['frequency']); + + $item['recurring']['price'] = $recurring_price; + + if ($item['recurring']['duration'] > 0) { + $recurring_description .= sprintf($this->language->get('text_length'), $item['recurring']['duration']); + } + + if (!$item['recurring']['trial']) { + // We need to override this value for the proper calculation in updateRecurringExpired + $item['recurring']['trial_duration'] = 0; + } + + + $this->model_extension_payment_squareup->createRecurring($item, $this->session->data['order_id'], $recurring_description, $transaction['id']); + } + } + + $order_status_comment = $this->language->get('squareup_status_comment_' . $transaction_status); + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $order_status_id, $order_status_comment, true); + } + + $json['redirect'] = $this->url->link('checkout/success', '', true); + } catch (\Squareup\Exception $e) { + if ($e->isCurlError()) { + $json['error'] = $this->language->get('text_token_issue_customer_error'); + } else if ($e->isAccessTokenRevoked()) { + // Send reminder e-mail to store admin to refresh the token + $this->model_extension_payment_squareup->tokenRevokedEmail(); + + $json['error'] = $this->language->get('text_token_issue_customer_error'); + } else if ($e->isAccessTokenExpired()) { + // Send reminder e-mail to store admin to refresh the token + $this->model_extension_payment_squareup->tokenExpiredEmail(); + + $json['error'] = $this->language->get('text_token_issue_customer_error'); + } else { + $json['error'] = $e->getMessage(); + } + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + +} diff --git a/public/catalog/controller/extension/payment/twocheckout.php b/public/catalog/controller/extension/payment/twocheckout.php new file mode 100644 index 0000000..140a68f --- /dev/null +++ b/public/catalog/controller/extension/payment/twocheckout.php @@ -0,0 +1,114 @@ +<?php +class ControllerExtensionPaymentTwoCheckout extends Controller { + public function index() { + $data['button_confirm'] = $this->language->get('button_confirm'); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $data['action'] = 'https://www.2checkout.com/checkout/purchase'; + + $data['sid'] = $this->config->get('payment_twocheckout_account'); + $data['currency_code'] = $order_info['currency_code']; + $data['total'] = $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false); + $data['cart_order_id'] = $this->session->data['order_id']; + $data['card_holder_name'] = $order_info['payment_firstname'] . ' ' . $order_info['payment_lastname']; + $data['street_address'] = $order_info['payment_address_1']; + $data['city'] = $order_info['payment_city']; + + if ($order_info['payment_iso_code_2'] == 'US' || $order_info['payment_iso_code_2'] == 'CA') { + $data['state'] = $order_info['payment_zone']; + } else { + $data['state'] = 'XX'; + } + + $data['zip'] = $order_info['payment_postcode']; + $data['country'] = $order_info['payment_country']; + $data['email'] = $order_info['email']; + $data['phone'] = $order_info['telephone']; + + if ($this->cart->hasShipping()) { + $data['ship_street_address'] = $order_info['shipping_address_1']; + $data['ship_city'] = $order_info['shipping_city']; + $data['ship_state'] = $order_info['shipping_zone']; + $data['ship_zip'] = $order_info['shipping_postcode']; + $data['ship_country'] = $order_info['shipping_country']; + } else { + $data['ship_street_address'] = $order_info['payment_address_1']; + $data['ship_city'] = $order_info['payment_city']; + $data['ship_state'] = $order_info['payment_zone']; + $data['ship_zip'] = $order_info['payment_postcode']; + $data['ship_country'] = $order_info['payment_country']; + } + + $data['products'] = array(); + + $products = $this->cart->getProducts(); + + foreach ($products as $product) { + $data['products'][] = array( + 'product_id' => $product['product_id'], + 'name' => $product['name'], + 'description' => $product['name'], + 'quantity' => $product['quantity'], + 'price' => $this->currency->format($product['price'], $order_info['currency_code'], $order_info['currency_value'], false) + ); + } + + if ($this->config->get('payment_twocheckout_test')) { + $data['demo'] = 'Y'; + } else { + $data['demo'] = ''; + } + + if ($this->config->get('payment_twocheckout_display')) { + $data['display'] = 'Y'; + } else { + $data['display'] = ''; + } + + $data['lang'] = $this->session->data['language']; + + $data['return_url'] = $this->url->link('extension/payment/twocheckout/callback', '', true); + + return $this->load->view('extension/payment/twocheckout', $data); + } + + public function callback() { + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->request->post['cart_order_id']); + + if (!$this->config->get('payment_twocheckout_test')) { + $order_number = $this->request->post['order_number']; + } else { + $order_number = '1'; + } + + if (strtoupper(md5($this->config->get('payment_twocheckout_secret') . $this->config->get('payment_twocheckout_account') . $order_number . $this->request->post['total'])) == $this->request->post['key']) { + if ($this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false) == $this->request->post['total']) { + $this->model_checkout_order->addOrderHistory($this->request->post['cart_order_id'], $this->config->get('payment_twocheckout_order_status_id')); + } else { + $this->model_checkout_order->addOrderHistory($this->request->post['cart_order_id'], $this->config->get('config_order_status_id'));// Ugh. Some one've faked the sum. What should we do? Probably drop a mail to the shop owner? + } + + // We can't use $this->response->redirect() here, because of 2CO behavior. It fetches this page + // on behalf of the user and thus user (and his browser) see this as located at 2checkout.com + // domain. So user's cookies are not here and he will see empty basket and probably other + // weird things. + + echo '<html>' . "\n"; + echo '<head>' . "\n"; + echo ' <meta http-equiv="Refresh" content="0; url=' . $this->url->link('checkout/success') . '">' . "\n"; + echo '</head>' . "\n"; + echo '<body>' . "\n"; + echo ' <p>Please follow <a href="' . $this->url->link('checkout/success') . '">link</a>!</p>' . "\n"; + echo '</body>' . "\n"; + echo '</html>' . "\n"; + exit(); + } else { + echo 'The response from 2checkout.com can\'t be parsed. Contact site administrator, please!'; + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/web_payment_software.php b/public/catalog/controller/extension/payment/web_payment_software.php new file mode 100644 index 0000000..958e90d --- /dev/null +++ b/public/catalog/controller/extension/payment/web_payment_software.php @@ -0,0 +1,134 @@ +<?php +class ControllerExtensionPaymentWebPaymentSoftware extends Controller { + public function index() { + $this->load->language('extension/payment/web_payment_software'); + + $data['months'] = array(); + + for ($i = 1; $i <= 12; $i++) { + $data['months'][] = array( + 'text' => strftime('%B', mktime(0, 0, 0, $i, 1, 2000)), + 'value' => sprintf('%02d', $i) + ); + } + + $today = getdate(); + + $data['year_expire'] = array(); + + for ($i = $today['year']; $i < $today['year'] + 11; $i++) { + $data['year_expire'][] = array( + 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), + 'value' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)) + ); + } + + return $this->load->view('extension/payment/web_payment_software', $data); + } + + public function send() { + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $request = 'MERCHANT_ID=' . urlencode($this->config->get('payment_web_payment_software_merchant_name')); + $request .= '&MERCHANT_KEY=' . urlencode($this->config->get('payment_web_payment_software_merchant_key')); + $request .= '&TRANS_TYPE=' . urlencode($this->config->get('payment_web_payment_software_method') == 'capture' ? 'AuthCapture' : 'AuthOnly'); + $request .= '&AMOUNT=' . urlencode($this->currency->format($order_info['total'], $order_info['currency_code'], 1.00000, false)); + $request .= '&CC_NUMBER=' . urlencode(str_replace(' ', '', $this->request->post['cc_number'])); + $request .= '&CC_EXP=' . urlencode($this->request->post['cc_expire_date_month'] . substr($this->request->post['cc_expire_date_year'], 2)); + $request .= '&CC_CVV=' . urlencode($this->request->post['cc_cvv2']); + $request .= '&CC_NAME=' . urlencode($order_info['payment_firstname'] . ' ' . $order_info['payment_lastname']); + $request .= '&CC_COMPANY=' . urlencode($order_info['payment_company']); + $request .= '&CC_ADDRESS=' . urlencode($order_info['payment_address_1']); + $request .= '&CC_CITY=' . urlencode($order_info['payment_city']); + $request .= '&CC_STATE=' . urlencode($order_info['payment_iso_code_2'] != 'US' ? $order_info['payment_zone'] : $order_info['payment_zone_code']); + $request .= '&CC_ZIP=' . urlencode($order_info['payment_postcode']); + $request .= '&CC_COUNTRY=' . urlencode($order_info['payment_country']); + $request .= '&CC_PHONE=' . urlencode($order_info['telephone']); + $request .= '&CC_EMAIL=' . urlencode($order_info['email']); + $request .= '&INVOICE_NUM=' . urlencode($this->session->data['order_id']); + + if ($this->config->get('payment_web_payment_software_mode') == 'test') { + $request .= '&TEST_MODE=1'; + } + + $curl = curl_init('https://secure.web-payment-software.com/gateway'); + + curl_setopt($curl, CURLOPT_PORT, 443); + curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_FORBID_REUSE, 1); + curl_setopt($curl, CURLOPT_FRESH_CONNECT, 1); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, $request); + + $response = curl_exec($curl); + + curl_close($curl); + + //If in test mode strip results to only contain xml data + if ($this->config->get('payment_web_payment_software_mode') == 'test') { + $end_index = strpos($response, '</WebPaymentSoftwareResponse>'); + $debug = substr($response, $end_index + 30); + $response = substr($response, 0, $end_index) . '</WebPaymentSoftwareResponse>'; + } + + //get response xml + $xml = simplexml_load_string($response); + + //create object to use as json + $json = array(); + + //If successful log transaction in opencart system + if ('00' === (string)$xml->response_code) { + $message = ''; + + $message .= 'Response Code: '; + + if (isset($xml->response_code)) { + $message .= (string)$xml->response_code . "\n"; + } + + $message .= 'Approval Code: '; + + if (isset($xml->approval_code)) { + $message .= (string)$xml->approval_code . "\n"; + } + + $message .= 'AVS Result Code: '; + + if (isset($xml->avs_result_code)) { + $message .= (string)$xml->avs_result_code . "\n"; + } + + $message .= 'Transaction ID (web payment software order id): '; + + if (isset($xml->order_id)) { + $message .= (string)$xml->order_id . "\n"; + } + + $message .= 'CVV Result Code: '; + + if (isset($xml->cvv_result_code)) { + $message .= (string)$xml->cvv_result_code . "\n"; + } + + $message .= 'Response Text: '; + + if (isset($xml->response_text)) { + $message .= (string)$xml->response_text . "\n"; + } + + $this->model_checkout_order->addOrderHistory($this->session->data['order_id'], $this->config->get('payment_web_payment_software_order_status_id'), $message, false); + + $json['redirect'] = $this->url->link('checkout/success', '', true); + } else { + $json['error'] = (string)$xml->response_text; + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/payment/wechat_pay.php b/public/catalog/controller/extension/payment/wechat_pay.php new file mode 100644 index 0000000..0affd0c --- /dev/null +++ b/public/catalog/controller/extension/payment/wechat_pay.php @@ -0,0 +1,134 @@ +<?php +/** + * @package OpenCart + * @author Meng Wenbin + * @copyright Copyright (c) 2010 - 2017, Chengdu Guangda Network Technology Co. Ltd. (https://www.opencart.cn/) + * @license https://opensource.org/licenses/GPL-3.0 + * @link https://www.opencart.cn + */ + +class ControllerExtensionPaymentWechatPay extends Controller { + public function index() { + $data['button_confirm'] = $this->language->get('button_confirm'); + + $data['redirect'] = $this->url->link('extension/payment/wechat_pay/qrcode'); + + return $this->load->view('extension/payment/wechat_pay', $data); + } + + public function qrcode() { + $this->load->language('extension/payment/wechat_pay'); + + $this->document->setTitle($this->language->get('heading_title')); + $this->document->addScript('catalog/view/javascript/qrcode.js'); + + $data['breadcrumbs'] = array(); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_home'), + 'href' => $this->url->link('common/home') + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_checkout'), + 'href' => $this->url->link('checkout/checkout', '', true) + ); + + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_qrcode'), + 'href' => $this->url->link('extension/payment/wechat_pay/qrcode') + ); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $order_id = trim($order_info['order_id']); + $data['order_id'] = $order_id; + $subject = trim($this->config->get('config_name')); + $currency = $this->config->get('payment_wechat_pay_currency'); + $total_amount = trim($this->currency->format($order_info['total'], $currency, '', false)); + $notify_url = HTTPS_SERVER . "payment_callback/wechat_pay"; //$this->url->link('wechat_pay/callback'); + + $options = array( + 'appid' => $this->config->get('payment_wechat_pay_app_id'), + 'appsecret' => $this->config->get('payment_wechat_pay_app_secret'), + 'mch_id' => $this->config->get('payment_wechat_pay_mch_id'), + 'partnerkey' => $this->config->get('payment_wechat_pay_api_secret') + ); + + \Wechat\Loader::config($options); + $pay = new \Wechat\WechatPay(); + + $result = $pay->getPrepayId(NULL, $subject, $order_id, $total_amount * 100, $notify_url, $trade_type = "NATIVE", NULL, $currency); + + $data['error'] = ''; + $data['code_url'] = ''; + if($result === FALSE){ + $data['error_warning'] = $pay->errMsg; + } else { + $data['code_url'] = $result; + } + + $data['action_success'] = $this->url->link('checkout/success'); + + $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/wechat_pay_qrcode', $data)); + } + + public function isOrderPaid() { + $json = array(); + + $json['result'] = false; + + if (isset($this->request->get['order_id'])) { + $order_id = $this->request->get['order_id']; + + $this->load->model('checkout/order'); + $order_info = $this->model_checkout_order->getOrder($order_id); + + if ($order_info['order_status_id'] == $this->config->get('payment_wechat_pay_completed_status_id')) { + $json['result'] = true; + } + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function callback() { + $options = array( + 'appid' => $this->config->get('payment_wechat_pay_app_id'), + 'appsecret' => $this->config->get('payment_wechat_pay_app_secret'), + 'mch_id' => $this->config->get('payment_wechat_pay_mch_id'), + 'partnerkey' => $this->config->get('payment_wechat_pay_api_secret') + ); + + \Wechat\Loader::config($options); + $pay = new \Wechat\WechatPay(); + $notifyInfo = $pay->getNotify(); + + if ($notifyInfo === FALSE) { + $this->log->write('Wechat Pay Error: ' . $pay->errMsg); + } else { + if ($notifyInfo['result_code'] == 'SUCCESS' && $notifyInfo['return_code'] == 'SUCCESS') { + $order_id = $notifyInfo['out_trade_no']; + $this->load->model('checkout/order'); + $order_info = $this->model_checkout_order->getOrder($order_id); + if ($order_info) { + $order_status_id = $order_info["order_status_id"]; + if (!$order_status_id) { + $this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_wechat_pay_completed_status_id')); + } + } + return xml(['return_code' => 'SUCCESS', 'return_msg' => 'DEAL WITH SUCCESS']); + } + } + } +} diff --git a/public/catalog/controller/extension/payment/worldpay.php b/public/catalog/controller/extension/payment/worldpay.php new file mode 100644 index 0000000..eae4c20 --- /dev/null +++ b/public/catalog/controller/extension/payment/worldpay.php @@ -0,0 +1,201 @@ +<?php +class ControllerExtensionPaymentWorldpay extends Controller { + public function index() { + $this->load->language('extension/payment/worldpay'); + + $data['worldpay_script'] = 'https://cdn.worldpay.com/v1/worldpay.js'; + + $data['worldpay_client_key'] = $this->config->get('payment_worldpay_client_key'); + + $data['form_submit'] = $this->url->link('extension/payment/worldpay/send', '', true); + + if ($this->config->get('payment_worldpay_card') == '1' && $this->customer->isLogged()) { + $data['payment_worldpay_card'] = true; + } else { + $data['payment_worldpay_card'] = false; + } + + $data['existing_cards'] = array(); + + if ($this->customer->isLogged() && $data['payment_worldpay_card']) { + $this->load->model('extension/payment/worldpay'); + $data['existing_cards'] = $this->model_extension_payment_worldpay->getCards($this->customer->getId()); + } + + $recurring_products = $this->cart->getRecurringProducts(); + + if (!empty($recurring_products)) { + $data['recurring_products'] = true; + } + + return $this->load->view('extension/payment/worldpay', $data); + } + + public function send() { + $this->load->language('extension/payment/worldpay'); + $this->load->model('checkout/order'); + $this->load->model('localisation/country'); + $this->load->model('extension/payment/worldpay'); + + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $recurring_products = $this->cart->getRecurringProducts(); + + if (empty($recurring_products)) { + $order_type = 'ECOM'; + } else { + $order_type = 'RECURRING'; + } + + $country_info = $this->model_localisation_country->getCountry($order_info['payment_country_id']); + + $billing_address = array( + "address1" => $order_info['payment_address_1'], + "address2" => $order_info['payment_address_2'], + "address3" => '', + "postalCode" => $order_info['payment_postcode'], + "city" => $order_info['payment_city'], + "state" => $order_info['payment_zone'], + "countryCode" => $country_info['iso_code_2'], + ); + + $order = array( + "token" => $this->request->post['token'], + "orderType" => $order_type, + "amount" => round($this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false)*100), + "currencyCode" => $order_info['currency_code'], + "name" => $order_info['firstname'] . ' ' . $order_info['lastname'], + "orderDescription" => $order_info['store_name'] . ' - ' . date('Y-m-d H:i:s'), + "customerOrderCode" => $order_info['order_id'], + "billingAddress" => $billing_address + ); + + $this->model_extension_payment_worldpay->logger($order); + + $response_data = $this->model_extension_payment_worldpay->sendCurl('orders', $order); + + $this->model_extension_payment_worldpay->logger($response_data); + + if (isset($response_data->paymentStatus) && $response_data->paymentStatus == 'SUCCESS') { + $this->model_checkout_order->addOrderHistory($order_info['order_id'], $this->config->get('config_order_status_id')); + + $worldpay_order_id = $this->model_extension_payment_worldpay->addOrder($order_info, $response_data->orderCode); + + $this->model_extension_payment_worldpay->addTransaction($worldpay_order_id, 'payment', $order_info); + + if (isset($this->request->post['save-card'])) { + $response = $this->model_extension_payment_worldpay->sendCurl('tokens/' . $this->request->post['token']); + + $this->model_extension_payment_worldpay->logger($response); + + $expiry_date = mktime(0, 0, 0, 0, (string)$response->paymentMethod->expiryMonth, (string)$response->paymentMethod->expiryYear); + + if (isset($response->paymentMethod)) { + $card_data = array(); + $card_data['customer_id'] = $this->customer->getId(); + $card_data['Token'] = $response->token; + $card_data['Last4Digits'] = (string)$response->paymentMethod->maskedCardNumber; + $card_data['ExpiryDate'] = date("m/y", $expiry_date); + $card_data['CardType'] = (string)$response->paymentMethod->cardType; + $this->model_extension_payment_worldpay->addCard($this->session->data['order_id'], $card_data); + } + } + + //loop through any products that are recurring items + foreach ($recurring_products as $item) { + $this->model_extension_payment_worldpay->recurringPayment($item, $this->session->data['order_id'] . rand(), $this->request->post['token']); + } + + $this->response->redirect($this->url->link('checkout/success', '', true)); + } else { + + $this->session->data['error'] = $this->language->get('error_process_order'); + $this->response->redirect($this->url->link('checkout/checkout', '', true)); + } + } + + public function deleteCard() { + $this->load->language('extension/payment/worldpay'); + $this->load->model('extension/payment/worldpay'); + + if (isset($this->request->post['token'])) { + if ($this->model_extension_payment_worldpay->deleteCard($this->request->post['token'])) { + $json['success'] = $this->language->get('text_card_success'); + } else { + $json['error'] = $this->language->get('text_card_error'); + } + + if (count($this->model_extension_payment_worldpay->getCards($this->customer->getId()))) { + $json['existing_cards'] = true; + } + } else { + $json['error'] = $this->language->get('text_error'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function webhook() { + if (isset($this->request->get['token']) && hash_equals($this->config->get('payment_worldpay_secret_token'), $this->request->get['token'])) { + $this->load->model('extension/payment/worldpay'); + $message = json_decode(file_get_contents('php://input'), true); + + if (isset($message['orderCode'])) { + $order = $this->model_extension_payment_worldpay->getWorldpayOrder($message['orderCode']); + $this->model_extension_payment_worldpay->logger($order); + switch ($message['paymentStatus']) { + case 'SUCCESS': + $order_status_id = $this->config->get('payment_worldpay_success_status_id'); + break; + case 'FAILED': + $order_status_id = $this->config->get('payment_worldpay_failed_status_id'); + break; + case 'SETTLED': + $order_status_id = $this->config->get('payment_worldpay_settled_status_id'); + break; + case 'REFUNDED': + $order_status_id = $this->config->get('payment_worldpay_refunded_status_id'); + break; + case 'PARTIALLY_REFUNDED': + $order_status_id = $this->config->get('payment_worldpay_partially_refunded_status_id'); + break; + case 'CHARGED_BACK': + $order_status_id = $this->config->get('payment_worldpay_charged_back_status_id'); + break; + case 'INFORMATION_REQUESTED': + $order_status_id = $this->config->get('payment_worldpay_information_requested_status_id'); + break; + case 'INFORMATION_SUPPLIED': + $order_status_id = $this->config->get('payment_worldpay_information_supplied_status_id'); + break; + case 'CHARGEBACK_REVERSED': + $order_status_id = $this->config->get('payment_worldpay_chargeback_reversed_status_id'); + break; + } + + $this->model_extension_payment_worldpay->logger($order_status_id); + if (isset($order['order_id'])) { + $this->load->model('checkout/order'); + $this->model_checkout_order->addOrderHistory($order['order_id'], $order_status_id); + } + } + } + + $this->response->addHeader('HTTP/1.1 200 OK'); + $this->response->addHeader('Content-Type: application/json'); + } + + public function cron() { + if ($this->request->get['token'] == $this->config->get('payment_worldpay_secret_token')) { + $this->load->model('extension/payment/worldpay'); + + $orders = $this->model_extension_payment_worldpay->cronPayment(); + + $this->model_extension_payment_worldpay->updateCronJobRunTime(); + + $this->model_extension_payment_worldpay->logger($orders); + } + } + +} diff --git a/public/catalog/controller/extension/recurring/pp_express.php b/public/catalog/controller/extension/recurring/pp_express.php new file mode 100644 index 0000000..0124770 --- /dev/null +++ b/public/catalog/controller/extension/recurring/pp_express.php @@ -0,0 +1,106 @@ +<?php +class ControllerExtensionRecurringPPExpress extends Controller { + public function index() { + $this->load->language('extension/recurring/pp_express'); + + if (isset($this->request->get['order_recurring_id'])) { + $order_recurring_id = $this->request->get['order_recurring_id']; + } else { + $order_recurring_id = 0; + } + + $this->load->model('account/recurring'); + + $recurring_info = $this->model_account_recurring->getOrderRecurring($order_recurring_id); + + if ($recurring_info) { + $data['continue'] = $this->url->link('account/recurring', '', true); + + if ($recurring_info['status'] == 2 || $recurring_info['status'] == 3) { + $data['order_recurring_id'] = $order_recurring_id; + } else { + $data['order_recurring_id'] = ''; + } + + return $this->load->view('extension/recurring/pp_express', $data); + } + } + + public function cancel() { + $json = array(); + + $this->load->language('extension/recurring/pp_express'); + + //cancel an active recurring + $this->load->model('account/recurring'); + + if (isset($this->request->get['order_recurring_id'])) { + $order_recurring_id = $this->request->get['order_recurring_id']; + } else { + $order_recurring_id = 0; + } + + $recurring_info = $this->model_account_recurring->getOrderRecurring($order_recurring_id); + + if ($recurring_info && $recurring_info['reference']) { + if ($this->config->get('payment_pp_express_test')) { + $api_url = 'https://api-3t.sandbox.paypal.com/nvp'; + $api_username = $this->config->get('payment_pp_express_sandbox_username'); + $api_password = $this->config->get('payment_pp_express_sandbox_password'); + $api_signature = $this->config->get('payment_pp_express_sandbox_signature'); + } else { + $api_url = 'https://api-3t.paypal.com/nvp'; + $api_username = $this->config->get('payment_pp_express_username'); + $api_password = $this->config->get('payment_pp_express_password'); + $api_signature = $this->config->get('payment_pp_express_signature'); + } + + $request = array( + 'USER' => $api_username, + 'PWD' => $api_password, + 'SIGNATURE' => $api_signature, + 'VERSION' => '109.0', + 'BUTTONSOURCE' => 'OpenCart_2.0_EC', + 'METHOD' => 'SetExpressCheckout', + 'METHOD' => 'ManageRecurringPaymentsProfileStatus', + 'PROFILEID' => $recurring_info['reference'], + 'ACTION' => 'Cancel' + ); + + $curl = curl_init($api_url); + + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, $request); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HEADER, false); + curl_setopt($curl, CURLOPT_TIMEOUT, 30); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + + $response = curl_exec($curl); + + if (!$response) { + $this->log(sprintf($this->language->get('error_curl'), curl_errno($curl), curl_error($curl))); + } + + curl_close($curl); + + $response_info = array(); + + parse_str($response, $response_info); + + if (isset($response_info['PROFILEID'])) { + $this->model_account_recurring->editOrderRecurringStatus($order_recurring_id, 4); + $this->model_account_recurring->addOrderRecurringTransaction($order_recurring_id, 5); + + $json['success'] = $this->language->get('text_cancelled'); + } else { + $json['error'] = sprintf($this->language->get('error_not_cancelled'), $response_info['L_LONGMESSAGE0']); + } + } else { + $json['error'] = $this->language->get('error_not_found'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/recurring/squareup.php b/public/catalog/controller/extension/recurring/squareup.php new file mode 100644 index 0000000..eabc932 --- /dev/null +++ b/public/catalog/controller/extension/recurring/squareup.php @@ -0,0 +1,170 @@ +<?php +class ControllerExtensionRecurringSquareup extends Controller { + public function index() { + $this->load->language('extension/recurring/squareup'); + + $this->load->model('account/recurring'); + $this->load->model('extension/payment/squareup'); + + if (isset($this->request->get['order_recurring_id'])) { + $order_recurring_id = $this->request->get['order_recurring_id']; + } else { + $order_recurring_id = 0; + } + + $recurring_info = $this->model_account_recurring->getOrderRecurring($order_recurring_id); + + if ($recurring_info) { + $data['cancel_url'] = html_entity_decode($this->url->link('extension/recurring/squareup/cancel', 'order_recurring_id=' . $order_recurring_id, 'SSL')); + + $data['continue'] = $this->url->link('account/recurring', '', true); + + if ($recurring_info['status'] == ModelExtensionPaymentSquareup::RECURRING_ACTIVE) { + $data['order_recurring_id'] = $order_recurring_id; + } else { + $data['order_recurring_id'] = ''; + } + + return $this->load->view('extension/recurring/squareup', $data); + } + } + + public function cancel() { + $this->load->language('extension/recurring/squareup'); + + $this->load->model('account/recurring'); + $this->load->model('extension/payment/squareup'); + + if (isset($this->request->get['order_recurring_id'])) { + $order_recurring_id = $this->request->get['order_recurring_id']; + } else { + $order_recurring_id = 0; + } + + $json = array(); + + $recurring_info = $this->model_account_recurring->getOrderRecurring($order_recurring_id); + + if ($recurring_info) { + $this->model_account_recurring->editOrderRecurringStatus($order_recurring_id, ModelExtensionPaymentSquareup::RECURRING_CANCELLED); + + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($recurring_info['order_id']); + + $this->model_checkout_order->addOrderHistory($recurring_info['order_id'], $order_info['order_status_id'], $this->language->get('text_order_history_cancel'), true); + + $json['success'] = $this->language->get('text_canceled'); + } else { + $json['error'] = $this->language->get('error_not_found'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function recurring() { + $this->load->language('extension/payment/squareup'); + + $this->load->model('extension/payment/squareup'); + + if (!$this->model_extension_payment_squareup->validateCRON()) { + return; + } + + $this->load->library('squareup'); + + $result = array( + 'transaction_success' => array(), + 'transaction_error' => array(), + 'transaction_fail' => array(), + 'token_update_error' => '' + ); + + $result['token_update_error'] = $this->model_extension_payment_squareup->updateToken(); + + $this->load->model('checkout/order'); + + foreach ($this->model_extension_payment_squareup->nextRecurringPayments() as $payment) { + try { + if (!$payment['is_free']) { + $transaction = $this->squareup->addTransaction($payment['transaction']); + + $transaction_status = !empty($transaction['tenders'][0]['card_details']['status']) ? + strtolower($transaction['tenders'][0]['card_details']['status']) : ''; + + $target_currency = $transaction['tenders'][0]['amount_money']['currency']; + + $amount = $this->squareup->standardDenomination($transaction['tenders'][0]['amount_money']['amount'], $target_currency); + + $this->model_extension_payment_squareup->addTransaction($transaction, $this->config->get('payment_squareup_merchant_id'), $payment['billing_address'], $payment['order_id'], "CRON JOB", "127.0.0.1"); + + $reference = $transaction['id']; + } else { + $amount = 0; + $target_currency = $this->config->get('config_currency'); + $reference = ''; + $transaction_status = 'captured'; + } + + $success = $transaction_status == 'captured'; + + $this->model_extension_payment_squareup->addRecurringTransaction($payment['order_recurring_id'], $reference, $amount, $success); + + $trial_expired = false; + $recurring_expired = false; + $profile_suspended = false; + + if ($success) { + $trial_expired = $this->model_extension_payment_squareup->updateRecurringTrial($payment['order_recurring_id']); + + $recurring_expired = $this->model_extension_payment_squareup->updateRecurringExpired($payment['order_recurring_id']); + + $result['transaction_success'][$payment['order_recurring_id']] = $this->currency->format($amount, $target_currency); + } else { + // Transaction was not successful. Suspend the recurring profile. + $profile_suspended = $this->model_extension_payment_squareup->suspendRecurringProfile($payment['order_recurring_id']); + + $result['transaction_fail'][$payment['order_recurring_id']] = $this->currency->format($amount, $target_currency); + } + + + $order_status_id = $this->config->get('payment_squareup_status_' . $transaction_status); + + if ($order_status_id) { + if (!$payment['is_free']) { + $order_status_comment = $this->language->get('squareup_status_comment_' . $transaction_status); + } else { + $order_status_comment = ''; + } + + if ($profile_suspended) { + $order_status_comment .= $this->language->get('text_squareup_profile_suspended'); + } + + if ($trial_expired) { + $order_status_comment .= $this->language->get('text_squareup_trial_expired'); + } + + if ($recurring_expired) { + $order_status_comment .= $this->language->get('text_squareup_recurring_expired'); + } + + if ($success) { + $notify = (bool)$this->config->get('payment_squareup_notify_recurring_success'); + } else { + $notify = (bool)$this->config->get('payment_squareup_notify_recurring_fail'); + } + + $this->model_checkout_order->addOrderHistory($payment['order_id'], $order_status_id, trim($order_status_comment), $notify); + } + } catch (\Squareup\Exception $e) { + $result['transaction_error'][] = '[ID: ' . $payment['order_recurring_id'] . '] - ' . $e->getMessage(); + } + }; + + if ($this->config->get('payment_squareup_cron_email_status')) { + $this->model_extension_payment_squareup->cronEmail($result); + } + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/total/coupon.php b/public/catalog/controller/extension/total/coupon.php new file mode 100644 index 0000000..d7db2c7 --- /dev/null +++ b/public/catalog/controller/extension/total/coupon.php @@ -0,0 +1,49 @@ +<?php +class ControllerExtensionTotalCoupon extends Controller { + public function index() { + if ($this->config->get('total_coupon_status')) { + $this->load->language('extension/total/coupon'); + + if (isset($this->session->data['coupon'])) { + $data['coupon'] = $this->session->data['coupon']; + } else { + $data['coupon'] = ''; + } + + return $this->load->view('extension/total/coupon', $data); + } + } + + public function coupon() { + $this->load->language('extension/total/coupon'); + + $json = array(); + + $this->load->model('extension/total/coupon'); + + if (isset($this->request->post['coupon'])) { + $coupon = $this->request->post['coupon']; + } else { + $coupon = ''; + } + + $coupon_info = $this->model_extension_total_coupon->getCoupon($coupon); + + if (empty($this->request->post['coupon'])) { + $json['error'] = $this->language->get('error_empty'); + + unset($this->session->data['coupon']); + } elseif ($coupon_info) { + $this->session->data['coupon'] = $this->request->post['coupon']; + + $this->session->data['success'] = $this->language->get('text_success'); + + $json['redirect'] = $this->url->link('checkout/cart'); + } else { + $json['error'] = $this->language->get('error_coupon'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } +} diff --git a/public/catalog/controller/extension/total/reward.php b/public/catalog/controller/extension/total/reward.php new file mode 100644 index 0000000..6a3a010 --- /dev/null +++ b/public/catalog/controller/extension/total/reward.php @@ -0,0 +1,73 @@ +<?php +class ControllerExtensionTotalReward extends Controller { + public function index() { + $points = $this->customer->getRewardPoints(); + + $points_total = 0; + + foreach ($this->cart->getProducts() as $product) { + if ($product['points']) { + $points_total += $product['points']; + } + } + + if ($points && $points_total && $this->config->get('total_reward_status')) { + $this->load->language('extension/total/reward'); + + $data['heading_title'] = sprintf($this->language->get('heading_title'), $points); + + $data['entry_reward'] = sprintf($this->language->get('entry_reward'), $points_total); + + if (isset($this->session->data['reward'])) { + $data['reward'] = $this->session->data['reward']; + } else { + $data['reward'] = ''; + } + + return $this->load->view('extension/total/reward', $data); + } + } + + public function reward() { + $this->load->language('extension/total/reward'); + + $json = array(); + + $points = $this->customer->getRewardPoints(); + + $points_total = 0; + + foreach ($this->cart->getProducts() as $product) { + if ($product['points']) { + $points_total += $product['points']; + } + } + + if (empty($this->request->post['reward'])) { + $json['error'] = $this->language->get('error_reward'); + } + + if ($this->request->post['reward'] > $points) { + $json['error'] = sprintf($this->language->get('error_points'), $this->request->post['reward']); + } + + if ($this->request->post['reward'] > $points_total) { + $json['error'] = sprintf($this->language->get('error_maximum'), $points_total); + } + + if (!$json) { + $this->session->data['reward'] = abs($this->request->post['reward']); + + $this->session->data['success'] = $this->language->get('text_success'); + + if (isset($this->request->post['redirect'])) { + $json['redirect'] = $this->url->link($this->request->post['redirect']); + } else { + $json['redirect'] = $this->url->link('checkout/cart'); + } + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } +} diff --git a/public/catalog/controller/extension/total/shipping.php b/public/catalog/controller/extension/total/shipping.php new file mode 100644 index 0000000..d4d67b6 --- /dev/null +++ b/public/catalog/controller/extension/total/shipping.php @@ -0,0 +1,211 @@ +<?php +class ControllerExtensionTotalShipping extends Controller { + public function index() { + if ($this->config->get('total_shipping_status') && $this->config->get('total_shipping_estimator') && $this->cart->hasShipping()) { + $this->load->language('extension/total/shipping'); + + if (isset($this->session->data['shipping_address']['country_id'])) { + $data['country_id'] = $this->session->data['shipping_address']['country_id']; + } else { + $data['country_id'] = $this->config->get('config_country_id'); + } + + $this->load->model('localisation/country'); + + $data['countries'] = $this->model_localisation_country->getCountries(); + + if (isset($this->session->data['shipping_address']['zone_id'])) { + $data['zone_id'] = $this->session->data['shipping_address']['zone_id']; + } else { + $data['zone_id'] = ''; + } + + if (isset($this->session->data['shipping_address']['postcode'])) { + $data['postcode'] = $this->session->data['shipping_address']['postcode']; + } else { + $data['postcode'] = ''; + } + + if (isset($this->session->data['shipping_method'])) { + $data['shipping_method'] = $this->session->data['shipping_method']['code']; + } else { + $data['shipping_method'] = ''; + } + + return $this->load->view('extension/total/shipping', $data); + } + } + + public function quote() { + $this->load->language('extension/total/shipping'); + + $json = array(); + + if (!$this->cart->hasProducts()) { + $json['error']['warning'] = $this->language->get('error_product'); + } + + if (!$this->cart->hasShipping()) { + $json['error']['warning'] = sprintf($this->language->get('error_no_shipping'), $this->url->link('information/contact')); + } + + if ($this->request->post['country_id'] == '') { + $json['error']['country'] = $this->language->get('error_country'); + } + + if (!isset($this->request->post['zone_id']) || $this->request->post['zone_id'] == '') { + $json['error']['zone'] = $this->language->get('error_zone'); + } + + $this->load->model('localisation/country'); + + $country_info = $this->model_localisation_country->getCountry($this->request->post['country_id']); + + if ($country_info && $country_info['postcode_required'] && (utf8_strlen(trim($this->request->post['postcode'])) < 2 || utf8_strlen(trim($this->request->post['postcode'])) > 10)) { + $json['error']['postcode'] = $this->language->get('error_postcode'); + } + + if (!$json) { + $this->tax->setShippingAddress($this->request->post['country_id'], $this->request->post['zone_id']); + + if ($country_info) { + $country = $country_info['name']; + $iso_code_2 = $country_info['iso_code_2']; + $iso_code_3 = $country_info['iso_code_3']; + $address_format = $country_info['address_format']; + } else { + $country = ''; + $iso_code_2 = ''; + $iso_code_3 = ''; + $address_format = ''; + } + + $this->load->model('localisation/zone'); + + $zone_info = $this->model_localisation_zone->getZone($this->request->post['zone_id']); + + if ($zone_info) { + $zone = $zone_info['name']; + $zone_code = $zone_info['code']; + } else { + $zone = ''; + $zone_code = ''; + } + + $this->session->data['shipping_address'] = array( + 'firstname' => '', + 'lastname' => '', + 'company' => '', + 'address_1' => '', + 'address_2' => '', + 'postcode' => $this->request->post['postcode'], + 'city' => '', + 'zone_id' => $this->request->post['zone_id'], + 'zone' => $zone, + 'zone_code' => $zone_code, + 'country_id' => $this->request->post['country_id'], + 'country' => $country, + 'iso_code_2' => $iso_code_2, + 'iso_code_3' => $iso_code_3, + 'address_format' => $address_format + ); + + $quote_data = array(); + + $this->load->model('setting/extension'); + + $results = $this->model_setting_extension->getExtensions('shipping'); + + foreach ($results as $result) { + if ($this->config->get('shipping_' . $result['code'] . '_status')) { + $this->load->model('extension/shipping/' . $result['code']); + + $quote = $this->{'model_extension_shipping_' . $result['code']}->getQuote($this->session->data['shipping_address']); + + if ($quote) { + $quote_data[$result['code']] = array( + 'title' => $quote['title'], + 'quote' => $quote['quote'], + 'sort_order' => $quote['sort_order'], + 'error' => $quote['error'] + ); + } + } + } + + $sort_order = array(); + + foreach ($quote_data as $key => $value) { + $sort_order[$key] = $value['sort_order']; + } + + array_multisort($sort_order, SORT_ASC, $quote_data); + + $this->session->data['shipping_methods'] = $quote_data; + + if ($this->session->data['shipping_methods']) { + $json['shipping_method'] = $this->session->data['shipping_methods']; + } else { + $json['error']['warning'] = sprintf($this->language->get('error_no_shipping'), $this->url->link('information/contact')); + } + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function shipping() { + $this->load->language('extension/total/shipping'); + + $json = array(); + + if (!empty($this->request->post['shipping_method'])) { + $shipping = explode('.', $this->request->post['shipping_method']); + + if (!isset($shipping[0]) || !isset($shipping[1]) || !isset($this->session->data['shipping_methods'][$shipping[0]]['quote'][$shipping[1]])) { + $json['warning'] = $this->language->get('error_shipping'); + } + } else { + $json['warning'] = $this->language->get('error_shipping'); + } + + if (!$json) { + $shipping = explode('.', $this->request->post['shipping_method']); + + $this->session->data['shipping_method'] = $this->session->data['shipping_methods'][$shipping[0]]['quote'][$shipping[1]]; + + $this->session->data['success'] = $this->language->get('text_success'); + + $json['redirect'] = $this->url->link('checkout/cart'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function country() { + $json = array(); + + $this->load->model('localisation/country'); + + $country_info = $this->model_localisation_country->getCountry($this->request->get['country_id']); + + if ($country_info) { + $this->load->model('localisation/zone'); + + $json = array( + 'country_id' => $country_info['country_id'], + 'name' => $country_info['name'], + 'iso_code_2' => $country_info['iso_code_2'], + 'iso_code_3' => $country_info['iso_code_3'], + 'address_format' => $country_info['address_format'], + 'postcode_required' => $country_info['postcode_required'], + 'zone' => $this->model_localisation_zone->getZonesByCountryId($this->request->get['country_id']), + 'status' => $country_info['status'] + ); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } +}
\ No newline at end of file diff --git a/public/catalog/controller/extension/total/voucher.php b/public/catalog/controller/extension/total/voucher.php new file mode 100644 index 0000000..0f7b1bc --- /dev/null +++ b/public/catalog/controller/extension/total/voucher.php @@ -0,0 +1,103 @@ +<?php +class ControllerExtensionTotalVoucher extends Controller { + public function index() { + if ($this->config->get('total_voucher_status')) { + $this->load->language('extension/total/voucher'); + + if (isset($this->session->data['voucher'])) { + $data['voucher'] = $this->session->data['voucher']; + } else { + $data['voucher'] = ''; + } + + return $this->load->view('extension/total/voucher', $data); + } + } + + public function voucher() { + $this->load->language('extension/total/voucher'); + + $json = array(); + + $this->load->model('extension/total/voucher'); + + if (isset($this->request->post['voucher'])) { + $voucher = $this->request->post['voucher']; + } else { + $voucher = ''; + } + + $voucher_info = $this->model_extension_total_voucher->getVoucher($voucher); + + if (empty($this->request->post['voucher'])) { + $json['error'] = $this->language->get('error_empty'); + } elseif ($voucher_info) { + $this->session->data['voucher'] = $this->request->post['voucher']; + + $this->session->data['success'] = $this->language->get('text_success'); + + $json['redirect'] = $this->url->link('checkout/cart'); + } else { + $json['error'] = $this->language->get('error_voucher'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + public function send($route, $args, $output) { + $this->load->model('checkout/order'); + + $order_info = $this->model_checkout_order->getOrder($args[0]); + + // If order status in the complete range create any vouchers that where in the order need to be made available. + if (in_array($order_info['order_status_id'], $this->config->get('config_complete_status'))) { + $voucher_query = $this->db->query("SELECT *, vtd.name AS theme FROM `" . DB_PREFIX . "voucher` v LEFT JOIN " . DB_PREFIX . "voucher_theme vt ON (v.voucher_theme_id = vt.voucher_theme_id) LEFT JOIN " . DB_PREFIX . "voucher_theme_description vtd ON (vt.voucher_theme_id = vtd.voucher_theme_id) WHERE v.order_id = '" . (int)$order_info['order_id'] . "' AND vtd.language_id = '" . (int)$order_info['language_id'] . "'"); + + if ($voucher_query->num_rows) { + // Send out any gift voucher mails + $language = new Language($order_info['language_code']); + $language->load($order_info['language_code']); + $language->load('mail/voucher'); + + foreach ($voucher_query->rows as $voucher) { + // HTML Mail + $data = array(); + + $data['title'] = sprintf($language->get('text_subject'), $voucher['from_name']); + + $data['text_greeting'] = sprintf($language->get('text_greeting'), $this->currency->format($voucher['amount'], $order_info['currency_code'], $order_info['currency_value'])); + $data['text_from'] = sprintf($language->get('text_from'), $voucher['from_name']); + $data['text_message'] = $language->get('text_message'); + $data['text_redeem'] = sprintf($language->get('text_redeem'), $voucher['code']); + $data['text_footer'] = $language->get('text_footer'); + + if (is_file(DIR_IMAGE . $voucher['image'])) { + $data['image'] = $this->config->get('config_url') . 'image/' . $voucher['image']; + } else { + $data['image'] = ''; + } + + $data['store_name'] = $order_info['store_name']; + $data['store_url'] = $order_info['store_url']; + $data['message'] = nl2br($voucher['message']); + + $mail = new Mail($this->config->get('config_mail_engine')); + $mail->parameter = $this->config->get('config_mail_parameter'); + $mail->smtp_hostname = $this->config->get('config_mail_smtp_hostname'); + $mail->smtp_username = $this->config->get('config_mail_smtp_username'); + $mail->smtp_password = html_entity_decode($this->config->get('config_mail_smtp_password'), ENT_QUOTES, 'UTF-8'); + $mail->smtp_port = $this->config->get('config_mail_smtp_port'); + $mail->smtp_timeout = $this->config->get('config_mail_smtp_timeout'); + + $mail->setTo($voucher['to_email']); + $mail->setFrom($this->config->get('config_email')); + $mail->setSender(html_entity_decode($order_info['store_name'], ENT_QUOTES, 'UTF-8')); + $mail->setSubject(html_entity_decode(sprintf($language->get('text_subject'), $voucher['from_name']), ENT_QUOTES, 'UTF-8')); + $mail->setHtml($this->load->view('mail/voucher', $data)); + $mail->send(); + } + } + } + } +} |