diff options
Diffstat (limited to 'public/catalog/controller/extension/payment')
51 files changed, 16319 insertions, 0 deletions
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); + } + } + +} |