diff --git a/jey_erp/custom_fields.py b/jey_erp/custom_fields.py index 7e1331b..df663f7 100644 --- a/jey_erp/custom_fields.py +++ b/jey_erp/custom_fields.py @@ -110,6 +110,16 @@ def create_custom_fields(): insert_after='item_name', in_list_view=0, in_standard_filter=0 + ), + # Product Category field + dict( + fieldname='product_category', + label='Product Category', + fieldtype='Link', + options='Item Category', + insert_after='product_group_code', + in_list_view=1, + in_standard_filter=1 ) ], "Bank": [ diff --git a/jey_erp/hooks.py b/jey_erp/hooks.py index 355d677..12d230a 100644 --- a/jey_erp/hooks.py +++ b/jey_erp/hooks.py @@ -28,8 +28,8 @@ doc_events = { "on_update": "jey_erp.custom_employee_onboarding.on_update" }, "Sales Invoice": { - "validate": "jey_erp.jey_erp.custom.sales_invoice.calculate_tax_free_amounts", - "on_update": "jey_erp.jey_erp.custom.sales_invoice.calculate_tax_free_amounts", + "validate": "jey_erp.custom.sales_invoice.calculate_tax_free_amounts", + "on_update": "jey_erp.custom.sales_invoice.calculate_tax_free_amounts", } } diff --git a/jey_erp/jey_erp/doctype/item_category/__init__.py b/jey_erp/jey_erp/doctype/item_category/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/jey_erp/jey_erp/doctype/item_category/item_category.js b/jey_erp/jey_erp/doctype/item_category/item_category.js new file mode 100644 index 0000000..b131ee6 --- /dev/null +++ b/jey_erp/jey_erp/doctype/item_category/item_category.js @@ -0,0 +1,8 @@ +// Copyright (c) 2025, JeyERP and contributors +// For license information, please see license.txt + +// frappe.ui.form.on("Item Category", { +// refresh(frm) { + +// }, +// }); diff --git a/jey_erp/jey_erp/doctype/item_category/item_category.json b/jey_erp/jey_erp/doctype/item_category/item_category.json new file mode 100644 index 0000000..2111c16 --- /dev/null +++ b/jey_erp/jey_erp/doctype/item_category/item_category.json @@ -0,0 +1,151 @@ +{ + "actions": [], + "allow_rename": 1, + "autoname": "field:category_name", + "creation": "2025-08-01 12:00:00.000000", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "category_name", + "category_code", + "column_break_3", + "parent_category", + "is_group", + "section_break_6", + "description", + "column_break_8", + "is_active" + ], + "fields": [ + { + "fieldname": "category_name", + "fieldtype": "Data", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Category Name", + "reqd": 1, + "unique": 1 + }, + { + "fieldname": "category_code", + "fieldtype": "Data", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Category Code", + "unique": 1 + }, + { + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, + { + "fieldname": "parent_category", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Parent Category", + "options": "Item Category" + }, + { + "default": "0", + "fieldname": "is_group", + "fieldtype": "Check", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Is Group" + }, + { + "fieldname": "section_break_6", + "fieldtype": "Section Break" + }, + { + "fieldname": "description", + "fieldtype": "Text Editor", + "label": "Description" + }, + { + "fieldname": "column_break_8", + "fieldtype": "Column Break" + }, + { + "default": "1", + "fieldname": "is_active", + "fieldtype": "Check", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Is Active" + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2025-08-01 12:00:00.000000", + "modified_by": "Administrator", + "module": "Jey ERP", + "name": "Item Category", + "naming_rule": "By fieldname", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Stock Manager", + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Stock User", + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Item Manager", + "share": 1, + "write": 1 + }, + { + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Sales User", + "share": 1 + }, + { + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Purchase User", + "share": 1 + } + ], + "search_fields": "category_code,parent_category", + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "title_field": "category_name", + "track_changes": 1 +} \ No newline at end of file diff --git a/jey_erp/jey_erp/doctype/item_category/item_category.py b/jey_erp/jey_erp/doctype/item_category/item_category.py new file mode 100644 index 0000000..86fde56 --- /dev/null +++ b/jey_erp/jey_erp/doctype/item_category/item_category.py @@ -0,0 +1,9 @@ +# Copyright (c) 2025, JeyERP and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class ItemCategory(Document): + pass diff --git a/jey_erp/jey_erp/doctype/item_category/test_item_category.py b/jey_erp/jey_erp/doctype/item_category/test_item_category.py new file mode 100644 index 0000000..91f652b --- /dev/null +++ b/jey_erp/jey_erp/doctype/item_category/test_item_category.py @@ -0,0 +1,30 @@ +# Copyright (c) 2025, JeyERP and Contributors +# See license.txt + +# import frappe +from frappe.tests import IntegrationTestCase, UnitTestCase + + +# On IntegrationTestCase, the doctype test records and all +# link-field test record depdendencies are recursively loaded +# Use these module variables to add/remove to/from that list +EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"] +IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"] + + +class UnitTestItemCategory(UnitTestCase): + """ + Unit tests for ItemCategory. + Use this class for testing individual functions and methods. + """ + + pass + + +class IntegrationTestItemCategory(IntegrationTestCase): + """ + Integration tests for ItemCategory. + Use this class for testing interactions between multiple components. + """ + + pass diff --git a/jey_erp/patches/replace_install_function.py b/jey_erp/patches/replace_install_function.py new file mode 100644 index 0000000..ebe72b8 --- /dev/null +++ b/jey_erp/patches/replace_install_function.py @@ -0,0 +1,351 @@ +# 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") \ No newline at end of file