folder rename

This commit is contained in:
gsinghpal
2026-04-16 20:53:53 -04:00
parent 3f3ddcbab4
commit 7c7ef06057
634 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
from . import models

View File

@@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
{
'name': 'Fusion Plating — Reports',
'version': '19.0.1.0.0',
'category': 'Manufacturing/Plating',
'summary': 'PDF reports for all Fusion Plating models: CoC, NCR, CAPA, bath logs, calibration, and more.',
'depends': [
'mrp',
'fusion_plating',
'fusion_plating_quality',
'fusion_plating_compliance',
'fusion_plating_safety',
'fusion_plating_portal',
],
'data': [
'security/ir.model.access.csv',
'report/report_base_styles.xml',
'report/report_actions.xml',
'report/report_coc.xml',
'report/report_ncr.xml',
'report/report_capa.xml',
'report/report_bath_chemistry_log.xml',
'report/report_calibration_cert.xml',
'report/report_fair.xml',
'report/report_audit.xml',
'report/report_incident.xml',
'report/report_spill.xml',
'report/report_waste_manifest.xml',
'report/report_discharge_sample.xml',
'report/report_wo_margin.xml',
],
'installable': True,
'application': False,
'auto_install': False,
'license': 'OPL-1',
}

View File

@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
# Part of the Fusion Plating product family.
from . import report_wo_margin

View File

@@ -0,0 +1,165 @@
# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
# Part of the Fusion Plating product family.
from odoo import api, models
class ReportWoMargin(models.AbstractModel):
"""Work Order Margin Report Data.
Computes cost, revenue, and margin breakdowns for manufacturing orders
so the QWeb template can render a Steelhead-style margin report.
"""
_name = 'report.fusion_plating_reports.report_wo_margin'
_description = 'WO Margin Report Data'
# ------------------------------------------------------------------
# helpers
# ------------------------------------------------------------------
def _get_station_costs(self, mo):
"""Return a list of dicts with per-station cost breakdown."""
station_costs = []
for wo in mo.workorder_ids:
wc = wo.workcenter_id
labour_rate = wc.costs_hour if wc else 0.0
# Sum tracked time from productivity records (minutes)
time_minutes = sum(wo.time_ids.mapped('duration'))
time_hours = time_minutes / 60.0
labour_cost = time_hours * labour_rate
# Operation cost uses the same rate & dwell for now
operation_rate = labour_rate
dwell_minutes = time_minutes
dwell_hours = dwell_minutes / 60.0
operation_cost = dwell_hours * operation_rate
total = labour_cost + operation_cost
station_costs.append({
'station': wc.name if wc else 'Unknown',
'labour_rate': labour_rate,
'labour_time': time_minutes,
'labour_hours': time_hours,
'labour_cost': labour_cost,
'operation_rate': operation_rate,
'dwell_time': dwell_minutes,
'dwell_hours': dwell_hours,
'operation_cost': operation_cost,
'total_cost': total,
})
return station_costs
def _get_part_margins(self, mo, revenue):
"""Return margin breakdown per unique product (part number)."""
parts = {}
for wo in mo.workorder_ids:
product = wo.product_id or mo.product_id
key = product.id
if key not in parts:
parts[key] = {
'product': product,
'part_number': product.default_code or product.name,
'count': 0,
'labour_cost': 0.0,
'station_labour_cost': 0.0,
'station_operation_cost': 0.0,
'outsourcing_cost': 0.0,
}
entry = parts[key]
entry['count'] += 1
time_hours = sum(wo.time_ids.mapped('duration')) / 60.0
rate = wo.workcenter_id.costs_hour if wo.workcenter_id else 0.0
cost = time_hours * rate
entry['labour_cost'] += cost
entry['station_labour_cost'] += cost
entry['station_operation_cost'] += cost
# Distribute revenue equally across parts for per-part metrics
part_list = list(parts.values())
total_parts = sum(p['count'] for p in part_list) or 1
for p in part_list:
p['so_total'] = revenue * (p['count'] / total_parts)
p['so_per_part'] = p['so_total'] / p['count'] if p['count'] else 0
p['unit_labour'] = p['labour_cost'] / p['count'] if p['count'] else 0
total_cost = (
p['labour_cost'] + p['station_labour_cost']
+ p['station_operation_cost'] + p['outsourcing_cost']
)
p['margin_pct'] = (
(p['so_total'] - total_cost) / p['so_total'] * 100
) if p['so_total'] else 0
return part_list
# ------------------------------------------------------------------
# Report entry point
# ------------------------------------------------------------------
@api.model
def _get_report_values(self, docids, data=None):
productions = self.env['mrp.production'].browse(docids)
docs = []
for mo in productions:
# Revenue from linked sale order
revenue = 0.0
if hasattr(mo, 'sale_order_id') and mo.sale_order_id:
revenue = sum(
mo.sale_order_id.order_line.mapped('price_subtotal')
)
# Station costs
station_costs = self._get_station_costs(mo)
part_labour_cost = sum(s['labour_cost'] for s in station_costs)
station_labour_cost = part_labour_cost # same pool
station_operation_cost = sum(
s['operation_cost'] for s in station_costs
)
# Inventory cost (raw materials)
inventory_cost = sum(
m.product_id.standard_price * m.quantity
for m in mo.move_raw_ids
)
# Outsourcing cost placeholder
outsourcing_cost = 0.0
total_cost = (
part_labour_cost + station_labour_cost
+ station_operation_cost + inventory_cost
+ outsourcing_cost
)
gross_profit = revenue - total_cost
margin_pct = (
(gross_profit / revenue * 100) if revenue else 0.0
)
# Station cost percentages
total_station_cost = sum(s['total_cost'] for s in station_costs)
for s in station_costs:
s['percentage'] = (
(s['total_cost'] / total_station_cost * 100)
if total_station_cost else 0
)
# Part margins
part_margins = self._get_part_margins(mo, revenue)
docs.append({
'mo': mo,
'revenue': revenue,
'part_labour_cost': part_labour_cost,
'station_labour_cost': station_labour_cost,
'station_operation_cost': station_operation_cost,
'inventory_cost': inventory_cost,
'outsourcing_cost': outsourcing_cost,
'total_cost': total_cost,
'gross_profit': gross_profit,
'margin_pct': margin_pct,
'station_costs': station_costs,
'part_margins': part_margins,
})
return {
'doc_ids': docids,
'docs': docs,
}

View File

