"
+ @classmethod
+ def from_request(cls, etudid=None, code_nip=None):
+ """Etudiant à partir de l'etudid ou du code_nip, soit
+ passés en argument soit retrouvés directement dans la requête web.
+ Erreur 404 si inexistant.
+ """
+ args = make_etud_args(etudid=etudid, code_nip=code_nip)
+ return Identite.query.filter_by(**args).first_or_404()
+
+ @property
def civilite_str(self):
"""returns 'M.' ou 'Mme' ou '' (pour le genre neutre,
personnes ne souhaitant pas d'affichage).
"""
return {"M": "M.", "F": "Mme", "X": ""}[self.civilite]
- def nom_disp(self):
- "nom à afficher"
+ def nom_disp(self) -> str:
+ "Nom à afficher"
if self.nom_usuel:
return (
(self.nom_usuel + " (" + self.nom + ")") if self.nom else self.nom_usuel
@@ -65,10 +79,50 @@ class Identite(db.Model):
else:
return self.nom
+ @cached_property
+ def nomprenom(self, reverse=False) -> str:
+ """Civilité/nom/prenom pour affichages: "M. Pierre Dupont"
+ Si reverse, "Dupont Pierre", sans civilité.
+ """
+ nom = self.nom_usuel or self.nom
+ prenom = self.prenom_str
+ if reverse:
+ fields = (nom, prenom)
+ else:
+ fields = (self.civilite_str, prenom, nom)
+ return " ".join([x for x in fields if x])
+
+ @property
+ def prenom_str(self):
+ """Prénom à afficher. Par exemple: "Jean-Christophe" """
+ if not self.prenom:
+ return ""
+ frags = self.prenom.split()
+ r = []
+ for frag in frags:
+ fields = frag.split("-")
+ r.append("-".join([x.lower().capitalize() for x in fields]))
+ return " ".join(r)
+
+ @cached_property
+ def sort_key(self) -> tuple:
+ "clé pour tris par ordre alphabétique"
+ return (self.nom_usuel or self.nom).lower(), self.prenom.lower()
+
def get_first_email(self, field="email") -> str:
- "le mail associé à la première adrese de l'étudiant, ou None"
+ "Le mail associé à la première adrese de l'étudiant, ou None"
return self.adresses[0].email or None if self.adresses.count() > 0 else None
+ def to_dict_scodoc7(self):
+ """Représentation dictionnaire,
+ compatible ScoDoc7 mais sans infos admission
+ """
+ e = dict(self.__dict__)
+ e.pop("_sa_instance_state", None)
+ # ScoDoc7 output_formators: (backward compat)
+ e["date_naissance"] = ndb.DateISOtoDMY(e["date_naissance"])
+ return {k: e[k] or "" for k in e} # convert_null_outputs_to_empty
+
def to_dict_bul(self, include_urls=True):
"""Infos exportées dans les bulletins"""
from app.scodoc import sco_photos
@@ -104,6 +158,17 @@ class Identite(db.Model):
]
return r[0] if r else None
+ def inscription_courante_date(self, date_debut, date_fin):
+ """La première inscription à un formsemestre incluant la
+ période [date_debut, date_fin]
+ """
+ r = [
+ ins
+ for ins in self.formsemestre_inscriptions
+ if ins.formsemestre.contient_periode(date_debut, date_fin)
+ ]
+ return r[0] if r else None
+
def etat_inscription(self, formsemestre_id):
"""etat de l'inscription de cet étudiant au semestre:
False si pas inscrit, ou scu.INSCRIT, DEMISSION, DEF
@@ -117,6 +182,42 @@ class Identite(db.Model):
return False
+def make_etud_args(
+ etudid=None, code_nip=None, use_request=True, raise_exc=False, abort_404=True
+) -> dict:
+ """forme args dict pour requete recherche etudiant
+ On peut specifier etudid
+ ou bien (si use_request) cherche dans la requete http: etudid, code_nip, code_ine
+ (dans cet ordre).
+
+ Résultat: dict avec soit "etudid", soit "code_nip", soit "code_ine"
+ """
+ args = None
+ if etudid:
+ args = {"etudid": etudid}
+ elif code_nip:
+ args = {"code_nip": code_nip}
+ elif use_request: # use form from current request (Flask global)
+ if request.method == "POST":
+ vals = request.form
+ elif request.method == "GET":
+ vals = request.args
+ else:
+ vals = {}
+ if "etudid" in vals:
+ args = {"etudid": int(vals["etudid"])}
+ elif "code_nip" in vals:
+ args = {"code_nip": str(vals["code_nip"])}
+ elif "code_ine" in vals:
+ args = {"code_ine": str(vals["code_ine"])}
+ if not args:
+ if abort_404:
+ abort(404, "pas d'étudiant sélectionné")
+ elif raise_exc:
+ raise ValueError("make_etud_args: pas d'étudiant sélectionné !")
+ return args
+
+
class Adresse(db.Model):
"""Adresse d'un étudiant
(le modèle permet plusieurs adresses, mais l'UI n'en gère qu'une seule)
diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py
index 450ea2ccf..928dd6093 100644
--- a/app/models/formsemestre.py
+++ b/app/models/formsemestre.py
@@ -3,6 +3,7 @@
"""ScoDoc models: formsemestre
"""
import datetime
+from functools import cached_property
import flask_sqlalchemy
@@ -84,7 +85,11 @@ class FormSemestre(db.Model):
etapes = db.relationship(
"FormSemestreEtape", cascade="all,delete", backref="formsemestre"
)
- modimpls = db.relationship("ModuleImpl", backref="formsemestre", lazy="dynamic")
+ modimpls = db.relationship(
+ "ModuleImpl",
+ backref="formsemestre",
+ lazy="dynamic",
+ )
etuds = db.relationship(
"Identite",
secondary="notes_formsemestre_inscription",
@@ -146,6 +151,13 @@ class FormSemestre(db.Model):
today = datetime.date.today()
return (self.date_debut <= today) and (today <= self.date_fin)
+ def contient_periode(self, date_debut, date_fin) -> bool:
+ """Vrai si l'intervalle [date_debut, date_fin] est
+ inclus dans le semestre.
+ (les dates de début et fin sont incluses)
+ """
+ return (self.date_debut <= date_debut) and (date_fin <= self.date_fin)
+
def est_decale(self):
"""Vrai si semestre "décalé"
c'est à dire semestres impairs commençant entre janvier et juin
@@ -240,7 +252,7 @@ class FormSemestre(db.Model):
etudid, self.date_debut.isoformat(), self.date_fin.isoformat()
)
- def get_inscrits(self, include_dem=False) -> list:
+ def get_inscrits(self, include_dem=False) -> list[Identite]:
"""Liste des étudiants inscrits à ce semestre
Si all, tous les étudiants, avec les démissionnaires.
"""
@@ -249,6 +261,11 @@ class FormSemestre(db.Model):
else:
return [ins.etud for ins in self.inscriptions if ins.etat == scu.INSCRIT]
+ @cached_property
+ def etuds_inscriptions(self) -> dict:
+ """Map { etudid : inscription }"""
+ return {ins.etud.id: ins for ins in self.inscriptions}
+
# Association id des utilisateurs responsables (aka directeurs des etudes) du semestre
notes_formsemestre_responsables = db.Table(
diff --git a/app/models/moduleimpls.py b/app/models/moduleimpls.py
index 172fe0767..fe48555ef 100644
--- a/app/models/moduleimpls.py
+++ b/app/models/moduleimpls.py
@@ -50,7 +50,7 @@ class ModuleImpl(db.Model):
if evaluations_poids is None:
from app.comp import moy_mod
- evaluations_poids, _ = moy_mod.df_load_evaluations_poids(self.id)
+ evaluations_poids, _ = moy_mod.load_evaluations_poids(self.id)
df_cache.EvaluationsPoidsCache.set(self.id, evaluations_poids)
return evaluations_poids
@@ -69,7 +69,7 @@ class ModuleImpl(db.Model):
return True
from app.comp import moy_mod
- return moy_mod.check_moduleimpl_conformity(
+ return moy_mod.moduleimpl_is_conforme(
self,
self.get_evaluations_poids(),
self.module.formation.get_module_coefs(self.module.semestre_id),
diff --git a/app/pe/pe_tagtable.py b/app/pe/pe_tagtable.py
index 03acc4a60..54e5e3955 100644
--- a/app/pe/pe_tagtable.py
+++ b/app/pe/pe_tagtable.py
@@ -68,7 +68,7 @@ class TableTag(object):
self.taglist = []
self.resultats = {}
- self.rangs = {}
+ self.etud_moy_gen_ranks = {}
self.statistiques = {}
# *****************************************************************************************************************
@@ -117,15 +117,15 @@ class TableTag(object):
# -----------------------------------------------------------------------------------------------------------
def get_moy_from_stats(self, tag):
- """ Renvoie la moyenne des notes calculées pour d'un tag donné"""
+ """Renvoie la moyenne des notes calculées pour d'un tag donné"""
return self.statistiques[tag][0] if tag in self.statistiques else None
def get_min_from_stats(self, tag):
- """ Renvoie la plus basse des notes calculées pour d'un tag donné"""
+ """Renvoie la plus basse des notes calculées pour d'un tag donné"""
return self.statistiques[tag][1] if tag in self.statistiques else None
def get_max_from_stats(self, tag):
- """ Renvoie la plus haute des notes calculées pour d'un tag donné"""
+ """Renvoie la plus haute des notes calculées pour d'un tag donné"""
return self.statistiques[tag][2] if tag in self.statistiques else None
# -----------------------------------------------------------------------------------------------------------
@@ -236,7 +236,7 @@ class TableTag(object):
return moystr
def str_res_d_un_etudiant(self, etudid, delim=";"):
- """Renvoie sur une ligne les résultats d'un étudiant à tous les tags (par ordre alphabétique). """
+ """Renvoie sur une ligne les résultats d'un étudiant à tous les tags (par ordre alphabétique)."""
return delim.join(
[self.str_resTag_d_un_etudiant(tag, etudid) for tag in self.get_all_tags()]
)
@@ -256,7 +256,7 @@ class TableTag(object):
# -----------------------------------------------------------------------
def str_tagtable(self, delim=";", decimal_sep=","):
- """Renvoie une chaine de caractère listant toutes les moyennes, les rangs des étudiants pour tous les tags. """
+ """Renvoie une chaine de caractère listant toutes les moyennes, les rangs des étudiants pour tous les tags."""
entete = ["etudid", "nom", "prenom"]
for tag in self.get_all_tags():
entete += [titre + "_" + tag for titre in ["note", "rang", "nb_inscrit"]]
diff --git a/app/scodoc/notes_table.py b/app/scodoc/notes_table.py
index 996feddab..828ea228c 100644
--- a/app/scodoc/notes_table.py
+++ b/app/scodoc/notes_table.py
@@ -25,7 +25,9 @@
#
##############################################################################
-"""Calculs sur les notes et cache des resultats
+"""Calculs sur les notes et cache des résultats
+
+ Ancien code ScoDoc 7 en cours de rénovation
"""
from operator import itemgetter
@@ -102,7 +104,7 @@ def comp_ranks(T):
def get_sem_ues_modimpls(formsemestre_id, modimpls=None):
"""Get liste des UE du semestre (à partir des moduleimpls)
- (utilisé quand on ne peut pas construire nt et faire nt.get_ues())
+ (utilisé quand on ne peut pas construire nt et faire nt.get_ues_stat_dict())
"""
if modimpls is None:
modimpls = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
@@ -200,7 +202,7 @@ class NotesTable:
self.inscrlist.sort(key=itemgetter("nomp"))
# { etudid : rang dans l'ordre alphabetique }
- self.rang_alpha = {e["etudid"]: i for i, e in enumerate(self.inscrlist)}
+ self._rang_alpha = {e["etudid"]: i for i, e in enumerate(self.inscrlist)}
self.bonus = scu.DictDefault(defaultvalue=0)
# Notes dans les modules { moduleimpl_id : { etudid: note_moyenne_dans_ce_module } }
@@ -294,7 +296,7 @@ class NotesTable:
for ue in self._ues:
is_cap[ue["ue_id"]] = ue_status[ue["ue_id"]]["is_capitalized"]
- for modimpl in self.get_modimpls():
+ for modimpl in self.get_modimpls_dict():
val = self.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid)
if is_cap[modimpl["module"]["ue_id"]]:
t.append("-c-")
@@ -316,7 +318,7 @@ class NotesTable:
self.moy_min = self.moy_max = "NA"
# calcul rangs (/ moyenne generale)
- self.rangs = comp_ranks(T)
+ self.etud_moy_gen_ranks = comp_ranks(T)
self.rangs_groupes = (
{}
@@ -364,7 +366,7 @@ class NotesTable:
moy = -float(x[0])
except (ValueError, TypeError):
moy = 1000.0
- return (moy, self.rang_alpha[x[-1]])
+ return (moy, self._rang_alpha[x[-1]])
def get_etudids(self, sorted=False):
if sorted:
@@ -417,46 +419,17 @@ class NotesTable:
else:
return ' (%s) ' % etat
- def get_ues(self, filter_sport=False, filter_non_inscrit=False, etudid=None):
- """liste des ue, ordonnée par numero.
- Si filter_non_inscrit, retire les UE dans lesquelles l'etudiant n'est
- inscrit à aucun module.
+ def get_ues_stat_dict(self, filter_sport=False): # was get_ues()
+ """Liste des UEs, ordonnée par numero.
Si filter_sport, retire les UE de type SPORT
"""
- if not filter_sport and not filter_non_inscrit:
+ if not filter_sport:
return self._ues
-
- if filter_sport:
- ues_src = [ue for ue in self._ues if ue["type"] != UE_SPORT]
else:
- ues_src = self._ues
- if not filter_non_inscrit:
- return ues_src
- ues = []
- for ue in ues_src:
- if self.get_etud_ue_status(etudid, ue["ue_id"])["is_capitalized"]:
- # garde toujours les UE capitalisees
- has_note = True
- else:
- has_note = False
- # verifie que l'etud. est inscrit a au moins un module de l'UE
- # (en fait verifie qu'il a une note)
- modimpls = self.get_modimpls(ue["ue_id"])
+ return [ue for ue in self._ues if ue["type"] != UE_SPORT]
- for modi in modimpls:
- moy = self.get_etud_mod_moy(modi["moduleimpl_id"], etudid)
- try:
- float(moy)
- has_note = True
- break
- except:
- pass
- if has_note:
- ues.append(ue)
- return ues
-
- def get_modimpls(self, ue_id=None):
- "liste des modules pour une UE (ou toutes si ue_id==None), triés par matières."
+ def get_modimpls_dict(self, ue_id=None):
+ "Liste des modules pour une UE (ou toutes si ue_id==None), triés par matières."
if ue_id is None:
r = self._modimpls
else:
@@ -522,7 +495,7 @@ class NotesTable:
Les moyennes d'UE ne tiennent pas compte des capitalisations.
"""
- ues = self.get_ues()
+ ues = self.get_ues_stat_dict()
sum_moy = 0 # la somme des moyennes générales valides
nb_moy = 0 # le nombre de moyennes générales valides
for ue in ues:
@@ -561,9 +534,9 @@ class NotesTable:
i = 0
for ue in ues:
i += 1
- ue["nb_moy"] = len(ue["_notes"])
- if ue["nb_moy"] > 0:
- ue["moy"] = sum(ue["_notes"]) / ue["nb_moy"]
+ ue["nb_vals"] = len(ue["_notes"])
+ if ue["nb_vals"] > 0:
+ ue["moy"] = sum(ue["_notes"]) / ue["nb_vals"]
ue["max"] = max(ue["_notes"])
ue["min"] = min(ue["_notes"])
else:
@@ -591,7 +564,7 @@ class NotesTable:
Si non inscrit, moy == 'NI' et sum_coefs==0
"""
assert ue_id
- modimpls = self.get_modimpls(ue_id)
+ modimpls = self.get_modimpls_dict(ue_id)
nb_notes = 0 # dans cette UE
sum_notes = 0.0
sum_coefs = 0.0
@@ -767,7 +740,7 @@ class NotesTable:
sem_ects_pot_fond = 0.0
sem_ects_pot_pro = 0.0
- for ue in self.get_ues():
+ for ue in self.get_ues_stat_dict():
# - On calcule la moyenne d'UE courante:
if not block_computation:
mu = self.comp_etud_moy_ue(etudid, ue_id=ue["ue_id"], cnx=cnx)
@@ -948,7 +921,7 @@ class NotesTable:
return infos
- def get_etud_moy_gen(self, etudid):
+ def get_etud_moy_gen(self, etudid): # -> float | str
"""Moyenne generale de cet etudiant dans ce semestre.
Prend en compte les UE capitalisées.
Si pas de notes: 'NA'
@@ -981,7 +954,7 @@ class NotesTable:
return self.T
def get_etud_rang(self, etudid) -> str:
- return self.rangs.get(etudid, "999")
+ return self.etud_moy_gen_ranks.get(etudid, "999")
def get_etud_rang_group(self, etudid, group_id):
"""Returns rank of etud in this group and number of etuds in group.
@@ -1347,7 +1320,7 @@ class NotesTable:
# Rappel des épisodes précédents: T est une liste de liste
# Colonnes: 0 moy_gen, moy_ue1, ..., moy_ue_n, moy_mod1, ..., moy_mod_n, etudid
- ues = self.get_ues() # incluant le(s) UE de sport
+ ues = self.get_ues_stat_dict() # incluant le(s) UE de sport
for t in self.T:
etudid = t[-1]
if etudid in results.etud_moy_gen: # evite les démissionnaires
@@ -1358,4 +1331,4 @@ class NotesTable:
# re-trie selon la nouvelle moyenne générale:
self.T.sort(key=self._row_key)
# Remplace aussi le rang:
- self.rangs = results.etud_moy_gen_ranks
+ self.etud_moy_gen_ranks = results.etud_moy_gen_ranks
diff --git a/app/scodoc/sco_abs_views.py b/app/scodoc/sco_abs_views.py
index 00a1870d2..2f108c243 100644
--- a/app/scodoc/sco_abs_views.py
+++ b/app/scodoc/sco_abs_views.py
@@ -32,6 +32,8 @@ import datetime
from flask import url_for, g, request, abort
+from app import log
+from app.models import Identite
import app.scodoc.sco_utils as scu
from app.scodoc import notesdb as ndb
from app.scodoc.scolog import logdb
@@ -46,7 +48,6 @@ from app.scodoc import sco_groups
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_photos
from app.scodoc import sco_preferences
-from app import log
from app.scodoc.sco_exceptions import ScoValueError
@@ -71,8 +72,8 @@ def doSignaleAbsence(
etudid: etudiant concerné. Si non spécifié, cherche dans
les paramètres de la requête courante.
"""
- etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
- etudid = etud["etudid"]
+ etud = Identite.from_request(etudid)
+
if not moduleimpl_id:
moduleimpl_id = None
description_abs = description
@@ -82,7 +83,7 @@ def doSignaleAbsence(
for jour in dates:
if demijournee == 2:
sco_abs.add_absence(
- etudid,
+ etud.id,
jour,
False,
estjust,
@@ -90,7 +91,7 @@ def doSignaleAbsence(
moduleimpl_id,
)
sco_abs.add_absence(
- etudid,
+ etud.id,
jour,
True,
estjust,
@@ -100,7 +101,7 @@ def doSignaleAbsence(
nbadded += 2
else:
sco_abs.add_absence(
- etudid,
+ etud.id,
jour,
demijournee,
estjust,
@@ -113,27 +114,27 @@ def doSignaleAbsence(
J = ""
else:
J = "NON "
- M = ""
+ indication_module = ""
if moduleimpl_id and moduleimpl_id != "NULL":
mod = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
formsemestre_id = mod["formsemestre_id"]
nt = sco_cache.NotesTableCache.get(formsemestre_id)
- ues = nt.get_ues(etudid=etudid)
+ ues = nt.get_ues_stat_dict()
for ue in ues:
- modimpls = nt.get_modimpls(ue_id=ue["ue_id"])
+ modimpls = nt.get_modimpls_dict(ue_id=ue["ue_id"])
for modimpl in modimpls:
if modimpl["moduleimpl_id"] == moduleimpl_id:
- M = "dans le module %s" % modimpl["module"]["code"]
+ indication_module = "dans le module %s" % modimpl["module"]["code"]
H = [
html_sco_header.sco_header(
- page_title="Signalement d'une absence pour %(nomprenom)s" % etud,
+ page_title=f"Signalement d'une absence pour {etud.nomprenom}",
),
"""Signalement d'absences
""",
]
if dates:
H.append(
"""Ajout de %d absences %sjustifiées du %s au %s %s
"""
- % (nbadded, J, datedebut, datefin, M)
+ % (nbadded, J, datedebut, datefin, indication_module)
)
else:
H.append(
@@ -142,11 +143,18 @@ def doSignaleAbsence(
)
H.append(
- """
-
"""
- % etud
+ f"""
+
+ """
)
H.append(sco_find_etud.form_search_etud())
H.append(html_sco_header.sco_footer())
@@ -175,7 +183,7 @@ def SignaleAbsenceEtud(): # etudid implied
"abs_require_module", formsemestre_id
)
nt = sco_cache.NotesTableCache.get(formsemestre_id)
- ues = nt.get_ues(etudid=etudid)
+ ues = nt.get_ues_stat_dict()
if require_module:
menu_module = """
+{% endblock %}
\ No newline at end of file
diff --git a/app/templates/entreprises/ajout_historique.html b/app/templates/entreprises/ajout_historique.html
new file mode 100644
index 000000000..c0a546d59
--- /dev/null
+++ b/app/templates/entreprises/ajout_historique.html
@@ -0,0 +1,32 @@
+{# -*- mode: jinja-html -*- #}
+{% extends 'base.html' %}
+{% import 'bootstrap/wtf.html' as wtf %}
+
+{% block styles %}
+{{super()}}
+
+
+{% endblock %}
+
+{% block app_content %}
+ {{ title }}
+
+
+
+ {{ wtf.quick_form(form, novalidate=True) }}
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/templates/entreprises/contacts.html b/app/templates/entreprises/contacts.html
new file mode 100644
index 000000000..54d77bd55
--- /dev/null
+++ b/app/templates/entreprises/contacts.html
@@ -0,0 +1,47 @@
+{# -*- mode: jinja-html -*- #}
+{% extends 'base.html' %}
+
+{% block app_content %}
+ {% if logs %}
+
+
Dernières opérations
+
+ {% for log in logs %}
+ - {{ log.date.strftime('%d %b %Hh%M') }}{{ log.text|safe }} par {{ log.authenticated_user|get_nomcomplet }}
+ {% endfor %}
+
+
+ {% endif %}
+
+
Liste des contacts
+ {% if contacts %}
+
+
+
+ Nom |
+ Prenom |
+ Telephone |
+ Mail |
+ Entreprise |
+
+ {% for contact in contacts %}
+
+ {{ contact[0].nom }} |
+ {{ contact[0].prenom }} |
+ {{ contact[0].telephone }} |
+ {{ contact[0].mail }} |
+ {{ contact[1].nom }} |
+
+ {% endfor %}
+
+ {% else %}
+
Aucun contact présent dans la base
+
+ {% endif %}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/templates/entreprises/delete_confirmation.html b/app/templates/entreprises/delete_confirmation.html
new file mode 100644
index 000000000..4894bca3e
--- /dev/null
+++ b/app/templates/entreprises/delete_confirmation.html
@@ -0,0 +1,15 @@
+{# -*- mode: jinja-html -*- #}
+{% extends 'base.html' %}
+{% import 'bootstrap/wtf.html' as wtf %}
+
+{% block app_content %}
+ {{ title }}
+
+ Cliquez sur le bouton supprimer pour confirmer votre supression
+
+
+
+ {{ wtf.quick_form(form) }}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/templates/entreprises/entreprises.html b/app/templates/entreprises/entreprises.html
new file mode 100644
index 000000000..fe790a8d6
--- /dev/null
+++ b/app/templates/entreprises/entreprises.html
@@ -0,0 +1,63 @@
+{# -*- mode: jinja-html -*- #}
+{% extends 'base.html' %}
+
+{% block app_content %}
+ {% if logs %}
+
+
Dernières opérations
+
+ {% for log in logs %}
+ - {{ log.date.strftime('%d %b %Hh%M') }}{{ log.text|safe }} par {{ log.authenticated_user|get_nomcomplet }}
+ {% endfor %}
+
+
+ {% endif %}
+
+
Liste des entreprises
+ {% if entreprises %}
+
+
+
+ SIRET |
+ Nom |
+ Adresse |
+ Code postal |
+ Ville |
+ Pays |
+ Action |
+
+ {% for entreprise in entreprises %}
+
+ {{ entreprise.siret }} |
+ {{ entreprise.nom }} |
+ {{ entreprise.adresse }} |
+ {{ entreprise.codepostal }} |
+ {{ entreprise.ville }} |
+ {{ entreprise.pays }} |
+
+
+ |
+
+ {% endfor %}
+
+ {% else %}
+
Aucune entreprise présent dans la base
+
+
+ {% endif %}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/templates/entreprises/envoi_offre_form.html b/app/templates/entreprises/envoi_offre_form.html
new file mode 100644
index 000000000..f67cb4e40
--- /dev/null
+++ b/app/templates/entreprises/envoi_offre_form.html
@@ -0,0 +1,32 @@
+{# -*- mode: jinja-html -*- #}
+{% extends 'base.html' %}
+{% import 'bootstrap/wtf.html' as wtf %}
+
+{% block styles %}
+{{super()}}
+
+
+{% endblock %}
+
+{% block app_content %}
+ {{ title }}
+
+
+
+ {{ wtf.quick_form(form, novalidate=True) }}
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/templates/entreprises/fiche_entreprise.html b/app/templates/entreprises/fiche_entreprise.html
new file mode 100644
index 000000000..d34531207
--- /dev/null
+++ b/app/templates/entreprises/fiche_entreprise.html
@@ -0,0 +1,76 @@
+{# -*- mode: jinja-html -*- #}
+{% extends 'base.html' %}
+
+{% block app_content %}
+{% if logs %}
+
+
Dernières opérations sur cette fiche
+
+ {% for log in logs %}
+ -
+ {{ log.date.strftime('%d %b %Hh%M') }}
+ {{ log.text|safe }} par {{ log.authenticated_user|get_nomcomplet }}
+
+ {% endfor %}
+
+
+{% endif %}
+{% if historique %}
+
+
Historique
+
+ {% for data in historique %}
+ -
+ {{ data[0].date_debut.strftime('%d/%m/%Y') }} - {{
+ data[0].date_fin.strftime('%d/%m/%Y') }}
+
+ {{ data[0].type_offre }} réalisé par {{ data[1].nom|format_nom }} {{ data[1].prenom|format_prenom }} en
+ {{ data[0].formation_text }}
+
+
+ {% endfor %}
+
+
+{% endif %}
+
+
Fiche entreprise - {{ entreprise.nom }} ({{ entreprise.siret }})
+
+
+
+ SIRET : {{ entreprise.siret }}
+ Nom : {{ entreprise.nom }}
+ Adresse : {{ entreprise.adresse }}
+ Code postal : {{ entreprise.codepostal }}
+ Ville : {{ entreprise.ville }}
+ Pays : {{ entreprise.pays }}
+
+
+
+ {% if contacts %}
+
+ {% for contact in contacts %}
+ Contact {{loop.index}}
+ {% include 'entreprises/_contact.html' %}
+ {% endfor %}
+
+ {% endif %}
+
+ {% if offres %}
+
+ {% for offre in offres %}
+ Offre {{loop.index}} (ajouté le {{offre[0].date_ajout.strftime('%d/%m/%Y') }})
+ {% include 'entreprises/_offre.html' %}
+ {% endfor %}
+
+ {% endif %}
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/templates/entreprises/form.html b/app/templates/entreprises/form.html
new file mode 100644
index 000000000..066224d8b
--- /dev/null
+++ b/app/templates/entreprises/form.html
@@ -0,0 +1,19 @@
+{# -*- mode: jinja-html -*- #}
+{% extends 'base.html' %}
+{% import 'bootstrap/wtf.html' as wtf %}
+
+{% block styles %}
+{{super()}}
+
+
+{% endblock %}
+
+{% block app_content %}
+ {{ title }}
+
+
+
+ {{ wtf.quick_form(form, novalidate=True) }}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/templates/entreprises/offres.html b/app/templates/entreprises/offres.html
new file mode 100644
index 000000000..ff3ab9bdc
--- /dev/null
+++ b/app/templates/entreprises/offres.html
@@ -0,0 +1,29 @@
+{# -*- mode: jinja-html -*- #}
+{% extends 'base.html' %}
+
+{% block app_content %}
+
+
{{ title }}
+ {% if offres_recus %}
+
+
+ {% for offre in offres_recus %}
+
+
+ Date envoi : {{ offre[0].date_envoi.strftime('%d/%m/%Y %H:%M') }}
+ Intitulé : {{ offre[1].intitule }}
+ Description : {{ offre[1].description }}
+ Type de l'offre : {{ offre[1].type_offre }}
+ Missions : {{ offre[1].missions }}
+ Durée : {{ offre[1].duree }}
+
+
+ {% endfor %}
+
+
+ {% else %}
+
Aucune offre reçue
+
+ {% endif %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/templates/error_500.html b/app/templates/error_500.html
index d986a00da..23a5c6095 100644
--- a/app/templates/error_500.html
+++ b/app/templates/error_500.html
@@ -1,11 +1,13 @@
+{# -*- mode: jinja-html -*- #}
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block title %}Une erreur est survenue !{% endblock %}
{% block body %}
Une erreur est survenue !
-Oups... ScoDoc version {{SCOVERSION}} a
- un problème, désolé.
+Oups... ScoDoc version
+ {{SCOVERSION}}
+ a un problème, désolé.
{{date}}
Si le problème persiste, contacter l'administrateur de votre site,
diff --git a/app/templates/error_access_denied.html b/app/templates/error_access_denied.html
index 5a765b761..516361d5c 100644
--- a/app/templates/error_access_denied.html
+++ b/app/templates/error_access_denied.html
@@ -1,3 +1,4 @@
+{# -*- mode: jinja-html -*- #}
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
diff --git a/app/templates/formsemestre_header.html b/app/templates/formsemestre_header.html
index 441a32872..aa8464ef4 100644
--- a/app/templates/formsemestre_header.html
+++ b/app/templates/formsemestre_header.html
@@ -1,3 +1,4 @@
+{# -*- mode: jinja-html -*- #}
{# Description un semestre (barre de menu et infos) #}
diff --git a/app/templates/main/index.html b/app/templates/main/index.html
index 6e21ac465..35005c95d 100644
--- a/app/templates/main/index.html
+++ b/app/templates/main/index.html
@@ -1,3 +1,4 @@
+{# -*- mode: jinja-html -*- #}
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
diff --git a/app/templates/pn/form_descr.html b/app/templates/pn/form_descr.html
index 347180257..6a0cda4ea 100644
--- a/app/templates/pn/form_descr.html
+++ b/app/templates/pn/form_descr.html
@@ -1,3 +1,4 @@
+{# -*- mode: jinja-html -*- #}
{# Chapeau description d'une formation #}