Merge branch 'entreprises' of https://scodoc.org/git/arthur.zhu/ScoDoc into entreprises

This commit is contained in:
Emmanuel Viennet 2022-04-18 17:34:42 +02:00
commit d4d84fcb1e
22 changed files with 1388 additions and 552 deletions

View File

@ -34,7 +34,7 @@ from flask_login import current_user
from app.entreprises.models import (
Entreprise,
EntrepriseContact,
EntrepriseCorrespondant,
EntrepriseOffre,
EntrepriseOffreDepartement,
EntreprisePreferences,
@ -85,6 +85,9 @@ def get_offre_files_and_depts(offre: EntrepriseOffre, depts: list):
Retourne l'offre, les fichiers attachés a l'offre et les département liés
"""
offre_depts = EntrepriseOffreDepartement.query.filter_by(offre_id=offre.id).all()
correspondant = EntrepriseCorrespondant.query.filter_by(
id=offre.correspondant_id
).first()
if not offre_depts or check_offre_depts(depts, offre_depts):
files = []
path = os.path.join(
@ -100,13 +103,11 @@ def get_offre_files_and_depts(offre: EntrepriseOffre, depts: list):
for _file in glob.glob(f"{dir}/*"):
file = [os.path.basename(dir), os.path.basename(_file)]
files.append(file)
return [offre, files, offre_depts]
return [offre, files, offre_depts, correspondant]
return None
def send_email_notifications_entreprise(
subject, entreprise: Entreprise, contact: EntrepriseContact
):
def send_email_notifications_entreprise(subject, entreprise: Entreprise):
txt = [
"Une entreprise est en attente de validation",
"Entreprise:",
@ -116,14 +117,6 @@ def send_email_notifications_entreprise(
f"\tcode postal: {entreprise.codepostal}",
f"\tville: {entreprise.ville}",
f"\tpays: {entreprise.pays}",
"",
"Contact:",
f"nom: {contact.nom}",
f"prenom: {contact.prenom}",
f"telephone: {contact.telephone}",
f"mail: {contact.mail}",
f"poste: {contact.poste}",
f"service: {contact.service}",
]
txt = "\n".join(txt)
email.send_email(
@ -135,34 +128,42 @@ def send_email_notifications_entreprise(
return txt
def verif_contact_data(contact_data):
def verif_correspondant_data(correspondant_data):
"""
Verifie les données d'une ligne Excel (contact)
contact_data[0]: nom
contact_data[1]: prenom
contact_data[2]: telephone
contact_data[3]: mail
contact_data[4]: poste
contact_data[5]: service
contact_data[6]: entreprise_id
Verifie les données d'une ligne Excel (correspondant)
correspondant_data[0]: nom
correspondant_data[1]: prenom
correspondant_data[2]: telephone
correspondant_data[3]: mail
correspondant_data[4]: poste
correspondant_data[5]: service
correspondant_data[6]: entreprise_id
"""
# champs obligatoires
if contact_data[0] == "" or contact_data[1] == "" or contact_data[6] == "":
if (
correspondant_data[0].strip() == ""
or correspondant_data[1].strip() == ""
or correspondant_data[6].strip() == ""
):
return False
# entreprise_id existant
entreprise = Entreprise.query.filter_by(siret=contact_data[6]).first()
entreprise = Entreprise.query.filter_by(siret=correspondant_data[6].strip()).first()
if entreprise is None:
return False
# contact possède le meme nom et prénom dans la meme entreprise
contact = EntrepriseContact.query.filter_by(
nom=contact_data[0], prenom=contact_data[1], entreprise_id=entreprise.id
# correspondant possède le meme nom et prénom dans la meme entreprise
correspondant = EntrepriseCorrespondant.query.filter_by(
nom=correspondant_data[0].strip(),
prenom=correspondant_data[1].strip(),
entreprise_id=entreprise.id,
).first()
if contact is not None:
if correspondant is not None:
return False
if contact_data[2] == "" and contact_data[3] == "": # 1 moyen de contact
if (
correspondant_data[2].strip() == "" and correspondant_data[3].strip() == ""
): # 1 moyen de contact
return False
return True
@ -174,23 +175,23 @@ def verif_entreprise_data(entreprise_data):
"""
if EntreprisePreferences.get_check_siret():
for data in entreprise_data: # champs obligatoires
if data == "":
if data.strip() == "":
return False
else:
for data in entreprise_data[1:]: # champs obligatoires
if data == "":
if data.strip() == "":
return False
if EntreprisePreferences.get_check_siret():
siret = entreprise_data[0].strip() # vérification sur le siret
siret = entreprise_data[0].replace(" ", "") # vérification sur le siret
if re.match("^\d{14}$", siret) is None:
return False
try:
req = requests.get(
f"https://entreprise.data.gouv.fr/api/sirene/v1/siret/{siret}"
)
if req.status_code != 200:
return False
except requests.ConnectionError:
print("no internet")
if req.status_code != 200:
return False
entreprise = Entreprise.query.filter_by(siret=siret).first()
if entreprise is not None:

View File

@ -40,11 +40,17 @@ from wtforms import (
SelectMultipleField,
DateField,
BooleanField,
FieldList,
FormField,
)
from wtforms.validators import ValidationError, DataRequired, Email, Optional
from wtforms.widgets import ListWidget, CheckboxInput
from app.entreprises.models import Entreprise, EntrepriseContact, EntreprisePreferences
from app.entreprises.models import (
Entreprise,
EntrepriseCorrespondant,
EntreprisePreferences,
)
from app.models import Identite, Departement
from app.auth.models import User
@ -66,7 +72,7 @@ def _build_string_field(label, required=True, render_kw=None):
class EntrepriseCreationForm(FlaskForm):
siret = _build_string_field(
"SIRET (*)",
render_kw={"placeholder": "Numéro composé de 14 chiffres", "maxlength": "14"},
render_kw={"placeholder": "Numéro composé de 14 chiffres"},
)
nom_entreprise = _build_string_field("Nom de l'entreprise (*)")
adresse = _build_string_field("Adresse de l'entreprise (*)")
@ -74,15 +80,18 @@ class EntrepriseCreationForm(FlaskForm):
ville = _build_string_field("Ville de l'entreprise (*)")
pays = _build_string_field("Pays de l'entreprise", required=False)
nom_contact = _build_string_field("Nom du contact (*)")
prenom_contact = _build_string_field("Prénom du contact (*)")
telephone = _build_string_field("Téléphone du contact (*)", required=False)
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 contact (*)",
"Mail du correspondant",
validators=[Optional(), Email(message="Adresse e-mail invalide")],
)
poste = _build_string_field("Poste du contact", required=False)
service = _build_string_field("Service du contact", required=False)
poste = _build_string_field("Poste du correspondant", required=False)
service = _build_string_field("Service du correspondant", required=False)
submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)
def validate(self):
@ -90,29 +99,46 @@ class EntrepriseCreationForm(FlaskForm):
if not FlaskForm.validate(self):
validate = False
if not self.telephone.data and not self.mail.data:
self.telephone.errors.append(
"Saisir un moyen de contact (mail ou téléphone)"
)
self.mail.errors.append("Saisir un moyen de contact (mail ou téléphone)")
validate = False
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()
):
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():
self.telephone.errors.append(
"Saisir un moyen de contact (mail ou téléphone)"
)
self.mail.errors.append(
"Saisir un moyen de contact (mail ou téléphone)"
)
validate = False
return validate
def validate_siret(self, siret):
if EntreprisePreferences.get_check_siret():
siret = siret.data.strip()
if re.match("^\d{14}$", siret) is None:
siret_data = siret.data.replace(" ", "")
self.siret.data = siret_data
if re.match("^\d{14}$", siret_data) is None:
raise ValidationError("Format incorrect")
try:
req = requests.get(
f"https://entreprise.data.gouv.fr/api/sirene/v1/siret/{siret}"
f"https://entreprise.data.gouv.fr/api/sirene/v1/siret/{siret_data}"
)
if req.status_code != 200:
raise ValidationError("SIRET inexistant")
except requests.ConnectionError:
print("no internet")
if req.status_code != 200:
raise ValidationError("SIRET inexistant")
entreprise = Entreprise.query.filter_by(siret=siret).first()
raise ValidationError("Impossible de vérifier l'existance du SIRET")
entreprise = Entreprise.query.filter_by(siret=siret_data).first()
if entreprise is not None:
lien = f'<a href="/ScoDoc/entreprises/fiche_entreprise/{entreprise.id}">ici</a>'
raise ValidationError(
@ -144,6 +170,7 @@ class MultiCheckboxField(SelectMultipleField):
class OffreCreationForm(FlaskForm):
hidden_entreprise_id = HiddenField()
intitule = _build_string_field("Intitulé (*)")
description = TextAreaField(
"Description (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
@ -159,17 +186,44 @@ class OffreCreationForm(FlaskForm):
duree = _build_string_field("Durée (*)")
depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int)
expiration_date = DateField("Date expiration", validators=[Optional()])
correspondant = SelectField("Correspondant à contacté", validators=[Optional()])
fichier = FileField(
"Fichier (*)",
validators=[
Optional(),
FileAllowed(["pdf", "docx"], "Fichier .pdf ou .docx uniquement"),
],
)
submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.correspondant.choices = [
(correspondant.id, f"{correspondant.nom} {correspondant.prenom}")
for correspondant in EntrepriseCorrespondant.query.filter_by(
entreprise_id=self.hidden_entreprise_id.data
)
]
self.depts.choices = [
(dept.id, dept.acronym) for dept in Departement.query.all()
]
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)]
@ -185,27 +239,79 @@ class OffreModificationForm(FlaskForm):
duree = _build_string_field("Durée (*)")
depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int)
expiration_date = DateField("Date expiration", validators=[Optional()])
correspondant = SelectField("Correspondant à contacté", validators=[Optional()])
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.correspondant.choices = [
(correspondant.id, f"{correspondant.nom} {correspondant.prenom}")
for correspondant in EntrepriseCorrespondant.query.filter_by(
entreprise_id=self.hidden_entreprise_id.data
)
]
self.depts.choices = [
(dept.id, dept.acronym) for dept in Departement.query.all()
]
def validate(self):
validate = True
if not FlaskForm.validate(self):
validate = False
class ContactCreationForm(FlaskForm):
hidden_entreprise_id = HiddenField()
nom = _build_string_field("Nom (*)")
prenom = _build_string_field("Prénom (*)")
telephone = _build_string_field("Téléphone (*)", required=False)
if len(self.depts.data) < 1:
self.depts.errors.append("Choisir au moins un département")
validate = False
return validate
class CorrespondantCreationForm(FlaskForm):
nom = _build_string_field("Nom (*)", render_kw={"class": "form-control"})
prenom = _build_string_field("Prénom (*)", 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)
service = _build_string_field("Service", required=False)
poste = _build_string_field(
"Poste", required=False, render_kw={"class": "form-control"}
)
service = _build_string_field(
"Service", required=False, render_kw={"class": "form-control"}
)
# depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int)
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
# self.depts.choices = [
# (dept.id, dept.acronym) for dept in Departement.query.all()
# ]
def validate(self):
validate = True
if not FlaskForm.validate(self):
validate = False
if not self.telephone.data and not self.mail.data:
self.telephone.errors.append(
"Saisir un moyen de contact (mail ou téléphone)"
)
self.mail.errors.append("Saisir un moyen de contact (mail ou téléphone)")
validate = False
return validate
class CorrespondantsCreationForm(FlaskForm):
hidden_entreprise_id = HiddenField()
correspondants = FieldList(FormField(CorrespondantCreationForm), min_entries=1)
submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)
def validate(self):
@ -213,28 +319,37 @@ class ContactCreationForm(FlaskForm):
if not FlaskForm.validate(self):
validate = False
contact = EntrepriseContact.query.filter_by(
entreprise_id=self.hidden_entreprise_id.data,
nom=self.nom.data,
prenom=self.prenom.data,
).first()
if contact is not None:
self.nom.errors.append("Ce contact existe déjà (même nom et prénom)")
self.prenom.errors.append("")
validate = False
if not self.telephone.data and not self.mail.data:
self.telephone.errors.append(
"Saisir un moyen de contact (mail ou téléphone)"
)
self.mail.errors.append("Saisir un moyen de contact (mail ou téléphone)")
validate = False
correspondant_list = []
for entry in self.correspondants.entries:
if entry.nom.data.strip() and entry.prenom.data.strip():
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(
entreprise_id=self.hidden_entreprise_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 ContactModificationForm(FlaskForm):
hidden_contact_id = HiddenField()
class CorrespondantModificationForm(FlaskForm):
hidden_correspondant_id = HiddenField()
hidden_entreprise_id = HiddenField()
nom = _build_string_field("Nom (*)")
prenom = _build_string_field("Prénom (*)")
@ -245,21 +360,29 @@ class ContactModificationForm(FlaskForm):
)
poste = _build_string_field("Poste", required=False)
service = _build_string_field("Service", required=False)
# depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int)
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
# self.depts.choices = [
# (dept.id, dept.acronym) for dept in Departement.query.all()
# ]
def validate(self):
validate = True
if not FlaskForm.validate(self):
validate = False
contact = EntrepriseContact.query.filter(
EntrepriseContact.id != self.hidden_contact_id.data,
EntrepriseContact.entreprise_id == self.hidden_entreprise_id.data,
EntrepriseContact.nom == self.nom.data,
EntrepriseContact.prenom == self.prenom.data,
correspondant = EntrepriseCorrespondant.query.filter(
EntrepriseCorrespondant.id != self.hidden_correspondant_id.data,
EntrepriseCorrespondant.entreprise_id == self.hidden_entreprise_id.data,
EntrepriseCorrespondant.nom == self.nom.data,
EntrepriseCorrespondant.prenom == self.prenom.data,
).first()
if contact is not None:
self.nom.errors.append("Ce contact existe déjà (même nom et prénom)")
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
@ -273,7 +396,59 @@ class ContactModificationForm(FlaskForm):
return validate
class HistoriqueCreationForm(FlaskForm):
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("Envoyer", 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)
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"},
@ -289,6 +464,7 @@ class HistoriqueCreationForm(FlaskForm):
date_fin = DateField(
"Date fin (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
)
notes = TextAreaField("Notes")
submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)
def validate(self):
@ -319,25 +495,87 @@ class HistoriqueCreationForm(FlaskForm):
raise ValidationError("Champ incorrect (selectionnez dans la liste)")
class StageApprentissageModificationForm(FlaskForm):
etudiant = _build_string_field(
"Étudiant (*)",
render_kw={"placeholder": "Tapez le nom de l'étudiant"},
)
type_offre = SelectField(
"Type de l'offre (*)",
choices=[("Stage"), ("Alternance")],
validators=[DataRequired(message=CHAMP_REQUIS)],
)
date_debut = DateField(
"Date début (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
)
date_fin = DateField(
"Date fin (*)", validators=[DataRequired(message=CHAMP_REQUIS)]
)
notes = TextAreaField("Notes")
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
def validate(self):
validate = True
if not FlaskForm.validate(self):
validate = False
if (
self.date_debut.data
and self.date_fin.data
and self.date_debut.data > self.date_fin.data
):
self.date_debut.errors.append("Les dates sont incompatibles")
self.date_fin.errors.append("Les dates sont incompatibles")
validate = False
return validate
def validate_etudiant(self, etudiant):
etudiant_data = etudiant.data.upper().strip()
stm = text(
"SELECT id, CONCAT(nom, ' ', prenom) as nom_prenom FROM Identite WHERE CONCAT(nom, ' ', prenom)=:nom_prenom"
)
etudiant = (
Identite.query.from_statement(stm).params(nom_prenom=etudiant_data).first()
)
if etudiant is None:
raise ValidationError("Champ incorrect (selectionnez dans la liste)")
class EnvoiOffreForm(FlaskForm):
responsable = _build_string_field(
"Responsable de formation (*)",
render_kw={"placeholder": "Tapez le nom du responsable de formation"},
responsables = FieldList(
_build_string_field(
"Responsable (*)",
render_kw={
"placeholder": "Tapez le nom du responsable de formation",
"class": "form-control",
},
),
min_entries=1,
)
submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)
def validate_responsable(self, responsable):
responsable_data = responsable.data.upper().strip()
stm = text(
"SELECT id, UPPER(CONCAT(nom, ' ', prenom, ' ', '(', user_name, ')')) FROM \"user\" WHERE UPPER(CONCAT(nom, ' ', prenom, ' ', '(', user_name, ')'))=:responsable_data"
)
responsable = (
User.query.from_statement(stm)
.params(responsable_data=responsable_data)
.first()
)
if responsable is None:
raise ValidationError("Champ incorrect (selectionnez dans la liste)")
def validate(self):
validate = 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:
entry.errors.append("Champ incorrect (selectionnez dans la liste)")
validate = False
return validate
class AjoutFichierForm(FlaskForm):

