Files
sgl/gestion_produit/views.py
2026-09-18 11:09:35 +00:00

647 lines
20 KiB
Python

"""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 authentification.models import Profile
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,
)
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.
"""
profile = Profile.objects.get(user=request.user)
mes_demandes = Demander.objects.filter(
valider_par_chef=option_validation_chef, 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
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):
"""Recuperez et renvoyez la liste des catégories de produit 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
def enregistrer_produit(request):
"""Enregistrez 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":
form = EnregistrementProduit(request.POST, request.FILES)
if form.is_valid():
form.save()
return JsonResponse(
{"success": True, "message": "Produit enregistré avec succès"}
)
return JsonResponse(
{
"success": False,
"message": "L'enregistrement du produit a échoué",
}
)
return redirect("gestion_produit:index")
@login_required
def detail_produit(_request, id_produit):
"""Renvoyez les détails d'un produit spécifique au format JSON.
Parameters
----------
request : HttpRequest
La requête HTTP entrante.
id_produit : int
L'ID du produit dont on veut récupérer les détails.
Returns
-------
JsonResponse
Réponse JSON contenant les détails du produit.
"""
detail_produit = calcul_stock_produit(Produit.objects.get(id=id_produit))
categories = Categorie.objects.all()
produit = {
"detailId": detail_produit["id"],
"detailLibelle": detail_produit["libelle"],
"detailCategorie": detail_produit["categorie_id"],
"detailConditionnement": detail_produit["conditionnement"],
"detailSeuilPreRupture": detail_produit["seuil_pre_rupture"],
"detailQuantiteStock": detail_produit["stockActuel"],
"detailImage": detail_produit["image"].url if detail_produit["image"] else "",
"listeCategorie": [
{"id": categorie.id, "categorie": categorie.categorie}
for categorie in categories
],
}
return JsonResponse(produit)
@login_required
def enregistrer_modification_produit(request):
"""Enregistrez les modifications apportées au 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":
id_produit = request.POST.get("id_produit")
produit_instance = Produit.objects.get(id=id_produit)
produit_instance.libelle = request.POST.get("libelle")
produit_instance.conditionnement = request.POST.get("conditionnement")
produit_instance.seuil_pre_rupture = request.POST.get("seuil_pre_rupture")
categorie_id = request.POST.get("categorie")
produit_instance.categorie = Categorie.objects.get(id=categorie_id)
produit_instance.quantite_stock = request.POST.get("quantite_stock")
produit_instance.save()
return JsonResponse(
{"success": True, "message": "Produit modifié avec succès"}
)
return redirect("gestion_produit:index")
@login_required
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
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
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
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 = {
"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
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 : int
L'action effectuée
1: Pour confirmer
0: Pour refuser
request.emetteur : str
L'émetteur de la demande ('chef' ou 'logisticien').
request.motif_refus : str
Le motif de refus.
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")
if not all([produit_id, action, emetteur]):
return JsonResponse(
{"success": False, "message": "Données manquantes"}, status=400
)
try:
demande = Demander.objects.get(id=produit_id)
except Demander.DoesNotExist:
return JsonResponse(
{"success": False, "message": "Demande introuvable"},
status=404
)
match action, emetteur:
case "1", "chef":
demande.valider_par_chef = True
case "1", "logisticien":
demande.valider_par_logisticien = True
case "0", "chef":
demande.valider_par_chef = False
case "0", "logisticien":
demande.valider_par_logisticien = False
demande.motif_refus = motifs
case _:
return JsonResponse(
{"success": False, "message": "Données invalides"},
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
def recuperer_liste_produit(request):
"""Récupèrez et renvoyez la liste des produits paginés.
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
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
def filtrer_produit_par_categorie(request, id_categorie):
"""Filtrez les produits par catégorie et renvoyez-les au format JSON.
Parameters
----------
request : HttpRequest
La requête HTTP entrante.
id_categorie : int
L'ID de la catégorie pour laquelle filtrer les produits.
Returns
-------
JsonResponse
Réponse JSON contenant la liste des produits filtrés par catégorie.
"""
produits = Produit.objects.filter(categorie_id=id_categorie)
produits_filtres = [
{
"id": produit.id,
"libelle": produit.libelle,
"conditionnement": produit.conditionnement,
"quantite_stock": produit.quantite_stock,
"seuil_pre_rupture": produit.seuil_pre_rupture,
"image": produit.image.url if produit.image else "",
"appartient_logistique": request.user.groups.filter(name="Logistique").exists(),
}
for produit in produits
]
return JsonResponse(produits_filtres, safe=False)
def filtre_par_nom_produit(request):
"""Filtrez les produits par nom et renvoyez-les au format JSON.
Parameters
----------
request : HttpRequest
La requête HTTP entrante.
nom_produit : str
Le nom du produit pour lequel filtrer les produits.
Returns
-------
JsonResponse
Réponse JSON contenant la liste des produits filtrés par nom.
"""
nom_produit = request.GET.get("nom", "")
if nom_produit == "":
produits = Produit.objects.all()
else:
produits = Produit.objects.filter(libelle__icontains=nom_produit)
produits_filtres = [
{
"id": produit.id,
"libelle": produit.libelle,
"conditionnement": produit.conditionnement,
"quantite_stock": produit.quantite_stock,
"seuil_pre_rupture": produit.seuil_pre_rupture,
"image": produit.image.url if produit.image else "",
"appartient_logistique": request.user.groups.filter(name="Logistique").exists(),
}
for produit in produits
]
return JsonResponse(produits_filtres, safe=False)
@login_required
def recuperer_fournisseur_par_categorie(_request, id_produit):
"""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)
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 = (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
def mouvement_stock(request):
"""Retournez 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
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_entree": commande.produit.libelle,
"categorie_entree": commande.produit.categorie.categorie,
"conditionnement_entree": commande.produit.conditionnement,
"fournisseur_entree": commande.fournisseur.nom_entreprise,
"date_commande_entree": commande.date_commande,
"date_livraison_entree": commande.date_livraison,
"quantite_commander_entree": 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_sortie": demande.produit.libelle,
"categorie_sortie": demande.produit.categorie.categorie,
"conditionnement_sortie": demande.produit.conditionnement,
"date_demande_sortie": demande.date_de_mise_a_dispo_souhaite,
# "date_mise_a_dispo": commande.date_commande,
"quantite_demander_sortie": demande.quantite,
}
for demande in Demander.objects.filter(
date_de_mise_a_dispo_souhaite__year=annee,
date_de_mise_a_dispo_souhaite__month=mois,
valider_par_logisticien=True,
)
])
return JsonResponse(mes_commandes, safe=False)