diff --git a/app/entreprises/__init__.py b/app/entreprises/__init__.py index d9358508eb..44968ffb1b 100644 --- a/app/entreprises/__init__.py +++ b/app/entreprises/__init__.py @@ -9,17 +9,21 @@ bp = Blueprint("entreprises", __name__) LOGS_LEN = 10 + @bp.app_template_filter() def format_prenom(s): return sco_etud.format_prenom(s) + @bp.app_template_filter() def format_nom(s): return sco_etud.format_nom(s) + @bp.app_template_filter() def get_nomcomplet(s): user = User.query.filter_by(user_name=s).first() - return user.get_nomcomplet(); + return user.get_nomcomplet() -from app.entreprises import routes \ No newline at end of file + +from app.entreprises import routes diff --git a/app/entreprises/forms.py b/app/entreprises/forms.py index 1ce49cc02e..0e145f43df 100644 --- a/app/entreprises/forms.py +++ b/app/entreprises/forms.py @@ -4,7 +4,7 @@ from markupsafe import Markup import requests, re from wtforms import StringField, SubmitField, TextAreaField, SelectField, HiddenField from wtforms.fields.html5 import EmailField, DateField -from flask_wtf.file import FileField, FileAllowed +from flask_wtf.file import FileField, FileAllowed, FileRequired from wtforms.validators import ValidationError, DataRequired, Email from app.entreprises.models import Entreprise, EntrepriseContact from app.models import Identite @@ -12,20 +12,55 @@ from app.auth.models import User from app.scodoc import sco_etud from sqlalchemy import text -DATA_REQUIRED_ERROR_MESSAGE = "Ce champ est requis" +CHAMP_REQUIS = "Ce champ est requis" + class EntrepriseCreationForm(FlaskForm): - siret = StringField("SIRET", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)], render_kw={"placeholder": "Numéro composé de 14 chiffres", "maxlength": "14"}) - nom_entreprise = StringField("Nom de l'entreprise", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - adresse = StringField("Adresse de l'entreprise", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - codepostal = StringField("Code postal de l'entreprise", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - ville = StringField("Ville de l'entreprise", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - pays = StringField("Pays de l'entreprise", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)], render_kw={"style": "margin-bottom: 50px;"}) + siret = StringField( + "SIRET", + validators=[DataRequired(message=CHAMP_REQUIS)], + render_kw={"placeholder": "Numéro composé de 14 chiffres", "maxlength": "14"}, + ) + nom_entreprise = StringField( + "Nom de l'entreprise", + validators=[DataRequired(message=CHAMP_REQUIS)], + ) + adresse = StringField( + "Adresse de l'entreprise", + validators=[DataRequired(message=CHAMP_REQUIS)], + ) + codepostal = StringField( + "Code postal de l'entreprise", + validators=[DataRequired(message=CHAMP_REQUIS)], + ) + ville = StringField( + "Ville de l'entreprise", + validators=[DataRequired(message=CHAMP_REQUIS)], + ) + pays = StringField( + "Pays de l'entreprise", + validators=[DataRequired(message=CHAMP_REQUIS)], + render_kw={"style": "margin-bottom: 50px;"}, + ) - nom_contact = StringField("Nom du contact", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - prenom_contact = StringField("Prénom du contact", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - telephone = StringField("Téléphone du contact", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - mail = EmailField("Mail du contact", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE), Email(message="Adresse e-mail invalide")]) + nom_contact = StringField( + "Nom du contact", validators=[DataRequired(message=CHAMP_REQUIS)] + ) + prenom_contact = StringField( + "Prénom du contact", + validators=[DataRequired(message=CHAMP_REQUIS)], + ) + telephone = StringField( + "Téléphone du contact", + validators=[DataRequired(message=CHAMP_REQUIS)], + ) + mail = EmailField( + "Mail du contact", + validators=[ + DataRequired(message=CHAMP_REQUIS), + Email(message="Adresse e-mail invalide"), + ], + ) poste = StringField("Poste du contact", validators=[]) service = StringField("Service du contact", validators=[]) submit = SubmitField("Envoyer", render_kw={"style": "margin-bottom: 10px;"}) @@ -34,46 +69,82 @@ class EntrepriseCreationForm(FlaskForm): siret = siret.data.strip() if re.match("^\d{14}$", siret) == None: raise ValidationError("Format incorrect") - req = requests.get(f"https://entreprise.data.gouv.fr/api/sirene/v1/siret/{siret}") + req = requests.get( + f"https://entreprise.data.gouv.fr/api/sirene/v1/siret/{siret}" + ) if req.status_code != 200: raise ValidationError("SIRET inexistant") entreprise = Entreprise.query.filter_by(siret=siret).first() if entreprise is not None: - lien = f"ici" - raise ValidationError(Markup(f"Entreprise déjà présent, lien vers la fiche : {lien}")) + lien = f'ici' + raise ValidationError( + Markup(f"Entreprise déjà présent, lien vers la fiche : {lien}") + ) + class EntrepriseModificationForm(FlaskForm): - siret = StringField("SIRET", validators=[], render_kw={"disabled":""}) - nom = StringField("Nom de l'entreprise", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - adresse = StringField("Adresse", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - codepostal = StringField("Code postal", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - ville = StringField("Ville", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - pays = StringField("Pays", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) + siret = StringField("SIRET", validators=[], render_kw={"disabled": ""}) + nom = StringField( + "Nom de l'entreprise", + validators=[DataRequired(message=CHAMP_REQUIS)], + ) + adresse = StringField("Adresse", validators=[DataRequired(message=CHAMP_REQUIS)]) + codepostal = StringField( + "Code postal", validators=[DataRequired(message=CHAMP_REQUIS)] + ) + ville = StringField("Ville", validators=[DataRequired(message=CHAMP_REQUIS)]) + pays = StringField("Pays", validators=[DataRequired(message=CHAMP_REQUIS)]) submit = SubmitField("Modifier", render_kw={"style": "margin-bottom: 10px;"}) + class OffreCreationForm(FlaskForm): - intitule = StringField("Intitulé", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - description = TextAreaField("Description", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - type_offre = SelectField("Type de l'offre", choices=[('Stage'), ('Alternance')], validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - missions = TextAreaField("Missions", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - duree = StringField("Durée", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - fichier = FileField("Fichier", validators=[FileAllowed(['pdf', 'docx'], 'Fichier .pdf ou .docx uniquement')]) + intitule = StringField("Intitulé", validators=[DataRequired(message=CHAMP_REQUIS)]) + 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 = StringField("Durée", validators=[DataRequired(message=CHAMP_REQUIS)]) submit = SubmitField("Envoyer", render_kw={"style": "margin-bottom: 10px;"}) + class OffreModificationForm(FlaskForm): - intitule = StringField("Intitulé", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - description = TextAreaField("Description", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - type_offre = SelectField("Type de l'offre", choices=[('Stage'), ('Alternance')], validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - missions = TextAreaField("Missions", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - duree = StringField("Durée", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) + intitule = StringField("Intitulé", validators=[DataRequired(message=CHAMP_REQUIS)]) + 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 = StringField("Durée", validators=[DataRequired(message=CHAMP_REQUIS)]) submit = SubmitField("Modifier", render_kw={"style": "margin-bottom: 10px;"}) + class ContactCreationForm(FlaskForm): hidden_entreprise_id = HiddenField() - nom = StringField("Nom", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - prenom = StringField("Prénom", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - telephone = StringField("Téléphone", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - mail = EmailField("Mail", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE), Email(message="Adresse e-mail invalide")]) + nom = StringField("Nom", validators=[DataRequired(message=CHAMP_REQUIS)]) + prenom = StringField("Prénom", validators=[DataRequired(message=CHAMP_REQUIS)]) + telephone = StringField( + "Téléphone", validators=[DataRequired(message=CHAMP_REQUIS)] + ) + mail = EmailField( + "Mail", + validators=[ + DataRequired(message=CHAMP_REQUIS), + Email(message="Adresse e-mail invalide"), + ], + ) poste = StringField("Poste", validators=[]) service = StringField("Service", validators=[]) submit = SubmitField("Envoyer", render_kw={"style": "margin-bottom: 10px;"}) @@ -82,11 +153,11 @@ class ContactCreationForm(FlaskForm): rv = FlaskForm.validate(self) if not rv: return False - + contact = EntrepriseContact.query.filter_by( - entreprise_id = self.hidden_entreprise_id.data, - nom = self.nom.data, - prenom = self.prenom.data + entreprise_id=self.hidden_entreprise_id.data, + nom=self.nom.data, + prenom=self.prenom.data, ).first() if contact is not None: @@ -96,20 +167,40 @@ class ContactCreationForm(FlaskForm): return True + class ContactModificationForm(FlaskForm): - nom = StringField("Nom", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - prenom = StringField("Prénom", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - telephone = StringField("Téléphone", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - mail = EmailField("Mail", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE), Email(message="Adresse e-mail invalide")]) + nom = StringField("Nom", validators=[DataRequired(message=CHAMP_REQUIS)]) + prenom = StringField("Prénom", validators=[DataRequired(message=CHAMP_REQUIS)]) + telephone = StringField( + "Téléphone", validators=[DataRequired(message=CHAMP_REQUIS)] + ) + mail = EmailField( + "Mail", + validators=[ + DataRequired(message=CHAMP_REQUIS), + Email(message="Adresse e-mail invalide"), + ], + ) poste = StringField("Poste", validators=[]) service = StringField("Service", validators=[]) submit = SubmitField("Modifier", render_kw={"style": "margin-bottom: 10px;"}) + class HistoriqueCreationForm(FlaskForm): - etudiant = StringField("Étudiant", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)], render_kw={"placeholder": "Tapez le nom de l'étudiant puis selectionnez"}) - type_offre = SelectField("Type de l'offre", choices=[('Stage'), ('Alternance')], validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - date_debut = DateField("Date début", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - date_fin = DateField("Date fin", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) + etudiant = StringField( + "Étudiant", + validators=[DataRequired(message=CHAMP_REQUIS)], + render_kw={"placeholder": "Tapez le nom de l'étudiant puis selectionnez"}, + ) + 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={"style": "margin-bottom: 10px;"}) def validate(self): @@ -125,21 +216,47 @@ class HistoriqueCreationForm(FlaskForm): 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() + 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 = StringField("Responsable de formation", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) + responsable = StringField( + "Responsable de formation", + validators=[DataRequired(message=CHAMP_REQUIS)], + ) submit = SubmitField("Envoyer", render_kw={"style": "margin-bottom: 10px;"}) 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() + 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("Envoyer", render_kw={"style": "margin-bottom: 10px;"}) + + class SuppressionConfirmationForm(FlaskForm): - submit = SubmitField("Supprimer", render_kw={"style": "margin-bottom: 10px;"}) \ No newline at end of file + submit = SubmitField("Supprimer", render_kw={"style": "margin-bottom: 10px;"}) diff --git a/app/entreprises/models.py b/app/entreprises/models.py index 3e2211e22b..b0cd25de72 100644 --- a/app/entreprises/models.py +++ b/app/entreprises/models.py @@ -1,5 +1,6 @@ from app import db + class Entreprise(db.Model): __tablename__ = "entreprises" id = db.Column(db.Integer, primary_key=True) @@ -9,51 +10,67 @@ class Entreprise(db.Model): codepostal = db.Column(db.Text) ville = db.Column(db.Text) pays = db.Column(db.Text) - contacts = db.relationship('EntrepriseContact', backref='entreprise', lazy='dynamic', cascade="all, delete-orphan") - offres = db.relationship('EntrepriseOffre', backref='entreprise', lazy='dynamic', cascade="all, delete-orphan") + contacts = db.relationship( + "EntrepriseContact", + backref="entreprise", + lazy="dynamic", + cascade="all, delete-orphan", + ) + offres = db.relationship( + "EntrepriseOffre", + backref="entreprise", + lazy="dynamic", + cascade="all, delete-orphan", + ) - def to_dict_export(self): + def to_dict(self): return { "siret": self.siret, "nom": self.nom, "adresse": self.adresse, "codepostal": self.codepostal, "ville": self.ville, - "pays": self.pays + "pays": self.pays, } + class EntrepriseContact(db.Model): __tablename__ = "entreprise_contact" id = db.Column(db.Integer, primary_key=True) - entreprise_id = db.Column(db.Integer, db.ForeignKey("entreprises.id", ondelete="cascade")) + entreprise_id = db.Column( + db.Integer, db.ForeignKey("entreprises.id", ondelete="cascade") + ) nom = db.Column(db.Text) prenom = db.Column(db.Text) telephone = db.Column(db.Text) mail = db.Column(db.Text) poste = db.Column(db.Text) service = db.Column(db.Text) - - def to_dict_export(self): + + def to_dict(self): return { "nom": self.nom, "prenom": self.prenom, "telephone": self.telephone, "mail": self.mail, "poste": self.poste, - "service": self.service + "service": self.service, } + class EntrepriseOffre(db.Model): __tablename__ = "entreprise_offre" id = db.Column(db.Integer, primary_key=True) - entreprise_id = db.Column(db.Integer, db.ForeignKey("entreprises.id", ondelete="cascade")) + entreprise_id = db.Column( + db.Integer, db.ForeignKey("entreprises.id", ondelete="cascade") + ) date_ajout = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) intitule = db.Column(db.Text) description = db.Column(db.Text) type_offre = db.Column(db.Text) missions = db.Column(db.Text) duree = db.Column(db.Text) - filename = db.Column(db.Text) + class EntrepriseLog(db.Model): __tablename__ = "entreprise_log" @@ -63,6 +80,7 @@ class EntrepriseLog(db.Model): object = db.Column(db.Integer) text = db.Column(db.Text) + class EntrepriseEtudiant(db.Model): __tablename__ = "entreprise_etudiant" id = db.Column(db.Integer, primary_key=True) @@ -74,9 +92,11 @@ class EntrepriseEtudiant(db.Model): formation_text = db.Column(db.Text) formation_scodoc = db.Column(db.Integer) + class EntrepriseEnvoiOffre(db.Model): __tablename__ = "entreprise_envoi_offre" id = db.Column(db.Integer, primary_key=True) - user_id = db.Column(db.Integer, db.ForeignKey("user.id")) + sender_id = db.Column(db.Integer, db.ForeignKey("user.id")) + receiver_id = db.Column(db.Integer, db.ForeignKey("user.id")) offre_id = db.Column(db.Integer, db.ForeignKey("entreprise_offre.id")) - date_envoi = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) \ No newline at end of file + date_envoi = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) diff --git a/app/entreprises/routes.py b/app/entreprises/routes.py index 94af6a758b..99d1cabe22 100644 --- a/app/entreprises/routes.py +++ b/app/entreprises/routes.py @@ -1,5 +1,8 @@ import os from config import Config +from datetime import datetime +import glob +import shutil from flask import render_template, redirect, url_for, request, flash, send_file, abort from flask.json import jsonify @@ -17,7 +20,8 @@ from app.entreprises.forms import ( ContactCreationForm, ContactModificationForm, HistoriqueCreationForm, - EnvoiOffreForm + EnvoiOffreForm, + AjoutFichierForm, ) from app.entreprises import bp from app.entreprises.models import ( @@ -26,11 +30,9 @@ from app.entreprises.models import ( EntrepriseContact, EntrepriseLog, EntrepriseEtudiant, - EntrepriseEnvoiOffre -) -from app.models import ( - Identite + EntrepriseEnvoiOffre, ) +from app.models import Identite from app.auth.models import User from app.scodoc.sco_find_etud import search_etud_by_name from app.scodoc.sco_permissions import Permission @@ -41,35 +43,88 @@ from app import db from sqlalchemy import text from werkzeug.utils import secure_filename, send_from_directory + @bp.route("/", methods=["GET"]) def index(): entreprises = Entreprise.query.all() logs = EntrepriseLog.query.order_by(EntrepriseLog.date.desc()).limit(LOGS_LEN).all() - return render_template("entreprises/entreprises.html", title=("Entreprises"), entreprises=entreprises, logs=logs) + return render_template( + "entreprises/entreprises.html", + title=("Entreprises"), + entreprises=entreprises, + logs=logs, + ) + @bp.route("/contacts", methods=["GET"]) def contacts(): - contacts = db.session.query(EntrepriseContact, Entreprise).\ - join(Entreprise, EntrepriseContact.entreprise_id == Entreprise.id).all() + contacts = ( + db.session.query(EntrepriseContact, Entreprise) + .join(Entreprise, EntrepriseContact.entreprise_id == Entreprise.id) + .all() + ) logs = EntrepriseLog.query.order_by(EntrepriseLog.date.desc()).limit(LOGS_LEN).all() - return render_template("entreprises/contacts.html", title=("Contacts"), contacts=contacts, logs=logs) + return render_template( + "entreprises/contacts.html", title=("Contacts"), contacts=contacts, logs=logs + ) + @bp.route("/fiche_entreprise/", methods=["GET"]) def fiche_entreprise(id): entreprise = Entreprise.query.filter_by(id=id).first_or_404() offres = entreprise.offres + offres_with_files = [] + for offre in offres: + path = os.path.join( + Config.SCODOC_VAR_DIR, "entreprises", f"{entreprise.id}", f"{offre.id}" + ) + if os.path.exists(path): + files = [] + for dir in glob.glob( + f"{path}/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]" + ): + for file in glob.glob(f"{dir}/*"): + file = [os.path.basename(dir), os.path.basename(file)] + files.append(file) + offres_with_files.append([offre, files]) + print(offres_with_files) contacts = entreprise.contacts - logs = EntrepriseLog.query.order_by(EntrepriseLog.date.desc()).filter_by(object=id).limit(LOGS_LEN).all() - historique = db.session.query(EntrepriseEtudiant, Identite).order_by(EntrepriseEtudiant.date_debut.desc()).\ - filter(EntrepriseEtudiant.entreprise_id == id).\ - join(Identite, Identite.id == EntrepriseEtudiant.etudid).all() - return render_template("entreprises/fiche_entreprise.html", title=("Fiche entreprise"), entreprise=entreprise, contacts=contacts, offres=offres, logs=logs, historique=historique) + logs = ( + EntrepriseLog.query.order_by(EntrepriseLog.date.desc()) + .filter_by(object=id) + .limit(LOGS_LEN) + .all() + ) + historique = ( + db.session.query(EntrepriseEtudiant, Identite) + .order_by(EntrepriseEtudiant.date_debut.desc()) + .filter(EntrepriseEtudiant.entreprise_id == id) + .join(Identite, Identite.id == EntrepriseEtudiant.etudid) + .all() + ) + return render_template( + "entreprises/fiche_entreprise.html", + title=("Fiche entreprise"), + entreprise=entreprise, + contacts=contacts, + offres=offres_with_files, + logs=logs, + historique=historique, + ) + @bp.route("/offres", methods=["GET"]) def offres(): - offres_recus = db.session.query(EntrepriseEnvoiOffre, EntrepriseOffre).filter(EntrepriseEnvoiOffre.user_id == current_user.id).\ - join(EntrepriseOffre, EntrepriseOffre.id == EntrepriseEnvoiOffre.offre_id).all() - return render_template("entreprises/offres.html", title=("Offres"), offres_recus=offres_recus) + offres_recus = ( + db.session.query(EntrepriseEnvoiOffre, EntrepriseOffre) + .filter(EntrepriseEnvoiOffre.receiver_id == current_user.id) + .join(EntrepriseOffre, EntrepriseOffre.id == EntrepriseEnvoiOffre.offre_id) + .all() + ) + return render_template( + "entreprises/offres.html", title=("Offres"), offres_recus=offres_recus + ) + @bp.route("/add_entreprise", methods=["GET", "POST"]) def add_entreprise(): @@ -81,7 +136,7 @@ def add_entreprise(): adresse=form.adresse.data.strip(), codepostal=form.codepostal.data.strip(), ville=form.ville.data.strip(), - pays=form.pays.data.strip() + pays=form.pays.data.strip(), ) db.session.add(entreprise) db.session.commit() @@ -93,19 +148,24 @@ def add_entreprise(): telephone=form.telephone.data.strip(), mail=form.mail.data.strip(), poste=form.poste.data.strip(), - service=form.service.data.strip() + service=form.service.data.strip(), ) db.session.add(contact) nom_entreprise = f"{entreprise.nom}" log = EntrepriseLog( - authenticated_user = current_user.user_name, - text = f"{nom_entreprise} - Création de la fiche entreprise ({entreprise.nom}) avec un contact", + authenticated_user=current_user.user_name, + text=f"{nom_entreprise} - Création de la fiche entreprise ({entreprise.nom}) avec un contact", ) db.session.add(log) db.session.commit() flash("L'entreprise a été ajouté à la liste.") return redirect(url_for("entreprises.index")) - return render_template("entreprises/ajout_entreprise.html", title=("Ajout entreprise + contact"), form=form) + return render_template( + "entreprises/ajout_entreprise.html", + title=("Ajout entreprise + contact"), + form=form, + ) + @bp.route("/edit_entreprise/", methods=["GET", "POST"]) def edit_entreprise(id): @@ -115,55 +175,58 @@ def edit_entreprise(id): nom_entreprise = f"{form.nom.data.strip()}" if entreprise.nom != form.nom.data.strip(): log = EntrepriseLog( - authenticated_user = current_user.user_name, - object = entreprise.id, - text = f"{nom_entreprise} - Modification du nom (ancien nom : {entreprise.nom})", + authenticated_user=current_user.user_name, + object=entreprise.id, + text=f"{nom_entreprise} - Modification du nom (ancien nom : {entreprise.nom})", ) entreprise.nom = form.nom.data.strip() db.session.add(log) if entreprise.adresse != form.adresse.data.strip(): log = EntrepriseLog( - authenticated_user = current_user.user_name, - object = entreprise.id, - text = f"{nom_entreprise} - Modification de l'adresse (ancienne adresse : {entreprise.adresse})", + authenticated_user=current_user.user_name, + object=entreprise.id, + text=f"{nom_entreprise} - Modification de l'adresse (ancienne adresse : {entreprise.adresse})", ) entreprise.adresse = form.adresse.data.strip() db.session.add(log) if entreprise.codepostal != form.codepostal.data.strip(): log = EntrepriseLog( - authenticated_user = current_user.user_name, - object = entreprise.id, - text = f"{nom_entreprise} - Modification du code postal (ancien code postal : {entreprise.codepostal})", + authenticated_user=current_user.user_name, + object=entreprise.id, + text=f"{nom_entreprise} - Modification du code postal (ancien code postal : {entreprise.codepostal})", ) entreprise.codepostal = form.codepostal.data.strip() db.session.add(log) if entreprise.ville != form.ville.data.strip(): log = EntrepriseLog( - authenticated_user = current_user.user_name, - object = entreprise.id, - text = f"{nom_entreprise} - Modification de la ville (ancienne ville : {entreprise.ville})", + authenticated_user=current_user.user_name, + object=entreprise.id, + text=f"{nom_entreprise} - Modification de la ville (ancienne ville : {entreprise.ville})", ) entreprise.ville = form.ville.data.strip() db.session.add(log) if entreprise.pays != form.pays.data.strip(): log = EntrepriseLog( - authenticated_user = current_user.user_name, - object = entreprise.id, - text = f"{nom_entreprise} - Modification du pays (ancien pays : {entreprise.pays})", + authenticated_user=current_user.user_name, + object=entreprise.id, + text=f"{nom_entreprise} - Modification du pays (ancien pays : {entreprise.pays})", ) entreprise.pays = form.pays.data.strip() db.session.add(log) db.session.commit() flash("L'entreprise a été modifié.") return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id)) - elif request.method == 'GET': + elif request.method == "GET": form.siret.data = entreprise.siret form.nom.data = entreprise.nom form.adresse.data = entreprise.adresse form.codepostal.data = entreprise.codepostal form.ville.data = entreprise.ville form.pays.data = entreprise.pays - return render_template("entreprises/form.html", title=("Modification entreprise"), form=form) + return render_template( + "entreprises/form.html", title=("Modification entreprise"), form=form + ) + @bp.route("/delete_entreprise/", methods=["GET", "POST"]) def delete_entreprise(id): @@ -172,15 +235,20 @@ def delete_entreprise(id): if form.validate_on_submit(): db.session.delete(entreprise) log = EntrepriseLog( - authenticated_user = current_user.user_name, - object = entreprise.id, - text = f"Suppression de la fiche entreprise ({entreprise.nom})", + authenticated_user=current_user.user_name, + object=entreprise.id, + text=f"Suppression de la fiche entreprise ({entreprise.nom})", ) db.session.add(log) db.session.commit() flash("L'entreprise a été supprimé de la liste.") return redirect(url_for("entreprises.index")) - return render_template("entreprises/delete_confirmation.html", title=("Supression entreprise"), form=form) + return render_template( + "entreprises/delete_confirmation.html", + title=("Supression entreprise"), + form=form, + ) + @bp.route("/add_offre/", methods=["GET", "POST"]) def add_offre(id): @@ -193,30 +261,21 @@ def add_offre(id): description=form.description.data.strip(), type_offre=form.type_offre.data.strip(), missions=form.missions.data.strip(), - duree=form.duree.data.strip() + duree=form.duree.data.strip(), + ) + log = EntrepriseLog( + authenticated_user=current_user.user_name, + object=entreprise.id, + text="Création d'une offre", ) db.session.add(offre) - db.session.commit() - if form.fichier.data is not None: - db.session.refresh(offre) - path = os.path.join(Config.SCODOC_VAR_DIR, "entreprises", f"{entreprise.id}", f"{offre.id}") - os.makedirs(path) - file = form.fichier.data - filename = secure_filename(file.filename) - file.save(os.path.join(path, filename)) - offre.filename = f"{filename}" - db.session.commit() - log = EntrepriseLog( - authenticated_user = current_user.user_name, - object = entreprise.id, - text = "Création d'une offre", - ) db.session.add(log) db.session.commit() flash("L'offre a été ajouté à la fiche entreprise.") return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id)) return render_template("entreprises/form.html", title=("Ajout offre"), form=form) + @bp.route("/edit_offre/", methods=["GET", "POST"]) def edit_offre(id): offre = EntrepriseOffre.query.filter_by(id=id).first_or_404() @@ -228,21 +287,24 @@ def edit_offre(id): offre.missions = form.missions.data.strip() offre.duree = form.duree.data.strip() log = EntrepriseLog( - authenticated_user = current_user.user_name, - object = offre.entreprise_id, - text = "Modification d'une offre", + authenticated_user=current_user.user_name, + object=offre.entreprise_id, + text="Modification d'une offre", ) db.session.add(log) db.session.commit() flash("L'offre a été modifié.") return redirect(url_for("entreprises.fiche_entreprise", id=offre.entreprise.id)) - elif request.method == 'GET': + elif request.method == "GET": form.intitule.data = offre.intitule form.description.data = offre.description form.type_offre.data = offre.type_offre form.missions.data = offre.missions form.duree.data = offre.duree - return render_template("entreprises/form.html", title=("Modification offre"), form=form) + return render_template( + "entreprises/form.html", title=("Modification offre"), form=form + ) + @bp.route("/delete_offre/", methods=["GET", "POST"]) def delete_offre(id): @@ -252,16 +314,19 @@ def delete_offre(id): if form.validate_on_submit(): db.session.delete(offre) log = EntrepriseLog( - authenticated_user = current_user.user_name, - object = offre.entreprise_id, - text = "Suppression d'une offre", + authenticated_user=current_user.user_name, + object=offre.entreprise_id, + text="Suppression d'une offre", ) db.session.add(log) db.session.commit() flash("L'offre a été supprimé de la fiche entreprise.") return redirect(url_for("entreprises.fiche_entreprise", id=entreprise_id)) - return render_template("entreprises/delete_confirmation.html", title=("Supression offre"), form=form) - + return render_template( + "entreprises/delete_confirmation.html", title=("Supression offre"), form=form + ) + + @bp.route("/add_contact/", methods=["GET", "POST"]) def add_contact(id): entreprise = Entreprise.query.filter_by(id=id).first_or_404() @@ -274,12 +339,12 @@ def add_contact(id): telephone=form.telephone.data.strip(), mail=form.mail.data.strip(), poste=form.poste.data.strip(), - service=form.service.data.strip() + service=form.service.data.strip(), ) log = EntrepriseLog( - authenticated_user = current_user.user_name, - object = entreprise.id, - text = "Création d'un contact", + authenticated_user=current_user.user_name, + object=entreprise.id, + text="Création d'un contact", ) db.session.add(log) db.session.add(contact) @@ -288,6 +353,7 @@ def add_contact(id): return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id)) return render_template("entreprises/form.html", title=("Ajout contact"), form=form) + @bp.route("/edit_contact/", methods=["GET", "POST"]) def edit_contact(id): contact = EntrepriseContact.query.filter_by(id=id).first_or_404() @@ -300,22 +366,27 @@ def edit_contact(id): contact.poste = form.poste.data.strip() contact.service = form.service.data.strip() log = EntrepriseLog( - authenticated_user = current_user.user_name, - object = contact.entreprise_id, - text = "Modification d'un contact", + authenticated_user=current_user.user_name, + object=contact.entreprise_id, + text="Modification d'un contact", ) db.session.add(log) db.session.commit() flash("Le contact a été modifié.") - return redirect(url_for("entreprises.fiche_entreprise", id=contact.entreprise.id)) - elif request.method == 'GET': + return redirect( + url_for("entreprises.fiche_entreprise", id=contact.entreprise.id) + ) + elif request.method == "GET": form.nom.data = contact.nom form.prenom.data = contact.prenom form.telephone.data = contact.telephone form.mail.data = contact.mail form.poste.data = contact.poste form.service.data = contact.service - return render_template("entreprises/form.html", title=("Modification contact"), form=form) + return render_template( + "entreprises/form.html", title=("Modification contact"), form=form + ) + @bp.route("/delete_contact/", methods=["GET", "POST"]) def delete_contact(id): @@ -323,22 +394,29 @@ def delete_contact(id): entreprise_id = contact.entreprise.id form = SuppressionConfirmationForm() if form.validate_on_submit(): - contact_count = EntrepriseContact.query.filter_by(entreprise_id=contact.entreprise.id).count() + contact_count = EntrepriseContact.query.filter_by( + entreprise_id=contact.entreprise.id + ).count() if contact_count == 1: - flash("Le contact n'a pas été supprimé de la fiche entreprise. (1 contact minimum)") + flash( + "Le contact n'a pas été supprimé de la fiche entreprise. (1 contact minimum)" + ) return redirect(url_for("entreprises.fiche_entreprise", id=entreprise_id)) else: db.session.delete(contact) log = EntrepriseLog( - authenticated_user = current_user.user_name, - object = contact.entreprise_id, - text = "Suppression d'un contact", + authenticated_user=current_user.user_name, + object=contact.entreprise_id, + text="Suppression d'un contact", ) db.session.add(log) db.session.commit() flash("Le contact a été supprimé de la fiche entreprise.") return redirect(url_for("entreprises.fiche_entreprise", id=entreprise_id)) - return render_template("entreprises/delete_confirmation.html", title=("Supression contact"), form=form) + return render_template( + "entreprises/delete_confirmation.html", title=("Supression contact"), form=form + ) + @bp.route("/add_historique/", methods=["GET", "POST"]) def add_historique(id): @@ -346,25 +424,36 @@ def add_historique(id): form = HistoriqueCreationForm() if form.validate_on_submit(): etudiant_nomcomplet = form.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_nomcomplet).first() - formation = etudiant.inscription_courante_date(form.date_debut.data, form.date_fin.data) + 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_nomcomplet) + .first() + ) + formation = etudiant.inscription_courante_date( + form.date_debut.data, form.date_fin.data + ) historique = EntrepriseEtudiant( - entreprise_id = entreprise.id, - etudid = etudiant.id, - type_offre = form.type_offre.data.strip(), - date_debut = form.date_debut.data, - date_fin = form.date_fin.data, - formation_text = formation.formsemestre.titre - if formation else None, - formation_scodoc = formation.formsemestre.formsemestre_id - if formation else None + entreprise_id=entreprise.id, + etudid=etudiant.id, + type_offre=form.type_offre.data.strip(), + date_debut=form.date_debut.data, + date_fin=form.date_fin.data, + formation_text=formation.formsemestre.titre if formation else None, + formation_scodoc=formation.formsemestre.formsemestre_id + if formation + else None, ) db.session.add(historique) db.session.commit() flash("L'étudiant a été ajouté sur la fiche entreprise.") return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id)) - return render_template("entreprises/ajout_historique.html", title=("Ajout historique"), form=form) + return render_template( + "entreprises/ajout_historique.html", title=("Ajout historique"), form=form + ) + @bp.route("/envoyer_offre/", methods=["GET", "POST"]) def envoyer_offre(id): @@ -372,21 +461,29 @@ def envoyer_offre(id): form = EnvoiOffreForm() if form.validate_on_submit(): responsable_data = form.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() + 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() + ) envoi_offre = EntrepriseEnvoiOffre( - user_id = responsable.id, - offre_id = offre.id + sender_id=current_user.id, receiver_id=responsable.id, offre_id=offre.id ) db.session.add(envoi_offre) db.session.commit() flash(f"L'offre a été envoyé à {responsable.get_nomplogin()}.") return redirect(url_for("entreprises.fiche_entreprise", id=offre.entreprise_id)) - return render_template("entreprises/envoi_offre_form.html", title=("Envoyer une offre"), form=form) + return render_template( + "entreprises/envoi_offre_form.html", title=("Envoyer une offre"), form=form + ) + @bp.route("/etudiants") def json_etudiants(): - term = request.args.get('term').strip() + term = request.args.get("term").strip() etudiants = Identite.query.filter(Identite.nom.ilike(f"%{term}%")).all() list = [] content = {} @@ -396,48 +493,41 @@ def json_etudiants(): content = { "id": f"{etudiant.id}", "value": value, - "info": f"{etudiant.inscription_courante().formsemestre.titre}" + "info": f"{etudiant.inscription_courante().formsemestre.titre}", } else: - content = { - "id": f"{etudiant.id}", - "value": value - } + content = {"id": f"{etudiant.id}", "value": value} list.append(content) content = {} return jsonify(results=list) - + + @bp.route("/responsables") def json_responsables(): - term = request.args.get('term').strip() - responsables = User.query.filter(User.nom.ilike(f"%{term}%"), User.nom.is_not(None), User.prenom.is_not(None)).all() + term = request.args.get("term").strip() + responsables = User.query.filter( + User.nom.ilike(f"%{term}%"), User.nom.is_not(None), User.prenom.is_not(None) + ).all() list = [] content = {} for responsable in responsables: value = f"{responsable.get_nomplogin()}" - content = { - "id": f"{responsable.id}", - "value": value, - "info": "" - } + content = {"id": f"{responsable.id}", "value": value, "info": ""} list.append(content) content = {} return jsonify(results=list) + @bp.route("/export_entreprises") def export_entreprises(): entreprises = Entreprise.query.all() if entreprises: - keys=[ - "siret", - "nom", - "adresse", - "ville", - "codepostal", - "pays" - ] + keys = ["siret", "nom", "adresse", "ville", "codepostal", "pays"] titles = keys[:] - L = [[entreprise.to_dict_export().get(k, "") for k in keys] for entreprise in entreprises] + L = [ + [entreprise.to_dict_export().get(k, "") for k in keys] + for entreprise in entreprises + ] title = "entreprises" xlsx = sco_excel.excel_simple_table(titles=titles, lines=L, sheet_name=title) filename = title @@ -445,20 +535,16 @@ def export_entreprises(): else: abort(404) + @bp.route("/export_contacts") def export_contacts(): contacts = EntrepriseContact.query.all() if contacts: - keys=[ - "nom", - "prenom", - "telephone", - "mail", - "poste", - "service" - ] + keys = ["nom", "prenom", "telephone", "mail", "poste", "service"] titles = keys[:] - L = [[contact.to_dict_export().get(k, "") for k in keys] for contact in contacts] + L = [ + [contact.to_dict_export().get(k, "") for k in keys] for contact in contacts + ] title = "contacts" xlsx = sco_excel.excel_simple_table(titles=titles, lines=L, sheet_name=title) filename = title @@ -466,9 +552,80 @@ def export_contacts(): else: abort(404) -@bp.route("/download_offre///") -def download_offre(entreprise_id, offre_id, filename): - if os.path.isfile(os.path.join(Config.SCODOC_VAR_DIR, "entreprises", f"{entreprise_id}", f"{offre_id}", f"{filename}")): - return send_file(os.path.join(Config.SCODOC_VAR_DIR, "entreprises", f"{entreprise_id}", f"{offre_id}", f"{filename}"), as_attachment=True) + +@bp.route( + "/get_offre_file////" +) +def get_offre_file(entreprise_id, offre_id, filedir, filename): + if os.path.isfile( + os.path.join( + Config.SCODOC_VAR_DIR, + "entreprises", + f"{entreprise_id}", + f"{offre_id}", + f"{filedir}", + f"{filename}", + ) + ): + return send_file( + os.path.join( + Config.SCODOC_VAR_DIR, + "entreprises", + f"{entreprise_id}", + f"{offre_id}", + f"{filedir}", + f"{filename}", + ), + as_attachment=True, + ) else: - abort(404) \ No newline at end of file + abort(404) + + +@bp.route("/add_offre_file/", methods=["GET", "POST"]) +def add_offre_file(offre_id): + offre = EntrepriseOffre.query.filter_by(id=offre_id).first_or_404() + form = AjoutFichierForm() + if form.validate_on_submit(): + date = f"{datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}" + path = os.path.join( + Config.SCODOC_VAR_DIR, + "entreprises", + f"{offre.entreprise_id}", + f"{offre.id}", + f"{date}", + ) + os.makedirs(path) + file = form.fichier.data + filename = secure_filename(file.filename) + file.save(os.path.join(path, filename)) + flash("Le fichier a été ajouté a l'offre.") + return redirect(url_for("entreprises.fiche_entreprise", id=offre.entreprise_id)) + return render_template( + "entreprises/form.html", title=("Ajout fichier à une offre"), form=form + ) + + +@bp.route("/delete_offre_file//", methods=["GET", "POST"]) +def delete_offre_file(offre_id, filedir): + offre = EntrepriseOffre.query.filter_by(id=offre_id).first_or_404() + form = SuppressionConfirmationForm() + if form.validate_on_submit(): + path = os.path.join( + Config.SCODOC_VAR_DIR, + "entreprises", + f"{offre.entreprise_id}", + f"{offre_id}", + f"{filedir}", + ) + if os.path.isdir(path): + shutil.rmtree(path) + flash("Le fichier relié à l'offre a été supprimé.") + return redirect( + url_for("entreprises.fiche_entreprise", id=offre.entreprise_id) + ) + return render_template( + "entreprises/delete_confirmation.html", + title=("Suppression fichier d'une offre"), + form=form, + ) diff --git a/app/templates/entreprises/_offre.html b/app/templates/entreprises/_offre.html index 07aa4caa19..fd21211d21 100644 --- a/app/templates/entreprises/_offre.html +++ b/app/templates/entreprises/_offre.html @@ -1,18 +1,20 @@

