278 lines
12 KiB
HTML
278 lines
12 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
{% load i18n %}
|
|
{% load l10n %}
|
|
|
|
{% block head %}
|
|
<style>
|
|
.products-table {
|
|
margin-bottom: 2rem;
|
|
}
|
|
.category-section {
|
|
margin-bottom: 3rem;
|
|
}
|
|
.category-header {
|
|
background-color: #f8f9fa;
|
|
padding: 0.75rem 1rem;
|
|
border-left: 4px solid #0d6efd;
|
|
margin-bottom: 1rem;
|
|
}
|
|
.alert-threshold {
|
|
background-color: #fff3cd;
|
|
}
|
|
.filter-section {
|
|
background-color: #f8f9fa;
|
|
padding: 1rem;
|
|
border-radius: 0.25rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
#map {
|
|
height: 400px;
|
|
width: 100%;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="row mt-2">
|
|
<div class="col-md-8" style="max-height: calc(100vh - 200px); overflow: auto;">
|
|
<h3 class="h3 d-flex align-items-center">
|
|
<i class="bi bi-buildings"></i>
|
|
<span class="mx-2">{{ warehouse.code }}</span>
|
|
<span class="mx-2">{{ warehouse.name }}</span>
|
|
</h3>
|
|
<hr>
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<h5>{% translate "Localisation" %}</h5>
|
|
<p>{{ warehouse.location|default:_("Non renseignée") }}</p>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<h5>{% translate "Gestionnaire principal" %}</h5>
|
|
<p>{{ warehouse.manager }}</p>
|
|
</div>
|
|
<div class="col-12">
|
|
<h5>{% translate "Description" %}</h5>
|
|
<p>{{ warehouse.description|default:_("Non renseignée") }}</p>
|
|
</div>
|
|
</div>
|
|
<hr>
|
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
<h4 class="h4 mb-0">{% translate "Emplacements" %}</h4>
|
|
{% if can_administer %}
|
|
<a href="{% url 'stock:warehouse_location_create' warehouse.id %}" class="btn btn-sm btn-primary">
|
|
<i class="bi bi-plus-circle"></i> {% translate "Nouvel emplacement" %}
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>{% translate "Nom" %}</th>
|
|
<th>{% translate "Gestionnaire" %}</th>
|
|
{% if can_administer %}<th class="text-end">{% translate "Actions" %}</th>{% endif %}
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for wl in warehouseLocations %}
|
|
<tr>
|
|
<td><a href="{% url 'stock:warehouse_location_detail' wl.id %}">{{ wl.name }}</a></td>
|
|
<td>{{ wl.warehouse.manager }}</td>
|
|
{% if can_administer %}
|
|
<td class="text-end">
|
|
<a href="{% url 'stock:warehouse_location_edit' wl.id %}" class="btn btn-sm btn-outline-secondary">
|
|
<i class="bi bi-pencil"></i>
|
|
</a>
|
|
<button type="button" class="btn btn-sm btn-outline-danger"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#deleteLocationModal"
|
|
data-location-id="{{ wl.id }}"
|
|
data-location-name="{{ wl.name }}">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</td>
|
|
{% endif %}
|
|
</tr>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="{% if can_administer %}3{% else %}2{% endif %}" class="text-center text-muted">{% translate "Aucun emplacement renseigné." %}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<hr>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div id="map"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filtres et produits pleine largeur -->
|
|
<div class="row mt-3">
|
|
<div class="col-12">
|
|
|
|
<h4 class="h4 mb-3">{% translate "Produits" %}</h4>
|
|
|
|
<!-- Filtres -->
|
|
<div class="filter-section">
|
|
<h4 class="h5 mb-3">
|
|
<i class="bi bi-funnel"></i> {% translate "Filtres" %}
|
|
</h4>
|
|
<div class="row g-2">
|
|
<div class="col-md-6">
|
|
<input type="text"
|
|
id="product-search"
|
|
class="form-control form-control-sm"
|
|
placeholder="{% translate 'Rechercher un produit par nom ou code...' %}">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="form-check">
|
|
<input class="form-check-input"
|
|
type="checkbox"
|
|
id="show-alerts-only">
|
|
<label class="form-check-label" for="show-alerts-only">
|
|
<i class="bi bi-exclamation-triangle text-warning"></i>
|
|
{% translate "Alertes seuil uniquement" %}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="form-check">
|
|
<input class="form-check-input"
|
|
type="checkbox"
|
|
id="show-stock-only">
|
|
<label class="form-check-label" for="show-stock-only">
|
|
<i class="bi bi-box-seam text-primary"></i>
|
|
{% translate "Stock > 0 uniquement" %}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div id="products-container">
|
|
{% for category, products in products_by_category.items %}
|
|
<div class="category-section" data-category="{{ category }}">
|
|
<h5 class="category-header">
|
|
{{ category }}
|
|
<span class="badge bg-secondary ms-2">{{ products|length }}</span>
|
|
</h5>
|
|
<div class="table-responsive">
|
|
<table class="table table-hover products-table">
|
|
<thead>
|
|
<tr>
|
|
<th>{% translate "Code" %}</th>
|
|
<th>{% translate "Produit" %}</th>
|
|
<th class="text-end">{% translate "Stock" %}</th>
|
|
<th class="text-end">{% translate "Seuil" %}</th>
|
|
<th class="text-center">{% translate "Statut" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for product in products %}
|
|
<tr class="product-row {% if product.is_below_threshold %}alert-threshold{% endif %}"
|
|
data-product-name="{{ product.name|lower }}"
|
|
data-product-code="{{ product.code|lower }}"
|
|
data-is-alert="{{ product.is_below_threshold|yesno:'true,false' }}"
|
|
data-stock="{{ product.stock }}">
|
|
<td>
|
|
<a href="{% url 'stock:product_detail' product.id %}" class="text-decoration-none">
|
|
{{ product.code }}
|
|
</a>
|
|
</td>
|
|
<td>{{ product.name }}</td>
|
|
<td class="text-end">
|
|
<strong>{{ product.stock }}</strong>
|
|
<small class="text-muted">{{ product.unit }}</small>
|
|
</td>
|
|
<td class="text-end {% if product.is_below_threshold %}text-danger fw-bold{% endif %}">
|
|
{{ product.threshold }} <small class="text-muted">{{ product.unit }}</small>
|
|
</td>
|
|
<td class="text-center">
|
|
{% if product.is_below_threshold %}
|
|
<span class="badge bg-warning text-dark">
|
|
<i class="bi bi-exclamation-triangle"></i> {% translate "Alerte" %}
|
|
</span>
|
|
{% else %}
|
|
<span class="badge bg-success">
|
|
<i class="bi bi-check-circle"></i> {% translate "OK" %}
|
|
</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<p class="text-muted">{% translate "Aucun produit dans cet entrepôt." %}</p>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<div id="no-results" class="alert alert-info d-none">
|
|
<i class="bi bi-info-circle"></i> {% translate "Aucun produit ne correspond aux filtres." %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock content%}
|
|
|
|
{% if can_administer %}
|
|
<!-- Modal de confirmation de suppression d'emplacement -->
|
|
<div class="modal fade" id="deleteLocationModal" 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 suppression" %}
|
|
</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
{% translate "Êtes-vous sûr de vouloir supprimer l'emplacement" %}
|
|
<strong id="deleteLocationName"></strong> ?
|
|
{% translate "Cette action est irréversible." %}
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
|
{% translate "Annuler" %}
|
|
</button>
|
|
<form id="deleteLocationForm" method="post" action="">
|
|
{% csrf_token %}
|
|
<button type="submit" class="btn btn-danger">
|
|
<i class="bi bi-trash"></i> {% translate "Supprimer" %}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% block script %}
|
|
<script>
|
|
const warehousesurl = "{% url 'stock:warehouses' %}";
|
|
{% localize off %}
|
|
const feature_lon = {% if warehouse.lon %}{{ warehouse.lon }}{% else %}null{% endif %};
|
|
const feature_lat = {% if warehouse.lat %}{{ warehouse.lat }}{% else %}null{% endif %};
|
|
{% endlocalize %}
|
|
{% if can_administer %}
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const modal = document.getElementById('deleteLocationModal');
|
|
if (modal) {
|
|
modal.addEventListener('show.bs.modal', function (event) {
|
|
const btn = event.relatedTarget;
|
|
document.getElementById('deleteLocationName').textContent = btn.getAttribute('data-location-name');
|
|
document.getElementById('deleteLocationForm').action = '/stock/warehouse-locations/' + btn.getAttribute('data-location-id') + '/delete/';
|
|
});
|
|
}
|
|
});
|
|
{% endif %}
|
|
</script>
|
|
<script src="{% static 'stock/warehouse_detail.js' %}"></script>
|
|
{% endblock script %}
|