changes
This commit is contained in:
@@ -0,0 +1,285 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2026 Nexa Systems Inc.
|
||||
License OPL-1 (Odoo Proprietary License v1.0)
|
||||
-->
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="fusion_plating_quality.FpQcChecklist">
|
||||
<div class="o_fp_qc">
|
||||
|
||||
<!-- ===== Loading / error ===== -->
|
||||
<t t-if="state.loading">
|
||||
<div class="o_fp_qc_state_loading">
|
||||
<i class="fa fa-spinner fa-spin"/>
|
||||
<span>Loading QC…</span>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-elif="state.error">
|
||||
<div class="o_fp_qc_state_error">
|
||||
<i class="fa fa-exclamation-triangle"/>
|
||||
<p><t t-esc="state.error"/></p>
|
||||
<button class="btn btn-primary" t-on-click="refresh">Retry</button>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-elif="state.check">
|
||||
<!-- ===== Header ===== -->
|
||||
<div class="o_fp_qc_header">
|
||||
<div class="o_fp_qc_header_left">
|
||||
<button class="o_fp_qc_back" t-on-click="openJob"
|
||||
t-if="state.check.job_id"
|
||||
title="Back to Job">
|
||||
<i class="fa fa-arrow-left"/>
|
||||
</button>
|
||||
<div class="o_fp_qc_title_block">
|
||||
<div class="o_fp_qc_breadcrumb">
|
||||
<span><t t-esc="state.check.job_name"/></span>
|
||||
<t t-if="state.check.partner_name">
|
||||
<span class="o_fp_qc_sep">·</span>
|
||||
<span><t t-esc="state.check.partner_name"/></span>
|
||||
</t>
|
||||
</div>
|
||||
<h1 class="o_fp_qc_title">
|
||||
<t t-esc="state.check.template_name or 'QC Checklist'"/>
|
||||
</h1>
|
||||
<div class="o_fp_qc_sub">
|
||||
<span class="o_fp_qc_ref"><t t-esc="state.check.name"/></span>
|
||||
<t t-if="state.check.inspector_name">
|
||||
<span class="o_fp_qc_sep">·</span>
|
||||
<span>Inspector: <t t-esc="state.check.inspector_name"/></span>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="o_fp_qc_state_chip"
|
||||
t-att-class="'o_fp_qc_chip_' + state.check.state">
|
||||
<t t-esc="state.check.state.replace('_', ' ').toUpperCase()"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===== Progress ===== -->
|
||||
<div class="o_fp_qc_progress_card">
|
||||
<div class="o_fp_qc_progress_numbers">
|
||||
<div class="o_fp_qc_progress_big">
|
||||
<t t-esc="progressPercent"/>%
|
||||
</div>
|
||||
<div class="o_fp_qc_progress_break">
|
||||
<div class="o_fp_qc_counter o_fp_qc_counter_pass">
|
||||
<span class="o_fp_qc_counter_n">
|
||||
<t t-esc="state.check.lines_passed"/>
|
||||
</span>
|
||||
<span class="o_fp_qc_counter_l">Pass</span>
|
||||
</div>
|
||||
<div class="o_fp_qc_counter o_fp_qc_counter_fail">
|
||||
<span class="o_fp_qc_counter_n">
|
||||
<t t-esc="state.check.lines_failed"/>
|
||||
</span>
|
||||
<span class="o_fp_qc_counter_l">Fail</span>
|
||||
</div>
|
||||
<div class="o_fp_qc_counter o_fp_qc_counter_pending">
|
||||
<span class="o_fp_qc_counter_n">
|
||||
<t t-esc="state.check.lines_pending"/>
|
||||
</span>
|
||||
<span class="o_fp_qc_counter_l">Pending</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="o_fp_qc_progress_bar">
|
||||
<div class="o_fp_qc_progress_fill"
|
||||
t-att-style="'width:' + progressPercent + '%'"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===== Thickness PDF (if required) ===== -->
|
||||
<t t-if="state.check.require_thickness_report_pdf or state.check.require_thickness_readings">
|
||||
<div class="o_fp_qc_thickness_card">
|
||||
<div class="o_fp_qc_thickness_head">
|
||||
<div>
|
||||
<div class="o_fp_qc_thickness_title">
|
||||
<i class="fa fa-bar-chart"/>
|
||||
Thickness Report
|
||||
</div>
|
||||
<div class="o_fp_qc_thickness_sub">
|
||||
<t t-if="state.check.has_thickness_pdf">
|
||||
PDF uploaded · <t t-esc="state.check.thickness_reading_count"/> reading(s) extracted
|
||||
</t>
|
||||
<t t-else="">
|
||||
Upload Fischerscope / XDAL 600 PDF export
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<button class="o_fp_qc_btn o_fp_qc_btn_primary"
|
||||
t-on-click="triggerPdfUpload"
|
||||
t-att-disabled="state.saving">
|
||||
<i class="fa fa-upload"/>
|
||||
<t t-if="state.check.has_thickness_pdf">Replace PDF</t>
|
||||
<t t-else="">Upload PDF</t>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- ===== Checklist ===== -->
|
||||
<div class="o_fp_qc_list">
|
||||
<t t-foreach="state.lines" t-as="line" t-key="line.id">
|
||||
<div class="o_fp_qc_item"
|
||||
t-att-class="{
|
||||
'o_fp_qc_item_pass': line.result == 'pass',
|
||||
'o_fp_qc_item_fail': line.result == 'fail',
|
||||
'o_fp_qc_item_na': line.result == 'na',
|
||||
'o_fp_qc_item_pending': line.result == 'pending' or !line.result,
|
||||
'o_fp_qc_item_open': state.expandedLineId == line.id,
|
||||
}">
|
||||
<div class="o_fp_qc_item_row"
|
||||
t-on-click="() => this.toggleExpanded(line)">
|
||||
<div class="o_fp_qc_item_icon">
|
||||
<i class="fa" t-att-class="checkTypeIcon(line.check_type)"/>
|
||||
</div>
|
||||
<div class="o_fp_qc_item_body">
|
||||
<div class="o_fp_qc_item_name">
|
||||
<t t-esc="line.name"/>
|
||||
<t t-if="!line.required">
|
||||
<span class="o_fp_qc_item_optional">(optional)</span>
|
||||
</t>
|
||||
</div>
|
||||
<div class="o_fp_qc_item_meta">
|
||||
<span class="o_fp_qc_badge"
|
||||
t-att-class="resultBadgeClass(line.result)">
|
||||
<t t-esc="(line.result or 'pending').toUpperCase()"/>
|
||||
</span>
|
||||
<t t-if="line.requires_value and line.value">
|
||||
<span class="o_fp_qc_item_value">
|
||||
<t t-esc="line.value"/>
|
||||
<t t-esc="line.value_uom"/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="line.requires_photo and line.has_photo">
|
||||
<span class="o_fp_qc_item_photo_ind">
|
||||
<i class="fa fa-camera"/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<i class="o_fp_qc_chevron fa"
|
||||
t-att-class="state.expandedLineId == line.id ? 'fa-chevron-up' : 'fa-chevron-down'"/>
|
||||
</div>
|
||||
|
||||
<t t-if="state.expandedLineId == line.id">
|
||||
<div class="o_fp_qc_item_detail">
|
||||
<t t-if="line.description">
|
||||
<div class="o_fp_qc_guidance">
|
||||
<t t-esc="line.description"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-if="line.requires_value">
|
||||
<div class="o_fp_qc_value_row">
|
||||
<label>Measured Value</label>
|
||||
<div class="o_fp_qc_value_input">
|
||||
<input type="number" step="0.0001"
|
||||
t-att-value="line.value or ''"
|
||||
t-att-placeholder="line.value_uom or ''"
|
||||
t-on-input="(ev) => this.onValueInput(line, ev)"/>
|
||||
<span class="o_fp_qc_uom"><t t-esc="line.value_uom"/></span>
|
||||
</div>
|
||||
<t t-if="line.value_min or line.value_max">
|
||||
<div class="o_fp_qc_range">
|
||||
Range: <t t-esc="line.value_min"/> – <t t-esc="line.value_max"/>
|
||||
<t t-esc="line.value_uom"/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-if="line.requires_photo">
|
||||
<div class="o_fp_qc_photo_row">
|
||||
<button class="o_fp_qc_btn o_fp_qc_btn_ghost"
|
||||
t-on-click="() => this.triggerPhoto(line)">
|
||||
<i class="fa fa-camera"/>
|
||||
<t t-if="line.has_photo">Replace photo</t>
|
||||
<t t-else="">Add photo</t>
|
||||
</button>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<div class="o_fp_qc_notes_row">
|
||||
<label>Notes</label>
|
||||
<textarea rows="2"
|
||||
t-att-value="line.notes or ''"
|
||||
t-on-input="(ev) => this.onNotesInput(line, ev)"
|
||||
placeholder="Optional — anything the inspector saw that matters"/>
|
||||
</div>
|
||||
|
||||
<div class="o_fp_qc_actions_row">
|
||||
<button class="o_fp_qc_btn o_fp_qc_btn_pass"
|
||||
t-on-click="() => this.markLine(line, 'pass')"
|
||||
t-att-disabled="state.saving">
|
||||
<i class="fa fa-check"/>
|
||||
Pass
|
||||
</button>
|
||||
<button class="o_fp_qc_btn o_fp_qc_btn_fail"
|
||||
t-on-click="() => this.markLine(line, 'fail')"
|
||||
t-att-disabled="state.saving">
|
||||
<i class="fa fa-times"/>
|
||||
Fail
|
||||
</button>
|
||||
<t t-if="!line.required">
|
||||
<button class="o_fp_qc_btn o_fp_qc_btn_ghost"
|
||||
t-on-click="() => this.markLine(line, 'na')"
|
||||
t-att-disabled="state.saving">
|
||||
N/A
|
||||
</button>
|
||||
</t>
|
||||
<t t-if="line.result != 'pending'">
|
||||
<button class="o_fp_qc_btn o_fp_qc_btn_ghost"
|
||||
t-on-click="() => this.markLine(line, 'pending')"
|
||||
t-att-disabled="state.saving">
|
||||
Reset
|
||||
</button>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<!-- ===== Sign-off bar ===== -->
|
||||
<t t-if="state.check.state != 'passed' and state.check.state != 'failed'">
|
||||
<div class="o_fp_qc_footer">
|
||||
<button class="o_fp_qc_btn o_fp_qc_btn_pass_lg"
|
||||
t-on-click="() => this.finalize('pass')"
|
||||
t-att-disabled="!canFinalize or state.saving">
|
||||
<i class="fa fa-check"/>
|
||||
<span>Sign Off — PASS</span>
|
||||
</button>
|
||||
<button class="o_fp_qc_btn o_fp_qc_btn_fail_lg"
|
||||
t-on-click="() => this.finalize('fail')"
|
||||
t-att-disabled="state.saving">
|
||||
<i class="fa fa-times"/>
|
||||
<span>Fail QC</span>
|
||||
</button>
|
||||
<button class="o_fp_qc_btn o_fp_qc_btn_ghost_lg"
|
||||
t-on-click="() => this.finalize('rework')"
|
||||
t-att-disabled="state.saving or !anyFailed">
|
||||
Send to Rework
|
||||
</button>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- ===== Hidden file inputs ===== -->
|
||||
<input type="file" t-ref="fileInput"
|
||||
accept="image/*" capture="environment"
|
||||
style="display:none"
|
||||
t-on-change="onPhotoSelected"/>
|
||||
<input type="file" t-ref="pdfInput"
|
||||
accept="application/pdf"
|
||||
style="display:none"
|
||||
t-on-change="onPdfSelected"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
Reference in New Issue
Block a user