wincan2ctrl.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. '''
  2. Met à jour la base controle avec les données d'un chantier Wincan
  3. usage: wincan2ctrl [-c <idchantier>] [-i <inspectioname>] [-o]
  4. Options:
  5. -c <idchantier> Passe le code chantier
  6. -i <inspectioname> Passe le nom de l'inpection wincan
  7. -o Ne demande pas confirmation avant de lancer le traitement
  8. -h, --help Affiche l'aide
  9. Attention: Si un des arguments comporte des espaces, pensez à le mettre entre guillemets
  10. @olivier.massot, mai 2018
  11. '''
  12. import logging
  13. import sys
  14. from docopt import docopt
  15. from path import Path
  16. from core import logconf
  17. from core.pde import ControlesDb, WincanDb, InspectionTronconWincan, \
  18. InterventionITV, PiracaDb
  19. from core.sqlformatter import SqlFormatter
  20. logger = logging.getLogger("wincan2ctrl")
  21. logconf.start("wincan2ctrl", logging.DEBUG)
  22. # # POUR TESTER, décommenter les lignes suivantes
  23. # > Lancer le script /resources/test_wincan2ctrl.py pour reinitialiser les données de la base de test
  24. ##-----------------------------------------------
  25. # ControlesDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\cg67Parc_data.mdb")
  26. # WincanDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\Wincan\parc_2007\DB\PARC_2007.mdb")
  27. # PiracaDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\db_Piraca.mdb")
  28. # logger.handlers = [h for h in logger.handlers if (type(h) == logging.StreamHandler)]
  29. # logger.warning("<<<<<<<<<<<<<< Mode TEST >>>>>>>>>>>>>>>>>")
  30. ##-----------------------------------------------
  31. def main():
  32. logger.info("Initialisation...")
  33. Sql = SqlFormatter()
  34. # Connexion à Controles
  35. controles_db = ControlesDb(autocommit=False)
  36. # Connexion à Wincan
  37. wincan_db = WincanDb(autocommit=False)
  38. # Connexion à CommunDb
  39. piraca_db = PiracaDb(autocommit=False)
  40. def get_lib(lib_id, tbl_id):
  41. row = piraca_db.first(Sql.format("""SELECT LIB_ID, LIB_LIB, TLB_ID
  42. FROM LISTE_LIBELLE_WINCAN
  43. WHERE TLB_ID='{}' AND LIB_ID='{}'""", tbl_id, lib_id))
  44. if not row:
  45. logger.error("Aucun libelle trouvé dans la table LISTE_LIBELLE_WINCAN pour %s, id=%s", tbl_id, lib_id)
  46. raise KeyError()
  47. return row.LIB_LIB
  48. def get_materiau(wincan_id):
  49. return controles_db.first(Sql.format("""SELECT strMateriauCourt
  50. FROM tblMateriaux
  51. WHERE strWincanId='{}'""", wincan_id)).strMateriauCourt
  52. # Parse les arguments
  53. args = docopt(__doc__, help=False)
  54. chantier_id = args["-c"] if args["-c"] else 0
  55. inspname = args["-i"] if args["-i"] else ""
  56. # Demande à l'utilisateur de saisir les informations qui n'ont pas été passées en argument
  57. if not inspname:
  58. # Propose une liste d'inspections possibles
  59. sql = """SELECT SI_InspName
  60. FROM SI_T
  61. WHERE SI_Spare1 Is Null OR Len([SI_Spare1])=0
  62. GROUP BY SI_InspName
  63. """
  64. candidats = wincan_db.read_all(sql)
  65. print("Veuillez choisir une inspection Wincan à traiter en saisissant son numéro:")
  66. for i, candidat in enumerate(candidats):
  67. print("[{}] - {}".format(i, candidat.SI_InspName))
  68. while not inspname:
  69. reponse = input("> ")
  70. try:
  71. inspname = candidats[int(reponse)].SI_InspName
  72. except ValueError:
  73. print("Valeur invalide!")
  74. if not chantier_id:
  75. try:
  76. default = int(inspname[:6])
  77. chantier_id = input("Veuillez saisir le code chantier [{}]: ".format(default))
  78. if not chantier_id:
  79. chantier_id = default
  80. except ValueError:
  81. chantier_id = input("Veuillez saisir le code chantier: ")
  82. if not chantier_id:
  83. logger.error("Code chantier invalide")
  84. return
  85. # Calcul du numéro d'intervention
  86. last_interv_id = controles_db.first("SELECT max(bytIntervId) as last_interv_id FROM tblVideoIntervs WHERE lngChantierId={}".format(chantier_id)).last_interv_id
  87. interv_id = last_interv_id + 1 if last_interv_id else 1
  88. # Récupération du numéro de commande en cours
  89. commande_id = controles_db.first("SELECT bytCommandeId FROM tblVideoBases WHERE lngChantierId={}".format(chantier_id)).bytCommandeId
  90. # Affiche les infos et demande confirmation avant ed lancer le traitement
  91. logger.info("## Traitement de l'inspection Wincan")
  92. logger.info("Nom chantier: %s", inspname)
  93. logger.info("Code chantier: %s", chantier_id)
  94. logger.info("Numero d'intervention: %s", interv_id)
  95. logger.info("Numero de commande: %s", commande_id)
  96. if not args["-o"]:
  97. if not input("Voulez-vous continuer? (o/n)") == 'o':
  98. if input("Etes-vous sûr de vouloir annuler l'opération? (o/n)") == 'o':
  99. logger.info("Opération annulée par l'utilisateur")
  100. return
  101. # Recuperation des données de l'intervention
  102. sql = """SELECT SI_T.SI_InspName, Sum(S_T.S_Sectionlength) AS Long_insp, Min(SI_T.SI_Date) AS mindate, Max(SI_T.SI_Date) AS maxdate,
  103. First(SI_T.SI_Operator) AS Equipe, First(SI_T.SI_Vehicle) AS Mat, First(SI_T.SI_InspMethod) AS InspMethod,
  104. First(SI_T.SI_ReasonOfInspection) AS SI_ReasonOfInspection, First(S_T.S_SectionPurpose) AS nature,
  105. First(S_T.S_SectionUse) AS Fonction, First(S_T.S_SectionType) AS Type
  106. FROM S_T INNER JOIN SI_T ON S_T.S_ID = SI_T.SI_Section_ID
  107. WHERE (((SI_T.[SI_InspName])='{}'))
  108. GROUP BY SI_T.SI_InspName
  109. HAVING Sum(S_T.S_Sectionlength) Is Not Null AND First(SI_T.SI_Operator) Is Not Null AND First(SI_T.SI_Vehicle) Is Not Null AND First(SI_T.SI_InspMethod) Is Not Null
  110. """.format(inspname)
  111. try:
  112. inspection = next(wincan_db.read(sql))
  113. except StopIteration:
  114. logger.error("Aucune inspection trouvée pour le nom '%s'", inspname)
  115. raise
  116. # Insère l'inspection dans la table tblVideoIntervs de Controles
  117. logger.info("Création de l'intervention dans tblVideoIntervs")
  118. interv = InterventionITV()
  119. interv.lngChantierId = chantier_id
  120. interv.bytIntervId = interv_id
  121. interv.dtmIntervDu = inspection.mindate
  122. interv.dtmIntervAu = inspection.maxdate
  123. interv.strEquipeId = inspection.Equipe
  124. interv.intlMaterielID = inspection.Mat
  125. interv.bytCommandeId = commande_id
  126. interv.lngTroncon = inspection.Long_insp
  127. interv.SI_InspMethod = inspection.InspMethod
  128. interv.SI_ReasonOfInspection = get_lib(inspection.SI_ReasonOfInspection, "SI_REASONOfINSPECTION")
  129. sql = Sql.format("""INSERT INTO tblVideoIntervs ( lngChantierId, bytIntervId, dtmIntervDu, dtmIntervAu, strEquipeId,
  130. intlMaterielID, bytCommandeId, lngTroncon, SI_InspMethod, SI_ReasonOfInspection )
  131. VALUES ({interv.lngChantierId}, {interv.bytIntervId}, {interv.dtmIntervDu:date}, {interv.dtmIntervAu:date}, {interv.strEquipeId:text},
  132. {interv.intlMaterielID}, {interv.bytCommandeId}, {interv.lngTroncon}, {interv.SI_InspMethod:text}, {interv.SI_ReasonOfInspection:text})
  133. """, interv=interv)
  134. controles_db.execute(sql)
  135. # Met a jour les champs SI_Spare1 et SI_Spare2 de la table Wincan en retour
  136. logger.info("Mise à jour en retour de SI_T")
  137. sql = """UPDATE SI_T
  138. SET SI_Spare1='{}', SI_Spare2='{}'
  139. WHERE SI_InspName='{}'
  140. """.format(chantier_id, interv_id, inspection.SI_InspName)
  141. wincan_db.execute(sql)
  142. # Met a jour la table tbl_so_rate de Controles
  143. logger.info("Traitement des inspections")
  144. # Extrait les données des tronçons
  145. sql = """SELECT SI_T.SI_ID, S_T.S_ID, SI_T.SI_InspName, SI_T.SI_Spare1, SI_T.SI_Spare2, SI_T.SI_AutoNumber, SI_T.SI_MediaNumber1, S_T.S_SectionFlow,
  146. S_T.S_StartNode, S_T.S_EndNode, S_T.S_StartNodeType, S_T.S_EndNodeType, S_T.S_StartNodeCoord_Z, S_T.S_EndNodeCoord_Z,
  147. S_T.S_Sectionlength, S_T.S_SectionPurpose, S_T.S_SectionUse, S_T.S_SectionType, S_T.S_PipeMaterial, S_T.S_YearLayed,
  148. S_T.S_PipeDia, S_T.S_Situation, S_T.S_Spare1, S_T.S_PipeShape, S_T.S_Pipelength, S_T.S_Spare3,
  149. SI_T.SI_Spare0, SI_T.SI_Date
  150. FROM S_T INNER JOIN SI_T ON S_T.S_ID = SI_T.SI_Section_ID
  151. WHERE SI_T.SI_Spare1='{}' AND SI_T.SI_Spare2='{}'
  152. """.format(chantier_id, interv_id)
  153. for data in wincan_db.read(sql):
  154. logger.info("* Traitement de %s (S_ID: %s)", data.SI_InspName, data.S_ID)
  155. inspection = InspectionTronconWincan()
  156. inspection.s_guid = data.S_ID[2:-1] if (data.S_ID[:2] == "b'" and data.S_ID[-1:] == "'") else data.S_ID
  157. inspection.si_guid = data.SI_ID[2:-1] if (data.SI_ID[:2] == "b'" and data.SI_ID[-1:] == "'") else data.SI_ID
  158. inspection.nom_chantier = data.SI_InspName
  159. inspection.lng_chantier_id = data.SI_Spare1
  160. inspection.byt_interv_id = data.SI_Spare2
  161. inspection.si_autonumber = data.SI_AutoNumber
  162. inspection.classement_troncons = data.SI_MediaNumber1
  163. inspection.nom_troncon = "{r1}-{r2}".format(r1=data.S_StartNode, r2=data.S_EndNode) if data.S_SectionFlow == '2' else "{r2}-{r1}".format(r1=data.S_StartNode, r2=data.S_EndNode)
  164. inspection.startnode_type = get_lib(data.S_StartNodeType, "S_StartNodeType")
  165. inspection.endnode_type = get_lib(data.S_StartNodeType, "S_EndNodeType")
  166. inspection.sens_ecoul = ">>" if data.S_SectionFlow == '1' else ('<<' if data.S_SectionFlow == '2' else '')
  167. inspection.startnode_z = data.S_StartNodeCoord_Z
  168. inspection.endnode_z = data.S_EndNodeCoord_Z
  169. inspection.section_length = data.S_Sectionlength
  170. inspection.section_purpose = data.S_SectionPurpose
  171. inspection.section_use = data.S_SectionUse
  172. inspection.section_type = data.S_SectionType
  173. inspection.materiau = get_materiau(data.S_PipeMaterial)
  174. inspection.annee_pose = data.S_YearLayed
  175. inspection.diametre = get_lib(int(data.S_PipeDia), "S_PipeDia")
  176. inspection.route = get_lib(data.S_Situation, "S_Situation")
  177. inspection.n_route = data.S_Spare1
  178. inspection.pipe_shape = data.S_PipeShape
  179. inspection.pipe_length = data.S_Pipelength
  180. if data.S_Spare3:
  181. inspection.arbres = get_lib(data.S_Spare3, "S_Spare3")
  182. inspection.test_ecoulement = data.SI_Spare0
  183. inspection.si_date = data.SI_Date
  184. sql = """ SELECT SO_T.SO_ID, SO_T.SO_Rate, SO_T.SO_Photonumber1, SO_T.SO_Photonumber2
  185. FROM SO_T
  186. WHERE SO_T.SO_Inspecs_ID='{}'
  187. """.format(inspection.si_guid)
  188. # Parcours les opérations réalisées au cours de l'inspection du tronçon
  189. for opdata in wincan_db.read(sql):
  190. inspection.nb_ops += 1
  191. if opdata.SO_Rate == 1:
  192. inspection.rate_1 = inspection.rate_1 + 1 if inspection.rate_1 else 1
  193. elif opdata.SO_Rate == 2:
  194. inspection.rate_2 = inspection.rate_2 + 1 if inspection.rate_2 else 1
  195. elif opdata.SO_Rate == 3:
  196. inspection.rate_3 = inspection.rate_3 + 1 if inspection.rate_3 else 1
  197. elif opdata.SO_Rate == 4:
  198. inspection.rate_4 = inspection.rate_4 + 1 if inspection.rate_4 else 1
  199. elif opdata.SO_Rate == 5:
  200. inspection.rate_5 = inspection.rate_5 + 1 if inspection.rate_5 else 1
  201. elif not opdata.SO_Rate:
  202. pass
  203. elif opdata.SO_Rate >= 6:
  204. logger.error("Attention: une valeur de [SO_Rate] supérieure à 5 a été enregistrée (SO_ID: %s)", opdata.SO_ID)
  205. if opdata.SO_Photonumber1:
  206. inspection.nb_photos += 1
  207. if opdata.SO_Photonumber2:
  208. inspection.nb_photos += 1
  209. if not any([inspection.rate_1, inspection.rate_2, inspection.rate_3, inspection.rate_4, inspection.rate_5]):
  210. inspection.DG = 'ABS' # Absence de défauts
  211. elif not any([inspection.rate_1, inspection.rate_2, inspection.rate_3]):
  212. inspection.DG = 'ACC' # Défauts acceptables
  213. else:
  214. inspection.DG = 'INT' # Défauts non-acceptables
  215. logger.info("\t- Mise à jour de tblso_Rate_Analyse")
  216. sql = Sql.format("""INSERT INTO tblso_Rate_Analyse (
  217. lngChantierId, bytIntervId, SI_InspName, SI_AutoNumber,
  218. [Classement tronons], Nom_troncon, S_StartNodeType,
  219. Sens_ecoul, S_EndNodeType, S_PipeShape, MateriauCourt,
  220. SI_Date, nb_Arbres, ANNEE_POSE,
  221. Route, NRoute, Test_ecoulement, MaxDeS_StartNodeCoord_Z, MaxDeS_EndNodeCoord_Z,
  222. MaxDeS_Sectionlength, MaxDeS_Pipelength, MaxDeDiametre, cpt_Photos, [Total de SO_ID],
  223. 1, 2, 3, 4, 5, DG
  224. )
  225. VALUES ({inspection.lng_chantier_id}, {inspection.byt_interv_id}, {inspection.nom_chantier:text}, {inspection.si_autonumber},
  226. {inspection.classement_troncons:text}, {inspection.nom_troncon:text}, {inspection.startnode_type:text},
  227. {inspection.sens_ecoul:text}, {inspection.endnode_type:text}, {inspection.pipe_shape:text}, {inspection.materiau:text},
  228. {inspection.si_date:date}, {inspection.arbres:text}, {inspection.annee_pose},
  229. {inspection.route:text}, {inspection.n_route:text}, {inspection.test_ecoulement:text}, {inspection.startnode_z}, {inspection.endnode_z},
  230. {inspection.section_length}, {inspection.pipe_length}, {inspection.diametre:text}, {inspection.nb_photos}, {inspection.nb_ops},
  231. {inspection.rate_1}, {inspection.rate_2}, {inspection.rate_3}, {inspection.rate_4}, {inspection.rate_5}, {inspection.DG:text}
  232. )
  233. """, inspection=inspection)
  234. controles_db.execute(sql)
  235. # Met à jour tblvideointervs.strResGlobal avec le resultat global
  236. # le resultat global vaut '-' si un de ces trois champs n'est pas nul: tbl_so_rate.1, tbl_so_rate.2, tbl_so_rate.3
  237. # >> On peut peut-être rassembler cette partie et l'insertion dans cette table au debut?
  238. logger.info("\t- Mise à jour du resultat global dans tblVideoIntervs")
  239. sql = """UPDATE tblVideoIntervs
  240. SET strResGlobal='{}'
  241. WHERE lngChantierId= {} AND bytIntervId= {}
  242. """.format('-' if inspection.DG == 'INT' else '+',
  243. chantier_id,
  244. interv_id)
  245. controles_db.execute(sql)
  246. # Met à jour la table tblVideoBases pour marquer le chantier comme traité
  247. logger.info("\t- Mise à jour de tblVideoBases")
  248. sql = """UPDATE tblVideoBases
  249. SET blnWincan=True,bytNbInterv={}
  250. WHERE lngChantierId={}
  251. """.format(inspection.byt_interv_id,
  252. inspection.lng_chantier_id)
  253. controles_db.execute(sql)
  254. # Met à jour les données du réseau dans tblChantiers
  255. logger.info("\t- Mise à jour des données du réseau dans tblChantiers")
  256. sql = """UPDATE tblChantiers
  257. SET bytFoncReseauId ={} , bytNatureReseauId={}, bytTypeReseauId={}
  258. WHERE lngChantierId={}
  259. """.format(inspection.section_use,
  260. inspection.section_purpose,
  261. inspection.section_type,
  262. inspection.lng_chantier_id)
  263. controles_db.execute(sql)
  264. logger.info("Commit des modifications")
  265. controles_db.commit()
  266. wincan_db.commit()
  267. if __name__ == "__main__":
  268. main()
  269. logger.info("-- Fin --")