|
|
@@ -6,6 +6,7 @@
|
|
|
'''
|
|
|
from datetime import datetime
|
|
|
import logging
|
|
|
+import string
|
|
|
import sys
|
|
|
|
|
|
from path import Path
|
|
|
@@ -19,28 +20,46 @@ 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"]
|
|
|
+ pass
|
|
|
|
|
|
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"]
|
|
|
-
|
|
|
+ def __init__(self):
|
|
|
+ # Valeurs fixes
|
|
|
+ self.bytNbDecQuantite = 2
|
|
|
+ self.dblCnvUniteCoef = 1
|
|
|
+ self.bytNbDecQuantiteConvertie = 2
|
|
|
+ self.bytNbDecPU = 2
|
|
|
+ self.bytLigneSousTotal = 1
|
|
|
+ self.intLigneIdRattachement = 0
|
|
|
+ self.blnLigneVisible = True
|
|
|
+ self.blnLigneGeneree = False
|
|
|
+ self.bytGenerateurId = 0
|
|
|
+ self.bytClasseRemiseArticleId = 0
|
|
|
+ self.bytTVAArticleId = 0
|
|
|
+ self.bytTVAId = 0
|
|
|
+ self.dblTVATaux = 0
|
|
|
+ self.bytUniteIdQuantite = 0
|
|
|
+ self.bytUniteIdPrix = 0
|
|
|
+
|
|
|
+class SqlFormatter(string.Formatter):
|
|
|
+ def format_field(self, value, format_spec):
|
|
|
+ if value is None:
|
|
|
+ value = "Null"
|
|
|
+ format_spec = ""
|
|
|
+ if format_spec == "date":
|
|
|
+ value = "#{:%Y-%m-%d %H:%M:%S}#".format(value)
|
|
|
+ format_spec = ""
|
|
|
+
|
|
|
+ formatted = super().format_field(value, "")
|
|
|
+ formatted = formatted.replace("'", "''")
|
|
|
+ formatted = formatted.replace("\"", "''")
|
|
|
+ formatted = formatted.replace("\t", " ")
|
|
|
+
|
|
|
+ if format_spec == "text":
|
|
|
+ formatted = "'{}'".format(formatted)
|
|
|
+
|
|
|
+ return formatted
|
|
|
+Sql = SqlFormatter()
|
|
|
|
|
|
# # POUR TESTER, décommenter les lignes suivantes
|
|
|
##-----------------------------------------------
|
|
|
@@ -61,10 +80,11 @@ 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
|
|
|
+current = "{:%m/%Y}".format(datetime.now())
|
|
|
+# mois_facturation = input("Veuillez renseigner le mois de facturation [defaut: {}] ('q' pour quitter): ".format(current)) # Format: voir avec jacky
|
|
|
# if mois_facturation == 'q':
|
|
|
# sys.exit(1)
|
|
|
-mois_facturation = "1801"
|
|
|
+mois_facturation = "01/2018"
|
|
|
|
|
|
sql = """SELECT * FROM tbl_Tarification
|
|
|
WHERE strStatut='A facturer'
|
|
|
@@ -82,15 +102,13 @@ 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]:
|
|
|
+ if str(piece_id)[:2] != mois_facturation[-2:]:
|
|
|
# On démarre une nouvelle année
|
|
|
piece_id = 10000 * int(mois_facturation[:2]) + 1
|
|
|
|
|
|
@@ -115,6 +133,7 @@ for affaireId, interventions in a_facturer.items():
|
|
|
# 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.strCodeProduit = destinataire.strCodeProduit
|
|
|
entete.bytTitreId = destinataire.bytTitreId
|
|
|
entete.strCodeAdresse = destinataire.strCodeAdresse
|
|
|
entete.strAdresse1 = destinataire.strAdresse1
|
|
|
@@ -155,18 +174,21 @@ for affaireId, interventions in a_facturer.items():
|
|
|
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"
|
|
|
+ entete.strReglement = "POUR ACQUITTER CET ETAT DE REDEVANCE, ATTENDEZ 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.memObsEntete = "[Mois : {mois_facturation}] " \
|
|
|
+ "[Lieu de travail : ]{affaire.strLieux} " \
|
|
|
+ "[V/Cde : ] {affaire.Ref} du {affaire.dtmCommande:%d/%m/%Y}" \
|
|
|
+ "".format(mois_facturation=mois_facturation,
|
|
|
+ affaire=affaire).replace("'", "")
|
|
|
|
|
|
- entete.memObsInterne = "N° Affaire analytique : {}".format(affaire.stLiaisonControle)
|
|
|
+ entete.memObsInterne = "N° Affaire analytique : {}".format(affaire.strLiaisonControle)
|
|
|
|
|
|
- entete.strStatDocEntete = "PC00" if ("/" in affaire.stLiaisonControle or affaire.stLiaisonControle == "RDBOEC") else "PT00"
|
|
|
+ entete.strStatDocEntete = "PC00" if ("/" in affaire.strLiaisonControle or affaire.strLiaisonControle == "RDBOEC") else "PT00"
|
|
|
|
|
|
- entete.strUserIdCreation = "analytique2facture"
|
|
|
- entete.strUserIdLastMod = "analytique2facture"
|
|
|
+ entete.strUserIdCreation = "script"
|
|
|
+ entete.strUserIdLastMod = "script"
|
|
|
|
|
|
i = 0
|
|
|
lignes = []
|
|
|
@@ -188,30 +210,29 @@ for affaireId, interventions in a_facturer.items():
|
|
|
taux = commun_db.first("SELECT dblTVATaux FROM tblTVATaux WHERE bytTVAId={}".format(ligne.bytTVAId))
|
|
|
ligne.dblTVATaux = taux.dblTVATaux
|
|
|
|
|
|
- ligne.dblQte = interv.dblquantite
|
|
|
+ ligne.dblQte = interv.dblQuantite
|
|
|
|
|
|
- unite = commun_db.first("SELECT * FROM tblUnite WHERE strUniteCourt='{}'".format(interv.strunite))
|
|
|
+ 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.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)
|
|
|
+ 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_ht = float(sum([ligne.dblPThtNetDev for ligne in lignes]))
|
|
|
+ taux_tva = float(lignes[0].dblTVATaux)
|
|
|
montant_tva = (0.01 * taux_tva) * montant_ht
|
|
|
montant_ttc = montant_ht + montant_tva
|
|
|
|
|
|
@@ -273,11 +294,71 @@ for affaireId, interventions in a_facturer.items():
|
|
|
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.
|
|
|
-
|
|
|
|
|
|
+ logger.info("* Nouvelle facture: {}".format(entete.lngPieceId))
|
|
|
+
|
|
|
+ # Insertion de l'en-tête
|
|
|
+ sql = Sql.format("""
|
|
|
+ INSERT INTO tblPieceEntete ( lngPieceId, lngDocId, lngTiersId, lngASTRE, strCodeProduit, bytTitreId, strCodeAdresse, strAdresse1, strAdresse2,
|
|
|
+ strAdresse3, strAdresse4, strAdresse5, [strPaysIdIso3166-A2], bytTVATiersId, strTelephone, strTelecopie, strPortable,
|
|
|
+ strEMail, strWeb, strLangueIdIso639, strCompteComptable, strDeviseIdIso4217, bytReglementId, strReglement,
|
|
|
+ bytClasseTarifId, bytClasseRemiseTiersId, bytNbExFacture, strStatTiers, bytSituationIdPrincipale, bytSituationIdSecondaire,
|
|
|
+ memObsEntete, memObsInterne, bytTypeDocumentId, strStatDocEntete, dblCoursDevise, dtmCoursDevise,
|
|
|
+ strUserIdCreation, strUserIdLastMod )
|
|
|
+ VALUES ({entete.lngPieceId}, {entete.lngDocId}, {entete.lngTiersId}, {entete.lngASTRE}, {entete.strCodeProduit:text}, {entete.bytTitreId},
|
|
|
+ {entete.strCodeAdresse:text}, {entete.strAdresse1:text}, {entete.strAdresse2:text}, {entete.strAdresse3:text}, {entete.strAdresse4:text}, {entete.strAdresse5:text},
|
|
|
+ {entete.strPaysIdIso3166:text}, {entete.bytTVATiersId}, {entete.strTelephone:text}, {entete.strTelecopie:text}, {entete.strPortable:text}, {entete.strEMail:text},
|
|
|
+ {entete.strWeb:text}, {entete.strLangueIdIso639:text}, {entete.strCompteComptable:text}, {entete.strDeviseIdIso4217:text}, {entete.bytReglementId},
|
|
|
+ {entete.strReglement:text}, {entete.bytClasseTarifId}, {entete.bytClasseRemiseTiersId}, {entete.bytNbExFacture}, {entete.strStatTiers:text},
|
|
|
+ {entete.bytSituationIdPrincipale}, {entete.bytSituationIdSecondaire}, {entete.memObsEntete:text}, {entete.memObsInterne:text},
|
|
|
+ {entete.bytTypeDocumentId}, {entete.strStatDocEntete:text}, {entete.dblCoursDevise}, {entete.dtmCoursDevise:date},
|
|
|
+ {entete.strUserIdCreation:text}, {entete.strUserIdLastMod:text})
|
|
|
+ """, entete=entete)
|
|
|
+
|
|
|
+ logger.debug(sql)
|
|
|
+ facture_db.execute(sql)
|
|
|
+
|
|
|
+ for ligne in lignes:
|
|
|
+
|
|
|
+ # Complete les champs manquants
|
|
|
+ for field in ["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"]:
|
|
|
+ if not hasattr(ligne, field):
|
|
|
+ setattr(ligne, field, None)
|
|
|
+
|
|
|
+
|
|
|
+ sql = Sql.format("""
|
|
|
+ INSERT INTO tblPieceLigne ( 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 )
|
|
|
+ VALUES ({ligne.lngPieceId}, {ligne.intLigneId}, {ligne.strArticleId:text}, {ligne.strArticle:text}, {ligne.bytTVAArticleId}, {ligne.bytTVAId}, {ligne.dblTVATaux},
|
|
|
+ {ligne.dblQte}, {ligne.bytUniteIdQuantite}, {ligne.bytNbDecQuantite}, {ligne.bytUniteIdPrix}, {ligne.dblCnvUniteCoef}, {ligne.bytNbDecQuantiteConvertie},
|
|
|
+ {ligne.dblPUhtBrutDev}, {ligne.dblPUttcBrutDev}, {ligne.dblPUhtNetDev}, {ligne.dblPUttcNetDev}, {ligne.bytNbDecPU}, {ligne.dblPThtBrutDev},
|
|
|
+ {ligne.dblPTttcBrutDev}, {ligne.dblPThtNetDev}, {ligne.dblPTttcNetDev}, {ligne.strStatArticle:text}, {ligne.strStatDocLigne:text},
|
|
|
+ {ligne.dblTauxRemise1}, {ligne.dblTauxRemise2}, {ligne.dblTauxRemise3}, {ligne.blnPrestation}, {ligne.strCompteComptable:text},
|
|
|
+ {ligne.memObs:text}, {ligne.memObsInterne:text}, {ligne.bytLigneSousTotal}, {ligne.intLigneIdRattachement}, {ligne.blnLigneVisible},
|
|
|
+ {ligne.blnLigneGeneree}, {ligne.bytGenerateurId}, {ligne.dblPUhtBrut}, {ligne.dblPUttcBrut}, {ligne.dblPUhtNet}, {ligne.dblPUttcNet},
|
|
|
+ {ligne.dblPThtBrut}, {ligne.dblPTttcBrut}, {ligne.dblPThtNet}, {ligne.dblPTttcNet}, {ligne.bytClasseRemiseArticleId}, {ligne.dblPUSaisie},
|
|
|
+ {ligne.strPUAff:text}, {ligne.strQteAff:text})
|
|
|
+ """, ligne=ligne)
|
|
|
+ logger.debug(sql)
|
|
|
+ facture_db.execute(sql)
|
|
|
+
|
|
|
+ # Maj tbl_Tarification.strNumFacture et strStatut pour marquer la ligne comme facturée.
|
|
|
+ sql = Sql.format(""" UPDATE tbl_Tarification SET strStatut = 'Facturée', strNumFacture = '{}'
|
|
|
+ WHERE DblTarifId={}; """, piece_id, interv.DblTarifId)
|
|
|
+ logger.debug(sql)
|
|
|
+ analytique_db.execute(sql)
|
|
|
+
|
|
|
+ facture_db.commit()
|
|
|
+ analytique_db.commit()
|
|
|
|
|
|
|
|
|
|