ctrl2analytique.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. '''
  2. Génère les affaires dans la base Analytique à partir des données de la base Contrôles.
  3. **IMPORTANT**: pour lancer le script sans interaction avec l'utilisateur
  4. (par ex, dans le cas d'une tâche planifiée), appeller le script avec l'option '-n'.
  5. @author: olivier.massot, févr. 2018
  6. '''
  7. from datetime import datetime
  8. import logging
  9. import sys
  10. from path import Path
  11. from core import logconf
  12. from core.model import Model
  13. from core.pde import ControlesDb, AnalytiqueDb, mk_workdir, CommunDb
  14. logger = logging.getLogger("ctrl2analytique")
  15. logconf.start("ctrl2analytique", logging.DEBUG)
  16. # # POUR TESTER, décommenter les lignes suivantes
  17. ##-----------------------------------------------
  18. logger.warning("<<<<<<<<<<<<<< Mode TEST >>>>>>>>>>>>>>>>>")
  19. ControlesDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\cg67Parc_data.mdb")
  20. AnalytiqueDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\Db_analytique.mdb")
  21. CommunDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\Commun_Data.mdb")
  22. ##-----------------------------------------------
  23. # *** Initialisation
  24. logger.info("Initialisation...")
  25. no_prompt = ("-n" in sys.argv)
  26. if no_prompt:
  27. logger.info("> Lancé en mode automatique (sans interruption)")
  28. # Connexion à Analytique
  29. analytique_db = AnalytiqueDb(autocommit=False)
  30. # Connexion à Controles
  31. controles_db = ControlesDb(autocommit=False)
  32. # Connexion à CommunDb
  33. commun_db = CommunDb(autocommit=False)
  34. # Make the working directory
  35. workdir = mk_workdir("ctrl2analytique")
  36. affaires_file = workdir / "affaires.csv"
  37. intervs_file = workdir / "intervs.csv"
  38. errors = []
  39. # > Supprime les fichiers d'import s'il existent
  40. for file in (affaires_file, intervs_file):
  41. if file.exists():
  42. logger.debug("Supprime le fichier %s", file)
  43. file.remove()
  44. class Affaire(Model):
  45. _FIELDS = ["strLiaisonControle", "strMOeId", "strCommneId", "strLieux",
  46. "strEntrepriseId", "strMOId", "dtmCommande", "Ref", "blnMarche",
  47. "dblMarche", "intDevisId", "strCT", "strTypeId",
  48. "intCoefFG", "strSituation"]
  49. def get_type_id(lngChantierId, bytCommandeId):
  50. """ Recupère le type de chantier.
  51. 'ZP': Chantier de contrôle d'étanchéité
  52. 'ZC': Chantier de contrôle du compactage
  53. 'ZI': Chantier d'inspection vidéo
  54. 'ZZ': Chantier mixte.
  55. '': Inconnu
  56. """
  57. sql = """SELECT lngChantierId, 'ZP' as type FROM tblEtancheiteBases WHERE [lngChantierId] = {chantier} AND [bytCommandeId] = {commande}
  58. UNION
  59. SELECT lngChantierId, 'ZC' as type FROM tblCompactageBases WHERE [lngChantierId] = {chantier}
  60. UNION
  61. SELECT lngChantierId, 'ZI' as type FROM tblVideoBases WHERE [lngChantierId] = {chantier};
  62. """.format(chantier=lngChantierId,
  63. commande=bytCommandeId)
  64. res = controles_db.read_all(sql)
  65. if len(res) == 0:
  66. return ""
  67. elif len(res) == 1:
  68. return res[0].type
  69. else:
  70. return "ZZ"
  71. def get_coeff_k(lngChantierId):
  72. # On déduit l'année du chantier à partir du code chantier
  73. annee = "20" + str(lngChantierId)[:2] if len(str(lngChantierId)) == 6 else "200" + str(lngChantierId)[:1]
  74. # On retrouve dans la table tbl_COEFFG le coefficient correspondant
  75. return analytique_db.first("SELECT [COEFFG] FROM tbl_COEFFG WHERE [ANNEE] = {}".format(annee)).COEFFG / 100
  76. # *** 1- Import des chantiers Contrôles dans le fichier affaires.csv
  77. nb_affaires, nb_intervs = 0, 0
  78. logger.debug("Génère le fichier %s", affaires_file)
  79. firstline = "\t".join(Affaire._FIELDS + ["\n"])
  80. with open(affaires_file, 'w+') as f:
  81. f.write(firstline)
  82. # on insère les affaires depuis tblCommandes et tblChantier (le lien est strLiaisonControle)
  83. compteur = 0
  84. sql = """ SELECT tblCommandes.lngChantierId, tblCommandes.bytCommandeId, tblChantiers.strSubdivisionId, tblChantiers.strCollectiviteId as ChantierCollectiviteId, tblChantiers.strLocChantier,
  85. tblChantiers.strEntrepriseId, tblCommandes.strCollectiviteId as CommandeCollectiviteId, tblCommandes.dtmCommande, tblCommandes.strRefCommande, tblCommandes.blnMarche, tblCommandes.dblMtMarche, tblCommandes.strdevis
  86. FROM tblChantiers INNER JOIN tblCommandes ON tblChantiers.lngChantierId = tblCommandes.lngChantierId
  87. WHERE (((tblCommandes.sngAffaireIdMos) Is Null Or (tblCommandes.sngAffaireIdMos)=0))
  88. """
  89. for data in controles_db.read(sql):
  90. # Création de l'affaire
  91. affaire = Affaire()
  92. affaire.strLiaisonControle = "{}/{}".format(data.lngChantierId, data.bytCommandeId)
  93. affaire.strMOeId = data.strSubdivisionId
  94. affaire.strCommneId = data.ChantierCollectiviteId
  95. affaire.strLieux = data.strLocChantier
  96. affaire.strEntrepriseId = data.strEntrepriseId
  97. affaire.strMOId = data.CommandeCollectiviteId
  98. affaire.dtmCommande = data.dtmCommande
  99. affaire.Ref = data.strRefCommande
  100. affaire.blnMarche = data.blnMarche
  101. affaire.dblMarche = data.dblMtMarche
  102. affaire.intDevisId = data.strdevis
  103. affaire.strCT = '1'
  104. affaire.strTypeId = get_type_id(data.lngChantierId, data.bytCommandeId)
  105. affaire.intCoefFG = get_coeff_k(data.lngChantierId)
  106. affaire.strSituation = "En cours"
  107. with open(affaires_file, 'a') as f:
  108. f.write(affaire.to_csv())
  109. # pour garder le lien avec la donnée d'origine:
  110. affaire.lngChantierId = data.lngChantierId
  111. affaire.bytCommandeId = data.bytCommandeId
  112. compteur += 1
  113. logger.info("> {} affaires ajoutées à {}".format(compteur, affaires_file))
  114. # *** 2- Import des interventions de contrôle du compactage dans le fichier intervs.csv
  115. class Interv(Model):
  116. _FIELDS = ["strEquipeId", "strEnginId", "strRapportId", "strTypeInterventionId",
  117. "strTypeInterventionId", "strCatégorieInterventionId", "dblquantite", "strunite", "dtmIntervention",
  118. "dtmDureeIntervention", "dtmDureeInstallation", "strLiaisonControle", "strArticleId", "intPeriode",
  119. "remarques", "strgrandeur1", "strgrandeur2", "strgrandeur3",
  120. "strcaracteristique1", "strcaracteristique2", "strcaracteristique3",
  121. "dtmImportation", "strTest", "LienAff"
  122. ]
  123. logger.debug("Génère le fichier %s", intervs_file)
  124. firstline = "\t".join(Interv._FIELDS + ["\n"])
  125. with open(intervs_file, 'w+') as f:
  126. f.write(firstline)
  127. def engin_existe(strEnginId):
  128. return analytique_db.exists("SELECT strEnginId FROM tbl_Engin WHERE strEnginId='{}'".format(strEnginId))
  129. def get_periode_validite(date_interv):
  130. sql = """SELECT intPeriodeValiditeId FROM tblTarifValidite
  131. WHERE [dtmValiditeDebut] <= #{date_interv}# AND [dtmValiditeFin] > #{date_interv}# AND [bytClasseTarifId]=1
  132. """.format(date_interv=date_interv)
  133. return commun_db.first(sql).intPeriodeValiditeId
  134. compteur = 0
  135. sql = """SELECT tblCompactageIntervs.lngChantierId, tblCompactageIntervs.bytCommandeId, tblCompactageIntervs.bytIntervId, tblCompactageIntervs.strEquipeId,
  136. tblCompactageEngins.strEnginId, tblCompactageIntervs.lngRapportId, tblCompactageBases.memTravaux, tblCompactageResultats.dtmEssai,
  137. tblCompactageResultats.dtmDuree, tblCompactagePartChantiers.strTrcRegard, tblMateriaux.strMatériau,
  138. tblCompactageResultats.bytPartChantierId, tblCompactageIntervs.sngIntervIdMos
  139. FROM ((tblMateriaux RIGHT JOIN ((((tblCompactageIntervs LEFT JOIN tblCompactageEngins ON tblCompactageIntervs.strEquipeId = tblCompactageEngins.strEquipeId)
  140. INNER JOIN tblCompactageResultats ON (tblCompactageIntervs.bytIntervId = tblCompactageResultats.bytIntervId)
  141. AND (tblCompactageIntervs.lngChantierId = tblCompactageResultats.lngChantierId)) INNER JOIN tblCompactagePartChantiers
  142. ON (tblCompactageResultats.bytPartChantierId = tblCompactagePartChantiers.bytPartChantierId)
  143. AND (tblCompactageResultats.lngChantierId = tblCompactagePartChantiers.lngChantierId)) INNER JOIN tblCompactageBases
  144. ON tblCompactageIntervs.lngChantierId = tblCompactageBases.lngChantierId) ON tblMateriaux.strMateriauId = tblCompactagePartChantiers.strMateriauRemblaiId)
  145. LEFT JOIN tblMateriaux AS tblMateriaux_1 ON tblCompactagePartChantiers.strMateriauEnrobageId = tblMateriaux_1.strMateriauId)
  146. LEFT JOIN tblMateriaux AS tblMateriaux_2 ON tblCompactagePartChantiers.strMateriauLitId = tblMateriaux_2.strMateriauId
  147. WHERE (((tblCompactageIntervs.sngIntervIdMos)=0 Or (tblCompactageIntervs.sngIntervIdMos) Is Null))
  148. """
  149. def get_type_compactage_interv(observation):
  150. if "ASSAINISEMENT" or "ASSAINISEMENT" in observation:
  151. return "CC3"
  152. elif "CABLE" in observation:
  153. return "CC1"
  154. elif "A.E.P" in observation:
  155. return "CC2"
  156. elif "GAZ" in observation:
  157. return "CC4"
  158. else:
  159. return "CC3"
  160. for data in controles_db.read(sql):
  161. interv = Interv()
  162. if not engin_existe(data.strEnginId):
  163. errors.append("""Intervention compactage {}/{}/{}/{}: l'engin {} n'existe pas"""
  164. .format(data.lngChantierId, data.bytCommandeId, data.bytIntervId, data.bytPartChantierId, data.strEnginId))
  165. interv.strEquipeId = "C{}".format(data.strEquipeId)
  166. interv.strEnginId = data.strEnginId
  167. interv.strRapportId = data.strRapportId
  168. interv.strTypeInterventionId = get_type_compactage_interv(data.memTravaux)
  169. interv.strCatégorieInterventionId = "CC"
  170. interv.dblquantite = 1
  171. interv.strunite = "u"
  172. interv.dtmIntervention = data.dtmEssai
  173. interv.dtmDureeIntervention = data.dtmDuree
  174. interv.dtmDureeInstallation = 0 # Les temps d'installation seront calculés en fin de traitement
  175. interv.strLiaisonControle = "{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId)
  176. interv.strArticleId = data.strEnginId
  177. interv.intPeriode = get_periode_validite(data.dtmEssai)
  178. interv.remarques = data.strTrcRegard
  179. interv.strgrandeur1 = data.strMatériau
  180. interv.strgrandeur2 = data.strMatériau
  181. interv.strgrandeur3 = data.strMatériau
  182. interv.strcaracteristique1 = "Matériau remblai"
  183. interv.strcaracteristique2 = "Matériau lit de pose"
  184. interv.strcaracteristique3 = "Matériau enrobage"
  185. interv.strunite1 = ""
  186. interv.strunite2 = ""
  187. interv.strunite3 = ""
  188. interv.dtmImportation = "{}".format(datetime.now().strftime("%Y-%m-%d"))
  189. interv.strTest = "{}/{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId, data.bytPartChantierId)
  190. interv.LienAff = "{}/{}".format(data.lngChantierId, data.bytCommandeId)
  191. with open(intervs_file, 'a') as f:
  192. f.write(interv.to_csv())
  193. compteur += 1
  194. logger.info("> {} interventions Compactage ajoutées au fichier".format(compteur))
  195. # *** 3- Import des interventions de contrôle d'étanchéité dans le fichier intervs.csv
  196. compteur = 0
  197. sql = """SELECT tblEtancheiteIntervs.lngChantierId, tblEtancheiteIntervs.bytCommandeId, tblEtancheiteIntervs.bytIntervId, tblEtancheiteIntervs.strEquipeId,
  198. tblEtancheiteIntervs.lngRapportId, tblEtancheitePartChantiers.bytTypeEssai, tblMateriaux.strMateriauId, tblMateriaux.strMatériau,
  199. tblEtancheitePartChantiers.intDiametre, tblEtancheitePartChantiers.sngLgHt, tblEtancheitePartChantiers.intNbJoint, tblEtancheiteResultats.dtmDuree,
  200. tblEtancheiteResultats.dtmEssai, tblEtancheitePartChantiers.strTrcRegard, tblEtancheiteResultats.bytPartChantierId
  201. FROM ((tblEtancheiteIntervs INNER JOIN tblEtancheiteResultats ON (tblEtancheiteIntervs.lngChantierId = tblEtancheiteResultats.lngChantierId)
  202. AND (tblEtancheiteIntervs.bytIntervId = tblEtancheiteResultats.bytIntervId)) INNER JOIN tblEtancheitePartChantiers
  203. ON (tblEtancheiteResultats.lngChantierId = tblEtancheitePartChantiers.lngChantierId)
  204. AND (tblEtancheiteResultats.bytPartChantierId = tblEtancheitePartChantiers.bytPartChantierId)) INNER JOIN tblMateriaux
  205. ON tblEtancheitePartChantiers.strMateriauId = tblMateriaux.strMateriauId
  206. WHERE (((tblEtancheiteIntervs.sngIntervIdMos)=0 Or (tblEtancheiteIntervs.sngIntervIdMos) Is Null));
  207. """
  208. def get_engin_etancheite(equipe, diametre, materiau, type_essai):
  209. """ retourne l'engin correspondant à l'essai en fonction eds caractéristiques de l'essai """
  210. sql = """SELECT strEnginId FROM tblEtancheiteEngins
  211. WHERE ([strEquipeId] = '{}') AND ([intDiametre] = {}) AND ([strMateriauId] = '{}') AND ([bytTypeEssaiId] ={})
  212. """.format(equipe, diametre, materiau, type_essai)
  213. row = controles_db.first(sql)
  214. return row.strEnginId if row else ""
  215. for data in controles_db.read(sql):
  216. interv = Interv()
  217. interv.strEquipeId = "C{}".format(data.strEquipeId)
  218. interv.strEnginId = get_engin_etancheite(data.strEquipeId, data.intDiametre, data.strMateriauId, data.bytTypeEssai)
  219. interv.strRapportId = data.lngRapportId
  220. interv.strTypeInterventionId = "CE{}".format(data.bytTypeEssai)
  221. interv.strCatégorieInterventionId = "CE"
  222. interv.dblquantite = data.intNbJoint
  223. interv.strunite = "u"
  224. interv.dtmIntervention = data.dtmEssai
  225. interv.dtmDureeIntervention = data.dtmDuree
  226. interv.dtmDureeInstallation = 0 # Les temps d'installation seront recalculés en fin de traitement
  227. interv.strLiaisonControle = "{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId)
  228. interv.strArticleId = interv.strEnginId
  229. interv.intPeriode = get_periode_validite(data.dtmEssai)
  230. interv.remarques = data.strTrcRegard
  231. interv.strgrandeur1 = data.strMatériau
  232. interv.strgrandeur2 = data.intDiametre
  233. interv.strgrandeur3 = data.sngLgHt
  234. interv.strcaracteristique1 = "Matériau"
  235. interv.strcaracteristique2 = "Diamètre"
  236. interv.strcaracteristique3 = "Longueur"
  237. interv.strunite1 = ""
  238. interv.strunite2 = "mm"
  239. interv.strunite3 = "m"
  240. interv.dtmImportation = "{}".format(datetime.now().strftime("%Y-%m-%d"))
  241. interv.strTest = "{}/{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId, data.bytPartChantierId)
  242. interv.LienAff = "{}/{}".format(data.lngChantierId, data.bytCommandeId)
  243. with open(intervs_file, 'a') as f:
  244. f.write(interv.to_csv())
  245. compteur += 1
  246. logger.info("> {} interventions Etanchéité ajoutées au fichier".format(compteur))
  247. # *** 4- Import des interventions d'inspection vidéo dans le fichier intervs.csv
  248. compteur = 0
  249. sql = """SELECT tblVideoIntervs.lngChantierId, tblVideoIntervs.bytCommandeId, tblVideoIntervs.bytIntervId, tblVideoIntervs.strEquipeId,
  250. tblVideoEngins.strEnginId, tblVideoIntervs.lngRapportId, First(tblso_rate_Analyse.MateriauCourt) AS strmateriau, tblVideoIntervs.lngTroncon,
  251. tblVideoIntervs.sngNbJourFact, First(tblso_rate_Analyse.MaxDeDiametre) AS diam, tblVideoIntervs.dtmDuree, tblVideoIntervs.dtmIntervDu,
  252. First(tblVideoIntervs.memObservation) AS memObservation, tblChantiers.strEntrepriseId
  253. FROM ((tblVideoEngins RIGHT JOIN tblVideoIntervs ON tblVideoEngins.strEquipeId = tblVideoIntervs.strEquipeId) INNER JOIN tblso_rate_Analyse ON
  254. (tblVideoIntervs.lngChantierId = tblso_rate_Analyse.lngChantierId) AND (tblVideoIntervs.bytIntervId = tblso_rate_Analyse.bytIntervId)) INNER JOIN
  255. tblChantiers ON tblVideoIntervs.lngChantierId = tblChantiers.lngChantierId
  256. WHERE (((tblVideoIntervs.sngIntervIdMos) Is Null Or (tblVideoIntervs.sngIntervIdMos)=0))
  257. GROUP BY tblVideoIntervs.lngChantierId, tblVideoIntervs.bytCommandeId, tblVideoIntervs.bytIntervId, tblVideoIntervs.strEquipeId,
  258. tblVideoIntervs.lngRapportId, tblVideoIntervs.lngTroncon, tblVideoIntervs.sngNbJourFact, tblVideoIntervs.dtmDuree,
  259. tblVideoIntervs.dtmIntervDu, tblVideoEngins.strEnginId, tblChantiers.strEntrepriseId
  260. """
  261. for data in controles_db.read(sql):
  262. interv = Interv()
  263. interv.strEquipeId = "C{}".format(data.strEquipeId)
  264. interv.strEnginId = data.strEnginId
  265. interv.strRapportId = data.lngRapportId
  266. interv.strTypeInterventionId = "CI1" if data.strEntrepriseId != 195 else "CI2"
  267. interv.strCatégorieInterventionId = "CI"
  268. interv.dblquantite = data.sngNbJourFact
  269. interv.strunite = "j"
  270. interv.dtmIntervention = data.dtmIntervDu
  271. interv.dtmDureeIntervention = data.dtmDuree
  272. interv.dtmDureeInstallation = 0 # Les temps d'installation seront recalculés en fin de traitement
  273. interv.strLiaisonControle = "{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId)
  274. interv.strArticleId = data.strEnginId
  275. interv.intPeriode = get_periode_validite(data.dtmIntervDu)
  276. interv.remarques = data.memObservation
  277. interv.strgrandeur1 = data.strmateriau
  278. interv.strgrandeur2 = data.diam
  279. interv.strgrandeur3 = data.lngTroncon
  280. interv.strcaracteristique1 = "Matériau"
  281. interv.strcaracteristique2 = "Diamètre"
  282. interv.strcaracteristique3 = "Longueur inspectée"
  283. interv.strunite1 = ""
  284. interv.strunite2 = "mm"
  285. interv.strunite3 = "m"
  286. interv.dtmImportation = "{}".format(datetime.now().strftime("%Y-%m-%d"))
  287. interv.strTest = "{}/{}/{}/1".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId)
  288. interv.LienAff = "{}/{}".format(data.lngChantierId, data.bytCommandeId)
  289. with open(intervs_file, 'a') as f:
  290. f.write(interv.to_csv())
  291. compteur += 1
  292. logger.info("> {} interventions ITV ajoutées au fichier".format(compteur))
  293. logging.info("Les données à importer ont été ajoutées aux fichiers '{}' et '{}'".format(affaires_file, intervs_file))
  294. logging.info("Ces fichiers sont au format CSV (séparateur: tabulation)")
  295. # *** 6- Recherche d'erreurs
  296. errors = -1
  297. while errors:
  298. errors = []
  299. with open(affaires_file) as f:
  300. next(f) # saute la première ligne
  301. for line in f:
  302. affaire = Affaire.from_csv(line)
  303. prefix = "Affaire {}: ".format(affaire.strLiaisonControle)
  304. if not affaire.strMOId:
  305. errors.append(prefix + "MO manquant")
  306. else:
  307. if not commun_db.exists("SELECT [lngTiersId] FROM tblTiers WHERE [lngTiersId]={}".format(affaire.strMOId)):
  308. errors.append(prefix + "Le MO {} n'existe pas dans tblTiers".format(affaire.strMOId))
  309. if not affaire.strMOeId:
  310. errors.append(prefix + "MOe manquant")
  311. else:
  312. if not commun_db.exists("SELECT [lngTiersId] FROM tblTiers WHERE [lngTiersId]={}".format(affaire.strMOeId)):
  313. errors.append(prefix + "Le MOe {} n'existe pas dans tblTiers".format(affaire.strMOeId))
  314. if not affaire.strEntrepriseId:
  315. errors.append(prefix + "Entreprise manquante")
  316. else:
  317. if not commun_db.exists("SELECT [lngTiersId] FROM tblTiers WHERE [lngTiersId]={}".format(affaire.strEntrepriseId)):
  318. errors.append(prefix + "L'entreprise {} n'existe pas dans tblTiers".format(affaire.strEntrepriseId))
  319. if not affaire.strCommneId:
  320. errors.append(prefix + "Commune manquante")
  321. else:
  322. if not commun_db.exists("SELECT [lngTiersId] FROM tblTiers WHERE [lngTiersId]={}".format(affaire.strCommneId)):
  323. errors.append(prefix + "La commune {} n'existe pas dans tblTiers".format(affaire.strCommneId))
  324. if not affaire.strTypeId:
  325. errors.append(prefix + "Type d'affaire manquant")
  326. if not affaire.dtmCommande:
  327. errors.append(prefix + "Date de commande manquante")
  328. if affaire.blnMarche == True and not affaire.intDevisId:
  329. errors.append(prefix + "Numéro de devis manquant")
  330. if analytique_db.exists("SELECT dblAffaireId FROM tbl_Affaires WHERE [strLiaisonControle]='{}'".format(affaire.strLiaisonControle)):
  331. errors.append(prefix + "Une affaire portant ce code existe déjà: {}".format(affaire.strLiaisonControle))
  332. with open(intervs_file) as f:
  333. next(f) # saute la première ligne
  334. for line in f:
  335. interv = Interv.from_csv(line)
  336. prefix = "Intervention {}: ".format(interv.strLiaisonControle)
  337. if not interv.strEquipeId:
  338. errors.append(prefix + "Equipe manquante")
  339. if not interv.strEnginId:
  340. errors.append(prefix + "Engin manquant")
  341. if not interv.strRapportId:
  342. errors.append(prefix + "Rapport manquant")
  343. if not interv.strCatégorieInterventionId:
  344. errors.append(prefix + "Catégorie de l'intervention manquante")
  345. if not interv.strTypeInterventionId:
  346. errors.append(prefix + "Type d'intervention manquant")
  347. if not interv.dblquantite:
  348. errors.append(prefix + "Quantité nulle")
  349. if not interv.strunite:
  350. errors.append(prefix + "Unité non renseignée")
  351. if not interv.dtmIntervention:
  352. errors.append(prefix + "Erreur : date d'intervention")
  353. if not interv.dtmDureeIntervention:
  354. errors.append(prefix + "Durée d'intervention nulle")
  355. if not interv.strunite:
  356. errors.append(prefix + "Unité non renseignée")
  357. if not engin_existe(interv.strEnginId):
  358. errors.append(prefix + "l'engin {} n'existe pas".format(interv.strEnginId))
  359. # *** 6- Interruption pour corection manuelle des données (si nécessaire)
  360. if errors:
  361. logging.error("<!> Des erreurs ont été détectées dans les données à importer. <!>")
  362. for msg in errors:
  363. logging.error(msg)
  364. prompt = ""
  365. while prompt != "v":
  366. prompt = input(">> Veuillez contrôler les données, puis taper 'v' pour continuer, ou 'q' pour quitter...")
  367. if prompt == "q":
  368. sys.exit(1)
  369. # *** 7- Insertion des données dans les tables Analytique
  370. affaires = {}
  371. with open(affaires_file) as f:
  372. next(f) # saute la première ligne
  373. for line in f:
  374. affaire = Affaire.from_csv(line)
  375. with open(intervs_file) as f:
  376. next(f) # saute la première ligne
  377. for line in f:
  378. interv = Interv.from_csv(line)
  379. try:
  380. affaires[interv.LienAff].append(interv)
  381. except KeyError:
  382. logger.error("L'intervention {} n'est liée à aucune affaire. Elle ne sera pas importée.".format(interv.strLiaisonControle))
  383. class Tarification(Model):
  384. _FIELDS = ["DblAffaireId", "strRapportId", "strArticleId", "dblQuantite", "strUnite",
  385. "dtmDebut", "dtmFin", "bytPeriode", "dblPrixUnitaire", "dblPrixTotal", "strStatut"]
  386. for affaire in affaires.values():
  387. # insertion dans tbl_Affaires
  388. sql = """ INSERT INTO tbl_Affaires ( strMOId, strMOeId, strEntrepriseId, strCommneId, strLieux, strTypeId, dtmCommande, Ref,
  389. blnMarche, dblMarche, intTypeContrat, strCT, strAvancement, strLiaisonControle, intDevisId, blnTarification,
  390. blnAnalyse, remarques, strSituation, dtmFin, intCoefFG )
  391. VALUES ('{affaire.strMOId}', '{affaire.strMOeId}', '{affaire.strEntrepriseId}', '{affaire.strCommneId}', '{affaire.strLieux}', '{affaire.strTypeId}',
  392. #{affaire.dtmCommande}#, '{affaire.Ref}', {affaire.blnMarche}, {affaire.dblMarche}, {affaire.intTypeContrat}, '{affaire.strCT}',
  393. '{affaire.strAvancement}', '{affaire.strLiaisonControle}', {affaire.intDevisId},True, {affaire.blnAnalyse},
  394. '{affaire.remarques}', '{affaire.strSituation}', #{affaire.dtmFin}#, {affaire.intCoefFG})
  395. """.format(affaire=affaire)
  396. analytique_db.execute(sql)
  397. affaire.DblAffaireId = analytique_db.first("SELECT TOP 1 DblAffaireId FROM tbl_Affaires WHERE [strLiaisonControle]='{}'".format(affaire.strLiaisonControle)).DblAffaireId
  398. # insertions des interventions dans tbl_Intervention
  399. for interv in affaire.intervs:
  400. sql = """INSERT INTO tbl_Intervention ( DblAffaireId, strEquipeId, strEnginId, strRapportId, strCatégorieInterventionId, strTypeInterventionId,
  401. dblquantite, strunite, dtmIntervention, dtmDureeIntervention, dtmDureeInstallation, strcaracteristique1, strgrandeur1, strunite1,
  402. strcaracteristique2, strgrandeur2, strunite2, strcaracteristique3, strgrandeur3, strunite3, strLiaisonControle, strarticleId,
  403. intPeriode, blnTarification, blnAnalyse, blnFacturer, remarques, blnPeriode, dtnPeriodeDebut, dtmImportation, blnVerifFacture, strTest )
  404. VALUES ({dblAffaireId}, '{interv.strEquipeId}', '{interv.strEnginId}', '{interv.strRapportId}', '{interv.strCatégorieInterventionId}',
  405. '{interv.strTypeInterventionId}', {interv.dblquantite}, '{interv.strunite}', #{interv.dtmIntervention}#, #{interv.dtmDureeIntervention}#,
  406. #{interv.dtmDureeInstallation}#, '{interv.strcaracteristique1}', '{interv.strgrandeur1}', '{interv.strunite1}', '{interv.strcaracteristique2}',
  407. '{interv.strgrandeur2}', '{interv.strunite2}', '{interv.strcaracteristique3}', '{interv.strgrandeur3}', '{interv.strunite3}', '{interv.strLiaisonControle}',
  408. '{interv.strarticleId}', {interv.intPeriode}, True, {interv.blnAnalyse}, {interv.blnFacturer}, '{interv.remarques}',
  409. {interv.blnPeriode},#{interv.dtnPeriodeDebut}#, #{interv.dtmImportation}#, {interv.blnVerifFacture}, '{interv.strTest}')
  410. """.format(dblAffaireId=affaire.DblAffaireId,
  411. interv=interv)
  412. analytique_db.execute(sql)
  413. # Calcul de la tarification et ajout à tbl_Tarification
  414. # > On va créer une ligne de tarification pour chaque engin (cad. pour chaque strArticleId)
  415. for strArticleId in set([interv.strArticleId for interv in affaires.intervs]):
  416. # recupere le prix unitaire de l'engin
  417. prix_unitaire = commun_db.first("""SELECT dblPU FROM tblTarif WHERE [strArticleId]='{}' AND [intPeriodeValiditeId]={}
  418. """.format(affaire.strArticleId, affaire.intPeriode)).dblPU
  419. # recupere le taux de tva applicable à l'engin
  420. taux_tva = commun_db.first("""SELECT tblTVATaux.dblTVATaux FROM tblArticle INNER JOIN tblTVATaux ON tblArticle.bytTVAArticleId = tblTVATaux.bytTVAId
  421. WHERE (((tblArticle.strArticleId)='{}'));""".format(strArticleId)).dblTVATaux
  422. tarif = Tarification()
  423. tarif.intervs = [interv for interv in affaires.intervs if interv.strArticleId == strArticleId]
  424. tarif.DblAffaireId = affaire.DblAffaireId
  425. tarif.strRapportId = tarif.intervs[0].strRapportId
  426. tarif.strArticleId = strArticleId
  427. tarif.dblQuantite = sum([interv.dblquantite for interv in tarif.intervs])
  428. tarif.strUnite = tarif.intervs[0].strUnite
  429. tarif.dtmDebut = min([interv.dtmIntervention for interv in tarif.intervs])
  430. tarif.dtmFin = max([interv.dtmIntervention for interv in tarif.intervs])
  431. tarif.bytPeriode = tarif.intervs[0].intPeriode
  432. tarif.dblPrixUnitaire = prix_unitaire
  433. tarif.dblPrixTotal = tarif.dblQuantite * tarif.dblPrixUnitaire
  434. tarif.dblTauxTVA = taux_tva
  435. tarif.dblPrixTVA = tarif.dblPrixTotal * (0.01 * tarif.dblTauxTVA)
  436. tarif.strStatut = 'A facturer'
  437. sql = """ INSERT INTO tbl_Tarification ( DblAffaireId, strRapportId, strArticleId, dblQuantite, strUnite, dtmDebut, dtmFin, bytPeriode, dblPrixUnitaire, dblPrixTotal, strStatut )
  438. VALUES ({tarif.DblAffaireId}, {tarif.strRapportId}, {tarif.strArticleId}, {tarif.dblQuantite}, {tarif.strUnite}, {tarif.dtmDebut},
  439. {tarif.dtmFin}, {tarif.bytPeriode}, {tarif.dblPrixUnitaire}, {tarif.dblPrixUnitaire}, {tarif.dblPrixTotal},
  440. {tarif.dblTauxTVA}, {tarif.dblPrixTVA}, {tarif.strStatut})
  441. """.format(tarif=tarif)
  442. analytique_db.execute(sql)
  443. # Maj champs MOS
  444. # (champs utilisés dans les tables Controles pour savoir si une ligne a déjà été importée)
  445. sql = """UPDATE tblCommandes SET tblCommandes.sngAffaireIdMos = {DblAffaireId}
  446. WHERE [lngChantierId]={lngChantierId} AND [bytCommandeId]={bytCommandeId}
  447. """.format(DblAffaireId=affaire.DblAffaireId,
  448. lngChantierId=affaire.lngChantierId,
  449. bytCommandeId=affaire.bytCommandeId)
  450. analytique_db.execute(sql)
  451. for tbl in ("tblCompactageIntervs", "tblEtancheiteIntervs", "tblVideoIntervs"):
  452. sql = """UPDATE {tbl} SET {tbl}.sngIntervIdMos = {DblAffaireId}
  453. WHERE [lngChantierId]={lngChantierId} AND [bytCommandeId]={bytCommandeId}
  454. """.format(DblAffaireId=affaire.DblAffaireId,
  455. lngChantierId=affaire.lngChantierId,
  456. bytCommandeId=affaire.bytCommandeId)
  457. analytique_db.execute(sql)
  458. # On commit les modifications
  459. analytique_db.commit()
  460. logger.info("> Affaire créée: {}".format(affaire.strLiaisonControle))
  461. for interv in affaire.intervs:
  462. logger.info("> Intervention créée: {}".format(interv.strLiaisonControle))
  463. # Maj des temps d'installation