qgis_sync_wincan.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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
  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. debug = False
  26. IMPORT_DEPUIS = 24 # Ne cherche des données à importer que sur les X derniers mois (mettre à 0 pour ignorer)
  27. # # POUR TESTER, décommenter les lignes suivantes
  28. ##-----------------------------------------------
  29. WincanDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\Wincan\parc_2007\DB\PARC_2007.mdb")
  30. debug = True
  31. logger.handlers = [h for h in logger.handlers if (type(h) == logging.StreamHandler)]
  32. logger.warning("<<<<<<<<<<<<<< Mode TEST >>>>>>>>>>>>>>>>>")
  33. ##-----------------------------------------------
  34. # Connexion à Wincan
  35. wincan_db = WincanDb(autocommit=False)
  36. # Regex pour parser les noms de repertoires
  37. rx = re.compile(r"^(I_)?(\d{5,6})(-S?\d{1,2})?[\s_]?(.*)$") # tous
  38. rxi = re.compile(r"^(\d{5,6})(-S?\d{1,2})?[\s_]?(.*)$") # non importés
  39. logger.info("Parcours des répertoires")
  40. a_importer = [subdir for subdir in ITV_DIR.dirs() if rxi.search(subdir.name)]
  41. if not a_importer:
  42. logger.info("Aucun nouveau dossier à importer")
  43. sys.exit()
  44. for chantier_dir in a_importer:
  45. # Ici, les noms de chantier sont de la forme 000000, 000000-0, ou 000000-S0
  46. dir_name = chantier_dir.name
  47. logger.info("Traitement du répertoire: {}".format(chantier_dir.name))
  48. # check the existence of the chantier in WincanDb, and check if the chantier has been treated in Controles (SI_Spare1 = 1)
  49. query = wincan_db.exec_(Sql.format("""SELECT SI_T.SI_AutoNumber
  50. FROM SI_T
  51. WHERE (((SI_T.SI_Spare1) is not null
  52. AND (SI_T.SI_JobNumber) Like {:text}))""", chantier_dir.name))
  53. if not query.first():
  54. logger.error("Le chantier n'existe pas dans wincan, ou SI_Spare1 est null")
  55. continue
  56. shp_path = chantier_dir / "{}_p_Regards.shp".format(chantier_dir.name)
  57. logger.debug("> Lecture du fichier shapefile")
  58. sf = shapefile.Reader(shp_path)
  59. # should we check? :
  60. if sf.shapeType != 1:
  61. logger.error("Le fichier shapefile n'est pas de type POINT")
  62. continue
  63. sh_points = sf.shapeRecords()
  64. if not sh_points:
  65. logger.error("Le fichier shapefile ne contient aucune donnees")
  66. continue
  67. # Génère des objets 'Points' à partir des données du shapefile
  68. points = []
  69. for sh_point in sh_points:
  70. point = QGisPoint()
  71. point.number = sh_point.record[0]
  72. point.name = sh_point.record[1]
  73. point.x, point.y = sh_point.shape.points[0]
  74. points.append(point)
  75. logger.info("> Contrôle des données")
  76. shp_regards_name = set([point.number for point in points])
  77. # Vérifie l'absence de duplicats
  78. if len(shp_regards_name) != len(points):
  79. logger.error("Shapefile - Doublons dans les noms de regards")
  80. continue
  81. # Vérifie l'existence des regards dans WincanDb
  82. wincan_regards_name = set([]) # Le set garantit l'unicité des items
  83. wincan_regards_name |= wincan_db.readall(Sql.format("""SELECT S_T.S_EndNode
  84. FROM S_T INNER JOIN SI_T ON S_T.S_ID = SI_T.SI_Section_ID
  85. WHERE (S_T.S_EndNode Not Like 'T%' And S_T.S_EndNode Not Like 'BP%'
  86. AND SI_T.SI_JobNumber Like {:text})""", chantier_dir.name))
  87. wincan_regards_name |= wincan_db.readall(Sql.format("""SELECT S_T.S_StartNode
  88. FROM S_T INNER JOIN SI_T ON S_T.S_ID = SI_T.SI_Section_ID
  89. WHERE (S_T.S_StartNode Not Like 'T%' And S_T.S_StartNode Not Like 'BP%'
  90. AND SI_T.SI_JobNumber Like {:text})""", chantier_dir.name))
  91. for regard_name in shp_regards_name - wincan_regards_name:
  92. logger.error("Regards manquant dans Wincan ({})".format(regard_name))
  93. for regard_name in wincan_regards_name - shp_regards_name:
  94. logger.error("Regards manquant dans le shapefile ({})".format(regard_name))
  95. if shp_regards_name != wincan_regards_name:
  96. continue
  97. # # Update the coordinates of the regards in WincanDb
  98. for point in points:
  99. q = wincan_db.execute(Sql.format("""UPDATE S_T INNER JOIN SI_T ON S_T.S_ID = SI_T.SI_Section_ID
  100. SET S_T.S_StartNodeCoord_X = {x}, S_T.S_StartNodeCoord_Y = {y}
  101. WHERE SI_T.SI_InspName Like {chantier:text} AND S_T.S_StartNode={num:text};
  102. """, chantier=chantier_dir.name + "%",
  103. num=point.number,
  104. x=point.x,
  105. y=point.y))
  106. q = wincan_db.execute(Sql.format("""UPDATE S_T INNER JOIN SI_T ON S_T.S_ID = SI_T.SI_Section_ID
  107. SET S_T.S_EndNodeCoord_X = {x}, S_T.S_EndNodeCoord_Y = {y}
  108. WHERE SI_T.SI_InspName Like {chantier:text} AND S_T.S_EndNode={num:text};
  109. """, chantier=chantier_dir.name + "%",
  110. num=point.number,
  111. x=point.x,
  112. y=point.y))
  113. wincan_db.commit()
  114. logger.info("> Mise à jour de la base Wincan")
  115. # rename the directory to mark it as imported ('I_')
  116. new_path = r"{}\I_{}".format(chantier_dir.parent, chantier_dir.name)
  117. logger.debug("> Renomme {} en {}".format(chantier_dir.name, new_path.name))
  118. if not debug:
  119. try:
  120. chantier_dir.rename(new_path)
  121. except:
  122. logger.error("Impossible de renommer le dossier")