diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index ea7d649..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.gitignore b/.gitignore index 1c1cfa0..4744982 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .vscode -custom.json \ No newline at end of file +custom.json + +.DS_Store \ No newline at end of file diff --git a/sterf/config.json b/sterf/config.json new file mode 100644 index 0000000..075a6a9 --- /dev/null +++ b/sterf/config.json @@ -0,0 +1,15 @@ +{ + "tree": { + "module": { + "site": { + "visit": { + "observation": null + } + } + } + }, + "data": { + "nomenclature": ["TYPE_SITE", "METH_DETERMIN"], + "user": ["__CODE_LIST_INVENTOR", "__CODE_LIST_OBSERVER"] + } +} diff --git a/sterf/exports/csv/export_csv.sql b/sterf/exports/csv/export_csv.sql new file mode 100644 index 0000000..4ff6b51 --- /dev/null +++ b/sterf/exports/csv/export_csv.sql @@ -0,0 +1,64 @@ +------- Export des observations STERF ---------- +DROP VIEW IF EXISTS gn_monitoring.v_export_sterf_standard; +CREATE OR REPLACE VIEW gn_monitoring.v_export_sterf_standard AS + SELECT + -- identifiant unique + o.uuid_observation AS uuid_observation, + -- Site et variables associées + s.base_site_name AS nom_transect, + st_astext(s.geom) AS wkt_transect, + st_x(st_centroid(s.geom_local)) AS x_centroid_local, + st_y(st_centroid(s.geom_local)) AS y_centroid_local, + s.altitude_min AS altitude_min, + s.altitude_max AS altitude_max, + com.communes, + nullif(sc.data::json ->> 'tirage_site', 'null') AS tirage_site, + nullif(sc.data::json ->> 'habitat_1', 'null') AS habitat_1, + nullif(sc.data::json ->> 'habitat_2', 'null') AS habitat_2, + nullif(sc.data::json ->> 'habitat_3', 'null') AS habitat_3, + nullif(sc.data::json ->> 'habitat_4', 'null') AS habitat_4, + -- Informations sur la visite + v.id_dataset, + d.dataset_name AS jeu_de_donnees, + v.uuid_base_visit AS uuid_visite, + v.visit_date_min AS date_visite, + nullif(vc.data::json ->> 'duration', 'null') AS duree_parcours, + obs.observers, + nullif(vc.data::json ->> 'start_time', 'null') AS heure_debut, + nullif(vc.data::json ->> 'meteo_cond', 'null') AS conditions_meteo, + nullif(vc.data::json ->> 'temperature', 'null') AS temperature, + nullif(vc.data::json ->> 'vent', 'null') AS vent, + nullif(vc.data::json ->> 'ennuagement', 'null') AS ennuagement, + v.comments AS commentaire_visite, + -- Informations sur l'observation + o.cd_nom AS cd_nom, + t.lb_nom AS nom_latin, + t.nom_vern AS nom_francais, + r.prenom_role||' '||r.nom_role AS determinateur, + nullif(oc.data::json ->> 'count_min', 'null') AS count_min, + nullif(oc.data::json ->> 'count_max', 'null') AS count_max, + ref_nomenclatures.get_nomenclature_label(nullif(json_extract_path(oc.data::json,'id_nomenclature_determination_method')::text,'null')::integer, 'fr') AS methode_determ, + o.comments AS commentaire_obs +FROM gn_monitoring.t_observations o +JOIN gn_monitoring.t_observation_complements oc ON oc.id_observation = o.id_observation +JOIN gn_monitoring.t_base_visits v ON o.id_base_visit = v.id_base_visit +JOIN gn_monitoring.t_visit_complements vc ON v.id_base_visit = vc.id_base_visit +JOIN gn_monitoring.t_base_sites s ON s.id_base_site = v.id_base_site +JOIN gn_monitoring.t_site_complements sc ON sc.id_base_site = s.id_base_site +JOIN gn_commons.t_modules m ON m.id_module = v.id_module +JOIN taxonomie.taxref t ON t.cd_nom = o.cd_nom +LEFT JOIN gn_meta.t_datasets d ON d.id_dataset=v.id_dataset +LEFT JOIN LATERAL (select string_agg(la.area_name, ', ') AS communes + FROM ref_geo.l_areas la + JOIN ref_geo.bib_areas_types bat ON la.id_type = bat.id_type + JOIN gn_monitoring.cor_site_area csa ON csa.id_area = la.id_area + WHERE bat.type_code='COM' + AND csa.id_base_site = s.id_base_site) AS com ON true +LEFT JOIN LATERAL ( SELECT array_agg(r.id_role) AS ids_observers, + string_agg(concat(r.nom_role, ' ', r.prenom_role, ' (',org.nom_organisme,') '), ' ; '::text) AS observers + FROM gn_monitoring.cor_visit_observer cvo + JOIN utilisateurs.t_roles r ON r.id_role = cvo.id_role + LEFT JOIN utilisateurs.bib_organismes org ON org.id_organisme =r.id_organisme + WHERE cvo.id_base_visit = v.id_base_visit) obs ON true +LEFT JOIN utilisateurs.t_roles r ON nullif(json_extract_path(oc.data::json,'determiner')::text,'null')::integer = r.id_role +WHERE m.module_code = 'sterf'; diff --git a/sterf/img.jpg b/sterf/img.jpg new file mode 100644 index 0000000..70c3885 Binary files /dev/null and b/sterf/img.jpg differ diff --git a/sterf/module.json b/sterf/module.json new file mode 100644 index 0000000..b14a66d --- /dev/null +++ b/sterf/module.json @@ -0,0 +1,7 @@ +{ + "module_label":"Suivi Temporel des Rhopalocères de France", + "module_desc":"Module de saisie du protocole STERF", + "export_csv": [ + { "label": "Format observations CSV", "type":"csv" , "method": "standard" } + ] +} diff --git a/sterf/nomenclature.json b/sterf/nomenclature.json new file mode 100644 index 0000000..c9de17d --- /dev/null +++ b/sterf/nomenclature.json @@ -0,0 +1,18 @@ +{ + "types": [ + { + "mnemonique": "TYPE_SITE", + "label_default": "Type de sites", + "definition_default": "Nomenclature des types de sites suivi dans gn_monitoring." + } + ], + "nomenclatures": [ + { + "type": "TYPE_SITE", + "cd_nomenclature": "STERF", + "mnemonique": "Site_STERF", + "label_default": "Site STERF", + "definition_default": "Site de relevé du protocole STERF" + } + ] +} diff --git a/sterf/observation.json b/sterf/observation.json new file mode 100644 index 0000000..aea1654 --- /dev/null +++ b/sterf/observation.json @@ -0,0 +1,58 @@ +{ + "display_properties": [ + "cd_nom", + "id_nomenclature_determination_method", + "determiner", + "count_min", + "count_max", + "comments" + ], + "display_list": [ + "cd_nom", + "id_nomenclature_determination_method", + "count_min", + "count_max" + ], + "keep": [ + "determiner", + "id_nomenclature_determination_method" + ], + "specific": { + "determiner": { + "type_widget": "datalist", + "attribut_label": "Déterminateur", + "api": "users/menu/__MODULE.ID_LIST_OBSERVER", + "application": "GeoNature", + "keyValue": "id_role", + "keyLabel": "nom_complet", + "type_util": "user", + "required": true + }, + "id_nomenclature_determination_method": { + "type_widget": "datalist", + "attribut_label": "Méthode de détermination", + "api": "nomenclatures/nomenclature/METH_DETERMIN", + "application": "GeoNature", + "keyValue": "id_nomenclature", + "keyLabel": "label_fr", + "data_path": "values", + "type_util": "nomenclature", + "required": false, + "default": { + "cd_nomenclature": "67" + } + }, + "count_min": { + "type_widget": "number", + "attribut_label": "Effectif minimal dénombré", + "required": true, + "min": 1 + }, + "count_max": { + "type_widget": "number", + "attribut_label": "Effectif maximal dénombré", + "required": true, + "min": "({value}) => value.count_min " + } + } +} diff --git a/sterf/site.json b/sterf/site.json new file mode 100644 index 0000000..0b9c8a0 --- /dev/null +++ b/sterf/site.json @@ -0,0 +1,102 @@ + +{ + "genre":"M", + "geometry_type": "LineString", + "label": "Transect", + "label_list": "Transects", + "map_label_field_name": "base_site_name", + "display_properties": [ + "base_site_name", + "id_inventor", + "first_use_date", + "last_visit", + "nb_visits", + "tirage_site", + "habitat_1", + "habitat_2", + "habitat_3", + "habitat_4" + ], + "display_list": [ + "base_site_name", + "first_use_date", + "last_visit", + "nb_visits" + ], + "keep": [ + "id_inventor", + "tirage_site" + ], + "specific": { + "id_nomenclature_type_site": { + "type_widget": "nomenclature", + "attribut_label": "Type site", + "code_nomenclature_type": "TYPE_SITE", + "type_util": "nomenclature", + "required": true, + "value": { + "code_nomenclature_type": "TYPE_SITE", + "cd_nomenclature": "STERF" + }, + "hidden": true + }, + "tirage_site": { + "type_widget": "select", + "attribut_label": "Modalité de sélection du site *", + "required": true, + "values": ["Tiré aléatoirement", "Choisi"], + "value":"Choisi" + }, + "habitat_1": { + "type_widget": "select", + "attribut_label": "Habitat (subdivision 1) *", + "required": true, + "values": ["A. Forêt (arbres > 5m de hauteur)","B. Buissons ou jeune forêt (<5m de hauteur)","C. Pelouses, marais et landes","D. Milieux agricoles","E. Milieux bâtis ou urbanisés","G. Rochers terrestres ou côtiers"] + }, + "habitat_2": { + "type_widget": "select", + "required": false, + "attribut_label": "Habitat (subdivision 2)", + "values": [ + "({value}) => {", + " if (value.habitat_1 == 'A. Forêt (arbres > 5m de hauteur)') { return [ 'a. Feuillus exclusifs','b. Mixte dom. Feuillus (< 10% conifères)','c. Mixte dom. conifères (< 10% feuillus)','d. Conifères exclusifs','e. Mixte' ] }", + " if (value.habitat_1 == 'B. Buissons ou jeune forêt (<5m de hauteur)') { return [ 'a. Feuillus exclusifs','b. Mixte dom. feuillus (< 10% conifères)','c. Mixte dom. conifères (< 10% feuillus)','d. Conifères exclusifs','e. Mixte' ] }", + " if (value.habitat_1 == 'C. Pelouses, marais et landes') { return [ 'a. Pelouse calcaire sèche','b. Lande herbacée','c. Lande à bruyères','d. Autres pelouses sèches','e. Pelouse d altitude', 'f. Pelouse humide naturelle', 'g. Pelouse inondée/marais pâturé', 'h. Tourbière', 'i. Roselière', 'j. Marais salant (halophile)', 'k. Autres zones humides ouvertes' ] }", + " if (value.habitat_1 == 'D. Milieux agricoles') { return [ 'a. Prairie cultivée','b. Prairie non cultivée','c. Prairie / cultures mixtes','d. Grandes cultures','e. Vergers / vignes / cultures maraîchères','f. Autres types de cultures' ] }", + " if (value.habitat_1 == 'E. Milieux bâtis ou urbanisés') { return [ 'a Zone urbaine résidentielle','b Zone urbaine industrielle','c Zone suburbaine résidentielle','d Zone suburbaine industrelle','e Zone rurale' ] }", + " else { return [ 'a. Falaise','b. Eboulis, pente rocheuse','c. Carrière','d. Autres sols rocheux' ]} ", + "}" + ] + }, + "habitat_3": { + "type_widget": "select", + "required": false, + "attribut_label": "Habitat (subdivision 3)", + "values": [ + "({value}) => {", + " if (value.habitat_1 == 'A. Forêt (arbres > 5m de hauteur)') { return [ '1. Sous-bois dense','2. Sous-bois clair','3. Clairière et lisière','4. Parc (arbres épars et prairies)' ] }", + " if (value.habitat_1 == 'B. Buissons ou jeune forêt (<5m de hauteur)') { return [ '1. Forêt de régénération ou taillis','2. Buissons calcicoles','3. Lande arbustive non calcicole','4. Garrigue (calcaire) (Méditerr)','5. Maquis (non calcaire) (Méditerr)','6. Buissons de zones humides' ] }", + " if (value.habitat_1 == 'C. Pelouses, marais et landes') { return [ '1. Entouré de haies avec arbres','2. Entouré de haies de buissons','3. Entouré de ligne d arbres sans haie','4. Avec buissons épars','5. Sans buissons épars','6. Groupes isolés de 1-10 arbres','7. Autres limites de terrain (digue, fossé, mur, ...)' ] }", + " if (value.habitat_1 == 'D. Milieux agricoles') { return [ '1. Entouré de haies avec arbres','2. Entouré de haies de buissons','3. Entouré de ligne d arbres sans haie','4. Entouré de bandes herbeuses','5. Avec des groupes isolés de 1-10 arbres','6. Autre limite de terrain (digue, fossé, mur, ...)' ] }", + " if (value.habitat_1 == 'E. Milieux bâtis ou urbanisés') { return [ '1. Zones bâties prédominantes','2. Jardin','3. Parc public, zone de loisirs','4. Bord d une route (< 50 m)','5. Bord d un chemin de fer (< 50 m)','6. Décharge d’ordures' ] }", + " else { return [ '1. En montagne','2. En bord de mer','3. En bord de lac ou de rivière','4. Autre' ]} ", + "}" + ] + }, + "habitat_4": { + "type_widget": "select", + "required": false, + "attribut_label": "Habitat (subdivision 4)", + "values": [ + "({value}) => {", + " if (value.habitat_1 == 'A. Forêt (arbres > 5m de hauteur)') { return [ 'a. Non perturbé','b. Peu exploité','c. Fortement exploité','d. Pâturé' ] }", + " if (value.habitat_1 == 'B. Buissons ou jeune forêt (<5m de hauteur)') { return [ 'a. Non perturbé','b. Peu exploité','c. Fortement exploité','d. Pâturé' ] }", + " if (value.habitat_1 == 'C. Pelouses, marais et landes') { return [ 'a. Non perturbé/non exploité','b. Fauché','c. Pâturé' ] }", + " if (value.habitat_1 == 'D. Milieux agricoles') { return [ 'a. Non exploité (jachère)','b. Fauché','c. Pâturé','d. Céréales','e. Arbres fruitiers','f. Autres cultures' ] }", + " if (value.habitat_1 == 'E. Milieux bâtis ou urbanisés') { return [ 'a. Avec peu d espaces verts (< 25 %)','b. Avec des espaces verts surtout composés de pelouses','c. Avec des espaces verts buissonants (parterres, friches)','d. Avec des espaces verts fortement arborés','e. Avec un (des) potager(s)' ] }", + " else { return [ 'a. A dominante calcaire avec végétation herbacée rase','b. A dominante calcaire avec végétation herbacée haute','c. A dominante calcaire avec végétation buissonnante','d. A dominante non calcaire avec végétation herbacée rase','e. A dominante non calcaire avec végétation herbacée haute','f. A dominante non calcaire avec végétation buissonnante' ]} ", + "}" + ] + } + } +} \ No newline at end of file diff --git a/sterf/synthese.sql b/sterf/synthese.sql new file mode 100644 index 0000000..c20882f --- /dev/null +++ b/sterf/synthese.sql @@ -0,0 +1,67 @@ +-- ############################# +-- Création d'une vue +-- permettant la remonté des données +-- STERF dans la synthèse +-- ############################# +DROP VIEW IF EXISTS gn_monitoring.v_synthese_sterf; + +-- gn_monitoring.v_synthese_sterf +CREATE OR REPLACE VIEW gn_monitoring.v_synthese_sterf +AS WITH source AS ( + SELECT t_sources.id_source + FROM gn_synthese.t_sources + WHERE t_sources.name_source::text = concat('MONITORING_', upper('sterf'::text)) + LIMIT 1 + ) + SELECT o.uuid_observation AS unique_id_sinp, + v.uuid_base_visit AS unique_id_sinp_grp, + ( SELECT source.id_source + FROM source) AS id_source, + o.id_observation AS entity_source_pk_value, + v.id_dataset, + ref_nomenclatures.get_id_nomenclature('METH_OBS'::character varying, '0'::character varying) AS id_nomenclature_obs_meth, + ref_nomenclatures.get_id_nomenclature('STADE_VIE'::character varying, '15'::character varying) AS id_nomenclature_life_stage, + ref_nomenclatures.get_id_nomenclature('SEXE'::character varying, '6'::character varying) AS id_nomenclature_sex, + ref_nomenclatures.get_id_nomenclature('OBJ_DENBR'::character varying, 'IND'::character varying) AS id_nomenclature_obj_count, + ref_nomenclatures.get_id_nomenclature('TYP_DENBR'::character varying, 'Co'::character varying) AS id_nomenclature_type_count, + ref_nomenclatures.get_id_nomenclature('STATUT_OBS'::character varying, 'Pr'::character varying) AS id_nomenclature_observation_status, + ref_nomenclatures.get_id_nomenclature('STATUT_SOURCE'::character varying, 'Te'::character varying) AS id_nomenclature_source_status, + ref_nomenclatures.get_id_nomenclature('TYP_INF_GEO'::character varying, '1'::character varying) AS id_nomenclature_info_geo_type, + ref_nomenclatures.get_id_nomenclature('ETA_BIO'::character varying, '2'::character varying) AS id_nomenclature_bio_condition, + ((oc.data::json #> '{count_min}'::text[])::text)::integer AS count_min, + ((oc.data::json #> '{count_max}'::text[])::text)::integer AS count_max, + o.id_observation, + o.cd_nom, + t.nom_complet AS nom_cite, + alt.altitude_min, + alt.altitude_max, + s.geom AS the_geom_4326, + st_centroid(s.geom) AS the_geom_point, + s.geom_local AS the_geom_local, + v.visit_date_min AS date_min, + v.visit_date_max AS date_max, + obs.observers, + s.id_digitiser, + ((oc.data::json #> '{id_nomenclature_determination_method}'::text[])::text)::integer AS id_nomenclature_determination_method, + v.id_module, + v.comments AS comment_context, + o.comments AS comment_description, + obs.ids_observers, + v.id_base_site, + v.id_base_visit, + jsonb_build_object('nom_site', s.base_site_name, 'code_site', s.base_site_code, 'habitat_1', NULLIF(replace((sc.data::json -> 'habitat_1'::text)::text, '"'::text, ''::text), 'null'::text), 'habitat_2', NULLIF(replace((sc.data::json -> 'habitat_2'::text)::text, '"'::text, ''::text), 'null'::text), 'habitat_3', NULLIF(replace((sc.data::json -> 'habitat_3'::text)::text, '"'::text, ''::text), 'null'::text), 'habitat_4', NULLIF(replace((sc.data::json -> 'habitat_4'::text)::text, '"'::text, ''::text), 'null'::text), 'vent', NULLIF(replace((vc.data::json -> 'vent'::text)::text, '"'::text, ''::text), 'null'::text), 'ennuagement', NULLIF(replace((vc.data::json -> 'ennuagement'::text)::text, '"'::text, ''::text), 'null'::text), 'temperature', NULLIF(replace((vc.data::json -> 'temperature'::text)::text, '"'::text, ''::text), 'null'::text), 'meteo_favorable', NULLIF(replace((vc.data::json -> 'meteo_cond'::text)::text, '"'::text, ''::text), 'null'::text), 'duree_transect', NULLIF(replace((vc.data::json -> 'duration'::text)::text, '"'::text, ''::text), 'null'::text), 'heure_debut', NULLIF(replace((vc.data::json -> 'start_time'::text)::text, '"'::text, ''::text), 'null'::text)) AS additional_data + FROM gn_monitoring.t_base_visits v + JOIN gn_monitoring.t_visit_complements vc ON v.id_base_visit = vc.id_base_visit + JOIN gn_monitoring.t_base_sites s ON s.id_base_site = v.id_base_site + JOIN gn_monitoring.t_site_complements sc ON s.id_base_site = sc.id_base_site + JOIN gn_commons.t_modules m ON m.id_module = v.id_module + JOIN gn_monitoring.t_observations o ON o.id_base_visit = v.id_base_visit + JOIN gn_monitoring.t_observation_complements oc ON oc.id_observation = o.id_observation + JOIN taxonomie.taxref t ON t.cd_nom = o.cd_nom + LEFT JOIN LATERAL ( SELECT array_agg(r.id_role) AS ids_observers, + string_agg(concat(r.nom_role, ' ', r.prenom_role), ' ; '::text) AS observers + FROM gn_monitoring.cor_visit_observer cvo + JOIN utilisateurs.t_roles r ON r.id_role = cvo.id_role + WHERE cvo.id_base_visit = v.id_base_visit) obs ON true + LEFT JOIN LATERAL ref_geo.fct_get_altitude_intersection(s.geom_local) alt(altitude_min, altitude_max) ON true + WHERE m.module_code::text = 'sterf'::text; \ No newline at end of file diff --git a/sterf/visit.json b/sterf/visit.json new file mode 100644 index 0000000..01fed37 --- /dev/null +++ b/sterf/visit.json @@ -0,0 +1,63 @@ +{ + "display_properties": [ + "id_dataset", + "observers", + "visit_date_min", + "start_time", + "duration", + "meteo_cond", + "temperature", + "vent", + "ennuagement", + "comments" + ], + "display_list": [ + "visit_date_min", + "observers", + "duration", + "meteo_cond" + ], + "keep": [ + "id_dataset", + "observers" + ], + "specific": { + "duration": { + "type_widget": "number", + "required":true, + "attribut_label": "Durée de parcours du transect (en mn) *", + "min":1, + "value":10 + }, + "start_time": { + "type_widget": "time", + "required":true, + "attribut_label": "Heure de début du relevé *" + }, + "meteo_cond": { + "type_widget": "radio", + "attribut_label": "Les conditions météorologiques favorables étaient-elles réunies ? *", + "required": true, + "values": ["Oui", "Non"], + "value":"Oui" + }, + "temperature": { + "type_widget": "select", + "attribut_label": "Température (en °C)", + "required":false, + "values": ["inférieure à 13°", "13 à 15°", "16 à 20°", "21 à 25°","26 à 30°", "31 à 35°", "supérieure à 35°"] + }, + "vent": { + "type_widget": "select", + "attribut_label": "Force du vent", + "required": false, + "values": ["Nul", "Léger", "Modéré", "Fort"] + }, + "ennuagement": { + "type_widget": "select", + "attribut_label": "Ennuagement", + "required": false, + "values": ["Soleil", "Peu nuageux", "Nuageux", "Très nuageux", "Couvert"] + } + } +}