gf2analytique.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. '''
  2. Created on 29 juin 2017
  3. @author: olivier.massot
  4. '''
  5. from datetime import datetime
  6. import logging
  7. import random
  8. import re
  9. import sys
  10. import time
  11. from core.pde import AnalytiqueDb
  12. from core.webservice import GfWebservice
  13. # TODO: vérifier le résultat des requêtes
  14. # TODO: proposer une méthode de correction des erreurs
  15. # TODO: configurer logging
  16. # TODO: envoi mail auto
  17. logger = logging.getLogger("factures")
  18. logging.basicConfig(level=logging.INFO)
  19. # logging.basicConfig(filename=r'log\factures_{:%Y%m%d_%H%M}.log'.format(datetime.now()),
  20. # level=logging.INFO)
  21. logger.info("Initialization")
  22. # Connect to factures.mdb
  23. analytique_db = AnalytiqueDb(autocommit=False)
  24. # Connect to the astre gf webservice
  25. ws = GfWebservice("GetPDEFactures")
  26. analysed, updated, errors = 0, 0, 0
  27. def shortuid():
  28. """ 15 cars decimal uuid """
  29. base = int(time.time()) << 32
  30. rand = random.SystemRandom().getrandbits(32)
  31. return hex((base + rand))[2:-1]
  32. def format_date(dat):
  33. return datetime.strptime(str(dat)[:10], "%Y-%m-%d").strftime("%m/%d/%Y")
  34. def nz(val, default="Null"):
  35. return val if val else default
  36. def is_valid(facture, prompt_for_correction=False):
  37. """ controle la validité des données d'une facture """
  38. if facture["codeAxe"] == "ENGIN":
  39. # Controle l'existence du materiel
  40. if not analytique_db.first("SELECT intlMaterielID FROM tbl_materiel WHERE txtMateriel='{}'".format(facture["codeCout"])):
  41. logger.warning("Le materiel n'existe pas: %s", facture["codeCout"])
  42. if prompt_for_correction:
  43. facture["codeCout"] = input("> txtMateriel: ")
  44. return is_valid(facture, True)
  45. else:
  46. return False
  47. elif facture["codeAxe"] == "AFFAI":
  48. # Controle l'existence de l'affaire
  49. if not analytique_db.first("SELECT dblAffaireId FROM tbl_Affaires WHERE strLiaisonControle='{}'".format(facture["codeCout"])):
  50. logger.warning("L'affaire n'existe pas: %s", facture["codeCout"])
  51. if prompt_for_correction:
  52. facture["codeCout"] = input("> strLiaisonControle: ")
  53. return is_valid(facture, True)
  54. else:
  55. return False
  56. else:
  57. # CodeAxe invalide
  58. logger.warning("Code axe inconnu: %s", facture["codeAxe"])
  59. return False
  60. return True
  61. def send(facture):
  62. """ ventile les données dans les tables de la base AnalytiqueDb """
  63. uid = shortuid()
  64. sql = """INSERT INTO tbl_Factures ( intExercice, strEnveloppe, strEngagement, strLiquidation, strObjet, strTiers,
  65. strTiersLibelle, strMotsClefs, intOperation, dtmDeb, strNomenclature0, dblMontantTVA,
  66. dblMontantTotal, strService, strUidImport, strORIGINE_DONNEES )
  67. VALUES ({intExercice}, '{strEnveloppe}', '{strEngagement}', '{strLiquidation}', '{strObjet}','{strTiers}',
  68. '{strTiersLibelle}', '{strMotsClefs}', {intOperation}, #{dtmDeb}#, '{strNomenclature0}',{dblMontantTVA},
  69. {dblMontantTotal}, '{strService}', '{strUidImport}', '{strORIGINE_DONNEES}')
  70. """.format(
  71. intExercice=facture["numExBudget"],
  72. strEnveloppe=facture["numEnv"],
  73. strEngagement=facture["numMandat"],
  74. strLiquidation=facture["numLiqMandat"],
  75. strObjet=nz(facture["libCout"]),
  76. strTiers=facture["numTiers"],
  77. strTiersLibelle=facture["libRai"],
  78. strMotsClefs=nz(facture["refIntMandat"]),
  79. intOperation=nz(facture["codePeriode"]),
  80. dtmDeb=format_date(facture["dateDepDelai"]),
  81. strNomenclature0=facture["typeNomencMarche"],
  82. dblMontantTVA=facture["mntTvaMandat"],
  83. dblMontantTotal=facture["mntVent"],
  84. strService='7710',
  85. strUidImport=uid,
  86. strORIGINE_DONNEES='ASTRE'
  87. )
  88. logger.debug("> %s", sql)
  89. analytique_db.execute(sql)
  90. factureId = analytique_db.first("SELECT dblFactureId FROM tbl_Factures WHERE [strUidImport]='{}'".format(uid))["dblfactureid"]
  91. logger.debug("retrieve dblFactureId: %s", factureId)
  92. if facture["codeAxe"] == "ENGIN":
  93. materiel = analytique_db.first("SELECT intlMaterielID FROM tbl_Materiel WHERE [txtMateriel]='{}'".format(facture["codeCout"]))
  94. materielId = materiel["intlmaterielid"] if materiel else '859'
  95. logger.debug("retrieve intlMaterielID: %s", materielId)
  96. sql = """INSERT INTO tbl_Facture_Engin ( dblFactureId, txtMateriel, strLibelle, strType, dblMontant, intlMaterielID )
  97. VALUES ({}, '{}', '{}', '{}', {}, {})
  98. """.format(factureId,
  99. facture["codeCout"],
  100. nz(facture["libCout"]),
  101. facture["libRai"],
  102. facture["mntVent"],
  103. materielId
  104. )
  105. elif facture["codeAxe"] == "AFFAI":
  106. sql = """INSERT INTO tbl_Facture_Affaire ( dblFactureId, strAffaireId, strType, strLibelle, dblMontant )
  107. VALUES ({}, '{}', '{}', '{}', {})
  108. """.format(factureId,
  109. facture["codeCout"],
  110. facture["libCout"],
  111. facture["libRai"],
  112. facture["mntVent"]
  113. )
  114. logger.debug("> %s", sql)
  115. analytique_db.execute(sql)
  116. sql = """INSERT INTO tbl_Mandatement ( dblFacture, strNumMandat, dtmMandat, strBordereau )
  117. VALUES ({}, '{}', #{}#, '{}')
  118. """.format(factureId,
  119. facture["numMandat"],
  120. format_date(facture["dateMandat"]),
  121. facture["numBj"]
  122. )
  123. logger.debug("> %s", sql)
  124. analytique_db.execute(sql)
  125. analytique_db.commit()
  126. logger.info("* imported: %s", factureId)
  127. def freeze(facture):
  128. pass
  129. ########
  130. if __name__ == "__main__":
  131. prompt_for_correction = "-c" in sys.argv
  132. for facture in ws:
  133. if not facture:
  134. continue
  135. analysed += 1
  136. record = analytique_db.first("""SELECT dblFactureId
  137. FROM tbl_Factures
  138. WHERE strService='7710'
  139. AND intExercice={}
  140. AND strLiquidation='{}'
  141. """.format(facture["numExBudget"], facture["numLiqMandat"]))
  142. if record:
  143. # already imported
  144. continue
  145. # correction auto des codes chantiers
  146. if re.match(r"\d{2}5\d{3}", facture["codeCout"]):
  147. facture["codeCout"] += "/1"
  148. if not is_valid(facture, prompt_for_correction):
  149. logger.warning("INVALID DATA: numEnv= %s", facture["numEnv"])
  150. errors += 1
  151. continue
  152. send(facture)
  153. updated += 1
  154. logger.info("Import terminé: {} lignes traitées / {} importées / {} erreurs".format(analysed, updated, errors))