View File

@ -11,8 +11,8 @@ class Entreprise(db.Model):
ville = db.Column(db.Text)
pays = db.Column(db.Text, default="FRANCE")
visible = db.Column(db.Boolean, default=False)
contacts = db.relationship(
"EntrepriseContact",
correspondants = db.relationship(
"EntrepriseCorrespondant",
backref="entreprise",
lazy="dynamic",
cascade="all, delete-orphan",
@ -35,12 +35,22 @@ class Entreprise(db.Model):
}
class EntrepriseContact(db.Model):
__tablename__ = "are_contacts"
# class EntrepriseSite(db.Model):
# __tablename__ = "are_sites"
# id = db.Column(db.Integer, primary_key=True)
# entreprise_id = db.Column(
# db.Integer, db.ForeignKey("are_entreprises.id", ondelete="cascade")
# )
# nom = db.Column(db.Text)
class EntrepriseCorrespondant(db.Model):
__tablename__ = "are_correspondants"
id = db.Column(db.Integer, primary_key=True)
entreprise_id = db.Column(
db.Integer, db.ForeignKey("are_entreprises.id", ondelete="cascade")
)
# site_id = db.Column(db.Integer, db.ForeignKey("are_sites.id", ondelete="cascade"))
nom = db.Column(db.Text)
prenom = db.Column(db.Text)
telephone = db.Column(db.Text)
@ -61,6 +71,17 @@ class EntrepriseContact(db.Model):
}
class EntrepriseContact(db.Model):
__tablename__ = "are_contacts"
id = db.Column(db.Integer, primary_key=True)
date = db.Column(db.DateTime(timezone=True))
user = db.Column(db.Integer, db.ForeignKey("user.id", ondelete="cascade"))
entreprise = db.Column(
db.Integer, db.ForeignKey("are_entreprises.id", ondelete="cascade")
)
notes = db.Column(db.Text)
class EntrepriseOffre(db.Model):
__tablename__ = "are_offres"
id = db.Column(db.Integer, primary_key=True)
@ -75,6 +96,9 @@ class EntrepriseOffre(db.Model):
duree = db.Column(db.Text)
expiration_date = db.Column(db.Date)
expired = db.Column(db.Boolean, default=False)
correspondant_id = db.Column(
db.Integer, db.ForeignKey("are_correspondants.id", ondelete="cascade")
)
def to_dict(self):
return {
@ -95,8 +119,8 @@ class EntrepriseLog(db.Model):
text = db.Column(db.Text)
class EntrepriseEtudiant(db.Model):
__tablename__ = "are_etudiants"
class EntrepriseStageApprentissage(db.Model):
__tablename__ = "are_stages_apprentissages"
id = db.Column(db.Integer, primary_key=True)
entreprise_id = db.Column(
db.Integer, db.ForeignKey("are_entreprises.id", ondelete="cascade")
@ -107,6 +131,7 @@ class EntrepriseEtudiant(db.Model):
date_fin = db.Column(db.Date)
formation_text = db.Column(db.Text)
formation_scodoc = db.Column(db.Integer)
notes = db.Column(db.Text)
class EntrepriseEnvoiOffre(db.Model):
@ -136,6 +161,15 @@ class EntrepriseOffreDepartement(db.Model):
dept_id = db.Column(db.Integer, db.ForeignKey("departement.id", ondelete="cascade"))
# class EntrepriseCorrespondantDepartement(db.Model):
# __tablename__ = "are_correspondant_departement"
# id = db.Column(db.Integer, primary_key=True)
# correspondant_id = db.Column(
# db.Integer, db.ForeignKey("are_correspondants.id", ondelete="cascade")
# )
# dept_id = db.Column(db.Integer, db.ForeignKey("departement.id", ondelete="cascade"))
class EntreprisePreferences(db.Model):
__tablename__ = "are_preferences"
id = db.Column(db.Integer, primary_key=True)

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,10 @@
}
.form-error {
color: #a94442;
}
.nav-entreprise>ul>li>a:hover {
color: red;
}
@ -50,23 +54,23 @@
margin-bottom: -5px;
}
.entreprise, .contact, .offre {
.entreprise, .correspondant, .offre {
border: solid 2px;
border-radius: 10px;
padding: 10px;
margin-bottom: 10px;
}
.contacts-et-offres {
.correspondants-et-offres {
display: flex;
justify-content: space-between;
}
.contacts-et-offres > div {
.correspondants-et-offres > div {
flex: 1 0 0;
}
.contacts-et-offres > div:nth-child(2) {
.correspondants-et-offres > div:nth-child(2) {
margin-left: 20px;
}

View File

@ -1,26 +0,0 @@
{# -*- mode: jinja-html -*- #}
<div class="contact">
<div>
Nom : {{ contact.nom }}<br>
Prénom : {{ contact.prenom }}<br>
{% if contact.telephone %}
Téléphone : {{ contact.telephone }}<br>
{% endif %}
{% if contact.mail %}
Mail : {{ contact.mail }}<br>
{% endif %}
{% if contact.poste %}
Poste : {{ contact.poste }}<br>
{% endif %}
{% if contact.service %}
Service : {{ contact.service }}<br>
{% endif %}
</div>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
<div class="parent-btn">
<a class="btn btn-primary" href="{{ url_for('entreprises.edit_contact', id=contact.id) }}">Modifier contact</a>
<a class="btn btn-danger" href="{{ url_for('entreprises.delete_contact', id=contact.id) }}">Supprimer contact</a>
</div>
{% endif %}
</div>

View File

@ -0,0 +1,26 @@
{# -*- mode: jinja-html -*- #}
<div class="correspondant">
<div>
Nom : {{ correspondant.nom }}<br>
Prénom : {{ correspondant.prenom }}<br>
{% if correspondant.telephone %}
Téléphone : {{ correspondant.telephone }}<br>
{% endif %}
{% if correspondant.mail %}
Mail : {{ correspondant.mail }}<br>
{% endif %}
{% if correspondant.poste %}
Poste : {{ correspondant.poste }}<br>
{% endif %}
{% if correspondant.service %}
Service : {{ correspondant.service }}<br>
{% endif %}
</div>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
<div class="parent-btn">
<a class="btn btn-primary" href="{{ url_for('entreprises.edit_correspondant', id=correspondant.id) }}">Modifier correspondant</a>
<a class="btn btn-danger" href="{{ url_for('entreprises.delete_correspondant', id=correspondant.id) }}">Supprimer correspondant</a>
</div>
{% endif %}
</div>

View File

@ -1,6 +1,7 @@
{# -*- mode: jinja-html -*- #}
<div class="offre">
<div>
Ajouté le {{ offre[0].date_ajout.strftime('%d/%m/%y') }} à {{ offre[0].date_ajout.strftime('%Hh%M') }}<br>
Intitulé : {{ offre[0].intitule }}<br>
Description : {{ offre[0].description }}<br>
Type de l'offre : {{ offre[0].type_offre }}<br>
@ -9,6 +10,16 @@
{% if offre[2] %}
Département(s) : {% for offre_dept in offre[2] %} <div class="offre-depts">{{ offre_dept.dept_id|get_dept_acronym }}</div> {% endfor %}<br>
{% endif %}
{% if offre[0].correspondant_id %}
Contacté {{ offre[3].nom }} {{ offre[3].prenom }}
{% if offre[3].mail and offre[3].telephone %}
({{ offre[3].mail }} - {{ offre[3].telephone }})<br>
{% else %}
({{ offre[3].mail }}{{offre[3].telephone}})<br>
{% endif %}
{% endif %}
{% for fichier in offre[1] %}
<a href="{{ url_for('entreprises.get_offre_file', entreprise_id=entreprise.id, offre_id=offre[0].id, filedir=fichier[0], filename=fichier[1] )}}">{{ fichier[1] }}</a>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
@ -16,6 +27,7 @@
{% endif %}
<br>
{% endfor %}
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
<a href="{{ url_for('entreprises.add_offre_file', offre_id=offre[0].id) }}">Ajoutez un fichier</a>
{% endif %}
@ -26,9 +38,11 @@
<a class="btn btn-primary" href="{{ url_for('entreprises.edit_offre', id=offre[0].id) }}">Modifier l'offre</a>
<a class="btn btn-danger" href="{{ url_for('entreprises.delete_offre', id=offre[0].id) }}">Supprimer l'offre</a>
{% endif %}
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesSend, None) %}
<a class="btn btn-primary" href="{{ url_for('entreprises.envoyer_offre', id=offre[0].id) }}">Envoyer l'offre</a>
{% endif %}
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
{% if not offre[0].expired %}
<a class="btn btn-danger" href="{{ url_for('entreprises.expired', id=offre[0].id) }}">Rendre expirée</a>

View File

@ -0,0 +1,56 @@
{# -*- mode: jinja-html -*- #}
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block styles %}
{{super()}}
{% endblock %}
{% block app_content %}
<h1>{{ title }}</h1>
<br>
<div class="row">
<div class="col-md-4">
<p>
(*) champs requis
</p>
<form method="POST" action="" novalidate>
{{ form.hidden_tag() }}
{% for subfield in form.correspondants %}
{% for subsubfield in subfield %}
{% if subsubfield.errors %}
{% for error in subsubfield.errors %}
<p class="help-block form-error">{{ error }}</p>
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}
{{ form.correspondants }}
<div style="margin-bottom: 10px;">
<button class="btn btn-default" id="add-correspondant-field">Ajouter un correspondant</button>
<input class="btn btn-default" type="submit" value="Envoyer">
</div>
</form>
</div>
</div>
<script>
window.onload = function(e) {
let addCorrespondantFieldBtn = document.getElementById('add-correspondant-field');
addCorrespondantFieldBtn.addEventListener('click', function(e){
e.preventDefault();
let allCorrepondantsFieldWrapper = document.getElementById('correspondants');
let allCorrepondantsField = allCorrepondantsFieldWrapper.getElementsByTagName('input');
let correspondantInputIds = []
let csrf_token = document.getElementById('csrf_token').value;
for(let i = 0; i < allCorrepondantsField.length; i++) {
correspondantInputIds.push(parseInt(allCorrepondantsField[i].name.split('-')[1]));
}
let newFieldName = `correspondants-${Math.max(...correspondantInputIds) + 1}`;
allCorrepondantsFieldWrapper.insertAdjacentHTML('beforeend',`
<li><label for="${newFieldName}">Correspondants-${Math.max(...correspondantInputIds) + 1}</label> <table id="${newFieldName}"><tr><th><label for="${newFieldName}-nom">Nom (*)</label></th><td><input class="form-control" id="${newFieldName}-nom" name="${newFieldName}-nom" required type="text" value=""></td></tr><tr><th><label for="${newFieldName}-prenom">Prénom (*)</label></th><td><input class="form-control" id="${newFieldName}-prenom" name="${newFieldName}-prenom" required type="text" value=""></td></tr><tr><th><label for="${newFieldName}-telephone">Téléphone (*)</label></th><td><input class="form-control" id="${newFieldName}-telephone" name="${newFieldName}-telephone" type="text" value=""></td></tr><tr><th><label for="${newFieldName}-mail">Mail (*)</label></th><td><input class="form-control" id="${newFieldName}-mail" name="${newFieldName}-mail" type="text" value=""></td></tr><tr><th><label for="${newFieldName}-poste">Poste</label></th><td><input class="form-control" id="${newFieldName}-poste" name="${newFieldName}-poste" type="text" value=""></td></tr><tr><th><label for="${newFieldName}-service">Service</label></th><td><input class="form-control" id="${newFieldName}-service" name="${newFieldName}-service" type="text" value=""></td></tr></table><input id="${newFieldName}-csrf_token" name="${newFieldName}-csrf_token" type="hidden" value=${csrf_token}></li>
`);
});
}
</script>
{% endblock %}

View File

@ -3,7 +3,7 @@
{% import 'bootstrap/wtf.html' as wtf %}
{% block app_content %}
<h1>Ajout entreprise avec contact</h1>
<h1>Ajout entreprise</h1>
<br>
<div class="row">
<div class="col-md-4">
@ -16,45 +16,43 @@
</div>
<script>
window.onload = function(e){
document.getElementById("siret").addEventListener("keyup", autocomplete);
function autocomplete() {
var input = document.getElementById("siret").value;
if(input.length == 14) {
fetch("https://entreprise.data.gouv.fr/api/sirene/v1/siret/" + input)
.then(response => {
if(response.ok)
return response.json()
else {
emptyForm()
}
})
.then(response => fillForm(response))
.catch(err => err)
}
}
function fillForm(response) {
document.getElementById("nom_entreprise").value = response.etablissement.l1_normalisee
document.getElementById("adresse").value = response.etablissement.l4_normalisee
document.getElementById("codepostal").value = response.etablissement.code_postal
document.getElementById("ville").value = response.etablissement.libelle_commune
}
function emptyForm() {
document.getElementById("nom_entreprise").value = ''
document.getElementById("adresse").value = ''
document.getElementById("codepostal").value = ''
document.getElementById("ville").value = ''
}
}
{# ajout margin-bottom sur le champ pays #}
var champ_pays = document.getElementById("pays")
if (champ_pays !== null) {
var closest_form_group = champ_pays.closest(".form-group")
closest_form_group.style.marginBottom = "50px"
}
document.getElementById("siret").addEventListener("keyup", autocomplete);
function autocomplete() {
var input = document.getElementById("siret").value.replaceAll(" ", "")
if(input.length >= 14) {
fetch("https://entreprise.data.gouv.fr/api/sirene/v1/siret/" + input)
.then(response => {
if(response.ok)
return response.json()
else {
emptyForm()
}
})
.then(response => fillForm(response))
.catch(err => err)
}
}
function fillForm(response) {
document.getElementById("nom_entreprise").value = response.etablissement.l1_normalisee
document.getElementById("adresse").value = response.etablissement.l4_normalisee
document.getElementById("codepostal").value = response.etablissement.code_postal
document.getElementById("ville").value = response.etablissement.libelle_commune
}
function emptyForm() {
document.getElementById("nom_entreprise").value = ''
document.getElementById("adresse").value = ''
document.getElementById("codepostal").value = ''
document.getElementById("ville").value = ''
}
</script>
{% endblock %}

View File

@ -9,7 +9,7 @@
{% endblock %}
{% block app_content %}
<h1>Ajout historique</h1>
<h1>{{ title }}</h1>
<br>
<div class="row">
<div class="col-md-4">

View File

@ -9,64 +9,51 @@
{% endblock %}
{% block app_content %}
{% include 'entreprises/nav.html' %}
{% if logs %}
<div class="container">
<h3>Dernières opérations <a href="{{ url_for('entreprises.logs') }}">Voir tout</a></h3>
<ul>
{% for log in logs %}
<li><span style="margin-right: 10px;">{{ log.date.strftime('%d %b %Hh%M') }}</span><span>{{ log.text|safe }} par {{ log.authenticated_user|get_nomcomplet_by_username }}</span></li>
{% endfor %}
</ul>
</div>
{% endif %}
<div class="container boutons">
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) %}
<a class="btn btn-default" href="{{ url_for('entreprises.import_contacts') }}">Importer des contacts</a>
{% endif %}
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) and contacts %}
<a class="btn btn-default" href="{{ url_for('entreprises.export_contacts') }}">Exporter la liste des contacts</a>
{% endif %}
</div>
<div class="container" style="margin-bottom: 10px;">
<div class="container" style="margin-bottom: 10px;">
<h1>Liste des contacts</h1>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
<a class="btn btn-primary" style="margin-bottom:10px;" href="{{ url_for('entreprises.add_contact', id=entreprise_id) }}">Ajouter contact</a>
{% endif %}
<table id="table-contacts">
<thead>
<tr>
<td data-priority="1">Nom</td>
<td data-priority="3">Prenom</td>
<td data-priority="4">Telephone</td>
<td data-priority="5">Mail</td>
<td data-priority="6">Poste</td>
<td data-priority="7">Service</td>
<td data-priority="2">Entreprise</td>
<td data-priority="">Date</td>
<td data-priority="">Utilisateur</td>
<td data-priority="">Notes</td>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
<td data-priority="">Action</td>
{% endif %}
</tr>
</thead>
<tbody>
{% for contact in contacts %}
{% for contact in contacts %}
<tr>
<td>{{ contact[0].nom }}</td>
<td>{{ contact[0].prenom }}</td>
<td>{{ contact[0].telephone }}</td>
<td>{{ contact[0].mail }}</td>
<td>{{ contact[0].poste}}</td>
<td>{{ contact[0].service}}</td>
<td><a href="{{ url_for('entreprises.fiche_entreprise', id=contact[1].id) }}">{{ contact[1].nom }}</a></td>
<td>{{ contact.date.strftime('%d/%m/%Y %Hh%M') }}</td>
<td>{{ contact.user|get_nomcomplet_by_id }}</td>
<td>{{ contact.notes }}</td>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
<td>
<div class="btn-group">
<a class="btn btn-default dropdown-toggle" data-toggle="dropdown" href="#">Action
<span class="caret"></span>
</a>
<ul class="dropdown-menu pull-left">
<li><a href="{{ url_for('entreprises.edit_contact', id=contact.id) }}">Modifier</a></li>
</ul>
</div>
</td>
{% endif %}
</tr>
{% endfor %}
{% endfor %}
</tbody>
<tfoot>
<tr>
<td>Nom</td>
<td>Prenom</td>
<td>Telephone</td>
<td>Mail</td>
<td>Poste</td>
<td>Service</td>
<td>Entreprise</td>
<td>Date</td>
<td>Utilisateur</td>
<td>Notes</td>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
<td>Action</td>
{% endif %}
</tr>
</tfoot>
</table>

View File

@ -0,0 +1,102 @@
{# -*- mode: jinja-html -*- #}
{% extends 'base.html' %}
{% block styles %}
{{super()}}
<script src="/ScoDoc/static/jQuery/jquery-1.12.4.min.js"></script>
<link rel="stylesheet" type="text/css" href="/ScoDoc/static/DataTables/datatables.min.css">
<script type="text/javascript" charset="utf8" src="/ScoDoc/static/DataTables/datatables.min.js"></script>
{% endblock %}
{% block app_content %}
{% include 'entreprises/nav.html' %}
{% if logs %}
<div class="container">
<h3>Dernières opérations <a href="{{ url_for('entreprises.logs') }}">Voir tout</a></h3>
<ul>
{% for log in logs %}
<li><span style="margin-right: 10px;">{{ log.date.strftime('%d %b %Hh%M') }}</span><span>{{ log.text|safe }} par {{ log.authenticated_user|get_nomcomplet_by_username }}</span></li>
{% endfor %}
</ul>
</div>
{% endif %}
<div class="container boutons">
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) %}
<a class="btn btn-default" href="{{ url_for('entreprises.import_correspondants') }}">Importer des correspondants</a>
{% endif %}
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) and correspondants %}
<a class="btn btn-default" href="{{ url_for('entreprises.export_correspondants') }}">Exporter la liste des correspondants</a>
{% endif %}
</div>
<div class="container" style="margin-bottom: 10px;">
<h1>Liste des correspondants</h1>
<table id="table-correspondants">
<thead>
<tr>
<td data-priority="1">Nom</td>
<td data-priority="3">Prenom</td>
<td data-priority="4">Téléphone</td>
<td data-priority="5">Mail</td>
<td data-priority="6">Poste</td>
<td data-priority="7">Service</td>
<td data-priority="2">Entreprise</td>
</tr>
</thead>
<tbody>
{% for correspondant in correspondants %}
<tr>
<td>{{ correspondant[0].nom }}</td>
<td>{{ correspondant[0].prenom }}</td>
<td>{{ correspondant[0].telephone }}</td>
<td>{{ correspondant[0].mail }}</td>
<td>{{ correspondant[0].poste}}</td>
<td>{{ correspondant[0].service}}</td>
<td><a href="{{ url_for('entreprises.fiche_entreprise', id=correspondant[1].id) }}">{{ correspondant[1].nom }}</a></td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td>Nom</td>
<td>Prenom</td>
<td>Téléphone</td>
<td>Mail</td>
<td>Poste</td>
<td>Service</td>
<td>Entreprise</td>
</tr>
</tfoot>
</table>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
let table = new DataTable('#table-correspondants',
{
"autoWidth": false,
"responsive": {
"details": true
},
"pageLength": 10,
"language": {
"emptyTable": "Aucune donnée disponible dans le tableau",
"info": "Affichage de _START_ à _END_ sur _TOTAL_ entrées",
"infoEmpty": "Affichage de 0 à 0 sur 0 entrées",
"infoFiltered": "(filtrées depuis un total de _MAX_ entrées)",
"lengthMenu": "Afficher _MENU_ entrées",
"loadingRecords": "Chargement...",
"processing": "Traitement...",
"search": "Rechercher:",
"zeroRecords": "Aucune entrée correspondante trouvée",
"paginate": {
"next": "Suivante",
"previous": "Précédente"
}
}
});
});
</script>
{% endblock %}

