feat(jobs): finish original plan — Job Margin, polish, legacy hide
Three batched changes that close out the original 10-phase
migration plan.
1. Phase 5 — Job Margin report bound to fp.job (replaces the
mrp.production-bound report_wo_margin). Per-step labour cost
table + margin summary using existing fp.job.step.cost_total
from Phase 1.
2. Polish:
- Real implementations for fp.job.step.button_pause,
button_skip, button_cancel (was NotImplementedError stubs).
button_pause closes the open timelog and sums duration_actual,
mirroring button_finish; button_skip/cancel transition state
with UserError guards.
- Explicit ondelete= policies on fp.job's cross-module Many2ones
(part_catalog/coating restrict, customer_spec/portal/delivery
set null) — was implicit set null.
- Standard Nexa Systems author/website/maintainer/support block
on fusion_plating_jobs manifest, suppressing the install
warning.
3. Legacy hide:
- New 'Plating Legacy Menus' group (group_fusion_plating_legacy_menus)
— nobody in it by default.
- Old shopfloor Manager Desk + Plant Overview + Tablet Station
menus restricted to that group, hiding them from operators
now that the native equivalents under 'Plating Jobs (Native)'
exist. (Note: ir.ui.menu uses group_ids in Odoo 19, not the
deprecated groups_id alias.)
Manifest 19.0.2.4.0 → 19.0.3.0.0. fusion_plating_shopfloor added
to depends so the legacy menu xmlid references resolve at install
time.
Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<record id="action_report_fp_job_margin" model="ir.actions.report">
|
||||
<field name="name">Job Margin Report</field>
|
||||
<field name="model">fp.job</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">fusion_plating_jobs.report_fp_job_margin_template</field>
|
||||
<field name="report_file">fusion_plating_jobs.report_fp_job_margin_template</field>
|
||||
<field name="print_report_name">'Job Margin - %s' % (object.name or '').replace('/', '-')</field>
|
||||
<field name="binding_model_id" ref="fusion_plating.model_fp_job"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
|
||||
<template id="report_fp_job_margin_template">
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="rows" t-as="row">
|
||||
<t t-call="web.external_layout">
|
||||
<div class="page">
|
||||
<h2>Job Margin — <span t-esc="row['job'].name"/></h2>
|
||||
<table class="table table-sm" style="margin-top: 1em; max-width: 600px;">
|
||||
<tr><th>Customer</th><td><span t-esc="row['job'].partner_id.name"/></td></tr>
|
||||
<tr><th>Recipe</th><td><span t-esc="row['job'].recipe_id.name or '-'"/></td></tr>
|
||||
<tr><th>Quantity</th><td><span t-esc="row['job'].qty"/></td></tr>
|
||||
<tr><th>Status</th><td><span t-esc="row['job'].state"/></td></tr>
|
||||
</table>
|
||||
|
||||
<h3 style="margin-top: 1.5em;">Step Breakdown</h3>
|
||||
<table class="table table-sm table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Step</th>
|
||||
<th>Work Centre</th>
|
||||
<th class="text-end">Expected (min)</th>
|
||||
<th class="text-end">Actual (min)</th>
|
||||
<th class="text-end">Rate / hr</th>
|
||||
<th class="text-end">Cost</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-foreach="row['steps']" t-as="step">
|
||||
<tr>
|
||||
<td><span t-esc="step['sequence']"/></td>
|
||||
<td><span t-esc="step['name']"/></td>
|
||||
<td><span t-esc="step['work_centre']"/></td>
|
||||
<td class="text-end"><span t-esc="step['duration_expected']"/></td>
|
||||
<td class="text-end"><span t-esc="step['duration_actual']"/></td>
|
||||
<td class="text-end"><span t-field="step['rate']" t-options="{'widget': 'monetary', 'display_currency': row['job'].currency_id}"/></td>
|
||||
<td class="text-end"><span t-field="step['cost']" t-options="{'widget': 'monetary', 'display_currency': row['job'].currency_id}"/></td>
|
||||
</tr>
|
||||
</t>
|
||||
<tr style="font-weight: bold; background: #f3f3f3;">
|
||||
<td colspan="3">Totals</td>
|
||||
<td></td>
|
||||
<td class="text-end"><span t-esc="row['total_minutes']"/></td>
|
||||
<td></td>
|
||||
<td class="text-end"><span t-field="row['total_labour']" t-options="{'widget': 'monetary', 'display_currency': row['job'].currency_id}"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3 style="margin-top: 1.5em;">Margin Summary</h3>
|
||||
<table class="table table-sm" style="max-width: 400px;">
|
||||
<tr><th>Quoted Revenue</th><td class="text-end"><span t-field="row['quoted_revenue']" t-options="{'widget': 'monetary', 'display_currency': row['job'].currency_id}"/></td></tr>
|
||||
<tr><th>Actual Cost</th><td class="text-end"><span t-field="row['actual_cost']" t-options="{'widget': 'monetary', 'display_currency': row['job'].currency_id}"/></td></tr>
|
||||
<tr style="font-weight: bold;"><th>Margin</th><td class="text-end"><span t-field="row['margin']" t-options="{'widget': 'monetary', 'display_currency': row['job'].currency_id}"/></td></tr>
|
||||
<tr><th>Margin %</th><td class="text-end"><span t-esc="round(row['margin_pct'], 1)"/>%</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user