Files
Odoo-Modules/fusion_clock/views/hr_attendance_views.xml
gsinghpal 3f78f652e7 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>
2026-05-31 11:20:06 -04:00

102 lines
6.0 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Extend Attendance List View -->
<record id="view_hr_attendance_list_fusion_clock" model="ir.ui.view">
<field name="name">hr.attendance.list.fusion.clock</field>
<field name="model">hr.attendance</field>
<field name="inherit_id" ref="hr_attendance.view_attendance_tree"/>
<field name="arch" type="xml">
<xpath expr="//list" position="attributes">
<attribute name="default_order">check_in desc</attribute>
</xpath>
<xpath expr="//field[@name='worked_hours']" position="after">
<field name="x_fclk_net_hours" string="Net Hours" widget="float_time" optional="show"/>
<field name="x_fclk_break_minutes" string="Break (min)" optional="show"/>
<field name="x_fclk_overtime_hours" string="Overtime (h)" widget="float_time" optional="show"
decoration-danger="x_fclk_is_overtime"/>
<field name="x_fclk_location_id" string="Location" optional="show"/>
<field name="x_fclk_clock_source" string="Source" optional="hide"/>
<field name="x_fclk_auto_clocked_out" string="Auto Out" optional="hide"/>
<field name="x_fclk_is_overtime" column_invisible="True"/>
</xpath>
</field>
</record>
<!-- Extend Attendance Form View -->
<record id="view_hr_attendance_form_fusion_clock" model="ir.ui.view">
<field name="name">hr.attendance.form.fusion.clock</field>
<field name="model">hr.attendance</field>
<field name="inherit_id" ref="hr_attendance.hr_attendance_view_form"/>
<field name="arch" type="xml">
<xpath expr="//sheet" position="inside">
<group string="Fusion Clock Details" name="fusion_clock_details">
<group>
<field name="x_fclk_location_id"/>
<field name="x_fclk_clock_source"/>
<field name="x_fclk_break_minutes"/>
<field name="x_fclk_net_hours" widget="float_time"/>
<field name="x_fclk_overtime_hours" widget="float_time"/>
</group>
<group>
<field name="x_fclk_in_distance"/>
<field name="x_fclk_out_distance"/>
<field name="x_fclk_auto_clocked_out"/>
<field name="x_fclk_grace_used"/>
<field name="x_fclk_is_overtime"/>
</group>
</group>
<group string="Verification Photos" name="fusion_clock_photo"
invisible="not x_fclk_check_in_photo and not x_fclk_check_out_photo and not x_fclk_checkin_photo">
<field name="x_fclk_check_in_photo" widget="image" string="Clock-In Photo"
options="{'size': [200, 200]}" invisible="not x_fclk_check_in_photo"/>
<field name="x_fclk_check_out_photo" widget="image" string="Clock-Out Photo"
options="{'size': [200, 200]}" invisible="not x_fclk_check_out_photo"/>
<field name="x_fclk_checkin_photo" widget="image" string="Portal Check-In Photo"
options="{'size': [200, 200]}" invisible="not x_fclk_checkin_photo"/>
</group>
<group string="Penalties" name="fusion_clock_penalties"
invisible="not x_fclk_penalty_ids">
<field name="x_fclk_penalty_ids" nolabel="1" colspan="2">
<list>
<field name="penalty_type"/>
<field name="scheduled_time"/>
<field name="actual_time"/>
<field name="difference_minutes"/>
<field name="penalty_minutes"/>
</list>
</field>
</group>
</xpath>
</field>
</record>
<!-- Extend Attendance Search View -->
<record id="view_hr_attendance_search_fusion_clock" model="ir.ui.view">
<field name="name">hr.attendance.search.fusion.clock</field>
<field name="model">hr.attendance</field>
<field name="inherit_id" ref="hr_attendance.hr_attendance_view_filter"/>
<field name="arch" type="xml">
<xpath expr="//search" position="inside">
<field name="x_fclk_location_id"/>
<separator/>
<filter name="fclk_portal" string="Portal" domain="[('x_fclk_clock_source', 'in', ['portal', 'portal_fab'])]"/>
<filter name="fclk_systray" string="Systray/Backend" domain="[('x_fclk_clock_source', 'in', ['systray', 'backend_fab'])]"/>
<filter name="fclk_kiosk" string="Kiosk" domain="[('x_fclk_clock_source', '=', 'kiosk')]"/>
<filter name="fclk_auto" string="Auto Clock-Out" domain="[('x_fclk_auto_clocked_out', '=', True)]"/>
<separator/>
<filter name="fclk_has_penalty" string="Has Penalty" domain="[('x_fclk_penalty_ids', '!=', False)]"/>
<filter name="fclk_has_overtime" string="Has Overtime" domain="[('x_fclk_is_overtime', '=', True)]"/>
<separator/>
<filter name="fclk_period_current" string="Current Pay Period" domain="[('x_fclk_in_current_period', '=', True)]"/>
<filter name="fclk_period_previous" string="Previous Pay Period" domain="[('x_fclk_in_previous_period', '=', True)]"/>
<filter name="fclk_period_next" string="Next Pay Period" domain="[('x_fclk_in_next_period', '=', True)]"/>
<separator/>
<filter name="group_location" string="Location" context="{'group_by': 'x_fclk_location_id'}"/>
<filter name="group_source" string="Source" context="{'group_by': 'x_fclk_clock_source'}"/>
</xpath>
</field>
</record>
</odoo>