feat: add order filtering and default descending sort for preparation and production orders
This commit is contained in:
parent
63a9a080de
commit
a08ef0f035
8 changed files with 137 additions and 57 deletions
|
|
@ -459,14 +459,22 @@ def stock_preparation_orders_mobile(request):
|
||||||
q_filter |= models.Q(intervention__id=int(search_q))
|
q_filter |= models.Q(intervention__id=int(search_q))
|
||||||
preparation_orders = preparation_orders.filter(q_filter)
|
preparation_orders = preparation_orders.filter(q_filter)
|
||||||
|
|
||||||
preparation_orders = preparation_orders.prefetch_related(
|
selected_order = request.GET.get('order', 'desc').strip()
|
||||||
'preparationorderitem_set__product'
|
if selected_order == 'asc':
|
||||||
).order_by('date')[:200]
|
preparation_orders = preparation_orders.prefetch_related(
|
||||||
|
'preparationorderitem_set__product'
|
||||||
|
).order_by('date')[:200]
|
||||||
|
else:
|
||||||
|
selected_order = 'desc'
|
||||||
|
preparation_orders = preparation_orders.prefetch_related(
|
||||||
|
'preparationorderitem_set__product'
|
||||||
|
).order_by('-date')[:200]
|
||||||
return render(request, "stock/mobile/stock_preparation_orders_mobile.html", {
|
return render(request, "stock/mobile/stock_preparation_orders_mobile.html", {
|
||||||
'preparation_orders': preparation_orders,
|
'preparation_orders': preparation_orders,
|
||||||
'selected_status': selected_status,
|
'selected_status': selected_status,
|
||||||
'selected_priority': selected_priority,
|
'selected_priority': selected_priority,
|
||||||
'search_q': search_q,
|
'search_q': search_q,
|
||||||
|
'selected_order': selected_order,
|
||||||
'preparation_order_status_choices': [
|
'preparation_order_status_choices': [
|
||||||
('active', _("À traiter & En attente")),
|
('active', _("À traiter & En attente")),
|
||||||
('to_process', _("A traiter")),
|
('to_process', _("A traiter")),
|
||||||
|
|
@ -544,7 +552,12 @@ def stock_production_orders_mobile(request):
|
||||||
q_filter |= models.Q(id=int(search_q)) | models.Q(preparation_order__intervention__id=int(search_q))
|
q_filter |= models.Q(id=int(search_q)) | models.Q(preparation_order__intervention__id=int(search_q))
|
||||||
production_orders = production_orders.filter(q_filter).distinct()
|
production_orders = production_orders.filter(q_filter).distinct()
|
||||||
|
|
||||||
production_orders = production_orders.order_by('created_at')[:200]
|
selected_order = request.GET.get('order', 'desc').strip()
|
||||||
|
if selected_order == 'asc':
|
||||||
|
production_orders = production_orders.order_by('created_at')[:200]
|
||||||
|
else:
|
||||||
|
selected_order = 'desc'
|
||||||
|
production_orders = production_orders.order_by('-created_at')[:200]
|
||||||
|
|
||||||
return render(request, "stock/mobile/stock_production_orders_mobile.html", {
|
return render(request, "stock/mobile/stock_production_orders_mobile.html", {
|
||||||
'production_orders': production_orders,
|
'production_orders': production_orders,
|
||||||
|
|
@ -552,6 +565,7 @@ def stock_production_orders_mobile(request):
|
||||||
'selected_status': selected_status,
|
'selected_status': selected_status,
|
||||||
'selected_warehouse': selected_warehouse,
|
'selected_warehouse': selected_warehouse,
|
||||||
'selected_destination': selected_destination,
|
'selected_destination': selected_destination,
|
||||||
|
'selected_order': selected_order,
|
||||||
'status_choices': [
|
'status_choices': [
|
||||||
('active', _("À traiter & En confection")),
|
('active', _("À traiter & En confection")),
|
||||||
] + list(ProductionOrder.STATUS_CHOICES),
|
] + list(ProductionOrder.STATUS_CHOICES),
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,11 @@ class Migration(migrations.Migration):
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterModelOptions(
|
migrations.AlterModelOptions(
|
||||||
name='preparationorder',
|
name='preparationorder',
|
||||||
options={'ordering': ('date',), 'verbose_name': 'Bon de préparation', 'verbose_name_plural': 'Bons de préparation'},
|
options={'ordering': ('-date',), 'verbose_name': 'Bon de préparation', 'verbose_name_plural': 'Bons de préparation'},
|
||||||
),
|
),
|
||||||
migrations.AlterModelOptions(
|
migrations.AlterModelOptions(
|
||||||
name='productionorder',
|
name='productionorder',
|
||||||
options={'ordering': ('created_at',), 'verbose_name': 'Bon de confection', 'verbose_name_plural': 'Bons de confection'},
|
options={'ordering': ('-created_at',), 'verbose_name': 'Bon de confection', 'verbose_name_plural': 'Bons de confection'},
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='stockmovementbatch',
|
model_name='stockmovementbatch',
|
||||||
|
|
|
||||||
|
|
@ -1451,7 +1451,7 @@ class PreparationOrder(models.Model):
|
||||||
}
|
}
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ("date",)
|
ordering = ("-date",)
|
||||||
verbose_name = _("Bon de préparation")
|
verbose_name = _("Bon de préparation")
|
||||||
verbose_name_plural = _("Bons de préparation")
|
verbose_name_plural = _("Bons de préparation")
|
||||||
|
|
||||||
|
|
@ -2248,7 +2248,7 @@ class ProductionOrder(models.Model):
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ("created_at",)
|
ordering = ("-created_at",)
|
||||||
verbose_name = _("Bon de confection")
|
verbose_name = _("Bon de confection")
|
||||||
verbose_name_plural = _("Bons de confection")
|
verbose_name_plural = _("Bons de confection")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,23 +47,29 @@
|
||||||
<button type="submit" class="btn btn-primary"><i class="bi bi-search"></i></button>
|
<button type="submit" class="btn btn-primary"><i class="bi bi-search"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-4">
|
||||||
<select class="form-select form-select-sm" name="status" onchange="this.form.submit()">
|
<select class="form-select form-select-sm" name="status" onchange="this.form.submit()">
|
||||||
<option value="">-- {% translate "Tous statuts" %} --</option>
|
<option value="">-- {% translate "Statut" %} --</option>
|
||||||
{% for val, label in preparation_order_status_choices %}
|
{% for val, label in preparation_order_status_choices %}
|
||||||
<option value="{{ val }}" {% if selected_status == val %}selected{% endif %}>{{ label }}</option>
|
<option value="{{ val }}" {% if selected_status == val %}selected{% endif %}>{{ label }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-4">
|
||||||
<select class="form-select form-select-sm" name="priority" onchange="this.form.submit()">
|
<select class="form-select form-select-sm" name="priority" onchange="this.form.submit()">
|
||||||
<option value="">-- {% translate "Toutes priorités" %} --</option>
|
<option value="">-- {% translate "Priorité" %} --</option>
|
||||||
{% for val, label in preparation_order_priority_choices %}
|
{% for val, label in preparation_order_priority_choices %}
|
||||||
<option value="{{ val }}" {% if selected_priority == val %}selected{% endif %}>{{ label }}</option>
|
<option value="{{ val }}" {% if selected_priority == val %}selected{% endif %}>{{ label }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
{% if selected_status or selected_priority or search_q %}
|
<div class="col-4">
|
||||||
|
<select class="form-select form-select-sm" name="order" onchange="this.form.submit()">
|
||||||
|
<option value="desc" {% if selected_order != 'asc' %}selected{% endif %}>{% translate "Plus récents" %}</option>
|
||||||
|
<option value="asc" {% if selected_order == 'asc' %}selected{% endif %}>{% translate "Plus anciens" %}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{% if selected_status or selected_priority or search_q or selected_order == 'asc' %}
|
||||||
<div class="col-12 text-center mt-1">
|
<div class="col-12 text-center mt-1">
|
||||||
<a href="?" class="btn btn-sm btn-outline-secondary py-0" style="font-size:0.75rem;">
|
<a href="?" class="btn btn-sm btn-outline-secondary py-0" style="font-size:0.75rem;">
|
||||||
<i class="bi bi-x-circle me-1"></i>{% translate "Effacer les filtres" %}
|
<i class="bi bi-x-circle me-1"></i>{% translate "Effacer les filtres" %}
|
||||||
|
|
|
||||||
|
|
@ -60,32 +60,38 @@
|
||||||
<button type="submit" class="btn btn-primary"><i class="bi bi-search"></i></button>
|
<button type="submit" class="btn btn-primary"><i class="bi bi-search"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-4">
|
||||||
<select class="form-select form-select-sm" name="status" onchange="this.form.submit()">
|
<select class="form-select form-select-sm" name="status" onchange="this.form.submit()">
|
||||||
<option value="">-- {% translate "Tous statuts" %} --</option>
|
<option value="">-- {% translate "Statut" %} --</option>
|
||||||
{% for val, label in status_choices %}
|
{% for val, label in status_choices %}
|
||||||
<option value="{{ val }}" {% if selected_status == val %}selected{% endif %}>{{ label }}</option>
|
<option value="{{ val }}" {% if selected_status == val %}selected{% endif %}>{{ label }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-4">
|
||||||
{% if warehouses|length > 1 %}
|
{% if warehouses|length > 1 %}
|
||||||
<select class="form-select form-select-sm" name="warehouse" onchange="this.form.submit()">
|
<select class="form-select form-select-sm" name="warehouse" onchange="this.form.submit()">
|
||||||
<option value="">-- {% translate "Tous entrepôts" %} --</option>
|
<option value="">-- {% translate "Entrepôt" %} --</option>
|
||||||
{% for wh in warehouses %}
|
{% for wh in warehouses %}
|
||||||
<option value="{{ wh.pk }}" {% if selected_warehouse == wh.pk|stringformat:"s" %}selected{% endif %}>{{ wh.name }}</option>
|
<option value="{{ wh.pk }}" {% if selected_warehouse == wh.pk|stringformat:"s" %}selected{% endif %}>{{ wh.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
{% else %}
|
{% else %}
|
||||||
<select class="form-select form-select-sm" name="destination" onchange="this.form.submit()">
|
<select class="form-select form-select-sm" name="destination" onchange="this.form.submit()">
|
||||||
<option value="">-- {% translate "Toutes destinations" %} --</option>
|
<option value="">-- {% translate "Dest." %} --</option>
|
||||||
{% for val, label in destination_choices %}
|
{% for val, label in destination_choices %}
|
||||||
<option value="{{ val }}" {% if selected_destination == val %}selected{% endif %}>{{ label }}</option>
|
<option value="{{ val }}" {% if selected_destination == val %}selected{% endif %}>{{ label }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% if selected_status or selected_warehouse or selected_destination or search_q %}
|
<div class="col-4">
|
||||||
|
<select class="form-select form-select-sm" name="order" onchange="this.form.submit()">
|
||||||
|
<option value="desc" {% if selected_order != 'asc' %}selected{% endif %}>{% translate "Plus récents" %}</option>
|
||||||
|
<option value="asc" {% if selected_order == 'asc' %}selected{% endif %}>{% translate "Plus anciens" %}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{% if selected_status or selected_warehouse or selected_destination or search_q or selected_order == 'asc' %}
|
||||||
<div class="col-12 text-center mt-1">
|
<div class="col-12 text-center mt-1">
|
||||||
<a href="{% url 'mobile:stock_production_orders_mobile' %}" class="btn btn-sm btn-outline-secondary py-0" style="font-size:0.75rem;">
|
<a href="{% url 'mobile:stock_production_orders_mobile' %}" class="btn btn-sm btn-outline-secondary py-0" style="font-size:0.75rem;">
|
||||||
<i class="bi bi-x-circle me-1"></i>{% translate "Effacer les filtres" %}
|
<i class="bi bi-x-circle me-1"></i>{% translate "Effacer les filtres" %}
|
||||||
|
|
@ -98,34 +104,34 @@
|
||||||
|
|
||||||
<!-- Filtres rapides par statut (Pills défilantes) -->
|
<!-- Filtres rapides par statut (Pills défilantes) -->
|
||||||
<div class="d-flex gap-1 overflow-auto pb-2 mb-2 status-pills-bar" style="white-space: nowrap;">
|
<div class="d-flex gap-1 overflow-auto pb-2 mb-2 status-pills-bar" style="white-space: nowrap;">
|
||||||
<a href="?{% if search_q %}q={{ search_q }}&{% endif %}{% if selected_warehouse %}warehouse={{ selected_warehouse }}&{% endif %}{% if selected_destination %}destination={{ selected_destination }}&{% endif %}"
|
<a href="?{% if search_q %}q={{ search_q }}&{% endif %}{% if selected_warehouse %}warehouse={{ selected_warehouse }}&{% endif %}{% if selected_destination %}destination={{ selected_destination }}&{% endif %}{% if selected_order %}order={{ selected_order }}&{% endif %}"
|
||||||
class="badge {% if not selected_status %}bg-primary text-white{% else %}bg-light text-dark border{% endif %} text-decoration-none py-1 px-2">
|
class="badge {% if not selected_status %}bg-primary text-white{% else %}bg-light text-dark border{% endif %} text-decoration-none py-1 px-2">
|
||||||
{% translate "Tous" %} ({{ prod_counts.total|default:0 }})
|
{% translate "Tous" %} ({{ prod_counts.total|default:0 }})
|
||||||
</a>
|
</a>
|
||||||
<a href="?status=active{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_warehouse %}&warehouse={{ selected_warehouse }}{% endif %}{% if selected_destination %}&destination={{ selected_destination }}{% endif %}"
|
<a href="?status=active{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_warehouse %}&warehouse={{ selected_warehouse }}{% endif %}{% if selected_destination %}&destination={{ selected_destination }}{% endif %}{% if selected_order %}&order={{ selected_order }}{% endif %}"
|
||||||
class="badge {% if selected_status == 'active' %}bg-danger text-white{% else %}bg-light text-dark border{% endif %} text-decoration-none py-1 px-2">
|
class="badge {% if selected_status == 'active' %}bg-danger text-white{% else %}bg-light text-dark border{% endif %} text-decoration-none py-1 px-2">
|
||||||
<i class="bi bi-play-circle me-1"></i>{% translate "À traiter & En confection" %} ({{ prod_counts.active|default:0 }})
|
<i class="bi bi-play-circle me-1"></i>{% translate "À traiter & En confection" %} ({{ prod_counts.active|default:0 }})
|
||||||
</a>
|
</a>
|
||||||
<a href="?status=to_process{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_warehouse %}&warehouse={{ selected_warehouse }}{% endif %}{% if selected_destination %}&destination={{ selected_destination }}{% endif %}"
|
<a href="?status=to_process{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_warehouse %}&warehouse={{ selected_warehouse }}{% endif %}{% if selected_destination %}&destination={{ selected_destination }}{% endif %}{% if selected_order %}&order={{ selected_order }}{% endif %}"
|
||||||
class="badge {% if selected_status == 'to_process' %}bg-danger text-white{% else %}bg-light text-dark border{% endif %} text-decoration-none py-1 px-2">
|
class="badge {% if selected_status == 'to_process' %}bg-danger text-white{% else %}bg-light text-dark border{% endif %} text-decoration-none py-1 px-2">
|
||||||
<i class="bi bi-hourglass-split me-1"></i>{% translate "À traiter" %} ({{ prod_counts.to_process|default:0 }})
|
<i class="bi bi-hourglass-split me-1"></i>{% translate "À traiter" %} ({{ prod_counts.to_process|default:0 }})
|
||||||
</a>
|
</a>
|
||||||
<a href="?status=in_production{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_warehouse %}&warehouse={{ selected_warehouse }}{% endif %}{% if selected_destination %}&destination={{ selected_destination }}{% endif %}"
|
<a href="?status=in_production{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_warehouse %}&warehouse={{ selected_warehouse }}{% endif %}{% if selected_destination %}&destination={{ selected_destination }}{% endif %}{% if selected_order %}&order={{ selected_order }}{% endif %}"
|
||||||
class="badge {% if selected_status == 'in_production' %}bg-primary text-white{% else %}bg-light text-dark border{% endif %} text-decoration-none py-1 px-2">
|
class="badge {% if selected_status == 'in_production' %}bg-primary text-white{% else %}bg-light text-dark border{% endif %} text-decoration-none py-1 px-2">
|
||||||
<i class="bi bi-gear-wide-connected me-1"></i>{% translate "En confection" %} ({{ prod_counts.in_production|default:0 }})
|
<i class="bi bi-gear-wide-connected me-1"></i>{% translate "En confection" %} ({{ prod_counts.in_production|default:0 }})
|
||||||
</a>
|
</a>
|
||||||
<a href="?status=completed{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_warehouse %}&warehouse={{ selected_warehouse }}{% endif %}{% if selected_destination %}&destination={{ selected_destination }}{% endif %}"
|
<a href="?status=completed{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_warehouse %}&warehouse={{ selected_warehouse }}{% endif %}{% if selected_destination %}&destination={{ selected_destination }}{% endif %}{% if selected_order %}&order={{ selected_order }}{% endif %}"
|
||||||
class="badge {% if selected_status == 'completed' %}bg-success text-white{% else %}bg-light text-dark border{% endif %} text-decoration-none py-1 px-2">
|
class="badge {% if selected_status == 'completed' %}bg-success text-white{% else %}bg-light text-dark border{% endif %} text-decoration-none py-1 px-2">
|
||||||
<i class="bi bi-check-circle me-1"></i>{% translate "Terminé" %} ({{ prod_counts.completed|default:0 }})
|
<i class="bi bi-check-circle me-1"></i>{% translate "Terminé" %} ({{ prod_counts.completed|default:0 }})
|
||||||
</a>
|
</a>
|
||||||
{% if prod_counts.draft %}
|
{% if prod_counts.draft %}
|
||||||
<a href="?status=draft{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_warehouse %}&warehouse={{ selected_warehouse }}{% endif %}{% if selected_destination %}&destination={{ selected_destination }}{% endif %}"
|
<a href="?status=draft{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_warehouse %}&warehouse={{ selected_warehouse }}{% endif %}{% if selected_destination %}&destination={{ selected_destination }}{% endif %}{% if selected_order %}&order={{ selected_order }}{% endif %}"
|
||||||
class="badge {% if selected_status == 'draft' %}bg-secondary text-white{% else %}bg-light text-dark border{% endif %} text-decoration-none py-1 px-2">
|
class="badge {% if selected_status == 'draft' %}bg-secondary text-white{% else %}bg-light text-dark border{% endif %} text-decoration-none py-1 px-2">
|
||||||
<i class="bi bi-pencil me-1"></i>{% translate "Brouillon" %} ({{ prod_counts.draft|default:0 }})
|
<i class="bi bi-pencil me-1"></i>{% translate "Brouillon" %} ({{ prod_counts.draft|default:0 }})
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if prod_counts.cancelled %}
|
{% if prod_counts.cancelled %}
|
||||||
<a href="?status=cancelled{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_warehouse %}&warehouse={{ selected_warehouse }}{% endif %}{% if selected_destination %}&destination={{ selected_destination }}{% endif %}"
|
<a href="?status=cancelled{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_warehouse %}&warehouse={{ selected_warehouse }}{% endif %}{% if selected_destination %}&destination={{ selected_destination }}{% endif %}{% if selected_order %}&order={{ selected_order }}{% endif %}"
|
||||||
class="badge {% if selected_status == 'cancelled' %}bg-secondary text-white{% else %}bg-light text-dark border{% endif %} text-decoration-none py-1 px-2">
|
class="badge {% if selected_status == 'cancelled' %}bg-secondary text-white{% else %}bg-light text-dark border{% endif %} text-decoration-none py-1 px-2">
|
||||||
<i class="bi bi-x-circle me-1"></i>{% translate "Annulé" %} ({{ prod_counts.cancelled|default:0 }})
|
<i class="bi bi-x-circle me-1"></i>{% translate "Annulé" %} ({{ prod_counts.cancelled|default:0 }})
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@
|
||||||
<!-- Préserver l'onglet actif -->
|
<!-- Préserver l'onglet actif -->
|
||||||
<input type="hidden" name="tab" value="preparation-orders">
|
<input type="hidden" name="tab" value="preparation-orders">
|
||||||
|
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<div class="input-group input-group-sm">
|
<div class="input-group input-group-sm">
|
||||||
<span class="input-group-text"><i class="bi bi-search"></i></span>
|
<span class="input-group-text"><i class="bi bi-search"></i></span>
|
||||||
<input type="text" class="form-control" name="q" value="{{ search_q }}" placeholder="{% translate 'N° bon, code ou titre d\'intervention...' %}">
|
<input type="text" class="form-control" name="q" value="{{ search_q }}" placeholder="{% translate 'N° bon, code ou titre d\'intervention...' %}">
|
||||||
|
|
@ -69,7 +69,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-3">
|
<div class="col-md-2">
|
||||||
<div class="input-group input-group-sm">
|
<div class="input-group input-group-sm">
|
||||||
<label class="input-group-text" for="filter-status"><i class="bi bi-funnel me-1"></i>{% translate "Statut" %}</label>
|
<label class="input-group-text" for="filter-status"><i class="bi bi-funnel me-1"></i>{% translate "Statut" %}</label>
|
||||||
<select class="form-select" id="filter-status" name="status" onchange="this.form.submit()">
|
<select class="form-select" id="filter-status" name="status" onchange="this.form.submit()">
|
||||||
|
|
@ -81,7 +81,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-3">
|
<div class="col-md-2">
|
||||||
<div class="input-group input-group-sm">
|
<div class="input-group input-group-sm">
|
||||||
<label class="input-group-text" for="filter-priority"><i class="bi bi-exclamation-triangle me-1"></i>{% translate "Priorité" %}</label>
|
<label class="input-group-text" for="filter-priority"><i class="bi bi-exclamation-triangle me-1"></i>{% translate "Priorité" %}</label>
|
||||||
<select class="form-select" id="filter-priority" name="priority" onchange="this.form.submit()">
|
<select class="form-select" id="filter-priority" name="priority" onchange="this.form.submit()">
|
||||||
|
|
@ -93,9 +93,19 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="input-group input-group-sm">
|
||||||
|
<label class="input-group-text" for="filter-prep-order"><i class="bi bi-arrow-down-up me-1"></i>{% translate "Tri" %}</label>
|
||||||
|
<select class="form-select" id="filter-prep-order" name="prep_order" onchange="this.form.submit()">
|
||||||
|
<option value="desc" {% if prep_order != 'asc' %}selected{% endif %}>{% translate "Plus récents d'abord" %}</option>
|
||||||
|
<option value="asc" {% if prep_order == 'asc' %}selected{% endif %}>{% translate "Plus anciens d'abord (inversé)" %}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="col-md-2 d-flex justify-content-between align-items-center gap-1">
|
<div class="col-md-2 d-flex justify-content-between align-items-center gap-1">
|
||||||
<div>
|
<div>
|
||||||
{% if selected_status or selected_priority or search_q %}
|
{% if selected_status or selected_priority or search_q or prep_order == 'asc' %}
|
||||||
<a href="?tab=preparation-orders" class="btn btn-sm btn-outline-secondary" title="{% translate 'Effacer les filtres' %}">
|
<a href="?tab=preparation-orders" class="btn btn-sm btn-outline-secondary" title="{% translate 'Effacer les filtres' %}">
|
||||||
<i class="bi bi-x-circle me-1"></i>{% translate "Effacer" %}
|
<i class="bi bi-x-circle me-1"></i>{% translate "Effacer" %}
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -114,23 +124,23 @@
|
||||||
<!-- Filtres rapides par statut (Pills) -->
|
<!-- Filtres rapides par statut (Pills) -->
|
||||||
<div class="d-flex flex-wrap align-items-center gap-2 mb-3">
|
<div class="d-flex flex-wrap align-items-center gap-2 mb-3">
|
||||||
<span class="small text-muted fw-semibold me-1"><i class="bi bi-funnel me-1"></i>{% translate "Vue rapide :" %}</span>
|
<span class="small text-muted fw-semibold me-1"><i class="bi bi-funnel me-1"></i>{% translate "Vue rapide :" %}</span>
|
||||||
<a href="?tab=preparation-orders{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_priority %}&priority={{ selected_priority }}{% endif %}"
|
<a href="?tab=preparation-orders{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_priority %}&priority={{ selected_priority }}{% endif %}{% if prep_order %}&prep_order={{ prep_order }}{% endif %}"
|
||||||
class="btn btn-sm py-1 px-2 {% if not selected_status %}btn-primary{% else %}btn-outline-secondary{% endif %} rounded-pill">
|
class="btn btn-sm py-1 px-2 {% if not selected_status %}btn-primary{% else %}btn-outline-secondary{% endif %} rounded-pill">
|
||||||
{% translate "Tous" %} <span class="badge {% if not selected_status %}bg-white text-primary{% else %}bg-secondary{% endif %} ms-1">{{ prep_counts.total|default:0 }}</span>
|
{% translate "Tous" %} <span class="badge {% if not selected_status %}bg-white text-primary{% else %}bg-secondary{% endif %} ms-1">{{ prep_counts.total|default:0 }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="?tab=preparation-orders&status=active{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_priority %}&priority={{ selected_priority }}{% endif %}"
|
<a href="?tab=preparation-orders&status=active{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_priority %}&priority={{ selected_priority }}{% endif %}{% if prep_order %}&prep_order={{ prep_order }}{% endif %}"
|
||||||
class="btn btn-sm py-1 px-2 {% if selected_status == 'active' %}btn-danger text-white{% else %}btn-outline-danger{% endif %} rounded-pill">
|
class="btn btn-sm py-1 px-2 {% if selected_status == 'active' %}btn-danger text-white{% else %}btn-outline-danger{% endif %} rounded-pill">
|
||||||
<i class="bi bi-play-circle me-1"></i>{% translate "À traiter & En attente" %} <span class="badge {% if selected_status == 'active' %}bg-white text-danger{% else %}bg-danger text-white{% endif %} ms-1">{{ prep_counts.active|default:0 }}</span>
|
<i class="bi bi-play-circle me-1"></i>{% translate "À traiter & En attente" %} <span class="badge {% if selected_status == 'active' %}bg-white text-danger{% else %}bg-danger text-white{% endif %} ms-1">{{ prep_counts.active|default:0 }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="?tab=preparation-orders&status=to_process{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_priority %}&priority={{ selected_priority }}{% endif %}"
|
<a href="?tab=preparation-orders&status=to_process{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_priority %}&priority={{ selected_priority }}{% endif %}{% if prep_order %}&prep_order={{ prep_order }}{% endif %}"
|
||||||
class="btn btn-sm py-1 px-2 {% if selected_status == 'to_process' %}btn-warning text-dark{% else %}btn-outline-warning text-dark{% endif %} rounded-pill">
|
class="btn btn-sm py-1 px-2 {% if selected_status == 'to_process' %}btn-warning text-dark{% else %}btn-outline-warning text-dark{% endif %} rounded-pill">
|
||||||
<i class="bi bi-hourglass-split me-1"></i>{% translate "À traiter" %} <span class="badge {% if selected_status == 'to_process' %}bg-dark text-white{% else %}bg-warning text-dark{% endif %} ms-1">{{ prep_counts.to_process|default:0 }}</span>
|
<i class="bi bi-hourglass-split me-1"></i>{% translate "À traiter" %} <span class="badge {% if selected_status == 'to_process' %}bg-dark text-white{% else %}bg-warning text-dark{% endif %} ms-1">{{ prep_counts.to_process|default:0 }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="?tab=preparation-orders&status=pending{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_priority %}&priority={{ selected_priority }}{% endif %}"
|
<a href="?tab=preparation-orders&status=pending{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_priority %}&priority={{ selected_priority }}{% endif %}{% if prep_order %}&prep_order={{ prep_order }}{% endif %}"
|
||||||
class="btn btn-sm py-1 px-2 {% if selected_status == 'pending' %}btn-info text-white{% else %}btn-outline-info{% endif %} rounded-pill">
|
class="btn btn-sm py-1 px-2 {% if selected_status == 'pending' %}btn-info text-white{% else %}btn-outline-info{% endif %} rounded-pill">
|
||||||
<i class="bi bi-clock me-1"></i>{% translate "En attente" %} <span class="badge {% if selected_status == 'pending' %}bg-white text-info{% else %}bg-info text-white{% endif %} ms-1">{{ prep_counts.pending|default:0 }}</span>
|
<i class="bi bi-clock me-1"></i>{% translate "En attente" %} <span class="badge {% if selected_status == 'pending' %}bg-white text-info{% else %}bg-info text-white{% endif %} ms-1">{{ prep_counts.pending|default:0 }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="?tab=preparation-orders&status=processed{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_priority %}&priority={{ selected_priority }}{% endif %}"
|
<a href="?tab=preparation-orders&status=processed{% if search_q %}&q={{ search_q }}{% endif %}{% if selected_priority %}&priority={{ selected_priority }}{% endif %}{% if prep_order %}&prep_order={{ prep_order }}{% endif %}"
|
||||||
class="btn btn-sm py-1 px-2 {% if selected_status == 'processed' %}btn-success{% else %}btn-outline-success{% endif %} rounded-pill">
|
class="btn btn-sm py-1 px-2 {% if selected_status == 'processed' %}btn-success{% else %}btn-outline-success{% endif %} rounded-pill">
|
||||||
<i class="bi bi-check-circle me-1"></i>{% translate "Traité" %} <span class="badge {% if selected_status == 'processed' %}bg-white text-success{% else %}bg-success text-white{% endif %} ms-1">{{ prep_counts.processed|default:0 }}</span>
|
<i class="bi bi-check-circle me-1"></i>{% translate "Traité" %} <span class="badge {% if selected_status == 'processed' %}bg-white text-success{% else %}bg-success text-white{% endif %} ms-1">{{ prep_counts.processed|default:0 }}</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -236,10 +246,10 @@
|
||||||
<!-- Préserver l'onglet actif -->
|
<!-- Préserver l'onglet actif -->
|
||||||
<input type="hidden" name="tab" value="production-orders">
|
<input type="hidden" name="tab" value="production-orders">
|
||||||
|
|
||||||
<div class="col-md-3">
|
<div class="col-md-2">
|
||||||
<div class="input-group input-group-sm">
|
<div class="input-group input-group-sm">
|
||||||
<span class="input-group-text"><i class="bi bi-search"></i></span>
|
<span class="input-group-text"><i class="bi bi-search"></i></span>
|
||||||
<input type="text" class="form-control" name="prod_q" value="{{ prod_search_q }}" placeholder="{% translate 'Code, produit, bon prép, composant...' %}">
|
<input type="text" class="form-control" name="prod_q" value="{{ prod_search_q }}" placeholder="{% translate 'Code, produit, bon...' %}">
|
||||||
<button type="submit" class="btn btn-primary"><i class="bi bi-search"></i></button>
|
<button type="submit" class="btn btn-primary"><i class="bi bi-search"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -270,7 +280,7 @@
|
||||||
|
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<div class="input-group input-group-sm">
|
<div class="input-group input-group-sm">
|
||||||
<label class="input-group-text" for="filter-prod-destination"><i class="bi bi-geo-alt me-1"></i>{% translate "Destination" %}</label>
|
<label class="input-group-text" for="filter-prod-destination"><i class="bi bi-geo-alt me-1"></i>{% translate "Dest." %}</label>
|
||||||
<select class="form-select" id="filter-prod-destination" name="prod_destination" onchange="this.form.submit()">
|
<select class="form-select" id="filter-prod-destination" name="prod_destination" onchange="this.form.submit()">
|
||||||
<option value="">-- {% translate "Toutes" %} --</option>
|
<option value="">-- {% translate "Toutes" %} --</option>
|
||||||
{% for val, label in prod_destination_choices %}
|
{% for val, label in prod_destination_choices %}
|
||||||
|
|
@ -280,15 +290,25 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-3 d-flex justify-content-end align-items-center gap-1">
|
<div class="col-md-2">
|
||||||
{% if prod_status or prod_warehouse or prod_destination or prod_search_q %}
|
<div class="input-group input-group-sm">
|
||||||
|
<label class="input-group-text" for="filter-prod-order"><i class="bi bi-arrow-down-up me-1"></i>{% translate "Tri" %}</label>
|
||||||
|
<select class="form-select" id="filter-prod-order" name="prod_order" onchange="this.form.submit()">
|
||||||
|
<option value="desc" {% if prod_order != 'asc' %}selected{% endif %}>{% translate "Plus récents" %}</option>
|
||||||
|
<option value="asc" {% if prod_order == 'asc' %}selected{% endif %}>{% translate "Plus anciens" %}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-2 d-flex justify-content-end align-items-center gap-1">
|
||||||
|
{% if prod_status or prod_warehouse or prod_destination or prod_search_q or prod_order == 'asc' %}
|
||||||
<a href="?tab=production-orders" class="btn btn-sm btn-outline-secondary" title="{% translate 'Effacer les filtres' %}">
|
<a href="?tab=production-orders" class="btn btn-sm btn-outline-secondary" title="{% translate 'Effacer les filtres' %}">
|
||||||
<i class="bi bi-x-circle me-1"></i>{% translate "Effacer" %}
|
<i class="bi bi-x-circle me-1"></i>{% translate "Effacer" %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if can_create_production_order %}
|
{% if can_create_production_order %}
|
||||||
<a href="{% url 'stock:production_order_create' %}" class="btn btn-sm btn-primary text-nowrap">
|
<a href="{% url 'stock:production_order_create' %}" class="btn btn-sm btn-primary text-nowrap">
|
||||||
<i class="bi bi-plus-circle me-1"></i>{% translate "Nouveau bon" %}
|
<i class="bi bi-plus-circle me-1"></i>{% translate "Nouveau" %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -299,34 +319,34 @@
|
||||||
<!-- Filtres rapides par statut (Pills) -->
|
<!-- Filtres rapides par statut (Pills) -->
|
||||||
<div class="d-flex flex-wrap align-items-center gap-2 mb-3">
|
<div class="d-flex flex-wrap align-items-center gap-2 mb-3">
|
||||||
<span class="small text-muted fw-semibold me-1"><i class="bi bi-funnel me-1"></i>{% translate "Vue rapide :" %}</span>
|
<span class="small text-muted fw-semibold me-1"><i class="bi bi-funnel me-1"></i>{% translate "Vue rapide :" %}</span>
|
||||||
<a href="?tab=production-orders{% if prod_search_q %}&prod_q={{ prod_search_q }}{% endif %}{% if prod_warehouse %}&prod_warehouse={{ prod_warehouse }}{% endif %}{% if prod_destination %}&prod_destination={{ prod_destination }}{% endif %}"
|
<a href="?tab=production-orders{% if prod_search_q %}&prod_q={{ prod_search_q }}{% endif %}{% if prod_warehouse %}&prod_warehouse={{ prod_warehouse }}{% endif %}{% if prod_destination %}&prod_destination={{ prod_destination }}{% endif %}{% if prod_order %}&prod_order={{ prod_order }}{% endif %}"
|
||||||
class="btn btn-sm py-1 px-2 {% if not prod_status %}btn-primary{% else %}btn-outline-secondary{% endif %} rounded-pill">
|
class="btn btn-sm py-1 px-2 {% if not prod_status %}btn-primary{% else %}btn-outline-secondary{% endif %} rounded-pill">
|
||||||
{% translate "Tous" %} <span class="badge {% if not prod_status %}bg-white text-primary{% else %}bg-secondary{% endif %} ms-1">{{ prod_counts.total|default:0 }}</span>
|
{% translate "Tous" %} <span class="badge {% if not prod_status %}bg-white text-primary{% else %}bg-secondary{% endif %} ms-1">{{ prod_counts.total|default:0 }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="?tab=production-orders&prod_status=active{% if prod_search_q %}&prod_q={{ prod_search_q }}{% endif %}{% if prod_warehouse %}&prod_warehouse={{ prod_warehouse }}{% endif %}{% if prod_destination %}&prod_destination={{ prod_destination }}{% endif %}"
|
<a href="?tab=production-orders&prod_status=active{% if prod_search_q %}&prod_q={{ prod_search_q }}{% endif %}{% if prod_warehouse %}&prod_warehouse={{ prod_warehouse }}{% endif %}{% if prod_destination %}&prod_destination={{ prod_destination }}{% endif %}{% if prod_order %}&prod_order={{ prod_order }}{% endif %}"
|
||||||
class="btn btn-sm py-1 px-2 {% if prod_status == 'active' %}btn-danger text-white{% else %}btn-outline-danger{% endif %} rounded-pill">
|
class="btn btn-sm py-1 px-2 {% if prod_status == 'active' %}btn-danger text-white{% else %}btn-outline-danger{% endif %} rounded-pill">
|
||||||
<i class="bi bi-play-circle me-1"></i>{% translate "À traiter & En confection" %} <span class="badge {% if prod_status == 'active' %}bg-white text-danger{% else %}bg-danger text-white{% endif %} ms-1">{{ prod_counts.active|default:0 }}</span>
|
<i class="bi bi-play-circle me-1"></i>{% translate "À traiter & En confection" %} <span class="badge {% if prod_status == 'active' %}bg-white text-danger{% else %}bg-danger text-white{% endif %} ms-1">{{ prod_counts.active|default:0 }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="?tab=production-orders&prod_status=to_process{% if prod_search_q %}&prod_q={{ prod_search_q }}{% endif %}{% if prod_warehouse %}&prod_warehouse={{ prod_warehouse }}{% endif %}{% if prod_destination %}&prod_destination={{ prod_destination }}{% endif %}"
|
<a href="?tab=production-orders&prod_status=to_process{% if prod_search_q %}&prod_q={{ prod_search_q }}{% endif %}{% if prod_warehouse %}&prod_warehouse={{ prod_warehouse }}{% endif %}{% if prod_destination %}&prod_destination={{ prod_destination }}{% endif %}{% if prod_order %}&prod_order={{ prod_order }}{% endif %}"
|
||||||
class="btn btn-sm py-1 px-2 {% if prod_status == 'to_process' %}btn-danger text-white{% else %}btn-outline-danger{% endif %} rounded-pill">
|
class="btn btn-sm py-1 px-2 {% if prod_status == 'to_process' %}btn-danger text-white{% else %}btn-outline-danger{% endif %} rounded-pill">
|
||||||
<i class="bi bi-hourglass-split me-1"></i>{% translate "À traiter" %} <span class="badge {% if prod_status == 'to_process' %}bg-white text-danger{% else %}bg-danger text-white{% endif %} ms-1">{{ prod_counts.to_process|default:0 }}</span>
|
<i class="bi bi-hourglass-split me-1"></i>{% translate "À traiter" %} <span class="badge {% if prod_status == 'to_process' %}bg-white text-danger{% else %}bg-danger text-white{% endif %} ms-1">{{ prod_counts.to_process|default:0 }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="?tab=production-orders&prod_status=in_production{% if prod_search_q %}&prod_q={{ prod_search_q }}{% endif %}{% if prod_warehouse %}&prod_warehouse={{ prod_warehouse }}{% endif %}{% if prod_destination %}&prod_destination={{ prod_destination }}{% endif %}"
|
<a href="?tab=production-orders&prod_status=in_production{% if prod_search_q %}&prod_q={{ prod_search_q }}{% endif %}{% if prod_warehouse %}&prod_warehouse={{ prod_warehouse }}{% endif %}{% if prod_destination %}&prod_destination={{ prod_destination }}{% endif %}{% if prod_order %}&prod_order={{ prod_order }}{% endif %}"
|
||||||
class="btn btn-sm py-1 px-2 {% if prod_status == 'in_production' %}btn-primary{% else %}btn-outline-primary{% endif %} rounded-pill">
|
class="btn btn-sm py-1 px-2 {% if prod_status == 'in_production' %}btn-primary{% else %}btn-outline-primary{% endif %} rounded-pill">
|
||||||
<i class="bi bi-gear-wide-connected me-1"></i>{% translate "En confection" %} <span class="badge {% if prod_status == 'in_production' %}bg-white text-primary{% else %}bg-primary text-white{% endif %} ms-1">{{ prod_counts.in_production|default:0 }}</span>
|
<i class="bi bi-gear-wide-connected me-1"></i>{% translate "En confection" %} <span class="badge {% if prod_status == 'in_production' %}bg-white text-primary{% else %}bg-primary text-white{% endif %} ms-1">{{ prod_counts.in_production|default:0 }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="?tab=production-orders&prod_status=completed{% if prod_search_q %}&prod_q={{ prod_search_q }}{% endif %}{% if prod_warehouse %}&prod_warehouse={{ prod_warehouse }}{% endif %}{% if prod_destination %}&prod_destination={{ prod_destination }}{% endif %}"
|
<a href="?tab=production-orders&prod_status=completed{% if prod_search_q %}&prod_q={{ prod_search_q }}{% endif %}{% if prod_warehouse %}&prod_warehouse={{ prod_warehouse }}{% endif %}{% if prod_destination %}&prod_destination={{ prod_destination }}{% endif %}{% if prod_order %}&prod_order={{ prod_order }}{% endif %}"
|
||||||
class="btn btn-sm py-1 px-2 {% if prod_status == 'completed' %}btn-success{% else %}btn-outline-success{% endif %} rounded-pill">
|
class="btn btn-sm py-1 px-2 {% if prod_status == 'completed' %}btn-success{% else %}btn-outline-success{% endif %} rounded-pill">
|
||||||
<i class="bi bi-check-circle me-1"></i>{% translate "Terminé" %} <span class="badge {% if prod_status == 'completed' %}bg-white text-success{% else %}bg-success text-white{% endif %} ms-1">{{ prod_counts.completed|default:0 }}</span>
|
<i class="bi bi-check-circle me-1"></i>{% translate "Terminé" %} <span class="badge {% if prod_status == 'completed' %}bg-white text-success{% else %}bg-success text-white{% endif %} ms-1">{{ prod_counts.completed|default:0 }}</span>
|
||||||
</a>
|
</a>
|
||||||
{% if prod_counts.draft %}
|
{% if prod_counts.draft %}
|
||||||
<a href="?tab=production-orders&prod_status=draft{% if prod_search_q %}&prod_q={{ prod_search_q }}{% endif %}{% if prod_warehouse %}&prod_warehouse={{ prod_warehouse }}{% endif %}{% if prod_destination %}&prod_destination={{ prod_destination }}{% endif %}"
|
<a href="?tab=production-orders&prod_status=draft{% if prod_search_q %}&prod_q={{ prod_search_q }}{% endif %}{% if prod_warehouse %}&prod_warehouse={{ prod_warehouse }}{% endif %}{% if prod_destination %}&prod_destination={{ prod_destination }}{% endif %}{% if prod_order %}&prod_order={{ prod_order }}{% endif %}"
|
||||||
class="btn btn-sm py-1 px-2 {% if prod_status == 'draft' %}btn-secondary{% else %}btn-outline-secondary{% endif %} rounded-pill">
|
class="btn btn-sm py-1 px-2 {% if prod_status == 'draft' %}btn-secondary{% else %}btn-outline-secondary{% endif %} rounded-pill">
|
||||||
<i class="bi bi-pencil me-1"></i>{% translate "Brouillon" %} <span class="badge {% if prod_status == 'draft' %}bg-white text-secondary{% else %}bg-secondary text-white{% endif %} ms-1">{{ prod_counts.draft|default:0 }}</span>
|
<i class="bi bi-pencil me-1"></i>{% translate "Brouillon" %} <span class="badge {% if prod_status == 'draft' %}bg-white text-secondary{% else %}bg-secondary text-white{% endif %} ms-1">{{ prod_counts.draft|default:0 }}</span>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if prod_counts.cancelled %}
|
{% if prod_counts.cancelled %}
|
||||||
<a href="?tab=production-orders&prod_status=cancelled{% if prod_search_q %}&prod_q={{ prod_search_q }}{% endif %}{% if prod_warehouse %}&prod_warehouse={{ prod_warehouse }}{% endif %}{% if prod_destination %}&prod_destination={{ prod_destination }}{% endif %}"
|
<a href="?tab=production-orders&prod_status=cancelled{% if prod_search_q %}&prod_q={{ prod_search_q }}{% endif %}{% if prod_warehouse %}&prod_warehouse={{ prod_warehouse }}{% endif %}{% if prod_destination %}&prod_destination={{ prod_destination }}{% endif %}{% if prod_order %}&prod_order={{ prod_order }}{% endif %}"
|
||||||
class="btn btn-sm py-1 px-2 {% if prod_status == 'cancelled' %}btn-secondary{% else %}btn-outline-secondary{% endif %} rounded-pill">
|
class="btn btn-sm py-1 px-2 {% if prod_status == 'cancelled' %}btn-secondary{% else %}btn-outline-secondary{% endif %} rounded-pill">
|
||||||
<i class="bi bi-x-circle me-1"></i>{% translate "Annulé" %} <span class="badge {% if prod_status == 'cancelled' %}bg-white text-secondary{% else %}bg-secondary text-white{% endif %} ms-1">{{ prod_counts.cancelled|default:0 }}</span>
|
<i class="bi bi-x-circle me-1"></i>{% translate "Annulé" %} <span class="badge {% if prod_status == 'cancelled' %}bg-white text-secondary{% else %}bg-secondary text-white{% endif %} ms-1">{{ prod_counts.cancelled|default:0 }}</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -575,29 +575,51 @@ class PreparationOrderPriorityTests(TestCase):
|
||||||
prod1.refresh_from_db()
|
prod1.refresh_from_db()
|
||||||
prod2.refresh_from_db()
|
prod2.refresh_from_db()
|
||||||
|
|
||||||
# 1. stock_movements page: check chronological (FIFO) order
|
# 1. stock_movements page: default is most recent first (descending)
|
||||||
resp = self.client.get(reverse("stock:stock_movements") + "?tab=preparation-orders")
|
resp = self.client.get(reverse("stock:stock_movements") + "?tab=preparation-orders")
|
||||||
self.assertEqual(resp.status_code, 200)
|
self.assertEqual(resp.status_code, 200)
|
||||||
prep_orders = list(resp.context["preparation_orders"])
|
prep_orders = list(resp.context["preparation_orders"])
|
||||||
self.assertLess(prep_orders.index(po1), prep_orders.index(po2))
|
self.assertLess(prep_orders.index(po2), prep_orders.index(po1))
|
||||||
|
|
||||||
resp_prod = self.client.get(reverse("stock:stock_movements") + f"?tab=production-orders&prod_warehouse={wh.id}")
|
resp_prod = self.client.get(reverse("stock:stock_movements") + f"?tab=production-orders&prod_warehouse={wh.id}")
|
||||||
self.assertEqual(resp_prod.status_code, 200)
|
self.assertEqual(resp_prod.status_code, 200)
|
||||||
prod_orders = list(resp_prod.context["production_orders"])
|
prod_orders = list(resp_prod.context["production_orders"])
|
||||||
self.assertLess(prod_orders.index(prod1), prod_orders.index(prod2))
|
self.assertLess(prod_orders.index(prod2), prod_orders.index(prod1))
|
||||||
|
|
||||||
# 2. Mobile pages: check chronological order
|
# Inverted sort option (ascending / oldest first)
|
||||||
|
resp_inv = self.client.get(reverse("stock:stock_movements") + "?tab=preparation-orders&prep_order=asc")
|
||||||
|
self.assertEqual(resp_inv.status_code, 200)
|
||||||
|
prep_orders_inv = list(resp_inv.context["preparation_orders"])
|
||||||
|
self.assertLess(prep_orders_inv.index(po1), prep_orders_inv.index(po2))
|
||||||
|
|
||||||
|
resp_prod_inv = self.client.get(reverse("stock:stock_movements") + f"?tab=production-orders&prod_warehouse={wh.id}&prod_order=asc")
|
||||||
|
self.assertEqual(resp_prod_inv.status_code, 200)
|
||||||
|
prod_orders_inv = list(resp_prod_inv.context["production_orders"])
|
||||||
|
self.assertLess(prod_orders_inv.index(prod1), prod_orders_inv.index(prod2))
|
||||||
|
|
||||||
|
# 2. Mobile pages: default is most recent first (descending)
|
||||||
resp_m_prep = self.client.get(reverse("mobile:stock_preparation_orders_mobile"))
|
resp_m_prep = self.client.get(reverse("mobile:stock_preparation_orders_mobile"))
|
||||||
self.assertEqual(resp_m_prep.status_code, 200)
|
self.assertEqual(resp_m_prep.status_code, 200)
|
||||||
m_prep_orders = list(resp_m_prep.context["preparation_orders"])
|
m_prep_orders = list(resp_m_prep.context["preparation_orders"])
|
||||||
self.assertLess(m_prep_orders.index(po1), m_prep_orders.index(po2))
|
self.assertLess(m_prep_orders.index(po2), m_prep_orders.index(po1))
|
||||||
|
|
||||||
resp_m_prod = self.client.get(reverse("mobile:stock_production_orders_mobile"))
|
resp_m_prod = self.client.get(reverse("mobile:stock_production_orders_mobile"))
|
||||||
self.assertEqual(resp_m_prod.status_code, 200)
|
self.assertEqual(resp_m_prod.status_code, 200)
|
||||||
m_prod_orders = list(resp_m_prod.context["production_orders"])
|
m_prod_orders = list(resp_m_prod.context["production_orders"])
|
||||||
self.assertLess(m_prod_orders.index(prod1), m_prod_orders.index(prod2))
|
self.assertLess(m_prod_orders.index(prod2), m_prod_orders.index(prod1))
|
||||||
|
|
||||||
# 3. Home widget
|
# Mobile pages: inverted sort option (ascending / oldest first)
|
||||||
|
resp_m_prep_inv = self.client.get(reverse("mobile:stock_preparation_orders_mobile") + "?order=asc")
|
||||||
|
self.assertEqual(resp_m_prep_inv.status_code, 200)
|
||||||
|
m_prep_orders_inv = list(resp_m_prep_inv.context["preparation_orders"])
|
||||||
|
self.assertLess(m_prep_orders_inv.index(po1), m_prep_orders_inv.index(po2))
|
||||||
|
|
||||||
|
resp_m_prod_inv = self.client.get(reverse("mobile:stock_production_orders_mobile") + "?order=asc")
|
||||||
|
self.assertEqual(resp_m_prod_inv.status_code, 200)
|
||||||
|
m_prod_orders_inv = list(resp_m_prod_inv.context["production_orders"])
|
||||||
|
self.assertLess(m_prod_orders_inv.index(prod1), m_prod_orders_inv.index(prod2))
|
||||||
|
|
||||||
|
# 3. Home shortcut widgets: default is oldest first (FIFO)
|
||||||
resp_home = self.client.get(reverse("home:index"))
|
resp_home = self.client.get(reverse("home:index"))
|
||||||
self.assertEqual(resp_home.status_code, 200)
|
self.assertEqual(resp_home.status_code, 200)
|
||||||
home_preps = list(resp_home.context["preparation_order_to_process_list"])
|
home_preps = list(resp_home.context["preparation_order_to_process_list"])
|
||||||
|
|
|
||||||
|
|
@ -594,6 +594,7 @@ def stock_movements(request):
|
||||||
selected_status = request.GET.get('prep_status', '').strip() or (request.GET.get('status', '').strip() if tab != 'production-orders' else '')
|
selected_status = request.GET.get('prep_status', '').strip() or (request.GET.get('status', '').strip() if tab != 'production-orders' else '')
|
||||||
selected_priority = request.GET.get('priority', '').strip()
|
selected_priority = request.GET.get('priority', '').strip()
|
||||||
search_q = request.GET.get('prep_q', '').strip() or (request.GET.get('q', '').strip() if tab != 'production-orders' else '')
|
search_q = request.GET.get('prep_q', '').strip() or (request.GET.get('q', '').strip() if tab != 'production-orders' else '')
|
||||||
|
prep_order = request.GET.get('prep_order', '').strip() or (request.GET.get('order', '').strip() if tab != 'production-orders' else '')
|
||||||
|
|
||||||
prep_counts = PreparationOrder.objects.aggregate(
|
prep_counts = PreparationOrder.objects.aggregate(
|
||||||
total=models.Count('id'),
|
total=models.Count('id'),
|
||||||
|
|
@ -622,7 +623,11 @@ def stock_movements(request):
|
||||||
if search_q.isdigit():
|
if search_q.isdigit():
|
||||||
q_filter |= models.Q(intervention__id=int(search_q))
|
q_filter |= models.Q(intervention__id=int(search_q))
|
||||||
preparation_orders = preparation_orders.filter(q_filter)
|
preparation_orders = preparation_orders.filter(q_filter)
|
||||||
preparation_orders = preparation_orders.order_by("date")[:1000]
|
if prep_order == 'asc':
|
||||||
|
preparation_orders = preparation_orders.order_by("date")[:1000]
|
||||||
|
else:
|
||||||
|
prep_order = 'desc'
|
||||||
|
preparation_orders = preparation_orders.order_by("-date")[:1000]
|
||||||
|
|
||||||
# Filtrer selon les entrepôts accessibles
|
# Filtrer selon les entrepôts accessibles
|
||||||
accessible_warehouses = get_user_accessible_warehouses(request.user)
|
accessible_warehouses = get_user_accessible_warehouses(request.user)
|
||||||
|
|
@ -632,6 +637,7 @@ def stock_movements(request):
|
||||||
prod_search_q = request.GET.get('prod_q', '').strip() or (request.GET.get('q', '').strip() if tab == 'production-orders' else '')
|
prod_search_q = request.GET.get('prod_q', '').strip() or (request.GET.get('q', '').strip() if tab == 'production-orders' else '')
|
||||||
prod_warehouse = request.GET.get('prod_warehouse', '').strip() or (request.GET.get('warehouse', '').strip() if tab == 'production-orders' else '')
|
prod_warehouse = request.GET.get('prod_warehouse', '').strip() or (request.GET.get('warehouse', '').strip() if tab == 'production-orders' else '')
|
||||||
prod_destination = request.GET.get('prod_destination', '').strip() or (request.GET.get('destination', '').strip() if tab == 'production-orders' else '')
|
prod_destination = request.GET.get('prod_destination', '').strip() or (request.GET.get('destination', '').strip() if tab == 'production-orders' else '')
|
||||||
|
prod_order = request.GET.get('prod_order', '').strip() or (request.GET.get('order', '').strip() if tab == 'production-orders' else '')
|
||||||
|
|
||||||
prod_base_qs = ProductionOrder.objects.filter(warehouse__in=accessible_warehouses)
|
prod_base_qs = ProductionOrder.objects.filter(warehouse__in=accessible_warehouses)
|
||||||
|
|
||||||
|
|
@ -681,7 +687,11 @@ def stock_movements(request):
|
||||||
prod_q_filter |= models.Q(id=int(prod_search_q)) | models.Q(preparation_order__intervention__id=int(prod_search_q))
|
prod_q_filter |= models.Q(id=int(prod_search_q)) | models.Q(preparation_order__intervention__id=int(prod_search_q))
|
||||||
production_orders = production_orders.filter(prod_q_filter).distinct()
|
production_orders = production_orders.filter(prod_q_filter).distinct()
|
||||||
|
|
||||||
production_orders = production_orders.order_by("created_at")[:1000]
|
if prod_order == 'asc':
|
||||||
|
production_orders = production_orders.order_by("created_at")[:1000]
|
||||||
|
else:
|
||||||
|
prod_order = 'desc'
|
||||||
|
production_orders = production_orders.order_by("-created_at")[:1000]
|
||||||
|
|
||||||
movements = StockMovement.objects.filter(
|
movements = StockMovement.objects.filter(
|
||||||
models.Q(source_location__warehouse__id__in=accessible_warehouses) |
|
models.Q(source_location__warehouse__id__in=accessible_warehouses) |
|
||||||
|
|
@ -771,10 +781,12 @@ def stock_movements(request):
|
||||||
"selected_status": selected_status,
|
"selected_status": selected_status,
|
||||||
"selected_priority": selected_priority,
|
"selected_priority": selected_priority,
|
||||||
"search_q": search_q,
|
"search_q": search_q,
|
||||||
|
"prep_order": prep_order,
|
||||||
"prod_status": prod_status,
|
"prod_status": prod_status,
|
||||||
"prod_search_q": prod_search_q,
|
"prod_search_q": prod_search_q,
|
||||||
"prod_warehouse": prod_warehouse,
|
"prod_warehouse": prod_warehouse,
|
||||||
"prod_destination": prod_destination,
|
"prod_destination": prod_destination,
|
||||||
|
"prod_order": prod_order,
|
||||||
"prod_status_choices": [
|
"prod_status_choices": [
|
||||||
('active', _("À traiter & En confection")),
|
('active', _("À traiter & En confection")),
|
||||||
] + list(ProductionOrder.STATUS_CHOICES),
|
] + list(ProductionOrder.STATUS_CHOICES),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue