master
cherif 2024-02-23 15:28:01 +01:00
parent c79e7710b0
commit 4bbe36b428
7 changed files with 2203 additions and 33 deletions

View File

@ -1,12 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="c6d0259a-16e1-410d-91a1-830590ee2a08" name="Changes" comment="17/02/2024 - 11h">
<list default="true" id="c6d0259a-16e1-410d-91a1-830590ee2a08" name="Changes" comment="dd">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Log/log_file.log" beforeDir="false" afterPath="$PROJECT_DIR$/Log/log_file.log" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Session_Formation.py" beforeDir="false" afterPath="$PROJECT_DIR$/Session_Formation.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/main.py" beforeDir="false" afterPath="$PROJECT_DIR$/main.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/partner_document_mgt.py" beforeDir="false" afterPath="$PROJECT_DIR$/partner_document_mgt.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/partner_order.py" beforeDir="false" afterPath="$PROJECT_DIR$/partner_order.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/partner_invoice.py" beforeDir="false" afterPath="$PROJECT_DIR$/partner_invoice.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/prj_common.py" beforeDir="false" afterPath="$PROJECT_DIR$/prj_common.py" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -76,13 +78,6 @@
<option name="presentableId" value="Default" />
<updated>1680804787304</updated>
</task>
<task id="LOCAL-00174" summary="15/12/2023 - 18h">
<created>1702658652894</created>
<option name="number" value="00174" />
<option name="presentableId" value="LOCAL-00174" />
<option name="project" value="LOCAL" />
<updated>1702658652895</updated>
</task>
<task id="LOCAL-00175" summary="16/12/2023 - 23h12">
<created>1702764810012</created>
<option name="number" value="00175" />
@ -419,7 +414,14 @@
<option name="project" value="LOCAL" />
<updated>1708179293703</updated>
</task>
<option name="localTasksCounter" value="223" />
<task id="LOCAL-00223" summary="18/02/2024 - 14h">
<created>1708260895527</created>
<option name="number" value="00223" />
<option name="presentableId" value="LOCAL-00223" />
<option name="project" value="LOCAL" />
<updated>1708260895528</updated>
</task>
<option name="localTasksCounter" value="224" />
<servers />
</component>
<component name="Vcs.Log.Tabs.Properties">
@ -434,8 +436,6 @@
</option>
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="16/01/2024 - 19h" />
<MESSAGE value="19/01/2024 - 16h" />
<MESSAGE value="21/01/2024 -18h30" />
<MESSAGE value="22/01/2024 -22h00" />
<MESSAGE value="24/01/2024 -12h00" />
@ -459,6 +459,8 @@
<MESSAGE value="sdsdqs" />
<MESSAGE value="13/02/2024 - 11h" />
<MESSAGE value="17/02/2024 - 11h" />
<option name="LAST_COMMIT_MESSAGE" value="17/02/2024 - 11h" />
<MESSAGE value="18/02/2024 - 14h" />
<MESSAGE value="dd" />
<option name="LAST_COMMIT_MESSAGE" value="dd" />
</component>
</project>

File diff suppressed because it is too large Load Diff

View File