View File

@ -16,7 +16,22 @@
<p>
(*) champs requis
</p>
{{ wtf.quick_form(form, novalidate=True) }}
<form method="POST" action="" novalidate>
{{ form.hidden_tag() }}
{{ form.responsables.label }}<br>
{% for subfield in form.responsables %}
{% if subfield.errors %}
{% for error in subfield.errors %}
<p class="help-block form-error">{{ error }}</p>
{% endfor %}
{% endif %}
{% endfor %}
{{ form.responsables }}
<div style="margin-bottom: 10px;">
<button class="btn btn-default" id="add-responsable-field">Ajouter un responsable</button>
<input class="btn btn-default" type="submit" value="Envoyer">
</div>
</form>
</div>
</div>
@ -30,7 +45,28 @@
minchars: 2,
timeout: 60000
};
var as_responsables = new bsn.AutoSuggest('responsable', responsables_options);
let allResponsablesFieldWrapper = document.getElementById('responsables');
let allResponsablesField = allResponsablesFieldWrapper.getElementsByTagName('input');
for(let i = 0; i < allResponsablesField.length; i++) {
new bsn.AutoSuggest(allResponsablesField[i].id, responsables_options);
}
let addResponsableFieldBtn = document.getElementById('add-responsable-field');
addResponsableFieldBtn.addEventListener('click', function(e){
e.preventDefault();
let allResponsablesFieldWrapper = document.getElementById('responsables');
let allResponsablesField = allResponsablesFieldWrapper.getElementsByTagName('input');
let responsableInputIds = []
for(let i = 0; i < allResponsablesField.length; i++) {
responsableInputIds.push(parseInt(allResponsablesField[i].name.split('-')[1]));
}
let newFieldName = `responsables-${Math.max(...responsableInputIds) + 1}`;
allResponsablesFieldWrapper.insertAdjacentHTML('beforeend',`
<li><label for="${newFieldName}">Responsable (*)</label> <input class="form-control" id="${newFieldName}" name="${newFieldName}" type="text" value="" placeholder="Tapez le nom du responsable de formation"></li>
`);
var as_r = new bsn.AutoSuggest(newFieldName, responsables_options);
});
}
</script>
{% endblock %}

