415 lines
16 KiB
Python
415 lines
16 KiB
Python
# -*- 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))
|
|
|
|
|