1371 lines
58 KiB
Python
1371 lines
58 KiB
Python
"""
|
|
Ce fichier permet de gerer les factures client et les methodes de payement
|
|
"""
|
|
import pymongo
|
|
from pymongo import MongoClient
|
|
import json
|
|
from bson import ObjectId
|
|
import re
|
|
from datetime import datetime
|
|
import prj_common as mycommon
|
|
import secrets
|
|
import inspect
|
|
import sys, os
|
|
import shutil
|
|
import csv
|
|
import pandas as pd
|
|
from pymongo import ReturnDocument
|
|
from math import isnan
|
|
import GlobalVariable as MYSY_GV
|
|
import email_mgt as email
|
|
from dateutil import tz
|
|
import pytz
|
|
from xhtml2pdf import pisa
|
|
import jinja2
|
|
import ftplib
|
|
import pysftp
|
|
from flask import send_file
|
|
from dateutil.relativedelta import relativedelta
|
|
import class_mgt as class_mgt
|
|
import strype_payement as Stripe
|
|
import code_promo_mgt as code_promo_mgt
|
|
import time
|
|
|
|
class JSONEncoder(json.JSONEncoder):
|
|
def default(self, o):
|
|
if isinstance(o, ObjectId):
|
|
return str(o)
|
|
return json.JSONEncoder.default(self, o)
|
|
|
|
|
|
def get_invoice_by_customer(diction):
|
|
try:
|
|
field_list = ['token',]
|
|
|
|
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'existe pas, Creation formation annulée")
|
|
return False, " Impossible de récupérer les factures"
|
|
|
|
'''
|
|
Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente,
|
|
On controle que les champs obligatoires sont presents dans la liste
|
|
'''
|
|
field_list_obligatoire = ['token']
|
|
|
|
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 la liste des arguments ")
|
|
return False, " Impossible de récupérer les factures"
|
|
|
|
# recuperation des paramettre
|
|
my_token = ""
|
|
user_recid = ""
|
|
|
|
if ("token" in diction.keys()):
|
|
if diction['token']:
|
|
my_token = diction['token']
|
|
|
|
user_recid = "None"
|
|
# Verification de la validité du token/mail dans le cas des user en mode connecté
|
|
if (len(str(my_token)) > 0):
|
|
retval = mycommon.check_partner_token_validity("", my_token)
|
|
|
|
if retval is False:
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - La session de connexion n'est pas valide")
|
|
return False, " Impossible de récupérer les factures"
|
|
|
|
# Recuperation du recid de l'utilisateur
|
|
user_recid = mycommon.get_parnter_recid_from_token(my_token)
|
|
if user_recid is False:
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de récupérer le token de l'utilisateur")
|
|
return False, " Impossible de récupérer les factures"
|
|
|
|
if (len(str(my_token)) <= 0):
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - Le token est vide")
|
|
return False, " Impossible de récupérer les factures"
|
|
|
|
RetObject = []
|
|
coll_facture = MYSY_GV.dbname['factures']
|
|
|
|
for retVal in coll_facture.find({'client_recid':user_recid, 'valide': '1'},
|
|
{'invoice_nom':1, 'total_ht':1, 'total_tva':1, 'total_ttc':1,
|
|
'order_id':1, 'invoice_id':1, 'due_date':1, 'invoice_date':1,
|
|
}
|
|
)\
|
|
.sort([("invoice_date", pymongo.DESCENDING), ("invoice_id", pymongo.DESCENDING), ]):
|
|
user = retVal
|
|
if ("_id" in user.keys()):
|
|
user['class_id'] = user.pop('_id')
|
|
|
|
user['lien_pdf'] = str(MYSY_GV.INVOICE_FTP_DIRECTORY)+str("invoice_")+str(user['invoice_id'])+str(".pdf")
|
|
|
|
|
|
RetObject.append(JSONEncoder().encode(user))
|
|
#print(" les facture du client = "+str(RetObject))
|
|
return True, RetObject
|
|
|
|
except Exception as e:
|
|
exc_type, exc_obj, exc_tb = sys.exc_info()
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
|
|
return False, "Impossible de récupérer les factures"
|
|
|
|
|
|
'''
|
|
Cette API enregistre la methode de payement.
|
|
/!\ un client a une seule mode de payement
|
|
ceci est enregistré dans la collection : payement_mode
|
|
'''
|
|
def add_payement_mode(diction):
|
|
try:
|
|
field_list = ['token', 'pwd', 'secret', 'nom_carte', 'num_carte', 'date_exp_carte', 'cvv_carte', 'nom_compte',
|
|
'iban', 'bic','type' ]
|
|
|
|
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'existe pas, Creation formation annulée")
|
|
return False, "Impossible d'ajouter le mode de payement"
|
|
|
|
'''
|
|
Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente,
|
|
On controle que les champs obligatoires sont presents dans la liste
|
|
'''
|
|
field_list_obligatoire = ['token', 'pwd', 'secret', 'type']
|
|
|
|
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 la liste des arguments ")
|
|
return False, "Impossible d'ajouter le mode de payement"
|
|
|
|
# recuperation des paramettre
|
|
my_token = ""
|
|
user_recid = ""
|
|
my_pwd = ""
|
|
my_secret = ""
|
|
|
|
|
|
if ("pwd" in diction.keys()):
|
|
if diction['pwd']:
|
|
my_pwd = diction['pwd']
|
|
|
|
if ("secret" in diction.keys()):
|
|
if diction['secret']:
|
|
my_secret = diction['secret']
|
|
|
|
if ("token" in diction.keys()):
|
|
if diction['token']:
|
|
my_token = diction['token']
|
|
|
|
# Verification de la validité du pwd et du secret
|
|
coll_tmp = MYSY_GV.dbname['partnair_account']
|
|
|
|
tmp_count = coll_tmp.count_documents({'pwd': str(my_pwd), 'active': '1', 'secret_key':str(my_secret)})
|
|
if (tmp_count <= 0):
|
|
return False, "Les identifiants sont incorrectes"
|
|
|
|
tmp_account = coll_tmp.find({'pwd': str(my_pwd), 'active': '1', 'secret_key':str(my_secret)})
|
|
|
|
"""
|
|
Stripe : recuperation du stripe_account_id
|
|
"""
|
|
partner_stripe_account_id = tmp_account[0]['stripe_account_id']
|
|
|
|
"""
|
|
Recuperation du PaymentMethod s'il en a un : 'stripe_paymentmethod_id'
|
|
"""
|
|
stripe_paymentmethod_id = ""
|
|
if ("stripe_paymentmethod_id" in tmp_account[0].keys()):
|
|
if tmp_account[0]['stripe_paymentmethod_id']:
|
|
stripe_paymentmethod_id = tmp_account[0]['stripe_paymentmethod_id']
|
|
|
|
|
|
user_recid = "None"
|
|
# Verification de la validité du token/mail dans le cas des user en mode connecté
|
|
if (len(str(my_token)) > 0):
|
|
retval = mycommon.check_partner_token_validity("", my_token)
|
|
|
|
if retval is False:
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - La session de connexion n'est pas valide")
|
|
return False, "Impossible d'ajouter le mode de payement"
|
|
|
|
# Recuperation du recid de l'utilisateur
|
|
user_recid = mycommon.get_parnter_recid_from_token(my_token)
|
|
if user_recid is False:
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + " - Impossible de récupérer le token de l'utilisateur")
|
|
return False, "Impossible d'ajouter le mode de payement"
|
|
|
|
if (len(str(my_token)) <= 0):
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - Le token est vide")
|
|
return False, "Impossible d'ajouter le mode de payement"
|
|
|
|
|
|
|
|
coll_name = MYSY_GV.dbname['payement_mode']
|
|
new_data = {}
|
|
new_data['valide'] = "1"
|
|
now = datetime.now()
|
|
new_data['date_update'] = str(now)
|
|
|
|
# initialisation pr nettoyer l'existant (faire comme un delete)
|
|
new_data['nom_carte'] = ""
|
|
new_data['num_carte'] = ""
|
|
new_data['date_exp_carte'] = ""
|
|
new_data['cvv_carte'] = ""
|
|
new_data['nom_compte'] = ""
|
|
new_data['iban'] = ""
|
|
new_data['bic'] = ""
|
|
|
|
if ("nom_carte" in diction.keys()):
|
|
if diction['nom_carte']:
|
|
new_data['nom_carte'] = diction['nom_carte']
|
|
|
|
if ("num_carte" in diction.keys()):
|
|
if diction['num_carte']:
|
|
new_data['num_carte'] = diction['num_carte']
|
|
|
|
if ("type" in diction.keys()):
|
|
if diction['type']:
|
|
new_data['type'] = diction['type']
|
|
|
|
if ("date_exp_carte" in diction.keys()):
|
|
if diction['date_exp_carte']:
|
|
new_data['date_exp_carte'] = diction['date_exp_carte']
|
|
|
|
if ("cvv_carte" in diction.keys()):
|
|
if diction['cvv_carte']:
|
|
new_data['cvv_carte'] = diction['cvv_carte']
|
|
|
|
if ("nom_compte" in diction.keys()):
|
|
if diction['nom_compte']:
|
|
new_data['nom_compte'] = diction['nom_compte']
|
|
|
|
if ("iban" in diction.keys()):
|
|
if diction['iban']:
|
|
new_data['iban'] = diction['iban']
|
|
|
|
if ("nom_compte" in diction.keys()):
|
|
if diction['nom_compte']:
|
|
new_data['nom_compte'] = diction['nom_compte']
|
|
|
|
if ("bic" in diction.keys()):
|
|
if diction['bic']:
|
|
new_data['bic'] = diction['bic']
|
|
|
|
|
|
print("mode de payement data :"+str(new_data))
|
|
|
|
#print("str(new_data['num_carte']) = "+str(new_data['num_carte']) +" len = "+str(len(str(new_data['num_carte']))) )
|
|
#print("str(new_data['nom_carte']) = " + str(new_data['nom_carte']) +" len ="+str(len(str(new_data['nom_carte']))) )
|
|
|
|
if( str(new_data['type']) == "cb"):
|
|
if( len(str(new_data['num_carte'])) <= 0 or len(str(new_data['nom_carte'])) <= 0
|
|
or len(str(new_data['date_exp_carte'])) <= 0 or len(str(new_data['cvv_carte'])) <= 0 ):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + " : Les données de la carte sont incorrectes")
|
|
return False, "Impossible d'ajouter le mode de paiement. Les données de la carte sont incorrectes"
|
|
|
|
|
|
|
|
# SI stripe_paymentmethod_id est vide alors on créé la carte
|
|
|
|
print(" #### Creation de la carte dans STRIPE")
|
|
tmp_tab = str(new_data['date_exp_carte']).split("/")
|
|
if( len(tmp_tab) != 2):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + " : La date d'expiration de la carte est incorrecte")
|
|
return False, "Impossible d'ajouter le mode de paiement. Les données de la carte sont incorrectes"
|
|
|
|
|
|
new_stripe_card = {}
|
|
new_stripe_card['customerid'] = partner_stripe_account_id
|
|
new_stripe_card['number'] = new_data['num_carte']
|
|
new_stripe_card['name'] = new_data['nom_carte']
|
|
new_stripe_card['exp_month'] = str(tmp_tab[0])
|
|
new_stripe_card['exp_year'] = str(tmp_tab[1])
|
|
new_stripe_card['cvc'] = new_data['cvv_carte']
|
|
new_stripe_card['stripe_paymentmethod_id'] = stripe_paymentmethod_id
|
|
|
|
|
|
print("### la carte à créer est "+str(new_stripe_card))
|
|
|
|
local_status, created_stripe_cart = Stripe.create_update_payment_card(new_stripe_card)
|
|
if( local_status is False):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + " : Impossible de créer la carte de payement dans Stripe")
|
|
return False, "Impossible d'ajouter le mode de paiement."
|
|
|
|
#print(" ### la carte est créée : "+str(created_stripe_cart))
|
|
|
|
|
|
if (str(new_data['type']) == "sepa"):
|
|
if (len(str(new_data['iban'])) <= 0 or len(str(new_data['bic']) <= 0)
|
|
or len(str(new_data['nom_compte'])) <= 0):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + " : Les données bancaires sont incorrectes")
|
|
return False, "Impossible d'ajouter le mode de paiement. Les données bancaires sont incorrectes"
|
|
|
|
new_data['stripe_paymentmethod_id'] = str(created_stripe_cart.id)
|
|
ret_val = coll_name.find_one_and_update(
|
|
{'client_recid': user_recid, 'valide': '1'},
|
|
{"$set": new_data},
|
|
upsert=True,
|
|
return_document=ReturnDocument.AFTER
|
|
)
|
|
|
|
if (ret_val['_id'] is False):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + " : Impossible d'ajouter le mode de payement")
|
|
return False, "Impossible d'ajouter le mode de payement"
|
|
|
|
|
|
'''
|
|
Une fois que le mode de payement est ajouté, alors valide le compte partenaire
|
|
en mettant : ispending à 0
|
|
'''
|
|
coll_name = MYSY_GV.dbname['partnair_account']
|
|
data_update = {'date_update':str(datetime.now()), 'ispending':'0', 'stripe_paymentmethod_id':str(created_stripe_cart.id)}
|
|
ret_val = coll_name.find_one_and_update(
|
|
{'recid': user_recid, },
|
|
{"$set": data_update},
|
|
upsert=False,
|
|
return_document=ReturnDocument.AFTER
|
|
)
|
|
|
|
if (ret_val is None or ret_val['_id'] is False):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + " : Impossible de mettre à jour (ispending':'1') le compte partenaire")
|
|
return False, "Impossible d'ajouter le mode de payement"
|
|
|
|
|
|
return True, " Le mode de payement a bien ete ajouté"
|
|
|
|
except Exception as e:
|
|
exc_type, exc_obj, exc_tb = sys.exc_info()
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
|
|
return False, "Impossible d'ajouter le mode de payement"
|
|
|
|
|
|
'''
|
|
Cette fonction recupere le mode de payement par defaut d'un client
|
|
'''
|
|
def get_payement_mode(diction):
|
|
try:
|
|
|
|
field_list = ['token', ]
|
|
|
|
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'existe pas, Creation formation annulée")
|
|
return False, " Impossible de récupérer les mode de payement", ""
|
|
|
|
'''
|
|
Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente,
|
|
On controle que les champs obligatoires sont presents dans la liste
|
|
'''
|
|
field_list_obligatoire = ['token']
|
|
|
|
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 la liste des arguments ")
|
|
return False, " Impossible de récupérer les mode de payement", ""
|
|
|
|
# recuperation des paramettre
|
|
my_token = ""
|
|
user_recid = ""
|
|
|
|
if ("token" in diction.keys()):
|
|
if diction['token']:
|
|
my_token = diction['token']
|
|
|
|
user_recid = "None"
|
|
# Verification de la validité du token/mail dans le cas des user en mode connecté
|
|
if (len(str(my_token)) > 0):
|
|
retval = mycommon.check_partner_token_validity("", my_token)
|
|
|
|
if retval is False:
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - La session de connexion n'est pas valide")
|
|
return False, " Impossible de récupérer les mode de payement", ""
|
|
|
|
# Recuperation du recid de l'utilisateur
|
|
user_recid = mycommon.get_parnter_recid_from_token(my_token)
|
|
if user_recid is False:
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de récupérer le token de l'utilisateur")
|
|
return False, " Impossible de récupérer les mode de payement", ""
|
|
|
|
if (len(str(my_token)) <= 0):
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - Le token est vide")
|
|
return False, " Impossible de récupérer les mode de payement", ""
|
|
|
|
"""
|
|
Recuperation du stripe_account_id
|
|
"""
|
|
stripe_account_id = mycommon.get_parnter_stripe_account_id_from_recid(user_recid)
|
|
if stripe_account_id is False:
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de récupérer le stripe_account_id de l'utilisateur")
|
|
return True, " Impossible de récupérer les modes de payement", "0"
|
|
|
|
"""
|
|
Recuperation de clé de payement stripe : stripe_paymentmethod_id
|
|
"""
|
|
stripe_paymentmethod_id = mycommon.get_parnter_stripe_stripe_paymentmethod_id_from_recid(user_recid)
|
|
if stripe_paymentmethod_id is False:
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + " - Impossible de récupérer le stripe_paymentmethod_id de l'utilisateur")
|
|
return False, " Impossible de récupérer les modes de payement", ""
|
|
|
|
|
|
|
|
RetObject_stripe = []
|
|
tmp_diction = {}
|
|
tmp_diction['stripe_account_id'] = str(stripe_account_id)
|
|
|
|
#print("### recherche mod de payement stripe_account_id = "+str(stripe_account_id) )
|
|
|
|
localStatus, payment_cards, nb_carte = Stripe.get_customer_payement_cards(tmp_diction)
|
|
|
|
|
|
if( localStatus and nb_carte != "0" ):
|
|
RetObject_stripe.append(payment_cards[0])
|
|
|
|
return True, RetObject_stripe, nb_carte
|
|
|
|
except Exception as e:
|
|
exc_type, exc_obj, exc_tb = sys.exc_info()
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
|
|
return False, " Impossible de récupérer les mode de payement", "0"
|
|
|
|
|
|
"""
|
|
Cette fonction crée une facture dans la collecion : factures.
|
|
|
|
/!\ : update du 09/07/2023 :
|
|
Apres la creation de la commande, une recap de la facture à venir est envoyé, ceci à titre d'information.
|
|
|
|
Le système recupere les informations depuis la plateforme strype. MAIS pour eviter des soucis de sychronisation,
|
|
c'est à dire récupérer les infos, alors que strype n'a pas fini sa mise à jour, on a desynchroniser complement
|
|
la finalisation de la commande et l'envoie des données de facture.
|
|
|
|
Pour ce faire, un va positionner un flag sur le partenaire pour dire :
|
|
"send_pre_invoice_data" à '1', "date_time_pre_invoice_created" à date_time_now.
|
|
|
|
Ensuite un job va tourner (frequence à definir) pour traiter tous les client
|
|
dont : "send_pre_invoice_data" = 1 et "date_time_pre_invoice_created" <= now() - 5 min.
|
|
Ainsi on laisse 5 minutes à strype pour bien se mettre à jour
|
|
|
|
"""
|
|
"""
|
|
14/04/2025 : desormais les pack ne sont pas liés au nombre de formation
|
|
Donc pour eviter des blocages coté LMS sur le nombre de formation,
|
|
on va TOUJOURS forcer le nombre de formation à 999
|
|
"""
|
|
|
|
def createOrder(diction):
|
|
try:
|
|
order_id = ""
|
|
nb_line = 0
|
|
|
|
num_facture = ""
|
|
'''
|
|
field_list = ['token', 'nb_product', 'periodicite', 'discount_code', 'discount_type', 'discount_valeur', 'discount_qty']
|
|
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é, Creation partenaire annulée")
|
|
return False, "Toutes les informations fournies ne sont pas valables", False
|
|
|
|
'''
|
|
'''
|
|
Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente,
|
|
On controle que les champs obligatoires sont presents dans la liste
|
|
'''
|
|
field_list_obligatoire = ['token', 'nb_product', 'periodicite']
|
|
|
|
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 la liste des arguments ")
|
|
return False, " Impossible de créer la facture", False
|
|
|
|
# recuperation des paramettre
|
|
my_token = ""
|
|
user_recid = ""
|
|
|
|
if ("token" in diction.keys()):
|
|
if diction['token']:
|
|
my_token = diction['token']
|
|
|
|
discount_code = ""
|
|
if ("discount_code" in diction.keys()):
|
|
if diction['discount_code']:
|
|
discount_code = diction['discount_code']
|
|
|
|
discount_type = ""
|
|
if ("discount_type" in diction.keys()):
|
|
if diction['discount_type']:
|
|
discount_type = diction['discount_type']
|
|
|
|
discount_valeur = ""
|
|
if ("discount_valeur" in diction.keys()):
|
|
if diction['discount_valeur']:
|
|
discount_valeur = diction['discount_valeur']
|
|
|
|
discount_qty = ""
|
|
if ("discount_qty" in diction.keys()):
|
|
if diction['discount_qty']:
|
|
discount_qty = diction['discount_qty']
|
|
|
|
user_recid = "None"
|
|
# Verification de la validité du token/mail dans le cas des user en mode connecté
|
|
if (len(str(my_token)) > 0):
|
|
retval = mycommon.check_partner_token_validity("", my_token)
|
|
|
|
if retval is False:
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - La session de connexion n'est pas valide")
|
|
return False, " Impossible de créer la facture", False
|
|
|
|
# Recuperation du recid de l'utilisateur
|
|
user_recid = mycommon.get_parnter_recid_from_token(my_token)
|
|
if user_recid is False:
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de récupérer le token de l'utilisateur")
|
|
return False," Impossible de créer la facture", False
|
|
|
|
if (len(str(my_token)) <= 0):
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - Le token est vide")
|
|
return False, " Impossible de créer la facture", False
|
|
|
|
|
|
new_data = {}
|
|
if ("nb_product" in diction.keys()):
|
|
if diction['nb_product']:
|
|
nb_line = mycommon.tryInt(diction['nb_product'])
|
|
|
|
periodicite = "mois"
|
|
if ("periodicite" in diction.keys()):
|
|
if diction['periodicite']:
|
|
new_data['periodicite'] = diction['periodicite']
|
|
periodicite = diction['periodicite']
|
|
|
|
if ("end_date" in diction.keys()):
|
|
if diction['end_date']:
|
|
new_data['end_date'] = diction['end_date']
|
|
|
|
# Recuperation des données client
|
|
new_data['client_recid'] = user_recid
|
|
coll_part_account = MYSY_GV.dbname['partnair_account']
|
|
|
|
# print(" myquery pr demo_account = " + str(myquery))
|
|
tmp_count = coll_part_account.count_documents({'recid':user_recid, 'active':'1'})
|
|
if (tmp_count <= 0):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + "Aucune donnée client, Impossible de créer la commande ")
|
|
return False, "Aucune donnée client, Impossible de créer la commande ", None
|
|
|
|
|
|
|
|
new_data['nb_product'] = str(nb_line)
|
|
i = 0
|
|
total_ht = 0
|
|
nb_formation = ""
|
|
while (i < nb_line):
|
|
#print("PRODUIT N° " + str((i + 1)) + " : " )
|
|
line_dict = json.loads(diction[str(i)])
|
|
#print(" line = "+str(line_dict)+" -- le type est : "+str(type(line_dict)))
|
|
#print(" code = "+str( line_dict['code'] ))
|
|
#print(" prix = " + str(line_dict['prix']))
|
|
#print(" qty = " + str(line_dict['qty']))
|
|
#print(" les produits du pack = " + str(line_dict['pack_products']))
|
|
|
|
montant_line = mycommon.tryFloat(str(line_dict['prix'])) * mycommon.tryInt(str(line_dict['qty']))
|
|
#print(" montant_line = " + str(montant_line))
|
|
|
|
total_ht = total_ht + montant_line
|
|
|
|
new_data_item = {}
|
|
new_data_item['code'] = line_dict['code']
|
|
new_data_item['prix'] = line_dict['prix']
|
|
new_data_item['qty'] = line_dict['qty']
|
|
"""
|
|
14/04/2025 : desormais les pack ne sont pas liés au nombre de formation
|
|
Donc pour eviter des blocages coté LMS sur le nombre de formation,
|
|
on va TJRS FORCER la valeur de nb_formation à 999
|
|
"""
|
|
|
|
nb_formation = "999"
|
|
new_data_item['pack_products'] = line_dict['pack_products']
|
|
|
|
new_data_item['amount'] = str(montant_line)
|
|
row = "item_"+str(i)
|
|
new_data[str(row)] = new_data_item
|
|
|
|
i = i + 1
|
|
|
|
|
|
"""
|
|
Recalcul du HT en incluant les remise, si remise
|
|
"""
|
|
montant_remise = 0
|
|
if( discount_code ) :
|
|
|
|
local_status, local_discount_valeur = mycommon.IsFloat(discount_valeur)
|
|
if( local_status is False):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][
|
|
3]) + " La valeur de la remise n'est pas correcte ")
|
|
return False, "La valeur de la remise n'est pas correcte ", None
|
|
|
|
local_status, local_discount_qty = mycommon.IsInt(discount_qty)
|
|
if (local_status is False):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][
|
|
3]) + " la valeur de 'discount_qty' n'est pas correcte ")
|
|
return False, "la valeur de 'discount_qty' n'est pas correcte ", None
|
|
|
|
|
|
|
|
local_my_data = {}
|
|
local_my_data['token'] = my_token
|
|
local_my_data['code_promo'] = discount_code
|
|
local_status, isValide_code_promo = code_promo_mgt.Is_Valide_Code_Promo(local_my_data)
|
|
if (local_status is False):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][
|
|
3]) + " Le code remise est invalide ")
|
|
return False, " Le code remise est invalide ", None
|
|
|
|
|
|
# Si le type de promo est 'percent'
|
|
if( discount_type == 'percent'):
|
|
tmp_val1 = mycommon.tryFloat(str(discount_valeur))/100
|
|
|
|
montant_remise = mycommon.tryFloat(str(total_ht)) * mycommon.tryFloat(tmp_val1)
|
|
total_ht = str(mycommon.tryFloat(str(total_ht)) - mycommon.tryFloat(str(montant_remise)))
|
|
#print(" #### percent : montant_remise = ", montant_remise)
|
|
#print(" #### percent : total_ht = ", total_ht)
|
|
|
|
elif( discount_type == "fix"):
|
|
montant_remise = mycommon.tryFloat(str(discount_valeur))
|
|
total_ht = str(mycommon.tryFloat(str(total_ht)) - mycommon.tryFloat(str(montant_remise)))
|
|
#print(" #### fix : montant_remise = ", montant_remise)
|
|
#print(" #### fix : total_ht = ", total_ht)
|
|
|
|
if(mycommon.tryFloat(str(total_ht)) < 0 ):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][
|
|
3]) + " La remise est supérieure au montant HT. ")
|
|
return False, " La remise est supérieure au montant HT ", None
|
|
|
|
new_data['discount_code'] = str(discount_code)
|
|
new_data['discount_type'] = str(discount_type)
|
|
new_data['discount_valeur'] = str(discount_valeur)
|
|
new_data['discount_montant_remise'] = str(montant_remise)
|
|
|
|
new_data['total_ht'] = total_ht
|
|
new_data['total_tva'] = mycommon.tryFloat(str(total_ht)) * MYSY_GV.TVA_TAUX
|
|
new_data['total_ttc'] = mycommon.tryFloat(str(total_ht)) + mycommon.tryFloat(str(new_data['total_tva']))
|
|
|
|
total_ttc_float = mycommon.tryFloat(str(new_data['total_ttc']))
|
|
#print("str(new_data['total_ttc']) === " + str(total_ttc_float))
|
|
|
|
|
|
if (tmp_count <= 0 and total_ttc_float > 0):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + " Aucune donnée de payement, Impossible de créer la commande ")
|
|
return False, " Aucune donnée de payement, Impossible de créer la commande ", None
|
|
|
|
part_account = coll_part_account.find({'recid':user_recid, 'active':'1'})
|
|
|
|
|
|
|
|
"""
|
|
/!\ : Si le montant à facturé à superieur à 0 alors on force le controle des données de facturation (email, adresse, etc)
|
|
"""
|
|
#print(" ### TOTAL TTC à FACTURER = "+str(total_ttc_float))
|
|
invoice_nom_check = ""
|
|
if ("invoice_nom" in part_account[0].keys()):
|
|
if part_account[0]['invoice_nom']:
|
|
invoice_nom_check = part_account[0]['invoice_nom']
|
|
|
|
if(len(invoice_nom_check.strip()) == 0 and total_ttc_float > 0 ):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + " Les données de facturation sont incompletes. Verifiez la raison sociale ")
|
|
return False, "Les données de facturation sont incompletes. Verifiez la raison sociale ", None
|
|
new_data['invoice_nom'] = invoice_nom_check
|
|
|
|
|
|
invoice_adr_city_check = ""
|
|
if ("invoice_adr_city" in part_account[0].keys()):
|
|
if part_account[0]['invoice_adr_city']:
|
|
invoice_adr_city_check = part_account[0]['invoice_adr_city']
|
|
|
|
if (len(invoice_adr_city_check.strip()) == 0 and total_ttc_float > 0 ):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][
|
|
3]) + " Les données de facturation sont incompletes. Verifiez la ville ")
|
|
return False, "Les données de facturation sont incompletes. Verifiez la ville ", None
|
|
|
|
new_data['invoice_adr_city'] = invoice_adr_city_check
|
|
|
|
|
|
invoice_adr_country_check = ""
|
|
if ("invoice_adr_country" in part_account[0].keys()):
|
|
if part_account[0]['invoice_adr_country']:
|
|
invoice_adr_country_check = part_account[0]['invoice_adr_country']
|
|
|
|
if (len(invoice_adr_country_check.strip()) == 0 and total_ttc_float > 0 ):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][
|
|
3]) + " Les données de facturation sont incompletes. Verifiez le pays ")
|
|
return False, "Les données de facturation sont incompletes. Verifiez le pays ", None
|
|
|
|
new_data['invoice_adr_country'] = invoice_adr_country_check
|
|
|
|
|
|
invoice_adr_street_check = ""
|
|
if ("invoice_adr_street" in part_account[0].keys()):
|
|
if part_account[0]['invoice_adr_street']:
|
|
invoice_adr_street_check = part_account[0]['invoice_adr_street']
|
|
|
|
if (len(invoice_adr_street_check.strip()) == 0 and total_ttc_float > 0 ):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][
|
|
3]) + " Les données de facturation sont incompletes. Verifiez l'adresse ")
|
|
return False, "Les données de facturation sont incompletes. Verifiez l'adresse ", None
|
|
new_data['invoice_adr_street'] = invoice_adr_street_check
|
|
|
|
|
|
invoice_adr_zip_check = ""
|
|
if ("invoice_adr_zip" in part_account[0].keys()):
|
|
if part_account[0]['invoice_adr_zip']:
|
|
invoice_adr_zip_check = part_account[0]['invoice_adr_zip']
|
|
|
|
if (len(invoice_adr_zip_check.strip()) == 0 and total_ttc_float > 0 ):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][
|
|
3]) + " Les données de facturation sont incompletes. Verifiez le code postal ")
|
|
return False, "Les données de facturation sont incompletes. Verifiez le code postal ", None
|
|
new_data['invoice_adr_zip'] = invoice_adr_zip_check
|
|
|
|
invoice_email_check = ""
|
|
if ("invoice_email" in part_account[0].keys()):
|
|
if part_account[0]['invoice_email']:
|
|
invoice_email_check = part_account[0]['invoice_email']
|
|
|
|
if (len(invoice_email_check.strip()) == 0 ):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][
|
|
3]) + " Les données de facturation sont incompletes. Verifiez l'adresse email ")
|
|
return False, "Les données de facturation sont incompletes. Verifiez l'adresse email ", None
|
|
new_data['invoice_email'] = invoice_email_check
|
|
|
|
invoice_vat_num_check = ""
|
|
if ("invoice_vat_num" in part_account[0].keys()):
|
|
if part_account[0]['invoice_vat_num']:
|
|
invoice_vat_num_check = part_account[0]['invoice_vat_num']
|
|
|
|
if ("invoice_telephone" in part_account[0].keys()):
|
|
if part_account[0]['invoice_telephone']:
|
|
new_data['invoice_telephone'] = part_account[0]['invoice_telephone']
|
|
|
|
new_data['invoice_vat_num'] = invoice_vat_num_check
|
|
|
|
|
|
|
|
# Recuperation ds données de payement
|
|
coll_part_payment = MYSY_GV.dbname['payement_mode']
|
|
local_count = coll_part_payment.count_documents({'client_recid': user_recid, 'valide': '1'})
|
|
|
|
if (local_count <= 0):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + "Aucun mode de payement pour ce client, Impossible de créer la commande ")
|
|
return False, "Aucun mode de payement pour ce client ", None
|
|
|
|
|
|
part_account = coll_part_payment.find({'client_recid': user_recid, 'valide': '1'})
|
|
|
|
#print(" new_data['total_ht'] = "+str(new_data['total_ht']) + " -- new_data['total_tva'] "
|
|
# +str(new_data['total_tva'])+ " -- new_data['total_ttc'] = "+ str(new_data['total_ttc']))
|
|
|
|
"""
|
|
# Les données de payement ne sont utilisées que si le montant > 0 ou si il y a un code promo.
|
|
|
|
En effet on peut avoir montant TTC = 0 par qu'on a benéficié d'un code promo à 100%
|
|
"""
|
|
if (total_ttc_float > 0 or len(str(discount_code)) > 2 ):
|
|
if ("type" in part_account[0].keys()):
|
|
if part_account[0]['type']:
|
|
new_data['type_payment'] = part_account[0]['type']
|
|
|
|
if ("bic" in part_account[0].keys()):
|
|
if part_account[0]['bic']:
|
|
new_data['bic_payment'] = part_account[0]['bic']
|
|
|
|
if ("cvv_carte" in part_account[0].keys()):
|
|
if part_account[0]['cvv_carte']:
|
|
new_data['cvv_carte_payment'] = part_account[0]['cvv_carte']
|
|
|
|
if ("date_exp_carte" in part_account[0].keys()):
|
|
if part_account[0]['date_exp_carte']:
|
|
new_data['date_exp_carte_payment'] = part_account[0]['date_exp_carte']
|
|
|
|
if ("iban" in part_account[0].keys()):
|
|
if part_account[0]['iban']:
|
|
new_data['iban_payment'] = part_account[0]['iban']
|
|
|
|
if ("nom_carte" in part_account[0].keys()):
|
|
if part_account[0]['nom_carte']:
|
|
new_data['nom_carte_payment'] = part_account[0]['nom_carte']
|
|
|
|
if ("nom_compte" in part_account[0].keys()):
|
|
if part_account[0]['nom_compte']:
|
|
new_data['nom_compte_payment'] = part_account[0]['nom_compte']
|
|
|
|
if ("num_carte" in part_account[0].keys()):
|
|
if part_account[0]['num_carte']:
|
|
new_data['num_carte_payment'] = part_account[0]['num_carte']
|
|
|
|
|
|
new_data['valide'] = "1"
|
|
now = datetime.now()
|
|
|
|
|
|
new_data['date_update'] = str(now)
|
|
new_data['order_date'] = str(now.strftime("%d/%m/%Y %H:%M:%S"))
|
|
|
|
new_data['order_id'] = "MySy_00"+str(mycommon.create_order_id())
|
|
|
|
print(" ### la line à facturer est ::::: "+str(new_data))
|
|
|
|
# Enregistrement de la commande dans la systeme
|
|
|
|
coll_order = MYSY_GV.dbname['sales_order']
|
|
ret_val = coll_order.insert_one(new_data)
|
|
|
|
if ret_val and ret_val.inserted_id:
|
|
#print( "str(new_data['invoice_email']) = "+str(new_data['invoice_email']))
|
|
# Envoie de l'email
|
|
local_status, message = email.SalesOrderConfirmationEmail(str(new_data['invoice_email']), new_data )
|
|
if( local_status is False):
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + "Impossible de créer la commande "+str(message))
|
|
return False, "Impossible de créer la commande ", None
|
|
|
|
# Mise à jour du partenaire (ajouter le nouveau pack)
|
|
"""
|
|
/!\ Important :
|
|
Si le partenaire avait deja une date d'arret de son abonnement, la creation d'une nouvelle commande
|
|
entraine automatiquement l'annulation de l'arret de l'abonnement.
|
|
"""
|
|
if ("pack" in diction.keys()):
|
|
if diction['pack']:
|
|
mypack = diction['pack']
|
|
coll_partner = MYSY_GV.dbname['partnair_account']
|
|
ret_val = coll_partner.find_one_and_update(
|
|
{'recid': str(user_recid), },
|
|
{"$set": {'pack_service':str(mypack),
|
|
'nb_formation':str(nb_formation),
|
|
'abonnement_periodicite': str(periodicite),
|
|
'end_date_abonnement':''}},
|
|
upsert=False,
|
|
return_document=ReturnDocument.AFTER
|
|
)
|
|
|
|
# Apres la creation du nouvel abonnement, il faut aller cloturer l'ancien abonnement actif
|
|
today_tmp = datetime.today().date()
|
|
ret_val_cloture = coll_order.update_many({'order_id': {'$ne' : str(new_data['order_id'])}, 'valide': '1',
|
|
'client_recid':str(user_recid)},
|
|
{"$set": {'end_date': str(today_tmp), 'date_update': str(datetime.now())}},
|
|
)
|
|
|
|
|
|
# Facturation de la commande
|
|
print(" ######## lancement de la facturation total_ttc_float = " + str(total_ttc_float))
|
|
|
|
# Recuperation des données du partenaire
|
|
local_status_01, my_partner_01 = mycommon.get_partner_data_from_recid(user_recid)
|
|
if (local_status_01 is False):
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - impossible de récupérer les données du partenaire")
|
|
return False, str(inspect.stack()[0][3]) + " - impossible de récupérer les données du partenaire. "
|
|
|
|
#print(" ### my_partner_01 = ", str(my_partner_01))
|
|
|
|
if ("stripe_subscription_id" in my_partner_01.keys()):
|
|
new_data['stripe_subscription_id'] = my_partner_01['stripe_subscription_id']
|
|
|
|
|
|
#print(" ### new_data = ", str(new_data))
|
|
|
|
|
|
"""
|
|
Ici creation de la facture mysy
|
|
Regle : On ne crée et envoie que la première facture du client.
|
|
Toutes les autres mises à jour ou changement d'abonnement
|
|
ne seront envoyé qu'apres payement dans stripe.
|
|
"""
|
|
# Verifier si on a deja une 1ere facture
|
|
has_stripe_invoice = False
|
|
if( "stripe_account_id" in my_partner_01.keys() ):
|
|
has_stripe_invoice = Stripe.Stripe_Customer_Has_Invoice(my_partner_01['stripe_account_id'])
|
|
|
|
if( has_stripe_invoice is False ):
|
|
print(" ### Il s'agit de la 1ere facturation pour le client ")
|
|
if (total_ttc_float > 0 or len(str(discount_code)) > 2):
|
|
local_invoice_status, local_invoice_retval = CreateInvoice(new_data)
|
|
if( local_invoice_status == False):
|
|
return False, local_invoice_retval, None
|
|
"""else:
|
|
# La facture a bien été créée, on va mettre à jour le client/partenaire avec les champ : "send_pre_invoice_data" à '1', "date_time_pre_invoice_created" à date_time_now.
|
|
ret_val_local = MYSY_GV.dbname['partnair_account'].find_one_and_update({"recid":str(user_recid), 'active':'1', 'locked':'0'},
|
|
{"$set": {'send_pre_invoice_data':'1', 'datetime_pre_invoice_created':str(datetime.now())}},
|
|
upsert=False,
|
|
return_document=ReturnDocument.AFTER
|
|
)
|
|
"""
|
|
else:
|
|
print(" ### Il NE s'agit PAS de la 1ere facturation du client ",str(my_partner_01['stripe_account_id']))
|
|
# La facture a bien été créée, on va mettre à jour le client/partenaire avec les champ : "send_pre_invoice_data" à '1', "date_time_pre_invoice_created" à date_time_now.
|
|
ret_val_local = MYSY_GV.dbname['partnair_account'].find_one_and_update(
|
|
{"recid": str(user_recid), 'active': '1', 'locked': '0'},
|
|
{"$set": {'send_pre_invoice_data': '1', 'datetime_pre_invoice_created': str(datetime.now())}},
|
|
upsert=False,
|
|
return_document=ReturnDocument.AFTER
|
|
)
|
|
|
|
|
|
# Apres la facturation, on met à jour le display_ranking des formations du partenaire.
|
|
tmp_diction = {"partnaire_recid":str(user_recid), "new_pack_name":str(mypack)}
|
|
|
|
class_mgt.UpdataPartnerRankingClass(tmp_diction)
|
|
|
|
|
|
return True, "la commande été correctement créee", str(new_data['order_id'])
|
|
else:
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + "Impossible de créer la commande ")
|
|
return False, "Impossible de créer la commande ", None
|
|
|
|
except Exception as e:
|
|
exc_type, exc_obj, exc_tb = sys.exc_info()
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
|
|
return False, " Impossible de créer la facture", False
|
|
|
|
|
|
|
|
"""
|
|
Cette fontion récupérer l'id de la dernière facture
|
|
"""
|
|
def Get_Last_Invoice_ID():
|
|
try:
|
|
last_invoice_id = 0
|
|
coll_invoice = MYSY_GV.dbname["factures"]
|
|
tmp_val = coll_invoice.count_documents({})
|
|
if( tmp_val ):
|
|
last_invoice_id = tmp_val
|
|
|
|
return True, last_invoice_id
|
|
except Exception as e:
|
|
exc_type, exc_obj, exc_tb = sys.exc_info()
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
|
|
return False, " Impossible de récupérer l'ID de la dernière facture "
|
|
|
|
|
|
"""
|
|
Cette fonction créer une facture
|
|
"""
|
|
def CreateInvoice(diction):
|
|
try:
|
|
field_list_obligatoire = ['client_recid', 'invoice_nom', 'order_id', 'order_date', 'total_ttc','total_tva',
|
|
'total_ht','item_0']
|
|
|
|
for val in field_list_obligatoire:
|
|
if val not in diction:
|
|
mycommon.myprint(str(inspect.stack()[0][
|
|
3]) + " - Le champ '" + val + "' n'existe pas, Creation facture annulée")
|
|
return False, " Impossible de créer la facture (1)"
|
|
|
|
order_id = ""
|
|
status_tmp, last_invoice_id = Get_Last_Invoice_ID()
|
|
if( status_tmp is False):
|
|
mycommon.myprint(str(inspect.stack()[0][
|
|
3]) + " Impossible de récupérer Get_Last_Invoice_ID ")
|
|
return False, " Impossible de créer la facture (2)"
|
|
|
|
#print(" ######## last_invoice_id = "+str(last_invoice_id))
|
|
last_invoice_id = last_invoice_id + 1
|
|
now = datetime.now()
|
|
prefix = "FACT_"+str(now.year)[-2:]+str(now.month)+str("000")
|
|
Order_Invoice = str(prefix)+str(last_invoice_id)
|
|
diction['invoice_id']= str(Order_Invoice)
|
|
|
|
diction['due_date'] = str(now.strftime("%d/%m/%Y"))
|
|
diction['invoice_date'] = str(now.strftime("%d/%m/%Y"))
|
|
diction['printed'] = "0"
|
|
|
|
#print(" collection de facture = "+str(diction))
|
|
coll_facture = MYSY_GV.dbname['factures']
|
|
ret_val = coll_facture.insert_one(diction)
|
|
|
|
if ret_val and ret_val.inserted_id:
|
|
#print("str(new_data['invoice_email']) = " + str(diction['invoice_email']))
|
|
#print("str(diction['invoice_id']) = " + str(diction['invoice_id']))
|
|
|
|
# Envoie de l'email de la facture
|
|
PrintAndSendInvoices(str(diction['invoice_id']))
|
|
#email.SalesOrderConfirmationEmail(str(new_data['invoice_email']), new_data)
|
|
|
|
|
|
"""
|
|
Mise à jour de la commande avec le prochaine date de facturation """
|
|
next_invoice_date = ""
|
|
if ("next_invoice_date" in diction.keys()):
|
|
if diction['next_invoice_date']:
|
|
local_status, tmp_date = mycommon.TryToDateYYYMMDD(diction['next_invoice_date'])
|
|
|
|
#print(" apres conversion tmp_date = "+str(tmp_date))
|
|
|
|
if( local_status and str(diction['periodicite']).lower() == "mensuel" ):
|
|
next_invoice_date = (tmp_date + relativedelta(months=+1)).date()
|
|
#print(" ### next_invoice_date = "+str(next_invoice_date))
|
|
elif (local_status is False):
|
|
#print(" ### IMPOSSIBLE DE FACTURER la COMMANDE")
|
|
return False, ""
|
|
|
|
if (local_status and str(diction['periodicite']).lower() == "annuel"):
|
|
next_invoice_date = (tmp_date + relativedelta(years=+1)).date()
|
|
#print(" ### next_invoice_date = " + str(next_invoice_date))
|
|
elif (local_status is False):
|
|
#print(" ### IMPOSSIBLE DE FACTURER la COMMANDE")
|
|
return False, ""
|
|
|
|
|
|
|
|
elif( str(diction['periodicite']).lower() == "mensuel" ):
|
|
next_invoice_date = datetime.today().date() + relativedelta(months=+1)
|
|
|
|
elif (str(diction['periodicite']).lower() == "annuel"):
|
|
next_invoice_date = datetime.today().date() + relativedelta(years=+1)
|
|
|
|
print(" ####### prochaine facturation de la commande : "+str(diction['order_id'])+" LE : "+str(next_invoice_date))
|
|
|
|
coll_orders = MYSY_GV.dbname['sales_order']
|
|
ret_val_order = coll_orders.find_one_and_update(
|
|
{'order_id': str(diction['order_id']) }, {"$set": {'next_invoice_date': str(next_invoice_date)}},
|
|
upsert=False,
|
|
return_document=ReturnDocument.AFTER
|
|
)
|
|
|
|
if ("id" not in ret_val_order.keys()):
|
|
mycommon.myprint(
|
|
" Impression de mettre à jour la date de la prochaine facturation de la commande : ° " + str(diction['order_id']) + " ")
|
|
|
|
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) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
|
|
return False, " Impossible de facturer la commande N° "+str(order_id)+" "
|
|
|
|
|
|
"""
|
|
Cette fonction recupere toutes le factures non imprimé (c'est a dire que le pdf n'est pas créé)
|
|
1 - Crée le fichier PDF
|
|
2 - Envoie l'email avec la facture
|
|
"""
|
|
def PrintAndSendInvoices(invoice_id=None):
|
|
try:
|
|
i = 0
|
|
query = {'printed':'0'}
|
|
if ( invoice_id and len(str(invoice_id)) > 0):
|
|
query = {'printed':'0','factures':str(invoice_id) }
|
|
|
|
coll_invoice = MYSY_GV.dbname['factures']
|
|
|
|
for val in coll_invoice.find({'printed':'0'}):
|
|
i = i +1
|
|
if( convertHtmlToPdf( val ) is False ):
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible d'imprimer la facture N° "+
|
|
str(val['invoice_id']))
|
|
else:
|
|
mycommon.myprint(" Impression facture N° " +str(val['invoice_id'])+" OK")
|
|
|
|
ret_val = coll_invoice.find_one_and_update(
|
|
{'invoice_id': str(val['invoice_id'])}, {"$set": {'printed':'1'}},
|
|
upsert=False,
|
|
return_document=ReturnDocument.AFTER
|
|
)
|
|
|
|
if (ret_val['_id'] is False):
|
|
mycommon.myprint(" Impression facture N° " +str(val['invoice_id'])+" ==> Impossible de mettre à jour la facture")
|
|
|
|
|
|
return True, str(i)+" Factures ont été traitées"
|
|
|
|
except Exception as e:
|
|
exc_type, exc_obj, exc_tb = sys.exc_info()
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
|
|
return False, " Impossible d'imprimer les factures "
|
|
|
|
|
|
def convertHtmlToPdf(diction):
|
|
try:
|
|
field_list_obligatoire =['invoice_nom', 'invoice_adr_street', 'invoice_adr_zip', 'invoice_adr_city',
|
|
'invoice_adr_country', 'invoice_id', 'invoice_date', 'due_date', 'order_id', 'item_0',
|
|
'total_ht', 'total_tva', 'total_ttc','client_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 la liste des arguments ")
|
|
return False, " Impossible d'imprimer les factures"
|
|
|
|
#print(" ### convertHtmlToPdf diction =", diction)
|
|
discount_code = ""
|
|
if ("discount_code" in diction.keys()):
|
|
if diction['discount_code']:
|
|
discount_code = diction['discount_code']
|
|
|
|
discount_type = ""
|
|
if ("discount_type" in diction.keys()):
|
|
if diction['discount_type']:
|
|
discount_type = diction['discount_type']
|
|
|
|
discount_valeur = ""
|
|
if ("discount_valeur" in diction.keys()):
|
|
if diction['discount_valeur']:
|
|
discount_valeur = diction['discount_valeur']
|
|
|
|
discount_montant_remise = ""
|
|
if ("discount_montant_remise" in diction.keys()):
|
|
if diction['discount_montant_remise']:
|
|
discount_montant_remise = diction['discount_montant_remise']
|
|
|
|
discount_display_text = ""
|
|
if (discount_type == "fix"):
|
|
discount_display_text = " -" + str(discount_valeur) + " €"
|
|
elif (discount_type == "percent"):
|
|
discount_display_text = " -" + str(discount_valeur) + " %"
|
|
|
|
|
|
templateLoader = jinja2.FileSystemLoader(searchpath="./")
|
|
templateEnv = jinja2.Environment(loader=templateLoader)
|
|
TEMPLATE_FILE = "Template/invoice.html"
|
|
template = templateEnv.get_template(TEMPLATE_FILE)
|
|
# This data can come from database query
|
|
body = {
|
|
"data": {
|
|
"client_name": str(diction['invoice_nom']),
|
|
"client_address": str(diction['invoice_adr_street']),
|
|
"client_zip_ville": str(diction['invoice_adr_zip'])+" "+str(diction['invoice_adr_city']),
|
|
"client_pays": str(diction['invoice_adr_country']),
|
|
"invoice_id": str(diction['invoice_id']),
|
|
"invoice_date": str(diction['invoice_date']),
|
|
"due_date": str(diction['due_date']),
|
|
"orign_order": str(diction['order_id']),
|
|
"packs": str(diction['item_0']['code']),
|
|
"qty": str(diction['item_0']['qty']),
|
|
"unit_price": str(diction['item_0']['prix']),
|
|
"montant": str(diction['item_0']['amount']),
|
|
"total_ht": str(diction['total_ht']),
|
|
"tva": str(diction['total_tva']),
|
|
"total_ttc": str(diction['total_ttc']),
|
|
"discount_montant_remise": discount_montant_remise,
|
|
"discount_code": discount_code,
|
|
"discount_type": discount_type,
|
|
"discount_valeur": discount_valeur,
|
|
"discount_display_text": discount_display_text,
|
|
}
|
|
}
|
|
|
|
#print(" ### body = ", body)
|
|
sourceHtml = template.render(json_data=body["data"])
|
|
orig_file_name = "invoice_"+str(diction['invoice_id'])+".pdf"
|
|
outputFilename = str(MYSY_GV.INVOICE_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()
|
|
|
|
|
|
#mycommon.myprint(str(inspect.stack()[0][3]) +" debut envoie de la factureeee "+diction['invoice_id'])
|
|
|
|
email.SendInvoiceEmail(str(diction['invoice_email']), diction )
|
|
|
|
|
|
|
|
# On deplace la facture vers le serveur ftp
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) + " On va deplacer de la facture vers " + str(
|
|
MYSY_GV.INVOICE_FTP_LOCAL_STORAGE_DIRECTORY))
|
|
|
|
print(" ### GRRRR remoteFilePath = ", str(MYSY_GV.INVOICE_FTP_LOCAL_STORAGE_DIRECTORY)+str(orig_file_name))
|
|
|
|
cnopts = pysftp.CnOpts()
|
|
cnopts.hostkeys = None
|
|
with pysftp.Connection(host=MYSY_GV.MYSY_FTP_HOST, username=MYSY_GV.MYSY_FTP_LOGIN, password=MYSY_GV.MYSY_FTP_PWD, cnopts=cnopts) as session:
|
|
print("Connection successfully established ... ")
|
|
localFilePath = outputFilename
|
|
remoteFilePath = str(MYSY_GV.INVOICE_FTP_LOCAL_STORAGE_DIRECTORY)+str(orig_file_name)
|
|
|
|
print(" DEBUT DEPLACEMENT DE " + str(localFilePath) + " VERS " + str(remoteFilePath) + " AVANTTT TRAITEMENT")
|
|
# Use put method to upload a file
|
|
session.put(localFilePath, remoteFilePath)
|
|
# Switch to a remote directory
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3])+" DEPLACEMENT DE "+str(localFilePath)+" VERS "+str(remoteFilePath)+" EST OKKKK")
|
|
|
|
|
|
|
|
# return True on success and False on errors
|
|
print(pisaStatus.err, type(pisaStatus.err))
|
|
|
|
""" update du 09/07/23 - test envoie info prochaine facture
|
|
local_diction = {}
|
|
local_diction['recid'] = diction['client_recid']
|
|
email.Strip_Get_Customer_Upcoming_Invoice(local_diction) """
|
|
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
mycommon.myprint(
|
|
str(inspect.stack()[0][3]) +"Exception when calling SMTPApi->send_transac_email: %s\n" % e)
|
|
exc_type, exc_obj, exc_tb = sys.exc_info()
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
|
|
|
|
return False
|
|
|
|
|
|
"""
|
|
Cette fonction la facture PDF d'un client
|
|
"""
|
|
|
|
def GetCustomerInvoice(diction):
|
|
try:
|
|
'''
|
|
Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente,
|
|
On controle que les champs obligatoires sont presents dans la liste
|
|
'''
|
|
field_list_obligatoire = ['token', 'invoiceid']
|
|
|
|
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 la liste des arguments ")
|
|
return False, " Impossible de récupérer la facture"
|
|
|
|
user_recid = "None"
|
|
my_token = ""
|
|
my_invoiceid = ""
|
|
my_invoice_name = ""
|
|
|
|
|
|
if ("token" in diction.keys()):
|
|
if diction['token']:
|
|
my_token = diction['token']
|
|
|
|
if ("invoiceid" in diction.keys()):
|
|
if diction['invoiceid']:
|
|
my_invoiceid = diction['invoiceid']
|
|
my_invoice_name = 'invoice_'+str(my_invoiceid)+".pdf"
|
|
|
|
#print(" on cherche la facure :"+my_invoice_name)
|
|
|
|
# Verification de la validité du token/mail dans le cas des user en mode connecté
|
|
if (len(str(my_token)) > 0):
|
|
retval = mycommon.check_partner_token_validity("", my_token)
|
|
|
|
if retval is False:
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - La session de connexion n'est pas valide")
|
|
return False, " Impossible de récupérer la formation"
|
|
|
|
# Recuperation du recid de l'utilisateur
|
|
user_recid = mycommon.get_parnter_recid_from_token(my_token)
|
|
if user_recid is False:
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de récupérer le token de l'utilisateur")
|
|
return False, " Impossible de récupérer la formation"
|
|
|
|
if (len(str(my_token)) <= 0):
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " - Le token est vide")
|
|
return False, " Impossible de récupérer la facture"
|
|
|
|
|
|
# Recuperation de la facture depuis le serveur sFTP
|
|
cnopts = pysftp.CnOpts()
|
|
cnopts.hostkeys = None
|
|
with pysftp.Connection(host=MYSY_GV.MYSY_FTP_HOST, username=MYSY_GV.MYSY_FTP_LOGIN,
|
|
password=MYSY_GV.MYSY_FTP_PWD, cnopts=cnopts) as session:
|
|
#print("Connection successfully established ... ")
|
|
session.chdir(MYSY_GV.INVOICE_FTP_LOCAL_STORAGE_DIRECTORY)
|
|
|
|
#print('our current working directory is: ', session.pwd)
|
|
|
|
session.get(my_invoice_name, './temp_direct/'+str(my_invoice_name))
|
|
|
|
if os.path.exists("./temp_direct/"+str(my_invoice_name)):
|
|
path = "./temp_direct/"+str(my_invoice_name)
|
|
|
|
return send_file(path, as_attachment=True)
|
|
|
|
|
|
except Exception as e:
|
|
exc_type, exc_obj, exc_tb = sys.exc_info()
|
|
print(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
|
|
return False, "KO"
|
|
|
|
|
|
"""
|
|
Cette fonction va créer toutes les facture pour les commandes
|
|
dont la date facturation est arrivée à échéance (colonne : next_invoice_date)
|
|
|
|
IMPORTANT : Meme la facturation n'est pas faire le meme jours, on qu'on a un retard de X jours, ceci
|
|
n'est pas grave tant que X < 1 mois.
|
|
|
|
- le end date doit etre vide
|
|
|
|
Car à la facturation, la date prochaine facturation se mettra à date de dernière facture + 1 mois ou un 1 an.
|
|
|
|
"""
|
|
"""
|
|
Cette fonction créer une facture
|
|
"""
|
|
def AutoamticCreateInvoice():
|
|
try:
|
|
|
|
|
|
field_list_obligatoire = ['client_recid', 'invoice_nom', 'order_id', 'order_date', 'total_ttc','total_tva','total_ht','item_0']
|
|
coll_order = MYSY_GV.dbname['sales_order']
|
|
|
|
today = datetime.today().date()
|
|
i = 0
|
|
for diction in coll_order.find({"next_invoice_date" : { '$lte' : str(today) },
|
|
'end_date': { '$exists': False }},{'_id':0}):
|
|
i = i +1
|
|
print(' Facturation de la commande '+str(diction['order_id'])+" -- "+str(diction['next_invoice_date']))
|
|
|
|
CreateInvoice(diction)
|
|
|
|
return True, str(i)+" Factures ont été créées"
|
|
|
|
except Exception as e:
|
|
exc_type, exc_obj, exc_tb = sys.exc_info()
|
|
mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
|
|
return False, " Impossible de créer les factures automatiques"
|
|
|