From 39d3f4580e42f8ad307a8d7fe166e3938914f357 Mon Sep 17 00:00:00 2001 From: khushi8112 Date: Wed, 18 Feb 2026 17:13:39 +0530 Subject: [PATCH] refactor(projects): add type hints to functions --- erpnext/projects/doctype/project/project.py | 13 +++++----- erpnext/projects/doctype/task/task.py | 20 +++++++++------ .../projects/doctype/timesheet/timesheet.py | 25 +++++++++++++------ 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index d9b025a7f92..fbbbd32c0a0 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -1,6 +1,7 @@ # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt +from typing import Any import frappe from email_reply_parser import EmailReplyParser @@ -456,7 +457,7 @@ def get_list_context(context=None): @frappe.whitelist() @frappe.validate_and_sanitize_search_inputs -def get_users_for_project(doctype, txt, searchfield, start, page_len, filters): +def get_users_for_project(doctype: str, txt: str, searchfield: str, start: int, page_len: int, filters: dict): conditions = [] return frappe.db.sql( """select name, concat_ws(' ', first_name, middle_name, last_name) @@ -483,7 +484,7 @@ def get_users_for_project(doctype, txt, searchfield, start, page_len, filters): @frappe.whitelist() -def get_cost_center_name(project): +def get_cost_center_name(project: str): return frappe.db.get_value("Project", project, "cost_center") @@ -553,7 +554,7 @@ def allow_to_make_project_update(project, time, frequency): @frappe.whitelist() -def create_duplicate_project(prev_doc, project_name): +def create_duplicate_project(prev_doc: str, project_name: str): """Create duplicate project based on the old project""" import json @@ -693,7 +694,7 @@ def update_project_sales_billing(): @frappe.whitelist() -def create_kanban_board_if_not_exists(project): +def create_kanban_board_if_not_exists(project: str): from frappe.desk.doctype.kanban_board.kanban_board import quick_kanban_board project = frappe.get_doc("Project", project) @@ -704,7 +705,7 @@ def create_kanban_board_if_not_exists(project): @frappe.whitelist() -def set_project_status(project, status): +def set_project_status(project: str, status: str): """ set status for project and all related tasks """ @@ -721,7 +722,7 @@ def set_project_status(project, status): project.save() -def get_holiday_list(company=None): +def get_holiday_list(company: str | None = None) -> str: if not company: company = get_default_company() or frappe.get_all("Company")[0].name diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py index ba06dccb0b9..c0a850043b9 100755 --- a/erpnext/projects/doctype/task/task.py +++ b/erpnext/projects/doctype/task/task.py @@ -326,7 +326,7 @@ class Task(NestedSet): @frappe.whitelist() -def check_if_child_exists(name): +def check_if_child_exists(name: str): child_tasks = frappe.get_all("Task", filters={"parent_task": name}) child_tasks = [get_link_to_form("Task", task.name) for task in child_tasks] return child_tasks @@ -334,7 +334,7 @@ def check_if_child_exists(name): @frappe.whitelist() @frappe.validate_and_sanitize_search_inputs -def get_project(doctype, txt, searchfield, start, page_len, filters): +def get_project(doctype: str, txt: str, searchfield: str, start: int, page_len: int, filters: dict): from erpnext.controllers.queries import get_match_cond meta = frappe.get_meta(doctype) @@ -360,7 +360,7 @@ def get_project(doctype, txt, searchfield, start, page_len, filters): @frappe.whitelist() -def set_multiple_status(names, status): +def set_multiple_status(names: str, status: str): names = json.loads(names) for name in names: task = frappe.get_doc("Task", name) @@ -382,8 +382,8 @@ def set_tasks_as_overdue(): @frappe.whitelist() -def make_timesheet(source_name, target_doc=None, ignore_permissions=False): - def set_missing_values(source, target): +def make_timesheet(source_name: str, target_doc: dict | None = None, ignore_permissions: bool = False): + def set_missing_values(source: dict, target: dict) -> None: target.parent_project = source.project target.append( "time_logs", @@ -408,7 +408,13 @@ def make_timesheet(source_name, target_doc=None, ignore_permissions=False): @frappe.whitelist() -def get_children(doctype, parent, task=None, project=None, is_root=False): +def get_children( + doctype: str, + parent: str | None = None, + task: str | None = None, + project: str | None = None, + is_root: bool = False, +): filters = [["docstatus", "<", "2"]] if task: @@ -450,7 +456,7 @@ def add_node(): @frappe.whitelist() -def add_multiple_tasks(data, parent): +def add_multiple_tasks(data: str, parent: str): data = json.loads(data) new_doc = {"doctype": "Task", "parent_task": parent if parent != "All Tasks" else ""} new_doc["project"] = frappe.db.get_value("Task", {"name": parent}, "project") or "" diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py index 7645ee263cc..f1a00086464 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.py +++ b/erpnext/projects/doctype/timesheet/timesheet.py @@ -302,7 +302,12 @@ class Timesheet(Document): @frappe.whitelist() -def get_projectwise_timesheet_data(project=None, parent=None, from_time=None, to_time=None): +def get_projectwise_timesheet_data( + project: str | None = None, + parent: str | None = None, + from_time: str | None = None, + to_time: str | None = None, +): condition = "" if project: condition += "AND tsd.project = %(project)s " @@ -341,7 +346,7 @@ def get_projectwise_timesheet_data(project=None, parent=None, from_time=None, to @frappe.whitelist() -def get_timesheet_detail_rate(timelog, currency): +def get_timesheet_detail_rate(timelog: str, currency: str): ts = frappe.qb.DocType("Timesheet") ts_detail = frappe.qb.DocType("Timesheet Detail") @@ -363,7 +368,7 @@ def get_timesheet_detail_rate(timelog, currency): @frappe.whitelist() @frappe.validate_and_sanitize_search_inputs -def get_timesheet(doctype, txt, searchfield, start, page_len, filters): +def get_timesheet(doctype: str, txt: str, searchfield: str, start: int, page_len: int, filters: dict): if not filters: filters = {} @@ -388,7 +393,7 @@ def get_timesheet(doctype, txt, searchfield, start, page_len, filters): @frappe.whitelist() -def get_timesheet_data(name, project): +def get_timesheet_data(name: str, project: str): data = None if project and project != "": data = get_projectwise_timesheet_data(project, name) @@ -409,7 +414,9 @@ def get_timesheet_data(name, project): @frappe.whitelist() -def make_sales_invoice(source_name, item_code=None, customer=None, currency=None): +def make_sales_invoice( + source_name: str, item_code: str | None = None, customer: str | None = None, currency: str | None = None +): target = frappe.new_doc("Sales Invoice") timesheet = frappe.get_doc("Timesheet", source_name) @@ -461,7 +468,9 @@ def make_sales_invoice(source_name, item_code=None, customer=None, currency=None @frappe.whitelist() -def get_activity_cost(employee=None, activity_type=None, currency=None): +def get_activity_cost( + employee: str | None = None, activity_type: str | None = None, currency: str | None = None +): base_currency = frappe.defaults.get_global_default("currency") rate = frappe.db.get_values( "Activity Cost", @@ -485,13 +494,13 @@ def get_activity_cost(employee=None, activity_type=None, currency=None): @frappe.whitelist() -def get_events(start, end, filters=None): +def get_events(start: str, end: str, filters: str | None = None): """Returns events for Gantt / Calendar view rendering. :param start: Start date-time. :param end: End date-time. :param filters: Filters (JSON). """ - filters = json.loads(filters) + filters = json.loads(filters) if filters else {} from frappe.desk.calendar import get_event_conditions conditions = get_event_conditions("Timesheet", filters)