loko/streetup/stock/templates/stock/serialized_item_form.html
2026-07-22 14:48:40 +02:00

146 lines
6.8 KiB
HTML

{% extends "base.html" %}
{% load i18n %}
{% block content %}
<div class="container mt-3" style="max-width: 700px;">
<div class="d-flex justify-content-between align-items-center mb-3">
<h3 class="h3">
<i class="bi bi-upc-scan"></i>
{% translate "Enregistrer un article tracé" %}
</h3>
<a href="{% url 'stock:serialized_items_list' %}" class="btn btn-light">
<i class="bi bi-arrow-left"></i> {% translate "Retour" %}
</a>
</div>
<div class="card shadow-sm">
<div class="card-body">
<form method="post">
{% csrf_token %}
<div class="mb-3">
<label class="form-label fw-semibold">{% translate "Produit" %} *</label>
<select name="product" class="form-select" required>
<option value="">— {% translate "Sélectionner un produit" %} —</option>
{% for p in serialized_products %}
<option value="{{ p.pk }}"
{% if initial_product and initial_product.pk == p.pk %}selected
{% elif post.product == p.pk|stringformat:"s" %}selected{% endif %}>
{{ p.name }} ({{ p.code }})
</option>
{% endfor %}
</select>
{% if not serialized_products %}
<div class="form-text text-warning">
<i class="bi bi-exclamation-triangle"></i>
{% translate "Aucun produit n'est configuré pour le suivi par numéro de série. Activez l'option « Articles tracés » sur le produit souhaité." %}
</div>
{% endif %}
</div>
<div class="mb-3">
<label class="form-label fw-semibold">{% translate "Numéro de série" %} *</label>
<input type="text" name="serial_number" class="form-control font-monospace"
value="{{ post.serial_number|default:'' }}"
placeholder="{% translate 'Ex: SN-2024-00123' %}" required>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">{% translate "Emplacement initial" %}</label>
<select name="current_location" class="form-select">
<option value="">— {% translate "Aucun" %} —</option>
{% for loc in locations %}
<option value="{{ loc.pk }}" {% if post.current_location == loc.pk|stringformat:"s" %}selected{% endif %}>
{{ loc.warehouse.name }} — {{ loc.name }}
</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">{% translate "Attribuer à (optionnel)" %}</label>
<select name="current_holder" class="form-select">
<option value="">— {% translate "Aucun" %} —</option>
{% for member in members %}
<option value="{{ member.pk }}" {% if post.current_holder == member.pk|stringformat:"s" %}selected{% endif %}>
{{ member.name }}{% if member.teams.exists %} ({{ member.teams_display }}){% endif %}
</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">{% translate "Notes" %}</label>
<textarea name="notes" class="form-control" rows="2"
placeholder="{% translate 'Notes optionnelles…' %}">{{ post.notes|default:'' }}</textarea>
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">
<i class="bi bi-check2"></i> {% translate "Enregistrer" %}
</button>
<a href="{% url 'stock:serialized_items_list' %}" class="btn btn-outline-secondary">
{% translate "Annuler" %}
</a>
</div>
</form>
</div>
</div>
</div>
{% endblock content %}
{% block script %}
<script>
document.addEventListener("DOMContentLoaded", function() {
const productSelect = document.querySelector('select[name="product"]');
const locationSelect = document.querySelector('select[name="current_location"]');
const originalOptions = Array.from(locationSelect.options);
const apiBaseUrl = "{% url 'stock:product_locations_api' 0 %}".replace('/0/', '/{id}/');
function filterLocations() {
const productId = productSelect.value;
if (!productId) {
// If no product is selected, show all options
locationSelect.innerHTML = "";
originalOptions.forEach(opt => locationSelect.appendChild(opt.cloneNode(true)));
locationSelect.disabled = false;
return;
}
locationSelect.disabled = true;
const currentSelectedValue = locationSelect.value;
const url = apiBaseUrl.replace('{id}', productId);
fetch(url)
.then(response => response.json())
.then(data => {
const allowedIds = new Set(data.locations.map(loc => loc.id.toString()));
// Rebuild options: keep the "-- Aucun --" option (empty value)
// and only the allowed locations.
locationSelect.innerHTML = "";
originalOptions.forEach(opt => {
if (opt.value === "" || allowedIds.has(opt.value)) {
const newOpt = opt.cloneNode(true);
if (opt.value === currentSelectedValue) {
newOpt.selected = true;
}
locationSelect.appendChild(newOpt);
}
});
locationSelect.disabled = false;
})
.catch(error => {
console.error("Error fetching locations:", error);
locationSelect.disabled = false;
});
}
productSelect.addEventListener("change", filterLocations);
// Run on initial load if product is already selected (e.g. initial_product or after POST error)
if (productSelect.value) {
filterLocations();
}
});
</script>
{% endblock script %}