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
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+9
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
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
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)