Elyos_FI_Back_Office/Job_Cron.py

1843 lines
89 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""
Ce fichier permet de gerer les crons et differents job
"""
import ast
from calendar import monthrange
import bson
import pymongo
import xlsxwriter
from pymongo import MongoClient
import json
from bson import ObjectId
import re
from datetime import datetime, date, timedelta
import Session_Formation
import module_editique
import partner_base_setup
import partner_client
import partner_order
import prj_common as mycommon
import secrets
import inspect
import sys, os
from pymongo import ReturnDocument
import GlobalVariable as MYSY_GV
import survey_mgt as survey_mgt
import Job_Cron_Common as Job_Cron_Common
"""
Ce job permet d'envoyer les demandes d'enquetes comme les
evaluation à froid.
Les informations sont stockées dans la collection : "survey"
Par exemple, une fois par jour ce job va tourner,
"date_demande_envoi" = date_jour, alors on envoi
on met à jour avec la collection avec
"""
def Global_MySy_Cron_Traitement():
try:
today = str(datetime.now().strftime("%d/%m/%Y"))
today_date_ISODATE = datetime.strptime(str(today), '%d/%m/%Y')
qery_match = {'$and': [{"valide": '1', 'locked':'0'},
{
'mysy_cron_date_start': {'$lte': today_date_ISODATE},
},
{
'mysy_cron_date_end': {'$gte': today_date_ISODATE,},
},
]}
pipe_qry = ([
{"$addFields": {
"mysy_cron_date_start": {
'$dateFromString': {
'dateString': '$date_start',
'format': "%d/%m/%Y"
}
}
}
},
{"$addFields": {
"mysy_cron_date_end": {
'$dateFromString': {
'dateString': '$date_end',
'format': "%d/%m/%Y"
}
}
}
},
{'$match': qery_match},
])
for val in MYSY_GV.dbname['Job_Cron'].aggregate(pipe_qry):
if( "job_name" in val.keys() ):
possibles = globals().copy()
possibles.update(locals())
cron_function = possibles.get(val['job_name'])
if not cron_function:
mycommon.myprint(str(
inspect.stack()[0][3]) + " Fonction '"+str(val['job_name'])+"' est introuvable")
continue
local_con_status, local_con_retval = cron_function()
print(" Traitement 01 du job = ", val['job_name'])
"""
Mettre à jour le cron pour dire que tout s'est bien poassé
"""
now = str(datetime.now())
cron_update_data = {}
cron_update_data['last_run'] = str(now)
if( local_con_status is True ):
cron_update_data['last_run_status'] = "1"
else:
cron_update_data['last_run_status'] = "0"
cron_update_data['last_run_message'] = local_con_retval
node_traitement = {}
node_traitement['run_date'] = str(now)
node_traitement['run_status'] = str(cron_update_data['last_run_status'])
node_traitement['run_message'] = str(local_con_retval)
if( "cront_list_traitement" in val.keys() and val['cront_list_traitement']):
local_cront_list_traitement = val['cront_list_traitement']
local_cront_list_traitement.append(node_traitement)
else:
local_cront_list_traitement = []
local_cront_list_traitement.append(node_traitement)
cron_update_data['cront_list_traitement'] = local_cront_list_traitement
ret_val = MYSY_GV.dbname['Job_Cron'].find_one_and_update(
{'_id': ObjectId(str(val['_id']))},
{"$set": cron_update_data},
return_document=ReturnDocument.AFTER,
upsert=False,
)
return True, "OK"
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno)
"""
CRON fonction qui envoie les demandes d'enquete
"""
def Cron_Send_Survey():
try:
print(" Cron : In function = Cron_Send_Survey")
for val in MYSY_GV.dbname['survey'].find({"automatique_traitement":"1",
'automatique_traitement_done':'0',
'valide':'1',
'locked':'0'}) :
if( "automatique_sending_request_date" in val.keys() and val['automatique_sending_request_date']):
automatic_date_to_send = str(val['automatique_sending_request_date'])[0:10]
local_status = mycommon.CheckisDate(automatic_date_to_send)
if (local_status is False):
mycommon.myprint(str(inspect.stack()[0][
3]) + " La date 'automatique_sending_request_date' de n'est pas au format jj/mm/aaaa.")
return False, " La date 'automatique_sending_request_date' de n'est pas au format jj/mm/aaaa."
if (datetime.strptime(str(automatic_date_to_send), '%d/%m/%Y') <= datetime.strptime(str(datetime.now().strftime("%d/%m/%Y")), '%d/%m/%Y') ) :
print(" OKK to run job ")
local_dicton = {}
local_dicton['partner_owner_recid'] = str(val['partner_owner_recid'])
local_dicton['tab_ids'] = (str(val['_id']))
local_status, local_retval = survey_mgt.Automatic_Send_Survey_TabIds(local_dicton)
#data['date_update'] = str(datetime.now())
survey_update_data = {}
sending_status = "0"
if( local_status is False ):
sending_status = "0"
else:
sending_status = "1"
survey_update_data['automatique_traitement_done'] = "1"
survey_update_data['date_envoi'] = str(datetime.now())
ret_val = MYSY_GV.dbname['survey'].find_one_and_update(
{'_id': ObjectId(str(val['_id']))},
{"$set": survey_update_data},
return_document=ReturnDocument.AFTER,
upsert=False,
)
return True, ""
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno)
"""
CRON fonction qui fait les relances de devis
/!\ Algorithme :
1 - Recuperer dans la collection "base_partner_setup" les partenaires
qui ont la relance auto active : "relance_auto"
2 - Pour chaque devis du partenaire concernée "partner_owner_recid", recuperé à l'etape 1
Verifier que les devis repondent aux critères suivants (la collection : partner_order_header, order_header_type = "devis"
- devis n'a pas expiré
- devis relance_auto = 1
- devis status : En cours => valeur 1
- devis nb_relance non depassé
- on ne relance un devis que la frequence de la relance est gerée
"""
def Cron_Quotation_Relance():
try:
print(" Cron : In function = Cron_Quotation_Relance")
todays_date = str(date.today().strftime("%d/%m/%Y"))
todays_date_ISODATE = datetime.strptime(str(todays_date), '%d/%m/%Y')
for relance_setp in MYSY_GV.dbname['base_partner_setup'].find({'valide':'1',
'locked':'0',
'config_name':'relance_auto',
'config_value':'1',
'related_collection':'quotation',
'partner_owner_recid': {'$ne': 'default'},
}):
if( "partner_owner_recid" in relance_setp.keys() and relance_setp['partner_owner_recid'] ):
local_partner_owner_recid = str(relance_setp['partner_owner_recid'])
devis_qery_match = {'$and': [{'partner_owner_recid':str(local_partner_owner_recid),
'valide':'1',
'locked':'0', 'order_header_type':'devis', 'order_header_status':'1',
'relance_auto':'1'},
{
'mysy_devis_expiration_date': {
'$gte': todays_date_ISODATE,
}
}, ]}
pipe_qry = ([
{"$addFields": {
"mysy_devis_expiration_date": {
'$dateFromString': {
'dateString': '$order_header_date_expiration',
'format': "%d/%m/%Y"
}
}
}
},
{'$match': devis_qery_match},
])
print(" ## pipe_qry Cron_Quotation_Relance = ", pipe_qry)
for local_devis in MYSY_GV.dbname['partner_order_header'].aggregate(pipe_qry):
is_quotation_validated = 0
if( "validation_by" in local_devis.keys() and local_devis['validation_by'] and
"date_validation" in local_devis.keys() and local_devis['date_validation'] ):
# Ce devis a déjà ete validée, donc pas de relance
is_quotation_validated = 1
print( "### local_devis a traiter = ", local_devis)
relance_done = 0
nb_limite_relance = 0
if( "nb_relance" in local_devis.keys() and local_devis['nb_relance']):
relance_done = mycommon.tryInt(str(local_devis['nb_relance']))
if ("nb_relance_auto" in local_devis.keys() and local_devis['nb_relance_auto']):
nb_limite_relance = mycommon.tryInt(str(local_devis['nb_relance_auto']))
date_derniere_relance_auto = "01/12/2099"
if( "date_dernier_relance_auto" in local_devis.keys() and local_devis['date_dernier_relance_auto'] ):
date_derniere_relance_auto = str(local_devis['date_dernier_relance_auto'])[0:10]
date_derniere_relance_auto_ISODATE = datetime.strptime(str(date_derniere_relance_auto), '%d/%m/%Y')
frequence_relance_auto = 0
if ("frequence_relance_auto" in local_devis.keys() and local_devis['frequence_relance_auto']):
frequence_relance_auto = mycommon.tryInt(str(local_devis['frequence_relance_auto']))
new_relance_date_ISODATE = date_derniere_relance_auto_ISODATE + timedelta(days=frequence_relance_auto)
"""
print(" ### LA frequence_relance_auto ", frequence_relance_auto)
print(" ### LA dernière relance date de ", date_derniere_relance_auto)
print(" ### LA PROCHAINE RELANCE EST ", new_relance_date_ISODATE)
"""
new_relance_date_no_ISODATE = str(new_relance_date_ISODATE.strftime("%d/%m/%Y"))
#print(" ### LA PROCHAINE RELANCE EST (new_relance_date_no_ISODATE) ", new_relance_date_no_ISODATE)
datetime.strptime(str(todays_date), '%d/%m/%Y')
if( is_quotation_validated == 0 and relance_done <= nb_limite_relance and datetime.strptime(str(todays_date), '%d/%m/%Y') >= datetime.strptime( str(new_relance_date_no_ISODATE).strip(), '%d/%m/%Y') ):
"""
On fait le traitement, on envoie le mail
1 - recuperation des data
"""
local_status, my_partner = mycommon.Get_Connected_User_Partner_Data_From_RecID(str(local_devis['partner_owner_recid']))
if (local_status is not True):
return local_status, my_partner
tab_client = []
tab_client.append(ObjectId(str(local_devis['order_header_client_id'])))
local_diction = {'token':str(my_partner['token']), 'order_id': str(local_devis['_id'])}
local_send_remind_status, local_send_remind_retval = partner_order.Send_Quotation_Remind_Level1(local_diction)
print(" relance return local_send_remind_status = ", local_send_remind_status)
if( local_send_remind_status is True):
print(" RELANCE FAIT ET OK ")
"""
Une fois la relance faite, on met à jour le devis avec les infos suivant :
- liste_relance
"""
frequence_relance_auto_reached = "0"
if("list_relance" in local_devis.keys() and local_devis['list_relance']):
local_node = {}
local_node['date_relance'] = str(date.today())
local_node['mesg_relance'] = str(local_send_remind_retval)
local_devis['list_relance'].append(local_node)
else :
local_node = {}
local_node['date_relance'] = str(date.today())
local_devis['list_relance'] = []
local_devis['list_relance'].append(local_node)
local_node['mesg_relance'] = str(local_send_remind_retval)
nb_relance = str(len(local_devis['list_relance']))
local_data_update = local_devis
id_to_update = str(local_data_update['_id'])
del local_data_update['_id']
del local_data_update['mysy_devis_expiration_date']
local_data_update['nb_relance'] = str(nb_relance)
local_data_update['date_dernier_relance_auto'] = str(todays_date)
result = MYSY_GV.dbname['partner_order_header'].find_one_and_update(
{'_id': ObjectId(str(id_to_update)),
'valide': '1',
'locked': '0'},
{"$set": local_data_update},
upsert=False,
return_document=ReturnDocument.AFTER
)
"""
else:
print(" ### NoNNNNNNNNNN on NEEEE fait la relanceeeeeeeeeeeee")
print(" limite relance atteint : ")
print(" limite relance_done : ", relance_done)
print(" limite nb_limite_relance : ", nb_limite_relance)
"""
return True, ""
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno)
"""
Cron de facturation automatique des inscriptions
Contrôle avant facturation :
Après la facturation, on ajout sur la ligne dinscription, la liste des factures. On remplit aussi les champs : invoice et invoice_date.
A la prochaine facturation, comme on est sur une facturation mensuelle, le système va vérifier que la ligne en question na pas été facturée le mois en cours.
"""
def Cron_Monthly_Invoice_Inscription():
try:
print(" Cron : In function = Cron_Monthly_Invoice_Inscription")
todays_date = str(date.today().strftime("%d/%m/%Y"))
todays_date_ISODATE = datetime.strptime(str(todays_date), '%d/%m/%Y')
"""
1 - Recuprer la liste des client facturation mensuelle automatique
"""
list_clients = []
for client_data in MYSY_GV.dbname['partner_client'].find({'valide':'1',
'locked':'0',
'invoice_automatique':'mois'}):
list_clients.append(str(client_data['_id']))
print(" Client à factuer : ", str(client_data['nom']) )
qery_match = {'$and': [{"valide": '1', },
{
'mysy_session_start_date': {'$lte': todays_date_ISODATE},
},
{
'mysy_session_end_date': {'$gte': todays_date_ISODATE, },
},
]}
pipe_qry = [
{"$addFields": {
"mysy_session_start_date": {
'$dateFromString': {
'dateString': '$date_debut',
'format': "%d/%m/%Y"
}
}
}
},
{"$addFields": {
"mysy_session_end_date": {
'$dateFromString': {
'dateString': '$date_fin',
'format': "%d/%m/%Y"
}
}
}
},
{'$match': qery_match},
{'$lookup': {
'from': 'inscription',
'let': {'session_id': {'$toString': '$_id'}, 'session_partner_owner_recid': '$partner_owner_recid'},
'pipeline': [
{'$match':
{'$expr':
{'$and':
[
{'$eq': ['$session_id', '$$session_id']},
{'$eq': ['$partner_owner_recid', '$$session_partner_owner_recid']},
{'$eq': ['$status', '1']},
{'$eq': ["facture_client_rattachement_id", str(client_data['_id'])]}
]
}
}
},
],
'as': 'inscription_collection'
}
},
]
#print(" ### Cron_Monthly_Invoice_Inscription pipe_qry = ", pipe_qry)
data_for_invoicing = {}
data_for_invoicing['list_client'] = []
data_for_invoicing['list_session'] = []
data_for_invoicing['detail_data'] = []
list_session = []
list_client = []
for val in MYSY_GV.dbname['session_formation'].aggregate(pipe_qry):
#print(" #### val = ", val)
if( str(client_data['_id']) not in list_client ):
list_client.append(str(client_data['_id']))
if (str(val['code_session']) not in list_session):
list_session.append(str(val['code_session']))
"""
30/05/2024 - update :
/!\ : Ici on parle du prix TOTAL de la session
Pour recalculer le prix mensuelle, il faut prendre
on fait un ratio :
- calculer le nombre de mois
- diviser le prix par le nombre de mois
"""
local_diction = {}
local_diction['date_from'] = str(val['date_debut'])
local_diction['date_to'] = str(val['date_fin'])
local_diction['total_price'] = str(val['prix_session'])
local_price_status, local_price_retval = mycommon.Compute_Monthly_Price_From_Dates(local_diction)
if (local_price_status is False):
return local_price_status, local_price_retval
new_price_data = local_price_retval
print(" ### le prix mensuel est de new_price_data = ", new_price_data)
for inscrit_data in val['inscription_collection'] :
"""
Verifier que la ligne d'inscription n'as pas été facturé le mois en cours
"""
inscription_allready_invoiced = "0"
if( "invoiced_date" in inscrit_data.keys() and inscrit_data['invoiced_date'] ):
today_yearmonth =str(datetime.now().strftime("%Y%m"))
last_invoiced_date = datetime.strptime(str(inscrit_data['invoiced_date'])[0:10], '%Y-%m-%d')
last_invoiced_yearmonth = str(last_invoiced_date.strftime("%Y%m"))
if(str(today_yearmonth) == str(last_invoiced_yearmonth)):
inscription_allready_invoiced = 1
print(" Cette inscription a a déjà ete facturé le "+str(last_invoiced_date))
"""
# On va aller prendre toutes les incriptions qui n'ont pas été facturées le mois en cours
"""
if( inscription_allready_invoiced == "0"):
local_node = {}
local_node['client_id'] = str(client_data['_id'])
local_node['client_nom'] = str(client_data['nom'])
local_node['client_raison_sociale'] = str(client_data['raison_sociale'])
local_node['nb_inscrit_to_invoice'] = str(len(val['inscription_collection']))
if( "_id" in val.keys() ):
local_node['session_id'] = str(val['_id'])
if ("code_session" in val.keys()):
local_node['code_session'] = val['code_session']
if ("titre" in val.keys()):
local_node['session_titre'] = val['titre']
class_title = ""
class_internal_url = ""
if( "class_internal_url" in val.keys() and val['class_internal_url']):
class_internal_url = val['class_internal_url']
class_data = MYSY_GV.dbname['myclass'].find_one({'internal_url':str(val['class_internal_url']),
'partner_owner_recid':str(val['partner_owner_recid']),
'valide':'1',
'locked':'0'})
if( class_data and "title" in class_data.keys() ):
class_title = class_data['title']
local_node['class_title'] = class_title
local_node['class_internal_url'] = class_internal_url
if ("date_debut" in val.keys()):
local_node['session_date_debut'] = val['date_debut']
if ("date_debut" in val.keys()):
local_node['session_date_debut'] = val['date_debut']
if ("date_fin" in val.keys()):
local_node['session_date_fin'] = val['date_fin']
if ("prix_session" in val.keys()):
local_node['prix_session'] = new_price_data['monthly_price']
if ("price_by" in val.keys()):
local_node['price_by'] = val['price_by']
local_node['inscription_id'] = str(inscrit_data['_id'])
### data Inscription
local_node['apprenant_id'] = str(inscrit_data['_id'])
if ("_id" in inscrit_data.keys()):
local_node['apprenant_id'] = str(inscrit_data['_id'])
# Si on a une apprenant_id, on va aller chercher les données de l'apprenant
if( "apprenant_id" in inscrit_data.keys() and inscrit_data['apprenant_id']):
apprenant_data = MYSY_GV.dbname['apprenant'].find_one({'_id':ObjectId(str(inscrit_data['apprenant_id'])),
'partner_owner_recid':str(val['partner_owner_recid'])})
if (apprenant_data and "email" in apprenant_data.keys()):
local_node['apprenant_email'] = apprenant_data['email']
if (apprenant_data and "civilite" in apprenant_data.keys()):
local_node['apprenant_civilite'] = apprenant_data['civilite']
if (apprenant_data and "prenom" in apprenant_data.keys()):
local_node['apprenant_prenom'] = apprenant_data['prenom']
if (apprenant_data and "nom" in apprenant_data.keys()):
local_node['apprenant_nom'] = apprenant_data['nom']
else:
# Situation anormale car toutes inscription validée à forcement un dossier apprenant. mais on fait pour se couvrir de bug
local_node['inscription_email'] = ""
local_node['inscription_civilite'] = ""
local_node['inscription_prenom'] = ""
local_node['inscription_nom'] = ""
local_node['partner_owner_recid'] = str(client_data['partner_recid'])
data_for_invoicing['detail_data'].append(local_node)
data_for_invoicing['list_client'] = list_client
data_for_invoicing['list_session'] = list_session
#print(" ### le tableau a facturer est : ")
#print(data_for_invoicing)
if( len(data_for_invoicing['detail_data']) > 0 ):
print(" DEBUT FACTURATION")
local_invoice_status, local_invoice_retval = Invoice_Data_From_Tab(data_for_invoicing)
if( local_invoice_status is False):
return local_invoice_status, local_invoice_retval
else:
print(" FACTURATION REUSSIE")
return True, ""
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno)
"""
Cette fonction prend le tableau des data à facturer et créer les facture dans les
tables et met à jour les inscriptions
"""
def Invoice_Data_From_Tab(diction):
try:
print(" Cron : In function = Invoice_Data_From_Tab")
todays_date_mode_2 = str(date.today().strftime("%Y-%m-%d"))
print( " ### diction FACTURATION= ", diction)
field_list_obligatoire = ['list_client', 'list_session', 'detail_data', ]
for val in field_list_obligatoire:
if val not in diction:
mycommon.myprint(
str(inspect.stack()[0][3]) + " : La valeur '" + val + "' n'est pas presente dans liste ")
return False, "La valeur '" + val + "' n'est pas presente dans liste"
field_list_detail_data_obligatoire = ['client_id', 'session_id', 'code_session', 'prix_session', 'price_by', 'nb_inscrit_to_invoice',
'apprenant_id', 'apprenant_email', 'apprenant_prenom', 'apprenant_nom', 'partner_owner_recid', 'class_internal_url']
for val in field_list_detail_data_obligatoire:
for tmp in diction['detail_data']:
if val not in tmp:
mycommon.myprint(
str(inspect.stack()[0][3]) + " : La valeur '" + val + "' n'est pas presente dans 'detail_data' ")
return False, "La valeur '" + val + "' n'est pas presente dans 'detail_data' "
data_array = diction['detail_data']
tab_ligne_a_facturer = []
ref_interne_facture = ""
"""
Calcul des totaux à facturer
"""
montant_total_ht = 0
for session_data in diction['list_session'] :
montant_total_ht_session = 0
nb_participant = 0
prix_session = 0
price_by_session = ""
liste_participant = ""
class_intenal_url_session = ""
partner_owner_recid = ""
for local_data in diction['detail_data']:
if( local_data['code_session'] == session_data ) :
if( "prix_session" in local_data.keys() and local_data['prix_session'] and
"price_by" in local_data.keys() and local_data['price_by'] ):
prix_insc = str(local_data['prix_session'])
price_by = str(local_data['price_by'])
if( price_by not in MYSY_GV.TRAINING_PRICE):
mycommon.myprint(
str(inspect.stack()[0][3]) + " La valeur '" + price_by + "' n'est pas valide ")
return False, " La valeur '" + price_by + "' n'est pas valide "
local_isfloat_status, local_isfloat_retval = mycommon.IsFloat(prix_insc)
if(local_isfloat_status is False ):
mycommon.myprint(
str(inspect.stack()[0][3]) + " La valeur '" + prix_insc + "' n'est pas valide ")
return False, " La valeur '" + prix_insc + "' n'est pas valide "
nb_participant = mycommon.tryInt(local_data['nb_inscrit_to_invoice'])
prix_session = local_isfloat_retval
price_by_session = price_by
liste_participant = str(local_data['apprenant_prenom'])+" "+str(local_data['apprenant_nom'])+str(local_data['apprenant_email'])+"\n"+liste_participant
class_intenal_url_session = local_data['class_internal_url']
partner_owner_recid = local_data['partner_owner_recid']
if( price_by_session == "perstagiaire"):
montant_total_ht_session = montant_total_ht_session + (prix_session * nb_participant )
"""
/!\ A faire plus tard : 30/05/5024
aller chercher le nombre de jour de formation sur le mois.
exemple le cas des formations qui finissent en milieu d'un mois
"""
elif( price_by_session == "persession"):
montant_total_ht_session = montant_total_ht_session + prix_session
"""
/!\ A faire plus tard : 30/05/5024
aller chercher le nombre de jour de formation sur le mois.
exemple le cas des formations qui finissent en milieu d'un mois
"""
montant_total_ht = montant_total_ht + montant_total_ht_session
partner_invoice_line_data = {}
list_partner_invoice_line_champ = ['order_line_formation', 'order_line_qty', 'order_line_prix_unitaire',
'order_line_tax', 'order_line_tax_amount',
'order_line_montant_toutes_taxes',
'order_line_montant_hors_taxes', 'order_line_type_reduction',
'order_line_type_valeur', 'order_line_montant_reduction',
'order_header_ref_interne',
'order_line_comment', 'order_header_id', 'valide', 'locked',
'date_update',
'partner_owner_recid', 'invoice_header_ref_interne', 'invoice_line_type',
'invoice_date', 'invoice_header_id']
# PreRemplir les champs
for val in list_partner_invoice_line_champ:
partner_invoice_line_data[str(val)] = ""
partner_invoice_line_data['order_line_formation'] = class_intenal_url_session
partner_invoice_line_data['order_line_qty'] = str(nb_participant)
partner_invoice_line_data['order_line_prix_unitaire'] = str(prix_session)
partner_invoice_line_data['order_line_montant_hors_taxes'] = str(montant_total_ht_session)
partner_invoice_line_data['order_line_comment'] = str(liste_participant)
partner_invoice_line_data['invoice_line_type'] = "facture"
partner_invoice_line_data['code_session'] = session_data
partner_invoice_line_data['update_by'] = "auto"
partner_invoice_line_data['valide'] = "1"
partner_invoice_line_data['locked'] = "0"
partner_invoice_line_data['partner_owner_recid'] = str(partner_owner_recid)
if( "order_line_formation" in partner_invoice_line_data.keys() and partner_invoice_line_data['order_line_formation'] and
"order_line_qty" in partner_invoice_line_data.keys() and partner_invoice_line_data['order_line_qty'] ):
tab_ligne_a_facturer.append(partner_invoice_line_data)
print(" ### montant_total_ht = ", montant_total_ht)
"""
1 - recuperation des données du client
"""
client_data = MYSY_GV.dbname['partner_client'].find_one({'_id':ObjectId(str(diction['list_client'][0])),
'valide':'1',
'locked':'0',
'partner_recid':str(str(data_array[0]['partner_owner_recid']))})
if( client_data is None ):
mycommon.myprint(
str(inspect.stack()[0][3]) + " L'identifiant du client "+str(data_array[0]['client_id'])+" est invalide ")
return False, " L'identifiant du client "+str(data_array[0]['client_id'])+" est invalide "
local_status, my_partner = mycommon.Get_Connected_User_Partner_Data_From_RecID( str(data_array[0]['partner_owner_recid']))
if (local_status is not True):
return local_status, my_partner
# Recuperation des contacts de communication du client
local_diction = {}
local_diction['token'] = str(my_partner['token'])
local_diction['_id'] = str(client_data['_id'])
print(" ##### local_diction = ", local_diction)
local_status, partner_client_contact_communication = partner_client.Get_Partner_Client_Communication_Contact(
local_diction)
if (local_status is False):
mycommon.myprint(" Impossible de récupérer les contacts de communication du client ")
return False, " Impossible de récupérer les contacts de communication du client "
partner_invoice_header_data = {}
list_partner_invoice_header_champ = ['order_header_client_id', 'order_header_ref_interne',
'order_header_email_client', 'order_header_origin',
'order_header_ref_client', 'order_header_vendeur_id',
'order_header_date_cmd', 'order_header_date_expiration',
'order_header_adr_fact_adresse', 'order_header_adr_fact_code_postal',
'order_header_adr_fact_ville', 'order_header_adr_fact_pays',
'order_header_adr_liv_adresse', 'order_header_adr_liv_code_postal',
'order_header_adr_liv_ville', 'order_header_adr_liv_pays', 'valide',
'locked', 'date_update',
'order_header_montant_reduction', 'order_header_tax',
'order_header_tax_amount', 'total_header_hors_taxe_after_header_reduction',
'total_header_hors_taxe_before_header_reduction',
'total_header_toutes_taxes', 'total_lines_hors_taxe_after_lines_reduction',
'total_lines_hors_taxe_before_lines_reduction',
'total_lines_montant_reduction', 'invoice_header_ref_interne',
'invoice_header_type', 'invoice_date', 'update_by']
# PreRemplir les champs
for val in list_partner_invoice_header_champ:
partner_invoice_header_data[str(val)] = ""
partner_invoice_header_data['order_header_client_id'] = str(client_data['_id'])
"""
Recuperation des conditions de paiement depuis le client
"""
ction_paiement_code = ""
ction_paiement_desc = ""
ction_paiement_depart = "facture"
ction_paiement_nb_jour = "0"
if ("invoice_condition_paiement_id" in client_data.keys() and client_data[
'invoice_condition_paiement_id']):
ction_paiement_data = MYSY_GV.dbname['base_partner_paiement_condition'].find_one(
{'partner_owner_recid': my_partner['recid'],
'valide': '1',
'locked': '0',
'_id': ObjectId(str(client_data['invoice_condition_paiement_id']))})
if (ction_paiement_data and "code" in ction_paiement_data.keys() and ction_paiement_data['code']):
ction_paiement_code = ction_paiement_data['code']
if (ction_paiement_data and "description" in ction_paiement_data.keys() and ction_paiement_data[
'description']):
ction_paiement_desc = ction_paiement_data['description']
if (ction_paiement_data and "nb_jour" in ction_paiement_data.keys() and ction_paiement_data['nb_jour'] and
"depart" in ction_paiement_data.keys() and ction_paiement_data['depart']):
ction_paiement_nb_jour = ction_paiement_data['nb_jour']
ction_paiement_depart = ction_paiement_data['depart']
nb_jour_int = mycommon.tryInt(str(ction_paiement_nb_jour))
today = datetime.today()
date_echance = datetime.today()
if (str(ction_paiement_depart) == "mois"):
days_in_month = lambda dt: monthrange(dt.year, dt.month)[1]
first_day_next_month = today.replace(day=1) + timedelta(days_in_month(today))
date_echance = first_day_next_month + timedelta(days=nb_jour_int)
else:
date_echance = today + timedelta(days=nb_jour_int)
date_echance = date_echance.strftime("%d/%m/%Y")
partner_invoice_header_data['invoice_date_echeance'] = str(date_echance)
partner_invoice_header_data['order_header_condition_paiement_code'] = str(ction_paiement_code)
partner_invoice_header_data['order_header_condition_paiement_description'] = str(ction_paiement_desc)
partner_invoice_header_data['order_header_ref_interne'] = "Fact_Auto_" + str(todays_date_mode_2)
order_header_email_client = ""
if ("email" in client_data.keys()):
order_header_email_client = client_data['email']
partner_invoice_header_data['order_header_email_client'] = order_header_email_client
order_header_origin = "session_id_" + str(client_data['_id'])
partner_invoice_header_data['order_header_origin'] = order_header_origin
order_header_adr_fact_adresse = ""
if ("invoice_adresse" in client_data.keys()):
order_header_adr_fact_adresse = client_data['invoice_adresse']
partner_invoice_header_data['order_header_adr_fact_adresse'] = order_header_adr_fact_adresse
order_header_adr_fact_ville = ""
if ("invoice_ville" in client_data.keys()):
order_header_adr_fact_ville = client_data['invoice_adresse']
partner_invoice_header_data['order_header_adr_fact_ville'] = order_header_adr_fact_ville
order_header_adr_fact_code_postal = ""
if ("invoice_code_postal" in client_data.keys()):
order_header_adr_fact_code_postal = client_data['invoice_code_postal']
partner_invoice_header_data['order_header_adr_fact_code_postal'] = order_header_adr_fact_code_postal
order_header_adr_fact_pays = ""
if ("invoice_pays" in client_data.keys()):
order_header_adr_fact_pays = client_data['invoice_pays']
partner_invoice_header_data['order_header_adr_fact_pays'] = order_header_adr_fact_pays
order_header_montant_reduction = "0"
partner_invoice_header_data['order_header_montant_reduction'] = order_header_montant_reduction
partner_invoice_header_data['total_header_hors_taxe_before_header_reduction'] = str(montant_total_ht)
# Recupération de la TVA de l'entité qui facture
taux_tva_statuts, taux_tva_retval = partner_base_setup.Get_Given_Partner_Basic_Setup(
{'token': str(my_partner['token']), 'config_name': 'tva'})
if (taux_tva_statuts is False):
mycommon.myprint(str(inspect.stack()[0][3]) + " Facturation : Impossible de récupérer le taux de TVA ")
return False, " Facturation : Impossible de récupérer le taux de TVA "
tmp = ast.literal_eval(taux_tva_retval[0])
taux_tva_retval = tmp['config_value']
tva_status, tva_value = mycommon.IsFloat(str(taux_tva_retval))
if (tva_status is False):
mycommon.myprint(str(inspect.stack()[0][3]) + " Facturation : Le taux de TVA est invalide ")
return False, " Facturation : Le taux de TVA est invalide "
partner_invoice_header_data['order_header_tax'] = taux_tva_retval
partner_invoice_header_data['order_header_tax_amount'] = str(round(tva_value * montant_total_ht / 100, 2))
partner_invoice_header_data['total_header_toutes_taxes'] = str(
round(montant_total_ht + (tva_value * montant_total_ht) / 100, 2))
partner_invoice_header_data['invoice_header_type'] = "facture"
# Récuperation de la sequence de l'objet "partner_invoice_header" dans la collection : "mysy_sequence"
retval_sequence_invoice = MYSY_GV.dbname['mysy_sequence'].find_one(
{'partner_invoice_header': 'partner_order_header',
'valide': '1', 'partner_owner_recid': str(
my_partner['recid'])})
if (retval_sequence_invoice is None):
# Il n'y pas de sequence pour le partenaire, on va aller chercher la sequence par defaut
retval_sequence_invoice = MYSY_GV.dbname['mysy_sequence'].find_one(
{'related_mysy_object': 'partner_invoice_header',
'valide': '1', 'partner_owner_recid': 'default'})
if (retval_sequence_invoice is None or "current_val" not in retval_sequence_invoice.keys()):
# Il n'y aucune sequence meme par defaut.
mycommon.myprint(" Facture : Impossible de récupérer la sequence 'retval_sequence_invoice' ")
return False, "Facture : Impossible de récupérer la sequence 'retval_sequence_invoice' ", False
current_seq_value = str(retval_sequence_invoice['current_val'])
new_sequence_value = int(mycommon.tryInt(current_seq_value)) + 1
new_sequance_data_to_update = {'current_val': new_sequence_value}
ret_val2 = MYSY_GV.dbname['mysy_sequence'].find_one_and_update(
{'_id': ObjectId(str(retval_sequence_invoice['_id'])), 'valide': '1'},
{"$set": new_sequance_data_to_update},
return_document=ReturnDocument.AFTER,
upsert=False,
)
invoice_date_time = str(datetime.now().strftime("%d/%m/%Y"))
"""
Verifier qu'il n'y pas une facture du partenaire avec le meme ref interne
"""
is_already_invoice_ref_exist = MYSY_GV.dbname['partner_invoice_header'].count_documents(
{'partner_invoice_header': str(my_partner['recid']),
'valide': '1',
'invoice_header_ref_interne': str(retval_sequence_invoice['prefixe'] + str(current_seq_value))})
if (is_already_invoice_ref_exist > 0):
mycommon.myprint(" Facture : Il existe déjà une facture avec la même ref. interne : " + str(
retval_sequence_invoice['prefixe'] + str(current_seq_value)))
return False, " Facture : Il existe déjà une facture avec la même ref. interne : " + str(
retval_sequence_invoice['prefixe'] + str(current_seq_value)), False
partner_invoice_header_data['invoice_header_ref_interne'] = retval_sequence_invoice['prefixe'] + str(
current_seq_value)
partner_invoice_header_data['invoice_header_type'] = "facture"
partner_invoice_header_data['invoice_date'] = invoice_date_time
partner_invoice_header_data['update_by'] = str(my_partner['_id'])
partner_invoice_header_data['valide'] = "1"
partner_invoice_header_data['locked'] = "0"
partner_invoice_header_data['partner_owner_recid'] = str(my_partner['recid'])
partner_invoice_header_data['date_update'] = str(datetime.now())
ref_interne_facture = retval_sequence_invoice['prefixe'] + str(
current_seq_value)
print(" #### partner_invoice_header_data = ", partner_invoice_header_data)
inserted_invoice_id = MYSY_GV.dbname['partner_invoice_header'].insert_one(
partner_invoice_header_data).inserted_id
if (not inserted_invoice_id):
mycommon.myprint(" Facture : Impossible de créer l'entête de la facture ")
return False, " Facture : Impossible de créer l'entête de la facture "
"""
Création des lignes de facture.
Pour memo, dans la collection : partner_invoice_line
order_line_formation = titre formation
order_line_qty = nb participants
order_line_comment = la liste des personnes participans
"""
for line in tab_ligne_a_facturer :
if( "order_line_formation" in line.keys() and line['order_line_formation'] and
"order_line_qty" in line.keys() and line['order_line_qty']):
line['invoice_header_id'] = str(inserted_invoice_id)
line['invoice_header_ref_interne'] = partner_invoice_header_data[
'invoice_header_ref_interne']
line['update_by'] = str(my_partner['_id'])
line['valide'] = "1"
line['locked'] = "0"
line['partner_owner_recid'] = str(my_partner['recid'])
print(" #### partner_invoice_line_data = ", line)
inserted_invoice_id = MYSY_GV.dbname['partner_invoice_line'].insert_one(
line).inserted_id
if (not inserted_invoice_id):
mycommon.myprint(" Facture : Impossible de créer les lignes de la facture " + str(
partner_invoice_header_data['invoice_header_ref_interne']))
return False, " Facture : Impossible de créer les lignes de la facture " + str(
partner_invoice_header_data['invoice_header_ref_interne'])
"""
Mettre à jour les inscrit avec le numero de facture
"""
ref_facture = ref_interne_facture
for val in diction['detail_data']:
if( "inscription_id" in val.keys() and val['inscription_id']):
node = {}
node['invoiced_date'] = str(date.today().strftime("%Y-%m-%d"))
node['invoiced_ref'] = str(ref_interne_facture)
inscription_data = MYSY_GV.dbname['inscription'].find_one({'_id':ObjectId(str(val['inscription_id']))})
local_list_facture = []
if( "list_facture" in inscription_data.keys() and inscription_data['list_facture']):
inscription_data['list_facture'] .append(node)
else:
inscription_data['list_facture'] = []
inscription_data['list_facture'] .append(node)
inscription_data['invoiced_date'] = str(date.today().strftime("%Y-%m-%d"))
inscription_data['invoiced_ref'] = str(ref_interne_facture)
del inscription_data['_id']
update_attendee_data = MYSY_GV.dbname['inscription'].find_one_and_update(
{'_id':ObjectId(str(val['inscription_id']))},
{"$set": inscription_data},
upsert=False,
return_document=ReturnDocument.AFTER
)
else:
mycommon.myprint(" Impossible de récupérer les invoice_condition_paiement_id du client ")
return False, " Impossible de récupérer les invoice_condition_paiement_id du client "
print(" FACTION CREE = ", ref_interne_facture)
return True, ""
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno)
"""
Ce cron permet d'envoyer les documents automatique qui sont paramettrés dans la collection : "base_document_automatic_setup".
Dans cette collection
Alogorithme :
/!\ Ce cron doit tourner tous les jours à 23h
1 - On va aller directement dans le collection 'session_formation' recuperer toutes les session ayant : {'automatic_traitement.actif':'1',
automatic_traitement.statut != '2' (statut 2 = Done) }
2 - Pour chacune des line retournées, on va faire le calcul manuellement (on pas un nombre gigantesque de session, ca peut donc passer pendant
qqtps, deplus ce sont des traitement noctures, donc ca devrait aller.
=> Pour chaque ligne (type document pr une session), on va faire le calcul :
- si start_date session = Date Today + nb_jour_action, alors il faut lancer l'edition des documents.
A la fin, ne surtout pas oublié de mettre à jour la ligne "session_formation.automatic_traitement" avec les info :
- actif = -1
- statut = 2 (done)
- date_traitement = date du jour
- statut traitement :
- commentaire : combien de document envoyé.
"""
def Cron_Daily_Automatic_Qualiopi_Documents():
try:
print(" Cron : In function = Cron_Daily_Document_Sending")
todays_date = str(date.today().strftime("%d/%m/%Y"))
todays_date_ISODATE = datetime.strptime(str(todays_date), '%d/%m/%Y')
qry_list_session_concerned = {}
qry_list_session_concerned['valide'] = "1"
qry_list_session_concerned['automatic_traitement.actif'] = "1"
qry_list_session_concerned['automatic_traitement.valide'] = "1"
#qry_list_session_concerned['automatic_traitement.statut'] = {"$ne": "2"}
print(" ### qry_list_session_concerned = ", qry_list_session_concerned)
for my_session in MYSY_GV.dbname['session_formation'].find(qry_list_session_concerned):
print(" # Code Session = ", my_session['code_session'])
print(" # Date Start Session = ", my_session['date_debut'])
print(" # Date End Session = ", my_session['date_fin'])
#print(" # automatic_traitement = ", my_session['automatic_traitement'])
diction_for_notification_email = {}
diction_for_notification_email['session_id'] = str(my_session['_id'])
diction_for_notification_email['tab_message'] = []
diction_for_notification_email['global_status'] = []
for data_automatic_traitement in my_session['automatic_traitement'] :
if (data_automatic_traitement["actif"] == "1" and data_automatic_traitement["valide"] == "1" and data_automatic_traitement["statut"] != "2"):
print(" # Analyse Document = ", str(data_automatic_traitement['nom_document']), " Pour la session_code = ", str(my_session['code_session']), )
print(" # Target Date = ", data_automatic_traitement['action_target_date'])
print(" # Nb jour action = ", data_automatic_traitement['nb_jour_action'])
print(" # Date du jour = ", str(todays_date))
local_status, nb_jour_action_Int = mycommon.IsInt(str(data_automatic_traitement['nb_jour_action']).strip())
if (local_status is False):
mycommon.myprint(str(
inspect.stack()[0][
3]) + " CRON WARNING : nb_jour_action_Int n'est pas une valeur entière. Session Formation = ", str(my_session['_id']))
# On log une erreur, et on continue le traitement dans la boucle.
continue
local_session_start_date = datetime.strptime(str(my_session['date_debut']).strip(), '%d/%m/%Y')
local_session_end_date = datetime.strptime(str(my_session['date_fin']).strip(), '%d/%m/%Y')
local_session_target_date_added_nb_jour_action = ""
local_session_target_date_added_nb_jour_action_formated = ""
if( data_automatic_traitement['action_target_date'] == "start_session"):
local_session_target_date_added_nb_jour_action = local_session_start_date + timedelta(days=nb_jour_action_Int)
local_session_target_date_added_nb_jour_action_formated = str(local_session_target_date_added_nb_jour_action.strftime("%d/%m/%Y"))
elif( data_automatic_traitement['action_target_date'] == "end_session"):
local_session_target_date_added_nb_jour_action = local_session_end_date + timedelta(days=nb_jour_action_Int)
local_session_target_date_added_nb_jour_action_formated = str(local_session_target_date_added_nb_jour_action.strftime("%d/%m/%Y"))
elif ( data_automatic_traitement['action_target_date'] == "every_session_sequence_day"):
"""
Il faut aller voir si on a une sequence en date d'aujoud'hui pour cette session.
Si oui, alors on local_session_target_date_added_nb_jour_action = date to day
"""
local_session_target_date_added_nb_jour_action = datetime.strptime(str(todays_date).strip(),'%d/%m/%Y')
print(" ### CMP 1 local_session_target_date_added_nb_jour_action = ", local_session_target_date_added_nb_jour_action)
print(" ### CMP 2 datetime.strptime(str(todays_date).strip(), '%d/%m/%Y') = ",
datetime.strptime(str(todays_date).strip(), '%d/%m/%Y'))
if (data_automatic_traitement['action_target_date'] == "start_session"):
print(" ### delta day (start_session) = ", datetime.strptime(str(todays_date).strip(), '%d/%m/%Y') - local_session_start_date )
if (data_automatic_traitement['action_target_date'] == "end_session"):
print(" ### delta day (end_session) = ", datetime.strptime(str(todays_date).strip(), '%d/%m/%Y') - local_session_end_date )
if (local_session_target_date_added_nb_jour_action > datetime.strptime(str(todays_date).strip(), '%d/%m/%Y')):
print(" ### SUPPPPPP : Action à faire dans le futur ")
elif (local_session_target_date_added_nb_jour_action < datetime.strptime(str(todays_date).strip(), '%d/%m/%Y') ):
print(" ### INFFFFFF : Alert il y a un pb sur une action non realiser ")
mycommon.myprint(str(
inspect.stack()[0][
3]) + " CRON WARNING * Cron_Daily_Document_Sending: Il a un CRON qui ne n'est pas exécuté à la date prévue."
" Session Formation = " + str(
my_session['_id']) + " Id du CRON courrier_template_type_document_id = " + str(
data_automatic_traitement['courrier_template_type_document_id']))
courrier_template_type_document_data = MYSY_GV.dbname[
'courrier_template_type_document'].find_one(
{'ref_interne': data_automatic_traitement['courrier_template_type_document_ref_interne'],
'valide': '1',
'locked': '0'})
node_notification = {}
node_notification['message'] = "Cette tâche n'a pas été exécutée. " \
" Date Initialement prévue "+str(local_session_target_date_added_nb_jour_action_formated)
node_notification['status'] = "Warning"
node_notification['action'] = str(courrier_template_type_document_data['ref_interne'])
diction_for_notification_email['tab_message'].append(node_notification)
diction_for_notification_email['global_status'].append("warning")
elif (local_session_target_date_added_nb_jour_action == datetime.strptime(str(todays_date).strip(), '%d/%m/%Y')):
"""
Effectuer l'action
"""
"""
Recuperer le type de document concerné
"""
courrier_template_type_document_data = MYSY_GV.dbname['courrier_template_type_document'].find_one(
{'ref_interne':data_automatic_traitement['courrier_template_type_document_ref_interne'],
'valide':'1',
'locked':'0'})
if( courrier_template_type_document_data and 'ref_interne' in courrier_template_type_document_data.keys() ):
print(" ### Action à faire : Envoyer le document de type ", courrier_template_type_document_data['ref_interne'])
else:
mycommon.myprint(str(
inspect.stack()[0][
3]) + " CRON WARNING * Cron_Daily_Document_Sending: Impossible de trouver le type de document concerné "
" Session Formation = " + str(
my_session['_id']) + " Id du CRON courrier_template_type_document_id = " + str(
data_automatic_traitement['courrier_template_type_document_id']))
continue
#print(" ### avant action 1 courrier_template_type_document_data = ", courrier_template_type_document_data)
#print(" ## data_automatic_traitement = ", data_automatic_traitement)
local_diction = {}
local_diction['session_id'] = str(my_session['_id'])
local_diction['document_ref_intern'] = str(courrier_template_type_document_data['ref_interne'])
local_diction['partner_owner_recid'] = str(my_session['partner_owner_recid'])
local_diction['courrier_template_type_document_ref_interne'] = str(data_automatic_traitement['courrier_template_type_document_ref_interne'])
local_diction['courrier_template_type_document_id'] = str( data_automatic_traitement['courrier_template_type_document_id'])
#print( " ### local_diction for Send_document_from_base_document_automatic_setup = ", local_diction)
local_status, local_retval = Send_document_from_base_document_automatic_setup(local_diction)
node_notification = {}
node_notification['message'] = str(courrier_template_type_document_data['ref_interne'])
local_status_tanslate = ""
if( local_status is True ):
local_status_tanslate = "Ok"
else:
local_status_tanslate = "Erreur"
node_notification['status'] = str(local_status_tanslate)
node_notification['action'] = str(courrier_template_type_document_data['ref_interne'])
diction_for_notification_email['tab_message'].append(node_notification)
diction_for_notification_email['global_status'].append(str(local_status).lower())
"""
Mettre à jour le document
/!\ 17/04/25 : Lorsqu'il s'agit d'une action d'emargement avec un targuet = 'every_session_sequence_day', alors
on ne desactive l'action que si la date du jous >= a la date de fin de session
"""
if( data_automatic_traitement['action_target_date'] != "every_session_sequence_day" or
( data_automatic_traitement['action_target_date'] == "every_session_sequence_day" and
local_session_end_date <= datetime.strptime(str(todays_date).strip(), '%d/%m/%Y') )):
local_update = MYSY_GV.dbname['session_formation'].update_many(
{'_id': ObjectId(str(my_session['_id'])),
'partner_owner_recid':str(my_session['partner_owner_recid']),
'valide': '1',
'automatic_traitement.courrier_template_type_document_id': str(data_automatic_traitement['courrier_template_type_document_id'])
},
{'$set':
{
'automatic_traitement.$[xxx].actif': "-1",
'automatic_traitement.$[xxx].statut': "2",
'automatic_traitement.$[xxx].date_traitement_cron': str(datetime.now()),
'automatic_traitement.$[xxx].date_update': str(datetime.now()),
'automatic_traitement.$[xxx].update_by': "Automatic Cron",
}
},
upsert=False,
array_filters=[
{"xxx.courrier_template_type_document_id": str(data_automatic_traitement['courrier_template_type_document_id'])}
]
)
if( local_update.matched_count < 1 ):
mycommon.myprint(str(
inspect.stack()[0][
3]) + " CRON WARNING * Cron_Daily_Document_Sending: La mise à jour du statut (actif = -1) du cron ne s'est "
" PAS bien passé : Session Formation = "+ str(my_session['_id'])+
" Id du CRON courrier_template_type_document_id = "+
str(data_automatic_traitement['courrier_template_type_document_id']))
local_status, my_partner = mycommon.Get_Connected_User_Partner_Data_From_RecID(str(my_session['partner_owner_recid']))
if (local_status is not True):
return local_status, my_partner
diction_for_notification_email['token'] = str(my_partner['token'])
local_status, local_retval = Job_Cron_Common.Cron_Qualiopi_Automatic_Traitement_Notification(diction_for_notification_email)
return True, "OK"
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno)
"""
Cette fonction prend en argument :
- L'_id de la session de formation
- Le type de document (ref_interne)
- Le partner_owner_recid (ceci pour aller choisir les documents qu'il a configurés)
puis procede à l'envoie des document
"""
def Send_document_from_base_document_automatic_setup(diction):
try:
diction = mycommon.strip_dictionary(diction)
"""
Verification des input acceptés
"""
field_list = [ 'session_id', 'document_ref_intern','partner_owner_recid',
'courrier_template_type_document_ref_interne', 'courrier_template_type_document_id']
incom_keys = diction.keys()
for val in incom_keys:
if val not in field_list and val.startswith('my_') is False:
mycommon.myprint(str(
inspect.stack()[0][3]) + " Le champ '" + val + "' n'est pas autorisé")
return False, " Les informations fournies sont incorrectes"
"""
Verification des champs obligatoires
"""
field_list_obligatoire = [ 'session_id', 'document_ref_intern', 'partner_owner_recid']
for val in field_list_obligatoire:
if val not in diction:
mycommon.myprint(
str(inspect.stack()[0][3]) + " - La valeur '" + val + "' n'est pas presente dans liste ")
return False, " Les informations fournies sont incorrectes"
"""
On va aller recuperer le courrier configuré par default
"""
local_status, my_partner = mycommon.Get_Connected_User_Partner_Data_From_RecID(
str(diction['partner_owner_recid']))
if (local_status is not True):
return local_status, my_partner
if( str(diction['document_ref_intern']) == 'CONVENTION_STAGIAIRE_ENTREPRISE' or str(diction['document_ref_intern']) == 'CONVENTION_STAGIAIRE_INDIVIDUELLE' ):
local_diction = {}
local_diction['token'] = my_partner['token']
local_diction['session_id'] = diction['session_id']
local_diction['courrier_template_id'] = ""
#print(" ### local_diction for Prepare_and_Send_Default_Convention_From_Session_By_PDF= ", local_diction)
local_status, local_retval = Session_Formation.Prepare_and_Send_Default_Convention_From_Session_By_PDF(local_diction)
local_diction_by_email = {}
local_diction_by_email['token'] = my_partner['token']
local_diction_by_email['session_id'] = diction['session_id']
local_diction_by_email['courrier_template_id'] = ""
local_diction_by_email['email_test'] = ""
local_diction_by_email['email_production'] = ""
local_diction_by_email['request_digital_signature'] = "1"
tab_files = []
Folder = ""
local_status, local_retval = Session_Formation.Prepare_and_Send_Default_Convention_From_Session_By_Email(tab_files,
Folder, local_diction_by_email)
elif ( str(diction['document_ref_intern']) == 'CONVOCATION_STAGIAIRE' ):
print(" ### Envoyer les convocations aux participants ")
local_diction_convocation_by_email = {}
local_diction_convocation_by_email = diction
local_diction_convocation_by_email['token'] = my_partner['token']
local_convoc_status, local_convoc_retval = Cron_Session_Convocation_Sending(local_diction_convocation_by_email)
elif ( str(diction['document_ref_intern']) == 'QUESTION_POSITIONNEMENT' ):
"""
1 - Aller chercher le formulaire (type = questionnaire de positionnement ) par defaut
2 - Initialiser l'enquete
3 - Envoyer l'enquete
"""
print(" ### DEBUT Initialiser le questionnaire de positionnement ")
local_default_form_count = MYSY_GV.dbname['formulaire'].count_documents(
{'type':'pos',
'valide': '1',
'locked': '0',
'default': '1',
'partner_owner_recid': str(my_partner['recid'])})
if(local_default_form_count != 1 ):
mycommon.myprint(
str(inspect.stack()[0][3]) + " La configuration du questionnaire de positionnement par défaut est invalide. Nb formulaire = "+str(local_default_form_count))
return False, " La configuration du questionnaire de positionnement par défaut est invalide"
local_default_form_data = MYSY_GV.dbname['formulaire'].find_one(
{'type': 'pos',
'valide': '1',
'locked': '0',
'default': '1',
'partner_owner_recid': str(my_partner['recid'])}, {'_id':1})
init_diction = {}
init_diction['token']= my_partner['token']
init_diction['session_id'] = diction['session_id']
init_diction['formulaire_id'] = local_default_form_data['_id']
init_diction['survey_type'] = "pos"
init_diction['sending_date'] = ""
init_diction['related_collection'] = "inscription"
local_status_init, local_retval_init = Job_Cron_Common.Cron_Init_Survey_Tab_For_Inscrit_Not_Init(init_diction)
if( local_status_init is False ):
return local_status_init, local_retval_init
print(" ### DEBUT Envoyer le questionnaire de positionnement ")
local_status_send, local_retval_send = Job_Cron_Common.Cron_Send_Survey_TabIds(init_diction)
if (local_status_send is False):
return local_status_send, local_retval_send
elif ( str(diction['document_ref_intern']) == 'EVAL_FORMATION' ):
"""
Evaluation à chaud
"""
print(" ### DEBUT Initialiser le questionnaire d'evaluation à chaud ")
local_default_form_count = MYSY_GV.dbname['formulaire'].count_documents(
{'type': 'hot_eval',
'valide': '1',
'locked': '0',
'default': '1',
'partner_owner_recid': str(my_partner['recid'])})
if (local_default_form_count != 1):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " La configuration du questionnaire de positionnement par défaut est invalide. Nb formulaire = ",
local_default_form_count)
return False, " La configuration du questionnaire d'évaluation à chaud par défaut est invalide"
local_default_form_data = MYSY_GV.dbname['formulaire'].find_one(
{'type': 'hot_eval',
'valide': '1',
'locked': '0',
'default': '1',
'partner_owner_recid': str(my_partner['recid'])}, {'_id': 1})
init_diction = {}
init_diction['token'] = my_partner['token']
init_diction['session_id'] = diction['session_id']
init_diction['formulaire_id'] = local_default_form_data['_id']
init_diction['survey_type'] = "hot_eval"
init_diction['sending_date'] = ""
init_diction['related_collection'] = "inscription"
local_status_init, local_retval_init = Job_Cron_Common.Cron_Init_Survey_Tab_For_Inscrit_Not_Init(
init_diction)
if (local_status_init is False):
return local_status_init, local_retval_init
print(" ### DEBUT Envoyer le questionnaire de Evaluation à Chaud ")
local_status_send, local_retval_send = Job_Cron_Common.Cron_Send_Survey_TabIds(init_diction)
if (local_status_send is False):
return local_status_send, local_retval_send
"""
Evaluation du formateur mis que la session de formation, si formateur
"""
print(" ### DEBUT Initialiser le questionnaire d'évaluation du formateur mis sur la session ")
#1 - Verifier s'il y a un formateur valide sur la session
session_data = MYSY_GV.dbname['session_formation'].find_one({'_id':ObjectId(str(diction['session_id']))}, {'_id':1, 'formateur_id':1})
if( session_data and "formateur_id" in session_data.keys() and session_data['formateur_id']):
# Aller chercher le formulaire par défaut pour l'evaluation des enseignants
local_default_form_count = MYSY_GV.dbname['formulaire'].count_documents(
{'type': 'human_eval',
'valide': '1',
'locked': '0',
'default': '1',
'partner_owner_recid': str(my_partner['recid'])})
if (local_default_form_count != 1):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " La configuration du questionnaire d'évaluation du formateur par défaut est invalide. Nb formulaire = " + str(
local_default_form_count))
return False, " La configuration du questionnaire d'évaluation du formateur par défaut est invalide"
local_default_form_data = MYSY_GV.dbname['formulaire'].find_one(
{'type': 'human_eval',
'valide': '1',
'locked': '0',
'default': '1',
'partner_owner_recid': str(my_partner['recid'])}, {'_id': 1})
init_diction = {}
init_diction['token'] = my_partner['token']
init_diction['session_id'] = diction['session_id']
init_diction['formulaire_id'] = local_default_form_data['_id']
init_diction['survey_type'] = "human_eval"
init_diction['sending_date'] = ""
init_diction['related_collection'] = "ressource_humaine"
init_diction['related_collection_id'] = str(session_data['formateur_id'])
local_status_init, local_retval_init = Job_Cron_Common.Cron_Init_Survey_Tab_For_Inscrit_Not_Init(
init_diction)
if (local_status_init is False):
return local_status_init, local_retval_init
print(" ### DEBUT Envoyer le questionnaire de Evaluation du formateur ")
print(" envoi eval formateur init_diction = ", init_diction)
local_status_send, local_retval_send = Job_Cron_Common.Cron_Send_Survey_TabIds(init_diction)
if (local_status_send is False):
return local_status_send, local_retval_send
"""
Evaluation à froid à envoyer 3 mois plus tard
"""
print(" ### DEBUT Initialiser le questionnaire d'evaluation à froid à faire 3 mois plus tard ")
local_default_form_count = MYSY_GV.dbname['formulaire'].count_documents(
{'type': 'cold_eval',
'valide': '1',
'locked': '0',
'default': '1',
'partner_owner_recid': str(my_partner['recid'])})
if (local_default_form_count != 1):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " La configuration du questionnaire d'évaluation à froid par défaut est invalide. Nb formulaire = "+str(
local_default_form_count))
return False, "La configuration du questionnaire d'évaluation à froid par défaut est invalide"
local_default_form_data = MYSY_GV.dbname['formulaire'].find_one(
{'type': 'cold_eval',
'valide': '1',
'locked': '0',
'default': '1',
'partner_owner_recid': str(my_partner['recid'])}, {'_id': 1})
today_plus_90_jours = date.today() + timedelta(days=90)
today_plus_90_jours_string = str(today_plus_90_jours.strftime("%d/%m/%Y"))
init_diction = {}
init_diction['token'] = my_partner['token']
init_diction['session_id'] = diction['session_id']
init_diction['formulaire_id'] = local_default_form_data['_id']
init_diction['survey_type'] = "cold_eval"
init_diction['sending_date'] = str(today_plus_90_jours_string)
init_diction['related_collection'] = "inscription"
local_status_init, local_retval_init = Job_Cron_Common.Cron_Init_Survey_Tab_For_Inscrit_Not_Init(
init_diction)
if (local_status_init is False):
return local_status_init, local_retval_init
elif ( str(diction['document_ref_intern']) == 'ATTESTATION_FORMATION' ):
print(" ### Debut Initialisation les attestations de formation ")
# 1 Recuperer le modele d'attestation par défaut
local_diction = {}
local_diction['ref_interne'] = "ATTESTATION_FORMATION"
local_diction['type_doc'] = "email"
local_diction['partner_owner_recid'] = str(diction['partner_owner_recid'])
local_diction['default_version'] = "1"
courrier_data_status, courrier_data_retval = mycommon.Get_Courrier_Template_Include_Default_Data(
local_diction)
if (courrier_data_status is False):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " Impossible de récuperer le modèle de courrier 'ATTESTATION_FORMATION', (type : Email) ")
return False, " Impossible de récuperer le modèle de courrier 'ATTESTATION_FORMATION', (type : Email) "
if ("contenu_doc" not in courrier_data_retval.keys() or str(courrier_data_retval['contenu_doc']) == ""):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " Le modèle de courrier 'ATTESTATION_FORMATION', (type : Email) n'est pas correctement configuré ")
return False, " Le modèle de courrier 'ATTESTATION_FORMATION', (type : Email) n'est pas correctement configuré"
init_diction = {}
init_diction['token'] = my_partner['token']
init_diction['session_id'] = diction['session_id']
init_diction['courrier_template_id'] = courrier_data_retval['_id']
local_status_init, local_retval_init = Job_Cron_Common.Cron_Init_Attestation_Formation_With_Template(init_diction)
if (local_status_init is False):
return local_status_init, local_retval_init
print(" ### Envoyer les attestations de formation ")
init_diction['email_test'] = ""
init_diction['email_production'] = ""
local_status_send_attestation, local_retval_send_attesation = Job_Cron_Common.Cron_Send_Attestation_From_Session_By_Email_for_not_sent(MYSY_GV.upload_folder, init_diction)
if (local_status_send_attestation is False):
return local_status_send_attestation, local_retval_send_attesation
elif ( str(diction['document_ref_intern']) == 'EMARGEMENT_FORMATION' ):
# 1 Recuperer le modele d'attestation par défaut
local_diction = {}
local_diction['ref_interne'] = "EMARGEMENT_FORMATION"
local_diction['type_doc'] = "email"
local_diction['partner_owner_recid'] = str(diction['partner_owner_recid'])
local_diction['default_version'] = "1"
courrier_data_status, courrier_data_retval = mycommon.Get_Courrier_Template_Include_Default_Data(
local_diction)
if (courrier_data_status is False):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " Impossible de récuperer le modèle de courrier 'EMARGEMENT_FORMATION', (type : Email) ")
return False, " Impossible de récuperer le modèle de courrier 'EMARGEMENT_FORMATION', (type : Email) "
if ("contenu_doc" not in courrier_data_retval.keys() or str(courrier_data_retval['contenu_doc']) == ""):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " Le modèle de courrier 'EMARGEMENT_FORMATION', (type : Email) n'est pas correctement configuré ")
return False, " Le modèle de courrier 'EMARGEMENT_FORMATION', (type : Email) n'est pas correctement configuré"
init_diction = {}
init_diction['token'] = my_partner['token']
init_diction['session_id'] = diction['session_id']
init_diction['courrier_template_id'] = courrier_data_retval['_id']
local_status_init, local_retval_init = Job_Cron_Common.Cron_Init_Emargement_By_Date_With_Template(
init_diction)
if (local_status_init is False):
return local_status_init, local_retval_init
init_diction['email_test'] = ""
init_diction['email_production'] = ""
local_status_send_attestation, local_retval_send_attesation, nb_emargment_traite = Job_Cron_Common.Cron_Send_Emargement_By_Date_By_Email_for_not_sent(
MYSY_GV.upload_folder, init_diction)
if (local_status_send_attestation is False):
return local_status_send_attestation, local_retval_send_attesation
if( nb_emargment_traite == "0"):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " WARNING : Aucune demande d'émargement envoyé. Verifier les données ")
return True, "OK Documents "
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, " Impossible d'envoyer automatiquement les documents "
"""
Cette fonction permet d'envoyer les convocation par defaut avec les cron
Algo :
1 - Recuperer le modele de document par defaut pour les convocations
2 - Envoyer les convocations
"""
def Cron_Session_Convocation_Sending(diction):
try:
diction = mycommon.strip_dictionary(diction)
"""
Verification des input acceptés
"""
field_list = [ 'token', 'session_id', 'document_ref_intern','partner_owner_recid',
'courrier_template_type_document_ref_interne', 'courrier_template_type_document_id']
incom_keys = diction.keys()
for val in incom_keys:
if val not in field_list and val.startswith('my_') is False:
mycommon.myprint(str(
inspect.stack()[0][3]) + " Le champ '" + val + "' n'est pas autorisé")
return False, " Les informations fournies sont incorrectes"
"""
Verification des champs obligatoires
"""
field_list_obligatoire = [ 'token', 'session_id', 'document_ref_intern','partner_owner_recid',
'courrier_template_type_document_ref_interne', 'courrier_template_type_document_id']
for val in field_list_obligatoire:
if val not in diction:
mycommon.myprint(
str(inspect.stack()[0][3]) + " - La valeur '" + val + "' n'est pas presente dans liste ")
return False, " Les informations fournies sont incorrectes"
local_status, my_partner = mycommon.Check_Connexion_And_Return_Partner_Data({'token': str(diction['token'])})
if (local_status is not True):
return local_status, my_partner
local_diction = {}
local_diction['ref_interne'] = "CONVOCATION_STAGIAIRE"
local_diction['type_doc'] = "email"
local_diction['partner_owner_recid'] = str(diction['partner_owner_recid'])
local_diction['default'] = "1"
courrier_data_status, courrier_data_retval = mycommon.Get_Courrier_Template_Include_Default_Data(local_diction)
if (courrier_data_status is False):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " Impossible de récuperer le modèle de courrier 'CONVOCATION_STAGIAIRE', (type : Email) ")
return False, " Impossible de récuperer le modèle de courrier 'CONVOCATION_STAGIAIRE', (type : Email) "
if ("contenu_doc" not in courrier_data_retval.keys() or str(courrier_data_retval['contenu_doc']) == ""):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " Le modèle de courrier 'CONVOCATION_STAGIAIRE', (type : Email) n'est pas correctement configuré ")
return False, " Le modèle de courrier 'CONVOCATION_STAGIAIRE', (type : Email) n'est pas correctement configuré"
print(" ### On a trouver un modele de convocation (type EMAIL) par defaut OKK")
local_diction_convocation_by_email = {}
local_diction_convocation_by_email['token'] = my_partner['token']
local_diction_convocation_by_email['session_id'] = diction['session_id']
local_diction_convocation_by_email['courrier_template_id'] = str(courrier_data_retval['_id'])
local_diction_convocation_by_email['email_test'] = ""
local_diction_convocation_by_email['email_production'] = ""
tab_files = []
Folder = ""
local_status, local_retval = Job_Cron_Common.Prepare_and_Send_Convocation_From_Session_By_Email(tab_files,
Folder, local_diction_convocation_by_email)
"""
Aller chercher le modele de courrier de type PDF
"""
local_diction = {}
local_diction['ref_interne'] = "CONVOCATION_STAGIAIRE"
local_diction['type_doc'] = "pdf"
local_diction['partner_owner_recid'] = str(diction['partner_owner_recid'])
local_diction['default'] = "1"
courrier_data_status, courrier_data_retval_pdf = mycommon.Get_Courrier_Template_Include_Default_Data(local_diction)
if (courrier_data_status is False):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " Impossible de récuperer le modèle de courrier 'CONVOCATION_STAGIAIRE', (type : PDF) ")
return False, " Impossible de récuperer le modèle de courrier 'CONVOCATION_STAGIAIRE', (type : PDF) "
if ("contenu_doc" not in courrier_data_retval_pdf.keys() or str(courrier_data_retval_pdf['contenu_doc']) == ""):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " Le modèle de courrier 'CONVOCATION_STAGIAIRE', (type : PDF) n'est pas correctement configuré ")
return False, " Le modèle de courrier 'CONVOCATION_STAGIAIRE', (type : PDF) n'est pas correctement configuré"
print(" ### On a trouver un modele de convocation (Type : PDF) par defaut OKK")
local_diction_convocation_by_PDF = {}
local_diction_convocation_by_PDF['token'] = my_partner['token']
local_diction_convocation_by_PDF['session_id'] = diction['session_id']
local_diction_convocation_by_PDF['courrier_template_id'] = str(courrier_data_retval_pdf['_id'])
local_status, local_retval = Job_Cron_Common.Prepare_and_Send_Convocation_From_Session_By_PDF(local_diction_convocation_by_PDF)
return True, "Les convocations ont été envoyées (CRON) "
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - Line : " + str(exc_tb.tb_lineno))
return False, " Impossible d'envoyer les convocations (CRON) "