- Intitulé : {{ offre.intitule }}
- Description : {{ offre.description }}
- Type de l'offre : {{ offre.type_offre }}
- Missions : {{ offre.missions }}
- Durée : {{ offre.duree }}
- {% if offre.filename %} - {{ offre.filename }} - {% endif %} + Intitulé : {{ offre[0].intitule }}
+ Description : {{ offre[0].description }}
+ Type de l'offre : {{ offre[0].type_offre }}
+ Missions : {{ offre[0].missions }}
+ Durée : {{ offre[0].duree }}
+ {% for fichier in offre[1] %} + {{ fichier[1] }} + supprimer
+ {% endfor %} + Ajoutez un fichier

\ No newline at end of file diff --git a/app/templates/entreprises/entreprises.html b/app/templates/entreprises/entreprises.html index 85854efb3a..9cbe2330fc 100644 --- a/app/templates/entreprises/entreprises.html +++ b/app/templates/entreprises/entreprises.html @@ -52,7 +52,7 @@
{% endif %} -
+
Ajouter une entreprise {% if entreprises %} Exporter la liste des entreprises diff --git a/app/templates/entreprises/fiche_entreprise.html b/app/templates/entreprises/fiche_entreprise.html index b84980366d..f3cc682693 100644 --- a/app/templates/entreprises/fiche_entreprise.html +++ b/app/templates/entreprises/fiche_entreprise.html @@ -55,7 +55,7 @@ {% if offres %}
{% for offre in offres %} - Offre {{loop.index}} (ajouté le {{offre.date_ajout.strftime('%d/%m/%Y') }}) + Offre {{loop.index}} (ajouté le {{offre[0].date_ajout.strftime('%d/%m/%Y') }}) {% include 'entreprises/_offre.html' %} {% endfor %}
diff --git a/migrations/versions/2dfafee725ae_creation_table_relations_entreprrises.py b/migrations/versions/2dfafee725ae_creation_table_relations_entreprrises.py index 3d48675708..126147c27a 100644 --- a/migrations/versions/2dfafee725ae_creation_table_relations_entreprrises.py +++ b/migrations/versions/2dfafee725ae_creation_table_relations_entreprrises.py @@ -49,7 +49,6 @@ def upgrade(): sa.Column('type_offre', sa.Text(), nullable=True), sa.Column('missions', sa.Text(), nullable=True), sa.Column('duree', sa.Text(), nullable=True), - sa.Column('filename', sa.Text(), nullable=True), sa.ForeignKeyConstraint(['entreprise_id'], ['entreprises.id'], ondelete='cascade'), sa.PrimaryKeyConstraint('id') )