changes
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
{
|
||||
'name': 'Fusion Plating — Native Jobs',
|
||||
'version': '19.0.10.2.0',
|
||||
'version': '19.0.10.8.0',
|
||||
'category': 'Manufacturing/Plating',
|
||||
'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.',
|
||||
'author': 'Nexa Systems Inc.',
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<field name="header_line" eval="False"/>
|
||||
<field name="header_spacing">0</field>
|
||||
<field name="disable_shrinking" eval="True"/>
|
||||
<!-- dpi=300 calibrated — see CLAUDE.md rule 14, 600 broke layout. -->
|
||||
<field name="dpi">300</field>
|
||||
</record>
|
||||
|
||||
@@ -47,6 +48,14 @@
|
||||
reads (so `_so or ...` doesn't NameError). We
|
||||
then override the ones we have data for. -->
|
||||
<t t-call="fusion_plating_reports.report_fp_wo_sticker_defaults"/>
|
||||
<!-- Multi-line trigger: parent SO has 2+ part-bearing lines.
|
||||
Even though this job is for a single specific part (jobs
|
||||
are grouped by recipe+part+coating+thickness+SN), the
|
||||
consolidated PO sticker is the requested behaviour. -->
|
||||
<t t-set="_so_part_lines" t-value="job.sale_order_id
|
||||
and job.sale_order_id.order_line.filtered(lambda l: l.x_fc_part_catalog_id)
|
||||
or job.env['sale.order.line']"/>
|
||||
<t t-set="_multi_line" t-value="len(_so_part_lines) >= 2"/>
|
||||
<!-- Pre-resolve the variables the shared inner template
|
||||
expects, sourcing them from fp.job's native fields. -->
|
||||
<t t-set="_order_id" t-value="job.name"/>
|
||||
@@ -54,13 +63,13 @@
|
||||
<t t-set="_scan_path" t-value="'/fp/job/'"/>
|
||||
<t t-set="_mo" t-value="False"/>
|
||||
<t t-set="_so" t-value="job.sale_order_id"/>
|
||||
<t t-set="_line" t-value="job.sale_order_line_ids[:1]"/>
|
||||
<t t-set="_part" t-value="('part_catalog_id' in job._fields and job.part_catalog_id) or False"/>
|
||||
<t t-set="_spec" t-value="('customer_spec_id' in job._fields and job.customer_spec_id) or False"/>
|
||||
<t t-set="_process" t-value="job.recipe_id or False"/>
|
||||
<t t-set="_due" t-value="job.date_deadline or False"/>
|
||||
<t t-set="_qty" t-value="job.qty"/>
|
||||
<t t-set="_qty_total" t-value="job.qty"/>
|
||||
<t t-set="_line" t-value="False if _multi_line else job.sale_order_line_ids[:1]"/>
|
||||
<t t-set="_part" t-value="False if _multi_line else (('part_catalog_id' in job._fields and job.part_catalog_id) or False)"/>
|
||||
<t t-set="_spec" t-value="False if _multi_line else (('customer_spec_id' in job._fields and job.customer_spec_id) or False)"/>
|
||||
<t t-set="_process" t-value="False if _multi_line else (job.recipe_id or False)"/>
|
||||
<t t-set="_due" t-value="(job.sale_order_id and job.sale_order_id.commitment_date) if _multi_line else (job.date_deadline or False)"/>
|
||||
<t t-set="_qty" t-value="sum(_so_part_lines.mapped('product_uom_qty')) if _multi_line else job.qty"/>
|
||||
<t t-set="_qty_total" t-value="1 if _multi_line else job.qty"/>
|
||||
<t t-set="_partner_name" t-value="job.partner_id.name"/>
|
||||
<!-- The fp.job's own name (WH/JOB/00033) is already
|
||||
printed in the header as "WO #...", so suppress
|
||||
@@ -91,25 +100,31 @@
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="job">
|
||||
<t t-call="fusion_plating_reports.report_fp_wo_sticker_defaults"/>
|
||||
<t t-set="_so_part_lines" t-value="job.sale_order_id
|
||||
and job.sale_order_id.order_line.filtered(lambda l: l.x_fc_part_catalog_id)
|
||||
or job.env['sale.order.line']"/>
|
||||
<t t-set="_multi_line" t-value="len(_so_part_lines) >= 2"/>
|
||||
<t t-set="_order_id" t-value="job.name"/>
|
||||
<t t-set="_scan_id" t-value="job.id"/>
|
||||
<t t-set="_scan_path" t-value="'/fp/job/'"/>
|
||||
<t t-set="_mo" t-value="False"/>
|
||||
<t t-set="_so" t-value="job.sale_order_id"/>
|
||||
<t t-set="_line" t-value="job.sale_order_line_ids[:1]"/>
|
||||
<t t-set="_part" t-value="('part_catalog_id' in job._fields and job.part_catalog_id) or False"/>
|
||||
<t t-set="_spec" t-value="('customer_spec_id' in job._fields and job.customer_spec_id) or False"/>
|
||||
<t t-set="_process" t-value="job.recipe_id or False"/>
|
||||
<t t-set="_due" t-value="job.date_deadline or False"/>
|
||||
<t t-set="_qty" t-value="job.qty"/>
|
||||
<t t-set="_qty_total" t-value="job.qty"/>
|
||||
<t t-set="_line" t-value="False if _multi_line else job.sale_order_line_ids[:1]"/>
|
||||
<t t-set="_part" t-value="False if _multi_line else (('part_catalog_id' in job._fields and job.part_catalog_id) or False)"/>
|
||||
<t t-set="_spec" t-value="False if _multi_line else (('customer_spec_id' in job._fields and job.customer_spec_id) or False)"/>
|
||||
<t t-set="_process" t-value="False if _multi_line else (job.recipe_id or False)"/>
|
||||
<t t-set="_due" t-value="(job.sale_order_id and job.sale_order_id.commitment_date) if _multi_line else (job.date_deadline or False)"/>
|
||||
<t t-set="_qty" t-value="sum(_so_part_lines.mapped('product_uom_qty')) if _multi_line else job.qty"/>
|
||||
<t t-set="_qty_total" t-value="1 if _multi_line else job.qty"/>
|
||||
<t t-set="_partner_name" t-value="job.partner_id.name"/>
|
||||
<t t-set="_mo_ref" t-value="''"/>
|
||||
<!-- Internal override: read x_fc_internal_description from
|
||||
the first linked SO line. -->
|
||||
<t t-set="_notes_content" t-value="(job.sale_order_line_ids[:1]
|
||||
and 'x_fc_internal_description' in job.sale_order_line_ids[:1]._fields
|
||||
and job.sale_order_line_ids[:1].x_fc_internal_description) or '-'"/>
|
||||
the first linked SO line. Multi-line PO blanks it
|
||||
since each line has its own description. -->
|
||||
<t t-set="_notes_content" t-value="'-' if _multi_line else
|
||||
((job.sale_order_line_ids[:1]
|
||||
and 'x_fc_internal_description' in job.sale_order_line_ids[:1]._fields
|
||||
and job.sale_order_line_ids[:1].x_fc_internal_description) or '-')"/>
|
||||
<t t-call="fusion_plating_reports.report_fp_wo_sticker_inner"/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
<div class="page fp-wo-detail">
|
||||
<style>
|
||||
.fp-wo-detail { font-family: Arial, sans-serif; font-size: 9pt; color: #000; }
|
||||
.fp-wo-detail h1 { text-align: center; font-size: 18pt; margin: 0 0 14px 0; font-weight: bold; color: #1a4d80; }
|
||||
.fp-wo-detail h1 { text-align: center; font-size: 22pt; margin: 0 0 14px 0; font-weight: bold; color: #2e2e2e; }
|
||||
.fp-wo-detail h3 { font-size: 11pt; margin: 12px 0 4px 0; font-weight: bold; }
|
||||
.fp-wo-detail .fp-meta { font-size: 8.5pt; color: #444; margin-bottom: 6px; }
|
||||
.fp-wo-detail table.bordered,
|
||||
@@ -134,8 +134,8 @@
|
||||
keeps captions glued to their image. */
|
||||
.fp-wo-detail .fp-photo-section { margin-top: 18px; }
|
||||
.fp-wo-detail .fp-photo-section h2 {
|
||||
font-size: 13pt; font-weight: bold; color: #1a4d80;
|
||||
margin: 0 0 8px 0; border-bottom: 2px solid #1a4d80;
|
||||
font-size: 13pt; font-weight: bold; color: #2e2e2e;
|
||||
margin: 0 0 8px 0; border-bottom: 2px solid #c1c1c1;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
.fp-wo-detail .fp-photo-grid {
|
||||
@@ -162,7 +162,7 @@
|
||||
font-size: 8pt; color: #444; line-height: 1.25;
|
||||
}
|
||||
.fp-wo-detail .fp-photo-ref {
|
||||
font-size: 8pt; color: #1a4d80; font-style: italic;
|
||||
font-size: 8pt; color: #4e4e4e; font-style: italic;
|
||||
white-space: nowrap;
|
||||
}
|
||||
/* Inline signature image inside the step
|
||||
@@ -243,6 +243,65 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- ===== Contract Review (QA-005) block =====
|
||||
Surfaces the part's QA-005 audit trail on
|
||||
every WO Detail print. Per Rule 4 of the
|
||||
contract-review flow, on repeat orders the
|
||||
contract-review WO step is auto-completed
|
||||
at job creation using the reviewer's
|
||||
identity + date from the existing review;
|
||||
this block makes that audit visible to
|
||||
customers and inspectors. Hidden when no
|
||||
review exists (e.g. customer doesn't
|
||||
require contract review). -->
|
||||
<t t-set="review"
|
||||
t-value="('part_catalog_id' in job._fields and job.part_catalog_id
|
||||
and 'x_fc_contract_review_id' in job.part_catalog_id._fields
|
||||
and job.part_catalog_id.x_fc_contract_review_id) or False"/>
|
||||
<t t-if="review">
|
||||
<t t-set="_signer"
|
||||
t-value="review.s30_signed_by or review.s20_signed_by"/>
|
||||
<t t-set="_signed_dt"
|
||||
t-value="review.s30_signed_date or review.s20_signed_date"/>
|
||||
<t t-set="_initials_src"
|
||||
t-value="(_signer and _signer.name) or ''"/>
|
||||
<t t-set="_initials"
|
||||
t-value="''.join([w[:1].upper() for w in _initials_src.split()[:3]])"/>
|
||||
<table class="bordered" style="margin-top: 8px;">
|
||||
<tr>
|
||||
<th colspan="4" style="font-size: 10pt;">Contract Review (QA-005)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="width: 28%;">Status</th>
|
||||
<th style="width: 30%;">Reviewer</th>
|
||||
<th style="width: 14%;">Initials</th>
|
||||
<th style="width: 28%;">Date Reviewed</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<t t-if="review.state == 'complete'">
|
||||
<span style="font-weight: bold; color: #2e2e2e;">QA-005 Approved</span>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span style="color: #aa0000;">Pending — <span t-esc="dict(review._fields['state'].selection).get(review.state, review.state)"/></span>
|
||||
</t>
|
||||
</td>
|
||||
<td>
|
||||
<span t-esc="(_signer and _signer.name) or '—'"/>
|
||||
</td>
|
||||
<td>
|
||||
<span style="font-weight: bold;" t-esc="_initials or '—'"/>
|
||||
</td>
|
||||
<td>
|
||||
<t t-if="_signed_dt">
|
||||
<span t-esc="job.fp_format_local(_signed_dt, '%Y-%m-%d')"/>
|
||||
</t>
|
||||
<t t-else="">—</t>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</t>
|
||||
|
||||
<div class="fp-spec">Specification(s):
|
||||
<span style="font-weight: normal;"
|
||||
t-esc="(job.recipe_id and job.recipe_id.name) or '—'"/>
|
||||
@@ -481,21 +540,30 @@
|
||||
<div style="page-break-before: always;"/>
|
||||
<div style="height: 8mm;"/>
|
||||
|
||||
<!-- Certifier = the job's plating manager. Pulls
|
||||
their Plating Signature (`x_fc_signature_image`)
|
||||
from Preferences → My Profile. Falls back to
|
||||
the company owner's signature, then to the
|
||||
settings override only if no user has one. -->
|
||||
<t t-set="certifier_user" t-value="job.manager_id or (('x_fc_owner_user_id' in company._fields and company.x_fc_owner_user_id) or False)"/>
|
||||
<!-- Certifier = the company's QA Manager, set in
|
||||
Settings → Fusion Plating → Contract Review.
|
||||
Falls back to the job's plating manager, then
|
||||
the company owner, then the settings signature
|
||||
override. Pulls the certifier's Plating
|
||||
Signature (`x_fc_signature_image`) from
|
||||
Preferences → My Profile.
|
||||
Resolution priority added 2026-05-17 per
|
||||
ops request — was auto-defaulting to the
|
||||
current user (whoever the job manager
|
||||
happened to be) which signed every cert as
|
||||
the wrong person. -->
|
||||
<t t-set="_qa_managers" t-value="('x_fc_qa_manager_user_ids' in company._fields and company.x_fc_qa_manager_user_ids) or False"/>
|
||||
<t t-set="certifier_user" t-value="(_qa_managers and _qa_managers[:1])
|
||||
or job.manager_id
|
||||
or (('x_fc_owner_user_id' in company._fields and company.x_fc_owner_user_id) or False)"/>
|
||||
<t t-set="signature_img" t-value="False"/>
|
||||
<t t-if="certifier_user and 'x_fc_signature_image' in certifier_user._fields and certifier_user.x_fc_signature_image">
|
||||
<t t-set="signature_img" t-value="certifier_user.x_fc_signature_image"/>
|
||||
</t>
|
||||
<!-- Final fallback: company-level override for sites
|
||||
whose certifier hasn't uploaded their signature yet. -->
|
||||
<t t-if="not signature_img and 'x_fc_coc_signature_override' in company._fields and company.x_fc_coc_signature_override">
|
||||
<t t-set="signature_img" t-value="company.x_fc_coc_signature_override"/>
|
||||
</t>
|
||||
<!-- Signature Override Image fallback retired
|
||||
2026-05-17. If no certifier user has uploaded
|
||||
their Plating Signature, the cert prints
|
||||
without a signature image (Name still shows). -->
|
||||
<t t-set="signer_name" t-value="(certifier_user and certifier_user.name) or ''"/>
|
||||
|
||||
<t t-set="_cust_stmt" t-value="(job.partner_id and 'x_fc_cert_statement' in job.partner_id._fields and job.partner_id.x_fc_cert_statement) or False"/>
|
||||
|
||||
Reference in New Issue
Block a user