Merge branch 'master' of https://scodoc.org/git/viennet/ScoDoc into situation_but

This commit is contained in:
Emmanuel Viennet 2022-07-07 17:23:17 +02:00
commit c9f399d9f7
25 changed files with 1577 additions and 643 deletions

3
.gitignore vendored
View File

@ -173,3 +173,6 @@ Thumbs.db
.idea/ .idea/
copy copy
# Symlinks static ScoDoc
app/static/links/[0-9]*.*[0-9]

View File

@ -1,6 +1,7 @@
"""entreprises.__init__ """entreprises.__init__
""" """
from datetime import datetime
from flask import Blueprint from flask import Blueprint
from app.scodoc import sco_etud from app.scodoc import sco_etud
from app.auth.models import User from app.auth.models import User
@ -47,4 +48,12 @@ def get_civilité(civ):
return "Madame" return "Madame"
@bp.app_template_filter()
def check_taxe_now(taxes):
for taxe in taxes:
if taxe.annee == int(datetime.now().strftime("%Y")):
return True
return False
from app.entreprises import routes from app.entreprises import routes

View File

@ -30,6 +30,7 @@ import re
import requests import requests
import glob import glob
from flask import flash
from flask_login import current_user from flask_login import current_user
from app.entreprises.models import ( from app.entreprises.models import (
@ -38,14 +39,61 @@ from app.entreprises.models import (
EntrepriseOffre, EntrepriseOffre,
EntrepriseOffreDepartement, EntrepriseOffreDepartement,
EntreprisePreferences, EntreprisePreferences,
EntrepriseSite,
EntrepriseHistorique,
) )
from app import email, db
from app import email
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
from app.scodoc import sco_excel
from app.models import Departement from app.models import Departement
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
ENTREPRISES_KEYS = [
"siret",
"nom_entreprise",
"adresse",
"ville",
"code_postal",
"pays",
]
SITES_KEYS = [
[
"siret_entreprise",
"id_site",
"nom_site",
"adresse",
"ville",
"code_postal",
"pays",
],
[
"civilite",
"nom",
"prenom",
"telephone",
"mail",
"poste",
"service",
"origine",
"notes",
],
]
CORRESPONDANTS_KEYS = [
"id",
"civilite",
"nom",
"prenom",
"telephone",
"mail",
"poste",
"service",
"origine",
"notes",
"nom_site",
]
def get_depts(): def get_depts():
""" """
Retourne une liste contenant les l'id des départements des roles de l'utilisateur courant Retourne une liste contenant les l'id des départements des roles de l'utilisateur courant
@ -58,7 +106,7 @@ def get_depts():
return depts return depts
def get_dept_id_by_acronym(acronym): def get_dept_id_by_acronym(acronym: str):
""" """
Retourne l'id d'un departement a l'aide de son acronym Retourne l'id d'un departement a l'aide de son acronym
""" """
@ -68,7 +116,14 @@ def get_dept_id_by_acronym(acronym):
return None return None
def check_offre_depts(depts, offre_depts): def get_dept_acronym_by_id(id: int):
dept = Departement.query.filter_by(id=id).first()
if dept is not None:
return dept.acronym
return None
def check_offre_depts(depts: list, offre_depts: list):
""" """
Retourne vrai si l'utilisateur a le droit de visibilité sur l'offre Retourne vrai si l'utilisateur a le droit de visibilité sur l'offre
""" """
@ -107,7 +162,7 @@ def get_offre_files_and_depts(offre: EntrepriseOffre, depts: list):
return None return None
def send_email_notifications_entreprise(subject, entreprise: Entreprise): def send_email_notifications_entreprise(subject: str, entreprise: Entreprise):
txt = [ txt = [
"Une entreprise est en attente de validation", "Une entreprise est en attente de validation",
"Entreprise:", "Entreprise:",
@ -128,69 +183,168 @@ def send_email_notifications_entreprise(subject, entreprise: Entreprise):
return txt return txt
def verif_correspondant_data(correspondant_data): def get_excel_book_are(export: bool = False):
""" """
Verifie les données d'une ligne Excel (correspondant) Retourne un Excel avec les 3 feuilles "Entreprises", "Sites" et "Correspondants"
correspondant_data[0]: civilite
correspondant_data[1]: nom
correspondant_data[2]: prenom
correspondant_data[3]: telephone
correspondant_data[4]: mail
correspondant_data[5]: poste
correspondant_data[6]: service
correspondant_data[7]: origine
correspondant_data[8]: notes
correspondant_data[9]: entreprise_siret
""" """
# champs obligatoires entreprises_titles = ENTREPRISES_KEYS[:]
sites_titles = SITES_KEYS[:]
correspondants_titles = CORRESPONDANTS_KEYS[:]
wb = sco_excel.ScoExcelBook()
ws1 = wb.create_sheet("Entreprises")
ws1.append_row(
[
ws1.make_cell(it, style)
for (it, style) in zip(
entreprises_titles,
[sco_excel.excel_make_style(bold=True)] * len(entreprises_titles),
)
]
)
ws2 = wb.create_sheet("Sites")
ws2.append_row(
[
ws2.make_cell(it, style)
for (it, style) in zip(
sites_titles[0],
[sco_excel.excel_make_style(bold=True)] * len(sites_titles[0]),
)
]
+ [
ws2.make_cell(it, style)
for (it, style) in zip(
sites_titles[1],
[sco_excel.excel_make_style(bold=True, color=sco_excel.COLORS.RED)]
* len(sites_titles[1]),
)
]
)
ws3 = wb.create_sheet("Correspondants")
ws3.append_row(
[
ws3.make_cell(it, style)
for (it, style) in zip(
correspondants_titles,
[sco_excel.excel_make_style(bold=True)] * len(correspondants_titles),
)
]
)
if export:
entreprises = Entreprise.query.filter_by(visible=True).all()
sites = (
db.session.query(EntrepriseSite)
.join(Entreprise, EntrepriseSite.entreprise_id == Entreprise.id)
.filter_by(visible=True)
.all()
)
correspondants = (
db.session.query(EntrepriseCorrespondant)
.join(Entreprise, EntrepriseCorrespondant.entreprise_id == Entreprise.id)
.filter_by(visible=True)
.all()
)
entreprises_lines = [
[entreprise.to_dict().get(k, "") for k in ENTREPRISES_KEYS]
for entreprise in entreprises
]
sites_lines = [
[site.to_dict().get(k, "") for k in SITES_KEYS[0]] for site in sites
]
correspondants_lines = [
[correspondant.to_dict().get(k, "") for k in CORRESPONDANTS_KEYS]
for correspondant in correspondants
]
for line in entreprises_lines:
cells = []
for it in line:
cells.append(ws1.make_cell(it))
ws1.append_row(cells)
for line in sites_lines:
cells = []
for it in line:
cells.append(ws2.make_cell(it))
ws2.append_row(cells)
for line in correspondants_lines:
cells = []
for it in line:
cells.append(ws3.make_cell(it))
ws3.append_row(cells)
return wb
def check_entreprises_import(m):
"""
Verifie la feuille Excel "Entreprises" de l'importation données
"""
entreprises_import = []
siret_list = []
ligne = 1
if m[0] != ENTREPRISES_KEYS:
flash(
f'Veuillez utilisez la feuille excel à remplir (Feuille "Entreprises", ligne {ligne})'
)
return False
l = list_to_dict(m)
for entreprise_data in l:
ligne += 1
entreprise_data["siret"] = entreprise_data["siret"].replace(" ", "")
if ( if (
correspondant_data[0].strip() == "" check_entreprise_import(entreprise_data)
or correspondant_data[1].strip() == "" and entreprise_data["siret"] not in siret_list
or correspondant_data[2].strip() == ""
or correspondant_data[9].strip() == ""
): ):
return False siret_list.append(entreprise_data["siret"])
entreprise = Entreprise.query.filter_by(
# civilite entre H ou F siret=entreprise_data["siret"], visible=True
if correspondant_data[0].strip() not in ["H", "F"]:
return False
# entreprise_id existant
entreprise = Entreprise.query.filter_by(siret=correspondant_data[9].strip()).first()
if entreprise is None:
return False
# correspondant possède le meme nom et prénom dans la meme entreprise
correspondant = EntrepriseCorrespondant.query.filter_by(
nom=correspondant_data[1].strip(),
prenom=correspondant_data[2].strip(),
entreprise_id=entreprise.id,
).first() ).first()
if correspondant is not None: if entreprise is None:
entreprise_import = Entreprise(
siret=entreprise_data["siret"],
nom=entreprise_data["nom_entreprise"],
adresse=entreprise_data["adresse"],
ville=entreprise_data["ville"],
codepostal=entreprise_data["code_postal"],
pays=entreprise_data["pays"]
if entreprise_data["pays"]
else "FRANCE",
visible=True,
)
entreprises_import.append(entreprise_import)
else:
entreprise.nom = entreprise_data["nom_entreprise"]
entreprise.adresse = entreprise_data["adresse"]
entreprise.ville = entreprise_data["ville"]
entreprise.codepostal = entreprise_data["code_postal"]
entreprise.pays = (
entreprise_data["pays"] if entreprise_data["pays"] else "FRANCE"
)
else:
flash(
f'Erreur lors de l\'importation (Feuille "Entreprises", ligne {ligne})'
)
return False return False
if ( if len(entreprises_import) > 0:
correspondant_data[3].strip() == "" and correspondant_data[4].strip() == "" log = EntrepriseHistorique(
): # 1 moyen de contact authenticated_user=current_user.user_name,
return False text=f"Importation de {len(entreprises_import)} entreprise(s)",
)
db.session.add(log)
return True return entreprises_import
def verif_entreprise_data(entreprise_data): def check_entreprise_import(entreprise_data):
""" """
Verifie les données d'une ligne Excel (entreprise) Verifie les données d'une ligne Excel (entreprise)
""" """
if EntreprisePreferences.get_check_siret(): champs_obligatoires = ["siret", "nom_entreprise", "adresse", "ville", "code_postal"]
for data in entreprise_data: # champs obligatoires for key, value in entreprise_data.items(): # champs obligatoires
if data.strip() == "": if key in champs_obligatoires and value == "":
return False
else:
for data in entreprise_data[1:]: # champs obligatoires
if data.strip() == "":
return False return False
siret = entreprise_data["siret"]
if EntreprisePreferences.get_check_siret(): if EntreprisePreferences.get_check_siret():
siret = entreprise_data[0].strip().replace(" ", "") # vérification sur le siret
if re.match("^\d{14}$", siret) is None: if re.match("^\d{14}$", siret) is None:
return False return False
try: try:
@ -201,7 +355,210 @@ def verif_entreprise_data(entreprise_data):
return False return False
except requests.ConnectionError: except requests.ConnectionError:
return False return False
entreprise = Entreprise.query.filter_by(siret=siret).first() return True
if entreprise is not None:
def check_sites_import(m):
"""
Verifie la feuille Excel "Sites" de l'importation données
"""
sites_import = []
correspondants_import = []
ligne = 1
if m[0] != sum(SITES_KEYS, []):
flash(
f'Veuillez utilisez la feuille excel à remplir (Feuille "Sites", ligne {ligne})'
)
return False, False
l = list_to_dict(m)
for site_data in l:
ligne += 1
site_data["siret_entreprise"] = site_data["siret_entreprise"].replace(" ", "")
if check_site_import(site_data):
entreprise = Entreprise.query.filter_by(
siret=site_data["siret_entreprise"], visible=True
).first()
if site_data["id_site"] == "":
site_import = EntrepriseSite(
entreprise_id=entreprise.id,
nom=site_data["nom_site"],
adresse=site_data["adresse"],
codepostal=site_data["code_postal"],
ville=site_data["ville"],
pays=site_data["pays"],
)
if site_data["civilite"] == "":
sites_import.append(site_import)
else:
correspondant_import = EntrepriseCorrespondant(
entreprise_id=entreprise.id,
civilite=site_data["civilite"],
nom=site_data["nom"],
prenom=site_data["prenom"],
telephone=site_data["telephone"],
mail=site_data["mail"],
poste=site_data["poste"],
service=site_data["service"],
origine=site_data["origine"],
notes=site_data["notes"],
)
sites_import.append(site_import)
correspondants_import.append([site_import, correspondant_import])
else:
site = EntrepriseSite.query.filter_by(id=site_data["id_site"]).first()
site.nom = site_data["nom_site"]
site.adresse = site_data["adresse"]
site.codepostal = site_data["code_postal"]
site.ville = site_data["ville"]
site.pays = site_data["pays"]
if site_data["civilite"] != "":
correspondant_import = EntrepriseCorrespondant(
entreprise_id=entreprise.id,
site_id=site.id,
civilite=site_data["civilite"],
nom=site_data["nom"],
prenom=site_data["prenom"],
telephone=site_data["telephone"],
mail=site_data["mail"],
poste=site_data["poste"],
service=site_data["service"],
origine=site_data["origine"],
notes=site_data["notes"],
)
correspondants_import.append([None, correspondant_import])
else:
flash(f'Erreur lors de l\'importation (Feuille "Sites", ligne {ligne})')
return False, False
if len(sites_import) > 0:
log = EntrepriseHistorique(
authenticated_user=current_user.user_name,
text=f"Importation de {len(sites_import)} site(s)",
)
db.session.add(log)
if len(correspondants_import) > 0:
log = EntrepriseHistorique(
authenticated_user=current_user.user_name,
text=f"Importation de {len(correspondants_import)} correspondant(s)",
)
db.session.add(log)
return sites_import, correspondants_import
def check_site_import(site_data):
"""
Verifie les données d'une ligne Excel (sites)
"""
champs_obligatoires = [
"siret_entreprise",
"nom_site",
"adresse",
"ville",
"code_postal",
"pays",
]
for key, value in site_data.items(): # champs obligatoires
if key in champs_obligatoires and value == "":
return False
if site_data["civilite"] != "":
if check_correspondant_import(site_data) is False:
return False
entreprise = Entreprise.query.filter_by(
siret=site_data["siret_entreprise"], visible=True
).first()
if entreprise is None:
return False
site = EntrepriseSite.query.filter_by(nom=site_data["nom_site"]).first()
if site_data["id_site"] == "" and site is not None:
return False
return True
def check_correspondants_import(m):
ligne = 1
if m[0] != CORRESPONDANTS_KEYS:
flash(
f'Veuillez utilisez la feuille excel à remplir (Feuille "Correspondants", ligne {ligne})'
)
return False
l = list_to_dict(m)
for correspondant_data in l:
ligne += 1
if correspondant_data["id"] == "":
flash(
f'Erreur lors de l\'importation (Feuille "Correspondants", ligne {ligne})'
)
return False
correspondant = EntrepriseCorrespondant.query.filter_by(
id=correspondant_data["id"]
).first()
if correspondant is not None and check_correspondant_import(correspondant_data):
correspondant.civilite = correspondant_data["civilite"]
correspondant.nom = correspondant_data["nom"]
correspondant.prenom = correspondant_data["prenom"]
correspondant.telephone = correspondant_data["telephone"]
correspondant.mail = correspondant_data["mail"]
correspondant.poste = correspondant_data["poste"]
correspondant.service = correspondant_data["service"]
correspondant.origine = correspondant_data["origine"]
correspondant.notes = correspondant_data["notes"]
else:
flash(
f'Erreur lors de l\'importation (Feuille "Correspondants", ligne {ligne})'
)
return False return False
return True return True
def check_correspondant_import(correspondant_data):
"""
Verifie les données d'une ligne Excel (correspondant)
"""
champs_obligatoires = ["civilite", "nom", "prenom"]
for key, value in correspondant_data.items(): # champs obligatoires
if key in champs_obligatoires and value == "":
return False
# civilite entre H ou F
if correspondant_data["civilite"] not in ["H", "F"]:
return False
if (
correspondant_data["telephone"] == "" and correspondant_data["mail"] == ""
): # 1 moyen de contact
return False
if "siret_entreprise" in correspondant_data:
# entreprise_id existant
entreprise = Entreprise.query.filter_by(
siret=correspondant_data["siret_entreprise"], visible=True
).first()
if entreprise is None:
return False
# correspondant possède le meme nom et prénom dans la meme entreprise
correspondant = EntrepriseCorrespondant.query.filter_by(
nom=correspondant_data["nom"],
prenom=correspondant_data["prenom"],
entreprise_id=entreprise.id,
).first()
if correspondant is not None:
return False
return True
def list_to_dict(m):
l = []
for data in m[1:]:
new_dict = {title: value.strip() for title, value in zip(m[0], data)}
l.append(new_dict)
return l

View File

@ -26,6 +26,7 @@
import re import re
import requests import requests
from datetime import datetime
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed, FileRequired from flask_wtf.file import FileField, FileAllowed, FileRequired
@ -33,6 +34,7 @@ from markupsafe import Markup
from sqlalchemy import text from sqlalchemy import text
from wtforms import ( from wtforms import (
StringField, StringField,
IntegerField,
SubmitField, SubmitField,
TextAreaField, TextAreaField,
SelectField, SelectField,
@ -42,14 +44,23 @@ from wtforms import (
BooleanField, BooleanField,
FieldList, FieldList,
FormField, FormField,
BooleanField,
)
from wtforms.validators import (
ValidationError,
DataRequired,
Email,
Optional,
NumberRange,
) )
from wtforms.validators import ValidationError, DataRequired, Email, Optional
from wtforms.widgets import ListWidget, CheckboxInput from wtforms.widgets import ListWidget, CheckboxInput
from app.entreprises.models import ( from app.entreprises.models import (
Entreprise, Entreprise,
EntrepriseCorrespondant, EntrepriseCorrespondant,
EntreprisePreferences, EntreprisePreferences,
EntrepriseSite,
EntrepriseTaxeApprentissage,
) )
from app.models import Identite, Departement from app.models import Identite, Departement
from app.auth.models import User from app.auth.models import User
@ -69,11 +80,17 @@ def _build_string_field(label, required=True, render_kw=None):
return StringField(label, validators=[Optional()], render_kw=render_kw) return StringField(label, validators=[Optional()], render_kw=render_kw)
class EntreprisesFilterForm(FlaskForm):
active = BooleanField("Toutes les entreprises")
association = BooleanField("Seulement les associations partenaires")
class EntrepriseCreationForm(FlaskForm): class EntrepriseCreationForm(FlaskForm):
siret = _build_string_field( siret = _build_string_field(
"SIRET (*)", "SIRET (*)",
render_kw={"placeholder": "Numéro composé de 14 chiffres"}, render_kw={"placeholder": "Numéro composé de 14 chiffres"},
) )
association = BooleanField("Association")
nom_entreprise = _build_string_field("Nom de l'entreprise (*)") nom_entreprise = _build_string_field("Nom de l'entreprise (*)")
adresse = _build_string_field("Adresse de l'entreprise (*)") adresse = _build_string_field("Adresse de l'entreprise (*)")
codepostal = _build_string_field("Code postal de l'entreprise (*)") codepostal = _build_string_field("Code postal de l'entreprise (*)")
@ -153,8 +170,8 @@ class EntrepriseCreationForm(FlaskForm):
class EntrepriseModificationForm(FlaskForm): class EntrepriseModificationForm(FlaskForm):
hidden_entreprise_siret = HiddenField()
siret = StringField("SIRET (*)") siret = StringField("SIRET (*)")
association = BooleanField("Association")
nom = _build_string_field("Nom de l'entreprise (*)") nom = _build_string_field("Nom de l'entreprise (*)")
adresse = _build_string_field("Adresse (*)") adresse = _build_string_field("Adresse (*)")
codepostal = _build_string_field("Code postal (*)") codepostal = _build_string_field("Code postal (*)")
@ -164,13 +181,11 @@ class EntrepriseModificationForm(FlaskForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.siret.render_kw = { self.siret.render_kw = {"disabled": ""}
"disabled": "",
"value": self.hidden_entreprise_siret.data,
}
class SiteCreationForm(FlaskForm): class SiteCreationForm(FlaskForm):
hidden_entreprise_id = HiddenField()
nom = _build_string_field("Nom du site (*)") nom = _build_string_field("Nom du site (*)")
adresse = _build_string_field("Adresse (*)") adresse = _build_string_field("Adresse (*)")
codepostal = _build_string_field("Code postal (*)") codepostal = _build_string_field("Code postal (*)")
@ -178,6 +193,49 @@ class SiteCreationForm(FlaskForm):
pays = _build_string_field("Pays", required=False) pays = _build_string_field("Pays", required=False)
submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE) submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)
def validate(self):
validate = True
if not FlaskForm.validate(self):
validate = False
site = EntrepriseSite.query.filter_by(
entreprise_id=self.hidden_entreprise_id.data, nom=self.nom.data
).first()
if site is not None:
self.nom.errors.append("Ce site existe déjà (même nom)")
validate = False
return validate
class SiteModificationForm(FlaskForm):
hidden_entreprise_id = HiddenField()
hidden_site_id = HiddenField()
nom = _build_string_field("Nom du site (*)")
adresse = _build_string_field("Adresse (*)")
codepostal = _build_string_field("Code postal (*)")
ville = _build_string_field("Ville (*)")
pays = _build_string_field("Pays", required=False)
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
def validate(self):
validate = True
if not FlaskForm.validate(self):
validate = False
site = EntrepriseSite.query.filter(
EntrepriseSite.entreprise_id == self.hidden_entreprise_id.data,
EntrepriseSite.id != self.hidden_site_id.data,
EntrepriseSite.nom == self.nom.data,
).first()
if site is not None:
self.nom.errors.append("Ce site existe déjà (même nom)")
validate = False
return validate
class MultiCheckboxField(SelectMultipleField): class MultiCheckboxField(SelectMultipleField):
widget = ListWidget(prefix_label=False) widget = ListWidget(prefix_label=False)
@ -214,7 +272,7 @@ class OffreCreationForm(FlaskForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.correspondant.choices = [ self.correspondant.choices = [("", "")] + [
(correspondant.id, f"{correspondant.nom} {correspondant.prenom}") (correspondant.id, f"{correspondant.nom} {correspondant.prenom}")
for correspondant in EntrepriseCorrespondant.query.filter_by( for correspondant in EntrepriseCorrespondant.query.filter_by(
entreprise_id=self.hidden_entreprise_id.data entreprise_id=self.hidden_entreprise_id.data
@ -260,7 +318,7 @@ class OffreModificationForm(FlaskForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.correspondant.choices = [ self.correspondant.choices = [("", "")] + [
(correspondant.id, f"{correspondant.nom} {correspondant.prenom}") (correspondant.id, f"{correspondant.nom} {correspondant.prenom}")
for correspondant in EntrepriseCorrespondant.query.filter_by( for correspondant in EntrepriseCorrespondant.query.filter_by(
entreprise_id=self.hidden_entreprise_id.data entreprise_id=self.hidden_entreprise_id.data
@ -290,8 +348,16 @@ class CorrespondantCreationForm(FlaskForm):
validators=[DataRequired(message=CHAMP_REQUIS)], validators=[DataRequired(message=CHAMP_REQUIS)],
render_kw={"class": "form-control"}, render_kw={"class": "form-control"},
) )
nom = _build_string_field("Nom (*)", render_kw={"class": "form-control"}) nom = StringField(
prenom = _build_string_field("Prénom (*)", render_kw={"class": "form-control"}) "Nom (*)",
validators=[DataRequired('Le champ "Nom" est requis')],
render_kw={"class": "form-control"},
)
prenom = StringField(
"Prénom (*)",
validators=[DataRequired('Le champ "Prénom" est requis')],
render_kw={"class": "form-control"},
)
telephone = _build_string_field( telephone = _build_string_field(
"Téléphone (*)", required=False, render_kw={"class": "form-control"} "Téléphone (*)", required=False, render_kw={"class": "form-control"}
) )
@ -321,7 +387,6 @@ class CorrespondantCreationForm(FlaskForm):
if not self.telephone.data and not self.mail.data: if not self.telephone.data and not self.mail.data:
msg = "Saisir un moyen de contact (mail ou téléphone)" msg = "Saisir un moyen de contact (mail ou téléphone)"
self.telephone.errors.append(msg) self.telephone.errors.append(msg)
self.mail.errors.append(msg)
validate = False validate = False
return validate return validate
@ -558,9 +623,75 @@ class StageApprentissageModificationForm(FlaskForm):
raise ValidationError("Champ incorrect (selectionnez dans la liste)") raise ValidationError("Champ incorrect (selectionnez dans la liste)")
class TaxeApprentissageForm(FlaskForm):
hidden_entreprise_id = HiddenField()
annee = IntegerField(
"Année (*)",
validators=[
DataRequired(message=CHAMP_REQUIS),
NumberRange(
min=1900,
max=int(datetime.now().strftime("%Y")),
message=f"L'année doit être inférieure ou égale à {int(datetime.now().strftime('%Y'))}",
),
],
default=int(datetime.now().strftime("%Y")),
)
montant = IntegerField(
"Montant (*)",
validators=[
DataRequired(message=CHAMP_REQUIS),
NumberRange(
min=1,
message="Le montant doit être supérieur à 0",
),
],
default=1,
)
notes = TextAreaField("Notes")
submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE)
def validate(self):
validate = True
if not FlaskForm.validate(self):
validate = False
taxe = EntrepriseTaxeApprentissage.query.filter_by(
entreprise_id=self.hidden_entreprise_id.data, annee=self.annee.data
).first()
if taxe is not None:
self.annee.errors.append(
"Une taxe d'apprentissage a déjà été versé pour cette année"
)
validate = False
return validate
class TaxeApprentissageModificationForm(FlaskForm):
annee = IntegerField("Année (*)")
montant = IntegerField(
"Montant (*)",
validators=[
DataRequired(message=CHAMP_REQUIS),
NumberRange(
min=1,
message="Le montant doit être supérieur à 0",
),
],
default=1,
)
notes = TextAreaField("Notes")
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.annee.render_kw = {"disabled": ""}
class EnvoiOffreForm(FlaskForm): class EnvoiOffreForm(FlaskForm):
responsables = FieldList( responsables = FieldList(
_build_string_field( StringField(
"Responsable (*)", "Responsable (*)",
render_kw={ render_kw={
"placeholder": "Tapez le nom du responsable de formation", "placeholder": "Tapez le nom du responsable de formation",
@ -573,6 +704,8 @@ class EnvoiOffreForm(FlaskForm):
def validate(self): def validate(self):
validate = True validate = True
list_select = True
if not FlaskForm.validate(self): if not FlaskForm.validate(self):
validate = False validate = False
@ -588,8 +721,12 @@ class EnvoiOffreForm(FlaskForm):
.first() .first()
) )
if responsable is None: if responsable is None:
entry.errors.append("Champ incorrect (selectionnez dans la liste)") validate, list_select = False, False
validate = False
if list_select is False:
self.responsables.errors.append(
"Champ incorrect (selectionnez dans la liste)"
)
return validate return validate
@ -611,7 +748,11 @@ class SuppressionConfirmationForm(FlaskForm):
class DesactivationConfirmationForm(FlaskForm): class DesactivationConfirmationForm(FlaskForm):
notes_active = TextAreaField("Notes sur la désactivation", validators=[Optional()]) notes_active = TextAreaField("Notes sur la désactivation", validators=[Optional()])
submit = SubmitField("Désactiver", render_kw=SUBMIT_MARGE) submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
class ActivationConfirmationForm(FlaskForm):
submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE)
class ValidationConfirmationForm(FlaskForm): class ValidationConfirmationForm(FlaskForm):
@ -633,6 +774,7 @@ class PreferencesForm(FlaskForm):
mail_entreprise = StringField( mail_entreprise = StringField(
"Mail notifications", "Mail notifications",
validators=[Optional(), Email(message="Adresse e-mail invalide")], validators=[Optional(), Email(message="Adresse e-mail invalide")],
description="utilisé pour envoi mail notification application relations entreprises",
) )
check_siret = BooleanField("Vérification SIRET") check_siret = BooleanField("Vérification SIRET")
submit = SubmitField("Valider", render_kw=SUBMIT_MARGE) submit = SubmitField("Valider", render_kw=SUBMIT_MARGE)

View File

@ -10,6 +10,7 @@ class Entreprise(db.Model):
codepostal = db.Column(db.Text) codepostal = db.Column(db.Text)
ville = db.Column(db.Text) ville = db.Column(db.Text)
pays = db.Column(db.Text) pays = db.Column(db.Text)
association = db.Column(db.Boolean, default=False)
visible = db.Column(db.Boolean, default=False) visible = db.Column(db.Boolean, default=False)
active = db.Column(db.Boolean, default=True) active = db.Column(db.Boolean, default=True)
notes_active = db.Column(db.Text) notes_active = db.Column(db.Text)
@ -36,6 +37,10 @@ class Entreprise(db.Model):
"code_postal": self.codepostal, "code_postal": self.codepostal,
"ville": self.ville, "ville": self.ville,
"pays": self.pays, "pays": self.pays,
"association": self.association,
"visible": self.visible,
"active": self.active,
"notes_active": self.notes_active,
} }
@ -58,6 +63,18 @@ class EntrepriseSite(db.Model):
cascade="all, delete-orphan", cascade="all, delete-orphan",
) )
def to_dict(self):
entreprise = Entreprise.query.get_or_404(self.entreprise_id)
return {
"siret_entreprise": entreprise.siret,
"id_site": self.id,
"nom_site": self.nom,
"adresse": self.adresse,
"code_postal": self.codepostal,
"ville": self.ville,
"pays": self.pays,
}
class EntrepriseCorrespondant(db.Model): class EntrepriseCorrespondant(db.Model):
__tablename__ = "are_correspondants" __tablename__ = "are_correspondants"
@ -77,8 +94,9 @@ class EntrepriseCorrespondant(db.Model):
notes = db.Column(db.Text) notes = db.Column(db.Text)
def to_dict(self): def to_dict(self):
entreprise = Entreprise.query.filter_by(id=self.entreprise_id).first() site = EntrepriseSite.query.get_or_404(self.site_id)
return { return {
"id": self.id,
"civilite": self.civilite, "civilite": self.civilite,
"nom": self.nom, "nom": self.nom,
"prenom": self.prenom, "prenom": self.prenom,
@ -88,7 +106,7 @@ class EntrepriseCorrespondant(db.Model):
"service": self.service, "service": self.service,
"origine": self.origine, "origine": self.origine,
"notes": self.notes, "notes": self.notes,
"entreprise_siret": entreprise.siret, "nom_site": site.nom,
} }
@ -131,12 +149,14 @@ class EntrepriseOffre(db.Model):
} }
class EntrepriseLog(db.Model): class EntrepriseHistorique(db.Model):
__tablename__ = "are_logs" __tablename__ = "are_historique"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
date = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
authenticated_user = db.Column(db.Text) authenticated_user = db.Column(db.Text)
object = db.Column(db.Integer) entreprise_id = db.Column(db.Integer)
object = db.Column(db.Text)
object_id = db.Column(db.Integer)
text = db.Column(db.Text) text = db.Column(db.Text)
@ -155,6 +175,17 @@ class EntrepriseStageApprentissage(db.Model):
notes = db.Column(db.Text) notes = db.Column(db.Text)
class EntrepriseTaxeApprentissage(db.Model):
__tablename__ = "are_taxe_apprentissage"
id = db.Column(db.Integer, primary_key=True)
entreprise_id = db.Column(
db.Integer, db.ForeignKey("are_entreprises.id", ondelete="cascade")
)
annee = db.Column(db.Integer)
montant = db.Column(db.Integer)
notes = db.Column(db.Text)
class EntrepriseEnvoiOffre(db.Model): class EntrepriseEnvoiOffre(db.Model):
__tablename__ = "are_envoi_offre" __tablename__ = "are_envoi_offre"
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)

View File

@ -12,11 +12,14 @@ from app.decorators import permission_required
from app.entreprises import LOGS_LEN from app.entreprises import LOGS_LEN
from app.entreprises.forms import ( from app.entreprises.forms import (
ActivationConfirmationForm,
CorrespondantsCreationForm, CorrespondantsCreationForm,
DesactivationConfirmationForm, DesactivationConfirmationForm,
EntrepriseCreationForm, EntrepriseCreationForm,
EntrepriseModificationForm, EntrepriseModificationForm,
EntreprisesFilterForm,
SiteCreationForm, SiteCreationForm,
SiteModificationForm,
SuppressionConfirmationForm, SuppressionConfirmationForm,
OffreCreationForm, OffreCreationForm,
OffreModificationForm, OffreModificationForm,
@ -27,6 +30,8 @@ from app.entreprises.forms import (
StageApprentissageModificationForm, StageApprentissageModificationForm,
EnvoiOffreForm, EnvoiOffreForm,
AjoutFichierForm, AjoutFichierForm,
TaxeApprentissageForm,
TaxeApprentissageModificationForm,
ValidationConfirmationForm, ValidationConfirmationForm,
ImportForm, ImportForm,
PreferencesForm, PreferencesForm,
@ -36,13 +41,14 @@ from app.entreprises.models import (
Entreprise, Entreprise,
EntrepriseOffre, EntrepriseOffre,
EntrepriseCorrespondant, EntrepriseCorrespondant,
EntrepriseLog, EntrepriseHistorique,
EntrepriseContact, EntrepriseContact,
EntrepriseSite, EntrepriseSite,
EntrepriseStageApprentissage, EntrepriseStageApprentissage,
EntrepriseEnvoiOffre, EntrepriseEnvoiOffre,
EntrepriseOffreDepartement, EntrepriseOffreDepartement,
EntreprisePreferences, EntreprisePreferences,
EntrepriseTaxeApprentissage,
) )
from app.entreprises import app_relations_entreprises as are from app.entreprises import app_relations_entreprises as are
from app.models import Identite from app.models import Identite
@ -52,18 +58,40 @@ from app.scodoc import sco_etud, sco_excel
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app import db from app import db
from sqlalchemy import text from sqlalchemy import text, sql
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
@bp.route("/", methods=["GET"]) @bp.route("/", methods=["GET", "POST"])
@permission_required(Permission.RelationsEntreprisesView) @permission_required(Permission.RelationsEntreprisesView)
def index(): def index():
""" """
Permet d'afficher une page avec la liste des entreprises (visible) et une liste des dernières opérations Permet d'afficher une page avec la liste des entreprises (visible) et une liste des dernières opérations
""" """
entreprises = Entreprise.query.filter_by(visible=True, active=True) entreprises = Entreprise.query.filter_by(visible=True, active=True)
logs = EntrepriseLog.query.order_by(EntrepriseLog.date.desc()).limit(LOGS_LEN).all() logs = (
EntrepriseHistorique.query.order_by(EntrepriseHistorique.date.desc())
.limit(LOGS_LEN)
.all()
)
if current_user.has_permission(Permission.RelationsEntreprisesChange, None):
form = EntreprisesFilterForm()
checked = [False, False]
if request.method == "POST":
checked[0] = form.active.data
checked[1] = form.association.data
if checked[0]:
entreprises = Entreprise.query.filter_by(visible=True)
if checked[1]:
entreprises = Entreprise.query.filter_by(association=True)
return render_template(
"entreprises/entreprises.html",
title="Entreprises",
entreprises=entreprises,
logs=logs,
form=form,
checked=checked,
)
return render_template( return render_template(
"entreprises/entreprises.html", "entreprises/entreprises.html",
title="Entreprises", title="Entreprises",
@ -79,9 +107,9 @@ def logs():
Permet d'afficher les logs (toutes les entreprises) Permet d'afficher les logs (toutes les entreprises)
""" """
page = request.args.get("page", 1, type=int) page = request.args.get("page", 1, type=int)
logs = EntrepriseLog.query.order_by(EntrepriseLog.date.desc()).paginate( logs = EntrepriseHistorique.query.order_by(
page=page, per_page=20 EntrepriseHistorique.date.desc()
) ).paginate(page=page, per_page=20)
return render_template( return render_template(
"entreprises/logs.html", "entreprises/logs.html",
title="Logs", title="Logs",
@ -110,11 +138,17 @@ def correspondants():
Permet d'afficher une page avec la liste des correspondants des entreprises visibles et une liste des dernières opérations Permet d'afficher une page avec la liste des correspondants des entreprises visibles et une liste des dernières opérations
""" """
correspondants = ( correspondants = (
db.session.query(EntrepriseCorrespondant, Entreprise) db.session.query(EntrepriseCorrespondant, EntrepriseSite)
.join(Entreprise, EntrepriseCorrespondant.entreprise_id == Entreprise.id) .join(EntrepriseSite, EntrepriseCorrespondant.site_id == EntrepriseSite.id)
.join(Entreprise, EntrepriseSite.entreprise_id == Entreprise.id)
.filter_by(visible=True, active=True) .filter_by(visible=True, active=True)
.all()
)
logs = (
EntrepriseHistorique.query.order_by(EntrepriseHistorique.date.desc())
.limit(LOGS_LEN)
.all()
) )
logs = EntrepriseLog.query.order_by(EntrepriseLog.date.desc()).limit(LOGS_LEN).all()
return render_template( return render_template(
"entreprises/correspondants.html", "entreprises/correspondants.html",
title="Correspondants", title="Correspondants",
@ -132,9 +166,9 @@ def fiche_entreprise(id):
La fiche entreprise comporte les informations de l'entreprise, les correspondants de l'entreprise et La fiche entreprise comporte les informations de l'entreprise, les correspondants de l'entreprise et
les offres de l'entreprise. les offres de l'entreprise.
""" """
entreprise = Entreprise.query.filter_by( entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404(
id=id, visible=True, active=True description=f"fiche entreprise {id} inconnue"
).first_or_404(description=f"fiche entreprise {id} inconnue") )
offres_with_files = [] offres_with_files = []
depts = are.get_depts() depts = are.get_depts()
for offre in entreprise.offres: for offre in entreprise.offres:
@ -150,8 +184,8 @@ def fiche_entreprise(id):
offres_with_files.append(offre_with_files) offres_with_files.append(offre_with_files)
sites = entreprise.sites[:] sites = entreprise.sites[:]
logs = ( logs = (
EntrepriseLog.query.order_by(EntrepriseLog.date.desc()) EntrepriseHistorique.query.order_by(EntrepriseHistorique.date.desc())
.filter_by(object=id) .filter(EntrepriseHistorique.entreprise_id == id)
.limit(LOGS_LEN) .limit(LOGS_LEN)
.all() .all()
) )
@ -162,6 +196,11 @@ def fiche_entreprise(id):
.join(Identite, Identite.id == EntrepriseStageApprentissage.etudid) .join(Identite, Identite.id == EntrepriseStageApprentissage.etudid)
.all() .all()
) )
taxes = (
EntrepriseTaxeApprentissage.query.filter_by(entreprise_id=id)
.order_by(EntrepriseTaxeApprentissage.annee.desc())
.all()
)
return render_template( return render_template(
"entreprises/fiche_entreprise.html", "entreprises/fiche_entreprise.html",
title="Fiche entreprise", title="Fiche entreprise",
@ -170,6 +209,7 @@ def fiche_entreprise(id):
offres=offres_with_files, offres=offres_with_files,
logs=logs, logs=logs,
stages_apprentissages=stages_apprentissages, stages_apprentissages=stages_apprentissages,
taxes=taxes,
) )
@ -184,8 +224,8 @@ def logs_entreprise(id):
description=f"logs fiche entreprise {id} inconnu" description=f"logs fiche entreprise {id} inconnu"
) )
logs = ( logs = (
EntrepriseLog.query.order_by(EntrepriseLog.date.desc()) EntrepriseHistorique.query.order_by(EntrepriseHistorique.date.desc())
.filter_by(object=id) .filter(EntrepriseHistorique.entreprise_id == entreprise.id)
.paginate(page=page, per_page=20) .paginate(page=page, per_page=20)
) )
return render_template( return render_template(
@ -205,12 +245,12 @@ def fiche_entreprise_validation(id):
entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404( entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404(
description=f"fiche entreprise (validation) {id} inconnue" description=f"fiche entreprise (validation) {id} inconnue"
) )
correspondants = entreprise.correspondants sites = entreprise.sites[:]
return render_template( return render_template(
"entreprises/fiche_entreprise_validation.html", "entreprises/fiche_entreprise_validation.html",
title="Validation fiche entreprise", title="Validation fiche entreprise",
entreprise=entreprise, entreprise=entreprise,
correspondants=correspondants, sites=sites,
) )
@ -290,6 +330,7 @@ def add_entreprise():
entreprise = Entreprise( entreprise = Entreprise(
nom=form.nom_entreprise.data.strip(), nom=form.nom_entreprise.data.strip(),
siret=form.siret.data.strip(), siret=form.siret.data.strip(),
association=form.association.data,
adresse=form.adresse.data.strip(), adresse=form.adresse.data.strip(),
codepostal=form.codepostal.data.strip(), codepostal=form.codepostal.data.strip(),
ville=form.ville.data.strip(), ville=form.ville.data.strip(),
@ -327,9 +368,10 @@ def add_entreprise():
if current_user.has_permission(Permission.RelationsEntreprisesValidate, None): if current_user.has_permission(Permission.RelationsEntreprisesValidate, None):
entreprise.visible = True entreprise.visible = True
nom_entreprise = f"<a href=/ScoDoc/entreprises/fiche_entreprise/{entreprise.id}>{entreprise.nom}</a>" nom_entreprise = f"<a href=/ScoDoc/entreprises/fiche_entreprise/{entreprise.id}>{entreprise.nom}</a>"
log = EntrepriseLog( log = EntrepriseHistorique(
authenticated_user=current_user.user_name, authenticated_user=current_user.user_name,
text=f"{nom_entreprise} - Création de la fiche entreprise ({entreprise.nom})", text=f"{nom_entreprise} - Création de la fiche entreprise ({entreprise.nom})",
entreprise_id=entreprise.id,
) )
db.session.add(log) db.session.add(log)
db.session.commit() db.session.commit()
@ -360,51 +402,52 @@ def edit_entreprise(id):
entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404(
description=f"entreprise {id} inconnue" description=f"entreprise {id} inconnue"
) )
form = EntrepriseModificationForm(hidden_entreprise_siret=entreprise.siret) form = EntrepriseModificationForm(siret=entreprise.siret)
if form.validate_on_submit(): if form.validate_on_submit():
nom_entreprise = f"<a href=/ScoDoc/entreprises/fiche_entreprise/{entreprise.id}>{form.nom.data.strip()}</a>" nom_entreprise = f"<a href=/ScoDoc/entreprises/fiche_entreprise/{entreprise.id}>{form.nom.data.strip()}</a>"
if entreprise.nom != form.nom.data.strip(): if entreprise.nom != form.nom.data.strip():
log = EntrepriseLog( log = EntrepriseHistorique(
authenticated_user=current_user.user_name, authenticated_user=current_user.user_name,
object=entreprise.id, entreprise_id=entreprise.id,
text=f"{nom_entreprise} - Modification du nom (ancien nom: {entreprise.nom})", text=f"{nom_entreprise} - Modification du nom (ancien nom: {entreprise.nom})",
) )
entreprise.nom = form.nom.data.strip() entreprise.nom = form.nom.data.strip()
db.session.add(log) db.session.add(log)
if entreprise.adresse != form.adresse.data.strip(): if entreprise.adresse != form.adresse.data.strip():
log = EntrepriseLog( log = EntrepriseHistorique(
authenticated_user=current_user.user_name, authenticated_user=current_user.user_name,
object=entreprise.id, entreprise_id=entreprise.id,
text=f"{nom_entreprise} - Modification de l'adresse (ancienne adresse: {entreprise.adresse})", text=f"{nom_entreprise} - Modification de l'adresse (ancienne adresse: {entreprise.adresse})",
) )
entreprise.adresse = form.adresse.data.strip() entreprise.adresse = form.adresse.data.strip()
db.session.add(log) db.session.add(log)
if entreprise.codepostal != form.codepostal.data.strip(): if entreprise.codepostal != form.codepostal.data.strip():
log = EntrepriseLog( log = EntrepriseHistorique(
authenticated_user=current_user.user_name, authenticated_user=current_user.user_name,
object=entreprise.id, entreprise_id=entreprise.id,
text=f"{nom_entreprise} - Modification du code postal (ancien code postal: {entreprise.codepostal})", text=f"{nom_entreprise} - Modification du code postal (ancien code postal: {entreprise.codepostal})",
) )
entreprise.codepostal = form.codepostal.data.strip() entreprise.codepostal = form.codepostal.data.strip()
db.session.add(log) db.session.add(log)
if entreprise.ville != form.ville.data.strip(): if entreprise.ville != form.ville.data.strip():
log = EntrepriseLog( log = EntrepriseHistorique(
authenticated_user=current_user.user_name, authenticated_user=current_user.user_name,
object=entreprise.id, entreprise_id=entreprise.id,
text=f"{nom_entreprise} - Modification de la ville (ancienne ville: {entreprise.ville})", text=f"{nom_entreprise} - Modification de la ville (ancienne ville: {entreprise.ville})",
) )
entreprise.ville = form.ville.data.strip() entreprise.ville = form.ville.data.strip()
db.session.add(log) db.session.add(log)
if entreprise.pays != form.pays.data.strip() or not form.pays.data.strip(): if entreprise.pays != form.pays.data.strip() or not form.pays.data.strip():
log = EntrepriseLog( log = EntrepriseHistorique(
authenticated_user=current_user.user_name, authenticated_user=current_user.user_name,
object=entreprise.id, entreprise_id=entreprise.id,
text=f"{nom_entreprise} - Modification du pays (ancien pays: {entreprise.pays})", text=f"{nom_entreprise} - Modification du pays (ancien pays: {entreprise.pays})",
) )
entreprise.pays = ( entreprise.pays = (
form.pays.data.strip() if form.pays.data.strip() else "FRANCE" form.pays.data.strip() if form.pays.data.strip() else "FRANCE"
) )
db.session.add(log) db.session.add(log)
entreprise.association = form.association.data
db.session.commit() db.session.commit()
flash("L'entreprise a été modifié.") flash("L'entreprise a été modifié.")
return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id)) return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id))
@ -415,6 +458,7 @@ def edit_entreprise(id):
form.codepostal.data = entreprise.codepostal form.codepostal.data = entreprise.codepostal
form.ville.data = entreprise.ville form.ville.data = entreprise.ville
form.pays.data = entreprise.pays form.pays.data = entreprise.pays
form.association.data = entreprise.association
return render_template( return render_template(
"entreprises/form_modification_entreprise.html", "entreprises/form_modification_entreprise.html",
title="Modification entreprise", title="Modification entreprise",
@ -428,21 +472,128 @@ def fiche_entreprise_desactiver(id):
""" """
Permet de désactiver une entreprise Permet de désactiver une entreprise
""" """
entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( entreprise = Entreprise.query.filter_by(
description=f"entreprise {id} inconnue" id=id, visible=True, active=True
) ).first_or_404(description=f"entreprise {id} inconnue")
form = DesactivationConfirmationForm() form = DesactivationConfirmationForm()
if form.validate_on_submit(): if form.validate_on_submit():
entreprise.notes_active = form.notes_active.data.strip() entreprise.notes_active = form.notes_active.data.strip()
entreprise.active = False entreprise.active = False
db.session.commit() db.session.commit()
flash("L'entreprise a été désactivé.") flash("L'entreprise a été désactivé.")
return redirect(url_for("entreprises.index")) return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id))
return render_template( return render_template(
"entreprises/confirmation_form.html", "entreprises/confirmation_form.html",
title="Désactiver entreprise", title="Désactiver entreprise",
form=form, form=form,
info_message="Cliquez sur le bouton Désactiver pour confirmer la désactivation", info_message="Cliquez sur le bouton Modifier pour confirmer la désactivation",
)
@bp.route("/fiche_entreprise/activer/<int:id>", methods=["GET", "POST"])
@permission_required(Permission.RelationsEntreprisesChange)
def fiche_entreprise_activer(id):
"""
Permet d'activer une entreprise
"""
entreprise = Entreprise.query.filter_by(
id=id, visible=True, active=False
).first_or_404(description=f"entreprise {id} inconnue")
form = ActivationConfirmationForm()
if form.validate_on_submit():
entreprise.active = True
db.session.commit()
flash("L'entreprise a été activé.")
return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id))
return render_template(
"entreprises/confirmation_form.html",
title="Activer entreprise",
form=form,
info_message="Cliquez sur le bouton Modifier pour confirmer l'activaction",
)
@bp.route("/fiche_entreprise/<int:id>/add_taxe_apprentissage", methods=["GET", "POST"])
def add_taxe_apprentissage(id):
"""
Permet d'ajouter une taxe d'apprentissage sur un fiche entreprise
"""
entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404(
description=f"entreprise {id} inconnue"
)
form = TaxeApprentissageForm(hidden_entreprise_id=id)
if form.validate_on_submit():
taxe = EntrepriseTaxeApprentissage(
entreprise_id=entreprise.id,
annee=form.annee.data,
montant=form.montant.data,
notes=form.notes.data.strip(),
)
db.session.add(taxe)
db.session.commit()
return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id))
return render_template(
"entreprises/form.html",
title="Ajout taxe apprentissage",
form=form,
)
@bp.route(
"/fiche_entreprise/<int:id_entreprise>/edit_taxe_apprentissage/<int:id_taxe>",
methods=["GET", "POST"],
)
def edit_taxe_apprentissage(id_entreprise, id_taxe):
"""
Permet de modifier une taxe d'apprentissage sur un fiche entreprise
"""
entreprise = Entreprise.query.filter_by(
id=id_entreprise, visible=True
).first_or_404(description=f"entreprise {id_entreprise} inconnue")
taxe = EntrepriseTaxeApprentissage.query.filter_by(id=id_taxe).first_or_404(
description=f"taxe d'apprentissage {id_taxe} inconnue"
)
form = TaxeApprentissageModificationForm(annee=taxe.annee)
if form.validate_on_submit():
taxe.montant = form.montant.data
taxe.notes = form.notes.data.strip()
db.session.commit()
return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id))
elif request.method == "GET":
form.montant.data = taxe.montant
form.notes.data = taxe.notes
return render_template(
"entreprises/form.html",
title="Modification taxe apprentissage",
form=form,
)
@bp.route(
"/fiche_entreprise/<int:id_entreprise>/delete_taxe_apprentissage/<int:id_taxe>",
methods=["GET", "POST"],
)
def delete_taxe_apprentissage(id_entreprise, id_taxe):
"""
Permet de modifier une taxe d'apprentissage sur un fiche entreprise
"""
entreprise = Entreprise.query.filter_by(
id=id_entreprise, visible=True
).first_or_404(description=f"entreprise {id_entreprise} inconnue")
taxe = EntrepriseTaxeApprentissage.query.filter_by(id=id_taxe).first_or_404(
description=f"taxe d'apprentissage {id_taxe} inconnue"
)
form = SuppressionConfirmationForm()
if form.validate_on_submit():
db.session.delete(taxe)
db.session.commit()
flash("La taxe d'apprentissage a été supprimé de la liste.")
return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id))
return render_template(
"entreprises/confirmation_form.html",
title="Supprimer taxe apprentissage",
form=form,
info_message="Cliquez sur le bouton Supprimer pour confirmer votre supression",
) )
@ -461,9 +612,10 @@ def validate_entreprise(id):
if form.validate_on_submit(): if form.validate_on_submit():
entreprise.visible = True entreprise.visible = True
nom_entreprise = f"<a href=/ScoDoc/entreprises/fiche_entreprise/{entreprise.id}>{entreprise.nom}</a>" nom_entreprise = f"<a href=/ScoDoc/entreprises/fiche_entreprise/{entreprise.id}>{entreprise.nom}</a>"
log = EntrepriseLog( log = EntrepriseHistorique(
authenticated_user=current_user.user_name, authenticated_user=current_user.user_name,
text=f"{nom_entreprise} - Validation de la fiche entreprise ({entreprise.nom}) avec un correspondant", entreprise_id=entreprise.id,
text=f"{nom_entreprise} - Validation de la fiche entreprise ({entreprise.nom})",
) )
db.session.add(log) db.session.add(log)
db.session.commit() db.session.commit()
@ -521,7 +673,9 @@ def add_offre(id):
missions=form.missions.data.strip(), missions=form.missions.data.strip(),
duree=form.duree.data.strip(), duree=form.duree.data.strip(),
expiration_date=form.expiration_date.data, expiration_date=form.expiration_date.data,
correspondant_id=form.correspondant.data, correspondant_id=form.correspondant.data
if form.correspondant.data != ""
else None,
) )
db.session.add(offre) db.session.add(offre)
db.session.commit() db.session.commit()
@ -545,9 +699,11 @@ def add_offre(id):
file = form.fichier.data file = form.fichier.data
filename = secure_filename(file.filename) filename = secure_filename(file.filename)
file.save(os.path.join(path, filename)) file.save(os.path.join(path, filename))
log = EntrepriseLog( log = EntrepriseHistorique(
authenticated_user=current_user.user_name, authenticated_user=current_user.user_name,
object=entreprise.id, entreprise_id=entreprise.id,
object="offre",
object_id=offre.id,
text="Création d'une offre", text="Création d'une offre",
) )
db.session.add(log) db.session.add(log)
@ -582,6 +738,9 @@ def edit_offre(id):
offre.missions = form.missions.data.strip() offre.missions = form.missions.data.strip()
offre.duree = form.duree.data.strip() offre.duree = form.duree.data.strip()
offre.expiration_date = form.expiration_date.data offre.expiration_date = form.expiration_date.data
if form.correspondant.data == "":
offre.correspondant_id = sql.null()
else:
offre.correspondant_id = form.correspondant.data offre.correspondant_id = form.correspondant.data
if offre_depts_list != form.depts.data: if offre_depts_list != form.depts.data:
for dept in form.depts.data: for dept in form.depts.data:
@ -597,9 +756,11 @@ def edit_offre(id):
offre_id=offre.id, dept_id=dept offre_id=offre.id, dept_id=dept
).first_or_404() ).first_or_404()
db.session.delete(offre_dept) db.session.delete(offre_dept)
log = EntrepriseLog( log = EntrepriseHistorique(
authenticated_user=current_user.user_name, authenticated_user=current_user.user_name,
object=offre.entreprise_id, entreprise_id=offre.entreprise_id,
object="offre",
object_id=offre.id,
text="Modification d'une offre", text="Modification d'une offre",
) )
db.session.add(log) db.session.add(log)
@ -642,9 +803,11 @@ def delete_offre(id):
) )
if os.path.isdir(path): if os.path.isdir(path):
shutil.rmtree(path) shutil.rmtree(path)
log = EntrepriseLog( log = EntrepriseHistorique(
authenticated_user=current_user.user_name, authenticated_user=current_user.user_name,
object=offre.entreprise_id, entreprise_id=offre.entreprise_id,
object="offre",
object_id=offre.id,
text="Suppression d'une offre", text="Suppression d'une offre",
) )
db.session.add(log) db.session.add(log)
@ -700,7 +863,7 @@ def add_site(id):
entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404(
description=f"entreprise {id} inconnue" description=f"entreprise {id} inconnue"
) )
form = SiteCreationForm() form = SiteCreationForm(hidden_entreprise_id=id)
if form.validate_on_submit(): if form.validate_on_submit():
site = EntrepriseSite( site = EntrepriseSite(
entreprise_id=entreprise.id, entreprise_id=entreprise.id,
@ -721,6 +884,41 @@ def add_site(id):
) )
@bp.route(
"/fiche_entreprise/<int:id_entreprise>/edit_site/<int:id_site>",
methods=["GET", "POST"],
)
def edit_site(id_entreprise, id_site):
entreprise = Entreprise.query.filter_by(
id=id_entreprise, visible=True
).first_or_404(description=f"entreprise {id_entreprise} inconnue")
site = EntrepriseSite.query.filter_by(
id=id_site, entreprise_id=entreprise.id
).first_or_404(description=f"site {id_site} inconnu")
form = SiteModificationForm(
hidden_entreprise_id=id_entreprise, hidden_site_id=id_site
)
if form.validate_on_submit():
site.nom = form.nom.data.strip()
site.adresse = form.adresse.data.strip()
site.codepostal = form.codepostal.data.strip()
site.ville = form.ville.data.strip()
site.pays = (form.pays.data.strip() if form.pays.data.strip() else "FRANCE",)
db.session.commit()
return redirect(url_for("entreprises.fiche_entreprise", id=site.entreprise_id))
elif request.method == "GET":
form.nom.data = site.nom
form.adresse.data = site.adresse
form.codepostal.data = site.codepostal
form.ville.data = site.ville
form.pays.data = site.pays
return render_template(
"entreprises/form.html",
title="Modification site",
form=form,
)
@bp.route( @bp.route(
"/fiche_entreprise/<int:id_entreprise>/add_correspondant/<int:id_site>", "/fiche_entreprise/<int:id_entreprise>/add_correspondant/<int:id_site>",
methods=["GET", "POST"], methods=["GET", "POST"],
@ -752,13 +950,17 @@ def add_correspondant(id_entreprise, id_site):
origine=correspondant_entry.origine.data.strip(), origine=correspondant_entry.origine.data.strip(),
notes=correspondant_entry.notes.data.strip(), notes=correspondant_entry.notes.data.strip(),
) )
log = EntrepriseLog( db.session.add(correspondant)
db.session.commit()
db.session.refresh(correspondant)
log = EntrepriseHistorique(
authenticated_user=current_user.user_name, authenticated_user=current_user.user_name,
object=entreprise.id, entreprise_id=correspondant.entreprise_id,
object="correspondant",
object_id=correspondant.id,
text="Création d'un correspondant", text="Création d'un correspondant",
) )
db.session.add(log) db.session.add(log)
db.session.add(correspondant)
db.session.commit() db.session.commit()
flash("Le correspondant a été ajouté à la fiche entreprise.") flash("Le correspondant a été ajouté à la fiche entreprise.")
return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id)) return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id))
@ -775,8 +977,11 @@ def edit_correspondant(id):
""" """
Permet de modifier un correspondant Permet de modifier un correspondant
""" """
correspondant = EntrepriseCorrespondant.query.filter_by(id=id).first_or_404( correspondant = (
description=f"correspondant {id} inconnu" db.session.query(EntrepriseCorrespondant)
.join(Entreprise, EntrepriseCorrespondant.entreprise_id == Entreprise.id)
.filter(EntrepriseCorrespondant.id == id, Entreprise.visible == True)
.first_or_404(description=f"correspondant {id} inconnu")
) )
form = CorrespondantModificationForm( form = CorrespondantModificationForm(
hidden_entreprise_id=correspondant.entreprise_id, hidden_entreprise_id=correspondant.entreprise_id,
@ -792,9 +997,11 @@ def edit_correspondant(id):
correspondant.service = form.service.data.strip() correspondant.service = form.service.data.strip()
correspondant.origine = form.origine.data.strip() correspondant.origine = form.origine.data.strip()
correspondant.notes = form.notes.data.strip() correspondant.notes = form.notes.data.strip()
log = EntrepriseLog( log = EntrepriseHistorique(
authenticated_user=current_user.user_name, authenticated_user=current_user.user_name,
object=correspondant.entreprise_id, entreprise_id=correspondant.entreprise_id,
object="correspondant",
object_id=correspondant.id,
text="Modification d'un correspondant", text="Modification d'un correspondant",
) )
db.session.add(log) db.session.add(log)
@ -826,15 +1033,20 @@ def delete_correspondant(id):
""" """
Permet de supprimer un correspondant Permet de supprimer un correspondant
""" """
correspondant = EntrepriseCorrespondant.query.filter_by(id=id).first_or_404( correspondant = (
description=f"correspondant {id} inconnu" db.session.query(EntrepriseCorrespondant)
.join(Entreprise, EntrepriseCorrespondant.entreprise_id == Entreprise.id)
.filter(EntrepriseCorrespondant.id == id, Entreprise.visible == True)
.first_or_404(description=f"correspondant {id} inconnu")
) )
form = SuppressionConfirmationForm() form = SuppressionConfirmationForm()
if form.validate_on_submit(): if form.validate_on_submit():
db.session.delete(correspondant) db.session.delete(correspondant)
log = EntrepriseLog( log = EntrepriseHistorique(
authenticated_user=current_user.user_name, authenticated_user=current_user.user_name,
object=correspondant.entreprise_id, entreprise_id=correspondant.entreprise_id,
object="correspondant",
object_id=correspondant.id,
text="Suppression d'un correspondant", text="Suppression d'un correspondant",
) )
db.session.add(log) db.session.add(log)
@ -937,7 +1149,10 @@ def contacts(id):
""" """
Permet d'afficher une page avec la liste des contacts d'une entreprise Permet d'afficher une page avec la liste des contacts d'une entreprise
""" """
contacts = EntrepriseContact.query.filter_by(entreprise=id).all() entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404(
description=f"entreprise {id} inconnue"
)
contacts = EntrepriseContact.query.filter_by(entreprise=entreprise.id).all()
return render_template( return render_template(
"entreprises/contacts.html", "entreprises/contacts.html",
title="Liste des contacts", title="Liste des contacts",
@ -1125,7 +1340,7 @@ def json_etudiants():
if request.args.get("term") is None: if request.args.get("term") is None:
abort(400) abort(400)
term = request.args.get("term").strip() term = request.args.get("term").strip()
etudiants = Identite.query.filter(Identite.nom.ilike(f"%{term}%")).all() etudiants = Identite.query.filter(Identite.nom.ilike(f"%{term}%")).limit(30).all()
list = [] list = []
for etudiant in etudiants: for etudiant in etudiants:
content = {} content = {}
@ -1134,10 +1349,14 @@ def json_etudiants():
content = { content = {
"id": f"{etudiant.id}", "id": f"{etudiant.id}",
"value": value, "value": value,
"info": f"{etudiant.inscription_courante().formsemestre.titre}", "info": f"Département {are.get_dept_acronym_by_id(etudiant.dept_id)} - {etudiant.inscription_courante().formsemestre.titre}",
} }
else: else:
content = {"id": f"{etudiant.id}", "value": value} content = {
"id": f"{etudiant.id}",
"value": value,
"info": f"Département {are.get_dept_acronym_by_id(etudiant.dept_id)}",
}
list.append(content) list.append(content)
return jsonify(results=list) return jsonify(results=list)
@ -1151,68 +1370,56 @@ def json_responsables():
if request.args.get("term") is None: if request.args.get("term") is None:
abort(400) abort(400)
term = request.args.get("term").strip() term = request.args.get("term").strip()
responsables = User.query.filter( responsables = (
User.query.filter(
User.nom.ilike(f"%{term}%"), User.nom.is_not(None), User.prenom.is_not(None) User.nom.ilike(f"%{term}%"), User.nom.is_not(None), User.prenom.is_not(None)
).all() )
.limit(30)
.all()
)
list = [] list = []
for responsable in responsables: for responsable in responsables:
content = {} content = {}
value = f"{responsable.get_nomplogin()}" value = f"{responsable.get_nomplogin()}"
content = {"id": f"{responsable.id}", "value": value, "info": ""} content = {"id": f"{responsable.id}", "value": value}
list.append(content) list.append(content)
return jsonify(results=list) return jsonify(results=list)
@bp.route("/export_entreprises") @bp.route("/export_donnees")
@permission_required(Permission.RelationsEntreprisesExport) @permission_required(Permission.RelationsEntreprisesExport)
def export_entreprises(): def export_donnees():
""" """
Permet d'exporter la liste des entreprises sous format excel (.xlsx) Permet d'exporter la liste des entreprises sous format excel (.xlsx)
""" """
entreprises = Entreprise.query.filter_by(visible=True).all() entreprise = Entreprise.query.filter_by(visible=True).first()
if entreprises: if entreprise:
keys = ["siret", "nom_entreprise", "adresse", "ville", "code_postal", "pays"] wb = are.get_excel_book_are(export=True)
titles = keys[:] xlsx = wb.generate()
L = [ filename = "ExportApplicationRelationsEntreprises"
[entreprise.to_dict().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) return scu.send_file(xlsx, filename, scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE)
else: else:
flash("Aucune entreprise dans la base.")
return redirect(url_for("entreprises.index")) return redirect(url_for("entreprises.index"))
@bp.route("/import_entreprises/get_import_entreprises_file_sample") @bp.route("/import_donnees/get_file_sample")
@permission_required(Permission.RelationsEntreprisesExport) @permission_required(Permission.RelationsEntreprisesExport)
def get_import_entreprises_file_sample(): def get_import_donnees_file_sample():
""" """
Permet de récupérer un fichier exemple vide pour pouvoir importer des entreprises Permet de récupérer un fichier exemple vide pour pouvoir importer des entreprises
""" """
keys = [ wb = are.get_excel_book_are()
"siret", xlsx = wb.generate()
"nom_entreprise", filename = "ImportApplicationRelationsEntreprises"
"adresse",
"ville",
"code_postal",
"pays",
]
titles = keys[:]
title = "ImportEntreprises"
xlsx = sco_excel.excel_simple_table(titles=titles, sheet_name="Entreprises")
filename = title
return scu.send_file(xlsx, filename, scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE) return scu.send_file(xlsx, filename, scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE)
@bp.route("/import_entreprises", methods=["GET", "POST"]) @bp.route("/import_donnees", methods=["GET", "POST"])
@permission_required(Permission.RelationsEntreprisesExport) @permission_required(Permission.RelationsEntreprisesExport)
def import_entreprises(): def import_donnees():
""" """
Permet d'importer des entreprises a l'aide d'un fichier excel (.xlsx) Permet d'importer des entreprises à partir d'un fichier excel (.xlsx)
""" """
form = ImportForm() form = ImportForm()
if form.validate_on_submit(): if form.validate_on_submit():
@ -1221,237 +1428,58 @@ def import_entreprises():
Config.SCODOC_VAR_DIR, "tmp", secure_filename(file.filename) Config.SCODOC_VAR_DIR, "tmp", secure_filename(file.filename)
) )
file.save(file_path) file.save(file_path)
data = sco_excel.excel_file_to_list(file_path) diag, lm = sco_excel.excel_workbook_to_list(file_path)
os.remove(file_path) os.remove(file_path)
entreprises_import = [] if lm is None or len(lm) < 2:
siret_list = []
ligne = 0
titles = ["siret", "nom_entreprise", "adresse", "ville", "code_postal", "pays"]
if data[1][0] != titles:
flash("Veuillez utilisez la feuille excel à remplir") flash("Veuillez utilisez la feuille excel à remplir")
return render_template( return redirect(url_for("entreprises.import_donnees"))
"entreprises/import_entreprises.html", entreprises_import = are.check_entreprises_import(lm[0])
title="Importation entreprises", sites_import, correspondants_import = are.check_sites_import(lm[1])
form=form,
)
for entreprise_data in data[1][1:]:
ligne += 1
if ( if (
are.verif_entreprise_data(entreprise_data) entreprises_import is False
and entreprise_data[0].replace(" ", "") not in siret_list or sites_import is False
or correspondants_import is False
or (len(lm) > 2 and are.check_correspondants_import(lm[2]) is False)
): ):
siret_list.append(entreprise_data[0].replace(" ", "")) return redirect(url_for("entreprises.import_donnees"))
entreprise = Entreprise(
siret=entreprise_data[0].replace(" ", ""),
nom=entreprise_data[1].strip(),
adresse=entreprise_data[2].strip(),
ville=entreprise_data[3].strip(),
codepostal=entreprise_data[4].strip(),
pays=entreprise_data[5].strip(),
visible=True,
)
entreprises_import.append(entreprise)
else:
flash(f"Erreur lors de l'importation (ligne {ligne})")
return render_template(
"entreprises/import_entreprises.html",
title="Importation entreprises",
form=form,
)
if len(entreprises_import) > 0:
for entreprise in entreprises_import: for entreprise in entreprises_import:
db.session.add(entreprise) db.session.add(entreprise)
log = EntrepriseLog(
authenticated_user=current_user.user_name,
text=f"Importation de {len(entreprises_import)} entreprise(s)",
)
db.session.add(log)
db.session.commit() db.session.commit()
flash(f"Importation réussie de {len(entreprises_import)} entreprise(s)") db.session.refresh(entreprise)
site = EntrepriseSite(
entreprise_id=entreprise.id,
nom=entreprise.nom,
adresse=entreprise.adresse,
codepostal=entreprise.codepostal,
ville=entreprise.ville,
pays=entreprise.pays,
)
db.session.add(site)
for site in sites_import:
db.session.add(site)
correspondants = []
for site, correspondant in correspondants_import:
if site is None:
db.session.add(correspondant)
else:
db.session.add(site)
db.session.commit()
db.session.refresh(site)
correspondant.site_id = site.id
db.session.add(correspondant)
correspondants.append(correspondant)
db.session.commit()
flash(f"Importation réussie")
return render_template( return render_template(
"entreprises/import_entreprises.html", "entreprises/import_donnees.html",
title="Importation entreprises", title="Importation données",
form=form, form=form,
entreprises_import=entreprises_import, entreprises_import=entreprises_import,
) sites_import=sites_import,
else: correspondants_import=correspondants,
flash('Feuille "Entreprises" vide')
return render_template(
"entreprises/import_entreprises.html",
title="Importation entreprises",
form=form,
)
@bp.route("/export_correspondants")
@permission_required(Permission.RelationsEntreprisesExport)
def export_correspondants():
"""
Permet d'exporter la liste des correspondants sous format excel (.xlsx)
"""
correspondants = (
db.session.query(EntrepriseCorrespondant)
.join(Entreprise, EntrepriseCorrespondant.entreprise_id == Entreprise.id)
.filter_by(visible=True)
.all()
)
if correspondants:
keys = [
"civilite",
"nom",
"prenom",
"telephone",
"mail",
"poste",
"service",
"origine",
"notes",
"entreprise_siret",
]
titles = keys[:]
L = [
[correspondant.to_dict().get(k, "") for k in keys]
for correspondant in correspondants
]
title = "Correspondants"
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:
flash("Aucun correspondant dans la base.")
return redirect(url_for("entreprises.correspondants"))
@bp.route("/import_correspondants/get_import_correspondants_file_sample")
@permission_required(Permission.RelationsEntreprisesExport)
def get_import_correspondants_file_sample():
"""
Permet de récupérer un fichier exemple vide pour pouvoir importer des correspondants
"""
keys = [
"civilite",
"nom",
"prenom",
"telephone",
"mail",
"poste",
"service",
"origine",
"notes",
"entreprise_siret",
]
titles = keys[:]
title = "ImportCorrespondants"
xlsx = sco_excel.excel_simple_table(titles=titles, sheet_name="Correspondants")
filename = title
return scu.send_file(xlsx, filename, scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE)
@bp.route("/import_correspondants", methods=["GET", "POST"])
@permission_required(Permission.RelationsEntreprisesExport)
def import_correspondants():
"""
Permet d'importer des correspondants a l'aide d'un fichier excel (.xlsx)
"""
form = ImportForm()
if form.validate_on_submit():
file = form.fichier.data
file_path = os.path.join(
Config.SCODOC_VAR_DIR, "tmp", secure_filename(file.filename)
)
file.save(file_path)
data = sco_excel.excel_file_to_list(file_path)
os.remove(file_path)
correspondants_import = []
correspondant_list = []
ligne = 0
titles = [
"civilite",
"nom",
"prenom",
"telephone",
"mail",
"poste",
"service",
"origine",
"notes",
"entreprise_siret",
]
if data[1][0] != titles:
flash("Veuillez utilisez la feuille excel à remplir")
return render_template(
"entreprises/import_correspondants.html",
title="Importation correspondants",
form=form,
)
for correspondant_data in data[1][1:]:
ligne += 1
if (
are.verif_correspondant_data(correspondant_data)
and (
correspondant_data[1].strip(),
correspondant_data[2].strip(),
correspondant_data[9].strip(),
)
not in correspondant_list
):
correspondant_list.append(
(
correspondant_data[1].strip(),
correspondant_data[2].strip(),
correspondant_data[9].strip(),
)
)
entreprise = Entreprise.query.filter_by(
siret=correspondant_data[9].strip()
).first()
correspondant = EntrepriseCorrespondant(
civilite=correspondant_data[0].strip(),
nom=correspondant_data[1].strip(),
prenom=correspondant_data[2].strip(),
telephone=correspondant_data[3].strip(),
mail=correspondant_data[4].strip(),
poste=correspondant_data[5].strip(),
service=correspondant_data[6].strip(),
origine=correspondant_data[7].strip(),
notes=correspondant_data[8].strip(),
entreprise_id=entreprise.id,
)
correspondants_import.append(correspondant)
else:
flash(f"Erreur lors de l'importation (ligne {ligne})")
return render_template(
"entreprises/import_correspondants.html",
title="Importation correspondants",
form=form,
)
if len(correspondants_import) > 0:
for correspondant in correspondants_import:
db.session.add(correspondant)
log = EntrepriseLog(
authenticated_user=current_user.user_name,
text=f"Importation de {len(correspondants_import)} correspondant(s)",
)
db.session.add(log)
db.session.commit()
flash(
f"Importation réussie de {len(correspondants_import)} correspondant(s)"
) )
return render_template( return render_template(
"entreprises/import_correspondants.html", "entreprises/import_donnees.html", title="Importation données", form=form
title="Importation correspondants",
form=form,
correspondants_import=correspondants_import,
)
else:
flash('Feuille "Correspondants" vide')
return render_template(
"entreprises/import_correspondants.html",
title="Importation correspondants",
form=form,
) )

View File

@ -40,10 +40,9 @@ from openpyxl.comments import Comment
from openpyxl import Workbook, load_workbook from openpyxl import Workbook, load_workbook
from openpyxl.cell import WriteOnlyCell from openpyxl.cell import WriteOnlyCell
from openpyxl.styles import Font, Border, Side, Alignment, PatternFill from openpyxl.styles import Font, Border, Side, Alignment, PatternFill
from openpyxl.worksheet.worksheet import Worksheet
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc import notesdb
from app.scodoc import sco_preferences
from app import log from app import log
from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_exceptions import ScoValueError
@ -593,60 +592,87 @@ def excel_feuille_saisie(e, titreannee, description, lines):
def excel_bytes_to_list(bytes_content): def excel_bytes_to_list(bytes_content):
try: try:
filelike = io.BytesIO(bytes_content) filelike = io.BytesIO(bytes_content)
return _excel_to_list(filelike) except Exception as exc:
except:
raise ScoValueError( raise ScoValueError(
"""Le fichier xlsx attendu n'est pas lisible ! """Le fichier xlsx attendu n'est pas lisible !
Peut-être avez-vous fourni un fichier au mauvais format (txt, xls, ..) Peut-être avez-vous fourni un fichier au mauvais format (txt, xls, ..)
""" """
) ) from exc
return _excel_to_list(filelike)
def excel_file_to_list(filename): def excel_file_to_list(filename):
try: try:
return _excel_to_list(filename) return _excel_to_list(filename)
except: except Exception as exc:
raise ScoValueError( raise ScoValueError(
"""Le fichier xlsx attendu n'est pas lisible ! """Le fichier xlsx attendu n'est pas lisible !
Peut-être avez-vous fourni un fichier au mauvais format (txt, xls, ...) Peut-être avez-vous fourni un fichier au mauvais format (txt, xls, ...)
""" """
) ) from exc
def excel_workbook_to_list(filename):
try:
return _excel_workbook_to_list(filename)
except Exception as exc:
raise ScoValueError(
"""Le fichier xlsx attendu n'est pas lisible !
Peut-être avez-vous fourni un fichier au mauvais format (txt, xls, ...)
"""
) from exc
def _open_workbook(filelike, dump_debug=False) -> Workbook:
"""Open document.
On error, if dump-debug is True, dump data in /tmp for debugging purpose
"""
try:
workbook = load_workbook(filename=filelike, read_only=True, data_only=True)
except Exception as exc:
log("Excel_to_list: failure to import document")
if dump_debug:
dump_filename = "/tmp/last_scodoc_import_failure" + scu.XLSX_SUFFIX
log(f"Dumping problemetic file on {dump_filename}")
with open(dump_filename, "wb") as f:
f.write(filelike)
raise ScoValueError(
"Fichier illisible: assurez-vous qu'il s'agit bien d'un document Excel xlsx !"
) from exc
return workbook
def _excel_to_list(filelike): def _excel_to_list(filelike):
"""returns list of list """returns list of list"""
convert_to_string is a conversion function applied to all non-string values (ie numbers) workbook = _open_workbook(filelike)
"""
try:
wb = load_workbook(filename=filelike, read_only=True, data_only=True)
except:
log("Excel_to_list: failure to import document")
with open("/tmp/last_scodoc_import_failure" + scu.XLSX_SUFFIX, "wb") as f:
f.write(filelike)
raise ScoValueError(
"Fichier illisible: assurez-vous qu'il s'agit bien d'un document Excel !"
)
diag = [] # liste de chaines pour former message d'erreur diag = [] # liste de chaines pour former message d'erreur
# n'utilise que la première feuille if len(workbook.get_sheet_names()) < 1:
if len(wb.get_sheet_names()) < 1:
diag.append("Aucune feuille trouvée dans le classeur !") diag.append("Aucune feuille trouvée dans le classeur !")
return diag, None return diag, None
if len(wb.get_sheet_names()) > 1: # n'utilise que la première feuille:
if len(workbook.get_sheet_names()) > 1:
diag.append("Attention: n'utilise que la première feuille du classeur !") diag.append("Attention: n'utilise que la première feuille du classeur !")
sheet_name = workbook.get_sheet_names()[0]
ws = workbook[sheet_name]
diag_sheet, matrix = _excel_sheet_to_list(ws, sheet_name)
diag += diag_sheet
return diag, matrix
def _excel_sheet_to_list(sheet: Worksheet, sheet_name: str) -> tuple[list, list]:
"""read a spreadsheet sheet, and returns:
- diag : a list of strings (error messages aimed at helping the user)
- a list of lists: the spreadsheet cells
"""
diag = []
# fill matrix # fill matrix
sheet_name = wb.get_sheet_names()[0]
ws = wb.get_sheet_by_name(sheet_name)
sheet_name = sheet_name.encode(scu.SCO_ENCODING, "backslashreplace")
values = {} values = {}
for row in ws.iter_rows(): for row in sheet.iter_rows():
for cell in row: for cell in row:
if cell.value is not None: if cell.value is not None:
values[(cell.row - 1, cell.column - 1)] = str(cell.value) values[(cell.row - 1, cell.column - 1)] = str(cell.value)
if not values: if not values:
diag.append( diag.append(f"Aucune valeur trouvée dans la feuille {sheet_name} !")
"Aucune valeur trouvée dans la feuille %s !"
% sheet_name.decode(scu.SCO_ENCODING)
)
return diag, None return diag, None
indexes = list(values.keys()) indexes = list(values.keys())
# search numbers of rows and cols # search numbers of rows and cols
@ -654,23 +680,38 @@ def _excel_to_list(filelike):
cols = [x[1] for x in indexes] cols = [x[1] for x in indexes]
nbcols = max(cols) + 1 nbcols = max(cols) + 1
nbrows = max(rows) + 1 nbrows = max(rows) + 1
m = [] matrix = []
for _ in range(nbrows): for _ in range(nbrows):
m.append([""] * nbcols) matrix.append([""] * nbcols)
for row_idx, col_idx in indexes: for row_idx, col_idx in indexes:
v = values[(row_idx, col_idx)] v = values[(row_idx, col_idx)]
# if isinstance(v, six.text_type): matrix[row_idx][col_idx] = v
# v = v.encode(scu.SCO_ENCODING, "backslashreplace") diag.append(f'Feuille "{sheet_name}", {len(matrix)} lignes')
# elif convert_to_string:
# v = convert_to_string(v) return diag, matrix
m[row_idx][col_idx] = v
diag.append(
'Feuille "%s", %d lignes' % (sheet_name.decode(scu.SCO_ENCODING), len(m)) def _excel_workbook_to_list(filelike):
) """Lit un classeur (workbook): chaque feuille est lue
# diag.append(str(M)) et est convertie en une liste de listes.
# Returns:
return diag, m - diag : a list of strings (error messages aimed at helping the user)
- a list of lists: the spreadsheet cells
"""
workbook = _open_workbook(filelike)
diag = [] # liste de chaines pour former message d'erreur
if len(workbook.get_sheet_names()) < 1:
diag.append("Aucune feuille trouvée dans le classeur !")
return diag, None
matrix_list = []
for sheet_name in workbook.get_sheet_names():
# fill matrix
sheet = workbook.get_sheet_by_name(sheet_name)
diag_sheet, matrix = _excel_sheet_to_list(sheet, sheet_name)
diag += diag_sheet
matrix_list.append(matrix)
return diag, matrix_list
def excel_feuille_listeappel( def excel_feuille_listeappel(

View File

@ -1,28 +1,37 @@
.nav-entreprise>ul { .nav-entreprise {
padding-left: 0; text-align: left;
}
.nav-entreprise ul {
padding: 0;
} }
.nav-entreprise li{ .nav-entreprise li{
list-style: none; list-style: none;
display: inline-block; display: inline-block;
padding: 10px; padding: 10px;
border: 2px black solid;
border-radius: 10px;
}
.nav-entreprise li:hover{
background-color: rgb(212, 212, 212);
} }
.nav-entreprise>ul>li>a { .nav-entreprise>ul>li>a {
text-decoration: none; text-decoration: none;
color: black; color: black;
padding: 15px; padding: 15px;
}
.nav-entreprise>ul>li>a:hover {
text-decoration: underline;
} }
.form-error { .form-error {
color: #a94442; color: #a94442;
} }
.nav-entreprise>ul>li>a:hover {
color: red;
}
.boutons .btn { .boutons .btn {
margin-top: 5px; margin-top: 5px;
margin-bottom: 5px; margin-bottom: 5px;
@ -59,14 +68,33 @@
margin-bottom: -5px; margin-bottom: -5px;
} }
.entreprise, .correspondant, .offre, .site{ .entreprise, .correspondant, .offre, .site, .info-active {
border: solid 2px; border: solid 2px black;
border-radius: 10px; border-radius: 10px;
padding: 10px; padding: 10px;
margin-bottom: 10px; margin-bottom: 10px;
margin-top: 10px; margin-top: 10px;
} }
.info-active {
border-color: red;
background-color: rgb(250, 220, 220);
}
.entreprise {
display: flex;
justify-content: space-between;
}
.entreprise > div {
flex: 1 0 0;
}
.taxe-apprentissage{
overflow-y: scroll;
height: 100px;
}
.sites-et-offres { .sites-et-offres {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -102,3 +130,46 @@
border-radius: 10px; border-radius: 10px;
padding: 10px; padding: 10px;
} }
#liste-taxes-apprentissages {
list-style: none;
padding-left: 0;
}
#form-entreprise-filter > label {
margin-right: 20px;
}
.title-form-error {
font-weight: bold;
color: #a94442;
}
.breadcrumbs {
padding: 0;
}
.breadcrumbs_item {
display: inline-block;
}
.breadcrumbs_item:not(:last-of-type)::after {
content: '\203a';
margin: 0 5px;
color: #777;
}
.breadcrumbs_link {
text-decoration: none;
color: #777;
}
.breadcrumbs_link:hover {
text-decoration: underline;
color: #333;
}
.breadcrumbs_link-active {
color: #333;
font-weight: bold;
}

View File

@ -16,7 +16,11 @@
</p> </p>
<form method="POST" action="" novalidate> <form method="POST" action="" novalidate>
{{ form.hidden_tag() }} {{ form.hidden_tag() }}
{{ form.correspondants.label }}
{% for subfield in form.correspondants %} {% for subfield in form.correspondants %}
{% if subfield.errors %}
<p class="title-form-error">Formulaire {{ subfield.label.text }}</p>
{% endif %}
{% for subsubfield in subfield %} {% for subsubfield in subfield %}
{% if subsubfield.errors %} {% if subsubfield.errors %}
{% for error in subsubfield.errors %} {% for error in subsubfield.errors %}
@ -56,7 +60,22 @@
} }
let newFieldName = `correspondants-${Math.max(...correspondantInputIds) + 1}`; let newFieldName = `correspondants-${Math.max(...correspondantInputIds) + 1}`;
allCorrepondantsFieldWrapper.insertAdjacentHTML('beforeend',` allCorrepondantsFieldWrapper.insertAdjacentHTML('beforeend',`
<li><label for="${newFieldName}">Correspondants-${Math.max(...correspondantInputIds) + 1}</label><table id="${newFieldName}"><tr><th><label for="${newFieldName}-civilite">Civilité (*)</label></th><td><select class="form-control" id="${newFieldName}-civilite" name="${newFieldName}-civilite" required><option value="H">Monsieur</option><option value="F">Madame</option></select></td></tr><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><tr><th><label for="${newFieldName}-origine">Origine</label></th><td><input class="form-control" id="${newFieldName}-origine" name="${newFieldName}-origine" type="text" value=""></td></tr><tr><th><label for="${newFieldName}-notes">Notes</label></th><td><input class="form-control" id="${newFieldName}-notes" name="${newFieldName}-notes" type="text" value=""></td></tr></table><input id="${newFieldName}-csrf_token" name="${newFieldName}-csrf_token" type="hidden" value=${csrf_token}><div class="btn btn-default btn-remove" onclick="deleteForm('${newFieldName}')">Retirer ce correspondant</div></li> <li>
<label for="${newFieldName}">Correspondants-${Math.max(...correspondantInputIds) + 1}</label>
<table id="${newFieldName}">
<tr><th><label for="${newFieldName}-civilite">Civilité (*)</label></th><td><select class="form-control" id="${newFieldName}-civilite" name="${newFieldName}-civilite" required><option value="H">Monsieur</option><option value="F">Madame</option></select></td></tr>
<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>
<tr><th><label for="${newFieldName}-origine">Origine</label></th><td><input class="form-control" id="${newFieldName}-origine" name="${newFieldName}-origine" type="text" value=""></td></tr>
<tr><th><label for="${newFieldName}-notes">Notes</label></th><td><input class="form-control" id="${newFieldName}-notes" name="${newFieldName}-notes" type="text" value=""></td></tr>
</table>
<input id="${newFieldName}-csrf_token" name="${newFieldName}-csrf_token" type="hidden" value=${csrf_token}>
<div class="btn btn-default btn-remove" onclick="deleteForm('${newFieldName}')">Retirer ce correspondant</div>
</li>
`); `);
}); });
} }

