From 48de43b808bd5aeef68bcd62255bae9deac90fd0 Mon Sep 17 00:00:00 2001 From: anjusha Date: Mon, 1 Dec 2025 11:41:18 +0530 Subject: [PATCH] refactor: Convert Task override to extended class inheritance --- .../one_compliance/doc_events/task.py | 275 +----------------- 1 file changed, 7 insertions(+), 268 deletions(-) diff --git a/one_compliance/one_compliance/doc_events/task.py b/one_compliance/one_compliance/doc_events/task.py index 611a9f3e..4c8e3d94 100644 --- a/one_compliance/one_compliance/doc_events/task.py +++ b/one_compliance/one_compliance/doc_events/task.py @@ -4,12 +4,10 @@ ) from erpnext.accounts.party import get_party_account from frappe import _, throw -from frappe.desk.form.assign_to import clear, close_all_assignments +from frappe.desk.form.assign_to import close_all_assignments from frappe.email.doctype.notification.notification import get_context -from frappe.utils import add_days, cstr, date_diff, flt, getdate, today -from frappe.utils.data import format_date -from frappe.utils.nestedset import NestedSet -from erpnext.projects.doctype.task.task import check_if_child_exists, CircularReferenceError +from frappe.utils import add_days, getdate, today +from erpnext.projects.doctype.task.task import Task from one_compliance.one_compliance.utils import ( create_project_completion_todos, @@ -17,116 +15,11 @@ send_notification_to_roles, ) - -class CustomTask(NestedSet): - # begin: auto-generated types - # This code is auto-generated. Do not modify anything in this block. - - from typing import TYPE_CHECKING - - if TYPE_CHECKING: - from erpnext.projects.doctype.task_depends_on.task_depends_on import ( - TaskDependsOn, - ) - from frappe.types import DF - - act_end_date: DF.Date | None - act_start_date: DF.Date | None - actual_time: DF.Float - closing_date: DF.Date | None - color: DF.Color | None - company: DF.Link | None - completed_by: DF.Link | None - completed_on: DF.Date | None - department: DF.Link | None - depends_on: DF.Table[TaskDependsOn] - depends_on_tasks: DF.Code | None - description: DF.TextEditor | None - duration: DF.Int - exp_end_date: DF.Date | None - exp_start_date: DF.Date | None - expected_time: DF.Float - is_group: DF.Check - is_milestone: DF.Check - is_template: DF.Check - issue: DF.Link | None - lft: DF.Int - old_parent: DF.Data | None - parent_task: DF.Link | None - priority: DF.Literal["Low", "Medium", "High", "Urgent"] - progress: DF.Percent - project: DF.Link | None - review_date: DF.Date | None - rgt: DF.Int - start: DF.Int - status: DF.Literal[ - "Open", "Working", "Pending Review", "Overdue", "Template", "Completed", "Cancelled" - ] - subject: DF.Data - task_weight: DF.Float - template_task: DF.Data | None - total_billing_amount: DF.Currency - total_costing_amount: DF.Currency - type: DF.Link | None - # end: auto-generated types - - nsm_parent_field = "parent_task" - - def get_customer_details(self): - cust = frappe.db.sql("select customer_name from `tabCustomer` where name=%s", self.customer) - if cust: - ret = {"customer_name": cust and cust[0][0] or ""} - return ret - +class CustomTask(Task): def validate(self): - self.validate_dates() - self.validate_progress() - self.validate_status() - self.update_depends_on() - self.validate_dependencies_for_template_task() - self.validate_completed_on() + super(CustomTask, self).validate() self.validate_reimbursement_check() - - def validate_dates(self): - self.validate_from_to_dates("exp_start_date", "exp_end_date") - self.validate_from_to_dates("act_start_date", "act_end_date") - self.validate_parent_expected_end_date() - self.validate_parent_project_dates() - - def validate_parent_expected_end_date(self): - if not self.parent_task or not self.exp_end_date: - return - - parent_exp_end_date = frappe.db.get_value("Task", self.parent_task, "exp_end_date") - if not parent_exp_end_date: - return - - if getdate(self.exp_end_date) > getdate(parent_exp_end_date): - frappe.throw( - _( - "Expected End Date should be less than or equal to parent task's Expected End Date {0}." - ).format(format_date(parent_exp_end_date)), - frappe.exceptions.InvalidDates, - ) - - def validate_parent_project_dates(self): - if not self.project or frappe.flags.in_test: - return - - if project_end_date := frappe.db.get_value("Project", self.project, "expected_end_date"): - project_end_date = getdate(project_end_date) - for fieldname in ("exp_start_date", "exp_end_date", "act_start_date", "act_end_date"): - task_date = self.get(fieldname) - if task_date and date_diff(project_end_date, getdate(task_date)) < 0: - frappe.throw( - _("{0}'s {1} cannot be after {2}'s Expected End Date.").format( - frappe.bold(frappe.get_desk_link("Task", self.name)), - _(self.meta.get_label(fieldname)), - frappe.bold(frappe.get_desk_link("Project", self.project)), - ), - frappe.exceptions.InvalidDates, - ) - + def validate_status(self): if self.is_template and self.status != "Template": self.status = "Template" @@ -145,35 +38,6 @@ def validate_status(self): close_all_assignments(self.doctype, self.name) - def validate_progress(self): - if flt(self.progress or 0) > 100: - frappe.throw(_("Progress % for a task cannot be more than 100.")) - - if self.status == "Completed": - self.progress = 100 - - def validate_dependencies_for_template_task(self): - if self.is_template: - self.validate_parent_template_task() - self.validate_depends_on_tasks() - - def validate_parent_template_task(self): - if self.parent_task: - if not frappe.db.get_value("Task", self.parent_task, "is_template"): - parent_task_format = f"""{self.parent_task}""" - frappe.throw(_("Parent Task {0} is not a Template Task").format(parent_task_format)) - - def validate_depends_on_tasks(self): - if self.depends_on: - for task in self.depends_on: - if not frappe.db.get_value("Task", task.task, "is_template"): - dependent_task_format = f"""{task.task}""" - frappe.throw(_("Dependent Task {0} is not a Template Task").format(dependent_task_format)) - - def validate_completed_on(self): - if self.completed_on and getdate(self.completed_on) > getdate(): - frappe.throw(_("Completed On cannot be greater than Today")) - def validate_reimbursement_check(self): ''' Validate Rembursement JV on Task Completion @@ -183,132 +47,6 @@ def validate_reimbursement_check(self): title=_("Reimbursement Journal Entry Missing"), msg=_("Please create Reimbursement Journal Entry before marking the task `{0}` as Completed".format(self.name))) - def update_depends_on(self): - depends_on_tasks = "" - for d in self.depends_on: - if d.task and d.task not in depends_on_tasks: - depends_on_tasks += d.task + "," - self.depends_on_tasks = depends_on_tasks - - def update_nsm_model(self): - frappe.utils.nestedset.update_nsm(self) - - def on_update(self): - self.update_nsm_model() - self.check_recursion() - self.reschedule_dependent_tasks() - self.update_project() - self.unassign_todo() - self.populate_depends_on() - - def unassign_todo(self): - if self.status == "Completed": - close_all_assignments(self.doctype, self.name) - if self.status == "Cancelled": - clear(self.doctype, self.name) - - def update_time_and_costing(self): - tl = frappe.db.sql( - """select min(from_time) as start_date, max(to_time) as end_date, - sum(billing_amount) as total_billing_amount, sum(costing_amount) as total_costing_amount, - sum(hours) as time from `tabTimesheet Detail` where task = %s and docstatus=1""", - self.name, - as_dict=1, - )[0] - if self.status == "Open": - self.status = "Working" - self.total_costing_amount = tl.total_costing_amount - self.total_billing_amount = tl.total_billing_amount - self.actual_time = tl.time - self.act_start_date = tl.start_date - self.act_end_date = tl.end_date - - def update_project(self): - if self.project and not self.flags.from_project: - frappe.get_cached_doc("Project", self.project).update_project() - - def check_recursion(self): - if self.flags.ignore_recursion_check: - return - check_list = [["task", "parent"], ["parent", "task"]] - for d in check_list: - task_list, count = [self.name], 0 - while len(task_list) > count: - tasks = frappe.db.sql( - " select {} from `tabTask Depends On` where {} = {} ".format(d[0], d[1], "%s"), - cstr(task_list[count]), - ) - count = count + 1 - for b in tasks: - if b[0] == self.name: - frappe.throw(_("Circular Reference Error"), CircularReferenceError) - if b[0]: - task_list.append(b[0]) - - if count == 15: - break - - def reschedule_dependent_tasks(self): - end_date = self.exp_end_date or self.act_end_date - if end_date: - for task_name in frappe.db.sql( - """ - select name from `tabTask` as parent - where parent.project = %(project)s - and parent.name in ( - select parent from `tabTask Depends On` as child - where child.task = %(task)s and child.project = %(project)s) - """, - {"project": self.project, "task": self.name}, - as_dict=1, - ): - task = frappe.get_doc("Task", task_name.name) - if ( - task.exp_start_date - and task.exp_end_date - and task.exp_start_date < getdate(end_date) - and task.status == "Open" - ): - task_duration = date_diff(task.exp_end_date, task.exp_start_date) - task.exp_start_date = add_days(end_date, 1) - task.exp_end_date = add_days(task.exp_start_date, task_duration) - task.flags.ignore_recursion_check = True - task.save() - - def has_webform_permission(self): - project_user = frappe.db.get_value( - "Project User", {"parent": self.project, "user": frappe.session.user}, "user" - ) - if project_user: - return True - - def populate_depends_on(self): - if self.parent_task: - parent = frappe.get_doc("Task", self.parent_task) - if self.name not in [row.task for row in parent.depends_on]: - parent.append( - "depends_on", {"doctype": "Task Depends On", "task": self.name, "subject": self.subject} - ) - parent.save() - - def on_trash(self): - if check_if_child_exists(self.name): - throw(_("Child Task exists for this Task. You can not delete this Task.")) - - self.update_nsm_model() - - def after_delete(self): - self.update_project() - - def update_status(self): - if self.status not in ("Cancelled", "Completed") and self.exp_end_date: - from datetime import datetime - - if self.exp_end_date < datetime.now().date(): - self.db_set("status", "Overdue", update_modified=False) - self.update_project() - - @frappe.whitelist() def append_users_to_project(doc, method): if doc.assigned_to and doc.project: @@ -704,3 +442,4 @@ def enable_customer_on_task_completion(doc, method): customer.aml_compliance_checked = 1 customer.save(ignore_permissions=True) frappe.msgprint(f"Customer {customer.name} has been enabled after AML compliance task completion.") +