309 lines
8.9 KiB
Python
309 lines
8.9 KiB
Python
from django.db import models
|
||
from datetime import date
|
||
from django.utils import timezone
|
||
|
||
class Bailleur(models.Model):
|
||
"""Modèle représentant un bailleur de fonds pour les projets de recherche."""
|
||
nom_organisme = models.CharField(
|
||
max_length=200,
|
||
unique=True
|
||
)
|
||
contact = models.CharField(
|
||
max_length=100,
|
||
blank=True,
|
||
null=True
|
||
)
|
||
email = models.EmailField(
|
||
blank=True,
|
||
null=True
|
||
)
|
||
pays = models.CharField(
|
||
max_length=100,
|
||
blank=True,
|
||
null=True
|
||
)
|
||
|
||
def __str__(self):
|
||
return self.nom_organisme
|
||
|
||
class DomaineDeRecherche(models.Model):
|
||
"""Modèle représentant les domaines de recherche"""
|
||
|
||
DOMAINE_RECHERCHE = [
|
||
('sciences_sociales', 'Sciences sociales'),
|
||
('naturelles', 'Naturelles'),
|
||
('humaines', 'Humaines'),
|
||
('veterinaires', 'Vétérinaires')
|
||
]
|
||
|
||
nom = models.CharField(
|
||
max_length=100,
|
||
verbose_name="Domaine de recherche",
|
||
choices=DOMAINE_RECHERCHE,
|
||
primary_key=True
|
||
)
|
||
|
||
class Meta:
|
||
verbose_name = 'Domaine de recherche'
|
||
verbose_name_plural = 'Domaines de recherche'
|
||
|
||
def __str__(self):
|
||
return self.nom
|
||
|
||
class Projet(models.Model):
|
||
"""Modèle représentant un projet de recherche avec ses caractéristiques et son bailleur associé."""
|
||
TYPE_PROJET = [
|
||
('laboratoire', 'Laboratoire'),
|
||
('épidémiologie', 'Épidémiologie'),
|
||
('sciences sociales', 'Sciences sociales'),
|
||
('cliniques', 'Cliniques'),
|
||
('autre', 'Autre'),
|
||
]
|
||
id_projet = models.CharField(
|
||
max_length=100,
|
||
blank=True,
|
||
unique=True,
|
||
primary_key=True,
|
||
verbose_name="ID du projet"
|
||
)
|
||
nom_projet = models.CharField(
|
||
max_length=200,
|
||
verbose_name="Nom du projet"
|
||
)
|
||
date_debut = models.DateField(
|
||
verbose_name="Date de début"
|
||
)
|
||
date_fin = models.DateField(
|
||
verbose_name="Date de fin"
|
||
)
|
||
numero_convention = models.CharField(
|
||
max_length=100,
|
||
verbose_name="Numéro de convention"
|
||
)
|
||
description = models.TextField(
|
||
verbose_name="Description"
|
||
)
|
||
type_projet = models.CharField(
|
||
max_length=100,
|
||
choices=TYPE_PROJET,
|
||
default='épidémiologie',
|
||
verbose_name="Type de projet"
|
||
)
|
||
domaine_recherche = models.ManyToManyField(DomaineDeRecherche)
|
||
budget=models.DecimalField(
|
||
max_digits=12,
|
||
decimal_places=2,
|
||
verbose_name="Budget"
|
||
)
|
||
budget_RH = models.DecimalField(
|
||
max_digits=12,
|
||
decimal_places=2,
|
||
verbose_name="Budget RH"
|
||
)
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
bailleur = models.ForeignKey(
|
||
Bailleur,
|
||
on_delete=models.SET_NULL,
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="Bailleur de fonds"
|
||
)
|
||
|
||
@property
|
||
def statut(self):
|
||
if self.date_fin < date.today():
|
||
return "Terminé"
|
||
return "En cours"
|
||
|
||
@property
|
||
def avancement(self):
|
||
aujourd_hui = date.today()
|
||
if (self.date_debut and self.date_fin) and (self.date_debut < self.date_fin):
|
||
duree_projet = (self.date_fin - self.date_debut).days
|
||
temps_ecoule = (aujourd_hui - self.date_debut).days
|
||
if duree_projet > 0:
|
||
return round((temps_ecoule / duree_projet) * 100, 2)
|
||
|
||
return 0
|
||
|
||
def __str__(self):
|
||
return f"{self.nom_projet}"
|
||
|
||
class FinancementProjet(models.Model):
|
||
"""
|
||
Modèle représentant le financement d'un projet par un bailleur,
|
||
avec le pourcentage de contribution.
|
||
"""
|
||
projet = models.ForeignKey(
|
||
Projet,
|
||
on_delete=models.CASCADE
|
||
)
|
||
bailleur = models.ForeignKey(
|
||
Bailleur,
|
||
on_delete=models.CASCADE
|
||
)
|
||
pourcentage = models.DecimalField(
|
||
max_digits = 5,
|
||
decimal_places=2
|
||
)
|
||
|
||
class Meta:
|
||
unique_together = ('projet', 'bailleur')
|
||
|
||
def __str__(self):
|
||
return f"{self.bailleur.nom} - {self.projet.nom_projet} ({self.pourcentage}%)"
|
||
|
||
class DocumentProjet(models.Model):
|
||
"""Modèle représentant un document associé à un projet, avec des métadonnées et un fichier attaché."""
|
||
NOM_DOCUMENT_CHOICES = [
|
||
('protocole', 'Protocole d’étude'),
|
||
('ethique', "Approbation du comité d'éthique"),
|
||
('autorisation', 'Autorisation (DNLP)'),
|
||
('rapport_technique', 'Rapport technique'),
|
||
('rapport_financier', 'Rapport financier'),
|
||
('rapport_avancement', "Rapport d'avancement"),
|
||
('convention', 'Convention'),
|
||
('rapport_final', 'Rapport final'),
|
||
('autre', 'Autre'),
|
||
]
|
||
|
||
projet = models.ForeignKey(
|
||
Projet,
|
||
on_delete=models.CASCADE,
|
||
related_name='documents',
|
||
verbose_name="Projet"
|
||
)
|
||
date_ajout = models.DateTimeField(
|
||
auto_now_add=True,
|
||
verbose_name="Date d'ajout"
|
||
)
|
||
nom_document = models.CharField(
|
||
max_length = 100,
|
||
choices = NOM_DOCUMENT_CHOICES,
|
||
verbose_name="Type de document"
|
||
)
|
||
description = models.TextField(
|
||
blank = True,
|
||
verbose_name = "Description"
|
||
)
|
||
numero = models.CharField(
|
||
max_length = 100,
|
||
blank = True,
|
||
null = True,
|
||
verbose_name = "Numéro du document"
|
||
)
|
||
date_validite = models.DateField(
|
||
blank = True,
|
||
null = True,
|
||
verbose_name = "Date de validité"
|
||
)
|
||
fichier = models.FileField(
|
||
upload_to = 'documents_projets/',
|
||
verbose_name = "Fichier à télécharger"
|
||
)
|
||
|
||
def __str__(self):
|
||
return f"{self.nom_document} ({self.projet})"
|
||
|
||
class ActiviteProjet(models.Model):
|
||
"""Modèle représentant le planning d'un projet, avec des activités associées et un statut."""
|
||
projet = models.ForeignKey(
|
||
Projet,
|
||
on_delete = models.CASCADE,
|
||
verbose_name = "Projet"
|
||
)
|
||
titre = models.CharField(
|
||
max_length = 200,
|
||
verbose_name = "Titre de l'activité"
|
||
)
|
||
description = models.TextField(
|
||
blank = True,
|
||
null = True,
|
||
verbose_name = "Description de l'activité"
|
||
)
|
||
date_debut = models.DateField(verbose_name="Date de début")
|
||
date_fin = models.DateField(verbose_name="Date de fin")
|
||
annuler = models.BooleanField(
|
||
default = False,
|
||
verbose_name = "Annuler l'activité"
|
||
)
|
||
motif_annulation = models.TextField(
|
||
blank = True,
|
||
null = True,
|
||
verbose_name = "Motif d'annulation"
|
||
)
|
||
|
||
motif_changement_budget = models.TextField(
|
||
blank = True,
|
||
null = True,
|
||
verbose_name = "Motif de changement de budget"
|
||
)
|
||
budget_prevu = models.DecimalField(
|
||
max_digits = 15,
|
||
decimal_places = 2,
|
||
default = 0,
|
||
verbose_name = "Budget prévu"
|
||
)
|
||
budget_depense = models.DecimalField(
|
||
max_digits = 15,
|
||
decimal_places = 2,
|
||
default = 0,
|
||
verbose_name = "Budget dépensé"
|
||
)
|
||
besoin_ressource_materielle = models.TextField(
|
||
verbose_name="Besoin de ressources matérielles"
|
||
)
|
||
|
||
@property
|
||
def statut(self):
|
||
today = timezone.now().date()
|
||
if not self.annuler:
|
||
if self.date_fin < today:
|
||
return 'Terminé'
|
||
elif self.date_debut > today:
|
||
return 'À venir'
|
||
else:
|
||
return 'En cours'
|
||
else:
|
||
return 'Annulé'
|
||
|
||
def __str__(self):
|
||
return f"{self.titre} ({self.projet.nom_projet})"
|
||
|
||
# class LivrableAttendu(models.Model):
|
||
# """
|
||
# Modèle représentant un livrable attendu pour une activité de projet,
|
||
# avec des critères de validation.
|
||
# """
|
||
# activite = models.ForeignKey(
|
||
# ActiviteProjet,
|
||
# on_delete = models.CASCADE,
|
||
# related_name = "livrables_attendus"
|
||
# )
|
||
# nom = models.CharField(max_length=255)
|
||
|
||
# def __str__(self):
|
||
# return f"{self.nom} (Activité: {self.activite.titre})"
|
||
|
||
class LivrablesLivres(models.Model):
|
||
"""Modèle représentant un livrable livré pour une activité de projet."""
|
||
activite = models.ForeignKey(
|
||
ActiviteProjet,
|
||
on_delete = models.CASCADE
|
||
)
|
||
# nom = models.ForeignKey(
|
||
# LivrableAttendu,
|
||
# on_delete = models.CASCADE
|
||
# )
|
||
nom = models.CharField(
|
||
max_length=255,
|
||
verbose_name="Nom du livrable"
|
||
)
|
||
|
||
fichier = models.FileField(
|
||
upload_to = 'fichier_livrables/',
|
||
blank = True,
|
||
null = True
|
||
)
|
||
def __str__(self):
|
||
return self.nom |