Skip to content

Commit 48de43b

Browse files
committed
refactor: Convert Task override to extended class inheritance
1 parent 913b9d6 commit 48de43b

1 file changed

Lines changed: 7 additions & 268 deletions

File tree

  • one_compliance/one_compliance/doc_events

one_compliance/one_compliance/doc_events/task.py

Lines changed: 7 additions & 268 deletions
Original file line numberDiff line numberDiff line change
@@ -4,129 +4,22 @@
44
)
55
from erpnext.accounts.party import get_party_account
66
from frappe import _, throw
7-
from frappe.desk.form.assign_to import clear, close_all_assignments
7+
from frappe.desk.form.assign_to import close_all_assignments
88
from frappe.email.doctype.notification.notification import get_context
9-
from frappe.utils import add_days, cstr, date_diff, flt, getdate, today
10-
from frappe.utils.data import format_date
11-
from frappe.utils.nestedset import NestedSet
12-
from erpnext.projects.doctype.task.task import check_if_child_exists, CircularReferenceError
9+
from frappe.utils import add_days, getdate, today
10+
from erpnext.projects.doctype.task.task import Task
1311

1412
from one_compliance.one_compliance.utils import (
1513
create_project_completion_todos,
1614
send_notification,
1715
send_notification_to_roles,
1816
)
1917

20-
21-
class CustomTask(NestedSet):
22-
# begin: auto-generated types
23-
# This code is auto-generated. Do not modify anything in this block.
24-
25-
from typing import TYPE_CHECKING
26-
27-
if TYPE_CHECKING:
28-
from erpnext.projects.doctype.task_depends_on.task_depends_on import (
29-
TaskDependsOn,
30-
)
31-
from frappe.types import DF
32-
33-
act_end_date: DF.Date | None
34-
act_start_date: DF.Date | None
35-
actual_time: DF.Float
36-
closing_date: DF.Date | None
37-
color: DF.Color | None
38-
company: DF.Link | None
39-
completed_by: DF.Link | None
40-
completed_on: DF.Date | None
41-
department: DF.Link | None
42-
depends_on: DF.Table[TaskDependsOn]
43-
depends_on_tasks: DF.Code | None
44-
description: DF.TextEditor | None
45-
duration: DF.Int
46-
exp_end_date: DF.Date | None
47-
exp_start_date: DF.Date | None
48-
expected_time: DF.Float
49-
is_group: DF.Check
50-
is_milestone: DF.Check
51-
is_template: DF.Check
52-
issue: DF.Link | None
53-
lft: DF.Int
54-
old_parent: DF.Data | None
55-
parent_task: DF.Link | None
56-
priority: DF.Literal["Low", "Medium", "High", "Urgent"]
57-
progress: DF.Percent
58-
project: DF.Link | None
59-
review_date: DF.Date | None
60-
rgt: DF.Int
61-
start: DF.Int
62-
status: DF.Literal[
63-
"Open", "Working", "Pending Review", "Overdue", "Template", "Completed", "Cancelled"
64-
]
65-
subject: DF.Data
66-
task_weight: DF.Float
67-
template_task: DF.Data | None
68-
total_billing_amount: DF.Currency
69-
total_costing_amount: DF.Currency
70-
type: DF.Link | None
71-
# end: auto-generated types
72-
73-
nsm_parent_field = "parent_task"
74-
75-
def get_customer_details(self):
76-
cust = frappe.db.sql("select customer_name from `tabCustomer` where name=%s", self.customer)
77-
if cust:
78-
ret = {"customer_name": cust and cust[0][0] or ""}
79-
return ret
80-
18+
class CustomTask(Task):
8119
def validate(self):
82-
self.validate_dates()
83-
self.validate_progress()
84-
self.validate_status()
85-
self.update_depends_on()
86-
self.validate_dependencies_for_template_task()
87-
self.validate_completed_on()
20+
super(CustomTask, self).validate()
8821
self.validate_reimbursement_check()
89-
90-
def validate_dates(self):
91-
self.validate_from_to_dates("exp_start_date", "exp_end_date")
92-
self.validate_from_to_dates("act_start_date", "act_end_date")
93-
self.validate_parent_expected_end_date()
94-
self.validate_parent_project_dates()
95-
96-
def validate_parent_expected_end_date(self):
97-
if not self.parent_task or not self.exp_end_date:
98-
return
99-
100-
parent_exp_end_date = frappe.db.get_value("Task", self.parent_task, "exp_end_date")
101-
if not parent_exp_end_date:
102-
return
103-
104-
if getdate(self.exp_end_date) > getdate(parent_exp_end_date):
105-
frappe.throw(
106-
_(
107-
"Expected End Date should be less than or equal to parent task's Expected End Date {0}."
108-
).format(format_date(parent_exp_end_date)),
109-
frappe.exceptions.InvalidDates,
110-
)
111-
112-
def validate_parent_project_dates(self):
113-
if not self.project or frappe.flags.in_test:
114-
return
115-
116-
if project_end_date := frappe.db.get_value("Project", self.project, "expected_end_date"):
117-
project_end_date = getdate(project_end_date)
118-
for fieldname in ("exp_start_date", "exp_end_date", "act_start_date", "act_end_date"):
119-
task_date = self.get(fieldname)
120-
if task_date and date_diff(project_end_date, getdate(task_date)) < 0:
121-
frappe.throw(
122-
_("{0}'s {1} cannot be after {2}'s Expected End Date.").format(
123-
frappe.bold(frappe.get_desk_link("Task", self.name)),
124-
_(self.meta.get_label(fieldname)),
125-
frappe.bold(frappe.get_desk_link("Project", self.project)),
126-
),
127-
frappe.exceptions.InvalidDates,
128-
)
129-
22+
13023
def validate_status(self):
13124
if self.is_template and self.status != "Template":
13225
self.status = "Template"
@@ -145,35 +38,6 @@ def validate_status(self):
14538

