only 2 buttons in asan login, and re-auth system

This commit is contained in:
Ali 2025-05-12 21:05:31 +04:00
parent 4d9cbc008a
commit 0a9ad34362
2 changed files with 363 additions and 92 deletions

View File

@ -467,8 +467,9 @@ def select_certificate(asan_login_name, certificate_data, certificate_name):
}
except Exception as e:
frappe.log_error(f"Error in select_certificate: {str(e)}\n{frappe.get_traceback()}", "Select Certificate Error")
return {"success": False, "message": f"Error: {str(e)}"}
@frappe.whitelist()
def select_taxpayer(asan_login_name):
"""Выбирает налогоплательщика для указанной настройки Asan Login"""
@ -501,6 +502,12 @@ def select_taxpayer(asan_login_name):
if not owner_type or not tin:
return {"success": False, "message": "Invalid certificate data. Cannot determine taxpayer type or ID."}
# Логируем попытку выбора налогоплательщика
frappe.log_error(
f"Attempting to choose taxpayer: type={owner_type}, tin={tin}, bearer_token={asan_login.bearer_token[:10]}...",
"Choose Taxpayer"
)
# Выбираем налогоплательщика
taxpayer_result = choose_taxpayer(asan_login.bearer_token, owner_type, tin)
@ -520,16 +527,29 @@ def select_taxpayer(asan_login_name):
asan_login.auth_status = "Fully Authenticated"
asan_login.save()
# Логируем успешный выбор налогоплательщика
frappe.log_error(
f"Successfully chose taxpayer: type={owner_type}, tin={tin}, main_token={asan_login.main_token[:10]}...",
"Choose Taxpayer Success"
)
return {
"success": True,
"message": "Taxpayer selected successfully."
}
else:
# Логируем ошибку выбора налогоплательщика
frappe.log_error(
f"Failed to choose taxpayer: type={owner_type}, tin={tin}, response={taxpayer_result}",
"Choose Taxpayer Error"
)
return {"success": False, "message": "Failed to select taxpayer."}
except Exception as e:
frappe.log_error(f"Error in select_taxpayer: {str(e)}\n{frappe.get_traceback()}", "Choose Taxpayer Exception")
return {"success": False, "message": f"Error: {str(e)}"}
@frappe.whitelist()
def import_invoice_to_purchase_order(invoice_data, purchase_order=None):
"""Импортирует данные счета-фактуры в Purchase Order"""
@ -2457,3 +2477,17 @@ def create_unmapped_parties(settings_name):
"message": str(e)
}
def handle_unauthorized_request(asan_login_name, operation_name="API request"):
"""Общая функция для обработки неавторизованных запросов"""
# Логирование события
frappe.log_error(
f"Unauthorized request for operation: {operation_name}, asan_login_name: {asan_login_name}",
"Unauthorized API Request"
)
return {
"error": "unauthorized",
"message": "Authentication required. Please login again.",
"operation": operation_name
}

View File

