monkey patched asset categories

This commit is contained in:
Ali 2026-01-09 22:58:43 +04:00
parent d5c92eef7d
commit 8865bb7b18
6 changed files with 206 additions and 68 deletions

View File

@ -21,82 +21,26 @@ def get_system_asset_categories():
def create_asset_categories(): def create_asset_categories():
""" """
Создает категории активов с настройками счетов УСТАРЕЛО: Функция оставлена для обратной совместимости.
Новые установки используют хук setup_wizard_complete.
Создает категории активов для первой компании в системе.
""" """
# Проверка существования таблицы Company # Проверка существования таблицы Company
if not frappe.db.table_exists("Company"): if not frappe.db.table_exists("Company"):
frappe.log_error("Company table not found", "Asset Categories Patch") frappe.log_error("Company table not found", "Asset Categories Patch")
return return
# Получаем первую компанию # Получаем первую компанию
company = frappe.get_all("Company", limit=1) company = frappe.get_all("Company", limit=1)
if not company: if not company:
frappe.log_error("No company found in the system", "Asset Categories Patch") frappe.log_error("No company found in the system", "Asset Categories Patch")
return return
company_name = company[0].name company_name = company[0].name
# Получаем список системных категорий # Используем новую функцию
asset_categories = get_system_asset_categories() _create_categories_for_company(company_name)
# Находим нужные счета
try:
accumulated_depreciation = get_account_by_name(
"Tikililər üzrə yığılmış amortizasiya",
company_name
)
depreciation_expense = get_account_by_name(
"Amortizasiya xərci",
company_name
)
fixed_asset = get_account_by_name(
"Digər uzunmüddətli aktivlər",
company_name
)
except Exception as e:
frappe.log_error(f"Required accounts not found: {str(e)}", "Asset Categories Patch")
return
# Создаем категории активов
created_count = 0
skipped_count = 0
for category_name in asset_categories:
try:
if not frappe.db.exists("Asset Category", category_name):
asset_category = frappe.new_doc("Asset Category")
asset_category.asset_category_name = category_name
asset_category.enable_cwip_accounting = 0
# Добавляем accounts
asset_category.append("accounts", {
"company_name": company_name,
"fixed_asset_account": fixed_asset,
"accumulated_depreciation_account": accumulated_depreciation,
"depreciation_expense_account": depreciation_expense,
"capital_work_in_progress_account": ""
})
asset_category.insert(ignore_permissions=True)
created_count += 1
frappe.msgprint(f"Created Asset Category: {category_name}")
else:
skipped_count += 1
except Exception as e:
frappe.log_error(
f"Failed to create Asset Category '{category_name}': {str(e)}",
"Asset Categories Patch"
)
# Коммитим все изменения разом
frappe.db.commit()
# Выводим итоговую информацию
message = f"Asset Categories Patch completed. Created: {created_count}, Skipped: {skipped_count}"
print(message)
frappe.msgprint(message)
def get_account_by_name(account_name, company): def get_account_by_name(account_name, company):
@ -116,6 +60,112 @@ def get_account_by_name(account_name, company):
return account return account
def create_asset_categories_for_company(company_name):
"""
Создает категории активов для конкретной компании.
Вызывается как фоновая задача после setup wizard.
Args:
company_name: Название компании
"""
try:
# Проверяем, что компания существует
if not frappe.db.exists("Company", company_name):
frappe.log_error(
f"Company '{company_name}' not found",
"Asset Categories Creation"
)
return
# Проверка идемпотентности: если категории уже есть, не создаем
system_categories = get_system_asset_categories()
existing_categories = frappe.db.count(
"Asset Category",
filters={"asset_category_name": ["in", system_categories]}
)
if existing_categories > 0:
frappe.log_error(
f"Asset categories already exist ({existing_categories} found). Skipping creation.",
"Asset Categories Creation - Info"
)
return
# Создаем категории
_create_categories_for_company(company_name)
except Exception as e:
# Не пробрасываем исключение - это фоновая задача
frappe.log_error(
f"Failed to create asset categories for {company_name}: {str(e)}",
"Asset Categories Creation - Error"
)
def _create_categories_for_company(company_name):
"""
Внутренняя функция для создания категорий активов.
Извлечена из create_asset_categories для переиспользования.
"""
asset_categories = get_system_asset_categories()
# Находим нужные счета
try:
accumulated_depreciation = get_account_by_name(
"Tikililər üzrə yığılmış amortizasiya",
company_name
)
depreciation_expense = get_account_by_name(
"Amortizasiya xərci",
company_name
)
fixed_asset = get_account_by_name(
"Digər uzunmüddətli aktivlər",
company_name
)
except Exception as e:
frappe.log_error(
f"Required accounts not found for {company_name}: {str(e)}",
"Asset Categories Creation - Error"
)
return
# Создаем категории
created_count = 0
skipped_count = 0
for category_name in asset_categories:
try:
if not frappe.db.exists("Asset Category", category_name):
asset_category = frappe.new_doc("Asset Category")
asset_category.asset_category_name = category_name
asset_category.enable_cwip_accounting = 0
asset_category.append("accounts", {
"company_name": company_name,
"fixed_asset_account": fixed_asset,
"accumulated_depreciation_account": accumulated_depreciation,
"depreciation_expense_account": depreciation_expense,
"capital_work_in_progress_account": ""
})
asset_category.insert(ignore_permissions=True)
created_count += 1
else:
skipped_count += 1
except Exception as e:
frappe.log_error(
f"Failed to create Asset Category '{category_name}': {str(e)}",
"Asset Categories Creation - Error"
)
frappe.db.commit()
message = f"Asset Categories created for {company_name}. Created: {created_count}, Skipped: {skipped_count}"
frappe.log_error(message, "Asset Categories Creation - Success")
print(message)
def prevent_delete_system_asset_categories(doc, method): def prevent_delete_system_asset_categories(doc, method):
""" """
Запрещает удаление системных категорий активов Запрещает удаление системных категорий активов

