ixg_platform/templates/ops/batch_lineage.html
ixgadmin 4b4477d359 Add batch create, edit and lineage screens to the ops portal
The batch form refuses to type over a QC status or move a failed batch, and
the lineage formset refuses an allocation the intake cannot support. The
origin-facility help text and the QC status card now describe what the form
actually does, and buyer POSTs to the create and edit screens are refused.
2026-09-17 14:48:06 +00:00

114 lines
4.5 KiB
HTML

{% extends 'ops/base_ops.html' %}
{% block title %}Intake lineage - {{ batch.batch_reference }} - IXG Operations{% endblock %}
{% block content %}
{% if messages %}
{% for m in messages %}<div class="alert alert-{{ m.tags }} py-2">{{ m }}</div>{% endfor %}
{% endif %}
<div class="page-header d-flex justify-content-between align-items-center">
<h2>Intake lineage: {{ batch.batch_reference }}</h2>
<a href="{% url 'ops:batch_detail' batch.pk %}" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left"></i> Back to the batch</a>
</div>
<div class="row g-3">
<div class="col-md-8">
<div class="stat-card">
<form method="post" novalidate>
{% csrf_token %}
{{ formset.management_form }}
{% if formset.non_form_errors %}
{% for e in formset.non_form_errors %}<div class="alert alert-danger py-2">{{ e }}</div>{% endfor %}
{% endif %}
<!-- table-layout: fixed, or the intake dropdown's intrinsic width (a native
select sizes to its longest option) pushes the weight field and the
Remove box off the card. -->
<table class="table table-sm align-middle mb-3" style="table-layout: fixed;">
<thead>
<tr>
<th>Harvest intake</th>
<th style="width: 10rem;">Allocated (kg)</th>
<th style="width: 6rem;">Remove</th>
</tr>
</thead>
<tbody>
{% for f in formset.forms %}
<tr>
{% for hidden in f.hidden_fields %}{{ hidden }}{% endfor %}
<td>
{{ f.harvest_intake }}
{% for e in f.harvest_intake.errors %}<div class="text-danger small">{{ e }}</div>{% endfor %}
</td>
<td>
{{ f.weight_allocated_kg }}
{% for e in f.weight_allocated_kg.errors %}<div class="text-danger small">{{ e }}</div>{% endfor %}
</td>
<td>
{% if f.instance.pk %}{{ f.DELETE }}{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="submit" class="btn btn-primary">Save lineage</button>
<a href="{% url 'ops:batch_detail' batch.pk %}" class="btn btn-outline-secondary">Cancel</a>
</form>
</div>
</div>
<div class="col-md-4">
<div class="stat-card mb-3">
<h6 class="mb-3"><i class="bi bi-calculator"></i> Weights</h6>
<table class="table table-sm mb-0">
<tr><td class="text-secondary">Allocated to this batch</td><td>{{ total_allocated }} kg</td></tr>
<tr><td class="text-secondary">Batch weight</td><td>{{ batch.weight_kg|default:'-' }} kg</td></tr>
{% if difference is not None %}
<tr>
<td class="text-secondary">Difference</td>
<td>{{ difference }} kg</td>
</tr>
{% endif %}
</table>
<p class="small text-secondary mt-2 mb-0">
The platform shows these two figures side by side; it does not reconcile
them. A difference where the batch is heavier means part of the batch is
not traced to an intake; allocations above the batch weight are the usual
processing loss.
</p>
</div>
<div class="stat-card mb-3">
<h6 class="mb-3"><i class="bi bi-shield-check"></i> What this feeds</h6>
<ul class="small mb-2 ps-3">
<li><strong>Lineage</strong> &mdash; the batch needs at least one intake</li>
<li><strong>Geolocation</strong> &mdash; every linked intake must point at a
<em>verified</em> origin zone</li>
<li><strong>Intake data</strong> &mdash; every linked intake needs a date and
a weight</li>
</ul>
<p class="small mb-0">
This table is what the due-diligence case for {{ batch.batch_reference }}
reads, and what a buyer or an auditor traces the batch back through.
</p>
</div>
<div class="stat-card">
<h6 class="mb-3"><i class="bi bi-exclamation-triangle"></i> One intake, limited weight</h6>
<p class="small mb-2">
An intake received a finite weight of shea, and what is allocated out of it
is counted across <strong>every</strong> batch. An allocation that would
take more than the intake received is refused, whether the excess is over
the intake's own weight or over what other batches have already taken.
</p>
<p class="small mb-0">
Removing a row here deletes the link only &mdash; the intake record itself
is untouched.
</p>
</div>
</div>
</div>
{% endblock %}