@ -48,80 +48,80 @@ frappe.ui.form.on('Asan Login', {
}, __('Login'));
// Кнопка для получения сертификатов (доступна только если авторизация успешна)
if (frm.doc.auth_status === 'Authenticated' || frm.doc.auth_status === 'Fully Authenticated') {
frm.add_custom_button(__('Get Certificates'), function() {
frappe.call({
method: 'invoice_az.api.get_auth_certificates',
args: {
'asan_login_name': frm.doc.name
},
callback: function(r) {
if (r.message && r.message.success) {
// Обновляем форму после успешного получения сертификатов
frm.reload_doc();
// if (frm.doc.auth_status === 'Authenticated' || frm.doc.auth_status === 'Fully Authenticated') {
// frm.add_custom_button(__('Get Certificates'), function() {
// frappe.call({
// method: 'invoice_az.api.get_auth_certificates',
// args: {
// 'asan_login_name': frm.doc.name
// },
// callback: function(r) {
// if (r.message && r.message.success) {
// // Обновляем форму после успешного получения сертификатов
// frm.reload_doc();
// Показываем сообщение об успешном получении сертификатов
frappe.msgprint({
title: __('Success'),
indicator: 'green',
message: __('Certificates retrieved successfully')
});
// // Показываем сообщение об успешном получении сертификатов
// frappe.msgprint({
// title: __('Success'),
// indicator: 'green',
// message: __('Certificates retrieved successfully')
// });
// Отображаем список сертификатов в диалоговом окне
if (r.message.certificates) {
showCertificatesDialog(r.message.certificates, frm);
}
} else if (r.message && r.message.unauthorized) {
// Если ошибка авторизации, предлагаем авторизоваться заново
showAuthDialog(frm);
} else {
// Другие ошибки
frappe.msgprint({
title: __('Error'),
indicator: 'red',
message: r.message ? r.message.message : __('Failed to get certificates')
});
}
}
});
}, __('Actions'));
}
// // Отображаем список сертификатов в диалоговом окне
// if (r.message.certificates) {
// showCertificatesDialog(r.message.certificates, frm);
// }
// } else if (r.message && r.message.unauthorized) {
// // Если ошибка авторизации, предлагаем авторизоваться заново
// showAuthDialog(frm);
// } else {
// // Другие ошибки
// frappe.msgprint({
// title: __('Error'),
// indicator: 'red',
// message: r.message ? r.message.message : __('Failed to get certificates')
// });
// }
// }
// });
// }, __('Actions'));
// }
// Кнопка для выбора налогоплательщика (доступна если авторизация успешна и сертификат выбран)
if ((frm.doc.auth_status === 'Authenticated' || frm.doc.auth_status === 'Fully Authenticated') &&
frm.doc.selected_certificate) {
frm.add_custom_button(__('Choose Taxpayer'), function() {
frappe.call({
method: 'invoice_az.api.select_taxpayer',
args: {
'asan_login_name': frm.doc.name
},
callback: function(r) {
if (r.message && r.message.success) {
// Обновляем форму после успешного выбора налогоплательщика
frm.reload_doc();
// if ((frm.doc.auth_status === 'Authenticated' || frm.doc.auth_status === 'Fully Authenticated') &&
// frm.doc.selected_certificate) {
// frm.add_custom_button(__('Choose Taxpayer'), function() {
// frappe.call({
// method: 'invoice_az.api.select_taxpayer',
// args: {
// 'asan_login_name': frm.doc.name
// },
// callback: function(r) {
// if (r.message && r.message.success) {
// // Обновляем форму после успешного выбора налогоплательщика
// frm.reload_doc();
// Показываем сообщение об успешном выборе
frappe.msgprint({
title: __('Success'),
indicator: 'green',
message: __('Taxpayer selected successfully')
});
} else if (r.message && r.message.unauthorized) {
// Если ошибка авторизации, предлагаем авторизоваться заново
showAuthDialog(frm);
} else {
// Другие ошибки
frappe.msgprint({
title: __('Error'),
indicator: 'red',
message: r.message ? r.message.message : __('Failed to select taxpayer')
});
}
}
});
}, __('Actions'));
}
// // Показываем сообщение об успешном выборе
// frappe.msgprint({
// title: __('Success'),
// indicator: 'green',
// message: __('Taxpayer selected successfully')
// });
// } else if (r.message && r.message.unauthorized) {
// // Если ошибка авторизации, предлагаем авторизоваться заново
// showAuthDialog(frm);
// } else {
// // Другие ошибки
// frappe.msgprint({
// title: __('Error'),
// indicator: 'red',
// message: r.message ? r.message.message : __('Failed to select taxpayer')
// });
// }
// }
// });
// }, __('Actions'));
// }
// Обработчик изменения выбранного сертификата
if (frm.doc.certificates_json) {
@ -194,7 +194,7 @@ frappe.ui.form.on('Asan Login', {
});
// Функция для запуска опроса через setTimeout вместо setInterval
function startPollingWithTimeout(frm) {
function startPollingWithTimeout(frm, successCallback) {
console.log('startPollingWithTimeout function has been called');
// Отображаем индикатор загрузки
@ -257,15 +257,16 @@ function startPollingWithTimeout(frm) {
`);
$('.lds-dual-ring').css('display', 'none');
// Обновляем поле auth_status
// Обновляем поле auth_status и сохраняем
frm.set_value('auth_status', 'Failed');
frm.save();
// Закрываем диалог через 3 секунды
setTimeout(function() {
// Меняем кнопку на "Close"
status_dialog.set_primary_action(__('Close'), function() {
status_dialog.hide();
frm.reload_doc();
}, 3000);
// Сохраняем документ и затем обновляем его с сервера
frm.save().then(() => frm.reload_doc());
});
}
return;
@ -294,10 +295,28 @@ function startPollingWithTimeout(frm) {
`);
$('.lds-dual-ring').css('display', 'none');
// Закрываем диалоговое окно через 2 секунды
// Обновляем кнопку
status_dialog.set_primary_action(__('Continue'), function() {
status_dialog.hide();
// Вызываем callback после успешной аутентификации, если он предоставлен
if (typeof successCallback === 'function') {
successCallback();
} else {
frm.reload_doc();
}
});
// Автоматически закрываем диалог через 2 секунды
setTimeout(function() {
status_dialog.hide();
frm.reload_doc();
// Вызываем callback после успешной аутентификации, если он предоставлен
if (typeof successCallback === 'function') {
successCallback();
} else {
frm.reload_doc();
}
}, 2000);
} else {
// Продолжаем опрос
@ -316,13 +335,14 @@ function startPollingWithTimeout(frm) {
// Обновляем поле auth_status
frm.set_value('auth_status', 'Failed');
frm.save();
// Закрываем диалог через 3 секунды
setTimeout(function() {
// Меняем кнопку на "Close"
status_dialog.set_primary_action(__('Close'), function() {
status_dialog.hide();
frm.reload_doc();
}, 3000);
// Сохраняем документ и затем обновляем его с сервера
frm.save().then(() => frm.reload_doc());
});
}
},
error: function(err) {
@ -496,22 +516,95 @@ function showAuthDialog(frm) {
primary_action: function() {
d.hide();
// Показываем сообщение о начале аутентификации
frappe.show_alert({
message: __('Starting authentication process...'),
indicator: 'blue'
}, 3);
// Вызываем процесс аутентификации
frappe.call({
method: 'invoice_az.api.handle_authentication',
args: {
'asan_login_name': frm.doc.name
},
freeze: true,
freeze_message: __('Sending authentication request...'),
callback: function(r) {
if (r.message && r.message.success) {
// Сохраняем токен в документе и запускаем опрос статуса
if (r.message.bearer_token) {
frm.set_value('bearer_token', r.message.bearer_token);
frm.save();
}
// Получаем bearer_token из ответа
const bearerToken = r.message.bearer_token;
// Запускаем опрос статуса
startPollingWithTimeout(frm);
// Обновляем значение в документе
frm.set_value('bearer_token', bearerToken);
// Запускаем опрос с передачей сертификата и налогоплательщика как callback
// для автоматического восстановления сессии
pollAuthenticationStatus(frm, function() {
// После успешной аутентификации проверяем, был ли ранее выбран сертификат
if (frm.doc.selected_certificate_json) {
try {
var certData = JSON.parse(frm.doc.selected_certificate_json);
var certName = frm.doc.selected_certificate;
frappe.show_alert({
message: __('Automatically restoring your session...'),
indicator: 'blue'
}, 3);
// Сначала восстанавливаем сертификат
frappe.call({
method: 'invoice_az.api.select_certificate',
args: {
'asan_login_name': frm.doc.name,
'certificate_data': certData,
'certificate_name': certName
},
callback: function(r) {
if (r.message && r.message.success) {
// Затем восстанавливаем налогоплательщика
frappe.call({
method: 'invoice_az.api.select_taxpayer',
args: {
'asan_login_name': frm.doc.name
},
callback: function(r2) {
if (r2.message && r2.message.success) {
frappe.show_alert({
message: __('Session restored successfully'),
indicator: 'green'
}, 5);
} else {
frappe.show_alert({
message: __('Partial session restore - please select certificate manually'),
indicator: 'orange'
}, 5);
}
// Обновляем документ с сервера
frm.reload_doc();
}
});
} else {
frappe.show_alert({
message: __('Please select your certificate manually'),
indicator: 'orange'
}, 5);
// Обновляем документ с сервера
frm.reload_doc();
}
}
});
} catch (e) {
console.error('Error restoring certificate:', e);
frm.reload_doc();
}
} else {
// Если сертификат не выбран, просто обновляем документ
frm.reload_doc();
}
});
} else {
// Показываем сообщение об ошибке
frappe.msgprint({
@ -530,4 +623,148 @@ function showAuthDialog(frm) {
});
d.show();
}
// Отдельная функция для опроса статуса аутентификации
function pollAuthenticationStatus(frm, successCallback) {
// Создаем всплывающее окно с информацией
const status_dialog = new frappe.ui.Dialog({
title: __('Authentication Status'),
fields: [
{
fieldname: 'status_html',
fieldtype: 'HTML',
options: `
<div class="text-center">
<div class="lds-dual-ring" style="display: inline-block; width: 64px; height: 64px;">
<div style="width: 64px; height: 64px; border: 6px solid #4e73df; border-radius: 50%; border-color: #4e73df transparent #4e73df transparent; animation: lds-dual-ring 1.2s linear infinite;"></div>
</div>
<style>
@keyframes lds-dual-ring {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
<div class="mt-3" id="poll_status_message">
<h4>Waiting for confirmation on your phone</h4>
<p>Please check your phone and confirm the authentication request.</p>
</div>
</div>
`
}
],
primary_action_label: __('Cancel'),
primary_action: function() {
// Останавливаем опрос и скрываем диалог
stopPolling = true;
status_dialog.hide();
// Обновляем документ с сервера
frm.reload_doc();
}
});
status_dialog.show();
// Счетчик попыток и флаг для остановки опроса
let attempts = 0;
const maxAttempts = 20; // 20 попыток с интервалом 6 секунд
let stopPolling = false;
// Функция опроса
function pollStatus() {
// Если достигнуто максимальное количество попыток или установлен флаг остановки
if (attempts >= maxAttempts || stopPolling) {
console.log('Polling stopped: ' + (attempts >= maxAttempts ? 'max attempts reached' : 'manually cancelled'));
if (attempts >= maxAttempts) {
// Обновляем информацию в диалоговом окне по таймауту
$('#poll_status_message').html(`
<h4 style="color: red;">Authentication Timeout</h4>
<p>The authentication request has timed out. Please try again.</p>
`);
$('.lds-dual-ring').css('display', 'none');
// Меняем кнопку на "Close"
status_dialog.set_primary_action(__('Close'), function() {
status_dialog.hide();
// Устанавливаем статус "Failed" и перезагружаем документ
frm.set_value('auth_status', 'Failed');
frm.save().then(() => frm.reload_doc());
});
}
return;
}
attempts++;
console.log(`Polling auth status, attempt ${attempts} of ${maxAttempts}`);
// Проверяем статус авторизации
frappe.call({
method: 'invoice_az.api.poll_auth_status',
args: {
'asan_login_name': frm.doc.name,
'bearer_token': frm.doc.bearer_token
},
callback: function(r) {
if (r.message && r.message.success) {
if (r.message.authenticated) {
// Авторизация успешна
stopPolling = true;
// Обновляем информацию в диалоговом окне
$('#poll_status_message').html(`
<h4 style="color: green;">Authentication Successful!</h4>
<p>You are now authenticated.</p>
`);
$('.lds-dual-ring').css('display', 'none');
// Меняем кнопку на "Continue"
status_dialog.set_primary_action(__('Continue'), function() {
status_dialog.hide();
// Выполняем callback, если он предоставлен
if (typeof successCallback === 'function') {
successCallback();
} else {
frm.reload_doc();
}
});
} else {
// Продолжаем опрос
setTimeout(pollStatus, 6000);
}
} else {
// Если ошибка, останавливаем опрос и показываем сообщение
stopPolling = true;
// Обновляем информацию в диалоговом окне
$('#poll_status_message').html(`
<h4 style="color: red;">Authentication Error</h4>
<p>${r.message ? r.message.message : 'An unknown error occurred.'}</p>
`);
$('.lds-dual-ring').css('display', 'none');
// Меняем кнопку на "Close"
status_dialog.set_primary_action(__('Close'), function() {
status_dialog.hide();
// Устанавливаем статус "Failed" и перезагружаем документ
frm.set_value('auth_status', 'Failed');
frm.save().then(() => frm.reload_doc());
});
}
},
error: function(err) {
// В случае ошибки продолжаем опрос
console.error('Error during status check:', err);
setTimeout(pollStatus, 6000);
}
});
}
// Начинаем опрос
pollStatus();
}