diff --git "a/OpenCart 3.x \342\200\224 API 2.0/ReadMe.md" "b/OpenCart 3.x \342\200\224 API 2.0/ReadMe.md" new file mode 100644 index 0000000..abb4a4a --- /dev/null +++ "b/OpenCart 3.x \342\200\224 API 2.0/ReadMe.md" @@ -0,0 +1,14 @@ +## Платежный модуль TRANZZO для CMS OpenCart 3.x + +Тестировался модуль на CMS OpenCart 3.0.2.0 + +### Установка +1. Создать архив **tranzzo.ocmod.zip**, добавить в архив папку **upload** +2. Установить модуль через установщик дополнений, в панели управления зайти в раздел меню _**Дополнения → Установка дополнений**_. +3. Открыть панель управления Вашего сайта и выбрать в меню _**Дополнения → Дополнения**_ , выберать тип дополнения "Платежи". +4. Найдите строчку со способом оплаты TRANZZO и нажмите "Установить". + +### Настройка +1. Получите ключи авторизации и идентификации сервиса TRANZZO (*POS_ID, API_KEY, API_SECRET, ENDPOINTS_KEY*). +2. После установки модуля, на странице списка способов оплаты, нажмите "Редактировать". +3. Настройте способ оплаты, заполнив все необходимые поля. \ No newline at end of file diff --git "a/OpenCart 3.x \342\200\224 API 2.0/upload/admin/controller/extension/payment/tranzzo.php" "b/OpenCart 3.x \342\200\224 API 2.0/upload/admin/controller/extension/payment/tranzzo.php" new file mode 100644 index 0000000..ccb431d --- /dev/null +++ "b/OpenCart 3.x \342\200\224 API 2.0/upload/admin/controller/extension/payment/tranzzo.php" @@ -0,0 +1,267 @@ +load->language('extension/payment/tranzzo'); + $this->document->setTitle($this->language->get('heading_title')); + $data = $this->language->all(); + + if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) { + $this->load->model('setting/setting'); + + $this->model_setting_setting->editSetting('payment_tranzzo', $this->request->post); + + $this->session->data['success'] = $this->language->get('text_success'); + + $this->response->redirect($this->url->link('extension/payment/tranzzo', 'user_token=' . $this->session->data['user_token']. '&type=payment', true)); + } + + if (isset($this->session->data['success'])) { + $data['success'] = $this->session->data['success']; + unset($this->session->data['success']); + } else { + $data['success'] = ''; + } + + if (isset($this->error['warning'])) { + $data['error_warning'] = $this->error['warning']; + } else { + $data['error_warning'] = ''; + } + + if (isset($this->error['pos_id'])) { + $data['error_pos_id'] = $this->error['pos_id']; + } else { + $data['error_pos_id'] = ''; + } + + if (isset($this->error['api_key'])) { + $data['error_api_key'] = $this->error['api_key']; + } else { + $data['error_api_key'] = ''; + } + if (isset($this->error['api_secret'])) { + $data['error_api_secret'] = $this->error['api_secret']; + } else { + $data['error_api_secret'] = ''; + } + if (isset($this->error['endpoints_key'])) { + $data['error_endpoints_key'] = $this->error['endpoints_key']; + } else { + $data['error_endpoints_key'] = ''; + } + + if (isset($this->error['order_status'])) { + $data['error_order_status'] = $this->error['order_status']; + } else { + $data['error_order_status'] = ''; + } + + if (isset($this->error['order_status_complete_id'])) { + $data['error_order_status_complete_id'] = $this->error['order_status_complete_id']; + } else { + $data['error_order_status_complete_id'] = ''; + } + if (isset($this->error['order_status_failure_id'])) { + $data['error_order_status_failure_id'] = $this->error['order_status_failure_id']; + } else { + $data['error_order_status_failure_id'] = ''; + } + if (isset($this->error['order_status_listen'])) { + $data['error_order_status_listen'] = $this->error['order_status_listen']; + } else { + $data['error_order_status_listen'] = ''; + } + + //new + if (isset($this->error['order_status_auth_id'])) { + $data['error_order_status_auth_id'] = $this->error['order_status_auth_id']; + } else { + $data['error_order_status_auth_id'] = ''; + } + //new + + $data['breadcrumbs'] = array(); + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_home'), + 'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'], true) + ); + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_extension'), + 'href' => $this->url->link('extension/extension', 'user_token=' . $this->session->data['user_token'] . '&type=payment', true) + ); + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('heading_title'), + 'href' => $this->url->link('extension/payment/tranzzo', 'user_token=' . $this->session->data['user_token'], true) + ); + + $data['action'] = $this->url->link('extension/payment/tranzzo', 'user_token=' . $this->session->data['user_token'], true); + + $data['cancel'] = $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=payment', true); + + $data['header'] = $this->load->controller('common/header'); + $data['column_left'] = $this->load->controller('common/column_left'); + $data['footer'] = $this->load->controller('common/footer'); + + $data = $this->prepareSettings($data); + + $data['user_token'] = $this->session->data['user_token']; + + $this->response->setOutput($this->load->view('extension/payment/tranzzo', $data)); + + } + + public function prepareSettings($data) + { + $this->load->model('localisation/order_status'); + $data['order_statuses'] = $this->model_localisation_order_status->getOrderStatuses(); + + $this->load->model('localisation/geo_zone'); + $data['geo_zones'] = $this->model_localisation_geo_zone->getGeoZones(); + + if (isset($this->request->post['payment_tranzzo_geo_zone_id'])) { + $data['payment_tranzzo_geo_zone_id'] = $this->request->post['payment_tranzzo_geo_zone_id']; + } else { + $data['payment_tranzzo_geo_zone_id'] = $this->config->get('payment_tranzzo_geo_zone_id'); + } + + if (isset($this->request->post['payment_tranzzo_sort_order'])) { + $data['payment_tranzzo_sort_order'] = $this->request->post['payment_tranzzo_sort_order']; + } else { + $data['payment_tranzzo_sort_order'] = $this->config->get('payment_tranzzo_sort_order'); + } + + if (isset($this->request->post['payment_tranzzo_pos_id'])) { + $data['payment_tranzzo_pos_id'] = $this->request->post['payment_tranzzo_pos_id']; + } else { + $data['payment_tranzzo_pos_id'] = $this->config->get('payment_tranzzo_pos_id'); + } + if (isset($this->request->post['payment_tranzzo_api_secret'])) { + $data['payment_tranzzo_api_secret'] = $this->request->post['payment_tranzzo_api_secret']; + } else { + $data['payment_tranzzo_api_secret'] = $this->config->get('payment_tranzzo_api_secret'); + } + if (isset($this->request->post['payment_tranzzo_api_key'])) { + $data['payment_tranzzo_api_key'] = $this->request->post['payment_tranzzo_api_key']; + } else { + $data['payment_tranzzo_api_key'] = $this->config->get('payment_tranzzo_api_key'); + } + if (isset($this->request->post['payment_tranzzo_endpoints_key'])) { + $data['payment_tranzzo_endpoints_key'] = $this->request->post['payment_tranzzo_endpoints_key']; + } else { + $data['payment_tranzzo_endpoints_key'] = $this->config->get('payment_tranzzo_endpoints_key'); + } + + if (isset($this->request->post['payment_tranzzo_status'])) { + $data['payment_tranzzo_status'] = $this->request->post['payment_tranzzo_status']; + } else { + $data['payment_tranzzo_status'] = $this->config->get('payment_tranzzo_status'); + } + if (isset($this->request->post['payment_tranzzo_total'])) { + $data['payment_tranzzo_total'] = $this->request->post['payment_tranzzo_total']; + } else { + $data['payment_tranzzo_total'] = $this->config->get('payment_tranzzo_total'); + } + if (isset($this->request->post['payment_tranzzo_order_status_complete_id'])) { + $data['payment_tranzzo_order_status_complete_id'] = $this->request->post['payment_tranzzo_order_status_complete_id']; + } else { + $data['payment_tranzzo_order_status_complete_id'] = $this->config->get('payment_tranzzo_order_status_complete_id'); + } + if (isset($this->request->post['payment_tranzzo_order_status_failure_id'])) { + $data['payment_tranzzo_order_status_failure_id'] = $this->request->post['payment_tranzzo_order_status_failure_id']; + } else { + $data['payment_tranzzo_order_status_failure_id'] = $this->config->get('payment_tranzzo_order_status_failure_id'); + } + if (isset($this->request->post['payment_tranzzo_order_status_listen'])) { + $data['payment_tranzzo_order_status_listen'] = $this->request->post['payment_tranzzo_order_status_listen']; + } else { + $data['payment_tranzzo_order_status_listen'] = $this->config->get('payment_tranzzo_order_status_listen'); + } + //new + if (isset($this->request->post['payment_tranzzo_type_payment'])) { + $data['payment_tranzzo_type_payment'] = $this->request->post['payment_tranzzo_type_payment']; + } else { + $data['payment_tranzzo_type_payment'] = $this->config->get('payment_tranzzo_type_payment'); + } + if (isset($this->request->post['payment_tranzzo_order_status_auth_id'])) { + $data['payment_tranzzo_order_status_auth_id'] = $this->request->post['payment_tranzzo_order_status_auth_id']; + } else { + $data['payment_tranzzo_order_status_auth_id'] = $this->config->get('payment_tranzzo_order_status_auth_id'); + } + + return $data; + } + + + protected function validate() + { + if (!$this->user->hasPermission('modify', 'extension/payment/tranzzo')) { + $this->error['warning'] = $this->language->get('error_permission'); + } + if (!$this->request->post['payment_tranzzo_pos_id']) { + $this->error['pos_id'] = $this->language->get('error_pos_id'); + } + if (!$this->request->post['payment_tranzzo_api_key']) { + $this->error['api_key'] = $this->language->get('error_api_key'); + } + if (!$this->request->post['payment_tranzzo_api_secret']) { + $this->error['api_secret'] = $this->language->get('error_api_secret'); + } + if (!$this->request->post['payment_tranzzo_endpoints_key']) { + $this->error['endpoints_key'] = $this->language->get('error_endpoints_key'); + } + if (!$this->request->post['payment_tranzzo_order_status_complete_id']) { + $this->error['order_status_complete_id'] = $this->language->get('error_order_status_complete_id'); + } + if (!$this->request->post['payment_tranzzo_order_status_failure_id']) { + $this->error['order_status_failure_id'] = $this->language->get('error_order_status_failure_id'); + } + + //new + if ($this->request->post['payment_tranzzo_type_payment'] && !$this->request->post['payment_tranzzo_order_status_auth_id']) { + $this->error['order_status_auth_id'] = $this->language->get('error_order_status_auth_id'); + } + //new + + $complete = (int)$this->request->post['payment_tranzzo_order_status_complete_id']; + //new + $auth = (int)$this->request->post['payment_tranzzo_order_status_auth_id']; + //new + $fail = (int)$this->request->post['payment_tranzzo_order_status_failure_id']; + if ($complete == $fail || $complete == $auth || $auth == $fail) { + $this->error['order_status'] = $this->language->get('error_order_status'); + } + + return !$this->error; + } + + public function install() + { + $this->load->model('setting/event'); + + $this->model_setting_event->addEvent('tranzzo', + 'catalog/model/checkout/order/addOrderHistory/before', + 'extension/payment/tranzzo/tranzzoRefund' + ); + + //new + $this->load->model('extension/payment/tranzzo'); + $this->model_extension_payment_tranzzo->install(); + //new + } + + public function uninstall() + { + $this->load->model('setting/event'); + $this->model_setting_event->deleteEvent('tranzzo'); + + //new + $this->load->model('extension/payment/tranzzo'); + $this->model_extension_payment_tranzzo->uninstall(); + //new + } +} \ No newline at end of file diff --git "a/OpenCart 3.x \342\200\224 API 2.0/upload/admin/language/en-gb/extension/payment/tranzzo.php" "b/OpenCart 3.x \342\200\224 API 2.0/upload/admin/language/en-gb/extension/payment/tranzzo.php" new file mode 100644 index 0000000..2a02d84 --- /dev/null +++ "b/OpenCart 3.x \342\200\224 API 2.0/upload/admin/language/en-gb/extension/payment/tranzzo.php" @@ -0,0 +1,43 @@ +TRANZZO'; + +// Entry +$_['entry_pos_id'] = 'POS_ID'; +$_['entry_api_key'] = 'API_KEY'; +$_['entry_api_secret'] = 'API_SECRET'; +$_['entry_endpoints_key'] = 'ENDPOINTS_KEY'; +$_['entry_status'] = 'Status'; +$_['entry_total'] = 'Lower bound'; +$_['entry_order_status_complete'] = 'Order status after payment'; +$_['entry_order_status_failure'] = 'Order status in case of failure'; +$_['entry_order_status_listen'] = 'Order status for refund'; +$_['entry_geo_zone'] = 'Geographical area'; +$_['entry_sort_order'] = 'Sorting order'; +//new +$_['error_type_payment'] = 'type_payment'; +$_['entry_order_status_auth'] = 'Order status after auth payment'; +//new + +// Error +$_['error_permission'] = 'You are not authorized to manage this module!'; +$_['error_pos_id'] = 'It is necessary to fill POS_ID!'; +$_['error_api_key'] = 'You must fill API_KEY!'; +$_['error_api_secret'] = 'API_SECRET must be filled!'; +$_['error_endpoints_key'] = 'You need to fill ENDPOINTS_KEY!'; +$_['error_order_status'] = 'Selected statuses can not be the same'; +$_['error_order_status_complete_id'] = 'You must select a status'; +$_['error_order_status_failure_id'] = 'You must select a status'; +$_['error_order_status_listen'] = 'You must select a status'; +//new +$_['error_order_status_auth_id'] = 'You must select a status'; +//new + +// Help +$_['help_total'] = 'The minimum order amount. Below this amount, the payment method will not be available.'; \ No newline at end of file diff --git "a/OpenCart 3.x \342\200\224 API 2.0/upload/admin/language/ru-ru/extension/payment/tranzzo.php" "b/OpenCart 3.x \342\200\224 API 2.0/upload/admin/language/ru-ru/extension/payment/tranzzo.php" new file mode 100644 index 0000000..abb4040 --- /dev/null +++ "b/OpenCart 3.x \342\200\224 API 2.0/upload/admin/language/ru-ru/extension/payment/tranzzo.php" @@ -0,0 +1,41 @@ +TRANZZO'; + +// Entry +$_['entry_pos_id'] = 'POS_ID'; +$_['entry_api_key'] = 'API_KEY'; +$_['entry_api_secret'] = 'API_SECRET'; +$_['entry_endpoints_key'] = 'ENDPOINTS_KEY'; +$_['entry_status'] = 'Статус'; +$_['entry_total'] = 'Нижняя граница'; +$_['entry_order_status_complete'] = 'Статус заказа после оплаты'; +$_['entry_order_status_failure'] = 'Статус заказа в случае неудачи'; +$_['entry_order_status_listen'] = 'Статус заказа для возврата средств'; +$_['entry_geo_zone'] = 'Географическая зона'; +$_['entry_sort_order'] = 'Порядок сортировки'; +//new +$_['entry_type_payment'] = 'Блокировка платежа'; +$_['entry_order_status_auth'] = 'Статус заказа с заблокированной оплатой'; +//new + +// Error +$_['error_permission'] = 'У Вас нет прав для управления данным модулем!'; +$_['error_pos_id'] = 'Необходимо заполнить POS_ID!'; +$_['error_api_key'] = 'Необходимо заполнить API_KEY!'; +$_['error_api_secret'] = 'Необходимо заполнить API_SECRET!'; +$_['error_endpoints_key'] = 'Необходимо заполнить ENDPOINTS_KEY!'; +$_['error_order_status'] = 'Выбраные статусы немогу совпадать'; +$_['error_order_status_complete_id'] = 'Необходимо выбрать статус'; +$_['error_order_status_failure_id'] = 'Необходимо выбрать статус'; +$_['error_order_status_listen'] = 'Необходимо выбрать статус'; + +// Help +$_['help_total'] = 'Минимальная сумма заказа. Ниже данной суммы, способ оплаты будет недоступен.'; \ No newline at end of file diff --git "a/OpenCart 3.x \342\200\224 API 2.0/upload/admin/model/extension/payment/tranzzo.php" "b/OpenCart 3.x \342\200\224 API 2.0/upload/admin/model/extension/payment/tranzzo.php" new file mode 100644 index 0000000..449a890 --- /dev/null +++ "b/OpenCart 3.x \342\200\224 API 2.0/upload/admin/model/extension/payment/tranzzo.php" @@ -0,0 +1,29 @@ +db->query("ALTER TABLE `" . DB_PREFIX . "order` ADD tranzzo_payment TEXT"); + } + + public function uninstall() + { + $this->db->query("ALTER TABLE `" . DB_PREFIX . "order` DROP tranzzo_payment"); + } +} + +//new + + diff --git "a/OpenCart 3.x \342\200\224 API 2.0/upload/admin/view/image/payment/tranzzo.png" "b/OpenCart 3.x \342\200\224 API 2.0/upload/admin/view/image/payment/tranzzo.png" new file mode 100644 index 0000000..50c59e4 Binary files /dev/null and "b/OpenCart 3.x \342\200\224 API 2.0/upload/admin/view/image/payment/tranzzo.png" differ diff --git "a/OpenCart 3.x \342\200\224 API 2.0/upload/admin/view/template/extension/payment/tranzzo.twig" "b/OpenCart 3.x \342\200\224 API 2.0/upload/admin/view/template/extension/payment/tranzzo.twig" new file mode 100644 index 0000000..f4d7a3f --- /dev/null +++ "b/OpenCart 3.x \342\200\224 API 2.0/upload/admin/view/template/extension/payment/tranzzo.twig" @@ -0,0 +1,255 @@ +{{ header }} {{ column_left }} +
+ +
+ {% if error_warning %} +
{{ error_warning }} + +
+ {% endif %} + {% if success %} +
{{ success }} + +
+ {% endif %} +
+
+