View File

@ -1,6 +1,13 @@
{# -*- mode: jinja-html -*- #}
{% extends 'base.html' %}
{% block styles %}
{{super()}}
<script src="/ScoDoc/static/jQuery/jquery-1.12.4.min.js"></script>
<link rel="stylesheet" type="text/css" href="/ScoDoc/static/DataTables/datatables.min.css">
<script type="text/javascript" charset="utf8" src="/ScoDoc/static/DataTables/datatables.min.js"></script>
{% endblock %}
{% block app_content %}
{% if logs %}
<div class="container">
@ -15,24 +22,6 @@
</ul>
</div>
{% endif %}
{% if historique %}
<div class="container">
<h3>Historique</h3>
<ul>
{% for data in historique %}
<li>
<span style="margin-right: 10px;">{{ data[0].date_debut.strftime('%d/%m/%Y') }} - {{
data[0].date_fin.strftime('%d/%m/%Y') }}</span>
<span style="margin-right: 10px;">
{{ data[0].type_offre }} réalisé par {{ data[1].nom|format_nom }} {{ data[1].prenom|format_prenom }}
{% if data[0].formation_text %} en {{ data[0].formation_text }}{% endif %}
</span>
</li>
{% endfor %}
</ul>
</div>
{% endif %}
<div class="container fiche-entreprise">
<h2>Fiche entreprise - {{ entreprise.nom }} ({{ entreprise.siret }})</h2>
@ -53,20 +42,19 @@
<a class="btn btn-primary" href="{{ url_for('entreprises.edit_entreprise', id=entreprise.id) }}">Modifier</a>
<a class="btn btn-danger" href="{{ url_for('entreprises.delete_entreprise', id=entreprise.id) }}">Supprimer</a>
<a class="btn btn-primary" href="{{ url_for('entreprises.add_offre', id=entreprise.id) }}">Ajouter offre</a>
<a class="btn btn-primary" href="{{ url_for('entreprises.add_contact', id=entreprise.id) }}">Ajouter contact</a>
<a class="btn btn-primary" href="{{ url_for('entreprises.add_historique', id=entreprise.id) }}">Ajouter
historique</a>
<a class="btn btn-primary" href="{{ url_for('entreprises.add_correspondant', id=entreprise.id) }}">Ajouter correspondant</a>
{% endif %}
<a class="btn btn-primary" href="{{ url_for('entreprises.contacts', id=entreprise.id) }}">Liste contacts</a>
<a class="btn btn-primary" href="{{ url_for('entreprises.offres_expirees', id=entreprise.id) }}">Voir les offres expirées</a>
<div>
<div class="contacts-et-offres">
{% if contacts %}
<div class="correspondants-et-offres">
{% if correspondants %}
<div>
<h3>Contacts</h3>
{% for contact in contacts %}
{% include 'entreprises/_contact.html' %}
<h3>Correspondants</h3>
{% for correspondant in correspondants %}
{% include 'entreprises/_correspondant.html' %}
{% endfor %}
</div>
{% endif %}
@ -81,4 +69,95 @@
{% endif %}
</div>
</div>
<div style="margin-bottom: 10px;">
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
<a class="btn btn-primary" href="{{ url_for('entreprises.add_stage_apprentissage', id=entreprise.id) }}">Ajouter stage ou apprentissage</a>
{% endif %}
<h3>Liste des stages et apprentissages réalisés au sein de l'entreprise</h3>
<table id="table-stages-apprentissages">
<thead>
<tr>
<td data-priority="">Date début</td>
<td data-priority="">Date fin</td>
<td data-priority="">Durée</td>
<td data-priority="">Type</td>
<td data-priority="">Étudiant</td>
<td data-priority="">Formation</td>
<td data-priority="">Notes</td>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
<td data-priority="3">Action</td>
{% endif %}
</tr>
</thead>
<tbody>
{% for data in stages_apprentissages %}
<tr>
<td>{{ data[0].date_debut.strftime('%d/%m/%Y') }}</td>
<td>{{ data[0].date_fin.strftime('%d/%m/%Y') }}</td>
<td>{{ (data[0].date_fin-data[0].date_debut).days//7 }} semaines</td>
<td>{{ data[0].type_offre }}</td>
<td>{{ data[1].nom|format_nom }} {{ data[1].prenom|format_prenom }}</td>
<td>{% if data[0].formation_text %}{{ data[0].formation_text }}{% endif %}</td>
<td>{{ data[0].notes }}</td>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
<td>
<div class="btn-group">
<a class="btn btn-default dropdown-toggle" data-toggle="dropdown" href="#">Action
<span class="caret"></span>
</a>
<ul class="dropdown-menu pull-left">
<li><a href="{{ url_for('entreprises.edit_stage_apprentissage', id=data[0].id) }}">Modifier</a></li>
<li><a href="{{ url_for('entreprises.delete_stage_apprentissage', id=data[0].id) }}" style="color:red">Supprimer</a></li>
</ul>
</div>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td>Date début</td>
<td>Date fin</td>
<td>Durée</td>
<td>Type</td>
<td>Étudiant</td>
<td>Formation</td>
<td>Notes</td>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
<td>Action</td>
{% endif %}
</tr>
</tfoot>
</table>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
let table = new DataTable('#table-stages-apprentissages',
{
"autoWidth": false,
"responsive": {
"details": true
},
"pageLength": 10,
"language": {
"emptyTable": "Aucune donnée disponible dans le tableau",
"info": "Affichage de _START_ à _END_ sur _TOTAL_ entrées",
"infoEmpty": "Affichage de 0 à 0 sur 0 entrées",
"infoFiltered": "(filtrées depuis un total de _MAX_ entrées)",
"lengthMenu": "Afficher _MENU_ entrées",
"loadingRecords": "Chargement...",
"processing": "Traitement...",
"search": "Rechercher:",
"zeroRecords": "Aucune entrée correspondante trouvée",
"paginate": {
"next": "Suivante",
"previous": "Précédente"
}
}
});
});
</script>
{% endblock %}

View File

@ -16,25 +16,25 @@
</div>
</div>
{% if contacts %}
{% if correspondants %}
<div>
{% for contact in contacts %}
{% for correspondant in correspondants %}
<div>
<h3>Contact</h3>
<div class="contact">
Nom : {{ contact.nom }}<br>
Prénom : {{ contact.prenom }}<br>
{% if contact.telephone %}
Téléphone : {{ contact.telephone }}<br>
<h3>Correspondant</h3>
<div class="correspondant">
Nom : {{ correspondant.nom }}<br>
Prénom : {{ correspondant.prenom }}<br>
{% if correspondant.telephone %}
Téléphone : {{ correspondant.telephone }}<br>
{% endif %}
{% if contact.mail %}
Mail : {{ contact.mail }}<br>
{% if correspondant.mail %}
Mail : {{ correspondant.mail }}<br>
{% endif %}
{% if contact.poste %}
Poste : {{ contact.poste }}<br>
{% if correspondant.poste %}
Poste : {{ correspondant.poste }}<br>
{% endif %}
{% if contact.service %}
Service : {{ contact.service }}<br>
{% if correspondant.service %}
Service : {{ correspondant.service }}<br>
{% endif %}
</div>
</div>

View File

@ -4,6 +4,8 @@
{% block styles %}
{{super()}}
<link type="text/css" rel="stylesheet" href="/ScoDoc/static/css/autosuggest_inquisitor.css" />
<script src="/ScoDoc/static/libjs/AutoSuggest.js"></script>
{% endblock %}
{% block app_content %}
@ -25,5 +27,36 @@
var closest_form_control = champ_depts.closest(".form-control")
closest_form_control.classList.remove("form-control")
}
if(document.getElementById("expiration_date") !== null && document.getElementById("expiration_date").value === "")
expiration()
if(document.getElementById("type_offre") !== null)
document.getElementById("type_offre").addEventListener("change", expiration);
function expiration() {
var date = new Date()
var expiration = document.getElementById("expiration_date")
var type_offre = document.getElementById("type_offre").value
if (type_offre === "Alternance") {
expiration.value = `${date.getFullYear() + 1}-01-01`
} else {
if(date.getMonth() + 1 < 8)
expiration.value = `${date.getFullYear()}-08-01`
else
expiration.value = `${date.getFullYear() + 1}-08-01`
}
}
var responsables_options = {
script: "/ScoDoc/entreprises/responsables?",
varname: "term",
json: true,
noresults: "Valeur invalide !",
minchars: 2,
timeout: 60000
};
var as_utilisateurs = new bsn.AutoSuggest('utilisateur', responsables_options);
</script>
{% endblock %}

