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>
208 lines
12 KiB
XML
208 lines
12 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<templates xml:space="preserve">
|
||
|
||
<t t-name="fusion_clock.Dashboard">
|
||
<div class="o_action fclk-dash">
|
||
<div class="fclk-dash-wrap">
|
||
|
||
<t t-if="state.loading">
|
||
<div class="fclk-dash-empty">
|
||
<i class="fa fa-spinner fa-spin fa-2x"/>
|
||
<p class="mt-2">Loading dashboard…</p>
|
||
</div>
|
||
</t>
|
||
|
||
<t t-if="state.error">
|
||
<div class="fclk-dash-card"><t t-esc="state.error"/></div>
|
||
</t>
|
||
|
||
<t t-if="!state.loading and !state.error">
|
||
<!-- HEADER -->
|
||
<div class="fclk-dash-header">
|
||
<div>
|
||
<div class="fclk-dash-hello"><t t-esc="greeting"/>, <t t-esc="state.personal.employee_name"/> 👋</div>
|
||
<div class="fclk-dash-date"><t t-esc="todayLabel"/></div>
|
||
</div>
|
||
<div class="fclk-dash-headctl">
|
||
<span class="fclk-dash-statusbadge" t-att-class="{'is-out': !state.personal.is_checked_in}">
|
||
<t t-if="state.personal.is_checked_in">● Clocked in</t>
|
||
<t t-else="">○ Not clocked in</t>
|
||
</span>
|
||
<button class="fclk-dash-btn-primary" t-on-click="onOpenClock">Open My Clock</button>
|
||
<button class="fclk-dash-btn-ghost" t-on-click="onRefresh"><i class="fa fa-refresh"/></button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- PERSONAL KPIs -->
|
||
<div class="fclk-kpi-row">
|
||
<div class="fclk-kpi fclk-kpi--today">
|
||
<div class="fclk-kpi-ic">⏱</div>
|
||
<div class="fclk-kpi-val"><t t-esc="state.personal.today_hours"/>h</div>
|
||
<div class="fclk-kpi-lbl">Today</div>
|
||
</div>
|
||
<div class="fclk-kpi fclk-kpi--week">
|
||
<div class="fclk-kpi-ic">📅</div>
|
||
<div class="fclk-kpi-val"><t t-esc="state.personal.week_hours"/>h</div>
|
||
<div class="fclk-kpi-lbl">This Week</div>
|
||
</div>
|
||
<div class="fclk-kpi fclk-kpi--ot">
|
||
<div class="fclk-kpi-ic">⚡</div>
|
||
<div class="fclk-kpi-val"><t t-esc="state.personal.overtime_week"/>h</div>
|
||
<div class="fclk-kpi-lbl">OT This Week</div>
|
||
</div>
|
||
<div class="fclk-kpi fclk-kpi--streak">
|
||
<div class="fclk-kpi-ic">🔥</div>
|
||
<div class="fclk-kpi-val"><t t-esc="state.personal.ontime_streak"/></div>
|
||
<div class="fclk-kpi-lbl">On-time Streak</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- PERSONAL DETAIL -->
|
||
<div class="fclk-dash-2col">
|
||
<div class="fclk-dash-card">
|
||
<h4>Today's Shift</h4>
|
||
<div class="fclk-dash-line">
|
||
<span>Scheduled</span>
|
||
<span class="fclk-dash-muted">
|
||
<t t-if="state.personal.shift.label"><t t-esc="state.personal.shift.label"/> (<t t-esc="state.personal.shift.hours"/>h)</t>
|
||
<t t-else="">Not scheduled today</t>
|
||
</span>
|
||
</div>
|
||
<div class="fclk-dash-line">
|
||
<span>Status</span>
|
||
<span t-att-class="state.personal.is_checked_in ? 'fclk-pin' : 'fclk-dash-muted'"><t t-esc="state.personal.shift.status_note"/></span>
|
||
</div>
|
||
<div class="fclk-dash-line">
|
||
<span>Source</span>
|
||
<span class="fclk-dash-muted"><t t-esc="sourceLabel(state.personal.shift.source)"/></span>
|
||
</div>
|
||
</div>
|
||
<div class="fclk-dash-card">
|
||
<h4>My Recent Activity</h4>
|
||
<t t-if="state.personal.recent_activity.length === 0">
|
||
<div class="fclk-dash-empty">No recent activity</div>
|
||
</t>
|
||
<t t-foreach="state.personal.recent_activity" t-as="a" t-key="a_index">
|
||
<div class="fclk-dash-line">
|
||
<span><t t-esc="fmtDate(a.check_in)"/></span>
|
||
<span class="fclk-dash-muted">
|
||
<t t-esc="a.worked_hours"/>h<t t-if="a.overtime_hours > 0"> · +<t t-esc="a.overtime_hours"/> OT</t>
|
||
</span>
|
||
</div>
|
||
</t>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="fclk-dash-2col">
|
||
<div class="fclk-dash-card">
|
||
<h4>Upcoming Leave</h4>
|
||
<t t-if="state.personal.leaves.length === 0">
|
||
<div class="fclk-dash-empty">No upcoming leave</div>
|
||
</t>
|
||
<t t-foreach="state.personal.leaves" t-as="lv" t-key="lv_index">
|
||
<div class="fclk-dash-line"><span><t t-esc="lv.label"/></span><span class="fclk-dash-muted"><t t-esc="lv.state"/></span></div>
|
||
</t>
|
||
</div>
|
||
<div class="fclk-dash-card">
|
||
<h4>Recent Penalties</h4>
|
||
<t t-if="state.personal.penalties.length === 0">
|
||
<div class="fclk-dash-empty">None this month 🎉</div>
|
||
</t>
|
||
<t t-foreach="state.personal.penalties" t-as="p" t-key="p_index">
|
||
<div class="fclk-dash-line"><span><t t-esc="p.type"/> · <t t-esc="p.date"/></span><span class="fclk-pyel">−<t t-esc="p.minutes"/> min</span></div>
|
||
</t>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- QUICK ACTIONS (kept above the team/org cards so managers reach them without scrolling) -->
|
||
<div class="fclk-dash-card">
|
||
<h4>Quick Actions</h4>
|
||
<div class="fclk-dash-actions">
|
||
<span class="fclk-dash-act" t-on-click="onOpenClock">🕒 Open My Clock</span>
|
||
<span class="fclk-dash-act" t-on-click="onViewTimesheets">📄 My Timesheets</span>
|
||
<t t-if="state.team">
|
||
<span class="fclk-dash-act" t-on-click="onViewAttendances">📋 All Attendances</span>
|
||
<span class="fclk-dash-act" t-on-click="onViewCorrections">📨 Approvals</span>
|
||
<span class="fclk-dash-act" t-on-click="onViewPenalties">⚠ Penalties</span>
|
||
<span class="fclk-dash-act" t-on-click="onViewActivityLogs">🗒 Activity Logs</span>
|
||
<span class="fclk-dash-act" t-on-click="onViewBiweekly">🗓 Bi-Weekly Period</span>
|
||
</t>
|
||
<t t-if="state.role === 'manager'">
|
||
<span class="fclk-dash-act" t-on-click="onViewShiftPlanner">📅 Shift Planner</span>
|
||
<span class="fclk-dash-act" t-on-click="onViewReports">📊 Reports</span>
|
||
</t>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- TEAM / ORG BAND -->
|
||
<t t-if="state.team">
|
||
<div class="fclk-dash-divider"><span>Team / Org</span></div>
|
||
|
||
<div class="fclk-kpi-row">
|
||
<div class="fclk-kpi fclk-kpi--present">
|
||
<div class="fclk-kpi-ic">✅</div>
|
||
<div class="fclk-kpi-val"><t t-esc="state.team.present_count"/></div>
|
||
<div class="fclk-kpi-lbl">Present now</div>
|
||
</div>
|
||
<div class="fclk-kpi fclk-kpi--absent">
|
||
<div class="fclk-kpi-ic">🚫</div>
|
||
<div class="fclk-kpi-val"><t t-esc="state.team.absent_count"/></div>
|
||
<div class="fclk-kpi-lbl">Absent today</div>
|
||
</div>
|
||
<div class="fclk-kpi fclk-kpi--late">
|
||
<div class="fclk-kpi-ic">⏰</div>
|
||
<div class="fclk-kpi-val"><t t-esc="state.team.late_count"/></div>
|
||
<div class="fclk-kpi-lbl">Late today</div>
|
||
</div>
|
||
<div class="fclk-kpi fclk-kpi--pending">
|
||
<div class="fclk-kpi-ic">📨</div>
|
||
<div class="fclk-kpi-val"><t t-esc="state.team.pending_approvals"/></div>
|
||
<div class="fclk-kpi-lbl">Pending approvals</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="fclk-dash-2col">
|
||
<div class="fclk-dash-card">
|
||
<h4>Currently Clocked In <span class="fclk-dash-muted"><t t-esc="state.team.present_count"/> of <t t-esc="state.team.total_employees"/></span></h4>
|
||
<t t-if="state.team.clocked_in.length === 0">
|
||
<div class="fclk-dash-empty">No one is clocked in right now</div>
|
||
</t>
|
||
<t t-foreach="state.team.clocked_in" t-as="emp" t-key="emp_index">
|
||
<div class="fclk-dash-line">
|
||
<span><span class="fclk-dash-av"><t t-esc="initials(emp.employee)"/></span><t t-esc="emp.employee"/>
|
||
<span t-if="emp.late" class="fclk-dash-late-badge">late</span>
|
||
</span>
|
||
<span class="fclk-dash-muted"><t t-esc="fmtTime(emp.check_in)"/> · <t t-esc="emp.location"/></span>
|
||
</div>
|
||
</t>
|
||
</div>
|
||
<div class="fclk-dash-card">
|
||
<h4>Needs Attention</h4>
|
||
<div class="fclk-dash-line" t-on-click="onViewActivityLogs" style="cursor:pointer;">
|
||
<span class="fclk-pred"><t t-esc="state.team.absent_count"/> absent (no leave)</span>
|
||
<span class="fclk-dash-muted">review →</span>
|
||
</div>
|
||
<div class="fclk-dash-line">
|
||
<span><t t-esc="state.team.on_leave_count"/> on approved leave</span>
|
||
<span class="fclk-dash-muted">today</span>
|
||
</div>
|
||
<div class="fclk-dash-line" t-on-click="onViewActivityLogs" style="cursor:pointer;">
|
||
<span class="fclk-pyel"><t t-esc="state.team.pending_reasons"/> auto clock-out — reason pending</span>
|
||
<span class="fclk-dash-muted">view →</span>
|
||
</div>
|
||
<div class="fclk-dash-line" t-on-click="onViewCorrections" style="cursor:pointer;">
|
||
<span><t t-esc="state.team.pending_approvals"/> correction requests</span>
|
||
<span class="fclk-dash-muted">open →</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</t>
|
||
|
||
</t>
|
||
|
||
</div>
|
||
</div>
|
||
</t>
|
||
|
||
</templates>
|