ixg_platform/templates/ops/eudr_detail.html
ixgadmin 08096e168f P99C: compliance automation - CoA auto-generation and EUDR due diligence
- 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
2026-08-05 13:58:39 +00:00

141 lines
6.3 KiB
HTML

{% extends 'ops/base_ops.html' %}
{% block title %}EUDR Case - IXG Operations{% endblock %}
{% block content %}
<div class=page-header d-flex justify-content-between align-items-center>
<h2>EUDR Case: {{ case.batch.batch_reference }}</h2>
<a href={% url 'ops:eudr_list' %} class=btn btn-sm btn-outline-secondary><i class=bi bi-arrow-left></i> Back</a>
</div>
{% if messages %}
{% for m in messages %}<div class="alert alert-{{ m.tags }} py-2">{{ m }}</div>{% endfor %}
{% endif %}
<div class=row g-3>
<div class=col-md-8>
<div class=stat-card mb-3>
<h6 class=mb-3>Completeness Check</h6>
{% if case.completeness_results %}
<table class=table table-sm mb-0>
<thead><tr><th>Check</th><th>Status</th><th>Detail</th></tr></thead>
<tbody>
{% for key, item in case.completeness_results.items %}
<tr>
<td>{{ key }}</td>
<td>{% if item.pass %}<span class=badge bg-success>Pass</span>{% else %}<span class=badge bg-danger>Fail</span>{% endif %}</td>
<td>{{ item.detail }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class=text-muted mb-0>Not yet run.</p>
{% endif %}
</div>
<div class=stat-card mb-3>
<h6 class=mb-3>Intake Lineage</h6>
{% if lineage %}
<table class=table table-sm mb-0>
<thead><tr><th>Intake</th><th>Date</th><th>Weight (kg)</th><th>Zone</th><th>Zone Status</th><th>Collector</th></tr></thead>
<tbody>
{% for link in lineage %}
<tr>
<td>{{ link.harvest_intake.intake_reference }}</td>
<td>{{ link.harvest_intake.intake_date|date:'d/m/Y'|default:'-' }}</td>
<td>{{ link.weight_allocated_kg|default:link.harvest_intake.weight_kg }}</td>
<td>{{ link.harvest_intake.origin_zone.zone_code|default:'-' }}</td>
<td>{% if link.harvest_intake.origin_zone %}<span class=badge {% if link.harvest_intake.origin_zone.verification_status == 'verified' %}bg-success{% elif link.harvest_intake.origin_zone.verification_status == 'rejected' %}bg-danger{% else %}bg-warning text-dark{% endif %}>{{ link.harvest_intake.origin_zone.get_verification_status_display }}</span>{% else %}-{% endif %}</td>
<td>{{ link.harvest_intake.collector_group.name|default:'-' }}</td>
</tr>
{% empty %}
<tr><td colspan=6 class=text-muted>No intakes linked. Record intake lineage via API/admin.</td></tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class=text-muted mb-0>No intake lineage recorded for this batch.</p>
{% endif %}
</div>
<div class=stat-card mb-3>
<h6 class=mb-3>Risk Assessments</h6>
{% for r in risk_assessments %}
<div class=border-bottom pb-2 mb-2>
<span class=badge {% if r.risk_level == 'high' %}bg-danger{% elif r.risk_level == 'low' %}bg-success{% else %}bg-info text-dark{% endif %}>{{ r.get_risk_level_display }}</span>
<span class=text-muted small>by {{ r.assessed_by.full_name|default:'-' }} · {{ r.assessed_at|date:'d/m/Y H:i' }}</span>
<div class=small mt-1>{{ r.basis }}</div>
</div>
{% empty %}
<p class=text-muted mb-0>No risk assessment recorded.</p>
{% endfor %}
</div>
<div class=stat-card mb-3>
<h6 class=mb-3>Mitigation Actions</h6>
{% for m in mitigation_actions %}
<div class=border-bottom pb-2 mb-2>
<span class=badge {% if m.status == 'verified' %}bg-success{% elif m.status == 'completed' %}bg-primary{% else %}bg-warning text-dark{% endif %}>{{ m.get_status_display }}</span>
<span class=small>{{ m.action }} <span class=text-muted>(owner: {{ m.owner|default:'-' }}{% if m.due_date %}, due {{ m.due_date|date:'d/m/Y' }}{% endif %})</span></span>
</div>
{% empty %}
<p class=text-muted mb-0>No mitigation actions.</p>
{% endfor %}
</div>
<div class=stat-card>
<h6 class=mb-3>External Submission (DDS) References</h6>
{% for s in statement_references %}
<div class=border-bottom pb-2 mb-2>
<span class=badge bg-secondary>{{ s.reconciliation_status }}</span>
<span class=small>Ref: <code>{{ s.dds_reference }}</code> · {{ s.submission_date|date:'d/m/Y'|default:'-' }} · by {{ s.submitted_by.full_name|default:'-' }}</span>
</div>
{% empty %}
<p class=text-muted mb-0>No external submission recorded. Submissions are manual.</p>
{% endfor %}
</div>
</div>
<div class=col-md-4>
<div class=stat-card mb-3>
<h6 class=mb-3>Case Controls</h6>
<form method=post class=mb-2>
{% csrf_token %}
<input type=hidden name=action value=check>
<button type=submit class="btn btn-outline-primary w-100"><i class=bi bi-check2-square></i> Run Completeness Check</button>
</form>
<form method=post class=mb-2>
{% csrf_token %}
<input type=hidden name=action value=assess_risk>
<button type=submit class="btn btn-outline-warning w-100"><i class=bi bi-activity></i> Run Risk Assessment</button>
</form>
<form method=post class=mb-2>
{% csrf_token %}
<input type=hidden name=action value=approve>
<button type=submit class="btn btn-success w-100"><i class=bi bi-check-circle></i> Approve Case</button>
</form>
<form method=post>
{% csrf_token %}
<input type=hidden name=action value=reject>
<label class=small>Reject reason</label>
<input type=text name=reason class="form-control form-control-sm mb-2" required>
<button type=submit class="btn btn-outline-danger w-100"><i class=bi bi-x-circle></i> Reject Case</button>
</form>
</div>
<div class=stat-card>
<h6 class=mb-3>Record External Submission</h6>
<form method=post>
{% csrf_token %}
<input type=hidden name=action value=record_submission>
<label class=small>DDS reference</label>
<input type=text name=dds_reference class="form-control form-control-sm mb-2" placeholder="e.g. DD-2026-00001" required>
<label class=small>Submission date</label>
<input type=date name=submission_date class="form-control form-control-sm mb-2">
<button type=submit class="btn btn-primary w-100"><i class=bi bi-send></i> Record Submission</button>
</form>
</div>
</div>
</div>
{% endblock %}