View File

@ -1,62 +0,0 @@
{# -*- mode: jinja-html -*- #}
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block styles %}
{{super()}}
{% endblock %}
{% block app_content %}
<h1>Importation contacts</h1>
<br>
<div>
<a href="{{ url_for('entreprises.get_import_contacts_file_sample') }}">Obtenir la feuille excel à remplir</a>
</div>
<br>
<div class="row">
<div class="col-md-4">
<p>
(*) champs requis
</p>
{{ wtf.quick_form(form, novalidate=True) }}
</div>
</div>
{% if not contacts_import %}
<table class="table">
<thead><tr><td><b>Attribut</b></td><td><b>Type</b></td><td><b>Description</b></td></tr></thead>
<tr><td>nom</td><td>text</td><td>nom du contact</td></tr>
<tr><td>prenom</td><td>text</td><td>prenom du contact</td></tr>
<tr><td>telephone</td><td>text</td><td>telephone du contact</td></tr>
<tr><td>mail</td><td>text</td><td>mail du contact</td></tr>
<tr><td>poste</td><td>text</td><td>poste du contact</td></tr>
<tr><td>service</td><td>text</td><td>service dans lequel travaille le contact</td></tr>
<tr><td>entreprise_siret</td><td>integer</td><td>SIRET de l'entreprise</td></tr>
</table>
{% endif %}
{% if contacts_import %}
<br><div>Importation de {{ contacts_import|length }} contact(s)</div>
{% for contact in contacts_import %}
<div class="contact">
<div>
Nom : {{ contact.nom }}<br>
Prénom : {{ contact.prenom }}<br>
{% if contact.telephone %}
Téléphone : {{ contact.telephone }}<br>
{% endif %}
{% if contact.mail %}
Mail : {{ contact.mail }}<br>
{% endif %}
{% if contact.poste %}
Poste : {{ contact.poste }}<br>
{% endif %}
{% if contact.service %}
Service : {{ contact.service }}<br>
{% endif %}
<a href="{{ url_for('entreprises.fiche_entreprise', id=contact.entreprise_id )}}">lien vers l'entreprise</a>
</div>
</div>
{% endfor %}
{% endif %}
{% endblock %}