{{ text_edit }}

+
+
+
+
+ +
+ + {% if error_pos_id %} +
{{ error_pos_id }}
+ {% endif %} +
+
+
+ +
+ + {% if error_api_key %} +
{{ error_api_key }}
+ {% endif %} +
+
+
+ +
+ + {% if error_api_secret %} +
{{ error_api_secret }}
+ {% endif %} +
+
+
+ +
+ + {% if error_endpoints_key %} +
{{ error_endpoints_key }}
+ {% endif %} +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + + {% if error_order_status_complete_id %} +
{{ error_order_status_complete_id }}
+ {% endif %} + {% if error_order_status %} +
{{ error_order_status }}
+ {% endif %} +
+
+
+ +
+ + + {% if error_order_status_auth_id %} +
{{ error_order_status_auth_id }}
+ {% endif %} + {% if error_order_status %} +
{{ error_order_status }}
+ {% endif %} +
+
+
+ +
+ + + {% if error_order_status_failure_id %} +
{{ error_order_status_failure_id }}
+ {% endif %} + {% if error_order_status %} +
{{ error_order_status }}
+ {% endif %} +
+
+
+ +
+ {% for order_status in order_statuses %} + {% if (payment_tranzzo_order_status_listen is iterable) and (order_status.order_status_id in payment_tranzzo_order_status_listen) %} + + {% else %} + + {% endif %} + {% endfor %} + + {% if error_order_status_listen %} +
{{ error_order_status_listen }}
+ {% endif %} + {% if error_order_status %} +
{{ error_order_status }}
+ {% endif %} +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+{{ footer }} \ No newline at end of file diff --git "a/OpenCart 3.x \342\200\224 API 2.0/upload/catalog/controller/extension/payment/tranzzo.php" "b/OpenCart 3.x \342\200\224 API 2.0/upload/catalog/controller/extension/payment/tranzzo.php" new file mode 100644 index 0000000..863a1da --- /dev/null +++ "b/OpenCart 3.x \342\200\224 API 2.0/upload/catalog/controller/extension/payment/tranzzo.php" @@ -0,0 +1,370 @@ +load->language('extension/payment/tranzzo'); + $data = $this->language->all(); + + $this->load->model('checkout/order'); + $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']); + + $this->load->library('tranzzoApi'); + + $order_id = $order_info['order_id']; + + $amount = $order_info['total'] * $order_info['currency_value']; + + $params = array(); + $params[TranzzoApi::P_REQ_SERVER_URL] = $this->url->link('extension/payment/tranzzo/callback', '', true); + $params[TranzzoApi::P_REQ_RESULT_URL] = $this->url->link('account/order/info&order_id=' . $order_id, '', true); + $params[TranzzoApi::P_REQ_ORDER] = strval($order_id); + $params[TranzzoApi::P_REQ_AMOUNT] = TranzzoApi::amountToDouble($amount); + $params[TranzzoApi::P_REQ_CURRENCY] = $order_info['currency_code']; + $params[TranzzoApi::P_REQ_DESCRIPTION] = "Order #{$order_id}"; + + if (!empty($order_info['customer_id'])) + $params[TranzzoApi::P_REQ_CUSTOMER_ID] = strval($order_info['customer_id']); + else + $params[TranzzoApi::P_REQ_CUSTOMER_ID] = !empty($order_info['email']) ? $order_info['email'] : 'unregistered'; + + $params[TranzzoApi::P_REQ_CUSTOMER_EMAIL] = !empty($order_info['email']) ? $order_info['email'] : 'unregistered'; + + if (!empty($order_info['firstname'])) + $params[TranzzoApi::P_REQ_CUSTOMER_FNAME] = $order_info['firstname']; + + if (!empty($order_info['lastname'])) + $params[TranzzoApi::P_REQ_CUSTOMER_LNAME] = $order_info['lastname']; + + if (!empty($order_info['telephone'])) + $params[TranzzoApi::P_REQ_CUSTOMER_PHONE] = $order_info['telephone']; + + $params[TranzzoApi::P_REQ_PRODUCTS] = array(); + + $this->load->model('account/order'); + $products = $this->model_account_order->getOrderProducts($order_id); + + if (count($products) > 0) { + $items = array(); + $this->load->model('catalog/product'); + foreach ($products as $product) { + $items[] = array( + 'id' => strval($product['product_id']), + 'name' => $product['name'], + 'url' => $this->url->link('product/product&product_id=' . $product['product_id']), + 'currency' => $order_info['currency_code'], + 'amount' => TranzzoApi::amountToDouble($product['total'] * $order_info['currency_value']), +// 'price_type' => 'gross', // net | gross +// 'vat' => 0, // НДС + 'qty' => intval($product['quantity']), +// 'entity_id' => '', + ); + } + + $params[TranzzoApi::P_REQ_PRODUCTS] = $items; + } + + $response = $this->tranzzoApi->createPaymentHosted($params); + + $data['action'] = $this->url->link('checkout/checkout', '', true); + $data['error'] = !empty($response['message']) ? $response['message'] : ''; + $data['error'] .= (!empty($response['args']) && is_array($response['args'])) ? ', args: ' . implode(', ', $response['args']) : ''; + + if (!empty($response['redirect_url'])) { + $data['redirect_url'] = $response['redirect_url']; + } + + $this->cart->clear(); + + return $this->load->view('extension/payment/tranzzo', $data); + } + + public function callback() + { + //new + //serialize_precision for json_encode + if (version_compare(phpversion(), '7.1', '>=')) { + ini_set('serialize_precision', -1); + } + //new + + $this->load->library('tranzzoApi'); + + $this->tranzzoApi->writeLog('callback', ''); + + if (empty($_POST['data']) || empty($_POST['signature'])) die('LOL! Bad Request!!!'); + $data = $_POST['data']; + $signature = $_POST['signature']; + $data_response = TranzzoApi::notificationDecode($data); + + $this->tranzzoApi->writeLog(array('$data_response', $data_response)); + + $this->load->model('extension/payment/tranzzo'); + + //new + if ($data_response['method'] == 'purchase' || $data_response['method'] == 'auth') { + $order_id = (int)$data_response[TranzzoApi::P_REQ_ORDER];//[TranzzoApi::P_RES_PROV_ORDER]; + } else { + $res = $this->model_extension_payment_tranzzo->getOrderId((int)$data_response['order_id']); + $order_id = $res->row['order_id']; + } + //new + $this->tranzzoApi->writeLog(array('order_id', $order_id)); + + if ($this->tranzzoApi->validateSignature($data, $signature) && $order_id) { + $this->load->language('extension/payment/tranzzo'); + $this->load->model('checkout/order'); + $order_info = $this->model_checkout_order->getOrder($order_id); + $amount_payment = TranzzoApi::amountToDouble($data_response[TranzzoApi::P_REQ_AMOUNT]); + $amount_order = TranzzoApi::amountToDouble($order_info['total'] * $order_info['currency_value']); + + + if ($data_response[TranzzoApi::P_RES_RESP_CODE] == 1000 && $data_response[TranzzoApi::P_REQ_METHOD] == 'purchase') { + // new + $payment_data = [ + 'method' => $data_response[TranzzoApi::P_REQ_METHOD], + 'amount_payment' => $amount_payment, + 'amount_order' => $amount_order, + 'order_id' => $data_response[TranzzoApi::P_REQ_BILL_ORDER] + ]; + + $this->model_extension_payment_tranzzo->addPaymentData($order_id, $payment_data); + // new + $this->model_checkout_order->addOrderHistory( + $order_id, + $this->config->get('payment_tranzzo_order_status_complete_id'), +// "{$this->language->get('text_pay_success')}\n + sprintf($this->language->get('text_pay_success'), $amount_order) . "\n + {$this->language->get('text_payment_id')}: {$data_response[TranzzoApi::P_RES_PAYMENT_ID]}\n + {$this->language->get('text_order')}: {$data_response[TranzzoApi::P_REQ_BILL_ORDER]}" + ); + + } // new + elseif ($data_response[TranzzoApi::P_RES_RESP_CODE] == 1002) { + $payment_data = [ + 'method' => $data_response[TranzzoApi::P_REQ_METHOD], + 'amount_payment' => $amount_payment,// + 'amount_order' => $amount_order, + 'order_id' => $data_response[TranzzoApi::P_REQ_BILL_ORDER], + ]; + $this->model_extension_payment_tranzzo->addPaymentData($order_id, $payment_data); + + $status_name = $this->model_extension_payment_tranzzo->getStatusName($this->config->get('payment_tranzzo_order_status_complete_id'), $this->config->get('config_language_id')); + + $this->model_checkout_order->addOrderHistory( + $order_id, + $this->config->get('payment_tranzzo_order_status_auth_id'), + "{$this->language->get('text_pay_auth')}'" . $status_name->row['name'] . "'\n + {$this->language->get('text_payment_id')}: {$data_response[TranzzoApi::P_RES_PAYMENT_ID]}\n + {$this->language->get('text_order')}: {$data_response[TranzzoApi::P_REQ_BILL_ORDER]}" + ); + } // new + elseif ($data_response['method'] == 'refund' && $data_response['status'] == 'success') { + + //new + $payment_data = [ + 'method' => 'refund', + 'order_id' => $data_response[TranzzoApi::P_REQ_ORDER], + 'refund_amount' => $amount_payment + ]; + + $this->load->model('extension/payment/tranzzo'); + $this->model_extension_payment_tranzzo->addPaymentData($order_id, $payment_data); + //new + + $this->model_checkout_order->addOrderHistory( + $order_id, + '8', + "{$this->language->get('text_pay_refund')}\n + {$this->language->get('text_payment_id')}: {$data_response[TranzzoApi::P_RES_PAYMENT_ID]}\n + {$this->language->get('text_order')}: {$data_response[TranzzoApi::P_REQ_ORDER]}" + + ); + } //new + elseif ($data_response['method'] == 'void' && $data_response['status'] == 'success') { + + //$this->tranzzoApi->writeLog('method void', ''); + + $payment_data = [ + 'method' => 'void', + 'order_id' => $data_response[TranzzoApi::P_REQ_ORDER], + 'refund_amount' => TranzzoApi::amountToDouble($data_response['amount']) + ]; + + //$this->tranzzoApi->writeLog(array('$refund_data', $payment_data)); + + $this->load->model('extension/payment/tranzzo'); + $this->model_extension_payment_tranzzo->addPaymentData($order_id, $payment_data); + + $this->model_checkout_order->addOrderHistory( + $order_id, + 7, // Отменено !!!!!!!!!!!!!!!!! получить статус возврта + "{$this->language->get('text_pay_void')}\n + {$this->language->get('text_payment_id')}: {$data_response[TranzzoApi::P_RES_PAYMENT_ID]}\n + {$this->language->get('text_order')}: {$data_response[TranzzoApi::P_REQ_ORDER]}" + ); + } + elseif ($data_response['method'] == 'capture' && $data_response['status'] == 'success') { + + $this->tranzzoApi->writeLog('method capture', ''); + + $payment_data_old = (array)json_decode($this->model_extension_payment_tranzzo->getPaymentData($order_id)); + + $payment_data = [ + 'method' => 'capture', + 'order_id' => $data_response[TranzzoApi::P_REQ_ORDER], + 'amount_payment' => TranzzoApi::amountToDouble($data_response['amount']), + 'amount_order_new' => $amount_order, + 'amount_order' => TranzzoApi::amountToDouble($payment_data_old['amount_order']) + ]; + + $this->tranzzoApi->writeLog(array('$refund_data', $payment_data)); + + $this->load->model('extension/payment/tranzzo'); + $this->model_extension_payment_tranzzo->addPaymentData($order_id, $payment_data); + + $this->model_checkout_order->addOrderHistory( + $order_id, + $this->config->get('payment_tranzzo_order_status_complete_id'), + sprintf($this->language->get('text_pay_success'), $amount_order) . "\n + {$this->language->get('text_payment_id')}: {$data_response[TranzzoApi::P_RES_PAYMENT_ID]}\n + {$this->language->get('text_order')}: {$data_response[TranzzoApi::P_REQ_ORDER]}" + ); + }//new + else { + $msg = !empty($data_response['response_code']) ? "Response code: {$data_response['response_code']} " : ""; + $msg .= !empty($data_response['response_description']) ? "Description: {$data_response['response_description']}" : ""; + $this->model_checkout_order->addOrderHistory( + $order_id, + $this->config->get('payment_tranzzo_order_status_failure_id'), + $msg + ); + } + } + } + + public function tranzzoRefund($route, &$args) + { + //new + //serialize_precision for json_encode + if (version_compare(phpversion(), '7.1', '>=')) { + ini_set('serialize_precision', -1); + } + //new + + $this->load->library('tranzzoApi'); + $this->tranzzoApi->writeLog(array('$args', $args)); + + + $order_id = (int)$args[0]; + $order_status = $args[1]; + + $this->load->model('checkout/order'); + $order_info = $this->model_checkout_order->getOrder($order_id); + + $order_status_listen = $this->config->get('payment_tranzzo_order_status_listen'); + + if (!empty($order_info) && $order_info['payment_code']) { + + //new + $this->load->model('extension/payment/tranzzo'); + $payment_data = (array)json_decode($this->model_extension_payment_tranzzo->getPaymentData($order_id)); + $this->tranzzoApi->writeLog(array('$payment_data', $payment_data)); + //new + + if (!empty($payment_data)) { + //new capture + $order_status_for_capture = $this->config->get('payment_tranzzo_order_status_complete_id'); + + if ($order_status == $order_status_for_capture && !empty($payment_data['order_id']) && $payment_data['method'] == 'auth') { + $tranzzoOrderId = $payment_data['order_id']; + + $orderAmountNew = $order_info['total'] * $order_info['currency_value']; //сумма заказа + $orderAmountOld = $payment_data['amount_order'] * $order_info['currency_value']; //сумма платежа без комиссии + $tranzzoAmount = $payment_data['amount_payment'] * $order_info['currency_value']; //сумма платежа с комиссией + + $data = [ + 'order_id' => strval($tranzzoOrderId), + 'order_currency' => $order_info['currency_code'], + 'order_amount' => TranzzoApi::amountToDouble($tranzzoAmount), // сумма платежа + 'server_url' => $this->url->link('extension/payment/tranzzo/callback', '', true), + ]; + $this->tranzzoApi->writeLog(array('$response return', $data)); + + if ($orderAmountOld >= $orderAmountNew) + $data['change_amount'] = TranzzoApi::amountToDouble($orderAmountNew);// сумма по заказу + else { + throw new \Exception('Захват не удался! Сумма заказа превышает сумму платежа'); + return false; + } + + $this->tranzzoApi->writeLog(array('capture $data', $data)); + + if ($payment_data['method'] == 'auth') { + $response = $this->tranzzoApi->createCapture($data); + + $this->tranzzoApi->writeLog(array('$response return', $response)); + + if (!empty($response['message'])) { + throw new \Exception('Захват не удался! ' . $response['message']); + return false; + + } + } + } // refund + elseif (is_array($order_status_listen) && in_array($order_status, $order_status_listen)) { + + if (!empty($payment_data['order_id'])) { + $tranzzoOrderId = $payment_data['order_id']; + + $amount = $order_info['total'] * $order_info['currency_value']; + $this->tranzzoApi->writeLog(array('$amount$amount', $amount)); + + //new + $tranzzoAmount = $payment_data['amount_payment'] * $order_info['currency_value']; // сумма блокировки с комиссией + //new + + $data = [ + 'order_id' => strval($tranzzoOrderId), + 'order_currency' => $order_info['currency_code'], + //new + 'order_amount' => TranzzoApi::amountToDouble($tranzzoAmount), // сумма заказа + //new + 'server_url' => $this->url->link('extension/payment/tranzzo/callback', '', true), + ]; + + if ($payment_data['method'] == 'auth') {// auth method + $response = $this->tranzzoApi->createVoid($data); + } else { + if ($payment_data['amount_order'] >= $order_info['total']) { + if ($payment_data['method'] == 'capture') + $data['refund_amount'] = TranzzoApi::amountToDouble($amount); + } else { + throw new \Exception('Возврат не удался! Сумма заказа превышает сумму платежа'); + return false; + } + $response = $this->tranzzoApi->createRefund($data); + } + +// $this->tranzzoApi->writeLog(array('$response return', $response)); + + if (!empty($response['message'])) { + throw new \Exception('Возврат не удался! ' . $response['message']); + return false; + + } else { + $refund_message = sprintf(' Refunded %1$s, Tranzzo order_id: %2$s', $amount, $response['order_id']); + + if (empty($args[2])) $args[2] = ''; + $args[2] .= $refund_message; + } + } else { + $refund_message = sprintf('Refunds Tranzzo impossible, not enough data.'); + $args[2] .= $refund_message; + } + } + } + } + } +} \ No newline at end of file diff --git "a/OpenCart 3.x \342\200\224 API 2.0/upload/catalog/language/en-gb/extension/payment/tranzzo.php" "b/OpenCart 3.x \342\200\224 API 2.0/upload/catalog/language/en-gb/extension/payment/tranzzo.php" new file mode 100644 index 0000000..7cfcd97 --- /dev/null +++ "b/OpenCart 3.x \342\200\224 API 2.0/upload/catalog/language/en-gb/extension/payment/tranzzo.php" @@ -0,0 +1,17 @@ +session->data['currency'], array('USD', 'EUR', 'UAH', 'RUB'))) { + return false; + } + + $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "zone_to_geo_zone WHERE geo_zone_id = '" . (int)$this->config->get('tranzzo_geo_zone_id') . "' AND country_id = '" . (int)$address['country_id'] . "' AND (zone_id = '" . (int)$address['zone_id'] . "' OR zone_id = '0')"); + + if ($this->config->get('tranzzo_total') > 0 && $this->config->get('tranzzo_total') > $total) { + $status = false; + } elseif (!$this->config->get('tranzzo_geo_zone_id')) { + $status = true; + } elseif ($query->num_rows) { + $status = true; + } else { + $status = false; + } + + $method_data = array(); + + if ($status) { + $this->load->language('extension/payment/tranzzo'); + $method_data = array( + 'code' => 'tranzzo', + 'title' => $this->language->get('text_title'), + 'terms' => '', + 'sort_order' => $this->config->get('tranzzo_sort_order') + ); + } + + return $method_data; + } + + //new + public function addPaymentData($order_id, $data) + { + $this->db->query("UPDATE " . DB_PREFIX . "order SET tracking = '" . $this->db->escape($data['order_id']) . "', tranzzo_payment = '" . $this->db->escape(json_encode($data)) . "' WHERE order_id = '" . (int)$order_id . "'"); + } + + public function getOrderId($tranzo_id) + { + $sql = "SELECT order_id FROM " . DB_PREFIX . "order WHERE tracking = '" . (int)$tranzo_id . "'"; + $query = $this->db->query($sql); + return $query; + } + + public function getStatusName($id, $lang) + { + $sql = "SELECT name FROM " . DB_PREFIX . "order_status WHERE order_status_id = '" . (int)$id . "' AND language_id = '" . (int)$lang . "'"; + $query = $this->db->query($sql); + return $query; + } + + public function getPaymentData($order_id) + { + $sql = "SELECT tranzzo_payment FROM " . DB_PREFIX . "order WHERE order_id = '" . (int)$order_id . "'"; + $query = $this->db->query($sql); + + $this->load->library('tranzzoApi'); + $this->tranzzoApi->writeLog(array('getPaymentData $sql', $sql)); + $this->tranzzoApi->writeLog(array('getPaymentData', $query)); + + return $query->row['tranzzo_payment']; + } + //new +} \ No newline at end of file diff --git "a/OpenCart 3.x \342\200\224 API 2.0/upload/catalog/view/theme/default/template/extension/payment/tranzzo.twig" "b/OpenCart 3.x \342\200\224 API 2.0/upload/catalog/view/theme/default/template/extension/payment/tranzzo.twig" new file mode 100644 index 0000000..bd77c03 --- /dev/null +++ "b/OpenCart 3.x \342\200\224 API 2.0/upload/catalog/view/theme/default/template/extension/payment/tranzzo.twig" @@ -0,0 +1,17 @@ +
+ {% if redirect_url %} +
+ +
+ {% else %} +
+
+ +
+
+ {% endif %} +
+

