523 lines
16 KiB
Python
523 lines
16 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 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)
|