Harvest intakes could only be recorded in the administration area or through the API, so the first record the business actually creates was entered outside the portal it works in. Add list, create and correct screens under Harvest Intakes. The form is deliberately stricter than the model. HarvestIntake allows almost everything to be blank because records also arrive by API, and the platform copes by flagging the gaps later — the EUDR completeness check has an intake data test whose whole job is to catch a missing date or weight. The form therefore requires every field those checks read: reference, collector group, origin zone, date, weight and grade. Three things it does beyond capturing the fields: it suggests the next intake reference for the year (editable, since it may have to match a weighbridge ticket), fills the origin zone in from the collector group while leaving it editable, and refuses a duplicate reference — including one differing only in case. It queries, rather than blocks, when the chosen zone is not the one the group is registered to, and it marks unverified zones in the dropdown, because geolocation passes only for a verified zone. Correcting amends the record in place: the reference a buyer or auditor quotes does not change.
69 lines
5.1 KiB
HTML
69 lines
5.1 KiB
HTML
<!DOCTYPE html>
|
|
<html lang=en>
|
|
<head>
|
|
<meta charset=utf-8>
|
|
<meta name=viewport content=width=device-width, initial-scale=1>
|
|
<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 rel=stylesheet href=https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css>
|
|
<style>
|
|
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 .nav-link { color: #a0aec0; padding: .65rem 1.25rem; font-size: .875rem; }
|
|
.sidebar .nav-link:hover, .sidebar .nav-link.active { color: #fff; background: rgba(255,255,255,.08); }
|
|
.sidebar .nav-link i { margin-right: .5rem; }
|
|
.sidebar .brand { padding: 1rem 1.25rem; font-size: 1.1rem; font-weight: 700; color: #fff; border-bottom: 1px solid rgba(255,255,255,.08); margin-bottom: .5rem; }
|
|
.main { margin-left: 240px; }
|
|
.topbar { background: #fff; border-bottom: 1px solid #e2e8f0; padding: .75rem 1.5rem; display: flex; justify-content: space-between; align-items: center; }
|
|
.content { padding: 1.5rem; }
|
|
.stat-card { background: #fff; border-radius: .5rem; padding: 1.25rem; border: 1px solid #e2e8f0; }
|
|
.stat-card .stat-value { font-size: 1.75rem; font-weight: 700; }
|
|
.stat-card .stat-label { font-size: .8rem; color: #718096; text-transform: uppercase; letter-spacing: .05em; }
|
|
.badge-status { font-size: .75rem; }
|
|
.page-header { margin-bottom: 1.5rem; }
|
|
.page-header h2 { font-weight: 600; }
|
|
.filter-bar { background: #fff; border-radius: .5rem; padding: 1rem; border: 1px solid #e2e8f0; margin-bottom: 1.5rem; }
|
|
.guide-content img { max-width: 100%; height: auto; border-radius: .375rem; }
|
|
.guide-content table { width: 100%; border-collapse: collapse; margin-bottom: 1rem; }
|
|
.guide-content th, .guide-content td { border: 1px solid #e2e8f0; padding: .5rem .75rem; }
|
|
.guide-content pre { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: .375rem; padding: .75rem; }
|
|
.guide-content blockquote { border-left: 4px solid #a7f3d0; padding-left: 1rem; color: #475569; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class=sidebar>
|
|
<div class=brand>IXG Platform</div>
|
|
<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 '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 '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 '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 '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 '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 'guide' in request.resolver_match.url_name %}active{% endif %} href={% url 'ops:guide_index' %}><i class=bi bi-book></i> Help</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class=main>
|
|
<div class=topbar>
|
|
<span></span>
|
|
<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>
|
|
<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>
|
|
</div>
|
|
</div>
|
|
<div class=content>
|
|
{% block content %}{% endblock %}
|
|
</div>
|
|
</div>
|
|
|
|
<script src=https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js></script>
|
|
</body>
|
|
</html>
|