qgis_sync_video.py 12 KB

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