From 1ea7b9b8de77dd5600cfa5fafea02ce491457fa9 Mon Sep 17 00:00:00 2001 From: Neha Fathima Date: Sun, 8 Mar 2026 05:33:36 +0530 Subject: [PATCH] feat: Implement the inter company in sales invoice --- rmax_custom/fixtures/custom_field.json | 59 +++- rmax_custom/hooks.py | 13 +- rmax_custom/inter_company.py | 191 ++++++++++++ .../public/js/sales_invoice_inter_company.js | 13 + rmax_custom/rmax_custom/custom/address.json | 289 ++++++++++++++++++ rmax_custom/rmax_custom/custom/customer.json | 164 ++++++++++ .../rmax_custom/custom/sales_invoice.json | 82 ++++- rmax_custom/rmax_custom/doctype/__init__.py | 0 .../doctype/inter_company_branch/__init__.py | 0 .../inter_company_branch.js | 35 +++ .../inter_company_branch.json | 56 ++++ .../inter_company_branch.py | 33 ++ .../test_inter_company_branch.py | 9 + .../__init__.py | 0 .../inter_company_branch_cost_center.json | 53 ++++ .../inter_company_branch_cost_center.py | 9 + 16 files changed, 989 insertions(+), 17 deletions(-) create mode 100644 rmax_custom/inter_company.py create mode 100644 rmax_custom/public/js/sales_invoice_inter_company.js create mode 100644 rmax_custom/rmax_custom/custom/address.json create mode 100644 rmax_custom/rmax_custom/custom/customer.json create mode 100644 rmax_custom/rmax_custom/doctype/__init__.py create mode 100644 rmax_custom/rmax_custom/doctype/inter_company_branch/__init__.py create mode 100644 rmax_custom/rmax_custom/doctype/inter_company_branch/inter_company_branch.js create mode 100644 rmax_custom/rmax_custom/doctype/inter_company_branch/inter_company_branch.json create mode 100644 rmax_custom/rmax_custom/doctype/inter_company_branch/inter_company_branch.py create mode 100644 rmax_custom/rmax_custom/doctype/inter_company_branch/test_inter_company_branch.py create mode 100644 rmax_custom/rmax_custom/doctype/inter_company_branch_cost_center/__init__.py create mode 100644 rmax_custom/rmax_custom/doctype/inter_company_branch_cost_center/inter_company_branch_cost_center.json create mode 100644 rmax_custom/rmax_custom/doctype/inter_company_branch_cost_center/inter_company_branch_cost_center.py diff --git a/rmax_custom/fixtures/custom_field.json b/rmax_custom/fixtures/custom_field.json index 89bd72c..f98890d 100644 --- a/rmax_custom/fixtures/custom_field.json +++ b/rmax_custom/fixtures/custom_field.json @@ -1,4 +1,61 @@ [ + { + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": null, + "depends_on": "eval:doc.is_internal_customer && doc.represents_company", + "description": null, + "docstatus": 0, + "doctype": "Custom Field", + "dt": "Sales Invoice", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "custom_inter_company_branch", + "fieldtype": "Link", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "company_tax_id", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Inter Company Branch", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "modified": "2026-03-07 23:10:01.661809", + "module": null, + "name": "Sales Invoice-custom_inter_company_branch", + "no_copy": 0, + "non_negative": 0, + "options": "Inter Company Branch", + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + }, { "allow_in_quick_entry": 0, "allow_on_submit": 0, @@ -52,7 +109,7 @@ "search_index": 0, "show_dashboard": 0, "sort_options": 0, - "translatable": 0, + "translatable": 1, "unique": 0, "width": null }, diff --git a/rmax_custom/hooks.py b/rmax_custom/hooks.py index 975148e..714de2a 100644 --- a/rmax_custom/hooks.py +++ b/rmax_custom/hooks.py @@ -148,13 +148,11 @@ # --------------- # Hook on document methods and events -# doc_events = { -# "*": { -# "on_update": "method", -# "on_cancel": "method", -# "on_trash": "method" -# } -# } +doc_events = { + "Sales Invoice": { + "on_submit": "rmax_custom.inter_company.sales_invoice_on_submit", + }, +} # Scheduled Tasks # --------------- @@ -263,6 +261,7 @@ [ # Sales Invoice "Sales Invoice-custom_payment_mode", + "Sales Invoice-custom_inter_company_branch", # Sales Invoice Item "Sales Invoice Item-total_vat_linewise", diff --git a/rmax_custom/inter_company.py b/rmax_custom/inter_company.py new file mode 100644 index 0000000..24e45fe --- /dev/null +++ b/rmax_custom/inter_company.py @@ -0,0 +1,191 @@ +""" +Auto-create draft Inter Company Purchase Invoice (from Sales Invoice) on submit. +Uses built-in methods, avoids duplicates. +""" + +from __future__ import annotations + +import frappe +from frappe import _ +from frappe.utils import cint + + +def sales_invoice_on_submit(doc, method=None): + """Auto-create draft Inter Company Purchase Invoice on SI submit (no duplicate).""" + if not doc.is_internal_customer or not doc.represents_company: + return + if frappe.db.exists( + "Purchase Invoice", + {"inter_company_invoice_reference": doc.name}, + ): + return + + try: + import erpnext + from erpnext.accounts.doctype.sales_invoice.sales_invoice import ( + make_inter_company_purchase_invoice, + ) + + # Bypass session/default warehouse so PI only gets values from Inter Company Branch + frappe.flags.in_inter_company_pi_creation = True + from sf_trading.overrides.get_item_details import apply_patch, restore_patch + from sf_trading.overrides.defaults import apply_defaults_patch, restore_defaults_patch + + apply_patch() + apply_defaults_patch() + try: + pi = make_inter_company_purchase_invoice(doc.name) + # Fetch Supplier Invoice No & Date from source Sales Invoice (built-in does not set these) + pi.bill_no = doc.name + pi.bill_date = doc.posting_date + # Cost center & warehouse: from Inter Company Branch if selected, else company default + branch_data = _get_branch_data(doc, pi.company) + frappe.flags._inter_company_pi_branch_data = branch_data + if branch_data.get("cost_center"): + pi.cost_center = branch_data["cost_center"] + for item in pi.items: + if hasattr(item, "cost_center"): + item.cost_center = branch_data["cost_center"] + # Warehouse: ONLY from Inter Company Branch when update_stock; never use item/company default + if cint(pi.update_stock): + warehouse = branch_data.get("warehouse") + if warehouse and _warehouse_belongs_to_company(warehouse, pi.company): + pi.set_warehouse = warehouse + for item in pi.items: + if hasattr(item, "warehouse"): + item.warehouse = warehouse + else: + # Don't use item default – clear any warehouse set by make_inter_company + pi.set_warehouse = None + for item in pi.items: + if hasattr(item, "warehouse"): + item.warehouse = None + branch_name = doc.get("inter_company_branch") or "" + frappe.throw( + _( + "Configure Warehouse in Inter Company Branch {0} for company {1} to create Purchase Invoice with stock update." + ).format(branch_name, pi.company), + ) + # Fetch default Purchase Taxes and Charges Template and fill taxes table + _apply_default_purchase_taxes(pi, branch_data) + # Strip any warehouse/cost_center from session defaults that don't belong to PI company + _clear_invalid_session_defaults(pi) + pi.insert(ignore_permissions=True) + frappe.msgprint( + _("Inter Company Purchase Invoice {0} created as draft.").format(pi.name), + alert=True, + ) + finally: + restore_patch() + restore_defaults_patch() + frappe.flags.in_inter_company_pi_creation = False + frappe.flags.pop("_inter_company_pi_branch_data", None) + except Exception as e: + frappe.log_error(title="Inter Company PI auto-create", message=frappe.get_traceback()) + frappe.msgprint( + _("Could not auto-create Inter Company Purchase Invoice: {0}").format(str(e)), + indicator="orange", + alert=True, + ) + + +def _apply_default_purchase_taxes(pi, branch_data: dict) -> None: + """Fetch default Purchase Taxes and Charges Template and fill the taxes table.""" + from erpnext.controllers.accounts_controller import get_taxes_and_charges + + company = pi.company + template = frappe.db.get_value( + "Purchase Taxes and Charges Template", + {"is_default": 1, "company": company}, + "name", + ) + if not template: + return + pi.taxes_and_charges = template + taxes = get_taxes_and_charges("Purchase Taxes and Charges Template", template) + if taxes: + for row in list(pi.taxes or []): + pi.remove(row) + pi.extend("taxes", taxes) + # Set cost center on tax rows from branch if applicable + if branch_data.get("cost_center"): + for row in pi.taxes or []: + if hasattr(row, "cost_center") and not row.cost_center: + row.cost_center = branch_data["cost_center"] + + + +def _get_branch_data(doc, buying_company: str) -> dict: + """Get cost_center and warehouse for PI from Inter Company Branch, else company defaults.""" + import erpnext + + result = {} + branch = doc.get("inter_company_branch") + if branch and buying_company: + row = frappe.db.get_value( + "Inter Company Branch Cost Center", + {"parent": branch, "company": buying_company}, + ["cost_center", "warehouse"], + as_dict=True, + ) + if row: + if row.cost_center: + result["cost_center"] = row.cost_center + if row.warehouse: + result["warehouse"] = row.warehouse + if "cost_center" not in result: + result["cost_center"] = erpnext.get_default_cost_center(buying_company) + + return result + +def purchase_invoice_before_validate(doc, method=None): + """When creating inter-company PI, strip warehouse/cost_center from session defaults and re-apply branch values.""" + if not getattr(frappe.flags, "in_inter_company_pi_creation", False): + return + _clear_invalid_session_defaults(doc) + # Re-apply branch values in case session defaults overwrote them during insert flow + _branch_data = getattr(frappe.flags, "_inter_company_pi_branch_data", None) + if _branch_data: + company = doc.company + if _branch_data.get("cost_center") and _cost_center_belongs_to_company(_branch_data["cost_center"], company): + doc.cost_center = _branch_data["cost_center"] + for item in doc.items or []: + if hasattr(item, "cost_center"): + item.cost_center = _branch_data["cost_center"] + if cint(doc.update_stock) and _branch_data.get("warehouse") and _warehouse_belongs_to_company(_branch_data["warehouse"], company): + doc.set_warehouse = _branch_data["warehouse"] + for item in doc.items or []: + if hasattr(item, "warehouse"): + item.warehouse = _branch_data["warehouse"] + + +def _clear_invalid_session_defaults(pi) -> None: + """Clear any warehouse/cost_center from session defaults that don't belong to PI company.""" + company = pi.company + for attr in ("set_warehouse", "set_from_warehouse", "rejected_warehouse"): + val = pi.get(attr) + if val and not _warehouse_belongs_to_company(val, company): + pi.set(attr, None) + if pi.get("cost_center") and not _cost_center_belongs_to_company(pi.cost_center, company): + pi.cost_center = None + for item in pi.items or []: + for attr in ("warehouse", "from_warehouse", "target_warehouse", "rejected_warehouse"): + if hasattr(item, attr) and item.get(attr) and not _warehouse_belongs_to_company(item.get(attr), company): + item.set(attr, None) + if hasattr(item, "cost_center") and item.get("cost_center") and not _cost_center_belongs_to_company(item.cost_center, company): + item.cost_center = None + + +def _cost_center_belongs_to_company(cost_center: str, company: str) -> bool: + if not cost_center or not company: + return False + cc_company = frappe.db.get_value("Cost Center", cost_center, "company", cache=True) + return cc_company == company + + +def _warehouse_belongs_to_company(warehouse: str, company: str) -> bool: + """Ensure warehouse belongs to company (avoids cross-company mismatch in production).""" + if not warehouse or not company: + return False + wh_company = frappe.db.get_value("Warehouse", warehouse, "company", cache=True) + return wh_company == company diff --git a/rmax_custom/public/js/sales_invoice_inter_company.js b/rmax_custom/public/js/sales_invoice_inter_company.js new file mode 100644 index 0000000..f01df10 --- /dev/null +++ b/rmax_custom/public/js/sales_invoice_inter_company.js @@ -0,0 +1,13 @@ +frappe.ui.form.on("Sales Invoice", { + onload: function (frm) { + frm.set_query("inter_company_branch", function () { + if (!frm.doc.represents_company) { + return { filters: { name: "" } }; + } + return { + query: "rmax_custom.rmax_custom.doctype.inter_company_branch.inter_company_branch.get_branches_for_company", + filters: { company: frm.doc.represents_company }, + }; + }); + }, +}); diff --git a/rmax_custom/rmax_custom/custom/address.json b/rmax_custom/rmax_custom/custom/address.json new file mode 100644 index 0000000..6db3c39 --- /dev/null +++ b/rmax_custom/rmax_custom/custom/address.json @@ -0,0 +1,289 @@ +{ + "custom_fields": [ + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "creation": "2026-03-05 12:02:57.676559", + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "dt": "Address", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "custom_area", + "fieldtype": "Data", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "idx": 8, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "custom_building_number", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Area/District", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "modified": "2026-03-05 12:02:57.676559", + "modified_by": "Administrator", + "module": null, + "name": "Address-custom_area", + "no_copy": 0, + "non_negative": 0, + "options": null, + "owner": "Administrator", + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 1, + "unique": 0, + "width": null + }, + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "creation": "2026-03-05 12:01:14.431707", + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "dt": "Address", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "custom_building_number", + "fieldtype": "Data", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "idx": 7, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "city", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Building Number", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "modified": "2026-03-05 12:01:14.431707", + "modified_by": "Administrator", + "module": null, + "name": "Address-custom_building_number", + "no_copy": 0, + "non_negative": 0, + "options": null, + "owner": "Administrator", + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 1, + "unique": 0, + "width": null + }, + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "creation": "2020-10-14 17:41:40.878179", + "default": "0", + "depends_on": null, + "description": null, + "docstatus": 0, + "dt": "Address", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "is_your_company_address", + "fieldtype": "Check", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "idx": 22, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "linked_with", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Is Your Company Address", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "modified": "2020-10-14 17:41:40.878179", + "modified_by": "Administrator", + "module": null, + "name": "Address-is_your_company_address", + "no_copy": 0, + "non_negative": 0, + "options": null, + "owner": "Administrator", + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + }, + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "creation": "2018-12-28 22:29:21.828090", + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "dt": "Address", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "tax_category", + "fieldtype": "Link", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "idx": 17, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "fax", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Tax Category", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "modified": "2018-12-28 22:29:21.828090", + "modified_by": "Administrator", + "module": null, + "name": "Address-tax_category", + "no_copy": 0, + "non_negative": 0, + "options": "Tax Category", + "owner": "Administrator", + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + } + ], + "custom_perms": [], + "doctype": "Address", + "links": [], + "property_setters": [ + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "creation": "2026-03-05 12:03:28.050761", + "default_value": null, + "doc_type": "Address", + "docstatus": 0, + "doctype_or_field": "DocType", + "field_name": null, + "idx": 0, + "is_system_generated": 0, + "modified": "2026-03-05 12:03:28.050761", + "modified_by": "Administrator", + "module": null, + "name": "Address-main-field_order", + "owner": "Administrator", + "property": "field_order", + "property_type": "Data", + "row_name": null, + "value": "[\"address_details\", \"address_title\", \"address_type\", \"address_line1\", \"address_line2\", \"city\", \"custom_building_number\", \"custom_area\", \"county\", \"state\", \"country\", \"pincode\", \"column_break0\", \"email_id\", \"phone\", \"fax\", \"tax_category\", \"is_primary_address\", \"is_shipping_address\", \"disabled\", \"linked_with\", \"is_your_company_address\", \"links\"]" + } + ], + "sync_on_migrate": 0 +} \ No newline at end of file diff --git a/rmax_custom/rmax_custom/custom/customer.json b/rmax_custom/rmax_custom/custom/customer.json new file mode 100644 index 0000000..83f4888 --- /dev/null +++ b/rmax_custom/rmax_custom/custom/customer.json @@ -0,0 +1,164 @@ +{ + "custom_fields": [ + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "creation": "2026-03-05 11:59:55.533346", + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "dt": "Customer", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "custom_vat_registration_number", + "fieldtype": "Data", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "idx": 7, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "customer_group", + "is_system_generated": 0, + "is_virtual": 0, + "label": "VAT Registration Number", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "modified": "2026-03-05 11:59:55.533346", + "modified_by": "Administrator", + "module": null, + "name": "Customer-custom_vat_registration_number", + "no_copy": 0, + "non_negative": 0, + "options": null, + "owner": "Administrator", + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 1, + "unique": 0, + "width": null + } + ], + "custom_perms": [], + "doctype": "Customer", + "links": [ + { + "creation": "2013-06-11 14:26:44", + "custom": 0, + "docstatus": 0, + "group": "Allowed Items", + "hidden": 0, + "idx": 1, + "is_child_table": 0, + "link_doctype": "Party Specific Item", + "link_fieldname": "party", + "modified": "2026-02-26 12:40:34.799347", + "modified_by": "Administrator", + "name": "spck7v9ar7", + "owner": "Administrator", + "parent": "Customer", + "parent_doctype": null, + "parentfield": "links", + "parenttype": "DocType", + "table_fieldname": null + } + ], + "property_setters": [ + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "creation": "2026-03-05 12:00:26.217315", + "default_value": null, + "doc_type": "Customer", + "docstatus": 0, + "doctype_or_field": "DocType", + "field_name": null, + "idx": 0, + "is_system_generated": 0, + "modified": "2026-03-05 12:00:26.217315", + "modified_by": "Administrator", + "module": null, + "name": "Customer-main-field_order", + "owner": "Administrator", + "property": "field_order", + "property_type": "Data", + "row_name": null, + "value": "[\"basic_info\", \"naming_series\", \"salutation\", \"customer_name\", \"customer_type\", \"customer_group\", \"custom_vat_registration_number\", \"column_break0\", \"territory\", \"gender\", \"lead_name\", \"opportunity_name\", \"prospect_name\", \"account_manager\", \"image\", \"defaults_tab\", \"default_currency\", \"default_bank_account\", \"column_break_14\", \"default_price_list\", \"internal_customer_section\", \"is_internal_customer\", \"represents_company\", \"column_break_70\", \"companies\", \"more_info\", \"market_segment\", \"industry\", \"customer_pos_id\", \"website\", \"language\", \"column_break_45\", \"customer_details\", \"dashboard_tab\", \"contact_and_address_tab\", \"address_contacts\", \"address_html\", \"column_break1\", \"contact_html\", \"primary_address_and_contact_detail\", \"column_break_26\", \"customer_primary_address\", \"primary_address\", \"column_break_nwor\", \"customer_primary_contact\", \"mobile_no\", \"email_id\", \"first_name\", \"last_name\", \"tax_tab\", \"taxation_section\", \"tax_id\", \"column_break_21\", \"tax_category\", \"tax_withholding_category\", \"accounting_tab\", \"credit_limit_section\", \"payment_terms\", \"credit_limits\", \"default_receivable_accounts\", \"accounts\", \"loyalty_points_tab\", \"loyalty_program\", \"column_break_54\", \"loyalty_program_tier\", \"sales_team_tab\", \"sales_team\", \"sales_team_section\", \"default_sales_partner\", \"column_break_66\", \"default_commission_rate\", \"settings_tab\", \"so_required\", \"dn_required\", \"column_break_53\", \"is_frozen\", \"disabled\", \"portal_users_tab\", \"portal_users\"]" + }, + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "creation": "2026-02-26 12:49:38.262747", + "default_value": null, + "doc_type": "Customer", + "docstatus": 0, + "doctype_or_field": "DocField", + "field_name": "naming_series", + "idx": 0, + "is_system_generated": 1, + "modified": "2026-02-26 12:49:38.262747", + "modified_by": "Administrator", + "module": null, + "name": "Customer-naming_series-hidden", + "owner": "Administrator", + "property": "hidden", + "property_type": "Check", + "row_name": null, + "value": "1" + }, + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "creation": "2026-02-26 12:49:38.125211", + "default_value": null, + "doc_type": "Customer", + "docstatus": 0, + "doctype_or_field": "DocField", + "field_name": "naming_series", + "idx": 0, + "is_system_generated": 1, + "modified": "2026-02-26 12:49:38.125211", + "modified_by": "Administrator", + "module": null, + "name": "Customer-naming_series-reqd", + "owner": "Administrator", + "property": "reqd", + "property_type": "Check", + "row_name": null, + "value": "0" + } + ], + "sync_on_migrate": 0 +} \ No newline at end of file diff --git a/rmax_custom/rmax_custom/custom/sales_invoice.json b/rmax_custom/rmax_custom/custom/sales_invoice.json index 0ca2edd..bfe1dd9 100644 --- a/rmax_custom/rmax_custom/custom/sales_invoice.json +++ b/rmax_custom/rmax_custom/custom/sales_invoice.json @@ -11,7 +11,71 @@ "collapsible": 0, "collapsible_depends_on": null, "columns": 0, - "creation": "2026-02-26 16:23:30.463431", + "creation": "2026-03-07 23:10:01.661809", + "default": null, + "depends_on": "eval:doc.is_internal_customer && doc.represents_company", + "description": null, + "docstatus": 0, + "dt": "Sales Invoice", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "custom_inter_company_branch", + "fieldtype": "Link", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "idx": 8, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "company_tax_id", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Inter Company Branch", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "modified": "2026-03-07 23:10:01.661809", + "modified_by": "Administrator", + "module": null, + "name": "Sales Invoice-custom_inter_company_branch", + "no_copy": 0, + "non_negative": 0, + "options": "Inter Company Branch", + "owner": "Administrator", + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + }, + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "creation": "2026-03-07 16:50:18.832354", "default": null, "depends_on": null, "description": null, @@ -25,7 +89,7 @@ "hide_border": 0, "hide_days": 0, "hide_seconds": 0, - "idx": 14, + "idx": 15, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_global_search": 0, @@ -40,13 +104,13 @@ "link_filters": null, "mandatory_depends_on": null, "modified": "2026-02-26 16:23:30.463431", - "modified_by": "neha@example.com", + "modified_by": "Administrator", "module": null, "name": "Sales Invoice-custom_payment_mode", "no_copy": 0, "non_negative": 0, "options": "Cash\nCredit", - "owner": "neha@example.com", + "owner": "Administrator", "permlevel": 0, "placeholder": null, "precision": "", @@ -256,7 +320,7 @@ "_comments": null, "_liked_by": null, "_user_tags": null, - "creation": "2026-02-26 16:23:39.047054", + "creation": "2026-03-07 23:10:01.561453", "default_value": null, "doc_type": "Sales Invoice", "docstatus": 0, @@ -264,15 +328,15 @@ "field_name": null, "idx": 0, "is_system_generated": 0, - "modified": "2026-02-26 16:23:39.047054", - "modified_by": "neha@example.com", + "modified": "2026-03-07 23:10:01.561453", + "modified_by": "Administrator", "module": null, "name": "Sales Invoice-main-field_order", - "owner": "neha@example.com", + "owner": "Administrator", "property": "field_order", "property_type": "Data", "row_name": null, - "value": "[\"customer_section\", \"title\", \"naming_series\", \"customer\", \"customer_name\", \"tax_id\", \"company\", \"company_tax_id\", \"column_break1\", \"posting_date\", \"posting_time\", \"set_posting_time\", \"due_date\", \"custom_payment_mode\", \"column_break_14\", \"is_pos\", \"pos_profile\", \"is_consolidated\", \"is_return\", \"return_against\", \"update_outstanding_for_self\", \"update_billed_amount_in_sales_order\", \"update_billed_amount_in_delivery_note\", \"is_debit_note\", \"amended_from\", \"accounting_dimensions_section\", \"cost_center\", \"dimension_col_break\", \"project\", \"currency_and_price_list\", \"currency\", \"conversion_rate\", \"column_break2\", \"selling_price_list\", \"price_list_currency\", \"plc_conversion_rate\", \"ignore_pricing_rule\", \"items_section\", \"scan_barcode\", \"update_stock\", \"last_scanned_warehouse\", \"column_break_39\", \"set_warehouse\", \"set_target_warehouse\", \"section_break_42\", \"items\", \"section_break_30\", \"total_qty\", \"total_net_weight\", \"column_break_32\", \"base_total\", \"base_net_total\", \"column_break_52\", \"total\", \"net_total\", \"taxes_section\", \"tax_category\", \"taxes_and_charges\", \"column_break_38\", \"shipping_rule\", \"column_break_55\", \"incoterm\", \"named_place\", \"section_break_40\", \"taxes\", \"section_break_43\", \"base_total_taxes_and_charges\", \"column_break_47\", \"total_taxes_and_charges\", \"totals\", \"base_grand_total\", \"base_rounding_adjustment\", \"base_rounded_total\", \"base_in_words\", \"column_break5\", \"grand_total\", \"rounding_adjustment\", \"use_company_roundoff_cost_center\", \"rounded_total\", \"in_words\", \"total_advance\", \"outstanding_amount\", \"disable_rounded_total\", \"section_break_49\", \"apply_discount_on\", \"base_discount_amount\", \"is_cash_or_non_trade_discount\", \"additional_discount_account\", \"column_break_51\", \"additional_discount_percentage\", \"discount_amount\", \"sec_tax_breakup\", \"other_charges_calculation\", \"pricing_rule_details\", \"pricing_rules\", \"packing_list\", \"packed_items\", \"product_bundle_help\", \"time_sheet_list\", \"timesheets\", \"section_break_104\", \"total_billing_hours\", \"column_break_106\", \"total_billing_amount\", \"payments_tab\", \"payments_section\", \"cash_bank_account\", \"payments\", \"section_break_84\", \"base_paid_amount\", \"column_break_86\", \"paid_amount\", \"section_break_88\", \"base_change_amount\", \"column_break_90\", \"change_amount\", \"account_for_change_amount\", \"advances_section\", \"allocate_advances_automatically\", \"only_include_allocated_payments\", \"get_advances\", \"advances\", \"write_off_section\", \"write_off_amount\", \"base_write_off_amount\", \"write_off_outstanding_amount_automatically\", \"column_break_74\", \"write_off_account\", \"write_off_cost_center\", \"loyalty_points_redemption\", \"redeem_loyalty_points\", \"loyalty_points\", \"loyalty_amount\", \"column_break_77\", \"loyalty_program\", \"loyalty_redemption_account\", \"loyalty_redemption_cost_center\", \"contact_and_address_tab\", \"address_and_contact\", \"customer_address\", \"address_display\", \"col_break4\", \"contact_person\", \"contact_display\", \"contact_mobile\", \"contact_email\", \"territory\", \"shipping_address_section\", \"shipping_address_name\", \"shipping_address\", \"shipping_addr_col_break\", \"dispatch_address_name\", \"dispatch_address\", \"company_address_section\", \"company_address\", \"company_address_display\", \"company_addr_col_break\", \"company_contact_person\", \"terms_tab\", \"payment_schedule_section\", \"ignore_default_payment_terms_template\", \"payment_terms_template\", \"payment_schedule\", \"terms_section_break\", \"tc_name\", \"terms\", \"more_info_tab\", \"customer_po_details\", \"po_no\", \"column_break_23\", \"po_date\", \"more_info\", \"debit_to\", \"party_account_currency\", \"is_opening\", \"column_break8\", \"unrealized_profit_loss_account\", \"against_income_account\", \"sales_team_section_break\", \"sales_partner\", \"amount_eligible_for_commission\", \"column_break10\", \"commission_rate\", \"total_commission\", \"section_break2\", \"sales_team\", \"edit_printing_settings\", \"letter_head\", \"group_same_items\", \"column_break_84\", \"select_print_heading\", \"language\", \"subscription_section\", \"subscription\", \"from_date\", \"auto_repeat\", \"column_break_140\", \"to_date\", \"update_auto_repeat_reference\", \"more_information\", \"status\", \"inter_company_invoice_reference\", \"campaign\", \"represents_company\", \"source\", \"customer_group\", \"col_break23\", \"is_internal_customer\", \"is_discounted\", \"remarks\", \"connections_tab\"]" + "value": "[\"customer_section\", \"title\", \"naming_series\", \"customer\", \"customer_name\", \"tax_id\", \"company\", \"company_tax_id\", \"inter_company_branch\", \"column_break1\", \"posting_date\", \"posting_time\", \"set_posting_time\", \"due_date\", \"custom_payment_mode\", \"column_break_14\", \"is_pos\", \"pos_profile\", \"is_consolidated\", \"is_return\", \"return_against\", \"update_outstanding_for_self\", \"update_billed_amount_in_sales_order\", \"update_billed_amount_in_delivery_note\", \"is_debit_note\", \"amended_from\", \"accounting_dimensions_section\", \"cost_center\", \"dimension_col_break\", \"project\", \"currency_and_price_list\", \"currency\", \"conversion_rate\", \"column_break2\", \"selling_price_list\", \"price_list_currency\", \"plc_conversion_rate\", \"ignore_pricing_rule\", \"items_section\", \"scan_barcode\", \"update_stock\", \"last_scanned_warehouse\", \"column_break_39\", \"set_warehouse\", \"set_target_warehouse\", \"section_break_42\", \"items\", \"section_break_30\", \"total_qty\", \"total_net_weight\", \"column_break_32\", \"base_total\", \"base_net_total\", \"column_break_52\", \"total\", \"net_total\", \"taxes_section\", \"tax_category\", \"taxes_and_charges\", \"column_break_38\", \"shipping_rule\", \"column_break_55\", \"incoterm\", \"named_place\", \"section_break_40\", \"taxes\", \"section_break_43\", \"base_total_taxes_and_charges\", \"column_break_47\", \"total_taxes_and_charges\", \"totals\", \"base_grand_total\", \"base_rounding_adjustment\", \"base_rounded_total\", \"base_in_words\", \"column_break5\", \"grand_total\", \"rounding_adjustment\", \"use_company_roundoff_cost_center\", \"rounded_total\", \"in_words\", \"total_advance\", \"outstanding_amount\", \"disable_rounded_total\", \"section_break_49\", \"apply_discount_on\", \"base_discount_amount\", \"is_cash_or_non_trade_discount\", \"additional_discount_account\", \"column_break_51\", \"additional_discount_percentage\", \"discount_amount\", \"sec_tax_breakup\", \"other_charges_calculation\", \"pricing_rule_details\", \"pricing_rules\", \"packing_list\", \"packed_items\", \"product_bundle_help\", \"time_sheet_list\", \"timesheets\", \"section_break_104\", \"total_billing_hours\", \"column_break_106\", \"total_billing_amount\", \"payments_tab\", \"payments_section\", \"cash_bank_account\", \"payments\", \"section_break_84\", \"base_paid_amount\", \"column_break_86\", \"paid_amount\", \"section_break_88\", \"base_change_amount\", \"column_break_90\", \"change_amount\", \"account_for_change_amount\", \"advances_section\", \"allocate_advances_automatically\", \"only_include_allocated_payments\", \"get_advances\", \"advances\", \"write_off_section\", \"write_off_amount\", \"base_write_off_amount\", \"write_off_outstanding_amount_automatically\", \"column_break_74\", \"write_off_account\", \"write_off_cost_center\", \"loyalty_points_redemption\", \"redeem_loyalty_points\", \"loyalty_points\", \"loyalty_amount\", \"column_break_77\", \"loyalty_program\", \"loyalty_redemption_account\", \"loyalty_redemption_cost_center\", \"contact_and_address_tab\", \"address_and_contact\", \"customer_address\", \"address_display\", \"col_break4\", \"contact_person\", \"contact_display\", \"contact_mobile\", \"contact_email\", \"territory\", \"shipping_address_section\", \"shipping_address_name\", \"shipping_address\", \"shipping_addr_col_break\", \"dispatch_address_name\", \"dispatch_address\", \"company_address_section\", \"company_address\", \"company_address_display\", \"company_addr_col_break\", \"company_contact_person\", \"terms_tab\", \"payment_schedule_section\", \"ignore_default_payment_terms_template\", \"payment_terms_template\", \"payment_schedule\", \"terms_section_break\", \"tc_name\", \"terms\", \"more_info_tab\", \"customer_po_details\", \"po_no\", \"column_break_23\", \"po_date\", \"more_info\", \"debit_to\", \"party_account_currency\", \"is_opening\", \"column_break8\", \"unrealized_profit_loss_account\", \"against_income_account\", \"sales_team_section_break\", \"sales_partner\", \"amount_eligible_for_commission\", \"column_break10\", \"commission_rate\", \"total_commission\", \"section_break2\", \"sales_team\", \"edit_printing_settings\", \"letter_head\", \"group_same_items\", \"column_break_84\", \"select_print_heading\", \"language\", \"subscription_section\", \"subscription\", \"from_date\", \"auto_repeat\", \"column_break_140\", \"to_date\", \"update_auto_repeat_reference\", \"more_information\", \"status\", \"inter_company_invoice_reference\", \"campaign\", \"represents_company\", \"source\", \"customer_group\", \"col_break23\", \"is_internal_customer\", \"is_discounted\", \"remarks\", \"connections_tab\"]" }, { "_assign": null, diff --git a/rmax_custom/rmax_custom/doctype/__init__.py b/rmax_custom/rmax_custom/doctype/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rmax_custom/rmax_custom/doctype/inter_company_branch/__init__.py b/rmax_custom/rmax_custom/doctype/inter_company_branch/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rmax_custom/rmax_custom/doctype/inter_company_branch/inter_company_branch.js b/rmax_custom/rmax_custom/doctype/inter_company_branch/inter_company_branch.js new file mode 100644 index 0000000..279d56e --- /dev/null +++ b/rmax_custom/rmax_custom/doctype/inter_company_branch/inter_company_branch.js @@ -0,0 +1,35 @@ +// Copyright (c) 2026, Enfono and contributors +// For license information, please see license.txt + +frappe.ui.form.on("Inter Company Branch", { + onload: function (frm) { + frm.set_query("cost_center", "company_cost_centers", function (doc, cdt, cdn) { + let row = locals[cdt][cdn]; + if (!row.company) return { filters: { name: "" } }; + return { + filters: [ + ["Cost Center", "company", "=", row.company], + ["Cost Center", "is_group", "=", 0], + ], + }; + }); + frm.set_query("warehouse", "company_cost_centers", function (doc, cdt, cdn) { + let row = locals[cdt][cdn]; + if (!row.company) return { filters: { name: "" } }; + return { + filters: [["Warehouse", "company", "=", row.company]], + }; + }); + }, +}); + +frappe.ui.form.on("Inter Company Branch Cost Center", { + company: function (frm, cdt, cdn) { + let row = locals[cdt][cdn]; + if (row.company) { + frappe.model.set_value(cdt, cdn, "cost_center", ""); + frappe.model.set_value(cdt, cdn, "warehouse", ""); + } + }, +}); + diff --git a/rmax_custom/rmax_custom/doctype/inter_company_branch/inter_company_branch.json b/rmax_custom/rmax_custom/doctype/inter_company_branch/inter_company_branch.json new file mode 100644 index 0000000..dbc58aa --- /dev/null +++ b/rmax_custom/rmax_custom/doctype/inter_company_branch/inter_company_branch.json @@ -0,0 +1,56 @@ +{ + "actions": [], + "allow_rename": 1, + "autoname": "field:branch_name", + "creation": "2026-03-07 12:48:03.441410", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "branch_name", + "company_cost_centers" + ], + "fields": [ + { + "fieldname": "branch_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Branch Name", + "reqd": 1, + "unique": 1 + }, + { + "fieldname": "company_cost_centers", + "fieldtype": "Table", + "label": "Company Cost Centers", + "options": "Inter Company Branch Cost Center" + } + ], + "grid_page_length": 50, + "index_web_pages_for_search": 1, + "links": [], + "modified": "2026-03-07 12:51:02.022378", + "modified_by": "Administrator", + "module": "Rmax Custom", + "name": "Inter Company Branch", + "naming_rule": "By fieldname", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "row_format": "Dynamic", + "rows_threshold_for_grid_search": 20, + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/rmax_custom/rmax_custom/doctype/inter_company_branch/inter_company_branch.py b/rmax_custom/rmax_custom/doctype/inter_company_branch/inter_company_branch.py new file mode 100644 index 0000000..6ea809c --- /dev/null +++ b/rmax_custom/rmax_custom/doctype/inter_company_branch/inter_company_branch.py @@ -0,0 +1,33 @@ +# Copyright (c) 2026, Enfono and contributors +# For license information, please see license.txt + +import frappe +from frappe.model.document import Document + + +class InterCompanyBranch(Document): + def validate(self): + companies = [row.company for row in self.company_cost_centers] + if len(companies) != len(set(companies)): + frappe.throw(frappe._("Duplicate company in Company Cost Centers")) + + + +@frappe.whitelist() +@frappe.validate_and_sanitize_search_inputs +def get_branches_for_company(doctype, txt, searchfield, start, page_len, filters): + """Return Inter Company Branch names that have cost center for the given company.""" + company = filters.get("company") if isinstance(filters, dict) and filters else None + if not company: + return [] + txt = txt or "" + # Return (name, name) for link field value and description + return frappe.db.sql( + """ + SELECT DISTINCT parent, parent FROM `tabInter Company Branch Cost Center` + WHERE company = %(company)s AND parent LIKE %(txt)s + ORDER BY parent + LIMIT %(start)s, %(page_len)s + """, + {"company": company, "txt": f"%%{txt}%%", "start": int(start), "page_len": int(page_len)}, + ) \ No newline at end of file diff --git a/rmax_custom/rmax_custom/doctype/inter_company_branch/test_inter_company_branch.py b/rmax_custom/rmax_custom/doctype/inter_company_branch/test_inter_company_branch.py new file mode 100644 index 0000000..8f4e994 --- /dev/null +++ b/rmax_custom/rmax_custom/doctype/inter_company_branch/test_inter_company_branch.py @@ -0,0 +1,9 @@ +# Copyright (c) 2026, Enfono and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestInterCompanyBranch(FrappeTestCase): + pass diff --git a/rmax_custom/rmax_custom/doctype/inter_company_branch_cost_center/__init__.py b/rmax_custom/rmax_custom/doctype/inter_company_branch_cost_center/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rmax_custom/rmax_custom/doctype/inter_company_branch_cost_center/inter_company_branch_cost_center.json b/rmax_custom/rmax_custom/doctype/inter_company_branch_cost_center/inter_company_branch_cost_center.json new file mode 100644 index 0000000..211bf35 --- /dev/null +++ b/rmax_custom/rmax_custom/doctype/inter_company_branch_cost_center/inter_company_branch_cost_center.json @@ -0,0 +1,53 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2026-03-07 12:43:39.894126", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "company", + "cost_center", + "warehouse" + ], + "fields": [ + { + "fieldname": "company", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Company", + "options": "Company", + "reqd": 1 + }, + { + "fieldname": "cost_center", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Cost Center", + "options": "Cost Center", + "reqd": 1 + }, + { + "fieldname": "warehouse", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Warehouse", + "options": "Warehouse" + } + ], + "grid_page_length": 50, + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2026-03-07 12:58:13.313941", + "modified_by": "Administrator", + "module": "Rmax Custom", + "name": "Inter Company Branch Cost Center", + "owner": "Administrator", + "permissions": [], + "row_format": "Dynamic", + "rows_threshold_for_grid_search": 20, + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/rmax_custom/rmax_custom/doctype/inter_company_branch_cost_center/inter_company_branch_cost_center.py b/rmax_custom/rmax_custom/doctype/inter_company_branch_cost_center/inter_company_branch_cost_center.py new file mode 100644 index 0000000..816970c --- /dev/null +++ b/rmax_custom/rmax_custom/doctype/inter_company_branch_cost_center/inter_company_branch_cost_center.py @@ -0,0 +1,9 @@ +# Copyright (c) 2026, Enfono and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class InterCompanyBranchCostCenter(Document): + pass