ctrl2analytique.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  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. # Créé le répertoire de travail
  35. workdir = mk_workdir("ctrl2analytique")
  36. affaires_file = workdir / "affaires.csv"
  37. intervs_file = workdir / "intervs.csv"
  38. # > Supprime les fichiers d'import s'il existent
  39. for file in (affaires_file, intervs_file):
  40. if file.exists():
  41. logger.debug("Supprime le fichier %s", file)
  42. file.remove()
  43. class Affaire(Model):
  44. """ Modèle de données d'une affaire Analytique """
  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. """ Récupère le coefficient de calcul des frais généraux (batiments, frais administratifs...Etc.) """
  73. # On déduit l'année du chantier à partir du code chantier
  74. annee = "20" + str(lngChantierId)[:2] if len(str(lngChantierId)) == 6 else "200" + str(lngChantierId)[:1]
  75. return analytique_db.first("SELECT [COEFFG] FROM tbl_COEFFG WHERE [ANNEE] = {}".format(annee)).COEFFG / 100
  76. # ########## IMPORT DES AFFAIRES ##########
  77. # Parcourt les chantiers de contrôle pour lesquels aucune affaire n'a été créée, et les ajoute au fichier affaire.csv
  78. compteur = 0
  79. sql = """ SELECT tblCommandes.lngChantierId, tblCommandes.bytCommandeId, tblChantiers.strSubdivisionId, tblChantiers.strCollectiviteId as ChantierCollectiviteId, tblChantiers.strLocChantier,
  80. tblChantiers.strEntrepriseId, tblCommandes.strCollectiviteId as CommandeCollectiviteId, tblCommandes.dtmCommande, tblCommandes.strRefCommande, tblCommandes.blnMarche, tblCommandes.dblMtMarche, tblCommandes.strdevis
  81. FROM tblChantiers INNER JOIN tblCommandes ON tblChantiers.lngChantierId = tblCommandes.lngChantierId
  82. WHERE (((tblCommandes.sngAffaireIdMos) Is Null Or (tblCommandes.sngAffaireIdMos)=0))
  83. """
  84. for data in controles_db.read(sql):
  85. # Création de l'affaire
  86. affaire = Affaire()
  87. affaire.strLiaisonControle = "{}/{}".format(data.lngChantierId, data.bytCommandeId)
  88. affaire.strMOeId = data.strSubdivisionId
  89. affaire.strCommneId = data.ChantierCollectiviteId
  90. affaire.strLieux = data.strLocChantier
  91. affaire.strEntrepriseId = data.strEntrepriseId
  92. affaire.strMOId = data.CommandeCollectiviteId
  93. affaire.dtmCommande = data.dtmCommande
  94. affaire.Ref = data.strRefCommande
  95. affaire.blnMarche = data.blnMarche
  96. affaire.dblMarche = data.dblMtMarche
  97. affaire.intDevisId = data.strdevis
  98. affaire.strCT = '1'
  99. affaire.strTypeId = get_type_id(data.lngChantierId, data.bytCommandeId)
  100. affaire.intCoefFG = get_coeff_k(data.lngChantierId)
  101. affaire.strSituation = "En cours"
  102. # Créé la ligne dans le fichier affaires.csv
  103. affaire.dump(affaires_file)
  104. # pour garder le lien avec la donnée d'origine:
  105. affaire.lngChantierId = data.lngChantierId
  106. affaire.bytCommandeId = data.bytCommandeId
  107. compteur += 1
  108. logger.info("> {} affaires ajoutées à {}".format(compteur, affaires_file))
  109. # ########## IMPORT DES INTERVENTIONS DE COMPACTAGE ##########
  110. # Importe les interventions de contrôle du compactage dans le fichier intervs.csv
  111. class Interv(Model):
  112. """ Modèle de données d'une intervention de contrôle réseaux """
  113. _FIELDS = ["strEquipeId", "strEnginId", "strRapportId", "strTypeInterventionId",
  114. "strTypeInterventionId", "strCatégorieInterventionId", "dblquantite", "strunite", "dtmIntervention",
  115. "dtmDureeIntervention", "dtmDureeInstallation", "strLiaisonControle", "strArticleId", "intPeriode",
  116. "remarques", "strgrandeur1", "strgrandeur2", "strgrandeur3",
  117. "strcaracteristique1", "strcaracteristique2", "strcaracteristique3",
  118. "dtmImportation", "strTest", "LienAff"
  119. ]
  120. def engin_existe(strEnginId):
  121. """ retourne True si le code de l'engin existe dans la table tbl_Engin """
  122. return analytique_db.exists("SELECT strEnginId FROM tbl_Engin WHERE strEnginId='{}'".format(strEnginId))
  123. def get_periode_validite(date_interv):
  124. """ retourne la préiode comptable correspondant à la date de l'intervention """
  125. sql = """SELECT intPeriodeValiditeId FROM tblTarifValidite
  126. WHERE [dtmValiditeDebut] <= #{date_interv}# AND [dtmValiditeFin] > #{date_interv}# AND [bytClasseTarifId]=1
  127. """.format(date_interv=date_interv)
  128. return commun_db.first(sql).intPeriodeValiditeId
  129. compteur = 0
  130. sql = """SELECT tblCompactageIntervs.lngChantierId, tblCompactageIntervs.bytCommandeId, tblCompactageIntervs.bytIntervId, tblCompactageIntervs.strEquipeId,
  131. tblCompactageEngins.strEnginId, tblCompactageIntervs.lngRapportId, tblCompactageBases.memTravaux, tblCompactageResultats.dtmEssai,
  132. tblCompactageResultats.dtmDuree, tblCompactagePartChantiers.strTrcRegard, tblMateriaux.strMatériau,
  133. tblCompactageResultats.bytPartChantierId, tblCompactageIntervs.sngIntervIdMos
  134. FROM ((tblMateriaux RIGHT JOIN ((((tblCompactageIntervs LEFT JOIN tblCompactageEngins ON tblCompactageIntervs.strEquipeId = tblCompactageEngins.strEquipeId)
  135. INNER JOIN tblCompactageResultats ON (tblCompactageIntervs.bytIntervId = tblCompactageResultats.bytIntervId)
  136. AND (tblCompactageIntervs.lngChantierId = tblCompactageResultats.lngChantierId)) INNER JOIN tblCompactagePartChantiers
  137. ON (tblCompactageResultats.bytPartChantierId = tblCompactagePartChantiers.bytPartChantierId)
  138. AND (tblCompactageResultats.lngChantierId = tblCompactagePartChantiers.lngChantierId)) INNER JOIN tblCompactageBases
  139. ON tblCompactageIntervs.lngChantierId = tblCompactageBases.lngChantierId) ON tblMateriaux.strMateriauId = tblCompactagePartChantiers.strMateriauRemblaiId)
  140. LEFT JOIN tblMateriaux AS tblMateriaux_1 ON tblCompactagePartChantiers.strMateriauEnrobageId = tblMateriaux_1.strMateriauId)
  141. LEFT JOIN tblMateriaux AS tblMateriaux_2 ON tblCompactagePartChantiers.strMateriauLitId = tblMateriaux_2.strMateriauId
  142. WHERE (((tblCompactageIntervs.sngIntervIdMos)=0 Or (tblCompactageIntervs.sngIntervIdMos) Is Null))
  143. """
  144. def get_type_compactage_interv(observation):
  145. """ retourne le sous-type d'intervention à partir du commentaire associé """
  146. if "ASSAINISEMENT" or "ASSAINISEMENT" in observation:
  147. return "CC3"
  148. elif "CABLE" in observation:
  149. return "CC1"
  150. elif "A.E.P" in observation:
  151. return "CC2"
  152. elif "GAZ" in observation:
  153. return "CC4"
  154. else:
  155. return "CC3"
  156. for data in controles_db.read(sql):
  157. interv = Interv()
  158. interv.strEquipeId = "C{}".format(data.strEquipeId)
  159. interv.strEnginId = data.strEnginId
  160. interv.strRapportId = data.strRapportId
  161. interv.strTypeInterventionId = get_type_compactage_interv(data.memTravaux)
  162. interv.strCatégorieInterventionId = "CC"
  163. interv.dblquantite = 1
  164. interv.strunite = "u"
  165. interv.dtmIntervention = data.dtmEssai
  166. interv.dtmDureeIntervention = data.dtmDuree
  167. interv.dtmDureeInstallation = 0 # Les temps d'installation seront calculés en fin de traitement
  168. interv.strLiaisonControle = "{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId)
  169. interv.strArticleId = data.strEnginId
  170. interv.intPeriode = get_periode_validite(data.dtmEssai)
  171. interv.remarques = data.strTrcRegard
  172. interv.strgrandeur1 = data.strMatériau
  173. interv.strgrandeur2 = data.strMatériau
  174. interv.strgrandeur3 = data.strMatériau
  175. interv.strcaracteristique1 = "Matériau remblai"
  176. interv.strcaracteristique2 = "Matériau lit de pose"
  177. interv.strcaracteristique3 = "Matériau enrobage"
  178. interv.strunite1 = ""
  179. interv.strunite2 = ""
  180. interv.strunite3 = ""
  181. interv.dtmImportation = "{}".format(datetime.now().strftime("%Y-%m-%d"))
  182. interv.strTest = "{}/{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId, data.bytPartChantierId)
  183. interv.LienAff = "{}/{}".format(data.lngChantierId, data.bytCommandeId)
  184. # Créé la ligne dans le fichier intervs.csv
  185. interv.dump(intervs_file)
  186. compteur += 1
  187. logger.info("> {} interventions Compactage ajoutées au fichier".format(compteur))
  188. # ########## IMPORT DES INTERVENTIONS D'ETANCHEITE ##########
  189. # Importe les interventions de contrôle d'étanchéité dans le fichier intervs.csv
  190. compteur = 0
  191. sql = """SELECT tblEtancheiteIntervs.lngChantierId, tblEtancheiteIntervs.bytCommandeId, tblEtancheiteIntervs.bytIntervId, tblEtancheiteIntervs.strEquipeId,
  192. tblEtancheiteIntervs.lngRapportId, tblEtancheitePartChantiers.bytTypeEssai, tblMateriaux.strMateriauId, tblMateriaux.strMatériau,
  193. tblEtancheitePartChantiers.intDiametre, tblEtancheitePartChantiers.sngLgHt, tblEtancheitePartChantiers.intNbJoint, tblEtancheiteResultats.dtmDuree,
  194. tblEtancheiteResultats.dtmEssai, tblEtancheitePartChantiers.strTrcRegard, tblEtancheiteResultats.bytPartChantierId
  195. FROM ((tblEtancheiteIntervs INNER JOIN tblEtancheiteResultats ON (tblEtancheiteIntervs.lngChantierId = tblEtancheiteResultats.lngChantierId)
  196. AND (tblEtancheiteIntervs.bytIntervId = tblEtancheiteResultats.bytIntervId)) INNER JOIN tblEtancheitePartChantiers
  197. ON (tblEtancheiteResultats.lngChantierId = tblEtancheitePartChantiers.lngChantierId)
  198. AND (tblEtancheiteResultats.bytPartChantierId = tblEtancheitePartChantiers.bytPartChantierId)) INNER JOIN tblMateriaux
  199. ON tblEtancheitePartChantiers.strMateriauId = tblMateriaux.strMateriauId
  200. WHERE (((tblEtancheiteIntervs.sngIntervIdMos)=0 Or (tblEtancheiteIntervs.sngIntervIdMos) Is Null));
  201. """
  202. def get_engin_etancheite(equipe, diametre, materiau, type_essai):
  203. """ retourne l'engin correspondant à l'essai en fonction eds caractéristiques de l'essai """
  204. sql = """SELECT strEnginId FROM tblEtancheiteEngins
  205. WHERE ([strEquipeId] = '{}') AND ([intDiametre] = {}) AND ([strMateriauId] = '{}') AND ([bytTypeEssaiId] ={})
  206. """.format(equipe, diametre, materiau, type_essai)
  207. row = controles_db.first(sql)
  208. return row.strEnginId if row else ""
  209. for data in controles_db.read(sql):
  210. interv = Interv()
  211. interv.strEquipeId = "C{}".format(data.strEquipeId)
  212. interv.strEnginId = get_engin_etancheite(data.strEquipeId, data.intDiametre, data.strMateriauId, data.bytTypeEssai)
  213. interv.strRapportId = data.lngRapportId
  214. interv.strTypeInterventionId = "CE{}".format(data.bytTypeEssai)
  215. interv.strCatégorieInterventionId = "CE"
  216. interv.dblquantite = data.intNbJoint
  217. interv.strunite = "u"
  218. interv.dtmIntervention = data.dtmEssai
  219. interv.dtmDureeIntervention = data.dtmDuree
  220. interv.dtmDureeInstallation = 0 # Les temps d'installation seront recalculés en fin de traitement
  221. interv.strLiaisonControle = "{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId)
  222. interv.strArticleId = interv.strEnginId
  223. interv.intPeriode = get_periode_validite(data.dtmEssai)
  224. interv.remarques = data.strTrcRegard
  225. interv.strgrandeur1 = data.strMatériau
  226. interv.strgrandeur2 = data.intDiametre
  227. interv.strgrandeur3 = data.sngLgHt
  228. interv.strcaracteristique1 = "Matériau"
  229. interv.strcaracteristique2 = "Diamètre"
  230. interv.strcaracteristique3 = "Longueur"
  231. interv.strunite1 = ""
  232. interv.strunite2 = "mm"
  233. interv.strunite3 = "m"
  234. interv.dtmImportation = "{}".format(datetime.now().strftime("%Y-%m-%d"))
  235. interv.strTest = "{}/{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId, data.bytPartChantierId)
  236. interv.LienAff = "{}/{}".format(data.lngChantierId, data.bytCommandeId)
  237. # Créé la ligne dans le fichier intervs.csv
  238. interv.dump(intervs_file)
  239. compteur += 1
  240. logger.info("> {} interventions Etanchéité ajoutées au fichier".format(compteur))
  241. # ########## IMPORT DES INTERVENTIONS D'INSPECTION VIDEO ##########
  242. # Importe les interventions d'inspection vidéo dans le fichier intervs.csv
  243. compteur = 0
  244. sql = """SELECT tblVideoIntervs.lngChantierId, tblVideoIntervs.bytCommandeId, tblVideoIntervs.bytIntervId, tblVideoIntervs.strEquipeId,
  245. tblVideoEngins.strEnginId, tblVideoIntervs.lngRapportId, First(tblso_rate_Analyse.MateriauCourt) AS strmateriau, tblVideoIntervs.lngTroncon,
  246. tblVideoIntervs.sngNbJourFact, First(tblso_rate_Analyse.MaxDeDiametre) AS diam, tblVideoIntervs.dtmDuree, tblVideoIntervs.dtmIntervDu,
  247. First(tblVideoIntervs.memObservation) AS memObservation, tblChantiers.strEntrepriseId
  248. FROM ((tblVideoEngins RIGHT JOIN tblVideoIntervs ON tblVideoEngins.strEquipeId = tblVideoIntervs.strEquipeId) INNER JOIN tblso_rate_Analyse ON
  249. (tblVideoIntervs.lngChantierId = tblso_rate_Analyse.lngChantierId) AND (tblVideoIntervs.bytIntervId = tblso_rate_Analyse.bytIntervId)) INNER JOIN
  250. tblChantiers ON tblVideoIntervs.lngChantierId = tblChantiers.lngChantierId
  251. WHERE (((tblVideoIntervs.sngIntervIdMos) Is Null Or (tblVideoIntervs.sngIntervIdMos)=0))
  252. GROUP BY tblVideoIntervs.lngChantierId, tblVideoIntervs.bytCommandeId, tblVideoIntervs.bytIntervId, tblVideoIntervs.strEquipeId,
  253. tblVideoIntervs.lngRapportId, tblVideoIntervs.lngTroncon, tblVideoIntervs.sngNbJourFact, tblVideoIntervs.dtmDuree,
  254. tblVideoIntervs.dtmIntervDu, tblVideoEngins.strEnginId, tblChantiers.strEntrepriseId
  255. """
  256. for data in controles_db.read(sql):
  257. interv = Interv()
  258. interv.strEquipeId = "C{}".format(data.strEquipeId)
  259. interv.strEnginId = data.strEnginId
  260. interv.strRapportId = data.lngRapportId
  261. interv.strTypeInterventionId = "CI1" if data.strEntrepriseId != 195 else "CI2"
  262. interv.strCatégorieInterventionId = "CI"
  263. interv.dblquantite = data.sngNbJourFact
  264. interv.strunite = "j"
  265. interv.dtmIntervention = data.dtmIntervDu
  266. interv.dtmDureeIntervention = data.dtmDuree
  267. interv.dtmDureeInstallation = 0 # Les temps d'installation seront recalculés en fin de traitement
  268. interv.strLiaisonControle = "{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId)
  269. interv.strArticleId = data.strEnginId
  270. interv.intPeriode = get_periode_validite(data.dtmIntervDu)
  271. interv.remarques = data.memObservation
  272. interv.strgrandeur1 = data.strmateriau
  273. interv.strgrandeur2 = data.diam
  274. interv.strgrandeur3 = data.lngTroncon
  275. interv.strcaracteristique1 = "Matériau"
  276. interv.strcaracteristique2 = "Diamètre"
  277. interv.strcaracteristique3 = "Longueur inspectée"
  278. interv.strunite1 = ""
  279. interv.strunite2 = "mm"
  280. interv.strunite3 = "m"
  281. interv.dtmImportation = "{}".format(datetime.now().strftime("%Y-%m-%d"))
  282. interv.strTest = "{}/{}/{}/1".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId)
  283. interv.LienAff = "{}/{}".format(data.lngChantierId, data.bytCommandeId)
  284. # Créé la ligne dans le fichier intervs.csv
  285. interv.dump(intervs_file)
  286. compteur += 1
  287. logger.info("> {} interventions ITV ajoutées au fichier".format(compteur))
  288. logging.info("Les données à importer ont été ajoutées aux fichiers '{}' et '{}'".format(affaires_file, intervs_file))
  289. logging.info("Ces fichiers sont au format CSV (séparateur: tabulation)")
  290. # ########## CONTROLE ET CORRECTION DES DONNEES ##########
  291. errors = -1
  292. while errors:
  293. errors = []
  294. with open(affaires_file) as f:
  295. next(f) # saute la première ligne
  296. for line in f:
  297. affaire = Affaire.from_csv(line)
  298. prefix = "Affaire {}: ".format(affaire.strLiaisonControle)
  299. if not affaire.strMOId:
  300. errors.append(prefix + "MO manquant")
  301. else:
  302. if not commun_db.exists("SELECT [lngTiersId] FROM tblTiers WHERE [lngTiersId]={}".format(affaire.strMOId)):
  303. errors.append(prefix + "Le MO {} n'existe pas dans tblTiers".format(affaire.strMOId))
  304. if not affaire.strMOeId:
  305. errors.append(prefix + "MOe manquant")
  306. else:
  307. if not commun_db.exists("SELECT [lngTiersId] FROM tblTiers WHERE [lngTiersId]={}".format(affaire.strMOeId)):
  308. errors.append(prefix + "Le MOe {} n'existe pas dans tblTiers".format(affaire.strMOeId))
  309. if not affaire.strEntrepriseId:
  310. errors.append(prefix + "Entreprise manquante")
  311. else:
  312. if not commun_db.exists("SELECT [lngTiersId] FROM tblTiers WHERE [lngTiersId]={}".format(affaire.strEntrepriseId)):
  313. errors.append(prefix + "L'entreprise {} n'existe pas dans tblTiers".format(affaire.strEntrepriseId))
  314. if not affaire.strCommneId:
  315. errors.append(prefix + "Commune manquante")
  316. else:
  317. if not commun_db.exists("SELECT [lngTiersId] FROM tblTiers WHERE [lngTiersId]={}".format(affaire.strCommneId)):
  318. errors.append(prefix + "La commune {} n'existe pas dans tblTiers".format(affaire.strCommneId))
  319. if not affaire.strTypeId:
  320. errors.append(prefix + "Type d'affaire manquant")
  321. if not affaire.dtmCommande:
  322. errors.append(prefix + "Date de commande manquante")
  323. if affaire.blnMarche == True and not affaire.intDevisId:
  324. errors.append(prefix + "Numéro de devis manquant")
  325. if analytique_db.exists("SELECT dblAffaireId FROM tbl_Affaires WHERE [strLiaisonControle]='{}'".format(affaire.strLiaisonControle)):
  326. errors.append(prefix + "Une affaire portant ce code existe déjà: {}".format(affaire.strLiaisonControle))
  327. with open(intervs_file) as f:
  328. next(f) # saute la première ligne
  329. for line in f:
  330. interv = Interv.from_csv(line)
  331. prefix = "Intervention {}: ".format(interv.strLiaisonControle)
  332. if not interv.strEquipeId:
  333. errors.append(prefix + "Equipe manquante")
  334. if not interv.strEnginId:
  335. errors.append(prefix + "Engin manquant")
  336. if not interv.strRapportId:
  337. errors.append(prefix + "Rapport manquant")
  338. if not interv.strCatégorieInterventionId:
  339. errors.append(prefix + "Catégorie de l'intervention manquante")
  340. if not interv.strTypeInterventionId:
  341. errors.append(prefix + "Type d'intervention manquant")
  342. if not interv.dblquantite:
  343. errors.append(prefix + "Quantité nulle")
  344. if not interv.strunite:
  345. errors.append(prefix + "Unité non renseignée")
  346. if not interv.dtmIntervention:
  347. errors.append(prefix + "Erreur : date d'intervention")
  348. if not interv.dtmDureeIntervention:
  349. errors.append(prefix + "Durée d'intervention nulle")
  350. if not interv.strunite:
  351. errors.append(prefix + "Unité non renseignée")
  352. if not engin_existe(interv.strEnginId):
  353. errors.append(prefix + "l'engin {} n'existe pas".format(interv.strEnginId))
  354. # *** 6- Interruption pour corection manuelle des données (si nécessaire)
  355. if errors:
  356. logging.error("<!> Des erreurs ont été détectées dans les données à importer. <!>")
  357. for msg in errors:
  358. logging.error(msg)
  359. prompt = ""
  360. while prompt != "v":
  361. prompt = input(">> Veuillez contrôler les données, puis taper 'v' pour continuer, ou 'q' pour quitter...")
  362. if prompt == "q":
  363. sys.exit(1)
  364. # ########## MISE A JOUR DE LA BASE DE DONNEES ANALYTIQUE ##########
  365. # On charge en mémoire les affaires et les interventions qui leurs sont associées
  366. affaires = {}
  367. with open(affaires_file) as f:
  368. next(f) # saute la première ligne
  369. for line in f:
  370. affaire = Affaire.from_csv(line)
  371. with open(intervs_file) as f:
  372. next(f) # saute la première ligne
  373. for line in f:
  374. interv = Interv.from_csv(line)
  375. try:
  376. affaires[interv.LienAff].append(interv)
  377. except KeyError:
  378. logger.error("L'intervention {} n'est liée à aucune affaire. Elle ne sera pas importée.".format(interv.strLiaisonControle))
  379. class Tarification(Model):
  380. """ Modèle de donnée d'une ligne de tarification """
  381. _FIELDS = ["DblAffaireId", "strRapportId", "strArticleId", "dblQuantite", "strUnite",
  382. "dtmDebut", "dtmFin", "bytPeriode", "dblPrixUnitaire", "dblPrixTotal", "strStatut"]
  383. # On insère les affaires, interventions dans Analytique, et on génère la ou les lignes de tarification associées
  384. for affaire in affaires.values():
  385. # insertion dans tbl_Affaires
  386. sql = """ INSERT INTO tbl_Affaires ( strMOId, strMOeId, strEntrepriseId, strCommneId, strLieux, strTypeId, dtmCommande, Ref,
  387. blnMarche, dblMarche, intTypeContrat, strCT, strAvancement, strLiaisonControle, intDevisId, blnTarification,
  388. blnAnalyse, remarques, strSituation, dtmFin, intCoefFG )
  389. VALUES ('{affaire.strMOId}', '{affaire.strMOeId}', '{affaire.strEntrepriseId}', '{affaire.strCommneId}', '{affaire.strLieux}', '{affaire.strTypeId}',
  390. #{affaire.dtmCommande}#, '{affaire.Ref}', {affaire.blnMarche}, {affaire.dblMarche}, {affaire.intTypeContrat}, '{affaire.strCT}',
  391. '{affaire.strAvancement}', '{affaire.strLiaisonControle}', {affaire.intDevisId},True, {affaire.blnAnalyse},
  392. '{affaire.remarques}', '{affaire.strSituation}', #{affaire.dtmFin}#, {affaire.intCoefFG})
  393. """.format(affaire=affaire)
  394. analytique_db.execute(sql)
  395. logger.info("> Ajout de l'affaire: {}".format(affaire.strLiaisonControle))
  396. affaire.DblAffaireId = analytique_db.first("SELECT TOP 1 DblAffaireId FROM tbl_Affaires WHERE [strLiaisonControle]='{}'".format(affaire.strLiaisonControle)).DblAffaireId
  397. # insertions des interventions dans tbl_Intervention
  398. for interv in affaire.intervs:
  399. sql = """INSERT INTO tbl_Intervention ( DblAffaireId, strEquipeId, strEnginId, strRapportId, strCatégorieInterventionId, strTypeInterventionId,
  400. dblquantite, strunite, dtmIntervention, dtmDureeIntervention, dtmDureeInstallation, strcaracteristique1, strgrandeur1, strunite1,
  401. strcaracteristique2, strgrandeur2, strunite2, strcaracteristique3, strgrandeur3, strunite3, strLiaisonControle, strarticleId,
  402. intPeriode, blnTarification, blnAnalyse, blnFacturer, remarques, blnPeriode, dtnPeriodeDebut, dtmImportation, blnVerifFacture, strTest )
  403. VALUES ({dblAffaireId}, '{interv.strEquipeId}', '{interv.strEnginId}', '{interv.strRapportId}', '{interv.strCatégorieInterventionId}',
  404. '{interv.strTypeInterventionId}', {interv.dblquantite}, '{interv.strunite}', #{interv.dtmIntervention}#, #{interv.dtmDureeIntervention}#,
  405. #{interv.dtmDureeInstallation}#, '{interv.strcaracteristique1}', '{interv.strgrandeur1}', '{interv.strunite1}', '{interv.strcaracteristique2}',
  406. '{interv.strgrandeur2}', '{interv.strunite2}', '{interv.strcaracteristique3}', '{interv.strgrandeur3}', '{interv.strunite3}', '{interv.strLiaisonControle}',
  407. '{interv.strarticleId}', {interv.intPeriode}, True, {interv.blnAnalyse}, {interv.blnFacturer}, '{interv.remarques}',
  408. {interv.blnPeriode},#{interv.dtnPeriodeDebut}#, #{interv.dtmImportation}#, {interv.blnVerifFacture}, '{interv.strTest}')
  409. """.format(dblAffaireId=affaire.DblAffaireId,
  410. interv=interv)
  411. analytique_db.execute(sql)
  412. logger.info("> Ajout de l'intervention: {}".format(interv.strLiaisonControle))
  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. logger.info("> Génération d'une ligne de tarification pour l'article: {}".format(affaire.strLiaisonControle, strArticleId))
  444. # Maj champs MOS
  445. # Ces champs sont utilisés dans les tables Controles pour savoir si une ligne a déjà été importée
  446. sql = """UPDATE tblCommandes SET tblCommandes.sngAffaireIdMos = {DblAffaireId}
  447. WHERE [lngChantierId]={lngChantierId} AND [bytCommandeId]={bytCommandeId}
  448. """.format(DblAffaireId=affaire.DblAffaireId,
  449. lngChantierId=affaire.lngChantierId,
  450. bytCommandeId=affaire.bytCommandeId)
  451. analytique_db.execute(sql)
  452. for tbl in ("tblCompactageIntervs", "tblEtancheiteIntervs", "tblVideoIntervs"):
  453. sql = """UPDATE {tbl} SET {tbl}.sngIntervIdMos = {DblAffaireId}
  454. WHERE [lngChantierId]={lngChantierId} AND [bytCommandeId]={bytCommandeId}
  455. """.format(DblAffaireId=affaire.DblAffaireId,
  456. lngChantierId=affaire.lngChantierId,
  457. bytCommandeId=affaire.bytCommandeId)
  458. analytique_db.execute(sql)
  459. logger.info("> Mise à jour des champs MOS")
  460. # On commit les modifications
  461. logger.info("Commit des modifications...")
  462. analytique_db.commit()
  463. # ########## MISE A JOUR DES TEMPS D'INSTALLATION ##########
  464. # > Le temps d'installation est le temps passé par chaque agent en transport, préparation, reporting...etc.
  465. # > C'est donc le temps de travail théorique, moins le temps d'intervention.
  466. logger.info("Mise à jour des temps d'installation...")
  467. sql = """ SELECT First(tbl_Intervention.dblInterventionId) AS dblInterventionId,
  468. tbl_Intervention.strEquipeId, tbl_Intervention.dtmIntervention,
  469. Year([dtmIntervention]) AS annee, Sum(tbl_Intervention.dtmDureeIntervention) AS SD,
  470. FROM tbl_Intervention
  471. WHERE (((tbl_Intervention.strLiaisonControle) Like '*/*'))
  472. GROUP BY tbl_Intervention.strEquipeId, Year([dtmIntervention]), tbl_Intervention.dtmIntervention
  473. HAVING (((tbl_Intervention.strEquipeId) Is Not Null)
  474. AND ((Year([dtmIntervention]))>=Year(Date())-1)
  475. AND ((tbl_Intervention.dtmIntervention) Is Not Null)
  476. AND ((Sum(tbl_Intervention.dtmDureeIntervention))>0
  477. And (Sum(tbl_Intervention.dtmDureeIntervention)) Is Not Null)
  478. AND ((Count(tbl_Intervention.dtmDureeIntervention))>0
  479. And (Count(tbl_Intervention.dtmDureeIntervention)) Is Not Null))"""
  480. for interv in analytique_db.read(sql):
  481. if interv.SD < (8 / 24):
  482. tps_install = ((8 / 24) - interv.SD)
  483. sql = """UPDATE tbl_Intervention SET tbl_Intervention.dtmDureeInstallation = #{}#
  484. WHERE (((tbl_Intervention.dblInterventionId)={}));""".format(tps_install, interv.dblInterventionId)
  485. logger.debug("* Mise à jour du temps d'installation de l'intervention {}".format(interv.dblInterventionId))
  486. logger.info("# Import terminé")