From f5b7e565777fb53caad5bff3cc244bc887ee96a0 Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Fri, 12 Jun 2026 16:47:05 +0000 Subject: [PATCH] fix(e-taxes): reliable dialog/progress close + working Cancel across all forms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- invoice_az/client/company.js | 19 ++++++-- invoice_az/client/e_taxes_customers_list.js | 27 +++++++---- invoice_az/client/e_taxes_items_list.js | 27 +++++++---- invoice_az/client/e_taxes_suppliers_list.js | 27 +++++++---- invoice_az/client/e_taxes_unit_list.js | 39 ++++++++++++---- invoice_az/client/employee.js | 6 +-- invoice_az/client/etaxes_common.js | 19 ++++++-- invoice_az/client/journal_entry.js | 23 +++++++--- invoice_az/client/purchase_invoice.js | 19 ++++++-- invoice_az/client/purchase_order.js | 48 ++++++++++++++----- invoice_az/client/sales_invoice.js | 48 ++++++++++++++----- invoice_az/client/sales_order.js | 51 ++++++++++++++++----- invoice_az/client/supplier.js | 19 ++++++-- 13 files changed, 277 insertions(+), 95 deletions(-) diff --git a/invoice_az/client/company.js b/invoice_az/client/company.js index 8b7868a..1e78e8f 100644 --- a/invoice_az/client/company.js +++ b/invoice_az/client/company.js @@ -92,10 +92,10 @@ ETaxes.dialogs = { }], primary_action_label: __('Cancel'), primary_action: function() { + // Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает, + // поэтому in-flight callback'и пагинации увидят отмену и выйдут. ETaxes.cancelLoading = true; - ETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); - ETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...')); - $('#status_message p').text(__('Cancelling the operation.')); + ETaxes.dialogs.hide(); } }); @@ -193,15 +193,24 @@ ETaxes.dialogs = { // Скрыть диалог hide: function() { + // Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда убирает модал + // (он зависает и следующий диалог накладывается сверху). Принудительно: + // modal('hide') + remove() + чистка осиротевшего backdrop. + // cancelLoading здесь НЕ сбрасываем — иначе отмена потеряется для in-flight + // callback'ов; флаг сбрасывается в начале операции / при создании диалога. if (ETaxes.loadingDialog) { try { - ETaxes.loadingDialog.hide(); + ETaxes.loadingDialog.$wrapper.modal('hide'); + ETaxes.loadingDialog.$wrapper.remove(); } catch (e) { console.error("Error hiding loading dialog:", e); } ETaxes.loadingDialog = null; } - ETaxes.cancelLoading = false; + if ($('.modal:visible').length === 0) { + $('.modal-backdrop').remove(); + $('body').removeClass('modal-open'); + } }, // Получить HTML для диалога загрузки diff --git a/invoice_az/client/e_taxes_customers_list.js b/invoice_az/client/e_taxes_customers_list.js index d788f92..665a131 100644 --- a/invoice_az/client/e_taxes_customers_list.js +++ b/invoice_az/client/e_taxes_customers_list.js @@ -44,7 +44,15 @@ $(document).on('page:before-change', function() { function cleanup_customers_loading_state() { try { // Скрываем прогресс бар - frappe.hide_progress(); + 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(); + } // Удаляем event listeners $(document).off('progress-cancel.loading_customers'); @@ -133,14 +141,20 @@ function show_loading_dialog_customers(title, message, submessage) { // ИСПРАВЛЕННАЯ функция для скрытия диалога загрузки function hide_loading_dialog_customers() { + // Принудительное закрытие: soft .hide() в jey_theme/Bootstrap не всегда + // убирает модал (он зависает, и следующий диалог накладывается сверху). if (loading_dialog_customers) { try { - loading_dialog_customers.hide(); - loading_dialog_customers = null; + loading_dialog_customers.$wrapper.modal('hide'); + loading_dialog_customers.$wrapper.remove(); } catch (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() { - if (loading_dialog_customers) { - loading_dialog_customers.hide(); - loading_dialog_customers = null; - } + hide_loading_dialog_customers(); if (callback) callback(); }, delay); } else if (callback) { diff --git a/invoice_az/client/e_taxes_items_list.js b/invoice_az/client/e_taxes_items_list.js index 4c88784..35a3822 100644 --- a/invoice_az/client/e_taxes_items_list.js +++ b/invoice_az/client/e_taxes_items_list.js @@ -43,7 +43,15 @@ $(document).on('page:before-change', function() { function cleanup_items_loading_state() { try { // Скрываем прогресс бар - frappe.hide_progress(); + 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(); + } // Удаляем event listeners $(document).off('progress-cancel.loading_items'); @@ -139,14 +147,20 @@ function show_verification_code_items(code) { // ИСПРАВЛЕННАЯ функция для скрытия диалога загрузки для items function hide_loading_dialog_items() { + // Принудительное закрытие: soft .hide() в jey_theme/Bootstrap не всегда + // убирает модал (он зависает, и следующий диалог накладывается сверху). if (loading_dialog_items) { try { - loading_dialog_items.hide(); - loading_dialog_items = null; + loading_dialog_items.$wrapper.modal('hide'); + loading_dialog_items.$wrapper.remove(); } catch (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() { - if (loading_dialog_items) { - loading_dialog_items.hide(); - loading_dialog_items = null; - } + hide_loading_dialog_items(); if (callback) callback(); }, delay); } else if (callback) { diff --git a/invoice_az/client/e_taxes_suppliers_list.js b/invoice_az/client/e_taxes_suppliers_list.js index da725d4..8643a4b 100644 --- a/invoice_az/client/e_taxes_suppliers_list.js +++ b/invoice_az/client/e_taxes_suppliers_list.js @@ -44,7 +44,15 @@ $(document).on('page:before-change', function() { function cleanup_suppliers_loading_state() { try { // Скрываем прогресс бар - frappe.hide_progress(); + 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(); + } // Удаляем event listeners $(document).off('progress-cancel.loading_suppliers'); @@ -133,14 +141,20 @@ function show_loading_dialog_suppliers(title, message, submessage) { // ИСПРАВЛЕННАЯ функция для скрытия диалога загрузки function hide_loading_dialog_suppliers() { + // Принудительное закрытие: soft .hide() в jey_theme/Bootstrap не всегда + // убирает модал (он зависает, и следующий диалог накладывается сверху). if (loading_dialog_suppliers) { try { - loading_dialog_suppliers.hide(); - loading_dialog_suppliers = null; + loading_dialog_suppliers.$wrapper.modal('hide'); + loading_dialog_suppliers.$wrapper.remove(); } catch (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() { - if (loading_dialog_suppliers) { - loading_dialog_suppliers.hide(); - loading_dialog_suppliers = null; - } + hide_loading_dialog_suppliers(); if (callback) callback(); }, delay); } else if (callback) { diff --git a/invoice_az/client/e_taxes_unit_list.js b/invoice_az/client/e_taxes_unit_list.js index ce374d4..0f64e4f 100644 --- a/invoice_az/client/e_taxes_unit_list.js +++ b/invoice_az/client/e_taxes_unit_list.js @@ -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'] = { add_fields: ['status', 'mapped_unit'], @@ -92,10 +109,19 @@ function show_verification_code_units(code) { // Функция для скрытия диалога загрузки для units function hide_loading_dialog_units() { + // Принудительное закрытие: soft .hide() в jey_theme/Bootstrap не всегда + // убирает модал (он зависает, и следующий диалог накладывается сверху). 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; } + if ($('.modal:visible').length === 0) { + $('.modal-backdrop').remove(); + $('body').removeClass('modal-open'); + } } // Функция для обновления сообщения в диалоге загрузки для units @@ -135,10 +161,7 @@ function set_loading_success_units(message, submessage, callback, delay = 1500) // Автоматически закрываем через указанную задержку setTimeout(function() { - if (loading_dialog_units) { - loading_dialog_units.hide(); - loading_dialog_units = null; - } + hide_loading_dialog_units(); if (callback) callback(); }, delay); } else if (callback) { @@ -781,7 +804,7 @@ function process_invoices_for_units(invoices, token, accumulated_data, current_i // Проверка отмены if (window.cancelUnitsLoading) { - frappe.hide_progress(); + close_units_progress(); $(document).off('progress-cancel.loading_units'); frappe.show_alert({ message: __('Unit extraction cancelled'), @@ -792,7 +815,7 @@ function process_invoices_for_units(invoices, token, accumulated_data, current_i // Если все инвойсы обработаны if (current_index >= invoices.length) { - frappe.hide_progress(); + close_units_progress(); $(document).off('progress-cancel.loading_units'); // Показываем итоговый результат с разбивкой по источникам @@ -864,7 +887,7 @@ function process_invoices_for_units(invoices, token, accumulated_data, current_i }, 50); // 50ms задержка между инвойсами для предотвращения перегрузки } else if (r.message && r.message.error === 'unauthorized') { - frappe.hide_progress(); + close_units_progress(); $(document).off('progress-cancel.loading_units'); frappe.confirm( diff --git a/invoice_az/client/employee.js b/invoice_az/client/employee.js index 4f475c9..915c10b 100644 --- a/invoice_az/client/employee.js +++ b/invoice_az/client/employee.js @@ -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) { // Check if finished if (employees_queue.length === 0) { - frappe.hide_progress(); + closeAmasProgress(); $(document).off('progress-cancel.loading_amas_employees'); 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 if (window.amas_cancel_loading) { employees_queue = []; - frappe.hide_progress(); + closeAmasProgress(); $(document).off('progress-cancel.loading_amas_employees'); 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.'), indicator: 'orange' }, 3); - frappe.hide_progress(); + closeAmasProgress(); }); // Get employee name for progress message diff --git a/invoice_az/client/etaxes_common.js b/invoice_az/client/etaxes_common.js index 707a291..2ba6dff 100644 --- a/invoice_az/client/etaxes_common.js +++ b/invoice_az/client/etaxes_common.js @@ -207,10 +207,10 @@ ETaxes.dialogs = { }], primary_action_label: __('Cancel'), primary_action: function() { + // Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает, + // поэтому in-flight callback'и пагинации увидят отмену и выйдут. ETaxes.state.cancelLoading = true; - ETaxes.state.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); - ETaxes.state.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...')); - $('#loading_message').text(__('Cancelling the operation...')); + ETaxes.dialogs.hide(); } }); @@ -294,15 +294,24 @@ ETaxes.dialogs = { * Hide loading dialog */ hide: function() { + // Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда убирает модал + // (он зависает и следующий диалог накладывается сверху). Принудительно: + // modal('hide') + remove() + чистка осиротевшего backdrop. + // cancelLoading здесь НЕ сбрасываем — иначе отмена потеряется для in-flight + // callback'ов; флаг сбрасывается в начале операции / при создании диалога. if (ETaxes.state.loadingDialog) { try { - ETaxes.state.loadingDialog.hide(); + ETaxes.state.loadingDialog.$wrapper.modal('hide'); + ETaxes.state.loadingDialog.$wrapper.remove(); } catch (e) { console.error("Error hiding loading dialog:", e); } ETaxes.state.loadingDialog = null; } - ETaxes.state.cancelLoading = false; + if ($('.modal:visible').length === 0) { + $('.modal-backdrop').remove(); + $('body').removeClass('modal-open'); + } }, /** diff --git a/invoice_az/client/journal_entry.js b/invoice_az/client/journal_entry.js index a9bf96e..663897c 100644 --- a/invoice_az/client/journal_entry.js +++ b/invoice_az/client/journal_entry.js @@ -124,10 +124,10 @@ VATETaxes.dialogs = { }], primary_action_label: __('Cancel'), primary_action: function() { + // Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает, + // поэтому in-flight callback'и пагинации увидят отмену и выйдут. VATETaxes.cancelLoading = true; - VATETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); - VATETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...')); - $('#status_message p').text(__('Cancelling the operation.')); + VATETaxes.dialogs.hide(); } }); @@ -208,17 +208,28 @@ VATETaxes.dialogs = { } }, - // Скрыть диалог + // Скрыть диалог. Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда + // убирает модал (он зависает и следующий диалог накладывается сверху). Поэтому + // принудительно: modal('hide') + remove() + чистка осиротевшего backdrop — + // тот же приём, что и в _closeProgress. + // cancelLoading здесь НЕ сбрасываем: иначе отмена потеряется для in-flight + // callback'ов. Флаг сбрасывается в начале операции (loadOperations/showLoading). hide: function() { if (VATETaxes.loadingDialog) { try { - VATETaxes.loadingDialog.hide(); + VATETaxes.loadingDialog.$wrapper.modal('hide'); + VATETaxes.loadingDialog.$wrapper.remove(); } catch (e) { console.error("Error hiding loading dialog:", e); } VATETaxes.loadingDialog = null; } - VATETaxes.cancelLoading = false; + // backdrop/scroll-lock убираем только если не осталось видимых модалов + // (иначе сломаем диалог, который показывается следом, напр. выбор даты). + if ($('.modal:visible').length === 0) { + $('.modal-backdrop').remove(); + $('body').removeClass('modal-open'); + } }, // Получить HTML для диалога загрузки diff --git a/invoice_az/client/purchase_invoice.js b/invoice_az/client/purchase_invoice.js index 9bb01dc..ae1712b 100644 --- a/invoice_az/client/purchase_invoice.js +++ b/invoice_az/client/purchase_invoice.js @@ -98,10 +98,10 @@ ETaxes.dialogs = { }], primary_action_label: __('Cancel'), primary_action: function() { + // Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает, + // поэтому in-flight callback'и пагинации увидят отмену и выйдут. ETaxes.cancelLoading = true; - ETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); - ETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...')); - $('#status_message p').text(__('Cancelling the operation.')); + ETaxes.dialogs.hide(); } }); @@ -203,15 +203,24 @@ ETaxes.dialogs = { // Скрыть диалог hide: function() { + // Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда убирает модал + // (он зависает и следующий диалог накладывается сверху). Принудительно: + // modal('hide') + remove() + чистка осиротевшего backdrop. + // cancelLoading здесь НЕ сбрасываем — иначе отмена потеряется для in-flight + // callback'ов; флаг сбрасывается в начале операции / при создании диалога. if (ETaxes.loadingDialog) { try { - ETaxes.loadingDialog.hide(); + ETaxes.loadingDialog.$wrapper.modal('hide'); + ETaxes.loadingDialog.$wrapper.remove(); } catch (e) { console.error("Error hiding loading dialog:", e); } ETaxes.loadingDialog = null; } - ETaxes.cancelLoading = false; + if ($('.modal:visible').length === 0) { + $('.modal-backdrop').remove(); + $('body').removeClass('modal-open'); + } }, // Получить HTML для диалога загрузки diff --git a/invoice_az/client/purchase_order.js b/invoice_az/client/purchase_order.js index 030ba07..b4600ea 100644 --- a/invoice_az/client/purchase_order.js +++ b/invoice_az/client/purchase_order.js @@ -92,10 +92,10 @@ ETaxes.dialogs = { }], primary_action_label: __('Cancel'), primary_action: function() { + // Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает, + // поэтому in-flight callback'и пагинации увидят отмену и выйдут. ETaxes.cancelLoading = true; - ETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); - ETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...')); - $('#status_message p').text(__('Cancelling the operation.')); + ETaxes.dialogs.hide(); } }); @@ -178,15 +178,24 @@ ETaxes.dialogs = { // Скрыть диалог hide: function() { + // Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда убирает модал + // (он зависает и следующий диалог накладывается сверху). Принудительно: + // modal('hide') + remove() + чистка осиротевшего backdrop. + // cancelLoading здесь НЕ сбрасываем — иначе отмена потеряется для in-flight + // callback'ов; флаг сбрасывается в начале операции / при создании диалога. if (ETaxes.loadingDialog) { try { - ETaxes.loadingDialog.hide(); + ETaxes.loadingDialog.$wrapper.modal('hide'); + ETaxes.loadingDialog.$wrapper.remove(); } catch (e) { console.error("Error hiding loading dialog:", e); } ETaxes.loadingDialog = null; } - ETaxes.cancelLoading = false; + if ($('.modal:visible').length === 0) { + $('.modal-backdrop').remove(); + $('body').removeClass('modal-open'); + } }, // Получить 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) { if (processedCount === 0 && currentIndex === 0) { @@ -1198,7 +1224,7 @@ ETaxes.import = { $(document).off('progress-cancel.loading_invoices'); if (invoiceIds.length === 0) { - frappe.hide_progress(); + ETaxes.import._closeProgress(); const errorsCount = ETaxes.loadingErrors.length; const totalInvoices = window.totalInvoicesToProcess || processedCount; @@ -1215,7 +1241,7 @@ ETaxes.import = { if (ETaxes.cancelLoading) { invoiceIds = []; - frappe.hide_progress(); + ETaxes.import._closeProgress(); ETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex); return; } @@ -1235,7 +1261,7 @@ ETaxes.import = { message: __('Cancelling import... Finishing current invoice.'), indicator: 'orange' }, 3); - frappe.hide_progress(); + ETaxes.import._closeProgress(); }); frappe.call({ @@ -1279,7 +1305,7 @@ ETaxes.import = { } }); } else if (r.message && r.message.error === 'unauthorized') { - frappe.hide_progress(); + ETaxes.import._closeProgress(); $(document).off('progress-cancel.loading_invoices'); frappe.confirm( @@ -1409,7 +1435,7 @@ ETaxes.import = { // Продолжить или завершить обработку _continueOrFinish: function(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice) { if (isLastInvoice) { - frappe.hide_progress(); + ETaxes.import._closeProgress(); $(document).off('progress-cancel.loading_invoices'); const totalToProcess = window.totalInvoicesToProcess || processedCount; @@ -1424,7 +1450,7 @@ ETaxes.import = { setTimeout(function() { if (invoiceIds.length === 0) { - frappe.hide_progress(); + ETaxes.import._closeProgress(); } ETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex); diff --git a/invoice_az/client/sales_invoice.js b/invoice_az/client/sales_invoice.js index 68f66aa..da4db8b 100644 --- a/invoice_az/client/sales_invoice.js +++ b/invoice_az/client/sales_invoice.js @@ -92,10 +92,10 @@ ETaxes.dialogs = { }], primary_action_label: __('Cancel'), primary_action: function() { + // Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает, + // поэтому in-flight callback'и пагинации увидят отмену и выйдут. ETaxes.cancelLoading = true; - ETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); - ETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...')); - $('#status_message p').text(__('Cancelling the operation.')); + ETaxes.dialogs.hide(); } }); @@ -197,15 +197,24 @@ ETaxes.dialogs = { // Скрыть диалог hide: function() { + // Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда убирает модал + // (он зависает и следующий диалог накладывается сверху). Принудительно: + // modal('hide') + remove() + чистка осиротевшего backdrop. + // cancelLoading здесь НЕ сбрасываем — иначе отмена потеряется для in-flight + // callback'ов; флаг сбрасывается в начале операции / при создании диалога. if (ETaxes.loadingDialog) { try { - ETaxes.loadingDialog.hide(); + ETaxes.loadingDialog.$wrapper.modal('hide'); + ETaxes.loadingDialog.$wrapper.remove(); } catch (e) { console.error("Error hiding loading dialog:", e); } ETaxes.loadingDialog = null; } - ETaxes.cancelLoading = false; + if ($('.modal:visible').length === 0) { + $('.modal-backdrop').remove(); + $('body').removeClass('modal-open'); + } }, // Получить 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) { if (processedCount === 0 && currentIndex === 0) { ETaxes.loadingErrors = []; @@ -1217,7 +1243,7 @@ ETaxes.import = { $(document).off('progress-cancel.loading_invoices'); if (invoiceIds.length === 0) { - frappe.hide_progress(); + ETaxes.import._closeProgress(); const errorsCount = ETaxes.loadingErrors.length; const totalInvoices = window.totalInvoicesToProcess || processedCount; @@ -1234,7 +1260,7 @@ ETaxes.import = { if (ETaxes.cancelLoading) { invoiceIds = []; - frappe.hide_progress(); + ETaxes.import._closeProgress(); ETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex); return; } @@ -1254,7 +1280,7 @@ ETaxes.import = { message: __('Cancelling import... Finishing current invoice.'), indicator: 'orange' }, 3); - frappe.hide_progress(); + ETaxes.import._closeProgress(); }); frappe.call({ @@ -1298,7 +1324,7 @@ ETaxes.import = { } }); } else if (r.message && r.message.error === 'unauthorized') { - frappe.hide_progress(); + ETaxes.import._closeProgress(); $(document).off('progress-cancel.loading_invoices'); frappe.confirm( @@ -1428,7 +1454,7 @@ ETaxes.import = { // Продолжить или завершить обработку _continueOrFinish: function(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice) { if (isLastInvoice) { - frappe.hide_progress(); + ETaxes.import._closeProgress(); $(document).off('progress-cancel.loading_invoices'); const totalToProcess = window.totalInvoicesToProcess || processedCount; @@ -1443,7 +1469,7 @@ ETaxes.import = { setTimeout(function() { if (invoiceIds.length === 0) { - frappe.hide_progress(); + ETaxes.import._closeProgress(); } ETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex); diff --git a/invoice_az/client/sales_order.js b/invoice_az/client/sales_order.js index c2b8794..478723d 100644 --- a/invoice_az/client/sales_order.js +++ b/invoice_az/client/sales_order.js @@ -92,10 +92,10 @@ SalesETaxes.dialogs = { }], primary_action_label: __('Cancel'), primary_action: function() { + // Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает, + // поэтому in-flight callback'и пагинации увидят отмену и выйдут. SalesETaxes.cancelLoading = true; - SalesETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); - SalesETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...')); - $('#status_message p').text(__('Cancelling the operation.')); + SalesETaxes.dialogs.hide(); } }); @@ -176,17 +176,27 @@ SalesETaxes.dialogs = { } }, - // Скрыть диалог + // Скрыть диалог. Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда + // убирает модал (он зависает и следующий диалог накладывается сверху). Поэтому + // принудительно: modal('hide') + remove() + чистка осиротевшего backdrop. + // cancelLoading здесь НЕ сбрасываем: иначе отмена потеряется для in-flight + // callback'ов. Флаг сбрасывается в начале операции (loadInvoices/showLoading). hide: function() { if (SalesETaxes.loadingDialog) { try { - SalesETaxes.loadingDialog.hide(); + SalesETaxes.loadingDialog.$wrapper.modal('hide'); + SalesETaxes.loadingDialog.$wrapper.remove(); } catch (e) { console.error("Error hiding loading dialog:", e); } SalesETaxes.loadingDialog = null; } - SalesETaxes.cancelLoading = false; + // backdrop/scroll-lock убираем только если не осталось видимых модалов + // (иначе сломаем диалог, который показывается следом, напр. выбор даты). + if ($('.modal:visible').length === 0) { + $('.modal-backdrop').remove(); + $('body').removeClass('modal-open'); + } }, // Получить 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) { if (processedCount === 0 && currentIndex === 0) { SalesETaxes.loadingErrors = []; @@ -1214,7 +1241,7 @@ SalesETaxes.import = { $(document).off('progress-cancel.loading_sales_invoices'); if (invoiceIds.length === 0) { - frappe.hide_progress(); + SalesETaxes.import._closeProgress(); const errorsCount = SalesETaxes.loadingErrors.length; const totalInvoices = window.totalSalesInvoicesToProcess || processedCount; @@ -1231,7 +1258,7 @@ SalesETaxes.import = { if (SalesETaxes.cancelLoading) { invoiceIds = []; - frappe.hide_progress(); + SalesETaxes.import._closeProgress(); SalesETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex); return; } @@ -1251,7 +1278,7 @@ SalesETaxes.import = { message: __('Cancelling import... Finishing current sales invoice.'), indicator: 'orange' }, 3); - frappe.hide_progress(); + SalesETaxes.import._closeProgress(); }); frappe.call({ @@ -1295,7 +1322,7 @@ SalesETaxes.import = { } }); } else if (r.message && r.message.error === 'unauthorized') { - frappe.hide_progress(); + SalesETaxes.import._closeProgress(); $(document).off('progress-cancel.loading_sales_invoices'); frappe.confirm( @@ -1474,7 +1501,7 @@ SalesETaxes.import = { // Продолжить или завершить обработку _continueOrFinish: function(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice) { if (isLastInvoice) { - frappe.hide_progress(); + SalesETaxes.import._closeProgress(); $(document).off('progress-cancel.loading_sales_invoices'); const totalToProcess = window.totalSalesInvoicesToProcess || processedCount; @@ -1489,7 +1516,7 @@ SalesETaxes.import = { setTimeout(function() { if (invoiceIds.length === 0) { - frappe.hide_progress(); + SalesETaxes.import._closeProgress(); } SalesETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex); diff --git a/invoice_az/client/supplier.js b/invoice_az/client/supplier.js index 53c5c7c..dfbbc2b 100644 --- a/invoice_az/client/supplier.js +++ b/invoice_az/client/supplier.js @@ -92,10 +92,10 @@ ETaxes.dialogs = { }], primary_action_label: __('Cancel'), primary_action: function() { + // Флаг ставим ПЕРЕД закрытием: hide() его больше не сбрасывает, + // поэтому in-flight callback'и пагинации увидят отмену и выйдут. ETaxes.cancelLoading = true; - ETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true); - ETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...')); - $('#status_message p').text(__('Cancelling the operation.')); + ETaxes.dialogs.hide(); } }); @@ -197,15 +197,24 @@ ETaxes.dialogs = { // Скрыть диалог hide: function() { + // Мягкий loadingDialog.hide() в jey_theme/Bootstrap НЕ всегда убирает модал + // (он зависает и следующий диалог накладывается сверху). Принудительно: + // modal('hide') + remove() + чистка осиротевшего backdrop. + // cancelLoading здесь НЕ сбрасываем — иначе отмена потеряется для in-flight + // callback'ов; флаг сбрасывается в начале операции / при создании диалога. if (ETaxes.loadingDialog) { try { - ETaxes.loadingDialog.hide(); + ETaxes.loadingDialog.$wrapper.modal('hide'); + ETaxes.loadingDialog.$wrapper.remove(); } catch (e) { console.error("Error hiding loading dialog:", e); } ETaxes.loadingDialog = null; } - ETaxes.cancelLoading = false; + if ($('.modal:visible').length === 0) { + $('.modal-backdrop').remove(); + $('body').removeClass('modal-open'); + } }, // Получить HTML для диалога загрузки