wincan2ctrl.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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. SI_T.SI_Operator AS Equipe, SI_T.SI_Vehicle AS Mat, SI_T.SI_InspMethod AS InspMethod, SI_T.SI_ReasonOfInspection,
  103. S_T.S_SectionPurpose AS nature, S_T.S_SectionUse AS Fonction, S_T.S_SectionType AS Type
  104. FROM S_T INNER JOIN SI_T ON S_T.S_ID = SI_T.SI_Section_ID
  105. WHERE (((SI_T.[SI_InspName])='{}'))
  106. GROUP BY SI_T.SI_InspName, SI_T.SI_Operator, SI_T.SI_Vehicle, SI_T.SI_InspMethod, SI_T.SI_ReasonOfInspection, S_T.S_SectionPurpose, S_T.S_SectionUse, S_T.S_SectionType
  107. HAVING Sum(S_T.S_Sectionlength) Is Not Null AND SI_T.SI_Operator Is Not Null AND SI_T.SI_Vehicle Is Not Null AND SI_T.SI_InspMethod Is Not Null
  108. """.format(inspname)
  109. try:
  110. inspection = next(wincan_db.read(sql))
  111. except StopIteration:
  112. logger.error("Aucune inspection trouvée pour le nom '%s'", inspname)
  113. raise
  114. # Insère l'inspection dans la table tblVideoIntervs de Controles
  115. logger.info("Création de l'intervention dans tblVideoIntervs")
  116. interv = InterventionITV()
  117. interv.lngChantierId = chantier_id
  118. interv.bytIntervId = interv_id
  119. interv.dtmIntervDu = inspection.mindate
  120. interv.dtmIntervAu = inspection.maxdate
  121. interv.strEquipeId = inspection.Equipe
  122. interv.intlMaterielID = inspection.Mat
  123. interv.bytCommandeId = commande_id
  124. interv.lngTroncon = inspection.Long_insp
  125. interv.SI_InspMethod = inspection.InspMethod
  126. interv.SI_ReasonOfInspection = get_lib(inspection.SI_ReasonOfInspection, "SI_REASONOfINSPECTION")
  127. sql = Sql.format("""INSERT INTO tblVideoIntervs ( lngChantierId, bytIntervId, dtmIntervDu, dtmIntervAu, strEquipeId,
  128. intlMaterielID, bytCommandeId, lngTroncon, SI_InspMethod, SI_ReasonOfInspection )
  129. VALUES ({interv.lngChantierId}, {interv.bytIntervId}, {interv.dtmIntervDu:date}, {interv.dtmIntervAu:date}, {interv.strEquipeId:text},
  130. {interv.intlMaterielID}, {interv.bytCommandeId}, {interv.lngTroncon}, {interv.SI_InspMethod:text}, {interv.SI_ReasonOfInspection:text})
  131. """, interv=interv)
  132. controles_db.execute(sql)
  133. # Met a jour les champs SI_Spare1 et SI_Spare2 de la table Wincan en retour
  134. logger.info("Mise à jour en retour de SI_T")
  135. sql = """UPDATE SI_T
  136. SET SI_Spare1='{}', SI_Spare2='{}'
  137. WHERE SI_InspName='{}'
  138. """.format(chantier_id, interv_id, inspection.SI_InspName)
  139. wincan_db.execute(sql)
  140. # Met a jour la table tbl_so_rate de Controles
  141. logger.info("Traitement des inspections")
  142. # Extrait les données des tronçons
  143. 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,
  144. 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,
  145. S_T.S_Sectionlength, S_T.S_SectionPurpose, S_T.S_SectionUse, S_T.S_SectionType, S_T.S_PipeMaterial, S_T.S_YearLayed,
  146. S_T.S_PipeDia, S_T.S_Situation, S_T.S_Spare1, S_T.S_PipeShape, S_T.S_Pipelength, S_T.S_Spare3,
  147. SI_T.SI_Spare0, SI_T.SI_Date
  148. FROM S_T INNER JOIN SI_T ON S_T.S_ID = SI_T.SI_Section_ID
  149. WHERE SI_T.SI_Spare1='{}' AND SI_T.SI_Spare2='{}'
  150. """.format(chantier_id, interv_id)
  151. for data in wincan_db.read(sql):
  152. logger.info("* Traitement de %s (S_ID: %s)", data.SI_InspName, data.S_ID)
  153. inspection = InspectionTronconWincan()
  154. inspection.s_guid = data.S_ID[2:-1] if (data.S_ID[:2] == "b'" and data.S_ID[-1:] == "'") else data.S_ID
  155. inspection.si_guid = data.SI_ID[2:-1] if (data.SI_ID[:2] == "b'" and data.SI_ID[-1:] == "'") else data.SI_ID
  156. inspection.nom_chantier = data.SI_InspName
  157. inspection.lng_chantier_id = data.SI_Spare1
  158. inspection.byt_interv_id = data.SI_Spare2
  159. inspection.si_autonumber = data.SI_AutoNumber
  160. inspection.classement_troncons = data.SI_MediaNumber1
  161. inspection.nom_troncon = ("{0}-{1}" if data.S_SectionFlow == 2 else "{1}-{0}").format(data.S_StartNode, data.S_EndNode)
  162. inspection.startnode_type = get_lib(data.S_StartNodeType, "S_StartNodeType")
  163. inspection.endnode_type = get_lib(data.S_StartNodeType, "S_EndNodeType")
  164. inspection.sens_ecoul = ">>" if data.S_SectionFlow == '1' else ('<<' if data.S_SectionFlow == '2' else '')
  165. inspection.startnode_z = data.S_StartNodeCoord_Z
  166. inspection.endnode_z = data.S_EndNodeCoord_Z
  167. inspection.section_length = data.S_Sectionlength
  168. inspection.section_purpose = data.S_SectionPurpose
  169. inspection.section_use = data.S_SectionUse
  170. inspection.section_type = data.S_SectionType
  171. inspection.materiau = get_materiau(data.S_PipeMaterial)
  172. inspection.annee_pose = data.S_YearLayed
  173. inspection.diametre = get_lib(int(data.S_PipeDia), "S_PipeDia")
  174. inspection.route = get_lib(data.S_Situation, "S_Situation")
  175. inspection.n_route = data.S_Spare1
  176. inspection.pipe_shape = data.S_PipeShape
  177. inspection.pipe_length = data.S_Pipelength
  178. if data.S_Spare3:
  179. inspection.arbres = get_lib(data.S_Spare3, "S_Spare3")
  180. inspection.test_ecoulement = data.SI_Spare0
  181. inspection.si_date = data.SI_Date
  182. sql = """ SELECT SO_T.SO_ID, SO_T.SO_Rate, SO_T.SO_Photonumber1, SO_T.SO_Photonumber2
  183. FROM SO_T
  184. WHERE SO_T.SO_Inspecs_ID='{}'
  185. """.format(inspection.si_guid)
  186. # Parcours les opérations réalisées au cours de l'inspection du tronçon
  187. for opdata in wincan_db.read(sql):
  188. inspection.nb_ops += 1
  189. if opdata.SO_Rate == 1:
  190. inspection.rate_1 = inspection.rate_1 + 1 if inspection.rate_1 else inspection.rate_1 = 1
  191. elif opdata.SO_Rate == 2:
  192. inspection.rate_2 = inspection.rate_2 + 1 if inspection.rate_2 else inspection.rate_2 = 1
  193. elif opdata.SO_Rate == 3:
  194. inspection.rate_3 = inspection.rate_3 + 1 if inspection.rate_3 else inspection.rate_3 = 1
  195. elif opdata.SO_Rate == 4:
  196. inspection.rate_4 = inspection.rate_4 + 1 if inspection.rate_4 else inspection.rate_4 = 1
  197. elif opdata.SO_Rate == 5:
  198. inspection.rate_5 = inspection.rate_5 + 1 if inspection.rate_5 else inspection.rate_5 = 1
  199. elif not opdata.SO_Rate:
  200. pass
  201. elif opdata.SO_Rate >= 6:
  202. logger.error("Attention: une valeur de [SO_Rate] supérieure à 5 a été enregistrée (SO_ID: %s)", opdata.SO_ID)
  203. if opdata.SO_Photonumber1:
  204. inspection.nb_photos += 1
  205. if opdata.SO_Photonumber2:
  206. inspection.nb_photos += 1
  207. if not any([inspection.rate_1, inspection.rate_2, inspection.rate_3, inspection.rate_4, inspection.rate_5]):
  208. inspection.DG = 'ABS' # Absence de défauts
  209. elif not any([inspection.rate_1, inspection.rate_2, inspection.rate_3]):
  210. inspection.DG = 'ACC' # Défauts acceptables
  211. else:
  212. inspection.DG = 'INT' # Défauts non-acceptables
  213. logger.info("\t- Mise à jour de tblso_Rate_Analyse")
  214. sql = Sql.format("""INSERT INTO tblso_Rate_Analyse (
  215. lngChantierId, bytIntervId, SI_InspName, SI_AutoNumber,
  216. [Classement tronons], Nom_troncon, S_StartNodeType,
  217. Sens_ecoul, S_EndNodeType, S_PipeShape, MateriauCourt,
  218. SI_Date, nb_Arbres, ANNEE_POSE,
  219. Route, NRoute, Test_ecoulement, MaxDeS_StartNodeCoord_Z, MaxDeS_EndNodeCoord_Z,
  220. MaxDeS_Sectionlength, MaxDeS_Pipelength, MaxDeDiametre, cpt_Photos, [Total de SO_ID],
  221. 1, 2, 3, 4, 5, DG
  222. )
  223. VALUES ({inspection.lng_chantier_id}, {inspection.byt_interv_id}, {inspection.nom_chantier:text}, {inspection.si_autonumber},
  224. {inspection.classement_troncons:text}, {inspection.nom_troncon:text}, {inspection.startnode_type:text},
  225. {inspection.sens_ecoul:text}, {inspection.endnode_type:text}, {inspection.pipe_shape:text}, {inspection.materiau:text},
  226. {inspection.si_date:date}, {inspection.arbres:text}, {inspection.annee_pose},
  227. {inspection.route:text}, {inspection.n_route:text}, {inspection.test_ecoulement:text}, {inspection.startnode_z}, {inspection.endnode_z},
  228. {inspection.section_length}, {inspection.pipe_length}, {inspection.diametre:text}, {inspection.nb_photos}, {inspection.nb_ops},
  229. {inspection.rate_1}, {inspection.rate_2}, {inspection.rate_3}, {inspection.rate_4}, {inspection.rate_5}, {inspection.DG:text}
  230. )
  231. """, inspection=inspection)
  232. controles_db.execute(sql)
  233. # Met à jour tblvideointervs.strResGlobal avec le resultat global
  234. # 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
  235. # >> On peut peut-être rassembler cette partie et l'insertion dans cette table au debut?
  236. logger.info("\t- Mise à jour du resultat global dans tblVideoIntervs")
  237. sql = """UPDATE tblVideoIntervs
  238. SET strResGlobal='{}'
  239. WHERE lngChantierId= {} AND bytIntervId= {}
  240. """.format('-' if inspection.DG == 'INT' else '+',
  241. chantier_id,
  242. interv_id)
  243. controles_db.execute(sql)
  244. # Met à jour la table tblVideoBases pour marquer le chantier comme traité
  245. logger.info("\t- Mise à jour de tblVideoBases")
  246. sql = """UPDATE tblVideoBases
  247. SET blnWincan=True,bytNbInterv={}
  248. WHERE lngChantierId={}
  249. """.format(inspection.byt_interv_id,
  250. inspection.lng_chantier_id)
  251. controles_db.execute(sql)
  252. # Met à jour les données du réseau dans tblChantiers
  253. logger.info("\t- Mise à jour des données du réseau dans tblChantiers")
  254. sql = """UPDATE tblChantiers
  255. SET bytFoncReseauId ={} , bytNatureReseauId={}, bytTypeReseauId={}
  256. WHERE lngChantierId={}
  257. """.format(inspection.section_use,
  258. inspection.section_purpose,
  259. inspection.section_type,
  260. inspection.lng_chantier_id)
  261. controles_db.execute(sql)
  262. logger.info("Commit des modifications")
  263. controles_db.commit()
  264. wincan_db.commit()