Walkthrough step 11 said shipment records came through the API or the admin area, because the portal was read-only. The list and detail pages now carry New shipment and Edit shipment controls, with /ops/shipments/new/ and /ops/shipments/<uuid>/edit/ mirroring the intake and batch screens. The form requires the fields the buyer's page reads — status, vessel, container, ETD and ETA — and refuses a departure after the arrival. The bill of lading and the forwarder stay optional, and the ports keep their model defaults. A batch that already has a shipment is flagged in the dropdown and warned about after saving rather than blocked, because a split consignment is legitimate. The batch dropdown labels each batch with its own journey status, and a card explains that the two statuses are independent. Also fixes a pre-existing defect the new screen would have shared: the native date inputs were rendered in the en-gb d/m/Y format, which the browser discards, so the intake and batch edit forms silently opened with empty dates. They now carry the ISO format a native date input requires.
89 lines
3.4 KiB
HTML
89 lines
3.4 KiB
HTML
{% extends 'ops/base_ops.html' %}
|
|
{% block title %}{{ page_title }} - IXG Operations{% endblock %}
|
|
{% block content %}
|
|
|
|
<div class="page-header d-flex justify-content-between align-items-center">
|
|
<h2>{{ page_title }}</h2>
|
|
<a href="{% url 'ops:shipment_list' %}" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left"></i> Back</a>
|
|
</div>
|
|
|
|
<div class="row g-3">
|
|
<div class="col-md-7">
|
|
<div class="stat-card">
|
|
<form method="post" novalidate id="shipment-form">
|
|
{% csrf_token %}
|
|
|
|
{% if form.non_field_errors %}
|
|
{% for e in form.non_field_errors %}<div class="alert alert-danger py-2">{{ e }}</div>{% endfor %}
|
|
{% endif %}
|
|
|
|
{% for field in form %}
|
|
<div class="mb-3">
|
|
<label class="form-label" for="{{ field.id_for_label }}">
|
|
{{ field.label }}{% if field.field.required %} <span class="text-danger">*</span>{% endif %}
|
|
</label>
|
|
{{ field }}
|
|
{% 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 %}
|
|
</div>
|
|
{% endfor %}
|
|
|
|
<button type="submit" class="btn btn-primary">{{ submit_label }}</button>
|
|
<a href="{% url 'ops:shipment_list' %}" class="btn btn-outline-secondary">Cancel</a>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-5">
|
|
<div class="stat-card mb-3">
|
|
<h6 class="mb-3"><i class="bi bi-truck"></i> What a shipment is</h6>
|
|
<p class="small mb-2">
|
|
The consignment itself: the vessel, the container and the two dates the
|
|
buyer asks about most. It hangs off a batch, and the buyer sees it on
|
|
that batch's page.
|
|
</p>
|
|
<p class="small mb-0">
|
|
The record holds the <strong>current</strong> status, not a history of it.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="stat-card mb-3">
|
|
<h6 class="mb-3"><i class="bi bi-diagram-3"></i> Two separate statuses</h6>
|
|
<p class="small mb-2">
|
|
The <strong>batch</strong> has its own journey status (Harvested …
|
|
Delivered), moved on the batch screen and shown next to the batch in the
|
|
dropdown above. The <strong>shipment</strong> status is the one below, and
|
|
it moves freely between its seven values.
|
|
</p>
|
|
<p class="small mb-0">
|
|
They are independent: setting a shipment status here does not move the
|
|
batch, and the batch screen does not move the shipment.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="stat-card">
|
|
<h6 class="mb-3"><i class="bi bi-eye"></i> What the buyer sees</h6>
|
|
<p class="small mb-0">
|
|
The buyer's batch page reflects a new shipment status immediately. There is
|
|
no notification, and no history of when each stage happened.
|
|
</p>
|
|
</div>
|
|
|
|
{% if other_shipments %}
|
|
<div class="stat-card mt-3">
|
|
<h6 class="mb-3"><i class="bi bi-exclamation-triangle"></i> Other shipments on this batch</h6>
|
|
<p class="small mb-2">
|
|
A split consignment is legitimate, so this is shown rather than blocked.
|
|
Check it is not a duplicate.
|
|
</p>
|
|
<ul class="small mb-0 ps-3">
|
|
{% for s in other_shipments %}
|
|
<li>{{ s.get_status_display }}{% if s.container_ref %} — {{ s.container_ref }}{% endif %}</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
{% endblock %}
|