From 515a44b0b256f1865bfe0ff75cbbf4b16d24fa03 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 15:56:37 +0530 Subject: [PATCH 01/25] fix(Travel Request): get currency from Employee Master's Company (backport #1807) (#1819) * fix(Travel Request): get currency from Employee Master's Company (#1807) (cherry picked from commit 533b968737320d60d24fc54c494bc168d048048d) # Conflicts: # hrms/hr/doctype/travel_request/travel_request.json # hrms/hr/doctype/travel_request_costing/travel_request_costing.json * chore: fix conficts --------- Co-authored-by: Viny Selopal <52369157+vinyselopal@users.noreply.github.com> Co-authored-by: Rucha Mahabal --- .../travel_request/travel_request.json | 13 +- .../travel_request_costing.json | 307 ++++-------------- 2 files changed, 72 insertions(+), 248 deletions(-) diff --git a/hrms/hr/doctype/travel_request/travel_request.json b/hrms/hr/doctype/travel_request/travel_request.json index 7908e1a8ea..ac4f49ac67 100644 --- a/hrms/hr/doctype/travel_request/travel_request.json +++ b/hrms/hr/doctype/travel_request/travel_request.json @@ -17,6 +17,7 @@ "employee_name", "cell_number", "prefered_email", + "company", "column_break_7", "date_of_birth", "personal_id_type", @@ -212,11 +213,19 @@ { "fieldname": "dimension_col_break", "fieldtype": "Column Break" + }, + { + "fetch_from": "employee.company", + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company", + "read_only": 1 } ], "is_submittable": 1, "links": [], - "modified": "2022-01-18 19:19:33.678664", + "modified": "2024-05-24 17:09:09.480838", "modified_by": "Administrator", "module": "HR", "name": "Travel Request", @@ -237,7 +246,7 @@ } ], "search_fields": "employee_name", - "sort_field": "modified", + "sort_field": "creation", "sort_order": "DESC", "states": [], "title_field": "employee_name", diff --git a/hrms/hr/doctype/travel_request_costing/travel_request_costing.json b/hrms/hr/doctype/travel_request_costing/travel_request_costing.json index b64b1a9343..ea4b283377 100644 --- a/hrms/hr/doctype/travel_request_costing/travel_request_costing.json +++ b/hrms/hr/doctype/travel_request_costing/travel_request_costing.json @@ -1,257 +1,72 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2018-05-15 10:28:37.429581", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "creation": "2018-05-15 10:28:37.429581", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "expense_type", + "column_break_2", + "sponsored_amount", + "funded_amount", + "total_amount", + "section_break_4", + "comments" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "expense_type", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Expense Type", - "length": 0, - "no_copy": 0, - "options": "Expense Claim Type", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "expense_type", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Expense Type", + "options": "Expense Claim Type" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_2", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_2", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sponsored_amount", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Sponsored Amount", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sponsored_amount", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Sponsored Amount", + "options": "Company:company:default_currency" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "funded_amount", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Funded Amount", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "funded_amount", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Funded Amount", + "options": "Company:company:default_currency" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "total_amount", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Total Amount", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "total_amount", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Total Amount", + "options": "Company:company:default_currency" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_4", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "section_break_4", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "comments", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Comments", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "comments", + "fieldtype": "Small Text", + "label": "Comments" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2018-05-15 10:42:07.960530", - "modified_by": "Administrator", - "module": "HR", - "name": "Travel Request Costing", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 + ], + "istable": 1, + "links": [], + "modified": "2024-05-24 12:00:47.413806", + "modified_by": "Administrator", + "module": "HR", + "name": "Travel Request Costing", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "creation", + "sort_order": "DESC", + "states": [], + "track_changes": 1 } \ No newline at end of file From 76541b6b52d6788ed109c368256d9c599af4a58b Mon Sep 17 00:00:00 2001 From: Viny Selopal Date: Thu, 18 Apr 2024 17:45:40 +0530 Subject: [PATCH 02/25] feat: allow adding formula to calculate final score in appraisal cycle (cherry picked from commit 1712990dea952734fd5cf13b37a8356466f4392c) # Conflicts: # hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json --- hrms/hr/doctype/appraisal/appraisal.py | 32 ++++++++++++++-- hrms/hr/doctype/appraisal/test_appraisal.py | 20 +++++++++- .../appraisal_cycle/appraisal_cycle.js | 38 +++++++++++++++++++ .../appraisal_cycle/appraisal_cycle.json | 25 ++++++++++++ .../appraisal_cycle/test_appraisal_cycle.py | 8 ++++ hrms/public/js/hrms.bundle.js | 1 + 6 files changed, 119 insertions(+), 5 deletions(-) diff --git a/hrms/hr/doctype/appraisal/appraisal.py b/hrms/hr/doctype/appraisal/appraisal.py index 9ea9b1b9d4..4950e894ad 100644 --- a/hrms/hr/doctype/appraisal/appraisal.py +++ b/hrms/hr/doctype/appraisal/appraisal.py @@ -9,6 +9,7 @@ from hrms.hr.doctype.appraisal_cycle.appraisal_cycle import validate_active_appraisal_cycle from hrms.hr.utils import validate_active_employee +from hrms.payroll.utils import sanitize_expression class Appraisal(Document): @@ -179,9 +180,34 @@ def calculate_avg_feedback_score(self, update=False): self.db_update() def calculate_final_score(self): - final_score = (flt(self.total_score) + flt(self.avg_feedback_score) + flt(self.self_score)) / 3 - - self.final_score = flt(final_score, self.precision("final_score")) + if self.appraisal_cycle: + final_score = 0 + appraisal_cycle_doc = frappe.get_doc("Appraisal Cycle", self.appraisal_cycle) + employee_doc = frappe.get_doc("Employee", self.employee) + + formula = appraisal_cycle_doc.final_score_formula + based_on_formula = appraisal_cycle_doc.calculate_final_score_based_on_formula + + if not based_on_formula == 1: + final_score = ( + flt(self.total_score) + flt(self.avg_feedback_score) + flt(self.self_score) + ) / 3 + else: + sanitized_formula = sanitize_expression(formula) + + data = { + "goal_score": flt(self.total_score), + "average_feedback_score": flt(self.avg_feedback_score), + "self_appraisal_score": flt(self.self_score), + } + + data.update(appraisal_cycle_doc.as_dict()) + data.update(employee_doc.as_dict()) + data.update(self.as_dict()) + + final_score = frappe.safe_eval(sanitized_formula, data) + + self.final_score = flt(final_score, self.precision("final_score")) @frappe.whitelist() def add_feedback(self, feedback, feedback_ratings): diff --git a/hrms/hr/doctype/appraisal/test_appraisal.py b/hrms/hr/doctype/appraisal/test_appraisal.py index 029b6c52bd..66e5eae137 100644 --- a/hrms/hr/doctype/appraisal/test_appraisal.py +++ b/hrms/hr/doctype/appraisal/test_appraisal.py @@ -67,9 +67,24 @@ def test_manual_kra_rating(self): self.assertEqual(appraisal.final_score, 1.2) def test_final_score(self): - cycle = create_appraisal_cycle(designation="Engineer", kra_evaluation_method="Manual Rating") + cycle = create_appraisal_cycle( + designation="Engineer", kra_evaluation_method="Manual Rating", based_on_formula=0 + ) + cycle.create_appraisals() + appraisal = self.setup_appraisal_cycle(cycle) + + self.assertEqual(appraisal.final_score, 3.767) + + def test_final_score_using_formula(self): + cycle = create_appraisal_cycle( + designation="Engineer", kra_evaluation_method="Manual Rating", based_on_formula=1 + ) cycle.create_appraisals() + appraisal = self.setup_appraisal_cycle(cycle) + + self.assertEqual(appraisal.final_score, 3.8) + def setup_appraisal_cycle(self, cycle): appraisal = frappe.db.exists("Appraisal", {"appraisal_cycle": cycle.name, "employee": self.employee1}) appraisal = frappe.get_doc("Appraisal", appraisal) @@ -97,7 +112,8 @@ def test_final_score(self): feedback.submit() appraisal.reload() - self.assertEqual(appraisal.final_score, 3.767) + + return appraisal def test_goal_score(self): """ diff --git a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js index b342030618..f8a9dc6c0e 100644 --- a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js +++ b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js @@ -3,6 +3,44 @@ frappe.ui.form.on("Appraisal Cycle", { refresh(frm) { + async function set_autocompletions_for_final_score_formula(frm) { + const autocompletions = [ + { + value: "goal_score", + score: 8, + meta: "Goal field", + }, + { + value: "average_feedback_score", + score: 8, + meta: "Appraisal field", + }, + { + value: "self_appraisal_score", + score: 8, + meta: "Appraisal field", + }, + ]; + + const doctypes = ["Employee", "Appraisal Cycle"]; + + await Promise.all( + doctypes.map((doctype) => + frappe.model.with_doctype(doctype, () => { + autocompletions.push( + ...frappe.get_meta(doctype).fields.map((f) => ({ + value: f.fieldname, + score: 8, + meta: __("{0} Field", [doctype]), + })), + ); + }), + ), + ); + frm.set_df_property("final_score_formula", "autocompletions", autocompletions); + } + + set_autocompletions_for_final_score_formula(frm); frm.set_query("department", () => { return { filters: { diff --git a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json index 4a376ef75f..41aa3c6173 100644 --- a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json +++ b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json @@ -17,6 +17,9 @@ "section_break_4", "description", "settings_section", + "calculate_final_score_based_on_formula", + "final_score_formula", + "column_break_wpgg", "kra_evaluation_method", "applicable_for_tab", "filters_section", @@ -154,6 +157,24 @@ "label": "Status", "options": "Not Started\nIn Progress\nCompleted", "read_only": 1 + }, + { + "depends_on": "eval:doc.calculate_final_score_based_on_formula === 1;", + "fieldname": "final_score_formula", + "fieldtype": "Code", + "label": "Final Score Formula", + "max_height": "5rem", + "options": "PythonExpression" + }, + { + "default": "0", + "fieldname": "calculate_final_score_based_on_formula", + "fieldtype": "Check", + "label": "Calculate final score based on formula" + }, + { + "fieldname": "column_break_wpgg", + "fieldtype": "Column Break" } ], "index_web_pages_for_search": 1, @@ -171,7 +192,11 @@ "link_fieldname": "appraisal_cycle" } ], +<<<<<<< HEAD "modified": "2023-03-29 12:28:36.247120", +======= + "modified": "2024-04-16 13:15:55.493958", +>>>>>>> 1712990de (feat: allow adding formula to calculate final score in appraisal cycle) "modified_by": "Administrator", "module": "HR", "name": "Appraisal Cycle", diff --git a/hrms/hr/doctype/appraisal_cycle/test_appraisal_cycle.py b/hrms/hr/doctype/appraisal_cycle/test_appraisal_cycle.py index 6ac8268edc..7b82b2c4fa 100644 --- a/hrms/hr/doctype/appraisal_cycle/test_appraisal_cycle.py +++ b/hrms/hr/doctype/appraisal_cycle/test_appraisal_cycle.py @@ -59,6 +59,8 @@ def create_appraisal_cycle(**args): if frappe.db.exists("Appraisal Cycle", name): frappe.delete_doc("Appraisal Cycle", name, force=True) + based_on_formula = args.based_on_formula + appraisal_cycle = frappe.get_doc( { "doctype": "Appraisal Cycle", @@ -66,8 +68,14 @@ def create_appraisal_cycle(**args): "company": args.company or "_Test Appraisal", "start_date": args.start_date or "2022-01-01", "end_date": args.end_date or "2022-03-31", + "calculate_final_score_based_on_formula": based_on_formula, } ) + if based_on_formula: + appraisal_cycle.final_score_formula = ( + args.final_score_formula + or "goal_score * 0.2 + self_appraisal_score * 0.2 + average_feedback_score * 0.6" + ) if args.kra_evaluation_method: appraisal_cycle.kra_evaluation_method = args.kra_evaluation_method diff --git a/hrms/public/js/hrms.bundle.js b/hrms/public/js/hrms.bundle.js index f53beddd87..d366ad7504 100644 --- a/hrms/public/js/hrms.bundle.js +++ b/hrms/public/js/hrms.bundle.js @@ -5,3 +5,4 @@ import "./templates/rating.html"; import "./utils"; import "./utils/payroll_utils"; import "./utils/leave_utils"; +import "./utils/appraisal_utils"; From 2ebcdc95f8b369857de88386ac7c1a4519d5bbce Mon Sep 17 00:00:00 2001 From: Viny Selopal Date: Fri, 19 Apr 2024 15:11:39 +0530 Subject: [PATCH 03/25] refactor: PR review changes (cherry picked from commit dc6610a28a9f74a5fdb836cbb3e241f75e5ce926) --- hrms/hr/doctype/appraisal/appraisal.py | 4 +- .../appraisal_cycle/appraisal_cycle.js | 74 +++++++++---------- hrms/public/js/hrms.bundle.js | 1 - 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/hrms/hr/doctype/appraisal/appraisal.py b/hrms/hr/doctype/appraisal/appraisal.py index 4950e894ad..fce55007ce 100644 --- a/hrms/hr/doctype/appraisal/appraisal.py +++ b/hrms/hr/doctype/appraisal/appraisal.py @@ -183,16 +183,16 @@ def calculate_final_score(self): if self.appraisal_cycle: final_score = 0 appraisal_cycle_doc = frappe.get_doc("Appraisal Cycle", self.appraisal_cycle) - employee_doc = frappe.get_doc("Employee", self.employee) formula = appraisal_cycle_doc.final_score_formula based_on_formula = appraisal_cycle_doc.calculate_final_score_based_on_formula - if not based_on_formula == 1: + if not based_on_formula: final_score = ( flt(self.total_score) + flt(self.avg_feedback_score) + flt(self.self_score) ) / 3 else: + employee_doc = frappe.get_doc("Employee", self.employee) sanitized_formula = sanitize_expression(formula) data = { diff --git a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js index f8a9dc6c0e..810971f67b 100644 --- a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js +++ b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js @@ -3,43 +3,6 @@ frappe.ui.form.on("Appraisal Cycle", { refresh(frm) { - async function set_autocompletions_for_final_score_formula(frm) { - const autocompletions = [ - { - value: "goal_score", - score: 8, - meta: "Goal field", - }, - { - value: "average_feedback_score", - score: 8, - meta: "Appraisal field", - }, - { - value: "self_appraisal_score", - score: 8, - meta: "Appraisal field", - }, - ]; - - const doctypes = ["Employee", "Appraisal Cycle"]; - - await Promise.all( - doctypes.map((doctype) => - frappe.model.with_doctype(doctype, () => { - autocompletions.push( - ...frappe.get_meta(doctype).fields.map((f) => ({ - value: f.fieldname, - score: 8, - meta: __("{0} Field", [doctype]), - })), - ); - }), - ), - ); - frm.set_df_property("final_score_formula", "autocompletions", autocompletions); - } - set_autocompletions_for_final_score_formula(frm); frm.set_query("department", () => { return { @@ -94,6 +57,43 @@ frappe.ui.form.on("Appraisal Cycle", { } }, + set_autocompletions_for_final_score_formula: async (frm) => { + const autocompletions = [ + { + value: "goal_score", + score: 8, + meta: "Goal field", + }, + { + value: "average_feedback_score", + score: 8, + meta: "Appraisal field", + }, + { + value: "self_appraisal_score", + score: 8, + meta: "Appraisal field", + }, + ]; + + const doctypes = ["Employee", "Appraisal Cycle"]; + + await Promise.all( + doctypes.map((doctype) => + frappe.model.with_doctype(doctype, () => { + autocompletions.push( + ...frappe.get_meta(doctype).fields.map((f) => ({ + value: f.fieldname, + score: 8, + meta: __("{0} Field", [doctype]), + })), + ); + }), + ), + ); + frm.set_df_property("final_score_formula", "autocompletions", autocompletions); + }, + get_employees(frm) { frappe.call({ method: "set_employees", diff --git a/hrms/public/js/hrms.bundle.js b/hrms/public/js/hrms.bundle.js index d366ad7504..f53beddd87 100644 --- a/hrms/public/js/hrms.bundle.js +++ b/hrms/public/js/hrms.bundle.js @@ -5,4 +5,3 @@ import "./templates/rating.html"; import "./utils"; import "./utils/payroll_utils"; import "./utils/leave_utils"; -import "./utils/appraisal_utils"; From 41d5733e28c1d2311c84fa229c691c3491273dd8 Mon Sep 17 00:00:00 2001 From: Viny Selopal Date: Tue, 23 Apr 2024 11:19:52 +0530 Subject: [PATCH 04/25] refactor: function placement in appraisal_cycle.py (cherry picked from commit cc42051094e77c35db9823cdf05cc59a955c0361) --- hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js index 810971f67b..780d627338 100644 --- a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js +++ b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js @@ -3,7 +3,7 @@ frappe.ui.form.on("Appraisal Cycle", { refresh(frm) { - set_autocompletions_for_final_score_formula(frm); + frm.events.set_autocompletions_for_final_score_formula(frm); frm.set_query("department", () => { return { filters: { From dc3124d75fa3ef75919ef28d875d871c845287cc Mon Sep 17 00:00:00 2001 From: Viny Selopal Date: Fri, 26 Apr 2024 16:32:58 +0530 Subject: [PATCH 05/25] refactor: separate logic for test_appraisal_using_formula from create_appraisal (cherry picked from commit bfb2d8cda3f4af8a909d5eeda3516d792d43e00b) --- hrms/hr/doctype/appraisal/test_appraisal.py | 18 +++++++++++------- .../appraisal_cycle/test_appraisal_cycle.py | 8 -------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/hrms/hr/doctype/appraisal/test_appraisal.py b/hrms/hr/doctype/appraisal/test_appraisal.py index 66e5eae137..dcf37a3e5f 100644 --- a/hrms/hr/doctype/appraisal/test_appraisal.py +++ b/hrms/hr/doctype/appraisal/test_appraisal.py @@ -67,22 +67,26 @@ def test_manual_kra_rating(self): self.assertEqual(appraisal.final_score, 1.2) def test_final_score(self): - cycle = create_appraisal_cycle( - designation="Engineer", kra_evaluation_method="Manual Rating", based_on_formula=0 - ) + cycle = create_appraisal_cycle(designation="Engineer", kra_evaluation_method="Manual Rating") cycle.create_appraisals() appraisal = self.setup_appraisal_cycle(cycle) - self.assertEqual(appraisal.final_score, 3.767) + self.assertEqual(appraisal.final_score, 3.77) def test_final_score_using_formula(self): - cycle = create_appraisal_cycle( - designation="Engineer", kra_evaluation_method="Manual Rating", based_on_formula=1 + cycle = create_appraisal_cycle(designation="Engineer", kra_evaluation_method="Manual Rating") + cycle.update( + { + "calculate_final_score_based_on_formula": 1, + "final_score_formula": "(goal_score + self_appraisal_score + average_feedback_score)/3 if self_appraisal_score else (goal_score + self_appraisal_score)/2", + } ) + + cycle.save() cycle.create_appraisals() appraisal = self.setup_appraisal_cycle(cycle) - self.assertEqual(appraisal.final_score, 3.8) + self.assertEqual(appraisal.final_score, 3.77) def setup_appraisal_cycle(self, cycle): appraisal = frappe.db.exists("Appraisal", {"appraisal_cycle": cycle.name, "employee": self.employee1}) diff --git a/hrms/hr/doctype/appraisal_cycle/test_appraisal_cycle.py b/hrms/hr/doctype/appraisal_cycle/test_appraisal_cycle.py index 7b82b2c4fa..6ac8268edc 100644 --- a/hrms/hr/doctype/appraisal_cycle/test_appraisal_cycle.py +++ b/hrms/hr/doctype/appraisal_cycle/test_appraisal_cycle.py @@ -59,8 +59,6 @@ def create_appraisal_cycle(**args): if frappe.db.exists("Appraisal Cycle", name): frappe.delete_doc("Appraisal Cycle", name, force=True) - based_on_formula = args.based_on_formula - appraisal_cycle = frappe.get_doc( { "doctype": "Appraisal Cycle", @@ -68,14 +66,8 @@ def create_appraisal_cycle(**args): "company": args.company or "_Test Appraisal", "start_date": args.start_date or "2022-01-01", "end_date": args.end_date or "2022-03-31", - "calculate_final_score_based_on_formula": based_on_formula, } ) - if based_on_formula: - appraisal_cycle.final_score_formula = ( - args.final_score_formula - or "goal_score * 0.2 + self_appraisal_score * 0.2 + average_feedback_score * 0.6" - ) if args.kra_evaluation_method: appraisal_cycle.kra_evaluation_method = args.kra_evaluation_method From 7eab87e6145b0fc942bcbc079b2e55b90f8f02c2 Mon Sep 17 00:00:00 2001 From: Viny Selopal Date: Tue, 30 Apr 2024 09:19:10 +0530 Subject: [PATCH 06/25] refactor: triggering form event (cherry picked from commit 546d5e27cb07711a5ed4ead033cc592b388b4327) --- hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js index 780d627338..1360681314 100644 --- a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js +++ b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js @@ -3,7 +3,7 @@ frappe.ui.form.on("Appraisal Cycle", { refresh(frm) { - frm.events.set_autocompletions_for_final_score_formula(frm); + frm.trigger("set_autocompletions_for_final_score_formula"); frm.set_query("department", () => { return { filters: { From 2090bb2709671994c0c89381a71696f1bde84db2 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 29 May 2024 15:47:40 +0530 Subject: [PATCH 07/25] fix(test): revert final score changes (cherry picked from commit 02fc26dc5c84ebed513260f41d71f963ece3fd9c) --- hrms/hr/doctype/appraisal/test_appraisal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hrms/hr/doctype/appraisal/test_appraisal.py b/hrms/hr/doctype/appraisal/test_appraisal.py index dcf37a3e5f..74dea2cbae 100644 --- a/hrms/hr/doctype/appraisal/test_appraisal.py +++ b/hrms/hr/doctype/appraisal/test_appraisal.py @@ -71,7 +71,7 @@ def test_final_score(self): cycle.create_appraisals() appraisal = self.setup_appraisal_cycle(cycle) - self.assertEqual(appraisal.final_score, 3.77) + self.assertEqual(appraisal.final_score, 3.767) def test_final_score_using_formula(self): cycle = create_appraisal_cycle(designation="Engineer", kra_evaluation_method="Manual Rating") @@ -86,7 +86,7 @@ def test_final_score_using_formula(self): cycle.create_appraisals() appraisal = self.setup_appraisal_cycle(cycle) - self.assertEqual(appraisal.final_score, 3.77) + self.assertEqual(appraisal.final_score, 3.767) def setup_appraisal_cycle(self, cycle): appraisal = frappe.db.exists("Appraisal", {"appraisal_cycle": cycle.name, "employee": self.employee1}) From 3eddaedf642595671eb6f923c750e1bd4bba48aa Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 29 May 2024 16:32:04 +0530 Subject: [PATCH 08/25] fix: adjust score for autocompletions (cherry picked from commit 401d2f05688d0b0a3b6029de76af70b4aae28521) --- .../appraisal_cycle/appraisal_cycle.js | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js index 1360681314..c196145d25 100644 --- a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js +++ b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js @@ -3,7 +3,6 @@ frappe.ui.form.on("Appraisal Cycle", { refresh(frm) { - frm.trigger("set_autocompletions_for_final_score_formula"); frm.set_query("department", () => { return { filters: { @@ -14,6 +13,7 @@ frappe.ui.form.on("Appraisal Cycle", { frm.trigger("show_custom_buttons"); frm.trigger("show_appraisal_summary"); + frm.trigger("set_autocompletions_for_final_score_formula"); }, show_custom_buttons(frm) { @@ -60,26 +60,24 @@ frappe.ui.form.on("Appraisal Cycle", { set_autocompletions_for_final_score_formula: async (frm) => { const autocompletions = [ { - value: "goal_score", - score: 8, - meta: "Goal field", + value: "total_score", + score: 10, + meta: __("Total Goal Score"), }, { value: "average_feedback_score", - score: 8, - meta: "Appraisal field", + score: 10, + meta: __("Average Feedback Score"), }, { value: "self_appraisal_score", - score: 8, - meta: "Appraisal field", + score: 10, + meta: __("Self Appraisal Score"), }, ]; - const doctypes = ["Employee", "Appraisal Cycle"]; - await Promise.all( - doctypes.map((doctype) => + ["Employee", "Appraisal Cycle", "Appraisal"].map((doctype) => frappe.model.with_doctype(doctype, () => { autocompletions.push( ...frappe.get_meta(doctype).fields.map((f) => ({ @@ -91,6 +89,7 @@ frappe.ui.form.on("Appraisal Cycle", { }), ), ); + frm.set_df_property("final_score_formula", "autocompletions", autocompletions); }, From daabeb038b66bfe96e2e48227fe0ac57e0fa6156 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 29 May 2024 16:46:34 +0530 Subject: [PATCH 09/25] fix: formula checkbox label (cherry picked from commit 3a8091d11d66814eebb09182d7bb8b3c161c5903) # Conflicts: # hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json --- hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json index 41aa3c6173..41f4747b8f 100644 --- a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json +++ b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json @@ -159,7 +159,7 @@ "read_only": 1 }, { - "depends_on": "eval:doc.calculate_final_score_based_on_formula === 1;", + "depends_on": "calculate_final_score_based_on_formula", "fieldname": "final_score_formula", "fieldtype": "Code", "label": "Final Score Formula", @@ -170,7 +170,7 @@ "default": "0", "fieldname": "calculate_final_score_based_on_formula", "fieldtype": "Check", - "label": "Calculate final score based on formula" + "label": "Calculate Final Score based on Formula" }, { "fieldname": "column_break_wpgg", @@ -192,11 +192,15 @@ "link_fieldname": "appraisal_cycle" } ], +<<<<<<< HEAD <<<<<<< HEAD "modified": "2023-03-29 12:28:36.247120", ======= "modified": "2024-04-16 13:15:55.493958", >>>>>>> 1712990de (feat: allow adding formula to calculate final score in appraisal cycle) +======= + "modified": "2024-05-29 16:45:22.291678", +>>>>>>> 3a8091d11 (fix: formula checkbox label) "modified_by": "Administrator", "module": "HR", "name": "Appraisal Cycle", From 3815b588b0602b9a39c5a30242e979424452dc80 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 29 May 2024 16:57:02 +0530 Subject: [PATCH 10/25] fix: goal score autocompletion (cherry picked from commit 969c2e8cc5bb8138a046c657eaf30f1924667721) --- hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js index c196145d25..e5538de82b 100644 --- a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js +++ b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js @@ -60,7 +60,7 @@ frappe.ui.form.on("Appraisal Cycle", { set_autocompletions_for_final_score_formula: async (frm) => { const autocompletions = [ { - value: "total_score", + value: "goal_score", score: 10, meta: __("Total Goal Score"), }, From 2b70786a9d98b6a6f9c98d76231edf351611b5be Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 29 May 2024 17:17:34 +0530 Subject: [PATCH 11/25] refactor: `calculate_final_score` function - remove unnecessary conditions - get cached doc for formula eval - rearrange related code blocks together (cherry picked from commit a2c2a8cd6ad36441eca20ffd6de410141452cce7) --- hrms/hr/doctype/appraisal/appraisal.py | 51 ++++++++++----------- hrms/hr/doctype/appraisal/test_appraisal.py | 8 ++-- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/hrms/hr/doctype/appraisal/appraisal.py b/hrms/hr/doctype/appraisal/appraisal.py index fce55007ce..fa72e4f35d 100644 --- a/hrms/hr/doctype/appraisal/appraisal.py +++ b/hrms/hr/doctype/appraisal/appraisal.py @@ -180,34 +180,29 @@ def calculate_avg_feedback_score(self, update=False): self.db_update() def calculate_final_score(self): - if self.appraisal_cycle: - final_score = 0 - appraisal_cycle_doc = frappe.get_doc("Appraisal Cycle", self.appraisal_cycle) - - formula = appraisal_cycle_doc.final_score_formula - based_on_formula = appraisal_cycle_doc.calculate_final_score_based_on_formula - - if not based_on_formula: - final_score = ( - flt(self.total_score) + flt(self.avg_feedback_score) + flt(self.self_score) - ) / 3 - else: - employee_doc = frappe.get_doc("Employee", self.employee) - sanitized_formula = sanitize_expression(formula) - - data = { - "goal_score": flt(self.total_score), - "average_feedback_score": flt(self.avg_feedback_score), - "self_appraisal_score": flt(self.self_score), - } - - data.update(appraisal_cycle_doc.as_dict()) - data.update(employee_doc.as_dict()) - data.update(self.as_dict()) - - final_score = frappe.safe_eval(sanitized_formula, data) - - self.final_score = flt(final_score, self.precision("final_score")) + final_score = 0 + appraisal_cycle_doc = frappe.get_cached_doc("Appraisal Cycle", self.appraisal_cycle) + + formula = appraisal_cycle_doc.final_score_formula + based_on_formula = appraisal_cycle_doc.calculate_final_score_based_on_formula + + if based_on_formula: + employee_doc = frappe.get_cached_doc("Employee", self.employee) + data = { + "goal_score": flt(self.total_score), + "average_feedback_score": flt(self.avg_feedback_score), + "self_appraisal_score": flt(self.self_score), + } + data.update(appraisal_cycle_doc.as_dict()) + data.update(employee_doc.as_dict()) + data.update(self.as_dict()) + + sanitized_formula = sanitize_expression(formula) + final_score = frappe.safe_eval(sanitized_formula, data) + else: + final_score = (flt(self.total_score) + flt(self.avg_feedback_score) + flt(self.self_score)) / 3 + + self.final_score = flt(final_score, self.precision("final_score")) @frappe.whitelist() def add_feedback(self, feedback, feedback_ratings): diff --git a/hrms/hr/doctype/appraisal/test_appraisal.py b/hrms/hr/doctype/appraisal/test_appraisal.py index 74dea2cbae..bff9a04db1 100644 --- a/hrms/hr/doctype/appraisal/test_appraisal.py +++ b/hrms/hr/doctype/appraisal/test_appraisal.py @@ -69,7 +69,7 @@ def test_manual_kra_rating(self): def test_final_score(self): cycle = create_appraisal_cycle(designation="Engineer", kra_evaluation_method="Manual Rating") cycle.create_appraisals() - appraisal = self.setup_appraisal_cycle(cycle) + appraisal = self.setup_appraisal(cycle) self.assertEqual(appraisal.final_score, 3.767) @@ -81,14 +81,14 @@ def test_final_score_using_formula(self): "final_score_formula": "(goal_score + self_appraisal_score + average_feedback_score)/3 if self_appraisal_score else (goal_score + self_appraisal_score)/2", } ) - cycle.save() cycle.create_appraisals() - appraisal = self.setup_appraisal_cycle(cycle) + + appraisal = self.setup_appraisal(cycle) self.assertEqual(appraisal.final_score, 3.767) - def setup_appraisal_cycle(self, cycle): + def setup_appraisal(self, cycle): appraisal = frappe.db.exists("Appraisal", {"appraisal_cycle": cycle.name, "employee": self.employee1}) appraisal = frappe.get_doc("Appraisal", appraisal) From 715faa48c21e98606eefab67e54b781e075856d3 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 29 May 2024 18:02:18 +0530 Subject: [PATCH 12/25] refactor(UX): avoid 2 primary btns in appraisal cycle form (cherry picked from commit af93aed4c97b1d859ef3b1928f68a9025bd9cc1b) --- .../appraisal_cycle/appraisal_cycle.js | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js index e5538de82b..dccae27988 100644 --- a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js +++ b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.js @@ -27,28 +27,42 @@ frappe.ui.form.on("Appraisal Cycle", { frappe.set_route("Tree", "Goal"); }); - let className = ""; let appraisals_created = frm.doc.__onload?.appraisals_created; if (frm.doc.status !== "Completed") { - className = appraisals_created ? "btn-default" : "btn-primary"; - - frm.add_custom_button(__("Create Appraisals"), () => { - frm.trigger("create_appraisals"); - }).addClass(className); + if (appraisals_created) { + frm.add_custom_button(__("Create Appraisals"), () => { + frm.trigger("create_appraisals"); + }); + } else { + frm.page.set_primary_action(__("Create Appraisals"), () => { + frm.trigger("create_appraisals"); + }); + } } - className = appraisals_created ? "btn-primary" : "btn-default"; - if (frm.doc.status === "Not Started") { - frm.add_custom_button(__("Start"), () => { - frm.set_value("status", "In Progress"); - frm.save(); - }).addClass(className); + if (appraisals_created) { + frm.page.set_primary_action(__("Start"), () => { + frm.set_value("status", "In Progress"); + frm.save(); + }); + } else { + frm.add_custom_button(__("Start"), () => { + frm.set_value("status", "In Progress"); + frm.save(); + }); + } } else if (frm.doc.status === "In Progress") { - frm.add_custom_button(__("Mark as Completed"), () => { - frm.trigger("complete_cycle"); - }).addClass(className); + if (appraisals_created) { + frm.page.set_primary_action(__("Mark as Completed"), () => { + frm.trigger("complete_cycle"); + }); + } else { + frm.add_custom_button(__("Mark as Completed"), () => { + frm.trigger("complete_cycle"); + }); + } } else if (frm.doc.status === "Completed") { frm.add_custom_button(__("Mark as In Progress"), () => { frm.set_value("status", "In Progress"); From 1929a5d378242b9fb9755ca312e998051cfdb308 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 29 May 2024 18:16:55 +0530 Subject: [PATCH 13/25] feat: set desc for formula setting & make formula mandatory if checkbox is enabled (cherry picked from commit 70e30c72f1b7e873b95acae8956d77623934ae1e) # Conflicts: # hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json --- .../appraisal_cycle/appraisal_cycle.json | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json index 41f4747b8f..1803af305c 100644 --- a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json +++ b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json @@ -17,10 +17,11 @@ "section_break_4", "description", "settings_section", + "column_break_vhzx", + "kra_evaluation_method", + "section_break_zykh", "calculate_final_score_based_on_formula", "final_score_formula", - "column_break_wpgg", - "kra_evaluation_method", "applicable_for_tab", "filters_section", "branch", @@ -163,18 +164,25 @@ "fieldname": "final_score_formula", "fieldtype": "Code", "label": "Final Score Formula", + "mandatory_depends_on": "calculate_final_score_based_on_formula", "max_height": "5rem", "options": "PythonExpression" }, { "default": "0", + "description": "By default, the Final Score is calculated as the average of Goal Score, Feedback Score, and Self Appraisal Score. Enable this to set a different formula", "fieldname": "calculate_final_score_based_on_formula", "fieldtype": "Check", "label": "Calculate Final Score based on Formula" }, { - "fieldname": "column_break_wpgg", + "fieldname": "column_break_vhzx", "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_zykh", + "fieldtype": "Section Break", + "hide_border": 1 } ], "index_web_pages_for_search": 1, @@ -193,6 +201,7 @@ } ], <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD "modified": "2023-03-29 12:28:36.247120", ======= @@ -201,6 +210,9 @@ ======= "modified": "2024-05-29 16:45:22.291678", >>>>>>> 3a8091d11 (fix: formula checkbox label) +======= + "modified": "2024-05-29 18:15:06.443594", +>>>>>>> 70e30c72f (feat: set desc for formula setting & make formula mandatory if checkbox is enabled) "modified_by": "Administrator", "module": "HR", "name": "Appraisal Cycle", From 01430752bb5b90a9a48c287ce6138fdd75d972b4 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 29 May 2024 18:44:23 +0530 Subject: [PATCH 14/25] chore: fix conflicts --- hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json index 1803af305c..89a1afd742 100644 --- a/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json +++ b/hrms/hr/doctype/appraisal_cycle/appraisal_cycle.json @@ -200,19 +200,7 @@ "link_fieldname": "appraisal_cycle" } ], -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD - "modified": "2023-03-29 12:28:36.247120", -======= - "modified": "2024-04-16 13:15:55.493958", ->>>>>>> 1712990de (feat: allow adding formula to calculate final score in appraisal cycle) -======= - "modified": "2024-05-29 16:45:22.291678", ->>>>>>> 3a8091d11 (fix: formula checkbox label) -======= "modified": "2024-05-29 18:15:06.443594", ->>>>>>> 70e30c72f (feat: set desc for formula setting & make formula mandatory if checkbox is enabled) "modified_by": "Administrator", "module": "HR", "name": "Appraisal Cycle", From dcb55e5933b54b8bcb6ec9f0419c665f67211f62 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 3 Apr 2024 07:27:31 +0530 Subject: [PATCH 15/25] feat: geolocation in Employee Checkin (cherry picked from commit e54e79b27907ddc7a205ba57c798b1ece4c38e07) # Conflicts: # hrms/hr/doctype/employee_checkin/employee_checkin.json --- .../employee_checkin/employee_checkin.json | 34 +++++++++++++++++++ .../employee_checkin/employee_checkin.py | 14 ++++++++ 2 files changed, 48 insertions(+) diff --git a/hrms/hr/doctype/employee_checkin/employee_checkin.json b/hrms/hr/doctype/employee_checkin/employee_checkin.json index 14eb5cbcfa..25017a8728 100644 --- a/hrms/hr/doctype/employee_checkin/employee_checkin.json +++ b/hrms/hr/doctype/employee_checkin/employee_checkin.json @@ -15,8 +15,13 @@ "device_id", "skip_auto_attendance", "attendance", + "location_section", + "coordinates", + "geolocation", + "shift_timings_section", "shift_start", "shift_end", + "column_break_vyyt", "shift_actual_start", "shift_actual_end" ], @@ -107,10 +112,39 @@ "fieldtype": "Datetime", "hidden": 1, "label": "Shift Actual End" + }, + { + "fieldname": "location_section", + "fieldtype": "Section Break", + "label": "Location" + }, + { + "fieldname": "coordinates", + "fieldtype": "Data", + "label": "Coordinates", + "read_only": 1 + }, + { + "fieldname": "geolocation", + "fieldtype": "Geolocation", + "label": "Geolocation" + }, + { + "fieldname": "shift_timings_section", + "fieldtype": "Section Break", + "label": "Shift Timings" + }, + { + "fieldname": "column_break_vyyt", + "fieldtype": "Column Break" } ], "links": [], +<<<<<<< HEAD "modified": "2024-04-02 01:50:23.150627", +======= + "modified": "2024-04-03 06:36:07.640893", +>>>>>>> e54e79b27 (feat: geolocation in Employee Checkin) "modified_by": "Administrator", "module": "HR", "name": "Employee Checkin", diff --git a/hrms/hr/doctype/employee_checkin/employee_checkin.py b/hrms/hr/doctype/employee_checkin/employee_checkin.py index 8524b6ef6a..7a5e784a76 100644 --- a/hrms/hr/doctype/employee_checkin/employee_checkin.py +++ b/hrms/hr/doctype/employee_checkin/employee_checkin.py @@ -18,6 +18,7 @@ def validate(self): validate_active_employee(self.employee) self.validate_duplicate_log() self.fetch_shift() + self.set_geolocation_coordinates() def validate_duplicate_log(self): doc = frappe.db.exists( @@ -60,6 +61,19 @@ def fetch_shift(self): else: self.shift = None + def set_geolocation_coordinates(self): + if not self.geolocation: + return + + try: + self.coordinates = str(get_coordinates_from_geolocation(self.geolocation)) + except Exception: + frappe.log_error("Error parsing geolocation field") + + +def get_coordinates_from_geolocation(geolocation: str): + return frappe.parse_json(geolocation)["features"][0]["geometry"]["coordinates"] + @frappe.whitelist() def add_log_based_on_employee_field( From 1132f91843877500ba88535aac49dc0eb99734bc Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 3 Apr 2024 07:29:07 +0530 Subject: [PATCH 16/25] feat(PWA): capture geolocation in checkins (cherry picked from commit 90237231c168b66f23c8d88c8aaa414a89285c4a) # Conflicts: # frontend/src/components/CheckInPanel.vue --- frontend/src/components/CheckInPanel.vue | 97 ++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/frontend/src/components/CheckInPanel.vue b/frontend/src/components/CheckInPanel.vue index 99481e03e8..add2ede489 100644 --- a/frontend/src/components/CheckInPanel.vue +++ b/frontend/src/components/CheckInPanel.vue @@ -1,11 +1,71 @@