{{ error }}

+ diff --git "a/OpenCart 3.x \342\200\224 API 2.0/upload/system/library/tranzzoApi.php" "b/OpenCart 3.x \342\200\224 API 2.0/upload/system/library/tranzzoApi.php" new file mode 100644 index 0000000..7258f74 --- /dev/null +++ "b/OpenCart 3.x \342\200\224 API 2.0/upload/system/library/tranzzoApi.php" @@ -0,0 +1,369 @@ +registry = $registry; + + $this->posId = trim( $this->config->get('payment_tranzzo_pos_id')); + $this->apiKey = trim( $this->config->get('payment_tranzzo_api_key')); + $this->apiSecret = trim( $this->config->get('payment_tranzzo_api_secret')); + $this->endpointsKey = trim( $this->config->get('payment_tranzzo_endpoints_key')); + + //new + $this->type_payment = ( $this->config->get('payment_tranzzo_type_payment') == '1') ? 1 : 0; + //new + + if(empty($this->posId) || empty($this->apiKey) || empty($this->apiSecret) || empty($this->endpointsKey)){ + self::writeLog('Invalid constructor parameters'); + } + } + + public function __get($name) + { + return $this->registry->get($name); + } + + /** + * @param array $params + * @return mixed + */ + public function createCreditPayment($params = array()) + { + $params[self::P_REQ_METHOD] = 'credit'; + $params[self::P_REQ_POS_ID] = $this->posId; + + $uri = self::U_METHOD_PAYMENT; + $this->setHeader('Content-Type:application/json'); + + return $this->request($params, self::R_METHOD_POST, $uri); + } + + /** + * @param array $params + * @return mixed + */ + public function createPaymentHosted($params = array()) + { + $params[self::P_REQ_POS_ID] = $this->posId; + $params[self::P_REQ_MODE] = self::P_MODE_HOSTED; +// $params[self::P_REQ_METHOD] = 'purchase'; + $params[self::P_REQ_METHOD] = empty($this->type_payment) ? 'purchase' : 'auth'; + $params[self::P_REQ_ORDER_3DS_BYPASS] = 'supported'; + + $this->setHeader('Accept: application/json'); + $this->setHeader('Content-Type: application/json'); + + //self::writeLog(array('createPaymentHosted $params'=>(array)$params)); + + return $this->request($params, self::R_METHOD_POST, self::U_METHOD_PAYMENT); + } + + /** + * @param $params + * @return mixed + */ + public function checkPaymentStatus($params) + { + $uri = self::U_METHOD_POS. '/' . $this->posId . '/orders/' . $params[self::P_REQ_ORDER]; + + return $this->request([], self::R_METHOD_GET, $uri); + } + + /** + * @param $params + * @return mixed + */ + private function request($params, $method, $uri) + { + //new + //serialize_precision for json_encode + if (version_compare(phpversion(), '7.1', '>=')) { + ini_set('serialize_precision', -1); + } + //new + $url = $this->apiUrl . $uri; + $data = json_encode($params); + $this->setHeader('X-API-Auth: CPAY '.$this->apiKey.':'.$this->apiSecret); + $this->setHeader('X-API-KEY: ' . $this->endpointsKey); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + + if($method === self::R_METHOD_POST){ + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + } + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); + curl_setopt($ch, CURLOPT_HEADER, false); + curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers); + + $server_output = curl_exec($ch); + $http_code = curl_getinfo($ch); + $errno = curl_errno($ch); + curl_close($ch); + + if(!$errno && empty($server_output)) + return $http_code; + else + return (json_decode($server_output, true))? json_decode($server_output, true) : $server_output; + } + + /** + * @param $data + * @return mixed|null + */ + public static function notificationDecode($data) + { + return json_decode(self::base64url_decode($data), true); + } + + /** + * @param $data + * @param $requestSign + * @return bool + */ + public function validateSignature($data, $requestSign) + { + $signStr = $this->apiSecret . $data . $this->apiSecret; + $sign = self::base64url_encode(sha1($signStr, true)); + + if ($requestSign !== $sign) { + self::writeLog('signature wrong!'); + return false; + } + + return true; + } + /** + * @param $params + * @return mixed + */ + public function createRefund($params = array()) + { + $params[self::P_REQ_POS_ID] = $this->posId; + + $this->setHeader('Accept: application/json'); + $this->setHeader('Content-Type: application/json'); + + return $this->request($params, self::R_METHOD_POST, self::U_METHOD_REFUND); + } + + //new + public function createVoid($params = array()) + { + $params[self::P_REQ_POS_ID] = $this->posId; + + $this->setHeader('Accept: application/json'); + $this->setHeader('Content-Type: application/json'); + + return $this->request($params, self::R_METHOD_POST, self::U_METHOD_VOID); + } + + public function createCapture($params = array()) + { + self::writeLog('createCapture'); + $params[self::P_REQ_POS_ID] = $this->posId; + + $this->setHeader('Accept: application/json'); + $this->setHeader('Content-Type: application/json'); + + return $this->request($params, self::R_METHOD_POST, self::U_METHOD_CAPTURE); + } + //new + + // + public function getTypeMethod(){ + return $this->type_payment; + } + // + + + /** + * @param $params + * @return string + */ + private function createSign($params) + { + $json = self::base64url_encode( json_encode($params) ); + $signature = $this->strToSign($this->apiSecret . $json . $this->apiSecret); + return $signature; + } + + /** + * @param $str + * @return string + */ + private function strToSign($str) + { + return self::base64url_encode(sha1($str,1)); + } + + /** + * @param $data + * @return string + */ + public static function base64url_encode($data) + { + return strtr(base64_encode($data), '+/', '-_'); + } + /** + * @param $data + * @return bool|string + */ + public static function base64url_decode($data) + { + return base64_decode(strtr($data, '-_', '+/')); + } + + /** + * @param $header + */ + private function setHeader($header) + { + $this->headers[] = $header; + } + + /** + * @param $key + * @return mixed + */ + private function getHeader($key) + { + return $this->headers[$key]; + } + + /** + * @param string $value + * @param int $round + * @return float + */ + static function amountToDouble($value = '', $round = null) + { + $val = floatval($value); + return is_null($round)? $val : round($value, (int)$round); + } + + static function writeLog($data, $flag = '', $filename = '', $append = true) + { + $filename = !empty($filename)? strval($filename) : basename(__FILE__); + file_put_contents(__DIR__ . "/{$filename}.log", "\n\n" . date('H:i:s') . " - $flag \n" . + (is_array($data)? json_encode($data, JSON_PRETTY_PRINT):$data) + , ($append? FILE_APPEND : 0) + ); + } +} + +/* + * изменения АПИ 2.0 + * транзоАпи: + * добавить const P_REQ_BILL_ORDER = 'billing_order_id'; + * изменить значение const P_RES_RESP_CODE = 'status_code'; + * + * каталог/контроллер: + * заменить константу $order_id = (int)$data_response[TranzzoApi::P_REQ_ORDER]; + * добавить для кода=1000 && $data_response[TranzzoApi::P_REQ_METHOD] == 'purchase' + * заменить константу для иф purchase в $payment_data и addOrderHistory P_REQ_ORDER на P_REQ_BILL_ORDER + * заменить константу для иф 1002 в $payment_data и addOrderHistory P_REQ_ORDER на P_REQ_BILL_ORDER + */ \ No newline at end of file