View File

@ -5,7 +5,7 @@
{% block app_content %} {% block app_content %}
<h1>{{ title }}</h1> <h1>{{ title }}</h1>
<br> <br>
<div style="color:red;">{{ info_message }}</div> <div>{{ info_message }}</div>
<br> <br>
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">

View File

@ -9,6 +9,20 @@
{% endblock %} {% endblock %}
{% block app_content %} {% block app_content %}
<div class="container">
<ul class="breadcrumbs">
<li class="breadcrumbs_item">
<a href="{{ url_for('entreprises.index') }}" class="breadcrumbs_link">Entreprises</a>
</li>
<li class="breadcrumbs_item">
<a href="{{ url_for('entreprises.fiche_entreprise', id=entreprise_id) }}" class="breadcrumbs_link">Fiche entreprise</a>
</li>
<li class="breadcrumbs_item">
<a href="" class="breadcrumbs_link breadcrumbs_link-active">Contacts</a>
</li>
</ul>
</div>
<div class="container" style="margin-bottom: 10px;"> <div class="container" style="margin-bottom: 10px;">
<h1>Liste des contacts</h1> <h1>Liste des contacts</h1>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}

View File

@ -22,15 +22,6 @@
</div> </div>
{% endif %} {% 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;"> <div class="container" style="margin-bottom: 10px;">
<h1>Liste des correspondants</h1> <h1>Liste des correspondants</h1>
<table id="table-correspondants"> <table id="table-correspondants">
@ -54,7 +45,7 @@
<td>{{ correspondant[0].mail }}</td> <td>{{ correspondant[0].mail }}</td>
<td>{{ correspondant[0].poste}}</td> <td>{{ correspondant[0].poste}}</td>
<td>{{ correspondant[0].service}}</td> <td>{{ correspondant[0].service}}</td>
<td><a href="{{ url_for('entreprises.fiche_entreprise', id=correspondant[1].id) }}">{{ correspondant[1].nom }}</a></td> <td><a href="{{ url_for('entreprises.fiche_entreprise', id=correspondant[1].entreprise_id) }}">{{ correspondant[1].nom }}</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@ -27,15 +27,22 @@
<a class="btn btn-default" href="{{ url_for('entreprises.add_entreprise') }}">Ajouter une entreprise</a> <a class="btn btn-default" href="{{ url_for('entreprises.add_entreprise') }}">Ajouter une entreprise</a>
{% endif %} {% endif %}
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) %} {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) %}
<a class="btn btn-default" href="{{ url_for('entreprises.import_entreprises') }}">Importer des entreprises</a> <a class="btn btn-default" href="{{ url_for('entreprises.import_donnees') }}">Importer des données</a>
{% endif %} {% endif %}
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) and entreprises %} {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) and entreprises %}
<a class="btn btn-default" href="{{ url_for('entreprises.export_entreprises') }}">Exporter la liste des entreprises</a> <a class="btn btn-default" href="{{ url_for('entreprises.export_donnees') }}">Exporter des données</a>
{% endif %} {% endif %}
</div> </div>
<div class="container" style="margin-bottom: 10px;"> <div class="container" style="margin-bottom: 10px;">
<h1>Liste des entreprises</h1> <h1>Liste des entreprises</h1>
{% if form %}
<form id="form-entreprise-filter" method="POST" action="">
{{ form.hidden_tag() }}
<input id="active" name="active" type="checkbox" onChange="form.submit()" {% if checked[0] %} checked {% endif %}> {{ form.active.label }}
<input id="association" name="association" type="checkbox" onChange="form.submit()" {% if checked[1] %} checked {% endif %}> {{ form.association.label }}
</form>
{% endif %}
<table id="table-entreprises"> <table id="table-entreprises">
<thead> <thead>
<tr> <tr>
@ -53,7 +60,7 @@
<tbody> <tbody>
{% for entreprise in entreprises %} {% for entreprise in entreprises %}
<tr> <tr>
<td><a href="{{ url_for('entreprises.fiche_entreprise', id=entreprise.id) }}">{{ entreprise.siret }}</a></td> <td><a href="{{ url_for('entreprises.fiche_entreprise', id=entreprise.id) }}" {% if not entreprise.active %} style="color:red" {% endif %}>{{ entreprise.siret }}</a></td>
<td>{{ entreprise.nom }}</td> <td>{{ entreprise.nom }}</td>
<td>{{ entreprise.adresse }}</td> <td>{{ entreprise.adresse }}</td>
<td>{{ entreprise.codepostal }}</td> <td>{{ entreprise.codepostal }}</td>
@ -67,7 +74,11 @@
</a> </a>
<ul class="dropdown-menu pull-left"> <ul class="dropdown-menu pull-left">
<li><a href="{{ url_for('entreprises.edit_entreprise', id=entreprise.id) }}">Modifier</a></li> <li><a href="{{ url_for('entreprises.edit_entreprise', id=entreprise.id) }}">Modifier</a></li>
{% if entreprise.active %}
<li><a href="{{ url_for('entreprises.fiche_entreprise_desactiver', id=entreprise.id)}}" style="color:red">Désactiver</a></li> <li><a href="{{ url_for('entreprises.fiche_entreprise_desactiver', id=entreprise.id)}}" style="color:red">Désactiver</a></li>
{% else %}
<li><a href="{{ url_for('entreprises.fiche_entreprise_activer', id=entreprise.id)}}" style="color:lightgreen">Activer</a></li>
{% endif %}
</ul> </ul>
</div> </div>
</td> </td>

