Quote the ops templates' HTML attributes so the classes apply
An unquoted attribute value ends at the first whitespace, so ``class=badge bg-danger`` is read by every browser as ``class="badge"`` plus two meaningless attributes. Bootstrap was loading perfectly well; the markup simply never asked for the styles. Across the ops portal that meant buttons rendered as plain links, status badges were invisible (white text on a white background: a failed result showed as nothing at all), the active sidebar item never highlighted, and the flex utility classes did nothing. The buyer portal templates quote their attributes, which is why only the ops portal looked unstyled. 346 attributes across 20 templates, rewritten mechanically with a conservative transform that handles the three shapes in use — a Django tag as the value, a multi-token class list, and a trailing simple conditional (the active-nav highlight) — and leaves anything it does not recognise exactly as it was.
This commit is contained in:
parent
7d7248a23b
commit
db05d6052a
20 changed files with 516 additions and 516 deletions
|
|
@ -1,11 +1,11 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang=en>
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset=utf-8>
|
<meta charset="utf-8">
|
||||||
<meta name=viewport content=width=device-width, initial-scale=1>
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>{% block title %}IXG Operations{% endblock %}</title>
|
<title>{% block title %}IXG Operations{% endblock %}</title>
|
||||||
<link href=https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css rel=stylesheet>
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link rel=stylesheet href=https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css>
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||||
<style>
|
<style>
|
||||||
body { font-size: .875rem; background: #f5f6fa; }
|
body { font-size: .875rem; background: #f5f6fa; }
|
||||||
.sidebar { position: fixed; top: 0; bottom: 0; left: 0; z-index: 100; padding: 48px 0 0; width: 240px; background: #1e2a3a; }
|
.sidebar { position: fixed; top: 0; bottom: 0; left: 0; z-index: 100; padding: 48px 0 0; width: 240px; background: #1e2a3a; }
|
||||||
|
|
@ -32,38 +32,38 @@ body { font-size: .875rem; background: #f5f6fa; }
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class=sidebar>
|
<div class="sidebar">
|
||||||
<div class=brand>IXG Platform</div>
|
<div class="brand">IXG Platform</div>
|
||||||
<ul class=nav flex-column>
|
<ul class="nav flex-column">
|
||||||
<li class=nav-item><a class=nav-link {% if request.resolver_match.url_name == 'dashboard' %}active{% endif %} href={% url 'ops:dashboard' %}><i class=bi bi-speedometer2></i> Dashboard</a></li>
|
<li class="nav-item"><a class="nav-link {% if request.resolver_match.url_name == 'dashboard' %}active{% endif %}" href="{% url 'ops:dashboard' %}"><i class="bi bi-speedometer2"></i> Dashboard</a></li>
|
||||||
<li class=nav-item><a class=nav-link {% if 'intake' in request.resolver_match.url_name %}active{% endif %} href={% url 'ops:intake_list' %}><i class=bi bi-basket></i> Harvest Intakes</a></li>
|
<li class="nav-item"><a class="nav-link {% if 'intake' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'ops:intake_list' %}"><i class="bi bi-basket"></i> Harvest Intakes</a></li>
|
||||||
<li class=nav-item><a class=nav-link {% if 'batch' in request.resolver_match.url_name %}active{% endif %} href={% url 'ops:batch_list' %}><i class=bi bi-box-seam></i> Batches</a></li>
|
<li class="nav-item"><a class="nav-link {% if 'batch' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'ops:batch_list' %}"><i class="bi bi-box-seam"></i> Batches</a></li>
|
||||||
<li class=nav-item><a class=nav-link {% if 'qc' in request.resolver_match.url_name %}active{% endif %} href={% url 'ops:qc_list' %}><i class=bi bi-clipboard-check></i> QC Results</a></li>
|
<li class="nav-item"><a class="nav-link {% if 'qc' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'ops:qc_list' %}"><i class="bi bi-clipboard-check"></i> QC Results</a></li>
|
||||||
<li class=nav-item><a class=nav-link {% if 'verify' in request.resolver_match.url_name %}active{% endif %} href={% url 'ops:qc_verify_list' %}><i class=bi bi-person-check></i> QC Approvals</a></li>
|
<li class="nav-item"><a class="nav-link {% if 'verify' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'ops:qc_verify_list' %}"><i class="bi bi-person-check"></i> QC Approvals</a></li>
|
||||||
<li class=nav-item><a class=nav-link {% if 'coa' in request.resolver_match.url_name %}active{% endif %} href={% url 'ops:coa_review_list' %}><i class=bi bi-file-earmark-medical></i> CoA Reviews</a></li>
|
<li class="nav-item"><a class="nav-link {% if 'coa' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'ops:coa_review_list' %}"><i class="bi bi-file-earmark-medical"></i> CoA Reviews</a></li>
|
||||||
<li class=nav-item><a class=nav-link {% if 'eudr' in request.resolver_match.url_name %}active{% endif %} href={% url 'ops:eudr_list' %}><i class=bi bi-shield-check></i> EUDR Compliance</a></li>
|
<li class="nav-item"><a class="nav-link {% if 'eudr' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'ops:eudr_list' %}"><i class="bi bi-shield-check"></i> EUDR Compliance</a></li>
|
||||||
<li class=nav-item><a class=nav-link {% if 'shipment' in request.resolver_match.url_name %}active{% endif %} href={% url 'ops:shipment_list' %}><i class=bi bi-truck></i> Shipments</a></li>
|
<li class="nav-item"><a class="nav-link {% if 'shipment' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'ops:shipment_list' %}"><i class="bi bi-truck"></i> Shipments</a></li>
|
||||||
<li class=nav-item><a class=nav-link {% if 'capa' in request.resolver_match.url_name %}active{% endif %} href={% url 'ops:capa_list' %}><i class=bi bi-exclamation-triangle></i> CAPA Records</a></li>
|
<li class="nav-item"><a class="nav-link {% if 'capa' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'ops:capa_list' %}"><i class="bi bi-exclamation-triangle"></i> CAPA Records</a></li>
|
||||||
<li class=nav-item><a class=nav-link {% if 'document' in request.resolver_match.url_name %}active{% endif %} href={% url 'ops:document_list' %}><i class=bi bi-file-earmark-text></i> Documents</a></li>
|
<li class="nav-item"><a class="nav-link {% if 'document' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'ops:document_list' %}"><i class="bi bi-file-earmark-text"></i> Documents</a></li>
|
||||||
<li class=nav-item><a class=nav-link {% if 'esg' in request.resolver_match.url_name %}active{% endif %} href={% url 'ops:esg_list' %}><i class=bi bi-tree></i> ESG Reports</a></li>
|
<li class="nav-item"><a class="nav-link {% if 'esg' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'ops:esg_list' %}"><i class="bi bi-tree"></i> ESG Reports</a></li>
|
||||||
<li class=nav-item><a class=nav-link {% if 'guide' in request.resolver_match.url_name %}active{% endif %} href={% url 'ops:guide_index' %}><i class=bi bi-book></i> Help</a></li>
|
<li class="nav-item"><a class="nav-link {% if 'guide' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'ops:guide_index' %}"><i class="bi bi-book"></i> Help</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=main>
|
<div class="main">
|
||||||
<div class=topbar>
|
<div class="topbar">
|
||||||
<span></span>
|
<span></span>
|
||||||
<div class=d-flex align-items-center gap-3>
|
<div class="d-flex align-items-center gap-3">
|
||||||
<a href=/admin/ class=text-decoration-none text-secondary><i class=bi bi-shield-lock></i> Admin</a>
|
<a href="/admin/" class="text-decoration-none text-secondary"><i class="bi bi-shield-lock"></i> Admin</a>
|
||||||
<span class=text-secondary>{{ request.user.full_name|default:request.user.email }}</span>
|
<span class="text-secondary">{{ request.user.full_name|default:request.user.email }}</span>
|
||||||
<a href={% url 'oidc_logout' %} class=btn btn-sm btn-outline-secondary>Logout</a>
|
<a href="{% url 'oidc_logout' %}" class="btn btn-sm btn-outline-secondary">Logout</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=content>
|
<div class="content">
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src=https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -2,44 +2,44 @@
|
||||||
{% block title %}{{ batch.batch_reference }} - IXG Operations{% endblock %}
|
{% block title %}{{ batch.batch_reference }} - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>Batch: {{ batch.batch_reference }}</h2>
|
<h2>Batch: {{ batch.batch_reference }}</h2>
|
||||||
<a href={% url 'ops:batch_list' %} class=btn btn-sm btn-outline-secondary><i class=bi bi-arrow-left></i> Back</a>
|
<a href="{% url 'ops:batch_list' %}" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left"></i> Back</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=row g-3 mb-4>
|
<div class="row g-3 mb-4">
|
||||||
<div class=col-md-6>
|
<div class="col-md-6">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<table class=table table-sm table-borderless mb-0>
|
<table class="table table-sm table-borderless mb-0">
|
||||||
<tr><td class=text-secondary>Status</td><td><span class=badge bg-secondary badge-status>{{ batch.get_status_display }}</span></td></tr>
|
<tr><td class="text-secondary">Status</td><td><span class="badge bg-secondary badge-status">{{ batch.get_status_display }}</span></td></tr>
|
||||||
<tr><td class=text-secondary>Grade</td><td>{{ batch.grade|default:'Not graded' }}</td></tr>
|
<tr><td class="text-secondary">Grade</td><td>{{ batch.grade|default:'Not graded' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Weight</td><td>{{ batch.weight_kg|default:'-' }} kg</td></tr>
|
<tr><td class="text-secondary">Weight</td><td>{{ batch.weight_kg|default:'-' }} kg</td></tr>
|
||||||
<tr><td class=text-secondary>Origin Facility</td><td>{{ batch.origin_facility }}</td></tr>
|
<tr><td class="text-secondary">Origin Facility</td><td>{{ batch.origin_facility }}</td></tr>
|
||||||
<tr><td class=text-secondary>Harvest Date</td><td>{{ batch.harvest_date|date:'d/m/Y'|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Harvest Date</td><td>{{ batch.harvest_date|date:'d/m/Y'|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Created By</td><td>{% if batch.created_by %}{{ batch.created_by.full_name|default:batch.created_by.email }}{% else %}-{% endif %}</td></tr>
|
<tr><td class="text-secondary">Created By</td><td>{% if batch.created_by %}{{ batch.created_by.full_name|default:batch.created_by.email }}{% else %}-{% endif %}</td></tr>
|
||||||
<tr><td class=text-secondary>Created At</td><td>{{ batch.created_at|date:'d/m/Y H:i' }}</td></tr>
|
<tr><td class="text-secondary">Created At</td><td>{{ batch.created_at|date:'d/m/Y H:i' }}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-md-6>
|
<div class="col-md-6">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>Notes</h6>
|
<h6 class="mb-3">Notes</h6>
|
||||||
<p class=mb-0>{{ batch.notes|linebreaks|default:'<span class=text-muted>No notes</span>' }}</p>
|
<p class="mb-0">{{ batch.notes|linebreaks|default:'<span class=text-muted>No notes</span>' }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=row g-3 mb-4>
|
<div class="row g-3 mb-4">
|
||||||
<div class=col-md-6>
|
<div class="col-md-6">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>QC Results ({{ qc_results|length }})</h6>
|
<h6 class="mb-3">QC Results ({{ qc_results|length }})</h6>
|
||||||
{% if qc_results %}
|
{% if qc_results %}
|
||||||
<table class=table table-sm mb-0>
|
<table class="table table-sm mb-0">
|
||||||
<thead><tr><th>Result</th><th>FFA%</th><th>Moisture%</th><th>Peroxide</th><th>Date</th></tr></thead>
|
<thead><tr><th>Result</th><th>FFA%</th><th>Moisture%</th><th>Peroxide</th><th>Date</th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for r in qc_results %}
|
{% for r in qc_results %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% if r.overall_pass %}<span class=badge bg-success>Pass</span>{% else %}<span class=badge bg-danger>Fail</span>{% endif %}</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.ffa_percentage }}</td>
|
||||||
<td>{{ r.moisture_percentage }}</td>
|
<td>{{ r.moisture_percentage }}</td>
|
||||||
<td>{{ r.peroxide_value }}</td>
|
<td>{{ r.peroxide_value }}</td>
|
||||||
|
|
@ -48,19 +48,19 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% else %}<p class=text-muted mb-0>No QC results</p>{% endif %}
|
{% else %}<p class="text-muted mb-0">No QC results</p>{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-md-6>
|
<div class="col-md-6">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>Shipments ({{ shipments|length }})</h6>
|
<h6 class="mb-3">Shipments ({{ shipments|length }})</h6>
|
||||||
{% if shipments %}
|
{% if shipments %}
|
||||||
<table class=table table-sm mb-0>
|
<table class="table table-sm mb-0">
|
||||||
<thead><tr><th>Status</th><th>Vessel</th><th>ETD</th><th>ETA</th></tr></thead>
|
<thead><tr><th>Status</th><th>Vessel</th><th>ETD</th><th>ETA</th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for s in shipments %}
|
{% for s in shipments %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><span class=badge bg-secondary badge-status>{{ s.get_status_display }}</span></td>
|
<td><span class="badge bg-secondary badge-status">{{ s.get_status_display }}</span></td>
|
||||||
<td>{{ s.vessel_name|default:'-' }}</td>
|
<td>{{ s.vessel_name|default:'-' }}</td>
|
||||||
<td>{{ s.etd_nigeria|date:'d/m/Y'|default:'-' }}</td>
|
<td>{{ s.etd_nigeria|date:'d/m/Y'|default:'-' }}</td>
|
||||||
<td>{{ s.eta_uk|date:'d/m/Y'|default:'-' }}</td>
|
<td>{{ s.eta_uk|date:'d/m/Y'|default:'-' }}</td>
|
||||||
|
|
@ -68,41 +68,41 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% else %}<p class=text-muted mb-0>No shipments</p>{% endif %}
|
{% else %}<p class="text-muted mb-0">No shipments</p>{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=row g-3>
|
<div class="row g-3">
|
||||||
<div class=col-md-6>
|
<div class="col-md-6">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>CAPA Records ({{ capa_records|length }})</h6>
|
<h6 class="mb-3">CAPA Records ({{ capa_records|length }})</h6>
|
||||||
{% if capa_records %}
|
{% if capa_records %}
|
||||||
<table class=table table-sm mb-0>
|
<table class="table table-sm mb-0">
|
||||||
<thead><tr><th>Issue</th><th>Status</th><th>Due Date</th></tr></thead>
|
<thead><tr><th>Issue</th><th>Status</th><th>Due Date</th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for c in capa_records %}
|
{% for c in capa_records %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ c.issue_description|truncatewords:10 }}</td>
|
<td>{{ c.issue_description|truncatewords:10 }}</td>
|
||||||
<td><span class=badge bg-warning text-dark badge-status>{{ c.get_status_display }}</span></td>
|
<td><span class="badge bg-warning text-dark badge-status">{{ c.get_status_display }}</span></td>
|
||||||
<td>{{ c.due_date|date:'d/m/Y'|default:'-' }}</td>
|
<td>{{ c.due_date|date:'d/m/Y'|default:'-' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% else %}<p class=text-muted mb-0>No CAPA records</p>{% endif %}
|
{% else %}<p class="text-muted mb-0">No CAPA records</p>{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-md-6>
|
<div class="col-md-6">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>Documents ({{ documents|length }})</h6>
|
<h6 class="mb-3">Documents ({{ documents|length }})</h6>
|
||||||
{% if documents %}
|
{% if documents %}
|
||||||
<ul class=list-unstyled mb-0>
|
<ul class="list-unstyled mb-0">
|
||||||
{% for d in documents %}
|
{% for d in documents %}
|
||||||
<li class=border-bottom pb-1 mb-1><a href="{% url 'ops:document_download' d.id %}" target=_blank class=text-decoration-none><i class=bi bi-file-earmark></i> {{ d.file_name }}</a> <span class=badge bg-light text-dark>{{ d.get_doc_type_display }}</span></li>
|
<li class="border-bottom pb-1 mb-1"><a href="{% url 'ops:document_download' d.id %}" target="_blank" class="text-decoration-none"><i class="bi bi-file-earmark"></i> {{ d.file_name }}</a> <span class="badge bg-light text-dark">{{ d.get_doc_type_display }}</span></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% else %}<p class=text-muted mb-0>No documents</p>{% endif %}
|
{% else %}<p class="text-muted mb-0">No documents</p>{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,41 +2,41 @@
|
||||||
{% block title %}Batches - IXG Operations{% endblock %}
|
{% block title %}Batches - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>Processing Batches</h2>
|
<h2>Processing Batches</h2>
|
||||||
<span class=text-secondary>{{ page_obj.paginator.count }} total</span>
|
<span class="text-secondary">{{ page_obj.paginator.count }} total</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=filter-bar>
|
<div class="filter-bar">
|
||||||
<form method=get class=row g-2 align-items-end>
|
<form method="get" class="row g-2 align-items-end">
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<input type=text name=q class=form-control form-control-sm placeholder=Search reference... value={{ current_q }}>
|
<input type="text" name="q" class="form-control form-control-sm" placeholder="Search reference..." value="{{ current_q }}">
|
||||||
</div>
|
</div>
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<select name=status class=form-select form-select-sm>
|
<select name="status" class="form-select form-select-sm">
|
||||||
<option value=>All Statuses</option>
|
<option value="">All Statuses</option>
|
||||||
{% for val, label in status_choices %}
|
{% for val, label in status_choices %}
|
||||||
<option value={{ val }} {% if current_status == val %}selected{% endif %}>{{ label }}</option>
|
<option value="{{ val }}" {% if current_status == val %}selected{% endif %}>{{ label }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<select name=grade class=form-select form-select-sm>
|
<select name="grade" class="form-select form-select-sm">
|
||||||
<option value=>All Grades</option>
|
<option value="">All Grades</option>
|
||||||
{% for val, label in grade_choices %}
|
{% for val, label in grade_choices %}
|
||||||
<option value={{ val }} {% if current_grade == val %}selected{% endif %}>{{ label }}</option>
|
<option value="{{ val }}" {% if current_grade == val %}selected{% endif %}>{{ label }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<button type=submit class=btn btn-sm btn-primary>Filter</button>
|
<button type="submit" class="btn btn-sm btn-primary">Filter</button>
|
||||||
<a href={% url 'ops:batch_list' %} class=btn btn-sm btn-outline-secondary>Clear</a>
|
<a href="{% url 'ops:batch_list' %}" class="btn btn-sm btn-outline-secondary">Clear</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card p-0>
|
<div class="stat-card p-0">
|
||||||
<table class=table table-hover mb-0>
|
<table class="table table-hover mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Reference</th>
|
<th>Reference</th>
|
||||||
|
|
@ -54,29 +54,29 @@
|
||||||
<td><strong>{{ b.batch_reference }}</strong></td>
|
<td><strong>{{ b.batch_reference }}</strong></td>
|
||||||
<td>{{ b.grade|default:'-' }}</td>
|
<td>{{ b.grade|default:'-' }}</td>
|
||||||
<td>{{ b.weight_kg|default:'-' }}</td>
|
<td>{{ b.weight_kg|default:'-' }}</td>
|
||||||
<td><span class=badge bg-secondary badge-status>{{ b.get_status_display }}</span></td>
|
<td><span class="badge bg-secondary badge-status">{{ b.get_status_display }}</span></td>
|
||||||
<td>{{ b.harvest_date|date:'d/m/Y'|default:'-' }}</td>
|
<td>{{ b.harvest_date|date:'d/m/Y'|default:'-' }}</td>
|
||||||
<td>{{ b.created_at|date:'d/m/Y' }}</td>
|
<td>{{ b.created_at|date:'d/m/Y' }}</td>
|
||||||
<td><a href={% url 'ops:batch_detail' b.pk %} class=btn btn-sm btn-outline-primary>View</a></td>
|
<td><a href="{% url 'ops:batch_detail' b.pk %}" class="btn btn-sm btn-outline-primary">View</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan=7 class=text-muted text-center py-3>No batches found</td></tr>
|
<tr><td colspan="7" class="text-muted text-center py-3">No batches found</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if page_obj.paginator.num_pages > 1 %}
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
<nav class=mt-3>
|
<nav class="mt-3">
|
||||||
<ul class=pagination pagination-sm justify-content-center>
|
<ul class="pagination pagination-sm justify-content-center">
|
||||||
{% if page_obj.has_previous %}
|
{% 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=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>
|
<li class="page-item"><a class="page-link" href="?page="{{ page_obj.previous_page_number }}>{{ page_obj.previous_page_number }}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class=page-item active><span class=page-link>{{ page_obj.number }}</span></li>
|
<li class="page-item active"><span class="page-link">{{ page_obj.number }}</span></li>
|
||||||
{% if page_obj.has_next %}
|
{% 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.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>
|
<li class="page-item"><a class="page-link" href="?page="{{ page_obj.paginator.num_pages }}>»</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
||||||
|
|
@ -2,45 +2,45 @@
|
||||||
{% block title %}CAPA Detail - IXG Operations{% endblock %}
|
{% block title %}CAPA Detail - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>CAPA Record: {{ record.batch.batch_reference }}</h2>
|
<h2>CAPA Record: {{ record.batch.batch_reference }}</h2>
|
||||||
<a href={% url 'ops:capa_list' %} class=btn btn-sm btn-outline-secondary><i class=bi bi-arrow-left></i> Back</a>
|
<a href="{% url 'ops:capa_list' %}" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left"></i> Back</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=row g-3>
|
<div class="row g-3">
|
||||||
<div class=col-md-8>
|
<div class="col-md-8">
|
||||||
<div class=stat-card mb-3>
|
<div class="stat-card mb-3">
|
||||||
<h6>Issue Description</h6>
|
<h6>Issue Description</h6>
|
||||||
<p>{{ record.issue_description|linebreaks }}</p>
|
<p>{{ record.issue_description|linebreaks }}</p>
|
||||||
</div>
|
</div>
|
||||||
{% if record.root_cause %}
|
{% if record.root_cause %}
|
||||||
<div class=stat-card mb-3>
|
<div class="stat-card mb-3">
|
||||||
<h6>Root Cause</h6>
|
<h6>Root Cause</h6>
|
||||||
<p>{{ record.root_cause|linebreaks }}</p>
|
<p>{{ record.root_cause|linebreaks }}</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if record.corrective_action %}
|
{% if record.corrective_action %}
|
||||||
<div class=stat-card mb-3>
|
<div class="stat-card mb-3">
|
||||||
<h6>Corrective Action</h6>
|
<h6>Corrective Action</h6>
|
||||||
<p>{{ record.corrective_action|linebreaks }}</p>
|
<p>{{ record.corrective_action|linebreaks }}</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if record.preventive_action %}
|
{% if record.preventive_action %}
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6>Preventive Action</h6>
|
<h6>Preventive Action</h6>
|
||||||
<p>{{ record.preventive_action|linebreaks }}</p>
|
<p>{{ record.preventive_action|linebreaks }}</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class=col-md-4>
|
<div class="col-md-4">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<table class=table table-sm table-borderless mb-0>
|
<table class="table table-sm table-borderless mb-0">
|
||||||
<tr><td class=text-secondary>Batch</td><td><a href={% url 'ops:batch_detail' record.batch.pk %}>{{ record.batch.batch_reference }}</a></td></tr>
|
<tr><td class="text-secondary">Batch</td><td><a href="{% url 'ops:batch_detail' record.batch.pk %}">{{ record.batch.batch_reference }}</a></td></tr>
|
||||||
<tr><td class=text-secondary>Status</td><td><span class=badge {% if record.status == open %}bg-danger{% elif record.status == in_progress %}bg-warning text-dark{% else %}bg-success{% endif %} badge-status>{{ record.get_status_display }}</span></td></tr>
|
<tr><td class="text-secondary">Status</td><td><span class="badge" {% if record.status == open %}bg-danger{% elif record.status == in_progress %}bg-warning text-dark{% else %}bg-success{% endif %} badge-status>{{ record.get_status_display }}</span></td></tr>
|
||||||
<tr><td class=text-secondary>Assigned To</td><td>{{ record.assigned_to|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Assigned To</td><td>{{ record.assigned_to|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Due Date</td><td>{{ record.due_date|date:'d/m/Y'|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Due Date</td><td>{{ record.due_date|date:'d/m/Y'|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Created</td><td>{{ record.created_at|date:'d/m/Y H:i' }}</td></tr>
|
<tr><td class="text-secondary">Created</td><td>{{ record.created_at|date:'d/m/Y H:i' }}</td></tr>
|
||||||
{% if record.closed_at %}<tr><td class=text-secondary>Closed</td><td>{{ record.closed_at|date:'d/m/Y H:i' }}</td></tr>{% endif %}
|
{% if record.closed_at %}<tr><td class="text-secondary">Closed</td><td>{{ record.closed_at|date:'d/m/Y H:i' }}</td></tr>{% endif %}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,30 +2,30 @@
|
||||||
{% block title %}CAPA Records - IXG Operations{% endblock %}
|
{% block title %}CAPA Records - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>CAPA Records</h2>
|
<h2>CAPA Records</h2>
|
||||||
<span class=text-secondary>{{ page_obj.paginator.count }} total</span>
|
<span class="text-secondary">{{ page_obj.paginator.count }} total</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=filter-bar>
|
<div class="filter-bar">
|
||||||
<form method=get class=row g-2 align-items-end>
|
<form method="get" class="row g-2 align-items-end">
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<select name=status class=form-select form-select-sm>
|
<select name="status" class="form-select form-select-sm">
|
||||||
<option value=>All Statuses</option>
|
<option value="">All Statuses</option>
|
||||||
{% for val, label in status_choices %}
|
{% for val, label in status_choices %}
|
||||||
<option value={{ val }} {% if current_status == val %}selected{% endif %}>{{ label }}</option>
|
<option value="{{ val }}" {% if current_status == val %}selected{% endif %}>{{ label }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<button type=submit class=btn btn-sm btn-primary>Filter</button>
|
<button type="submit" class="btn btn-sm btn-primary">Filter</button>
|
||||||
<a href={% url 'ops:capa_list' %} class=btn btn-sm btn-outline-secondary>Clear</a>
|
<a href="{% url 'ops:capa_list' %}" class="btn btn-sm btn-outline-secondary">Clear</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card p-0>
|
<div class="stat-card p-0">
|
||||||
<table class=table table-hover mb-0>
|
<table class="table table-hover mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th>Batch</th><th>Issue</th><th>Status</th><th>Assigned To</th><th>Due Date</th><th>Created</th><th></th></tr>
|
<tr><th>Batch</th><th>Issue</th><th>Status</th><th>Assigned To</th><th>Due Date</th><th>Created</th><th></th></tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -34,24 +34,24 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>{{ r.batch.batch_reference }}</strong></td>
|
<td><strong>{{ r.batch.batch_reference }}</strong></td>
|
||||||
<td>{{ r.issue_description|truncatewords:15 }}</td>
|
<td>{{ r.issue_description|truncatewords:15 }}</td>
|
||||||
<td><span class=badge {% if r.status == open %}bg-danger{% elif r.status == in_progress %}bg-warning text-dark{% else %}bg-success{% endif %} badge-status>{{ r.get_status_display }}</span></td>
|
<td><span class="badge" {% if r.status == open %}bg-danger{% elif r.status == in_progress %}bg-warning text-dark{% else %}bg-success{% endif %} badge-status>{{ r.get_status_display }}</span></td>
|
||||||
<td>{{ r.assigned_to|default:'-' }}</td>
|
<td>{{ r.assigned_to|default:'-' }}</td>
|
||||||
<td>{{ r.due_date|date:'d/m/Y'|default:'-' }}</td>
|
<td>{{ r.due_date|date:'d/m/Y'|default:'-' }}</td>
|
||||||
<td>{{ r.created_at|date:'d/m/Y' }}</td>
|
<td>{{ r.created_at|date:'d/m/Y' }}</td>
|
||||||
<td><a href={% url 'ops:capa_detail' r.pk %} class=btn btn-sm btn-outline-primary>View</a></td>
|
<td><a href="{% url 'ops:capa_detail' r.pk %}" class="btn btn-sm btn-outline-primary">View</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan=7 class=text-muted text-center py-3>No CAPA records</td></tr>
|
<tr><td colspan="7" class="text-muted text-center py-3">No CAPA records</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if page_obj.paginator.num_pages > 1 %}
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
<nav class=mt-3><ul class=pagination pagination-sm justify-content-center>
|
<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 %}
|
{% 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>
|
<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 %}
|
{% 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>
|
</ul></nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,58 +2,58 @@
|
||||||
{% block title %}CoA Review - IXG Operations{% endblock %}
|
{% block title %}CoA Review - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>CoA Review: {{ coa.batch.batch_reference }}</h2>
|
<h2>CoA Review: {{ coa.batch.batch_reference }}</h2>
|
||||||
<a href={% url 'ops:coa_review_list' %} class=btn btn-sm btn-outline-secondary><i class=bi bi-arrow-left></i> Back</a>
|
<a href="{% url 'ops:coa_review_list' %}" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left"></i> Back</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
{% for m in messages %}<div class="alert alert-{{ m.tags }} py-2">{{ m }}</div>{% endfor %}
|
{% for m in messages %}<div class="alert alert-{{ m.tags }} py-2">{{ m }}</div>{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class=row g-3>
|
<div class="row g-3">
|
||||||
<div class=col-md-7>
|
<div class="col-md-7">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>Certificate Details</h6>
|
<h6 class="mb-3">Certificate Details</h6>
|
||||||
<table class=table table-sm table-borderless mb-0>
|
<table class="table table-sm table-borderless mb-0">
|
||||||
<tr><td class=text-secondary>Batch</td><td><a href={% url 'ops:batch_detail' coa.batch.pk %}>{{ coa.batch.batch_reference }}</a></td></tr>
|
<tr><td class="text-secondary">Batch</td><td><a href="{% url 'ops:batch_detail' coa.batch.pk %}">{{ coa.batch.batch_reference }}</a></td></tr>
|
||||||
<tr><td class=text-secondary>Status</td><td><span class=badge {% if coa.status == 'published' %}bg-success{% elif coa.status == 'superseded' %}bg-secondary{% else %}bg-warning text-dark{% endif %}>{{ coa.get_status_display }}</span></td></tr>
|
<tr><td class="text-secondary">Status</td><td><span class="badge" {% if coa.status == 'published' %}bg-success{% elif coa.status == 'superseded' %}bg-secondary{% else %}bg-warning text-dark{% endif %}>{{ coa.get_status_display }}</span></td></tr>
|
||||||
<tr><td class=text-secondary>Version</td><td>v{{ coa.version }}</td></tr>
|
<tr><td class="text-secondary">Version</td><td>v{{ coa.version }}</td></tr>
|
||||||
<tr><td class=text-secondary>Specification</td><td>{{ coa.spec_version|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Specification</td><td>{{ coa.spec_version|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Issuer</td><td>{{ coa.issuer|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Issuer</td><td>{{ coa.issuer|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Issue Date</td><td>{{ coa.issue_date|date:'d/m/Y'|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Issue Date</td><td>{{ coa.issue_date|date:'d/m/Y'|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Quality Approved By</td><td>{% if coa.quality_approved_by %}{{ coa.quality_approved_by.full_name|default:coa.quality_approved_by.email }}{% else %}-{% endif %}</td></tr>
|
<tr><td class="text-secondary">Quality Approved By</td><td>{% if coa.quality_approved_by %}{{ coa.quality_approved_by.full_name|default:coa.quality_approved_by.email }}{% else %}-{% endif %}</td></tr>
|
||||||
<tr><td class=text-secondary>Quality Approved At</td><td>{{ coa.quality_approved_at|date:'d/m/Y H:i'|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Quality Approved At</td><td>{{ coa.quality_approved_at|date:'d/m/Y H:i'|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Released At</td><td>{{ coa.released_at|date:'d/m/Y H:i'|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Released At</td><td>{{ coa.released_at|date:'d/m/Y H:i'|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Published At</td><td>{{ coa.published_at|date:'d/m/Y H:i'|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Published At</td><td>{{ coa.published_at|date:'d/m/Y H:i'|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>SHA-256</td><td><code>{{ coa.sha256_hash|default:'-' }}</code></td></tr>
|
<tr><td class="text-secondary">SHA-256</td><td><code>{{ coa.sha256_hash|default:'-' }}</code></td></tr>
|
||||||
<tr><td class=text-secondary>Summary PDF</td><td><a href="{% url 'ops:coa_download' coa.id %}" target=_blank class=text-decoration-none><i class=bi bi-file-earmark-pdf></i> {{ coa.file_name }}</a></td></tr>
|
<tr><td class="text-secondary">Summary PDF</td><td><a href="{% url 'ops:coa_download' coa.id %}" target="_blank" class="text-decoration-none"><i class="bi bi-file-earmark-pdf"></i> {{ coa.file_name }}</a></td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-md-5>
|
<div class="col-md-5">
|
||||||
<div class=stat-card mb-3>
|
<div class="stat-card mb-3">
|
||||||
<h6 class=mb-3>Source Documents</h6>
|
<h6 class="mb-3">Source Documents</h6>
|
||||||
<p class=small text-muted>Independent laboratory report (authoritative):</p>
|
<p class="small text-muted">Independent laboratory report (authoritative):</p>
|
||||||
{% if coa.source_document %}
|
{% if coa.source_document %}
|
||||||
<a href="{% url 'ops:document_download' coa.source_document.id %}" target=_blank class=text-decoration-none><i class=bi bi-file-earmark-pdf></i> {{ coa.source_document.file_name }}</a>
|
<a href="{% url 'ops:document_download' coa.source_document.id %}" target="_blank" class="text-decoration-none"><i class="bi bi-file-earmark-pdf"></i> {{ coa.source_document.file_name }}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class=text-muted mb-0>No lab report linked. <a href={% url 'ops:document_list' %}>Upload</a> the original laboratory PDF for the batch.</p>
|
<p class="text-muted mb-0">No lab report linked. <a href="{% url 'ops:document_list' %}">Upload</a> the original laboratory PDF for the batch.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if lab_documents %}
|
{% if lab_documents %}
|
||||||
<hr>
|
<hr>
|
||||||
<p class=small text-muted mb-1>All lab documents for batch:</p>
|
<p class="small text-muted mb-1">All lab documents for batch:</p>
|
||||||
{% for d in lab_documents %}<div><a href="{% url 'ops:document_download' d.id %}" target=_blank class=text-decoration-none><i class=bi bi-file-earmark-pdf></i> {{ d.file_name }}</a></div>{% endfor %}
|
{% for d in lab_documents %}<div><a href="{% url 'ops:document_download' d.id %}" target="_blank" class="text-decoration-none"><i class="bi bi-file-earmark-pdf"></i> {{ d.file_name }}</a></div>{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>Commercial Release</h6>
|
<h6 class="mb-3">Commercial Release</h6>
|
||||||
{% if coa.status == 'pending_approval' %}
|
{% if coa.status == 'pending_approval' %}
|
||||||
<form method=post>
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type=hidden name=action value=approve>
|
<input type="hidden" name="action" value="approve">
|
||||||
<p class=text-muted>Publishing exposes the summary PDF to authorised buyers and triggers buyer notification.</p>
|
<p class="text-muted">Publishing exposes the summary PDF to authorised buyers and triggers buyer notification.</p>
|
||||||
<button type=submit class="btn btn-success w-100"><i class=bi bi-send></i> Approve & Publish</button>
|
<button type="submit" class="btn btn-success w-100"><i class="bi bi-send"></i> Approve & Publish</button>
|
||||||
</form>
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class=text-muted mb-0">Commercial release approved. Buyer document and notification created.</p>
|
<p class=text-muted mb-0">Commercial release approved. Buyer document and notification created.</p>
|
||||||
|
|
|
||||||
|
|
@ -2,30 +2,30 @@
|
||||||
{% block title %}CoA Reviews - IXG Operations{% endblock %}
|
{% block title %}CoA Reviews - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>Certificate of Analysis Reviews</h2>
|
<h2>Certificate of Analysis Reviews</h2>
|
||||||
<span class=text-secondary>{{ page_obj.paginator.count }} total</span>
|
<span class="text-secondary">{{ page_obj.paginator.count }} total</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=filter-bar>
|
<div class="filter-bar">
|
||||||
<form method=get class=row g-2 align-items-end>
|
<form method="get" class="row g-2 align-items-end">
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<select name=status class=form-select form-select-sm>
|
<select name="status" class="form-select form-select-sm">
|
||||||
<option value=>Pending Approval</option>
|
<option value="">Pending Approval</option>
|
||||||
{% for val, label in status_choices %}
|
{% for val, label in status_choices %}
|
||||||
<option value={{ val }} {% if current_status == val %}selected{% endif %}>{{ label }}</option>
|
<option value="{{ val }}" {% if current_status == val %}selected{% endif %}>{{ label }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<button type=submit class=btn btn-sm btn-primary>Filter</button>
|
<button type="submit" class="btn btn-sm btn-primary">Filter</button>
|
||||||
<a href={% url 'ops:coa_review_list' %} class=btn btn-sm btn-outline-secondary>Clear</a>
|
<a href="{% url 'ops:coa_review_list' %}" class="btn btn-sm btn-outline-secondary">Clear</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card p-0>
|
<div class="stat-card p-0">
|
||||||
<table class=table table-hover mb-0>
|
<table class="table table-hover mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th>Batch</th><th>Version</th><th>Status</th><th>Spec</th><th>Quality Approved</th><th>Issued</th><th></th></tr>
|
<tr><th>Batch</th><th>Version</th><th>Status</th><th>Spec</th><th>Quality Approved</th><th>Issued</th><th></th></tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -34,24 +34,24 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>{{ c.batch.batch_reference }}</strong></td>
|
<td><strong>{{ c.batch.batch_reference }}</strong></td>
|
||||||
<td>v{{ c.version }}</td>
|
<td>v{{ c.version }}</td>
|
||||||
<td><span class=badge {% if c.status == 'published' %}bg-success{% elif c.status == 'superseded' %}bg-secondary{% else %}bg-warning text-dark{% endif %}>{{ c.get_status_display }}</span></td>
|
<td><span class="badge" {% if c.status == 'published' %}bg-success{% elif c.status == 'superseded' %}bg-secondary{% else %}bg-warning text-dark{% endif %}>{{ c.get_status_display }}</span></td>
|
||||||
<td>{{ c.spec_version|default:'-' }}</td>
|
<td>{{ c.spec_version|default:'-' }}</td>
|
||||||
<td>{{ c.quality_approved_by.full_name|default:'-' }}</td>
|
<td>{{ c.quality_approved_by.full_name|default:'-' }}</td>
|
||||||
<td>{{ c.issue_date|date:'d/m/Y'|default:'-' }}</td>
|
<td>{{ c.issue_date|date:'d/m/Y'|default:'-' }}</td>
|
||||||
<td><a href={% url 'ops:coa_review_detail' c.pk %} class="btn btn-sm {% if c.status == 'pending_approval' %}btn-primary{% else %}btn-outline-secondary{% endif %}">Review</a></td>
|
<td><a href="{% url 'ops:coa_review_detail' c.pk %}" class="btn btn-sm {% if c.status == 'pending_approval' %}btn-primary{% else %}btn-outline-secondary{% endif %}">Review</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan=7 class=text-muted text-center py-3>No CoA records</td></tr>
|
<tr><td colspan="7" class="text-muted text-center py-3">No CoA records</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if page_obj.paginator.num_pages > 1 %}
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
<nav class=mt-3><ul class=pagination pagination-sm justify-content-center>
|
<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 %}
|
{% 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>
|
<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 %}
|
{% 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>
|
</ul></nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,69 +2,69 @@
|
||||||
{% block title %}Dashboard - IXG Operations{% endblock %}
|
{% block title %}Dashboard - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>Operations Dashboard</h2>
|
<h2>Operations Dashboard</h2>
|
||||||
<span class=text-secondary>Total Batches: <strong>{{ total_batches }}</strong></span>
|
<span class="text-secondary">Total Batches: <strong>{{ total_batches }}</strong></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=row g-3 mb-4>
|
<div class="row g-3 mb-4">
|
||||||
<div class=col-md-3>
|
<div class="col-md-3">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<div class=stat-value text-success>{{ qc_summary.passed }}</div>
|
<div class="stat-value text-success">{{ qc_summary.passed }}</div>
|
||||||
<div class=stat-label>QC Passed</div>
|
<div class="stat-label">QC Passed</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-md-3>
|
<div class="col-md-3">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<div class=stat-value text-danger>{{ qc_summary.failed }}</div>
|
<div class="stat-value text-danger">{{ qc_summary.failed }}</div>
|
||||||
<div class=stat-label>QC Failed</div>
|
<div class="stat-label">QC Failed</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-md-3>
|
<div class="col-md-3">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<div class=stat-value text-primary>{{ active_shipments }}</div>
|
<div class="stat-value text-primary">{{ active_shipments }}</div>
|
||||||
<div class=stat-label>Active Shipments</div>
|
<div class="stat-label">Active Shipments</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-md-3>
|
<div class="col-md-3">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<div class=stat-value text-warning>{{ open_capas }}</div>
|
<div class="stat-value text-warning">{{ open_capas }}</div>
|
||||||
<div class=stat-label>Open CAPAs</div>
|
<div class="stat-label">Open CAPAs</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=row g-3 mb-4>
|
<div class="row g-3 mb-4">
|
||||||
<div class=col-md-6>
|
<div class="col-md-6">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>Batches by Status</h6>
|
<h6 class="mb-3">Batches by Status</h6>
|
||||||
<table class=table table-sm table-borderless mb-0>
|
<table class="table table-sm table-borderless mb-0">
|
||||||
{% for label, count in batches_by_status.items %}
|
{% for label, count in batches_by_status.items %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><span class=badge bg-secondary badge-status>{{ label }}</span></td>
|
<td><span class="badge bg-secondary badge-status">{{ label }}</span></td>
|
||||||
<td class=text-end><strong>{{ count }}</strong></td>
|
<td class="text-end"><strong>{{ count }}</strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td class=text-muted>No batches yet</td></tr>
|
<tr><td class="text-muted">No batches yet</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-md-6>
|
<div class="col-md-6">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>Recent Batches</h6>
|
<h6 class="mb-3">Recent Batches</h6>
|
||||||
<table class=table table-sm mb-0>
|
<table class="table table-sm mb-0">
|
||||||
<thead><tr><th>Reference</th><th>Status</th><th>Grade</th><th>Created</th></tr></thead>
|
<thead><tr><th>Reference</th><th>Status</th><th>Grade</th><th>Created</th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for b in recent_batches %}
|
{% for b in recent_batches %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href={% url 'ops:batch_detail' b.pk %}>{{ b.batch_reference }}</a></td>
|
<td><a href="{% url 'ops:batch_detail' b.pk %}">{{ b.batch_reference }}</a></td>
|
||||||
<td><span class=badge bg-secondary badge-status>{{ b.get_status_display }}</span></td>
|
<td><span class="badge bg-secondary badge-status">{{ b.get_status_display }}</span></td>
|
||||||
<td>{{ b.grade|default:'-' }}</td>
|
<td>{{ b.grade|default:'-' }}</td>
|
||||||
<td>{{ b.created_at|date:'d/m/Y' }}</td>
|
<td>{{ b.created_at|date:'d/m/Y' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan=4 class=text-muted>No batches yet</td></tr>
|
<tr><td colspan="4" class="text-muted">No batches yet</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
@ -72,37 +72,37 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=row g-3>
|
<div class="row g-3">
|
||||||
<div class=col-md-6>
|
<div class="col-md-6">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>Recent QC Results</h6>
|
<h6 class="mb-3">Recent QC Results</h6>
|
||||||
<table class=table table-sm mb-0>
|
<table class="table table-sm mb-0">
|
||||||
<thead><tr><th>Batch</th><th>Result</th><th>FFA%</th><th>Date</th></tr></thead>
|
<thead><tr><th>Batch</th><th>Result</th><th>FFA%</th><th>Date</th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for r in recent_qc %}
|
{% for r in recent_qc %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href={% url 'ops:qc_detail' r.pk %}>{{ r.batch.batch_reference }}</a></td>
|
<td><a href="{% url 'ops:qc_detail' r.pk %}">{{ r.batch.batch_reference }}</a></td>
|
||||||
<td>{% if r.overall_pass %}<span class=badge bg-success>Pass</span>{% else %}<span class=badge bg-danger>Fail</span>{% endif %}</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.ffa_percentage }}</td>
|
||||||
<td>{{ r.tested_at|date:'d/m/Y' }}</td>
|
<td>{{ r.tested_at|date:'d/m/Y' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan=4 class=text-muted>No QC results yet</td></tr>
|
<tr><td colspan="4" class="text-muted">No QC results yet</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-md-6>
|
<div class="col-md-6">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>Unread Notifications</h6>
|
<h6 class="mb-3">Unread Notifications</h6>
|
||||||
{% for n in recent_notifications %}
|
{% for n in recent_notifications %}
|
||||||
<div class=border-bottom pb-2 mb-2>
|
<div class="border-bottom pb-2 mb-2">
|
||||||
<strong>{{ n.title }}</strong>
|
<strong>{{ n.title }}</strong>
|
||||||
<p class=mb-0 text-muted small>{{ n.message|truncatewords:20 }}</p>
|
<p class="mb-0 text-muted small">{{ n.message|truncatewords:20 }}</p>
|
||||||
</div>
|
</div>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p class=text-muted mb-0>No unread notifications</p>
|
<p class="text-muted mb-0">No unread notifications</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,55 +2,55 @@
|
||||||
{% block title %}Documents - IXG Operations{% endblock %}
|
{% block title %}Documents - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>Documents</h2>
|
<h2>Documents</h2>
|
||||||
<span class=text-secondary>{{ page_obj.paginator.count }} total</span>
|
<span class="text-secondary">{{ page_obj.paginator.count }} total</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=filter-bar>
|
<div class="filter-bar">
|
||||||
<form method=get class=row g-2 align-items-end>
|
<form method="get" class="row g-2 align-items-end">
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<select name=doc_type class=form-select form-select-sm>
|
<select name="doc_type" class="form-select form-select-sm">
|
||||||
<option value=>All Types</option>
|
<option value="">All Types</option>
|
||||||
{% for val, label in doc_type_choices %}
|
{% for val, label in doc_type_choices %}
|
||||||
<option value={{ val }} {% if current_doc_type == val %}selected{% endif %}>{{ label }}</option>
|
<option value="{{ val }}" {% if current_doc_type == val %}selected{% endif %}>{{ label }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<button type=submit class=btn btn-sm btn-primary>Filter</button>
|
<button type="submit" class="btn btn-sm btn-primary">Filter</button>
|
||||||
<a href={% url 'ops:document_list' %} class=btn btn-sm btn-outline-secondary>Clear</a>
|
<a href="{% url 'ops:document_list' %}" class="btn btn-sm btn-outline-secondary">Clear</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card p-0>
|
<div class="stat-card p-0">
|
||||||
<table class=table table-hover mb-0>
|
<table class="table table-hover mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th>File Name</th><th>Type</th><th>Batch</th><th>Visibility</th><th>Uploaded By</th><th>Uploaded</th></tr>
|
<tr><th>File Name</th><th>Type</th><th>Batch</th><th>Visibility</th><th>Uploaded By</th><th>Uploaded</th></tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for d in documents %}
|
{% for d in documents %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="{% url 'ops:document_download' d.id %}" target=_blank class=text-decoration-none><i class=bi bi-file-earmark></i> {{ d.file_name }}</a></td>
|
<td><a href="{% url 'ops:document_download' d.id %}" target="_blank" class="text-decoration-none"><i class="bi bi-file-earmark"></i> {{ d.file_name }}</a></td>
|
||||||
<td><span class=badge bg-light text-dark>{{ d.get_doc_type_display }}</span></td>
|
<td><span class="badge bg-light text-dark">{{ d.get_doc_type_display }}</span></td>
|
||||||
<td>{{ d.batch.batch_reference|default:'-' }}</td>
|
<td>{{ d.batch.batch_reference|default:'-' }}</td>
|
||||||
<td><span class=badge bg-info text-dark>{{ d.get_visibility_display }}</span></td>
|
<td><span class="badge bg-info text-dark">{{ d.get_visibility_display }}</span></td>
|
||||||
<td>{% if d.uploaded_by %}{{ d.uploaded_by.full_name|default:d.uploaded_by.email }}{% else %}-{% endif %}</td>
|
<td>{% if d.uploaded_by %}{{ d.uploaded_by.full_name|default:d.uploaded_by.email }}{% else %}-{% endif %}</td>
|
||||||
<td>{{ d.uploaded_at|date:'d/m/Y' }}</td>
|
<td>{{ d.uploaded_at|date:'d/m/Y' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan=6 class=text-muted text-center py-3>No documents</td></tr>
|
<tr><td colspan="6" class="text-muted text-center py-3">No documents</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if page_obj.paginator.num_pages > 1 %}
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
<nav class=mt-3><ul class=pagination pagination-sm justify-content-center>
|
<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 %}
|
{% 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>
|
<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 %}
|
{% 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>
|
</ul></nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@
|
||||||
{% block title %}ESG Reports - IXG Operations{% endblock %}
|
{% block title %}ESG Reports - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>ESG Field Reports</h2>
|
<h2>ESG Field Reports</h2>
|
||||||
<span class=text-secondary>{{ page_obj.paginator.count }} total</span>
|
<span class="text-secondary">{{ page_obj.paginator.count }} total</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card p-0>
|
<div class="stat-card p-0">
|
||||||
<table class=table table-hover mb-0>
|
<table class="table table-hover mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th>Batch</th><th>Women Employed</th><th>Total Workers</th><th>Fair Wage</th><th>Safety Equipment</th><th>Report Date</th><th>Reported By</th></tr>
|
<tr><th>Batch</th><th>Women Employed</th><th>Total Workers</th><th>Fair Wage</th><th>Safety Equipment</th><th>Report Date</th><th>Reported By</th></tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -18,23 +18,23 @@
|
||||||
<td><strong>{{ r.batch.batch_reference }}</strong></td>
|
<td><strong>{{ r.batch.batch_reference }}</strong></td>
|
||||||
<td>{{ r.women_employed }}</td>
|
<td>{{ r.women_employed }}</td>
|
||||||
<td>{{ r.total_workers }}</td>
|
<td>{{ r.total_workers }}</td>
|
||||||
<td>{% if r.fair_wage_paid %}<span class=badge bg-success>Yes</span>{% else %}<span class=badge bg-danger>No</span>{% endif %}</td>
|
<td>{% if r.fair_wage_paid %}<span class="badge bg-success">Yes</span>{% else %}<span class="badge bg-danger">No</span>{% endif %}</td>
|
||||||
<td>{% if r.safety_equipment_used %}<span class=badge bg-success>Yes</span>{% else %}<span class=badge bg-danger>No</span>{% endif %}</td>
|
<td>{% if r.safety_equipment_used %}<span class="badge bg-success">Yes</span>{% else %}<span class="badge bg-danger">No</span>{% endif %}</td>
|
||||||
<td>{{ r.report_date|date:'d/m/Y'|default:'-' }}</td>
|
<td>{{ r.report_date|date:'d/m/Y'|default:'-' }}</td>
|
||||||
<td>{{ r.reported_by|default:'-' }}</td>
|
<td>{{ r.reported_by|default:'-' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan=7 class=text-muted text-center py-3>No ESG reports</td></tr>
|
<tr><td colspan="7" class="text-muted text-center py-3">No ESG reports</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if page_obj.paginator.num_pages > 1 %}
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
<nav class=mt-3><ul class=pagination pagination-sm justify-content-center>
|
<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 %}
|
{% 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>
|
<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 %}
|
{% 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>
|
</ul></nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,41 +2,41 @@
|
||||||
{% block title %}EUDR Case - IXG Operations{% endblock %}
|
{% block title %}EUDR Case - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>EUDR Case: {{ case.batch.batch_reference }}</h2>
|
<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>
|
<a href="{% url 'ops:eudr_list' %}" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left"></i> Back</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
{% for m in messages %}<div class="alert alert-{{ m.tags }} py-2">{{ m }}</div>{% endfor %}
|
{% for m in messages %}<div class="alert alert-{{ m.tags }} py-2">{{ m }}</div>{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class=row g-3>
|
<div class="row g-3">
|
||||||
<div class=col-md-8>
|
<div class="col-md-8">
|
||||||
<div class=stat-card mb-3>
|
<div class="stat-card mb-3">
|
||||||
<h6 class=mb-3>Completeness Check</h6>
|
<h6 class="mb-3">Completeness Check</h6>
|
||||||
{% if case.completeness_results %}
|
{% if case.completeness_results %}
|
||||||
<table class=table table-sm mb-0>
|
<table class="table table-sm mb-0">
|
||||||
<thead><tr><th>Check</th><th>Status</th><th>Detail</th></tr></thead>
|
<thead><tr><th>Check</th><th>Status</th><th>Detail</th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for key, item in case.completeness_results.items %}
|
{% for key, item in case.completeness_results.items %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ key }}</td>
|
<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>{% if item.pass %}<span class="badge bg-success">Pass</span>{% else %}<span class="badge bg-danger">Fail</span>{% endif %}</td>
|
||||||
<td>{{ item.detail }}</td>
|
<td>{{ item.detail }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class=text-muted mb-0>Not yet run.</p>
|
<p class="text-muted mb-0">Not yet run.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card mb-3>
|
<div class="stat-card mb-3">
|
||||||
<h6 class=mb-3>Intake Lineage</h6>
|
<h6 class="mb-3">Intake Lineage</h6>
|
||||||
{% if lineage %}
|
{% if lineage %}
|
||||||
<table class=table table-sm mb-0>
|
<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>
|
<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>
|
<tbody>
|
||||||
{% for link in lineage %}
|
{% for link in lineage %}
|
||||||
|
|
@ -45,94 +45,94 @@
|
||||||
<td>{{ link.harvest_intake.intake_date|date:'d/m/Y'|default:'-' }}</td>
|
<td>{{ link.harvest_intake.intake_date|date:'d/m/Y'|default:'-' }}</td>
|
||||||
<td>{% if link.weight_allocated_kg %}{{ link.weight_allocated_kg }}{% elif link.harvest_intake %}{{ link.harvest_intake.weight_kg }}{% else %}-{% endif %}</td>
|
<td>{% if link.weight_allocated_kg %}{{ link.weight_allocated_kg }}{% elif link.harvest_intake %}{{ link.harvest_intake.weight_kg }}{% else %}-{% endif %}</td>
|
||||||
<td>{{ link.harvest_intake.origin_zone.zone_code|default:'-' }}</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>{% 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>
|
<td>{{ link.harvest_intake.collector_group.name|default:'-' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan=6 class=text-muted>No intakes linked. Record intake lineage via API/admin.</td></tr>
|
<tr><td colspan="6" class="text-muted">No intakes linked. Record intake lineage via API/admin.</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class=text-muted mb-0>No intake lineage recorded for this batch.</p>
|
<p class="text-muted mb-0">No intake lineage recorded for this batch.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card mb-3>
|
<div class="stat-card mb-3">
|
||||||
<h6 class=mb-3>Risk Assessments</h6>
|
<h6 class="mb-3">Risk Assessments</h6>
|
||||||
{% for r in risk_assessments %}
|
{% for r in risk_assessments %}
|
||||||
<div class=border-bottom pb-2 mb-2>
|
<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="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>
|
<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 class="small mt-1">{{ r.basis }}</div>
|
||||||
</div>
|
</div>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p class=text-muted mb-0>No risk assessment recorded.</p>
|
<p class="text-muted mb-0">No risk assessment recorded.</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card mb-3>
|
<div class="stat-card mb-3">
|
||||||
<h6 class=mb-3>Mitigation Actions</h6>
|
<h6 class="mb-3">Mitigation Actions</h6>
|
||||||
{% for m in mitigation_actions %}
|
{% for m in mitigation_actions %}
|
||||||
<div class=border-bottom pb-2 mb-2>
|
<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="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>
|
<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>
|
</div>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p class=text-muted mb-0>No mitigation actions.</p>
|
<p class="text-muted mb-0">No mitigation actions.</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>External Submission (DDS) References</h6>
|
<h6 class="mb-3">External Submission (DDS) References</h6>
|
||||||
{% for s in statement_references %}
|
{% for s in statement_references %}
|
||||||
<div class=border-bottom pb-2 mb-2>
|
<div class="border-bottom pb-2 mb-2">
|
||||||
<span class=badge bg-secondary>{{ s.reconciliation_status }}</span>
|
<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>
|
<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>
|
</div>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p class=text-muted mb-0>No external submission recorded. Submissions are manual.</p>
|
<p class="text-muted mb-0">No external submission recorded. Submissions are manual.</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=col-md-4>
|
<div class="col-md-4">
|
||||||
<div class=stat-card mb-3>
|
<div class="stat-card mb-3">
|
||||||
<h6 class=mb-3>Case Controls</h6>
|
<h6 class="mb-3">Case Controls</h6>
|
||||||
<form method=post class=mb-2>
|
<form method="post" class="mb-2">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type=hidden name=action value=check>
|
<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>
|
<button type="submit" class="btn btn-outline-primary w-100"><i class="bi bi-check2-square"></i> Run Completeness Check</button>
|
||||||
</form>
|
</form>
|
||||||
<form method=post class=mb-2>
|
<form method="post" class="mb-2">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type=hidden name=action value=assess_risk>
|
<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>
|
<button type="submit" class="btn btn-outline-warning w-100"><i class="bi bi-activity"></i> Run Risk Assessment</button>
|
||||||
</form>
|
</form>
|
||||||
<form method=post class=mb-2>
|
<form method="post" class="mb-2">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type=hidden name=action value=approve>
|
<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>
|
<button type="submit" class="btn btn-success w-100"><i class="bi bi-check-circle"></i> Approve Case</button>
|
||||||
</form>
|
</form>
|
||||||
<form method=post>
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type=hidden name=action value=reject>
|
<input type="hidden" name="action" value="reject">
|
||||||
<label class=small>Reject reason</label>
|
<label class="small">Reject reason</label>
|
||||||
<input type=text name=reason class="form-control form-control-sm mb-2" required>
|
<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>
|
<button type="submit" class="btn btn-outline-danger w-100"><i class="bi bi-x-circle"></i> Reject Case</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>Record External Submission</h6>
|
<h6 class="mb-3">Record External Submission</h6>
|
||||||
<form method=post>
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type=hidden name=action value=record_submission>
|
<input type="hidden" name="action" value="record_submission">
|
||||||
<label class=small>DDS reference</label>
|
<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>
|
<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>
|
<label class="small">Submission date</label>
|
||||||
<input type=date name=submission_date class="form-control form-control-sm mb-2">
|
<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>
|
<button type="submit" class="btn btn-primary w-100"><i class="bi bi-send"></i> Record Submission</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,35 +2,35 @@
|
||||||
{% block title %}EUDR Compliance - IXG Operations{% endblock %}
|
{% block title %}EUDR Compliance - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>EUDR Due Diligence Cases</h2>
|
<h2>EUDR Due Diligence Cases</h2>
|
||||||
<span class=text-secondary>{{ page_obj.paginator.count }} total</span>
|
<span class="text-secondary">{{ page_obj.paginator.count }} total</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=alert alert-light border py-2 small>
|
<div class="alert alert-light border py-2 small">
|
||||||
<i class=bi bi-info-circle></i> Shea butter is not listed in EUDR Annex I; this tracker provides due-diligence
|
<i class="bi bi-info-circle"></i> Shea butter is not listed in EUDR Annex I; this tracker provides due-diligence
|
||||||
evidence and buyer assurance, not an EU-mandated filing.
|
evidence and buyer assurance, not an EU-mandated filing.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=filter-bar>
|
<div class="filter-bar">
|
||||||
<form method=get class=row g-2 align-items-end>
|
<form method="get" class="row g-2 align-items-end">
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<select name=status class=form-select form-select-sm>
|
<select name="status" class="form-select form-select-sm">
|
||||||
<option value=>All Statuses</option>
|
<option value="">All Statuses</option>
|
||||||
{% for val, label in status_choices %}
|
{% for val, label in status_choices %}
|
||||||
<option value={{ val }} {% if current_status == val %}selected{% endif %}>{{ label }}</option>
|
<option value="{{ val }}" {% if current_status == val %}selected{% endif %}>{{ label }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<button type=submit class=btn btn-sm btn-primary>Filter</button>
|
<button type="submit" class="btn btn-sm btn-primary">Filter</button>
|
||||||
<a href={% url 'ops:eudr_list' %} class=btn btn-sm btn-outline-secondary>Clear</a>
|
<a href="{% url 'ops:eudr_list' %}" class="btn btn-sm btn-outline-secondary">Clear</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card p-0>
|
<div class="stat-card p-0">
|
||||||
<table class=table table-hover mb-0>
|
<table class="table table-hover mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th>Batch</th><th>Status</th><th>Risk Level</th><th>Approved</th><th>Updated</th><th></th></tr>
|
<tr><th>Batch</th><th>Status</th><th>Risk Level</th><th>Approved</th><th>Updated</th><th></th></tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -38,29 +38,29 @@
|
||||||
{% for c in cases %}
|
{% for c in cases %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>{{ c.batch.batch_reference }}</strong></td>
|
<td><strong>{{ c.batch.batch_reference }}</strong></td>
|
||||||
<td><span class=badge
|
<td><span class="badge"
|
||||||
{% if c.status == 'approved' %}bg-success
|
{% if c.status == 'approved' %}bg-success
|
||||||
{% elif c.status == 'rejected' %}bg-danger
|
{% elif c.status == 'rejected' %}bg-danger
|
||||||
{% elif c.status == 'complete_for_review' %}bg-primary
|
{% elif c.status == 'complete_for_review' %}bg-primary
|
||||||
{% elif c.status == 'mitigation_required' or c.status == 'risk_identified' %}bg-warning text-dark
|
{% elif c.status == 'mitigation_required' or c.status == 'risk_identified' %}bg-warning text-dark
|
||||||
{% else %}bg-secondary{% endif %}>{{ c.get_status_display }}</span></td>
|
{% else %}bg-secondary{% endif %}>{{ c.get_status_display }}</span></td>
|
||||||
<td><span class=badge {% if c.risk_level == 'high' %}bg-danger{% elif c.risk_level == 'low' %}bg-success{% else %}bg-info text-dark{% endif %}>{{ c.get_risk_level_display }}</span></td>
|
<td><span class="badge" {% if c.risk_level == 'high' %}bg-danger{% elif c.risk_level == 'low' %}bg-success{% else %}bg-info text-dark{% endif %}>{{ c.get_risk_level_display }}</span></td>
|
||||||
<td>{{ c.approved_at|date:'d/m/Y H:i'|default:'-' }}</td>
|
<td>{{ c.approved_at|date:'d/m/Y H:i'|default:'-' }}</td>
|
||||||
<td>{{ c.updated_at|date:'d/m/Y' }}</td>
|
<td>{{ c.updated_at|date:'d/m/Y' }}</td>
|
||||||
<td><a href={% url 'ops:eudr_detail' c.pk %} class=btn btn-sm btn-primary>Review</a></td>
|
<td><a href="{% url 'ops:eudr_detail' c.pk %}" class="btn btn-sm btn-primary">Review</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan=6 class=text-muted text-center py-3>No due diligence cases</td></tr>
|
<tr><td colspan="6" class="text-muted text-center py-3">No due diligence cases</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if page_obj.paginator.num_pages > 1 %}
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
<nav class=mt-3><ul class=pagination pagination-sm justify-content-center>
|
<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 %}
|
{% 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>
|
<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 %}
|
{% 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>
|
</ul></nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,15 @@
|
||||||
{% block title %}{{ page_title }} - IXG Operations{% endblock %}
|
{% block title %}{{ page_title }} - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>{{ page_title }}</h2>
|
<h2>{{ page_title }}</h2>
|
||||||
<a href={% url 'ops:intake_list' %} class=btn btn-sm btn-outline-secondary><i class=bi bi-arrow-left></i> Back</a>
|
<a href="{% url 'ops:intake_list' %}" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left"></i> Back</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=row g-3>
|
<div class="row g-3">
|
||||||
<div class=col-md-7>
|
<div class="col-md-7">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<form method=post novalidate id=intake-form data-group-zones="{{ group_zones }}">
|
<form method="post novalidate" id="intake-form" data-group-zones="{{ group_zones }}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
{% if form.non_field_errors %}
|
{% if form.non_field_errors %}
|
||||||
|
|
@ -19,29 +19,29 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
<div class=mb-3>
|
<div class="mb-3">
|
||||||
<label class=form-label for="{{ field.id_for_label }}">
|
<label class="form-label" for="{{ field.id_for_label }}">
|
||||||
{{ field.label }}{% if field.field.required %} <span class=text-danger>*</span>{% endif %}
|
{{ field.label }}{% if field.field.required %} <span class="text-danger">*</span>{% endif %}
|
||||||
</label>
|
</label>
|
||||||
{{ field }}
|
{{ field }}
|
||||||
{% if field.help_text %}<div class=form-text>{{ field.help_text }}</div>{% endif %}
|
{% if field.help_text %}<div class="form-text">{{ field.help_text }}</div>{% endif %}
|
||||||
{% for e in field.errors %}<div class="text-danger small">{{ e }}</div>{% endfor %}
|
{% for e in field.errors %}<div class="text-danger small">{{ e }}</div>{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<button type=submit class="btn btn-primary">{{ submit_label }}</button>
|
<button type="submit" class="btn btn-primary">{{ submit_label }}</button>
|
||||||
<a href={% url 'ops:intake_list' %} class="btn btn-outline-secondary">Cancel</a>
|
<a href="{% url 'ops:intake_list' %}" class="btn btn-outline-secondary">Cancel</a>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=col-md-5>
|
<div class="col-md-5">
|
||||||
<div class="stat-card mb-3">
|
<div class="stat-card mb-3">
|
||||||
<h6 class=mb-3><i class=bi bi-info-circle></i> Recording an intake</h6>
|
<h6 class="mb-3"><i class="bi bi-info-circle"></i> Recording an intake</h6>
|
||||||
<p class="small mb-2">
|
<p class="small mb-2">
|
||||||
An intake is the moment a collector group hands over shea at the processing
|
An intake is the moment a collector group hands over shea at the processing
|
||||||
site. It is the record a finished batch is traced back to, so the fields
|
site. It is the record a finished batch is traced back to, so the fields
|
||||||
marked <span class=text-danger>*</span> are required: they are the ones the
|
marked <span class="text-danger">*</span> are required: they are the ones the
|
||||||
platform's due-diligence checks read.
|
platform's due-diligence checks read.
|
||||||
</p>
|
</p>
|
||||||
<p class="small mb-0">
|
<p class="small mb-0">
|
||||||
|
|
@ -51,8 +51,8 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3><i class=bi bi-shield-check></i> What these records feed</h6>
|
<h6 class="mb-3"><i class="bi bi-shield-check"></i> What these records feed</h6>
|
||||||
<ul class="small mb-0 ps-3">
|
<ul class="small mb-0 ps-3">
|
||||||
<li><strong>Lineage</strong> — a batch needs at least one intake linked to it</li>
|
<li><strong>Lineage</strong> — a batch needs at least one intake linked to it</li>
|
||||||
<li><strong>Intake data</strong> — a linked intake must have both a date and a weight</li>
|
<li><strong>Intake data</strong> — a linked intake must have both a date and a weight</li>
|
||||||
|
|
|
||||||
|
|
@ -6,36 +6,36 @@
|
||||||
{% for m in messages %}<div class="alert alert-{{ m.tags }} py-2">{{ m }}</div>{% endfor %}
|
{% for m in messages %}<div class="alert alert-{{ m.tags }} py-2">{{ m }}</div>{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>Harvest Intakes</h2>
|
<h2>Harvest Intakes</h2>
|
||||||
<div>
|
<div>
|
||||||
<span class="text-secondary me-2">{{ page_obj.paginator.count }} total</span>
|
<span class="text-secondary me-2">{{ page_obj.paginator.count }} total</span>
|
||||||
<a href={% url 'ops:intake_create' %} class=btn btn-sm btn-primary><i class=bi bi-plus-lg></i> New intake</a>
|
<a href="{% url 'ops:intake_create' %}" class="btn btn-sm btn-primary"><i class="bi bi-plus-lg"></i> New intake</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=filter-bar>
|
<div class="filter-bar">
|
||||||
<form method=get class=row g-2 align-items-end>
|
<form method="get" class="row g-2 align-items-end">
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<input type=text name=q class=form-control form-control-sm placeholder=Search reference... value={{ current_q }}>
|
<input type="text" name="q" class="form-control form-control-sm" placeholder="Search reference..." value="{{ current_q }}">
|
||||||
</div>
|
</div>
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<select name=status class=form-select form-select-sm>
|
<select name="status" class="form-select form-select-sm">
|
||||||
<option value=>All Statuses</option>
|
<option value="">All Statuses</option>
|
||||||
{% for val, label in status_choices %}
|
{% for val, label in status_choices %}
|
||||||
<option value={{ val }} {% if current_status == val %}selected{% endif %}>{{ label }}</option>
|
<option value="{{ val }}" {% if current_status == val %}selected{% endif %}>{{ label }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<button type=submit class=btn btn-sm btn-primary>Filter</button>
|
<button type="submit" class="btn btn-sm btn-primary">Filter</button>
|
||||||
<a href={% url 'ops:intake_list' %} class=btn btn-sm btn-outline-secondary>Clear</a>
|
<a href="{% url 'ops:intake_list' %}" class="btn btn-sm btn-outline-secondary">Clear</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card p-0>
|
<div class="stat-card p-0">
|
||||||
<table class=table table-hover mb-0>
|
<table class="table table-hover mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Reference</th>
|
<th>Reference</th>
|
||||||
|
|
@ -64,27 +64,27 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}-{% endif %}
|
{% else %}-{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td><span class=badge bg-secondary badge-status>{{ i.get_status_display }}</span></td>
|
<td><span class="badge bg-secondary badge-status">{{ i.get_status_display }}</span></td>
|
||||||
<td><a href={% url 'ops:intake_update' i.pk %} class=btn btn-sm btn-outline-primary>Correct</a></td>
|
<td><a href="{% url 'ops:intake_update' i.pk %}" class="btn btn-sm btn-outline-primary">Correct</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan=8 class=text-muted text-center py-3>No intakes recorded yet</td></tr>
|
<tr><td colspan="8" class="text-muted text-center py-3">No intakes recorded yet</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if page_obj.paginator.num_pages > 1 %}
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
<nav class=mt-3>
|
<nav class="mt-3">
|
||||||
<ul class=pagination pagination-sm justify-content-center>
|
<ul class="pagination pagination-sm justify-content-center">
|
||||||
{% if page_obj.has_previous %}
|
{% 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=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>
|
<li class="page-item"><a class="page-link" href="?page="{{ page_obj.previous_page_number }}>{{ page_obj.previous_page_number }}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class=page-item active><span class=page-link>{{ page_obj.number }}</span></li>
|
<li class="page-item active"><span class="page-link">{{ page_obj.number }}</span></li>
|
||||||
{% if page_obj.has_next %}
|
{% 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.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>
|
<li class="page-item"><a class="page-link" href="?page="{{ page_obj.paginator.num_pages }}>»</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,24 @@
|
||||||
{% block title %}QC Detail - IXG Operations{% endblock %}
|
{% block title %}QC Detail - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>QC Result: {{ result.batch.batch_reference }}</h2>
|
<h2>QC Result: {{ result.batch.batch_reference }}</h2>
|
||||||
<a href={% url 'ops:qc_list' %} class=btn btn-sm btn-outline-secondary><i class=bi bi-arrow-left></i> Back</a>
|
<a href="{% url 'ops:qc_list' %}" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left"></i> Back</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=row g-3>
|
<div class="row g-3">
|
||||||
<div class=col-md-6>
|
<div class="col-md-6">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<table class=table table-sm table-borderless mb-0>
|
<table class="table table-sm table-borderless mb-0">
|
||||||
<tr><td class=text-secondary>Batch</td><td><a href={% url 'ops:batch_detail' result.batch.pk %}>{{ result.batch.batch_reference }}</a></td></tr>
|
<tr><td class="text-secondary">Batch</td><td><a href="{% url 'ops:batch_detail' result.batch.pk %}">{{ result.batch.batch_reference }}</a></td></tr>
|
||||||
<tr><td class=text-secondary>Overall Result</td><td>{% if result.overall_pass %}<span class=badge bg-success>Pass</span>{% else %}<span class=badge bg-danger>Fail</span>{% endif %}</td></tr>
|
<tr><td class="text-secondary">Overall Result</td><td>{% if result.overall_pass %}<span class="badge bg-success">Pass</span>{% else %}<span class="badge bg-danger">Fail</span>{% endif %}</td></tr>
|
||||||
<tr><td class=text-secondary>FFA %</td><td>{{ result.ffa_percentage }}</td></tr>
|
<tr><td class="text-secondary">FFA %</td><td>{{ result.ffa_percentage }}</td></tr>
|
||||||
<tr><td class=text-secondary>Moisture %</td><td>{{ result.moisture_percentage }}</td></tr>
|
<tr><td class="text-secondary">Moisture %</td><td>{{ result.moisture_percentage }}</td></tr>
|
||||||
<tr><td class=text-secondary>Peroxide Value</td><td>{{ result.peroxide_value }}</td></tr>
|
<tr><td class="text-secondary">Peroxide Value</td><td>{{ result.peroxide_value }}</td></tr>
|
||||||
<tr><td class=text-secondary>Visual Grade</td><td>{{ result.visual_grade }}</td></tr>
|
<tr><td class="text-secondary">Visual Grade</td><td>{{ result.visual_grade }}</td></tr>
|
||||||
<tr><td class=text-secondary>Tested By</td><td>{{ result.tested_by|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Tested By</td><td>{{ result.tested_by|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Tested At</td><td>{{ result.tested_at|date:'d/m/Y H:i' }}</td></tr>
|
<tr><td class="text-secondary">Tested At</td><td>{{ result.tested_at|date:'d/m/Y H:i' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Lab Reference</td><td>{{ result.lab_reference|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Lab Reference</td><td>{{ result.lab_reference|default:'-' }}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,29 +2,29 @@
|
||||||
{% block title %}QC Results - IXG Operations{% endblock %}
|
{% block title %}QC Results - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>QC Results</h2>
|
<h2>QC Results</h2>
|
||||||
<span class=text-secondary>{{ page_obj.paginator.count }} total</span>
|
<span class="text-secondary">{{ page_obj.paginator.count }} total</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=filter-bar>
|
<div class="filter-bar">
|
||||||
<form method=get class=row g-2 align-items-end>
|
<form method="get" class="row g-2 align-items-end">
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<select name=passed class=form-select form-select-sm>
|
<select name="passed" class="form-select form-select-sm">
|
||||||
<option value=>All Results</option>
|
<option value="">All Results</option>
|
||||||
<option value=1 {% if current_passed == '1' %}selected{% endif %}>Passed</option>
|
<option value="1" {% if current_passed == '1' %}selected{% endif %}>Passed</option>
|
||||||
<option value=0 {% if current_passed == '0' %}selected{% endif %}>Failed</option>
|
<option value="0" {% if current_passed == '0' %}selected{% endif %}>Failed</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<button type=submit class=btn btn-sm btn-primary>Filter</button>
|
<button type="submit" class="btn btn-sm btn-primary">Filter</button>
|
||||||
<a href={% url 'ops:qc_list' %} class=btn btn-sm btn-outline-secondary>Clear</a>
|
<a href="{% url 'ops:qc_list' %}" class="btn btn-sm btn-outline-secondary">Clear</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card p-0>
|
<div class="stat-card p-0">
|
||||||
<table class=table table-hover mb-0>
|
<table class="table table-hover mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th>Batch</th><th>Result</th><th>FFA%</th><th>Moisture%</th><th>Peroxide</th><th>Visual</th><th>Tested</th><th></th></tr>
|
<tr><th>Batch</th><th>Result</th><th>FFA%</th><th>Moisture%</th><th>Peroxide</th><th>Visual</th><th>Tested</th><th></th></tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -32,26 +32,26 @@
|
||||||
{% for r in results %}
|
{% for r in results %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>{{ r.batch.batch_reference }}</strong></td>
|
<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>{% 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.ffa_percentage }}</td>
|
||||||
<td>{{ r.moisture_percentage }}</td>
|
<td>{{ r.moisture_percentage }}</td>
|
||||||
<td>{{ r.peroxide_value }}</td>
|
<td>{{ r.peroxide_value }}</td>
|
||||||
<td>{{ r.visual_grade }}</td>
|
<td>{{ r.visual_grade }}</td>
|
||||||
<td>{{ r.tested_at|date:'d/m/Y' }}</td>
|
<td>{{ r.tested_at|date:'d/m/Y' }}</td>
|
||||||
<td><a href={% url 'ops:qc_detail' r.pk %} class=btn btn-sm btn-outline-primary>View</a></td>
|
<td><a href="{% url 'ops:qc_detail' r.pk %}" class="btn btn-sm btn-outline-primary">View</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan=8 class=text-muted text-center py-3>No QC results</td></tr>
|
<tr><td colspan="8" class="text-muted text-center py-3">No QC results</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if page_obj.paginator.num_pages > 1 %}
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
<nav class=mt-3><ul class=pagination pagination-sm justify-content-center>
|
<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 %}
|
{% 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>
|
<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 %}
|
{% 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>
|
</ul></nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,48 +2,48 @@
|
||||||
{% block title %}QC Verification - IXG Operations{% endblock %}
|
{% block title %}QC Verification - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>QC Verification: {{ result.batch.batch_reference }}</h2>
|
<h2>QC Verification: {{ result.batch.batch_reference }}</h2>
|
||||||
<a href={% url 'ops:qc_verify_list' %} class=btn btn-sm btn-outline-secondary><i class=bi bi-arrow-left></i> Back</a>
|
<a href="{% url 'ops:qc_verify_list' %}" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left"></i> Back</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
{% for m in messages %}<div class="alert alert-{{ m.tags }} py-2">{{ m }}</div>{% endfor %}
|
{% for m in messages %}<div class="alert alert-{{ m.tags }} py-2">{{ m }}</div>{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class=row g-3>
|
<div class="row g-3">
|
||||||
<div class=col-md-7>
|
<div class="col-md-7">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>Structured QC Result</h6>
|
<h6 class="mb-3">Structured QC Result</h6>
|
||||||
<table class=table table-sm table-borderless mb-0>
|
<table class="table table-sm table-borderless mb-0">
|
||||||
<tr><td class=text-secondary>Batch</td><td><a href={% url 'ops:batch_detail' result.batch.pk %}>{{ result.batch.batch_reference }}</a></td></tr>
|
<tr><td class="text-secondary">Batch</td><td><a href="{% url 'ops:batch_detail' result.batch.pk %}">{{ result.batch.batch_reference }}</a></td></tr>
|
||||||
<tr><td class=text-secondary>Overall Result</td><td>{% if result.overall_pass %}<span class=badge bg-success>Pass</span>{% else %}<span class=badge bg-danger>Fail</span>{% endif %}</td></tr>
|
<tr><td class="text-secondary">Overall Result</td><td>{% if result.overall_pass %}<span class="badge bg-success">Pass</span>{% else %}<span class="badge bg-danger">Fail</span>{% endif %}</td></tr>
|
||||||
<tr><td class=text-secondary>Specification</td><td>{{ result.spec_version|default:'legacy limits' }}</td></tr>
|
<tr><td class="text-secondary">Specification</td><td>{{ result.spec_version|default:'legacy limits' }}</td></tr>
|
||||||
<tr><td class=text-secondary>FFA %</td><td>{{ result.ffa_percentage }} <span class=text-muted>({{ result.method_ffa|default:'no method' }})</span></td></tr>
|
<tr><td class="text-secondary">FFA %</td><td>{{ result.ffa_percentage }} <span class="text-muted">({{ result.method_ffa|default:'no method' }})</span></td></tr>
|
||||||
<tr><td class=text-secondary>Moisture %</td><td>{{ result.moisture_percentage }} <span class=text-muted>({{ result.method_moisture|default:'no method' }})</span></td></tr>
|
<tr><td class="text-secondary">Moisture %</td><td>{{ result.moisture_percentage }} <span class="text-muted">({{ result.method_moisture|default:'no method' }})</span></td></tr>
|
||||||
<tr><td class=text-secondary>Peroxide Value</td><td>{{ result.peroxide_value }} <span class=text-muted>({{ result.method_peroxide|default:'no method' }})</span></td></tr>
|
<tr><td class="text-secondary">Peroxide Value</td><td>{{ result.peroxide_value }} <span class="text-muted">({{ result.method_peroxide|default:'no method' }})</span></td></tr>
|
||||||
<tr><td class=text-secondary>Visual Grade</td><td>{{ result.visual_grade }}</td></tr>
|
<tr><td class="text-secondary">Visual Grade</td><td>{{ result.visual_grade }}</td></tr>
|
||||||
<tr><td class=text-secondary>Result Status</td><td>{{ result.get_result_status_display }}</td></tr>
|
<tr><td class="text-secondary">Result Status</td><td>{{ result.get_result_status_display }}</td></tr>
|
||||||
<tr><td class=text-secondary>Lab Reference</td><td>{{ result.lab_reference|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Lab Reference</td><td>{{ result.lab_reference|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Tested By</td><td>{{ result.tested_by|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Tested By</td><td>{{ result.tested_by|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Entered By</td><td>{% if result.entered_by %}{{ result.entered_by.full_name|default:result.entered_by.email }}{% else %}-{% endif %}</td></tr>
|
<tr><td class="text-secondary">Entered By</td><td>{% if result.entered_by %}{{ result.entered_by.full_name|default:result.entered_by.email }}{% else %}-{% endif %}</td></tr>
|
||||||
<tr><td class=text-secondary>Tested At</td><td>{{ result.tested_at|date:'d/m/Y H:i' }}</td></tr>
|
<tr><td class="text-secondary">Tested At</td><td>{{ result.tested_at|date:'d/m/Y H:i' }}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-md-5>
|
<div class="col-md-5">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<h6 class=mb-3>Approval Decision</h6>
|
<h6 class="mb-3">Approval Decision</h6>
|
||||||
{% if result.verification_status == 'draft' %}
|
{% if result.verification_status == 'draft' %}
|
||||||
<form method=post>
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<p class=text-muted>This action is recorded as the quality approval. The submitter cannot approve their own result.</p>
|
<p class="text-muted">This action is recorded as the quality approval. The submitter cannot approve their own result.</p>
|
||||||
<button type=submit name=approved value=1 class="btn btn-success w-100 mb-2"><i class=bi bi-check-circle></i> Approve & Generate CoA</button>
|
<button type="submit" name="approved" value="1" class="btn btn-success w-100 mb-2"><i class="bi bi-check-circle"></i> Approve & Generate CoA</button>
|
||||||
<button type=submit name=approved value=0 class="btn btn-outline-danger w-100"><i class=bi bi-x-circle></i> Reject</button>
|
<button type="submit" name="approved" value="0" class="btn btn-outline-danger w-100"><i class="bi bi-x-circle"></i> Reject</button>
|
||||||
</form>
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p><span class=badge {% if result.verification_status == 'approved' %}bg-success{% else %}bg-danger{% endif %}>{{ result.get_verification_status_display }}</span></p>
|
<p><span class="badge" {% if result.verification_status == 'approved' %}bg-success{% else %}bg-danger{% endif %}>{{ result.get_verification_status_display }}</span></p>
|
||||||
{% if result.verified_by %}<p class=text-muted mb-0>Verified by {{ result.verified_by.full_name|default:result.verified_by.email }} on {{ result.approved_at|date:'d/m/Y H:i' }}</p>{% endif %}
|
{% if result.verified_by %}<p class="text-muted mb-0">Verified by {{ result.verified_by.full_name|default:result.verified_by.email }} on {{ result.approved_at|date:'d/m/Y H:i' }}</p>{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,29 +2,29 @@
|
||||||
{% block title %}QC Approvals - IXG Operations{% endblock %}
|
{% block title %}QC Approvals - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>QC Approvals (four-eyes verification)</h2>
|
<h2>QC Approvals (four-eyes verification)</h2>
|
||||||
<span class=text-secondary>{{ page_obj.paginator.count }} pending</span>
|
<span class="text-secondary">{{ page_obj.paginator.count }} pending</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=filter-bar>
|
<div class="filter-bar">
|
||||||
<form method=get class=row g-2 align-items-end>
|
<form method="get" class="row g-2 align-items-end">
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<select name=passed class=form-select form-select-sm>
|
<select name="passed" class="form-select form-select-sm">
|
||||||
<option value=>All Results</option>
|
<option value="">All Results</option>
|
||||||
<option value=1 {% if current_passed == '1' %}selected{% endif %}>Passed</option>
|
<option value="1" {% if current_passed == '1' %}selected{% endif %}>Passed</option>
|
||||||
<option value=0 {% if current_passed == '0' %}selected{% endif %}>Failed</option>
|
<option value="0" {% if current_passed == '0' %}selected{% endif %}>Failed</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<button type=submit class=btn btn-sm btn-primary>Filter</button>
|
<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>
|
<a href="{% url 'ops:qc_verify_list' %}" class="btn btn-sm btn-outline-secondary">Clear</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card p-0>
|
<div class="stat-card p-0">
|
||||||
<table class=table table-hover mb-0>
|
<table class="table table-hover mb-0">
|
||||||
<thead>
|
<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>
|
<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>
|
</thead>
|
||||||
|
|
@ -32,27 +32,27 @@
|
||||||
{% for r in results %}
|
{% for r in results %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>{{ r.batch.batch_reference }}</strong></td>
|
<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>{% 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.ffa_percentage }}</td>
|
||||||
<td>{{ r.moisture_percentage }}</td>
|
<td>{{ r.moisture_percentage }}</td>
|
||||||
<td>{{ r.peroxide_value }}</td>
|
<td>{{ r.peroxide_value }}</td>
|
||||||
<td>{{ r.visual_grade }}</td>
|
<td>{{ r.visual_grade }}</td>
|
||||||
<td>{% if r.entered_by %}{{ r.entered_by.full_name|default:r.entered_by.email }}{% else %}-{% endif %}</td>
|
<td>{% if r.entered_by %}{{ r.entered_by.full_name|default:r.entered_by.email }}{% else %}-{% endif %}</td>
|
||||||
<td>{{ r.spec_version|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>
|
<td><a href="{% url 'ops:qc_verify_detail' r.pk %}" class="btn btn-sm btn-primary">Verify</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan=9 class=text-muted text-center py-3>No QC results awaiting verification</td></tr>
|
<tr><td colspan="9" class="text-muted text-center py-3">No QC results awaiting verification</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if page_obj.paginator.num_pages > 1 %}
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
<nav class=mt-3><ul class=pagination pagination-sm justify-content-center>
|
<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 %}
|
{% 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>
|
<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 %}
|
{% 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>
|
</ul></nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,25 +2,25 @@
|
||||||
{% block title %}Shipment Detail - IXG Operations{% endblock %}
|
{% block title %}Shipment Detail - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>Shipment: {{ shipment.batch.batch_reference }}</h2>
|
<h2>Shipment: {{ shipment.batch.batch_reference }}</h2>
|
||||||
<a href={% url 'ops:shipment_list' %} class=btn btn-sm btn-outline-secondary><i class=bi bi-arrow-left></i> Back</a>
|
<a href="{% url 'ops:shipment_list' %}" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left"></i> Back</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=row g-3>
|
<div class="row g-3">
|
||||||
<div class=col-md-6>
|
<div class="col-md-6">
|
||||||
<div class=stat-card>
|
<div class="stat-card">
|
||||||
<table class=table table-sm table-borderless mb-0>
|
<table class="table table-sm table-borderless mb-0">
|
||||||
<tr><td class=text-secondary>Batch</td><td><a href={% url 'ops:batch_detail' shipment.batch.pk %}>{{ shipment.batch.batch_reference }}</a></td></tr>
|
<tr><td class="text-secondary">Batch</td><td><a href="{% url 'ops:batch_detail' shipment.batch.pk %}">{{ shipment.batch.batch_reference }}</a></td></tr>
|
||||||
<tr><td class=text-secondary>Status</td><td><span class=badge bg-secondary badge-status>{{ shipment.get_status_display }}</span></td></tr>
|
<tr><td class="text-secondary">Status</td><td><span class="badge bg-secondary badge-status">{{ shipment.get_status_display }}</span></td></tr>
|
||||||
<tr><td class=text-secondary>Origin Port</td><td>{{ shipment.origin_port }}</td></tr>
|
<tr><td class="text-secondary">Origin Port</td><td>{{ shipment.origin_port }}</td></tr>
|
||||||
<tr><td class=text-secondary>Destination Port</td><td>{{ shipment.destination_port }}</td></tr>
|
<tr><td class="text-secondary">Destination Port</td><td>{{ shipment.destination_port }}</td></tr>
|
||||||
<tr><td class=text-secondary>Vessel Name</td><td>{{ shipment.vessel_name|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Vessel Name</td><td>{{ shipment.vessel_name|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Container Ref</td><td>{{ shipment.container_ref|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Container Ref</td><td>{{ shipment.container_ref|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>ETD Nigeria</td><td>{{ shipment.etd_nigeria|date:'d/m/Y'|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">ETD Nigeria</td><td>{{ shipment.etd_nigeria|date:'d/m/Y'|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>ETA UK</td><td>{{ shipment.eta_uk|date:'d/m/Y'|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">ETA UK</td><td>{{ shipment.eta_uk|date:'d/m/Y'|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Bill of Lading</td><td>{{ shipment.bl_number|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Bill of Lading</td><td>{{ shipment.bl_number|default:'-' }}</td></tr>
|
||||||
<tr><td class=text-secondary>Freight Forwarder</td><td>{{ shipment.freight_forwarder|default:'-' }}</td></tr>
|
<tr><td class="text-secondary">Freight Forwarder</td><td>{{ shipment.freight_forwarder|default:'-' }}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,30 +2,30 @@
|
||||||
{% block title %}Shipments - IXG Operations{% endblock %}
|
{% block title %}Shipments - IXG Operations{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class=page-header d-flex justify-content-between align-items-center>
|
<div class="page-header d-flex justify-content-between align-items-center">
|
||||||
<h2>Shipments</h2>
|
<h2>Shipments</h2>
|
||||||
<span class=text-secondary>{{ page_obj.paginator.count }} total</span>
|
<span class="text-secondary">{{ page_obj.paginator.count }} total</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=filter-bar>
|
<div class="filter-bar">
|
||||||
<form method=get class=row g-2 align-items-end>
|
<form method="get" class="row g-2 align-items-end">
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<select name=status class=form-select form-select-sm>
|
<select name="status" class="form-select form-select-sm">
|
||||||
<option value=>All Statuses</option>
|
<option value="">All Statuses</option>
|
||||||
{% for val, label in status_choices %}
|
{% for val, label in status_choices %}
|
||||||
<option value={{ val }} {% if current_status == val %}selected{% endif %}>{{ label }}</option>
|
<option value="{{ val }}" {% if current_status == val %}selected{% endif %}>{{ label }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class=col-auto>
|
<div class="col-auto">
|
||||||
<button type=submit class=btn btn-sm btn-primary>Filter</button>
|
<button type="submit" class="btn btn-sm btn-primary">Filter</button>
|
||||||
<a href={% url 'ops:shipment_list' %} class=btn btn-sm btn-outline-secondary>Clear</a>
|
<a href="{% url 'ops:shipment_list' %}" class="btn btn-sm btn-outline-secondary">Clear</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=stat-card p-0>
|
<div class="stat-card p-0">
|
||||||
<table class=table table-hover mb-0>
|
<table class="table table-hover mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th>Batch</th><th>Status</th><th>Vessel</th><th>Container</th><th>ETD Nigeria</th><th>ETA UK</th><th></th></tr>
|
<tr><th>Batch</th><th>Status</th><th>Vessel</th><th>Container</th><th>ETD Nigeria</th><th>ETA UK</th><th></th></tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -33,25 +33,25 @@
|
||||||
{% for s in shipments %}
|
{% for s in shipments %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>{{ s.batch.batch_reference }}</strong></td>
|
<td><strong>{{ s.batch.batch_reference }}</strong></td>
|
||||||
<td><span class=badge bg-secondary badge-status>{{ s.get_status_display }}</span></td>
|
<td><span class="badge bg-secondary badge-status">{{ s.get_status_display }}</span></td>
|
||||||
<td>{{ s.vessel_name|default:'-' }}</td>
|
<td>{{ s.vessel_name|default:'-' }}</td>
|
||||||
<td>{{ s.container_ref|default:'-' }}</td>
|
<td>{{ s.container_ref|default:'-' }}</td>
|
||||||
<td>{{ s.etd_nigeria|date:'d/m/Y'|default:'-' }}</td>
|
<td>{{ s.etd_nigeria|date:'d/m/Y'|default:'-' }}</td>
|
||||||
<td>{{ s.eta_uk|date:'d/m/Y'|default:'-' }}</td>
|
<td>{{ s.eta_uk|date:'d/m/Y'|default:'-' }}</td>
|
||||||
<td><a href={% url 'ops:shipment_detail' s.pk %} class=btn btn-sm btn-outline-primary>View</a></td>
|
<td><a href="{% url 'ops:shipment_detail' s.pk %}" class="btn btn-sm btn-outline-primary">View</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan=7 class=text-muted text-center py-3>No shipments</td></tr>
|
<tr><td colspan="7" class="text-muted text-center py-3">No shipments</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if page_obj.paginator.num_pages > 1 %}
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
<nav class=mt-3><ul class=pagination pagination-sm justify-content-center>
|
<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 %}
|
{% 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>
|
<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 %}
|
{% 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>
|
</ul></nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue