Skip to content

Commit cfb105e

Browse files
authored
Merge pull request #338 from frappe/version-14-hotfix
2 parents c1f7072 + f2246ef commit cfb105e

8 files changed

Lines changed: 131 additions & 56 deletions

File tree

hrms/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "14.0.2"
1+
__version__ = "14.0.3"

hrms/hr/doctype/leave_application/leave_application.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,9 @@ def get_leave_balance_on(
825825
allocation = allocation_records.get(leave_type, frappe._dict())
826826

827827
end_date = allocation.to_date if cint(consider_all_leaves_in_the_allocation_period) else date
828-
cf_expiry = get_allocation_expiry_for_cf_leaves(employee, leave_type, to_date, date)
828+
cf_expiry = get_allocation_expiry_for_cf_leaves(
829+
employee, leave_type, to_date, allocation.from_date
830+
)
829831

830832
leaves_taken = get_leaves_for_period(employee, leave_type, allocation.from_date, end_date)
831833

@@ -840,6 +842,7 @@ def get_leave_balance_on(
840842
def get_leave_allocation_records(employee, date, leave_type=None):
841843
"""Returns the total allocated leaves and carry forwarded leaves based on ledger entries"""
842844
Ledger = frappe.qb.DocType("Leave Ledger Entry")
845+
LeaveAllocation = frappe.qb.DocType("Leave Allocation")
843846

844847
cf_leave_case = (
845848
frappe.qb.terms.Case().when(Ledger.is_carry_forward == "1", Ledger.leaves).else_(0)
@@ -853,6 +856,8 @@ def get_leave_allocation_records(employee, date, leave_type=None):
853856

854857
query = (
855858
frappe.qb.from_(Ledger)
859+
.inner_join(LeaveAllocation)
860+
.on(Ledger.transaction_name == LeaveAllocation.name)
856861
.select(
857862
sum_cf_leaves,
858863
sum_new_leaves,
@@ -862,12 +867,21 @@ def get_leave_allocation_records(employee, date, leave_type=None):
862867
)
863868
.where(
864869
(Ledger.from_date <= date)
865-
& (Ledger.to_date >= date)
866870
& (Ledger.docstatus == 1)
867871
& (Ledger.transaction_type == "Leave Allocation")
868872
& (Ledger.employee == employee)
869873
& (Ledger.is_expired == 0)
870874
& (Ledger.is_lwp == 0)
875+
& (
876+
# newly allocated leave's end date is same as the leave allocation's to date
877+
((Ledger.is_carry_forward == 0) & (Ledger.to_date >= date))
878+
# carry forwarded leave's end date won't be same as the leave allocation's to date
879+
# it's between the leave allocation's from and to date
880+
| (
881+
(Ledger.is_carry_forward == 1)
882+
& (Ledger.to_date.between(LeaveAllocation.from_date, LeaveAllocation.to_date))
883+
)
884+
)
871885
)
872886
)
873887

@@ -933,8 +947,12 @@ def _get_remaining_leaves(remaining_leaves, end_date):
933947

934948
# balance for carry forwarded leaves
935949
if cf_expiry and allocation.unused_leaves:
936-
cf_leaves = flt(allocation.unused_leaves) + flt(leaves_taken)
937-
remaining_cf_leaves = _get_remaining_leaves(cf_leaves, cf_expiry)
950+
if getdate(date) > getdate(cf_expiry):
951+
# carry forwarded leave expiry date passed
952+
cf_leaves = remaining_cf_leaves = 0
953+
else:
954+
cf_leaves = flt(allocation.unused_leaves) + flt(leaves_taken)
955+
remaining_cf_leaves = _get_remaining_leaves(cf_leaves, cf_expiry)
938956

939957
leave_balance = flt(allocation.new_leaves_allocated) + flt(cf_leaves)
940958
leave_balance_for_consumption = flt(allocation.new_leaves_allocated) + flt(remaining_cf_leaves)

hrms/hr/doctype/leave_application/test_leave_application.py

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -699,8 +699,7 @@ def test_leave_balance_near_allocaton_expiry(self):
699699
leave_type_name="_Test_CF_leave_expiry",
700700
is_carry_forward=1,
701701
expire_carry_forwarded_leaves_after_days=90,
702-
)
703-
leave_type.insert()
702+
).insert()
704703

705704
create_carry_forwarded_allocation(employee, leave_type)
706705
details = get_leave_balance_on(
@@ -924,17 +923,51 @@ def test_get_leave_details_for_dashboard(self):
924923
self.assertEqual(leave_allocation["remaining_leaves"], 26)
925924

926925
@set_holiday_list("Salary Slip Test Holiday List", "_Test Company")
927-
def test_get_leave_allocation_records(self):
926+
def test_leave_details_with_expired_cf_leaves(self):
928927
employee = get_employee()
929928
leave_type = create_leave_type(
930929
leave_type_name="_Test_CF_leave_expiry",
931930
is_carry_forward=1,
932931
expire_carry_forwarded_leaves_after_days=90,
932+
).insert()
933+
934+
leave_alloc = create_carry_forwarded_allocation(employee, leave_type)
935+
cf_expiry = frappe.db.get_value(
936+
"Leave Ledger Entry", {"transaction_name": leave_alloc.name, "is_carry_forward": 1}, "to_date"
933937
)
934-
leave_type.insert()
938+
939+
# all leaves available before cf leave expiry
940+
leave_details = get_leave_details(employee.name, add_days(cf_expiry, -1))
941+
self.assertEqual(leave_details["leave_allocation"][leave_type.name]["remaining_leaves"], 30.0)
942+
943+
# cf leaves expired
944+
leave_details = get_leave_details(employee.name, add_days(cf_expiry, 1))
945+
expected_data = {
946+
"total_leaves": 30.0,
947+
"expired_leaves": 15.0,
948+
"leaves_taken": 0.0,
949+
"leaves_pending_approval": 0.0,
950+
"remaining_leaves": 15.0,
951+
}
952+
self.assertEqual(leave_details["leave_allocation"][leave_type.name], expected_data)
953+
954+
@set_holiday_list("Salary Slip Test Holiday List", "_Test Company")
955+
def test_get_leave_allocation_records(self):
956+
"""Tests if total leaves allocated before and after carry forwarded leave expiry is same"""
957+
employee = get_employee()
958+
leave_type = create_leave_type(
959+
leave_type_name="_Test_CF_leave_expiry",
960+
is_carry_forward=1,
961+
expire_carry_forwarded_leaves_after_days=90,
962+
).insert()
935963

936964
leave_alloc = create_carry_forwarded_allocation(employee, leave_type)
937-
details = get_leave_allocation_records(employee.name, getdate(), leave_type.name)
965+
cf_expiry = frappe.db.get_value(
966+
"Leave Ledger Entry", {"transaction_name": leave_alloc.name, "is_carry_forward": 1}, "to_date"
967+
)
968+
969+
# test total leaves allocated before cf leave expiry
970+
details = get_leave_allocation_records(employee.name, add_days(cf_expiry, -1), leave_type.name)
938971
expected_data = {
939972
"from_date": getdate(leave_alloc.from_date),
940973
"to_date": getdate(leave_alloc.to_date),
@@ -945,6 +978,11 @@ def test_get_leave_allocation_records(self):
945978
}
946979
self.assertEqual(details.get(leave_type.name), expected_data)
947980

981+
# test leaves allocated after carry forwarded leaves expiry, should be same thoroughout allocation period
982+
# cf leaves should show up under expired or taken leaves later
983+
details = get_leave_allocation_records(employee.name, add_days(cf_expiry, 1), leave_type.name)
984+
self.assertEqual(details.get(leave_type.name), expected_data)
985+
948986

949987
def create_carry_forwarded_allocation(employee, leave_type):
950988
# initial leave allocation

hrms/hr/doctype/shift_assignment/shift_assignment.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ def add_assignments(start, end, conditions=None):
176176
"title": cstr(d.employee_name) + ": " + cstr(d.shift_type),
177177
"docstatus": d.docstatus,
178178
"allDay": 0,
179+
"convertToUserTz": 0,
179180
}
180181
if e not in events:
181182
events.append(e)

hrms/hr/doctype/shift_assignment/shift_assignment_calendar.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ frappe.views.calendar["Shift Assignment"] = {
88
"id": "name",
99
"docstatus": 1,
1010
"allDay": "allDay",
11+
"convertToUserTz": "convertToUserTz",
1112
},
1213
get_events_method: "hrms.hr.doctype.shift_assignment.shift_assignment.get_events"
1314
}

