wincan2ctrl.py 15 KB

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