333 lines
17 KiB
Python
333 lines
17 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: UTF-8 -*-.
|
|
|
|
from sqlalchemy import create_engine, text
|
|
from sqlalchemy.engine import URL
|
|
from datetime import datetime as dt
|
|
import pandas as pd
|
|
import geopandas as gpd
|
|
|
|
nom_numerateur = 'GEIER'
|
|
pnom_numerator = 'Colas'
|
|
today = dt.now().date().isoformat()
|
|
# Parametres bdd
|
|
user = 'cen_admin'
|
|
pwd = '#CEN38@venir'
|
|
adr = '91.134.194.221'
|
|
port = '5432'
|
|
base = 'sicen2'
|
|
|
|
url = URL.create('postgresql+psycopg2',
|
|
username=user,
|
|
password=pwd,
|
|
host=adr,
|
|
database=base,
|
|
)
|
|
con = create_engine(url)
|
|
|
|
nom_numerateur = nom_numerateur.upper()
|
|
pnom_numerator = pnom_numerator[0].upper() + pnom_numerator[1:]
|
|
query_get_numerator = """
|
|
SELECT * FROM md.personne
|
|
WHERE nom = '%s'
|
|
AND prenom = '%s'
|
|
AND id_structure = 1
|
|
""" % (nom_numerateur,pnom_numerator)
|
|
numerateur = pd.read_sql_query(
|
|
sql = query_get_numerator,
|
|
con = con
|
|
)
|
|
|
|
|
|
select_import = """
|
|
SELECT * FROM import.import_data_cen38;
|
|
"""
|
|
data_import = pd.read_sql_query(
|
|
sql = select_import,
|
|
con = con)
|
|
|
|
|
|
check_datageom = """
|
|
DROP VIEW IF EXISTS import.test_geom_prestation;
|
|
CREATE OR REPLACE VIEW import.test_geom_prestation as (
|
|
SELECT ROW_NUMBER() OVER (ORDER BY date_obs ASC) AS gid, localisation,
|
|
CASE WHEN latitude::numeric > 6000000
|
|
THEN ST_GeomFromText('POINT('||longitude::double precision||' '||latitude::double precision||')',2154) -- coordonnées en lambert93
|
|
WHEN latitude::numeric > 50 AND latitude::numeric < 3000000
|
|
THEN ST_transform(ST_GeomFromText('POINT('||longitude::double precision||' '||latitude::double precision||')',27572),2154) -- coordonnées en Lambert II étendu
|
|
--WHEN latitude is null THEN st_pointonsurface(b.geom) -- pas de coordonnées XY on récupère la geom du centroide du site CenRA si elle existe et si une partie du nom du site est renseignée dans la colonne LOCALISATION
|
|
ELSE ST_transform(ST_GeomFromText('POINT('||longitude::double precision||' '||latitude::double precision||')',4326),2154) -- coordonnées en WGS84
|
|
END as geometrie
|
|
FROM import.import_data_cen38
|
|
--LEFT JOIN import.sites_serena_cren_mu_2015 b ON lower(b.nom_site) like '%'||lower(trim(localisation,'s'))||'%' -- on joint la table des sites CenRA pour récupérer éventuellement le centroide d'un site si pas de XY
|
|
WHERE cd_nom is not null and (date_obs is not null or date_debut_obs is not null)) ; -- pour ignorer les lignes vides qui traineraient dans le csv
|
|
SELECT * FROM import.test_geom_prestation;
|
|
"""
|
|
df_check_datageom = gpd.read_postgis(
|
|
sql = text(check_datageom),
|
|
con = con,
|
|
geom_col='geometrie')
|
|
if df_check_datageom.geometry.is_valid.all() \
|
|
and df_check_datageom.crs.srs == 'epsg:2154':
|
|
drop_datageom = """DROP VIEW IF EXISTS import.test_geom_prestation;"""
|
|
with con.begin() as cnx:
|
|
cnx.execute(drop_datageom)
|
|
|
|
|
|
create_table_pers = """
|
|
DROP TABLE IF EXISTS md.temp_import_personne;
|
|
CREATE TABLE md.temp_import_personne AS
|
|
|
|
WITH personnel AS (
|
|
SELECT a.id_personne,a.nom,a.prenom,b.id_structure,b.nom_structure
|
|
FROM md.personne a
|
|
JOIN md.structure b USING (id_structure)
|
|
)
|
|
SELECT DISTINCT
|
|
-- personne
|
|
CASE WHEN observateur2 is null THEN (c.nom||' '||c.prenom)::text
|
|
WHEN observateur2 is not null AND observateur3 is null THEN (c.nom||' '||c.prenom)||'&'||(d.nom||' '||d.prenom)
|
|
WHEN observateur3 is not null AND observateur4 is null THEN (c.nom||' '||c.prenom)||'&'||(d.nom||' '||d.prenom)||'&'||(e.nom||' '||e.prenom)
|
|
WHEN observateur4 is not null AND observateur5 is null THEN (c.nom||' '||c.prenom)||'&'||(d.nom||' '||d.prenom)||'&'||(e.nom||' '||e.prenom)||'&'||(f.nom||' '||f.prenom)
|
|
|
|
ELSE c.nom_structure||'&'||d.nom_structure||'&'||(e.nom||' '||e.prenom)||'&'||(f.nom||' '||f.prenom)||'&'||(g.nom||' '||g.prenom)
|
|
END AS personne,
|
|
|
|
-- nom_structure
|
|
CASE WHEN observateur2 is null THEN c.nom_structure::text
|
|
WHEN observateur2 is not null AND observateur3 is null AND c.nom_structure <> d.nom_structure
|
|
THEN c.nom_structure||'&'||d.nom_structure
|
|
WHEN observateur2 is not null AND observateur3 is null AND c.nom_structure = d.nom_structure
|
|
THEN c.nom_structure
|
|
|
|
WHEN observateur3 is not null AND observateur4 is null AND c.nom_structure <> d.nom_structure AND d.nom_structure <> e.nom_structure
|
|
AND c.nom_structure <> e.nom_structure
|
|
THEN c.nom_structure||'&'||d.nom_structure||'&'||e.nom_structure
|
|
WHEN observateur3 is not null AND observateur4 is null AND c.nom_structure = d.nom_structure AND d.nom_structure <> e.nom_structure
|
|
THEN c.nom_structure||'&'||e.nom_structure
|
|
WHEN observateur3 is not null AND observateur4 is null AND c.nom_structure <> d.nom_structure AND d.nom_structure = e.nom_structure
|
|
THEN c.nom_structure||'&'||d.nom_structure
|
|
|
|
WHEN observateur4 is not null AND observateur5 is null AND c.nom_structure <> d.nom_structure
|
|
THEN c.nom_structure||'&'||d.nom_structure||'&'||e.nom_structure||'&'||f.nom_structure
|
|
|
|
ELSE c.nom_structure||'&'||d.nom_structure||'&'||e.nom_structure||'&'||f.nom_structure||'&'||g.nom_structure
|
|
END AS nom_structure,
|
|
|
|
-- observateur
|
|
CASE WHEN observateur2 is null THEN c.id_personne::text
|
|
WHEN observateur2 is not null AND observateur3 is null THEN c.id_personne||'&'||d.id_personne
|
|
WHEN observateur3 is not null AND observateur4 is null THEN c.id_personne||'&'||d.id_personne||'&'||e.id_personne
|
|
WHEN observateur4 is not null AND observateur5 is null THEN c.id_personne||'&'||d.id_personne||'&'||e.id_personne||'&'||f.id_personne
|
|
|
|
ELSE c.id_personne||'&'||d.id_personne||'&'||e.id_personne||'&'||f.id_personne||'&'||g.id_personne
|
|
END AS observateur,
|
|
structure
|
|
FROM import.import_data_cen38 a
|
|
LEFT JOIN personnel c ON (c.nom||' '||c.prenom) = trim(a.observateur1::text) AND lower(c.nom_structure) = lower(a.structure)
|
|
LEFT JOIN personnel d ON (d.nom||' '||d.prenom) = trim(a.observateur2::text) AND lower(d.nom_structure) = lower(a.structure)
|
|
LEFT JOIN personnel e ON (e.nom||' '||e.prenom) = trim(a.observateur3::text) AND lower(e.nom_structure) = lower(a.structure)
|
|
LEFT JOIN personnel f ON (f.nom||' '||f.prenom) = trim(a.observateur4::text) AND lower(f.nom_structure) = lower(a.structure)
|
|
LEFT JOIN personnel g ON (g.nom||' '||g.prenom) = trim(a.observateur5::text) AND lower(g.nom_structure) = lower(a.structure)
|
|
;
|
|
""".format(id_creator = numerateur.id_personne.item())
|
|
with con.begin() as cnx:
|
|
cnx.execute(create_table_pers)
|
|
|
|
select_pers = 'SELECT * FROM md.temp_import_personne'
|
|
df_pers = pd.read_sql_query(
|
|
sql = select_pers,
|
|
con = con)
|
|
|
|
|
|
|
|
|
|
with_dataTOinsert = """
|
|
WITH personnel AS (
|
|
SELECT a.id_personne,a.nom,a.prenom,b.id_structure,b.nom_structure
|
|
FROM md.personne a
|
|
JOIN md.structure b USING (id_structure)
|
|
),
|
|
t as (
|
|
SELECT
|
|
CASE WHEN a.heure IS NULL THEN '00:00:00'
|
|
ELSE a.heure END heure,
|
|
a.date_obs, a.date_debut_obs, a.date_fin_obs, a.duree as date_textuelle,
|
|
CASE WHEN b.regne IS NULL THEN bb.regne
|
|
ELSE b.regne END regne,
|
|
CASE WHEN b.phylum IS NULL THEN bb.phylum
|
|
ELSE b.phylum END phylum,
|
|
CASE WHEN b.classe IS NULL THEN bb.classe
|
|
ELSE b.classe END classe,
|
|
CASE WHEN b.ordre IS NULL THEN bb.ordre
|
|
ELSE b.ordre END ordre,
|
|
CASE WHEN b.famille IS NULL THEN bb.famille
|
|
ELSE b.famille END famille,
|
|
CASE WHEN b.nom_valide IS NULL THEN bb.nom_valide
|
|
ELSE b.nom_valide END nom_valide,
|
|
CASE WHEN b.nom_vern IS NULL THEN bb.nom_vern
|
|
ELSE b.nom_vern END nom_vern,
|
|
CASE WHEN b.nom_complet IS NULL THEN bb.nom_complet
|
|
ELSE b.nom_complet END nom_complet,
|
|
CASE WHEN b.cd_nom IS NULL THEN bb.cd_nom::text
|
|
ELSE b.cd_nom END cd_nom,
|
|
a.abondance_dominance as effectif_textuel, a.effectif_min, a.effectif_max,
|
|
CASE WHEN strate::text is not null THEN strate::text
|
|
ELSE age::text END AS type_effectif,
|
|
CASE WHEN phenologie is not null THEN phenologie
|
|
ELSE sexe END AS phenologie,
|
|
|
|
CASE WHEN latitude::numeric > 6000000
|
|
THEN ST_X(st_transform(ST_GeomFromText('POINT('||longitude::double precision||' '||latitude::double precision||')',2154),4326)) -- coordonnée X en lambert93
|
|
WHEN latitude::numeric > 50 AND latitude::numeric < 3000000
|
|
THEN ST_X(st_transform(ST_GeomFromText('POINT('||longitude::double precision||' '||latitude::double precision||')',27572),4326)) -- coordonnées en Lambert II étendu
|
|
-- WHEN latitude is null
|
|
-- THEN ST_X(st_transform(st_pointonsurface(i.geom),4326)) -- pas de coordonnées XY on récupère la geom du centroide du site CenRA si elle existe et si une partie du nom du site est renseignée dans la colonne LOCALISATION
|
|
ELSE longitude::double precision -- coordonnées en WGS84
|
|
END as longitude,
|
|
|
|
CASE WHEN latitude::numeric > 6000000
|
|
THEN ST_Y(st_transform(ST_GeomFromText('POINT('||longitude::double precision||' '||latitude::double precision||')',2154),4326)) -- coordonnée X en lambert93
|
|
WHEN latitude::numeric > 50 AND latitude::numeric < 3000000
|
|
THEN ST_Y(st_transform(ST_GeomFromText('POINT('||longitude::double precision||' '||latitude::double precision||')',27572),4326)) -- coordonnées en Lambert II étendu
|
|
-- WHEN latitude is null
|
|
-- THEN ST_Y(st_transform(st_pointonsurface(i.geom),4326)) -- pas de coordonnées XY on récupère la geom du centroide du site CenRA si elle existe et si une partie du nom du site est renseignée dans la colonne LOCALISATION
|
|
ELSE latitude::double precision
|
|
END as latitude,
|
|
localisation,
|
|
|
|
CASE WHEN observateur2 is null THEN c.id_personne::text
|
|
WHEN observateur2 is not null AND observateur3 is null THEN c.id_personne||'&'||d.id_personne
|
|
WHEN observateur3 is not null AND observateur4 is null THEN c.id_personne||'&'||d.id_personne||'&'||e.id_personne
|
|
WHEN observateur4 is not null AND observateur5 is null THEN c.id_personne||'&'||d.id_personne||'&'||e.id_personne||'&'||f.id_personne
|
|
|
|
ELSE c.id_personne||'&'||d.id_personne||'&'||e.id_personne||'&'||f.id_personne||'&'||g.id_personne
|
|
END AS observateur,
|
|
{id_numerateur}::integer as numerisateur, -- adapter l'identifiant du numérisateur en fonction de la personne qui réalise l'import en masse
|
|
|
|
-- cas d'une prestation on ajoute le CenRA à la structure de l'observateur '&1' sinon il faut supprimer
|
|
CASE WHEN h.id_structure <> 1 THEN (h.id_structure||'&1')::text
|
|
ELSE h.id_structure::text END as structure,
|
|
remarque_obs,
|
|
CASE WHEN lower(a.structure) like '%CEN Isère%' THEN true::boolean
|
|
ELSE false::boolean END as diffusable,
|
|
precision::saisie.enum_precision as precision,
|
|
-- CASE
|
|
-- WHEN latitude is null AND round(st_maxdistance(st_PointOnSurface(i.geom), st_convexhull(i.geom))::numeric,-2) < 101 THEN '10 à 100m'::saisie.enum_precision
|
|
-- WHEN latitude is null AND round(st_maxdistance(st_PointOnSurface(i.geom), st_convexhull(i.geom))::numeric,-2) < 501 AND round(st_maxdistance(ST_PointOnSurface(i.geom), st_convexhull(i.geom))::numeric,-2) > 100 THEN '100 à 500m'::saisie.enum_precision
|
|
-- WHEN latitude is null AND round(st_maxdistance(st_PointOnSurface(i.geom), st_convexhull(i.geom))::numeric,-2) < 1001 AND round(st_maxdistance(ST_PointOnSurface(i.geom), st_convexhull(i.geom))::numeric,-2) > 500 THEN '500 à 1000m'::saisie.enum_precision
|
|
-- WHEN latitude is null AND round(st_maxdistance(st_PointOnSurface(i.geom), st_convexhull(i.geom))::numeric,-2) > 1001 THEN '> 1000m'::saisie.enum_precision
|
|
-- ELSE precision::saisie.enum_precision
|
|
-- END as precision,
|
|
'validée'::saisie.enum_statut_validation as statut_validation,
|
|
j.id_etude,
|
|
k.id_protocole,
|
|
effectif::integer,
|
|
CASE WHEN statut_repro::text IS NOT NULL THEN (statut_repro::text)::saisie.enum_reprostatut
|
|
ELSE NULL END reprostatut,
|
|
|
|
CASE WHEN latitude::numeric > 6000000
|
|
THEN ST_GeomFromText('POINT('||longitude::double precision||' '||latitude::double precision||')',2154) -- coordonnées en lambert93
|
|
WHEN latitude::numeric > 50 AND latitude::numeric < 3000000
|
|
THEN ST_transform(ST_GeomFromText('POINT('||longitude::double precision||' '||latitude::double precision||')',27572),2154) -- coordonnées en Lambert II étendu
|
|
-- WHEN latitude is null
|
|
-- THEN st_pointonsurface(i.geom) -- pas de coordonnées XY on récupère la geom du centroide du site CenRA si elle existe et si une partie du nom du site est renseignée dans la colonne LOCALISATION
|
|
ELSE ST_transform(ST_GeomFromText('POINT('||longitude::double precision||' '||latitude::double precision||')',4326),2154) -- coordonnées en WGS84
|
|
END as geometrie,
|
|
|
|
code_releve,
|
|
CASE WHEN obs_null::text ilike 'oui' THEN true::boolean
|
|
ELSE false::boolean END as obs_null
|
|
|
|
FROM import.import_data_cen38 a
|
|
LEFT JOIN inpn.taxref b ON b.cd_nom::text = a.cd_nom::text
|
|
LEFT JOIN inpn.taxref bb ON bb.nom_complet::text = a.nom_complet::text
|
|
LEFT JOIN personnel c ON (c.nom||' '||c.prenom) = trim(a.observateur1::text) AND lower(c.nom_structure) = lower(a.structure)
|
|
LEFT JOIN personnel d ON (d.nom||' '||d.prenom) = trim(a.observateur2::text) AND lower(d.nom_structure) = lower(a.structure)
|
|
LEFT JOIN personnel e ON (e.nom||' '||e.prenom) = trim(a.observateur3::text) AND lower(e.nom_structure) = lower(a.structure)
|
|
LEFT JOIN personnel f ON (f.nom||' '||f.prenom) = trim(a.observateur4::text) AND lower(f.nom_structure) = lower(a.structure)
|
|
LEFT JOIN personnel g ON (g.nom||' '||g.prenom) = trim(a.observateur5::text) AND lower(g.nom_structure) = lower(a.structure)
|
|
JOIN md.structure h ON lower(h.nom_structure) = lower(replace(replace(a.structure,' & ','&'),'CEN38&',''))
|
|
LEFT JOIN md.etude j on a.id_etude = j.nom_etude
|
|
LEFT JOIN md.protocole k USING (id_protocole)
|
|
--LEFT JOIN import.sites_serena_cren_mu_2015 i ON lower(i.nom_site) like '%'||lower(trim(localisation,'s'))||'%' -- on joint la table des sites CenRA pour récupérer éventuellement le centroide d'un site si pas de XY
|
|
--JOIN md.etude i ON i.nom_etude = a.id_etude -- à utiliser si les champs id_etude et id_protocole contiennent le libelle plutôt que l'identifiant, modifier aussi au-dessus id_etude en i.id_etude, id_protocole en j.id_protocole
|
|
--JOIN md.protocole j ON j.libelle = a.id_protocole
|
|
)
|
|
""".format(id_numerateur=numerateur.id_personne.item())
|
|
|
|
select_dataTOinsert = """
|
|
SELECT DISTINCT
|
|
heure::TIME WITHOUT TIME ZONE as heure_obs, date_obs, date_debut_obs, date_fin_obs, date_textuelle,
|
|
regne, nom_vern, nom_complet, cd_nom, effectif_textuel,
|
|
effectif_min, effectif_max, type_effectif, phenologie,
|
|
longitude, latitude,
|
|
localisation,
|
|
observateur, numerisateur,
|
|
structure, remarque_obs,
|
|
c.code_insee,
|
|
diffusable, "precision",
|
|
statut_validation,
|
|
id_etude, id_protocole,
|
|
effectif, reprostatut,
|
|
t.geometrie,
|
|
code_releve id_waypoint,
|
|
obs_null
|
|
FROM t, ign_bd_topo.commune c
|
|
WHERE ST_intersects(t.geometrie ,c.geometrie)
|
|
--ORDER BY nom_complet, date_obs, longitude, latitude
|
|
;
|
|
"""
|
|
df_data_insert = gpd.read_postgis(
|
|
sql = text(with_dataTOinsert+select_dataTOinsert),
|
|
con = con,
|
|
geom_col='geometrie')
|
|
# pd.read_sql_query(
|
|
# sql = text(with_dataTOinsert+select_dataTOinsert),
|
|
# con = con,)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if df_data_insert.shape[0] == data_import.shape[0]:
|
|
insert_data = """
|
|
INSERT INTO saisie.saisie_observation(
|
|
heure_obs, date_obs, date_debut_obs, date_fin_obs, date_textuelle, regne, nom_vern, nom_complet, cd_nom, effectif_textuel,
|
|
effectif_min, effectif_max, type_effectif, phenologie, longitude, latitude, localisation, observateur, numerisateur, structure, remarque_obs, code_insee, diffusable, "precision",
|
|
statut_validation, id_etude, id_protocole, effectif, reprostatut, geometrie, id_waypoint, obs_null)
|
|
"""
|
|
with con.begin() as cnx:
|
|
cnx.execute(
|
|
text(with_dataTOinsert+
|
|
insert_data+
|
|
select_dataTOinsert)
|
|
)
|
|
update_structure_name = """
|
|
UPDATE saisie.suivi_saisie_observation a
|
|
SET utilisateur = REPLACE(utilisateur, 'inconnu', '{email_numerator}')
|
|
WHERE date_operation > '{today}'
|
|
;
|
|
""".format(
|
|
email_numerator=numerateur.email.item(),
|
|
today = today
|
|
)
|
|
drop_temp_table = """
|
|
DROP TABLE IF EXISTS md.temp_import_personne;
|
|
"""
|
|
with con.begin() as cnx:
|
|
cnx.execute(update_structure_name)
|
|
cnx.execute(drop_temp_table)
|
|
else :
|
|
print(data_import[~data_import.index.isin(df_data_insert.index)])
|
|
data_import[~data_import.index.isin(data_import.drop_duplicates().index)]
|
|
|
|
|
|
|
|
check_datageom = """
|
|
DROP VIEW IF EXISTS import.test_geom_prestation;
|
|
"""
|
|
with con.begin() as cnx:
|
|
cnx.execute(check_datageom)
|