View File

@ -18,14 +18,10 @@
</p> </p>
<form method="POST" action="" novalidate> <form method="POST" action="" novalidate>
{{ form.hidden_tag() }} {{ form.hidden_tag() }}
{{ form.responsables.label }}<br> {{ form.responsables.label }}
{% for subfield in form.responsables %} {% for error in form.responsables.errors %}
{% if subfield.errors %}
{% for error in subfield.errors %}
<p class="help-block form-error">{{ error }}</p> <p class="help-block form-error">{{ error }}</p>
{% endfor %} {% endfor %}
{% endif %}
{% endfor %}
{{ form.responsables }} {{ form.responsables }}
<div style="margin-bottom: 10px;"> <div style="margin-bottom: 10px;">
<button class="btn btn-default" id="add-responsable-field">Ajouter un responsable</button> <button class="btn btn-default" id="add-responsable-field">Ajouter un responsable</button>
@ -71,7 +67,11 @@
} }
let newFieldName = `responsables-${Math.max(...responsableInputIds) + 1}`; let newFieldName = `responsables-${Math.max(...responsableInputIds) + 1}`;
allResponsablesFieldWrapper.insertAdjacentHTML('beforeend',` 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"><div class="btn btn-default btn-remove" onclick="deleteForm('${newFieldName}')">Retirer</div></li> <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">
<div class="btn btn-default btn-remove" onclick="deleteForm('${newFieldName}')">Retirer</div>
</li>
`); `);
var as_r = new bsn.AutoSuggest(newFieldName, responsables_options); var as_r = new bsn.AutoSuggest(newFieldName, responsables_options);
}); });

View File

@ -9,6 +9,17 @@
{% endblock %} {% endblock %}
{% block app_content %} {% block app_content %}
<div class="container">
<ul class="breadcrumbs">
<li class="breadcrumbs_item">
<a href="{{ url_for('entreprises.index') }}" class="breadcrumbs_link">Entreprises</a>
</li>
<li class="breadcrumbs_item">
<a href="" class="breadcrumbs_link breadcrumbs_link-active">Fiche entreprise</a>
</li>
</ul>
</div>
{% if logs %} {% if logs %}
<div class="container"> <div class="container">
<h3>Dernières opérations sur cette fiche <a href="{{ url_for('entreprises.logs_entreprise', id=entreprise.id) }}">Voir tout</a></h3> <h3>Dernières opérations sur cette fiche <a href="{{ url_for('entreprises.logs_entreprise', id=entreprise.id) }}">Voir tout</a></h3>
@ -26,6 +37,15 @@
<div class="container fiche-entreprise"> <div class="container fiche-entreprise">
<h2>Fiche entreprise - {{ entreprise.nom }} ({{ entreprise.siret }})</h2> <h2>Fiche entreprise - {{ entreprise.nom }} ({{ entreprise.siret }})</h2>
{% if not entreprise.active %}
<div class="info-active">
La fiche entreprise est désactivée<br>
{% if entreprise.notes_active != "" %}
Notes : {{ entreprise.notes_active }}
{% endif %}
</div>
{% endif %}
<div class="entreprise"> <div class="entreprise">
<div> <div>
SIRET : {{ entreprise.siret }}<br> SIRET : {{ entreprise.siret }}<br>
@ -33,14 +53,41 @@
Adresse : {{ entreprise.adresse }}<br> Adresse : {{ entreprise.adresse }}<br>
Code postal : {{ entreprise.codepostal }}<br> Code postal : {{ entreprise.codepostal }}<br>
Ville : {{ entreprise.ville }}<br> Ville : {{ entreprise.ville }}<br>
Pays : {{ entreprise.pays }} Pays : {{ entreprise.pays }}<br>
{% if entreprise.association %}
Association
{% endif %}
</div> </div>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
<div>
Taxe d'apprentissage<br>
<a class="btn btn-primary" href="{{ url_for('entreprises.add_taxe_apprentissage', id=entreprise.id) }}">Ajouter taxe apprentissage</a>
<div class="taxe-apprentissage">
<ul id="liste-taxes-apprentissages">
{% if not taxes|check_taxe_now %}
<li>année actuelle : non versée</li>
{% endif %}
{% for taxe in taxes %}
<li>
<a href="{{ url_for('entreprises.delete_taxe_apprentissage', id_entreprise=entreprise.id, id_taxe=taxe.id) }}"><img title="Supprimer taxe d'apprentissage" alt="supprimer" width="10" height="9" border="0" src="/ScoDoc/static/icons/delete_small_img.png" /></a>
<a href="{{ url_for('entreprises.edit_taxe_apprentissage', id_entreprise=entreprise.id, id_taxe=taxe.id) }}">{{ taxe.annee }}</a> : {{ taxe.montant }} euros {% if taxe.notes %}- {{ taxe.notes}} {% endif %}
</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
</div> </div>
<div> <div>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
<a class="btn btn-primary" href="{{ url_for('entreprises.edit_entreprise', id=entreprise.id) }}">Modifier</a> <a class="btn btn-primary" href="{{ url_for('entreprises.edit_entreprise', id=entreprise.id) }}">Modifier</a>
{% if entreprise.active %}
<a class="btn btn-danger" href="{{ url_for('entreprises.fiche_entreprise_desactiver', id=entreprise.id) }}">Désactiver</a> <a class="btn btn-danger" href="{{ url_for('entreprises.fiche_entreprise_desactiver', id=entreprise.id) }}">Désactiver</a>
{% else %}
<a class="btn btn-success" href="{{ url_for('entreprises.fiche_entreprise_activer', id=entreprise.id) }}">Activer</a>
{% endif %}
<a class="btn btn-primary" href="{{ url_for('entreprises.add_site', id=entreprise.id) }}">Ajouter site</a> <a class="btn btn-primary" href="{{ url_for('entreprises.add_site', id=entreprise.id) }}">Ajouter site</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_offre', id=entreprise.id) }}">Ajouter offre</a>
{% endif %} {% endif %}
@ -61,7 +108,10 @@
Ville : {{ site.ville }}<br> Ville : {{ site.ville }}<br>
Pays : {{ site.pays }} Pays : {{ site.pays }}
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
<br><a class="btn btn-primary" href="{{ url_for('entreprises.add_correspondant', id_entreprise=entreprise.id, id_site=site.id) }}">Ajouter correspondant</a> <div>
<a class="btn btn-primary" href="{{ url_for('entreprises.edit_site', id_entreprise=entreprise.id, id_site=site.id) }}">Modifier</a>
<a class="btn btn-primary" href="{{ url_for('entreprises.add_correspondant', id_entreprise=entreprise.id, id_site=site.id) }}">Ajouter correspondant</a>
</div>
{% endif %} {% endif %}
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesCorrespondants, None) %} {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesCorrespondants, None) %}
{% for correspondant in site.correspondants %} {% for correspondant in site.correspondants %}
@ -111,7 +161,7 @@
<td>{{ data[0].date_fin.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].date_fin-data[0].date_debut).days//7 }} semaines</td>
<td>{{ data[0].type_offre }}</td> <td>{{ data[0].type_offre }}</td>
<td>{{ data[1].nom|format_nom }} {{ data[1].prenom|format_prenom }}</td> <td><a href="{{ url_for('scolar.ficheEtud', scodoc_dept=data[1].dept_id|get_dept_acronym, etudid=data[0].etudid) }}">{{ data[1].nom|format_nom }} {{ data[1].prenom|format_prenom }}</a></td>
<td>{% if data[0].formation_text %}{{ data[0].formation_text }}{% endif %}</td> <td>{% if data[0].formation_text %}{{ data[0].formation_text }}{% endif %}</td>
<td>{{ data[0].notes }}</td> <td>{{ data[0].notes }}</td>
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}

View File

@ -12,16 +12,29 @@
Adresse : {{ entreprise.adresse }}<br> Adresse : {{ entreprise.adresse }}<br>
Code postal : {{ entreprise.codepostal }}<br> Code postal : {{ entreprise.codepostal }}<br>
Ville : {{ entreprise.ville }}<br> Ville : {{ entreprise.ville }}<br>
Pays : {{ entreprise.pays }} Pays : {{ entreprise.pays }}<br>
{% if entreprise.association %}
Association
{% endif %}
</div> </div>
</div> </div>
{% if correspondants %} <div class="sites-et-offres">
{% if sites %}
<div> <div>
{% for correspondant in correspondants %} <h3>Sites</h3>
<div> {% for site in sites %}
<h3>Correspondant</h3> <div class="site">
Nom : {{ site.nom }}<br>
Adresse : {{ site.adresse }}<br>
Code postal : {{ site.codepostal }}<br>
Ville : {{ site.ville }}<br>
Pays : {{ site.pays }}
{% if current_user.has_permission(current_user.Permission.RelationsEntreprisesCorrespondants, None) %}
{% for correspondant in site.correspondants %}
<div class="correspondant"> <div class="correspondant">
<div>
Civilité : {{ correspondant.civilite|get_civilité }}<br>
Nom : {{ correspondant.nom }}<br> Nom : {{ correspondant.nom }}<br>
Prénom : {{ correspondant.prenom }}<br> Prénom : {{ correspondant.prenom }}<br>
{% if correspondant.telephone %} {% if correspondant.telephone %}
@ -36,11 +49,21 @@
{% if correspondant.service %} {% if correspondant.service %}
Service : {{ correspondant.service }}<br> Service : {{ correspondant.service }}<br>
{% endif %} {% endif %}
{% if correspondant.origine %}
Origine : {{ correspondant.origine }}<br>
{% endif %}
{% if correspondant.notes %}
Notes : {{ correspondant.notes }}<br>
{% endif %}
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
{% endif %}
</div>
{% endfor %}
</div> </div>
{% endif %} {% endif %}
</div>
<div> <div>
<a class="btn btn-success" href="{{ url_for('entreprises.validate_entreprise', id=entreprise.id) }}">Valider</a> <a class="btn btn-success" href="{{ url_for('entreprises.validate_entreprise', id=entreprise.id) }}">Valider</a>

View File

@ -1,72 +0,0 @@
{# -*- 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>civilite</td><td>text</td><td>civilite du correspondant (H ou F)</td></tr>
<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>origine</td><td>text</td><td>origine du correspondant</td></tr>
<tr><td>notes</td><td>text</td><td>notes sur le correspondant</td></tr>
<tr><td>entreprise_siret</td><td>text</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>
Civilité : {{ correspondant.civilite|get_civilité }}<br>
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 %}
{% if correspondant.origine %}
Origine : {{ correspondant.origine }}<br>
{% endif %}
{% if correspondant.notes %}
Notes : {{ correspondant.notes }}<br>
{% endif %}
<a href="{{ url_for('entreprises.fiche_entreprise', id=correspondant.entreprise_id )}}" target="_blank">lien vers l'entreprise</a>
</div>
</div>
{% endfor %}
{% endif %}
{% endblock %}

View File

@ -0,0 +1,149 @@
{# -*- mode: jinja-html -*- #}
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block styles %}
{{super()}}
{% endblock %}
{% block app_content %}
<div class="container">
<ul class="breadcrumbs">
<li class="breadcrumbs_item">
<a href="{{ url_for('entreprises.index') }}" class="breadcrumbs_link">Entreprises</a>
</li>
<li class="breadcrumbs_item">
<a href="" class="breadcrumbs_link breadcrumbs_link-active">Importation données</a>
</li>
</ul>
</div>
<div class="container">
<h1>{{ title }}</h1>
<br>
<div>
<a href="{{ url_for('entreprises.get_import_donnees_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 entreprises_import and not sites_import and not correspondants_import %}
<div>Feuille Entreprises</div>
<table class="table">
<thead><tr><td><b>Attribut</b></td><td><b>Type</b></td><td><b>Description</b></td></tr></thead>
<tr><td>siret (*)</td><td>text</td><td>siret de l'entreprise</td></tr>
<tr><td>nom_entreprise (*)</td><td>text</td><td>nom de l'entreprise</td></tr>
<tr><td>adresse (*)</td><td>text</td><td>adresse de l'entreprise</td></tr>
<tr><td>ville (*)</td><td>text</td><td>ville de l'entreprise</td></tr>
<tr><td>code_postal (*)</td><td>text</td><td>code postal de l'entreprise</td></tr>
<tr><td>pays</td><td>text</td><td>pays de l'entreprise</td></tr>
</table>
<div>Feuille Sites</div>
<table class="table">
<thead><tr><td><b>Attribut</b></td><td><b>Type</b></td><td><b>Description</b></td></tr></thead>
<tr><td>siret_entreprise (*)</td><td>text</td><td>siret de l'entreprise</td></tr>
<tr><td>id_site (*)</td><td>text</td><td>id du site (ne rien remplir pour créer un site)</td></tr>
<tr><td>nom_site (*)</td><td>text</td><td>nom du site</td></tr>
<tr><td>adresse (*)</td><td>text</td><td>adresse du site</td></tr>
<tr><td>ville (*)</td><td>text</td><td>ville du site</td></tr>
<tr><td>code_postal (*)</td><td>text</td><td>code postal du site</td></tr>
<tr><td>pays (*)</td><td>text</td><td>pays du site</td></tr>
</table>
<div>Feuille Correspondants (à utiliser pour les modifications)</div>
<table class="table">
<thead><tr><td><b>Attribut</b></td><td><b>Type</b></td><td><b>Description</b></td></tr></thead>
<tr><td>civilite (*)</td><td>text</td><td>civilite du correspondant (H ou F)</td></tr>
<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>origine</td><td>text</td><td>origine du correspondant</td></tr>
<tr><td>notes</td><td>text</td><td>notes sur le correspondant</td></tr>
<tr><td>nom_site</td><td>text</td><td>nom du site lié au correspondant</td></tr>
</table>
{% endif %}
{% if entreprises_import %}
<br><div>Importation de {{ entreprises_import|length }} entreprise(s)</div>
{% for entreprise in entreprises_import %}
<div class="entreprise">
<div>
SIRET : {{ entreprise.siret }}<br>
Nom : {{ entreprise.nom }}<br>
Adresse : {{ entreprise.adresse }}<br>
Code postal : {{ entreprise.codepostal }}<br>
Ville : {{ entreprise.ville }}<br>
Pays : {{ entreprise.pays }}<br>
<a href="{{ url_for('entreprises.fiche_entreprise', id=entreprise.id) }}" target="_blank">Fiche entreprise</a>
</div>
{% for site in entreprise.sites %}
<div class="site">
Nom : {{ site.nom }}<br>
Adresse : {{ site.adresse }}<br>
Code postal : {{ site.codepostal }}<br>
Ville : {{ site.ville }}<br>
Pays : {{ site.pays }}
</div>
{% endfor %}
</div>
{% endfor %}
{% endif %}
{% if sites_import %}
<br><div>Importation de {{ sites_import|length }} site(s)</div>
{% for site in sites_import %}
<div class="site">
Nom : {{ site.nom }}<br>
Adresse : {{ site.adresse }}<br>
Code postal : {{ site.codepostal }}<br>
Ville : {{ site.ville }}<br>
Pays : {{ site.pays }}<br>
<a href="{{ url_for('entreprises.fiche_entreprise', id=site.entreprise_id) }}" target="_blank">Fiche entreprise</a>
</div>
{% endfor %}
{% endif %}
{% if correspondants_import %}
<br><div>Importation de {{ correspondants_import|length }} correspondant(s)</div>
{% for correspondant in correspondants_import %}
<div class="correspondant">
<div>
Civilité : {{ correspondant.civilite|get_civilité }}<br>
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 %}
{% if correspondant.origine %}
Origine : {{ correspondant.origine }}<br>
{% endif %}
{% if correspondant.notes %}
Notes : {{ correspondant.notes }}<br>
{% endif %}
<a href="{{ url_for('entreprises.fiche_entreprise', id=correspondant.entreprise_id) }}" target="_blank">Fiche entreprise</a>
</div>
</div>
{% endfor %}
{% endif %}
</div>
{% endblock %}

View File

@ -1,52 +0,0 @@
{# -*- mode: jinja-html -*- #}
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block styles %}
{{super()}}
{% endblock %}
{% block app_content %}
<h1>Importation entreprises</h1>
<br>
<div>
<a href="{{ url_for('entreprises.get_import_entreprises_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 entreprises_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>siret</td><td>text</td><td>siret de l'entreprise</td></tr>
<tr><td>nom_entreprise</td><td>text</td><td>nom de l'entreprise</td></tr>
<tr><td>adresse</td><td>text</td><td>adresse de l'entreprise</td></tr>
<tr><td>ville</td><td>text</td><td>ville de l'entreprise</td></tr>
<tr><td>code_postal</td><td>text</td><td>code postal de l'entreprise</td></tr>
<tr><td>pays</td><td>text</td><td>pays de l'entreprise</td></tr>
</table>
{% endif %}
{% if entreprises_import %}
<br><div>Importation de {{ entreprises_import|length }} entreprise(s)</div>
{% for entreprise in entreprises_import %}
<div class="entreprise">
<div>
SIRET : {{ entreprise.siret }}<br>
Nom : {{ entreprise.nom }}<br>
Adresse : {{ entreprise.adresse }}<br>
Code postal : {{ entreprise.codepostal }}<br>
Ville : {{ entreprise.ville }}<br>
Pays : {{ entreprise.pays }}
</div>
</div>
{% endfor %}
{% endif %}
{% endblock %}

View File

@ -2,6 +2,17 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block app_content %} {% block app_content %}
<div class="container">
<ul class="breadcrumbs">
<li class="breadcrumbs_item">
<a href="{{ url_for('entreprises.index') }}" class="breadcrumbs_link">Entreprises</a>
</li>
<li class="breadcrumbs_item">
<a href="" class="breadcrumbs_link breadcrumbs_link-active">Dernières opérations</a>
</li>
</ul>
</div>
<div class="container"> <div class="container">
<h3>Dernières opérations</h3> <h3>Dernières opérations</h3>
{% if logs.items %} {% if logs.items %}

View File

@ -2,6 +2,20 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block app_content %} {% block app_content %}
<div class="container">
<ul class="breadcrumbs">
<li class="breadcrumbs_item">
<a href="{{ url_for('entreprises.index') }}" class="breadcrumbs_link">Entreprises</a>
</li>
<li class="breadcrumbs_item">
<a href="{{ url_for('entreprises.fiche_entreprise', id=entreprise.id) }}" class="breadcrumbs_link">Fiche entreprise</a>
</li>
<li class="breadcrumbs_item">
<a href="" class="breadcrumbs_link breadcrumbs_link-active">Dernières opérations</a>
</li>
</ul>
</div>
<div class="container"> <div class="container">
<h3>Dernières opérations - {{ entreprise.nom }}</h3> <h3>Dernières opérations - {{ entreprise.nom }}</h3>
{% if logs.items %} {% if logs.items %}

View File

@ -1,4 +1,5 @@
{# -*- mode: jinja-html -*- #} {# -*- mode: jinja-html -*- #}
<div class="container">
<nav class="nav-entreprise"> <nav class="nav-entreprise">
<ul> <ul>
<li><a href="{{ url_for('entreprises.index') }}">Entreprises</a></li> <li><a href="{{ url_for('entreprises.index') }}">Entreprises</a></li>
@ -12,3 +13,4 @@
{% endif %} {% endif %}
</ul> </ul>
</nav> </nav>
</div>

View File

@ -2,6 +2,20 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block app_content %} {% block app_content %}
<div class="container">
<ul class="breadcrumbs">
<li class="breadcrumbs_item">
<a href="{{ url_for('entreprises.index') }}" class="breadcrumbs_link">Entreprises</a>
</li>
<li class="breadcrumbs_item">
<a href="{{ url_for('entreprises.fiche_entreprise', id=entreprise.id) }}" class="breadcrumbs_link">Fiche entreprise</a>
</li>
<li class="breadcrumbs_item">
<a href="" class="breadcrumbs_link breadcrumbs_link-active">Offres expirées</a>
</li>
</ul>
</div>
<div class="container"> <div class="container">
<h1>Offres expirées - {{ entreprise.nom }}</h1> <h1>Offres expirées - {{ entreprise.nom }}</h1>
{% if offres_expirees %} {% if offres_expirees %}

View File

@ -5,6 +5,7 @@
{% block app_content %} {% block app_content %}
{% include 'entreprises/nav.html' %} {% include 'entreprises/nav.html' %}
<div class="container">
<h1>Préférences module gestion entreprises</h1> <h1>Préférences module gestion entreprises</h1>
<br> <br>
<div class="row"> <div class="row">
@ -12,4 +13,5 @@
{{ wtf.quick_form(form, novalidate=True) }} {{ wtf.quick_form(form, novalidate=True) }}
</div> </div>
</div> </div>
</div>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,76 @@
"""ajout taxe apprentissage, association, changement historique
Revision ID: 0b337376e9f7
Revises: ee21c76c8183
Create Date: 2022-07-04 21:10:53.946385
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = "0b337376e9f7"
down_revision = "ee21c76c8183"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"are_historique",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column(
"date",
sa.DateTime(timezone=True),
server_default=sa.text("now()"),
nullable=True,
),
sa.Column("authenticated_user", sa.Text(), nullable=True),
sa.Column("entreprise_id", sa.Integer(), nullable=True),
sa.Column("object", sa.Text(), nullable=True),
sa.Column("object_id", sa.Integer(), nullable=True),
sa.Column("text", sa.Text(), nullable=True),
sa.PrimaryKeyConstraint("id"),
)
op.create_table(
"are_taxe_apprentissage",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("entreprise_id", sa.Integer(), nullable=True),
sa.Column("annee", sa.Integer(), nullable=True),
sa.Column("montant", sa.Integer(), nullable=True),
sa.Column("notes", sa.Text(), nullable=True),
sa.ForeignKeyConstraint(
["entreprise_id"], ["are_entreprises.id"], ondelete="cascade"
),
sa.PrimaryKeyConstraint("id"),
)
op.drop_table("are_logs")
op.add_column(
"are_entreprises", sa.Column("association", sa.Boolean(), nullable=True)
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column("are_entreprises", "association")
op.create_table(
"are_logs",
sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column(
"date",
postgresql.TIMESTAMP(timezone=True),
server_default=sa.text("now()"),
autoincrement=False,
nullable=True,
),
sa.Column("authenticated_user", sa.TEXT(), autoincrement=False, nullable=True),
sa.Column("object", sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column("text", sa.TEXT(), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint("id", name="are_logs_pkey"),
)
op.drop_table("are_taxe_apprentissage")
op.drop_table("are_historique")
# ### end Alembic commands ###