initial upload

This commit is contained in:
2023-06-22 10:26:17 +02:00
parent 14dc417203
commit 11304c5b8a
306 changed files with 83527 additions and 49 deletions

0
monaem/views/__init__.py Normal file
View File

1148
monaem/views/default.py Normal file

File diff suppressed because it is too large Load Diff

1161
monaem/views/inscriptions.py Normal file

File diff suppressed because it is too large Load Diff

9
monaem/views/notfound.py Normal file
View File

@@ -0,0 +1,9 @@
# -*- coding: utf8 -*-
from pyramid.view import notfound_view_config
@notfound_view_config(renderer='../templates/404.pt')
def notfound_view(request):
request.response.status = 404
return {
'page_title': 'Oups!',
}

274
monaem/views/reglement.py Normal file
View File

@@ -0,0 +1,274 @@
# -*- coding: utf8 -*-
from pyramid.response import Response
from pyramid.renderers import render, get_renderer
from pyramid.view import (
view_config,
)
from pyramid.httpexceptions import (
HTTPFound,
)
from datetime import *
from dateutil.relativedelta import relativedelta
from time import strftime
import math
import hashlib
import binascii
import hmac
from ..models.default import *
from ..models.reglement import *
from ..views.default import (
to_decimal,
)
def hash_hmac(request, msg):
# lire la clé HMAC donné par PAYBOX et stocké dans agence 6
agence6 = get_agences(request, 6)
hmac_key = agence6.hmac_key
# Transformer la key en binaire
binary_key = binascii.unhexlify(hmac_key.encode('utf-8'))
# hasher le msg avec la key binaire
res = hmac.new(binary_key, msg.encode('utf-8'), hashlib.sha512).hexdigest()
return res.upper()
# - - - - - - - - - - - - - - - - - - - - - - - - - -
@view_config(route_name='crediter', renderer='../templates/reglement/crediter.pt')
def crediter(request):
url = request.route_url('crediter')
logged_in = request.authenticated_userid
eleve_info = get_eleve_info(request, logged_in)
message = ""
# lire les articles possibles selon le permise demandé ?
items = get_tarifs(request, eleve_info['permis'])
qtes = []
for item in items :
qtes.append('0')
mttotal = 0
if 'form.submitted' in request.params or 'regler.submitted' in request.params:
# calculer le montant total
qtes = []
for item in items :
# récupère la qté saisie pour la REF
qte = int(request.params[item.REF])
qtes.append(str(qte))
mttotal += item.PUTTC * qte
if 'regler.submitted' in request.params:
# case CGV cocher ?
if 'cb_cgv' not in request.params:
request.session.flash(u"Veuillez accepter les Conditions Générales de Vente pour continuer.", 'danger')
else:
return HTTPFound(location=request.route_url('reglement', ref='CRE', mttotal=mttotal, nfois='1'))
return {
'page_title': "Créditer mon compte",
'url': url,
'message': message,
'items': items,
'qtes': qtes,
'mttotal': mttotal,
}
@view_config(route_name='reglement', renderer='../templates/reglement/reglement.pt', permission='view')
def reglement(request):
def get_cb_maxdate(nfois):
today = date.today()
cb_maxdate = today + relativedelta(months=+int(nfois)-1)
return cb_maxdate.strftime('%y%m') # format AAMM
def get_schedule_dates():
today = date.today()
second_reglement = today + relativedelta(months=+1)
third_reglement = today + relativedelta(months=+2)
return [today.strftime('%d/%m/%Y'),
second_reglement.strftime('15/%m/%Y'),
third_reglement.strftime('15/%m/%Y')]
def calc_montant_nfois(total, display):
"""Divise total par 3, et retourne le binôme suivant :
[ ([int] résultat entier + reste), ([str10] résultat entier avec zéros devant) ]
display est utilisé pour produire soit des paramètres (display = 0), soit des
chaînes d'affichage (display = 1).
"""
total = int(total)
a = int(total / 3 + total % 3)
b = int(total / 3)
if display == 0:
b = str(b)
b = b.zfill(10)
return [a, b]
ref = request.matchdict['ref']
sum_to_pay = float(request.matchdict['mttotal'])
nfois = request.matchdict['nfois']
logged_in = request.authenticated_userid
url = request.route_url('reglement', ref=ref, mttotal=request.matchdict['mttotal'], nfois=nfois)
# --- sites de prod
url_paybox = "https://tpeweb.e-transactions.fr/cgi/MYchoix_pagepaiement.cgi"
url_retour = request.route_url('reglement_ret')
# --- sites de test
# carte de test : 1111222233334444 12/18 123
# url_paybox = "https://preprod-tpeweb.e-transactions.fr/cgi/MYchoix_pagepaiement.cgi"
# url_retour = "http://62.35.112.130/reglement_ret"
pbx_site = '1119903'
pbx_rang = '01'
pbx_identifiant = '210073358'
pbx_total = 0
pbx_devise = '978'
pbx_cmd = '%s%s/' % (ref, logged_in)
pbx_porteur = get_eleve_info(request, logged_in)['email']
pbx_retour = 'reference:R;montant:M;autorisation:A;erreur:E'
pbx_datevalmax = ''
pbx_repondre_a = url_retour
pbx_hash = 'SHA512'
pbx_time = datetime.now().isoformat()
pbx_hmac = ''
# préparer les macros
snippets = get_renderer('../templates/inscriptions/macros.pt').implementation()
pay_ok = False
schedule_dates = None
schedule_sums = None
mt_total = 0
if 'form.submitted' in request.params:
pay_ok = True
nfois = request.params['nfois']
pbx_datevalmax = get_cb_maxdate(nfois)
pbx_total = int(math.ceil(to_decimal(100.)*to_decimal(sum_to_pay))) # was montantcmd
mt_total = sum_to_pay
if nfois == '3':
# Splitted reglement
if pbx_total < 30000:
pay_ok = False
else:
sums = calc_montant_nfois(pbx_total, 0)
save_total = pbx_total
pbx_total = sums[0] # 1ere echeance
mt_total = float(pbx_total)
today = strftime('%d-%m-%Y')
# compléter la référence commande
pbx_cmd += today + 'PBX_2MONT' + sums[1] + 'PBX_NBPAIE02PBX_FREQ01PBX_QUAND00'
schedule_dates = get_schedule_dates()
schedule_sums = calc_montant_nfois(save_total, 1)
# hash the parameters by hmac
param = 'PBX_SITE=%s&PBX_RANG=%s&PBX_IDENTIFIANT=%s' % (pbx_site, pbx_rang, pbx_identifiant)
param += '&PBX_TOTAL=%s&PBX_DEVISE=%s&PBX_CMD=%s&PBX_PORTEUR=%s&PBX_RETOUR=%s' % (
pbx_total, pbx_devise, pbx_cmd, pbx_porteur, pbx_retour)
param += '&PBX_DATEVALMAX=%s&PBX_REPONDRE_A=%s&PBX_HASH=%s&PBX_TIME=%s' % (
pbx_datevalmax, pbx_repondre_a, pbx_hash, pbx_time)
pbx_hmac = hash_hmac(request, param)
return {
'page_title': 'Paiement',
'url': url,
'url_paybox': url_paybox,
'pbx_site': pbx_site,
'pbx_rang': pbx_rang,
'pbx_identifiant': pbx_identifiant,
'pbx_total': pbx_total,
'pbx_devise': pbx_devise,
'pbx_cmd': pbx_cmd,
'pbx_porteur': pbx_porteur,
'pbx_retour': pbx_retour,
'pbx_datevalmax': pbx_datevalmax,
'pbx_repondre_a': pbx_repondre_a,
'pbx_hash': pbx_hash,
'pbx_time': pbx_time,
'pbx_hmac': pbx_hmac,
'ref': ref,
'sum_to_pay': sum_to_pay,
'mt_total': mt_total,
'nfois': nfois,
'pay_ok': pay_ok,
'schedule_dates': schedule_dates,
'schedule_sums': schedule_sums,
'snippets': snippets,
}
@view_config(route_name='reglement_acc', renderer='../templates/reglement/reglement_acc.pt')
def reglement_acc(request):
page_title = "Paiement accepté"
return {
'page_title': "Paiement accepté",
}
@view_config(route_name='reglement_ann', renderer='../templates/reglement/reglement_ann.pt')
def reglement_ann(request):
return {
'page_title': "Paiement annulé",
}
@view_config(route_name='reglement_ref', renderer='../templates/reglement/reglement_ref.pt')
def reglement_ref(request):
return {
'page_title': "Paiement refusé",
}
@view_config(route_name='reglement_ret')
def reglement_ret(request):
reference = request.params['reference']
montant = request.params['montant']
erreur = request.params['erreur']
if 'autorisation' in request.params:
autorisation = request.params['autorisation']
else:
#en cas de refus de paybox
autorisation = 'ERREUR'
if reference.find("/") > 6:
cd_cli = reference[3:9]
else:
# ancien format
cd_cli = reference[:6]
montant = float(montant)/100
# paiement en 1 fois ?
if reference.find("PBX") == -1:
# réglement comptant
prochain_montant = 0.0
# réglement PASS ROUSSEAU ? oui, confirmer
if reference[:3] == "PRS" and erreur == '00000':
confirmerPass(request, cd_cli)
else:
# réglement 3 fois sans frais
# reference = CPT100481/22-09-2020PBX_2MONT0000076300PBX_NBPAIE02PBX_FREQ01PBX_QUAND00
# reference = CRE661759/18-06-2018PBX_2MONT0000018800PBX_NBPAIE02PBX_FREQ01PBX_QUAND00
prochain_montant = reference.split("PBX")[1]
prochain_montant = prochain_montant.split("MONT")[1]
prochain_montant = float(int (prochain_montant))/100
reference = reference.split("PBX")[0]
if 'ETAT_PBX' in request.params:
reconduction = request.params['ETAT_PBX']
else:
reconduction = ''
ins_tickets(request, cd_cli, datetime.now(), reference[:20], montant, autorisation, erreur, prochain_montant, reconduction)
return Response(
content_type='text/plain',
body='1'
)

