(function ($) { "use strict"; var kaspi = function () { var o = this; }; var p = kaspi.prototype; p.webroot = '/'+window.location.pathname.split('/')[1]+'/'; p.url = ''; //адрес терминала p.name = '';//имя кассы для идентификации/регистрации в терминале p.state = 0; //состояние(зарегистрированна касса или нет) p.accessToken = null;//токен доступа p.refreshToken = null;//токен для обновления токена доступа p.expirationDate = null;//срок годности токена доступа p.headers = { 'accesstoken':'' };//заголовки p.processId = null;//идентификатор процесса продажи p.transactionId = null;//идентификатор завершённой транзакции(привязывается к чеку внешней системы) p.transactionMethod = null;//метод оплаты проведенной транзакции p.timerId = null;//идентификатор таймера(по секундный) p.waiting_time = 0;//показатель секунд прошедших в ожидании p.timeout = 240;//лимит ожидания в секундах p.timeoutId = null;//идентификатор таймера опроса терминала p.kaspi_qr = null;//признак включеного kaspi qr в настройках внешней системы p.next_action = null;//метод внешней системы p.next_action_args = null;//метод внешней системы p.load_finish = null; p.refund_data = null; p.refund_check_data = null; p.repeat_func = null; p.repeat_data = null; //инициализация p.init = async function(url, kaspi_qr, next_action) { if (!p.isEmpty(url)) p.url = url; if (!p.isEmpty(kaspi_qr)) p.kaspi_qr = kaspi_qr; if (!p.isEmpty(next_action)) p.next_action = next_action; p.load('start'); // console.log(p.kaspi_qr); // console.log(p.next_action); // console.log(p.state); // console.log(p.accessToken); return $.post(p.webroot + 'Kaspi_api/kaspi/get_state',{}, function(data){ //console.log(data); if (p.is_json(data)) { var obj = JSON.parse(data); if (!p.isEmpty(obj['accessToken'])) { p.set_state(obj); } } p.load('finish'); }); } //устанавливаем состояние для интеграции из сессии сервера внешней системы p.set_state = function(data) { p.state = 0; p.accessToken = null; p.refreshToken = null; p.expirationDate = null; if (data) { if (!p.isEmpty(data['accessToken'])) { p.state = 1; p.name = data['name']; p.accessToken = data['accessToken']; p.refreshToken = data['refreshToken']; p.expirationDate = data['expirationDate']; } p.transactionId = data['transactionId']; } p.reflect_button_connect(); if(p.url) { //const expirationDate = new Date('2023-08-25 15:20:18'); const expirationDate = new Date(p.expirationDate); const now = new Date(); if (expirationDate <= now) {//если токен доступа устарел - обновляем p.revoke({ url:p.url, name:p.name }); } } if (!p.isEmpty(localStorage.getItem('kaspi_repeat_data'))) { var repeat_data = JSON.parse(localStorage.getItem('kaspi_repeat_data')); console.log(repeat_data['transactionId']); if (!p.isEmpty(repeat_data['transactionId'])) { p.repeat(); } else { p.remove_refund_data(); } } } //регистрация или обновление связи с терминалом в настройках внешней системы p.connect = function(data) { if (p.state) p.revoke(data); else p.register(data); }; //регистрация кассы внешней системы в терминале p.register = function(data) { p.url = data.url; p.load('start'); $.get(p.url + '/register?name='+data.name, function(response){ //console.log(response); if (!p.isEmpty(response['accessToken'])) { p.update_session(response); p.set_state(response); ajax_msg('main_kaspi', 'success', 'Подключение прошло успешно', 2); } else { ajax_msg('main_kaspi', 'danger', 'Терминал отклонил попытку подключения или недоступен', 2); } p.load('finish'); }).fail(function(xhr, status, error) { //console.log(xhr);console.log(status);console.log(data); ajax_msg('main_kaspi', 'danger', p.error_message(xhr), 2); p.load('finish'); }); }; //обновление токена доступа внешней системы к терминалу p.revoke = function(data) { p.url = data.url; console.log(p.url + '/revoke?name='+data.name+'&refreshToken='+p.refreshToken); p.load('start'); $.Query(p.url + '/revoke?name='+data.name+'&refreshToken='+p.refreshToken, function(response){ //console.log(response); if (!p.isEmpty(response['accessToken'])) { p.update_session(response); p.set_state(response); ajax_msg('main_kaspi', 'success', 'Подключение обновлено успешно', 2); } else { ajax_msg('main_kaspi', 'danger', 'Терминал отклонил попытку подключения', 2); } p.load('finish'); }).fail(function(xhr, status, error) { if (xhr.responseJSON) { p.reset_session(); p.set_state(); } console.log(xhr);console.log(status);console.log(error); ajax_msg('main_kaspi', 'danger', p.error_message(xhr), 2); p.load('finish'); }); }; //старт процесса продажи на терминале p.payment = function(data) { //console.log(data); p.headers.accesstoken = p.accessToken; $.Query(p.url + '/payment?amount='+data.amount+'&owncheque=false', function(data){ console.log(data); if (!p.isEmpty(data['processId'])) { p.processId = data['processId']; p.polling(); $('#kaspiProcess').modal('show'); } else { ajax_msg('main_kaspi', 'danger', 'Терминал отклонил попытку подключения или недоступен', 2); } p.load('finish'); }).fail(function(xhr, status, error) { console.log(xhr);console.log(status);console.log(data); ajax_msg('main_kaspi', 'danger', p.error_message(xhr), 2); p.stop_timer(); }); }; p.start_refund = function(args, data, callback) { // console.log('start_refund'); // console.log(args); // console.log(p.next_action_args); // console.log(p.refund_data[args[0]]); if (p.isEmpty(localStorage.getItem('kaspi_repeat_args'))) { localStorage.setItem('kaspi_repeat_args', JSON.stringify(args)); } if (data) p.refund_check_data = data; if (callback) p.next_action = callback; else p.next_action = null; p.next_action_args = args; var guid = !args[2] ? 'item'+args[0] : args[0] var check = p.refund_data[guid]; if (args) { p.refund({ amount: check['sum'], method: check['transactionMethod'], transactionId: check['transactionId'], }); } } //возврат c подтверждением от клиентом на терминале p.refund = function(data) { console.log(data); if (p.isEmpty(localStorage.getItem('kaspi_repeat_data'))) { localStorage.setItem('kaspi_repeat_data', JSON.stringify(data)); } p.repeat_data = data; p.headers.accesstoken = p.accessToken; $.Query(p.url + '/refund?amount='+data.amount+'&method='+data.method+'&transactionId='+data.transactionId+'&owncheque=true', function(data){ //console.log(data); if (!p.isEmpty(data['processId'])) { p.processId = data['processId']; p.polling(); $('#kaspiProcess').modal('show'); } else { ajax_msg('main_kaspi', 'danger', 'Терминал отклонил попытку подключения или недоступен', 2); } p.load('finish'); }).fail(function(xhr, status, error) { console.log(xhr);console.log(status);console.log(data); ajax_msg('main_kaspi', 'danger', p.error_message(xhr, true), 2); p.stop_timer(); }); }; //опрос терминала о статусе продажи p.polling = function() { p.start_timer(); p.timeoutId = setTimeout(function poll() { $('#kaspiProcess').modal('show'); p.status().then(function(data) { if (data['status'] === 'wait' && p.waiting_time < p.timeout) { p.timeoutId = setTimeout(poll, 1000); } else { p.stop_timer(); $('#kaspiProcess').modal('hide'); } }); }, 1000); } //старт таймера реализующего общий таймаут на проведение продажи p.start_timer = function() { p.timerId = setInterval(function() { p.waiting_time += 1; }, 1000) } //остановка таймера реализующего общий таймаут на проведение продажи и таймера опроса p.stop_timer = function() { if (p.load_finish) p.load_finish(); clearTimeout(p.timeoutId); clearInterval(p.timerId); } //обработка статуса продажи p.status = function() { p.headers.accesstoken = p.accessToken; return $.Query(p.url + '/status?processId='+p.processId, function(data){ if (!p.isEmpty(data['status'])) { if (data['status'] == 'success') { //console.log(data); //$('#kaspiProcess').modal('hide'); // if (data["chequeInfo"]["method"] == "qr" && p.kaspi_qr) { // $('#kaspi_check').prop("checked", true); // } p.transactionId = data["transactionId"]; if (data["chequeInfo"]) { p.transactionMethod = data["chequeInfo"]["method"]; } // console.log(p.next_action); // console.log(p.next_action_args); // console.log(p.refund_check_data); if (p.next_action) { if (p.refund_check_data) { p.next_action(p.next_action_args[0], p.next_action_args[1], p.refund_check_data); p.next_action = null; } else p.next_action(); } p.remove_refund_data(); } } else { ajax_msg('main_kaspi', 'danger', 'Терминал отклонил попытку подключения или недоступен', 2); } }).fail(function(xhr, status, error) { //console.log(xhr);console.log(status);console.log(data); ajax_msg('main_kaspi', 'danger', p.error_message(xhr), 2); $('#kaspiProcess').modal('hide'); p.stop_timer(); p.remove_refund_data(); }); } //обновляем сессионные переменные kaspi на сервере внешней системы p.update_session = function(data){ $.post(p.webroot + 'Kaspi_api/kaspi/update_session',data, function(response){ console.log('session updated'); }); } //обновляем сессионные переменные kaspi на сервере внешней системы p.reset_session = function(){ $.post(p.webroot + 'Kaspi_api/kaspi/reset_session',{}, function(response){ console.log('session reset'); }); } //поиск ошибок от вебкассы(если продажа на терминале прошла успешно, но продажа во внешней системе прошла без вебкассы) p.webkassa_errors = function() { $.post(p.webroot + 'Kaspi_api/kaspi/webkassa_errors',{}, function(response){ if (p.is_json(response)) { var obj = JSON.parse(response); if (obj['msg']) { if (obj['msg'].includes('(Code2)')) { obj['msg'] += ' Восстановить'; } if (obj['msg'].includes('(Code11)')) { obj['msg'] += ' ---->Закрыть смену'; } setTimeout(function() { ajax_msg('main_kaspi', 'danger', obj['msg'], 2); }, 1200); } } }); } p.set_refund_data = function(json) { if (json) p.refund_data = json; //console.log(p.refund_data); } p.remove_refund_data = function() { localStorage.removeItem('kaspi_repeat_data'); localStorage.removeItem('kaspi_repeat_args'); localStorage.removeItem('kaspi_repeat_check'); } //отображение кнопки подключения к терминалу, в настройках внешней системы p.reflect_button_connect = function() { if (p.state) $('#title_kaspipos_connect').html('Обновить подключение'); else $('#title_kaspipos_connect').html('Подключится'); } //показываем/скрываем процесс загрузки p.load = function(comand){ if (comand == 'start') $('.kaspi_load').addClass('spin'); else $('.kaspi_load').removeClass('spin'); } p.set_load_finish = function(func) { p.load_finish = func; } //обработка ошибок p.error_message = function(xhr, repeat) { if (xhr.responseJSON) return 'Kaspi POS: '+xhr.responseJSON.message; var repeat_btn = ''; if (repeat) { if (!p.isEmpty(localStorage.getItem('kaspi_repeat_data'))) { var repeat_data = JSON.parse(localStorage.getItem('kaspi_repeat_data')); if (!p.isEmpty(repeat_data['transactionId'])) { repeat_btn = ' Отменить | Повторить'; } } } if (p.isEmpty(repeat)) repeat_btn = ' Обновите страницу и попробуйте ещё раз.'; return 'Терминал недоступен или вышло время ожидания.'+repeat_btn; } p.repeat = function() { console.log(p.repeat_func); console.log(p.repeat_data); if (p.repeat_func) { var repeat_data = p.repeat_data; if (p.isEmpty(repeat_data)) { repeat_data = JSON.parse(localStorage.getItem('kaspi_repeat_data')); } if (!p.next_action_args) { p.next_action_args = JSON.parse(localStorage.getItem('kaspi_repeat_args')); } if (!p.refund_check_data) { p.refund_check_data = localStorage.getItem('kaspi_repeat_check'); } if (repeat_data) { p.repeat_func(repeat_data); } //p.repeat_func = null; } } p.is_json = function(str) { try { JSON.parse(str); } catch (e) { return false; } return true; } p.isEmpty = function(str) { return (!str || str.length === 0 ); } $.Query = function(url, callback) { //console.log( p.headers ); // console.log( data ); return $.ajax({ headers: p.headers, 'type': 'GET', 'url': url, 'success': callback, 'timeout': 3000 }); }; p.repeat_func = p.refund; window.Kaspi = new kaspi; }(jQuery));