Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion beams/beams/custom_scripts/purchase_invoice/purchase_invoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,25 @@ function fetch_advances_from_mcts(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('Purchase Invoice Item', {
item_code: function(frm, cdt, cdn) {
set_cost_head(cdt, cdn);
}
});
10 changes: 10 additions & 0 deletions beams/beams/custom_scripts/purchase_invoice/purchase_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
21 changes: 21 additions & 0 deletions beams/beams/custom_scripts/purchase_order/purchase_order.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,24 @@ 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);
}
});
22 changes: 22 additions & 0 deletions beams/beams/custom_scripts/sales_invoice/sales_invoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});

21 changes: 21 additions & 0 deletions beams/beams/custom_scripts/sales_order/sales_order.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,24 @@ 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);
}
});
5 changes: 2 additions & 3 deletions beams/beams/doctype/batta_claim/batta_claim.json
Original file line number Diff line number Diff line change
Expand Up @@ -287,11 +287,10 @@
"label": "Is Delhi Bureau"
},
{
"depends_on": "eval:doc.workflow_state==\"Pending Approval\"",
"depends_on": "eval:(frappe.user.has_role(\"HOD\") || frappe.user.has_role(\"Admin User\"))",
"fieldname": "expense_type",
"fieldtype": "Select",
"label": "Expense Type",
"mandatory_depends_on": "eval:doc.workflow_state==\"Pending Approval\"",
"options": "\nDirect\nIndirect",
"permlevel": 1
},
Expand Down Expand Up @@ -346,7 +345,7 @@
"link_fieldname": "batta_claim_reference"
}
],
"modified": "2026-02-05 14:16:38.084292",
"modified": "2026-04-06 12:13:50.993598",
"modified_by": "Administrator",
"module": "BEAMS",
"name": "Batta Claim",
Expand Down
2 changes: 1 addition & 1 deletion beams/beams/doctype/batta_claim/batta_claim.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def set_from_bureau_flag(self):
self.from_bureau = 1

