diff --git a/loko/mobile/views.py b/loko/mobile/views.py index 1b067a2..9fb4ae2 100644 --- a/loko/mobile/views.py +++ b/loko/mobile/views.py @@ -485,13 +485,67 @@ def stock_production_orders_mobile(request): """Mobile list of production orders (bons de confection).""" from stock.models import ProductionOrder from stock.permissions import get_user_accessible_warehouses + from django.db import models + + search_q = request.GET.get('q', '').strip() or request.GET.get('prod_q', '').strip() + selected_status = request.GET.get('status', '').strip() or request.GET.get('prod_status', '').strip() + selected_warehouse = request.GET.get('warehouse', '').strip() or request.GET.get('prod_warehouse', '').strip() + selected_destination = request.GET.get('destination', '').strip() or request.GET.get('prod_destination', '').strip() accessible_warehouses = get_user_accessible_warehouses(request.user) - production_orders = ProductionOrder.objects.filter( - warehouse__id__in=accessible_warehouses - ).select_related('warehouse').order_by('-created_at')[:200] + base_qs = ProductionOrder.objects.filter(warehouse__in=accessible_warehouses) + + # Compteurs par statut (pour les filtres rapides mobiles) + prod_counts = base_qs.aggregate( + total=models.Count('id'), + to_process=models.Count('id', filter=models.Q(status=ProductionOrder.STATUS_TO_PROCESS)), + in_production=models.Count('id', filter=models.Q(status=ProductionOrder.STATUS_IN_PRODUCTION)), + completed=models.Count('id', filter=models.Q(status=ProductionOrder.STATUS_COMPLETED)), + draft=models.Count('id', filter=models.Q(status=ProductionOrder.STATUS_DRAFT)), + cancelled=models.Count('id', filter=models.Q(status=ProductionOrder.STATUS_CANCELLED)), + ) + + production_orders = base_qs.select_related( + 'warehouse', 'preparation_order', 'output_product', 'output_location', + 'preparation_order__intervention', 'preparation_order_other_item', + ).prefetch_related( + 'order_components__product', + ) + + if selected_status: + production_orders = production_orders.filter(status=selected_status) + if selected_warehouse: + production_orders = production_orders.filter(warehouse_id=selected_warehouse) + if selected_destination: + production_orders = production_orders.filter(destination=selected_destination) + if search_q: + q_filter = ( + models.Q(code__icontains=search_q) | + models.Q(output_product__name__icontains=search_q) | + models.Q(output_product_name__icontains=search_q) | + models.Q(preparation_order__order_number__icontains=search_q) | + models.Q(preparation_order__intervention__code__icontains=search_q) | + models.Q(preparation_order__intervention__title__icontains=search_q) | + models.Q(preparation_order_other_item__description__icontains=search_q) | + models.Q(notes__icontains=search_q) | + models.Q(order_components__product__name__icontains=search_q) + ) + if search_q.isdigit(): + 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.order_by('-created_at')[:200] + return render(request, "stock/mobile/stock_production_orders_mobile.html", { 'production_orders': production_orders, + 'search_q': search_q, + 'selected_status': selected_status, + 'selected_warehouse': selected_warehouse, + 'selected_destination': selected_destination, + 'status_choices': ProductionOrder.STATUS_CHOICES, + 'destination_choices': ProductionOrder.DESTINATION_CHOICES, + 'warehouses': accessible_warehouses, + 'prod_counts': prod_counts, }) diff --git a/loko/stock/models.py b/loko/stock/models.py index 97b99a8..e9b2f66 100644 --- a/loko/stock/models.py +++ b/loko/stock/models.py @@ -2237,6 +2237,19 @@ class ProductionOrder(models.Model): class Meta: ordering = ("-created_at",) + @property + def display_output_product_name(self): + """Retourne le nom d'affichage du produit fini / confectionné.""" + if self.output_product: + return self.output_product.name + if self.output_product_name: + return self.output_product_name + if self.preparation_order_other_item and self.preparation_order_other_item.description: + return self.preparation_order_other_item.description + if self.notes and 'Issu de' in self.notes and ': ' in self.notes: + return self.notes.split(': ', 1)[1].strip() + return "" + def __str__(self): return _("Confection {code} x{qty}").format( code=self.code or f"#{self.pk}", diff --git a/loko/stock/templates/stock/mobile/stock_production_orders_mobile.html b/loko/stock/templates/stock/mobile/stock_production_orders_mobile.html index a28c366..72d7e69 100644 --- a/loko/stock/templates/stock/mobile/stock_production_orders_mobile.html +++ b/loko/stock/templates/stock/mobile/stock_production_orders_mobile.html @@ -1,4 +1,4 @@ -{% extends 'mobile/mobile_base.html' %} +{% extends 'mobile/mobile_base.html' %} {% load static %} {% load i18n %} @@ -31,44 +31,180 @@ } .list-card-title { font-weight: 600; font-size: 1rem; } .list-card-meta { font-size: 0.83rem; color: #6c757d; } + .status-pills-bar { + scrollbar-width: thin; + -webkit-overflow-scrolling: touch; + } {% endblock extra_head %} {% block content %} -