fix: updating base amounts through python for timesheet

(cherry picked from commit 88d8310a47)

# Conflicts:
#	erpnext/projects/doctype/timesheet_detail/timesheet_detail.py
This commit is contained in:
Nishka Gosalia
2025-12-09 16:20:20 +05:30
committed by Mergify
parent 46ca347578
commit e8a96f5903

View File

@@ -40,4 +40,94 @@ class TimesheetDetail(Document):
to_time: DF.Datetime | None
# end: auto-generated types
<<<<<<< HEAD
pass
=======
def set_to_time(self):
"""Set to_time based on from_time and hours."""
if not (self.from_time and self.hours):
return
_to_time = get_datetime(add_to_date(self.from_time, hours=self.hours, as_datetime=True))
if abs(time_diff_in_seconds(_to_time, self.to_time)) >= 1:
self.to_time = _to_time
def set_project(self):
"""Set project based on task."""
if self.task and not self.project:
self.project = frappe.db.get_value("Task", self.task, "project")
def calculate_hours(self):
"""Calculate hours based on from_time and to_time."""
if self.to_time and self.from_time:
self.hours = time_diff_in_hours(self.to_time, self.from_time)
def update_billing_hours(self):
"""Update billing hours based on hours."""
if not self.is_billable:
self.billing_hours = 0
return
if flt(self.billing_hours) == 0.0:
self.billing_hours = self.hours
def update_cost(self, employee: str):
"""Update costing and billing rates based on activity type."""
from erpnext.projects.doctype.timesheet.timesheet import get_activity_cost
if not self.is_billable and not self.activity_type:
return
rate = get_activity_cost(employee, self.activity_type)
if not rate:
return
self.billing_rate = (
flt(rate.get("billing_rate")) if flt(self.billing_rate) == 0 else self.billing_rate
)
self.costing_rate = (
flt(rate.get("costing_rate")) if flt(self.costing_rate) == 0 else self.costing_rate
)
self.billing_amount = self.billing_rate * (self.billing_hours or 0)
self.costing_amount = self.costing_rate * (self.hours or 0)
exchange_rate = flt(frappe.get_value("Timesheet", self.parent, "exchange_rate")) or 1.0
self.base_billing_rate = flt(self.billing_rate) * exchange_rate
self.base_costing_rate = flt(self.costing_rate) * exchange_rate
self.base_billing_amount = flt(self.billing_amount) * exchange_rate
self.base_costing_amount = flt(self.costing_amount) * exchange_rate
def validate_dates(self):
"""Validate that to_time is not before from_time."""
if self.from_time and self.to_time and time_diff_in_hours(self.to_time, self.from_time) < 0:
frappe.throw(_("To Time cannot be before from date"))
def validate_parent_project(self, parent_project: str):
"""Validate that project is same as Timesheet's parent project."""
if parent_project and parent_project != self.project:
frappe.throw(
_("Row {0}: Project must be same as the one set in the Timesheet: {1}.").format(
self.idx, parent_project
)
)
def validate_task_project(self):
"""Validate that the the task belongs to the project specified in the timesheet detail."""
if self.task and self.project:
task_project = frappe.db.get_value("Task", self.task, "project")
if task_project and task_project != self.project:
frappe.throw(
_("Row {0}: Task {1} does not belong to Project {2}").format(
self.idx, frappe.bold(self.task), frappe.bold(self.project)
)
)
def validate_billing_hours(self):
"""Warn if billing hours are more than actual hours."""
if flt(self.billing_hours) > flt(self.hours):
frappe.msgprint(
_("Warning - Row {0}: Billing Hours are more than Actual Hours").format(self.idx),
indicator="orange",
alert=True,
)
>>>>>>> 88d8310a47 (fix: updating base amounts through python for timesheet)