Split 49 modules/suites into independent git repos; untrack from monorepo
Each top-level module/suite folder is now its own private repo on GitHub (gsinghpal/<name>) and gitea (admin/<name>), with a fresh single initial commit. The monorepo no longer tracks them (added to .gitignore + git rm --cached); working-tree files are retained on disk and managed in their own repos. The monorepo keeps shared root files (CLAUDE.md, docs/, scripts/, tools/, AGENTS.md, WIP/obsolete dirs) and full history. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,201 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- S19 - Surface Fischerscope thickness PDF on the cert form -->
|
||||
<!-- ============================================================ -->
|
||||
<!-- Without this extension the operator has no way to know, -->
|
||||
<!-- before clicking Issue, whether the QC's Fischerscope PDF -->
|
||||
<!-- will be appended to the CoC. After Issue, no indicator that -->
|
||||
<!-- the merged PDF actually contains it. This extension fixes -->
|
||||
<!-- both gaps with a banner + smart button + clickable file. -->
|
||||
<record id="fp_certificate_view_form_jobs"
|
||||
model="ir.ui.view">
|
||||
<field name="name">fp.certificate.form.inherit.jobs</field>
|
||||
<field name="model">fp.certificate</field>
|
||||
<field name="inherit_id"
|
||||
ref="fusion_plating_certificates.fp_certificate_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<!-- 1. Smart button: linked Plating Job, and a separate -->
|
||||
<!-- smart button for the Fischerscope-source QC. -->
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button name="action_open_job"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-cogs"
|
||||
invisible="not x_fc_job_id">
|
||||
<field name="x_fc_job_id" widget="statinfo"
|
||||
string="Work Order"/>
|
||||
</button>
|
||||
<button name="action_view_thickness_qc"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-microscope"
|
||||
invisible="not x_fc_thickness_qc_id">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_text">
|
||||
<field name="x_fc_thickness_status" widget="badge"
|
||||
decoration-info="x_fc_thickness_status == 'pending'"
|
||||
decoration-success="x_fc_thickness_status == 'merged'"/>
|
||||
</span>
|
||||
<span class="o_stat_text">Fischerscope</span>
|
||||
</div>
|
||||
</button>
|
||||
</xpath>
|
||||
|
||||
<!-- 2. Banner row above the title - explicit, can't miss. -->
|
||||
<!-- Three states with distinct alert classes. -->
|
||||
<xpath expr="//sheet/div[@class='oe_title']" position="before">
|
||||
<div class="alert alert-info" role="alert"
|
||||
invisible="x_fc_thickness_status != 'pending'">
|
||||
<i class="fa fa-info-circle" title="Info"
|
||||
aria-label="Info"/>
|
||||
<strong> Fischerscope thickness PDF is on file.</strong>
|
||||
It will be automatically appended as page 2 of
|
||||
the CoC when you click <strong>Issue</strong>.
|
||||
</div>
|
||||
<div class="alert alert-success" role="alert"
|
||||
invisible="x_fc_thickness_status != 'merged'">
|
||||
<i class="fa fa-check-circle" title="Merged"
|
||||
aria-label="Merged"/>
|
||||
<strong> Fischerscope thickness report merged.</strong>
|
||||
The issued CoC PDF includes the Fischerscope report
|
||||
as page 2 - open the Certificate PDF tab to verify.
|
||||
</div>
|
||||
<div class="alert alert-warning" role="alert"
|
||||
invisible="state != 'draft' or x_fc_thickness_status != 'none' or not partner_id"
|
||||
style="margin-top:0;">
|
||||
<i class="fa fa-exclamation-triangle" title="Warning"
|
||||
aria-label="Warning"/>
|
||||
<strong> No Fischerscope PDF available.</strong>
|
||||
Drop the PDF into the <em>Thickness Report
|
||||
(Fischerscope)</em> tab below, or upload it on the
|
||||
linked QC check, before issuing. Thickness Report
|
||||
certs cannot issue without thickness data.
|
||||
</div>
|
||||
</xpath>
|
||||
|
||||
<!-- 3. Thickness Report tab - single place to see/edit
|
||||
every Fischerscope-related field on the cert.
|
||||
Reorganized 2026-05-21:
|
||||
* Status + linked QC at the top (read-only context)
|
||||
* XDAL 600 metadata (operator/product/etc.) editable
|
||||
so manager can correct OCR mistakes
|
||||
* Microscope image preview (auto-extracted from RTF
|
||||
or manually uploaded - either way editable here)
|
||||
* Source files (PDF / non-PDF evidence / source name)
|
||||
* Upload wizard button + help text -->
|
||||
<xpath expr="//notebook/page[@name='pdf']" position="after">
|
||||
<page string="Thickness Report (Fischerscope)"
|
||||
name="thickness_pdf">
|
||||
|
||||
<!-- Status + QC link (read-only context) -->
|
||||
<group>
|
||||
<field name="x_fc_thickness_status" widget="badge"
|
||||
readonly="1"
|
||||
decoration-muted="x_fc_thickness_status == 'none'"
|
||||
decoration-info="x_fc_thickness_status == 'pending'"
|
||||
decoration-success="x_fc_thickness_status == 'merged'"/>
|
||||
<field name="x_fc_thickness_qc_id" readonly="1"
|
||||
invisible="not x_fc_thickness_qc_id"/>
|
||||
</group>
|
||||
|
||||
<!-- Hints rotate by state -->
|
||||
<div class="text-muted"
|
||||
invisible="x_fc_thickness_status != 'none'">
|
||||
<p>
|
||||
No Fischerscope thickness data has been
|
||||
uploaded yet. Click <strong>Upload Thickness
|
||||
Report</strong> below to drop a `.doc` / `.docx`
|
||||
/ `.rtf` / `.pdf` file straight from the
|
||||
XDAL 600. The wizard parses readings +
|
||||
metadata and fills out the fields on this tab.
|
||||
</p>
|
||||
</div>
|
||||
<div class="text-muted"
|
||||
invisible="x_fc_thickness_status != 'pending'">
|
||||
<p>
|
||||
<i class="fa fa-arrow-up"/>
|
||||
Click <strong>Issue</strong> in the header to
|
||||
merge the Fischerscope PDF as page 2 of
|
||||
the CoC. Readings will render inline in the
|
||||
body of the cert either way.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Upload wizard CTA -->
|
||||
<div style="margin: 8px 0;">
|
||||
<button name="%(fusion_plating_certificates.action_fp_thickness_upload_wizard)d"
|
||||
type="action"
|
||||
class="btn-primary"
|
||||
string="Upload Thickness Report"
|
||||
context="{'default_certificate_id': id}"
|
||||
invisible="state != 'draft'"/>
|
||||
</div>
|
||||
|
||||
<separator string="XDAL 600 Measurement Context"/>
|
||||
<p class="text-muted small">
|
||||
These values are pulled from the uploaded file
|
||||
and printed on the CoC's thickness section. Edit
|
||||
any field here to override what the parser saw.
|
||||
</p>
|
||||
<group>
|
||||
<group>
|
||||
<field name="x_fc_thickness_equipment"
|
||||
placeholder="Fischerscope XDAL 600"/>
|
||||
<field name="x_fc_thickness_operator"
|
||||
placeholder="Operator initials / name"/>
|
||||
<field name="x_fc_thickness_datetime"/>
|
||||
<field name="x_fc_thickness_measuring_time_sec"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="x_fc_thickness_product"
|
||||
placeholder="e.g. 2805031 / NiP/Al-alloys 2805030"/>
|
||||
<field name="x_fc_thickness_application"
|
||||
placeholder="e.g. 16 / NiP/Al-alloys"/>
|
||||
<field name="x_fc_thickness_directory"
|
||||
placeholder="XDAL save directory"/>
|
||||
<field name="x_fc_thickness_source_filename"
|
||||
readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<separator string="Microscope Image"/>
|
||||
<p class="text-muted small">
|
||||
Auto-extracted from RTF uploads (via libwmf) or
|
||||
manually uploaded via the wizard. Drop a new
|
||||
PNG/JPEG here to override.
|
||||
</p>
|
||||
<group>
|
||||
<field name="x_fc_thickness_image_id"
|
||||
options="{'no_create': True}"/>
|
||||
</group>
|
||||
|
||||
<separator string="Source Files"/>
|
||||
<group>
|
||||
<group string="Fischerscope PDF"
|
||||
invisible="not x_fc_local_thickness_pdf">
|
||||
<field name="x_fc_local_thickness_pdf"
|
||||
filename="x_fc_local_thickness_pdf_filename"/>
|
||||
<field name="x_fc_local_thickness_pdf_filename"
|
||||
invisible="1"/>
|
||||
</group>
|
||||
<group string="Non-PDF Evidence (RTF/DOCX)"
|
||||
invisible="not x_fc_local_thickness_evidence_id">
|
||||
<field name="x_fc_local_thickness_evidence_id"
|
||||
options="{'no_create': True}"/>
|
||||
</group>
|
||||
<group string="QC-side Fischerscope PDF"
|
||||
invisible="not x_fc_thickness_pdf_id">
|
||||
<field name="x_fc_thickness_pdf_id" readonly="1"
|
||||
widget="many2one_binary"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -1,22 +0,0 @@
|
||||
<?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.
|
||||
|
||||
One-shot backfill for closed jobs that never produced a CoC because
|
||||
of the `coating` NameError regression (fixed 2026-05-18). Surfaced
|
||||
as a Settings > Technical menu item so the user can click once after
|
||||
deploying the fix.
|
||||
-->
|
||||
<odoo>
|
||||
<record id="action_fp_job_backfill_missing_certs" model="ir.actions.server">
|
||||
<field name="name">Generate Missing Certs for Closed Jobs</field>
|
||||
<field name="model_id" ref="fusion_plating.model_fp_job"/>
|
||||
<field name="binding_model_id" ref="fusion_plating.model_fp_job"/>
|
||||
<field name="binding_view_types">list</field>
|
||||
<field name="group_ids" eval="[(4, ref('base.group_system'))]"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = env['fp.job'].action_backfill_missing_certs()</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,65 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="view_fp_job_consumption_list" model="ir.ui.view">
|
||||
<field name="name">fp.job.consumption.list</field>
|
||||
<field name="model">fp.job.consumption</field>
|
||||
<field name="arch" type="xml">
|
||||
<list editable="bottom" default_order="logged_date desc">
|
||||
<field name="logged_date"/>
|
||||
<field name="job_id"/>
|
||||
<field name="step_id"/>
|
||||
<field name="product_id"/>
|
||||
<field name="quantity"/>
|
||||
<field name="uom_id"/>
|
||||
<field name="currency_id" column_invisible="1"/>
|
||||
<field name="unit_cost" widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}"/>
|
||||
<field name="total_cost" widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}" sum="Total"/>
|
||||
<field name="source"/>
|
||||
<field name="logged_by_id" optional="hide"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_fp_job_consumption_form" model="ir.ui.view">
|
||||
<field name="name">fp.job.consumption.form</field>
|
||||
<field name="model">fp.job.consumption</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="job_id"/>
|
||||
<field name="step_id"/>
|
||||
<field name="product_id"/>
|
||||
<field name="product_name"/>
|
||||
<field name="source"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="quantity"/>
|
||||
<field name="uom_id"/>
|
||||
<field name="currency_id"/>
|
||||
<field name="unit_cost" widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}"/>
|
||||
<field name="total_cost" widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}" readonly="1"/>
|
||||
<field name="logged_date"/>
|
||||
<field name="logged_by_id"/>
|
||||
</group>
|
||||
</group>
|
||||
<separator string="Notes"/>
|
||||
<field name="notes"/>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_fp_job_consumption" model="ir.actions.act_window">
|
||||
<field name="name">Job Consumables Log</field>
|
||||
<field name="res_model">fp.job.consumption</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -1,343 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<!--
|
||||
Adds a "Process Tree" header button + smart-button row to the
|
||||
fp.job form. The fp.job form in core has no button_box yet, so
|
||||
we inject one at the top of the sheet (xpath //sheet position
|
||||
"inside" with a sibling reference at the start).
|
||||
|
||||
Smart buttons appear only when the underlying count is > 0
|
||||
(except Steps, which always shows since every confirmed job
|
||||
has steps). Pattern follows the existing oe_stat_button row
|
||||
from sale.order / mrp.production.
|
||||
|
||||
Process Tree header button is hidden while the job is in draft
|
||||
(no recipe-derived steps yet).
|
||||
-->
|
||||
<record id="view_fp_job_form_jobs_inherit" model="ir.ui.view">
|
||||
<field name="name">fp.job.form.jobs.inherit</field>
|
||||
<field name="model">fp.job</field>
|
||||
<field name="inherit_id" ref="fusion_plating.view_fp_job_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position="inside">
|
||||
<!-- Heal a WO that was created before the recipe was set
|
||||
on the SO line: re-pull the recipe and build steps.
|
||||
Hidden once steps exist or the job is terminal. -->
|
||||
<button name="action_fp_resync_recipe_from_so" type="object"
|
||||
string="Re-sync Recipe from SO"
|
||||
class="btn-secondary"
|
||||
icon="fa-refresh"
|
||||
invisible="state in ('done', 'cancelled') or step_ids"/>
|
||||
<!-- Phase 1 - Tablet redesign. Opens the JobWorkspace OWL
|
||||
client action focused on this WO. Primary entry point
|
||||
for techs before the Landing kanban (Phase 3) ships;
|
||||
stays as a back-office shortcut after. -->
|
||||
<button name="action_open_workspace" type="object"
|
||||
string="Workspace"
|
||||
class="btn-primary"
|
||||
icon="fa-tablet"
|
||||
invisible="state == 'draft'"/>
|
||||
<button name="action_open_process_tree" type="object"
|
||||
class="btn-secondary"
|
||||
icon="fa-sitemap"
|
||||
invisible="state == 'draft'"/>
|
||||
<!-- Steelhead-style "Finish & Next": one click finishes
|
||||
whatever's running and auto-starts the next pending
|
||||
step. Falls back to starting the first step if
|
||||
nothing is running yet. The classic Move wizard is
|
||||
still available via the per-row Move button (used
|
||||
for cross-station moves and rework / scrap). -->
|
||||
<button name="action_finish_current_step" type="object"
|
||||
string="Finish & Next"
|
||||
class="btn-primary"
|
||||
icon="fa-arrow-right"
|
||||
invisible="state not in ('confirmed', 'in_progress') or all_steps_terminal"/>
|
||||
|
||||
<!-- Milestone cascade (Phase 1). All four share the same
|
||||
dispatcher; visibility is gated on next_milestone_action
|
||||
so only one ever renders at a time. -->
|
||||
<button name="action_advance_next_milestone" type="object"
|
||||
string="Mark Job Done"
|
||||
class="btn-success"
|
||||
icon="fa-check-circle"
|
||||
invisible="next_milestone_action != 'mark_done'"/>
|
||||
<button name="action_advance_next_milestone" type="object"
|
||||
string="Issue Certs"
|
||||
class="btn-primary"
|
||||
icon="fa-certificate"
|
||||
invisible="next_milestone_action != 'issue_certs'"/>
|
||||
<button name="action_advance_next_milestone" type="object"
|
||||
string="Schedule Delivery"
|
||||
class="btn-primary"
|
||||
icon="fa-truck"
|
||||
invisible="next_milestone_action != 'schedule_delivery'"/>
|
||||
<button name="action_advance_next_milestone" type="object"
|
||||
string="Mark Shipped"
|
||||
class="btn-success"
|
||||
icon="fa-paper-plane"
|
||||
invisible="next_milestone_action != 'mark_shipped'"
|
||||
groups="fusion_plating.group_fp_manager,fusion_plating.group_fp_owner"/>
|
||||
<field name="all_steps_terminal" invisible="1"/>
|
||||
<field name="next_milestone_action" invisible="1"/>
|
||||
<button name="action_print_sticker" type="object"
|
||||
class="btn-secondary"
|
||||
icon="fa-qrcode"
|
||||
invisible="state == 'draft'"
|
||||
help="Print Sticker"/>
|
||||
</xpath>
|
||||
|
||||
<!-- Sub 14 - Replace the generic Draft/Confirmed/In Progress/Done
|
||||
statusbar with the configurable workflow_state_id bar.
|
||||
Operators see meaningful plating milestones (Received,
|
||||
Inspected, Shipped, etc.) instead of generic Odoo states. -->
|
||||
<xpath expr="//header/field[@name='state']" position="replace">
|
||||
<field name="workflow_state_id"
|
||||
widget="statusbar"
|
||||
options="{'clickable': '0'}"/>
|
||||
</xpath>
|
||||
|
||||
<!-- Surface part / coating / recipe on the header so the
|
||||
floor knows WHAT they're plating without diving into
|
||||
Source. The "Reference Product" line in core is just
|
||||
the FP-SERVICE stub from the SO - relabel it so it
|
||||
doesn't compete with the real part identification. -->
|
||||
<xpath expr="//field[@name='product_id']" position="attributes">
|
||||
<attribute name="string">Service Product</attribute>
|
||||
<attribute name="invisible">part_catalog_id</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='product_id']" position="after">
|
||||
<field name="part_catalog_id" string="Part"/>
|
||||
<field name="customer_spec_id" string="Specification" invisible="1"/>
|
||||
<field name="recipe_id" string="Process Recipe" readonly="1"/>
|
||||
</xpath>
|
||||
<!-- Show qty completed alongside total so the partial-qty
|
||||
picture is visible at a glance without opening Move Log. -->
|
||||
<xpath expr="//field[@name='qty']" position="after">
|
||||
<field name="qty_done" string="Qty Done"/>
|
||||
<field name="qty_scrapped" string="Qty Scrapped"
|
||||
invisible="not qty_scrapped"/>
|
||||
</xpath>
|
||||
|
||||
<!-- Replace the bare-bones Steps list with the action-rich
|
||||
manager view. Per-row buttons mirror what an operator
|
||||
sees on the tablet; Running Min ticks on every refresh
|
||||
for the active step. -->
|
||||
<xpath expr="//page[@name='steps']/field[@name='step_ids']" position="replace">
|
||||
<field name="step_ids" mode="list"
|
||||
context="{'form_view_ref': 'fusion_plating_jobs.view_fp_job_step_quick_look_form'}">
|
||||
<list editable="bottom" create="false" delete="false"
|
||||
decoration-info="state in ('ready', 'in_progress')"
|
||||
decoration-success="state == 'done'"
|
||||
decoration-warning="state == 'paused'"
|
||||
decoration-muted="state in ('skipped', 'cancelled')">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<button name="action_open_quick_look" type="object"
|
||||
title="View step details"
|
||||
icon="fa-info-circle"
|
||||
width="30"
|
||||
class="btn-link o_fp_step_info_btn"/>
|
||||
<field name="name"/>
|
||||
<field name="work_centre_id" optional="show"/>
|
||||
<field name="tank_id" optional="hide"/>
|
||||
<field name="kind" optional="hide"/>
|
||||
<field name="state" widget="badge"
|
||||
decoration-info="state in ('ready', 'in_progress')"
|
||||
decoration-success="state == 'done'"
|
||||
decoration-warning="state == 'paused'"
|
||||
decoration-muted="state in ('skipped', 'cancelled')"/>
|
||||
<field name="assigned_user_id" optional="show"/>
|
||||
<field name="duration_expected" optional="show"/>
|
||||
<field name="duration_running_minutes" string="Running Min" optional="show"/>
|
||||
<field name="duration_actual" optional="show"/>
|
||||
<!-- Live qty currently parked at this step. Hits
|
||||
zero once everything has moved on; >0 means
|
||||
the floor still has parts to process here. -->
|
||||
<field name="qty_at_step" string="Qty Here" optional="show"/>
|
||||
<!-- Primary action: state-aware. Pending/ready → Start,
|
||||
in_progress → Finish & Next (auto-advance like
|
||||
Steelhead), paused → Resume. Done / skipped /
|
||||
cancelled rows show no primary. -->
|
||||
<button name="button_start" type="object"
|
||||
string="Start" icon="fa-play"
|
||||
class="btn-link text-success"
|
||||
invisible="state not in ('ready', 'pending')"/>
|
||||
<button name="button_resume" type="object"
|
||||
title="Resume" icon="fa-play-circle"
|
||||
class="btn-link text-success"
|
||||
invisible="state != 'paused'"/>
|
||||
<button name="action_finish_and_advance" type="object"
|
||||
title="Finish & Next" icon="fa-check-circle"
|
||||
class="btn-link o_fp_finish_btn"
|
||||
invisible="state != 'in_progress'"/>
|
||||
<!-- Reset / redo - back to Ready so the step can be
|
||||
run again (mistake, accidental skip, customer
|
||||
redo). Clears finish + sign-off stamps; keeps the
|
||||
start audit + moves. Hidden on ready/pending. -->
|
||||
<button name="button_reset" type="object"
|
||||
title="Reset step (redo)" icon="fa-undo"
|
||||
class="btn-link text-warning"
|
||||
invisible="state in ('ready', 'pending')"/>
|
||||
|
||||
<!-- Secondary actions - small icons only. Pause is
|
||||
only relevant on a running step; Record Inputs
|
||||
stays available so operators can capture
|
||||
measurements without finishing the step;
|
||||
Skip + Move (cross-station) tucked together. -->
|
||||
<button name="button_pause" type="object"
|
||||
title="Pause" icon="fa-pause"
|
||||
class="btn-link text-warning"
|
||||
invisible="state != 'in_progress'"/>
|
||||
<!-- Streaming flow: complete 1 part at a time,
|
||||
move to next step. Hidden when nothing is
|
||||
parked or the step isn't actively running.
|
||||
Auto-finishes when qty_at_step drains to 0. -->
|
||||
<button name="action_complete_one_to_next" type="object"
|
||||
title="Complete 1 → Next (streaming flow)" icon="fa-forward"
|
||||
class="btn-link text-success"
|
||||
invisible="state != 'in_progress' or qty_at_step < 1"/>
|
||||
<button name="action_open_input_wizard" type="object"
|
||||
title="Record Inputs" icon="fa-pencil-square-o"
|
||||
class="btn-link"
|
||||
invisible="state in ('cancelled', 'skipped')"/>
|
||||
<button name="button_skip" type="object"
|
||||
title="Skip step" icon="fa-step-forward"
|
||||
class="btn-link text-muted"
|
||||
invisible="state not in ('pending', 'ready')"/>
|
||||
<button name="action_open_move_wizard" type="object"
|
||||
title="Move… (custom qty / destination)" icon="fa-exchange"
|
||||
class="btn-link text-muted"
|
||||
invisible="state in ('done', 'cancelled', 'skipped', 'pending')"/>
|
||||
</list>
|
||||
</field>
|
||||
</xpath>
|
||||
|
||||
<!-- New tabs in the notebook: Move Log + Time Logs.
|
||||
Both read-only - operators write via the wizards;
|
||||
these tabs are the audit window. -->
|
||||
<xpath expr="//page[@name='source']" position="before">
|
||||
<page string="Move Log" name="move_log">
|
||||
<field name="move_ids" readonly="1">
|
||||
<list create="false" edit="false" delete="false"
|
||||
decoration-info="transfer_type == 'step'"
|
||||
decoration-warning="transfer_type in ('hold', 'rework')"
|
||||
decoration-danger="transfer_type == 'scrap'">
|
||||
<field name="move_datetime"/>
|
||||
<field name="from_step_id"/>
|
||||
<field name="to_step_id"/>
|
||||
<field name="transfer_type" widget="badge"/>
|
||||
<field name="qty_moved"/>
|
||||
<field name="moved_by_user_id"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Time Logs" name="time_logs">
|
||||
<field name="time_log_ids" readonly="1">
|
||||
<list create="false" edit="false" delete="false">
|
||||
<field name="step_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="date_started"/>
|
||||
<field name="date_finished"/>
|
||||
<field name="duration_minutes"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
</xpath>
|
||||
|
||||
<!-- Inject a button_box at the top of the sheet, before the
|
||||
oe_title block. Smart buttons drill into the matching
|
||||
records the way sale.order does. -->
|
||||
<xpath expr="//sheet/div[hasclass('oe_title')]" position="before">
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="action_view_sale_order" type="object"
|
||||
class="oe_stat_button" icon="fa-shopping-cart"
|
||||
invisible="sale_order_count == 0">
|
||||
<field name="sale_order_count" widget="statinfo"
|
||||
string="Sale Order"/>
|
||||
</button>
|
||||
<button name="action_view_steps" type="object"
|
||||
class="oe_stat_button" icon="fa-list-ol">
|
||||
<field name="step_count" widget="statinfo"
|
||||
string="Steps"/>
|
||||
</button>
|
||||
<button name="action_view_deliveries" type="object"
|
||||
class="oe_stat_button" icon="fa-truck"
|
||||
invisible="delivery_count == 0">
|
||||
<field name="delivery_count" widget="statinfo"
|
||||
string="Delivery"/>
|
||||
</button>
|
||||
<button name="action_view_invoices" type="object"
|
||||
class="oe_stat_button" icon="fa-file-text-o"
|
||||
invisible="invoice_count == 0">
|
||||
<field name="invoice_count" widget="statinfo"
|
||||
string="Invoices"/>
|
||||
</button>
|
||||
<button name="action_view_payments" type="object"
|
||||
class="oe_stat_button" icon="fa-money"
|
||||
invisible="payment_count == 0">
|
||||
<field name="payment_count" widget="statinfo"
|
||||
string="Payments"/>
|
||||
</button>
|
||||
<button name="action_view_quality_holds" type="object"
|
||||
class="oe_stat_button" icon="fa-pause-circle"
|
||||
invisible="quality_hold_count == 0">
|
||||
<field name="quality_hold_count" widget="statinfo"
|
||||
string="Holds"/>
|
||||
</button>
|
||||
<button name="action_view_certificates" type="object"
|
||||
class="oe_stat_button" icon="fa-certificate"
|
||||
invisible="certificate_count == 0">
|
||||
<field name="certificate_count" widget="statinfo"
|
||||
string="Certificates"/>
|
||||
</button>
|
||||
<button name="action_view_timelogs" type="object"
|
||||
class="oe_stat_button" icon="fa-clock-o"
|
||||
invisible="timelog_count == 0">
|
||||
<field name="timelog_count" widget="statinfo"
|
||||
string="Time Logs"/>
|
||||
</button>
|
||||
<button name="action_view_portal_job" type="object"
|
||||
class="oe_stat_button" icon="fa-globe"
|
||||
invisible="portal_job_count == 0">
|
||||
<field name="portal_job_count" widget="statinfo"
|
||||
string="Portal Job"/>
|
||||
</button>
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//group[@name='x_fc_customer_refs']" position="inside">
|
||||
<field name="x_fc_delivery_method"/>
|
||||
<field name="x_fc_ship_via"/>
|
||||
<field name="x_fc_invoice_strategy"/>
|
||||
</xpath>
|
||||
<xpath expr="//group[@name='x_fc_customer_refs']" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
</xpath>
|
||||
<!-- Notes group sits awkwardly above the main fields in core; relocate
|
||||
to a notebook tab so the form opens on the operationally relevant
|
||||
fields (customer / part / steps) instead of empty note placeholders. -->
|
||||
<xpath expr="//group[@name='x_fc_notes']" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//page[@name='costs']" position="before">
|
||||
<page string="Masking Refs" name="masking_refs"
|
||||
invisible="not x_fc_masking_attachment_ids">
|
||||
<div class="text-muted mb-2">
|
||||
Masking reference image(s)/PDF(s) attached at order entry (Express).
|
||||
The operator sees these on the masking step in the workstation.
|
||||
</div>
|
||||
<field name="x_fc_masking_attachment_ids" widget="many2many_binary"
|
||||
readonly="1" nolabel="1"/>
|
||||
</page>
|
||||
</xpath>
|
||||
<xpath expr="//page[@name='costs']" position="before">
|
||||
<page string="Notes" name="notes">
|
||||
<group>
|
||||
<field name="x_fc_internal_note" nolabel="1"
|
||||
placeholder="Internal note (not shown to customer)…"/>
|
||||
<field name="x_fc_external_note" nolabel="1"
|
||||
placeholder="External note (printed on customer paperwork)…"/>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,50 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2026 Nexa Systems Inc.
|
||||
License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
Sub 12 Phase D - quality smart-button row on fp.job. The quality
|
||||
fields (fp_qc_hold_count, fp_qc_check_count, fp_qc_ncr_count,
|
||||
fp_qc_capa_count, fp_qc_rma_count) are defined in fusion_plating_quality
|
||||
via _inherit on fp.job. The view lives here because the button_box
|
||||
container is added by fusion_plating_jobs (this module loads after
|
||||
quality so we can safely reference quality fields).
|
||||
-->
|
||||
<odoo>
|
||||
<record id="view_fp_job_form_quality_buttons" model="ir.ui.view">
|
||||
<field name="name">fp.job.form.quality.buttons</field>
|
||||
<field name="model">fp.job</field>
|
||||
<field name="inherit_id" ref="view_fp_job_form_jobs_inherit"/>
|
||||
<field name="arch" type="xml">
|
||||
<!-- Hidden at a count of 0 so the row shows only quality work
|
||||
that actually exists on this job (2026-06-04). -->
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button name="action_view_fp_holds" type="object"
|
||||
class="oe_stat_button" icon="fa-hand-paper-o"
|
||||
invisible="fp_qc_hold_count == 0">
|
||||
<field name="fp_qc_hold_count" widget="statinfo" string="Holds"/>
|
||||
</button>
|
||||
<button name="action_view_fp_checks" type="object"
|
||||
class="oe_stat_button" icon="fa-check-square-o"
|
||||
invisible="fp_qc_check_count == 0">
|
||||
<field name="fp_qc_check_count" widget="statinfo" string="Checks"/>
|
||||
</button>
|
||||
<button name="action_view_fp_ncrs" type="object"
|
||||
class="oe_stat_button" icon="fa-exclamation-triangle"
|
||||
invisible="fp_qc_ncr_count == 0">
|
||||
<field name="fp_qc_ncr_count" widget="statinfo" string="NCRs"/>
|
||||
</button>
|
||||
<button name="action_view_fp_capas" type="object"
|
||||
class="oe_stat_button" icon="fa-wrench"
|
||||
invisible="fp_qc_capa_count == 0">
|
||||
<field name="fp_qc_capa_count" widget="statinfo" string="CAPAs"/>
|
||||
</button>
|
||||
<button name="action_view_fp_rmas" type="object"
|
||||
class="oe_stat_button" icon="fa-undo"
|
||||
invisible="fp_qc_rma_count == 0">
|
||||
<field name="fp_qc_rma_count" widget="statinfo" string="RMAs"/>
|
||||
</button>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,169 +0,0 @@
|
||||
<?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.
|
||||
|
||||
Read-only "Step Details" quick-look modal. Triggered by clicking a
|
||||
step's name in the embedded step list inside fp.job's form. Bound
|
||||
via context="{'form_view_ref': '...'}" on the parent - see
|
||||
fp_job_form_inherit.xml. The standalone editable form view stays
|
||||
registered for the Job Steps menu / direct navigation.
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<record id="view_fp_job_step_quick_look_form" model="ir.ui.view">
|
||||
<field name="name">fp.job.step.quick.look.form</field>
|
||||
<field name="model">fp.job.step</field>
|
||||
<field name="priority">50</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Step Details" edit="false" create="false" delete="false">
|
||||
<sheet>
|
||||
<!-- Hidden helper fields used by section visibility
|
||||
conditions below. Without these the empty-state
|
||||
hides for Equipment / Schedule won't evaluate. -->
|
||||
<field name="work_centre_id" invisible="1"/>
|
||||
<field name="tank_id" invisible="1"/>
|
||||
<field name="bath_id" invisible="1"/>
|
||||
<field name="rack_id" invisible="1"/>
|
||||
<field name="duration_expected" invisible="1"/>
|
||||
<field name="duration_actual" invisible="1"/>
|
||||
<field name="assigned_user_id" invisible="1"/>
|
||||
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name" readonly="1"/>
|
||||
</h1>
|
||||
<div class="text-muted">
|
||||
Step #<field name="sequence" readonly="1"/> ·
|
||||
<field name="kind" readonly="1"/> ·
|
||||
<field name="state" widget="badge"
|
||||
decoration-info="state == 'in_progress'"
|
||||
decoration-success="state == 'done'"
|
||||
decoration-warning="state == 'paused'"
|
||||
decoration-muted="state in ('skipped','cancelled')"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Job context - what job is this step part of, who's
|
||||
the customer, what part, how many. The single most
|
||||
useful thing to surface up top so the operator
|
||||
orients themselves before drilling in. -->
|
||||
<group string="Job Context">
|
||||
<group>
|
||||
<field name="job_id" readonly="1" options="{'no_open': True}"/>
|
||||
<field name="quick_look_part_catalog_id" readonly="1"
|
||||
options="{'no_open': True}"
|
||||
invisible="not quick_look_part_catalog_id"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="quick_look_partner_id" readonly="1"
|
||||
options="{'no_open': True}"
|
||||
invisible="not quick_look_partner_id"/>
|
||||
<field name="quick_look_qty" readonly="1"
|
||||
invisible="not quick_look_qty"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Equipment / Schedule - only render when there's
|
||||
actually something to show. An Inspection step with
|
||||
no tank / bath / time-budget shouldn't display
|
||||
four empty rows of "-" - that's misleading. -->
|
||||
<group invisible="not work_centre_id and not tank_id and not bath_id and not rack_id and not duration_expected and not duration_actual and not assigned_user_id">
|
||||
<group string="Equipment"
|
||||
invisible="not work_centre_id and not tank_id and not bath_id and not rack_id">
|
||||
<field name="work_centre_id" readonly="1"
|
||||
invisible="not work_centre_id"/>
|
||||
<field name="tank_id" readonly="1"
|
||||
invisible="not tank_id"/>
|
||||
<field name="bath_id" readonly="1"
|
||||
invisible="not bath_id"/>
|
||||
<field name="rack_id" readonly="1"
|
||||
invisible="not rack_id"/>
|
||||
</group>
|
||||
<group string="Schedule"
|
||||
invisible="not duration_expected and not duration_actual and not assigned_user_id">
|
||||
<field name="duration_expected" readonly="1"
|
||||
invisible="not duration_expected"/>
|
||||
<field name="duration_actual" readonly="1"
|
||||
invisible="not duration_actual"/>
|
||||
<field name="assigned_user_id" readonly="1"
|
||||
invisible="not assigned_user_id"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Master switch banner -->
|
||||
<field name="quick_look_collect_master" invisible="1"/>
|
||||
<div class="alert alert-warning"
|
||||
role="alert"
|
||||
invisible="quick_look_collect_master or not recipe_node_id">
|
||||
<i class="fa fa-exclamation-triangle"/>
|
||||
<strong> Master switch off</strong> - no values will be collected at runtime for this step.
|
||||
</div>
|
||||
|
||||
<!-- Operator Instructions - hide the whole section when
|
||||
the recipe author didn't write any. -->
|
||||
<separator string="Operator Instructions"
|
||||
invisible="not quick_look_instructions"/>
|
||||
<div class="o_fp_quick_look_instructions"
|
||||
invisible="not quick_look_instructions">
|
||||
<field name="quick_look_instructions" nolabel="1" readonly="1"/>
|
||||
</div>
|
||||
|
||||
<!-- Instruction images - visual reference photos /
|
||||
screenshots the recipe author attached to the
|
||||
node. Hidden when none. -->
|
||||
<separator string="Reference Images"
|
||||
invisible="not quick_look_instruction_attachment_ids"/>
|
||||
<field name="quick_look_instruction_attachment_ids"
|
||||
nolabel="1" readonly="1"
|
||||
widget="many2many_binary"
|
||||
invisible="not quick_look_instruction_attachment_ids"/>
|
||||
|
||||
<separator string="Measurement Prompts"/>
|
||||
<field name="quick_look_prompt_ids" nolabel="1" readonly="1">
|
||||
<list create="false" delete="false" edit="false">
|
||||
<field name="collect" widget="boolean_toggle" readonly="1" string="Collect"/>
|
||||
<field name="name"/>
|
||||
<field name="input_type"/>
|
||||
<field name="target_min" optional="show"/>
|
||||
<field name="target_max" optional="show"/>
|
||||
<field name="target_unit" optional="show"/>
|
||||
<field name="required" widget="boolean_toggle" readonly="1"/>
|
||||
<field name="hint" optional="hide"/>
|
||||
</list>
|
||||
</field>
|
||||
<p class="text-muted small"
|
||||
invisible="quick_look_prompt_ids">
|
||||
No measurement prompts authored for this step.
|
||||
</p>
|
||||
|
||||
<separator string="Values Recorded So Far"/>
|
||||
<field name="quick_look_recorded_value_ids" nolabel="1" readonly="1">
|
||||
<list create="false" delete="false" edit="false" default_order="create_date desc">
|
||||
<field name="node_input_id" string="Prompt"/>
|
||||
<field name="value_text" optional="show"/>
|
||||
<field name="value_number" optional="show"/>
|
||||
<field name="value_boolean" optional="hide"/>
|
||||
<field name="value_date" optional="hide"/>
|
||||
<field name="value_attachment_id" optional="hide"/>
|
||||
<field name="create_uid" string="Recorded By"/>
|
||||
<field name="create_date" string="When"/>
|
||||
</list>
|
||||
</field>
|
||||
<p class="text-muted small"
|
||||
invisible="quick_look_recorded_value_ids">
|
||||
No values recorded yet.
|
||||
</p>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button name="action_open_full_form" type="object"
|
||||
string="Open Full Form" class="btn-primary"/>
|
||||
<button string="Close" class="btn-secondary"
|
||||
special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -1,54 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2026 Nexa Systems Inc.
|
||||
License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
Adds the Work Order smart button + header button to fp.receiving so
|
||||
the receiving form mirrors the SO's WO entry point. Header button
|
||||
appears once state == 'closed' and at least one linked fp.job is
|
||||
still open. Smart button is always visible when WOs exist.
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<record id="view_fp_receiving_form_fp_jobs" model="ir.ui.view">
|
||||
<field name="name">fp.receiving.form.fp.jobs</field>
|
||||
<field name="model">fp.receiving</field>
|
||||
<field name="inherit_id" ref="fusion_plating_receiving.view_fp_receiving_form"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<!-- Work Order header button - only after receiving is
|
||||
closed and while at least one job is still open. -->
|
||||
<xpath expr="//header" position="inside">
|
||||
<field name="x_fc_show_work_order_btn" invisible="1"/>
|
||||
<button name="action_view_fp_jobs"
|
||||
string="Work Order" type="object"
|
||||
class="btn-primary" icon="fa-cogs"
|
||||
invisible="not x_fc_show_work_order_btn"
|
||||
help="Open the Work Order(s) for this receiving. Hidden automatically once every linked WO is marked Done."/>
|
||||
<!-- Print box stickers for this receiving's work order - one
|
||||
label per tracked box (external = customer copy, internal
|
||||
= shop copy with internal notes). Shown once a WO exists. -->
|
||||
<button name="action_print_external_sticker"
|
||||
string="External Sticker" type="object" icon="fa-print"
|
||||
invisible="x_fc_fp_job_count == 0"
|
||||
help="Print the customer (external) box sticker(s) - one per box."/>
|
||||
<button name="action_print_internal_sticker"
|
||||
string="Internal Sticker" type="object" icon="fa-print"
|
||||
invisible="x_fc_fp_job_count == 0"
|
||||
help="Print the shop (internal) box sticker(s) - same layout, internal notes."/>
|
||||
</xpath>
|
||||
|
||||
<!-- Work Order smart button on the button_box (mirrors the
|
||||
one on the SO form). Always visible when count > 0. -->
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button name="action_view_fp_jobs" type="object"
|
||||
class="oe_stat_button" icon="fa-cogs"
|
||||
invisible="x_fc_fp_job_count == 0">
|
||||
<field name="x_fc_fp_job_count" widget="statinfo" string="WO"/>
|
||||
</button>
|
||||
</xpath>
|
||||
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -1,101 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2026 Nexa Systems Inc.
|
||||
License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
Phase 3 (Sub 11) - native Production Priorities kanban / list on
|
||||
fp.job.step. Replaces the bridge_mrp version that bound to
|
||||
mrp.workorder. Same UX (drag-drop ordering across work centres,
|
||||
list with handle, badges by state).
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<record id="view_fp_step_priority_kanban" model="ir.ui.view">
|
||||
<field name="name">fp.job.step.priority.kanban</field>
|
||||
<field name="model">fp.job.step</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="work_centre_id" default_order="sequence, id">
|
||||
<field name="name"/>
|
||||
<field name="work_centre_id"/>
|
||||
<field name="job_id"/>
|
||||
<field name="state"/>
|
||||
<field name="sequence"/>
|
||||
<field name="duration_actual"/>
|
||||
<field name="duration_expected"/>
|
||||
<field name="assigned_user_id"/>
|
||||
<templates>
|
||||
<t t-name="card">
|
||||
<div class="oe_kanban_card oe_kanban_global_click">
|
||||
<div class="o_kanban_record_top mb-0">
|
||||
<div class="o_kanban_record_headings">
|
||||
<strong class="o_kanban_record_title">
|
||||
<field name="job_id"/>
|
||||
</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="o_kanban_record_body">
|
||||
<div><strong><field name="name"/></strong></div>
|
||||
<div class="text-muted">
|
||||
<t t-if="record.assigned_user_id.raw_value">
|
||||
<field name="assigned_user_id"/>
|
||||
</t>
|
||||
<t t-if="record.duration_actual.raw_value">
|
||||
- <field name="duration_actual" widget="float_time"/> elapsed
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<div class="o_kanban_record_bottom">
|
||||
<div class="oe_kanban_bottom_left">
|
||||
<field name="state" widget="badge"
|
||||
decoration-info="state == 'ready'"
|
||||
decoration-warning="state == 'in_progress'"
|
||||
decoration-muted="state == 'paused'"
|
||||
decoration-success="state == 'done'"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_fp_step_priority_list" model="ir.ui.view">
|
||||
<field name="name">fp.job.step.priority.list</field>
|
||||
<field name="model">fp.job.step</field>
|
||||
<field name="arch" type="xml">
|
||||
<list default_order="sequence, id">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="job_id"/>
|
||||
<field name="work_centre_id"/>
|
||||
<field name="assigned_user_id"/>
|
||||
<field name="duration_expected" widget="float_time"/>
|
||||
<field name="duration_actual" widget="float_time"/>
|
||||
<field name="state" widget="badge"
|
||||
decoration-info="state == 'ready'"
|
||||
decoration-warning="state == 'in_progress'"
|
||||
decoration-muted="state == 'paused'"
|
||||
decoration-success="state == 'done'"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_fp_step_priority" model="ir.actions.act_window">
|
||||
<field name="name">Production Priorities</field>
|
||||
<field name="res_model">fp.job.step</field>
|
||||
<field name="view_mode">kanban,list,form</field>
|
||||
<field name="domain">[('state', 'in', ['pending', 'ready', 'in_progress', 'paused'])]</field>
|
||||
<field name="view_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'kanban', 'view_id': ref('view_fp_step_priority_kanban')}),
|
||||
(0, 0, {'view_mode': 'list', 'view_id': ref('view_fp_step_priority_list')})]"/>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_fp_step_priority"
|
||||
name="Production Priorities"
|
||||
parent="fusion_plating.menu_fp_operations"
|
||||
action="action_fp_step_priority"
|
||||
sequence="10"
|
||||
groups="fusion_plating.group_fusion_plating_supervisor"/>
|
||||
|
||||
</odoo>
|
||||
@@ -1,141 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2026 Nexa Systems Inc.
|
||||
License OPL-1 (Odoo Proprietary License v1.0)
|
||||
Sub 14 - Workflow state catalog UI (admin / Settings).
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<!-- ====================== List view ====================== -->
|
||||
<record id="view_fp_workflow_state_list" model="ir.ui.view">
|
||||
<field name="name">fp.job.workflow.state.list</field>
|
||||
<field name="model">fp.job.workflow.state</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Workflow States" default_order="sequence, id">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="color" widget="badge"
|
||||
decoration-info="color == 'blue'"
|
||||
decoration-success="color == 'success' or color == 'green'"
|
||||
decoration-warning="color == 'yellow' or color == 'orange'"
|
||||
decoration-danger="color == 'danger'"
|
||||
decoration-muted="color == 'grey'"/>
|
||||
<field name="trigger_default_kinds"/>
|
||||
<field name="trigger_first_step_started"/>
|
||||
<field name="trigger_all_steps_done"/>
|
||||
<field name="block_when_quality_hold"/>
|
||||
<field name="is_initial"/>
|
||||
<field name="is_terminal"/>
|
||||
<field name="active" widget="boolean_toggle"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ====================== Form view ====================== -->
|
||||
<record id="view_fp_workflow_state_form" model="ir.ui.view">
|
||||
<field name="name">fp.job.workflow.state.form</field>
|
||||
<field name="model">fp.job.workflow.state</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Workflow State">
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<label for="name"/>
|
||||
<h1><field name="name" placeholder="Received"/></h1>
|
||||
</div>
|
||||
|
||||
<group>
|
||||
<group string="Identity">
|
||||
<field name="code" placeholder="received"/>
|
||||
<field name="sequence"/>
|
||||
<field name="color" widget="badge"/>
|
||||
<field name="active"/>
|
||||
</group>
|
||||
<group string="Lifecycle role">
|
||||
<field name="is_initial"/>
|
||||
<field name="is_terminal"/>
|
||||
<field name="block_when_quality_hold"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<separator string="Trigger Conditions"/>
|
||||
<group>
|
||||
<field name="trigger_default_kinds"
|
||||
placeholder="receiving, inspect"/>
|
||||
<field name="trigger_first_step_started"/>
|
||||
<field name="trigger_all_steps_done"/>
|
||||
</group>
|
||||
|
||||
<!-- Help block - full sheet width, alert-info card so
|
||||
the explanation is readable instead of squeezed
|
||||
into a 2-column form layout. -->
|
||||
<div class="alert alert-info mt-3" role="alert">
|
||||
<h6 class="alert-heading mb-2">
|
||||
<i class="fa fa-info-circle me-2"/>
|
||||
How triggers combine
|
||||
</h6>
|
||||
<p class="mb-2">
|
||||
A state is <strong>"passed"</strong> when
|
||||
<strong>either</strong>:
|
||||
</p>
|
||||
<ul class="mb-2">
|
||||
<li>
|
||||
The special trigger is true
|
||||
(<code>trigger_first_step_started</code> or
|
||||
<code>trigger_all_steps_done</code>),
|
||||
<strong>OR</strong>
|
||||
</li>
|
||||
<li>
|
||||
Every recipe step matching the listed
|
||||
<code>trigger_default_kinds</code> (or tagged
|
||||
via the per-node override on the recipe) is
|
||||
in <code>done</code> / <code>skipped</code> /
|
||||
<code>cancelled</code> state.
|
||||
</li>
|
||||
</ul>
|
||||
<p class="mb-0">
|
||||
<strong>Blocked by Quality Hold:</strong> holds
|
||||
back the advance even if the trigger conditions
|
||||
are met, until all open quality holds on the job
|
||||
are closed.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<separator string="Notes"/>
|
||||
<field name="description" nolabel="1"
|
||||
placeholder="What this milestone represents and when it should fire..."/>
|
||||
</sheet>
|
||||
<!-- Chatter - adds activity log + message thread + followers
|
||||
so admins can audit who changed which trigger and when. -->
|
||||
<chatter/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ====================== Action + Menu ====================== -->
|
||||
<record id="action_fp_workflow_state" model="ir.actions.act_window">
|
||||
<field name="name">Workflow States</field>
|
||||
<field name="res_model">fp.job.workflow.state</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Create your first workflow state.
|
||||
</p>
|
||||
<p>
|
||||
Workflow states are the milestones that appear on the
|
||||
status bar of every plating job. Each state passes
|
||||
automatically when its trigger conditions are met
|
||||
(recipe step kind finishes, all steps done, etc.).
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Workflow milestones live under "Recipes & Steps" because each
|
||||
state is triggered by a recipe-step kind / per-step override. -->
|
||||
<menuitem id="menu_fp_workflow_state"
|
||||
name="Job Workflow Stages"
|
||||
parent="fusion_plating.menu_fp_config_recipes_steps"
|
||||
action="action_fp_workflow_state"
|
||||
sequence="50"/>
|
||||
|
||||
</odoo>
|
||||
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<!--
|
||||
Add "Work Orders" and "Steps" as children of fusion_plating_shopfloor's
|
||||
Shop Floor menu. We can reference shopfloor's xmlid here because
|
||||
fusion_plating_jobs declares it as a depend.
|
||||
|
||||
Sequences fit between Tablet Station (10) and Bake Windows (20)
|
||||
in shopfloor's existing fp_menu.xml.
|
||||
|
||||
Renamed 2026-05-25 - "All Jobs" → "Work Orders" for consistency
|
||||
with the rest of the UI (SO smart button is "WO", tablet cards
|
||||
show "WO # 00001", KPI tile says "Work Orders"). xmlid kept
|
||||
as menu_fp_jobs_all_jobs so bookmarks and inherits don't break.
|
||||
-->
|
||||
|
||||
<menuitem id="menu_fp_jobs_all_jobs"
|
||||
name="Work Orders"
|
||||
parent="fusion_plating_shopfloor.menu_fp_shopfloor"
|
||||
action="fusion_plating.action_fp_job"
|
||||
sequence="15"/>
|
||||
|
||||
<menuitem id="menu_fp_jobs_steps"
|
||||
name="Steps"
|
||||
parent="fusion_plating_shopfloor.menu_fp_shopfloor"
|
||||
action="fusion_plating.action_fp_job_step"
|
||||
sequence="17"
|
||||
groups="fusion_plating.group_fusion_plating_supervisor"/>
|
||||
</odoo>
|
||||
@@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo noupdate="0">
|
||||
<!-- After the shopfloor consolidation (2026-04-24) the shopfloor
|
||||
operator UIs are the canonical native fp.job / fp.job.step
|
||||
consoles. Only bridge_mrp's Production Priorities menu (still
|
||||
bound to mrp.workorder) remains legacy.
|
||||
|
||||
The group_fusion_plating_legacy_menus group is preserved so a
|
||||
site that needs to bring legacy menus back can simply add a
|
||||
user to the group. -->
|
||||
|
||||
<!-- Reset group_ids on the shopfloor menus that used to be
|
||||
hidden - they are now the canonical UIs and should be visible
|
||||
to all users (subject to the original groups= attribute on
|
||||
each menuitem in fusion_plating_shopfloor/views/fp_menu.xml). -->
|
||||
<record id="fusion_plating_shopfloor.menu_fp_shopfloor_manager" model="ir.ui.menu">
|
||||
<field name="group_ids" eval="[(6, 0, [ref('fusion_plating.group_fusion_plating_manager')])]"/>
|
||||
</record>
|
||||
<record id="fusion_plating_shopfloor.menu_fp_shopfloor_tablet" model="ir.ui.menu">
|
||||
<field name="group_ids" eval="[(6, 0, [])]"/>
|
||||
</record>
|
||||
|
||||
<!-- Phase 3 tablet redesign (2026-05-22) - the standalone Plant
|
||||
Overview menu was superseded by the single Workstation entry.
|
||||
The original <delete> directive lived here; it was retired
|
||||
2026-05-25 because the menu row had been gone for weeks and the
|
||||
re-run of `<delete model="ir.ui.menu" ref="...">` against a
|
||||
missing xmlid raises ValueError on every -u. The action record
|
||||
(action_fp_plant_overview) is kept and retargeted to
|
||||
fp_plant_kanban for bookmark back-compat. -->
|
||||
|
||||
<!-- bridge_mrp Production Priorities reference removed post-Sub 11
|
||||
(the bridge module is uninstalled and its menu xmlid no longer
|
||||
resolves). fp.job has its own priority field on the header. -->
|
||||
</odoo>
|
||||
@@ -1,39 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!--
|
||||
Add a plating-signature pad to the user preferences dialog.
|
||||
Anchors on the existing HTML 'signature' field (email signature)
|
||||
and adds our binary image-signature right after it. The
|
||||
widget="signature" gives finger / mouse drawing + image upload.
|
||||
-->
|
||||
<record id="view_users_preferences_form_fp_signature" model="ir.ui.view">
|
||||
<field name="name">res.users.preferences.form.fp.signature</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form_simple_modif"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='signature']" position="after">
|
||||
<field name="x_fc_signature_image"
|
||||
widget="signature"
|
||||
string="Plating Signature"
|
||||
options="{'full_name': 'name'}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Same field on the full user form (Settings > Users) so admins
|
||||
can review or seed signatures for operators who aren't tech-
|
||||
savvy enough to do it themselves. -->
|
||||
<record id="view_users_form_fp_signature" model="ir.ui.view">
|
||||
<field name="name">res.users.form.fp.signature</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='signature']" position="after">
|
||||
<field name="x_fc_signature_image"
|
||||
widget="signature"
|
||||
string="Plating Signature"
|
||||
options="{'full_name': 'name'}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,74 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2026 Nexa Systems Inc.
|
||||
License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
Adds the SO → fp.job smart button so the SO form is a hub for the
|
||||
native job lifecycle (replaces the legacy MO smart button when the
|
||||
use_native_jobs flag is on).
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<record id="view_sale_order_form_fp_jobs" model="ir.ui.view">
|
||||
<field name="name">sale.order.form.fp.jobs</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<!-- After the legacy Manufacturing button (added by bridge_mrp).
|
||||
Hidden at a count of 0 (2026-06-04) so the SO button row only
|
||||
shows what has data. A confirmed plating SO always has >=1 WO,
|
||||
so this only hides the button on drafts/quotations with no job
|
||||
yet; the header "Work Order" button below still reaches jobs
|
||||
when one is open. -->
|
||||
<xpath expr="//div[hasclass('oe_button_box')]" position="inside">
|
||||
<button name="action_view_fp_jobs" type="object"
|
||||
class="oe_stat_button" icon="fa-cogs"
|
||||
invisible="x_fc_fp_job_count == 0">
|
||||
<field name="x_fc_fp_job_count" widget="statinfo"
|
||||
string="WO"/>
|
||||
</button>
|
||||
<!-- Sarah/Tom path: SO → Certificates (one click instead -->
|
||||
<!-- of two via the job). Hidden until a cert exists. -->
|
||||
<button name="action_view_fp_certificates" type="object"
|
||||
class="oe_stat_button" icon="fa-certificate"
|
||||
invisible="x_fc_fp_certificate_count == 0">
|
||||
<field name="x_fc_fp_certificate_count" widget="statinfo"
|
||||
string="Certificates"/>
|
||||
</button>
|
||||
</xpath>
|
||||
|
||||
<!-- Work Order header action - appears once any linked
|
||||
receiving is closed AND at least one WO is still open.
|
||||
Reuses the existing action_view_fp_jobs smart-button
|
||||
target so single-job SOs land on the form directly. -->
|
||||
<xpath expr="//header" position="inside">
|
||||
<field name="x_fc_show_work_order_btn" invisible="1"/>
|
||||
<button name="action_view_fp_jobs"
|
||||
string="Work Order" type="object"
|
||||
class="btn-primary" icon="fa-cogs"
|
||||
invisible="not x_fc_show_work_order_btn"
|
||||
help="Open the Work Order(s) for this order. Hidden automatically once every linked WO is marked Done."/>
|
||||
</xpath>
|
||||
|
||||
<!-- Quote ref: small grey "Originally quoted as Q202605-200"
|
||||
line under the SO name (the big SO-30000 heading). Only
|
||||
renders once the SO has been confirmed (quote_ref is set
|
||||
on create, parent_number is set on confirm - both
|
||||
needed for the line to make sense).
|
||||
NB: Odoo 19 forbids t-if in standard form views - using
|
||||
`invisible` attribute on the wrapper div instead. -->
|
||||
<xpath expr="//div[hasclass('oe_title')]" position="inside">
|
||||
<field name="x_fc_parent_number" invisible="1"/>
|
||||
<div class="text-muted"
|
||||
style="font-size: 0.9em; margin-top: 4px;"
|
||||
invisible="not x_fc_quote_ref or not x_fc_parent_number">
|
||||
Originally quoted as
|
||||
<field name="x_fc_quote_ref"
|
||||
readonly="1" nolabel="1"
|
||||
class="d-inline"/>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user