Fonctionnalite : Ajout de la liste des contrats

This commit is contained in:
2026-04-30 13:28:57 +02:00
parent c0cdca48fa
commit 4146563f41
264 changed files with 43484 additions and 26 deletions

View File

6
gestion_projet/admin.py Normal file
View File

@@ -0,0 +1,6 @@
from django.contrib import admin
from .models import DomaineDeRecherche
@admin.register(DomaineDeRecherche)
class DomaineDeRecherche(admin.ModelAdmin):
list_display = ('nom',)

176
gestion_projet/forms.py Normal file
View File

@@ -0,0 +1,176 @@
from django import forms
from gestion_projet.models import Projet
from .models import (
ActiviteProjet,
Bailleur,
DocumentProjet,
FinancementProjet,
LivrablesLivres,
DomaineDeRecherche
)
class ProjetForm(forms.ModelForm):
"""Formulaire de création et de modification d'un projet, avec validation des dates et personnalisation des champs."""
class Meta:
model = Projet
fields = (
'id_projet',
'nom_projet',
'date_debut',
'date_fin',
'numero_convention',
'domaine_recherche',
'type_projet',
'budget',
'budget_RH',
'description'
)
# domaine_recherche = forms.ModelMultipleChoiceField(
# queryset=DomaineDeRecherche.objects.all(),
# to_field_name="nom",
# required=False
# )
widgets = {
'id_projet': forms.TextInput(attrs={'class': "form-control"}),
'nom_projet': forms.TextInput(attrs={'class': "form-control"}),
'numero_convention': forms.TextInput(attrs={'class': "form-control"}),
'domaine_recherche': forms.SelectMultiple(attrs={'class': "form-control"}),
'type_projet': forms.Select(attrs={'class': "form-select"}),
'budget': forms.NumberInput(attrs={'class': "form-control"}),
'budget_RH': forms.NumberInput(attrs={'class': "form-control"}),
'description': forms.Textarea(attrs={'class': "form-control"}),
'date_debut': forms.DateInput(attrs={'type': 'date', 'class': "form-control"}),
'date_fin': forms.DateInput(attrs={'type': 'date', 'class': "form-control"}),
}
class BailleurForm(forms.ModelForm):
"""
Formulaire de création et de modification d'un bailleur,
avec validation des champs et personnalisation des labels.
"""
class Meta:
model = Bailleur
fields = ('nom_organisme', 'contact', 'email', 'pays')
widgets = {
'nom_organisme':forms.TextInput(attrs={
'class':'form-control',
}),
'contact':forms.TextInput(attrs={
'class':'form-control',
}),
'email':forms.TextInput(attrs={
'class':'form-control',
}),
'pays':forms.TextInput(attrs={
'class':'form-control',
}),
}
class DocumentProjetForm(forms.ModelForm):
"""
Formulaire pour ajouter ou modifier un document associé à un projet,
avec validation des champs et personnalisation des labels.
"""
class Meta:
model = DocumentProjet
fields = [
'nom_document',
'numero',
'date_validite',
'fichier',
'description'
]
widgets = {
'nom_document': forms.Select(attrs={'class': 'form-select'}),
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
'numero': forms.TextInput(attrs={'class': 'form-control'}),
'date_validite': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'fichier': forms.ClearableFileInput(attrs={'class': 'form-control'}),
}
class ActiviteProjetForm(forms.ModelForm):
"""Formulaire pour créer ou modifier une activité de projet, avec validation des champs et personnalisation des widgets."""
class Meta:
model = ActiviteProjet
fields = (
'titre',
'date_debut',
'date_fin',
'besoin_ressource_materielle',
'budget_prevu',
'description',
)
widgets = {
'titre':forms.TextInput(attrs={
'class':'form-control',
'placeholder':'Titre de lactivité'
}),
'description':forms.Textarea(attrs={
'class':'form-control',
'rows':3,
'placeholder':'Description de lactivité'
}),
'date_debut':forms.DateInput(attrs={
'class':'form-control',
'type':'date'
}),
'date_fin':forms.DateInput(attrs={
'class':'form-control',
'type':'date'
}),
'besoin_ressource_materielle': forms.Textarea(attrs={
'class':'form-control',
'rows':3,
'placeholder':'Besoin de ressources matérielles'
}),
'budget_prevu': forms.NumberInput(attrs={
'class':'form-control',
'placeholder':'Budget prévu'
}),
}
class FinancementProjetFrom(forms.ModelForm):
"""Formulaire pour créer ou modifier le financement relatif à un projet."""
class Meta:
model = FinancementProjet
fields = (
'projet',
'bailleur',
'pourcentage',
)
widgets = {
'projet':forms.Select(attrs={
'class':'form-select',
}),
'bailleur':forms.Select(attrs={
'class':'form-select',
}),
'pourcentage':forms.NumberInput(attrs={
'class':'form-control',
}),
}
class LivrablesLivresForm(forms.ModelForm):
"""Formulaire pour créer ou modifier un livrable livré dans le cadre d'une activité de projet."""
class Meta:
model = LivrablesLivres
fields = (
'activite',
'nom',
'fichier',
)
widgets = {
'activite': forms.Select(attrs={
'class':'form-select',
}),
'nom': forms.TextInput(attrs={
'class':'form-control',
'placeholder':'Nom du livrable'
}),
'fichier': forms.ClearableFileInput(attrs={
'class':'form-control',
}),
}

