feat(plating): Sub 4 — Contract Review (optional, QA-005 1:1 PDF)
Per-part contract review record (fp.contract.review) gated by a customer-level toggle, signed in two sections (QA Assistant → QA Manager), settings-based signer rosters (no new res.groups), banner on the part form that auto-dismisses once the first MO for the part hits confirmed. QA-005 Rev. 0 paper form reproduced 1:1 in a QWeb PDF. Never blocks MO/SO/WO — review is purely an audit artefact. Smoke test run on entech: 12 assertions pass including the 25-cell risk matrix parity with the paper form and 22 KB PDF render. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,270 @@
|
||||
<?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 4 — Contract Review (QA-005 1:1 reproduction).
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<!-- ================================================================== -->
|
||||
<!-- FORM VIEW — laid out to mirror QA-005 Rev. 0 as closely as Odoo -->
|
||||
<!-- backend forms permit. Printed PDF is the 1:1 artefact; this form -->
|
||||
<!-- is the data-entry counterpart. -->
|
||||
<!-- ================================================================== -->
|
||||
<record id="view_fp_contract_review_form" model="ir.ui.view">
|
||||
<field name="name">fp.contract.review.form</field>
|
||||
<field name="model">fp.contract.review</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Contract Review (QA-005)">
|
||||
<header>
|
||||
<button name="action_sign_section_20" type="object"
|
||||
string="Sign Section 2.0"
|
||||
class="btn-primary"
|
||||
invisible="s20_locked or state == 'dismissed'"/>
|
||||
<button name="action_sign_section_30" type="object"
|
||||
string="Sign Section 3.0"
|
||||
class="btn-primary"
|
||||
invisible="s30_locked or not s20_locked or state == 'dismissed'"/>
|
||||
<button name="action_print_qa005" type="object"
|
||||
string="Print QA-005"
|
||||
class="btn-secondary"/>
|
||||
<button name="action_reopen" type="object"
|
||||
string="Re-open"
|
||||
confirm="This will clear both signatures and reset the review. Continue?"
|
||||
groups="fusion_plating.group_fusion_plating_manager"
|
||||
invisible="state != 'complete'"/>
|
||||
<button name="action_dismiss" type="object"
|
||||
string="Dismiss"
|
||||
invisible="state in ('complete','dismissed')"/>
|
||||
<field name="state" widget="statusbar"
|
||||
statusbar_visible="draft,assistant_review,manager_review,complete"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1><field name="name" readonly="1"/></h1>
|
||||
</div>
|
||||
|
||||
<!-- ===== HEADER (Customer, PO, Part, Qty, Due) ===== -->
|
||||
<group>
|
||||
<group string="Customer & Order">
|
||||
<field name="customer_id" readonly="1"/>
|
||||
<field name="contract_po_number"/>
|
||||
<field name="quote_or_job_number"/>
|
||||
<field name="date_received"/>
|
||||
</group>
|
||||
<group string="Part">
|
||||
<field name="part_id" readonly="1"/>
|
||||
<field name="part_number" readonly="1"/>
|
||||
<field name="part_revision" readonly="1"/>
|
||||
<field name="qty"/>
|
||||
<field name="due_date"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<notebook>
|
||||
<!-- ========= SECTION 2.0 — Planning / Production Review ========= -->
|
||||
<page string="2.0 Planning / Production Review"
|
||||
name="section_20">
|
||||
<group>
|
||||
<field name="s20_locked" invisible="1"/>
|
||||
</group>
|
||||
<group col="4" string="Checklist">
|
||||
<field name="s20_acceptable_lead_time" readonly="s20_locked"/>
|
||||
<field name="s20_capacity_to_process" readonly="s20_locked"/>
|
||||
<field name="s20_skills_to_process" readonly="s20_locked"/>
|
||||
<field name="s20_fixtures_required" readonly="s20_locked"/>
|
||||
<field name="s20_prime_approvals" readonly="s20_locked"/>
|
||||
<field name="s20_pricing" readonly="s20_locked"/>
|
||||
<field name="s20_approved_technique" readonly="s20_locked"/>
|
||||
<field name="s20_drawings_available" readonly="s20_locked"/>
|
||||
<field name="s20_process_type_class_grade" readonly="s20_locked"/>
|
||||
<field name="s20_pre_post_processing_steps" readonly="s20_locked"/>
|
||||
</group>
|
||||
<group string="Outcome">
|
||||
<field name="s20_accepted" readonly="s20_locked"/>
|
||||
<field name="s20_evaluate_risk" readonly="s20_locked"/>
|
||||
<field name="s20_risk_level" readonly="s20_locked"
|
||||
invisible="not s20_evaluate_risk"/>
|
||||
</group>
|
||||
<group string="Comments">
|
||||
<field name="s20_comments" nolabel="1" readonly="s20_locked"/>
|
||||
</group>
|
||||
<group string="Signature" invisible="not s20_locked">
|
||||
<field name="s20_signed_by" readonly="1"/>
|
||||
<field name="s20_signed_date" readonly="1"/>
|
||||
</group>
|
||||
</page>
|
||||
|
||||
<!-- ========= SECTION 3.0 — Quality Review ========= -->
|
||||
<page string="3.0 Quality Review" name="section_30">
|
||||
<group>
|
||||
<field name="s30_locked" invisible="1"/>
|
||||
</group>
|
||||
<group col="4" string="Checklist">
|
||||
<field name="s30_source_control_docs" readonly="s30_locked"/>
|
||||
<field name="s30_quality_clauses_supplied" readonly="s30_locked"/>
|
||||
<field name="s30_quality_clauses_attainable" readonly="s30_locked"/>
|
||||
<field name="s30_critical_tolerance" readonly="s30_locked"/>
|
||||
<field name="s30_measuring_tooling" readonly="s30_locked"/>
|
||||
<field name="s30_quality_tests_verified" readonly="s30_locked"/>
|
||||
<field name="s30_specification_revisions" readonly="s30_locked"/>
|
||||
<field name="s30_certifications_requirements" readonly="s30_locked"/>
|
||||
<field name="s30_psd_rfd_reviewed" readonly="s30_locked"/>
|
||||
<field name="s30_specification_deviations" readonly="s30_locked"/>
|
||||
<field name="s30_design_authority" readonly="s30_locked"/>
|
||||
</group>
|
||||
<group string="Outcome">
|
||||
<field name="s30_accepted" readonly="s30_locked"/>
|
||||
<field name="s30_evaluate_risk" readonly="s30_locked"/>
|
||||
</group>
|
||||
<group string="Risk Assessment"
|
||||
invisible="not s30_evaluate_risk">
|
||||
<field name="s30_risk_consequence" readonly="s30_locked"/>
|
||||
<field name="s30_risk_likelihood" readonly="s30_locked"/>
|
||||
<field name="s30_risk_band" readonly="1"
|
||||
decoration-success="s30_risk_band == 'green'"
|
||||
decoration-warning="s30_risk_band == 'yellow'"
|
||||
decoration-danger="s30_risk_band == 'red'"
|
||||
widget="badge"/>
|
||||
<field name="s30_mitigation_plan_required" readonly="s30_locked"/>
|
||||
</group>
|
||||
<group string="Signature" invisible="not s30_locked">
|
||||
<field name="s30_signed_by" readonly="1"/>
|
||||
<field name="s30_signed_date" readonly="1"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<chatter/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ================================================================== -->
|
||||
<!-- LIST VIEW -->
|
||||
<!-- ================================================================== -->
|
||||
<record id="view_fp_contract_review_list" model="ir.ui.view">
|
||||
<field name="name">fp.contract.review.list</field>
|
||||
<field name="model">fp.contract.review</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Contract Reviews"
|
||||
decoration-success="state == 'complete'"
|
||||
decoration-muted="state == 'dismissed'"
|
||||
decoration-info="state == 'manager_review'"
|
||||
decoration-warning="state == 'assistant_review'">
|
||||
<field name="name"/>
|
||||
<field name="customer_id"/>
|
||||
<field name="part_number"/>
|
||||
<field name="part_revision"/>
|
||||
<field name="date_received"/>
|
||||
<field name="s20_signed_by"/>
|
||||
<field name="s30_signed_by"/>
|
||||
<field name="state" widget="badge"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ================================================================== -->
|
||||
<!-- KANBAN VIEW (grouped by state) -->
|
||||
<!-- ================================================================== -->
|
||||
<record id="view_fp_contract_review_kanban" model="ir.ui.view">
|
||||
<field name="name">fp.contract.review.kanban</field>
|
||||
<field name="model">fp.contract.review</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="state"
|
||||
class="o_kanban_small_column">
|
||||
<field name="name"/>
|
||||
<field name="customer_id"/>
|
||||
<field name="part_number"/>
|
||||
<field name="part_revision"/>
|
||||
<field name="state"/>
|
||||
<templates>
|
||||
<t t-name="card">
|
||||
<div class="oe_kanban_global_click">
|
||||
<div class="o_kanban_record_title">
|
||||
<strong><field name="name"/></strong>
|
||||
</div>
|
||||
<div class="o_kanban_record_subtitle">
|
||||
<field name="customer_id"/>
|
||||
</div>
|
||||
<div>
|
||||
<span>Part: </span>
|
||||
<field name="part_number"/>
|
||||
<span> Rev </span>
|
||||
<field name="part_revision"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ================================================================== -->
|
||||
<!-- SEARCH VIEW -->
|
||||
<!-- ================================================================== -->
|
||||
<record id="view_fp_contract_review_search" model="ir.ui.view">
|
||||
<field name="name">fp.contract.review.search</field>
|
||||
<field name="model">fp.contract.review</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="name"/>
|
||||
<field name="customer_id"/>
|
||||
<field name="part_number"/>
|
||||
<field name="part_revision"/>
|
||||
<field name="contract_po_number"/>
|
||||
<field name="quote_or_job_number"/>
|
||||
<separator/>
|
||||
<filter name="filter_pending"
|
||||
string="Pending"
|
||||
domain="[('state','in',['draft','assistant_review','manager_review'])]"/>
|
||||
<filter name="filter_complete"
|
||||
string="Complete"
|
||||
domain="[('state','=','complete')]"/>
|
||||
<filter name="filter_dismissed"
|
||||
string="Dismissed"
|
||||
domain="[('state','=','dismissed')]"/>
|
||||
<group>
|
||||
<filter name="group_state" string="Status"
|
||||
context="{'group_by': 'state'}"/>
|
||||
<filter name="group_customer" string="Customer"
|
||||
context="{'group_by': 'customer_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ================================================================== -->
|
||||
<!-- ACTION -->
|
||||
<!-- ================================================================== -->
|
||||
<record id="action_fp_contract_review" model="ir.actions.act_window">
|
||||
<field name="name">Contract Reviews</field>
|
||||
<field name="res_model">fp.contract.review</field>
|
||||
<field name="view_mode">kanban,list,form</field>
|
||||
<field name="search_view_id" ref="view_fp_contract_review_search"/>
|
||||
<field name="context">{'search_default_filter_pending': 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
No Contract Reviews yet.
|
||||
</p>
|
||||
<p>
|
||||
Contract Reviews (QA-005) capture QA sign-off on new parts
|
||||
before production. They are always optional and never
|
||||
block manufacturing. Toggle
|
||||
<b>Require Contract Review for new parts</b> on a customer
|
||||
to show the reminder banner on new parts under that customer.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ================================================================== -->
|
||||
<!-- MENU (under Plating → Quality) -->
|
||||
<!-- ================================================================== -->
|
||||
<menuitem id="menu_fp_quality_contract_review"
|
||||
name="Contract Reviews"
|
||||
parent="menu_fp_quality"
|
||||
action="action_fp_contract_review"
|
||||
sequence="15"/>
|
||||
|
||||
</odoo>
|
||||
@@ -0,0 +1,84 @@
|
||||
<?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 4 — Contract Review banner + tab on fp.part.catalog.
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<record id="view_fp_part_catalog_form_contract_review" model="ir.ui.view">
|
||||
<field name="name">fp.part.catalog.form.contract.review</field>
|
||||
<field name="model">fp.part.catalog</field>
|
||||
<field name="inherit_id" ref="fusion_plating_configurator.view_fp_part_catalog_form"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<!-- ===== Reminder banner above the title block ===== -->
|
||||
<xpath expr="//div[hasclass('oe_title')]" position="before">
|
||||
<field name="x_fc_contract_review_banner_visible" invisible="1"/>
|
||||
<field name="x_fc_contract_review_state" invisible="1"/>
|
||||
<field name="x_fc_contract_review_dismissed" invisible="1"/>
|
||||
<div class="alert alert-info"
|
||||
role="alert"
|
||||
invisible="not x_fc_contract_review_banner_visible">
|
||||
<i class="fa fa-info-circle me-2"/>
|
||||
<strong>New part created.</strong>
|
||||
Please complete the Contract Review (QA-005) if applicable.
|
||||
This is optional — it can be dismissed and never blocks production.
|
||||
<div class="mt-2">
|
||||
<button name="action_start_contract_review"
|
||||
type="object"
|
||||
string="Start Contract Review"
|
||||
class="btn btn-primary btn-sm me-2"/>
|
||||
<button name="action_dismiss_contract_review"
|
||||
type="object"
|
||||
string="Dismiss"
|
||||
class="btn btn-link btn-sm"/>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
|
||||
<!-- ===== Contract Review tab at end of notebook ===== -->
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="Contract Review" name="contract_review">
|
||||
<group>
|
||||
<field name="x_fc_contract_review_id" readonly="1"/>
|
||||
<field name="x_fc_contract_review_state" readonly="1"
|
||||
widget="badge"
|
||||
decoration-success="x_fc_contract_review_state == 'complete'"
|
||||
decoration-info="x_fc_contract_review_state == 'manager_review'"
|
||||
decoration-warning="x_fc_contract_review_state == 'assistant_review'"
|
||||
decoration-muted="x_fc_contract_review_state == 'dismissed'"
|
||||
invisible="not x_fc_contract_review_id"/>
|
||||
</group>
|
||||
<div invisible="x_fc_contract_review_id or not partner_id">
|
||||
<field name="x_fc_customer_requires_contract_review" invisible="1"/>
|
||||
<p invisible="x_fc_customer_requires_contract_review">
|
||||
This customer is not configured to require
|
||||
Contract Reviews on new parts. You can still
|
||||
start one manually.
|
||||
</p>
|
||||
<button name="action_start_contract_review"
|
||||
type="object"
|
||||
string="Start Contract Review"
|
||||
class="btn btn-primary"/>
|
||||
</div>
|
||||
<div invisible="not x_fc_contract_review_id">
|
||||
<button name="action_start_contract_review"
|
||||
type="object"
|
||||
string="Open Review"
|
||||
class="btn btn-secondary me-2"/>
|
||||
<button name="action_undismiss_contract_review"
|
||||
type="object"
|
||||
string="Undismiss Reminder"
|
||||
class="btn btn-link"
|
||||
groups="fusion_plating.group_fusion_plating_manager"
|
||||
invisible="not x_fc_contract_review_dismissed"/>
|
||||
</div>
|
||||
</page>
|
||||
</xpath>
|
||||
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -0,0 +1,48 @@
|
||||
<?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 4 — Contract Review signer rosters in Fusion Plating settings.
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<record id="res_config_settings_view_form_fp_quality" model="ir.ui.view">
|
||||
<field name="name">res.config.settings.view.form.fp.quality</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id"
|
||||
ref="fusion_plating.res_config_settings_view_form_fp_core"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//app[@name='fusion_plating']" position="inside">
|
||||
<block title="Contract Review (QA-005)"
|
||||
name="fp_contract_review_settings"
|
||||
help="Choose which users are authorised to sign each
|
||||
section of a Contract Review. Users on these
|
||||
lists gain only the right to sign — no other
|
||||
permissions are affected. Plating Managers can
|
||||
always sign regardless of these lists.">
|
||||
<setting id="fp_qa_assistant_signers"
|
||||
string="QA Assistant Signers"
|
||||
help="Users authorised to sign Section 2.0
|
||||
(Planning / Production Review). Typically
|
||||
one or two people. Leave empty if any
|
||||
user should be able to sign — in that
|
||||
case a Plating Manager is the only
|
||||
required approver.">
|
||||
<field name="x_fc_qa_assistant_user_ids"
|
||||
widget="many2many_tags"/>
|
||||
</setting>
|
||||
<setting id="fp_qa_manager_signers"
|
||||
string="QA Manager Signers"
|
||||
help="Users authorised to sign Section 3.0
|
||||
(Quality Review). Typically the QA
|
||||
Manager for the shop.">
|
||||
<field name="x_fc_qa_manager_user_ids"
|
||||
widget="many2many_tags"/>
|
||||
</setting>
|
||||
</block>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?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 4 — Contract Review toggle on customer.
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<record id="view_partner_form_fp_contract_review" model="ir.ui.view">
|
||||
<field name="name">res.partner.form.fp.contract.review</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="Plating Contract Review"
|
||||
name="fp_contract_review_prefs"
|
||||
invisible="is_company != True">
|
||||
<group name="fp_contract_review_group">
|
||||
<p class="text-muted" colspan="2">
|
||||
Toggle this on so QA sees a Contract Review
|
||||
reminder banner whenever a new part is created
|
||||
under this customer. The reminder is always
|
||||
optional — it can be dismissed and never blocks
|
||||
production. Once the part reaches a confirmed
|
||||
manufacturing order, the banner disappears on
|
||||
its own.
|
||||
</p>
|
||||
<field name="x_fc_contract_review_required"
|
||||
widget="boolean_toggle"/>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user