qgis_sync_video.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. '''
  2. Créé les chantiers, tronçons et regards correspondant aux contrôles Vidéo.
  3. Les données des chantiers sont issues de la base Wincan
  4. Les lignes (issues de la requête csig_sync_video) sont traitées si:
  5. - SI_Spare3 est null
  6. - les coordonnées des regards ont été mises à jour (non null)
  7. Lorsqu'un chantier est correctement créé, la valeur SI_Spare3 est mise à jour à '1'
  8. @author: olivier.massot, mai 2018
  9. '''
  10. import logging
  11. import re
  12. import sys
  13. from path import Path
  14. from core import logconf
  15. from core.model import Sql
  16. from core.pde import WincanDb, QGisRegard, QGisChantier, QGisTroncon, \
  17. ControlesDb, CSigDb, SRID
  18. logger = logging.getLogger("qgis_sync_video")
  19. logconf.start("qgis_sync_video", logging.DEBUG)
  20. # # POUR TESTER, décommenter les lignes suivantes
  21. ##-----------------------------------------------
  22. # ControlesDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\cg67Parc_data.mdb")
  23. # WincanDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\Wincan\parc_2007\DB\PARC_2007.mdb")
  24. # CSigDb.server = "TR-POSTGIS-02"
  25. # CSigDb.pwd = "Am5VOMkdFHU7WwrfVOs9"
  26. # logger.handlers = [h for h in logger.handlers if (type(h) == logging.StreamHandler)]
  27. # logger.warning("<<<<<<<<<<<<<< Mode TEST >>>>>>>>>>>>>>>>>")
  28. ##-----------------------------------------------
  29. # Connexion à CSig
  30. csig_db = CSigDb(autocommit=False)
  31. # Connexion à Wincan
  32. wincan_db = WincanDb(autocommit=False)
  33. # Connexion à Controles
  34. controles_db = ControlesDb(autocommit=False)
  35. logger.info("Chargement des données")
  36. qessais = wincan_db.read(Sql.format("""SELECT S_AutoNumber, S_StartNode, S_EndNode, S_StartNodeCoord_X, S_StartNodeCoord_Y,
  37. S_EndNodeCoord_X, S_EndNodeCoord_Y, SI_AutoNumber, SI_InspName
  38. FROM csig_sync_video;"""))
  39. chantiers = {}
  40. for essai in qessais:
  41. chantier_name = "<inconnu>"
  42. r1, r2 = QGisRegard(), QGisRegard()
  43. r1.number = essai.S_StartNode
  44. r1.x = essai.S_StartNodeCoord_X
  45. r1.y = essai.S_StartNodeCoord_Y
  46. r2.number = essai.S_EndNode
  47. r2.x = essai.S_EndNodeCoord_X
  48. r2.y = essai.S_EndNodeCoord_Y
  49. if not essai.SI_AutoNumber:
  50. logger.error("%s - Le SI_Autonumber du troncon est manquant", essai.SI_InspName)
  51. continue
  52. # Parse le nom du chantier
  53. parsed = re.search(r"^(\d{5,6})(-S?\d{1,2})?[\s_]?(.*)$", essai.SI_InspName)
  54. if not parsed:
  55. logger.error("Nom de chantier illisible: '{}'".format(essai.SI_InspName))
  56. continue
  57. chantier_number = parsed.group(1)
  58. # Créé un nouveau chantier si pas encore créé
  59. try:
  60. chantier = chantiers[chantier_number]
  61. except KeyError:
  62. chantier = QGisChantier()
  63. chantier.name = essai.SI_InspName
  64. chantier.number = chantier_number
  65. chantiers[chantier_number] = chantier
  66. # Créé un nouveau tronçon
  67. troncon = QGisTroncon()
  68. troncon.r1 = r1
  69. troncon.r2 = r2
  70. troncon.si_autonumber = essai.SI_AutoNumber
  71. troncon.s_autonumber = essai.S_AutoNumber
  72. # Importe le résultat de l'essai Vidéo depuis contrôle
  73. row = controles_db.first(Sql.format("""SELECT DG FROM csig_itv_results
  74. WHERE SI_AutoNumber={si_autonumber}
  75. """, si_autonumber=essai.SI_AutoNumber))
  76. if row:
  77. troncon.res_itv = row.DG
  78. else:
  79. logger.error("Impossible de trouver le resultat ITV du tronçon {}-{} (%s)", r1.number, r2.number, essai.SI_InspName)
  80. # Importe le résultat de l'essai d'Etanchéité du tronçon depuis contrôle
  81. row = controles_db.first(Sql.format("""SELECT strResSigne FROM csig_etancheite_results
  82. WHERE (strTrcRegard='{r1}-{r2}' OR strTrcRegard='{r2}-{r1}')
  83. AND lngChantierId={lngChantierId}
  84. """, r1=r1.number, r2=r2.number, lngChantierId=chantier_number))
  85. if row:
  86. troncon.res_ce = row.strResSigne
  87. else:
  88. logger.error("Impossible de trouver le resultat Etanchéité du tronçon %s-%s (%s)", r1.number, r2.number, essai.SI_InspName)
  89. # Importe le résultat de l'essai d'Etanchéité des regards depuis contrôle
  90. for regard in (troncon.r1, troncon.r2):
  91. row = controles_db.first(Sql.format("""SELECT strResSigne FROM csig_etancheite_results
  92. WHERE strTrcRegard={regard:text} AND lngChantierId={lngChantierId}
  93. """, regard=regard.number, lngChantierId=chantier_number))
  94. if row:
  95. regard.res_ce = row.strResSigne
  96. else:
  97. logger.error("Impossible de trouver le resultat Etanchéité du regard %s (%s)", regard.number, essai.SI_InspName)
  98. chantier.items.append(troncon)
  99. if not chantiers:
  100. logger.info("Aucun nouveaux chantiers")
  101. sys.exit(0)
  102. logger.info("{} chantiers chargés en mémoire".format(len(chantiers)))
  103. # Pour la génération des etiquettes
  104. _labbelled = []
  105. def label_for(id_chantier, regard_number):
  106. """ Renvoie le contenu de l'etiquette pour le regard
  107. Un regard est etiquetté seulement si c'est le premier du chantier portant ce numéro """
  108. if not (id_chantier, regard_number) in _labbelled:
  109. _labbelled.append((id_chantier, regard_number))
  110. return regard_number
  111. else:
  112. return ""
  113. for chantier in chantiers.values():
  114. logger.info("** Création du chantier: {}".format(chantier.name))
  115. # Vérifie si le chantier existe déjà
  116. existants = csig_db.read_all(Sql.format("SELECT id FROM t_chantiers WHERE nom = {:text} AND id_type_chantier=1", chantier.name))
  117. cancel = False
  118. for row in existants:
  119. logger.info("Un chantier portant ce nom existe déjà dans ControlesSig {} (id {})".format(chantier.name, row.id))
  120. replace = input("Voulez-vous le remplacer? (o/n)")
  121. if replace:
  122. # Supprime l'ancien chantier
  123. csig_db.execute(Sql.format("""DELETE FROM t_troncons WHERE id_chantier = {}""", row.id))
  124. csig_db.execute(Sql.format("""DELETE FROM t_regards WHERE id_chantier = {}""", row.id))
  125. csig_db.execute(Sql.format("""DELETE FROM t_chantiers WHERE id = {}""", row.id))
  126. else:
  127. # pass the chantier, do not register any error
  128. logger.warning("Import du chantier annulé par l'utilisateur")
  129. cancel = True
  130. if cancel:
  131. continue
  132. # Calcule l'emprise du chantier
  133. regards = set([troncon.r1 for troncon in chantier.items]) | set([troncon.r2 for troncon in chantier.items])
  134. chantier.x0 = min([regard.x for regard in regards]) - 5
  135. chantier.x1 = max([regard.x for regard in regards]) + 5
  136. chantier.y0 = min([regard.y for regard in regards]) - 5
  137. chantier.y1 = max([regard.y for regard in regards]) + 5
  138. # Créé le chantier
  139. logger.info("> Création du chantier")
  140. row = csig_db.first(Sql.format("""INSERT INTO t_chantiers(id_type_chantier, numero, nom, archive, geom)
  141. VALUES ({chantier_type}, {number}, {name:text}, False,
  142. ST_GeomFromText('POLYGON(({x0} {y0}, {x0} {y1}, {x1} {y1}, {x1} {y0}, {x0} {y0}))', {srid}))
  143. RETURNING id
  144. """, chantier_type=1,
  145. number=chantier.number,
  146. name=chantier.name,
  147. x0=chantier.x0,
  148. x1=chantier.x1,
  149. y0=chantier.y0,
  150. y1=chantier.y1,
  151. srid=SRID
  152. )
  153. )
  154. # Récupère son id postgis
  155. chantier.pgid = row.id
  156. # Créé les regards, puis le tronçon
  157. for troncon in chantier.items:
  158. for regard in (troncon.r1, troncon.r2):
  159. logger.info("> Création du regard %s", regard.number)
  160. label = label_for(chantier.pgid, regard.number)
  161. row = csig_db.first(Sql.format("""INSERT INTO t_regards(nom, id_chantier, res_ce, s_autonumber, geom, label, archive)
  162. VALUES ({name:text}, {chantier_id}, {res_ce:text}, {s_autonumber}, ST_GeomFromText('POINT({x} {y})', {srid}), {label:text}, False)
  163. RETURNING id
  164. """, name=regard.number,
  165. chantier_id=chantier.pgid,
  166. res_ce=regard.res_ce,
  167. s_autonumber=troncon.s_autonumber,
  168. x=regard.x,
  169. y=regard.y,
  170. srid=SRID,
  171. label=label)
  172. )
  173. regard.pgid = row.id
  174. logger.debug("> Création du tronçon {}".format("{}-{}".format(troncon.r1.number, troncon.r2.number)))
  175. csig_db.first(Sql.format("""INSERT INTO t_troncons(nom, id_chantier, id_regard_depart, id_regard_fin, s_autonumber, si_autonumber, res_itv, res_ce, geom, archive)
  176. VALUES ({name:text}, {chantier_id}, {id_regard_depart}, {id_regard_fin}, {s_autonumber}, {si_autonumber}, {res_itv:text}, {res_ce:text},
  177. ST_GeomFromText('LINESTRING ({x1} {y1}, {x2} {y2})', {srid}), False)
  178. RETURNING id
  179. """, name="{}-{}".format(troncon.r1.number, troncon.r2.number),
  180. chantier_id=chantier.pgid,
  181. id_regard_depart=troncon.r1.pgid,
  182. id_regard_fin=troncon.r2.pgid,
  183. s_autonumber=troncon.s_autonumber,
  184. si_autonumber=troncon.si_autonumber,
  185. res_itv=troncon.res_itv,
  186. res_ce=troncon.res_ce,
  187. x1=troncon.r1.x,
  188. y1=troncon.r1.y,
  189. x2=troncon.r2.x,
  190. y2=troncon.r2.y,
  191. srid=SRID
  192. )
  193. )
  194. csig_db.commit()
  195. # update si_spare3 in Wincan to mark the chantier as imported
  196. logger.info("> Marque le chantier comme importé dans WincanDb")
  197. wincan_db.execute(Sql.format("UPDATE SI_T SET SI_T.SI_Spare3 = '1' \
  198. WHERE (((SI_T.SI_InspName) Like '{}%'));", chantier.number))
  199. wincan_db.commit()
  200. logger.info("Chantier créé")