qgis_sync_video.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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. from path import Path # @UnusedImport
  13. from core import logconf
  14. from core.model import Sql
  15. from core.pde import WincanDb, QGisRegard, QGisChantier, QGisTroncon, \
  16. ControlesDb, CSigDb, SRID
  17. import qgis_sync_wincan
  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. def main():
  30. # Connexion à CSig
  31. csig_db = CSigDb(autocommit=False)
  32. # Connexion à Wincan
  33. wincan_db = WincanDb(autocommit=False)
  34. # Connexion à Controles
  35. controles_db = ControlesDb(autocommit=False)
  36. logger.info("Chargement des données")
  37. qessais = wincan_db.read(Sql.format("""SELECT S_AutoNumber, S_StartNode, S_EndNode, S_StartNodeCoord_X, S_StartNodeCoord_Y,
  38. S_EndNodeCoord_X, S_EndNodeCoord_Y, SI_AutoNumber, SI_InspName
  39. FROM csig_sync_video;"""))
  40. chantiers = {}
  41. for essai in qessais:
  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. return
  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. logger.info("Le chantier existant a été supprimé")
  127. else:
  128. # pass the chantier, do not register any error
  129. logger.warning("Import du chantier annulé par l'utilisateur")
  130. cancel = True
  131. if cancel:
  132. continue
  133. # Calcule l'emprise du chantier
  134. regards = set([troncon.r1 for troncon in chantier.items]) | set([troncon.r2 for troncon in chantier.items])
  135. chantier.x0 = min([regard.x for regard in regards]) - 5
  136. chantier.x1 = max([regard.x for regard in regards]) + 5
  137. chantier.y0 = min([regard.y for regard in regards]) - 5
  138. chantier.y1 = max([regard.y for regard in regards]) + 5
  139. # Créé le chantier
  140. logger.info("> Création du chantier")
  141. row = csig_db.first(Sql.format("""INSERT INTO t_chantiers(id_type_chantier, numero, nom, archive, geom)
  142. VALUES ({chantier_type}, {number}, {name:text}, False,
  143. ST_GeomFromText('POLYGON(({x0} {y0}, {x0} {y1}, {x1} {y1}, {x1} {y0}, {x0} {y0}))', {srid}))
  144. RETURNING id
  145. """, chantier_type=1,
  146. number=chantier.number,
  147. name=chantier.name,
  148. x0=chantier.x0,
  149. x1=chantier.x1,
  150. y0=chantier.y0,
  151. y1=chantier.y1,
  152. srid=SRID
  153. )
  154. )
  155. # Récupère son id postgis
  156. chantier.pgid = row.id
  157. # Créé les regards, puis le tronçon
  158. for troncon in chantier.items:
  159. for regard in (troncon.r1, troncon.r2):
  160. logger.info("> Création du regard %s", regard.number)
  161. label = label_for(chantier.pgid, regard.number)
  162. row = csig_db.first(Sql.format("""INSERT INTO t_regards(nom, id_chantier, res_ce, s_autonumber, geom, label, archive)
  163. VALUES ({name:text}, {chantier_id}, {res_ce:text}, {s_autonumber}, ST_GeomFromText('POINT({x} {y})', {srid}), {label:text}, False)
  164. RETURNING id
  165. """, name=regard.number,
  166. chantier_id=chantier.pgid,
  167. res_ce=regard.res_ce,
  168. s_autonumber=troncon.s_autonumber,
  169. x=regard.x,
  170. y=regard.y,
  171. srid=SRID,
  172. label=label)
  173. )
  174. regard.pgid = row.id
  175. logger.debug("> Création du tronçon {}".format("{}-{}".format(troncon.r1.number, troncon.r2.number)))
  176. 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)
  177. VALUES ({name:text}, {chantier_id}, {id_regard_depart}, {id_regard_fin}, {s_autonumber}, {si_autonumber}, {res_itv:text}, {res_ce:text},
  178. ST_GeomFromText('LINESTRING ({x1} {y1}, {x2} {y2})', {srid}), False)
  179. RETURNING id
  180. """, name="{}-{}".format(troncon.r1.number, troncon.r2.number),
  181. chantier_id=chantier.pgid,
  182. id_regard_depart=troncon.r1.pgid,
  183. id_regard_fin=troncon.r2.pgid,
  184. s_autonumber=troncon.s_autonumber,
  185. si_autonumber=troncon.si_autonumber,
  186. res_itv=troncon.res_itv,
  187. res_ce=troncon.res_ce,
  188. x1=troncon.r1.x,
  189. y1=troncon.r1.y,
  190. x2=troncon.r2.x,
  191. y2=troncon.r2.y,
  192. srid=SRID
  193. )
  194. )
  195. csig_db.commit()
  196. # update si_spare3 in Wincan to mark the chantier as imported
  197. logger.info("> Marque le chantier comme importé dans WincanDb")
  198. wincan_db.execute(Sql.format("UPDATE SI_T SET SI_T.SI_Spare3 = '1' \
  199. WHERE (((SI_T.SI_InspName) Like '{}%'));", chantier.number))
  200. wincan_db.commit()
  201. logger.info("Chantier créé")
  202. if __name__ == "__main__":
  203. # lance la synchro compactage avant
  204. qgis_sync_wincan.main()
  205. main()
  206. logger.info("-- Fin --")