From 8537556e2d96ec436d308fd3023e55e4f93da11e Mon Sep 17 00:00:00 2001 From: hridyalakshmi Date: Wed, 1 Apr 2026 11:43:12 +0530 Subject: [PATCH 1/2] feat: Cost Head Mapping in SO,SI,PO and PI --- .../purchase_invoice/purchase_invoice.js | 24 ++++++++++++++++++- .../purchase_invoice/purchase_invoice.py | 10 ++++++++ .../purchase_order/purchase_order.js | 22 +++++++++++++++++ .../sales_invoice/sales_invoice.js | 22 +++++++++++++++++ .../custom_scripts/sales_order/sales_order.js | 22 +++++++++++++++++ beams/hooks.py | 14 ++++++++--- beams/setup.py | 7 ++++++ 7 files changed, 117 insertions(+), 4 deletions(-) diff --git a/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.js b/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.js index 4d115662f..4893d213b 100644 --- a/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.js +++ b/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.js @@ -189,4 +189,26 @@ function fetch_advances_from_mcts(frm) { }, }); } -} \ No newline at end of file +} + +/** + * Fetch cost head from the item doctype. + */ +function set_cost_head(cdt, cdn) { + let row = locals[cdt][cdn]; + + if (row.item_code) { + frappe.db.get_value('Item', row.item_code, 'cost_head') + .then(r => { + if (r.message && r.message.cost_head) { + frappe.model.set_value(cdt, cdn, 'cost_head', r.message.cost_head); + } + }); + } +} + +frappe.ui.form.on('Purchase Invoice Item', { + item_code: function(frm, cdt, cdn) { + set_cost_head(cdt, cdn); + } +}); \ No newline at end of file diff --git a/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.py b/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.py index 0f3bd1195..954c2c4f7 100644 --- a/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.py +++ b/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.py @@ -33,3 +33,13 @@ def set_from_bureau_flag(doc, method): if "Bureau User" in frappe.get_roles(user): doc.from_bureau = 1 +def set_cost_head_from_item(doc, method=None): + """ + Fetch cost head from item doctype + """ + for row in doc.get("items"): + if not row.item_code: + continue + item_cost_head = frappe.db.get_value("Item", row.item_code, "cost_head") + if item_cost_head: + row.cost_head = item_cost_head \ No newline at end of file diff --git a/beams/beams/custom_scripts/purchase_order/purchase_order.js b/beams/beams/custom_scripts/purchase_order/purchase_order.js index 46e5f6f4b..c532b765c 100644 --- a/beams/beams/custom_scripts/purchase_order/purchase_order.js +++ b/beams/beams/custom_scripts/purchase_order/purchase_order.js @@ -48,3 +48,25 @@ function clear_checkbox_exceed(frm){ frm.set_value("is_budget_exceeded", 0); } } + +/** + * Fetch cost head from the item doctype. + */ +function set_cost_head(cdt, cdn) { + let row = locals[cdt][cdn]; + + if (row.item_code) { + frappe.db.get_value('Item', row.item_code, 'cost_head') + .then(r => { + if (r.message && r.message.cost_head) { + frappe.model.set_value(cdt, cdn, 'cost_head', r.message.cost_head); + } + }); + } +} + +frappe.ui.form.on('Purchase Order Item', { + item_code: function(frm, cdt, cdn) { + set_cost_head(cdt, cdn); + } +}); \ No newline at end of file diff --git a/beams/beams/custom_scripts/sales_invoice/sales_invoice.js b/beams/beams/custom_scripts/sales_invoice/sales_invoice.js index 6ac985647..b3cb8ad29 100644 --- a/beams/beams/custom_scripts/sales_invoice/sales_invoice.js +++ b/beams/beams/custom_scripts/sales_invoice/sales_invoice.js @@ -74,3 +74,25 @@ function check_include_in_ibf(frm) { }); } } + +/** + * Fetch cost head from the item doctype. + */ +function set_cost_head(cdt, cdn) { + let row = locals[cdt][cdn]; + + if (row.item_code) { + frappe.db.get_value('Item', row.item_code, 'cost_head') + .then(r => { + if (r.message && r.message.cost_head) { + frappe.model.set_value(cdt, cdn, 'cost_head', r.message.cost_head); + } + }); + } +} + +frappe.ui.form.on('Sales Invoice Item', { + item_code: function(frm, cdt, cdn) { + set_cost_head(cdt, cdn); + } +}); diff --git a/beams/beams/custom_scripts/sales_order/sales_order.js b/beams/beams/custom_scripts/sales_order/sales_order.js index 3e07265a2..1d260d237 100644 --- a/beams/beams/custom_scripts/sales_order/sales_order.js +++ b/beams/beams/custom_scripts/sales_order/sales_order.js @@ -137,3 +137,25 @@ function check_is_agent_from_customer(frm) { }); } } + +/** + * Fetch cost head from the item doctype. + */ +function set_cost_head(cdt, cdn) { + let row = locals[cdt][cdn]; + + if (row.item_code) { + frappe.db.get_value('Item', row.item_code, 'cost_head') + .then(r => { + if (r.message && r.message.cost_head) { + frappe.model.set_value(cdt, cdn, 'cost_head', r.message.cost_head); + } + }); + } +} + +frappe.ui.form.on('Sales Order Item', { + item_code: function(frm, cdt, cdn) { + set_cost_head(cdt, cdn); + } +}); \ No newline at end of file diff --git a/beams/hooks.py b/beams/hooks.py index b56afcb8b..e071a3d30 100644 --- a/beams/hooks.py +++ b/beams/hooks.py @@ -197,7 +197,10 @@ "Sales Invoice": { "on_update_after_submit":"beams.beams.custom_scripts.sales_invoice.sales_invoice.on_update_after_submit", "autoname": "beams.beams.custom_scripts.sales_invoice.sales_invoice.autoname", - "validate": "beams.beams.custom_scripts.sales_invoice.sales_invoice.validate_sales_invoice_for_barter" + "validate": [ + "beams.beams.custom_scripts.sales_invoice.sales_invoice.validate_sales_invoice_for_barter", + "beams.beams.custom_scripts.purchase_invoice.purchase_invoice.set_cost_head_from_item", + ], }, "Quotation": { "validate": "beams.beams.custom_scripts.quotation.quotation.validate_is_barter", @@ -208,6 +211,7 @@ "before_save": "beams.beams.custom_scripts.purchase_invoice.purchase_invoice.before_save", "before_insert": "beams.beams.custom_scripts.purchase_invoice.purchase_invoice.set_from_bureau_flag", "before_validate": "beams.beams.custom_scripts.purchase_order.purchase_order.set_is_budgeted", + "validate": "beams.beams.custom_scripts.purchase_invoice.purchase_invoice.set_cost_head_from_item", }, "Account": { "after_insert": "beams.beams.custom_scripts.account.account.create_todo_on_creation_for_account" @@ -229,7 +233,10 @@ }, "Purchase Order": { "on_update": "beams.beams.custom_scripts.purchase_order.purchase_order.create_todo_on_finance_verification", - "validate": "beams.beams.custom_scripts.purchase_order.purchase_order.validate_reason_for_rejection", + "validate": [ + "beams.beams.custom_scripts.purchase_order.purchase_order.validate_reason_for_rejection", + "beams.beams.custom_scripts.purchase_invoice.purchase_invoice.set_cost_head_from_item", + ], "before_validate": "beams.beams.custom_scripts.purchase_order.purchase_order.set_is_budgeted", "on_change":"beams.beams.custom_scripts.purchase_order.purchase_order.update_equipment_quantities", }, @@ -243,7 +250,8 @@ "Sales Order": { "autoname": "beams.beams.custom_scripts.sales_order.sales_order.autoname", "before_save": "beams.beams.custom_scripts.sales_order.sales_order.validate_sales_order_amount_with_quotation", - "before_insert": "beams.beams.custom_scripts.sales_order.sales_order.set_region_from_quotation" + "before_insert": "beams.beams.custom_scripts.sales_order.sales_order.set_region_from_quotation", + "validate": "beams.beams.custom_scripts.purchase_invoice.purchase_invoice.set_cost_head_from_item", }, "Contract": { "on_update": "beams.beams.custom_scripts.contract.contract.create_todo_on_contract_verified_by_finance", diff --git a/beams/setup.py b/beams/setup.py index b51e8e843..d9d2d8311 100644 --- a/beams/setup.py +++ b/beams/setup.py @@ -1999,6 +1999,13 @@ def get_item_custom_fields(): "fieldtype": "Check", "label": "Is Bundle Item", "insert_after": "has_variants" + }, + { + "fieldname": "cost_head", + "fieldtype": "Link", + "label": "Cost Head", + "options": "Cost Head", + "insert_after": "item_defaults" } ] } From 92a804709b8f03e802203343e3af2f231aaa2ea1 Mon Sep 17 00:00:00 2001 From: hridyalakshmi Date: Wed, 1 Apr 2026 13:02:32 +0530 Subject: [PATCH 2/2] fix: coding standards --- .../beams/custom_scripts/purchase_invoice/purchase_invoice.js | 3 +-- .../beams/custom_scripts/purchase_invoice/purchase_invoice.py | 2 +- beams/beams/custom_scripts/purchase_order/purchase_order.js | 3 +-- beams/beams/custom_scripts/sales_invoice/sales_invoice.js | 2 +- beams/beams/custom_scripts/sales_order/sales_order.js | 3 +-- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.js b/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.js index 4893d213b..5cbc67a16 100644 --- a/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.js +++ b/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.js @@ -196,7 +196,6 @@ function fetch_advances_from_mcts(frm) { */ function set_cost_head(cdt, cdn) { let row = locals[cdt][cdn]; - if (row.item_code) { frappe.db.get_value('Item', row.item_code, 'cost_head') .then(r => { @@ -211,4 +210,4 @@ frappe.ui.form.on('Purchase Invoice Item', { item_code: function(frm, cdt, cdn) { set_cost_head(cdt, cdn); } -}); \ No newline at end of file +}); diff --git a/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.py b/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.py index 954c2c4f7..6275d2c71 100644 --- a/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.py +++ b/beams/beams/custom_scripts/purchase_invoice/purchase_invoice.py @@ -42,4 +42,4 @@ def set_cost_head_from_item(doc, method=None): continue item_cost_head = frappe.db.get_value("Item", row.item_code, "cost_head") if item_cost_head: - row.cost_head = item_cost_head \ No newline at end of file + row.cost_head = item_cost_head diff --git a/beams/beams/custom_scripts/purchase_order/purchase_order.js b/beams/beams/custom_scripts/purchase_order/purchase_order.js index c532b765c..97ba34c4e 100644 --- a/beams/beams/custom_scripts/purchase_order/purchase_order.js +++ b/beams/beams/custom_scripts/purchase_order/purchase_order.js @@ -54,7 +54,6 @@ function clear_checkbox_exceed(frm){ */ function set_cost_head(cdt, cdn) { let row = locals[cdt][cdn]; - if (row.item_code) { frappe.db.get_value('Item', row.item_code, 'cost_head') .then(r => { @@ -69,4 +68,4 @@ frappe.ui.form.on('Purchase Order Item', { item_code: function(frm, cdt, cdn) { set_cost_head(cdt, cdn); } -}); \ No newline at end of file +}); diff --git a/beams/beams/custom_scripts/sales_invoice/sales_invoice.js b/beams/beams/custom_scripts/sales_invoice/sales_invoice.js index b3cb8ad29..2209a5c88 100644 --- a/beams/beams/custom_scripts/sales_invoice/sales_invoice.js +++ b/beams/beams/custom_scripts/sales_invoice/sales_invoice.js @@ -80,7 +80,6 @@ function check_include_in_ibf(frm) { */ function set_cost_head(cdt, cdn) { let row = locals[cdt][cdn]; - if (row.item_code) { frappe.db.get_value('Item', row.item_code, 'cost_head') .then(r => { @@ -96,3 +95,4 @@ frappe.ui.form.on('Sales Invoice Item', { set_cost_head(cdt, cdn); } }); + diff --git a/beams/beams/custom_scripts/sales_order/sales_order.js b/beams/beams/custom_scripts/sales_order/sales_order.js index 1d260d237..bcbf77854 100644 --- a/beams/beams/custom_scripts/sales_order/sales_order.js +++ b/beams/beams/custom_scripts/sales_order/sales_order.js @@ -143,7 +143,6 @@ function check_is_agent_from_customer(frm) { */ function set_cost_head(cdt, cdn) { let row = locals[cdt][cdn]; - if (row.item_code) { frappe.db.get_value('Item', row.item_code, 'cost_head') .then(r => { @@ -158,4 +157,4 @@ frappe.ui.form.on('Sales Order Item', { item_code: function(frm, cdt, cdn) { set_cost_head(cdt, cdn); } -}); \ No newline at end of file +});