View File

@ -54,6 +54,11 @@ doc_events = {
} }
} }
# Setup Wizard
# ------------
setup_wizard_complete = "jey_erp.setup.setup_wizard_handler.setup_wizard_complete_handler"
after_migrate = "jey_erp.hooks.after_migrate_combined" after_migrate = "jey_erp.hooks.after_migrate_combined"
def after_migrate_combined(): def after_migrate_combined():
@ -64,10 +69,12 @@ def after_migrate_combined():
show_item_tax_template_in_sales_invoice() show_item_tax_template_in_sales_invoice()
from jey_erp.custom.vat_calculations import patch_sales_documents from jey_erp.custom.vat_calculations import patch_sales_documents
patch_sales_documents() patch_sales_documents()
from jey_erp.custom.create_asset_categories import create_asset_categories # REMOVED: Asset categories creation moved to setup_wizard_complete hook
create_asset_categories() # from jey_erp.custom.create_asset_categories import create_asset_categories
# create_asset_categories()
after_install = "jey_erp.custom.create_asset_categories.create_asset_categories" # REMOVED: Asset categories creation moved to setup_wizard_complete hook
# after_install = "jey_erp.custom.create_asset_categories.create_asset_categories"
fixtures = [ fixtures = [
{ {

View File

@ -3,4 +3,5 @@
# Read docs to understand patches: https://frappeframework.com/docs/v14/user/en/database-migrations # Read docs to understand patches: https://frappeframework.com/docs/v14/user/en/database-migrations
[post_model_sync] [post_model_sync]
# Patches added in this section will be executed after doctypes are migrated # Patches added in this section will be executed after doctypes are migrated
jey_erp.patches.create_asset_categories_post_migration

View File

@ -0,0 +1,36 @@
import frappe
def execute():
"""
Патч для создания категорий активов на существующих установках.
Выполняется при bench migrate после обновления кода.
"""
# Проверяем, что патч не был уже выполнен
system_categories = [
"Binalar, tikililər və qurğular",
"Maşınlar və avadanlıqlar",
"Yüksək texnologiyalar məhsulu olan hesablama texnikası",
"Nəqliyyat vasitələri",
"Digər əsas vəsaitlər",
"Düzən torpaqlar",
"Dağ torpaqlar",
"Orta və yüksək dağ torpaqlar",
"Şəhərin mövcud hüdudundan kənarda olan kənd təsərrüfatı təyinatlı torpaqlar",
"Sənaye, tikinti, nəqliyyat, rabitə, ticarət-məişət xidməti və digər xüsusi təyinatlı torpaq sahələri"
]
# Если хотя бы одна категория существует, считаем что патч уже выполнен
if frappe.db.exists("Asset Category", {"asset_category_name": system_categories[0]}):
return
# Проверяем, что компания существует
companies = frappe.get_all("Company", limit=1)
if not companies:
return # Нет компании - патч не нужен
company_name = companies[0].name
# Импортируем и запускаем создание
from jey_erp.custom.create_asset_categories import create_asset_categories_for_company
create_asset_categories_for_company(company_name)

View File

@ -0,0 +1 @@
# Empty file to make this a Python package

View File

@ -0,0 +1,43 @@
import frappe
def setup_wizard_complete_handler(args):
"""
Вызывается после завершения ERPNext setup wizard.
Ставит в очередь фоновую задачу для создания категорий активов.
Args:
args: Словарь с параметрами визарда, включая:
- company_name: Название созданной компании
- country: Выбранная страна
- currency: Валюта по умолчанию
"""
company_name = args.get("company_name")
if not company_name:
# Fallback: получаем первую компанию
companies = frappe.get_all("Company", limit=1)
if companies:
company_name = companies[0].name
else:
frappe.log_error(
"Company name not found in setup wizard args and no companies exist",
"Asset Categories Setup"
)
return
# Ставим в очередь фоновую задачу (некритично, не блокирует визард)
frappe.enqueue(
"jey_erp.custom.create_asset_categories.create_asset_categories_for_company",
queue="default",
timeout=300,
enqueue_after_commit=True,
at_front=False, # Некритично, может подождать
company_name=company_name
)
frappe.msgprint(
f"Категории активов будут созданы в фоновом режиме для {company_name}",
title="Настройка выполняется",
indicator="blue"
)