- Versioned product specification table (Unrefined Shea Butter v1.0 seed) with spec-based QC evaluation replacing hard-coded thresholds - Structured QC results with test methods and four-eyes verification (submitter cannot self-approve) - reportlab IXG Quality Summary PDF auto-generated on quality approval, SHA-256 hashed; original independent lab PDF kept authoritative - CertificateOfAnalysis version/status/hash/approval/supersede lifecycle; commercial release publishes to buyers and triggers notification - EUDR evidence workflow: Facility, OriginZone, CollectorGroup, HarvestIntake, IntakeBatchLineage, DueDiligenceCase, EUDREvidence, RiskAssessment, MitigationAction, DueDiligenceStatementReference with rule-based completeness check and risk assessment (no AI legal conclusions) - Ops portal: QC Approvals, CoA Reviews, EUDR Compliance screens - Buyer portal: /portal/compliance page - 22 automated tests covering four-eyes, CAPA, PDF+hash, publish/notify, EUDR blocks and buyer isolation
59 lines
2.7 KiB
HTML
59 lines
2.7 KiB
HTML
{% extends 'ops/base_ops.html' %}
|
|
{% block title %}QC Approvals - IXG Operations{% endblock %}
|
|
{% block content %}
|
|
|
|
<div class=page-header d-flex justify-content-between align-items-center>
|
|
<h2>QC Approvals (four-eyes verification)</h2>
|
|
<span class=text-secondary>{{ page_obj.paginator.count }} pending</span>
|
|
</div>
|
|
|
|
<div class=filter-bar>
|
|
<form method=get class=row g-2 align-items-end>
|
|
<div class=col-auto>
|
|
<select name=passed class=form-select form-select-sm>
|
|
<option value=>All Results</option>
|
|
<option value=1 {% if current_passed == '1' %}selected{% endif %}>Passed</option>
|
|
<option value=0 {% if current_passed == '0' %}selected{% endif %}>Failed</option>
|
|
</select>
|
|
</div>
|
|
<div class=col-auto>
|
|
<button type=submit class=btn btn-sm btn-primary>Filter</button>
|
|
<a href={% url 'ops:qc_verify_list' %} class=btn btn-sm btn-outline-secondary>Clear</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class=stat-card p-0>
|
|
<table class=table table-hover mb-0>
|
|
<thead>
|
|
<tr><th>Batch</th><th>Result</th><th>FFA%</th><th>Moisture%</th><th>Peroxide</th><th>Visual</th><th>Entered By</th><th>Spec</th><th></th></tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for r in results %}
|
|
<tr>
|
|
<td><strong>{{ r.batch.batch_reference }}</strong></td>
|
|
<td>{% if r.overall_pass %}<span class=badge bg-success>Pass</span>{% else %}<span class=badge bg-danger>Fail</span>{% endif %}</td>
|
|
<td>{{ r.ffa_percentage }}</td>
|
|
<td>{{ r.moisture_percentage }}</td>
|
|
<td>{{ r.peroxide_value }}</td>
|
|
<td>{{ r.visual_grade }}</td>
|
|
<td>{{ r.entered_by.full_name|default:r.entered_by.email|default:'-' }}</td>
|
|
<td>{{ r.spec_version|default:'-' }}</td>
|
|
<td><a href={% url 'ops:qc_verify_detail' r.pk %} class=btn btn-sm btn-primary>Verify</a></td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr><td colspan=9 class=text-muted text-center py-3>No QC results awaiting verification</td></tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
{% if page_obj.paginator.num_pages > 1 %}
|
|
<nav class=mt-3><ul class=pagination pagination-sm justify-content-center>
|
|
{% if page_obj.has_previous %}<li class=page-item><a class=page-link href=?page=1>«</a></li><li class=page-item><a class=page-link href=?page={{ page_obj.previous_page_number }}>{{ page_obj.previous_page_number }}</a></li>{% endif %}
|
|
<li class=page-item active><span class=page-link>{{ page_obj.number }}</span></li>
|
|
{% if page_obj.has_next %}<li class=page-item><a class=page-link href=?page={{ page_obj.next_page_number }}>{{ page_obj.next_page_number }}</a></li><li class=page-item><a class=page-link href=?page={{ page_obj.paginator.num_pages }}>»</a></li>{% endif %}
|
|
</ul></nav>
|
|
{% endif %}
|
|
|
|
{% endblock %}
|