Skip to content

Commit 356c6db

Browse files
authored
Merge pull request #2754 from frappe/version-14-hotfix
chore: release v14
2 parents e081f62 + e76856d commit 356c6db

File tree

9 files changed

+121
-50
lines changed

9 files changed

+121
-50
lines changed

.github/workflows/ci.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ jobs:
124124
CAPTURE_COVERAGE: ${{ github.event_name != 'pull_request' }}
125125

126126
- name: Upload coverage data
127-
uses: actions/upload-artifact@v3
127+
uses: actions/upload-artifact@v4
128128
if: github.event_name != 'pull_request'
129129
with:
130130
name: coverage-${{ matrix.container }}
@@ -140,7 +140,7 @@ jobs:
140140
uses: actions/checkout@v2
141141

142142
- name: Download artifacts
143-
uses: actions/download-artifact@v3
143+
uses: actions/download-artifact@v4
144144

145145
- name: Upload coverage data
146146
uses: codecov/codecov-action@v2

hrms/hr/doctype/attendance/attendance.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@
122122
"label": "Attendance Date",
123123
"oldfieldname": "attendance_date",
124124
"oldfieldtype": "Date",
125-
"reqd": 1
125+
"reqd": 1,
126+
"search_index": 1
126127
},
127128
{
128129
"fetch_from": "employee.company",
@@ -207,7 +208,7 @@
207208
"idx": 1,
208209
"is_submittable": 1,
209210
"links": [],
210-
"modified": "2024-04-05 20:55:02.905452",
211+
"modified": "2025-01-31 11:45:54.846562",
211212
"modified_by": "Administrator",
212213
"module": "HR",
213214
"name": "Attendance",

hrms/hr/doctype/attendance/attendance.py

+27-31
Original file line numberDiff line numberDiff line change
@@ -228,42 +228,38 @@ def unlink_attendance_from_checkins(self):
228228

229229
@frappe.whitelist()
230230
def get_events(start, end, filters=None):
231-
from frappe.desk.reportview import get_filters_cond
232-
233-
events = []
234-
235231
employee = frappe.db.get_value("Employee", {"user_id": frappe.session.user})
236-
237232
if not employee:
238-
return events
239-
240-
conditions = get_filters_cond("Attendance", filters, [])
241-
add_attendance(events, start, end, conditions=conditions)
242-
add_holidays(events, start, end, employee)
243-
return events
244-
233+
return []
234+
if isinstance(filters, str):
235+
import json
245236

246-
def add_attendance(events, start, end, conditions=None):
247-
query = """select name, attendance_date, status, employee_name
248-
from `tabAttendance` where
249-
attendance_date between %(from_date)s and %(to_date)s
250-
and docstatus < 2"""
237+
filters = json.loads(filters)
238+
if not filters:
239+
filters = []
240+
filters.append(["attendance_date", "between", [get_datetime(start).date(), get_datetime(end).date()]])
241+
attendance_records = add_attendance(filters)
242+
add_holidays(attendance_records, start, end, employee)
243+
return attendance_records
251244

252-
if conditions:
253-
query += conditions
254245

255-
for d in frappe.db.sql(query, {"from_date": start, "to_date": end}, as_dict=True):
256-
e = {
257-
"name": d.name,
258-
"doctype": "Attendance",
259-
"start": d.attendance_date,
260-
"end": d.attendance_date,
261-
"title": f"{d.employee_name}: {cstr(d.status)}",
262-
"status": d.status,
263-
"docstatus": d.docstatus,
264-
}
265-
if e not in events:
266-
events.append(e)
246+
def add_attendance(filters):
247+
attendance = frappe.get_list(
248+
"Attendance",
249+
fields=[
250+
"name",
251+
"'Attendance' as doctype",
252+
"attendance_date as start",
253+
"attendance_date as end",
254+
"employee_name",
255+
"status",
256+
"docstatus",
257+
],
258+
filters=filters,
259+
)
260+
for record in attendance:
261+
record["title"] = f"{record.employee_name} : {record.status}"
262+
return attendance
267263

268264

269265
def add_holidays(events, start, end, employee=None):

hrms/hr/doctype/leave_allocation/test_earned_leaves.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,14 @@ def test_alloc_based_on_joining_date(self):
137137

138138
# assignment created on the last day of the current month
139139
frappe.flags.current_date = get_last_day(getdate())
140-
141-
leave_policy_assignments = make_policy_assignment(self.employee, assignment_based_on="Joining Date")
140+
"""set end date while making assignment based on Joining date because while start date is fetched from
141+
employee master, make_policy_assignment ends up taking current date as end date if not specified which
142+
causes the date of assignment to be later than the end date of leave period"""
143+
start_date = self.employee.date_of_joining
144+
end_date = get_last_day(add_months(self.employee.date_of_joining, 12))
145+
leave_policy_assignments = make_policy_assignment(
146+
self.employee, assignment_based_on="Joining Date", start_date=start_date, end_date=end_date
147+
)
142148
leaves_allocated = get_allocated_leaves(leave_policy_assignments[0])
143149
effective_from = frappe.db.get_value(
144150
"Leave Policy Assignment", leave_policy_assignments[0], "effective_from"
@@ -563,6 +569,7 @@ def make_policy_assignment(
563569
rounding=0.5,
564570
earned_leave_frequency="Monthly",
565571
start_date=None,
572+
end_date=None,
566573
annual_allocation=12,
567574
carry_forward=0,
568575
assignment_based_on="Leave Period",
@@ -582,6 +589,8 @@ def make_policy_assignment(
582589
"leave_policy": leave_policy.name,
583590
"leave_period": leave_period.name,
584591
"carry_forward": carry_forward,
592+
"effective_from": start_date,
593+
"effective_to": end_date,
585594
}
586595

587596
leave_policy_assignments = create_assignment_for_multiple_employees([employee.name], frappe._dict(data))

hrms/hr/doctype/leave_encashment/test_leave_encashment.py

+1
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ def get_encashment_created_after_leave_period(self, employee, is_carry_forward):
236236
"Salary Structure for Encashment",
237237
"Monthly",
238238
employee,
239+
from_date=start_date,
239240
other_details={"leave_encashment_amount_per_day": 50},
240241
)
241242

hrms/hr/doctype/leave_policy_assignment/leave_policy_assignment.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ def set_dates(self):
3838
)
3939
elif self.assignment_based_on == "Joining Date":
4040
self.effective_from = frappe.db.get_value("Employee", self.employee, "date_of_joining")
41+
if not self.effective_to:
42+
self.effective_to = get_last_day(add_months(self.effective_from, 12))
4143

4244
def validate_policy_assignment_overlap(self):
4345
leave_policy_assignments = frappe.get_all(
@@ -132,12 +134,13 @@ def get_new_leaves(self, annual_allocation, leave_details, date_of_joining):
132134
from frappe.model.meta import get_field_precision
133135

134136
precision = get_field_precision(frappe.get_meta("Leave Allocation").get_field("new_leaves_allocated"))
135-
137+
current_date = getdate(frappe.flags.current_date) or getdate()
136138
# Earned Leaves and Compensatory Leaves are allocated by scheduler, initially allocate 0
137139
if leave_details.is_compensatory:
138140
new_leaves_allocated = 0
141+
# if earned leave is being allcated after the effective period, then let them be calculated pro-rata
139142

140-
elif leave_details.is_earned_leave:
143+
elif leave_details.is_earned_leave and current_date < getdate(self.effective_to):
141144
new_leaves_allocated = self.get_leaves_for_passed_months(
142145
annual_allocation, leave_details, date_of_joining
143146
)
@@ -162,7 +165,7 @@ def get_leaves_for_passed_months(self, annual_allocation, leave_details, date_of
162165
from hrms.hr.utils import get_monthly_earned_leave
163166

164167
def _get_current_and_from_date():
165-
current_date = frappe.flags.current_date or getdate()
168+
current_date = getdate(frappe.flags.current_date) or getdate()
166169
if current_date > getdate(self.effective_to):
167170
current_date = getdate(self.effective_to)
168171

hrms/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py

+59-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import frappe
55
from frappe.tests.utils import FrappeTestCase
6-
from frappe.utils import add_months, get_first_day, get_year_ending, getdate
6+
from frappe.utils import add_days, add_months, get_first_day, get_year_ending, get_year_start, getdate
77

88
from hrms.hr.doctype.leave_application.test_leave_application import get_employee, get_leave_period
99
from hrms.hr.doctype.leave_period.test_leave_period import create_leave_period
@@ -33,6 +33,9 @@ def setUp(self):
3333
self.original_doj = employee.date_of_joining
3434
self.employee = employee
3535

36+
def tearDown(self):
37+
frappe.db.set_value("Employee", self.employee.name, "date_of_joining", self.original_doj)
38+
3639
def test_grant_leaves(self):
3740
leave_period = get_leave_period()
3841
leave_policy = create_leave_policy(annual_allocation=10)
@@ -208,5 +211,58 @@ def test_pro_rated_leave_allocation_for_custom_date_range(self):
208211

209212
self.assertGreater(new_leaves_allocated, 0)
210213

211-
def tearDown(self):
212-
frappe.db.set_value("Employee", self.employee.name, "date_of_joining", self.original_doj)
214+
def test_earned_leave_allocation_if_leave_policy_assignment_submitted_after_period(self):
215+
year_start_date = get_year_start(getdate())
216+
year_end_date = get_year_ending(getdate())
217+
leave_period = create_leave_period(year_start_date, year_end_date)
218+
219+
# assignment 10 days after the leave period
220+
frappe.flags.current_date = add_days(year_end_date, 10)
221+
leave_type = create_leave_type(
222+
leave_type_name="_Test Earned Leave", is_earned_leave=True, allocate_on_day="Last Day"
223+
)
224+
annual_earned_leaves = 10
225+
leave_policy = create_leave_policy(leave_type=leave_type, annual_allocation=annual_earned_leaves)
226+
leave_policy.submit()
227+
228+
data = {
229+
"assignment_based_on": "Leave Period",
230+
"leave_policy": leave_policy.name,
231+
"leave_period": leave_period.name,
232+
}
233+
assignment = create_assignment(self.employee.name, frappe._dict(data))
234+
assignment.submit()
235+
236+
earned_leave_allocation = frappe.get_value(
237+
"Leave Allocation", {"leave_policy_assignment": assignment.name}, "new_leaves_allocated"
238+
)
239+
self.assertEqual(earned_leave_allocation, annual_earned_leaves)
240+
241+
def test_earned_leave_allocation_for_leave_period_spanning_two_years(self):
242+
first_year_start_date = get_year_start(getdate())
243+
second_year_end_date = get_year_ending(add_months(first_year_start_date, 12))
244+
leave_period = create_leave_period(first_year_start_date, second_year_end_date)
245+
246+
# assignment during mid second year
247+
frappe.flags.current_date = add_months(second_year_end_date, -6)
248+
leave_type = create_leave_type(
249+
leave_type_name="_Test Earned Leave", is_earned_leave=True, allocate_on_day="Last Day"
250+
)
251+
annual_earned_leaves = 24
252+
leave_policy = create_leave_policy(leave_type=leave_type, annual_allocation=annual_earned_leaves)
253+
leave_policy.submit()
254+
255+
data = {
256+
"assignment_based_on": "Leave Period",
257+
"leave_policy": leave_policy.name,
258+
"leave_period": leave_period.name,
259+
}
260+
assignment = create_assignment(self.employee.name, frappe._dict(data))
261+
assignment.submit()
262+
263+
earned_leave_allocation = frappe.get_value(
264+
"Leave Allocation", {"leave_policy_assignment": assignment.name}, "new_leaves_allocated"
265+
)
266+
# months passed (18) are calculated correctly but total allocation of 36 exceeds 24 hence 24
267+
# this upper cap is intentional, without that 36 leaves would be allocated correctly
268+
self.assertEqual(earned_leave_allocation, 24)

hrms/payroll/doctype/salary_slip/salary_slip.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -865,10 +865,14 @@ def compute_income_tax_breakup(self):
865865

866866
if hasattr(self, "total_structured_tax_amount") and hasattr(self, "current_structured_tax_amount"):
867867
self.future_income_tax_deductions = (
868-
self.total_structured_tax_amount - self.income_tax_deducted_till_date
868+
self.total_structured_tax_amount
869+
+ self.get("full_tax_on_additional_earnings", 0)
870+
- self.income_tax_deducted_till_date
869871
)
870872

871-
self.current_month_income_tax = self.current_structured_tax_amount
873+
self.current_month_income_tax = self.current_structured_tax_amount + self.get(
874+
"full_tax_on_additional_earnings", 0
875+
)
872876

873877
# non included current_month_income_tax separately as its already considered
874878
# while calculating income_tax_deducted_till_date
@@ -882,7 +886,6 @@ def compute_ctc(self):
882886
+ self.current_structured_taxable_earnings_before_exemption
883887
+ self.future_structured_taxable_earnings_before_exemption
884888
+ self.current_additional_earnings
885-
+ self.other_incomes
886889
+ self.unclaimed_taxable_benefits
887890
+ self.non_taxable_earnings
888891
)

hrms/payroll/doctype/salary_slip/test_salary_slip.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -1270,7 +1270,9 @@ def test_statistical_component_based_on_payment_days(self):
12701270
precision = entry.precision("amount")
12711271
break
12721272

1273-
self.assertEqual(amount, flt((1000 * ss.payment_days / ss.total_working_days) * 0.5, precision))
1273+
self.assertEqual(
1274+
amount, flt(flt((1000 * ss.payment_days / ss.total_working_days), precision) * 0.5, precision)
1275+
)
12741276

12751277
def make_activity_for_employee(self):
12761278
activity_type = frappe.get_doc("Activity Type", "_Test Activity Type")
@@ -1416,14 +1418,14 @@ def test_income_tax_breakup_fields(self):
14161418

14171419
monthly_tax_amount = 11403.6
14181420

1419-
self.assertEqual(salary_slip.ctc, 1226000.0)
1421+
self.assertEqual(salary_slip.ctc, 1216000.0)
14201422
self.assertEqual(salary_slip.income_from_other_sources, 10000.0)
14211423
self.assertEqual(salary_slip.non_taxable_earnings, 10000.0)
1422-
self.assertEqual(salary_slip.total_earnings, 1236000.0)
1424+
self.assertEqual(salary_slip.total_earnings, 1226000.0)
14231425
self.assertEqual(salary_slip.standard_tax_exemption_amount, 50000.0)
14241426
self.assertEqual(salary_slip.tax_exemption_declaration, 100000.0)
14251427
self.assertEqual(salary_slip.deductions_before_tax_calculation, 2400.0)
1426-
self.assertEqual(salary_slip.annual_taxable_amount, 1073600.0)
1428+
self.assertEqual(salary_slip.annual_taxable_amount, 1063600.0)
14271429
self.assertEqual(flt(salary_slip.income_tax_deducted_till_date, 2), monthly_tax_amount)
14281430
self.assertEqual(flt(salary_slip.current_month_income_tax, 2), monthly_tax_amount)
14291431
self.assertEqual(flt(salary_slip.future_income_tax_deductions, 2), 125439.65)

0 commit comments

Comments
 (0)