794
monaem/views/reservation.py Normal file
View File

@@ -0,0 +1,794 @@
# -*- coding: utf8 -*-
from pyramid.renderers import render, get_renderer
from pyramid.response import Response
from pyramid.view import (
view_config,
forbidden_view_config,
)
from pyramid.httpexceptions import (
HTTPFound,
)
from datetime import *
from time import strftime, sleep
from email.utils import formataddr
from urllib.request import urlopen
from urllib.parse import quote
from pyramid_mailer import get_mailer
from pyramid_mailer.message import Message, Attachment
import json
from ..models.reservation import *
from ..models.default import *
from ..views.default import (
to_euro,
to_date,
to_time,
to_int,
to_percent,
envoyerMail,
getConfirmText,
getMessageText,
)
@view_config(route_name='carnet_rdv', renderer='../templates/reservation/carnet_rdv.pt', permission='view')
def carnet_rdv(request):
"""Carnet de rendez-vous view"""
logged_in = request.authenticated_userid
eleve_info = get_eleve_info(request, logged_in)
ajoutRDVB = ""
ajoutPlateau = ""
ajoutRoute = ""
ajoutTA = ""
if eleve_info['permis'] == 'B' or eleve_info['permis'] == 'B78':
# si permis B, autoriser ajouter rdv B
ajoutRDVB = request.route_url('rdvb_dispo')
elif eleve_info['permis'] == 'A1' or eleve_info['permis'] == 'A2':
try:
# déterminer les ajouts de RDV possibles selon le suivi pédagogique
html = urlopen('https://suivi-eleve.marietton.com/CONTROLES/CTRL-suiviA2.php?codeE=' + logged_in)
# analyser la réponse : X;ZZ-2020 : X plateau / ZZ mois de examen prevu
rep = html.read().decode("utf-8")
reponse = rep.split(';')
# niveau de l'élève renseigné ?
niveau = reponse[0]
if niveau != '':
# niveau de l'élève après le 1er plateau
if niveau != '0':
# eleve a-t-il eu son examen pratique ? oui, ne plus proposer ajout PLATEAU
if ctl_pratique_ok(request, logged_in):
ajoutPlateau = ''
else:
ajoutPlateau = request.route_url('rdva_dispo', type_lecon='PLATEAU')
if niveau == '1':
plateau_min = 3 # niveau = 1, eleve doit avoir min 3 plateaux pour prendre des routes
else:
plateau_min = 2
# eleve a-t-il le niveau pour faire la route ?
if ctl_heures_plateau(request, logged_in) >= plateau_min:
ajoutRoute = request.route_url('rdva_dispo', type_lecon='ROUTE')
else:
ajoutRoute = ''
if reponse[1] != '0':
# l' éève a déjà un examen blanc, il ne peut plus en ajouter
if ctl_heures_TA(request, logged_in):
ajoutTA = ''
else:
ajoutTA = request.route_url('rdva_dispo', type_lecon='EXAM BLANC')
except Exception as e :
pass
# lire les rdv de l'élève
items = get_rdv_by_code(request, logged_in)
return {
'page_title': "Carnet de rendez-vous",
'items': items,
'ajoutRDVB': ajoutRDVB,
'ajoutPlateau': ajoutPlateau,
'ajoutRoute': ajoutRoute,
'ajoutTA': ajoutTA,
'now': datetime.now(),
}
@view_config(route_name='rdvb_del', renderer='../templates/reservation/rdvb_del.pt', permission='view')
def rdvb_del(request):
logged_in = request.authenticated_userid
pla_ligne = request.matchdict["no_ligne"]
# lire le rendez-vous dans le carnet
item = get_rdvB_by_no(request, pla_ligne)
if not item:
request.session.flash("Le rendez-vous no %s n'existe pas." % pla_ligne, 'danger')
return HTTPFound(location=request.route_url('carnet_rdv'))
if item.NoPlan == 0:
# RDV déjà supprimé, le client a cliqué 2 fois ?
return HTTPFound(location=request.route_url('carnet_rdv'))
# controle heure spéciale ?
if item.CIRCUIT > 0:
request.session.flash('Veuillez contacter <a href="/agence">votre agence</a> pour annuler ce rendez-vous (%s).' % item.INTITULE[:-4], 'danger')
return HTTPFound(location=request.route_url('carnet_rdv'))
if 'AVT PERMIS' in item.COMMENT.upper() or 'AVANT PERMIS' in item.COMMENT.upper():
request.session.flash('Veuillez contacter <a href="/agence">votre agence</a> pour annuler ce rendez-vous (AVANT PERMIS).', 'danger')
return HTTPFound(location=request.route_url('carnet_rdv'))
# controler le délai annulation ?
delaiOK = ctl_delai_annul(request, item.DATE, item.NoPlan, item.cree_le - timedelta(days=10), item.STATUT)
if 'form.submitted' in request.params:
if delaiOK == True :
# mise à jour de la ligne comme annulée
upd_eleves_rdv_annule(request, 'B', pla_ligne, logged_in)
statut_rdv = ""
jour_rdv = "d'%s" % item.DATE.strftime('%d-%m-%Y')
type_msg = "annulP48"
# créer la même heure en dispo web
update_rdvb(request, 0, 0, 99995, item.DATE, item.NoPlan, item.QTE, "HCB", item.CD_MON, item.AGENCE, '', 0, 0, 0, 0, 'WEB')
# logger dans t_log_nuit
ins_t_log_nuit(request, 'ANNUL+48', '%s %s %sh -> %s - %s' % (item.REF, item.DATE.strftime('%d-%m-%Y'), item.NoPlan, logged_in, item.NOM))
message = "Votre rendez-vous du %s à %sh00 a été annulé." % (item.DATE.strftime('%d-%m-%Y'), item.NoPlan)
else:
# mise à jour de la ligne comme annulée -48h
upd_eleves_rdv_statut3(request, 'B', pla_ligne)
# logger dans t_log_nuit
ins_t_log_nuit(request, 'ANNUL-48', '%s -> %s - %s' % (item.REF, logged_in, item.NOM))
statut_rdv = "- URGENT -"
type_msg = "annulM48"
if item.DATE == date.today():
jour_rdv = "d'AUJOURD'HUI"
else:
jour_rdv = "de DEMAIN"
message = "Votre rendez-vous du %s à %sh00 a été proposé aux autres élèves." % (item.DATE.strftime('%d-%m-%Y'), item.NoPlan)
# envoyer un message à la secrétaire
agence_email = get_eleve_agence(request, logged_in).email
# Fabrication du corps du Message
body = getMessageText(request, 'annuleRDV',
item.NOM, logged_in, '%s à %s h' % (jour_rdv, item.NoPlan), 'B', item.INTITULE + item.COMMENT)
destinataires=[agence_email]
envoyerMail(request, destinataires, "%s Annulation de rendez-vous en ligne" % statut_rdv, body)
# envoyer un message au moniteur via la tablette
date_heure = '%s %s:00' % (item.DATE.strftime('%d-%m-%Y'), str(item.NoPlan).zfill(2))
intitule = item.INTITULE
url = 'https://suivi-eleve.marietton.com/MSG-fromAEM.php?codeE=%s&dest=%s&msgType=%s&date=%s&qte=%s&type=%s' \
% (logged_in, item.CD_MON, type_msg, quote(date_heure), item.QTE, quote(intitule))
html = urlopen(url)
# nlus = html.read()
request.session.flash(message, 'success')
return HTTPFound(location=request.route_url('carnet_rdv'))
return {
'page_title': "Annulation de rendez-vous",
'item': item,
'delaiOK': delaiOK,
}
@view_config(route_name='rdvb_add', renderer='../templates/reservation/rdvb_add.pt', permission='view')
def rdvb_add(request):
logged_in = request.authenticated_userid
pla_ligne = request.matchdict["no_ligne"]
message = ''
# lire le rendez-vous dans le planning B
item = get_rdvB_by_no(request, pla_ligne)
if not item:
request.session.flash(u"Le rendez-vous no %s n'existe pas." % pla_ligne, 'danger')
return HTTPFound(location=request.route_url('carnet_rdv'))
if item.NoPlan == 0:
# RDV déjà pris, le client a fait cliqué 2 fois ?
return HTTPFound(location=request.route_url('carnet_rdv'))
# controler le délai annulation ?
delaiOK = ctl_delai_annul(request, item.DATE, item.NoPlan, item.cree_le + timedelta(days=10), item.STATUT)
# controler heures autorisées
err_msg = {1 : 'Vous avez déjà un rendez-vous à la même date et même heure, le ',
2 : 'Vous allez dépasser les 2h de leçon maximum par jour, le ',
3 : 'Vous allez dépasser les 4h de leçon maximum par semaine du ',
}
retour = ctl_heures_resaB(request, logged_in, logged_in, item.CD_MON, item.DATE, item.NoPlan, item.QTE)
if retour > 0 :
request.session.flash(err_msg[retour] + item.DATE.strftime('%d-%m-%Y'), 'danger')
return HTTPFound(location=request.route_url("rdvb_dispo"))
if 'form.submitted' in request.params:
nDelai = ctl_solde_resa(request, int(logged_in), "HCB")
# plafond dépassé ?
if nDelai == -1:
message = "Votre encours a dépassé son plafond autorisé. Impossible d'ajouter une heure."
else:
update_rdvb(request, item.no_ligne, item.CD_CLI, int(logged_in), item.DATE, item.NoPlan, item.QTE, "HCB", item.CD_MON, item.AGENCE, '', 0, 0, nDelai, item.cd_cli_old, 'WEB')
eleve = get_eleves_by_code(request, logged_in)
# lire le compte
cptes = get_eleve_cpt_extrait(request, logged_in)
# calculer le solde de > 0'élève
sum_to_pay = 0
sum_paid = 0
for cpt in cptes:
sum_to_pay += float(cpt.DEBIT)
sum_paid += float(cpt.CREDIT)
solde = sum_paid + eleve.encours_societe - sum_to_pay
# logger dans t_log_nuit
ins_t_log_nuit(request, 'AJOUT-' + str(nDelai), '%s %s %sh -> %s - %s' % (item.REF, item.DATE.strftime('%d-%m-%Y'), item.NoPlan, logged_in, eleve.NOMPREN))
if nDelai == 0:
request.session.flash(u"Le rendez-vous a été CONFIRME avec succès.", 'success')
else:
request.session.flash(u"Le rendez-vous a été RESERVE avec succès.", 'warning')
nompren = "%s %s %s" % (eleve.CIVILITE, eleve.NOM, eleve.PRENOM)
if solde >= 0:
# heure confirmée
body = getConfirmText(request, 'HCB', nompren, logged_in,
'%s à %s:00' % (item.DATE.strftime('%d-%m-%Y'), item.NoPlan), item.moniteur, item.QTE)
envoyerMail(request, [eleve.email], "Votre réservation a été confirmée", body)
return HTTPFound(location=request.route_url("carnet_rdv"))
else:
# heure réservée
body = getConfirmText(request, 'HCBR', nompren, logged_in,
'%s à %s:00' % (item.DATE.strftime('%d-%m-%Y'), item.NoPlan), '', '')
envoyerMail(request, [eleve.email], "Votre réservation a été prise en compte", body)
return HTTPFound(location=request.route_url("confirm_rdv"))
return {
'page_title': "Réserver un rendez-vous",
'message': message,
'item': item,
'delaiOK': delaiOK,
}
@view_config(route_name='rdvb_dispo', renderer='../templates/reservation/rdvb_dispo.pt', permission='view')
def rdvb_dispo(request):
def generer_planning(cd_cli):
rows = get_rdvb_dispos(request, cd_cli)
# construire la liste des events
dateMin = date.today() + timedelta(days=365) # today + 1 year
events = []
for row in rows:
# heure du créneau dispo est passée ? oui, ignorer
if not (row.DATE == date.today() and row.noplan <= datetime.now().hour and (row.cd_cli==99995 or row.statut==3)):
# déterminer la date la plus récente
if row.DATE < dateMin:
dateMin = row.DATE
# déterminer la couleur de l'event
if row.cd_cli == int(cd_cli) :
color = 'LightBlue' # rdv élève
url = ''
elif row.statut == 3 or row.cd_cli == 99995:
color = 'LightGreen' # creneau disponible
url = '/rdvb_add/%s' % (row.no_ligne)
else:
color = 'LightYellow' # ???
url = ''
json_event = {
'title': '%sh %s' % (row.qte, row.nom_moniteur),
'start': '%s %02d:00:00' % (row.DATE.strftime('%Y-%m-%d'), row.noplan),
'end': '%s %02d:00:00' % (row.DATE.strftime('%Y-%m-%d'), row.noplan + row.qte),
'allDay': False,
'color': color,
'textColor': '#000000',
'url': url,
}
events.append(json_event)
return events, dateMin
# récupérer les paramètres de l'appel de la view
logged_in = request.authenticated_userid
message = ''
# generer le calendrier des dispos
events, dateMin = generer_planning(logged_in)
datePlan = dateMin.strftime('%Y-%m-%d')
return {
'page_title': "Prise de rendez-vous",
'datePlan': datePlan,
'message': message,
'fullcalendar_events': json.dumps(events),
'nb_events': len(events),
}
@view_config(route_name='extrait_compte', renderer='../templates/reservation/extrait_compte.pt', permission='view')
@view_config(route_name='confirm_rdv', renderer='../templates/reservation/extrait_compte.pt', permission='view')
def extrait_compte(request):
"""Extrait de compte view"""
if 'confirm_rdv' in request.current_route_path():
confirm_rdv = True
page_title = "Récap sur mon en-cours"
else:
confirm_rdv = False
page_title = "Mon en-cours"
logged_in = request.authenticated_userid
eleve = get_eleves_by_code(request, logged_in)
# get compte
items = get_eleve_cpt_extrait(request, logged_in)
# calculate sums
sum_to_pay = 0
sum_paid = 0
for item in items:
sum_to_pay += float(item.DEBIT)
sum_paid += float(item.CREDIT)
# ajouter la prise en charge de la societe
sum_paid += eleve.encours_societe
solde = float(sum_to_pay - sum_paid)
if 'form.submitted' in request.params:
return HTTPFound(location=request.route_url('reglement', ref='CPT', mttotal=solde, nfois='1'))
return {
'page_title': page_title,
'items': items,
'sum_to_pay': to_euro(sum_to_pay),
'sum_paid': to_euro(sum_paid),
'today': strftime("%d/%m/%Y"),
'solde': solde,
'remain_to_pay': to_euro(solde * -1),
'member_has_email': bool(eleve.email),
'pec_designation': 'PRISE EN CHARGE %s' % eleve.NOM_ENTREPRISE,
'pec_montant': eleve.encours_societe,
'confirm_rdv': confirm_rdv,
}
@view_config(route_name='rdva_del', renderer='../templates/reservation/rdva_del.pt', permission='view')
def rdva_del(request):
logged_in = request.authenticated_userid
pla_ligne = request.matchdict["no_ligne"]
# lire le rendez-vous dans le carnet
item = get_rdvA_by_no(request, pla_ligne)
if not item:
request.session.flash(u"Le rendez-vous no %s n'existe pas." % pla_ligne, 'danger')
return HTTPFound(location=request.route_url('carnet_rdv'))
# controle heure spéciale ?
if item.LIBELLE.find('1er pla') == 0:
request.session.flash('Veuillez contacter <a href="/agence">votre agence</a> pour annuler ce rendez-vous (%s).' % item.LIBELLE, 'danger')
return HTTPFound(location=request.route_url('carnet_rdv'))
# controler le délai annulation ?
delaiOK = ctl_delai_annul(request, item.DATE, 8, item.cree_le - timedelta(days=10), item.STATUT)
if 'form.submitted' in request.params:
if delaiOK == True :
# mise à jour de la ligne comme annulée
upd_eleves_rdv_annule(request, 'A', pla_ligne, logged_in, )
statut_rdv = ""
jour_rdv = "du %s" % item.DATE.strftime('%d-%m-%Y')
# logger dans t_log_nuit
ins_t_log_nuit(request, 'ANNUL+48', '%s %s -> %s - %s' % (item.REF, item.DATE.strftime('%d-%m-%Y'), logged_in, item.NOM))
message = "Votre rendez-vous %s a été annulé." % jour_rdv
else:
# mise à jour de la ligne comme annulée -48h
upd_eleves_rdv_statut3(request, 'A', pla_ligne)
# logger dans t_log_nuit
ins_t_log_nuit(request, 'ANNUL-48', '%s %s -> %s - %s' % (item.REF, item.DATE.strftime('%d-%m-%Y'), logged_in, item.NOM))
statut_rdv = "- URGENT -"
if item.DATE == date.today():
jour_rdv = "d'AUJOURD'HUI"
else:
jour_rdv = "de DEMAIN"
message = "Votre rendez-vous %s a été proposé aux autres élèves." % jour_rdv
# envoyer un message à la secrétaire
agence_email = get_eleve_agence(request, logged_in).email
# Fabrication du corps du Message
body = getMessageText(request, 'annuleRDV', item.NOM, logged_in, jour_rdv, 'A', '')
destinataires=[agence_email]
envoyerMail(request, destinataires, "%s Annulation de rendez-vous en ligne" % statut_rdv, body)
request.session.flash(message, 'success')
return HTTPFound(location=request.route_url('carnet_rdv'))
return {
'page_title': "Annulation de rendez-vous",
'item': item,
'delaiOK': delaiOK,
}
@view_config(route_name='rdva_add', renderer='../templates/reservation/rdva_add.pt', permission='view')
def rdva_add(request):
logged_in = request.authenticated_userid
rdv_cli = request.matchdict["cd_cli"]
if rdv_cli == logged_in:
# ne peut pas prendre ce lecon en statut=3
return HTTPFound(location=request.route_url('carnet_rdv'))
rdv_id = request.matchdict["rdv_id"]
rdv_type = rdv_id[0]
rdv_date = rdv_id[1:11]
rdv_groupe = rdv_id[11:12]
rdv_lecon = rdv_id[12]
if rdv_lecon == 'P':
lecon = "une leçon PLATEAU"
ref = 'HCA3'
route = 0
elif rdv_lecon == 'R':
lecon = "une leçon ROUTE"
ref = 'HCA3'
route = -1
else:
lecon = "un examen blanc"
ref = 'TA'
route = 0
# une seule lecon TA
if ctl_heures_TA(request, logged_in) :
request.session.flash('Vous avez déjà un examen blanc programmé.', 'danger')
return HTTPFound(location=request.route_url("carnet_rdv"))
# obtenir heure de debut et duree lecon
debut, duree = getHeureDureeLeconA(rdv_type, rdv_groupe)
# date du rdv en format date
madate = datetime.strptime(rdv_date, '%Y-%m-%d')
date_rdv = '%s à %s h' % (madate.strftime('%d-%m-%Y'), debut)
# controle délai
delaiOK = ctl_delai_annul_A(request, madate)
message = ''
# controler heures autorisées
msg_retour = ctl_heures_resaA(request, rdv_lecon, logged_in, rdv_date, rdv_groupe)
if msg_retour != '' :
request.session.flash(msg_retour, 'danger')
return HTTPFound(location=request.route_url("carnet_rdv"))
if 'form.submitted' in request.params:
if rdv_cli != '0':
# cas de lecçon avec statut 3, relire le rdv
item = get_rdvA_by_id(request, rdv_type, rdv_date, rdv_groupe, rdv_cli)
if not item:
request.session.flash(u"Le rendez-vous no %s n'existe pas." % rdv_id, 'danger')
return HTTPFound(location=request.route_url('carnet_rdv'))
nDelai = ctl_solde_resa(request, int(logged_in), "HCA3")
# plafond dépassé ?
if nDelai == -1:
message = "Votre encours a dépassé son plafond autorisé. Impossible d'ajouter une leçon."
else:
update_rdva(request, rdv_type, rdv_date, rdv_groupe, int(rdv_cli), int(logged_in), duree, ref, route, nDelai)
eleve = get_eleves_by_code(request, logged_in)
# lire le compte
cptes = get_eleve_cpt_extrait(request, logged_in)
# calculer le solde de l'élève
sum_to_pay = 0
sum_paid = 0
for cpt in cptes:
sum_to_pay += float(cpt.DEBIT)
sum_paid += float(cpt.CREDIT)
solde = sum_paid + eleve.encours_societe - sum_to_pay
# logger dans t_log_nuit
ins_t_log_nuit(request, 'AJOUT-' + str(nDelai), '%s %s G:%s -> %s - %s' % (ref, date_rdv, rdv_groupe, logged_in, eleve.NOMPREN))
if nDelai == 0:
request.session.flash(u"Le rendez-vous a été CONFIRME avec succès.", 'success')
else:
request.session.flash(u"Le rendez-vous a été RESERVE avec succès.", 'warning')
nompren = "%s %s %s" % (eleve.CIVILITE, eleve.NOM, eleve.PRENOM)
if solde >= 0:
# heure confirmée
body = getConfirmText(request, ref, nompren, logged_in, date_rdv, lecon, str(duree))
envoyerMail(request, [eleve.email], "Votre réservation a été confirmée", body)
return HTTPFound(location=request.route_url("carnet_rdv"))
else:
# heure réservée
body = getConfirmText(request, 'HCAR', nompren, logged_in, date_rdv, '', '')
envoyerMail(request, [eleve.email], "Votre réservation a été prise en compte", body)
return HTTPFound(location=request.route_url("confirm_rdv"))
return {
'page_title': "Réserver %s" % lecon,
'message': message,
'date_rdv': date_rdv,
'duree': duree,
'delaiOK': delaiOK,
}
@view_config(route_name='rdva_dispo', renderer='../templates/reservation/rdva_dispo.pt', permission='view')
def rdva_dispo(request):
def generer_planning(type_lecon, cd_cli):
rows = get_rdva_dispos(request, type_lecon, cd_cli)
# construire la liste des events
dateMin = date.today() + timedelta(days=365) # today + 1 year
events = []
for row in rows:
# identifiant du rdv = id du planning ligne + 1er car du type de lecon
rdv_id = row.type + row.date.strftime('%Y-%m-%d') + row.groupe + type_lecon[0]
# déterminer la date la plus récente
if row.date < dateMin:
dateMin = row.date
# déterminer le début et la durée de la leçon
debut, duree = getHeureDureeLeconA(row.type, row.groupe)
# déterminer la couleur de la leçon
if row.cd_cli == int(cd_cli) :
color = 'LightBlue' # rdv élève
url = ''
elif row.cd_cli > 0:
color = 'LightGreen' # séance avec statut 3
url = '/rdva_add/%s/%s' % (rdv_id, row.cd_cli)
else:
color = 'LightGreen' # séance normale
url = '/rdva_add/%s/0' % (rdv_id)
json_event = {
'title': str(duree) + ' h',
'start': '%s %02d:00:00' % (row.date.strftime('%Y-%m-%d'), debut),
'end': '%s %02d:00:00' % (row.date.strftime('%Y-%m-%d'), debut + duree),
'allDay': False,
'color': color,
'textColor': '#000000',
'url': url,
}
events.append(json_event)
return events, dateMin
# récupérer les paramètres de l'appel de la view
logged_in = request.authenticated_userid
type_lecon = request.matchdict["type_lecon"]
message = ''
# lire le Max leçons A par semaine
agence6 = get_agences(request, 6)
if agence6.MaxLeconASemaine == 0:
request.session.flash('La réservation de leçon A est temporairement suspendue. Veuillez revenir plus tard', 'danger')
return HTTPFound(location=request.route_url("carnet_rdv"))
# generer le calendrier des dispos
events, dateMin = generer_planning(type_lecon, logged_in)
datePlan = dateMin.strftime('%Y-%m-%d')
# compter les séances dispo
nb = 0
for item in events :
if item['url'] != '':
nb += 1
return {
'page_title': "Disponiblités %s" % type_lecon,
'datePlan': datePlan,
'message': message,
'fullcalendar_events': json.dumps(events),
'nb_events': nb,
}
def getHeureDureeLeconA(type, groupe):
# déterminer le début et la durée de la leçon
if type == "A":
duree = 3
if groupe == "F" or groupe == "G":
debut = 13
elif groupe == "B":
debut = 12
elif groupe == "C":
debut = 15
elif groupe == "D":
debut = 18
else:
# groupes A et E
debut = 8
else:
# groupe F : exmaen blanc
debut = ord(groupe) - 57
duree = 1
return debut, duree
@view_config(route_name='batch_jour')
def batch_jour(request):
"""
Ce traitement est lancé périodiquement sur le serveur du site web, par une tâche planifiée :
- Executer en tant que : root
- Commande : wget http://localhost:6543/batch_jour/Arya5tark
- Quand executer : chaque jour, tous les 5 minutes
Par sécurité, ce view ne peut être appelé qu'avec un paramètre secret 'Arya5tark'
Il a pour but de confirmer les réservations effectuées par le WEB
"""
# contrôle : paramètre correct ? ? non, terminer
par = request.matchdict['param']
if par != 'Arya5tark':
return Response('Erreur : paramètre incorrect')
# =============== CONFIRMATION DES INSCRIPTIONS ===================
confirm_inscriptions(request)
# attendre 5 secondes
sleep(5)
# ----- lancer les notifications inscription
notifier_reservations(request, 'INSCR')
return Response('Batch jour terminé OK')
def confirm_inscriptions(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_inscriptions(request)
for resa in resas:
# controler le solde REEL de l'élève
eleve = get_solde_eleve(request, resa.cd_cli, resa.ref)
if eleve.solde >= 0 :
# -- confirmer inscription STAGES
update_reservation_confirm(request, "C", resa.no_ligne, resa.ref, resa.statut, resa.cd_cli_old)
if resa.ref in ["POINT", "PEM125", "PASSERELLE", "B96", "CODE"] :
# -- creer une notification de confirmation STAGE
insert_email_resa(request, resa.ref, resa.cd_cli, "Inscr.", resa.date, resa.noplan, "CONFIRMEE")
elif resa.ref == "HCB" :
# -- creer une notification de confirmation HEURE
insert_email_resa(request, resa.ref, resa.cd_cli, "WEB_B", resa.date, resa.noplan, "CONFIRMEE")
# -- heure annuléen hors dleai HCB ?
if resa.statut == 3 and resa.cd_cli_old > 0 :
# -- creer une notification de l'ancien élève
insert_email_resa(request, resa.ref, resa.cd_cli_old, "WEB_48H", resa.date, resa.noplan, "CONFIRMEE")
else:
# -- fin de résa a dépassé de 10 mn ?
delai = (datetime.now() - resa.cree_le).total_seconds()/60
if round(delai) > 10:
#-- annuler l'inscription
update_reservation_confirm(request, "A", resa.no_ligne, resa.ref, resa.statut, resa.cd_cli_old)
if resa.ref in ["POINT", "PEM125", "PASSERELLE", "B96", "CODE"] :
# -- creer une notification de annulation
insert_email_resa(request, resa.ref, resa.cd_cli, "Inscr.", resa.date, resa.noplan, "ANNULEE")
elif resa.ref in ["TA", "HCA3"] :
# -- creer une notification de confirmation HEURE MOTO
insert_email_resa(request, resa.ref, resa.cd_cli, "WEB_A", resa.date, resa.noplan, "ANNULEE")
elif resa.ref in ["TB", "HCB"] :
# -- creer une notification de confirmation HEURE
insert_email_resa(request, resa.ref, resa.cd_cli, "WEB_B", resa.date, resa.noplan, "ANNULEE")
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 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 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, destinataires))
return len(msg)