forked from ScoDoc/ScoDoc
- clé étrangère sur Identite dans EntrepriseStageApprentissage - nouveau mécanisme pour le choix d'étudiant via auto-completion (ajout de autoComplete.js-10.2.7) - nouveau point d'API: /etudiants/name/<string:start> (et son test unitaire)
822 lines
30 KiB
Python
822 lines
30 KiB
Python
# -*- mode: python -*-
|
|
# -*- coding: utf-8 -*-
|
|
|
|
##############################################################################
|
|
#
|
|
# Gestion scolarite IUT
|
|
#
|
|
# Copyright (c) 1999 - 2023 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
|
|
#
|
|
#
|
|
##############################################################################
|
|
|
|
from datetime import datetime
|
|
import re
|
|
import requests
|
|
|
|
from flask import url_for
|
|
from flask_wtf import FlaskForm
|
|
from flask_wtf.file import FileField, FileAllowed, FileRequired
|
|
from markupsafe import Markup
|
|
from sqlalchemy import text
|
|
from wtforms import (
|
|
BooleanField,
|
|
DateField,
|
|
FieldList,
|
|
FormField,
|
|
HiddenField,
|
|
IntegerField,
|
|
SelectField,
|
|
SelectMultipleField,
|
|
StringField,
|
|
SubmitField,
|
|
TextAreaField,
|
|
)
|
|
from wtforms.validators import (
|
|
ValidationError,
|
|
DataRequired,
|
|
Email,
|
|
Optional,
|
|
NumberRange,
|
|
)
|
|
from wtforms.widgets import ListWidget, CheckboxInput
|
|
|
|
from app.entreprises.models import (
|
|
Entreprise,
|
|
EntrepriseCorrespondant,
|
|
EntreprisePreferences,
|
|
EntrepriseSite,
|
|
EntrepriseTaxeApprentissage,
|
|
)
|
|
from app import db
|
|
from app.auth.models import User
|
|
from app.entreprises import SIRET_PROVISOIRE_START
|
|
from app.models import Identite, Departement
|
|
from app.scodoc import sco_utils as scu
|
|
|
|
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 EntreprisesFilterForm(FlaskForm):
|
|
active = BooleanField("Toutes les entreprises")
|
|
association = BooleanField("Seulement les associations partenaires")
|
|
siret_provisoire = BooleanField("Seulement SIRET provisoire")
|
|
|
|
|
|
class EntrepriseCreationForm(FlaskForm):
|
|
siret = StringField(
|
|
"SIRET",
|
|
validators=[Optional()],
|
|
render_kw={"placeholder": "Numéro composé de 14 chiffres"},
|
|
description="Laissez vide pour générer un SIRET provisoire",
|
|
)
|
|
association = BooleanField("Association")
|
|
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)
|
|
|
|
civilite = SelectField(
|
|
"Civilité du correspondant",
|
|
choices=[("H", "Monsieur"), ("F", "Madame")],
|
|
validators=[DataRequired(message=CHAMP_REQUIS)],
|
|
)
|
|
nom_correspondant = _build_string_field("Nom du correspondant", required=False)
|
|
prenom_correspondant = _build_string_field(
|
|
"Prénom du correspondant", required=False
|
|
)
|
|
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)
|
|
origine = _build_string_field("Origine du correspondant", required=False)
|
|
notes = _build_string_field("Notes sur le correspondant", required=False)
|
|
|
|
submit = SubmitField("Enregistrer", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|
|
|
|
def validate(self):
|
|
validate = True
|
|
if not FlaskForm.validate(self):
|
|
validate = False
|
|
|
|
if EntreprisePreferences.get_check_siret() and self.siret.data != "":
|
|
siret_data = self.siret.data.strip().replace(" ", "")
|
|
self.siret.data = siret_data
|
|
if re.match("^\d{14}$", siret_data) is None:
|
|
self.siret.errors.append("Format incorrect")
|
|
validate = False
|
|
else:
|
|
try:
|
|
req = requests.get(
|
|
f"https://entreprise.data.gouv.fr/api/sirene/v1/siret/{siret_data}",
|
|
timeout=scu.SCO_EXT_TIMEOUT,
|
|
)
|
|
if req.status_code != 200:
|
|
self.siret.errors.append("SIRET inexistant")
|
|
validate = False
|
|
except requests.ConnectionError:
|
|
self.siret.errors.append(
|
|
"Impossible de vérifier l'existance du SIRET"
|
|
)
|
|
validate = False
|
|
entreprise = Entreprise.query.filter_by(siret=siret_data).first()
|
|
if entreprise is not None:
|
|
if entreprise.visible is True:
|
|
lien = f"<a href='{url_for('entreprises.fiche_entreprise', entreprise_id=entreprise.id)}'>ici</a>"
|
|
self.siret.errors.append(
|
|
Markup(
|
|
f"Entreprise déjà présent, lien vers la fiche : {lien}"
|
|
)
|
|
)
|
|
validate = False
|
|
else:
|
|
self.siret.errors.append("Entreprise en phase de validation")
|
|
validate = False
|
|
|
|
if (
|
|
self.nom_correspondant.data.strip()
|
|
or self.prenom_correspondant.data.strip()
|
|
or self.telephone.data.strip()
|
|
or self.mail.data.strip()
|
|
or self.poste.data.strip()
|
|
or self.service.data.strip()
|
|
or self.origine.data.strip()
|
|
or self.notes.data.strip()
|
|
):
|
|
if not self.nom_correspondant.data.strip():
|
|
self.nom_correspondant.errors.append("Ce champ est requis")
|
|
validate = False
|
|
if not self.prenom_correspondant.data.strip():
|
|
self.prenom_correspondant.errors.append("Ce champ est requis")
|
|
validate = False
|
|
if not self.telephone.data.strip() and not self.mail.data.strip():
|
|
msg = "Saisir un moyen de contact (mail ou téléphone)"
|
|
self.telephone.errors.append(msg)
|
|
self.mail.errors.append(msg)
|
|
validate = False
|
|
|
|
return validate
|
|
|
|
|
|
class EntrepriseModificationForm(FlaskForm):
|
|
siret = StringField("SIRET (*)")
|
|
new_siret = StringField(
|
|
"Modification du SIRET provisoire (*)",
|
|
description="Activé uniquement pour les entreprises avec SIRET provisoire",
|
|
)
|
|
association = BooleanField("Association")
|
|
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)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.siret.render_kw = {"disabled": ""}
|
|
if self.siret.data.startswith(SIRET_PROVISOIRE_START) is True:
|
|
self.new_siret.validators = [Optional()]
|
|
else:
|
|
self.new_siret.render_kw = {"disabled": ""}
|
|
|
|
def validate_new_siret(self, new_siret):
|
|
if EntreprisePreferences.get_check_siret() and new_siret.data is not None:
|
|
siret_data = new_siret.data.strip().replace(" ", "")
|
|
self.new_siret.data = siret_data
|
|
if re.match("^\d{14}$", siret_data) is None:
|
|
raise ValidationError("Format incorrect")
|
|
else:
|
|
try:
|
|
req = requests.get(
|
|
f"https://entreprise.data.gouv.fr/api/sirene/v1/siret/{siret_data}",
|
|
timeout=scu.SCO_EXT_TIMEOUT,
|
|
)
|
|
if req.status_code != 200:
|
|
raise ValidationError("SIRET inexistant")
|
|
except requests.ConnectionError:
|
|
raise ValidationError("Impossible de vérifier l'existance du SIRET")
|
|
entreprise = Entreprise.query.filter_by(siret=siret_data).first()
|
|
if entreprise is not None:
|
|
if entreprise.visible is True:
|
|
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}"
|
|
)
|
|
)
|
|
else:
|
|
raise ValidationError("Entreprise en phase de validation")
|
|
|
|
|
|
class SiteCreationForm(FlaskForm):
|
|
hidden_entreprise_id = HiddenField()
|
|
nom = _build_string_field("Nom du site (*)")
|
|
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("Enregistrer", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|
|
|
|
def validate(self):
|
|
validate = True
|
|
if not FlaskForm.validate(self):
|
|
validate = False
|
|
|
|
site = EntrepriseSite.query.filter_by(
|
|
entreprise_id=self.hidden_entreprise_id.data, nom=self.nom.data
|
|
).first()
|
|
|
|
if site is not None:
|
|
self.nom.errors.append("Ce site existe déjà (même nom)")
|
|
validate = False
|
|
|
|
return validate
|
|
|
|
|
|
class SiteModificationForm(FlaskForm):
|
|
hidden_entreprise_id = HiddenField()
|
|
hidden_site_id = HiddenField()
|
|
nom = _build_string_field("Nom du site (*)")
|
|
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)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|
|
|
|
def validate(self):
|
|
validate = True
|
|
if not FlaskForm.validate(self):
|
|
validate = False
|
|
|
|
site = EntrepriseSite.query.filter(
|
|
EntrepriseSite.entreprise_id == self.hidden_entreprise_id.data,
|
|
EntrepriseSite.id != self.hidden_site_id.data,
|
|
EntrepriseSite.nom == self.nom.data,
|
|
).first()
|
|
|
|
if site is not None:
|
|
self.nom.errors.append("Ce site existe déjà (même nom)")
|
|
validate = False
|
|
|
|
return validate
|
|
|
|
|
|
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 à contacter", validators=[Optional()])
|
|
fichier = FileField(
|
|
"Fichier",
|
|
validators=[
|
|
Optional(),
|
|
FileAllowed(["pdf", "docx"], "Fichier .pdf ou .docx uniquement"),
|
|
],
|
|
)
|
|
submit = SubmitField("Enregistrer", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", 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 db.session.query(EntrepriseCorrespondant)
|
|
.join(EntrepriseSite, EntrepriseCorrespondant.site_id == EntrepriseSite.id)
|
|
.filter(EntrepriseSite.entreprise_id == self.hidden_entreprise_id.data)
|
|
.all()
|
|
]
|
|
|
|
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
|
|
|
|
if len(self.depts.data) < 1:
|
|
self.depts.errors.append("Choisir au moins un département")
|
|
validate = False
|
|
|
|
return validate
|
|
|
|
|
|
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 à contacter", validators=[Optional()])
|
|
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", 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 db.session.query(EntrepriseCorrespondant)
|
|
.join(EntrepriseSite, EntrepriseCorrespondant.site_id == EntrepriseSite.id)
|
|
.filter(EntrepriseSite.entreprise_id == self.hidden_entreprise_id.data)
|
|
.all()
|
|
]
|
|
|
|
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
|
|
|
|
if len(self.depts.data) < 1:
|
|
self.depts.errors.append("Choisir au moins un département")
|
|
validate = False
|
|
|
|
return validate
|
|
|
|
|
|
class CorrespondantCreationForm(FlaskForm):
|
|
civilite = SelectField(
|
|
"Civilité (*)",
|
|
choices=[("H", "Monsieur"), ("F", "Madame")],
|
|
validators=[DataRequired(message=CHAMP_REQUIS)],
|
|
render_kw={"class": "form-control"},
|
|
)
|
|
nom = StringField(
|
|
"Nom (*)",
|
|
validators=[DataRequired('Le champ "Nom" est requis')],
|
|
render_kw={"class": "form-control"},
|
|
)
|
|
prenom = StringField(
|
|
"Prénom (*)",
|
|
validators=[DataRequired('Le champ "Prénom" est requis')],
|
|
render_kw={"class": "form-control"},
|
|
)
|
|
telephone = _build_string_field(
|
|
"Téléphone (*)", required=False, render_kw={"class": "form-control"}
|
|
)
|
|
mail = StringField(
|
|
"Mail (*)",
|
|
validators=[Optional(), Email(message="Adresse e-mail invalide")],
|
|
render_kw={"class": "form-control"},
|
|
)
|
|
poste = _build_string_field(
|
|
"Poste", required=False, render_kw={"class": "form-control"}
|
|
)
|
|
service = _build_string_field(
|
|
"Service", required=False, render_kw={"class": "form-control"}
|
|
)
|
|
origine = _build_string_field(
|
|
"Origine", required=False, render_kw={"class": "form-control"}
|
|
)
|
|
notes = _build_string_field(
|
|
"Notes", required=False, render_kw={"class": "form-control"}
|
|
)
|
|
|
|
def validate(self):
|
|
validate = True
|
|
if not FlaskForm.validate(self):
|
|
validate = False
|
|
|
|
if not self.telephone.data and not self.mail.data:
|
|
msg = "Saisir un moyen de contact (mail ou téléphone)"
|
|
self.telephone.errors.append(msg)
|
|
validate = False
|
|
|
|
return validate
|
|
|
|
|
|
class CorrespondantsCreationForm(FlaskForm):
|
|
hidden_site_id = HiddenField()
|
|
correspondants = FieldList(FormField(CorrespondantCreationForm), min_entries=1)
|
|
submit = SubmitField("Enregistrer")
|
|
cancel = SubmitField("Annuler")
|
|
|
|
def validate(self):
|
|
validate = True
|
|
if not FlaskForm.validate(self):
|
|
validate = False
|
|
|
|
correspondant_list = []
|
|
for entry in self.correspondants.entries:
|
|
if entry.nom.data and entry.prenom.data:
|
|
if (
|
|
entry.nom.data.strip(),
|
|
entry.prenom.data.strip(),
|
|
) in correspondant_list:
|
|
entry.nom.errors.append(
|
|
"Vous avez saisi 2 fois le même nom et prenom"
|
|
)
|
|
entry.prenom.errors.append("")
|
|
validate = False
|
|
correspondant_list.append(
|
|
(entry.nom.data.strip(), entry.prenom.data.strip())
|
|
)
|
|
correspondant = EntrepriseCorrespondant.query.filter_by(
|
|
site_id=self.hidden_site_id.data,
|
|
nom=entry.nom.data,
|
|
prenom=entry.prenom.data,
|
|
).first()
|
|
if correspondant is not None:
|
|
entry.nom.errors.append(
|
|
"Ce correspondant existe déjà (même nom et prénom)"
|
|
)
|
|
entry.prenom.errors.append("")
|
|
validate = False
|
|
return validate
|
|
|
|
|
|
class CorrespondantModificationForm(FlaskForm):
|
|
hidden_correspondant_id = HiddenField()
|
|
hidden_site_id = HiddenField()
|
|
hidden_entreprise_id = HiddenField()
|
|
civilite = SelectField(
|
|
"Civilité (*)",
|
|
choices=[("H", "Monsieur"), ("F", "Madame")],
|
|
validators=[DataRequired(message=CHAMP_REQUIS)],
|
|
)
|
|
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)
|
|
origine = _build_string_field("Origine", required=False)
|
|
notes = _build_string_field("Notes", required=False)
|
|
site = SelectField(
|
|
"Site du correspondant", validators=[DataRequired()], description="Nom du site"
|
|
)
|
|
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.site.choices = [
|
|
(site.id, f"{site.nom}")
|
|
for site in db.session.query(EntrepriseSite)
|
|
.filter(EntrepriseSite.entreprise_id == self.hidden_entreprise_id.data)
|
|
.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.site_id == self.hidden_site_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:
|
|
msg = "Saisir un moyen de contact (mail ou téléphone)"
|
|
self.telephone.errors.append(msg)
|
|
self.mail.errors.append(msg)
|
|
validate = False
|
|
|
|
return validate
|
|
|
|
|
|
class ContactCreationForm(FlaskForm):
|
|
date = _build_string_field(
|
|
"Date (*)",
|
|
render_kw={"type": "datetime-local"},
|
|
)
|
|
utilisateur = _build_string_field(
|
|
"Utilisateur (*)",
|
|
render_kw={"placeholder": "Tapez le nom de l'utilisateur"},
|
|
)
|
|
notes = TextAreaField("Notes (*)", validators=[DataRequired(message=CHAMP_REQUIS)])
|
|
submit = SubmitField("Enregistrer", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|
|
|
|
def validate_utilisateur(self, utilisateur):
|
|
utilisateur_data = self.utilisateur.data.upper().strip()
|
|
stm = text(
|
|
"SELECT id, UPPER(CONCAT(nom, ' ', prenom, ' ', '(', user_name, ')')) FROM \"user\" WHERE UPPER(CONCAT(nom, ' ', prenom, ' ', '(', user_name, ')'))=:utilisateur_data"
|
|
)
|
|
utilisateur = (
|
|
User.query.from_statement(stm)
|
|
.params(utilisateur_data=utilisateur_data)
|
|
.first()
|
|
)
|
|
if utilisateur is None:
|
|
raise ValidationError("Champ incorrect (selectionnez dans la liste)")
|
|
|
|
|
|
class ContactModificationForm(FlaskForm):
|
|
date = _build_string_field(
|
|
"Date (*)",
|
|
render_kw={"type": "datetime-local"},
|
|
)
|
|
utilisateur = _build_string_field(
|
|
"Utilisateur (*)",
|
|
render_kw={"placeholder": "Tapez le nom de l'utilisateur"},
|
|
)
|
|
notes = TextAreaField("Notes (*)", validators=[DataRequired(message=CHAMP_REQUIS)])
|
|
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|
|
|
|
def validate_utilisateur(self, utilisateur):
|
|
utilisateur_data = self.utilisateur.data.upper().strip()
|
|
stm = text(
|
|
"SELECT id, UPPER(CONCAT(nom, ' ', prenom, ' ', '(', user_name, ')')) FROM \"user\" WHERE UPPER(CONCAT(nom, ' ', prenom, ' ', '(', user_name, ')'))=:utilisateur_data"
|
|
)
|
|
utilisateur = (
|
|
User.query.from_statement(stm)
|
|
.params(utilisateur_data=utilisateur_data)
|
|
.first()
|
|
)
|
|
if utilisateur is None:
|
|
raise ValidationError("Champ incorrect (selectionnez dans la liste)")
|
|
|
|
|
|
class StageApprentissageCreationForm(FlaskForm):
|
|
etudiant = _build_string_field(
|
|
"Étudiant (*)",
|
|
render_kw={"placeholder": "Tapez le nom de l'étudiant", "autocomplete": "off"},
|
|
)
|
|
etudid = HiddenField()
|
|
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)]
|
|
)
|
|
notes = TextAreaField("Notes")
|
|
submit = SubmitField("Enregistrer", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|
|
|
|
def validate(self, extra_validators=None):
|
|
validate = True
|
|
if not super().validate(extra_validators):
|
|
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_etudid(self, field):
|
|
"L'etudid doit avoit été placé par le JS"
|
|
etudid = int(field.data) if field.data else None
|
|
etudiant = Identite.query.get(etudid) if etudid is not None else None
|
|
if etudiant is None:
|
|
raise ValidationError("Étudiant introuvable (sélectionnez dans la liste)")
|
|
|
|
|
|
class TaxeApprentissageForm(FlaskForm):
|
|
hidden_entreprise_id = HiddenField()
|
|
annee = IntegerField(
|
|
"Année (*)",
|
|
validators=[
|
|
DataRequired(message=CHAMP_REQUIS),
|
|
NumberRange(
|
|
min=1900,
|
|
max=int(datetime.now().strftime("%Y")),
|
|
message=f"L'année doit être inférieure ou égale à {int(datetime.now().strftime('%Y'))}",
|
|
),
|
|
],
|
|
default=int(datetime.now().strftime("%Y")),
|
|
)
|
|
montant = IntegerField(
|
|
"Montant (*)",
|
|
validators=[
|
|
DataRequired(message=CHAMP_REQUIS),
|
|
NumberRange(
|
|
min=1,
|
|
message="Le montant doit être supérieur à 0",
|
|
),
|
|
],
|
|
default=1,
|
|
)
|
|
notes = TextAreaField("Notes")
|
|
submit = SubmitField("Enregistrer", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|
|
|
|
def validate(self):
|
|
validate = True
|
|
if not FlaskForm.validate(self):
|
|
validate = False
|
|
|
|
taxe = EntrepriseTaxeApprentissage.query.filter_by(
|
|
entreprise_id=self.hidden_entreprise_id.data, annee=self.annee.data
|
|
).first()
|
|
if taxe is not None:
|
|
self.annee.errors.append(
|
|
"Une taxe d'apprentissage a déjà été versé pour cette année"
|
|
)
|
|
validate = False
|
|
|
|
return validate
|
|
|
|
|
|
class TaxeApprentissageModificationForm(FlaskForm):
|
|
annee = IntegerField("Année (*)")
|
|
montant = IntegerField(
|
|
"Montant (*)",
|
|
validators=[
|
|
DataRequired(message=CHAMP_REQUIS),
|
|
NumberRange(
|
|
min=1,
|
|
message="Le montant doit être supérieur à 0",
|
|
),
|
|
],
|
|
default=1,
|
|
)
|
|
notes = TextAreaField("Notes")
|
|
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.annee.render_kw = {"disabled": ""}
|
|
|
|
|
|
class EnvoiOffreForm(FlaskForm):
|
|
responsables = FieldList(
|
|
StringField(
|
|
"Responsable (*)",
|
|
render_kw={
|
|
"placeholder": "Tapez le nom du responsable de formation",
|
|
"class": "form-control",
|
|
},
|
|
),
|
|
min_entries=1,
|
|
)
|
|
submit = SubmitField("Envoyer")
|
|
cancel = SubmitField("Annuler")
|
|
|
|
def validate(self):
|
|
validate = True
|
|
list_select = True
|
|
|
|
if not FlaskForm.validate(self):
|
|
validate = False
|
|
|
|
for entry in self.responsables.entries:
|
|
if entry.data:
|
|
responsable_data = entry.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:
|
|
validate, list_select = False, False
|
|
|
|
if list_select is False:
|
|
self.responsables.errors.append(
|
|
"Champ incorrect (selectionnez dans la liste)"
|
|
)
|
|
|
|
return validate
|
|
|
|
|
|
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)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|
|
|
|
|
|
class SuppressionConfirmationForm(FlaskForm):
|
|
submit = SubmitField("Supprimer", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|
|
|
|
|
|
class DesactivationConfirmationForm(FlaskForm):
|
|
notes_active = TextAreaField("Notes sur la désactivation", validators=[Optional()])
|
|
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|
|
|
|
|
|
class ActivationConfirmationForm(FlaskForm):
|
|
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|
|
|
|
|
|
class ValidationConfirmationForm(FlaskForm):
|
|
submit = SubmitField("Valider", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", 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")],
|
|
description="utilisé pour envoi mail notification application relations entreprises",
|
|
)
|
|
check_siret = BooleanField("Vérification SIRET")
|
|
submit = SubmitField("Valider", render_kw=SUBMIT_MARGE)
|
|
cancel = SubmitField("Annuler", render_kw=SUBMIT_MARGE)
|