From 4926d5c63756a9b13e9910b08224e309e4f2b3b2 Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Fri, 12 Jun 2026 16:19:22 +0000 Subject: [PATCH] feat(etaxes): classification code + explanation custom fields; quieter asset-category logs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add read-only custom fields etaxes_classification_code (Təsnifat Kodu) and etaxes_explanation on Journal Entry for E-Taxes VAT imports, with matching translation markers. Move asset-category creation logging from frappe.log_error (which spammed the Error Log DocType) to a file logger; keep log_error only for real creation failures. Drop the manual frappe.db.commit inside the Company.on_update path so the framework keeps the save atomic. Reuse the realtime progress-bar race fix in currency_exchange_list.js. Co-Authored-By: Claude Opus 4.8 (1M context) --- jey_erp/custom/create_asset_categories.py | 88 +++++++++++---------- jey_erp/custom_fields.py | 23 ++++++ jey_erp/public/js/currency_exchange_list.js | 26 +++++- jey_erp/translation_markers.py | 4 + 4 files changed, 99 insertions(+), 42 deletions(-) diff --git a/jey_erp/custom/create_asset_categories.py b/jey_erp/custom/create_asset_categories.py index ffcc89d..9bed3ae 100644 --- a/jey_erp/custom/create_asset_categories.py +++ b/jey_erp/custom/create_asset_categories.py @@ -1,6 +1,16 @@ import frappe +def _logger(): + """Файловый логгер для процесса создания категорий активов. + + Используем frappe.logger() для info/debug-сообщений (пишутся в + logs/asset_categories.log), а frappe.log_error() оставляем только + для реальных ошибок (записи в Error Log DocType). + """ + return frappe.logger("asset_categories", allow_site=True, file_count=20) + + def get_system_asset_categories(): """ Возвращает список системных категорий активов @@ -79,25 +89,24 @@ def create_asset_categories_on_company_update(doc, method): # Проверяем первую категорию из списка if frappe.db.exists("Asset Category", {"asset_category_name": system_categories[0]}): # Категории уже созданы (они создаются для всех компаний сразу) - frappe.log_error( - f"Asset categories already exist, skipping creation\nCompany: {company_name}\nFirst category found: {system_categories[0]}", - "AC Skip Existing" + _logger().info( + f"Asset categories already exist, skipping creation. " + f"Company: {company_name}, first category found: {system_categories[0]}" ) return # Логируем начало создания - frappe.log_error( - f"Creating asset categories automatically\nTriggered by: Company.on_update\nCompany: {company_name}", - "AC Auto Create" + _logger().info( + f"Creating asset categories automatically (Company.on_update). Company: {company_name}" ) try: # Создаем категории _create_categories_for_company(company_name) - frappe.log_error( - f"Asset categories created successfully\nCompany: {company_name}\nCategories: {len(system_categories)}", - "AC Created" + _logger().info( + f"Asset categories created successfully. " + f"Company: {company_name}, categories: {len(system_categories)}" ) except Exception as e: import traceback @@ -116,10 +125,7 @@ def create_asset_categories_for_company(company_name): Args: company_name: Название компании """ - frappe.log_error( - f"Function started\nCompany: {company_name}", - "AC Create Start" - ) + _logger().info(f"create_asset_categories_for_company started. Company: {company_name}") try: # Проверяем, что компания существует @@ -132,10 +138,7 @@ def create_asset_categories_for_company(company_name): ) return - frappe.log_error( - f"Company exists in database\nCompany: {company_name}", - "AC Company OK" - ) + _logger().debug(f"Company exists in database. Company: {company_name}") # Проверка идемпотентности: если категории уже есть, не создаем system_categories = get_system_asset_categories() @@ -144,28 +147,27 @@ def create_asset_categories_for_company(company_name): filters={"asset_category_name": ["in", system_categories]} ) - frappe.log_error( - f"Idempotency check\nSystem categories: {len(system_categories)}\nExisting categories: {existing_categories}\nCategories list: {system_categories}", - "AC Check Existing" + _logger().debug( + f"Idempotency check. System categories: {len(system_categories)}, " + f"existing: {existing_categories}" ) if existing_categories > 0: - frappe.log_error( - f"Categories already exist, skipping creation\nFound: {existing_categories} of {len(system_categories)}", - "AC Already Exist" + _logger().info( + f"Categories already exist, skipping creation. " + f"Found: {existing_categories} of {len(system_categories)}" ) return # Создаем категории - frappe.log_error( - f"Starting category creation\nCompany: {company_name}\nCategories to create: {len(system_categories)}", - "AC Creating" + _logger().info( + f"Starting category creation. Company: {company_name}, " + f"categories to create: {len(system_categories)}" ) _create_categories_for_company(company_name) - frappe.log_error( - f"Asset categories creation completed successfully\nCompany: {company_name}", - "AC Complete" + _logger().info( + f"Asset categories creation completed successfully. Company: {company_name}" ) except Exception as e: @@ -185,10 +187,7 @@ def _create_categories_for_company(company_name): asset_categories = get_system_asset_categories() # Находим нужные счета - frappe.log_error( - f"Searching for required accounts\nCompany: {company_name}\nAccounts needed: 3", - "AC Search Accounts" - ) + _logger().debug(f"Searching for required accounts. Company: {company_name}, needed: 3") try: accumulated_depreciation = get_account_by_name( @@ -204,9 +203,10 @@ def _create_categories_for_company(company_name): company_name ) - frappe.log_error( - f"All required accounts found\nCompany: {company_name}\n\nAccounts:\n1. Accumulated Depreciation: {accumulated_depreciation}\n2. Depreciation Expense: {depreciation_expense}\n3. Fixed Asset: {fixed_asset}", - "AC Accounts OK" + _logger().debug( + f"All required accounts found. Company: {company_name}, " + f"fixed_asset: {fixed_asset}, accumulated_depreciation: {accumulated_depreciation}, " + f"depreciation_expense: {depreciation_expense}" ) except Exception as e: @@ -250,14 +250,22 @@ def _create_categories_for_company(company_name): f"AC Cat ERROR {idx}" ) - frappe.db.commit() + # NB: commit намеренно НЕ вызываем. В активном пути (Company.on_update) + # транзакцию коммитит сам фреймворк; ручной commit внутри хука разрывает + # атомарность сохранения Company. В фоновой задаче (frappe.enqueue) и в + # патчах commit тоже выполняется обёрткой после успешного завершения. # Финальный отчет status = "SUCCESS" if created_count > 0 else ("SKIP" if skipped_count > 0 else "ERROR") - frappe.log_error( - f"Category creation finished\nCompany: {company_name}\nCreated: {created_count}\nSkipped: {skipped_count}\nErrors: {len(errors)}\n\nError details:\n{chr(10).join(errors) if errors else 'No errors'}", - f"AC {status}" + summary = ( + f"Category creation finished [{status}]. Company: {company_name}, " + f"created: {created_count}, skipped: {skipped_count}, errors: {len(errors)}" ) + if errors: + # Реальные ошибки создания категорий — в Error Log, чтобы были заметны. + frappe.log_error(summary + "\n\n" + "\n".join(errors), f"AC {status}") + else: + _logger().info(summary) def prevent_delete_system_asset_categories(doc, method): diff --git a/jey_erp/custom_fields.py b/jey_erp/custom_fields.py index 894b979..ca57459 100644 --- a/jey_erp/custom_fields.py +++ b/jey_erp/custom_fields.py @@ -1054,6 +1054,29 @@ def create_custom_fields(): hidden=1, read_only=1, no_copy=1 + ), + dict( + fieldname='etaxes_classification_code', + label='Təsnifat Kodu', + fieldtype='Link', + options='Classification code', + insert_after='loaded_from_etaxes', + read_only=1, + no_copy=1, + translatable=0, + description='Təsnifat kodu (taxCodeInfo.code) imported from E-Taxes' + ), + dict( + fieldname='etaxes_explanation', + label='Explanation', + fieldtype='Small Text', + insert_after='etaxes_classification_code', + in_list_view=1, + columns=3, + read_only=1, + no_copy=1, + translatable=0, + description='Explanation imported from E-Taxes VAT operation' ) ], "Bank": [ diff --git a/jey_erp/public/js/currency_exchange_list.js b/jey_erp/public/js/currency_exchange_list.js index 2a86720..93b4d35 100644 --- a/jey_erp/public/js/currency_exchange_list.js +++ b/jey_erp/public/js/currency_exchange_list.js @@ -50,10 +50,31 @@ function _show_import_dialog(available_currencies) { d.hide(); + // Защита от гонки realtime: 'complete' вызывает hide_progress() (обнуляет + // frappe.cur_progress). Опоздавший 'progress' иначе пересоздаёт модал, который + // уже никто не закрывает. Флаг делает обработчик прогресса no-op после finish. + let importFinished = false; + // Надёжное закрытие прогресс-бара: frappe.hide_progress() в этом окружении + // (jey_theme/Bootstrap) не всегда убирает модал — он зависает. Принудительно. + const 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"); + } + }; + frappe.realtime.off("cbar_import_progress"); frappe.realtime.off("cbar_import_complete"); frappe.realtime.on("cbar_import_progress", function (data) { + if (importFinished) return; frappe.show_progress( __("Importing CBAR Rates"), data.current, @@ -63,9 +84,10 @@ function _show_import_dialog(available_currencies) { }); frappe.realtime.on("cbar_import_complete", function (data) { + importFinished = true; frappe.realtime.off("cbar_import_progress"); frappe.realtime.off("cbar_import_complete"); - frappe.hide_progress(); + closeProgress(); const { created, updated, skipped_dates } = data; let msg = `${__("Import complete")}
${__("Created")}: ${created}
${__("Updated")}: ${updated}`; @@ -89,7 +111,7 @@ function _show_import_dialog(available_currencies) { error: function () { frappe.realtime.off("cbar_import_progress"); frappe.realtime.off("cbar_import_complete"); - frappe.hide_progress(); + closeProgress(); } }); } diff --git a/jey_erp/translation_markers.py b/jey_erp/translation_markers.py index e0f6b19..3d5051a 100644 --- a/jey_erp/translation_markers.py +++ b/jey_erp/translation_markers.py @@ -77,6 +77,8 @@ _lt("Employer Name") _lt("Employer Position") _lt("Enter the tax-exempt area value") _lt("Expense/Income") +_lt("Explanation") +_lt("Explanation imported from E-Taxes VAT operation") _lt("FIN") _lt("First Name") _lt("For agricultural: hectares. For industrial: square meters.") @@ -178,6 +180,8 @@ _lt("Taxable Assets Information") _lt("Taxation system") _lt("Taxpayer Activity Group") _lt("Type of act for e-taxes") +_lt("Təsnifat Kodu") +_lt("Təsnifat kodu (taxCodeInfo.code) imported from E-Taxes") _lt("Used as the Expense Account when this service item is selected in a Landed Cost Voucher.") _lt("Uçot metodu (Accounting Method)") _lt("VAT 0% with amount")