View File

@ -0,0 +1,62 @@
{# -*- mode: jinja-html -*- #}
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block styles %}
{{super()}}
{% endblock %}
{% block app_content %}
<h1>Importation correspondants</h1>
<br>
<div>
<a href="{{ url_for('entreprises.get_import_correspondants_file_sample') }}">Obtenir la feuille excel à remplir</a>
</div>
<br>
<div class="row">
<div class="col-md-4">
<p>
(*) champs requis
</p>
{{ wtf.quick_form(form, novalidate=True) }}
</div>
</div>
{% if not correspondants_import %}
<table class="table">
<thead><tr><td><b>Attribut</b></td><td><b>Type</b></td><td><b>Description</b></td></tr></thead>
<tr><td>nom</td><td>text</td><td>nom du correspondant</td></tr>
<tr><td>prenom</td><td>text</td><td>prenom du correspondant</td></tr>
<tr><td>telephone</td><td>text</td><td>telephone du correspondant</td></tr>
<tr><td>mail</td><td>text</td><td>mail du correspondant</td></tr>
<tr><td>poste</td><td>text</td><td>poste du correspondant</td></tr>
<tr><td>service</td><td>text</td><td>service dans lequel travaille le correspondant</td></tr>
<tr><td>entreprise_siret</td><td>integer</td><td>SIRET de l'entreprise</td></tr>
</table>
{% endif %}
{% if correspondants_import %}
<br><div>Importation de {{ correspondants_import|length }} correspondant(s)</div>
{% for correspondant in correspondants_import %}
<div class="correspondant">
<div>
Nom : {{ correspondant.nom }}<br>
Prénom : {{ correspondant.prenom }}<br>
{% if correspondant.telephone %}
Téléphone : {{ correspondant.telephone }}<br>
{% endif %}
{% if correspondant.mail %}
Mail : {{ correspondant.mail }}<br>
{% endif %}
{% if correspondant.poste %}
Poste : {{ correspondant.poste }}<br>
{% endif %}
{% if correspondant.service %}
Service : {{ correspondant.service }}<br>
{% endif %}
<a href="{{ url_for('entreprises.fiche_entreprise', id=correspondant.entreprise_id )}}">lien vers l'entreprise</a>
</div>
</div>
{% endfor %}
{% endif %}
{% endblock %}

