@@ -18,7 +18,7 @@ defmodule Mix.Tasks.Transport.ImportAOMs do
1818
1919 @ shortdoc "Refreshes the database table `aom` with the latest data"
2020 use Mix.Task
21- import Ecto . { Query }
21+ import Ecto.Query
2222 alias DB . { AOM , Commune , Region , Repo }
2323 require Logger
2424
@@ -27,12 +27,12 @@ defmodule Mix.Tasks.Transport.ImportAOMs do
2727 # download the Cerema file (.ods)
2828 # rename columns that are on two lines
2929 # export as CSV and publish as community resource
30- @ aom_file "https://static .data.gouv.fr/resources/liste-et-composition-des-autorites-organisatrices-de-la-mobilite-aom/20241108-105224/liste-aoms-2024.csv "
30+ @ aom_file "https://www .data.gouv.fr/api/1/datasets/r/2e89a90a-6ca5-445b-b6c2-6f49cdeb8a2d "
3131 # Same for composition of each AOM, but no need even to rename columns
32- @ aom_insee_file "https://static .data.gouv.fr/resources/liste-et-composition-des-autorites-organisatrices-de-la-mobilite-aom/20241122-154942/composition-communale-aom-2024.csv "
32+ @ aom_insee_file "https://www .data.gouv.fr/api/1/datasets/r/5195d58d-572e-4f13-8477-bbb11da42b93 "
3333
3434 # We don’t add collectivité d’outremer de Saint-Martin
35- @ ignored_aom_ids [ "312 " ]
35+ @ ignored_aom_sirens [ "219711272 " ]
3636
3737 @ spec to_int ( binary ( ) ) :: number ( ) | nil
3838 def to_int ( "" ) , do: nil
@@ -58,13 +58,12 @@ defmodule Mix.Tasks.Transport.ImportAOMs do
5858 Logger . info ( "aom #{ nom } || previous region #{ aom . region . nom } --- #{ new_region . nom } " )
5959 end
6060
61- external_id = to_int ( line [ "Id réseau" ] )
61+ siren = line [ "N° SIREN" ] |> String . trim ( )
6262
63- { external_id ,
63+ { siren ,
6464 Ecto.Changeset . change ( aom , % {
65- composition_res_id: external_id ,
6665 departement: extract_departement_insee ( line [ "Département" ] ) ,
67- siren: line [ "N° SIREN" ] |> String . trim ( ) ,
66+ siren: siren ,
6867 nom: nom ,
6968 forme_juridique: normalize_forme ( line [ "Forme juridique" ] ) ,
7069 # This is inconsistent with the real number of communes for some lines
@@ -91,6 +90,7 @@ defmodule Mix.Tasks.Transport.ImportAOMs do
9190 defp normalize_forme ( "CC" ) , do: "Communauté de communes"
9291 defp normalize_forme ( "METRO" ) , do: "Métropole"
9392 defp normalize_forme ( "PETR" ) , do: "Pôle d'équilibre territorial et rural"
93+ defp normalize_forme ( "POLEM" ) , do: "Pôle Métropolitain"
9494 defp normalize_forme ( f ) , do: f
9595
9696 @ spec normalize_nom ( binary ( ) ) :: binary ( )
@@ -109,11 +109,11 @@ defmodule Mix.Tasks.Transport.ImportAOMs do
109109 old_aoms =
110110 AOM
111111 |> Repo . all ( )
112- |> Map . new ( fn aom -> { aom . composition_res_id , aom } end )
112+ |> Map . new ( fn aom -> { aom . siren , aom } end )
113113
114114 # get all the aom to import, outside of the transaction to reduce the time in the transaction
115115 # this already builds the changeset
116- # Mapset of {composition_res_id , changeset}
116+ # Mapset of {aom_siren , changeset}
117117 aoms_to_add = get_aom_to_import ( ) |> Enum . map ( & changeset / 1 ) |> MapSet . new ( )
118118
119119 display_changes ( old_aoms , aoms_to_add )
@@ -131,7 +131,7 @@ defmodule Mix.Tasks.Transport.ImportAOMs do
131131 import_insee_aom ( )
132132 enable_trigger ( )
133133 end ,
134- timeout: 1_000_000
134+ timeout: :infinity
135135 )
136136
137137 # we can then compute the aom geometries (the union of each cities geometries)
@@ -153,12 +153,12 @@ defmodule Mix.Tasks.Transport.ImportAOMs do
153153 |> IO . binstream ( :line )
154154 |> CSV . decode ( separator: ?, , headers: true , validate_row_length: true )
155155 |> Enum . map ( fn { :ok , line } -> line end )
156- |> Enum . reject ( fn line -> line [ "Id réseau " ] in ( [ "" , nil ] ++ @ ignored_aom_ids ) end )
156+ |> Enum . reject ( fn line -> line [ "N° SIREN " ] in ( [ "" , nil ] ++ @ ignored_aom_sirens ) end )
157157 end
158158
159159 defp existing_or_new_aom ( line ) do
160160 AOM
161- |> Repo . get_by ( composition_res_id: to_int ( line [ "Id réseau" ] ) )
161+ |> Repo . get_by ( nom: normalize_nom ( String . trim ( line [ "Nom" ] ) ) )
162162 |> case do
163163 nil ->
164164 % AOM { }
@@ -176,14 +176,14 @@ defmodule Mix.Tasks.Transport.ImportAOMs do
176176 defp delete_old_aoms ( aom_added , old_aoms ) do
177177 Logger . info ( "deleting removed aom" )
178178
179- composition_res_id_added =
179+ ids_added =
180180 aom_added
181181 |> Enum . map ( fn { id , _changeset } -> id end )
182182 |> MapSet . new ( )
183183
184184 old_aoms
185- |> Enum . each ( fn { composition_res_id , old_aom } ->
186- unless MapSet . member? ( composition_res_id_added , composition_res_id ) do
185+ |> Enum . each ( fn { aom_siren , old_aom } ->
186+ unless MapSet . member? ( ids_added , aom_siren ) do
187187 Logger . info ( "trying to delete old aom: #{ old_aom . id } - #{ old_aom . nom } " )
188188
189189 # Note: if the delete is impossible, you need to find what still depend on this aom,
@@ -194,7 +194,7 @@ defmodule Mix.Tasks.Transport.ImportAOMs do
194194 end
195195
196196 defp import_insee_aom do
197- Logger . info ( "Linking aoms to cities" )
197+ Logger . info ( "Linking AOMs to cities" )
198198
199199 { :ok , % HTTPoison.Response { status_code: 200 , body: body } } =
200200 HTTPoison . get ( @ aom_insee_file , [ ] , hackney: [ follow_redirect: true ] )
@@ -204,15 +204,15 @@ defmodule Mix.Tasks.Transport.ImportAOMs do
204204 stream
205205 |> IO . binstream ( :line )
206206 |> CSV . decode ( separator: ?, , headers: true , validate_row_length: true )
207- |> Enum . map ( fn { :ok , line } -> { line [ "N° INSEE" ] , line [ "Id réseau " ] } end )
208- |> Enum . reject ( fn { _insee , id_reseau } -> id_reseau == "" || id_reseau == "-" end )
209- |> Enum . flat_map ( fn { insee , id_reseau } ->
207+ |> Enum . map ( fn { :ok , line } -> { line [ "N° INSEE" ] , line [ "N° SIREN AOM " ] } end )
208+ |> Enum . reject ( fn { _insee , siren_reseau } -> siren_reseau == "" || siren_reseau == "-" end )
209+ |> Enum . flat_map ( fn { insee , siren_reseau } ->
210210 # To reduce the number of UPDATE in the DB, we first check which city needs to be updated
211211 Commune
212- |> where ( [ c ] , c . insee == ^ insee and ( c . aom_res_id != ^ id_reseau or is_nil ( c . aom_res_id ) ) )
212+ |> where ( [ c ] , c . insee == ^ insee and ( c . aom_siren != ^ siren_reseau or is_nil ( c . aom_siren ) ) )
213213 |> select ( [ c ] , c . id )
214214 |> Repo . all ( )
215- |> Enum . map ( fn c -> { c , id_reseau } end )
215+ |> Enum . map ( fn c -> { c , siren_reseau } end )
216216 end )
217217 |> Enum . reduce ( % { } , fn { commune , aom } , commune_by_aom ->
218218 # Then we group those city by AO, to only do one UPDATE query for several cities
@@ -222,7 +222,7 @@ defmodule Mix.Tasks.Transport.ImportAOMs do
222222 |> Enum . map ( fn { aom , list_communes } ->
223223 Commune
224224 |> where ( [ c ] , c . id in ^ list_communes )
225- |> Repo . update_all ( set: [ aom_res_id : aom ] )
225+ |> Repo . update_all ( set: [ aom_siren : aom ] )
226226 end )
227227 end
228228
@@ -240,16 +240,16 @@ defmodule Mix.Tasks.Transport.ImportAOMs do
240240 SELECT
241241 ST_UNION(commune.geom)
242242 FROM commune
243- WHERE commune.aom_res_id = ?
243+ WHERE commune.aom_siren = ?
244244 )
245245 """ ,
246- a . composition_res_id
246+ a . siren
247247 )
248248 ]
249249 ]
250250 ) ,
251251 [ ] ,
252- timeout: 1_000_000
252+ timeout: :infinity
253253 )
254254 end
255255
@@ -258,54 +258,38 @@ defmodule Mix.Tasks.Transport.ImportAOMs do
258258
259259 max_for_each_aom =
260260 from ( c in DB.Commune ,
261- where: not is_nil ( c . aom_res_id ) ,
262- group_by: c . aom_res_id ,
263- select: % { aom_res_id : c . aom_res_id , max_population: max ( c . population ) }
261+ where: not is_nil ( c . aom_siren ) ,
262+ group_by: c . aom_siren ,
263+ select: % { aom_siren : c . aom_siren , max_population: max ( c . population ) }
264264 )
265265
266266 main_communes =
267267 from ( c in DB.Commune ,
268- where: not is_nil ( c . aom_res_id ) ,
268+ where: not is_nil ( c . aom_siren ) ,
269269 join: max_for_each_aom in subquery ( max_for_each_aom ) ,
270- on: c . aom_res_id == max_for_each_aom . aom_res_id and c . population == max_for_each_aom . max_population ,
271- select: [ c . aom_res_id , c . insee ]
270+ on: c . aom_siren == max_for_each_aom . aom_siren and c . population == max_for_each_aom . max_population ,
271+ select: [ c . aom_siren , c . insee ]
272272 )
273273
274274 main_communes =
275275 main_communes
276276 |> DB.Repo . all ( )
277- |> MapSet . new ( fn [ aom_res_id , insee ] -> { aom_res_id , insee } end )
277+ |> MapSet . new ( fn [ aom_siren , insee ] -> { aom_siren , insee } end )
278278
279279 { :ok , _ } =
280280 Repo . transaction (
281281 fn ->
282- disable_trigger ( )
283-
284282 main_communes
285- |> Enum . each ( fn { aom_res_id , insee } ->
283+ |> Enum . each ( fn { aom_siren , insee } ->
286284 AOM
287- |> Repo . get_by! ( composition_res_id: aom_res_id )
288- |> Ecto.Changeset . change ( % { insee_commune_principale: insee } )
289- |> Repo . update ( )
285+ |> where ( [ a ] , a . siren == ^ aom_siren )
286+ |> Repo . update_all ( set: [ insee_commune_principale: insee ] )
290287 end )
291-
292- enable_trigger ( )
293288 end ,
294- timeout: 1_000_000
289+ timeout: :infinity
295290 )
296291 end
297292
298- defp disable_trigger do
299- Repo . query! ( "ALTER TABLE aom DISABLE TRIGGER refresh_places_aom_trigger;" )
300- Repo . query! ( "ALTER TABLE commune DISABLE TRIGGER refresh_places_commune_trigger;" )
301- end
302-
303- defp enable_trigger do
304- Repo . query! ( "ALTER TABLE aom ENABLE TRIGGER refresh_places_aom_trigger;" )
305- Repo . query! ( "ALTER TABLE commune ENABLE TRIGGER refresh_places_commune_trigger;" )
306- Repo . query! ( "REFRESH MATERIALIZED VIEW places;" )
307- end
308-
309293 defp migrate_datasets_to_new_aoms do
310294 queries = """
311295 -- This could be mostly automatized, you just have to look for a commune of the old AOM and see where it was migrated.
@@ -336,47 +320,71 @@ defmodule Mix.Tasks.Transport.ImportAOMs do
336320 --
337321 -- 2024
338322 -- Migrates a dataset to Pôle Métropolitain Mobilités Le Mans – Sarthe
339- update dataset_aom_legal_owner set aom_id = (select id from aom where composition_res_id = 1293) where aom_id IN (1283, 1285, 1288, 1292, 1294);
323+ -- update dataset_aom_legal_owner set aom_id = (select id from aom where composition_res_id = 1293) where aom_id IN (1283, 1285, 1288, 1292, 1294);
324+ -- 2025
325+ -- Datasets still associated with deleted AOM as territory
326+ -- %{
327+ -- 26 => [[26, "256900994", 1217], [26, "256900994", 871], [26, "256900994", 1216], [26, "256900994", 1259], [26, "256900994", 1139], [26, "256900994", 755], [26, "256900994", 695], [26, "256900994", 318]],
328+ -- 66 => [[66, "200011773", 1179], [66, "200011773", 164]],
329+ -- 168 => [[168, "246700967", 531]],
330+ -- 263 => [[263, "200016632", 940]],
331+ -- 1047 => [[1047, "243800984", 742]],
332+ -- 1301 => [[1301, "200070464", 1123]]
333+ -- }
334+ update dataset set aom_id = (select id from aom where siren = '200096386') where aom_id = 26;
335+ update dataset set aom_id = (select id from aom where siren = '200075372') where aom_id = 66;
336+ update dataset set aom_id = (select id from aom where siren = '200069680') where aom_id = 168;
337+ update dataset set aom_id = (select id from aom where nom = 'Région Auvergne-Rhône-Alpes (CC du Bassin d''Aubenas)') where aom_id = 263;
338+ update dataset set aom_id = (select id from aom where siren = '253800825') where aom_id = 1047;
339+ update dataset set aom_id = (select id from aom where nom = 'Région Auvergne-Rhône-Alpes (CC Coeur de Maurienne Arvan)') where aom_id = 1301;
340340 """
341341
342342 queries |> String . split ( ";" ) |> Enum . each ( & Repo . query! / 1 )
343343 end
344344
345+ defp disable_trigger do
346+ DB.Repo . query! ( "ALTER TABLE aom DISABLE TRIGGER aom_update_trigger;" )
347+ end
348+
349+ defp enable_trigger do
350+ DB.Repo . query! ( "ALTER TABLE aom ENABLE TRIGGER aom_update_trigger;" )
351+ end
352+
345353 defp display_changes ( old_aoms , aoms_to_add ) do
346354 mapset_first_elem_diff = fn a , b ->
347355 a |> MapSet . new ( & elem ( & 1 , 0 ) ) |> MapSet . difference ( b |> MapSet . new ( & elem ( & 1 , 0 ) ) )
348356 end
349357
350358 new_aoms = mapset_first_elem_diff . ( aoms_to_add , old_aoms )
351359 removed_aoms = mapset_first_elem_diff . ( old_aoms , aoms_to_add )
352- Logger . info ( "#{ new_aoms |> Enum . count ( ) } new AOMs. reseau_id codes : #{ Enum . join ( new_aoms , ", " ) } " )
353- Logger . info ( "#{ removed_aoms |> Enum . count ( ) } removed AOMs. reseau_id codes : #{ Enum . join ( removed_aoms , ", " ) } " )
360+ Logger . info ( "#{ new_aoms |> Enum . count ( ) } new AOMs. SIRENs : #{ Enum . join ( new_aoms , ", " ) } " )
361+ Logger . info ( "#{ removed_aoms |> Enum . count ( ) } removed AOMs. SIRENs : #{ Enum . join ( removed_aoms , ", " ) } " )
354362
355363 # Some Ecto fun: two ways of joining through assoc, see https://hexdocs.pm/ecto/associations.html
356364 deleted_aom_datasets =
357365 DB.Dataset
358366 |> join ( :left , [ d ] , aom in assoc ( d , :aom ) )
359- |> where ( [ d , aom ] , aom . composition_res_id in ^ ( removed_aoms |> MapSet . to_list ( ) ) )
360- |> select ( [ d , aom ] , [ aom . id , aom . composition_res_id , d . id ] )
367+ |> where ( [ d , aom ] , aom . siren in ^ ( removed_aoms |> MapSet . to_list ( ) ) )
368+ |> select ( [ d , aom ] , [ aom . id , aom . siren , d . id ] )
361369 |> DB.Repo . all ( )
362370 |> Enum . group_by ( & hd ( & 1 ) )
363371
364372 Logger . info (
365- "Datasets still associated with deleted AOM as territory (aom.id => [aom.id, aom.composition_res_id , dataset.id]) : #{ inspect ( deleted_aom_datasets ) } "
373+ "Datasets still associated with deleted AOM as territory (aom.id => [aom.id, aom.siren , dataset.id]) : #{ inspect ( deleted_aom_datasets ) } "
366374 )
367375
368376 deleted_legal_owners_query =
369377 from ( d in DB.Dataset ,
370378 # This magically works with the many_to_many
371379 join: aom in assoc ( d , :legal_owners_aom ) ,
372- where: aom . composition_res_id in ^ ( removed_aoms |> MapSet . to_list ( ) ) ,
373- select: [ aom . id , aom . composition_res_id , d . id ]
380+ where: aom . siren in ^ ( removed_aoms |> MapSet . to_list ( ) ) ,
381+ select: [ aom . id , aom . siren , d . id ]
374382 )
375383
376384 deleted_legal_owners = deleted_legal_owners_query |> DB.Repo . all ( ) |> Enum . group_by ( & hd ( & 1 ) )
377385
378386 Logger . info (
379- "Datasets still associated with deleted AOM as legal owner (aom.id => [aom.id, aom.composition_res_id , dataset.id]): #{ inspect ( deleted_legal_owners ) } "
387+ "Datasets still associated with deleted AOM as legal owner (aom.id => [aom.id, aom.siren , dataset.id]): #{ inspect ( deleted_legal_owners ) } "
380388 )
381389 end
382390end
0 commit comments