@@ -0,0 +1,205 @@
<?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.
Paper format + report actions for all Fusion Plating reports.
-->
<odoo>
<!-- ============================================================= -->
<!-- Landscape Paper Format -->
<!-- ============================================================= -->
<record id="paperformat_fp_a4_landscape" model="report.paperformat">
<field name="name">A4 Landscape (Fusion Plating)</field>
<field name="default" eval="False"/>
<field name="format">A4</field>
<field name="orientation">Landscape</field>
<field name="margin_top">20</field>
<field name="margin_bottom">20</field>
<field name="margin_left">7</field>
<field name="margin_right">7</field>
<field name="header_line" eval="False"/>
<field name="header_spacing">20</field>
<field name="dpi">90</field>
</record>
<!-- ============================================================= -->
<!-- 1. Certificate of Conformance (Portal Job) -->
<!-- ============================================================= -->
<record id="action_report_coc" model="ir.actions.report">
<field name="name">Certificate of Conformance</field>
<field name="model">fusion.plating.portal.job</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">fusion_plating_reports.report_coc</field>
<field name="report_file">fusion_plating_reports.report_coc</field>
<field name="print_report_name">'CoC - %s' % object.name</field>
<field name="binding_model_id" ref="fusion_plating_portal.model_fusion_plating_portal_job"/>
<field name="binding_type">report</field>
<field name="paperformat_id" ref="paperformat_fp_a4_landscape"/>
</record>
<!-- ============================================================= -->
<!-- 2. Non-Conformance Report -->
<!-- ============================================================= -->
<record id="action_report_ncr" model="ir.actions.report">
<field name="name">Non-Conformance Report</field>
<field name="model">fusion.plating.ncr</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">fusion_plating_reports.report_ncr</field>
<field name="report_file">fusion_plating_reports.report_ncr</field>
<field name="print_report_name">'NCR - %s' % object.name</field>
<field name="binding_model_id" ref="fusion_plating_quality.model_fusion_plating_ncr"/>
<field name="binding_type">report</field>
<field name="paperformat_id" ref="paperformat_fp_a4_landscape"/>
</record>
<!-- ============================================================= -->
<!-- 3. Corrective / Preventive Action -->
<!-- ============================================================= -->
<record id="action_report_capa" model="ir.actions.report">
<field name="name">CAPA Report</field>
<field name="model">fusion.plating.capa</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">fusion_plating_reports.report_capa</field>
<field name="report_file">fusion_plating_reports.report_capa</field>
<field name="print_report_name">'CAPA - %s' % object.name</field>
<field name="binding_model_id" ref="fusion_plating_quality.model_fusion_plating_capa"/>
<field name="binding_type">report</field>
<field name="paperformat_id" ref="paperformat_fp_a4_landscape"/>
</record>
<!-- ============================================================= -->
<!-- 4. Bath Chemistry Log -->
<!-- ============================================================= -->
<record id="action_report_bath_log" model="ir.actions.report">
<field name="name">Bath Chemistry Log</field>
<field name="model">fusion.plating.bath.log</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">fusion_plating_reports.report_bath_chemistry_log</field>
<field name="report_file">fusion_plating_reports.report_bath_chemistry_log</field>
<field name="print_report_name">'Bath Log - %s' % object.name</field>
<field name="binding_model_id" ref="fusion_plating.model_fusion_plating_bath_log"/>
<field name="binding_type">report</field>
<field name="paperformat_id" ref="paperformat_fp_a4_landscape"/>
</record>
<!-- ============================================================= -->
<!-- 5. Calibration Certificate -->
<!-- ============================================================= -->
<record id="action_report_calibration" model="ir.actions.report">
<field name="name">Calibration Certificate</field>
<field name="model">fusion.plating.calibration.equipment</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">fusion_plating_reports.report_calibration_cert</field>
<field name="report_file">fusion_plating_reports.report_calibration_cert</field>
<field name="print_report_name">'Calibration - %s' % object.code</field>
<field name="binding_model_id" ref="fusion_plating_quality.model_fusion_plating_calibration_equipment"/>
<field name="binding_type">report</field>
<field name="paperformat_id" ref="paperformat_fp_a4_landscape"/>
</record>
<!-- ============================================================= -->
<!-- 6. First Article Inspection Report -->
<!-- ============================================================= -->
<record id="action_report_fair" model="ir.actions.report">
<field name="name">FAIR Report</field>
<field name="model">fusion.plating.fair</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">fusion_plating_reports.report_fair</field>
<field name="report_file">fusion_plating_reports.report_fair</field>
<field name="print_report_name">'FAIR - %s' % object.name</field>
<field name="binding_model_id" ref="fusion_plating_quality.model_fusion_plating_fair"/>
<field name="binding_type">report</field>
<field name="paperformat_id" ref="paperformat_fp_a4_landscape"/>
</record>
<!-- ============================================================= -->
<!-- 7. Audit Report -->
<!-- ============================================================= -->
<record id="action_report_audit" model="ir.actions.report">
<field name="name">Audit Report</field>
<field name="model">fusion.plating.audit</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">fusion_plating_reports.report_audit</field>
<field name="report_file">fusion_plating_reports.report_audit</field>
<field name="print_report_name">'Audit - %s' % object.name</field>
<field name="binding_model_id" ref="fusion_plating_quality.model_fusion_plating_audit"/>
<field name="binding_type">report</field>
<field name="paperformat_id" ref="paperformat_fp_a4_landscape"/>
</record>
<!-- ============================================================= -->
<!-- 8. Incident Report -->
<!-- ============================================================= -->
<record id="action_report_incident" model="ir.actions.report">
<field name="name">Incident Report</field>
<field name="model">fusion.plating.incident</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">fusion_plating_reports.report_incident</field>
<field name="report_file">fusion_plating_reports.report_incident</field>
<field name="print_report_name">'Incident - %s' % object.name</field>
<field name="binding_model_id" ref="fusion_plating_safety.model_fusion_plating_incident"/>
<field name="binding_type">report</field>
<field name="paperformat_id" ref="paperformat_fp_a4_landscape"/>
</record>
<!-- ============================================================= -->
<!-- 9. Spill Register -->
<!-- ============================================================= -->
<record id="action_report_spill" model="ir.actions.report">
<field name="name">Spill Report</field>
<field name="model">fusion.plating.spill.register</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">fusion_plating_reports.report_spill</field>
<field name="report_file">fusion_plating_reports.report_spill</field>
<field name="print_report_name">'Spill - %s' % object.name</field>
<field name="binding_model_id" ref="fusion_plating_compliance.model_fusion_plating_spill_register"/>
<field name="binding_type">report</field>
<field name="paperformat_id" ref="paperformat_fp_a4_landscape"/>
</record>
<!-- ============================================================= -->
<!-- 10. Waste Manifest -->
<!-- ============================================================= -->
<record id="action_report_waste_manifest" model="ir.actions.report">
<field name="name">Waste Manifest</field>
<field name="model">fusion.plating.waste.manifest</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">fusion_plating_reports.report_waste_manifest</field>
<field name="report_file">fusion_plating_reports.report_waste_manifest</field>
<field name="print_report_name">'Waste Manifest - %s' % object.name</field>
<field name="binding_model_id" ref="fusion_plating_compliance.model_fusion_plating_waste_manifest"/>
<field name="binding_type">report</field>
<field name="paperformat_id" ref="paperformat_fp_a4_landscape"/>
</record>
<!-- ============================================================= -->
<!-- 11. Discharge Sample -->
<!-- ============================================================= -->
<record id="action_report_discharge_sample" model="ir.actions.report">
<field name="name">Discharge Sample Report</field>
<field name="model">fusion.plating.discharge.sample</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">fusion_plating_reports.report_discharge_sample</field>
<field name="report_file">fusion_plating_reports.report_discharge_sample</field>
<field name="print_report_name">'Discharge - %s' % object.name</field>
<field name="binding_model_id" ref="fusion_plating_compliance.model_fusion_plating_discharge_sample"/>
<field name="binding_type">report</field>
<field name="paperformat_id" ref="paperformat_fp_a4_landscape"/>
</record>
<!-- ============================================================= -->
<!-- 12. Work Order Margin Report -->
<!-- ============================================================= -->
<record id="action_report_wo_margin" model="ir.actions.report">
<field name="name">Work Order Margin Report</field>
<field name="model">mrp.production</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">fusion_plating_reports.report_wo_margin</field>
<field name="report_file">fusion_plating_reports.report_wo_margin</field>
<field name="print_report_name">'Margin Report - %s' % object.name</field>
<field name="binding_model_id" ref="mrp.model_mrp_production"/>
<field name="binding_type">report</field>
<field name="paperformat_id" ref="paperformat_fp_a4_landscape"/>
</record>
</odoo>

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Audit Report
-->
<odoo>
<template id="report_audit">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="web.external_layout">
<t t-call="fusion_plating_reports.fp_landscape_styles"/>
<div class="fp-landscape">
<div class="page">
<h2 style="text-align: left;">
Audit Report
<span t-field="doc.name"/>
</h2>
<!-- Header Info -->
<table class="bordered info-table">
<thead><tr>
<th>AUDIT #</th>
<th>TYPE</th>
<th>SCOPE</th>
<th>FACILITY</th>
<th>AUDIT DATE</th>
<th>STATUS</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.name"/></td>
<td class="text-center"><span t-field="doc.audit_type"/></td>
<td class="text-center"><span t-field="doc.scope"/></td>
<td class="text-center"><span t-field="doc.facility_id"/></td>
<td class="text-center"><span t-field="doc.audit_date" t-options="{'widget': 'date'}"/></td>
<td class="text-center"><span t-field="doc.state"/></td>
</tr></tbody>
</table>
<!-- Auditors & Stats -->
<table class="bordered info-table">
<thead><tr>
<th>AUDITORS</th>
<th># FINDINGS</th>
<th>LINKED CAPAs</th>
</tr></thead>
<tbody><tr>
<td class="text-center">
<t t-foreach="doc.auditor_ids" t-as="aud">
<span t-out="aud.name"/>
<t t-if="not aud_last">, </t>
</t>
</td>
<td class="text-center"><span t-field="doc.findings_count"/></td>
<td class="text-center"><span t-field="doc.capa_count"/></td>
</tr></tbody>
</table>
<!-- Findings -->
<t t-if="doc.findings_html">
<table class="bordered">
<tr class="section-row"><td>FINDINGS</td></tr>
<tr><td><t t-out="doc.findings_html"/></td></tr>
</table>
</t>
<!-- Linked CAPAs Table -->
<t t-if="doc.capa_ids">
<table class="bordered">
<thead><tr>
<th>CAPA #</th>
<th>TYPE</th>
<th>STATUS</th>
<th>OWNER</th>
<th>DUE DATE</th>
</tr></thead>
<tbody>
<t t-foreach="doc.capa_ids" t-as="capa">
<tr>
<td><span t-field="capa.name"/></td>
<td class="text-center"><span t-field="capa.type"/></td>
<td class="text-center"><span t-field="capa.state"/></td>
<td class="text-center"><span t-field="capa.owner_id"/></td>
<td class="text-center"><span t-field="capa.due_date" t-options="{'widget': 'date'}"/></td>
</tr>
</t>
</tbody>
</table>
</t>
</div>
</div>
</t>
</t>
</t>
</template>
</odoo>

