Mon commit initial

This commit is contained in:
2025-12-19 09:43:33 +00:00
commit f11d1e62b4
336 changed files with 6247 additions and 0 deletions

0
SGL/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

16
SGL/asgi.py Normal file
View File

@@ -0,0 +1,16 @@
"""
ASGI config for SGL project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "SGL.settings")
application = get_asgi_application()

147
SGL/settings.py Normal file
View File

@@ -0,0 +1,147 @@
"""
Django settings for SGL project.
Generated by 'django-admin startproject' using Django 5.2.6.
For more information on this file, see
https://docs.djangoproject.com/en/5.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.2/ref/settings/
"""
from pathlib import Path
from os.path import join
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-3mmf81^pt+k6-^dj$n2&*kvf6m09n5i%*+ajv70(ynaxifj5fg"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"gestion_produit",
"gestion_fournisseur",
"gestion_vehicule",
"authentification",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "SGL.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [join(BASE_DIR, "SGL", "templates")],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "SGL.wsgi.application"
# Database
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.2/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.2/howto/static-files/
STATIC_URL = "static/"
STATICFILES_DIRS = [
BASE_DIR / "static",
]
# Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "media"
# Gestion de l'envoi des mails
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "ssl0.ovh.net"
EMAIL_PORT = 465
EMAIL_USE_SSL = False
EMAIL_USE_TLS = False
EMAIL_HOST_USER = "support.it@cerfig.org"
EMAIL_HOST_PASSWORD = "Cerfig2025"
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
EMAIL_TIMEOUT = 10
# ALLOWED_HOSTS = ['support.cerfig.org', '41.223.50.187', 'localhost', '127.0.0.1']

114
SGL/templates/BASE.html Normal file
View File

@@ -0,0 +1,114 @@
{% load static %}
{% load tags_personnaliser %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'css/tabulator_bootstrap5.min.css' %}">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.min.css">
<title>{% block page_titre %} Tableau de bord {% endblock %}</title>
</head>
<body>
<div class="container-fluid">
<div class="row vh-100">
<div class="col-3 bg-danger d-none d-lg-flex flex-column">
{% if user|has_group:"Administration" %}
<a href="{% url 'index' %}" class="btn btn-danger py-3 mt-4 fw-bold d-flex" style="font-size: 1.2em;">
<i class="bi bi-file-bar-graph d-block" style="width: 50px;"></i>
Tableau de bord
</a>
{% endif %}
{% if user|has_group:"Employe" %}
<a href="{% url 'gestion_produit:index' %}" class="btn btn-danger py-3 mt-1 fw-bold d-flex" style="font-size: 1.2em;">
<i class="bi bi-backpack4 d-block" style="width: 50px;"></i>
Gestion des produits
</a>
{% endif %}
{% if user|has_group:"Administration" %}
<a href="{% url 'gestion_fournisseur:index' %}" class="btn btn-danger py-3 mt-1 fw-bold d-flex" style="font-size: 1.2em;">
<i class="bi bi-truck d-block" style="width: 50px;"></i>
Gestion des fournisseurs
</a>
{% endif %}
{% if user|has_group:"Employe" %}
<a href="{% url 'gestion_vehicule:index' %}" class="btn btn-danger py-3 mt-1 fw-bold d-flex" style="font-size: 1.2em;">
<i class="bi bi-car-front-fill d-block" style="width: 50px;"></i>
Gestion des véhicules
</a>
{% endif %}
<a href="{% url 'authentification:deconnexion' %}" class="btn btn-danger py-3 mt-1 fw-bold d-flex" style="font-size: 1.2em;">
<i class="bi bi-person-dash d-block" style="width: 50px;"></i>
Deconnexion
</a>
</div>
<div class="col-12 col-lg-9" style="overflow-y: auto;">
<!-- --------------------------------------------------- Navigation mobile -->
<nav class="navbar navbar-danger bg-danger d-lg-none">
<div class="container-fluid">
<a class="navbar-brand" href="#">CERFIG</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarTogglerDemo01" aria-controls="navbarTogglerDemo01" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarTogglerDemo01">
<!-- <a class="navbar-brand" href="#">Hidden brand</a> -->
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
{% if user|has_group:"Administration" %}
<li class="nav-item">
<a class="nav-link d-flex text-white fw-bold" aria-current="page" href="{% url 'index' %}">
<i class="bi bi-backpack4 d-block" style="width: 50px;"></i>
Tableau de bord
</a>
</li>
{% endif %}
{% if user|has_group:"Employe" %}
<li class="nav-item">
<a class="nav-link d-flex text-white fw-bold" href="{% url 'gestion_produit:index' %}">
<i class="bi bi-backpack4 d-block" style="width: 50px;"></i>
Gestion des produits
</a>
</li>
{% endif %}
{% if user|has_group:"Administration" %}
<li class="nav-item">
<a class="nav-link d-flex text-white fw-bold" href="{% url 'gestion_fournisseur:index' %}" tabindex="-1" aria-disabled="true">
<i class="bi bi-truck d-block" style="width: 50px;"></i>
Gestion des fournisseurs
</a>
</li>
{% endif %}
{% if user|has_group:"Employe" %}
<li class="nav-item">
<a class="nav-link d-flex text-white fw-bold" href="{% url 'gestion_vehicule:index' %}" tabindex="-1" aria-disabled="true">
<i class="bi bi-truck d-block" style="width: 50px;"></i>
Gestion des véhicules
</a>
</li>
{% endif %}
<li class="nav-item">
<a class="nav-link d-flex text-white fw-bold" href="{% url 'authentification:deconnexion' %}" tabindex="-1" aria-disabled="true">
<i class="bi bi-person-dash d-block" style="width: 50px;"></i>
Deconnexion
</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- ------------------------------------------------------ -->
{% block "contenu" %} {% endblock %}
</div>
</div>
</div>
<script src="{% static 'js\tabulator.min.js' %}"></script>
<script src="{% static 'js\bootstrap.min.js' %}"></script>
{% block "js" %} {% endblock %}
</body>
</html>

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Message test</title>
</head>
<body>
<div style="background-color: aliceblue; min-height: 100vh; width: 100%; display: flex; justify-content: center;">
<div style="background-color: white; width: 80%; margin-top: 10px; border-radius: 15px; padding: 10px;">
<img src="téléchargement.png" alt="Logo cerfig" style="display: block; margin: auto;">
<h1 style="text-align: center;">Réception de nouveau produit</h1>
<p>
Bonjour M. Sylla Soriba, la livraison de nouveaux ordinateurs au CERFIG a été effectuée
avec succès. Merci à vous
</p>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

206
SGL/templates/index.html Normal file
View File

@@ -0,0 +1,206 @@
{% extends "BASE.html" %}
{% load static %}
{% load tags_personnaliser %}
{% block page_titre %} Tableau de bord {% endblock %}
{% block "contenu" %}
<div class="row p-2 d-flex justify-content-around">
<div class="col-5 col-lg-3 border border-3 rounded border-danger p-2 d-flex" style="cursor: pointer;" id="produit_rupture">
<img src="{% static 'images/stock-rupture.png' %}" alt="" style="width: 30%; height: 75%;">
<div class="d-flex justify-content-center flex-column ms-1">
<h3 class="text-center fw-bold">Rupture</h3>
<p class="text-center">{{ nombre_rupture }} produits</p>
</div>
</div>
<div class="col-5 col-lg-3 border border-3 rounded border-warning p-2 d-flex" style="cursor: pointer;" id="produit_pre_rupture">
<img src="{% static 'images/stock-prerupture.png' %}" alt="" style="width: 30%; height: 75%;">
<div class="d-flex justify-content-center flex-column ms-1">
<h3 class="text-center fw-bold">Pré-rupture</h3>
<p class="text-center">{{ nombre_pre_rupture }} produits</p>
</div>
</div>
<div class="col-5 col-lg-3 mt-2 mt-lg-0 border border-3 rounded border-success p-2 d-flex" style="cursor: pointer;" id="produit_normal">
<img src="{% static 'images/stock-bon.png' %}" alt="" style="width: 30%; height: 75%;">
<div class="d-flex justify-content-center flex-column ms-1">
<h3 class="text-center fw-bold">Correct</h3>
<p class="text-center">{{ nombre_normal }} produits</p>
</div>
</div>
</div>
<button class="btn btn-primary m-auto d-block" data-bs-toggle="modal" data-bs-target="#aRendreModal">
<i class="bi bi-eye"></i>
Equipement à rendre ...
</button>
<div class="row mt-5 d-flex flex-column flex-lg-row">
<div class="col-12 col-lg-6">
<h5 class="text-center">Demandes de produit ({{ nb_demande }})</h5>
<div id="demande_produit" data-url="{% url 'demande_en_cours' %}"></div>
</div>
<div class="col-12 col-lg-6 mt-3 mt-lg-0">
<h5 class="text-center">Commandes en attentes ({{ nb_commande }})</h5>
<div id="commande_attentes" data-url="{% url 'commande_en_cours' %}"></div>
</div>
</div>
<!-- ------------- Modal pour la liste des demandes en cours ---------------------- -->
<div class="modal fade" id="listeDemandesModal" tabindex="-1" aria-labelledby="listeDemandesModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="listeDemandesModalLabel">Demande de produit</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form action="">
<div class="mb-3">
<label for="produit" class="form-label">Demandeur :</label>
<input type="text" class="form-control" id="demandeur" readonly>
</div>
<div class="mb-3">
<label for="produit" class="form-label">Produit</label>
<input type="text" class="form-control" id="produit" readonly>
</div>
<div class="mb-3">
<label for="quantite" class="form-label">Quantité</label>
<input type="number" class="form-control" id="quantite" readonly>
</div>
<div class="mb-3">
<label for="motifs" class="form-label">Motifs</label>
<textarea class="form-control" id="motifs" rows="3" readonly></textarea>
</div>
<div class="mb-3">
<label for="date_demande" class="form-label">Date de mise à disposition souhaitée :</label>
<input type="date" class="form-control" id="date_demande" readonly>
</div>
<div class="mb-3">
<label for="a_rendre" class="form-label">À rendre ?</label>
<input type="checkbox" class="form-check-input" id="a_rendre" disabled>
</div>
<div class="mb-3">
<label for="">Valider par le supérieur hiérarchique</label>
<input type="checkbox" class="form-check-input" id="valider_par_chef" disabled>
</div>
<hr>
<h6 class="text-center">Décision de la logistique</h6>
<div class="d-flex justify-content-around mb-3">
<div class="form-check">
<input class="form-check-input" type="radio" name="radioDefault" id="radioValider">
<label class="form-check-label" for="radioValider">
Valider la demande
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="radioDefault" id="radioRefuser" data-url="{% url 'gestion_produit:update-demande' %}">
<label class="form-check-label" for="radioRefuser">
Refuser la demande
</label>
</div>
</div>
<div class="mb-3 d-none" id="box-motif-refus">
<label for="motifs_refus" class="form-label">Motifs de refus</label>
<textarea class="form-control" id="motifs_refus" rows="3"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
<button type="button" class="btn btn-primary" id="enregistrerModifs">Enregistrer les modifications</button>
</div>
</div>
</div>
</div>
<!-- ------------- Modal pour la liste des commandes en cours ---------------------- -->
<div class="modal fade" id="listeCommandesModal" tabindex="-1" aria-labelledby="listeCommandesModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="listeCommandesModalLabel">Commande de produit</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form action="">
<div class="mb-3">
<label for="produit" class="form-label">Produit</label>
<input type="text" class="form-control" id="produitCommande" readonly>
</div>
<div class="mb-3">
<label for="quantite" class="form-label">Fournisseur :</label>
<input type="text" class="form-control" id="fournisseur" readonly>
</div>
<div class="mb-3">
<label for="motifs" class="form-label">Quantité</label>
<input class="form-control" id="quantiteCommande" readonly></input>
</div>
<div class="mb-3">
<label for="date_commande" class="form-label">Date de commande</label>
<input type="date" class="form-control" id="date_commande" readonly>
</div>
<div class="mb-3">
<label for="date_livraison" class="form-label">Date de Livraison</label>
<input type="date" class="form-control" id="date_livraison" readonly>
</div>
<hr>
<h6 class="text-center">Confirmation de la livraison du produit</h6>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="produit_livre">
<label class="form-check-label" for="produit_livre">Le produit a été livré</label>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
<button type="button" class="btn btn-primary" id="enregistrerModifsCommande" data-url="{% url 'enregistrer_livraison_produit' %}">Enregistrer les modifications</button>
</div>
</div>
</div>
</div>
<!-- ------------------------------------- Modal pour stock en rupture ------------------------------ -->
<div class="modal fade" id="produitRuptureModal" tabindex="-1" aria-labelledby="produitRuptureModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="produitRuptureModalLabel">Produit en rupture</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="tableau-produit-rupture" data-url="{% url 'listeProduitRupture' %}"></div>
</div>
</div>
</div>
</div>
<!-- ----------------------------------- Modal équipement à rendre -------------------------------- -->
<div class="modal fade" id="aRendreModal" tabindex="-1" aria-labelledby="aRendreModalLabel">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="aRendreModalLabel">
Equipement à rendre
</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="tableau-equipement-rendre" data-url="{% url 'equipement-a-rendre' %}"></div>
</div>
{% if user|has_group:"Logisticien" %}
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
<button type="button" class="btn btn-primary" id="equipementARendreEnregistrer" data-url="{% url 'update-equipement-a-rendre' %}">Enregistrer</button>
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}
{% block "js" %}
<script src="{% static 'js\index.js' %}"></script>
{% endblock %}

68
SGL/urls.py Normal file
View File

@@ -0,0 +1,68 @@
"""
URL configuration for SGL project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
""" #noqa : D212
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("gestion-produit/", include("gestion_produit.urls")),
path("gestion-fournisseur/", include("gestion_fournisseur.urls")),
path("gestion-vehicule/", include("gestion_vehicule.urls")),
path("authentification/", include("authentification.urls")),
path(
"liste-commande-en-cours/",
views.liste_produit_commander,
name="commande_en_cours",
),
path(
"liste-demande-en-cours/",
views.liste_demandes,
name="demande_en_cours"
),
path(
"enregistrer-livraison-produit/",
views.enregistrer_livraison_produit,
name="enregistrer_livraison_produit",
),
path(
"admin/",
admin.site.urls
),
path(
"dashboard-produit/",
views.liste_produit_rupture,
name="listeProduitRupture"
),
path(
"equipement-a-rendre/",
views.produit_a_rendre,
name="equipement-a-rendre"
),
path(
"update-equipement-a-rendre/",
views.produit_a_rendre_update,
name="update-equipement-a-rendre",
),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

334
SGL/views.py Normal file
View File

@@ -0,0 +1,334 @@
"""Fichier views.py de gestion de la page dashboard de l'application SGL.
Principales fonctionnalités couvertes :
1- Gestion des stocks des produits (rupture, pré-rupture, normal).
2- Affichage des commandes en cours et validations des dites commandes
3- Affichage des demandes en cours et validations des dites demandes.
"""
from django.shortcuts import render, redirect
from django.http import JsonResponse
from gestion_produit.models import Commander, Demander, Produit
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required
import json
from gestion_produit.views import calcul_stock_produit
def dashboard_quantite_produit():
"""Calculez les quantités des produits en rupture, pré-rupture et normal.
Returns
-------
dict
Dictionnaire contenant les nombres et les listes des produits par
catégorie.
"""
tous_les_produits = Produit.objects.all()
nombre_rupture = 0
nombre_pre_rupture = 0
nombre_normal = 0
produit_rupture = []
produit_pre_rupture = []
produit_normal = []
for produit in tous_les_produits:
stock_actuel = calcul_stock_produit(produit)
stock_actuel.pop("image")
if stock_actuel["stockActuel"] == 0:
nombre_rupture += 1
produit_rupture.append(stock_actuel)
elif stock_actuel["stockActuel"] < produit.seuil_pre_rupture:
nombre_pre_rupture += 1
produit_pre_rupture.append(stock_actuel)
else:
nombre_normal += 1
produit_normal.append(stock_actuel)
return {
"nombre_rupture": nombre_rupture,
"nombre_pre_rupture": nombre_pre_rupture,
"nombre_normal": nombre_normal,
"produit_rupture": produit_rupture,
"produit_pre_rupture": produit_pre_rupture,
"produit_normale": produit_normal,
}
@login_required(login_url="authentification:login")
def index(request):
"""Vue pour la page d'accueil du dashboard.
Parameters
----------
request : HttpRequest
La requête HTTP entrante.
Returns
-------
HttpResponse
La réponse HTTP contenant la page d'accueil du dashboard.
"""
if request.user.groups.filter(name="Chauffeur").exists():
return redirect("gestion_vehicule:index")
if not request.user.groups.filter(name="Administration").exists():
return redirect("gestion_produit:index")
commandes_en_cours = Commander.objects.filter(livrer=False)
demandes_en_cours = Demander.objects.filter(
valider_par_chef=True, valider_par_logisticien=None
)
gestion_quantite_produit = dashboard_quantite_produit()
nombre_rupture = gestion_quantite_produit["nombre_rupture"]
nombre_pre_rupture = gestion_quantite_produit["nombre_pre_rupture"]
nombre_normal = gestion_quantite_produit["nombre_normal"]
return render(
request,
"index.html",
{
"nb_commande": len(commandes_en_cours),
"nb_demande": len(demandes_en_cours),
"nombre_rupture": nombre_rupture,
"nombre_pre_rupture": nombre_pre_rupture,
"nombre_normal": nombre_normal,
},
)
@login_required(login_url="login")
def produit_a_rendre(request): #noqa: ARG001
"""Vue pour obtenir la liste des équipements à rendre.
Cette vue est appelée via une requête AJAX et renvoie une liste
d'équipements qui doivent être rendus.
Parameters
----------
request : HttpRequest
La requête HTTP entrante.
Returns
-------
JsonResponse
Une réponse JSON contenant la liste des équipements à rendre.
"""
equipement_a_rendre = Demander.objects.filter(a_rendre=True, rendu=False)
liste_equipement = [
{
"id_demande": equipement.id,
"produit": equipement.produit.libelle,
"quantite": equipement.quantite,
"detenteur": (
f"{equipement.user.user.first_name} "
f"{equipement.user.user.last_name}"
),
"action": equipement.rendu,
}
for equipement in equipement_a_rendre
]
return JsonResponse(liste_equipement, safe=False)
@login_required(login_url="login")
@csrf_exempt
def produit_a_rendre_update(request):
"""Vue pour mettre à jour le statut des équipements à rendre.
Lorsqu'une requête POST est reçue, cette vue met à jour le statut
des équipements à rendre en fonction des données fournies dans la
requête.
Parameters
----------
request : HttpRequest
request.id_demande : int
L'identifiant de la demande d'équipement à mettre à jour.
request.action : bool
Le nouveau statut de rendu de l'équipement.
Returns
-------
JsonResponse
Une réponse JSON indiquant le succès de l'opération.
"""
if request.method == "POST":
data = json.loads(request.body)
for d in data:
demande = Demander.objects.get(id=d["id_demande"])
demande.rendu = d["action"]
demande.save()
return JsonResponse(
{"status": "success", "message": "Produits mis à jour"}
)
@login_required(login_url="login")
def liste_produit_rupture(request):
"""Vue pour obtenir la liste des produits en fonction de leur type.
Cette vue est appelée via une requête AJAX à chaque fois que l'on clique
sur un cadran (rupture, pré-rupture, en stock normal) et renvoie une liste
de produits en fonction du type spécifié dans les paramètres de la
requête.
Parameters
----------
request : HttpRequest
request.type : str
Le statut de produits à récupérer qui sont en "rupture",
"pre_rupture" ou "normal".
Returns
-------
JsonResponse
Une réponse JSON contenant la liste des produits correspondant
au type spécifié.
"""
type_encadrer = request.GET["type"]
dashboard_gestion = dashboard_quantite_produit()
donnees_charger = []
if type_encadrer == "rupture":
donnees_charger = dashboard_gestion["produit_rupture"]
elif type_encadrer == "pre_rupture":
donnees_charger = dashboard_gestion["produit_pre_rupture"]
elif type_encadrer == "normal":
donnees_charger = dashboard_gestion["produit_normale"]
return JsonResponse(donnees_charger, safe=False)
@login_required(login_url="login")
def liste_produit_commander(request):
"""Listez des produits commandés non encore livrés.
Parameters
----------
request : HttpRequest
La requête HTTP entrante.
Returns
-------
JsonResponse
Une réponse JSON contenant la liste des produits commandés
non encore livrés.
"""
commandes_en_cours = Commander.objects.filter(livrer=False)
ma_liste_commandes = [
{
"id_commande": commande.id,
"produit": commande.produit.libelle,
"quantite": commande.quantite_commander,
"date_commande": commande.date_commande,
"date_livraison": commande.date_livraison,
"fournisseur": commande.fournisseur.nom_entreprise,
"is_logisticien": (
request.user.profile.departement.
nom_departement == "Logistique"
),
}
for commande in commandes_en_cours
]
return JsonResponse(ma_liste_commandes, safe=False)
@login_required(login_url="login")
@csrf_exempt
def enregistrer_livraison_produit(request):
"""Enregistrez la livraison d'un produit commandé.
Lorsqu'une requête POST est reçue, cette vue met à jour le statut
de livraison du produit commandé en fonction de l'identifiant de la
commande fourni dans la requête.
Parameters
----------
request : HttpRequest
request.id_commande : int
L'identifiant de la commande dont la livraison doit
être enregistrée.
Returns
-------
JsonResponse
Une réponse JSON indiquant le succès ou l'échec de l'opération.
"""
if request.method == "POST":
id_commande = request.POST.get("id_commande")
try:
commande = Commander.objects.get(id=id_commande)
commande.livrer = True
commande.save()
return JsonResponse(
{
"status": "success",
"message": "Livraison enregistrée avec succès."
}
)
except Commander.DoesNotExist:
return JsonResponse(
{"status": "error", "message": "Commande non trouvée."}
)
return JsonResponse(
{"status": "error", "message": "Méthode non autorisée."}
)
@login_required(login_url="login")
def liste_demandes(request):
"""Listez des demandes en cours de validation.
Parameters
----------
request : HttpRequest
La requête HTTP entrante.
Returns
-------
JsonResponse
Une réponse JSON contenant la liste des demandes en cours
de validation.
"""
demandes_en_cours = Demander.objects.filter(
valider_par_chef=True, valider_par_logisticien=None
)
is_logisticien = (
request.user.profile.departement.nom_departement == "Logistique"
)
ma_liste_demandes = [
{
"id_demande": demande.id,
"demandeur": (
f"{demande.user.user.first_name} "
f"{demande.user.user.last_name}"
),
"produit": demande.produit.libelle,
"quantite": demande.quantite,
"motifs": demande.motifs,
"date_de_mise_a_dispo_souhaite": demande.date_de_mise_a_dispo_souhaite.strftime("%Y-%m-%d"),
"a_rendre": demande.a_rendre,
"valider_par_chef": demande.valider_par_chef,
"valider_par_logisticien": demande.valider_par_logisticien,
"is_logisticien": is_logisticien,
}
for demande in demandes_en_cours
]
return JsonResponse(ma_liste_demandes, safe=False)

16
SGL/wsgi.py Normal file
View File

@@ -0,0 +1,16 @@
"""
WSGI config for SGL project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "SGL.settings")
application = get_wsgi_application()