14639
close_all_assignments(self.doctype, self.name)
14740

148-
def validate_progress(self):
149-
if flt(self.progress or 0) > 100:
150-
frappe.throw(_("Progress % for a task cannot be more than 100."))
151-
152-
if self.status == "Completed":
153-
self.progress = 100
154-
155-
def validate_dependencies_for_template_task(self):
156-
if self.is_template:
157-
self.validate_parent_template_task()
158-
self.validate_depends_on_tasks()
159-
160-
def validate_parent_template_task(self):
161-
if self.parent_task:
162-
if not frappe.db.get_value("Task", self.parent_task, "is_template"):
163-
parent_task_format = f"""<a href="#Form/Task/{self.parent_task}">{self.parent_task}</a>"""
164-
frappe.throw(_("Parent Task {0} is not a Template Task").format(parent_task_format))
165-
166-
def validate_depends_on_tasks(self):
167-
if self.depends_on:
168-
for task in self.depends_on:
169-
if not frappe.db.get_value("Task", task.task, "is_template"):
170-
dependent_task_format = f"""<a href="#Form/Task/{task.task}">{task.task}</a>"""
171-
frappe.throw(_("Dependent Task {0} is not a Template Task").format(dependent_task_format))
172-
173-
def validate_completed_on(self):
174-
if self.completed_on and getdate(self.completed_on) > getdate():
175-
frappe.throw(_("Completed On cannot be greater than Today"))
176-
17741
def validate_reimbursement_check(self):
17842
'''
17943
Validate Rembursement JV on Task Completion
@@ -183,132 +47,6 @@ def validate_reimbursement_check(self):
18347
title=_("Reimbursement Journal Entry Missing"),
18448
msg=_("Please create Reimbursement Journal Entry before marking the task <b>`{0}`</b> as Completed".format(self.name)))
18549

186-
def update_depends_on(self):
187-
depends_on_tasks = ""
188-
for d in self.depends_on:
189-
if d.task and d.task not in depends_on_tasks:
190-
depends_on_tasks += d.task + ","
191-
self.depends_on_tasks = depends_on_tasks
192-
193-
def update_nsm_model(self):
194-
frappe.utils.nestedset.update_nsm(self)
195-
196-
def on_update(self):
197-
self.update_nsm_model()
198-
self.check_recursion()
199-
self.reschedule_dependent_tasks()
200-
self.update_project()
201-
self.unassign_todo()
202-
self.populate_depends_on()
203-
204-
def unassign_todo(self):
205-
if self.status == "Completed":
206-
close_all_assignments(self.doctype, self.name)
207-
if self.status == "Cancelled":
208-
clear(self.doctype, self.name)
209-
210-
def update_time_and_costing(self):
211-
tl = frappe.db.sql(
212-
"""select min(from_time) as start_date, max(to_time) as end_date,
213-
sum(billing_amount) as total_billing_amount, sum(costing_amount) as total_costing_amount,
214-
sum(hours) as time from `tabTimesheet Detail` where task = %s and docstatus=1""",
215-
self.name,
216-
as_dict=1,
217-
)[0]
218-
if self.status == "Open":
219-
self.status = "Working"
220-
self.total_costing_amount = tl.total_costing_amount
221-
self.total_billing_amount = tl.total_billing_amount
222-
self.actual_time = tl.time
223-
self.act_start_date = tl.start_date
224-
self.act_end_date = tl.end_date
225-
226-
def update_project(self):
227-
if self.project and not self.flags.from_project:
228-
frappe.get_cached_doc("Project", self.project).update_project()
229-
230-
def check_recursion(self):
231-
if self.flags.ignore_recursion_check:
232-
return
233-
check_list = [["task", "parent"], ["parent", "task"]]
234-
for d in check_list:
235-
task_list, count = [self.name], 0
236-
while len(task_list) > count:
237-
tasks = frappe.db.sql(
238-
" select {} from `tabTask Depends On` where {} = {} ".format(d[0], d[1], "%s"),
239-
cstr(task_list[count]),
240-
)
241-
count = count + 1
242-
for b in tasks:
243-
if b[0] == self.name:
244-
frappe.throw(_("Circular Reference Error"), CircularReferenceError)
245-
if b[0]:
246-
task_list.append(b[0])
247-
248-
if count == 15:
249-
break
250-
251-
def reschedule_dependent_tasks(self):
252-
end_date = self.exp_end_date or self.act_end_date
253-
if end_date:
254-
for task_name in frappe.db.sql(
255-
"""
256-
select name from `tabTask` as parent
257-
where parent.project = %(project)s
258-
and parent.name in (
259-
select parent from `tabTask Depends On` as child
260-
where child.task = %(task)s and child.project = %(project)s)
261-
""",
262-
{"project": self.project, "task": self.name},
263-
as_dict=1,
264-
):
265-
task = frappe.get_doc("Task", task_name.name)
266-
if (
267-
task.exp_start_date
268-
and task.exp_end_date
269-
and task.exp_start_date < getdate(end_date)
270-
and task.status == "Open"
271-
):
272-
task_duration = date_diff(task.exp_end_date, task.exp_start_date)
273-
task.exp_start_date = add_days(end_date, 1)
274-
task.exp_end_date = add_days(task.exp_start_date, task_duration)
275-
task.flags.ignore_recursion_check = True
276-
task.save()
277-
278-
def has_webform_permission(self):
279-
project_user = frappe.db.get_value(
280-
"Project User", {"parent": self.project, "user": frappe.session.user}, "user"
281-
)
282-
if project_user:
283-
return True
284-
285-
def populate_depends_on(self):
286-
if self.parent_task:
287-
parent = frappe.get_doc("Task", self.parent_task)
288-
if self.name not in [row.task for row in parent.depends_on]:
289-
parent.append(
290-
"depends_on", {"doctype": "Task Depends On", "task": self.name, "subject": self.subject}
291-
)
292-
parent.save()
293-
294-
def on_trash(self):
295-
if check_if_child_exists(self.name):
296-
throw(_("Child Task exists for this Task. You can not delete this Task."))
297-
298-
self.update_nsm_model()
299-
300-
def after_delete(self):
301-
self.update_project()
302-
303-
def update_status(self):
304-
if self.status not in ("Cancelled", "Completed") and self.exp_end_date:
305-
from datetime import datetime
306-
307-
if self.exp_end_date < datetime.now().date():
308-
self.db_set("status", "Overdue", update_modified=False)
309-
self.update_project()
310-
311-
31250
@frappe.whitelist()
31351
def append_users_to_project(doc, method):
31452
if doc.assigned_to and doc.project:
@@ -704,3 +442,4 @@ def enable_customer_on_task_completion(doc, method):
704442
customer.aml_compliance_checked = 1
705443
customer.save(ignore_permissions=True)
706444
frappe.msgprint(f"Customer {customer.name} has been enabled after AML compliance task completion.")
445+

0 commit comments

Comments
 (0)