| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- '''
- Génère des factures dans la base Factures à partir des données de Tarification de Analytique
- @author: olivier.massot, févr. 2018
- '''
- from datetime import datetime
- import logging
- import sys
- from path import Path
- from core import logconf
- from core.model import Model
- from core.pde import FacturesDb, AnalytiqueDb, CommunDb
- logger = logging.getLogger("analytique2facture")
- logconf.start("analytique2facture", logging.DEBUG)
- class EnTete(Model):
- _FIELDS = ["lngPieceId", "lngDocId", "lngTiersId", "lngASTRE", "strCodeProduit", "bytTitreId",
- "strCodeAdresse", "strAdresse1", "strAdresse2", "strAdresse3", "strAdresse4", "strAdresse5",
- "strPaysIdIso3166", "bytTVATiersId", "strTelephone", "strTelecopie", "strPortable",
- "strEMail", "strWeb", "strLangueIdIso639", "strCompteComptable", "strDeviseIdIso4217",
- "bytReglementId", "strReglement", "bytClasseTarifId", "bytClasseRemiseTiersId", "bytNbExFacture",
- "strStatTiers", "bytSituationIdPrincipale", "bytSituationIdSecondaire", "memObsEntete",
- "memObsPied", "memObsInterne", "bytTypeDocumentId", "strStatDocEntete", "dblCoursDevise",
- "dtmCoursDevise", "dtmCreation", "strUserIdCreation", "dtmLastMod", "strUserIdLastMod",
- "dtmPiece", "dtmFirstPrint", "dtmLastPrint", "dtmCompta", "dtmLivraison", "dtmEcheance",
- "bytTypeTarif", "idEtatEmission"]
- class Ligne(Model):
- _FIELDS = ["lngPieceId", "intLigneId", "strArticleId", "strArticle", "bytTVAArticleId", "bytTVAId", "dblTVATaux",
- "dblQte", "bytUniteIdQuantite", "bytNbDecQuantite", "bytUniteIdPrix", "dblCnvUniteCoef",
- "bytNbDecQuantiteConvertie", "dblPUhtBrutDev", "dblPUttcBrutDev", "dblPUhtNetDev", "dblPUttcNetDev",
- "bytNbDecPU", "dblPThtBrutDev", "dblPTttcBrutDev", "dblPThtNetDev", "dblPTttcNetDev", "strStatArticle",
- "strStatDocLigne", "dblTauxRemise1", "dblTauxRemise2", "dblTauxRemise3", "blnPrestation",
- "strCompteComptable", "memObs", "memObsInterne", "bytLigneSousTotal", "intLigneIdRattachement",
- "blnLigneVisible", "blnLigneGeneree", "bytGenerateurId", "dblPUhtBrut", "dblPUttcBrut", "dblPUhtNet",
- "dblPUttcNet", "dblPThtBrut", "dblPTttcBrut", "dblPThtNet", "dblPTttcNet", "bytClasseRemiseArticleId",
- "dblPUSaisie", "strPUAff", "strQteAff"]
- # # POUR TESTER, décommenter les lignes suivantes
- ##-----------------------------------------------
- logger.warning("<<<<<<<<<<<<<< Mode TEST >>>>>>>>>>>>>>>>>")
- AnalytiqueDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\Db_analytique.mdb")
- FacturesDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\Facture_data.mdb")
- CommunDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\Commun_Data.mdb")
- ##-----------------------------------------------
- # Connexion à Analytique
- analytique_db = AnalytiqueDb(autocommit=False)
- # Connexion à Controles
- facture_db = FacturesDb(autocommit=False)
- # Connexion à CommunDb
- commun_db = CommunDb(autocommit=False)
- # mois_facturation = input("Veuillez renseigner le mois de facturation ('q' pour quitter): ") # Format: voir avec jacky
- # if mois_facturation == 'q':
- # sys.exit(1)
- mois_facturation = "1801"
- sql = """SELECT * FROM tbl_Tarification
- WHERE strStatut='A facturer'
- ORDER BY DblAffaireId, DblTarifId DESC;
- """
- # Liste les interventions à facturer par affaire
- a_facturer = {}
- for interv in analytique_db.read(sql):
- if not interv.DblAffaireId in a_facturer.keys():
- a_facturer[interv.DblAffaireId] = []
- a_facturer[interv.DblAffaireId].append(interv)
- if not a_facturer:
- logger.info("Aucune facture à créer - Opération annulée")
- sys.exit(1)
- # Pour chaque facture, on va ajouter une ligne dans tblPieceEntete, et une ligne par intervention dans tblPieceLigne
- # > NB: On ne touche pas aux interventions de cette affaire qui ont déja été facturées
- for affaireId, interventions in a_facturer.items():
- piece_id = facture_db.first("SELECT Max(lngpieceId) As Id FROM tblPieceEntete").Id + 1
- if str(piece_id)[:2] != mois_facturation[:2]:
- # On démarre une nouvelle année
- piece_id = 10000 * int(mois_facturation[:2]) + 1
- affaire = analytique_db.first("SELECT * FROM tbl_Affaires WHERE dblAffaireId={}".format(affaireId))
- if not affaire:
- logger.error("Affaire {} - L'affaire n'existe pas dans tbl_Affaires".format(affaireId))
- continue
- if not affaire.strMOId:
- logger.error("Affaire {} - Destinataire manquant dans tbl_Affaires".format(affaireId))
- continue
- destinataire = commun_db.first("SELECT * FROM tblTiers WHERE lngTiersId={}".format(affaire.strMOId))
- if not destinataire:
- logger.warning("Affaire {} - Destinataire introuvable dans tblTiers ('{}'), remplacé par tiers n°190".format(affaireId, affaire.strMOId))
- destinataire = commun_db.first("SELECT * FROM tblTiers WHERE lngTiersId=190")
- entete = EnTete()
- entete.lngPieceId = piece_id
- # on recupere les champs de tblTiers depuis le champ lngASTRE (champ n°3) jusqu'au champ strCodeProduit (champ n°26)
- # ATTENTION: le champ 'strPaysIdIso3166-A2' n'etant pas un nom de propriété valide, il est renomme en strPaysIdIso3166 dans le modèle.
- entete.lngTiersId = destinataire.lngTiersId
- entete.lngASTRE = destinataire.lngASTRE
- entete.bytTitreId = destinataire.bytTitreId
- entete.strCodeAdresse = destinataire.strCodeAdresse
- entete.strAdresse1 = destinataire.strAdresse1
- entete.strAdresse2 = destinataire.strAdresse2
- entete.strAdresse3 = destinataire.strAdresse3
- entete.strAdresse4 = destinataire.strAdresse4
- entete.strAdresse5 = destinataire.strAdresse5
- entete.strPaysIdIso3166 = destinataire.field_11
- entete.bytTVATiersId = destinataire.bytTVATiersId
- entete.strTelephone = destinataire.strTelephone
- entete.strTelecopie = destinataire.strTelecopie
- entete.strPortable = destinataire.strPortable
- entete.strEMail = destinataire.strEMail
- entete.strWeb = destinataire.strWeb
- entete.strLangueIdIso639 = destinataire.strLangueIdIso639
- entete.strCompteComptable = destinataire.strCompteComptable
- entete.strDeviseIdIso4217 = destinataire.strDeviseIdIso4217
- entete.bytReglementId = destinataire.bytReglementId
- entete.bytClasseTarifId = destinataire.bytClasseTarifId
- entete.bytNbExFacture = destinataire.bytNbExFacture
- entete.bytClasseRemiseTiersId = destinataire.bytClasseRemiseTiersId
- entete.bytNbExFacture = destinataire.bytNbExFacture
- entete.strStatTiers = destinataire.strStatTiers
- # Valeurs fixes
- entete.lngDocId = 0
- entete.strLangueIdIso639 = "fr"
- entete.strDeviseIdIso4217 = "EUR"
- entete.bytReglementId = 1
- entete.bytClasseTarifId = 1
- entete.bytClasseRemiseTiersId = 1
- entete.bytNbExFacture = 1
- entete.strStatTiers = ""
- entete.bytSituationIdPrincipale = 2
- entete.bytSituationIdSecondaire = 41
- entete.bytTypeDocumentId = 50
- entete.strStatDocEntete = "PI00"
- entete.dblCoursDevise = 1
- entete.dtmCoursDevise = datetime(2002, 1, 1)
- entete.bytTypeTarif = 1
- entete.strReglement = "POUR ACQUITTER CET ETAT DE REDEVANCE,\nATTENDEZ IMPERATIVEMENT DE RECEVOIR LE TITRE DE PERCEPTION EMANANT DE LA PAIERIE DEPARTEMENTALE"
- # Commentaires
- entete.memObsEntete = """[Mois : {mois_facturation}]\n [Lieu de travail : ] {affaire.strLieux}\n [V/Cde : ] {affaire.Ref} du {affaire.dtmCommande}
- """.format(mois_facturation, affaire)
- entete.memObsInterne = "N° Affaire analytique : {}".format(affaire.stLiaisonControle)
- entete.strStatDocEntete = "PC00" if ("/" in affaire.stLiaisonControle or affaire.stLiaisonControle == "RDBOEC") else "PT00"
- entete.strUserIdCreation = "analytique2facture"
- entete.strUserIdLastMod = "analytique2facture"
- i = 0
- lignes = []
- for interv in interventions:
- i += 1
- ligne = Ligne()
- ligne.lngPieceId = piece_id
- ligne.intLigneId = i
- ligne.strArticleId = interv.strArticleId
- article = commun_db.first("SELECT * FROM tblArticle WHERE strArticleId='{}'".format(interv.strArticleId))
- ligne.strArticle = article.strArticle if article else ""
- ligne.bytTVAArticleId = article.bytTVAArticleId if article else 0
- tva = commun_db.first("SELECT bytTVAId FROM tblTVA WHERE bytTVATiersId={} AND bytTVAArticleId={}".format(destinataire.bytTVATiersId, ligne.bytTVAArticleId))
- ligne.bytTVAId = tva.bytTVAId
- taux = commun_db.first("SELECT dblTVATaux FROM tblTVATaux WHERE bytTVAId={}".format(ligne.bytTVAId))
- ligne.dblTVATaux = taux.dblTVATaux
- ligne.dblQte = interv.dblquantite
- unite = commun_db.first("SELECT * FROM tblUnite WHERE strUniteCourt='{}'".format(interv.strunite))
- ligne.bytUniteIdQuantite = unite.bytUniteId
- ligne.bytUniteIdPrix = unite.bytUniteId
- ligne.dblPUhtBrutDev = interv.dblPrixUnitaire
- ligne.dblPUhtNetDev = interv.dblPrixUnitaire
- ligne.dblPThtNetDev = interv.dblPrixTotal
- ligne.blnPrestation = True
- ligne.memObs = "Intervention le {}{}".format(interv.dtmFin,
- "\nRapport no : {}".format(interv.strRapportId) if interv.strRapportId else "")
- ligne.blnLigneGeneree = True
- ligne.bytGenerateurId = 1
- ligne.dblPThtNet = interv.dblPrixTotal
- ligne.bytClasseRemiseArticleId = 1
- ligne.dblPUSaisie = interv.dblPrixUnitaire
- ligne.strPUAff = "{} EUR/{}".format(interv.dblPrixUnitaire, interv.strunite)
- ligne.strQteAff = "{:03.02f} {}".format(interv.dblquantite, interv.strunite)
- lignes.append(ligne)
- # Toutes les lignes ont été ajoutées: on créé maintenant les lignes de totaux
- montant_ht = sum([ligne.dblPThtNetDev for ligne in lignes])
- taux_tva = lignes[0].dblTVATaux
- montant_tva = (0.01 * taux_tva) * montant_ht
- montant_ttc = montant_ht + montant_tva
- # Sous-total HT (ligne 32000)
- ligne_total_1 = Ligne()
- ligne_total_1.lngPieceId = piece_id
- ligne_total_1.intLigneId = 32000
- ligne_total_1.strArticleId = ""
- ligne_total_1.strArticle = "Total H.T."
- ligne_total_1.dblPThtNetDev = montant_ht
- ligne_total_1.dblPTttcNetDev = montant_ttc
- ligne_total_1.bytLigneSousTotal = 10
- ligne_total_1.blnLigneVisible = False
- ligne_total_1.dblPThtNet = montant_ht
- ligne_total_1.dblPTttcNet = round(montant_ttc, 2)
- ligne_total_1.dblPUSaisie = round(montant_ht, 2)
- ligne_total_1.strPUAff = "{:03.02f} EUR".format(montant_ht)
- lignes.append(ligne_total_1)
- # Sous-total TVA (ligne 32001)
- ligne_total_2 = Ligne()
- ligne_total_2.lngPieceId = piece_id
- ligne_total_2.intLigneId = 32001
- ligne_total_2.strArticleId = ""
- ligne_total_2.strArticle = """TVA 1 : {taux_tva}% H.T. : {montant_ht:03.02f} T.V.A. :
- {montant_tva:03.02f} T.T.C. : {montant_ttc:03.02f}:""".format(taux_tva=taux_tva,
- montant_ht=montant_ht,
- montant_tva=montant_tva,
- montant_ttc=montant_ttc)
- ligne_total_2.bytTVAId = lignes[0].bytTVAId
- ligne_total_2.dblTVATaux = taux_tva
- ligne_total_2.dblPThtNetDev = montant_ht
- ligne_total_2.dblPTttcNetDev = montant_ttc
- ligne_total_2.bytLigneSousTotal = 11
- ligne_total_2.blnLigneVisible = False
- ligne_total_2.dblPThtNet = montant_ht
- ligne_total_2.dblPTttcNet = round(ligne_total_1.dblPTttcNetDev, 2)
- ligne_total_2.dblPUSaisie = round(montant_tva, 2)
- ligne_total_2.strPUAff = "{:03.02f} EUR".format(montant_tva)
- lignes.append(ligne_total_2)
- # Sous-total TTC (ligne 32500)
- ligne_total_3 = Ligne()
- ligne_total_3.lngPieceId = piece_id
- ligne_total_3.intLigneId = 32500
- ligne_total_3.strArticleId = ""
- ligne_total_3.strArticle = "Total T.T.C."
- ligne_total_3.dblPThtNetDev = montant_ht
- ligne_total_3.dblPTttcNetDev = montant_ttc
- ligne_total_3.bytLigneSousTotal = 12
- ligne_total_3.blnLigneVisible = False
- ligne_total_3.dblPThtNet = montant_ttc
- ligne_total_3.dblPTttcNet = round(montant_ttc, 2)
- ligne_total_3.dblPUSaisie = round(montant_ttc, 2)
- ligne_total_3.strPUAff = "{:03.02f} EUR".format(montant_ttc)
- lignes.append(ligne_total_3)
- # Insérer les données dans tbl_Facture
- # Maj tbl_Tarification.strNumFacture et strStatut pour marquer la ligne comme facturée.
|