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

341 lines
17 KiB
HTML

{% extends "base.html" %}
{% load i18n %}
{% block content %}
<div class="container mt-3">
<div class="row">
<div class="col-lg-8 mx-auto">
<!-- En-tête -->
<div class="mb-4">
<h3>
<i class="bi bi-box-seam"></i>
{% if action == 'create' %}
{% translate "Nouveau produit" %}
{% else %}
{% translate "Modifier le produit" %} — {{ product.name }}
{% endif %}
</h3>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="{% url 'stock:warehouses' %}?tab=products">{% translate "Produits" %}</a>
</li>
{% if action == 'edit' %}
<li class="breadcrumb-item">
<a href="{% url 'stock:product_detail' product.pk %}">{{ product.name }}</a>
</li>
{% endif %}
<li class="breadcrumb-item active">
{% if action == 'create' %}{% translate "Nouveau" %}{% else %}{% translate "Modifier" %}{% endif %}
</li>
</ol>
</nav>
</div>
<!-- Formulaire -->
<div class="card shadow-sm">
<div class="card-body">
<form method="post">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-danger">
{{ form.non_field_errors }}
</div>
{% endif %}
<!-- Identification -->
<h6 class="text-muted text-uppercase fw-semibold mb-3 border-bottom pb-1">
{% translate "Identification" %}
</h6>
<div class="row">
<div class="col-md-4 mb-3">
<label for="{{ form.code.id_for_label }}" class="form-label">
{{ form.code.label }} <span class="text-danger">*</span>
</label>
{{ form.code }}
{% if form.code.errors %}
<div class="text-danger small mt-1">{{ form.code.errors }}</div>
{% endif %}
<div class="form-text">
{% if action == 'create' %}
<i class="bi bi-lock"></i> {% translate "Généré automatiquement" %}
{% else %}
{% translate "Code unique du produit" %}
{% endif %}
</div>
</div>
<div class="col-md-4 mb-3">
<label for="{{ form.sku.id_for_label }}" class="form-label">
{{ form.sku.label }} <span class="text-danger">*</span>
</label>
{{ form.sku }}
{% if form.sku.errors %}
<div class="text-danger small mt-1">{{ form.sku.errors }}</div>
{% endif %}
<div class="form-text">
{% if action == 'create' %}
<i class="bi bi-lock"></i> {% translate "Généré automatiquement" %}
{% else %}
{% translate "Référence fournisseur / interne" %}
{% endif %}
</div>
</div>
<div class="col-md-4 mb-3">
<label for="{{ form.category.id_for_label }}" class="form-label">
{{ form.category.label }}
</label>
{{ form.category }}
{% if form.category.errors %}
<div class="text-danger small mt-1">{{ form.category.errors }}</div>
{% endif %}
</div>
</div>
<div class="mb-3">
<label for="{{ form.name.id_for_label }}" class="form-label">
{{ form.name.label }} <span class="text-danger">*</span>
</label>
{{ form.name }}
{% if form.name.errors %}
<div class="text-danger small mt-1">{{ form.name.errors }}</div>
{% endif %}
</div>
<div class="mb-3">
<label for="{{ form.description.id_for_label }}" class="form-label">
{{ form.description.label }}
</label>
{{ form.description }}
{% if form.description.errors %}
<div class="text-danger small mt-1">{{ form.description.errors }}</div>
{% endif %}
</div>
<!-- Traçabilité -->
<h6 class="text-muted text-uppercase fw-semibold mb-3 border-bottom pb-1 mt-4">
{% translate "Traçabilité" %}
</h6>
<div class="mb-3">
<div class="form-check">
{{ form.is_serialized }}
<label class="form-check-label" for="{{ form.is_serialized.id_for_label }}">
{{ form.is_serialized.label }}
</label>
</div>
{% if form.is_serialized.help_text %}
<div class="form-text">{{ form.is_serialized.help_text }}</div>
{% endif %}
{% if form.is_serialized.errors %}
<div class="text-danger small mt-1">{{ form.is_serialized.errors }}</div>
{% endif %}
</div>
<!-- Unité, prix & seuil -->
<h6 class="text-muted text-uppercase fw-semibold mb-3 border-bottom pb-1 mt-4">
{% translate "Stock & tarification" %}
</h6>
<div class="row">
<div class="col-md-4 mb-3">
<label for="{{ form.unit.id_for_label }}" class="form-label">
{{ form.unit.label }} <span class="text-danger">*</span>
</label>
{{ form.unit }}
{% if form.unit.errors %}
<div class="text-danger small mt-1">{{ form.unit.errors }}</div>
{% endif %}
</div>
<div class="col-md-4 mb-3">
<label for="{{ form.price.id_for_label }}" class="form-label">
{{ form.price.label }}
</label>
<div class="input-group">
{{ form.price }}
<span class="input-group-text">€</span>
</div>
{% if form.price.errors %}
<div class="text-danger small mt-1">{{ form.price.errors }}</div>
{% endif %}
</div>
<div class="col-md-4 mb-3">
<label for="{{ form.threshold.id_for_label }}" class="form-label">
{{ form.threshold.label }}
<span class="text-danger">*</span>
<i class="bi bi-info-circle text-muted"
data-bs-toggle="tooltip"
title="{% translate 'Quantité minimale déclenchant une alerte de stock' %}"></i>
</label>
{{ form.threshold }}
{% if form.threshold.errors %}
<div class="text-danger small mt-1">{{ form.threshold.errors }}</div>
{% endif %}
</div>
<!-- Emplacements autorisés -->
<h6 class="text-muted text-uppercase fw-semibold mb-3 border-bottom pb-1 mt-4">
{% translate "Emplacements autorisés" %}
</h6>
<div class="mb-3">
<label for="{{ form.authorized_locations.id_for_label }}" class="form-label">
{{ form.authorized_locations.label }}
</label>
{{ form.authorized_locations }}
{% if form.authorized_locations.help_text %}
<div class="form-text">{{ form.authorized_locations.help_text }}</div>
{% endif %}
{% if form.authorized_locations.errors %}
<div class="text-danger small mt-1">{{ form.authorized_locations.errors }}</div>
{% endif %}
</div>
{% if action == 'create' %}
<div id="initial-quantities-section" class="mt-4 p-3 bg-light rounded border border-light-subtle" style="display: none;">
<h6 class="text-secondary fw-semibold mb-3">
<i class="bi bi-plus-circle me-1"></i>{% translate "Quantités initiales pour les emplacements sélectionnés" %}
</h6>
<div id="initial-quantities-container"></div>
</div>
{% endif %}
<!-- Boutons -->
<div class="d-flex justify-content-between mt-4">
<a href="{% if action == 'edit' %}{% url 'stock:product_detail' product.pk %}{% else %}{% url 'stock:warehouses' %}?tab=products{% endif %}"
class="btn btn-light">
<i class="bi bi-arrow-left"></i> {% translate "Annuler" %}
</a>
<button type="submit" class="btn btn-primary">
<i class="bi bi-check-lg"></i>
{% if action == 'create' %}
{% translate "Créer le produit" %}
{% else %}
{% translate "Enregistrer les modifications" %}
{% endif %}
</button>
</div>
</form>
</div>
</div>
<!-- Zone de danger (suppression) -->
{% if action == 'edit' %}
<div class="card border-danger mt-4">
<div class="card-header bg-danger text-white">
<i class="bi bi-exclamation-triangle"></i> {% translate "Désactivation" %}
</div>
<div class="card-body">
{% if product.is_active %}
<p class="text-muted mb-3">
{% translate "Rendre ce produit inactif empêchera son utilisation pour les futurs mouvements de stock ou bons de commande, mais préservera tout son historique." %}
</p>
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteProductModal">
<i class="bi bi-trash"></i> {% translate "Désactiver ce produit" %}
</button>
{% else %}
<span class="badge bg-danger p-2"><i class="bi bi-x-circle me-1"></i>{% translate "Ce produit est déjà inactif" %}</span>
{% endif %}
</div>
</div>
<!-- Modal suppression -->
<div class="modal fade" id="deleteProductModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title text-danger">
<i class="bi bi-exclamation-triangle"></i>
{% translate "Confirmer la désactivation" %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
{% blocktranslate with name=product.name %}
Êtes-vous sûr de vouloir rendre le produit <strong>{{ name }}</strong> inactif ?
Il ne sera plus visible pour les nouvelles opérations de stock ou d'intervention, mais restera accessible dans l'historique.
{% endblocktranslate %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
{% translate "Annuler" %}
</button>
<form method="post" action="{% url 'stock:product_delete' product.pk %}">
{% csrf_token %}
<button type="submit" class="btn btn-danger">
<i class="bi bi-trash"></i> {% translate "Désactiver" %}
</button>
</form>
</div>
</div>
</div>
</div>
{% endif %}
</div>
</div>
</div>
<script>
// Activer tous les tooltips Bootstrap
document.addEventListener('DOMContentLoaded', function () {
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.forEach(function (el) {
new bootstrap.Tooltip(el);
});
});
{% if action == 'create' %}
document.addEventListener('DOMContentLoaded', function () {
const locationsSelect = document.getElementById('id_authorized_locations');
const section = document.getElementById('initial-quantities-section');
const container = document.getElementById('initial-quantities-container');
if (locationsSelect && section && container) {
function updateQuantities() {
container.innerHTML = '';
const selectedOptions = Array.from(locationsSelect.selectedOptions);
if (selectedOptions.length === 0) {
section.style.display = 'none';
return;
}
section.style.display = 'block';
selectedOptions.forEach(opt => {
const locationId = opt.value;
const locationName = opt.text;
const row = document.createElement('div');
row.className = 'row mb-3 align-items-center';
row.innerHTML = `
<div class="col-md-6">
<span class="fw-semibold text-muted" style="font-size: 0.9rem;">
<i class="bi bi-geo-alt me-1 text-primary"></i>${locationName}
</span>
</div>
<div class="col-md-6">
<div class="input-group input-group-sm">
<span class="input-group-text bg-white text-muted">{% translate "Quantité" %}</span>
<input type="number" name="initial_qty_${locationId}" class="form-control" min="0" value="0" style="max-width: 150px;">
</div>
</div>
`;
container.appendChild(row);
});
}
locationsSelect.addEventListener('change', updateQuantities);
// Initial run
updateQuantities();
}
});
{% endif %}
</script>
{% endblock content %}