def on_submit(self):
if self.workflow_state == 'Approved':
if self.workflow_state in ["Approved by CEO", "Approved"] and self.docstatus == 1:
if not self.expense_type:
frappe.throw(
title="Expense Type Required",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"column_break_jkfg",
"rent_expense_item",
"batta_ot_expense_item",
"advance_account"
"advance_account",
"batta_expense_cost_head"
],
"fields": [
{
Expand Down Expand Up @@ -203,12 +204,18 @@
"fieldtype": "Link",
"label": "Advance Account",
"options": "Account"
},
{
"fieldname": "batta_expense_cost_head",
"fieldtype": "Link",
"label": "Batta Expense Cost Head",
"options": "Cost Head"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2026-03-17 14:51:14.096058",
"modified": "2026-03-31 19:44:46.985532",
"modified_by": "Administrator",
"module": "BEAMS",
"name": "Beams Accounts Settings",
Expand Down
9 changes: 8 additions & 1 deletion beams/beams/doctype/bureau_trip_sheet/bureau_trip_sheet.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"ending_date_and_time",
"check_in_time",
"total_hours",
"last_trip",
"section_break_tjbr",
"purpose",
"fuel_details_section",
Expand Down Expand Up @@ -341,12 +342,18 @@
"fieldname": "check_in_time",
"fieldtype": "Datetime",
"label": "Check In Time"
},
{
"default": "0",
"fieldname": "last_trip",
"fieldtype": "Check",
"label": "Last Trip"
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2026-03-26 15:50:44.470313",
"modified": "2026-04-01 10:46:15.616295",
"modified_by": "Administrator",
"module": "BEAMS",
"name": "Bureau Trip Sheet",
Expand Down
32 changes: 31 additions & 1 deletion beams/beams/doctype/bureau_trip_sheet/bureau_trip_sheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,20 @@ def calculate_batta(self):
'''
Calculate total trip batta from daily rate × number of days (or food allowance total).
'''
policy = get_batta_policy_values(supplier=self.supplier)

if policy.get("is_actual_with") or policy.get("is_actual_without") or policy.get("is_actual_food"):

self.total_food_allowance = (
flt(self.breakfast) +
flt(self.lunch) +
flt(self.dinner)
)

self.batta = self.total_food_allowance

return

if self.total_food_allowance:
self.batta = self.total_food_allowance
else:
Expand Down Expand Up @@ -105,14 +119,25 @@ def calculate_total_daily_batta(self):
self.total_daily_batta = flt(self.batta) or 0

def calculate_total_ot_batta(self):
"""Total OT batta = (total_hours - ot_working_hours) * ot_batta rate, when supplier and hours are set."""
"""
Calculate OT batta ONLY when last_trip is checked
"""

if not self.last_trip:
self.total_ot_batta = 0
return

total_hours = flt(self.total_hours or 0)
ot_rate = flt(self.ot_batta or 0)

if not self.supplier or not total_hours:
self.total_ot_batta = 0
return

ot_working_hours = flt(get_ot_working_hours(self.supplier) or 0)

ot_hours = max(0, total_hours - ot_working_hours)

self.total_ot_batta = round(ot_hours * ot_rate, 2)

def calculate_daily_batta(self):
Expand All @@ -126,6 +151,11 @@ def calculate_daily_batta(self):
- Else → No Allowance
When policy allows actual (editable) daily amounts, user-entered values are preserved on save.
'''
policy = get_batta_policy_values(supplier=self.supplier)

if policy.get("is_actual_with") or policy.get("is_actual_without") or policy.get("is_actual_food"):
return

# Preserve manually entered daily rates before reset.
manual_daily_batta_without_overnight = flt(self.get("daily_batta_without_overnight_stay"))
manual_daily_batta_with_overnight = flt(self.get("daily_batta_with_overnight_stay"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ def create_journal_entry(monthly_consolidated_trip_sheet_name):
fuel_expense_account = settings.get("fuel_expense_item")
ot_account = settings.get("batta_ot_expense_item")
fuel_card_account = settings.get("fuel_card_account")
batta_cost_head = settings.get("batta_expense_cost_head")

supplier_payable_account = _get_supplier_payable_account(doc.supplier, company)
if not supplier_payable_account:
Expand Down Expand Up @@ -336,25 +337,29 @@ def create_journal_entry(monthly_consolidated_trip_sheet_name):
"account": batta_account,
"debit_in_account_currency": total_batta_je,
"credit_in_account_currency": 0,
"cost_head": batta_cost_head
})
if ot_account and total_ot_je:
accounts.append({
"account": ot_account,
"debit_in_account_currency": total_ot_je,
"credit_in_account_currency": 0,
"cost_head": batta_cost_head
})
if fuel_expense_account and total_fuel_expense:
accounts.append({
"account": fuel_expense_account,
"debit_in_account_currency": total_fuel_expense,
"credit_in_account_currency": 0,
"cost_head": batta_cost_head
})
# Credits — fuel card / fuel log only (advance is already reflected in batta_after / ot_after)
if fuel_card_account and total_fuel_log:
accounts.append({
"account": fuel_card_account,
"debit_in_account_currency": 0,
"credit_in_account_currency": total_fuel_log,
"cost_head": batta_cost_head
})
# Supplier balancing: credit when company owes supplier, debit when recovering
if supplier_payable_account and supplier_amount != 0:
Expand All @@ -364,6 +369,7 @@ def create_journal_entry(monthly_consolidated_trip_sheet_name):
"party": doc.supplier,
"debit_in_account_currency": abs(supplier_amount) if supplier_amount < 0 else 0,
"credit_in_account_currency": supplier_amount if supplier_amount > 0 else 0,
"cost_head": batta_cost_head
})

if not accounts:
Expand Down
14 changes: 11 additions & 3 deletions beams/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"
Expand All @@ -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",
},
Expand All @@ -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",
Expand Down
7 changes: 7 additions & 0 deletions beams/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
]
}
Expand Down
Loading