diff --git a/.github/helper/documentation.py b/.github/helper/documentation.py index 378983e95f..8ceb7f7436 100644 --- a/.github/helper/documentation.py +++ b/.github/helper/documentation.py @@ -3,14 +3,6 @@ from urllib.parse import urlparse -docs_repos = [ - "frappe_docs", - "erpnext_documentation", - "erpnext_com", - "frappe_io", -] - - def uri_validator(x): result = urlparse(x) return all([result.scheme, result.netloc, result.path]) @@ -22,15 +14,15 @@ def docs_link_exists(body): parsed_url = urlparse(word) if parsed_url.netloc == "github.com": parts = parsed_url.path.split('/') - if len(parts) == 5 and parts[1] == "frappe" and parts[2] in docs_repos: + if len(parts) == 5 and parts[1] == "frappe" and parts[2] == "hrms": return True - elif parsed_url.netloc == "docs.erpnext.com": + elif parsed_url.netloc == "frappehr.com": return True if __name__ == "__main__": pr = sys.argv[1] - response = requests.get("https://api.github.com/repos/frappe/erpnext/pulls/{}".format(pr)) + response = requests.get("https://api.github.com/repos/frappe/hrms/pulls/{}".format(pr)) if response.ok: payload = response.json() diff --git a/hrms/__init__.py b/hrms/__init__.py index 4a77120ba1..6a5011a85d 100644 --- a/hrms/__init__.py +++ b/hrms/__init__.py @@ -1 +1 @@ -__version__ = "14.2.1" +__version__ = "14.2.2" diff --git a/hrms/hr/doctype/appraisal/appraisal.py b/hrms/hr/doctype/appraisal/appraisal.py index e9d33a8213..b00f402ee8 100644 --- a/hrms/hr/doctype/appraisal/appraisal.py +++ b/hrms/hr/doctype/appraisal/appraisal.py @@ -107,7 +107,7 @@ def set_kras_and_rating_criteria(self): self.append( table_name, { - "kra": entry.kra, + "kra": entry.key_result_area, "per_weightage": entry.per_weightage, }, ) diff --git a/hrms/hr/doctype/appraisal_cycle/test_appraisal_cycle.py b/hrms/hr/doctype/appraisal_cycle/test_appraisal_cycle.py index f58e38c1c8..43512a5bc2 100644 --- a/hrms/hr/doctype/appraisal_cycle/test_appraisal_cycle.py +++ b/hrms/hr/doctype/appraisal_cycle/test_appraisal_cycle.py @@ -44,7 +44,7 @@ def test_create_appraisals(self): for i in range(2): # check if KRAs are set - self.assertEqual(appraisal.appraisal_kra[i].kra, self.template.goals[i].kra) + self.assertEqual(appraisal.appraisal_kra[i].kra, self.template.goals[i].key_result_area) self.assertEqual(appraisal.appraisal_kra[i].per_weightage, self.template.goals[i].per_weightage) # check if rating criteria is set diff --git a/hrms/hr/doctype/appraisal_template/test_appraisal_template.py b/hrms/hr/doctype/appraisal_template/test_appraisal_template.py index ee8f4a297d..c302153254 100644 --- a/hrms/hr/doctype/appraisal_template/test_appraisal_template.py +++ b/hrms/hr/doctype/appraisal_template/test_appraisal_template.py @@ -50,11 +50,11 @@ def create_appraisal_template(title=None, kras=None, rating_criteria=None): if not kras: kras = [ { - "kra": "Quality", + "key_result_area": "Quality", "per_weightage": 30, }, { - "kra": "Development", + "key_result_area": "Development", "per_weightage": 70, }, ] @@ -71,7 +71,7 @@ def create_appraisal_template(title=None, kras=None, rating_criteria=None): }, ] - create_kras([entry["kra"] for entry in kras]) + create_kras([entry["key_result_area"] for entry in kras]) create_criteria([entry["criteria"] for entry in rating_criteria]) appraisal_template = frappe.new_doc("Appraisal Template") diff --git a/hrms/hr/doctype/appraisal_template_goal/appraisal_template_goal.json b/hrms/hr/doctype/appraisal_template_goal/appraisal_template_goal.json index ebd3124ec2..5f431c7003 100644 --- a/hrms/hr/doctype/appraisal_template_goal/appraisal_template_goal.json +++ b/hrms/hr/doctype/appraisal_template_goal/appraisal_template_goal.json @@ -6,23 +6,10 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "kra", + "key_result_area", "per_weightage" ], "fields": [ - { - "description": "Key Performance Area", - "fieldname": "kra", - "fieldtype": "Link", - "in_list_view": 1, - "label": "KRA", - "oldfieldname": "kra", - "oldfieldtype": "Small Text", - "options": "KRA", - "print_width": "200px", - "reqd": 1, - "width": "200px" - }, { "fieldname": "per_weightage", "fieldtype": "Percent", @@ -33,12 +20,21 @@ "print_width": "100px", "reqd": 1, "width": "100px" + }, + { + "description": "Key Result Area", + "fieldname": "key_result_area", + "fieldtype": "Link", + "in_list_view": 1, + "label": "KRA", + "options": "KRA", + "reqd": 1 } ], "idx": 1, "istable": 1, "links": [], - "modified": "2022-08-29 17:57:02.907867", + "modified": "2023-04-17 17:01:46.294286", "modified_by": "Administrator", "module": "HR", "name": "Appraisal Template Goal", diff --git a/hrms/hr/doctype/attendance/attendance.py b/hrms/hr/doctype/attendance/attendance.py index 3cea3f10b4..fd64a8b841 100644 --- a/hrms/hr/doctype/attendance/attendance.py +++ b/hrms/hr/doctype/attendance/attendance.py @@ -10,7 +10,7 @@ add_days, cint, cstr, - formatdate, + format_date, get_datetime, get_link_to_form, getdate, @@ -53,9 +53,19 @@ def validate_attendance_date(self): and not self.leave_application and getdate(self.attendance_date) > getdate(nowdate()) ): - frappe.throw(_("Attendance can not be marked for future dates")) + frappe.throw( + _("Attendance can not be marked for future dates: {0}").format( + frappe.bold(format_date(self.attendance_date)), + ) + ) elif date_of_joining and getdate(self.attendance_date) < getdate(date_of_joining): - frappe.throw(_("Attendance date can not be less than employee's joining date")) + frappe.throw( + _("Attendance date {0} can not be less than employee {1}'s joining date: {2}").format( + frappe.bold(format_date(self.attendance_date)), + frappe.bold(self.employee), + frappe.bold(format_date(date_of_joining)), + ) + ) def validate_duplicate_record(self): duplicate = get_duplicate_attendance_record( @@ -66,7 +76,7 @@ def validate_duplicate_record(self): frappe.throw( _("Attendance for employee {0} is already marked for the date {1}: {2}").format( frappe.bold(self.employee), - frappe.bold(self.attendance_date), + frappe.bold(format_date(self.attendance_date)), get_link_to_form("Attendance", duplicate[0].name), ), title=_("Duplicate Attendance"), @@ -112,19 +122,19 @@ def check_leave_record(self): if d.half_day_date == getdate(self.attendance_date): self.status = "Half Day" frappe.msgprint( - _("Employee {0} on Half day on {1}").format(self.employee, formatdate(self.attendance_date)) + _("Employee {0} on Half day on {1}").format(self.employee, format_date(self.attendance_date)) ) else: self.status = "On Leave" frappe.msgprint( - _("Employee {0} is on Leave on {1}").format(self.employee, formatdate(self.attendance_date)) + _("Employee {0} is on Leave on {1}").format(self.employee, format_date(self.attendance_date)) ) if self.status in ("On Leave", "Half Day"): if not leave_record: frappe.msgprint( _("No leave record found for employee {0} on {1}").format( - self.employee, formatdate(self.attendance_date) + self.employee, format_date(self.attendance_date) ), alert=1, ) diff --git a/hrms/overrides/company.py b/hrms/overrides/company.py index 96fafeb55d..cc01b5fd79 100644 --- a/hrms/overrides/company.py +++ b/hrms/overrides/company.py @@ -71,6 +71,7 @@ def make_salary_components(country): try: doc = frappe.get_doc(d) doc.flags.ignore_permissions = True + doc.flags.ignore_mandatory = True doc.insert(ignore_if_duplicate=True) except frappe.NameError: frappe.clear_messages() diff --git a/hrms/patches.txt b/hrms/patches.txt index 44ff0e2644..ff9052f730 100644 --- a/hrms/patches.txt +++ b/hrms/patches.txt @@ -1,8 +1,8 @@ [pre_model_sync] -hrms.patches.v14_0.update_performance_module_changes [post_model_sync] hrms.patches.post_install.set_payroll_entry_status hrms.patches.v1_0.rearrange_employee_fields -hrms.patches.v1_0.update_allocate_on_in_leave_type -hrms.patches.v14_0.create_custom_field_for_appraisal_template \ No newline at end of file +hrms.patches.post_install.update_allocate_on_in_leave_type +hrms.patches.v14_0.create_custom_field_for_appraisal_template +hrms.patches.post_install.update_performance_module_changes #2023-04-17 \ No newline at end of file diff --git a/hrms/patches/post_install/drop_column_max_days_allowed.py b/hrms/patches/post_install/drop_column_max_days_allowed.py deleted file mode 100644 index bfc8163399..0000000000 --- a/hrms/patches/post_install/drop_column_max_days_allowed.py +++ /dev/null @@ -1,7 +0,0 @@ -import frappe - - -def execute(): - if frappe.db.exists("DocType", "Leave Type"): - if frappe.db.has_column("Leave Type", "max_days_allowed"): - frappe.db.sql("alter table `tabLeave Type` drop column max_days_allowed") diff --git a/hrms/patches/post_install/migrate_daily_work_summary_settings_to_daily_work_summary_group.py b/hrms/patches/post_install/migrate_daily_work_summary_settings_to_daily_work_summary_group.py index aa8632fd1b..ac289b20b8 100644 --- a/hrms/patches/post_install/migrate_daily_work_summary_settings_to_daily_work_summary_group.py +++ b/hrms/patches/post_install/migrate_daily_work_summary_settings_to_daily_work_summary_group.py @@ -6,7 +6,7 @@ def execute(): - if not frappe.db.table_exists("Daily Work Summary Group"): + if frappe.db.table_exists("Daily Work Summary Settings"): frappe.reload_doc("hr", "doctype", "daily_work_summary_group") frappe.reload_doc("hr", "doctype", "daily_work_summary_group_user") @@ -37,6 +37,7 @@ def execute(): ) new_group.flags.ignore_permissions = True new_group.flags.ignore_validate = True + new_group.flags.ignore_mandatory = True new_group.insert(ignore_if_duplicate=True) frappe.delete_doc_if_exists("DocType", "Daily Work Summary Settings") diff --git a/hrms/patches/post_install/move_doctype_reports_and_notification_from_hr_to_payroll.py b/hrms/patches/post_install/move_doctype_reports_and_notification_from_hr_to_payroll.py index 1dd2b34f97..b3ab857c8e 100644 --- a/hrms/patches/post_install/move_doctype_reports_and_notification_from_hr_to_payroll.py +++ b/hrms/patches/post_install/move_doctype_reports_and_notification_from_hr_to_payroll.py @@ -6,17 +6,12 @@ def execute(): - if frappe.db.exists("DocType", {"module": "Payroll", "name": "Employee Incentive"}): - return - frappe.db.sql( """UPDATE `tabPrint Format` - SET module = 'Payroll' - WHERE name IN ('Salary Slip Based On Timesheet', 'Salary Slip Standard')""" + SET module = 'Payroll' + WHERE name IN ('Salary Slip Based On Timesheet', 'Salary Slip Standard')""" ) - frappe.db.sql("""UPDATE `tabNotification` SET module='Payroll' WHERE name='Retention Bonus';""") - doctypes_moved = [ "Employee Benefit Application Detail", "Employee Tax Exemption Declaration Category", diff --git a/hrms/patches/post_install/rename_field_max_days_allowed.py b/hrms/patches/post_install/rename_field_max_days_allowed.py index a179178cdd..8743a5e057 100644 --- a/hrms/patches/post_install/rename_field_max_days_allowed.py +++ b/hrms/patches/post_install/rename_field_max_days_allowed.py @@ -16,3 +16,8 @@ def execute(): frappe.db.sql_ddl("""ALTER table `tabLeave Type` modify max_days_allowed int(8) NOT NULL""") frappe.reload_doc("hr", "doctype", "leave_type") rename_field("Leave Type", "max_days_allowed", "max_continuous_days_allowed") + + if frappe.db.has_column("Leave Type", "max_days_allowed"): + frappe.db.sql("alter table `tabLeave Type` drop column max_days_allowed") + # clear cache for doctype as it stores table columns in cache + frappe.clear_cache(doctype="Leave Type") diff --git a/hrms/patches/post_install/set_job_offer_applicant_email.py b/hrms/patches/post_install/set_job_offer_applicant_email.py index 0e3b5c4d2a..22fbdbc617 100644 --- a/hrms/patches/post_install/set_job_offer_applicant_email.py +++ b/hrms/patches/post_install/set_job_offer_applicant_email.py @@ -2,13 +2,13 @@ def execute(): - frappe.reload_doc("hr", "doctype", "job_offer") + Offer = frappe.qb.DocType("Job Offer") + Applicant = frappe.qb.DocType("Job Applicant") - frappe.db.sql( - """ - UPDATE - `tabJob Offer` AS offer - SET - applicant_email = (SELECT email_id FROM `tabJob Applicant` WHERE name = offer.job_applicant) - """ - ) + ( + frappe.qb.update(Offer) + .inner_join(Applicant) + .on(Applicant.name == Offer.job_applicant) + .set(Offer.applicant_email, Applicant.email_id) + .where(Offer.applicant_email.isnull()) + ).run() diff --git a/hrms/patches/v1_0/update_allocate_on_in_leave_type.py b/hrms/patches/post_install/update_allocate_on_in_leave_type.py similarity index 78% rename from hrms/patches/v1_0/update_allocate_on_in_leave_type.py rename to hrms/patches/post_install/update_allocate_on_in_leave_type.py index 6b6a4833df..e11d517c4f 100644 --- a/hrms/patches/v1_0/update_allocate_on_in_leave_type.py +++ b/hrms/patches/post_install/update_allocate_on_in_leave_type.py @@ -2,6 +2,8 @@ def execute(): + frappe.clear_cache(doctype="Leave Type") + if frappe.db.has_column("Leave Type", "based_on_date_of_joining"): LeaveType = frappe.qb.DocType("Leave Type") frappe.qb.update(LeaveType).set(LeaveType.allocate_on_day, "Last Day").where( @@ -13,3 +15,5 @@ def execute(): ).run() frappe.db.sql_ddl("alter table `tabLeave Type` drop column `based_on_date_of_joining`") + # clear cache for doctype as it stores table columns in cache + frappe.clear_cache(doctype="Leave Type") diff --git a/hrms/patches/v14_0/update_performance_module_changes.py b/hrms/patches/post_install/update_performance_module_changes.py similarity index 69% rename from hrms/patches/v14_0/update_performance_module_changes.py rename to hrms/patches/post_install/update_performance_module_changes.py index 02148ee0c6..a218ae5575 100644 --- a/hrms/patches/v14_0/update_performance_module_changes.py +++ b/hrms/patches/post_install/update_performance_module_changes.py @@ -4,28 +4,25 @@ def execute(): create_kras() - - for doctype in ( - "Appraisal Template", - "Appraisal Cycle", - "Appraisal KRA", - "Appraisal Goal", - "Employee Feedback Rating", - "Appraisal", - ): - frappe.reload_doc("hr", "doctype", doctype) - rename_fields() update_kra_evaluation_method() def create_kras(): - # Appraisal Template Goal's KRA field was changed from Small Text to Link + # A new Link field `key_result_area` was added in the Appraisal Template Goal table + # Old field's (`kra` (Small Text)) data now needs to be copied to the new field # This patch will create KRA's for all existing Appraisal Template Goal entries # keeping 140 characters as the KRA title and the whole KRA as the description - frappe.reload_doc("hr", "doctype", "kra") + # and then set the new title (140 characters) in the `key_result_area` field + if not frappe.db.has_column("Appraisal Template Goal", "kra"): + return - template_goals = frappe.get_all("Appraisal Template Goal", fields=["name", "kra"], as_list=True) + template_goals = frappe.get_all( + "Appraisal Template Goal", + filters={"parenttype": "Appraisal Template"}, + fields=["name", "kra"], + as_list=True, + ) if len(template_goals) > 10000: frappe.db.auto_commit_on_many_writes = 1 @@ -48,7 +45,10 @@ def create_kras(): } ).db_insert() - frappe.db.set_value("Appraisal Template Goal", name, "kra", kra_title, update_modified=False) + # set 140 char kra in the `key_result_area` field + frappe.db.set_value( + "Appraisal Template Goal", name, "key_result_area", kra_title, update_modified=False + ) if frappe.db.auto_commit_on_many_writes: frappe.db.auto_commit_on_many_writes = 0 diff --git a/hrms/setup.py b/hrms/setup.py index 38dd6bcfa1..cbf0643236 100644 --- a/hrms/setup.py +++ b/hrms/setup.py @@ -19,7 +19,6 @@ def after_install(): add_non_standard_user_types() set_single_defaults() update_erpnext_access() - frappe.db.commit() run_post_install_patches() @@ -235,6 +234,7 @@ def get_custom_fields(): "label": "Appraisal Template", "options": "Appraisal Template", "insert_after": "description", + "allow_in_quick_entry": 1, }, { "fieldname": "required_skills_section", @@ -624,9 +624,7 @@ def get_post_install_patches(): "erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group", "erpnext.patches.v11_0.move_leave_approvers_from_employee", "erpnext.patches.v11_0.rename_field_max_days_allowed", - "erpnext.patches.v11_0.set_department_for_doctypes", "erpnext.patches.v11_0.add_expense_claim_default_account", - "erpnext.patches.v11_0.drop_column_max_days_allowed", "erpnext.patches.v11_0.rename_additional_salary_component_additional_salary", "erpnext.patches.v11_1.set_salary_details_submittable", "erpnext.patches.v11_1.rename_depends_on_lwp", @@ -652,6 +650,8 @@ def get_post_install_patches(): "erpnext.patches.v13_0.set_payroll_entry_status", # HRMS "create_country_fixtures", + "update_allocate_on_in_leave_type", + "update_performance_module_changes", ) @@ -663,10 +663,11 @@ def run_post_install_patches(): try: for patch in POST_INSTALL_PATCHES: - # patch has not run on the site before - if not frappe.db.exists("Patch Log", {"patch": ("like", f"%{patch}%")}): - patch_name = patch.split(".")[-1] - frappe.get_attr(f"hrms.patches.post_install.{patch_name}.execute")() + patch_name = patch.split(".")[-1] + if not patch_name: + continue + + frappe.get_attr(f"hrms.patches.post_install.{patch_name}.execute")() finally: frappe.flags.in_patch = False