qgis_sync_wincan.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. '''
  2. Met à jour les coordonnées des regards dans la base Wincan
  3. Les coordonnées sont issues des dossiers du répertoire 'itv_dir'
  4. Une fois traités, ces dossiers sont renommés 'XXXXXX' > 'I_XXXXXX'
  5. Plusieurs contrôles sont exécutés au cours de l'opération.
  6. Les erreurs suivantes sont bloquantes:
  7. - Le chantier correspondant n'existe pas dans Wincan
  8. - Le champ SI_Spare1 du tronçon analysé est NULL
  9. (ce qui signifie que la ligne n'a pas été traitée dans l'application Contrôles)
  10. - Regards présents dans le shapefile et pas dans Wincan
  11. - Regards présents dans Wincan et pas dans le shapefile
  12. - Regards en doublons dans le shapefile
  13. @author: olivier.massot, mai 2018
  14. '''
  15. import logging
  16. import re
  17. import sys
  18. from path import Path # @UnusedImport
  19. import shapefile
  20. from core import logconf
  21. from core.model import Sql
  22. from core.pde import WincanDb, ITV_DIR, QGisPoint
  23. logger = logging.getLogger("qgis_sync_wincan")
  24. logconf.start("qgis_sync_wincan", logging.DEBUG)
  25. IMPORT_DEPUIS = 24 # Ne cherche des données à importer que sur les X derniers mois (mettre à 0 pour ignorer)
  26. # # POUR TESTER, décommenter les lignes suivantes
  27. ##-----------------------------------------------
  28. # WincanDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\Wincan\parc_2007\DB\PARC_2007.mdb")
  29. # ITV_DIR = Path(__file__).parent / "resources" / "test_qgis_sync_wincan"
  30. # logger.handlers = [h for h in logger.handlers if (type(h) == logging.StreamHandler)]
  31. # logger.warning("<<<<<<<<<<<<<< Mode TEST >>>>>>>>>>>>>>>>>")
  32. ##-----------------------------------------------
  33. def main():
  34. # Connexion à Wincan
  35. wincan_db = WincanDb(autocommit=False)
  36. # Regex pour parser les noms de repertoires
  37. rxi = re.compile(r"^(\d{5,6})(-S?\d{1,2})?[\s_]?(.*)$") # non importés
  38. logger.info("Parcours des répertoires")
  39. a_importer = [subdir for subdir in ITV_DIR.dirs() if rxi.search(subdir.name)]
  40. if not a_importer:
  41. logger.info("Aucun nouveau dossier à importer")
  42. return
  43. for chantier_dir in a_importer:
  44. # Ici, les noms de chantier sont de la forme 000000, 000000-0, ou 000000-S0
  45. logger.info("# Traitement du répertoire: {}".format(chantier_dir.name))
  46. # check the existence of the chantier in WincanDb, and check if the chantier has been treated in Controles (SI_Spare1 = 1)
  47. if not wincan_db.exists(Sql.format("""SELECT SI_T.SI_AutoNumber
  48. FROM SI_T
  49. WHERE (((SI_T.SI_Spare1) is not null
  50. AND (SI_T.SI_JobNumber) Like {:text}))""", chantier_dir.name)):
  51. logger.error("Le chantier n'existe pas dans wincan, ou SI_Spare1 est null")
  52. continue
  53. shp_path = chantier_dir / "{}_p_Regards.shp".format(chantier_dir.name)
  54. logger.debug("> Lecture du fichier shapefile")
  55. sf = shapefile.Reader(shp_path)
  56. # should we check? :
  57. if sf.shapeType != 1:
  58. logger.error("Le fichier shapefile n'est pas de type POINT")
  59. continue
  60. sh_points = sf.shapeRecords()
  61. if not sh_points:
  62. logger.error("Le fichier shapefile ne contient aucune donnees")
  63. continue
  64. # Génère des objets 'Points' à partir des données du shapefile
  65. points = []
  66. for sh_point in sh_points:
  67. point = QGisPoint()
  68. point.number = sh_point.record[0]
  69. point.name = sh_point.record[1]
  70. point.x, point.y = sh_point.shape.points[0]
  71. points.append(point)
  72. del sf, sh_points
  73. logger.info("> Contrôle des données")
  74. shp_regards_name = set([point.number for point in points])
  75. # Vérifie l'absence de duplicats
  76. if len(shp_regards_name) != len(points):
  77. logger.error("Shapefile - Doublons dans les noms de regards")
  78. continue
  79. # Vérifie l'existence des regards dans WincanDb
  80. wincan_regards_name = set([]) # Le set garantit l'unicité des items
  81. wincan_regards_name |= {r.nom for r in wincan_db.read_all(Sql.format("""SELECT S_T.S_EndNode as nom
  82. FROM S_T INNER JOIN SI_T ON S_T.S_ID = SI_T.SI_Section_ID
  83. WHERE (S_T.S_EndNode Not Like 'T%' And S_T.S_EndNode Not Like 'BP%'
  84. AND SI_T.SI_JobNumber Like {:text})""", chantier_dir.name))}
  85. wincan_regards_name |= {r.nom for r in wincan_db.read_all(Sql.format("""SELECT S_T.S_StartNode as nom
  86. FROM S_T INNER JOIN SI_T ON S_T.S_ID = SI_T.SI_Section_ID
  87. WHERE (S_T.S_StartNode Not Like 'T%' And S_T.S_StartNode Not Like 'BP%'
  88. AND SI_T.SI_JobNumber Like {:text})""", chantier_dir.name))}
  89. for regard_name in shp_regards_name - wincan_regards_name:
  90. logger.error("Le regards suivant n'existe pas dans Wincan ({})".format(regard_name))
  91. for regard_name in wincan_regards_name - shp_regards_name:
  92. logger.error("Le regards suivant est absent du fichier shapefile ({})".format(regard_name))
  93. if shp_regards_name != wincan_regards_name:
  94. logger.info("Mise à jour annulée")
  95. continue
  96. # # Update the coordinates of the regards in WincanDb
  97. for point in points:
  98. wincan_db.execute(Sql.format("""UPDATE S_T INNER JOIN SI_T ON S_T.S_ID = SI_T.SI_Section_ID
  99. SET S_T.S_StartNodeCoord_X = {x}, S_T.S_StartNodeCoord_Y = {y}
  100. WHERE SI_T.SI_InspName Like {chantier:text} AND S_T.S_StartNode={num:text};
  101. """, chantier=chantier_dir.name + "%",
  102. num=point.number,
  103. x=point.x,
  104. y=point.y))
  105. wincan_db.execute(Sql.format("""UPDATE S_T INNER JOIN SI_T ON S_T.S_ID = SI_T.SI_Section_ID
  106. SET S_T.S_EndNodeCoord_X = {x}, S_T.S_EndNodeCoord_Y = {y}
  107. WHERE SI_T.SI_InspName Like {chantier:text} AND S_T.S_EndNode={num:text};
  108. """, chantier=chantier_dir.name + "%",
  109. num=point.number,
  110. x=point.x,
  111. y=point.y))
  112. wincan_db.commit()
  113. logger.info("> Mise à jour de la base Wincan")
  114. # rename the directory to mark it as imported ('I_')
  115. new_path = chantier_dir.parent / "I_{}".format(chantier_dir.name)
  116. logger.debug("> Renomme {} en {}".format(chantier_dir.name, new_path.name))
  117. try:
  118. chantier_dir.rename(new_path)
  119. except:
  120. logger.error("Impossible de renommer le dossier")
  121. if __name__ == "__main__":
  122. main()
  123. logger.info("-- Fin --")