feat(etaxes): classification code + explanation custom fields; quieter asset-category logs
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) <noreply@anthropic.com>
This commit is contained in:
parent
4e8a151851
commit
4926d5c637
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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": [
|
||||
|
|
|
|||
|
|
@ -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 = `<b>${__("Import complete")}</b><br>${__("Created")}: ${created}<br>${__("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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in New Issue