feat(sub12c): Labor History views + Plating menu (Task 4)

Plating → Labor History (sequence 64, between Move Log 62 and
Aerospace 65). List view colour-coded by state (info/warning/
success/muted), with billed_pct progressbar and rich field optionals.

Search filters: My Timers (default), Today, Running, Paused, Pending
Reconciliation, Reconciled. Group-by: Operator, Job, Date.

Form view (read-only header with statusbar): identity fields readonly,
billed_hrs/min/sec editable for supervisors+ until state=reconciled.
Notes group at bottom. create=false (timers are runtime-produced;
manual creation goes through the tablet flow).

ACL rows for fp.job.step.timelog already shipped in Sub 12b's CSV
(operator/supervisor/manager) — no security changes needed here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-27 21:43:07 -04:00
parent 9d88c25136
commit 504c8f34db

View File

@@ -0,0 +1,142 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Part of the Fusion Plating product family.
Sub 12c — Labor History views.
fp.job.step.timelog now has a state machine + reconciliation
columns (Sub 12b). This file surfaces the history under
Plating → Labor History for billing audit + payroll
reconciliation.
-->
<odoo>
<record id="view_fp_job_step_timelog_list" model="ir.ui.view">
<field name="name">fp.job.step.timelog.list</field>
<field name="model">fp.job.step.timelog</field>
<field name="arch" type="xml">
<list string="Labor History" default_order="date_started desc"
decoration-info="state == 'running'"
decoration-warning="state == 'paused'"
decoration-muted="state == 'reconciled'">
<field name="user_id"/>
<field name="job_id"/>
<field name="step_id"/>
<field name="state" widget="badge"
decoration-info="state == 'running'"
decoration-warning="state == 'paused'"
decoration-success="state == 'stopped'"
decoration-muted="state == 'reconciled'"/>
<field name="date_started"/>
<field name="date_finished" optional="show"/>
<field name="accrued_seconds" optional="show"/>
<field name="billed_hrs" optional="show"/>
<field name="billed_min" optional="show"/>
<field name="billed_sec" optional="show"/>
<field name="billed_pct" widget="progressbar" optional="show"/>
<field name="product_id" optional="hide"/>
</list>
</field>
</record>
<record id="view_fp_job_step_timelog_form" model="ir.ui.view">
<field name="name">fp.job.step.timelog.form</field>
<field name="model">fp.job.step.timelog</field>
<field name="arch" type="xml">
<form string="Labor Timer" create="false">
<header>
<field name="state" widget="statusbar"
statusbar_visible="running,paused,stopped,reconciled"/>
</header>
<sheet>
<div class="oe_title">
<h1><field name="display_name" readonly="1"/></h1>
</div>
<group>
<group>
<field name="user_id" readonly="1"/>
<field name="job_id" readonly="1"/>
<field name="step_id" readonly="1"/>
<field name="date_started" readonly="1"/>
<field name="date_finished" readonly="1"/>
</group>
<group>
<field name="accrued_seconds" readonly="1"/>
<label for="billed_hrs" string="Billed Time"/>
<div>
<field name="billed_hrs" class="oe_inline"
readonly="state == 'reconciled'"
groups="fusion_plating.group_fusion_plating_supervisor"/>
hrs
<field name="billed_min" class="oe_inline"
readonly="state == 'reconciled'"
groups="fusion_plating.group_fusion_plating_supervisor"/>
min
<field name="billed_sec" class="oe_inline"
readonly="state == 'reconciled'"
groups="fusion_plating.group_fusion_plating_supervisor"/>
sec
</div>
<field name="billed_pct" widget="progressbar" readonly="1"/>
<field name="product_id"/>
</group>
</group>
<group string="Notes">
<field name="notes" nolabel="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_fp_job_step_timelog_search" model="ir.ui.view">
<field name="name">fp.job.step.timelog.search</field>
<field name="model">fp.job.step.timelog</field>
<field name="arch" type="xml">
<search>
<field name="user_id"/>
<field name="job_id"/>
<field name="step_id"/>
<field name="product_id"/>
<separator/>
<filter string="My Timers" name="my_timers"
domain="[('user_id','=',uid)]"/>
<filter string="Today" name="today"
domain="[('date_started','&gt;=',(context_today() ).strftime('%Y-%m-%d 00:00:00'))]"/>
<separator/>
<filter string="Running" name="running"
domain="[('state','=','running')]"/>
<filter string="Paused" name="paused"
domain="[('state','=','paused')]"/>
<filter string="Pending Reconciliation" name="pending"
domain="[('state','=','stopped')]"/>
<filter string="Reconciled" name="reconciled"
domain="[('state','=','reconciled')]"/>
<group>
<filter string="Operator" name="group_user"
context="{'group_by':'user_id'}"/>
<filter string="Job" name="group_job"
context="{'group_by':'job_id'}"/>
<filter string="Date" name="group_date"
context="{'group_by':'date_started:day'}"/>
</group>
</search>
</field>
</record>
<record id="action_fp_labor_history" model="ir.actions.act_window">
<field name="name">Labor History</field>
<field name="res_model">fp.job.step.timelog</field>
<field name="view_mode">list,form</field>
<field name="search_view_id" ref="view_fp_job_step_timelog_search"/>
<field name="context">{'search_default_my_timers': 1}</field>
</record>
<menuitem id="menu_fp_labor_history"
name="Labor History"
parent="menu_fp_root"
action="action_fp_labor_history"
sequence="64"/>
</odoo>