From 4ba419349dec1029d03732a51f8fc16e130c35cc Mon Sep 17 00:00:00 2001 From: Aysha Date: Sun, 19 Jan 2025 16:35:10 +0530 Subject: [PATCH 01/10] fix: add company_data_to_be_ignored hook (cherry picked from commit ae7e5771da75f781a0809fb1d1d0fab59e2ce385) --- hrms/hooks.py | 5 +++++ hrms/overrides/company.py | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/hrms/hooks.py b/hrms/hooks.py index 163492f37f..965145ed0c 100644 --- a/hrms/hooks.py +++ b/hrms/hooks.py @@ -1,3 +1,5 @@ +from hrms.overrides.company import get_company_data_to_be_ignored + app_name = "hrms" app_title = "Frappe HR" app_publisher = "Frappe Technologies Pvt. Ltd." @@ -168,6 +170,7 @@ "hrms.overrides.company.make_company_fixtures", "hrms.overrides.company.set_default_hr_accounts", ], + "on_trash": "hrms.overrides.company.unset_company_field", }, "Holiday List": { "on_update": "hrms.utils.holiday_list.invalidate_cache", @@ -347,3 +350,5 @@ # Recommended only for DocTypes which have limited documents with untranslated names # For example: Role, Gender, etc. # translated_search_doctypes = [] + +company_data_to_be_ignored = get_company_data_to_be_ignored() diff --git a/hrms/overrides/company.py b/hrms/overrides/company.py index c9fe4d6397..bfd2f9f3cc 100644 --- a/hrms/overrides/company.py +++ b/hrms/overrides/company.py @@ -132,3 +132,21 @@ def validate_default_accounts(doc, method=None): "The currency of {0} should be same as the company's default currency. Please select another account." ).format(frappe.bold(_("Default Payroll Payable Account"))) ) + + +def get_company_data_to_be_ignored(): + if "erpnext" in frappe.get_installed_apps(): + return [ + "Salary Component Account", + "Salary Structure", + "Salary Structure Assignment", + "Payroll Period", + "Income Tax Slab", + "Leave Policy", + "Leave Period", + "Leave Policy Assignment", + "Employee Onboarding Template", + "Employee Separation Template", + "Job Offer Term Template", + ] + return [] From 2c2229e9d5ac699653ae1c1ed89c1c3b280348aa Mon Sep 17 00:00:00 2001 From: Aysha Date: Sun, 19 Jan 2025 16:38:06 +0530 Subject: [PATCH 02/10] fix: set company field empty for single and master doctypes during company deletion (cherry picked from commit b9f272244bfd797c1e8f98cad2ed78973d088085) --- hrms/overrides/company.py | 58 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/hrms/overrides/company.py b/hrms/overrides/company.py index bfd2f9f3cc..c04ed325e2 100644 --- a/hrms/overrides/company.py +++ b/hrms/overrides/company.py @@ -150,3 +150,61 @@ def get_company_data_to_be_ignored(): "Job Offer Term Template", ] return [] + + +def unset_company_field(doc, method=None): + unset_company_field_for_single_doctype(doc) + unset_company_field_for_non_single_doctype(doc) + + +def unset_company_field_for_single_doctype(doc): + for doctype in get_single_doctypes_with_company_field(): + fields = frappe.get_meta(doctype).fields + if any(field.fieldname == "company" for field in fields): + frappe.db.sql( + """ + UPDATE `tabSingles` + SET value = '' + WHERE doctype = %s AND field = 'company' AND value = %s + """, + (doctype, doc.name), + ) + + +def unset_company_field_for_non_single_doctype(doc): + for doctype in get_company_data_to_be_ignored(): + company_field = frappe.get_all( + "DocField", + filters={"parent": doctype, "fieldtype": "Link", "options": "Company"}, + fields=["fieldname"], + ) + if company_field: + frappe.db.sql( + f""" + UPDATE `tab{doctype}` + SET company = '' + WHERE company = %s + """, + (doc.name,), + ) + + +def get_single_doctypes_with_company_field(): + DocType = frappe.qb.DocType("DocType") + DocField = frappe.qb.DocType("DocField") + + return ( + frappe.qb.from_(DocField) + .select(DocField.parent) + .where( + (DocField.fieldtype == "Link") + & (DocField.options == "Company") + & ( + DocField.parent.isin( + frappe.qb.from_(DocType) + .select(DocType.name) + .where((DocType.issingle == 1) & (DocType.module.isin(["HR", "Payroll"]))) + ) + ) + ) + ).run(pluck="name") From defbcf6402ac43bca29f22a30968f812892692ff Mon Sep 17 00:00:00 2001 From: Aysha Date: Tue, 21 Jan 2025 12:57:44 +0530 Subject: [PATCH 03/10] fix: add doctype list to ignore to hooks directly (cherry picked from commit 5051d6a9fb56de2028a199982e286842caef07ae) --- hrms/hooks.py | 16 +++++++++++++--- hrms/overrides/company.py | 21 ++------------------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/hrms/hooks.py b/hrms/hooks.py index 965145ed0c..865023a699 100644 --- a/hrms/hooks.py +++ b/hrms/hooks.py @@ -1,5 +1,3 @@ -from hrms.overrides.company import get_company_data_to_be_ignored - app_name = "hrms" app_title = "Frappe HR" app_publisher = "Frappe Technologies Pvt. Ltd." @@ -351,4 +349,16 @@ # For example: Role, Gender, etc. # translated_search_doctypes = [] -company_data_to_be_ignored = get_company_data_to_be_ignored() +company_data_to_be_ignored = [ + "Salary Component Account", + "Salary Structure", + "Salary Structure Assignment", + "Payroll Period", + "Income Tax Slab", + "Leave Policy", + "Leave Period", + "Leave Policy Assignment", + "Employee Onboarding Template", + "Employee Separation Template", + "Job Offer Term Template", +] diff --git a/hrms/overrides/company.py b/hrms/overrides/company.py index c04ed325e2..65e2e3cb27 100644 --- a/hrms/overrides/company.py +++ b/hrms/overrides/company.py @@ -134,24 +134,6 @@ def validate_default_accounts(doc, method=None): ) -def get_company_data_to_be_ignored(): - if "erpnext" in frappe.get_installed_apps(): - return [ - "Salary Component Account", - "Salary Structure", - "Salary Structure Assignment", - "Payroll Period", - "Income Tax Slab", - "Leave Policy", - "Leave Period", - "Leave Policy Assignment", - "Employee Onboarding Template", - "Employee Separation Template", - "Job Offer Term Template", - ] - return [] - - def unset_company_field(doc, method=None): unset_company_field_for_single_doctype(doc) unset_company_field_for_non_single_doctype(doc) @@ -172,7 +154,8 @@ def unset_company_field_for_single_doctype(doc): def unset_company_field_for_non_single_doctype(doc): - for doctype in get_company_data_to_be_ignored(): + company_data_to_be_ignored = frappe.get_hooks("company_data_to_be_ignored") or [] + for doctype in company_data_to_be_ignored: company_field = frappe.get_all( "DocField", filters={"parent": doctype, "fieldtype": "Link", "options": "Company"}, From 17970d9079dbb6436eaed45c89e46dfa95f10a9b Mon Sep 17 00:00:00 2001 From: Aysha Date: Tue, 21 Jan 2025 23:55:59 +0530 Subject: [PATCH 04/10] fix: update function clearing company field and replace SQL with query builder (cherry picked from commit ba780fa44ec5a68a0512bf11e253afe869c6a29d) --- hrms/hooks.py | 2 +- hrms/overrides/company.py | 64 ++++++++------------------------------- 2 files changed, 13 insertions(+), 53 deletions(-) diff --git a/hrms/hooks.py b/hrms/hooks.py index 865023a699..01af1ad43e 100644 --- a/hrms/hooks.py +++ b/hrms/hooks.py @@ -168,7 +168,7 @@ "hrms.overrides.company.make_company_fixtures", "hrms.overrides.company.set_default_hr_accounts", ], - "on_trash": "hrms.overrides.company.unset_company_field", + "on_trash": "hrms.overrides.company.clear_company_field_in_linked_docs", }, "Holiday List": { "on_update": "hrms.utils.holiday_list.invalidate_cache", diff --git a/hrms/overrides/company.py b/hrms/overrides/company.py index 65e2e3cb27..943e648b66 100644 --- a/hrms/overrides/company.py +++ b/hrms/overrides/company.py @@ -134,60 +134,20 @@ def validate_default_accounts(doc, method=None): ) -def unset_company_field(doc, method=None): - unset_company_field_for_single_doctype(doc) - unset_company_field_for_non_single_doctype(doc) - - -def unset_company_field_for_single_doctype(doc): - for doctype in get_single_doctypes_with_company_field(): - fields = frappe.get_meta(doctype).fields - if any(field.fieldname == "company" for field in fields): - frappe.db.sql( - """ - UPDATE `tabSingles` - SET value = '' - WHERE doctype = %s AND field = 'company' AND value = %s - """, - (doctype, doc.name), - ) - - -def unset_company_field_for_non_single_doctype(doc): +def clear_company_field_in_linked_docs(doc, method=None): company_data_to_be_ignored = frappe.get_hooks("company_data_to_be_ignored") or [] for doctype in company_data_to_be_ignored: - company_field = frappe.get_all( + # get field in the doctype linked to Company + company_field = frappe.db.get_value( "DocField", - filters={"parent": doctype, "fieldtype": "Link", "options": "Company"}, - fields=["fieldname"], + {"parent": doctype, "fieldtype": "Link", "options": "Company"}, + "fieldname", ) - if company_field: - frappe.db.sql( - f""" - UPDATE `tab{doctype}` - SET company = '' - WHERE company = %s - """, - (doc.name,), - ) - -def get_single_doctypes_with_company_field(): - DocType = frappe.qb.DocType("DocType") - DocField = frappe.qb.DocType("DocField") - - return ( - frappe.qb.from_(DocField) - .select(DocField.parent) - .where( - (DocField.fieldtype == "Link") - & (DocField.options == "Company") - & ( - DocField.parent.isin( - frappe.qb.from_(DocType) - .select(DocType.name) - .where((DocType.issingle == 1) & (DocType.module.isin(["HR", "Payroll"]))) - ) - ) - ) - ).run(pluck="name") + if company_field: + doctype_table = frappe.qb.DocType(doctype) + ( + frappe.qb.update(doctype_table) + .set(doctype_table[company_field], "") + .where(doctype_table[company_field] == doc.name) + ).run() From 466e487ea0fb2107042a9bbdcd6086f15ac0f344 Mon Sep 17 00:00:00 2001 From: Aysha Date: Thu, 23 Jan 2025 17:06:02 +0530 Subject: [PATCH 05/10] fix: edit company_data_to_be_ignored hook content (cherry picked from commit 5b1729bd7a465e48db011771bf17056ff42f522b) --- hrms/hooks.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/hrms/hooks.py b/hrms/hooks.py index 01af1ad43e..5d102cc0b3 100644 --- a/hrms/hooks.py +++ b/hrms/hooks.py @@ -355,10 +355,8 @@ "Salary Structure Assignment", "Payroll Period", "Income Tax Slab", - "Leave Policy", "Leave Period", "Leave Policy Assignment", "Employee Onboarding Template", "Employee Separation Template", - "Job Offer Term Template", ] From d026ca53cf7e773e770b48d2f2da79b0cd8ba90f Mon Sep 17 00:00:00 2001 From: Aysha Date: Thu, 23 Jan 2025 17:07:57 +0530 Subject: [PATCH 06/10] fix: clear company field in single docs, delete other linked docs (cherry picked from commit 6cd653b8476bb1552159cccfdd80fb8c6c75a872) --- hrms/hooks.py | 2 +- hrms/overrides/company.py | 61 ++++++++++++++++++++++++++++++--------- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/hrms/hooks.py b/hrms/hooks.py index 5d102cc0b3..c9c54d1b4b 100644 --- a/hrms/hooks.py +++ b/hrms/hooks.py @@ -168,7 +168,7 @@ "hrms.overrides.company.make_company_fixtures", "hrms.overrides.company.set_default_hr_accounts", ], - "on_trash": "hrms.overrides.company.clear_company_field_in_linked_docs", + "on_trash": "hrms.overrides.company.handle_linked_docs", }, "Holiday List": { "on_update": "hrms.utils.holiday_list.invalidate_cache", diff --git a/hrms/overrides/company.py b/hrms/overrides/company.py index 943e648b66..2636d51f71 100644 --- a/hrms/overrides/company.py +++ b/hrms/overrides/company.py @@ -134,20 +134,53 @@ def validate_default_accounts(doc, method=None): ) -def clear_company_field_in_linked_docs(doc, method=None): +def handle_linked_docs(doc, method=None): + delete_docs_with_company_field(doc) + clear_company_field_for_single_doctypes(doc) + + +def delete_docs_with_company_field(doc, method=None): + """ + Deletes records from linked doctypes where the 'company' field matches the company's name + """ company_data_to_be_ignored = frappe.get_hooks("company_data_to_be_ignored") or [] for doctype in company_data_to_be_ignored: - # get field in the doctype linked to Company - company_field = frappe.db.get_value( - "DocField", - {"parent": doctype, "fieldtype": "Link", "options": "Company"}, - "fieldname", + records_to_delete = frappe.get_all(doctype, filters={"company": doc.name}, pluck="name") + if records_to_delete: + frappe.db.delete(doctype, {"name": ["in", records_to_delete]}) + + +def clear_company_field_for_single_doctypes(doc): + """ + Clears the 'company' value in Single doctypes where applicable + """ + single_docs = get_single_doctypes_with_company_field() + singles = frappe.qb.DocType("Singles") + ( + frappe.qb.update(singles) + .set(singles.value, "") + .where(singles.doctype.isin(single_docs)) + .where(singles.field == "company") + .where(singles.value == doc.name) + ).run() + + +def get_single_doctypes_with_company_field(): + DocType = frappe.qb.DocType("DocType") + DocField = frappe.qb.DocType("DocField") + + return ( + frappe.qb.from_(DocField) + .select(DocField.parent) + .where( + (DocField.fieldtype == "Link") + & (DocField.options == "Company") + & ( + DocField.parent.isin( + frappe.qb.from_(DocType) + .select(DocType.name) + .where((DocType.issingle == 1) & (DocType.module.isin(["HR", "Payroll"]))) + ) + ) ) - - if company_field: - doctype_table = frappe.qb.DocType(doctype) - ( - frappe.qb.update(doctype_table) - .set(doctype_table[company_field], "") - .where(doctype_table[company_field] == doc.name) - ).run() + ).run(pluck=True) From 650c05b2905e26295645e111aae09848485e81f1 Mon Sep 17 00:00:00 2001 From: Aysha Date: Wed, 22 Jan 2025 16:04:47 +0530 Subject: [PATCH 07/10] fix: allow setting payroll frequency for timesheet based payroll entry, calculate salary slip dates if payroll frequency is set not if its not a timesheet based salary slip (cherry picked from commit 8abf1c4ee8eb41236fc2a301a5829432855543cf) # Conflicts: # hrms/payroll/doctype/payroll_entry/payroll_entry.json --- hrms/payroll/doctype/payroll_entry/payroll_entry.json | 5 ++++- hrms/payroll/doctype/salary_slip/salary_slip.js | 5 ----- hrms/payroll/doctype/salary_slip/salary_slip.py | 6 +++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/hrms/payroll/doctype/payroll_entry/payroll_entry.json b/hrms/payroll/doctype/payroll_entry/payroll_entry.json index c9c6cced2b..196a34df91 100644 --- a/hrms/payroll/doctype/payroll_entry/payroll_entry.json +++ b/hrms/payroll/doctype/payroll_entry/payroll_entry.json @@ -62,7 +62,6 @@ "reqd": 1 }, { - "depends_on": "eval:doc.salary_slip_based_on_timesheet == 0", "fieldname": "payroll_frequency", "fieldtype": "Select", "label": "Payroll Frequency", @@ -336,7 +335,11 @@ "icon": "fa fa-cog", "is_submittable": 1, "links": [], +<<<<<<< HEAD "modified": "2023-10-10 14:21:24.517349", +======= + "modified": "2025-01-22 15:27:16.652848", +>>>>>>> 8abf1c4e (fix: allow setting payroll frequency for timesheet based payroll entry, calculate salary slip dates if payroll frequency is set not if its not a timesheet based salary slip) "modified_by": "Administrator", "module": "Payroll", "name": "Payroll Entry", diff --git a/hrms/payroll/doctype/salary_slip/salary_slip.js b/hrms/payroll/doctype/salary_slip/salary_slip.js index e6fd498d29..2c9a550ff6 100644 --- a/hrms/payroll/doctype/salary_slip/salary_slip.js +++ b/hrms/payroll/doctype/salary_slip/salary_slip.js @@ -251,11 +251,6 @@ frappe.ui.form.on("Salary Slip", { ["hourly_wages", "timesheets"], cint(frm.doc.salary_slip_based_on_timesheet) === 1, ); - - frm.toggle_display( - ["payment_days", "total_working_days", "leave_without_pay"], - frm.doc.payroll_frequency != "", - ); }, get_emp_and_working_day_details: function (frm) { diff --git a/hrms/payroll/doctype/salary_slip/salary_slip.py b/hrms/payroll/doctype/salary_slip/salary_slip.py index b07c906aba..3d2aa1e7db 100644 --- a/hrms/payroll/doctype/salary_slip/salary_slip.py +++ b/hrms/payroll/doctype/salary_slip/salary_slip.py @@ -141,7 +141,7 @@ def validate(self): self.validate_dates() self.check_existing() - if not self.salary_slip_based_on_timesheet: + if self.payroll_frequency: self.get_date_details() if not (len(self.get("earnings")) or len(self.get("deductions"))): @@ -321,7 +321,7 @@ def get_emp_and_working_day_details(self): self.set("earnings", []) self.set("deductions", []) - if not self.salary_slip_based_on_timesheet: + if self.payroll_frequency: self.get_date_details() self.validate_dates() @@ -1913,7 +1913,7 @@ def set_status(self, status=None): def process_salary_structure(self, for_preview=0): """Calculate salary after salary structure details have been updated""" - if not self.salary_slip_based_on_timesheet: + if self.payroll_frequency: self.get_date_details() self.pull_emp_details() self.get_working_days_details(for_preview=for_preview) From 489b8dfefd3f0ce289d60f49f2b8b5812d0024f4 Mon Sep 17 00:00:00 2001 From: Aysha Date: Wed, 22 Jan 2025 16:52:19 +0530 Subject: [PATCH 08/10] fix: set payment frequency in payroll entry for timesheet based salary slips (cherry picked from commit 722696131cafff12a423621682cfc59090a6def7) --- hrms/payroll/doctype/payroll_entry/payroll_entry.js | 3 +-- hrms/payroll/doctype/salary_structure/salary_structure.js | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/hrms/payroll/doctype/payroll_entry/payroll_entry.js b/hrms/payroll/doctype/payroll_entry/payroll_entry.js index 1f59a6a40e..0947d034a0 100644 --- a/hrms/payroll/doctype/payroll_entry/payroll_entry.js +++ b/hrms/payroll/doctype/payroll_entry/payroll_entry.js @@ -334,11 +334,10 @@ frappe.ui.form.on("Payroll Entry", { salary_slip_based_on_timesheet: function (frm) { frm.toggle_reqd(["payroll_frequency"], !frm.doc.salary_slip_based_on_timesheet); - hrms.set_payroll_frequency_to_null(frm); }, set_start_end_dates: function (frm) { - if (!frm.doc.salary_slip_based_on_timesheet) { + if (frm.doc.payroll_frequency) { frappe.call({ method: "hrms.payroll.doctype.payroll_entry.payroll_entry.get_start_end_dates", args: { diff --git a/hrms/payroll/doctype/salary_structure/salary_structure.js b/hrms/payroll/doctype/salary_structure/salary_structure.js index ddc1c46f28..dc10876cc3 100755 --- a/hrms/payroll/doctype/salary_structure/salary_structure.js +++ b/hrms/payroll/doctype/salary_structure/salary_structure.js @@ -175,7 +175,6 @@ frappe.ui.form.on("Salary Structure", { salary_slip_based_on_timesheet: function (frm) { frm.trigger("toggle_fields"); - hrms.set_payroll_frequency_to_null(frm); }, preview_salary_slip: function (frm) { From 490e580b3a3126f68fa0fde36c0fbaea82843e0c Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 24 Jan 2025 12:29:09 +0530 Subject: [PATCH 09/10] fix: HRA calculation if there are multiple salary structure assignments for the current payroll period (backport #2691) (#2694) Co-authored-by: Nabin Hait --- hrms/hr/utils.py | 12 ++++++++---- .../test_employee_tax_exemption_declaration.py | 4 +++- hrms/regional/india/setup.py | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/hrms/hr/utils.py b/hrms/hr/utils.py index af01d95111..c3fae61e33 100644 --- a/hrms/hr/utils.py +++ b/hrms/hr/utils.py @@ -542,17 +542,21 @@ def get_salary_assignments(employee, payroll_period): order_by="from_date", ) - if not assignments: + if not assignments or getdate(assignments[0].from_date) > getdate(start_date): # if no assignments found for the given period - # get the last one assigned before the period that is still active - assignments = frappe.get_all( + # or the latest assignment hast started in the middle of the period + # get the last one assigned before the period start date + past_assignment = frappe.get_all( "Salary Structure Assignment", - filters={"employee": employee, "docstatus": 1, "from_date": ["<=", start_date]}, + filters={"employee": employee, "docstatus": 1, "from_date": ["<", start_date]}, fields=["*"], order_by="from_date desc", limit=1, ) + if past_assignment: + assignments = past_assignment + assignments + return assignments diff --git a/hrms/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py b/hrms/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py index ac6175ae4d..e0e7036b73 100644 --- a/hrms/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py +++ b/hrms/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py @@ -349,6 +349,7 @@ def test_india_hra_exemption_with_multiple_assignments(self): ) # salary structure with base 50000, HRA 3000 + # effective from 3 months before payroll period make_salary_structure( "Monthly Structure for HRA Exemption 1", "Monthly", @@ -356,7 +357,7 @@ def test_india_hra_exemption_with_multiple_assignments(self): company="_Test Company", currency="INR", payroll_period=payroll_period.name, - from_date=payroll_period.start_date, + from_date=add_months(payroll_period.start_date, -3), ) # salary structure with base 70000, HRA = base * 0.2 = 14000 @@ -379,6 +380,7 @@ def test_india_hra_exemption_with_multiple_assignments(self): salary_structure.submit() + # effective from 6 months after payroll period create_salary_structure_assignment( employee, salary_structure.name, diff --git a/hrms/regional/india/setup.py b/hrms/regional/india/setup.py index e2ebbb55cc..f7674634ac 100644 --- a/hrms/regional/india/setup.py +++ b/hrms/regional/india/setup.py @@ -84,7 +84,7 @@ def get_custom_fields(): "fieldname": "hra_section", "label": "HRA Settings", "fieldtype": "Section Break", - "insert_after": "asset_received_but_not_billed", + "insert_after": "default_payroll_payable_account", "collapsible": 1, }, { From e2b36c773c8573f2049fefa6e84432439700d79e Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Fri, 24 Jan 2025 12:34:31 +0530 Subject: [PATCH 10/10] chore: fix conflicts --- hrms/payroll/doctype/payroll_entry/payroll_entry.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hrms/payroll/doctype/payroll_entry/payroll_entry.json b/hrms/payroll/doctype/payroll_entry/payroll_entry.json index 196a34df91..724ccb540c 100644 --- a/hrms/payroll/doctype/payroll_entry/payroll_entry.json +++ b/hrms/payroll/doctype/payroll_entry/payroll_entry.json @@ -335,11 +335,7 @@ "icon": "fa fa-cog", "is_submittable": 1, "links": [], -<<<<<<< HEAD - "modified": "2023-10-10 14:21:24.517349", -======= "modified": "2025-01-22 15:27:16.652848", ->>>>>>> 8abf1c4e (fix: allow setting payroll frequency for timesheet based payroll entry, calculate salary slip dates if payroll frequency is set not if its not a timesheet based salary slip) "modified_by": "Administrator", "module": "Payroll", "name": "Payroll Entry",