added item group rename

This commit is contained in:
Ali 2025-08-13 15:26:23 +04:00
parent 15e78d19e5
commit 64096d7c5a
3 changed files with 175 additions and 351 deletions

View File

@ -39,6 +39,9 @@ def after_migrate_combined():
from jey_erp.custom_fields import create_custom_fields
create_custom_fields()
from jey_erp.overrides.custom_install import rename_item_groups
rename_item_groups()
fixtures = [
{

View File

@ -0,0 +1,172 @@
import frappe
import urllib.parse
def rename_item_groups():
"""
Переименовывает группы номенклатур: и названия, и ID на азербайджанский
"""
# Маппинг: старый_ID -> {"new_name": "название", "new_id": "тожеазвание"}
translation_map = {
"All Item Groups": {
"new_name": "Bütün Məhsul Qrupları",
},
"Products": {
"new_name": "Məhsullar",
},
"Raw Material": {
"new_name": "Xammal",
},
"Services": {
"new_name": "Xidmətlər",
},
"Sub Assemblies": {
"new_name": "Alt Montajlar",
},
"Consumable": {
"new_name": "İstehlak Malları",
}
}
# ID будет точно таким же, как и название (на азербайджанском)
for key, value in translation_map.items():
new_name = value["new_name"]
# ID = название (без URL-encoding)
value["new_id"] = new_name
try:
updated_count = 0
renamed_count = 0
frappe.flags.ignore_permissions = True
frappe.flags.ignore_links = True
frappe.flags.ignore_validate_update_after_submit = True
# Получаем все группы, отсортированные по иерархии
all_groups = frappe.get_all(
"Item Group",
fields=["name", "item_group_name", "parent_item_group", "lft", "rgt"],
order_by="lft" # От корневых к дочерним
)
# Создаем маппинг для обновления родительских ссылок
id_mapping = {}
groups_to_process = []
# Собираем информацию о группах для переименования
for old_id, translation in translation_map.items():
new_name = translation["new_name"]
new_id = translation["new_id"]
# Находим группу по текущему ID
existing_group = None
for group in all_groups:
if group.name == old_id:
existing_group = group
break
if existing_group:
id_mapping[old_id] = new_id
groups_to_process.append({
"old_id": old_id,
"new_id": new_id,
"new_name": new_name,
"lft": existing_group.lft,
"current_parent": existing_group.parent_item_group
})
# Обрабатываем группы в правильном порядке (от корневых к дочерним)
for group_info in sorted(groups_to_process, key=lambda x: x["lft"]):
old_id = group_info["old_id"]
new_id = group_info["new_id"]
new_name = group_info["new_name"]
current_parent = group_info["current_parent"]
# Проверяем, не существует ли уже группа с новым ID
if frappe.db.exists("Item Group", new_id):
continue
try:
# Обновляем родительскую ссылку если родитель тоже переименовывается
updated_parent = current_parent
if current_parent and current_parent in id_mapping:
updated_parent = id_mapping[current_parent]
# Сначала обновляем название
frappe.db.sql("""
UPDATE `tabItem Group`
SET item_group_name = %s
WHERE name = %s
""", (new_name, old_id))
updated_count += 1
# Теперь переименовываем ID
if old_id != new_id:
# Используем низкоуровневые SQL запросы для избежания проверок
# 1. Обновляем основную запись
frappe.db.sql("""
UPDATE `tabItem Group`
SET name = %s
WHERE name = %s
""", (new_id, old_id))
# 2. Обновляем parent_item_group ссылки
frappe.db.sql("""
UPDATE `tabItem Group`
SET parent_item_group = %s
WHERE parent_item_group = %s
""", (new_id, old_id))
# 3. Обновляем ссылки в товарах
frappe.db.sql("""
UPDATE `tabItem`
SET item_group = %s
WHERE item_group = %s
""", (new_id, old_id))
# 4. Обновляем другие возможные ссылки
other_tables = [
("tabItem Default", "parent_item_group"),
("tabPurchase Invoice Item", "item_group"),
("tabSales Invoice Item", "item_group"),
("tabDelivery Note Item", "item_group"),
("tabPurchase Receipt Item", "item_group")
]
for table, field in other_tables:
if frappe.db.has_column(table, field):
frappe.db.sql(f"""
UPDATE `{table}`
SET `{field}` = %s
WHERE `{field}` = %s
""", (new_id, old_id))
renamed_count += 1
except Exception as process_error:
continue
# Сохраняем изменения
frappe.db.commit()
# Очищаем кэш
frappe.clear_cache()
# Перестраиваем дерево
try:
from frappe.utils.nestedset import rebuild_tree
rebuild_tree("Item Group", "parent_item_group")
except Exception as tree_error:
pass
except Exception as e:
frappe.log_error(f"URL-encoded Item Groups Error: {str(e)}")
frappe.db.rollback()
raise
finally:
frappe.flags.ignore_permissions = False
frappe.flags.ignore_links = False
frappe.flags.ignore_validate_update_after_submit = False

View File

@ -1,351 +0,0 @@
# your_app/patches/replace_install_function.py
import json
import os
from pathlib import Path
import frappe
from frappe.desk.doctype.global_search_settings.global_search_settings import (
update_global_search_doctypes,
)
from frappe.desk.page.setup_wizard.setup_wizard import make_records
from frappe.utils import cstr, getdate
from erpnext.accounts.doctype.account.account import RootNotEditable
from erpnext.regional.address_template.setup import set_up_address_templates
def _(x, *args, **kwargs):
"""Redefine the translation function to return the string as is.
We want to create english records but still mark the strings as translatable.
The respective DocTypes have 'Translate Link Fields' enabled."""
return x
def read_lines(filename: str) -> list[str]:
"""Return a list of lines from a file in the data directory."""
return (Path(__file__).parent.parent / "data" / filename).read_text().splitlines()
def custom_install(country=None):
"""Ваша замененная функция install - вставьте сюда ваш код"""
records = [
# ensure at least an empty Address Template exists for this Country
{"doctype": "Address Template", "country": country},
# item group
{
"doctype": "Item Group",
"item_group_name": _("Bütün Element Qrupları"),
"is_group": 1,
"parent_item_group": "",
},
{
"doctype": "Item Group",
"item_group_name": _("Məhsullar"),
"is_group": 0,
"parent_item_group": _("Bütün Element Qrupları"),
"show_in_website": 1,
},
{
"doctype": "Item Group",
"item_group_name": _("Xammal"),
"is_group": 0,
"parent_item_group": _("Bütün Element Qrupları"),
},
{
"doctype": "Item Group",
"item_group_name": _("Xidmətlər"),
"is_group": 0,
"parent_item_group": _("Bütün Element Qrupları"),
},
{
"doctype": "Item Group",
"item_group_name": _("Alt məclislər"),
"is_group": 0,
"parent_item_group": _("Bütün Element Qrupları"),
},
{
"doctype": "Item Group",
"item_group_name": _("İstehlak materialı"),
"is_group": 0,
"parent_item_group": _("Bütün Element Qrupları"),
},
# Stock Entry Type
{
"doctype": "Stock Entry Type",
"name": _("Material Issue"),
"purpose": "Material Issue",
"is_standard": 1,
},
{
"doctype": "Stock Entry Type",
"name": _("Material Receipt"),
"purpose": "Material Receipt",
"is_standard": 1,
},
{
"doctype": "Stock Entry Type",
"name": _("Material Transfer"),
"purpose": "Material Transfer",
"is_standard": 1,
},
{
"doctype": "Stock Entry Type",
"name": _("Manufacture"),
"purpose": "Manufacture",
"is_standard": 1,
},
{
"doctype": "Stock Entry Type",
"name": _("Repack"),
"purpose": "Repack",
"is_standard": 1,
},
{"doctype": "Stock Entry Type", "name": "Disassemble", "purpose": "Disassemble", "is_standard": 1},
{
"doctype": "Stock Entry Type",
"name": _("Send to Subcontractor"),
"purpose": "Send to Subcontractor",
"is_standard": 1,
},
{
"doctype": "Stock Entry Type",
"name": _("Material Transfer for Manufacture"),
"purpose": "Material Transfer for Manufacture",
"is_standard": 1,
},
{
"doctype": "Stock Entry Type",
"name": _("Material Consumption for Manufacture"),
"purpose": "Material Consumption for Manufacture",
"is_standard": 1,
},
# territory: with two default territories, one for home country and one named Rest of the World
{
"doctype": "Territory",
"territory_name": _("All Territories"),
"is_group": 1,
"name": _("All Territories"),
"parent_territory": "",
},
{
"doctype": "Territory",
"territory_name": country.replace("'", ""),
"is_group": 0,
"parent_territory": _("All Territories"),
},
{
"doctype": "Territory",
"territory_name": _("Rest Of The World"),
"is_group": 0,
"parent_territory": _("All Territories"),
},
# customer group
{
"doctype": "Customer Group",
"customer_group_name": _("All Customer Groups"),
"is_group": 1,
"name": _("All Customer Groups"),
"parent_customer_group": "",
},
{
"doctype": "Customer Group",
"customer_group_name": _("Individual"),
"is_group": 0,
"parent_customer_group": _("All Customer Groups"),
},
{
"doctype": "Customer Group",
"customer_group_name": _("Commercial"),
"is_group": 0,
"parent_customer_group": _("All Customer Groups"),
},
{
"doctype": "Customer Group",
"customer_group_name": _("Non Profit"),
"is_group": 0,
"parent_customer_group": _("All Customer Groups"),
},
{
"doctype": "Customer Group",
"customer_group_name": _("Government"),
"is_group": 0,
"parent_customer_group": _("All Customer Groups"),
},
# supplier group
{
"doctype": "Supplier Group",
"supplier_group_name": _("All Supplier Groups"),
"is_group": 1,
"name": _("All Supplier Groups"),
"parent_supplier_group": "",
},
{
"doctype": "Supplier Group",
"supplier_group_name": _("Xidmətlər"),
"is_group": 0,
"parent_supplier_group": _("All Supplier Groups"),
},
{
"doctype": "Supplier Group",
"supplier_group_name": _("Local"),
"is_group": 0,
"parent_supplier_group": _("All Supplier Groups"),
},
{
"doctype": "Supplier Group",
"supplier_group_name": _("Xammal"),
"is_group": 0,
"parent_supplier_group": _("All Supplier Groups"),
},
{
"doctype": "Supplier Group",
"supplier_group_name": _("Electrical"),
"is_group": 0,
"parent_supplier_group": _("All Supplier Groups"),
},
{
"doctype": "Supplier Group",
"supplier_group_name": _("Hardware"),
"is_group": 0,
"parent_supplier_group": _("All Supplier Groups"),
},
{
"doctype": "Supplier Group",
"supplier_group_name": _("Pharmaceutical"),
"is_group": 0,
"parent_supplier_group": _("All Supplier Groups"),
},
{
"doctype": "Supplier Group",
"supplier_group_name": _("Distributor"),
"is_group": 0,
"parent_supplier_group": _("All Supplier Groups"),
},
# Sales Person
{
"doctype": "Sales Person",
"sales_person_name": _("Sales Team"),
"is_group": 1,
"parent_sales_person": "",
},
# Mode of Payment
{
"doctype": "Mode of Payment",
"mode_of_payment": "Check" if country == "United States" else _("Cheque"),
"type": "Bank",
},
{"doctype": "Mode of Payment", "mode_of_payment": _("Cash"), "type": "Cash"},
{"doctype": "Mode of Payment", "mode_of_payment": _("Credit Card"), "type": "Bank"},
{"doctype": "Mode of Payment", "mode_of_payment": _("Wire Transfer"), "type": "Bank"},
{"doctype": "Mode of Payment", "mode_of_payment": _("Bank Draft"), "type": "Bank"},
# Activity Type
{"doctype": "Activity Type", "activity_type": _("Planning")},
{"doctype": "Activity Type", "activity_type": _("Research")},
{"doctype": "Activity Type", "activity_type": _("Proposal Writing")},
{"doctype": "Activity Type", "activity_type": _("Execution")},
{"doctype": "Activity Type", "activity_type": _("Communication")},
{
"doctype": "Item Attribute",
"attribute_name": _("Size"),
"item_attribute_values": [
{"attribute_value": _("Extra Small"), "abbr": "XS"},
{"attribute_value": _("Small"), "abbr": "S"},
{"attribute_value": _("Medium"), "abbr": "M"},
{"attribute_value": _("Large"), "abbr": "L"},
{"attribute_value": _("Extra Large"), "abbr": "XL"},
],
},
{
"doctype": "Item Attribute",
"attribute_name": _("Colour"),
"item_attribute_values": [
{"attribute_value": _("Red"), "abbr": "RED"},
{"attribute_value": _("Green"), "abbr": "GRE"},
{"attribute_value": _("Blue"), "abbr": "BLU"},
{"attribute_value": _("Black"), "abbr": "BLA"},
{"attribute_value": _("White"), "abbr": "WHI"},
],
},
# Issue Priority
{"doctype": "Issue Priority", "name": _("Low")},
{"doctype": "Issue Priority", "name": _("Medium")},
{"doctype": "Issue Priority", "name": _("High")},
{"doctype": "Email Account", "email_id": "sales@example.com", "append_to": "Opportunity"},
{"doctype": "Email Account", "email_id": "support@example.com", "append_to": "Issue"},
{"doctype": "Party Type", "party_type": "Customer", "account_type": "Receivable"},
{"doctype": "Party Type", "party_type": "Supplier", "account_type": "Payable"},
{"doctype": "Party Type", "party_type": "Employee", "account_type": "Payable"},
{"doctype": "Party Type", "party_type": "Shareholder", "account_type": "Payable"},
{"doctype": "Opportunity Type", "name": _("Sales")},
{"doctype": "Opportunity Type", "name": _("Support")},
{"doctype": "Opportunity Type", "name": _("Maintenance")},
{"doctype": "Project Type", "project_type": _("Internal")},
{"doctype": "Project Type", "project_type": _("External")},
{"doctype": "Project Type", "project_type": _("Other")},
{"doctype": "Print Heading", "print_heading": _("Credit Note")},
{"doctype": "Print Heading", "print_heading": _("Debit Note")},
# Share Management
{"doctype": "Share Type", "title": _("Equity")},
{"doctype": "Share Type", "title": _("Preference")},
# Market Segments
{"doctype": "Market Segment", "market_segment": _("Lower Income")},
{"doctype": "Market Segment", "market_segment": _("Middle Income")},
{"doctype": "Market Segment", "market_segment": _("Upper Income")},
# Warehouse Type
{"doctype": "Warehouse Type", "name": "Transit"},
]
for doctype, title_field, filename in (
("Designation", "designation_name", "designation.txt"),
("Sales Stage", "stage_name", "sales_stage.txt"),
("Industry Type", "industry", "industry_type.txt"),
("UTM Source", "name", "marketing_source.txt"),
("Sales Partner Type", "sales_partner_type", "sales_partner_type.txt"),
):
records += [{"doctype": doctype, title_field: title} for title in read_lines(filename)]
base_path = frappe.get_app_path("erpnext", "stock", "doctype")
response = frappe.read_file(os.path.join(base_path, "delivery_trip/dispatch_notification_template.html"))
records += [
{
"doctype": "Email Template",
"name": _("Dispatch Notification"),
"response": response,
"subject": _("Your order is out for delivery!"),
"owner": frappe.session.user,
}
]
# Records for the Supplier Scorecard
from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import make_default_records
make_default_records()
make_records(records)
set_up_address_templates(default_country=country)
# Импортируем функции из оригинального модуля
from erpnext.setup.setup_wizard.operations.install_fixtures import (
update_selling_defaults,
update_buying_defaults,
add_uom_data,
update_item_variant_settings
)
update_selling_defaults()
update_buying_defaults()
add_uom_data()
update_item_variant_settings()
update_global_search_doctypes()
def execute():
"""Функция для применения monkey patch"""
import erpnext.setup.setup_wizard.operations.install_fixtures as install_fixtures
# Заменяем функцию install на вашу кастомную версию
install_fixtures.install = custom_install
frappe.logger().info("Custom install function has been applied via monkey patching")