forked from ScoDoc/DocScoDoc
464 lines
16 KiB
Python
464 lines
16 KiB
Python
# -*- mode: python -*-
|
|
# -*- coding: utf-8 -*-
|
|
|
|
##############################################################################
|
|
#
|
|
# Gestion scolarite IUT
|
|
#
|
|
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
#
|
|
#
|
|
##############################################################################
|
|
|
|
import re
|
|
import requests
|
|
|
|
from flask_wtf import FlaskForm
|
|
from flask_wtf.file import FileField, FileAllowed, FileRequired
|
|
from markupsafe import Markup
|
|
from sqlalchemy import text
|
|
from wtforms import (
|
|
StringField,
|
|
SubmitField,
|
|
TextAreaField,
|
|
SelectField,
|
|
HiddenField,
|
|
SelectMultipleField,
|
|
DateField,
|
|
BooleanField,
|
|
)
|
|
from wtforms.validators import ValidationError, DataRequired, Email, Optional
|
|
from wtforms.widgets import ListWidget, CheckboxInput
|
|
|
|
from app.entreprises.models import (
|
|
Entreprise,
|
|
EntrepriseCorrespondant,
|
|
EntreprisePreferences,
|
|
)
|
|
from app.models import Identite, Departement
|
|
from app.auth.models import User
|
|
|
|
CHAMP_REQUIS = "Ce champ est requis"
|
|
SUBMIT_MARGE = {"style": "margin-bottom: 10px;"}
|
|
|
|
|
|
def _build_string_field(label, required=True, render_kw=None):
|
|
if required:
|
|
return StringField(
|
|
label,
|
|
validators=[DataRequired(message=CHAMP_REQUIS)],
|
|
render_kw=render_kw,
|
|
)
|
|
else:
|
|
return StringField(label, validators=[Optional()], render_kw=render_kw)
|
|
|
|
|
|
class EntrepriseCreationForm(FlaskForm):
|
|
siret = _build_string_field(
|
|
"SIRET (*)",
|
|
render_kw={"placeholder": "Numéro composé de 14 chiffres", "maxlength": "14"},
|
|
)
|
|
nom_entreprise = _build_string_field("Nom de l'entreprise (*)")
|
|
adresse = _build_string_field("Adresse de l'entreprise (*)")
|
|
codepostal = _build_string_field("Code postal de l'entreprise (*)")
|
|
ville = _build_string_field("Ville de l'entreprise (*)")
|
|
pays = _build_string_field("Pays de l'entreprise", required=False)
|
|
|
|
nom_correspondant = _build_string_field("Nom du correspondant (*)")
|
|
prenom_correspondant = _build_string_field("Prénom du correspondant (*)")
|
|
telephone = _build_string_field("Téléphone du correspondant (*)", required=False)
|
|
mail = StringField(
|
|
"Mail du correspondant (*)",
|
|
validators=[Optional(), Email(message="Adresse e-mail invalide")],
|
|
)
|
|
poste = _build_string_field("Poste du correspondant", required=False)
|
|
service = _build_string_field("Service du correspondant", required=False)
|
|
submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)
|
|
|
|
def validate(self):
|
|
validate = True
|
|
if not FlaskForm.validate(self):
|
|
validate = False
|
|
|
|
if not self.telephone.data and not self.mail.data:
|
|
self.telephone.errors.append(
|
|
"Saisir un moyen de contact (mail ou téléphone)"
|
|
)
|
|
self.mail.errors.append("Saisir un moyen de contact (mail ou téléphone)")
|
|
validate = False
|
|
|
|
return validate
|
|
|
|
def validate_siret(self, siret):
|
|
if EntreprisePreferences.get_check_siret():
|
|
siret = siret.data.strip()
|
|
if re.match("^\d{14}$", siret) is None:
|
|
raise ValidationError("Format incorrect")
|
|
try:
|
|
req = requests.get(
|
|
f"https://entreprise.data.gouv.fr/api/sirene/v1/siret/{siret}"
|
|
)
|
|
if req.status_code != 200:
|
|
raise ValidationError("SIRET inexistant")
|
|
except requests.ConnectionError:
|
|
print("no internet")
|
|
entreprise = Entreprise.query.filter_by(siret=siret).first()
|
|
if entreprise is not None:
|
|
lien = f'<a href="/ScoDoc/entreprises/fiche_entreprise/{entreprise.id}">ici</a>'
|
|
raise ValidationError(
|
|
Markup(f"Entreprise déjà présent, lien vers la fiche : {lien}")
|
|
)
|
|
|
|
|
|
class EntrepriseModificationForm(FlaskForm):
|
|
hidden_entreprise_siret = HiddenField()
|
|
siret = StringField("SIRET (*)")
|
|
nom = _build_string_field("Nom de l'entreprise (*)")
|
|
adresse = _build_string_field("Adresse (*)")
|
|
codepostal = _build_string_field("Code postal (*)")
|
|
ville = _build_string_field("Ville (*)")
|
|
pays = _build_string_field("Pays", required=False)
|
|
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.siret.render_kw = {
|
|
"disabled": "",
|
|
"value": self.hidden_entreprise_siret.data,
|
|
}
|
|
|
|
|
|
class MultiCheckboxField(SelectMultipleField):
|
|
widget = ListWidget(prefix_label=False)
|
|
option_widget = CheckboxInput()
|
|
|
|
|
|
class OffreCreationForm(FlaskForm):
|
|
hidden_entreprise_id = HiddenField()
|
|
intitule = _build_string_field("Intitulé (*)")
|
|
description = TextAreaField(
|
|
"Description (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
|
|
)
|
|
type_offre = SelectField(
|
|
"Type de l'offre (*)",
|
|
choices=[("Stage"), ("Alternance")],
|
|
validators=[DataRequired(message=CHAMP_REQUIS)],
|
|
)
|
|
missions = TextAreaField(
|
|
"Missions (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
|
|
)
|
|
duree = _build_string_field("Durée (*)")
|
|
depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int)
|
|
expiration_date = DateField("Date expiration", validators=[Optional()])
|
|
correspondant = SelectField("Correspondant à contacté (*)", validators=[Optional()])
|
|
submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.correspondant.choices = [
|
|
(correspondant.id, f"{correspondant.nom} {correspondant.prenom}")
|
|
for correspondant in EntrepriseCorrespondant.query.filter_by(
|
|
entreprise_id=self.hidden_entreprise_id.data
|
|
)
|
|
]
|
|
|
|
self.depts.choices = [
|
|
(dept.id, dept.acronym) for dept in Departement.query.all()
|
|
]
|
|
|
|
|
|
class OffreModificationForm(FlaskForm):
|
|
hidden_entreprise_id = HiddenField()
|
|
intitule = _build_string_field("Intitulé (*)")
|
|
description = TextAreaField(
|
|
"Description (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
|
|
)
|
|
type_offre = SelectField(
|
|
"Type de l'offre (*)",
|
|
choices=[("Stage"), ("Alternance")],
|
|
validators=[DataRequired(message=CHAMP_REQUIS)],
|
|
)
|
|
missions = TextAreaField(
|
|
"Missions (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
|
|
)
|
|
duree = _build_string_field("Durée (*)")
|
|
depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int)
|
|
expiration_date = DateField("Date expiration", validators=[Optional()])
|
|
correspondant = SelectField("Correspondant à contacté (*)", validators=[Optional()])
|
|
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.correspondant.choices = [
|
|
(correspondant.id, f"{correspondant.nom} {correspondant.prenom}")
|
|
for correspondant in EntrepriseCorrespondant.query.filter_by(
|
|
entreprise_id=self.hidden_entreprise_id.data
|
|
)
|
|
]
|
|
|
|
self.depts.choices = [
|
|
(dept.id, dept.acronym) for dept in Departement.query.all()
|
|
]
|
|
|
|
|
|
class CorrespondantCreationForm(FlaskForm):
|
|
hidden_entreprise_id = HiddenField()
|
|
nom = _build_string_field("Nom (*)")
|
|
prenom = _build_string_field("Prénom (*)")
|
|
telephone = _build_string_field("Téléphone (*)", required=False)
|
|
mail = StringField(
|
|
"Mail (*)",
|
|
validators=[Optional(), Email(message="Adresse e-mail invalide")],
|
|
)
|
|
poste = _build_string_field("Poste", required=False)
|
|
service = _build_string_field("Service", required=False)
|
|
# depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int)
|
|
submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)
|
|
|
|
# def __init__(self, *args, **kwargs):
|
|
# super().__init__(*args, **kwargs)
|
|
|
|
# self.depts.choices = [
|
|
# (dept.id, dept.acronym) for dept in Departement.query.all()
|
|
# ]
|
|
|
|
def validate(self):
|
|
validate = True
|
|
if not FlaskForm.validate(self):
|
|
validate = False
|
|
|
|
correspondant = EntrepriseCorrespondant.query.filter_by(
|
|
entreprise_id=self.hidden_entreprise_id.data,
|
|
nom=self.nom.data,
|
|
prenom=self.prenom.data,
|
|
).first()
|
|
if correspondant is not None:
|
|
self.nom.errors.append("Ce correspondant existe déjà (même nom et prénom)")
|
|
self.prenom.errors.append("")
|
|
validate = False
|
|
|
|
if not self.telephone.data and not self.mail.data:
|
|
self.telephone.errors.append(
|
|
"Saisir un moyen de contact (mail ou téléphone)"
|
|
)
|
|
self.mail.errors.append("Saisir un moyen de contact (mail ou téléphone)")
|
|
validate = False
|
|
|
|
return validate
|
|
|
|
|
|
class CorrespondantModificationForm(FlaskForm):
|
|
hidden_correspondant_id = HiddenField()
|
|
hidden_entreprise_id = HiddenField()
|
|
nom = _build_string_field("Nom (*)")
|
|
prenom = _build_string_field("Prénom (*)")
|
|
telephone = _build_string_field("Téléphone (*)", required=False)
|
|
mail = StringField(
|
|
"Mail (*)",
|
|
validators=[Optional(), Email(message="Adresse e-mail invalide")],
|
|
)
|
|
poste = _build_string_field("Poste", required=False)
|
|
service = _build_string_field("Service", required=False)
|
|
# depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int)
|
|
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
|
|
|
|
# def __init__(self, *args, **kwargs):
|
|
# super().__init__(*args, **kwargs)
|
|
|
|
# self.depts.choices = [
|
|
# (dept.id, dept.acronym) for dept in Departement.query.all()
|
|
# ]
|
|
|
|
def validate(self):
|
|
validate = True
|
|
if not FlaskForm.validate(self):
|
|
validate = False
|
|
|
|
correspondant = EntrepriseCorrespondant.query.filter(
|
|
EntrepriseCorrespondant.id != self.hidden_correspondant_id.data,
|
|
EntrepriseCorrespondant.entreprise_id == self.hidden_entreprise_id.data,
|
|
EntrepriseCorrespondant.nom == self.nom.data,
|
|
EntrepriseCorrespondant.prenom == self.prenom.data,
|
|
).first()
|
|
if correspondant is not None:
|
|
self.nom.errors.append("Ce correspondant existe déjà (même nom et prénom)")
|
|
self.prenom.errors.append("")
|
|
validate = False
|
|
|
|
if not self.telephone.data and not self.mail.data:
|
|
self.telephone.errors.append(
|
|
"Saisir un moyen de contact (mail ou téléphone)"
|
|
)
|
|
self.mail.errors.append("Saisir un moyen de contact (mail ou téléphone)")
|
|
validate = False
|
|
|
|
return validate
|
|
|
|
|
|
class StageApprentissageCreationForm(FlaskForm):
|
|
etudiant = _build_string_field(
|
|
"Étudiant (*)",
|
|
render_kw={"placeholder": "Tapez le nom de l'étudiant"},
|
|
)
|
|
type_offre = SelectField(
|
|
"Type de l'offre (*)",
|
|
choices=[("Stage"), ("Alternance")],
|
|
validators=[DataRequired(message=CHAMP_REQUIS)],
|
|
)
|
|
date_debut = DateField(
|
|
"Date début (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
|
|
)
|
|
date_fin = DateField(
|
|
"Date fin (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
|
|
)
|
|
submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)
|
|
|
|
def validate(self):
|
|
validate = True
|
|
if not FlaskForm.validate(self):
|
|
validate = False
|
|
|
|
if (
|
|
self.date_debut.data
|
|
and self.date_fin.data
|
|
and self.date_debut.data > self.date_fin.data
|
|
):
|
|
self.date_debut.errors.append("Les dates sont incompatibles")
|
|
self.date_fin.errors.append("Les dates sont incompatibles")
|
|
validate = False
|
|
|
|
return validate
|
|
|
|
def validate_etudiant(self, etudiant):
|
|
etudiant_data = etudiant.data.upper().strip()
|
|
stm = text(
|
|
"SELECT id, CONCAT(nom, ' ', prenom) as nom_prenom FROM Identite WHERE CONCAT(nom, ' ', prenom)=:nom_prenom"
|
|
)
|
|
etudiant = (
|
|
Identite.query.from_statement(stm).params(nom_prenom=etudiant_data).first()
|
|
)
|
|
if etudiant is None:
|
|
raise ValidationError("Champ incorrect (selectionnez dans la liste)")
|
|
|
|
|
|
class StageApprentissageModificationForm(FlaskForm):
|
|
etudiant = _build_string_field(
|
|
"Étudiant (*)",
|
|
render_kw={"placeholder": "Tapez le nom de l'étudiant"},
|
|
)
|
|
type_offre = SelectField(
|
|
"Type de l'offre (*)",
|
|
choices=[("Stage"), ("Alternance")],
|
|
validators=[DataRequired(message=CHAMP_REQUIS)],
|
|
)
|
|
date_debut = DateField(
|
|
"Date début (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
|
|
)
|
|
date_fin = DateField(
|
|
"Date fin (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
|
|
)
|
|
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
|
|
|
|
def validate(self):
|
|
validate = True
|
|
if not FlaskForm.validate(self):
|
|
validate = False
|
|
|
|
if (
|
|
self.date_debut.data
|
|
and self.date_fin.data
|
|
and self.date_debut.data > self.date_fin.data
|
|
):
|
|
self.date_debut.errors.append("Les dates sont incompatibles")
|
|
self.date_fin.errors.append("Les dates sont incompatibles")
|
|
validate = False
|
|
|
|
return validate
|
|
|
|
def validate_etudiant(self, etudiant):
|
|
etudiant_data = etudiant.data.upper().strip()
|
|
stm = text(
|
|
"SELECT id, CONCAT(nom, ' ', prenom) as nom_prenom FROM Identite WHERE CONCAT(nom, ' ', prenom)=:nom_prenom"
|
|
)
|
|
etudiant = (
|
|
Identite.query.from_statement(stm).params(nom_prenom=etudiant_data).first()
|
|
)
|
|
if etudiant is None:
|
|
raise ValidationError("Champ incorrect (selectionnez dans la liste)")
|
|
|
|
|
|
class EnvoiOffreForm(FlaskForm):
|
|
responsable = _build_string_field(
|
|
"Responsable de formation (*)",
|
|
render_kw={"placeholder": "Tapez le nom du responsable de formation"},
|
|
)
|
|
submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)
|
|
|
|
def validate_responsable(self, responsable):
|
|
responsable_data = responsable.data.upper().strip()
|
|
stm = text(
|
|
"SELECT id, UPPER(CONCAT(nom, ' ', prenom, ' ', '(', user_name, ')')) FROM \"user\" WHERE UPPER(CONCAT(nom, ' ', prenom, ' ', '(', user_name, ')'))=:responsable_data"
|
|
)
|
|
responsable = (
|
|
User.query.from_statement(stm)
|
|
.params(responsable_data=responsable_data)
|
|
.first()
|
|
)
|
|
if responsable is None:
|
|
raise ValidationError("Champ incorrect (selectionnez dans la liste)")
|
|
|
|
|
|
class AjoutFichierForm(FlaskForm):
|
|
fichier = FileField(
|
|
"Fichier (*)",
|
|
validators=[
|
|
FileRequired(message=CHAMP_REQUIS),
|
|
FileAllowed(["pdf", "docx"], "Fichier .pdf ou .docx uniquement"),
|
|
],
|
|
)
|
|
submit = SubmitField("Ajouter", render_kw=SUBMIT_MARGE)
|
|
|
|
|
|
class SuppressionConfirmationForm(FlaskForm):
|
|
submit = SubmitField("Supprimer", render_kw=SUBMIT_MARGE)
|
|
|
|
|
|
class ValidationConfirmationForm(FlaskForm):
|
|
submit = SubmitField("Valider", render_kw=SUBMIT_MARGE)
|
|
|
|
|
|
class ImportForm(FlaskForm):
|
|
fichier = FileField(
|
|
"Fichier (*)",
|
|
validators=[
|
|
FileRequired(message=CHAMP_REQUIS),
|
|
FileAllowed(["xlsx"], "Fichier .xlsx uniquement"),
|
|
],
|
|
)
|
|
submit = SubmitField("Importer", render_kw=SUBMIT_MARGE)
|
|
|
|
|
|
class PreferencesForm(FlaskForm):
|
|
mail_entreprise = StringField(
|
|
"Mail notifications",
|
|
validators=[Optional(), Email(message="Adresse e-mail invalide")],
|
|
)
|
|
check_siret = BooleanField("Vérification SIRET")
|
|
submit = SubmitField("Valider", render_kw=SUBMIT_MARGE)
|