@ -39,7 +39,7 @@ from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import partner_base_setup as partner_base_setup
"""
Fonction de creation et mise à jour d'une session de formation.
@ -4185,11 +4185,11 @@ def Duplicate_List_Session_Formation(diction):
"""
Cette fonction les convention par email de formation en partant de la session.
Cette fonction les conventions par email de formation en partant de la session.
Algo :
On recuperer les stagaiaires qu'on groupe par client_rattachement_id
On recuperer les stagiaires qu'on groupe par client_rattachement_id
Pour tous ceux qui on le meme, on envoie une convention groupée
pour les autres, on envoi des conventions individuelle
@ -6892,3 +6892,865 @@ def Sent_Attestation_Stagiaire_By_Email(tab_files, Folder, diction):
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 la convention par email "
"""
Cette fonction permet de facturer une session de formation selon les regles suivants :
Sur une session :
- les participants groupés par client_rattachement_id
- facturation du client si j'ai un client rattachement id
- Cas particulier :
- un participant qui est en autonome (donc pas de client )
- pour le facturer il faudra obligatoirement créer une client.
"""
def Prepare_and_Send_Facture_From_Session_By_Email(tab_files, Folder, diction):
try:
field_list_obligatoire = ['token', 'session_id', 'courrier_template_id', 'email_test', 'email_production']
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"
my_token = ""
if ("token" in diction.keys()):
if diction['token']:
my_token = diction['token']
local_status, my_partner = mycommon.Check_Connexion_And_Return_Partner_Data(diction)
if (local_status is not True):
return local_status, my_partner
# Verifier que la session est valide
is_session_valide = MYSY_GV.dbname['session_formation'].count_documents(
{'_id': ObjectId(str(diction['session_id'])),
'valide': '1',
'partner_owner_recid': str(my_partner['recid'])})
if (is_session_valide != 1):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " L'identifiant de la session est invalide ")
return False, " L'identifiant de la session est invalide "
# Verifier qu'il ya bien des inscriptions valides dans la session pour le client
liste_client_rattachement_id = MYSY_GV.dbname['inscription'].distinct("client_rattachement_id",
{'session_id':str(diction['session_id']),
'status': '1',
'partner_owner_recid': str(
my_partner['recid']),
"client_rattachement_id": { '$ne': ''}
}
)
print(" ### la liste des liste_client_rattachement_id = ", liste_client_rattachement_id)
# Sauvegarde des fichiers joints depuis le front
tab_saved_file_full_path = []
for file in tab_files:
status, saved_file_full_path = mycommon.Upload_Save_PDF_IMG_File(file, Folder)
if (status is False):
mycommon.myprint("Impossible de récupérer correctement le fichier à importer")
return False, "Impossible de récupérer correctement le fichier à importer"
tab_saved_file_full_path.append(saved_file_full_path)
print(" #### tab_saved_file_full_path = ", tab_saved_file_full_path)
# Recupération des données du modèle de document
courrier_template_data = MYSY_GV.dbname['courrier_template'].find_one(
{'_id': ObjectId(str(diction['courrier_template_id'])),
'valide': '1',
'locked': '0',
'partner_owner_recid': str(my_partner['recid'])}
)
# Envoie des conventions pour les inscrits AVEC client_id (conventions d'entreprise)
for single_client in liste_client_rattachement_id:
print(" Traintement du client_id = ", single_client)
# Recuperation des contacts de communication du client
local_diction = {}
local_diction['token'] = diction['token']
local_diction['_id'] = str(single_client)
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 "
print(" ### partner_client_contact_communication = ", partner_client_contact_communication)
tab_local_email_production = []
for tmp in partner_client_contact_communication:
tmp_JSON = ast.literal_eval(tmp)
if ("email" in tmp_JSON.keys()):
tab_local_email_production.append(str(tmp_JSON["email"]))
list_local_email_production = ",".join(tab_local_email_production)
new_diction_client = {}
new_diction_client['partner_client_id'] = single_client
new_diction_client['token'] = diction['token']
new_diction_client['courrier_template_id'] = diction['courrier_template_id']
new_diction_client['email_test'] = diction['email_test']
new_diction_client['email_production'] = str(list_local_email_production)
new_diction_client['session_id'] = diction['session_id']
print(" ##### new_diction_client 0102 = ", new_diction_client)
# Creation de la facture du client
diction_invoice = {}
diction_invoice['token'] = diction['token']
diction_invoice['partner_client_id'] = single_client
diction_invoice['session_id'] = diction['session_id']
print(" ##### diction_invoice 0202 = ", diction_invoice)
local_create_invoice_status, local_create_invoice_retval = Invoice_Partner_From_Session(diction_invoice)
if( local_create_invoice_status is False ):
return local_create_invoice_status, local_create_invoice_retval
"""
local_status, local_retval = Sent_Facture_Stagiaire_By_Email_By_Partner_client(tab_saved_file_full_path, Folder, new_diction_client)
if (local_status is False):
mycommon.myprint(" WARNING : impossible d'envoyer la convention au client : " + str(single_client))
"""
return True, " Les Factures ont été correctement créées et envoyées par emails"
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 de créer et d'envoyer les factures par email "
"""
Cette fonction va créer une facture pour un client
lié à des apprenants sur une session de formation
"""
def Invoice_Partner_From_Session( diction):
try:
field_list_obligatoire = ['token', 'partner_client_id', 'session_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, " La valeur '" + val + "' n'est pas presente dans liste"
my_token = ""
if ("token" in diction.keys()):
if diction['token']:
my_token = diction['token']
local_status, my_partner = mycommon.Check_Connexion_And_Return_Partner_Data(diction)
if (local_status is not True):
return local_status, my_partner
# Verifier que la session est valide
is_session_id_valide = MYSY_GV.dbname['session_formation'].count_documents(
{'_id': ObjectId(str(diction['session_id'])),
'valide': '1',
'partner_owner_recid': str(my_partner['recid'])})
if (is_session_id_valide != 1):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " L'identifiant de la session est invalide ")
return False, " L'identifiant de la session est invalide "
# Verifier que ce client a bien des inscriptions valide pour cette session
nb_valide_inscription_pr_client = MYSY_GV.dbname['inscription'].count_documents(
{'client_rattachement_id': str(diction['partner_client_id']),
'session_id': str(diction['session_id']),
'partner_owner_recid': str(my_partner['recid']),
'status': '1'})
if (nb_valide_inscription_pr_client <= 0):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " Aucune inscription valide pour ce client pour cette session ")
return False, " Aucune inscription valide pour ce client pour cette session "
partner_client_id_data = MYSY_GV.dbname['partner_client'].find_one(
{'_id': ObjectId(str(diction['partner_client_id'])),
'valide': '1',
'locked': '0',
'partner_recid': str(my_partner['recid'])})
# Recuperation des données du stagiaire
inscription_data = MYSY_GV.dbname['inscription'].find({'session_id': str(diction['session_id']),
'status': '1',
'partner_owner_recid': str(my_partner['recid']),
'client_rattachement_id':str(diction['partner_client_id'])})
tab_apprenant = []
tab_participant = []
for val in inscription_data:
tab_participant.append(val['_id'])
"""
update du 30/01/2024
si le participant à un apprenant_id, alors on recupere la valeur de l'apprenant id. On doit travailler sur cette dernier.
En general, avant d'envoyer une convocation ou convention, l'inscription est validée et donc le dossier apprenant existe.
Du coup si tout se passe bien, dans cette fonction, on travaillera tjrs avec l'apprenant_id
"""
if ("apprenant_id" in val.keys() and val['apprenant_id']):
tab_apprenant.append(ObjectId(str(val['apprenant_id'])))
print(" ### tab_participant = ", tab_participant)
# Recuperations des info de la session de formation
session_data = MYSY_GV.dbname['session_formation'].find_one({'_id': ObjectId(str(diction['session_id']))})
tab_session = []
tab_session.append(session_data['_id'])
# Recuperation du titre de la formation
class_data = MYSY_GV.dbname['myclass'].find({'internal_url': str(session_data['class_internal_url']),
'valide': '1',
'partner_owner_recid': str(my_partner['recid']),
'locked': '0'})
price_by = "perstagiaire"
if( "perstagiaire" in session_data.keys() ):
price_by = session_data['perstagiaire']
if( price_by not in MYSY_GV.TRAINING_PRICE) :
mycommon.myprint(str(inspect.stack()[0][3]) + " Le prix par " + str(price_by) + " n'est valide. Les valeurs autorisées sont " + str(MYSY_GV.TRAINING_PRICE))
return False, " Le prix par " + str(price_by) + " n'est valide. Les valeurs autorisées sont " + str(MYSY_GV.TRAINING_PRICE) + " "
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(partner_client_id_data['_id'])
code_session = ""
if( "code_session" in session_data.keys() ):
code_session = session_data['code_session']
partner_invoice_header_data['order_header_ref_interne'] = "Code_Session_"+str(code_session)
order_header_email_client = ""
if ("email" in partner_client_id_data.keys()):
order_header_email_client = partner_client_id_data['email']
partner_invoice_header_data['order_header_email_client'] = order_header_email_client
order_header_origin = "session_id_"+str(session_data['_id'])
partner_invoice_header_data['order_header_origin'] = order_header_origin
order_header_adr_fact_adresse = ""
if( "invoice_adresse" in partner_client_id_data.keys() ):
order_header_adr_fact_adresse = partner_client_id_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 partner_client_id_data.keys()):
order_header_adr_fact_ville = partner_client_id_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 partner_client_id_data.keys()):
order_header_adr_fact_code_postal = partner_client_id_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 partner_client_id_data.keys()):
order_header_adr_fact_pays = partner_client_id_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
# Calcul du Totol HT sans reduction
total_ht = 0
prix_session = 0
session_price = 0
if( "prix_session" not in session_data.keys() ):
mycommon.myprint(str(inspect.stack()[0][3]) + " Facturation : La session n'a pas de prix valide")
return False, " Facturation : La session n'a pas de prix valide "
if( str(session_data['prix_session']).strip() == "" ):
mycommon.myprint(str(inspect.stack()[0][3]) + " Facturation : La session n'a pas de prix valide (2) ")
return False, " Facturation : La session n'a pas de prix valide (2) "
prix_session = mycommon.tryFloat(str(session_data['prix_session']))
if( str(price_by).strip() == "persession" ):
total_ht = round(prix_session, 2)
else:
total_ht = round(prix_session * nb_valide_inscription_pr_client, 2)
partner_invoice_header_data['total_header_hors_taxe_before_header_reduction'] = 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(diction['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']
print(" ### taux_tva_retval = ", taux_tva_retval)
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'] = round(tva_value * total_ht, 2)
partner_invoice_header_data['total_header_toutes_taxes'] = round(total_ht + (tva_value * total_ht), 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' "
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"))
partner_invoice_header_data['invoice_header_ref_interne'] = "facture"
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'])
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 "
return True, "L'email a été correctement envoyé "
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 la convention par email "
"""
Envoie par email pour les stagiaires rattachés à un client
important :
si le champ 'email_test' est rempli, alors il s'agit d'un email de test.
donc on n'envoie pas l'email à l'adresss de prod ou contact du client
"""
def Sent_Facture_Stagiaire_By_Email_By_Partner_client(tab_files_name_full_path, Folder, diction):
try:
field_list_obligatoire = ['token', 'courrier_template_id', 'email_test', 'email_production', 'partner_client_id', 'session_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, " La valeur '" + val + "' n'est pas presente dans liste"
my_token = ""
if ("token" in diction.keys()):
if diction['token']:
my_token = diction['token']
local_status, my_partner = mycommon.Check_Connexion_And_Return_Partner_Data(diction)
if (local_status is not True):
return local_status, my_partner
# Verifier que la session est valide
is_session_id_valide = MYSY_GV.dbname['session_formation'].count_documents(
{'_id': ObjectId(str(diction['session_id'])),
'valide': '1',
'partner_owner_recid': str(my_partner['recid'])})
if (is_session_id_valide != 1):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " L'identifiant de la session est invalide ")
return False, " L'identifiant de la session est invalide "
# Verifier que ce client a bien des inscriptions valide pour cette session
is_valide_inscription_pr_client = MYSY_GV.dbname['inscription'].count_documents(
{'client_rattachement_id': str(diction['partner_client_id']),
'session_id': str(diction['session_id']),
'partner_owner_recid': str(my_partner['recid']),
'status': '1'})
if (is_valide_inscription_pr_client <= 0):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " Aucune inscription valide pour ce client pour cette session ")
return False, " Aucune inscription valide pour ce client pour cette session "
partner_client_id_data = MYSY_GV.dbname['partner_client'].find_one(
{'_id': ObjectId(str(diction['partner_client_id'])),
'valide': '1',
'locked': '0',
'partner_recid': str(my_partner['recid'])})
# Traitement de l'eventuel fichier joint
tab_files_to_attache_to_mail = []
for file_name_full_path in tab_files_name_full_path:
"""status, saved_file = mycommon.Upload_Save_PDF_IMG_File(file, Folder)
if (status is False):
mycommon.myprint("Impossible de récupérer correctement le fichier à importer")
return False, "Impossible de récupérer correctement le fichier à importer"
"""
file_to_attache_to_mail = MIMEBase('application', "octet-stream")
file_to_attache_to_mail.set_payload(open(file_name_full_path, "rb").read())
encoders.encode_base64(file_to_attache_to_mail)
file_to_attache_to_mail.add_header('Content-Disposition',
'attachment; filename="{0}"'.format(os.path.basename(file_name_full_path)))
new_node = {"attached_file": file_to_attache_to_mail}
tab_files_to_attache_to_mail.append(new_node)
# Verification de la validité des adresses email_recu
"""
/!\ : Si l'email de test est repli, alors on considere que c'est un test, on ne prend pas en compte l'email de email_production.
Ceci pour forcer les utilisateur à ne remplir que l'email de prod s'il veulent l'envoyer en prod.
Si l'adresse email_prodution = "defaul", cela veut dire qu'on envoie la convention à :
- l'adresse email du stagiaire et ses tuteurs (si les tuteurs on cochés la case 'inclu com'
"""
send_in_production = 0
tab_emails_destinataire = []
if ("email_test" in diction.keys() and diction['email_test']):
tab_email_test = str(diction['email_test']).replace(";", ",").split(",")
for email in tab_email_test:
email = email.strip()
if (mycommon.isEmailValide(email) is False):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " L'adresse email " + str(email) + " est invalide ")
return False, " L'adresse email " + str(email) + " est invalide "
tab_emails_destinataire = tab_email_test
elif ("email_production" in diction.keys() and diction['email_production']):
send_in_production = 1
if (str(diction['email_production']) != "default"):
tab_email_prod = str(diction['email_production']).replace(";", ",").split(",")
for email in tab_email_prod:
email = email.strip()
if (mycommon.isEmailValide(str(email)) is False):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " L'adresse email '" + str(email) + "' est invalide ")
return False, " L'adresse email " + str(email) + " est invalide "
tab_emails_destinataire = tab_email_prod
else:
tab_email_prod = "default"
else:
mycommon.myprint(
str(inspect.stack()[0][
3]) + " Aucune adresse email n'a été fourni. ")
return False, " Aucune adresse email n'a été fourni. "
print(" ## laaa : tab_emails_destinataire lalala = ", tab_emails_destinataire)
# Verifier que le 'courrier_template_id' est valide
# Ici le template doit etre un email
is_courrier_template_id_valide = MYSY_GV.dbname['courrier_template'].count_documents(
{'_id': ObjectId(str(diction['courrier_template_id'])),
'valide': '1',
'type_doc': 'email',
'locked': '0',
'partner_owner_recid': str(my_partner['recid'])}
)
if (is_courrier_template_id_valide != 1):
mycommon.myprint(str(inspect.stack()[0][3]) + " L'identifiant du modèle de courrier est invalide ")
return False, " L'identifiant du modèle de courrier est invalide "
# Recupération des données du modèle de document
courrier_template_data = MYSY_GV.dbname['courrier_template'].find_one(
{'_id': ObjectId(str(diction['courrier_template_id'])),
'valide': '1',
'locked': '0',
'partner_owner_recid': str(my_partner['recid'])}
)
# Recuperation des eventuelles pièces jointes du modèle que courrier
local_dic = {}
local_dic['token'] = str(diction['token'])
local_dic['object_owner_collection'] = "courrier_template"
local_dic['object_owner_id'] = str(courrier_template_data['_id'])
local_status, local_retval = attached_file_mgt.Get_List_object_owner_collection_Stored_Files(local_dic)
if (local_status is False):
return local_status, local_retval
# print(" ### file stocké = ", local_retval)
# Recuperation des fichiers attachés au modele de courrier, s'il y en a
for file in local_retval:
local_JSON = ast.literal_eval(file)
saved_file = local_JSON['full_path']
file_to_attache_to_mail = MIMEBase('application', "octet-stream")
file_to_attache_to_mail.set_payload(open(saved_file, "rb").read())
encoders.encode_base64(file_to_attache_to_mail)
file_to_attache_to_mail.add_header('Content-Disposition',
'attachment; filename="{0}"'.format(os.path.basename(saved_file)))
new_node = {"attached_file": file_to_attache_to_mail}
tab_files_to_attache_to_mail.append(new_node)
# Recuperation des données du stagiaire
inscription_data = MYSY_GV.dbname['inscription'].find({'session_id': str(diction['session_id']),
'status': '1',
'partner_owner_recid': str(my_partner['recid']),
'client_rattachement_id':str(diction['partner_client_id'])})
tab_apprenant = []
tab_participant = []
for val in inscription_data:
tab_participant.append(val['_id'])
"""
update du 30/01/2024
si le participant à un apprenant_id, alors on recupere la valeur de l'apprenant id. On doit travailler sur cette dernier.
En general, avant d'envoyer une convocation ou convention, l'inscription est validée et donc le dossier apprenant existe.
Du coup si tout se passe bien, dans cette fonction, on travaillera tjrs avec l'apprenant_id
"""
if ("apprenant_id" in val.keys() and val['apprenant_id']):
tab_apprenant.append(ObjectId(str(val['apprenant_id'])))
print(" ### tab_participant = ", tab_participant)
# Recuperations des info de la session de formation
session_data = MYSY_GV.dbname['session_formation'].find_one({'_id': ObjectId(str(diction['session_id']))})
tab_session = []
tab_session.append(session_data['_id'])
# Recuperation du titre de la formation
class_data = MYSY_GV.dbname['myclass'].find({'internal_url': str(session_data['class_internal_url']),
'valide': '1',
'partner_owner_recid': str(my_partner['recid']),
'locked': '0'})
tab_class = []
for val in class_data:
tab_class.append(val['_id'])
# Recuperer les données du client
client_data = MYSY_GV.dbname['partner_client'].find_one({'_id':ObjectId(str(diction['partner_client_id'])),
'valide':'1',
'locked':'0',
'partner_recid': str(my_partner['recid']),
})
tab_client = []
tab_client.append(client_data['_id'])
# Creation du dictionnaire d'information à utiliser pour la creation du doc
convention_dictionnary_data = {}
new_diction = {}
new_diction['token'] = diction['token']
new_diction['list_stagiaire_id'] = tab_participant
new_diction['list_session_id'] = tab_session
new_diction['list_class_id'] = tab_class
new_diction['list_client_id'] = tab_client
local_status, local_retval = mycommon.Get_Dictionnary_data_For_Template(new_diction)
if (local_status is False):
return local_status, local_retval
convention_dictionnary_data = local_retval
print(" ")
## Creation du PDF
body = {
"params": convention_dictionnary_data,
}
# ---
# Verifier s'il s'agit d'un document à envoyer avec une version de pièce jointe.
if ("joint_pdf" in courrier_template_data.keys() and str(courrier_template_data['joint_pdf']) == "1"):
# Il s'agit bien d'un envoie avec 'contenu_doc' en pièce jointe PDF
"""
1 - Creation du PDF
"""
contenu_doc_Template = jinja2.Template(str(courrier_template_data['contenu_doc']))
sourceHtml = contenu_doc_Template.render(params=body["params"])
todays_date = str(date.today().strftime("%d/%m/%Y"))
ts = datetime.now().timestamp()
ts = str(ts).replace(".", "").replace(",", "")[-5:]
orig_file_name = "Convention_" + str(my_partner['recid'])[0:5] + "_" + str(ts) + ".pdf"
outputFilename = str(MYSY_GV.TEMPORARY_DIRECTORY) + "/" + str(orig_file_name)
# open output file for writing (truncated binary)
resultFile = open(outputFilename, "w+b")
# convert HTML to PDF
pisaStatus = pisa.CreatePDF(
src=sourceHtml, # the HTML to convert
dest=resultFile) # file handle to receive result
# close output file
resultFile.close()
# Attachement du fichier joint
file_to_attache_to_mail = MIMEBase('application', "octet-stream")
file_to_attache_to_mail.set_payload(open(outputFilename, "rb").read())
encoders.encode_base64(file_to_attache_to_mail)
file_to_attache_to_mail.add_header('Content-Disposition',
'attachment; filename="{0}"'.format(os.path.basename(outputFilename)))
new_node = {"attached_file": file_to_attache_to_mail}
tab_files_to_attache_to_mail.append(new_node)
## Creation du mail au format email
corps_mail_Template = jinja2.Template(str(courrier_template_data['corps_mail']))
sourceHtml = corps_mail_Template.render(params=body["params"])
html_mime = MIMEText(sourceHtml, 'html')
# Creation de l'email à enoyer
msg = MIMEMultipart("alternative")
else:
# Il s'agit d'une simple email
## Creation du mail au format email
contenu_doc_Template = jinja2.Template(str(courrier_template_data['contenu_doc']))
sourceHtml = contenu_doc_Template.render(params=body["params"])
html_mime = MIMEText(sourceHtml, 'html')
# Creation de l'email à enoyer
msg = MIMEMultipart("alternative")
# ---
"""
## Creation du PDF
contenu_doc_Template = jinja2.Template(str(courrier_template_data['contenu_doc']))
sourceHtml = contenu_doc_Template.render(params=body["params"])
html_mime = MIMEText(sourceHtml, 'html')
# Creation de l'email à enoyer
msg = MIMEMultipart("alternative")
"""
"""
Recuperation des parametre SMTP du partner si le client a decidé d'utiliser son propre smpt
"""
partner_own_smtp_value = "0"
partner_own_smtp = MYSY_GV.dbname['base_partner_setup'].find_one(
{'partner_owner_recid': str(my_partner['recid']),
'config_name': 'partner_smtp',
'valide': '1',
'locked': '0'})
if (partner_own_smtp and "config_value" in partner_own_smtp.keys()):
partner_own_smtp_value = partner_own_smtp['config_value']
if (str(partner_own_smtp_value) == "1"):
partner_SMTP_COUNT_password = str(MYSY_GV.dbname['base_partner_setup'].find_one(
{'partner_owner_recid': str(my_partner['recid']),
'config_name': 'smtp_user_pwd',
'valide': '1',
'locked': '0'}, {'config_value': 1})['config_value'])
partner_SMTP_COUNT_smtpsrv = str(MYSY_GV.dbname['base_partner_setup'].find_one(
{'partner_owner_recid': str(my_partner['recid']),
'config_name': 'smtp_server',
'valide': '1',
'locked': '0'}, {'config_value': 1})['config_value'])
partner_SMTP_COUNT_user = str(MYSY_GV.dbname['base_partner_setup'].find_one(
{'partner_owner_recid': str(my_partner['recid']),
'config_name': 'smtp_user',
'valide': '1',
'locked': '0'}, {'config_value': 1})['config_value'])
partner_SMTP_COUNT_From_User = str(MYSY_GV.dbname['base_partner_setup'].find_one(
{'partner_owner_recid': str(my_partner['recid']),
'config_name': 'smtp_count_from_name',
'valide': '1',
'locked': '0'}, {'config_value': 1})['config_value'])
partner_SMTP_COUNT_port = str(MYSY_GV.dbname['base_partner_setup'].find_one(
{'partner_owner_recid': str(my_partner['recid']),
'config_name': 'smtp_count_port',
'valide': '1',
'locked': '0'}, {'config_value': 1})['config_value'])
if (str(partner_own_smtp_value) == "1"):
smtpserver = smtplib.SMTP(partner_SMTP_COUNT_smtpsrv, partner_SMTP_COUNT_port)
else:
smtpserver = smtplib.SMTP(MYSY_GV.O365_SMTP_COUNT_smtpsrv, MYSY_GV.O365_SMTP_COUNT_port)
if (str(partner_own_smtp_value) == "1"):
msg.attach(html_mime)
msg['From'] = partner_SMTP_COUNT_From_User
msg['Bcc'] = 'contact@mysy-training.com'
msg['Subject'] = courrier_template_data['sujet']
# msg['to'] = "billardman01@hotmail.com"
toaddrs = ", ".join(tab_emails_destinataire)
msg['to'] = str(toaddrs)
# Attacher l'eventuelle pièces jointes
for myfile in tab_files_to_attache_to_mail:
msg.attach(myfile['attached_file'])
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.login(partner_SMTP_COUNT_user, partner_SMTP_COUNT_password)
else:
msg.attach(html_mime)
msg['From'] = MYSY_GV.O365_SMTP_COUNT_From_User
msg['Bcc'] = 'contact@mysy-training.com'
msg['Subject'] = courrier_template_data['sujet']
# msg['to'] = "billardman01@hotmail.com"
toaddrs = ", ".join(tab_emails_destinataire)
msg['to'] = str(toaddrs)
for myfile in tab_files_to_attache_to_mail:
msg.attach(myfile['attached_file'])
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.login(MYSY_GV.O365_SMTP_COUNT_user, MYSY_GV.O365_SMTP_COUNT_password)
val = smtpserver.send_message(msg)
smtpserver.close()
print(" Email envoyé " + str(val))
"""
25/01/2024 : pour loger une action dans la collection ==> courrier_template_tracking_history
"""
# Recuperation des données du stagiaire
inscription_data = MYSY_GV.dbname['inscription'].find({'session_id': str(diction['session_id']),
'status': '1',
'partner_owner_recid': str(my_partner['recid']),
'client_rattachement_id': str(
diction['partner_client_id'])})
for inscription in inscription_data:
local_status, local_retval = module_editique.Editic_Log_History_Action_From_courrier_template_type_document_ref_interne(
my_partner, "CONVENTION_STAGIAIRE_ENTREPRISE", str(diction['session_id']), 'inscription',
str(inscription['_id']), str(courrier_template_data['_id']))
#print(" local_status = ", local_status)
"""
# Ajout de l'evenement dans l'historique
"""
# L'action n'est loggué pour les envois reels (en prod)
if (send_in_production == 1):
now = str(datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
history_event_dict = {}
history_event_dict['token'] = diction['token']
history_event_dict['related_collection'] = "partner_client"
history_event_dict['related_collection_recid'] = str(diction['partner_client_id'])
history_event_dict['action_date'] = str(now)
history_event_dict['action_description'] = "Convention envoyée par email à la liste : " + str(
tab_emails_destinataire)
local_status, local_retval = mycommon.Collection_Historique.Add_Historique_Event(history_event_dict)
if (local_status is False):
mycommon.myprint(
" WARNING : Impossible de logguer l'historique pour l'évènement : " + str(history_event_dict))
return True, "L'email a été correctement envoyé "
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 la convention par email "

25
main.py
View File

@ -2161,7 +2161,7 @@ def Duplicate_List_Session_Formation():
"""
API : pour préprer et envoyer les convention en partant d'une session
API : pour préparer et envoyer les convention en partant d'une session
"""
@app.route('/myclass/api/Prepare_and_Send_Convention_From_Session_By_Email/', methods=['POST','GET'])
@crossdomain(origin='*')
@ -7762,6 +7762,29 @@ def Delete_Given_Site_Formation():
"""
API : pour préparer et envoyer les factures en partant d'une session
"""
@app.route('/myclass/api/Prepare_and_Send_Facture_From_Session_By_Email/', methods=['POST','GET'])
@crossdomain(origin='*')
def Prepare_and_Send_Facture_From_Session_By_Email():
# On recupere le corps (payload) de la requete
payload = mycommon.strip_dictionary (request.form.to_dict())
print(" ### Prepare_and_Send_Facture_From_Session_By_Email : payload = ",str(payload))
file = []
if request.method == 'POST':
# Create variable for uploaded file
tab_files = []
for tmp in request.files.getlist("File"):
tab_files.append(tmp)
status, retval = SF.Prepare_and_Send_Facture_From_Session_By_Email(tab_files, MYSY_GV.TEMPORARY_DIRECTORY_V2, payload)
return jsonify(status=status, message=retval)
if __name__ == '__main__':
print(" debut api")
context = SSL.Context(SSL.SSLv23_METHOD)

View File

@ -76,6 +76,43 @@ def Add_Partner_Document(diction):
data = {}
data['partner_owner_recid'] = my_partner['recid']
if ("original_courrier_template_id" in diction.keys() and diction['original_courrier_template_id']):
is_original_courrier_template_id_valide = MYSY_GV.dbname['courrier_template'].count_documents(
{'_id': ObjectId(str(diction['original_courrier_template_id'])),
'valide': '1',
'locked': '0',
'partner_owner_recid': 'default'})
if (is_original_courrier_template_id_valide != 1):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " L'identifiant du courrier d'origine (original_courrier_template_id) est invalide ")
return False, " L'identifiant du courrier d'origine (original_courrier_template_id) est invalide "
# Cette n'est ajoutée que le champ existe et est valide. donc l'indemtation est dans le 'if', normal
data['original_courrier_template_id'] = diction['original_courrier_template_id']
# Recuperation de quelques valeurs par défaut
is_original_courrier_template_id_data = MYSY_GV.dbname['courrier_template'].find_one(
{'_id': ObjectId(str(diction['original_courrier_template_id'])),
'valide': '1',
'locked': '0',
'partner_owner_recid': 'default'})
if ("duplicate" in is_original_courrier_template_id_data.keys()):
data['duplicate'] = is_original_courrier_template_id_data['duplicate']
if ("joint_pdf" in is_original_courrier_template_id_data.keys()):
data['joint_pdf'] = is_original_courrier_template_id_data['joint_pdf']
if ("edit_by_client" in is_original_courrier_template_id_data.keys()):
data['edit_by_client'] = is_original_courrier_template_id_data['edit_by_client']
if ("type_doc" in is_original_courrier_template_id_data.keys()):
data['type_doc'] = is_original_courrier_template_id_data['type_doc']
ref_interne = ""
if ("ref_interne" in diction.keys()):
if diction['ref_interne']:
@ -101,21 +138,6 @@ def Add_Partner_Document(diction):
data['nom'] = nom
if( "original_courrier_template_id" in diction.keys() and diction['original_courrier_template_id']):
is_original_courrier_template_id_valide = MYSY_GV.dbname['courrier_template'].count_documents({'_id':ObjectId(str(diction['original_courrier_template_id'])),
'valide':'1',
'locked':'0',
'partner_owner_recid':'default'})
if( is_original_courrier_template_id_valide != 1 ):
mycommon.myprint(
str(inspect.stack()[0][
3]) + " L'identifiant du courrier d'origine (original_courrier_template_id) est invalide ")
return False, " L'identifiant du courrier d'origine (original_courrier_template_id) est invalide "
# Cette n'est ajoutée que le champ existe et est valide. donc l'indemtation est dans le 'if', normal
data['original_courrier_template_id'] = diction['original_courrier_template_id']
sujet = ""
if ("sujet" in diction.keys()):

View File

@ -193,7 +193,7 @@ def Invoice_Partner_Order(diction):
"""
# Rcuperation de la sequence de l'objet "partner_invoice_header" dans la collection : "mysy_sequence"
# 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'])})

View File

@ -4879,3 +4879,5 @@ def Get_Partner_Currency(partner_owner_recid):
exc_type, exc_obj, exc_tb = sys.exc_info()
myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
return False