View File

@ -2,7 +2,7 @@
<nav class="nav-entreprise">
<ul>
<li><a href="{{ url_for('entreprises.index') }}">Entreprises</a></li>
<li><a href="{{ url_for('entreprises.contacts') }}">Contacts</a></li>
<li><a href="{{ url_for('entreprises.correspondants') }}">Correspondants</a></li>
<li><a href="{{ url_for('entreprises.offres_recues') }}">Offres reçues</a></li>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesValidate, None) %}
<li><a href="{{ url_for('entreprises.validation') }}">Entreprises à valider</a></li>

View File

@ -10,12 +10,22 @@
{% for offre in offres_recues %}
<div class="offre offre-recue">
<div>
Envoyé le {{ offre[0].date_envoi.strftime('%d %B %Y à %H:%M') }} par {{ offre[0].sender_id|get_nomcomplet_by_id }}<br>
Envoyé le {{ offre[0].date_envoi.strftime('%d/%m/%Y') }} à {{ offre[0].date_envoi.strftime('%Hh%M') }} par {{ offre[0].sender_id|get_nomcomplet_by_id }}<br>
Intitulé : {{ offre[1].intitule }}<br>
Description : {{ offre[1].description }}<br>
Type de l'offre : {{ offre[1].type_offre }}<br>
Missions : {{ offre[1].missions }}<br>
Durée : {{ offre[1].duree }}<br>
{% if offre[1].correspondant_id %}
Contacté {{ offre[3].nom }} {{ offre[3].prenom }}
{% if offre[3].mail and offre[3].telephone %}
({{ offre[3].mail }} - {{ offre[3].telephone }})<br>
{% else %}
({{ offre[3].mail }}{{offre[3].telephone}})<br>
{% endif %}
{% endif %}
<a href="{{ url_for('entreprises.fiche_entreprise', id=offre[1].entreprise_id) }}">lien vers l'entreprise</a><br>
{% for fichier in offre[2] %}