View File

@@ -0,0 +1,33 @@
<?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.
Shared landscape CSS for all Fusion Plating reports.
-->
<odoo>
<template id="fp_landscape_styles">
<style>
.fp-landscape { font-family: Arial, sans-serif; font-size: 11pt; }
.fp-landscape table { width: 100%; border-collapse: collapse; margin-bottom: 12px; }
.fp-landscape table.bordered, .fp-landscape table.bordered th, .fp-landscape table.bordered td { border: 1px solid #000; }
.fp-landscape th { background-color: #0066a1; color: white; padding: 8px 10px; font-weight: bold; font-size: 10pt; }
.fp-landscape td { padding: 6px 8px; vertical-align: top; font-size: 10pt; }
.fp-landscape .text-center { text-align: center; }
.fp-landscape .text-end { text-align: right; }
.fp-landscape .text-start { text-align: left; }
.fp-landscape .adp-bg { background-color: #e3f2fd; }
.fp-landscape .client-bg { background-color: #fff3e0; }
.fp-landscape .section-row { background-color: #f0f0f0; font-weight: bold; }
.fp-landscape .note-row { font-style: italic; }
.fp-landscape h2 { color: #0066a1; margin: 10px 0; font-size: 18pt; }
.fp-landscape .info-table td { padding: 8px 12px; font-size: 11pt; }
.fp-landscape .info-table th { background-color: #f5f5f5; color: #333; font-size: 10pt; padding: 6px 12px; }
.fp-landscape .totals-table { border: 1px solid #000; }
.fp-landscape .totals-table td { border: 1px solid #000; padding: 8px 12px; font-size: 11pt; }
.fp-landscape .status-ok { color: #2e7d32; font-weight: bold; }
.fp-landscape .status-warning { color: #f57f17; font-weight: bold; }
.fp-landscape .status-fail { color: #c62828; font-weight: bold; }
</style>
</template>
</odoo>

View File

@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Bath Chemistry Log Report
-->
<odoo>
<template id="report_bath_chemistry_log">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="web.external_layout">
<t t-call="fusion_plating_reports.fp_landscape_styles"/>
<div class="fp-landscape">
<div class="page">
<h2 style="text-align: left;">
Bath Chemistry Log
<span t-field="doc.name"/>
</h2>
<!-- Header Info -->
<table class="bordered info-table">
<thead><tr>
<th>LOG REF</th>
<th>BATH</th>
<th>TANK</th>
<th>PROCESS TYPE</th>
<th>LOGGED AT</th>
<th>OPERATOR</th>
<th>SHIFT</th>
<th>STATUS</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.name"/></td>
<td class="text-center"><span t-field="doc.bath_id"/></td>
<td class="text-center"><span t-field="doc.tank_id"/></td>
<td class="text-center"><span t-field="doc.process_type_id"/></td>
<td class="text-center"><span t-field="doc.log_date" t-options="{'widget': 'date'}"/></td>
<td class="text-center"><span t-field="doc.operator_id"/></td>
<td class="text-center"><span t-field="doc.shift"/></td>
<td class="text-center">
<span t-if="doc.status == 'ok'" class="status-ok">OK</span>
<span t-if="doc.status == 'warning'" class="status-warning">Warning</span>
<span t-if="doc.status == 'out_of_spec'" class="status-fail">Out of Spec</span>
</td>
</tr></tbody>
</table>
<!-- Readings Table -->
<t t-if="doc.line_ids">
<table class="bordered">
<thead><tr>
<th>PARAMETER</th>
<th>VALUE</th>
<th>TARGET MIN</th>
<th>TARGET MAX</th>
<th>UoM</th>
<th>STATUS</th>
<th>NOTES</th>
</tr></thead>
<tbody>
<t t-foreach="doc.line_ids" t-as="line">
<tr>
<td><span t-field="line.parameter_id"/></td>
<td class="text-center"><span t-field="line.value"/></td>
<td class="text-center"><span t-field="line.target_min"/></td>
<td class="text-center"><span t-field="line.target_max"/></td>
<td class="text-center"><span t-field="line.uom"/></td>
<td class="text-center">
<span t-if="line.status == 'ok'" class="status-ok">OK</span>
<span t-if="line.status == 'warning'" class="status-warning">Warning</span>
<span t-if="line.status == 'out_of_spec'" class="status-fail">Out of Spec</span>
</td>
<td><span t-field="line.notes"/></td>
</tr>
</t>
</tbody>
</table>
</t>
<!-- Notes -->
<t t-if="doc.notes">
<table class="bordered">
<tr class="section-row"><td>NOTES</td></tr>
<tr><td><span t-field="doc.notes"/></td></tr>
</table>
</t>
</div>
</div>
</t>
</t>
</t>
</template>
</odoo>

View File

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Calibration Certificate Report
-->
<odoo>
<template id="report_calibration_cert">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="web.external_layout">
<t t-call="fusion_plating_reports.fp_landscape_styles"/>
<div class="fp-landscape">
<div class="page">
<h2 style="text-align: left;">
Calibration Certificate
<span t-field="doc.code"/>
</h2>
<!-- Equipment Info -->
<table class="bordered info-table">
<thead><tr>
<th>EQUIPMENT</th>
<th>ASSET CODE</th>
<th>TYPE</th>
<th>NIST TRACEABLE</th>
<th>STATUS</th>
<th>FACILITY</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.name"/></td>
<td class="text-center"><span t-field="doc.code"/></td>
<td class="text-center"><span t-field="doc.equipment_type"/></td>
<td class="text-center">
<t t-if="doc.nist_traceable">Yes</t>
<t t-else="">No</t>
</td>
<td class="text-center"><span t-field="doc.state"/></td>
<td class="text-center"><span t-field="doc.facility_id"/></td>
</tr></tbody>
</table>
<!-- Calibration Dates -->
<table class="bordered info-table">
<thead><tr>
<th>LAST CALIBRATION</th>
<th>NEXT CALIBRATION</th>
<th>INTERVAL (DAYS)</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.last_cal_date" t-options="{'widget': 'date'}"/></td>
<td class="text-center"><span t-field="doc.next_cal_date" t-options="{'widget': 'date'}"/></td>
<td class="text-center"><span t-field="doc.calibration_interval_days"/></td>
</tr></tbody>
</table>
<!-- Event History -->
<t t-if="doc.event_ids">
<table class="bordered">
<thead><tr>
<th>CALIBRATION DATE</th>
<th>PERFORMED BY</th>
<th>EXTERNAL LAB</th>
<th>RESULT</th>
<th>CERTIFICATE #</th>
<th>AS-FOUND</th>
<th>AS-LEFT</th>
</tr></thead>
<tbody>
<t t-foreach="doc.event_ids" t-as="evt">
<tr>
<td class="text-center"><span t-field="evt.cal_date" t-options="{'widget': 'date'}"/></td>
<td class="text-center"><span t-field="evt.performed_by_id"/></td>
<td class="text-center"><span t-field="evt.performed_by_external"/></td>
<td class="text-center"><span t-field="evt.result"/></td>
<td class="text-center"><span t-field="evt.certificate_ref"/></td>
<td><span t-field="evt.as_found_notes"/></td>
<td><span t-field="evt.as_left_notes"/></td>
</tr>
</t>
</tbody>
</table>
</t>
</div>
</div>
</t>
</t>
</t>
</template>
</odoo>

View File

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Corrective / Preventive Action Report
-->
<odoo>
<template id="report_capa">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="web.external_layout">
<t t-call="fusion_plating_reports.fp_landscape_styles"/>
<div class="fp-landscape">
<div class="page">
<h2 style="text-align: left;">
CAPA Report
<span t-field="doc.name"/>
</h2>
<!-- Header Info -->
<table class="bordered info-table">
<thead><tr>
<th>CAPA #</th>
<th>TYPE</th>
<th>STATUS</th>
<th>SOURCE NCR</th>
<th>OWNER</th>
<th>DUE DATE</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.name"/></td>
<td class="text-center"><span t-field="doc.type"/></td>
<td class="text-center"><span t-field="doc.state"/></td>
<td class="text-center"><span t-field="doc.ncr_id"/></td>
<td class="text-center"><span t-field="doc.owner_id"/></td>
<td class="text-center"><span t-field="doc.due_date" t-options="{'widget': 'date'}"/></td>
</tr></tbody>
</table>
<!-- Facility -->
<table class="bordered info-table">
<thead><tr>
<th>FACILITY</th>
<th>VERIFIED BY</th>
<th>VERIFICATION DATE</th>
<th>EFFECTIVE</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.facility_id"/></td>
<td class="text-center"><span t-field="doc.verification_by_id"/></td>
<td class="text-center"><span t-field="doc.verification_date" t-options="{'widget': 'date'}"/></td>
<td class="text-center">
<t t-if="doc.is_effective">Yes</t>
<t t-else="">No</t>
</td>
</tr></tbody>
</table>
<!-- Description -->
<table class="bordered">
<tr class="section-row"><td>DESCRIPTION</td></tr>
<tr><td><t t-out="doc.description"/></td></tr>
</table>
<!-- Root Cause Analysis -->
<t t-if="doc.root_cause_analysis">
<table class="bordered">
<tr class="section-row"><td>ROOT CAUSE ANALYSIS</td></tr>
<tr><td><t t-out="doc.root_cause_analysis"/></td></tr>
</table>
</t>
<!-- Action Plan -->
<t t-if="doc.action_plan">
<table class="bordered">
<tr class="section-row"><td>ACTION PLAN</td></tr>
<tr><td><t t-out="doc.action_plan"/></td></tr>
</table>
</t>
<!-- Effectiveness Notes -->
<t t-if="doc.effectiveness_notes">
<table class="bordered">
<tr class="section-row"><td>EFFECTIVENESS NOTES</td></tr>
<tr><td><t t-out="doc.effectiveness_notes"/></td></tr>
</table>
</t>
</div>
</div>
</t>
</t>
</t>
</template>
</odoo>

View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Certificate of Conformance — Portal Job
-->
<odoo>
<template id="report_coc">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="web.external_layout">
<t t-call="fusion_plating_reports.fp_landscape_styles"/>
<div class="fp-landscape">
<div class="page">
<h2 style="text-align: left;">
Certificate of Conformance
<span t-field="doc.name"/>
</h2>
<!-- Job Info -->
<table class="bordered info-table">
<thead><tr>
<th>JOB REF</th>
<th>CUSTOMER</th>
<th>QUANTITY</th>
<th>RECEIVED</th>
<th>SHIP DATE</th>
<th>TRACKING REF</th>
<th>STATUS</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.name"/></td>
<td><span t-field="doc.partner_id"/></td>
<td class="text-center"><span t-field="doc.quantity"/></td>
<td class="text-center"><span t-field="doc.received_date" t-options="{'widget': 'date'}"/></td>
<td class="text-center"><span t-field="doc.actual_ship_date" t-options="{'widget': 'date'}"/></td>
<td class="text-center"><span t-field="doc.tracking_ref"/></td>
<td class="text-center"><span t-field="doc.state"/></td>
</tr></tbody>
</table>
<!-- Customer Address -->
<table class="bordered">
<thead><tr>
<th colspan="2">CUSTOMER DETAILS</th>
</tr></thead>
<tbody>
<tr>
<td style="width:30%; font-weight:bold;">Name</td>
<td><span t-field="doc.partner_id.name"/></td>
</tr>
<tr>
<td style="font-weight:bold;">Address</td>
<td>
<span t-field="doc.partner_id" t-options="{'widget': 'contact', 'fields': ['address'], 'no_marker': True}"/>
</td>
</tr>
</tbody>
</table>
<!-- Processes -->
<table class="bordered" t-if="doc.process_type_ids">
<thead><tr>
<th>PROCESSES APPLIED</th>
</tr></thead>
<tbody><tr>
<td>
<t t-foreach="doc.process_type_ids" t-as="pt">
<span t-out="pt.name"/>
<t t-if="not pt_last">, </t>
</t>
</td>
</tr></tbody>
</table>
<!-- Certification Statement -->
<table class="bordered">
<tr class="section-row"><td>CERTIFICATION</td></tr>
<tr><td style="padding: 16px 12px; font-size: 11pt;">
This certifies that the above items were processed in accordance
with applicable specifications and meet all requirements as stated
in the purchase order. All work was performed in compliance with
the quality management system.
</td></tr>
</table>
<!-- Notes -->
<t t-if="doc.notes">
<table class="bordered">
<tr class="section-row"><td>NOTES</td></tr>
<tr><td><t t-out="doc.notes"/></td></tr>
</table>
</t>
<!-- Signature Block -->
<table class="bordered" style="margin-top: 30px;">
<tbody>
<tr>
<td style="width:50%; height: 60px; vertical-align: bottom; font-weight: bold;">
Quality Manager Signature: ___________________________
</td>
<td style="width:50%; height: 60px; vertical-align: bottom; font-weight: bold;">
Date: ___________________________
</td>
</tr>
</tbody>
</table>
</div>
</div>
</t>
</t>
</t>
</template>
</odoo>

View File

@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Discharge Sample Report
-->
<odoo>
<template id="report_discharge_sample">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="web.external_layout">
<t t-call="fusion_plating_reports.fp_landscape_styles"/>
<div class="fp-landscape">
<div class="page">
<h2 style="text-align: left;">
Discharge Sample Report
<span t-field="doc.name"/>
</h2>
<!-- Header Info -->
<table class="bordered info-table">
<thead><tr>
<th>SAMPLE #</th>
<th>SAMPLE DATE</th>
<th>FACILITY</th>
<th>SAMPLE POINT</th>
<th>STATUS</th>
<th>WORST RESULT</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.name"/></td>
<td class="text-center"><span t-field="doc.sample_date" t-options="{'widget': 'date'}"/></td>
<td class="text-center"><span t-field="doc.facility_id"/></td>
<td class="text-center"><span t-field="doc.sample_point"/></td>
<td class="text-center"><span t-field="doc.state"/></td>
<td class="text-center">
<span t-if="doc.worst_status == 'ok'" class="status-ok">OK</span>
<span t-if="doc.worst_status == 'warning'" class="status-warning">Warning</span>
<span t-if="doc.worst_status == 'out_of_spec'" class="status-fail">Out of Spec</span>
<span t-if="doc.worst_status == 'pending'" style="color: #666;">Pending</span>
</td>
</tr></tbody>
</table>
<!-- Lab Details -->
<table class="bordered info-table">
<thead><tr>
<th>COLLECTED BY</th>
<th>CHAIN OF CUSTODY #</th>
<th>LAB</th>
<th>LAB REPORT #</th>
<th>RESULTS RECEIVED</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.collected_by_id"/></td>
<td class="text-center"><span t-field="doc.chain_of_custody_ref"/></td>
<td class="text-center"><span t-field="doc.lab_id"/></td>
<td class="text-center"><span t-field="doc.lab_report_ref"/></td>
<td class="text-center"><span t-field="doc.received_date" t-options="{'widget': 'date'}"/></td>
</tr></tbody>
</table>
<!-- Parameter Lines -->
<t t-if="doc.line_ids">
<table class="bordered">
<thead><tr>
<th>PARAMETER</th>
<th>RESULT</th>
<th>UoM</th>
<th>STATUS</th>
<th>NOTE</th>
</tr></thead>
<tbody>
<t t-foreach="doc.line_ids" t-as="line">
<tr>
<td><span t-field="line.parameter"/></td>
<td class="text-center"><span t-field="line.value"/></td>
<td class="text-center"><span t-field="line.uom"/></td>
<td class="text-center">
<span t-if="line.status == 'ok'" class="status-ok">OK</span>
<span t-if="line.status == 'warning'" class="status-warning">Warning</span>
<span t-if="line.status == 'out_of_spec'" class="status-fail">Out of Spec</span>
<span t-if="line.status == 'pending'" style="color: #666;">Pending</span>
</td>
<td><span t-field="line.notes"/></td>
</tr>
</t>
</tbody>
</table>
</t>
<!-- Notes -->
<t t-if="doc.notes">
<table class="bordered">
<tr class="section-row"><td>NOTES</td></tr>
<tr><td><t t-out="doc.notes"/></td></tr>
</table>
</t>
</div>
</div>
</t>
</t>
</t>
</template>
</odoo>

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
First Article Inspection Report
-->
<odoo>
<template id="report_fair">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="web.external_layout">
<t t-call="fusion_plating_reports.fp_landscape_styles"/>
<div class="fp-landscape">
<div class="page">
<h2 style="text-align: left;">
First Article Inspection Report
<span t-field="doc.name"/>
</h2>
<!-- Header Info -->
<table class="bordered info-table">
<thead><tr>
<th>FAIR #</th>
<th>PART NUMBER</th>
<th>REVISION</th>
<th>CUSTOMER</th>
<th>RESULT</th>
<th>STATUS</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.name"/></td>
<td class="text-center"><span t-field="doc.part_number"/></td>
<td class="text-center"><span t-field="doc.part_revision"/></td>
<td class="text-center"><span t-field="doc.customer_id"/></td>
<td class="text-center">
<span t-if="doc.result == 'pass'" class="status-ok">Pass</span>
<span t-if="doc.result == 'fail'" class="status-fail">Fail</span>
<span t-if="doc.result == 'conditional'" class="status-warning">Conditional</span>
</td>
<td class="text-center"><span t-field="doc.state"/></td>
</tr></tbody>
</table>
<!-- Inspection Details -->
<table class="bordered info-table">
<thead><tr>
<th>INSPECTION DATE</th>
<th>INSPECTOR</th>
<th>PROCESSES</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.performed_date" t-options="{'widget': 'date'}"/></td>
<td class="text-center"><span t-field="doc.performed_by_id"/></td>
<td class="text-center">
<t t-foreach="doc.process_type_ids" t-as="pt">
<span t-out="pt.name"/>
<t t-if="not pt_last">, </t>
</t>
</td>
</tr></tbody>
</table>
<!-- Notes / Findings -->
<t t-if="doc.notes">
<table class="bordered">
<tr class="section-row"><td>FINDINGS / NOTES</td></tr>
<tr><td><t t-out="doc.notes"/></td></tr>
</table>
</t>
</div>
</div>
</t>
</t>
</t>
</template>
</odoo>

View File

@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Incident Report
-->
<odoo>
<template id="report_incident">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="web.external_layout">
<t t-call="fusion_plating_reports.fp_landscape_styles"/>
<div class="fp-landscape">
<div class="page">
<h2 style="text-align: left;">
Incident Report
<span t-field="doc.name"/>
</h2>
<!-- Header Info -->
<table class="bordered info-table">
<thead><tr>
<th>INCIDENT #</th>
<th>DATE</th>
<th>FACILITY</th>
<th>TYPE</th>
<th>STATUS</th>
<th>REPORTED BY</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.name"/></td>
<td class="text-center"><span t-field="doc.incident_date" t-options="{'widget': 'date'}"/></td>
<td class="text-center"><span t-field="doc.facility_id"/></td>
<td class="text-center"><span t-field="doc.incident_type"/></td>
<td class="text-center"><span t-field="doc.state"/></td>
<td class="text-center"><span t-field="doc.reported_by_id"/></td>
</tr></tbody>
</table>
<!-- Employee / Location / WSIB -->
<table class="bordered info-table">
<thead><tr>
<th>EMPLOYEE INVOLVED</th>
<th>LOCATION</th>
<th>WSIB REPORTABLE</th>
<th>WSIB FORM 7 SUBMITTED</th>
<th>LOST-TIME DAYS</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.employee_id"/></td>
<td class="text-center"><span t-field="doc.location"/></td>
<td class="text-center">
<t t-if="doc.wsib_reportable">Yes</t>
<t t-else="">No</t>
</td>
<td class="text-center">
<t t-if="doc.wsib_form_7_submitted">Yes</t>
<t t-else="">No</t>
</td>
<td class="text-center"><span t-field="doc.lost_time_days"/></td>
</tr></tbody>
</table>
<!-- Description -->
<table class="bordered">
<tr class="section-row"><td>DESCRIPTION</td></tr>
<tr><td><t t-out="doc.description"/></td></tr>
</table>
<!-- Immediate Action -->
<t t-if="doc.immediate_action">
<table class="bordered">
<tr class="section-row"><td>IMMEDIATE ACTION</td></tr>
<tr><td><t t-out="doc.immediate_action"/></td></tr>
</table>
</t>
<!-- Investigation -->
<t t-if="doc.investigation">
<table class="bordered">
<tr class="section-row"><td>INVESTIGATION</td></tr>
<tr><td><t t-out="doc.investigation"/></td></tr>
</table>
</t>
<!-- Root Cause -->
<t t-if="doc.root_cause">
<table class="bordered">
<tr class="section-row"><td>ROOT CAUSE</td></tr>
<tr><td><t t-out="doc.root_cause"/></td></tr>
</table>
</t>
<!-- Corrective Action -->
<t t-if="doc.corrective_action">
<table class="bordered">
<tr class="section-row"><td>CORRECTIVE ACTION</td></tr>
<tr><td><t t-out="doc.corrective_action"/></td></tr>
</table>
</t>
</div>
</div>
</t>
</t>
</t>
</template>
</odoo>

View File

@@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Non-Conformance Report
-->
<odoo>
<template id="report_ncr">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="web.external_layout">
<t t-call="fusion_plating_reports.fp_landscape_styles"/>
<div class="fp-landscape">
<div class="page">
<h2 style="text-align: left;">
Non-Conformance Report
<span t-field="doc.name"/>
</h2>
<!-- Header Info -->
<table class="bordered info-table">
<thead><tr>
<th>NCR #</th>
<th>STATUS</th>
<th>FACILITY</th>
<th>SEVERITY</th>
<th>SOURCE</th>
<th>REPORTED</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.name"/></td>
<td class="text-center"><span t-field="doc.state"/></td>
<td class="text-center"><span t-field="doc.facility_id"/></td>
<td class="text-center"><span t-field="doc.severity"/></td>
<td class="text-center"><span t-field="doc.source"/></td>
<td class="text-center"><span t-field="doc.reported_date" t-options="{'widget': 'date'}"/></td>
</tr></tbody>
</table>
<!-- Secondary Info -->
<table class="bordered info-table">
<thead><tr>
<th>REPORTED BY</th>
<th>PART / LOT</th>
<th>QTY AFFECTED</th>
<th>BATH</th>
<th>CUSTOMER</th>
<th>DISPOSITION</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.reported_by_id"/></td>
<td class="text-center"><span t-field="doc.part_ref"/></td>
<td class="text-center"><span t-field="doc.quantity_affected"/></td>
<td class="text-center"><span t-field="doc.bath_id"/></td>
<td class="text-center"><span t-field="doc.customer_partner_id"/></td>
<td class="text-center"><span t-field="doc.disposition"/></td>
</tr></tbody>
</table>
<!-- Description -->
<table class="bordered">
<tr class="section-row"><td>DESCRIPTION</td></tr>
<tr><td><t t-out="doc.description"/></td></tr>
</table>
<!-- Root Cause -->
<t t-if="doc.root_cause">
<table class="bordered">
<tr class="section-row"><td>ROOT CAUSE</td></tr>
<tr><td><t t-out="doc.root_cause"/></td></tr>
</table>
</t>
<!-- Containment -->
<t t-if="doc.containment">
<table class="bordered">
<tr class="section-row"><td>CONTAINMENT ACTIONS</td></tr>
<tr><td><t t-out="doc.containment"/></td></tr>
</table>
</t>
<!-- Linked CAPAs -->
<t t-if="doc.capa_ids">
<table class="bordered">
<thead><tr>
<th>LINKED CAPA</th>
<th>TYPE</th>
<th>STATUS</th>
<th>OWNER</th>
<th>DUE DATE</th>
</tr></thead>
<tbody>
<t t-foreach="doc.capa_ids" t-as="capa">
<tr>
<td><span t-field="capa.name"/></td>
<td class="text-center"><span t-field="capa.type"/></td>
<td class="text-center"><span t-field="capa.state"/></td>
<td class="text-center"><span t-field="capa.owner_id"/></td>
<td class="text-center"><span t-field="capa.due_date" t-options="{'widget': 'date'}"/></td>
</tr>
</t>
</tbody>
</table>
</t>
<!-- Closed Date -->
<t t-if="doc.closed_date">
<table class="bordered info-table">
<thead><tr><th>CLOSED ON</th></tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.closed_date" t-options="{'widget': 'date'}"/></td>
</tr></tbody>
</table>
</t>
</div>
</div>
</t>
</t>
</t>
</template>
</odoo>

View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Spill Register Report
-->
<odoo>
<template id="report_spill">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="web.external_layout">
<t t-call="fusion_plating_reports.fp_landscape_styles"/>
<div class="fp-landscape">
<div class="page">
<h2 style="text-align: left;">
Spill Report
<span t-field="doc.name"/>
</h2>
<!-- Header Info -->
<table class="bordered info-table">
<thead><tr>
<th>SPILL #</th>
<th>DATE</th>
<th>FACILITY</th>
<th>SUBSTANCE</th>
<th>QUANTITY</th>
<th>UoM</th>
<th>STATUS</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.name"/></td>
<td class="text-center"><span t-field="doc.spill_date" t-options="{'widget': 'date'}"/></td>
<td class="text-center"><span t-field="doc.facility_id"/></td>
<td class="text-center"><span t-field="doc.substance"/></td>
<td class="text-center"><span t-field="doc.quantity"/></td>
<td class="text-center"><span t-field="doc.uom"/></td>
<td class="text-center"><span t-field="doc.state"/></td>
</tr></tbody>
</table>
<!-- Location & Notification -->
<table class="bordered info-table">
<thead><tr>
<th>LOCATION</th>
<th>REPORTED BY</th>
<th>REGULATOR NOTIFIED</th>
<th>NOTIFICATION DATE</th>
<th>CAPA REF</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.location"/></td>
<td class="text-center"><span t-field="doc.reported_by_id"/></td>
<td class="text-center">
<t t-if="doc.regulator_notified">Yes</t>
<t t-else="">No</t>
</td>
<td class="text-center"><span t-field="doc.regulator_notification_date" t-options="{'widget': 'date'}"/></td>
<td class="text-center"><span t-field="doc.capa_ref"/></td>
</tr></tbody>
</table>
<!-- Containment Action -->
<t t-if="doc.containment_action">
<table class="bordered">
<tr class="section-row"><td>CONTAINMENT ACTION</td></tr>
<tr><td><span t-field="doc.containment_action"/></td></tr>
</table>
</t>
<!-- Root Cause -->
<t t-if="doc.root_cause">
<table class="bordered">
<tr class="section-row"><td>ROOT CAUSE</td></tr>
<tr><td><span t-field="doc.root_cause"/></td></tr>
</table>
</t>
<!-- Corrective Action -->
<t t-if="doc.corrective_action">
<table class="bordered">
<tr class="section-row"><td>CORRECTIVE ACTION</td></tr>
<tr><td><span t-field="doc.corrective_action"/></td></tr>
</table>
</t>
</div>
</div>
</t>
</t>
</t>
</template>
</odoo>

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Waste Manifest Report
-->
<odoo>
<template id="report_waste_manifest">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="web.external_layout">
<t t-call="fusion_plating_reports.fp_landscape_styles"/>
<div class="fp-landscape">
<div class="page">
<h2 style="text-align: left;">
Waste Manifest
<span t-field="doc.name"/>
</h2>
<!-- Header Info -->
<table class="bordered info-table">
<thead><tr>
<th>MANIFEST REF</th>
<th>WASTE STREAM</th>
<th>FACILITY</th>
<th>SHIP DATE</th>
<th>STATUS</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.name"/></td>
<td class="text-center"><span t-field="doc.waste_stream_id"/></td>
<td class="text-center"><span t-field="doc.facility_id"/></td>
<td class="text-center"><span t-field="doc.ship_date" t-options="{'widget': 'date'}"/></td>
<td class="text-center"><span t-field="doc.state"/></td>
</tr></tbody>
</table>
<!-- Shipment Details -->
<table class="bordered info-table">
<thead><tr>
<th>QUANTITY</th>
<th>UoM</th>
<th>CARRIER</th>
<th>RECEIVER</th>
<th>MANIFEST #</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><span t-field="doc.quantity"/></td>
<td class="text-center"><span t-field="doc.uom"/></td>
<td class="text-center"><span t-field="doc.carrier_id"/></td>
<td class="text-center"><span t-field="doc.receiver_id"/></td>
<td class="text-center"><span t-field="doc.manifest_number"/></td>
</tr></tbody>
</table>
<!-- Notes -->
<t t-if="doc.notes">
<table class="bordered">
<tr class="section-row"><td>NOTES</td></tr>
<tr><td><t t-out="doc.notes"/></td></tr>
</table>
</t>
</div>
</div>
</t>
</t>
</t>
</template>
</odoo>

View File

@@ -0,0 +1,229 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Work Order Margin Report — Manufacturing Order
-->
<odoo>
<template id="report_wo_margin">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="d">
<t t-call="web.external_layout">
<t t-call="fusion_plating_reports.fp_landscape_styles"/>
<div class="fp-landscape">
<div class="page">
<!-- Extra styles for margin report -->
<style>
.fp-margin-header { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.fp-margin-box {
border: 1px solid #ccc; border-radius: 4px;
padding: 8px 14px; text-align: center; min-width: 110px;
flex: 1;
}
.fp-margin-box .label { font-size: 8pt; color: #666; text-transform: uppercase; margin-bottom: 2px; }
.fp-margin-box .amount { font-size: 13pt; font-weight: bold; }
.fp-margin-green { color: #2e7d32; }
.fp-margin-yellow { color: #f57f17; }
.fp-margin-red { color: #c62828; }
</style>
<h2>
Work Order Margin Report
<span style="font-size: 14pt; color: #333;">
<t t-out="d['mo'].name"/>
</span>
</h2>
<!-- MO Info Line -->
<table class="bordered info-table" style="margin-bottom: 14px;">
<thead><tr>
<th>MO REF</th>
<th>PRODUCT</th>
<th>QUANTITY</th>
<th>STATE</th>
<th>SALE ORDER</th>
<th>DATE PLANNED</th>
</tr></thead>
<tbody><tr>
<td class="text-center"><t t-out="d['mo'].name"/></td>
<td><t t-out="d['mo'].product_id.display_name"/></td>
<td class="text-center">
<t t-out="'%.2f' % d['mo'].product_qty"/>
<t t-out="d['mo'].product_uom_id.name"/>
</td>
<td class="text-center"><t t-out="d['mo'].state"/></td>
<td class="text-center">
<t t-if="d['mo'].sale_order_id">
<t t-out="d['mo'].sale_order_id.name"/>
</t>
<t t-else=""></t>
</td>
<td class="text-center">
<t t-if="d['mo'].date_start">
<t t-out="d['mo'].date_start" t-options="{'widget': 'date'}"/>
</t>
<t t-else=""></t>
</td>
</tr></tbody>
</table>
<!-- ============================================= -->
<!-- HEADER SUMMARY BOXES -->
<!-- ============================================= -->
<div class="fp-margin-header">
<div class="fp-margin-box">
<div class="label">Revenue</div>
<div class="amount">$ <t t-out="'%.2f' % d['revenue']"/></div>
</div>
<div class="fp-margin-box">
<div class="label">Part Labour Cost</div>
<div class="amount">$ <t t-out="'%.2f' % d['part_labour_cost']"/></div>
</div>
<div class="fp-margin-box">
<div class="label">Station Labour Cost</div>
<div class="amount">$ <t t-out="'%.2f' % d['station_labour_cost']"/></div>
</div>
<div class="fp-margin-box">
<div class="label">Station Operation Cost</div>
<div class="amount">$ <t t-out="'%.2f' % d['station_operation_cost']"/></div>
</div>
<div class="fp-margin-box">
<div class="label">Inventory Cost</div>
<div class="amount">$ <t t-out="'%.2f' % d['inventory_cost']"/></div>
</div>
<div class="fp-margin-box">
<div class="label">Outsourcing Cost</div>
<div class="amount">$ <t t-out="'%.2f' % d['outsourcing_cost']"/></div>
</div>
<div class="fp-margin-box">
<div class="label">Total Cost</div>
<div class="amount">$ <t t-out="'%.2f' % d['total_cost']"/></div>
</div>
<div class="fp-margin-box">
<div class="label">Gross Profit</div>
<div class="amount"
t-attf-style="color: {{ 'green' if d['gross_profit'] >= 0 else 'red' }};">
$ <t t-out="'%.2f' % d['gross_profit']"/>
</div>
</div>
<div class="fp-margin-box">
<div class="label">Margin %</div>
<div t-attf-class="amount {{ 'fp-margin-green' if d['margin_pct'] > 15 else ('fp-margin-red' if d['margin_pct'] &lt; 5 else 'fp-margin-yellow') }}">
<t t-out="'%.1f' % d['margin_pct']"/> %
</div>
</div>
</div>
<!-- ============================================= -->
<!-- MARGIN PER PART NUMBER -->
<!-- ============================================= -->
<h2 style="font-size: 14pt; margin-top: 20px;">Margin Per Part Number</h2>
<table class="bordered">
<thead><tr>
<th>Part Number</th>
<th class="text-center">Count</th>
<th class="text-end">SO Total $</th>
<th class="text-end">SO $/Part</th>
<th class="text-end">Unit Labour Cost</th>
<th class="text-end">Part Labour Cost</th>
<th class="text-end">Station Labour Cost</th>
<th class="text-end">Station Op Cost</th>
<th class="text-end">Outsourcing Cost</th>
<th class="text-center">Margin %</th>
</tr></thead>
<tbody>
<t t-foreach="d['part_margins']" t-as="pm">
<tr>
<td><t t-out="pm['part_number']"/></td>
<td class="text-center"><t t-out="pm['count']"/></td>
<td class="text-end">$ <t t-out="'%.2f' % pm['so_total']"/></td>
<td class="text-end">$ <t t-out="'%.2f' % pm['so_per_part']"/></td>
<td class="text-end">$ <t t-out="'%.2f' % pm['unit_labour']"/></td>
<td class="text-end">$ <t t-out="'%.2f' % pm['labour_cost']"/></td>
<td class="text-end">$ <t t-out="'%.2f' % pm['station_labour_cost']"/></td>
<td class="text-end">$ <t t-out="'%.2f' % pm['station_operation_cost']"/></td>
<td class="text-end">$ <t t-out="'%.2f' % pm['outsourcing_cost']"/></td>
<td class="text-center"
t-attf-style="color: {{ 'green' if pm['margin_pct'] > 15 else ('red' if pm['margin_pct'] &lt; 5 else '#f57f17') }}; font-weight: bold;">
<t t-out="'%.1f' % pm['margin_pct']"/> %
</td>
</tr>
</t>
<t t-if="not d['part_margins']">
<tr><td colspan="10" class="text-center" style="font-style: italic;">No work order data available.</td></tr>
</t>
</tbody>
</table>
<!-- ============================================= -->
<!-- COST PER STATION -->
<!-- ============================================= -->
<h2 style="font-size: 14pt; margin-top: 20px;">Cost Per Station</h2>
<table class="bordered">
<thead><tr>
<th>Station</th>
<th class="text-end">Labour Rate ($/hr)</th>
<th class="text-end">Part Labour Time</th>
<th class="text-end">Part Labour Cost</th>
<th class="text-end">Station Labour Cost</th>
<th class="text-end">Op Rate ($/hr)</th>
<th class="text-end">Station Dwell Time</th>
<th class="text-end">Operation Cost</th>
<th class="text-end">Total Cost</th>
<th class="text-center">Percentage</th>
</tr></thead>
<tbody>
<t t-foreach="d['station_costs']" t-as="sc">
<tr>
<td><t t-out="sc['station']"/></td>
<td class="text-end">$ <t t-out="'%.2f' % sc['labour_rate']"/></td>
<td class="text-end">
<t t-out="'%.0f' % sc['labour_time']"/> min
(<t t-out="'%.2f' % sc['labour_hours']"/> hr)
</td>
<td class="text-end">$ <t t-out="'%.2f' % sc['labour_cost']"/></td>
<td class="text-end">$ <t t-out="'%.2f' % sc['labour_cost']"/></td>
<td class="text-end">$ <t t-out="'%.2f' % sc['operation_rate']"/></td>
<td class="text-end">
<t t-out="'%.0f' % sc['dwell_time']"/> min
(<t t-out="'%.2f' % sc['dwell_hours']"/> hr)
</td>
<td class="text-end">$ <t t-out="'%.2f' % sc['operation_cost']"/></td>
<td class="text-end">$ <t t-out="'%.2f' % sc['total_cost']"/></td>
<td class="text-center" style="font-weight: bold;">
<t t-out="'%.1f' % sc['percentage']"/> %
</td>
</tr>
</t>
<t t-if="not d['station_costs']">
<tr><td colspan="10" class="text-center" style="font-style: italic;">No station data available.</td></tr>
</t>
</tbody>
<!-- Totals Row -->
<tfoot t-if="d['station_costs']">
<tr class="section-row">
<td><strong>TOTAL</strong></td>
<td/>
<td/>
<td class="text-end"><strong>$ <t t-out="'%.2f' % sum(s['labour_cost'] for s in d['station_costs'])"/></strong></td>
<td class="text-end"><strong>$ <t t-out="'%.2f' % sum(s['labour_cost'] for s in d['station_costs'])"/></strong></td>
<td/>
<td/>
<td class="text-end"><strong>$ <t t-out="'%.2f' % sum(s['operation_cost'] for s in d['station_costs'])"/></strong></td>
<td class="text-end"><strong>$ <t t-out="'%.2f' % sum(s['total_cost'] for s in d['station_costs'])"/></strong></td>
<td class="text-center"><strong>100 %</strong></td>
</tr>
</tfoot>
</table>
<!-- Report Footer -->
<p style="font-size: 8pt; color: #888; margin-top: 20px; text-align: right;">
Generated by Fusion Plating — Nexa Systems Inc.
</p>
</div>
</div>
</t>
</t>
</t>
</template>
</odoo>

View File

@@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_report_wo_margin_operator,report.wo.margin.operator,model_report_fusion_plating_reports_report_wo_margin,fusion_plating.group_fusion_plating_operator,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_report_wo_margin_operator report.wo.margin.operator model_report_fusion_plating_reports_report_wo_margin fusion_plating.group_fusion_plating_operator 1 0 0 0