"""Views pour la gestion des produits.""" from django.shortcuts import render, redirect from django.core.paginator import Paginator from django.db.models import Sum from django.views.decorators.csrf import csrf_exempt from django.contrib.auth.decorators import login_required from django.http import JsonResponse from .models import ( Categorie, Produit, Demander, Fournisseur, Commander ) from .forms import ( EnregistrementProduit, EnregistrementCategorie, CommanderProduit, DemanderProduit, ) PRODUIT_NON_A__RENDRE = False PRODUIT_NON_RENDU = False def gestion_affichage_demande( request, option_validation_chef, ordre_inverse=False ): """Affichez les demandes de produit selon le profil de l'utilisateur. Parameters ---------- request : HttpRequest La requête HTTP entrante. option_validation_chef : bool or None Filtre pour la validation par le chef de département. 1- True : demandes validées par le chef. 2- False : demandes non validées par le chef. 3- None : demandes en attentes. ordre_inverse : bool, optional Si True, les demandes sont triées par ordre décroissant, par défaut False. Returns ------- QuerySet: Ensemble des demandes filtrées selon les critères spécifiés. """ mes_demandes = Demander.objects.filter( valider_par_chef=option_validation_chef, user=request.user.profile ) demandes_departement = None if request.user.profile.chef_departement: demandes_departement = Demander.objects.filter( valider_par_chef=option_validation_chef, user__departement=request.user.profile.departement, ) if ordre_inverse: return ( (mes_demandes | demandes_departement).order_by("-id") if demandes_departement else mes_demandes ) return ( (mes_demandes | demandes_departement) if demandes_departement else mes_demandes ) @login_required(login_url="login") def index(request): """Gérer le rendu de la page d'accueil de la gestion des produits. Parameters ---------- request : HttpRequest La requête HTTP entrante. Returns ------- HttpResponse La réponse HTTP contenant la page rendue. """ liste_produit = Produit.objects.all().order_by("-id") liste_categorie = Categorie.objects.all().order_by("categorie") liste_produit_finale = [ calcul_stock_produit(produit) for produit in liste_produit ] pagination = Paginator(liste_produit_finale, 8) page_number = request.GET.get("page") page_obj = pagination.get_page(page_number) return render( request, "gestion_produit/index.html", { "formulaireEnregistrementCategorie": EnregistrementCategorie, "formulaireEnregistrementProduit": EnregistrementProduit, "formulaireCommanderProduit": CommanderProduit, "formulaireDemanderProduit": DemanderProduit, "mes_demandes": gestion_affichage_demande( request, option_validation_chef=None ), "page_obj": page_obj, "liste_categorie": liste_categorie, }, ) def liste_categories(request): # noqa: ARG001 """Récupère et renvoie la liste des catégories de produits au format JSON. Parameters ---------- request : HttpRequest La requête HTTP entrante. Returns ------- JsonResponse Réponse JSON contenant la liste des catégories de produits. """ mes_categories = [ {"categorie": categorie.categorie} for categorie in Categorie.objects.all() ] return JsonResponse(mes_categories, safe=False) @login_required(login_url="login") @csrf_exempt def enregistrer_produit(request): """Enregistre un nouveau produit à partir des données POST. Parameters ---------- request : HttpRequest La requête HTTP entrante. Returns ------- JsonResponse Réponse JSON indiquant le succès ou l'échec de l'enregistrement. """ if request.method == "POST": p = EnregistrementProduit(request.POST, request.FILES) if p.is_valid(): p.save() return JsonResponse( {"success": True, "message": "Produit enregistré avec succès"} ) return JsonResponse( { "success": False, "message": "L'enregistrement du produit a échoué", } ) return redirect(index) @login_required(login_url="login") def enregistrer_commande(request): """Enregistrez une nouvelle commande de produit.""" if request.method == "POST": form = CommanderProduit(request.POST) if form.is_valid(): form.save() return redirect("gestion_produit:index") @login_required(login_url="login") def enregistrer_demande(request): """Enregistrez une nouvelle demande de produit.""" if request.method == "POST": form = DemanderProduit(request.POST) if form.is_valid(): ma_demande = form.save(commit=False) ma_demande.user = request.user.profile if request.user.profile.chef_departement: ma_demande.valider_par_chef = True ma_demande.save() return redirect("gestion_produit:index") @login_required(login_url="login") def liste_demandes(request): """Retournez la liste des demandes de produits au format JSON.""" liste_demandes = gestion_affichage_demande( request, option_validation_chef=True, ordre_inverse=True ) les_demandes = [ { "dateDemande": demande.date_de_mise_a_dispo_souhaite, "produit": demande.produit.libelle, "motifs": demande.motifs, "a_rendre": demande.a_rendre, "dateDeMiseADispoSouhaite": demande.date_de_mise_a_dispo_souhaite, "valider_par_chef": demande.valider_par_chef, "valider_par_logisticien": demande.valider_par_logisticien, "motifs_refus": demande.motif_refus, } for demande in liste_demandes ] return JsonResponse(les_demandes, safe=False) @login_required(login_url="login") def detail_demande(request, id_demande): """Renvoyez les détails d'une demande spécifique de produit.""" detail_demande = Demander.objects.get(id=id_demande) demande = { # "image": detail_demande.produit.image.url, "detailNom": detail_demande.produit.libelle, "detailCategorie": detail_demande.produit.categorie.categorie, "detailmotif": detail_demande.motifs, "detailDeMiseADispo": detail_demande.date_de_mise_a_dispo_souhaite, "detailARendre": detail_demande.a_rendre, "chef_departement": request.user.profile.chef_departement, } return JsonResponse(demande) @login_required(login_url="login") @csrf_exempt def update_statut(request): """Met à jour le statut d'une demande de produit. Parameters ---------- request : HttpRequest La requête HTTP entrante. request.id : int L'ID de la demande à mettre à jour. request.action : str L'action à effectuer ('confirmer' ou 'refuser'). request.emetteur : str L'émetteur de la demande ('chef' ou 'logisticien'). request.motif_refus : str Le motif de refus (si applicable). Returns ------- JsonResponse Réponse JSON indiquant le succès ou l'échec de la mise à jour. """ if request.method == "POST": produit_id = request.POST.get("id") action = request.POST.get("action") emetteur = request.POST.get("emetteur") motifs = request.POST.get("motif_refus") try: demande = Demander.objects.get(id=produit_id) except Demander.DoesNotExist: return JsonResponse( { "success": False, "message": "Demande introuvable" }, status=404 ) if action == "1": if emetteur == "chef": demande.valider_par_chef = True elif emetteur == "logisticien": demande.valider_par_logisticien = True elif action == "0": if emetteur == "chef": demande.valider_par_chef = False elif emetteur == "logisticien": demande.valider_par_logisticien = False demande.motif_refus = motifs else: return JsonResponse( {"success": False, "message": "Action invalide"}, status=400 ) demande.save() return JsonResponse({"success": True, "message": "Statut mis à jour"}) return JsonResponse( {"success": False, "message": "Méthode non autorisée"}, status=405 ) @login_required(login_url="login") def recuperer_liste_produit(request): """Récupèrez et renvoyez la liste des produits paginée. Parameters ---------- request : HttpRequest La requête HTTP entrante. Returns ------- HttpResponse La réponse HTTP contenant la page rendue avec la liste des produits. """ liste_produit = Produit.objects.all().order_by("-id") pagination = Paginator(liste_produit, 8) page_number = request.GET.get("page") page_obj = pagination.get_page(page_number) return render( request, "gestion_produit/index.html", {"page_obj": page_obj} ) @login_required(login_url="login") @csrf_exempt def enregistrer_categorie(request): """Enregistrez une nouvelle catégorie de produit. Cette vue est appelée via une requête AJAX avec la méthode POST et enregistre une nouvelle. Parameters ---------- request : HttpRequest La requête HTTP entrante. Returns ------- JsonResponse Réponse JSON indiquant le succès ou l'échec de l'enregistrement. """ if request.method == "POST": categories = EnregistrementCategorie(request.POST) if categories.is_valid(): categories.save() return JsonResponse({"success": True}) return JsonResponse({"success": False}) return None @login_required(login_url="login") def recuperer_fournisseur_par_categorie(request, id_produit): # noqa: ARG001 """Récupèrez les fournisseurs associés à la catégorie d'un produit donné. Parameters ---------- request : HttpRequest La requête HTTP entrante. id_produit : int L'ID du produit dont on veut récupérer les fournisseurs. Returns ------- JsonResponse Réponse JSON contenant la liste des fournisseurs associés à la catégorie du produit. """ produit = Produit.objects.get(id=id_produit) fournisseur = Fournisseur.objects.filter(categorie=produit.categorie) produit_founisseur = [ { "id": fournisseur_produit.id, "nom_fournisseur": fournisseur_produit.nom_entreprise, } for fournisseur_produit in fournisseur ] return JsonResponse(produit_founisseur, safe=False) # @login_required(login_url="login") def calcul_stock_produit(produit): """Calculez le stock actuel d'un produit donné. Parameters ---------- produit : Produit L'instance du produit pour lequel calculer le stock. Returns ------- dict Dictionnaire contenant les détails du produit et son stock actuel. """ quantite_livrer = ( Commander.objects.filter(livrer=True, produit=produit).aggregate( Sum("quantite_commander") )["quantite_commander__sum"] or 0 ) produit_demander_a_rendre = Demander.objects.filter( produit=produit, valider_par_logisticien=True, ) quantite_produit_sortis = 0 for produit_demander in produit_demander_a_rendre: if ( (produit_demander.a_rendre and produit_demander.rendu is False) or produit_demander.a_rendre is False ): quantite_produit_sortis += produit_demander.quantite ## Stock actuel = Quantite initiale + total livrer - quantiteSorties stock_actuel = (produit.quantite_stock + quantite_livrer - quantite_produit_sortis) return { "id": produit.id, "libelle": produit.libelle, "quantite_stock": produit.quantite_stock, "conditionnement": produit.conditionnement, "seuil_pre_rupture": produit.seuil_pre_rupture, "image": produit.image, "categorie_id": produit.categorie_id, "stockActuel": stock_actuel, } @login_required(login_url="login") def mouvement_stock(request): """Rendez la page de mouvement de stock. Parameters ---------- request : HttpRequest La requête HTTP entrante. Returns ------- HttpResponse La réponse HTTP contenant la page rendue. """ return render(request, "gestion_produit/mouvement_stock.html") @login_required(login_url="login") def rapport_mouvement_stock(request): """Générez un rapport de mouvement de stock basé sur les filtres donnés. Parameters ---------- request : HttpRequest La requête HTTP entrante. request.GET["dateFiltre"] : str La date de filtre au format "YYYY-MM". request.GET["typeFiltre"] : str Le type de filtre ("entree" ou "sortie"). Returns ------- JsonResponse Réponse JSON contenant le rapport de mouvement de stock. """ mes_commandes = [] date_filtre = request.GET["dateFiltre"] annee, mois = date_filtre.split("-") type_filtre = request.GET["typeFiltre"] if type_filtre == "entree": mes_commandes.extend([ { "produit": commande.produit.libelle, "categorie": commande.produit.categorie.categorie, "conditionnement": commande.produit.conditionnement, "fournisseur": commande.fournisseur.nom_entreprise, "date_commande": commande.date_commande, "date_livraison": commande.date_livraison, "quantite_commander": commande.quantite_commander, } for commande in Commander.objects.filter( date_livraison__year=annee, date_livraison__month=mois, livrer=True ) ]) elif type_filtre == "sortie": mes_commandes.extend([ { "produit": demande.produit.libelle, "categorie": demande.produit.categorie.categorie, "conditionnement": demande.produit.conditionnement, "date_demande": demande.dateDemande, # "date_mise_a_dispo": commande.date_commande, "quantite_demander": demande.quantite, } for demande in Demander.objects.filter( dateDemande__year=annee, dateDemande__month=mois, valider_par_logisticien=True, ) ]) return JsonResponse(mes_commandes, safe=False)