View File

@@ -0,0 +1,107 @@
# Generated by Django 5.2.13 on 2026-04-17 12:03
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='ActiviteProjet',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('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(decimal_places=2, default=0, max_digits=15, verbose_name='Budget prévu')),
('budget_depense', models.DecimalField(decimal_places=2, default=0, max_digits=15, verbose_name='Budget dépensé')),
('besoin_ressource_materielle', models.TextField(verbose_name='Besoin de ressources matérielles')),
],
),
migrations.CreateModel(
name='Bailleur',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('nom_organisme', models.CharField(max_length=200, unique=True)),
('contact', models.CharField(blank=True, max_length=100, null=True)),
('email', models.EmailField(blank=True, max_length=254, null=True)),
('pays', models.CharField(blank=True, max_length=100, null=True)),
],
),
migrations.CreateModel(
name='DomaineDeRecherche',
fields=[
('nom', models.CharField(choices=[('sciences_sociales', 'Sciences sociales'), ('naturelles', 'Naturelles'), ('humaines', 'Humaines'), ('veterinaires', 'Vétérinaires')], max_length=100, primary_key=True, serialize=False, verbose_name='Domaine de recherche')),
],
options={
'verbose_name': 'Domaine de recherche',
'verbose_name_plural': 'Domaines de recherche',
},
),
migrations.CreateModel(
name='LivrablesLivres',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('nom', models.CharField(max_length=255, verbose_name='Nom du livrable')),
('fichier', models.FileField(blank=True, null=True, upload_to='fichier_livrables/')),
('activite', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_projet.activiteprojet')),
],
),
migrations.CreateModel(
name='Projet',
fields=[
('id_projet', models.CharField(blank=True, max_length=100, primary_key=True, serialize=False, unique=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(choices=[('laboratoire', 'Laboratoire'), ('épidémiologie', 'Épidémiologie'), ('sciences sociales', 'Sciences sociales'), ('cliniques', 'Cliniques'), ('autre', 'Autre')], default='épidémiologie', max_length=100, verbose_name='Type de projet')),
('budget', models.DecimalField(decimal_places=2, max_digits=12, verbose_name='Budget')),
('budget_RH', models.DecimalField(decimal_places=2, max_digits=12, verbose_name='Budget RH')),
('created_at', models.DateTimeField(auto_now_add=True)),
('bailleur', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='gestion_projet.bailleur', verbose_name='Bailleur de fonds')),
('domaine_recherche', models.ManyToManyField(to='gestion_projet.domainederecherche')),
],
),
migrations.CreateModel(
name='DocumentProjet',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date_ajout', models.DateTimeField(auto_now_add=True, verbose_name="Date d'ajout")),
('nom_document', models.CharField(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')], max_length=100, verbose_name='Type de document')),
('description', models.TextField(blank=True, verbose_name='Description')),
('numero', models.CharField(blank=True, max_length=100, 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')),
('projet', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documents', to='gestion_projet.projet', verbose_name='Projet')),
],
),
migrations.AddField(
model_name='activiteprojet',
name='projet',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_projet.projet', verbose_name='Projet'),
),
migrations.CreateModel(
name='FinancementProjet',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('pourcentage', models.DecimalField(decimal_places=2, max_digits=5)),
('bailleur', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_projet.bailleur')),
('projet', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_projet.projet')),
],
options={
'unique_together': {('projet', 'bailleur')},
},
),
]

View File

309
gestion_projet/models.py Normal file
View File

@@ -0,0 +1,309 @@
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

View File

@@ -0,0 +1,19 @@
const boutonEnregistrerProjet = $("btnEnregistrerProjet");
boutonEnregistrerProjet.addEventListener("click", function() {
const formulaire = $("formCreationProjet");
const formData = new FormData(formulaire);
fetch(formulaire.action, {
method: "POST",
body: formData,
headers: {
"X-CSRFToken": formData.get("csrfmiddlewaretoken")
}
})
.then(response => {
if (response.ok) {
window.location.reload();
alert("Projet enregistré avec succès !");
}
});
});

View File

@@ -23,29 +23,25 @@ btnEnregistrerBailleur.addEventListener('click', function() {
});
});
document.addEventListener("DOMContentLoaded", function () {
table = new Tabulator("#table-bailleurs", {
ajaxURL: "/gestion-projet/bailleurs/",
layout: "fitColumns",
pagination: "local",
paginationSize: 5,
table = new Tabulator("#table-bailleurs", {
ajaxURL: "/gestion-projet/bailleurs/",
layout: "fitColumns",
pagination: "local",
paginationSize: 5,
columns: [
{title: "#", formatter: "rownum", width: 60},
{title: "Organisme", field: "nom_organisme"},
{title: "Contact", field: "contact"},
{title: "Email", field: "email"},
{title: "Pays", field: "pays"},
],
rowDblClick: function(e, row) {
const data = row.getData();
columns: [
{title: "#", formatter: "rownum", width: 60},
{title: "Organisme", field: "nom_organisme"},
{title: "Contact", field: "contact"},
{title: "Email", field: "email"},
{title: "Pays", field: "pays"},
],
rowDblClick: function(e, row) {
const data = row.getData();
if (confirm(`Voulez-vous vraiment supprimer ${data.nom_organisme} ?`)) {
supprimerBailleur(data.id);
}
if (confirm(`Voulez-vous vraiment supprimer ${data.nom_organisme} ?`)) {
supprimerBailleur(data.id);
}
});
});
}
});

View File

@@ -0,0 +1,22 @@
const btn_enregistrer_financement = document.getElementById('btn_enregistrer_financement');
btn_enregistrer_financement.addEventListener('click', function() {
const form = document.getElementById('form_financement');
const formData = new FormData(form);
fetch(form.action, {
method: 'POST',
body: formData,
headers: {
'X-CSRFToken': formData.get('csrfmiddlewaretoken')
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert(data.message);
window.location.reload();
}else {
alert(data.message);
}
});
});

View File

@@ -0,0 +1,64 @@
const $ = (element) => document.getElementById(element)
const url_liste_projet = $("tableau-liste-projet").dataset.url;
const tableau_liste_projet = new Tabulator("#tableau-liste-projet", {
fitColumns: true,
responsiveLayout : true,
columns: [
{title: "Projet", field: "nom_projet"},
{title: "Source de financement", field: "source_financement"},
{title: "Budget Total", field: "budget"},
{title: "Budget RH", field: "budget_RH"},
{title: "Avancement", field: "avancement", formatter: "progress"},
{title: "Statut", field: "statut"},
],
ajaxURL: url_liste_projet
})
const employes_affectes_projet = new Tabulator("#employes_affectes_projet", {
columns: [
{title: "Employé", field: "employe"},
{title: "Pourcentage d'affectation", field: "pourcentage_affectation"},
],
placeholder: "Aucun employé affecté pour ce projet",
})
const bailleurs_projet = new Tabulator("#bailleurs_projet", {
columns: [
{title: "Bailleur", field: "bailleur"},
{title: "Pourcentage de financement", field: "pourcentage_financement"},
],
placeholder: "Aucun bailleur attribué pour ce projet",
})
tableau_liste_projet.on("rowClick", function (row, rowData) {
const data = rowData.getData();
const modal = new bootstrap.Modal($("modalDetailProjet"));
$("detail_id_projet").value = data.id_projet;
$("detail_nom_projet").value = data.nom_projet;
$("detail_date_debut").value = data.date_debut;
$("detail_date_fin").value = data.date_fin;
$("detail_numero_convention").value = data.numero_convention;
$("detail_type_projet").value = data.type_projet;
Array.from($("detail_domaine_recherche").options).forEach(option => {
if (data.domaine_recherche.includes(option.value)) {
option.selected = true;
} else {
option.selected = false;
}
});
$("detail_budget").value = data.budget;
$("detail_budget_rh").value = data.budget_RH;
$("detail_description").value = data.description;
$("detail_statut").value = data.statut;
employes_affectes_projet.setData(`projet/liste-employes-par-projet/${$("detail_id_projet").value}`);
bailleurs_projet.setData(`projet/bailleurs/${data.id_projet}/`);
modal.show();
})
// $('detail-projet-form').addEventListener('submit', (e) => {
// e.preventDefault();
// new FormData($("detail-projet-form"));
// })

View File

@@ -0,0 +1,20 @@
const urlListeDocument = document.getElementById('listeDocuments').dataset.urllistedocument;
const table_liste_documents = new Tabulator(document.getElementById('listeDocuments'), {
layout: "fitColumns",
placeholder: "Aucun document trouvé",
columns: [
{ title: "Nom du Document", field: "nom_document" },
{ title: "Numéro", field: "numero" },
{ title: "Date de Validité", field: "date_validite", formatter: "datetime", formatterParams: {
inputFormat: "yyyy-MM-dd",
outputFormat: "dd/MM/yyyy"
}
},
{ title: "Lien vers le Document", field: "lien_document", formatter:"link", formatterParams:{
target:"_blank",
}
},
],
ajaxURL: urlListeDocument,
});

View File

@@ -0,0 +1,59 @@
const $ = (element) => document.getElementById(element)
const url_liste_activite = $("tableau-liste-activite").dataset.urllisteactivite
const tableau_liste_activite = new Tabulator("#tableau-liste-activite", {
columns: [
{title: "Activité", field: "titre"},
{title: "Date début", field: "date_debut"},
{title: "Date fin", field: "date_fin"},
{title: "Budget prévu", field: "budget_prevu"},
{title: "Budget dépensé", field: "budget_depense"},
{title: "Motif de changement de budget", field: "motif_changement_budget"},
{title: "Statut", field: "statut"},
],
ajaxURL: url_liste_activite,
})
tableau_liste_activite.on("rowClick", function (row, rowData) {
const data = rowData.getData();
$("idDetailActivite").value = data.id;
$("titreDetailActivite").value = data.titre;
$("descriptionDetailActivite").value = data.description;
$("date_debutDetailActivite").value = data.date_debut;
$("date_finDetailActivite").value = data.date_fin;
$("statutDetailActivite").value = data.statut;
$("budget_prevuDetailActivite").value = data.budget_prevu;
$("besoin_ressources_materiellesDetailActivite").value = data.besoin_ressource_materielle;
const modal = new bootstrap.Modal($("modalDetailActivite"));
modal.show();
fetch(`liste-des-livrables/${data.id}/`)
.then(response => response.json())
.then(livrables => {
tableau_liste_livrable.setData(livrables);
})
})
const tableau_liste_livrable = new Tabulator("#listeLivrables", {
columns: [
{title: "Livrable", field: "titre"},
{title: "Lien du livrable", field: "lien", formatter: "link", formatterParams: {blank: true}},
],
placeholder: "Aucun livrable trouvé",
})
$("btnMiseAJourDepense").addEventListener("click", function() {
const modal = new bootstrap.Modal($("modalDepenseActivite"));
bootstrap.Modal.getOrCreateInstance($("modalDetailActivite")).hide();
const idActivite = $("idDetailActivite").value;
const budgetPrevu = $("budget_prevuDetailActivite").value;
$("id_activite_depense").value = idActivite;
$("budget_prevu").value = budgetPrevu;
modal.show();
})
$("btnAnnulerActivite").addEventListener("click", function(event) {
new bootstrap.Modal($("modalAnnulerActivite")).show();
$("id_activite_annulation").value = $("idDetailActivite").value;
bootstrap.Modal.getOrCreateInstance($("modalDetailActivite")).hide();
})

View File

@@ -0,0 +1,37 @@
{% extends "BASE.html" %}
{% load static %}
{% block 'titre_page' %} Gestion des projets {% endblock %}
{% block 'contenu' %}
<button class="btn btn-primary mb-3">
<i class="bi bi-caret-left-fill"></i> Retour
</button>
{% if messages %}
{% for message in messages %}
<div class="alert alert-{% if message.tags == "error" %}danger{% else %}success{% endif %} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endif %}
<div class="row d-flex justify-content-center">
<div class="col-8 card bordered rounded py-4 px-2 ">
<h5>Ajout du financement au projet (Nom du projet ici)</h5>
<hr>
<form method="POST" action="{% url 'gestion_projet:creation-projet' %}">
{% csrf_token %}
{{ formulaire_creation_projet.as_p }}
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-danger">Annuler</button>
<a href="{% url 'gestion_projet:ajouter_financement' %}" class="btn btn-primary ms-2">Enregistrer et ajouter un financement</a>
</div>
</form>
</div>
</div>
{% endblock %}
{% block 'modal' %}
{% include "gestion_projet/parts/modalAjoutProjet.html" %}
{% endblock %}
{% block 'js' %}
<script type="text/javascript" src="{% static 'gestion_projet/js/index.js' %}"></script>
{% endblock %}

View File

@@ -0,0 +1,32 @@
{% extends "BASE.html" %}
{% load static %}
{% block 'titre_page' %} Gestion des projets {% endblock %}
{% block 'contenu' %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endif %}
{% comment %} <h3>Enregistrement d'un nouveau projet</h3> {% endcomment %}
<div class="row d-flex justify-content-center">
<div class="col-8 card bordered rounded py-4 px-2 ">
<h5>Enregistrement d'un nouveau projet</h5>
<hr>
<form method="POST" action="{% url 'gestion_projet:creation-projet' %}">
{% csrf_token %}
{{ formulaire_creation_projet.as_p }}
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-danger">Annuler</button>
<button class="btn btn-primary ms-2">Enregistrer</button>
</div>
</form>
</div>
</div>
{% endblock %}
{% block 'modal' %}
{% endblock %}
{% block 'js' %}
{% endblock %}

View File

@@ -0,0 +1,61 @@
{% extends "BASE.html" %}
{% load static %}
{% load tags_personnaliser %}
{% block 'titre_page' %} Gestion des projets {% endblock %}
{% block 'contenu' %}
<h3>Gestion des projets</h3>
{% if messages %}
{% for message in messages %}
<div class="alert alert-{% if message.tags == "error" %}danger{% else %}success{% endif %} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endif %}
<div class="row">
<div class="col text-white bg-success d-flex flex-column justify-content-center align-items-center border rounded p-4">
<span class="fs-5">Projets en cours</span>
<h3>{{projet_en_cours}}</h3>
</div>
<div class="col text-white bg-success d-flex flex-column justify-content-center align-items-center border rounded p-4 mx-2">
<span class="fs-5">Budget Total (GNF)</span>
<h3>{{budget_total}}</h3>
</div>
<div class="col text-white bg-success d-flex flex-column justify-content-center align-items-center border rounded p-4">
<span class="fs-5">Personnel sous projet</span>
<h3>{{nombre_personnel}}</h3>
</div>
</div>
<div class="row mt-4">
<div class="col d-flex justify-content-between align-items-center mb-3">
<h5 class="mb-4" >La liste des projets </h5>
{% if user|has_group:"ressource_humaine" %}
<div>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalProjet">
<i class="bi bi-plus-circle"></i> Ajouter un projet
</button>
<button class="btn btn-info" data-bs-toggle="modal" data-bs-target="#modalBailleur">
<i class="bi bi-person"></i> Ajouter un bailleur
</button>
</div>
{% endif %}
</div>
<div class="row">
<div class="col">
<div id="tableau-liste-projet" data-url="{% url 'gestion_projet:liste-projet' %}"></div>
</div>
</div>
</div>
{% endblock %}
{% block 'modal' %}
{% include "gestion_projet/parts/modalAjoutProjet.html" %}
{% include "gestion_projet/parts/modalFinancement.html" %}
{% include "gestion_projet/parts/creation_bailleur.html" %}
{% include "gestion_projet/parts/modalDetailProjet.html" %}
{% endblock %}
{% block 'js' %}
<script type="text/javascript" src="{% static 'gestion_projet/js/index.js' %}"></script>
<script type="text/javascript" src="{% static 'gestion_projet/js/creation_projet.js' %}"></script>
<script type="text/javascript" src="{% static 'gestion_projet/js/enregistrement_bailleur.js' %}"></script>
<script type="text/javascript" src="{% static 'gestion_projet/js/enregistrement_financement.js' %}"></script>
{% endblock %}

View File

@@ -48,4 +48,3 @@
</div>
</div>
</div>

View File

@@ -0,0 +1,16 @@
<div class="modal fade" id="modalListeDocument" tabindex="-1" aria-labelledby="modalListeDocumentLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title fw-bold" id="modalListeDocumentLabel">Liste des Documents</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-4">
<div id="listeDocuments" data-urllistedocument="{% url 'gestion_projet:liste-documents-projet' %}"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,20 @@
<div class="modal fade" id="modalAjoutActivite" tabindex="-1" aria-labelledby="modalAjoutActiviteLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalAjoutActiviteLabel">Ajouter une Activité</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form method="POST" action="{% url 'gestion_projet:ajouter-activite' %}">
{% csrf_token %}
<div class="modal-body">
{{ form_ajout_activite.as_p }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
<button type="submit" class="btn btn-primary">Ajouter</button>
</div>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,20 @@
<div class="modal fade" id="modalAjoutDocument" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Ajouter un Document</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST" action="{% url 'gestion_projet:ajouter-document' %}" enctype="multipart/form-data">
{% csrf_token %}
<div class="modal-body">
{{ form_ajout_document.as_p }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
<button type="submit" class="btn btn-primary">Ajouter</button>
</div>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,20 @@
<div class="modal fade" id="modalAjouterLivrable" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Ajouter un livrable - (Nom du livrable)</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form method="post" action="{% url 'gestion_projet:ajouter-livrable' %}" enctype="multipart/form-data">
{% csrf_token %}
{{ form_ajout_livrable.as_p }}
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
<button type="submit" class="btn btn-success">Enregistrer</button>
</div>
</form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,21 @@
<!-- Modale Projet -->
<div class="modal fade" id="modalProjet" tabindex="-1" aria-labelledby="modalProjetLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-orange-dark">
<h5 class="modal-title" id="modalProjetLabel">Ajouter un projet</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
</div>
<div class="modal-body p-3">
<form method="POST" id="formCreationProjet" action="{% url 'gestion_projet:creation-projet' %}">
{% csrf_token %}
{{ formulaire_creation_projet.as_p }}
</form>
</div>
<div class="modal-footer">
<button type="submit" id="btnEnregistrerProjet" class="btn btn-success">Enregistrer</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,26 @@
<div class="modal fade" id="modalAnnulerActivite" tabindex="-1" aria-labelledby="modalAnnulerActiviteLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title fw-bold" id="modalAnnulerActiviteLabel">Annuler l'activité</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-4">
<form method="POST" action="{% url 'gestion_projet:annuler-activite' %}">
{% csrf_token %}
<input type="hidden" name="id_activite" id="id_activite_annulation">
<div class="mb-3">
<label for="motif_annulation" class="form-label">Motif d'annulation</label>
<textarea class="form-control" name="motif_annulation" id="motif_annulation" rows="4" required></textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
<button type="submit" class="btn btn-danger">
<i class="bi bi-x-circle"></i> Confirmer l'annulation
</button>
</div>
</form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,58 @@
<div class="modal fade" id="modalDetailActivite" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-orange-dark">
<h5 class="modal-title">Détails de l'activité</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="row g-3">
<div class="">
<input type="hidden" id="idDetailActivite">
<div class="form-group mb-2">
<label>Titre :</label>
<input type="text" class="form-control" id="titreDetailActivite">
</div>
<div class="form-group mb-2">
<label>Description :</label>
<textarea class="form-control" id="descriptionDetailActivite"></textarea>
</div>
<div class="form-group mb-2">
<label>Date de début :</label>
<input type="date" class="form-control" id="date_debutDetailActivite">
</div>
<div class="form-group mb-2">
<label>Date de fin :</label>
<input type="date" class="form-control" id="date_finDetailActivite">
</div>
<div class="form-group mb-2">
<label>Statut:</label>
<input type="text" class="form-control" id="statutDetailActivite">
</div>
<div class="form-group mb-2">
<label>Budget prévu :</label>
<input type="number" class="form-control" id="budget_prevuDetailActivite">
</div>
<div class="form-group mb-2">
<label>Besoin de ressources matérielles:</label>
<textarea class="form-control" id="besoin_ressources_materiellesDetailActivite"></textarea>
</div>
<p><strong>Liste des livrables :</strong></p>
<div id="listeLivrables"></div>
<button class="btn btn-danger d-block mx-auto" id="btnAnnulerActivite">
Annuler cette activité
</button>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-success" id="btnMiseAJourDepense">
<i class="bi bi-plus-circle"></i> Mise à jour du budget
</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalAjouterLivrable">
<i class="bi bi-plus-circle"></i> Ajouter un livrable
</button>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,115 @@
{% load tags_personnaliser %}
<div class="modal fade" id="modalDetailProjet{{ activite.id }}" tabindex="-1">
<div class="modal-dialog ">
<div class="modal-content">
<div class="modal-header ">
<h5 class="modal-title">Détails du projet </h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="row g-3">
<div class="col" id="detail-projet-container">
<form method='post' action="{% url 'gestion_projet:mises-a-jour-projet' %}" id="detail-projet-form">
{% csrf_token %}
<div class="form-group mb-2">
<label>Id projet:</label>
<input type="text" class="form-control" id="detail_id_projet" name='id_projet' readonly>
</div>
<div class="form-group mb-2">
<label> Nom projet :</label>
<input type="text" class="form-control" id="detail_nom_projet" name='nom_projet'>
</div>
<div class="form-group mb-2">
<label>Numero de convention:</label>
<input type="text" class="form-control" id="detail_numero_convention" name="numero_convention">
</div>
<div class="form-group mb-2">
<label>Date de début :</label>
<input type="date" class="form-control" id="detail_date_debut" name='date_debut'>
</div>
<div class="form-group mb-2">
<label>Date de fin :</label>
<input type="date" class="form-control" id="detail_date_fin" name='date_fin'>
</div>
<div class="form-group mb-2">
<label> Type de projet </label>
<select class="form-select" id="detail_type_projet" name='type_projet'>
<option value="laboratoire">Laboratoire</option>
<option value="épidémiologie">Épidémiologie</option>
<option value="sciences sociales">Sciences sociales</option>
<option value="cliniques">Cliniques</option>
<option value="autre">Autre</option>
</select>
</div>
<div class="form-group mb-2">
<label> Domaine de recherche </label>
<select class="form-select" multiple id="detail_domaine_recherche" name="domaine_recherche">
<option value="sciences_sociales">Sciences sociales</option>
<option value="naturelles">Naturelles</option>
<option value="humaines">Humaines</option>
<option value="veterinaires">Vétérinaires</option>
</select>
</div>
<div class="form-group mb-2">
<label>Budget :</label>
<input type="number" class="form-control" id="detail_budget" name='budget'>
</div>
<div class="form-group mb-2">
<label>Budget RH:</label>
<input type="number" class="form-control" id="detail_budget_rh" name='budget_RH'>
</div>
<div class="form-group mb-2">
<label>Description :</label>
<textarea class="form-control" id="detail_description" name='description'></textarea>
</div>
<div class="form-check-group mb-2">
<label class="form-check-label">Statut :</label>
<input type="text" class="form-control" id="detail_statut" readonly>
</div>
<button type='submit' class="btn btn-warning">
<i class="bi bi-pencil"></i> Modifier Projet
</button>
</form>
<hr class="my-4">
<div class="accordion" id="accordionDetailProjet">
<div class="accordion-item">
<h2 class="accordion-header" id="employesAffectes">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
Employés Affectés
</button>
</h2>
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="employesAffectes" data-bs-parent="#accordionDetailProjet">
<div class="accordion-body">
<div id="employes_affectes_projet"></div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="bailleursProjet">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
Liste des bailleurs
</button>
</h2>
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="bailleursProjet" data-bs-parent="#accordionDetailProjet">
<div class="accordion-body">
<div id="bailleurs_projet"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
{% if user|has_group:"ressource_humaine" %}
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#modal_ajout_financement">
<i class="bi bi-plus-circle"></i> Ajouter un financement
</button>
{% endif %}
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
<i class="bi bi-x-circle"></i> Fermer
</button>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,20 @@
<div class="modal fade" id="modal_ajout_financement" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Ajout de financement</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
</div>
<div class="modal-body">
<form method="POST" id="form_financement" action="{% url 'gestion_projet:ajouter_financement' %}">
{% csrf_token %}
{{ form_ajout_financement.as_p }}
</form>
</div>
<div class="modal-footer">
<button type="submit" id="btn_enregistrer_financement" class="btn btn-success">Enregistrer</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,36 @@
<div class="modal fade" id="modalDepenseActivite" tabindex="-1" aria-labelledby="modalDepenseActiviteLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalDepenseActiviteLabel">
<i class="bi bi-cash-stack me-2"></i> Mise à jour des dépenses
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form method="POST" action="{% url 'gestion_projet:mettre-a-jour-depense' %}">
{% csrf_token %}
<input type="hidden" name="id_activite" id="id_activite_depense">
<div class="mb-2">
<label class="form-label">Budget prévu (GNF)</label>
<input type="number" class="form-control" name="budget_prevu" id="budget_prevu" value="" disabled>
</div>
<div class="mb-2">
<label for="budget_depense" class="form-label">Montant dépensé (GNF)</label>
<input type="number" name="budget_depense" id="budget_depense" class="form-control" required>
</div>
<div class="mb-2">
<label class="form-label">Motif de différence</label>
<textarea class="form-control" name="motif" rows="3"></textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
<button type="submit" class="btn btn-success">
<i class="bi bi-save"></i> Enregistrer
</button>
</div>
</form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,64 @@
{% extends "BASE.html" %}
{% load static %}
{% block 'titre_page' %} Gestion des projets {% endblock %}
{% block 'contenu' %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-{% if message.tags == "error" %}danger{% else %}success{% endif %} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endif %}
<h5 class="mb-4 fw-bold text-uppercase text-orange-dark">
<i class="bi bi-kanban-fill me-2"></i> Suivi des Activités ({{ nom_projet }} )
</h5>
<div class="row d-flex justify-content-center mb-4">
<div class="col text-white bg-success d-flex flex-column justify-content-center align-items-center border rounded p-4">
<span class="fs-5">Budget Total (GNF)</span>
<h3>{{ budget_total }}</h3>
</div>
<div class="col text-white bg-info d-flex flex-column justify-content-center align-items-center border rounded mx-3 p-4">
<span class="fs-5">Budget RH (GNF)</span>
<h3>{{ budget_RH }}</h3>
</div>
<div class="col text-white bg-warning d-flex flex-column justify-content-center align-items-center border rounded p-4">
<span class="fs-5">Budget Dépensé (GNF)</span>
<h3>{{budget_depense}}</h3>
</div>
</div>
<div class="row">
<div class="mt-4 d-flex justify-content-between mb-3">
<h5><i class="bi bi-people"></i> La liste des Activités</h5>
<div>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalAjoutActivite">
<i class="bi bi-plus-circle me-2"></i> Ajouter une Activité
</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalAjoutDocument">
<i class="bi bi-plus-circle me-2"></i> Ajouter un document
</button>
<button class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#modalListeDocument">
Documents du projet
</button>
</div>
</div>
</div>
<div class="table-responsive">
<div id="tableau-liste-activite" data-urllisteactivite="{% url 'gestion_projet:liste-activites-projet' %}"></div>
</div>
{% endblock %}
{% block 'modal' %}
{% include "gestion_projet/parts/modalAjoutActivite.html" %}
{% include "gestion_projet/parts/modalDetailActivite.html" %}
{% include "gestion_projet/parts/modalAjoutDocument.html" %}
{% include "gestion_projet/parts/modalMiseAJourDepense.html" %}
{% include "gestion_projet/parts/modalAjoutLivrable.html" %}
{% include "gestion_projet/parts/liste_document_projet.html" %}
{% include "gestion_projet/parts/modalAnnulerActivite.html" %}
{% endblock %}
{% block 'js' %}
<script type="text/javascript" src="{% static 'gestion_projet/js/suivi-activites.js' %}"></script>
<script type="text/javascript" src="{% static 'gestion_projet/js/liste_documents_projet.js' %}"></script>
{% endblock %}

3
gestion_projet/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@@ -335,7 +335,6 @@ def activites_projet(request):
}
return render(request, 'gestion_projet/suivi_activite.html', context)
@login_required
def ajouter_activite_projet(request):
"""Vue pour ajouter une activité à un projet spécifique via un formulaire"""