fix(e-taxes): reliable dialog/progress close + working Cancel across all forms

Under jey_theme/Bootstrap, soft .hide() / frappe.hide_progress() does NOT
reliably remove a modal — it sticks and the next dialog stacks on top of it
(e.g. the ASAN auth "success" message stayed under the date/org picker).
The loading-spinner Cancel button only changed its label, never closing.

- dialogs.hide(): force modal('hide') + remove() + orphaned-backdrop cleanup
  (guarded by .modal:visible); no longer resets cancelLoading there so in-flight
  pagination callbacks still see the cancel and bail out
- Cancel button now actually closes the spinner
- add import._closeProgress() and route every frappe.hide_progress() through a
  robust force-close: purchase/sales order, sales invoice, journal entry,
  employee/AMAS (closeAmasProgress), and the E-Taxes unit list
- E-Taxes list-view loading dialogs (items/customers/suppliers/units) and their
  success paths force-close the same way

Applies the fix uniformly across all ETaxes JS modules and list views.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ali 2026-06-12 16:47:05 +00:00
parent e67a2d2ec1
commit f5b7e56577
13 changed files with 277 additions and 95 deletions

View File

@ -92,10 +92,10 @@ ETaxes.dialogs = {
}], }],
primary_action_label: __('Cancel'), primary_action_label: __('Cancel'),
primary_action: function() { primary_action: function() {
// Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает,
// поэтому in-flight callback'и пагинации увидят отмену и выйдут.
ETaxes.cancelLoading = true; ETaxes.cancelLoading = true;
ETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); ETaxes.dialogs.hide();
ETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...'));
$('#status_message p').text(__('Cancelling the operation.'));
} }
}); });
@ -193,15 +193,24 @@ ETaxes.dialogs = {
// Скрыть диалог // Скрыть диалог
hide: function() { hide: function() {
// Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда убирает модал
// (он зависает и следующий диалог накладывается сверху). Принудительно:
// modal('hide') + remove() + чистка осиротевшего backdrop.
// cancelLoading здесь НЕ сбрасываем — иначе отмена потеряется для in-flight
// callback'ов; флаг сбрасывается в начале операции / при создании диалога.
if (ETaxes.loadingDialog) { if (ETaxes.loadingDialog) {
try { try {
ETaxes.loadingDialog.hide(); ETaxes.loadingDialog.$wrapper.modal('hide');
ETaxes.loadingDialog.$wrapper.remove();
} catch (e) { } catch (e) {
console.error("Error hiding loading dialog:", e); console.error("Error hiding loading dialog:", e);
} }
ETaxes.loadingDialog = null; ETaxes.loadingDialog = null;
} }
ETaxes.cancelLoading = false; if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
}, },
// Получить HTML для диалога загрузки // Получить HTML для диалога загрузки

View File

@ -44,7 +44,15 @@ $(document).on('page:before-change', function() {
function cleanup_customers_loading_state() { function cleanup_customers_loading_state() {
try { try {
// Скрываем прогресс бар // Скрываем прогресс бар
if (frappe.cur_progress) {
try {
frappe.cur_progress.$wrapper.modal('hide');
frappe.cur_progress.$wrapper.remove();
} catch (e) {}
frappe.cur_progress = null;
} else {
frappe.hide_progress(); frappe.hide_progress();
}
// Удаляем event listeners // Удаляем event listeners
$(document).off('progress-cancel.loading_customers'); $(document).off('progress-cancel.loading_customers');
@ -133,14 +141,20 @@ function show_loading_dialog_customers(title, message, submessage) {
// ИСПРАВЛЕННАЯ функция для скрытия диалога загрузки // ИСПРАВЛЕННАЯ функция для скрытия диалога загрузки
function hide_loading_dialog_customers() { function hide_loading_dialog_customers() {
// Принудительное закрытие: soft .hide() в jey_theme/Bootstrap не всегда
// убирает модал (он зависает, и следующий диалог накладывается сверху).
if (loading_dialog_customers) { if (loading_dialog_customers) {
try { try {
loading_dialog_customers.hide(); loading_dialog_customers.$wrapper.modal('hide');
loading_dialog_customers = null; loading_dialog_customers.$wrapper.remove();
} catch (e) { } catch (e) {
console.error('Error hiding loading dialog customers:', e); console.error('Error hiding loading dialog customers:', e);
}
loading_dialog_customers = null; loading_dialog_customers = null;
} }
if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
} }
} }
@ -181,10 +195,7 @@ function set_loading_success_customers(message, submessage, callback, delay = 20
// Автоматически закрываем через указанную задержку // Автоматически закрываем через указанную задержку
setTimeout(function() { setTimeout(function() {
if (loading_dialog_customers) { hide_loading_dialog_customers();
loading_dialog_customers.hide();
loading_dialog_customers = null;
}
if (callback) callback(); if (callback) callback();
}, delay); }, delay);
} else if (callback) { } else if (callback) {

View File

@ -43,7 +43,15 @@ $(document).on('page:before-change', function() {
function cleanup_items_loading_state() { function cleanup_items_loading_state() {
try { try {
// Скрываем прогресс бар // Скрываем прогресс бар
if (frappe.cur_progress) {
try {
frappe.cur_progress.$wrapper.modal('hide');
frappe.cur_progress.$wrapper.remove();
} catch (e) {}
frappe.cur_progress = null;
} else {
frappe.hide_progress(); frappe.hide_progress();
}
// Удаляем event listeners // Удаляем event listeners
$(document).off('progress-cancel.loading_items'); $(document).off('progress-cancel.loading_items');
@ -139,14 +147,20 @@ function show_verification_code_items(code) {
// ИСПРАВЛЕННАЯ функция для скрытия диалога загрузки для items // ИСПРАВЛЕННАЯ функция для скрытия диалога загрузки для items
function hide_loading_dialog_items() { function hide_loading_dialog_items() {
// Принудительное закрытие: soft .hide() в jey_theme/Bootstrap не всегда
// убирает модал (он зависает, и следующий диалог накладывается сверху).
if (loading_dialog_items) { if (loading_dialog_items) {
try { try {
loading_dialog_items.hide(); loading_dialog_items.$wrapper.modal('hide');
loading_dialog_items = null; loading_dialog_items.$wrapper.remove();
} catch (e) { } catch (e) {
console.error('Error hiding loading dialog:', e); console.error('Error hiding loading dialog:', e);
}
loading_dialog_items = null; loading_dialog_items = null;
} }
if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
} }
} }
@ -187,10 +201,7 @@ function set_loading_success_items(message, submessage, callback, delay = 1500)
// Автоматически закрываем через указанную задержку // Автоматически закрываем через указанную задержку
setTimeout(function() { setTimeout(function() {
if (loading_dialog_items) { hide_loading_dialog_items();
loading_dialog_items.hide();
loading_dialog_items = null;
}
if (callback) callback(); if (callback) callback();
}, delay); }, delay);
} else if (callback) { } else if (callback) {

View File

@ -44,7 +44,15 @@ $(document).on('page:before-change', function() {
function cleanup_suppliers_loading_state() { function cleanup_suppliers_loading_state() {
try { try {
// Скрываем прогресс бар // Скрываем прогресс бар
if (frappe.cur_progress) {
try {
frappe.cur_progress.$wrapper.modal('hide');
frappe.cur_progress.$wrapper.remove();
} catch (e) {}
frappe.cur_progress = null;
} else {
frappe.hide_progress(); frappe.hide_progress();
}
// Удаляем event listeners // Удаляем event listeners
$(document).off('progress-cancel.loading_suppliers'); $(document).off('progress-cancel.loading_suppliers');
@ -133,14 +141,20 @@ function show_loading_dialog_suppliers(title, message, submessage) {
// ИСПРАВЛЕННАЯ функция для скрытия диалога загрузки // ИСПРАВЛЕННАЯ функция для скрытия диалога загрузки
function hide_loading_dialog_suppliers() { function hide_loading_dialog_suppliers() {
// Принудительное закрытие: soft .hide() в jey_theme/Bootstrap не всегда
// убирает модал (он зависает, и следующий диалог накладывается сверху).
if (loading_dialog_suppliers) { if (loading_dialog_suppliers) {
try { try {
loading_dialog_suppliers.hide(); loading_dialog_suppliers.$wrapper.modal('hide');
loading_dialog_suppliers = null; loading_dialog_suppliers.$wrapper.remove();
} catch (e) { } catch (e) {
console.error('Error hiding loading dialog suppliers:', e); console.error('Error hiding loading dialog suppliers:', e);
}
loading_dialog_suppliers = null; loading_dialog_suppliers = null;
} }
if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
} }
} }
@ -181,10 +195,7 @@ function set_loading_success_suppliers(message, submessage, callback, delay = 20
// Автоматически закрываем через указанную задержку // Автоматически закрываем через указанную задержку
setTimeout(function() { setTimeout(function() {
if (loading_dialog_suppliers) { hide_loading_dialog_suppliers();
loading_dialog_suppliers.hide();
loading_dialog_suppliers = null;
}
if (callback) callback(); if (callback) callback();
}, delay); }, delay);
} else if (callback) { } else if (callback) {

View File

@ -1,3 +1,20 @@
// Надёжное закрытие прогресс-бара. frappe.hide_progress() в jey_theme/Bootstrap
// не всегда убирает модал (он зависает, и следующий confirm/alert накладывается
// сверху). Принудительно: modal('hide') + remove() + чистка осиротевшего backdrop.
function close_units_progress() {
if (frappe.cur_progress) {
try {
frappe.cur_progress.$wrapper.modal('hide');
frappe.cur_progress.$wrapper.remove();
} catch (e) {}
frappe.cur_progress = null;
}
if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
}
frappe.listview_settings['E-Taxes Unit'] = { frappe.listview_settings['E-Taxes Unit'] = {
add_fields: ['status', 'mapped_unit'], add_fields: ['status', 'mapped_unit'],
@ -92,10 +109,19 @@ function show_verification_code_units(code) {
// Функция для скрытия диалога загрузки для units // Функция для скрытия диалога загрузки для units
function hide_loading_dialog_units() { function hide_loading_dialog_units() {
// Принудительное закрытие: soft .hide() в jey_theme/Bootstrap не всегда
// убирает модал (он зависает, и следующий диалог накладывается сверху).
if (loading_dialog_units) { if (loading_dialog_units) {
loading_dialog_units.hide(); try {
loading_dialog_units.$wrapper.modal('hide');
loading_dialog_units.$wrapper.remove();
} catch (e) {}
loading_dialog_units = null; loading_dialog_units = null;
} }
if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
} }
// Функция для обновления сообщения в диалоге загрузки для units // Функция для обновления сообщения в диалоге загрузки для units
@ -135,10 +161,7 @@ function set_loading_success_units(message, submessage, callback, delay = 1500)
// Автоматически закрываем через указанную задержку // Автоматически закрываем через указанную задержку
setTimeout(function() { setTimeout(function() {
if (loading_dialog_units) { hide_loading_dialog_units();
loading_dialog_units.hide();
loading_dialog_units = null;
}
if (callback) callback(); if (callback) callback();
}, delay); }, delay);
} else if (callback) { } else if (callback) {
@ -781,7 +804,7 @@ function process_invoices_for_units(invoices, token, accumulated_data, current_i
// Проверка отмены // Проверка отмены
if (window.cancelUnitsLoading) { if (window.cancelUnitsLoading) {
frappe.hide_progress(); close_units_progress();
$(document).off('progress-cancel.loading_units'); $(document).off('progress-cancel.loading_units');
frappe.show_alert({ frappe.show_alert({
message: __('Unit extraction cancelled'), message: __('Unit extraction cancelled'),
@ -792,7 +815,7 @@ function process_invoices_for_units(invoices, token, accumulated_data, current_i
// Если все инвойсы обработаны // Если все инвойсы обработаны
if (current_index >= invoices.length) { if (current_index >= invoices.length) {
frappe.hide_progress(); close_units_progress();
$(document).off('progress-cancel.loading_units'); $(document).off('progress-cancel.loading_units');
// Показываем итоговый результат с разбивкой по источникам // Показываем итоговый результат с разбивкой по источникам
@ -864,7 +887,7 @@ function process_invoices_for_units(invoices, token, accumulated_data, current_i
}, 50); // 50ms задержка между инвойсами для предотвращения перегрузки }, 50); // 50ms задержка между инвойсами для предотвращения перегрузки
} else if (r.message && r.message.error === 'unauthorized') { } else if (r.message && r.message.error === 'unauthorized') {
frappe.hide_progress(); close_units_progress();
$(document).off('progress-cancel.loading_units'); $(document).off('progress-cancel.loading_units');
frappe.confirm( frappe.confirm(

View File

@ -844,7 +844,7 @@ function process_employees_one_by_one(listview, asan_login_name, employees_queue
created_count, updated_count, error_count, errors, current_index) { created_count, updated_count, error_count, errors, current_index) {
// Check if finished // Check if finished
if (employees_queue.length === 0) { if (employees_queue.length === 0) {
frappe.hide_progress(); closeAmasProgress();
$(document).off('progress-cancel.loading_amas_employees'); $(document).off('progress-cancel.loading_amas_employees');
const total = created_count + updated_count + error_count; const total = created_count + updated_count + error_count;
@ -858,7 +858,7 @@ function process_employees_one_by_one(listview, asan_login_name, employees_queue
// Check if cancelled // Check if cancelled
if (window.amas_cancel_loading) { if (window.amas_cancel_loading) {
employees_queue = []; employees_queue = [];
frappe.hide_progress(); closeAmasProgress();
$(document).off('progress-cancel.loading_amas_employees'); $(document).off('progress-cancel.loading_amas_employees');
const total = created_count + updated_count + error_count; const total = created_count + updated_count + error_count;
@ -896,7 +896,7 @@ function process_employees_one_by_one(listview, asan_login_name, employees_queue
message: __('Cancelling import... Finishing current employee.'), message: __('Cancelling import... Finishing current employee.'),
indicator: 'orange' indicator: 'orange'
}, 3); }, 3);
frappe.hide_progress(); closeAmasProgress();
}); });
// Get employee name for progress message // Get employee name for progress message

View File

@ -207,10 +207,10 @@ ETaxes.dialogs = {
}], }],
primary_action_label: __('Cancel'), primary_action_label: __('Cancel'),
primary_action: function() { primary_action: function() {
// Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает,
// поэтому in-flight callback'и пагинации увидят отмену и выйдут.
ETaxes.state.cancelLoading = true; ETaxes.state.cancelLoading = true;
ETaxes.state.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); ETaxes.dialogs.hide();
ETaxes.state.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...'));
$('#loading_message').text(__('Cancelling the operation...'));
} }
}); });
@ -294,15 +294,24 @@ ETaxes.dialogs = {
* Hide loading dialog * Hide loading dialog
*/ */
hide: function() { hide: function() {
// Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда убирает модал
// (он зависает и следующий диалог накладывается сверху). Принудительно:
// modal('hide') + remove() + чистка осиротевшего backdrop.
// cancelLoading здесь НЕ сбрасываем — иначе отмена потеряется для in-flight
// callback'ов; флаг сбрасывается в начале операции / при создании диалога.
if (ETaxes.state.loadingDialog) { if (ETaxes.state.loadingDialog) {
try { try {
ETaxes.state.loadingDialog.hide(); ETaxes.state.loadingDialog.$wrapper.modal('hide');
ETaxes.state.loadingDialog.$wrapper.remove();
} catch (e) { } catch (e) {
console.error("Error hiding loading dialog:", e); console.error("Error hiding loading dialog:", e);
} }
ETaxes.state.loadingDialog = null; ETaxes.state.loadingDialog = null;
} }
ETaxes.state.cancelLoading = false; if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
}, },
/** /**

View File

@ -124,10 +124,10 @@ VATETaxes.dialogs = {
}], }],
primary_action_label: __('Cancel'), primary_action_label: __('Cancel'),
primary_action: function() { primary_action: function() {
// Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает,
// поэтому in-flight callback'и пагинации увидят отмену и выйдут.
VATETaxes.cancelLoading = true; VATETaxes.cancelLoading = true;
VATETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); VATETaxes.dialogs.hide();
VATETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...'));
$('#status_message p').text(__('Cancelling the operation.'));
} }
}); });
@ -208,17 +208,28 @@ VATETaxes.dialogs = {
} }
}, },
// Скрыть диалог // Скрыть диалог. Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда
// убирает модал (он зависает и следующий диалог накладывается сверху). Поэтому
// принудительно: modal('hide') + remove() + чистка осиротевшего backdrop —
// тот же приём, что и в _closeProgress.
// cancelLoading здесь НЕ сбрасываем: иначе отмена потеряется для in-flight
// callback'ов. Флаг сбрасывается в начале операции (loadOperations/showLoading).
hide: function() { hide: function() {
if (VATETaxes.loadingDialog) { if (VATETaxes.loadingDialog) {
try { try {
VATETaxes.loadingDialog.hide(); VATETaxes.loadingDialog.$wrapper.modal('hide');
VATETaxes.loadingDialog.$wrapper.remove();
} catch (e) { } catch (e) {
console.error("Error hiding loading dialog:", e); console.error("Error hiding loading dialog:", e);
} }
VATETaxes.loadingDialog = null; VATETaxes.loadingDialog = null;
} }
VATETaxes.cancelLoading = false; // backdrop/scroll-lock убираем только если не осталось видимых модалов
// (иначе сломаем диалог, который показывается следом, напр. выбор даты).
if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
}, },
// Получить HTML для диалога загрузки // Получить HTML для диалога загрузки

View File

@ -98,10 +98,10 @@ ETaxes.dialogs = {
}], }],
primary_action_label: __('Cancel'), primary_action_label: __('Cancel'),
primary_action: function() { primary_action: function() {
// Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает,
// поэтому in-flight callback'и пагинации увидят отмену и выйдут.
ETaxes.cancelLoading = true; ETaxes.cancelLoading = true;
ETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); ETaxes.dialogs.hide();
ETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...'));
$('#status_message p').text(__('Cancelling the operation.'));
} }
}); });
@ -203,15 +203,24 @@ ETaxes.dialogs = {
// Скрыть диалог // Скрыть диалог
hide: function() { hide: function() {
// Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда убирает модал
// (он зависает и следующий диалог накладывается сверху). Принудительно:
// modal('hide') + remove() + чистка осиротевшего backdrop.
// cancelLoading здесь НЕ сбрасываем — иначе отмена потеряется для in-flight
// callback'ов; флаг сбрасывается в начале операции / при создании диалога.
if (ETaxes.loadingDialog) { if (ETaxes.loadingDialog) {
try { try {
ETaxes.loadingDialog.hide(); ETaxes.loadingDialog.$wrapper.modal('hide');
ETaxes.loadingDialog.$wrapper.remove();
} catch (e) { } catch (e) {
console.error("Error hiding loading dialog:", e); console.error("Error hiding loading dialog:", e);
} }
ETaxes.loadingDialog = null; ETaxes.loadingDialog = null;
} }
ETaxes.cancelLoading = false; if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
}, },
// Получить HTML для диалога загрузки // Получить HTML для диалога загрузки

View File

@ -92,10 +92,10 @@ ETaxes.dialogs = {
}], }],
primary_action_label: __('Cancel'), primary_action_label: __('Cancel'),
primary_action: function() { primary_action: function() {
// Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает,
// поэтому in-flight callback'и пагинации увидят отмену и выйдут.
ETaxes.cancelLoading = true; ETaxes.cancelLoading = true;
ETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); ETaxes.dialogs.hide();
ETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...'));
$('#status_message p').text(__('Cancelling the operation.'));
} }
}); });
@ -178,15 +178,24 @@ ETaxes.dialogs = {
// Скрыть диалог // Скрыть диалог
hide: function() { hide: function() {
// Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда убирает модал
// (он зависает и следующий диалог накладывается сверху). Принудительно:
// modal('hide') + remove() + чистка осиротевшего backdrop.
// cancelLoading здесь НЕ сбрасываем — иначе отмена потеряется для in-flight
// callback'ов; флаг сбрасывается в начале операции / при создании диалога.
if (ETaxes.loadingDialog) { if (ETaxes.loadingDialog) {
try { try {
ETaxes.loadingDialog.hide(); ETaxes.loadingDialog.$wrapper.modal('hide');
ETaxes.loadingDialog.$wrapper.remove();
} catch (e) { } catch (e) {
console.error("Error hiding loading dialog:", e); console.error("Error hiding loading dialog:", e);
} }
ETaxes.loadingDialog = null; ETaxes.loadingDialog = null;
} }
ETaxes.cancelLoading = false; if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
}, },
// Получить HTML для диалога загрузки // Получить HTML для диалога загрузки
@ -1188,6 +1197,23 @@ ETaxes.import = {
}); });
}, },
// Надёжное закрытие прогресс-бара. frappe.hide_progress() в jey_theme/Bootstrap
// не всегда убирает модал (он зависает, и summary/диалог накладывается сверху).
// Принудительно: modal('hide') + remove() + чистка осиротевшего backdrop.
_closeProgress: function() {
if (frappe.cur_progress) {
try {
frappe.cur_progress.$wrapper.modal('hide');
frappe.cur_progress.$wrapper.remove();
} catch (e) {}
frappe.cur_progress = null;
}
if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
},
// Загрузка выбранных инвойсов // Загрузка выбранных инвойсов
loadSelectedInvoices: function(invoiceIds, token, warehouse, processedCount = 0, currentIndex = 0) { loadSelectedInvoices: function(invoiceIds, token, warehouse, processedCount = 0, currentIndex = 0) {
if (processedCount === 0 && currentIndex === 0) { if (processedCount === 0 && currentIndex === 0) {
@ -1198,7 +1224,7 @@ ETaxes.import = {
$(document).off('progress-cancel.loading_invoices'); $(document).off('progress-cancel.loading_invoices');
if (invoiceIds.length === 0) { if (invoiceIds.length === 0) {
frappe.hide_progress(); ETaxes.import._closeProgress();
const errorsCount = ETaxes.loadingErrors.length; const errorsCount = ETaxes.loadingErrors.length;
const totalInvoices = window.totalInvoicesToProcess || processedCount; const totalInvoices = window.totalInvoicesToProcess || processedCount;
@ -1215,7 +1241,7 @@ ETaxes.import = {
if (ETaxes.cancelLoading) { if (ETaxes.cancelLoading) {
invoiceIds = []; invoiceIds = [];
frappe.hide_progress(); ETaxes.import._closeProgress();
ETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex); ETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex);
return; return;
} }
@ -1235,7 +1261,7 @@ ETaxes.import = {
message: __('Cancelling import... Finishing current invoice.'), message: __('Cancelling import... Finishing current invoice.'),
indicator: 'orange' indicator: 'orange'
}, 3); }, 3);
frappe.hide_progress(); ETaxes.import._closeProgress();
}); });
frappe.call({ frappe.call({
@ -1279,7 +1305,7 @@ ETaxes.import = {
} }
}); });
} else if (r.message && r.message.error === 'unauthorized') { } else if (r.message && r.message.error === 'unauthorized') {
frappe.hide_progress(); ETaxes.import._closeProgress();
$(document).off('progress-cancel.loading_invoices'); $(document).off('progress-cancel.loading_invoices');
frappe.confirm( frappe.confirm(
@ -1409,7 +1435,7 @@ ETaxes.import = {
// Продолжить или завершить обработку // Продолжить или завершить обработку
_continueOrFinish: function(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice) { _continueOrFinish: function(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice) {
if (isLastInvoice) { if (isLastInvoice) {
frappe.hide_progress(); ETaxes.import._closeProgress();
$(document).off('progress-cancel.loading_invoices'); $(document).off('progress-cancel.loading_invoices');
const totalToProcess = window.totalInvoicesToProcess || processedCount; const totalToProcess = window.totalInvoicesToProcess || processedCount;
@ -1424,7 +1450,7 @@ ETaxes.import = {
setTimeout(function() { setTimeout(function() {
if (invoiceIds.length === 0) { if (invoiceIds.length === 0) {
frappe.hide_progress(); ETaxes.import._closeProgress();
} }
ETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex); ETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex);

View File

@ -92,10 +92,10 @@ ETaxes.dialogs = {
}], }],
primary_action_label: __('Cancel'), primary_action_label: __('Cancel'),
primary_action: function() { primary_action: function() {
// Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает,
// поэтому in-flight callback'и пагинации увидят отмену и выйдут.
ETaxes.cancelLoading = true; ETaxes.cancelLoading = true;
ETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); ETaxes.dialogs.hide();
ETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...'));
$('#status_message p').text(__('Cancelling the operation.'));
} }
}); });
@ -197,15 +197,24 @@ ETaxes.dialogs = {
// Скрыть диалог // Скрыть диалог
hide: function() { hide: function() {
// Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда убирает модал
// (он зависает и следующий диалог накладывается сверху). Принудительно:
// modal('hide') + remove() + чистка осиротевшего backdrop.
// cancelLoading здесь НЕ сбрасываем — иначе отмена потеряется для in-flight
// callback'ов; флаг сбрасывается в начале операции / при создании диалога.
if (ETaxes.loadingDialog) { if (ETaxes.loadingDialog) {
try { try {
ETaxes.loadingDialog.hide(); ETaxes.loadingDialog.$wrapper.modal('hide');
ETaxes.loadingDialog.$wrapper.remove();
} catch (e) { } catch (e) {
console.error("Error hiding loading dialog:", e); console.error("Error hiding loading dialog:", e);
} }
ETaxes.loadingDialog = null; ETaxes.loadingDialog = null;
} }
ETaxes.cancelLoading = false; if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
}, },
// Получить HTML для диалога загрузки // Получить HTML для диалога загрузки
@ -1208,6 +1217,23 @@ ETaxes.import = {
}, },
// Загрузка выбранных инвойсов // Загрузка выбранных инвойсов
// Надёжное закрытие прогресс-бара. frappe.hide_progress() в jey_theme/Bootstrap
// не всегда убирает модал (он зависает, и summary/диалог накладывается сверху).
// Принудительно: modal('hide') + remove() + чистка осиротевшего backdrop.
_closeProgress: function() {
if (frappe.cur_progress) {
try {
frappe.cur_progress.$wrapper.modal('hide');
frappe.cur_progress.$wrapper.remove();
} catch (e) {}
frappe.cur_progress = null;
}
if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
},
loadSelectedInvoices: function(invoiceIds, token, warehouse, processedCount = 0, currentIndex = 0) { loadSelectedInvoices: function(invoiceIds, token, warehouse, processedCount = 0, currentIndex = 0) {
if (processedCount === 0 && currentIndex === 0) { if (processedCount === 0 && currentIndex === 0) {
ETaxes.loadingErrors = []; ETaxes.loadingErrors = [];
@ -1217,7 +1243,7 @@ ETaxes.import = {
$(document).off('progress-cancel.loading_invoices'); $(document).off('progress-cancel.loading_invoices');
if (invoiceIds.length === 0) { if (invoiceIds.length === 0) {
frappe.hide_progress(); ETaxes.import._closeProgress();
const errorsCount = ETaxes.loadingErrors.length; const errorsCount = ETaxes.loadingErrors.length;
const totalInvoices = window.totalInvoicesToProcess || processedCount; const totalInvoices = window.totalInvoicesToProcess || processedCount;
@ -1234,7 +1260,7 @@ ETaxes.import = {
if (ETaxes.cancelLoading) { if (ETaxes.cancelLoading) {
invoiceIds = []; invoiceIds = [];
frappe.hide_progress(); ETaxes.import._closeProgress();
ETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex); ETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex);
return; return;
} }
@ -1254,7 +1280,7 @@ ETaxes.import = {
message: __('Cancelling import... Finishing current invoice.'), message: __('Cancelling import... Finishing current invoice.'),
indicator: 'orange' indicator: 'orange'
}, 3); }, 3);
frappe.hide_progress(); ETaxes.import._closeProgress();
}); });
frappe.call({ frappe.call({
@ -1298,7 +1324,7 @@ ETaxes.import = {
} }
}); });
} else if (r.message && r.message.error === 'unauthorized') { } else if (r.message && r.message.error === 'unauthorized') {
frappe.hide_progress(); ETaxes.import._closeProgress();
$(document).off('progress-cancel.loading_invoices'); $(document).off('progress-cancel.loading_invoices');
frappe.confirm( frappe.confirm(
@ -1428,7 +1454,7 @@ ETaxes.import = {
// Продолжить или завершить обработку // Продолжить или завершить обработку
_continueOrFinish: function(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice) { _continueOrFinish: function(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice) {
if (isLastInvoice) { if (isLastInvoice) {
frappe.hide_progress(); ETaxes.import._closeProgress();
$(document).off('progress-cancel.loading_invoices'); $(document).off('progress-cancel.loading_invoices');
const totalToProcess = window.totalInvoicesToProcess || processedCount; const totalToProcess = window.totalInvoicesToProcess || processedCount;
@ -1443,7 +1469,7 @@ ETaxes.import = {
setTimeout(function() { setTimeout(function() {
if (invoiceIds.length === 0) { if (invoiceIds.length === 0) {
frappe.hide_progress(); ETaxes.import._closeProgress();
} }
ETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex); ETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex);

View File

@ -92,10 +92,10 @@ SalesETaxes.dialogs = {
}], }],
primary_action_label: __('Cancel'), primary_action_label: __('Cancel'),
primary_action: function() { primary_action: function() {
// Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает,
// поэтому in-flight callback'и пагинации увидят отмену и выйдут.
SalesETaxes.cancelLoading = true; SalesETaxes.cancelLoading = true;
SalesETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); SalesETaxes.dialogs.hide();
SalesETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...'));
$('#status_message p').text(__('Cancelling the operation.'));
} }
}); });
@ -176,17 +176,27 @@ SalesETaxes.dialogs = {
} }
}, },
// Скрыть диалог // Скрыть диалог. Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда
// убирает модал (он зависает и следующий диалог накладывается сверху). Поэтому
// принудительно: modal('hide') + remove() + чистка осиротевшего backdrop.
// cancelLoading здесь НЕ сбрасываем: иначе отмена потеряется для in-flight
// callback'ов. Флаг сбрасывается в начале операции (loadInvoices/showLoading).
hide: function() { hide: function() {
if (SalesETaxes.loadingDialog) { if (SalesETaxes.loadingDialog) {
try { try {
SalesETaxes.loadingDialog.hide(); SalesETaxes.loadingDialog.$wrapper.modal('hide');
SalesETaxes.loadingDialog.$wrapper.remove();
} catch (e) { } catch (e) {
console.error("Error hiding loading dialog:", e); console.error("Error hiding loading dialog:", e);
} }
SalesETaxes.loadingDialog = null; SalesETaxes.loadingDialog = null;
} }
SalesETaxes.cancelLoading = false; // backdrop/scroll-lock убираем только если не осталось видимых модалов
// (иначе сломаем диалог, который показывается следом, напр. выбор даты).
if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
}, },
// Получить HTML для диалога загрузки // Получить HTML для диалога загрузки
@ -1205,6 +1215,23 @@ SalesETaxes.import = {
}, },
// Загрузка выбранных инвойсов // Загрузка выбранных инвойсов
// Надёжное закрытие прогресс-бара. frappe.hide_progress() в jey_theme/Bootstrap
// не всегда убирает модал (он зависает, и summary/диалог накладывается сверху).
// Принудительно: modal('hide') + remove() + чистка осиротевшего backdrop.
_closeProgress: function() {
if (frappe.cur_progress) {
try {
frappe.cur_progress.$wrapper.modal('hide');
frappe.cur_progress.$wrapper.remove();
} catch (e) {}
frappe.cur_progress = null;
}
if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
},
loadSelectedInvoices: function(invoiceIds, token, warehouse, processedCount = 0, currentIndex = 0) { loadSelectedInvoices: function(invoiceIds, token, warehouse, processedCount = 0, currentIndex = 0) {
if (processedCount === 0 && currentIndex === 0) { if (processedCount === 0 && currentIndex === 0) {
SalesETaxes.loadingErrors = []; SalesETaxes.loadingErrors = [];
@ -1214,7 +1241,7 @@ SalesETaxes.import = {
$(document).off('progress-cancel.loading_sales_invoices'); $(document).off('progress-cancel.loading_sales_invoices');
if (invoiceIds.length === 0) { if (invoiceIds.length === 0) {
frappe.hide_progress(); SalesETaxes.import._closeProgress();
const errorsCount = SalesETaxes.loadingErrors.length; const errorsCount = SalesETaxes.loadingErrors.length;
const totalInvoices = window.totalSalesInvoicesToProcess || processedCount; const totalInvoices = window.totalSalesInvoicesToProcess || processedCount;
@ -1231,7 +1258,7 @@ SalesETaxes.import = {
if (SalesETaxes.cancelLoading) { if (SalesETaxes.cancelLoading) {
invoiceIds = []; invoiceIds = [];
frappe.hide_progress(); SalesETaxes.import._closeProgress();
SalesETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex); SalesETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex);
return; return;
} }
@ -1251,7 +1278,7 @@ SalesETaxes.import = {
message: __('Cancelling import... Finishing current sales invoice.'), message: __('Cancelling import... Finishing current sales invoice.'),
indicator: 'orange' indicator: 'orange'
}, 3); }, 3);
frappe.hide_progress(); SalesETaxes.import._closeProgress();
}); });
frappe.call({ frappe.call({
@ -1295,7 +1322,7 @@ SalesETaxes.import = {
} }
}); });
} else if (r.message && r.message.error === 'unauthorized') { } else if (r.message && r.message.error === 'unauthorized') {
frappe.hide_progress(); SalesETaxes.import._closeProgress();
$(document).off('progress-cancel.loading_sales_invoices'); $(document).off('progress-cancel.loading_sales_invoices');
frappe.confirm( frappe.confirm(
@ -1474,7 +1501,7 @@ SalesETaxes.import = {
// Продолжить или завершить обработку // Продолжить или завершить обработку
_continueOrFinish: function(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice) { _continueOrFinish: function(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice) {
if (isLastInvoice) { if (isLastInvoice) {
frappe.hide_progress(); SalesETaxes.import._closeProgress();
$(document).off('progress-cancel.loading_sales_invoices'); $(document).off('progress-cancel.loading_sales_invoices');
const totalToProcess = window.totalSalesInvoicesToProcess || processedCount; const totalToProcess = window.totalSalesInvoicesToProcess || processedCount;
@ -1489,7 +1516,7 @@ SalesETaxes.import = {
setTimeout(function() { setTimeout(function() {
if (invoiceIds.length === 0) { if (invoiceIds.length === 0) {
frappe.hide_progress(); SalesETaxes.import._closeProgress();
} }
SalesETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex); SalesETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex);

View File

@ -92,10 +92,10 @@ ETaxes.dialogs = {
}], }],
primary_action_label: __('Cancel'), primary_action_label: __('Cancel'),
primary_action: function() { primary_action: function() {
// Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает,
// поэтому in-flight callback'и пагинации увидят отмену и выйдут.
ETaxes.cancelLoading = true; ETaxes.cancelLoading = true;
ETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); ETaxes.dialogs.hide();
ETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...'));
$('#status_message p').text(__('Cancelling the operation.'));
} }
}); });
@ -197,15 +197,24 @@ ETaxes.dialogs = {
// Скрыть диалог // Скрыть диалог
hide: function() { hide: function() {
// Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда убирает модал
// (он зависает и следующий диалог накладывается сверху). Принудительно:
// modal('hide') + remove() + чистка осиротевшего backdrop.
// cancelLoading здесь НЕ сбрасываем — иначе отмена потеряется для in-flight
// callback'ов; флаг сбрасывается в начале операции / при создании диалога.
if (ETaxes.loadingDialog) { if (ETaxes.loadingDialog) {
try { try {
ETaxes.loadingDialog.hide(); ETaxes.loadingDialog.$wrapper.modal('hide');
ETaxes.loadingDialog.$wrapper.remove();
} catch (e) { } catch (e) {
console.error("Error hiding loading dialog:", e); console.error("Error hiding loading dialog:", e);
} }
ETaxes.loadingDialog = null; ETaxes.loadingDialog = null;
} }
ETaxes.cancelLoading = false; if ($('.modal:visible').length === 0) {
$('.modal-backdrop').remove();
$('body').removeClass('modal-open');
}
}, },
// Получить HTML для диалога загрузки // Получить HTML для диалога загрузки