hrms/hr/report/employee_leave_balance/employee_leave_balance.js

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,60 @@
22
// License: GNU General Public License v3. See license.txt
33

44
frappe.query_reports["Employee Leave Balance"] = {
5-
"filters": [
5+
filters: [
66
{
7-
"fieldname": "from_date",
8-
"label": __("From Date"),
9-
"fieldtype": "Date",
10-
"reqd": 1,
11-
"default": frappe.defaults.get_default("year_start_date")
7+
fieldname: "from_date",
8+
label: __("From Date"),
9+
fieldtype: "Date",
10+
reqd: 1,
11+
default: frappe.defaults.get_default("year_start_date")
1212
},
1313
{
14-
"fieldname": "to_date",
15-
"label": __("To Date"),
16-
"fieldtype": "Date",
17-
"reqd": 1,
18-
"default": frappe.defaults.get_default("year_end_date")
14+
fieldname: "to_date",
15+
label: __("To Date"),
16+
fieldtype: "Date",
17+
reqd: 1,
18+
default: frappe.defaults.get_default("year_end_date")
1919
},
2020
{
21-
"fieldname": "company",
22-
"label": __("Company"),
23-
"fieldtype": "Link",
24-
"options": "Company",
25-
"reqd": 1,
26-
"default": frappe.defaults.get_user_default("Company")
21+
label: __("Company"),
22+
fieldname: "company",
23+
fieldtype: "Link",
24+
options: "Company",
25+
reqd: 1,
26+
default: frappe.defaults.get_user_default("Company")
2727
},
2828
{
29-
"fieldname": "department",
30-
"label": __("Department"),
31-
"fieldtype": "Link",
32-
"options": "Department",
29+
fieldname: "department",
30+
label: __("Department"),
31+
fieldtype: "Link",
32+
options: "Department",
3333
},
3434
{
35-
"fieldname": "employee",
36-
"label": __("Employee"),
37-
"fieldtype": "Link",
38-
"options": "Employee",
35+
fieldname: "employee",
36+
label: __("Employee"),
37+
fieldtype: "Link",
38+
options: "Employee",
3939
},
4040
{
41-
"fieldname": "employee_status",
42-
"label": __("Employee Status"),
43-
"fieldtype": "Select",
44-
"options": [
41+
fieldname: "employee_status",
42+
label: __("Employee Status"),
43+
fieldtype: "Select",
44+
options: [
4545
"",
4646
{ "value": "Active", "label": __("Active") },
4747
{ "value": "Inactive", "label": __("Inactive") },
4848
{ "value": "Suspended", "label": __("Suspended") },
4949
{ "value": "Left", "label": __("Left") },
5050
],
51-
"default": "Active",
51+
default: "Active",
52+
},
53+
{
54+
fieldname: "consolidate_leave_types",
55+
label: __("Consolidate Leave Types"),
56+
fieldtype: "Check",
57+
default: 1,
58+
depends_on: "eval: !doc.employee",
5259
}
5360
],
5461

hrms/hr/report/employee_leave_balance/employee_leave_balance.py

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def execute(filters: Optional[Filters] = None) -> Tuple:
2424

2525
columns = get_columns()
2626
data = get_data(filters)
27-
charts = get_chart_data(data)
27+
charts = get_chart_data(data, filters)
2828
return columns, data, None, charts
2929

3030

@@ -89,7 +89,7 @@ def get_data(filters: Filters) -> List:
8989
conditions = get_conditions(filters)
9090

9191
user = frappe.session.user
92-
department_approver_map = get_department_leave_approver_map(filters.get("department"))
92+
department_approver_map = get_department_leave_approver_map(filters.department)
9393

9494
active_employees = frappe.get_list(
9595
"Employee",
@@ -98,22 +98,26 @@ def get_data(filters: Filters) -> List:
9898
)
9999

100100
precision = cint(frappe.db.get_single_value("System Settings", "float_precision", cache=True))
101+
consolidate_leave_types = len(active_employees) > 1 and filters.consolidate_leave_types
102+
row = None
103+
101104
data = []
102105

103106
for leave_type in leave_types:
104-
if len(active_employees) > 1:
107+
if consolidate_leave_types:
105108
data.append({"leave_type": leave_type})
106109
else:
107110
row = frappe._dict({"leave_type": leave_type})
108111

109112
for employee in active_employees:
110-
111113
leave_approvers = department_approver_map.get(employee.department_name, []).append(
112114
employee.leave_approver
113115
)
114116

115-
if len(active_employees) > 1:
117+
if consolidate_leave_types:
116118
row = frappe._dict()
119+
else:
120+
row = frappe._dict({"leave_type": leave_type})
117121

118122
row.employee = employee.name
119123
row.employee_name = employee.employee_name
@@ -167,17 +171,17 @@ def get_opening_balance(
167171
def get_conditions(filters: Filters) -> Dict:
168172
conditions = {}
169173

170-
if filters.get("employee"):
171-
conditions["name"] = filters.get("employee")
174+
if filters.employee:
175+
conditions["name"] = filters.employee
172176

173-
if filters.get("company"):
174-
conditions["company"] = filters.get("company")
177+
if filters.company:
178+
conditions["company"] = filters.company
175179

176-
if filters.get("department"):
177-
conditions["department"] = filters.get("department")
180+
if filters.department:
181+
conditions["department"] = filters.department
178182

179-
if filters.get("employee_status"):
180-
conditions["status"] = filters.get("employee_status")
183+
if filters.employee_status:
184+
conditions["status"] = filters.employee_status
181185

182186
return conditions
183187

@@ -269,12 +273,15 @@ def get_leave_ledger_entries(
269273
return records
270274

271275

272-
def get_chart_data(data: List) -> Dict:
276+
def get_chart_data(data: List, filters: Filters) -> Dict:
273277
labels = []
274278
datasets = []
275279
employee_data = data
276280

277-
if data and data[0].get("employee_name"):
281+
if not data:
282+
return None
283+
284+
if data and filters.employee:
278285
get_dataset_for_chart(employee_data, datasets, labels)
279286

280287
chart = {

hrms/payroll/doctype/payroll_entry/payroll_entry.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ def make_payment_entry(self):
655655
if statistical_component != 1:
656656
if process_payroll_accounting_entry_based_on_employee:
657657
self.set_employee_based_payroll_payable_entries(
658-
"deduction", salary_slip.employee, sal_detail.amount
658+
"deductions", salary_slip.employee, sal_detail.amount
659659
)
660660

661661
salary_slip_total -= sal_detail.amount
@@ -691,6 +691,9 @@ def create_journal_entry(self, je_payment_amount, user_remark):
691691
if self.employee_based_payroll_payable_entries:
692692
for employee, employee_details in self.employee_based_payroll_payable_entries.items():
693693
je_payment_amount = employee_details["earnings"] - employee_details["deduction"]
694+
je_payment_amount = employee_details.get("earnings") - (
695+
employee_details.get("deductions") or 0
696+
)
694697
exchange_rate, amount = self.get_amount_and_exchange_rate_for_journal_entry(
695698
self.payment_account, je_payment_amount, company_currency, currencies
696699
)

0 commit comments

Comments
 (0)