initial upload
This commit is contained in:
0
aem_gestion/views/__init__.py
Normal file
0
aem_gestion/views/__init__.py
Normal file
446
aem_gestion/views/compta.py
Normal file
446
aem_gestion/views/compta.py
Normal file
@@ -0,0 +1,446 @@
|
||||
# -*- coding: utf8 -*-
|
||||
from pyramid.view import (
|
||||
view_config,
|
||||
)
|
||||
from pyramid.httpexceptions import (
|
||||
HTTPFound,
|
||||
)
|
||||
|
||||
from datetime import datetime as dt, date
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import json
|
||||
|
||||
from ..models.compta import *
|
||||
from ..models.default import (
|
||||
get_users_by_code,
|
||||
)
|
||||
from ..models.eleves import get_permis
|
||||
from ..views.default import (
|
||||
to_date,
|
||||
to_euro,
|
||||
to_euroz,
|
||||
to_time,
|
||||
to_int,
|
||||
to_percent,
|
||||
)
|
||||
|
||||
@view_config(route_name='export_cpta', renderer='../templates/compta/export_cpta.pt', permission='manage')
|
||||
def export_cpta(request):
|
||||
logged_in = request.authenticated_userid.lower()
|
||||
url = request.route_url('export_cpta')
|
||||
message = ''
|
||||
|
||||
brouillard = []
|
||||
total_debit = 0
|
||||
total_credit = 0
|
||||
NOW = dt.now()
|
||||
|
||||
if 'etape' in request.params:
|
||||
etape = '2'
|
||||
etape = request.params['etape']
|
||||
# récuprérer la date de fin
|
||||
date_fin = dt.strptime(request.params['date_fin'], '%d-%m-%Y')
|
||||
else:
|
||||
etape = '1'
|
||||
date_fin = NOW.date()
|
||||
|
||||
nom_fichier = "C-AEM-%s-%s.PNM" % (date_fin.strftime("%y%m%d"), NOW.strftime("%H%M"))
|
||||
|
||||
if 'form.extraction' in request.params:
|
||||
|
||||
# générer le brouillard jusqu'à la date de fin
|
||||
message = generer_brouillard(request, logged_in, date_fin)
|
||||
|
||||
if len(message) == 0:
|
||||
etape = '2'
|
||||
# si extraction OK, afficher le brouillard
|
||||
brouillard = get_brouillard(request, logged_in)
|
||||
for item in brouillard:
|
||||
if item.SENS == 'C':
|
||||
total_credit += float(item.MONTANT)
|
||||
else:
|
||||
total_debit += float(item.MONTANT)
|
||||
else:
|
||||
# afficher message erreur
|
||||
request.session.flash(message, 'danger')
|
||||
|
||||
|
||||
if 'form.generer' in request.params:
|
||||
import os
|
||||
|
||||
# créer le répertoire /JUSTIFS/EXPORT
|
||||
path = request.registry.settings['aem_gestion.justifs_dir'] + '/EXPORT/'
|
||||
os.makedirs(path, exist_ok=True)
|
||||
|
||||
path_fichier = path + nom_fichier
|
||||
# générer le fichier PNM dans le répertoire EXPORT
|
||||
message = generer_export(request, logged_in, path_fichier)
|
||||
|
||||
# MAJ les comptes clients exportés dans la période
|
||||
update_cpt_export(request, date_fin)
|
||||
|
||||
request.session.flash("La génération du fichier d'export " + nom_fichier + " est terminée.", 'success')
|
||||
etape = '3'
|
||||
|
||||
return {
|
||||
'page_title': "Exportation des écritures",
|
||||
'url': url,
|
||||
'message': message,
|
||||
'etape' : etape,
|
||||
'date_fin': date_fin,
|
||||
'nom_fichier': nom_fichier,
|
||||
'brouillard': brouillard,
|
||||
'total_credit': to_euro(total_credit),
|
||||
'total_debit': to_euro(total_debit),
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='jnl_caisse', renderer='../templates/compta/jnl_caisse.pt', permission='view')
|
||||
def jnl_caisse(request):
|
||||
logged_in = request.authenticated_userid
|
||||
url = request.route_url('jnl_caisse')
|
||||
message = ''
|
||||
|
||||
member = get_users_by_code(request, logged_in)
|
||||
if member.secu < 6 :
|
||||
request.session.flash("Vous n'avez le niveau d'accès requis pour ce traitement", 'error')
|
||||
return HTTPFound(location=request.route_url('home'))
|
||||
|
||||
date_edition = dt.now().date()
|
||||
agence = member.agence
|
||||
|
||||
if 'form.submitted' in request.params:
|
||||
# récuprérer la date d'édition
|
||||
date_edition = request.params['date_edition']
|
||||
return HTTPFound(location=request.route_url('prt_caisse', date_edition=date_edition))
|
||||
|
||||
return {
|
||||
'page_title': 'Agence %s : Journal de caisse du %s' % (agence, date_edition.strftime('%d-%m-%Y')),
|
||||
'url': url,
|
||||
'message': message,
|
||||
'date_edition': date_edition,
|
||||
}
|
||||
|
||||
@view_config(route_name='prt_caisse', renderer='../templates/compta/prt_caisse.pt', permission='view')
|
||||
def prt_caisse(request):
|
||||
date_edition = dt.strptime(request.matchdict['date_edition'], '%d-%m-%Y')
|
||||
logged_in = request.authenticated_userid
|
||||
|
||||
member = get_users_by_code(request, logged_in)
|
||||
if member.secu <= 6 :
|
||||
return HTTPFound(location=request.route_url('home'))
|
||||
|
||||
agence = member.agence
|
||||
# lire la caisse du jour
|
||||
items = get_caisse(request, agence, date_edition)
|
||||
|
||||
# construire la liste
|
||||
liste=[]
|
||||
|
||||
# lire la caisse du jour
|
||||
items = get_caisse(request, agence, date_edition)
|
||||
|
||||
totalMode = 0.0
|
||||
totalGeneral = 0.0
|
||||
groupe = ''
|
||||
for item in items:
|
||||
# rupture sur mode_regl
|
||||
if groupe != item.lib4 :
|
||||
if groupe != '':
|
||||
# ajouter une ligne de sous-total
|
||||
d = ('', '', '', '*** TOTAL pour ' + groupe, to_euro(totalMode), groupe, '', '')
|
||||
liste.append(d)
|
||||
totalGeneral += totalMode
|
||||
totalMode = 0.0
|
||||
cree_le = item.cree_le.strftime('%d-%m-%y')
|
||||
modif_le = item.modif_le.strftime('%d-%m')
|
||||
d = (item.CD_CLI, item.NOM, item.permis_demande, item.INTITULE, to_euro(item.CREDIT),
|
||||
item.lib4, item.CD_UTI, cree_le + ', ' + modif_le)
|
||||
liste.append(d)
|
||||
|
||||
totalMode += float(item.CREDIT)
|
||||
groupe = item.lib4
|
||||
|
||||
# ajouter une ligne de sous-total
|
||||
d = ('', '', '', '*** TOTAL pour ' + groupe, to_euro(totalMode), groupe, '', '')
|
||||
liste.append(d)
|
||||
# ajouter ligne Total général
|
||||
totalGeneral += totalMode
|
||||
d = ('', '', '', '*** TOTAL AGENCE ' + str(agence), to_euro(totalGeneral), '', '', '')
|
||||
liste.append(d)
|
||||
|
||||
return {
|
||||
'page_title': 'Agence %s : Journal de caisse du %s' % (agence, date_edition.strftime('%d-%m-%Y')),
|
||||
'date_edition': date_edition,
|
||||
'dt_data': json.dumps(liste),
|
||||
'agence': agence,
|
||||
}
|
||||
|
||||
@view_config(route_name='solder_contrats', renderer='../templates/compta/solder_contrats.pt', permission='manage')
|
||||
def solder_contrats(request):
|
||||
logged_in = request.authenticated_userid.lower()
|
||||
url = request.route_url('solder_contrats')
|
||||
message = ''
|
||||
|
||||
if 'form.solder_auto' in request.params:
|
||||
|
||||
# Solder les comptes clients
|
||||
result = update_contrats_auto(request, 6, logged_in)
|
||||
|
||||
request.session.flash(str(result.NB) + " contrats AUTO ont été soldés !", 'success')
|
||||
|
||||
if 'form.solder_moto' in request.params:
|
||||
|
||||
# Solder les comptes clients
|
||||
result = update_contrats_auto(request, 6, logged_in)
|
||||
|
||||
request.session.flash(str(result.NB) + " contrats MOTO ont été soldés !", 'success')
|
||||
|
||||
return {
|
||||
'page_title': "Solder les contrats échus",
|
||||
'url': url,
|
||||
'message': message,
|
||||
}
|
||||
|
||||
@view_config(route_name='balance_clients', renderer='../templates/compta/balance_clients.pt', permission='manage')
|
||||
def balance_clients(request):
|
||||
logged_in = request.authenticated_userid.lower()
|
||||
url = request.route_url('balance_clients')
|
||||
message = ''
|
||||
|
||||
TODAY = dt.now().date()
|
||||
|
||||
permis = get_permis(request)
|
||||
cat = 'B'
|
||||
# date début = 01/01 de l'année
|
||||
date_debut = date(TODAY.year, 1, 1)
|
||||
date_fin = date(TODAY.year, 12, 31)
|
||||
|
||||
if 'form.submitted' in request.params:
|
||||
cat = request.params['cat']
|
||||
# récuprérer la date de debut
|
||||
date_debut = dt.strptime(request.params['date_debut'], '%d-%m-%Y')
|
||||
# récuprérer la date de fin
|
||||
date_fin = dt.strptime(request.params['date_fin'], '%d-%m-%Y')
|
||||
|
||||
# "La date de fin doit être supérieure à la date début"
|
||||
if date_debut > date_fin :
|
||||
message("La date de fin doit être supérieure à la date début")
|
||||
else:
|
||||
# générerles écritures de balance
|
||||
generer_balance(request, logged_in, cat, date_debut, date_fin)
|
||||
request.session.flash("La génération de la balance est terminée !", 'success')
|
||||
|
||||
if 'form.printed' in request.params:
|
||||
return HTTPFound(location=request.route_url('balance_print'))
|
||||
|
||||
# dates de début et fin de la génération en cours
|
||||
balance_debut, balance_fin, balance_criteres = get_dates_balance(request)
|
||||
if balance_debut:
|
||||
generer_debut = balance_debut.strftime('%d-%m-%Y %H:%M')
|
||||
else:
|
||||
generer_debut = "Pas de génération en cours"
|
||||
if balance_fin:
|
||||
generer_fin = balance_fin.strftime('%d-%m-%Y %H:%M')
|
||||
else:
|
||||
generer_fin = "Génération non terminée..."
|
||||
|
||||
|
||||
return {
|
||||
'page_title': "Balance CLIENTS",
|
||||
'url': url,
|
||||
'message': message,
|
||||
'date_debut': date_debut,
|
||||
'date_fin': date_fin,
|
||||
'generer_debut': generer_debut,
|
||||
'generer_fin' : generer_fin,
|
||||
'balance_fin': balance_fin,
|
||||
'balance_criteres': balance_criteres,
|
||||
'permis': permis,
|
||||
'cat': cat,
|
||||
}
|
||||
|
||||
@view_config(route_name='balance_print', renderer='../templates/compta/balance_print.pt', permission='manage')
|
||||
def balance_print(request):
|
||||
logged_in = request.authenticated_userid.lower()
|
||||
|
||||
TODAY = dt.now().date()
|
||||
# construire la liste
|
||||
liste=[]
|
||||
|
||||
# lire la balance générée
|
||||
items = get_balance(request, logged_in)
|
||||
# dates de début et fin de la génération en cours
|
||||
balance_debut, balance_fin, criteres = get_dates_balance(request)
|
||||
if balance_fin == None:
|
||||
return HTTPFound(location=request.route_url('balance_clients'))
|
||||
|
||||
# total agence
|
||||
agence = 0
|
||||
ta_solde = 0.0
|
||||
ta_mtval = 0.0
|
||||
ta_credit = 0.0
|
||||
ta_solde_c = 0.0
|
||||
ta_solde_d = 0.0
|
||||
# total générale
|
||||
tl_solde = 0.0
|
||||
tl_mtval = 0.0
|
||||
tl_credit = 0.0
|
||||
tl_solde_c = 0.0
|
||||
tl_solde_d = 0.0
|
||||
for item in items:
|
||||
# rupture sur mode_regl
|
||||
if agence != item.AGENCE :
|
||||
if agence != 0:
|
||||
# ajouter une ligne de sous-total
|
||||
d = ('', '*** TOTAL Agence ' + str(agence), '', to_euro(ta_solde),
|
||||
to_euro(ta_mtval), to_euro(ta_credit), to_euro(ta_solde_d), to_euro(ta_solde_c), to_euro(ta_solde_c - ta_solde_d))
|
||||
liste.append(d)
|
||||
tl_solde += ta_solde
|
||||
tl_mtval += ta_mtval
|
||||
tl_credit += ta_credit
|
||||
tl_solde_c += ta_solde_c
|
||||
tl_solde_d += ta_solde_d
|
||||
ta_solde = 0.0
|
||||
ta_mtval = 0.0
|
||||
ta_credit = 0.0
|
||||
ta_solde_c = 0.0
|
||||
ta_solde_d = 0.0
|
||||
agence = item.AGENCE
|
||||
|
||||
solde = float(item.Solde + item.CREDIT - item.MTVAL)
|
||||
if solde < 0 :
|
||||
solde_c = 0
|
||||
solde_d = solde * -1
|
||||
else :
|
||||
solde_c = solde
|
||||
solde_d = 0
|
||||
|
||||
d = (item.CD_CLI, item.INTITULE, item.FORMULE, to_euro(item.Solde), to_euro(item.MTVAL), to_euro(item.CREDIT),
|
||||
to_euro(solde_d), to_euro(solde_c), '')
|
||||
liste.append(d)
|
||||
|
||||
ta_solde += float(item.Solde)
|
||||
ta_mtval += float(item.MTVAL)
|
||||
ta_credit += float(item.CREDIT)
|
||||
ta_solde_c += solde_c
|
||||
ta_solde_d += solde_d
|
||||
|
||||
# ajouter dernière ligne de sous-total
|
||||
d = ('', '*** TOTAL Agence ' + str(agence), '', to_euro(ta_solde),
|
||||
to_euro(ta_mtval), to_euro(ta_credit), to_euro(ta_solde_d), to_euro(ta_solde_c), to_euro(ta_solde_c - ta_solde_d))
|
||||
liste.append(d)
|
||||
# ajouter ligne Total général
|
||||
tl_solde += ta_solde
|
||||
tl_mtval += ta_mtval
|
||||
tl_credit += ta_credit
|
||||
tl_solde_c += ta_solde_c
|
||||
tl_solde_d += ta_solde_d
|
||||
d = ('', '*** TOTAL SOCIETE', '', to_euro(tl_solde),
|
||||
to_euro(tl_mtval), to_euro(tl_credit), to_euro(tl_solde_d), to_euro(tl_solde_c), to_euro(tl_solde_c - tl_solde_d))
|
||||
liste.append(d)
|
||||
|
||||
return {
|
||||
'page_title': "Balance CLIENTS " + criteres,
|
||||
'TODAY': TODAY,
|
||||
'dt_data': json.dumps(liste),
|
||||
}
|
||||
|
||||
@view_config(route_name='recap_moniteur', renderer='../templates/compta/recap_moniteur.pt', permission='manage')
|
||||
def recap_moniteur(request):
|
||||
logged_in = request.authenticated_userid.lower()
|
||||
url = request.route_url('recap_moniteur')
|
||||
message = ''
|
||||
|
||||
TODAY = dt.now().date()
|
||||
|
||||
# date début = 01 du mois
|
||||
date_debut = date(TODAY.year, TODAY.month, 1)
|
||||
date_fin = date_debut + relativedelta(day=31)
|
||||
# lire les moniteurs
|
||||
moniteurs = get_moniteurs_byCode(request)
|
||||
cd_mon1 = moniteurs[0].CD_MON
|
||||
cd_mon2 = moniteurs[len(moniteurs) - 1].CD_MON
|
||||
|
||||
if 'form.submitted' in request.params:
|
||||
cd_mon1 = request.params['cd_mon1']
|
||||
cd_mon2 = request.params['cd_mon2']
|
||||
# récuprérer la date de debut
|
||||
date_debut = dt.strptime(request.params['date_debut'], '%d-%m-%Y')
|
||||
# récuprérer la date de fin
|
||||
date_fin = dt.strptime(request.params['date_fin'], '%d-%m-%Y')
|
||||
|
||||
# "La date de fin doit être supérieure à la date début"
|
||||
if date_debut > date_fin :
|
||||
message("La date de fin doit être supérieure à la date début")
|
||||
else:
|
||||
return HTTPFound(location=request.route_url('recap_print',
|
||||
cd_mon1=cd_mon1, cd_mon2=cd_mon2, date1=date_debut.date(), date2=date_fin.date()))
|
||||
|
||||
|
||||
return {
|
||||
'page_title': "Récap des activités Moniteurs",
|
||||
'url': url,
|
||||
'message': message,
|
||||
'date_debut': date_debut,
|
||||
'date_fin': date_fin,
|
||||
'moniteurs': moniteurs,
|
||||
'cd_mon1': cd_mon1,
|
||||
'cd_mon2': cd_mon2,
|
||||
}
|
||||
|
||||
@view_config(route_name='recap_print', renderer='../templates/compta/recap_print.pt', permission='manage')
|
||||
def recap_print(request):
|
||||
cd_mon1 = request.matchdict['cd_mon1']
|
||||
cd_mon2 = request.matchdict['cd_mon2']
|
||||
date1 = request.matchdict['date1']
|
||||
date2 = request.matchdict['date2']
|
||||
d1 = dt.strptime(date1, '%Y-%m-%d')
|
||||
d2 = dt.strptime(date2, '%Y-%m-%d')
|
||||
periode = 'du %s au %s' % (d1.strftime('%d-%m-%Y'), d2.strftime('%d-%m-%Y'))
|
||||
|
||||
TODAY = dt.now().date()
|
||||
|
||||
# lire le recap des activités des moniteurs
|
||||
# rupture sur CD_MON / REF / STATUT
|
||||
items = get_recap(request, cd_mon1, cd_mon2, date1, date2)
|
||||
|
||||
# total moniteur
|
||||
nom = ''
|
||||
tm_heures = 0
|
||||
|
||||
# construire la liste
|
||||
liste=[]
|
||||
for item in items:
|
||||
# rupture sur NOM
|
||||
if nom != item.NOM :
|
||||
if nom != '':
|
||||
# ajouter une ligne de total Moniteur
|
||||
d = (nom,'','*** TOTAL', nom + ' - ' + cd_mon, str(tm_heures) + ' h')
|
||||
liste.append(d)
|
||||
tm_heures = 0
|
||||
|
||||
if item.STATUT == 15:
|
||||
statut = '(%s)' % item.STATUT
|
||||
qte = '(%s)' % item.SUM_QTE
|
||||
else:
|
||||
statut = str(item.STATUT)
|
||||
qte = str(item.SUM_QTE)
|
||||
|
||||
d = (item.NOM, statut, item.REF, item.INTITULE, qte)
|
||||
liste.append(d)
|
||||
# cumuler les heures
|
||||
tm_heures += item.SUM_QTE
|
||||
nom = item.NOM
|
||||
cd_mon = item.CD_MON
|
||||
|
||||
# ajouter une ligne de total Moniteur
|
||||
d = (nom,'','*** TOTAL', nom + ' - ' + cd_mon, str(tm_heures) + ' h')
|
||||
liste.append(d)
|
||||
|
||||
return {
|
||||
'page_title': "Récap des activités Moniteurs",
|
||||
'periode': periode,
|
||||
'TODAY': TODAY,
|
||||
'dt_data': json.dumps(liste),
|
||||
}
|
||||
1016
aem_gestion/views/crm.py
Normal file
1016
aem_gestion/views/crm.py
Normal file
File diff suppressed because it is too large
Load Diff
799
aem_gestion/views/default.py
Normal file
799
aem_gestion/views/default.py
Normal file
@@ -0,0 +1,799 @@
|
||||
# -*- coding: utf8 -*-
|
||||
from pyramid.response import Response
|
||||
from pyramid.view import (
|
||||
view_config,
|
||||
forbidden_view_config,
|
||||
)
|
||||
from pyramid.security import (
|
||||
remember,
|
||||
forget,
|
||||
)
|
||||
from pyramid.httpexceptions import (
|
||||
HTTPFound,
|
||||
)
|
||||
from pyramid_mailer import get_mailer
|
||||
from pyramid_mailer.message import Message
|
||||
|
||||
from datetime import date, datetime
|
||||
from dateutil.relativedelta import *
|
||||
from urllib.request import urlopen
|
||||
from user_agents import parse
|
||||
|
||||
import transaction
|
||||
import json
|
||||
import locale
|
||||
import hashlib
|
||||
|
||||
from ..models.default import *
|
||||
from ..models.parametres import (
|
||||
get_charts_data,
|
||||
)
|
||||
from ..models.eleves import (
|
||||
get_eleves_by_code,
|
||||
get_eleves_by_name,
|
||||
get_eleves_by_name78,
|
||||
get_eleves_not_b78_by_name,
|
||||
get_eleves_ajax
|
||||
)
|
||||
from ..models.crm import (
|
||||
get_prospects_by_name,
|
||||
)
|
||||
|
||||
|
||||
def to_age(dob, type):
|
||||
today = date.today()
|
||||
age = relativedelta(today, dob)
|
||||
if type == '>':
|
||||
if age.years >= 0:
|
||||
a = '%s ans %s mois' % (age.years, age.months)
|
||||
else:
|
||||
a = '???'
|
||||
else:
|
||||
if age.years < 0 or age.years < 0:
|
||||
if age.years <= -1:
|
||||
a = '%sa %sm' % (age.years, age.months)
|
||||
else:
|
||||
a = '%sm' % (age.months)
|
||||
else:
|
||||
a = ''
|
||||
|
||||
return a.replace('-', '')
|
||||
|
||||
|
||||
def to_decimal(x):
|
||||
import decimal
|
||||
return decimal.Decimal(str(x))
|
||||
|
||||
|
||||
def to_sha1(message):
|
||||
return hashlib.sha1(message.encode('utf-8')).hexdigest()
|
||||
|
||||
|
||||
def to_int(x):
|
||||
if x == None:
|
||||
return 0
|
||||
try:
|
||||
number = int(x.replace(',', '.'))
|
||||
return number
|
||||
except ValueError:
|
||||
return 0
|
||||
|
||||
|
||||
def to_euro(x):
|
||||
"""Takes a float and returns 12 345,67 €"""
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
return locale.currency(x, True, True)
|
||||
|
||||
|
||||
def to_euroz(x):
|
||||
"""Takes a float and returns 12 345,67 € if non zero"""
|
||||
if x == 0:
|
||||
return ""
|
||||
else:
|
||||
return to_euro(x)
|
||||
|
||||
|
||||
def to_decz(x):
|
||||
"""Takes a float and returns a number with 2 dec"""
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
if x == 0:
|
||||
return ""
|
||||
else:
|
||||
return locale.format_string('%.2f', x, False)
|
||||
|
||||
|
||||
def to_euroN(x):
|
||||
"""Takes a float and returns a currency without decimal"""
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
if x == 0:
|
||||
return ""
|
||||
else:
|
||||
return locale.format_string('%.0f', x)
|
||||
|
||||
|
||||
def to_percent(x):
|
||||
"""Takes a float and returns a string"""
|
||||
return ("%.2f " % x).replace('.', ',') + "%"
|
||||
|
||||
|
||||
def to_date(date_text):
|
||||
try:
|
||||
madate = datetime.strptime(date_text, '%d/%m/%Y')
|
||||
if madate.year >= 1900:
|
||||
return madate
|
||||
else:
|
||||
return False
|
||||
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
def to_time(date_text):
|
||||
try:
|
||||
madate = datetime.strptime(date_text, '%H:%M')
|
||||
return madate
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
def to_str(s):
|
||||
if s is None:
|
||||
return ''
|
||||
else:
|
||||
return str(s)
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
@view_config(route_name='ajax_lookup')
|
||||
def ajax_lookup(request):
|
||||
recherche = request.GET['recherche']
|
||||
type = recherche[:1] # 1er car.
|
||||
name = recherche[1:]
|
||||
|
||||
if type == 'E':
|
||||
# lire les élèves commencant par
|
||||
items = get_eleves_not_b78_by_name(request, name, 10)
|
||||
else:
|
||||
# lire les propsects commencant par
|
||||
items = get_prospects_by_name(request, name, False)
|
||||
|
||||
liste = []
|
||||
for row in items:
|
||||
if type == 'E':
|
||||
d = "%s - %s | %s" % (row.nompren, row.permis_demande, str(row.cd_cli).zfill(6))
|
||||
else:
|
||||
d = "%s - %s | %s" % (row.nomprenom, row.permis_demande, str(row.cd_prospect).zfill(6))
|
||||
liste.append(d)
|
||||
|
||||
return Response(json.dumps(liste))
|
||||
|
||||
@view_config(route_name='ajax_eleve')
|
||||
def ajax_eleve(request):
|
||||
recherche = request.GET['recherche']
|
||||
items = get_eleves_ajax(request, recherche)
|
||||
|
||||
liste = []
|
||||
for row in items:
|
||||
d = "%s - %s | %s" % (row.nompren, row.permis_demande, str(row.cd_cli).zfill(6))
|
||||
liste.append(d)
|
||||
|
||||
return Response(json.dumps(liste))
|
||||
|
||||
@view_config(route_name='ajax_lookupb78')
|
||||
def ajax_lookupb78(request):
|
||||
recherche = request.GET['recherche']
|
||||
type = recherche[:1] # 1er car.
|
||||
name = recherche[1:]
|
||||
|
||||
if type == 'E':
|
||||
# lire les élèves commencant par
|
||||
items = get_eleves_by_name78(request, name, 10)
|
||||
else:
|
||||
# lire les propsects commencant par
|
||||
items = get_prospects_by_name(request, name, False)
|
||||
|
||||
liste = []
|
||||
for row in items:
|
||||
if type == 'E':
|
||||
d = "%s - %s | %s" % (row.nompren, row.permis_demande, str(row.cd_cli).zfill(6))
|
||||
else:
|
||||
d = "%s - %s | %s" % (row.nomprenom, row.permis_demande, str(row.cd_prospect).zfill(6))
|
||||
liste.append(d)
|
||||
|
||||
return Response(json.dumps(liste))
|
||||
|
||||
@view_config(route_name='ajax_moniteur')
|
||||
def ajax_moniteur(request):
|
||||
recherche = request.GET['recherche']
|
||||
items = get_all_moniteur_active_by_name(request, recherche)
|
||||
liste = []
|
||||
for row in items:
|
||||
code = row.CD_MON
|
||||
name = row.NOM+ ' | ' + row.PLANNING
|
||||
liste.append({"data": code, "value": name})
|
||||
|
||||
return Response(json.dumps(liste))
|
||||
|
||||
|
||||
@view_config(route_name='ajax_codepostal')
|
||||
def ajax_codepostal(request):
|
||||
recherche = request.GET['recherche']
|
||||
|
||||
# lire les codes postaux commencant par
|
||||
items = get_codespostaux(request, recherche)
|
||||
|
||||
liste = []
|
||||
for row in items:
|
||||
d = row.code_postal + " | " + row.libelle
|
||||
liste.append({"value": d, "data": d})
|
||||
return Response(json.dumps(liste))
|
||||
|
||||
|
||||
@view_config(route_name='ajax_tarifs')
|
||||
def ajax_tarifs(request):
|
||||
recherche = request.GET['recherche']
|
||||
|
||||
# lire les tarifs commencant par
|
||||
items = get_tarifs_byName(request, recherche)
|
||||
|
||||
liste = []
|
||||
for row in items:
|
||||
d = row.REF # + " - " + row.LIB
|
||||
liste.append(d)
|
||||
return Response(json.dumps(liste))
|
||||
|
||||
|
||||
@view_config(route_name='ajax_type_devis', renderer='json')
|
||||
def ajax_type_devis(request):
|
||||
type_devis = request.POST['type_devis']
|
||||
# lire le type de devis dans la BD
|
||||
item = get_types_devis(request, type_devis)
|
||||
if item:
|
||||
montant = str(item.montantTTC)
|
||||
montant_ht = str(item.montantHT)
|
||||
nb_heures = str(item.nb_heures)
|
||||
else:
|
||||
montant = '0.00'
|
||||
montant_ht = '0.00'
|
||||
nb_heures = '0'
|
||||
return {
|
||||
'montant': montant,
|
||||
'montant_ht': montant_ht,
|
||||
'nb_heures': nb_heures,
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='ajax_valid_formules')
|
||||
def ajax_valid_formules(request):
|
||||
permis = request.GET["permis"]
|
||||
formules = get_all_formules(request, permis)
|
||||
liste = []
|
||||
for item in formules:
|
||||
liste.append({"value": item.FORMULE, "data": item.FORMULE})
|
||||
return Response(json.dumps(liste))
|
||||
|
||||
|
||||
@view_config(route_name='ajax_formules')
|
||||
def ajax_formules(request):
|
||||
recherche = request.GET['recherche']
|
||||
|
||||
validite = 'EN-COURS'
|
||||
|
||||
# si validite a changé
|
||||
if 'validite' in request.GET:
|
||||
validite = request.GET["validite"]
|
||||
# lire les formules
|
||||
items = get_formules(request, recherche, validite)
|
||||
|
||||
# construire la liste
|
||||
liste = []
|
||||
for item in items:
|
||||
liste.append({"value": item.FORMULE, "data": item.FORMULE})
|
||||
# lire les codes postaux commencant par
|
||||
|
||||
return Response(json.dumps(liste))
|
||||
|
||||
|
||||
@view_config(route_name='ajax_dept_nais')
|
||||
def ajax_dept_nais(request):
|
||||
recherche = request.GET['recherche']
|
||||
items = get_dept_nais(request, recherche)
|
||||
liste = []
|
||||
for item in items:
|
||||
liste.append({"value": item.code, "data": item.libelle})
|
||||
|
||||
return Response(json.dumps(liste))
|
||||
|
||||
|
||||
@view_config(route_name='ajax_login')
|
||||
def ajax_login(request):
|
||||
login = request.params['login']
|
||||
item = get_users_by_code(request, login)
|
||||
data = {}
|
||||
agences = []
|
||||
if item != None:
|
||||
data['find']= True
|
||||
if item.mobile == True :
|
||||
data['mobile']= True
|
||||
list_agences = get_agences(request,0)
|
||||
for agence in list_agences :
|
||||
dict_agence ={
|
||||
'code' : agence.CODE,
|
||||
'libelle' : agence.LIBELLE
|
||||
}
|
||||
agences.append(dict_agence)
|
||||
else:
|
||||
data['mobile']= False
|
||||
else:
|
||||
data['find']= False
|
||||
data['agence'] = agences
|
||||
return Response(json.dumps(data))
|
||||
|
||||
@view_config(route_name='ajax_mode_regl')
|
||||
def ajax_mode_regl(request):
|
||||
recherche = request.GET['recherche']
|
||||
items = get_mode_mode_regl(request, recherche)
|
||||
# construire la liste
|
||||
liste = []
|
||||
for item in items:
|
||||
liste.append({"value": item.LIBELLE, "data": item.CODE})
|
||||
return Response(json.dumps(liste))
|
||||
|
||||
|
||||
@view_config(route_name='ajax_libelle_regl')
|
||||
def ajax_libelle_regl(request):
|
||||
recherche = request.GET['recherche']
|
||||
items = get_libelle_mode_regl(request, recherche)
|
||||
# construire la liste
|
||||
liste = []
|
||||
for item in items:
|
||||
liste.append({"value": item.LIBELLE, "data": item.CODE})
|
||||
return Response(json.dumps(liste))
|
||||
|
||||
@view_config(route_name='ajax_activity')
|
||||
def ajax_activity(request):
|
||||
recherche = request.GET['recherche']
|
||||
items = get_list_activity(request, recherche)
|
||||
# construire la liste
|
||||
liste = []
|
||||
for item in items:
|
||||
liste.append({"value": item.NOM, "data": item.CD_CLI, 'label': item.NOM})
|
||||
return Response(json.dumps(liste))
|
||||
|
||||
def envoyerMail(request, destinataires, nom, objet, corps):
|
||||
# si expediteur vide -> prendre le defaut
|
||||
expediteur = request.registry.settings['aem_gestion.admin_email']
|
||||
|
||||
# ajouter entête et pied au corps du message
|
||||
html_body = """
|
||||
<p>Bonjour %s,</p>
|
||||
%s
|
||||
<p>
|
||||
Cordialement,<br />
|
||||
<b>Espace Moniteurs MARIETTON</b><br/>
|
||||
<a href="https://moniteurs.marietton.com">https://moniteurs.marietton.com</a>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
""" % (nom, corps)
|
||||
|
||||
message = Message(subject="[MARIETTON] %s" % objet,
|
||||
sender=expediteur,
|
||||
recipients=destinataires,
|
||||
html=html_body)
|
||||
|
||||
mailer = get_mailer(request)
|
||||
mailer.send_immediately(message, fail_silently=True)
|
||||
|
||||
|
||||
@view_config(route_name='affiche_message', renderer='../templates/default/affiche_message.pt')
|
||||
def affiche_message(request):
|
||||
login = request.matchdict['login']
|
||||
messages = request.session.pop_flash()
|
||||
|
||||
return {
|
||||
'page_title': "Demande effectuée",
|
||||
'login': login,
|
||||
'messages': messages,
|
||||
'url_identification': request.route_url('login_as', login=login)
|
||||
}
|
||||
|
||||
|
||||
def envoyerMailEleve(request, destinataires, objet, corps):
|
||||
# si expediteur vide -> prendre le defaut
|
||||
expediteur = request.registry.settings['aem_gestion.admin_email']
|
||||
html_body = corps
|
||||
message = Message(subject="[MARIETTON] %s" % objet,
|
||||
sender=expediteur,
|
||||
recipients=destinataires,
|
||||
html=html_body)
|
||||
|
||||
mailer = get_mailer(request)
|
||||
mailer.send_immediately(message, fail_silently=True)
|
||||
|
||||
|
||||
@view_config(route_name='affiche_message', renderer='../templates/default/affiche_message.pt')
|
||||
def affiche_message(request):
|
||||
login = request.matchdict['login']
|
||||
messages = request.session.pop_flash()
|
||||
|
||||
return {
|
||||
'page_title': "Demande effectuée",
|
||||
'login': login,
|
||||
'messages': messages,
|
||||
'url_identification': request.route_url('login_as', login=login)
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='change_password', renderer='../templates/default/change_password.pt', permission='view')
|
||||
def change_password(request):
|
||||
url = request.route_url('change_password')
|
||||
logged_in = request.authenticated_userid
|
||||
message = ''
|
||||
|
||||
member = get_users_by_code(request, logged_in)
|
||||
|
||||
if 'form.submitted' in request.params:
|
||||
old_password = request.params['old_password']
|
||||
new_password = request.params['new_password1']
|
||||
# On encode le password pour ne plus avoir de plantage avec les "é"
|
||||
if (member.mdp_hash == to_sha1(old_password)):
|
||||
update_password(request, logged_in, new_password)
|
||||
request.session.flash("Votre mot de passe a été mis à jour avec succès.", 'success')
|
||||
return HTTPFound(location=request.route_url('home'))
|
||||
else:
|
||||
message = "L'ancien mot de passe fourni est incorrect."
|
||||
return {
|
||||
'page_title': "Changer mon mot de passe",
|
||||
'url': url,
|
||||
'member': member,
|
||||
'message': message,
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='email_password', renderer='../templates/default/email_password.pt')
|
||||
def email_password(request):
|
||||
url = request.route_url('email_password')
|
||||
message = ''
|
||||
|
||||
if 'form.submitted' in request.params:
|
||||
login = request.params['login']
|
||||
member = get_users_by_code(request, login)
|
||||
if member:
|
||||
if member.actif == 0:
|
||||
message = "Le compte de cet utilisateur est désactivé. Contactez votre agence."
|
||||
elif member.email:
|
||||
# Fabrication du corps du Message
|
||||
lien = update_membre_mdp_oublie(request, login)
|
||||
body = """
|
||||
<p>Vous avez oublié votre mot de passe. Par mesure de sécurité, nous vous demandons de bien vouloir le réinitialiser en cliquant sur ce lien :</p>
|
||||
<p>%s</p>
|
||||
<p>Ce lien ne sera valable que pendant 48 heures.</p>
|
||||
""" % (request.route_url('redefinir_mdp', lien=lien))
|
||||
destinataires = [member.email]
|
||||
envoyerMail(request, destinataires, member.nom, "Oubli de mot de passe", body)
|
||||
request.session.flash("Le lien permettant de redéfinir votre mot de passe vous a été envoyé à l'adresse : %s." % member.email, 'success')
|
||||
return HTTPFound(location=request.route_url('affiche_message', login=login))
|
||||
else:
|
||||
message = "L'adresse e-mail de cet utilisateur n'est pas renseignée. Contactez votre agence."
|
||||
else:
|
||||
message = "Aucun utilisateur trouvé avec ce code. Veuillez réessayer."
|
||||
|
||||
return {
|
||||
'page_title': "Mot de passe oublié ?",
|
||||
'url': url,
|
||||
'message': message,
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='home', renderer='../templates/default/home.pt', permission='view')
|
||||
def home(request):
|
||||
def getChartColor(valeur):
|
||||
# retourne la couleur du graphique selon la valeur
|
||||
if valeur < 40:
|
||||
color = 'red'
|
||||
elif valeur < 50:
|
||||
color = 'orange'
|
||||
elif valeur < 60:
|
||||
color = 'yellow'
|
||||
else:
|
||||
color = 'green'
|
||||
|
||||
return color
|
||||
|
||||
"""Home view"""
|
||||
logged_in = request.authenticated_userid
|
||||
member = get_users_by_code(request, logged_in)
|
||||
now = datetime.now()
|
||||
# examens = get_examen_by_agence(request,member.agence)
|
||||
|
||||
# récupère le nombre de messages non lus de l'utilisateur
|
||||
try:
|
||||
html = urlopen('https://suivi-eleve.marietton.com/MSG-nl.php?codeU=%s' % logged_in,timeout=30)
|
||||
nlus = html.read()
|
||||
except:
|
||||
nlus = 0
|
||||
|
||||
barChart_annee_3 = []
|
||||
|
||||
mois_3 = now - relativedelta(months=+3)
|
||||
mois_2 = now - relativedelta(months=+2)
|
||||
mois_1 = now - relativedelta(months=+1)
|
||||
mois = now - relativedelta(months=+0)
|
||||
|
||||
# lire les résultats exmanes mois M-2
|
||||
items = get_charts_data(request, 'examens01', mois_3.strftime('%Y%m'))
|
||||
# construire la liste pour barChart
|
||||
barChart_annee_3 = []
|
||||
barChart_annee_3.append(('Mode', '%', {'role': 'style'}, {'role': 'annotation'}, {'type': 'string','role': 'tooltip'}))
|
||||
title_3 = ''
|
||||
average = 0
|
||||
sum_totale=0
|
||||
sum_reussite=0
|
||||
moyenne = 0
|
||||
for item in items:
|
||||
title_3 = item.group1_lib
|
||||
average = round(item.moyenne)
|
||||
valeur = round(item.valeur)
|
||||
moyenne = item.moyenne
|
||||
sum_totale = item.mar_totale
|
||||
sum_reussite = item.mar_reussite
|
||||
tooltip = 'Agence: '+item.group2_lib+'\nReussite: '+str(item.reussite)+'\nTotale: '+str(item.totale)+'\nTaux: '+str(round(item.valeur)) + ' %'
|
||||
# construire la liste pour barChart cible
|
||||
d = (item.group2_lib, valeur, getChartColor(valeur),'('+str(item.reussite)+'/'+str(item.totale)+')\xa0\xa0\xa0'+str(valeur) + ' %',tooltip)
|
||||
barChart_annee_3.append(d)
|
||||
# ajouter colonne MARIETTON
|
||||
mar_tooltip = 'Marietton\nReussite: '+str(sum_reussite)+'\nTotale: '+str(sum_totale)+'\nTaux: '+str(round(moyenne)) + ' %'
|
||||
d = ('MARIETTON', average, 'MidnightBlue','('+str(sum_reussite)+'/'+str(sum_totale)+')\xa0\xa0\xa0'+ str(average) + ' %', mar_tooltip)
|
||||
barChart_annee_3.append(d)
|
||||
|
||||
|
||||
# lire les résultats exmanes mois M-2
|
||||
items = get_charts_data(request, 'examens01', mois_2.strftime('%Y%m'))
|
||||
# construire la liste pour barChart
|
||||
barChart_annee_2 = []
|
||||
barChart_annee_2.append(('Mode', '%', {'role': 'style'}, {'role': 'annotation'}, {'type': 'string','role': 'tooltip'}))
|
||||
title_2 = ''
|
||||
average = 0
|
||||
sum_totale=0
|
||||
sum_reussite=0
|
||||
moyenne = 0
|
||||
for item in items:
|
||||
title_2 = item.group1_lib
|
||||
average = round(item.moyenne)
|
||||
valeur = round(item.valeur)
|
||||
moyenne = item.moyenne
|
||||
sum_totale = item.mar_totale
|
||||
sum_reussite = item.mar_reussite
|
||||
tooltip = 'Agence: '+item.group2_lib+'\nReussite: '+str(item.reussite)+'\nTotale: '+str(item.totale)+'\nTaux: '+str(round(item.valeur)) + ' %'
|
||||
# construire la liste pour barChart cible
|
||||
d = (item.group2_lib, valeur, getChartColor(valeur),'('+str(item.reussite)+'/'+str(item.totale)+')\xa0\xa0\xa0'+str(valeur) + ' %',tooltip)
|
||||
barChart_annee_2.append(d)
|
||||
# ajouter colonne MARIETTON
|
||||
mar_tooltip = 'Marietton\nReussite: '+str(sum_reussite)+'\nTotale: '+str(sum_totale)+'\nTaux: '+str(round(moyenne)) + ' %'
|
||||
d = ('MARIETTON', average, 'MidnightBlue','('+str(sum_reussite)+'/'+str(sum_totale)+')\xa0\xa0\xa0'+ str(average) + ' %', mar_tooltip)
|
||||
barChart_annee_2.append(d)
|
||||
|
||||
# lire les résultats exmanes mois M-
|
||||
items = get_charts_data(request, 'examens01', mois_1.strftime('%Y%m'))
|
||||
# construire la liste pour barChart
|
||||
barChart_annee_1 = []
|
||||
barChart_annee_1.append(('Mode', '%', {'role': 'style'}, {'role': 'annotation'}, {'type': 'string','role': 'tooltip'}))
|
||||
title_1 = ''
|
||||
average = 0
|
||||
sum_totale = 0
|
||||
sum_reussite = 0
|
||||
moyenne = 0
|
||||
for item in items:
|
||||
title_1 = item.group1_lib
|
||||
title_1h = str(round(item.moyenne))
|
||||
average = round(item.moyenne)
|
||||
valeur = (round(item.valeur))
|
||||
totale = item.totale
|
||||
reussite = item.reussite
|
||||
moyenne = item.moyenne
|
||||
sum_totale = item.mar_totale
|
||||
sum_reussite = item.mar_reussite
|
||||
tooltip = 'Agence: '+item.group2_lib+'\nReussite: ' + str(item.reussite)+'\nTotale: '+str(item.totale) + '\nTaux: '+str(round(item.valeur)) + ' %'
|
||||
# construire la liste pour barChart cible
|
||||
d = (item.group2_lib, valeur, getChartColor(valeur), '('+str(item.reussite)+'/'+str(item.totale)+')\xa0\xa0\xa0'+str(valeur) + ' %', tooltip)
|
||||
barChart_annee_1.append(d)
|
||||
mar_tooltip = 'Marietton\nReussite: '+str(sum_reussite)+'\nTotale: '+str(sum_totale)+'\nTaux: '+str(round(moyenne)) + ' %'
|
||||
d = ('MARIETTON', average, 'MidnightBlue','('+str(sum_reussite)+'/'+str(sum_totale)+')\xa0\xa0\xa0'+ str(average) + ' %', mar_tooltip)
|
||||
barChart_annee_1.append(d)
|
||||
# lire les résultats exmanes mois M
|
||||
items = get_charts_data(request, 'examens01', mois.strftime('%Y%m'))
|
||||
barChart_annee = []
|
||||
barChart_annee.append(('Mode', '%', {'role': 'style'}, {'role': 'annotation'}, {'type': 'string','role': 'tooltip'}))
|
||||
title = ''
|
||||
average = 0
|
||||
sum_totale = 0
|
||||
sum_reussite = 0
|
||||
moyenne = 0
|
||||
for item in items:
|
||||
title = item.group1_lib
|
||||
title_h = str(round(item.moyenne))
|
||||
average = round(item.moyenne)
|
||||
valeur = round(item.valeur)
|
||||
totale = item.totale
|
||||
reussite = item.reussite
|
||||
moyenne = item.moyenne
|
||||
sum_totale = item.mar_totale
|
||||
sum_reussite = item.mar_reussite
|
||||
tooltip = 'Agence: '+item.group2_lib+'\nReussite: ' + str(item.reussite)+'\nTotale: '+str(item.totale) + '\nTaux: '+str(round(item.valeur)) + ' %'
|
||||
# construire la liste pour barChart cible
|
||||
d = (item.group2_lib, valeur, getChartColor(valeur),'('+str(item.reussite)+'/'+str(item.totale)+')\xa0\xa0\xa0'+ str(valeur) + ' %', tooltip)
|
||||
barChart_annee.append(d)
|
||||
# ajouter colonne MARIETTON
|
||||
mar_tooltip = 'Marietton\nReussite: '+str(sum_reussite)+'\nTotale: '+str(sum_totale)+'\nTaux: '+str(round(moyenne)) + ' %'
|
||||
d = ('MARIETTON', average, 'MidnightBlue','('+str(sum_reussite)+'/'+str(sum_totale)+')\xa0\xa0\xa0'+ str(average) + ' %', mar_tooltip)
|
||||
barChart_annee.append(d)
|
||||
|
||||
return {
|
||||
'page_title': 'Bienvenue %s (Agence %s)' % (member.nom, member.agence),
|
||||
'logged_in': logged_in,
|
||||
'nlus': nlus,
|
||||
'bar_annee_3': json.dumps(barChart_annee_3),
|
||||
'bar_annee_2': json.dumps(barChart_annee_2),
|
||||
'bar_annee_1': json.dumps(barChart_annee_1),
|
||||
'bar_annee': json.dumps(barChart_annee),
|
||||
'title': title,
|
||||
'title_1': title_1,
|
||||
'title_2': title_2,
|
||||
'title_3': title_3,
|
||||
'access': member.secu,
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='login', renderer='../templates/default/login.pt', permission='view')
|
||||
@view_config(route_name='login_as', renderer='../templates/default/login.pt', permission='view')
|
||||
@view_config(route_name='login_from', renderer='../templates/default/login.pt', permission='view')
|
||||
@forbidden_view_config(renderer='../templates/default/login.pt')
|
||||
def login(request):
|
||||
device = ''
|
||||
login = ''
|
||||
current_route_path = request.current_route_path()
|
||||
if 'login_as' in current_route_path:
|
||||
# memoriser l'identifiant du user
|
||||
login = request.matchdict['login']
|
||||
login_url = request.route_url('login_as', login=login)
|
||||
elif 'login_from' in current_route_path:
|
||||
logged_in = request.authenticated_userid
|
||||
# if user is already logged in, go to home
|
||||
if logged_in is not None:
|
||||
return HTTPFound(location=request.route_url('home'))
|
||||
|
||||
# memoriser l'identifiant de la tablette
|
||||
device = request.matchdict['device']
|
||||
login_url = request.route_url('login_from', device=device)
|
||||
else:
|
||||
login_url = request.route_url('login')
|
||||
|
||||
referrer = request.url
|
||||
if referrer == login_url:
|
||||
referrer = '/' # never use the login form itself as came_from
|
||||
|
||||
came_from = request.params.get('came_from', referrer)
|
||||
|
||||
message = ''
|
||||
password = ''
|
||||
|
||||
if 'form.submitted' in request.params:
|
||||
login = request.params['login'].upper()
|
||||
password = request.params['password']
|
||||
record = get_users_by_code(request, login)
|
||||
if record:
|
||||
# controler que la fiche n'est pas cloturee
|
||||
if record.actif != 0:
|
||||
# On encode le password pour ne plus avoir de plantage avec les "é"
|
||||
if record.mdp_hash == to_sha1(password):
|
||||
# get user agent string from request
|
||||
ua_string = request.user_agent
|
||||
user_agent = parse(ua_string)
|
||||
update_last_connection(request, login, user_agent.device.family + ' / ' + device)
|
||||
# Update agence
|
||||
if 'agence' in request.params:
|
||||
agence = request.params['agence']
|
||||
update_user_agency(request,record.cd_uti,agence)
|
||||
|
||||
if 'login_from' in current_route_path:
|
||||
try:
|
||||
urlopen(
|
||||
'https://suivi-eleve.marietton.com/log_tablet.php?codeU=%s&device=%s' % (login, device),
|
||||
timeout=30)
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# force le commit car il ne se fait pas automatiquement après l'update
|
||||
transaction.commit()
|
||||
|
||||
headers = remember(request, login)
|
||||
return HTTPFound(location=came_from, headers=headers)
|
||||
else:
|
||||
message = "Le code utilisateur ou le mot de passe est incorrect. Identification échouée."
|
||||
else:
|
||||
message = "Votre code utilisateur a été désactivé. Accès refusé."
|
||||
else:
|
||||
message = "Le code utilisateur ou le mot de passe est incorrect. Identification échouée."
|
||||
|
||||
return {
|
||||
'page_title': "",
|
||||
'message': message,
|
||||
'url': login_url,
|
||||
'came_from': came_from,
|
||||
'login': login,
|
||||
'password': password,
|
||||
'device': device,
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='logout')
|
||||
def logout(request):
|
||||
headers = forget(request)
|
||||
request.session.flash("Vous avez bien été déconnecté.", 'success')
|
||||
return HTTPFound(location=request.route_url('login', login=''),
|
||||
headers=headers)
|
||||
|
||||
|
||||
@view_config(route_name='connecter_a', permission='manage')
|
||||
def connecter_a(request):
|
||||
# paramètre fourni ?
|
||||
login = request.matchdict["login"]
|
||||
if len(login) > 0:
|
||||
request.session.invalidate()
|
||||
headers = forget(request)
|
||||
headers = remember(request, login)
|
||||
return HTTPFound(location="/", headers=headers)
|
||||
else:
|
||||
return HTTPFound(location="/")
|
||||
|
||||
|
||||
@view_config(route_name='redefinir_mdp', renderer='..//templates/default/redefinir_mdp.pt')
|
||||
def redefinir_mdp(request):
|
||||
lien = request.matchdict["lien"]
|
||||
# tester si le champ "motdepasse_oublie" est encore valide
|
||||
if is_lien_mdp_oublie(request, lien) == True:
|
||||
membre = get_mdp_oublie_infos(request, lien)
|
||||
|
||||
if 'form.submitted' in request.params:
|
||||
mdp = request.params["new_password1"]
|
||||
update_password(request, membre.cd_uti, mdp)
|
||||
request.session.flash("Votre mot de passe a bien été mis à jour avec succès.", 'success')
|
||||
return HTTPFound(location=request.route_url('login'))
|
||||
else:
|
||||
return HTTPFound(location=request.route_url('login'))
|
||||
|
||||
return {
|
||||
'page_title': "Redéfinir le mot de passe",
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='change_agency', renderer='../templates/default/change_agency.pt', permission='view')
|
||||
def change_agency(request):
|
||||
cd_uti = request.authenticated_userid
|
||||
url = request.route_url('change_agency')
|
||||
message = ''
|
||||
agences = get_agences(request, 0)
|
||||
|
||||
# lire la fiche de l'individu
|
||||
individu = get_users_by_code(request, cd_uti)
|
||||
if not individu:
|
||||
request.session.flash("Utilisateur non trouvé : %s" % cd_uti, 'warning')
|
||||
return HTTPFound(location=request.route_url('home'))
|
||||
|
||||
if 'form.submitted' in request.params:
|
||||
agence = request.params["agence"]
|
||||
|
||||
update_user_agency(request, cd_uti, agence)
|
||||
request.session.flash("L'agence a été mise à jour avec succès.", 'success')
|
||||
return HTTPFound(location=request.route_url('home'))
|
||||
|
||||
return {
|
||||
'page_title': "Changement d'agence",
|
||||
'url': url,
|
||||
'individu': individu,
|
||||
'agences': agences,
|
||||
'message': message,
|
||||
}
|
||||
1471
aem_gestion/views/eleves.py
Normal file
1471
aem_gestion/views/eleves.py
Normal file
File diff suppressed because it is too large
Load Diff
437
aem_gestion/views/examens.py
Normal file
437
aem_gestion/views/examens.py
Normal file
@@ -0,0 +1,437 @@
|
||||
# -*- coding: utf8 -*-
|
||||
from pyramid.view import (
|
||||
view_config,
|
||||
)
|
||||
from pyramid.httpexceptions import (
|
||||
HTTPFound,
|
||||
)
|
||||
|
||||
from datetime import date, datetime
|
||||
from dateutil.relativedelta import *
|
||||
|
||||
from urllib.request import urlopen
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import imaplib
|
||||
import email
|
||||
|
||||
from ..models.examens import *
|
||||
from ..models.default import *
|
||||
|
||||
@view_config(route_name='examens_schd', renderer='../templates/examens/examens_schd.pt', permission='view')
|
||||
def examens_schd(request):
|
||||
|
||||
def generer_planning(datedeb, permis):
|
||||
rows = get_examens_byDate(request, datedeb, permis)
|
||||
|
||||
# construire la liste des events
|
||||
events = []
|
||||
for row in rows:
|
||||
# déterminer la couleur de l'event
|
||||
color = get_examens_aff_color(request, row)
|
||||
|
||||
debut = datetime.strptime('%s %s:%s:00' % (row.DATE.strftime('%Y-%m-%d'), row.HEURE.seconds//3600, (row.HEURE.seconds//60)%60),
|
||||
'%Y-%m-%d %H:%M:00')
|
||||
fin = debut + relativedelta(minutes = 60)
|
||||
agence = getAgenceLib(request, row.AGENCE)
|
||||
|
||||
json_event = {
|
||||
'title': '%s à %s' % (row.NO_EXA, row.LIEU),
|
||||
'start': debut.strftime('%Y-%m-%d %H:%M:00'),
|
||||
'end': fin.strftime('%Y-%m-%d %H:%M:00'),
|
||||
'description': '%s | %s' % (row.CD_MON, agence[7:]),
|
||||
'allDay': False,
|
||||
'color': color,
|
||||
'textColor': '#000000',
|
||||
'url': '/examen_list/%s/%s' % (row.DATE.strftime('%Y-%m-%d'), row.NO_EXA),
|
||||
}
|
||||
events.append(json_event)
|
||||
|
||||
return json.dumps(events)
|
||||
|
||||
# récupérer les paramètres de l'appel de la view
|
||||
datePlan = request.matchdict['date']
|
||||
permis = request.matchdict['permis']
|
||||
logged_in = request.authenticated_userid
|
||||
types_permis = ['ETG','B','2R','GL']
|
||||
|
||||
if datePlan == 'today':
|
||||
datePlan = date.today().strftime('%Y-%m-%d')
|
||||
|
||||
# si permis a été changé par le user
|
||||
if 'permis' in request.params:
|
||||
permis = request.params["permis"]
|
||||
|
||||
url = request.route_url('examens_schd', date=datePlan, permis=permis)
|
||||
|
||||
TODAY = date.today()
|
||||
# début = aujourd'hui - 4 semaines
|
||||
d = TODAY + relativedelta(weeks=-8)
|
||||
datedeb = d.strftime('%Y-%m-%d')
|
||||
|
||||
# generer le planning
|
||||
calendar_events = generer_planning(datedeb, permis)
|
||||
|
||||
|
||||
return {
|
||||
'page_title': "Examens %s" % permis,
|
||||
'url': url,
|
||||
'datePlan': datePlan,
|
||||
'permis': permis,
|
||||
'types_permis': types_permis,
|
||||
'calendar_events': calendar_events,
|
||||
}
|
||||
|
||||
@view_config(route_name='examen_list', renderer='../templates/examens/examen_list.pt', permission='view')
|
||||
def examen_list(request):
|
||||
date_exa = request.matchdict['date_exa']
|
||||
no_exa = request.matchdict['no_exa']
|
||||
# convertir date_exa en format date
|
||||
date = datetime.strptime(date_exa, '%Y-%m-%d')
|
||||
|
||||
# lire examen
|
||||
examen = get_examens(request, date_exa, no_exa)
|
||||
if examen:
|
||||
lieu_exa = examen.LIEU
|
||||
permis = examen.PERMIS
|
||||
accompgntr = examen.CD_MON
|
||||
dateheure = datetime.strptime('%s %s:%s:00' % (examen.DATE.strftime('%Y-%m-%d'), examen.HEURE.seconds//3600, (examen.HEURE.seconds//60)%60),
|
||||
'%Y-%m-%d %H:%M:00').strftime('%d-%m-%Y %H h')
|
||||
else:
|
||||
lieu_exa = 'Non trouvé'
|
||||
permis = ""
|
||||
accompgntr = ""
|
||||
dateheure = ""
|
||||
|
||||
# lire les inscrits dans examen
|
||||
items = get_examens_aff(request, date_exa, no_exa)
|
||||
|
||||
total_unites = 0
|
||||
# construire la liste
|
||||
liste=[]
|
||||
for item in items:
|
||||
# cumuler le total d'unité
|
||||
total_unites += item.UNITE
|
||||
|
||||
if item.TR_T_OK:
|
||||
ETG_OK = item.TR_T_OK.strftime('%d-%m-%Y')
|
||||
else:
|
||||
ETG_OK = ""
|
||||
|
||||
tel = ''
|
||||
if item.TEL:
|
||||
if len(item.TEL) > 0:
|
||||
tel += item.TEL + ' '
|
||||
if item.TEL2:
|
||||
if len(item.TEL2) > 0:
|
||||
tel += item.TEL2 + ' '
|
||||
if item.TEL3:
|
||||
if len(item.TEL3) > 0:
|
||||
tel += 'P:' + item.TEL3 + ' '
|
||||
if item.TEL4:
|
||||
if len(item.TEL4) > 0:
|
||||
tel += 'M:' + item.TEL4 + ' '
|
||||
|
||||
agence = getAgenceLib(request, item.AGENCE)
|
||||
d = (agence[7:10], '%s - %s' % ("%06d" % item.CD_CLI, item.NOM), item.NOM_JF, item.filiere, item.CD_MON, tel, ETG_OK,
|
||||
'%s - %s' % (item.INDICE, item.UNITE))
|
||||
liste.append(d)
|
||||
|
||||
return {
|
||||
'page_title': 'Examen N° %s du %s' % (no_exa, dateheure),
|
||||
'lieu_exa': lieu_exa,
|
||||
'permis': permis,
|
||||
'total_unites': total_unites,
|
||||
'accompgntr': accompgntr,
|
||||
'dt_data': json.dumps(liste),
|
||||
}
|
||||
|
||||
@view_config(route_name='results_import', renderer='../templates/examens/results_import.pt', permission='view')
|
||||
def results_import(request):
|
||||
|
||||
|
||||
def get_emails(lecture):
|
||||
# créer la liste des entêtes des messages
|
||||
liste = []
|
||||
# connecter au serveur de mail
|
||||
conn, data = mailbox_connect(request)
|
||||
if conn == None:
|
||||
request.session.flash("ERREUR de lecture de la boîte de réception", 'danger')
|
||||
return liste
|
||||
|
||||
mail_ids = data[0]
|
||||
for email_UID in mail_ids.split():
|
||||
rv, msg_data = conn.fetch(email_UID, '(RFC822)')
|
||||
if rv != 'OK':
|
||||
request.session.flash("ERREUR de lecture du message %s" % email_UID, 'danger')
|
||||
return liste
|
||||
|
||||
msg = email.message_from_bytes(msg_data[0][1])
|
||||
hdr = email.header.make_header(email.header.decode_header(msg['Subject']))
|
||||
email_subject = str(hdr)
|
||||
email_from = email.utils.parseaddr(msg['from'])[1]
|
||||
# Now convert to local date-time
|
||||
date_tuple = email.utils.parsedate_tz(msg['Date'])
|
||||
if date_tuple:
|
||||
email_date = datetime.fromtimestamp(email.utils.mktime_tz(date_tuple))
|
||||
else:
|
||||
email_date = datetime.now()
|
||||
|
||||
d = {
|
||||
"email_date": email_date,
|
||||
"email_from": email_from.split('@')[1],
|
||||
'email_subject':email_subject,
|
||||
"email_uid": email_UID
|
||||
}
|
||||
liste.append(d)
|
||||
|
||||
if lecture == 'first':
|
||||
break
|
||||
|
||||
# deconnexion du serveur
|
||||
conn.close()
|
||||
conn.logout()
|
||||
return liste
|
||||
|
||||
def analyser_email(body):
|
||||
neph = ""
|
||||
date_exa = ''
|
||||
resultat_exa = ''
|
||||
|
||||
# scan le body pour extraire les infos utiles
|
||||
body = body.decode('latin-1')
|
||||
# analyser la phrase suivante:
|
||||
# Le candidat n°210269100510 que vous avez présenté à l'examen pratique (BC) du 19/07/2021 a été ajourné.
|
||||
|
||||
# récupère le neph (12 car.)
|
||||
i = body.find('Le candidat n°')
|
||||
if i > 0:
|
||||
neph = body[i+14:i+26]
|
||||
|
||||
# récupère la date examen (10 car.)
|
||||
i = body.find('du ', i)
|
||||
if i > 0:
|
||||
date_exa = body[i+3:i+13]
|
||||
|
||||
# récupère le résultat
|
||||
if body.find("a été reçu") > 0:
|
||||
resultat_exa = 10 # "BON"
|
||||
resultat_lib = "BON"
|
||||
elif body.find("a été ajourné") > 0:
|
||||
resultat_exa = 1 # "ECHEC"
|
||||
resultat_lib = "ECHEC"
|
||||
else:
|
||||
resultat_exa = 7 # "ABS"
|
||||
resultat_lib = "ABS. EXCUSEE"
|
||||
|
||||
return neph, date_exa, resultat_exa, resultat_lib
|
||||
|
||||
def import_email(request, email_uid):
|
||||
# importer le résulat dans la BD
|
||||
# retour :
|
||||
# - "completed" : importation réussi
|
||||
# - "not_found" : éléve non trouvé
|
||||
# - "error" : erreur détectée
|
||||
|
||||
# connecter au serveur de mail
|
||||
conn, data = mailbox_connect(request)
|
||||
if conn == None:
|
||||
request.session.flash("ERREUR de lecture de la boîte de réception", 'danger')
|
||||
return "error"
|
||||
|
||||
# lire le message avec UID
|
||||
rv, msg_data = conn.fetch(email_uid, '(RFC822)')
|
||||
if rv != 'OK':
|
||||
request.session.flash("ERREUR de lecture du message %S" % (email_uid), 'danger')
|
||||
return "error"
|
||||
|
||||
email_message = email.message_from_bytes(msg_data[0][1])
|
||||
# get the message's body
|
||||
body = ''
|
||||
for part in email_message.walk():
|
||||
ctype = part.get_content_type()
|
||||
cdispo = str(part.get('Content-Disposition'))
|
||||
|
||||
# skip any text/plain (txt) attachments
|
||||
if ctype == 'text/plain' and 'attachment' not in cdispo:
|
||||
body = part.get_payload(decode=True) # decode
|
||||
break
|
||||
|
||||
# Analyser le message pour récupérer les infos utiles
|
||||
neph, date_exa, resultat_exa, resultat_lib = analyser_email(body)
|
||||
|
||||
# convertir la date en 'yyyy/mm/dd'
|
||||
dateexa = datetime.strptime(date_exa, '%d/%m/%Y')
|
||||
dateexa = dateexa.strftime('%Y-%m-%d')
|
||||
if neph != '':
|
||||
# éléve trouvé ?
|
||||
eleve = get_eleves_by_neph(request, neph)
|
||||
if eleve:
|
||||
update_resultat(request, eleve.CD_CLI, dateexa, resultat_exa, logged_in)
|
||||
try:
|
||||
# envoyer un message interne au moniteur référent s'il
|
||||
if len(eleve.CD_MON) > 0:
|
||||
urlopen('https://Suivi-eleve.marietton.com/MSG-fromAEM.php?codeE=%s&type=cepcOK&date=%s&dest=%s&resultat=%s'
|
||||
% (eleve.CD_CLI, dateexa, eleve.CD_MON, resultat_lib),timeout=30 )
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
request.session.flash("NEPH %s non trouvé dans la BD, impossible d'importer l'examen" % neph, 'danger')
|
||||
return "not_found"
|
||||
|
||||
# downloading attachment
|
||||
temp_file_path = download_pdf_to_tmp(email_message)
|
||||
if temp_file_path != '':
|
||||
# si attachement existe, verifier qu'il n'est pas déjà importé
|
||||
next_code = get_next_cepc(request, eleve.CD_CLI, dateexa)
|
||||
if len(next_code) > 0:
|
||||
# fabriquer le nom du document
|
||||
filename = '%s_%s_%s_%s.PDF' % (eleve.CD_CLI, 'DOC', next_code, dateexa)
|
||||
# l'insérer dans la fiche élève
|
||||
cepcFile2Dossier(request, eleve.CD_CLI, temp_file_path, filename, next_code, logged_in)
|
||||
|
||||
# déplacer le message dans la corbeille
|
||||
conn.store(email_uid, '+FLAGS', '\\Deleted')
|
||||
|
||||
conn.expunge()
|
||||
conn.close()
|
||||
# deconnexion du serveur
|
||||
conn.logout()
|
||||
|
||||
return "completed"
|
||||
|
||||
|
||||
# ------- main -------
|
||||
logged_in = request.authenticated_userid.upper()
|
||||
url = request.route_url('results_import')
|
||||
message = ''
|
||||
|
||||
# -- importer les emails
|
||||
if 'form.import' in request.params:
|
||||
nbTraite = 0
|
||||
|
||||
for i in range(100):
|
||||
# lire le premier email des résultats pratique
|
||||
message = get_emails('first')
|
||||
if message:
|
||||
nbTraite += 1
|
||||
res = import_email(request, message[0]['email_uid'])
|
||||
if res == "not_found":
|
||||
# si élève non trouvé, arrêter l'import
|
||||
break
|
||||
else:
|
||||
# si plus d'email, arrêter
|
||||
break
|
||||
# message de fin
|
||||
request.session.flash("%s Résultat(s) mis à jour avec succès." % str(nbTraite), 'success')
|
||||
|
||||
# lister les messages reçus
|
||||
emails = []
|
||||
# emails = emails + get_emails('objectif_code', 'all')
|
||||
emails = emails + get_emails('all')
|
||||
|
||||
# ister les résultats mis à jour
|
||||
examens_maj = get_examens_maj(request, logged_in)
|
||||
|
||||
return {
|
||||
'page_title': "Liste des emails de résultats d'examen",
|
||||
'url': url,
|
||||
'emails': emails,
|
||||
'examens_maj': examens_maj,
|
||||
}
|
||||
|
||||
def download_pdf_to_tmp(email_message):
|
||||
|
||||
# import pdb;pdb.set_trace()
|
||||
temp_file_path = ''
|
||||
# downloading attachments
|
||||
for part in email_message.walk():
|
||||
# this part comes from the snipped I don't understand yet...
|
||||
if part.get_content_maintype() == 'multipart':
|
||||
continue
|
||||
if part.get('Content-Disposition') is None:
|
||||
continue
|
||||
fileName = part.get_filename()
|
||||
if bool(fileName):
|
||||
# copier le fichier PDF dans le dossier /tmp
|
||||
temp_file_path = os.path.join('/tmp/', fileName)
|
||||
# if not os.path.isfile(temp_file_path) :
|
||||
fp = open(temp_file_path, 'wb')
|
||||
fp.write(part.get_payload(decode=True))
|
||||
fp.close()
|
||||
|
||||
return temp_file_path
|
||||
|
||||
def cepcFile2Dossier(request, cd_cli, temp_file, filename, next_code, logged_in):
|
||||
# créer le répertoire de eleve
|
||||
path = '%s/%s' % (request.registry.settings['aem_gestion.justifs_dir'], cd_cli)
|
||||
os.makedirs(path, exist_ok=True)
|
||||
|
||||
filepath = os.path.join('%s/%s' % (path, filename))
|
||||
# Finally move the temporary file to folder
|
||||
shutil.move(temp_file, filepath)
|
||||
|
||||
filesize = round(os.path.getsize(filepath) / 1024)
|
||||
insert_eleve_cepc(request, cd_cli, next_code, filename, filesize, logged_in)
|
||||
|
||||
@view_config(route_name='result_del', renderer='../templates/examens/result_del.pt', permission='view')
|
||||
def result_del(request):
|
||||
email_uid = request.matchdict['email_uid']
|
||||
url = request.route_url('result_del',email_uid=email_uid)
|
||||
|
||||
message = ""
|
||||
|
||||
if 'form.submitted' in request.params:
|
||||
# connecter au serveur de mail
|
||||
conn, data = mailbox_connect(request)
|
||||
|
||||
# déplacer le message dans la corbeille
|
||||
conn.store(email_uid, '+FLAGS', '\\Deleted')
|
||||
|
||||
# deconnexion du serveur
|
||||
conn.close()
|
||||
conn.logout()
|
||||
|
||||
request.session.flash("Le message %s a été supprimée avec succès." % email_uid, 'success')
|
||||
return HTTPFound(location=request.route_url('results_import'))
|
||||
|
||||
return {
|
||||
'page_title': "Supprimer le message %s" % email_uid,
|
||||
'url': url,
|
||||
'message': message,
|
||||
}
|
||||
|
||||
def mailbox_connect(request):
|
||||
# Cette fonction effectue :
|
||||
# 1. la connexion au serveur de mail
|
||||
# 2. la lecture des messages de INBOX
|
||||
# puis retourne 2 résultats :
|
||||
# - conn : la connexion ou None si erreur rencontré
|
||||
# - data : la liste UID des messages
|
||||
|
||||
# connecter au serveur IMAP
|
||||
mbx_name = 'resultats-examens@marietton.com'
|
||||
mbx_pwd = '9KmKPn36a'
|
||||
conn = imaplib.IMAP4_SSL('SSL0.OVH.NET', 993)
|
||||
#mbx_name = 'phuoc@caotek.fr'
|
||||
#mbx_pwd = 'pcao.8211'
|
||||
#conn = imaplib.IMAP4_SSL('imap.gmail.com')
|
||||
|
||||
try:
|
||||
# se connecter à la mailbox
|
||||
conn.login(mbx_name, mbx_pwd)
|
||||
except imaplib.IMAP4.error:
|
||||
request.session.flash("ERREUR d'authentification à %s" % mbx_name, 'danger')
|
||||
return None, None
|
||||
|
||||
# select INBOX
|
||||
conn.select('INBOX')
|
||||
criteria = 'SUBJECT "des examens du permis de conduire" UNDELETED'
|
||||
rv, data = conn.search(None, criteria)
|
||||
if rv != 'OK':
|
||||
request.session.flash("ERREUR de lecture de la boîte de réception", 'danger')
|
||||
return None, None
|
||||
|
||||
return conn, data
|
||||
|
||||
9
aem_gestion/views/notfound.py
Normal file
9
aem_gestion/views/notfound.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# -*- coding: utf8 -*-
|
||||
from pyramid.view import notfound_view_config
|
||||
|
||||
@notfound_view_config(renderer='../templates/default/404.pt')
|
||||
def notfound_view(request):
|
||||
request.response.status = 404
|
||||
return {
|
||||
'page_title': 'Oups!',
|
||||
}
|
||||
1772
aem_gestion/views/parametres.py
Normal file
1772
aem_gestion/views/parametres.py
Normal file
File diff suppressed because it is too large
Load Diff
2980
aem_gestion/views/planning.py
Normal file
2980
aem_gestion/views/planning.py
Normal file
File diff suppressed because it is too large
Load Diff
414
aem_gestion/views/utils.py
Normal file
414
aem_gestion/views/utils.py
Normal file
@@ -0,0 +1,414 @@
|
||||
# -*- coding: utf8 -*-
|
||||
import json
|
||||
import os
|
||||
from pyramid.response import Response
|
||||
from pyramid.view import (
|
||||
view_config,
|
||||
)
|
||||
|
||||
from pyramid_mailer import get_mailer
|
||||
from pyramid_mailer.message import Message
|
||||
import requests
|
||||
from time import sleep
|
||||
from datetime import datetime as dt
|
||||
|
||||
from ..models.utils import *
|
||||
from ..models.default import *
|
||||
|
||||
@view_config(route_name='batch_nuit')
|
||||
def batch_nuit(request):
|
||||
"""
|
||||
Ce traitement est lancé chaque nuit, sur le serveur du site web, par une tâche planifiée :
|
||||
- Executer en tant que : root
|
||||
- Commande : wget http://localhost:6544/batch_nuit/JonSn0w
|
||||
- Quand executer : à 02:00 chaque jour
|
||||
|
||||
Par sécurité, ce view ne peut être appelé qu'avec un paramètre secret 'JonSn0w'
|
||||
|
||||
"""
|
||||
# contrôle : paramètre correct ? non, terminer
|
||||
par = request.matchdict['param']
|
||||
if par != 'JonSn0w':
|
||||
return Response('Erreur : paramètre incorrect')
|
||||
|
||||
# ----- effacer le log
|
||||
truncate_log(request)
|
||||
# ----- Début TRAITEMENT DE NUIT
|
||||
insert_log(request, '****','- Début TRAITEMENT DE NUIT')
|
||||
|
||||
# ----- LETTRAGE AUTOMATIQUE
|
||||
insert_log(request, 'LETTRAGE','- Début LETTRAGE AUTO')
|
||||
nbLus = lettrage_auto(request)
|
||||
insert_log(request, 'LETTRAGE','- Fin LETTRAGE : ' + str(nbLus) + ' élèves lus')
|
||||
|
||||
# ----- MAJ des statistiques examens
|
||||
insert_log(request, 'STATS','- Début Mise à jour des STATS EXAMENS')
|
||||
update_statistiques(request)
|
||||
# ----- PURGE des données obsolètes
|
||||
insert_log(request, 'PURGE','- Début PURGE DES DONNEES OBSOLETES')
|
||||
purge_obsoletes(request)
|
||||
|
||||
# ----- CONFIRMATION DES RESERVATIONS HEURES
|
||||
TODAY = date.today()
|
||||
if TODAY.weekday() == 0 :
|
||||
# ===== si lundi, pas de confirmation des RESA ===================
|
||||
insert_log(request, 'RESA', '- Pas de CONFIRMATION des RESA le LUNDI')
|
||||
else:
|
||||
insert_log(request, 'RESA', '- Début CONFIRMATION des RESA HEURES')
|
||||
confirm_reservations(request)
|
||||
|
||||
|
||||
# ----- RAPPELS DES RENDEZ-VOUS
|
||||
update_rappels(request)
|
||||
# attendre 5 secondes
|
||||
sleep(5)
|
||||
|
||||
# log : Début ENVOI emails RESA
|
||||
insert_log(request, 'RESA','- Début ENVOI emails')
|
||||
# ----- lancer les notifications
|
||||
nbLus, nbConfirmes, nbAnnules = notifier_reservations(request, 'HEURES')
|
||||
# log : fin ENVOI emails RESA
|
||||
insert_log(request, 'RESA', "- Fin ENVOI emails : %s résa lus, %s confirmées, %s annulées." % (str(nbLus), str(nbConfirmes), str(nbAnnules)))
|
||||
|
||||
insert_log(request, '****', '- Fin TRAITEMENT DE NUIT')
|
||||
# ----- ENVOI RAPPORTS di traitement
|
||||
email_rapport(request)
|
||||
|
||||
return Response('Batch nuit terminé OK')
|
||||
|
||||
def notifier_rappels(request):
|
||||
|
||||
# log : Début ENVOI emails
|
||||
insert_log(request, 'RAPPELS','- Début ENVOI emails')
|
||||
|
||||
# lire les rappels non encore envoyés
|
||||
rappels = get_email_rappels(request)
|
||||
|
||||
nbLus = 0
|
||||
nbLecons = 0
|
||||
nbExamens = 0
|
||||
|
||||
for item in rappels:
|
||||
nbLus += 1
|
||||
# RDV ayant une heure (HCB) or(HCB78) ?
|
||||
if item.rdv_date.hour > 0 :
|
||||
date_heure = item.rdv_date.strftime('%d/%m/%Y - %H:%M')
|
||||
else:
|
||||
# RDV ayant une heure
|
||||
date_heure = item.rdv_date.strftime('%d/%m/%Y')
|
||||
|
||||
# si examen 2R, notifier from Vaugneray sinon from agence de l'élève
|
||||
if item.ref == "EPA" :
|
||||
noAgence = 6
|
||||
else:
|
||||
noAgence = item.agence
|
||||
|
||||
szBody = get_msg_body(request, item, date_heure)
|
||||
destinataires = [item.email]
|
||||
if item.payeur_email:
|
||||
destinataires.append(item.payeur_email)
|
||||
|
||||
reponse = email_notification(request, "RAPPEL : rendez-vous le " + date_heure, szBody, destinataires, noAgence)
|
||||
if reponse == 0:
|
||||
# marquer le rdv comme envoyé ou traité
|
||||
update_email_rappels(request, item.no_id)
|
||||
|
||||
# rappels pour examens ?
|
||||
if item.ref in ['EPA', 'EPB', 'EPC', 'ECHECT'] :
|
||||
nbExamens += 1
|
||||
else:
|
||||
nbLecons += 1
|
||||
|
||||
if nbLus == 150:
|
||||
# si quota atteint, arrêter les emails
|
||||
insert_log(request, 'RAPPELS', "- Fin ENVOI emails : %s rdv lus, %s rappels leçons, %s rppels examens." % (str(nbLus), str(nbLecons), str(nbExamens)))
|
||||
return
|
||||
else:
|
||||
# sinon on continue après une pause de 3 secondes, envoi de 15 emails par minute
|
||||
sleep(3)
|
||||
|
||||
insert_log(request, 'RAPPELS', "- Fin ENVOI emails : %s rdv lus, %s rappels leçons, %s rppels examens." % (str(nbLus), str(nbLecons), str(nbExamens)))
|
||||
return
|
||||
|
||||
def email_notification(request, objet, corps, destinataires, code):
|
||||
# lire l'agence
|
||||
agence = get_agences(request, code)
|
||||
if agence:
|
||||
expediteur = agence.email
|
||||
else:
|
||||
expediteur = "circuit@marietton.com"
|
||||
|
||||
# si annulation de résa, CC à l'agence de l'élève
|
||||
if objet.find(' ANNULEE, ') > 0:
|
||||
destinataires.append(expediteur)
|
||||
|
||||
reponse = 0
|
||||
reponse = send_mail(request, expediteur, destinataires, objet, corps)
|
||||
|
||||
return reponse
|
||||
|
||||
def email_rapport(request):
|
||||
NOW = dt.now()
|
||||
corps = "<html><body><p>=============================================</p>"
|
||||
corps += "<p>Rapport du traitement de nuit du " + NOW.strftime('%d/%m/%Y - %H:%M') + "</p>"
|
||||
corps += "<p>=============================================</p><p></p><p>"
|
||||
|
||||
# Lire le fichier log
|
||||
items = get_log(request)
|
||||
for item in items:
|
||||
corps += " - " + item.date.strftime('%d/%m/%Y - %H:%M') + " - " + item.proc + " : " + item.msg + "<br />"
|
||||
|
||||
corps += "</p><p></p><p>=============================================</p><p></p>"
|
||||
|
||||
expediteur = request.registry.settings['aem_gestion.admin_email']
|
||||
destinataire = ["francois.varnier@groovelsoftware.com","comptabilite@marietton.com"]
|
||||
send_mail(request, expediteur, destinataire, "Rapport des traitements de nuit", corps)
|
||||
|
||||
return
|
||||
|
||||
|
||||
def send_mail(request, expediteur, destinataires, objet, corps):
|
||||
body = """
|
||||
|
||||
%s
|
||||
""" % (corps)
|
||||
|
||||
message = Message(subject=objet,
|
||||
sender=expediteur,
|
||||
recipients=destinataires,
|
||||
html=body)
|
||||
mailer = get_mailer(request)
|
||||
# import pdb;pdb.set_trace()
|
||||
msg = ''
|
||||
try:
|
||||
mailer.send_immediately(message)
|
||||
|
||||
except Exception as e:
|
||||
# Just print(e) is cleaner and more likely what you want,
|
||||
# but if you insist on printing message specifically whenever possible...
|
||||
if hasattr(e, 'message'):
|
||||
msg = e.message
|
||||
else:
|
||||
msg = e
|
||||
# logguer l'erreur
|
||||
insert_log(request, 'MAILER', "- ERROR : %s, TO : %s" % (msg[0:512], destinataires))
|
||||
|
||||
return len(str(msg))
|
||||
|
||||
def get_msg_body(request, rappel, date_heure):
|
||||
|
||||
szLieu = rappel.rdv_lieu
|
||||
if szLieu.find("GORGE DE LOUP") > 0:
|
||||
szLieu = szLieu + " (<a href=""https://monespace.marietton.com/faq_view/2771""><b>Navette pour Vaugneray</b></a>)"
|
||||
|
||||
# lire le message selon la référence du tarif
|
||||
message = get_message(request, rappel.ref)
|
||||
if message:
|
||||
szBody = message.rappel_html
|
||||
else:
|
||||
szBody = "<blockquote>Rappel de rendez-vous " + rappel.ref + "</blockquote>"
|
||||
|
||||
# remplacer les mots clés
|
||||
szBody = szBody.replace("!civNomPrenom!", rappel.nompren)
|
||||
szBody = szBody.replace("!codeClient!", str(rappel.cd_cli))
|
||||
szBody = szBody.replace("!dateRDV!", date_heure)
|
||||
szBody = szBody.replace("!lieuRDV!", szLieu)
|
||||
if rappel.rdv_statut:
|
||||
szBody = szBody.replace("!statutRDV!", rappel.rdv_statut)
|
||||
|
||||
return szBody
|
||||
|
||||
def notifier_reservations(request, type_resa):
|
||||
|
||||
# lire les rappels non encore envoyés
|
||||
rappels = get_email_resa(request, type_resa)
|
||||
|
||||
nbLus = 0
|
||||
nbConfirmes = 0
|
||||
nbAnnules = 0
|
||||
|
||||
for item in rappels:
|
||||
# import pdb;pdb.set_trace()
|
||||
nbLus += 1
|
||||
# Résa ayant une heure (HCB) ?
|
||||
if item.resa_date.hour > 0 :
|
||||
date_heure = item.resa_date.strftime('%d/%m/%Y - %H:%M')
|
||||
else:
|
||||
date_heure = item.resa_date.strftime('%d/%m/%Y')
|
||||
|
||||
noAgence = item.agence
|
||||
if item.resa_statut == "CONFIRMEE" :
|
||||
nbConfirmes += 1
|
||||
confirm = "CONFIRMEE"
|
||||
else:
|
||||
nbAnnules += 1
|
||||
confirm = "ANNULEE, faute de crédit suffisant"
|
||||
if item.ref == "HCA3" or item.resa_type == "Inscr.":
|
||||
# envoyer CC à l'agence Vaugneray
|
||||
noAgence = 6
|
||||
|
||||
# selon le type de résa, préparer le message
|
||||
if item.resa_type == "Inscr.":
|
||||
# résa de stage effectuée sur le WEB
|
||||
message = "<p>Nous vous informons que votre inscription au stage %s du %s a été %s.</p>" % (item.ref, date_heure, confirm)
|
||||
elif item.resa_type == "WEB_48H.":
|
||||
# heure annulée en moins 48 heures sur le WEB remplacée
|
||||
message = "<p>Nous vous informons que l'annulation de votre leçon de %s du %s ne vous sera pas débitée " + \
|
||||
"car nous avons pu vous trouver un remplaçant.</p>" % (item.ref, date_heure)
|
||||
elif item.resa_type in ["WEB_A", "WEB_B"] :
|
||||
# résa d'heure A ou B effectuée sur le WEB
|
||||
message = "<p>Nous vous informons que votre inscription au stage %s du %s a été %s.</p>" % (item.ref, date_heure, confirm)
|
||||
else:
|
||||
# résa d'heure A ou B effectuée en agence
|
||||
message = "<p>Nous vous informons qu'une réservation de leçon a été <b>" + confirm + "</b>.</p>"
|
||||
|
||||
szBody = "<html><body><p>Bonjour " + item.nompren + ",</p>" + message + \
|
||||
"<p>Merci de consulter votre carnet de rendez-vous remis à jour sur votre espace : " + \
|
||||
"<a href=""http://monespace.marietton.com"">monespace.marietton.com</a></p>" + \
|
||||
"<p>Nous vous rappelons votre code élève pour vous connecter : <b>" + str(item.cd_cli) + "</b></p>" + \
|
||||
"<p>Veuillez agréer nos sincères salutations.</p>" + \
|
||||
"<p>Votre équipe Marietton</p></body></html>"
|
||||
destinataires = [item.email]
|
||||
if len(item.payeur_email) > 0:
|
||||
destinataires.append(item.payeur_email)
|
||||
|
||||
# import pdb;pdb.set_trace()
|
||||
email_notification(request, "Réservation de leçon " + confirm, szBody, destinataires, noAgence)
|
||||
# attendre 6 secondes, envoi de 10 emails par minute
|
||||
sleep(6)
|
||||
|
||||
# marquer le rdv comme envoyé ou traité
|
||||
update_email_resa(request, item.no_id)
|
||||
|
||||
# si résa WEB, logguer la confirmation
|
||||
if type_resa == 'INSCR':
|
||||
insert_log(request, item.resa_type, "%s -> %s : %s - %s" % (item.resa_type, confirm, str(item.cd_cli), item.nompren))
|
||||
|
||||
return nbLus, nbConfirmes, nbAnnules
|
||||
|
||||
|
||||
def confirm_reservations(request):
|
||||
"""
|
||||
- LIRE LES RESA des PLANNINGS B et A
|
||||
- REMPLIR la table EMAILS_RESA
|
||||
|
||||
"""
|
||||
|
||||
TODAY = date.today()
|
||||
|
||||
# LIRE LES RESA des PLANNINGS B et A
|
||||
resas = get_reservations(request)
|
||||
for resa in resas:
|
||||
# --------------- PLANNING B et B78
|
||||
if resa.ref == "HCB" or resa.ref == "HCB78":
|
||||
# date de la leçon antérieur à aujourd'hui, confirmer de suite
|
||||
if TODAY > resa.date :
|
||||
# confimer la résa
|
||||
update_planning_B_confirm(request, 'C', resa.no_ligne, resa.cd_cli)
|
||||
else:
|
||||
# controler le solde REEL de l'élève et le total des resa
|
||||
eleve = get_solde_eleve(request, resa.cd_cli, resa.ref)
|
||||
if eleve.solde + eleve.total_resa >= resa.debit :
|
||||
# confirmer le rdv
|
||||
update_planning_B_confirm(request, 'C', resa.no_ligne, resa.cd_cli)
|
||||
# creer une notification de confirmation
|
||||
insert_email_resa(request, resa.ref, resa.cd_cli, "d'heure "+resa.ref[2:], resa.date, resa.noplan, "CONFIRMEE")
|
||||
else:
|
||||
# date de fin de résa atteinte ?
|
||||
if TODAY > resa.fin_reservation :
|
||||
# annuler la résa
|
||||
update_planning_B_confirm(request, 'A', resa.no_ligne, resa.cd_cli)
|
||||
# creer une notification de annulation
|
||||
insert_email_resa(request, resa.ref, resa.cd_cli, "d'heure "+resa.ref[2:], resa.date, resa.noplan, "ANNULEE")
|
||||
|
||||
# ------------ HEURES PLANNING A
|
||||
elif resa.ref in ["TA", "TB","HCA3", "HCA4"] :
|
||||
# date de la leçon antérieure à aujourd'hui ? Oui, confirmer de suite
|
||||
if TODAY > resa.date :
|
||||
# confirmer le rdv
|
||||
update_planning_A_confirm(request, "C", resa.no_ligne, resa.cd_cli)
|
||||
else:
|
||||
# controler le solde REEL de l'élève
|
||||
eleve = get_solde_eleve(request, resa.cd_cli, resa.ref)
|
||||
if eleve.solde + eleve.total_resa >= resa.debit :
|
||||
# confirmer le rdv
|
||||
update_planning_A_confirm(request, "C", resa.no_ligne, resa.cd_cli)
|
||||
# creer une notification de confirmation
|
||||
insert_email_resa(request, resa.ref, resa.cd_cli, "Moto", resa.date, 0, "CONFIRMEE")
|
||||
else:
|
||||
# date de fin de résa atteinte ?
|
||||
if TODAY > resa.fin_reservation :
|
||||
# annuler la résa
|
||||
update_planning_A_confirm(request, 'A', resa.no_ligne, resa.cd_cli)
|
||||
# creer une notification de annulation
|
||||
insert_email_resa(request, resa.ref, resa.cd_cli, "Moto", resa.date, 0, "ANNULEE")
|
||||
|
||||
@view_config(route_name='batch_email')
|
||||
def batch_email(request):
|
||||
"""
|
||||
Ce traitement est lancé chaque nuit, sur le serveur du site web, par une tâche planifiée :
|
||||
- Executer en tant que : root
|
||||
- Commande : wget http://localhost:6544/batch_email/JonSn0w
|
||||
- Quand executer : chaque jour, à 03:00 et 04:30
|
||||
Par sécurité, ce view ne peut être appelé qu'avec un paramètre secret 'JonSn0w'
|
||||
|
||||
A cause du quota d'envoi limité à 200 emails par heure imposé par OVH,
|
||||
ce traitement envoie les notifications par email par lot de 150 emails.
|
||||
Il sera lancé 2 fois par nuit, chaque fois espacé de 1h30
|
||||
|
||||
"""
|
||||
# contrôle : paramètre correct ? non, terminer
|
||||
par = request.matchdict['param']
|
||||
if par != 'JonSn0w':
|
||||
return Response('Erreur : paramètre incorrect')
|
||||
|
||||
# ----- envoyer les rappels
|
||||
notifier_rappels(request)
|
||||
|
||||
@view_config(route_name='batch_test')
|
||||
def batch_test(request):
|
||||
"""
|
||||
Ce traitement sert à tester une fonction particulière du batch de nuit ou de jour :
|
||||
- Commande : http://localhost:6544/batch_test/JonSn0w
|
||||
|
||||
Par sécurité, ce view ne peut être appelé qu'avec un paramètre secret 'JonSn0w'
|
||||
|
||||
"""
|
||||
# contrôle : paramètre correct ? non, terminer
|
||||
par = request.matchdict['param']
|
||||
if par != 'JonSn0w':
|
||||
return Response('Erreur : paramètre incorrect')
|
||||
|
||||
# ----- CONFIRMATION DES RESERVATIONS HEURES
|
||||
confirm_reservations(request)
|
||||
|
||||
|
||||
@view_config(route_name='batch_justif')
|
||||
def batch_justif(request):
|
||||
"""
|
||||
Ce traitement sert à tester une fonction particulière du batch de nuit ou de jour :
|
||||
- Commande : http://localhost:6544/batch_justif/JonSn0w
|
||||
|
||||
Par sécurité, ce view ne peut être appelé qu'avec un paramètre secret 'JonSn0w'
|
||||
|
||||
"""
|
||||
# contrôle : paramètre correct ? non, terminer
|
||||
par = request.matchdict['param']
|
||||
if par != 'JonSn0w':
|
||||
return Response('Erreur : paramètre incorrect')
|
||||
|
||||
all_justifs = get_justify_not_found(request, datetime.strptime('2021-09-01', '%Y-%m-%d'))
|
||||
base_folder = str(request.registry.settings['aem_gestion.justifs_dir'])
|
||||
data_not_found = {}
|
||||
for justif in all_justifs:
|
||||
try:
|
||||
justif_path = os.path.join(base_folder, str(justif.cd_cli), str(justif.nom_fic))
|
||||
if not os.path.isfile(justif_path):
|
||||
# update_justify_not_found(request,justif.no_ligne)
|
||||
insert_log(request, 'justif_CKECK', str(justif.no_ligne) + '->' + justif_path)
|
||||
data_not_found[str(justif.no_ligne)] = justif_path
|
||||
except Exception as e:
|
||||
pass
|
||||
return Response(json.dumps(data_not_found))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user