View File

@ -1,8 +1,8 @@
"""tables module gestion relations entreprises
Revision ID: af05f03b81be
Revision ID: e5043b68e6b9
Revises: b9aadc10227f
Create Date: 2022-03-01 17:12:32.927643
Create Date: 2022-04-04 09:14:54.605480
"""
from alembic import op
@ -10,7 +10,7 @@ import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = "af05f03b81be"
revision = "e5043b68e6b9"
down_revision = "b9aadc10227f"
branch_labels = None
depends_on = None
@ -54,6 +54,19 @@ def upgrade():
op.create_table(
"are_contacts",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("date", sa.DateTime(timezone=True), nullable=True),
sa.Column("user", sa.Integer(), nullable=True),
sa.Column("entreprise", sa.Integer(), nullable=True),
sa.Column("notes", sa.Text(), nullable=True),
sa.ForeignKeyConstraint(
["entreprise"], ["are_entreprises.id"], ondelete="cascade"
),
sa.ForeignKeyConstraint(["user"], ["user.id"], ondelete="cascade"),
sa.PrimaryKeyConstraint("id"),
)
op.create_table(
"are_correspondants",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("entreprise_id", sa.Integer(), nullable=True),
sa.Column("nom", sa.Text(), nullable=True),
sa.Column("prenom", sa.Text(), nullable=True),
@ -67,7 +80,7 @@ def upgrade():
sa.PrimaryKeyConstraint("id"),
)
op.create_table(
"are_etudiants",
"are_stages_apprentissages",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("entreprise_id", sa.Integer(), nullable=True),
sa.Column("etudid", sa.Integer(), nullable=True),
@ -76,6 +89,7 @@ def upgrade():
sa.Column("date_fin", sa.Date(), nullable=True),
sa.Column("formation_text", sa.Text(), nullable=True),
sa.Column("formation_scodoc", sa.Integer(), nullable=True),
sa.Column("notes", sa.Text(), nullable=True),
sa.ForeignKeyConstraint(
["entreprise_id"], ["are_entreprises.id"], ondelete="cascade"
),
@ -98,6 +112,10 @@ def upgrade():
sa.Column("duree", sa.Text(), nullable=True),
sa.Column("expiration_date", sa.Date(), nullable=True),
sa.Column("expired", sa.Boolean(), nullable=True),
sa.Column("correspondant_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(
["correspondant_id"], ["are_correspondants.id"], ondelete="cascade"
),
sa.ForeignKeyConstraint(
["entreprise_id"], ["are_entreprises.id"], ondelete="cascade"
),
@ -146,9 +164,9 @@ def upgrade():
sa.ForeignKeyConstraint(["offre_id"], ["are_offres.id"], ondelete="cascade"),
sa.PrimaryKeyConstraint("id"),
)
op.drop_index("ix_entreprises_dept_id", table_name="entreprises")
op.drop_table("entreprise_contact")
op.drop_table("entreprise_correspondant")
op.drop_index("ix_entreprises_dept_id", table_name="entreprises")
op.drop_table("entreprises")
# ### end Alembic commands ###
@ -246,7 +264,8 @@ def downgrade():
op.drop_table("are_envoi_offre_etudiant")
op.drop_table("are_envoi_offre")
op.drop_table("are_offres")
op.drop_table("are_etudiants")
op.drop_table("are_stages_apprentissages")
op.drop_table("are_correspondants")
op.drop_table("are_contacts")
op.drop_table("are_preferences")
op.drop_table("are_logs")