feat(fusion_clock): bi-weekly attendance filter — pay-period filters + picker
Reuse the existing Pay Period setting (Frequency + Anchor) as the single source of truth via a shared pure helper (models/pay_period.py); fusion.clock.report delegates to it. Add Current/Previous/Next Pay Period filters to the attendance search view (search-method computed booleans on hr.attendance), a Bi-Weekly Period picker wizard (pick start -> auto +2 weeks, editable; Apply opens the filtered list) reachable from an Attendance menu item and a dashboard tile. Window follows the configured frequency; TZ-correct via local-day boundaries. Bump 3.14.4 -> 3.15.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -455,53 +455,13 @@ class FusionClockReport(models.Model):
|
||||
|
||||
@api.model
|
||||
def _calculate_current_period(self, schedule_type, period_start_str, reference_date):
|
||||
"""Calculate the period start/end dates based on schedule type."""
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import datetime
|
||||
"""Calculate the period start/end dates based on schedule type.
|
||||
|
||||
if period_start_str:
|
||||
try:
|
||||
anchor = fields.Date.from_string(period_start_str)
|
||||
except Exception:
|
||||
anchor = reference_date.replace(day=1)
|
||||
else:
|
||||
anchor = reference_date.replace(day=1)
|
||||
|
||||
if schedule_type == 'weekly':
|
||||
days_diff = (reference_date - anchor).days
|
||||
period_num = days_diff // 7
|
||||
period_start = anchor + timedelta(days=period_num * 7)
|
||||
period_end = period_start + timedelta(days=6)
|
||||
|
||||
elif schedule_type == 'biweekly':
|
||||
days_diff = (reference_date - anchor).days
|
||||
period_num = days_diff // 14
|
||||
period_start = anchor + timedelta(days=period_num * 14)
|
||||
period_end = period_start + timedelta(days=13)
|
||||
|
||||
elif schedule_type == 'semi_monthly':
|
||||
if reference_date.day <= 15:
|
||||
period_start = reference_date.replace(day=1)
|
||||
period_end = reference_date.replace(day=15)
|
||||
else:
|
||||
period_start = reference_date.replace(day=16)
|
||||
# Last day of month
|
||||
next_month = reference_date.replace(day=28) + timedelta(days=4)
|
||||
period_end = next_month - timedelta(days=next_month.day)
|
||||
|
||||
elif schedule_type == 'monthly':
|
||||
period_start = reference_date.replace(day=1)
|
||||
next_month = reference_date.replace(day=28) + timedelta(days=4)
|
||||
period_end = next_month - timedelta(days=next_month.day)
|
||||
|
||||
else:
|
||||
# Default biweekly
|
||||
days_diff = (reference_date - anchor).days
|
||||
period_num = days_diff // 14
|
||||
period_start = anchor + timedelta(days=period_num * 14)
|
||||
period_end = period_start + timedelta(days=13)
|
||||
|
||||
return period_start, period_end
|
||||
Delegates to the shared pure helper so reports, the attendance period
|
||||
filters and the Bi-Weekly Period picker all use one implementation.
|
||||
"""
|
||||
from .pay_period import compute_pay_period
|
||||
return compute_pay_period(schedule_type, period_start_str, reference_date)
|
||||
|
||||
@api.model
|
||||
def action_generate_historical_reports(self):
|
||||
|
||||
Reference in New Issue
Block a user