diff --git a/app/entreprises/forms.py b/app/entreprises/forms.py index d2f3762b6..1ce49cc02 100644 --- a/app/entreprises/forms.py +++ b/app/entreprises/forms.py @@ -1,10 +1,10 @@ from flask import flash -from markupsafe import Markup -from flask.app import Flask -import requests, re from flask_wtf import FlaskForm -from wtforms import StringField, SubmitField, TextAreaField, SelectField, FileField, HiddenField +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 wtforms.validators import ValidationError, DataRequired, Email from app.entreprises.models import Entreprise, EntrepriseContact from app.models import Identite @@ -15,18 +15,20 @@ from sqlalchemy import text DATA_REQUIRED_ERROR_MESSAGE = "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"}) + 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)]) + pays = StringField("Pays de l'entreprise", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)], 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")]) - submit = SubmitField("Envoyer") + poste = StringField("Poste du contact", validators=[]) + service = StringField("Service du contact", validators=[]) + submit = SubmitField("Envoyer", render_kw={"style": "margin-bottom: 10px;"}) def validate_siret(self, siret): siret = siret.data.strip() @@ -47,7 +49,7 @@ class EntrepriseModificationForm(FlaskForm): 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)]) - submit = SubmitField("Modifier") + submit = SubmitField("Modifier", render_kw={"style": "margin-bottom: 10px;"}) class OffreCreationForm(FlaskForm): intitule = StringField("Intitulé", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) @@ -55,8 +57,8 @@ class OffreCreationForm(FlaskForm): 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)]) - ficher = FileField("Fichier", validators=[]) - submit = SubmitField("Envoyer") + fichier = FileField("Fichier", validators=[FileAllowed(['pdf', 'docx'], 'Fichier .pdf ou .docx uniquement')]) + submit = SubmitField("Envoyer", render_kw={"style": "margin-bottom: 10px;"}) class OffreModificationForm(FlaskForm): intitule = StringField("Intitulé", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) @@ -64,15 +66,17 @@ class OffreModificationForm(FlaskForm): 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)]) - submit = SubmitField("Modifier") + 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")]) - hidden_entreprise_id = HiddenField() - submit = SubmitField("Envoyer") + poste = StringField("Poste", validators=[]) + service = StringField("Service", validators=[]) + submit = SubmitField("Envoyer", render_kw={"style": "margin-bottom: 10px;"}) def validate(self): rv = FlaskForm.validate(self) @@ -97,14 +101,16 @@ class ContactModificationForm(FlaskForm): 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")]) - submit = SubmitField("Modifier") + 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)]) - submit = SubmitField("Envoyer") + submit = SubmitField("Envoyer", render_kw={"style": "margin-bottom: 10px;"}) def validate(self): rv = FlaskForm.validate(self) @@ -126,7 +132,7 @@ class HistoriqueCreationForm(FlaskForm): class EnvoiOffreForm(FlaskForm): responsable = StringField("Responsable de formation", validators=[DataRequired(message=DATA_REQUIRED_ERROR_MESSAGE)]) - submit = SubmitField("Envoyer") + submit = SubmitField("Envoyer", render_kw={"style": "margin-bottom: 10px;"}) def validate_responsable(self, responsable): responsable_data = responsable.data.upper().strip() @@ -136,4 +142,4 @@ class EnvoiOffreForm(FlaskForm): raise ValidationError("Champ incorrect (selectionnez dans la liste)") class SuppressionConfirmationForm(FlaskForm): - submit = SubmitField("Supprimer") \ No newline at end of file + submit = SubmitField("Supprimer", render_kw={"style": "margin-bottom: 10px;"}) \ No newline at end of file diff --git a/app/entreprises/models.py b/app/entreprises/models.py index ec963be20..3e2211e22 100644 --- a/app/entreprises/models.py +++ b/app/entreprises/models.py @@ -12,27 +12,48 @@ class Entreprise(db.Model): 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): + return { + "siret": self.siret, + "nom": self.nom, + "adresse": self.adresse, + "codepostal": self.codepostal, + "ville": self.ville, + "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")) + 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): + return { + "nom": self.nom, + "prenom": self.prenom, + "telephone": self.telephone, + "mail": self.mail, + "poste": self.poste, + "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")) + 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" diff --git a/app/entreprises/routes.py b/app/entreprises/routes.py index 1791199e5..94af6a758 100644 --- a/app/entreprises/routes.py +++ b/app/entreprises/routes.py @@ -1,9 +1,13 @@ -from flask import render_template, redirect, url_for, request, flash +import os +from config import Config + +from flask import render_template, redirect, url_for, request, flash, send_file, abort from flask.json import jsonify from flask_login import current_user + from app.decorators import permission_required + from app.entreprises import LOGS_LEN -from app.scodoc.sco_permissions import Permission from app.entreprises.forms import ( EntrepriseCreationForm, EntrepriseModificationForm, @@ -21,16 +25,21 @@ from app.entreprises.models import ( EntrepriseOffre, EntrepriseContact, EntrepriseLog, - EntrepriseEtudiant + EntrepriseEtudiant, + 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 +from app.scodoc import sco_etud, sco_excel +import app.scodoc.sco_utils as scu + from app import db -from app.scodoc import sco_etud from sqlalchemy import text +from werkzeug.utils import secure_filename, send_from_directory @bp.route("/", methods=["GET"]) def index(): @@ -45,17 +54,23 @@ def contacts(): logs = EntrepriseLog.query.order_by(EntrepriseLog.date.desc()).limit(LOGS_LEN).all() return render_template("entreprises/contacts.html", title=("Contacts"), contacts=contacts, logs=logs) -@bp.route("/fiche_entreprise/", methods=["GET"]) +@bp.route("/fiche_entreprise/", methods=["GET"]) def fiche_entreprise(id): entreprise = Entreprise.query.filter_by(id=id).first_or_404() offres = entreprise.offres 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_by(entreprise_id=id).\ + 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) +@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) + @bp.route("/add_entreprise", methods=["GET", "POST"]) def add_entreprise(): form = EntrepriseCreationForm() @@ -76,7 +91,9 @@ def add_entreprise(): nom=form.nom_contact.data.strip(), prenom=form.prenom_contact.data.strip(), telephone=form.telephone.data.strip(), - mail=form.mail.data.strip() + mail=form.mail.data.strip(), + poste=form.poste.data.strip(), + service=form.service.data.strip() ) db.session.add(contact) nom_entreprise = f"{entreprise.nom}" @@ -90,7 +107,7 @@ def add_entreprise(): return redirect(url_for("entreprises.index")) return render_template("entreprises/ajout_entreprise.html", title=("Ajout entreprise + contact"), form=form) -@bp.route("/edit_entreprise/", methods=["GET", "POST"]) +@bp.route("/edit_entreprise/", methods=["GET", "POST"]) def edit_entreprise(id): entreprise = Entreprise.query.filter_by(id=id).first_or_404() form = EntrepriseModificationForm() @@ -148,7 +165,7 @@ def edit_entreprise(id): form.pays.data = entreprise.pays return render_template("entreprises/form.html", title=("Modification entreprise"), form=form) -@bp.route("/delete_entreprise/", methods=["GET", "POST"]) +@bp.route("/delete_entreprise/", methods=["GET", "POST"]) def delete_entreprise(id): entreprise = Entreprise.query.filter_by(id=id).first_or_404() form = SuppressionConfirmationForm() @@ -165,7 +182,7 @@ def delete_entreprise(id): return redirect(url_for("entreprises.index")) return render_template("entreprises/delete_confirmation.html", title=("Supression entreprise"), form=form) -@bp.route("/add_offre/", methods=["GET", "POST"]) +@bp.route("/add_offre/", methods=["GET", "POST"]) def add_offre(id): entreprise = Entreprise.query.filter_by(id=id).first_or_404() form = OffreCreationForm() @@ -178,19 +195,29 @@ def add_offre(id): missions=form.missions.data.strip(), duree=form.duree.data.strip() ) + 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.add(offre) 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"]) +@bp.route("/edit_offre/", methods=["GET", "POST"]) def edit_offre(id): offre = EntrepriseOffre.query.filter_by(id=id).first_or_404() form = OffreModificationForm() @@ -217,7 +244,7 @@ def edit_offre(id): form.duree.data = offre.duree return render_template("entreprises/form.html", title=("Modification offre"), form=form) -@bp.route("/delete_offre/", methods=["GET", "POST"]) +@bp.route("/delete_offre/", methods=["GET", "POST"]) def delete_offre(id): offre = EntrepriseOffre.query.filter_by(id=id).first_or_404() entreprise_id = offre.entreprise.id @@ -235,7 +262,7 @@ def delete_offre(id): return redirect(url_for("entreprises.fiche_entreprise", id=entreprise_id)) return render_template("entreprises/delete_confirmation.html", title=("Supression offre"), form=form) -@bp.route("/add_contact/", methods=["GET", "POST"]) +@bp.route("/add_contact/", methods=["GET", "POST"]) def add_contact(id): entreprise = Entreprise.query.filter_by(id=id).first_or_404() form = ContactCreationForm(hidden_entreprise_id=entreprise.id) @@ -245,7 +272,9 @@ def add_contact(id): nom=form.nom.data.strip(), prenom=form.prenom.data.strip(), telephone=form.telephone.data.strip(), - mail=form.mail.data.strip() + mail=form.mail.data.strip(), + poste=form.poste.data.strip(), + service=form.service.data.strip() ) log = EntrepriseLog( authenticated_user = current_user.user_name, @@ -259,7 +288,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"]) +@bp.route("/edit_contact/", methods=["GET", "POST"]) def edit_contact(id): contact = EntrepriseContact.query.filter_by(id=id).first_or_404() form = ContactModificationForm() @@ -268,6 +297,8 @@ def edit_contact(id): contact.prenom = form.prenom.data.strip() contact.telephone = form.telephone.data.strip() contact.mail = form.mail.data.strip() + contact.poste = form.poste.data.strip() + contact.service = form.service.data.strip() log = EntrepriseLog( authenticated_user = current_user.user_name, object = contact.entreprise_id, @@ -282,9 +313,11 @@ def edit_contact(id): 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) -@bp.route("/delete_contact/", methods=["GET", "POST"]) +@bp.route("/delete_contact/", methods=["GET", "POST"]) def delete_contact(id): contact = EntrepriseContact.query.filter_by(id=id).first_or_404() entreprise_id = contact.entreprise.id @@ -307,7 +340,7 @@ def delete_contact(id): return redirect(url_for("entreprises.fiche_entreprise", id=entreprise_id)) return render_template("entreprises/delete_confirmation.html", title=("Supression contact"), form=form) -@bp.route("/add_historique/", methods=["GET", "POST"]) +@bp.route("/add_historique/", methods=["GET", "POST"]) def add_historique(id): entreprise = Entreprise.query.filter_by(id=id).first_or_404() form = HistoriqueCreationForm() @@ -333,11 +366,22 @@ def add_historique(id): return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id)) return render_template("entreprises/ajout_historique.html", title=("Ajout historique"), form=form) -@bp.route("/envoyer_offre/", methods=["GET", "POST"]) +@bp.route("/envoyer_offre/", methods=["GET", "POST"]) def envoyer_offre(id): + offre = EntrepriseOffre.query.filter_by(id=id).first_or_404() form = EnvoiOffreForm() if form.validate_on_submit(): - print("tmp") # faire l'envoie du mail + 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() + envoi_offre = EntrepriseEnvoiOffre( + user_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) @bp.route("/etudiants") @@ -378,4 +422,53 @@ def json_responsables(): } list.append(content) content = {} - return jsonify(results=list) \ No newline at end of file + return jsonify(results=list) + +@bp.route("/export_entreprises") +def export_entreprises(): + entreprises = Entreprise.query.all() + if entreprises: + keys=[ + "siret", + "nom", + "adresse", + "ville", + "codepostal", + "pays" + ] + titles = keys[:] + 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 + return scu.send_file(xlsx, filename, scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE) + else: + abort(404) + +@bp.route("/export_contacts") +def export_contacts(): + contacts = EntrepriseContact.query.all() + if contacts: + keys=[ + "nom", + "prenom", + "telephone", + "mail", + "poste", + "service" + ] + titles = keys[:] + 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 + return scu.send_file(xlsx, filename, scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE) + 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) + else: + abort(404) \ No newline at end of file diff --git a/app/templates/entreprises/_offre.html b/app/templates/entreprises/_offre.html index e64f3c16c..07aa4caa1 100644 --- a/app/templates/entreprises/_offre.html +++ b/app/templates/entreprises/_offre.html @@ -5,6 +5,9 @@ Type de l'offre : {{ offre.type_offre }}
Missions : {{ offre.missions }}
Durée : {{ offre.duree }}
+ {% if offre.filename %} + {{ offre.filename }} + {% endif %}

diff --git a/app/templates/entreprises/contacts.html b/app/templates/entreprises/contacts.html index 7f1433334..87112710f 100644 --- a/app/templates/entreprises/contacts.html +++ b/app/templates/entreprises/contacts.html @@ -33,11 +33,14 @@ {% endfor %} -
{% else %}
Aucun contact présent dans la base
-
{% endif %} +
+ {% if contacts %} + Exporter la liste des contacts + {% endif %} +
{% endblock %} \ No newline at end of file diff --git a/app/templates/entreprises/entreprises.html b/app/templates/entreprises/entreprises.html index a33dd7e77..85854efb3 100644 --- a/app/templates/entreprises/entreprises.html +++ b/app/templates/entreprises/entreprises.html @@ -38,7 +38,7 @@ Action -