From 14ca79d49ea4b0891bad3266ffcd07d22cc314cc Mon Sep 17 00:00:00 2001 From: Aurince AKAKPO Date: Sat, 21 Mar 2026 15:58:37 +0100 Subject: [PATCH] fusion maj parcelle,batiment,ulo et leur enquete --- .../DonneesImpositionTfuController.java | 6 +- .../rfu/metier/DonneesImpositionTfu.java | 4 + .../DonneesImpositionTfuServiceImpl.java | 4 +- .../metier/DonneesImpositionTfuService.java | 2 +- .../generer_donnees_imposition_tfu_batie.sql | 415 +++++++++++++++++- .../DonneesImpositionTfuRepository.java | 6 +- 6 files changed, 429 insertions(+), 8 deletions(-) diff --git a/src/main/java/io/gmss/fiscad/controllers/rfu/metier/DonneesImpositionTfuController.java b/src/main/java/io/gmss/fiscad/controllers/rfu/metier/DonneesImpositionTfuController.java index c250025..7709415 100644 --- a/src/main/java/io/gmss/fiscad/controllers/rfu/metier/DonneesImpositionTfuController.java +++ b/src/main/java/io/gmss/fiscad/controllers/rfu/metier/DonneesImpositionTfuController.java @@ -461,12 +461,12 @@ public class DonneesImpositionTfuController { } } - @GetMapping("/all/by-exercice-id/by-structure-id/{exerciceId}/{structureId}") - public ResponseEntity getAllDonneesImpositionTfuByExerciceIdAndStructureId(@PathVariable Long exerciceId, @PathVariable Long structureId) { + @GetMapping("/all/by-exercice-id/by-structure-id/by-quartier-id/{exerciceId}/{structureId}/{quartierId}") + public ResponseEntity getAllDonneesImpositionTfuByExerciceIdAndStructureId(@PathVariable Long exerciceId, @PathVariable Long structureId, @PathVariable Long quartierId) { try { System.out.println("NOUS SOMMES ICI"); return new ResponseEntity<>( - new ApiResponse<>(true, donneesImpositionTfuService.getDonneesFiscalesByExerciceAndStructureId(exerciceId,structureId), "Liste des caractéristiques chargée avec succès."), + new ApiResponse<>(true, donneesImpositionTfuService.getDonneesFiscalesByExerciceAndStructureId(exerciceId,structureId,quartierId), "Liste des caractéristiques chargée avec succès."), HttpStatus.OK ); } catch (HttpClientErrorException.MethodNotAllowed e) { diff --git a/src/main/java/io/gmss/fiscad/entities/rfu/metier/DonneesImpositionTfu.java b/src/main/java/io/gmss/fiscad/entities/rfu/metier/DonneesImpositionTfu.java index 5b74cc3..aeb7c29 100644 --- a/src/main/java/io/gmss/fiscad/entities/rfu/metier/DonneesImpositionTfu.java +++ b/src/main/java/io/gmss/fiscad/entities/rfu/metier/DonneesImpositionTfu.java @@ -97,10 +97,12 @@ public class DonneesImpositionTfu extends BaseEntity implements Serializable { @JsonDeserialize(using = LocalDateDeserializer.class) private LocalDate dateEnquete; private Long enqueteId; + @JsonIgnore @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "structure_id") private Structure structure ; + private Long secteurId; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "zone_rfu_id") @@ -137,4 +139,6 @@ public class DonneesImpositionTfu extends BaseEntity implements Serializable { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "unite_logement_id") private UniteLogement uniteLogementImposee ; + + } diff --git a/src/main/java/io/gmss/fiscad/implementations/rfu/metier/DonneesImpositionTfuServiceImpl.java b/src/main/java/io/gmss/fiscad/implementations/rfu/metier/DonneesImpositionTfuServiceImpl.java index 1040520..cacf3b9 100644 --- a/src/main/java/io/gmss/fiscad/implementations/rfu/metier/DonneesImpositionTfuServiceImpl.java +++ b/src/main/java/io/gmss/fiscad/implementations/rfu/metier/DonneesImpositionTfuServiceImpl.java @@ -199,7 +199,7 @@ public class DonneesImpositionTfuServiceImpl implements DonneesImpositionTfuServ } @Override - public List getDonneesFiscalesByExerciceAndStructureId(Long exerciceId, Long structureId) { - return donneesImpositionTfuRepository.findAllByExericeIdStructureId(exerciceId,structureId); + public List getDonneesFiscalesByExerciceAndStructureId(Long exerciceId, Long structureId,Long quartierId) { + return donneesImpositionTfuRepository.findAllByExericeIdStructureId(exerciceId,structureId,quartierId); } } diff --git a/src/main/java/io/gmss/fiscad/interfaces/rfu/metier/DonneesImpositionTfuService.java b/src/main/java/io/gmss/fiscad/interfaces/rfu/metier/DonneesImpositionTfuService.java index 6b187b5..ccf5aa1 100755 --- a/src/main/java/io/gmss/fiscad/interfaces/rfu/metier/DonneesImpositionTfuService.java +++ b/src/main/java/io/gmss/fiscad/interfaces/rfu/metier/DonneesImpositionTfuService.java @@ -43,6 +43,6 @@ public interface DonneesImpositionTfuService { Page getDonneesFiscalesByImpositionSrtbIdBatieUniteLogPageable(Long impositionsTfuId, Pageable pageable); Page getDonneesFiscalesByExerciceAndStructureIdPageable(Long exerciceId, Long structureId, Pageable pageable); - List getDonneesFiscalesByExerciceAndStructureId(Long exerciceId, Long structureId); + List getDonneesFiscalesByExerciceAndStructureId(Long exerciceId, Long structureId,Long quartierId); } diff --git a/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_tfu_batie.sql b/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_tfu_batie.sql index 9c9c1b6..d45b0af 100644 --- a/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_tfu_batie.sql +++ b/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_tfu_batie.sql @@ -1,4 +1,4 @@ -CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_tfu_batie( +/*CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_tfu_batie( p_impositions_tfu_id BIGINT, p_user_id BIGINT ) @@ -342,5 +342,418 @@ WHERE impositions_tfu_id = p_impositions_tfu_id ); RETURN v_rows_inserted; END; +$$;*/ + +CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_tfu_batie( + p_impositions_tfu_id BIGINT, + p_user_id BIGINT +) + RETURNS INTEGER + LANGUAGE plpgsql +AS $$ +DECLARE + v_rows_inserted INTEGER; + v_annee BIGINT; + v_structure_id BIGINT; + v_taux_defaut_sup_sol NUMERIC; + v_taux_tfu NUMERIC; + v_taux_tfu_ratio NUMERIC; -- v_taux_tfu / 100 (pré-calculé) + v_taux_valeur_locat_prof NUMERIC; + v_taux_vlp_ratio NUMERIC; -- v_taux_valeur_locat_prof / 100 (pré-calculé) + v_tfu_piscine_unitaire NUMERIC; + v_today DATE; +BEGIN + + v_today := CURRENT_DATE; + + -- ------------------------------------------------------------------------- + -- 1. Récupération de l'année et de la structure (inchangée) + -- ------------------------------------------------------------------------- + SELECT ex.annee, it.structure_id + INTO STRICT v_annee, v_structure_id + FROM impositions_tfu it + JOIN exercice ex ON ex.id = it.exercice_id + WHERE it.id = p_impositions_tfu_id; + + -- ------------------------------------------------------------------------- + -- 2. Récupération des 4 paramètres en UNE seule requête + -- (évite 4 accès séquentiels à la table parameters) + -- ------------------------------------------------------------------------- + SELECT + MAX(value) FILTER (WHERE name = 'TAUX_DEFAUT_SUPERFICIE_AU_SOL'), + MAX(value) FILTER (WHERE name = 'TAUX_TFU'), + MAX(value) FILTER (WHERE name = 'TAUX_VALEUR_LOCATIVE_PROFESSIONNELLE'), + MAX(value) FILTER (WHERE name = 'TFU_PAR_PISCINE') + INTO STRICT + v_taux_defaut_sup_sol, + v_taux_tfu, + v_taux_valeur_locat_prof, + v_tfu_piscine_unitaire + FROM parameters + WHERE name IN ( + 'TAUX_DEFAUT_SUPERFICIE_AU_SOL', + 'TAUX_TFU', + 'TAUX_VALEUR_LOCATIVE_PROFESSIONNELLE', + 'TFU_PAR_PISCINE' + ); + + -- Ratios pré-calculés pour éviter la division répétée dans le SELECT + v_taux_tfu_ratio := v_taux_tfu / 100.0; + v_taux_vlp_ratio := v_taux_valeur_locat_prof / 100.0; + + -- ------------------------------------------------------------------------- + -- 3. INSERT avec calcul complet de valeur_locative_adm et montant_taxe + -- → supprime l'UPDATE post-INSERT (économie d'un second scan de table) + -- ------------------------------------------------------------------------- + INSERT INTO donnees_imposition_tfu ( + annee, + code_departement, + nom_departement, + code_commune, + nom_commune, + code_arrondissement, + nom_arrondissement, + code_quartier_village, + nom_quartier_village, + q, + ilot, + parcelle, + nup, + titre_foncier, + num_batiment, + ifu, + npi, + tel_prop, + email_prop, + nom_prop, + prenom_prop, + raison_sociale, + adresse_prop, + tel_sc, + nom_sc, + prenom_sc, + longitude, + latitude, + batie, + exonere, + batiment_exonere, + standing_bat, + categorie_bat, + nombre_piscine, + date_enquete, + structure_id, + zone_rfu_id, + nature_impot, + superficie_parc, + superficie_au_sol_bat, + valeur_batiment, + valeur_locative_adm_metre_carre, + montant_loyer_annuel, + tfu_metre_carre, + tfu_minimum, + impositions_tfu_id, + deleted, + created_at, + created_by, + "source", + updated_at, + updated_by, + categorie_usage, + superficie_au_sol_taux_prop_parc, -- 70 % superficie parcelle + valeur_locative_adm_taux_prop_parc, + tfu_calcule_taux_prop_parc, -- TFU à 70 % + valeur_locative_adm_sup_reel, + valeur_locative_adm, -- valeur locative administrative finale + tfu_superficie_au_sol_reel, + tfu_piscine, + montant_taxe, -- TFU finale + taux_tfu, + parcelle_id, + batiment_id, + unite_logement_id + ) + SELECT + v_annee, + d.code, + d.nom, + c.code, + c.nom, + a.code, + a.nom, + q.code, + q.nom, + p.q, + p.i, + p.p, + p.nup, + ep.numero_titre_foncier, + b.nub, + pers.ifu, + pers.npi, + pers.tel1, + pers.email, + pers.nom, + pers.prenom, + pers.raison_sociale, + pers.adresse, + ep.representant_tel, + ep.representant_nom, + ep.representant_prenom, + p.longitude, + p.latitude, + TRUE, + -- exonere parcelle + (v_today BETWEEN ep.date_debut_exemption + AND COALESCE(ep.date_fin_exemption, v_today)), + -- exonere batiment + (v_today BETWEEN eb.date_debut_excemption + AND COALESCE(eb.date_fin_excemption, v_today)), + cb.standing, + cb.nom, + eb.nombre_piscine, + eb.date_enquete, + st.id, + ep.zone_rfu_id, + 'TFU', + p.superficie, + eb.superficie_au_sol, + -- valeur_batiment : première valeur non nulle non zéro + COALESCE( + NULLIF(eb.valeur_batiment_reel, 0), + NULLIF(eb.valeur_batiment_calcule, 0), + NULLIF(eb.valeur_batiment_estime, 0), + 0 + ), + brb.valeur_locative, + -- montant_loyer_annuel + COALESCE( + NULLIF(eb.montant_locatif_annuel_declare, 0), + NULLIF(eb.montant_locatif_annuel_calcule, 0), + NULLIF(eb.montant_locatif_annuel_estime, 0), + 0 + ), + brb.tfu_metre_carre, + brb.tfu_minimum, + p_impositions_tfu_id, + FALSE, + v_today, + p_user_id, + 'FISCAD', + v_today, + p_user_id, + eb.categorie_usage, + + -- superficie_au_sol_taux_prop_parc (70 % parcelle) + p.superficie * v_taux_defaut_sup_sol / 100.0, + + -- valeur_locative_adm_taux_prop_parc + CASE WHEN eb.categorie_usage = 'HABITATION' + THEN (p.superficie * v_taux_defaut_sup_sol / 100.0) * brb.valeur_locative + ELSE 0 + END, + + -- tfu_calcule_taux_prop_parc + CASE WHEN eb.categorie_usage = 'HABITATION' + THEN (p.superficie * v_taux_defaut_sup_sol / 100.0) * brb.valeur_locative * v_taux_tfu_ratio + ELSE 0 + END, + + -- valeur_locative_adm_sup_reel + CASE WHEN eb.categorie_usage = 'HABITATION' + THEN eb.superficie_au_sol * brb.valeur_locative + ELSE 0 + END, + + -- --------------------------------------------------------------- + -- 🔧 CORRECTION : valeur_locative_adm avec tests explicites + -- --------------------------------------------------------------- + CASE + WHEN eb.categorie_usage = 'HABITATION' + AND eb.superficie_au_sol <> 0 + THEN eb.superficie_au_sol * brb.valeur_locative + + WHEN eb.categorie_usage = 'HABITATION' + AND eb.superficie_au_sol = 0 + THEN (p.superficie * v_taux_defaut_sup_sol / 100.0) * brb.valeur_locative + + -- ✅ Test explicite : valeur_batiment <> 0 + WHEN eb.categorie_usage IN ('PROFESSIONNELLE', 'MIXTE') + AND COALESCE(NULLIF(eb.valeur_batiment_reel, 0), + NULLIF(eb.valeur_batiment_calcule, 0), + NULLIF(eb.valeur_batiment_estime, 0), 0) <> 0 + THEN COALESCE(NULLIF(eb.valeur_batiment_reel, 0), + NULLIF(eb.valeur_batiment_calcule, 0), + NULLIF(eb.valeur_batiment_estime, 0), 0) + * v_taux_vlp_ratio + + -- ✅ Test explicite : valeur_batiment = 0 + WHEN eb.categorie_usage IN ('PROFESSIONNELLE', 'MIXTE') + AND COALESCE(NULLIF(eb.valeur_batiment_reel, 0), + NULLIF(eb.valeur_batiment_calcule, 0), + NULLIF(eb.valeur_batiment_estime, 0), 0) = 0 + THEN COALESCE(NULLIF(eb.montant_locatif_annuel_declare, 0), + NULLIF(eb.montant_locatif_annuel_calcule, 0), + NULLIF(eb.montant_locatif_annuel_estime, 0), 0) + + ELSE 0 + END, + + -- tfu_superficie_au_sol_reel + CASE WHEN eb.categorie_usage = 'HABITATION' + THEN eb.superficie_au_sol * brb.valeur_locative * v_taux_tfu_ratio + ELSE 0 + END, + + -- tfu_piscine + eb.nombre_piscine * v_tfu_piscine_unitaire, + + -- --------------------------------------------------------------- + -- montant_taxe ← calculé directement (plus d'UPDATE) + -- Utilise des CTE inline via expression pour éviter la redondance + -- --------------------------------------------------------------- + ( + -- On matérialise valeur_batiment et valeur_locative une seule fois + WITH calc AS ( + SELECT + COALESCE(NULLIF(eb.valeur_batiment_reel, 0), + NULLIF(eb.valeur_batiment_calcule, 0), + NULLIF(eb.valeur_batiment_estime, 0), 0) AS vb, + COALESCE(NULLIF(eb.montant_locatif_annuel_declare, 0), + NULLIF(eb.montant_locatif_annuel_calcule, 0), + NULLIF(eb.montant_locatif_annuel_estime, 0), 0) AS loyer, + eb.superficie_au_sol * brb.valeur_locative AS vla_reel, + (p.superficie * v_taux_defaut_sup_sol / 100.0) + * brb.valeur_locative AS vla_70 + ) + SELECT + CASE + WHEN eb.categorie_usage = 'HABITATION' + AND eb.superficie_au_sol <> 0 + THEN GREATEST(brb.tfu_minimum, + calc.vla_reel * v_taux_tfu_ratio + + eb.nombre_piscine * v_tfu_piscine_unitaire) + + WHEN eb.categorie_usage = 'HABITATION' + AND eb.superficie_au_sol = 0 + THEN GREATEST(brb.tfu_minimum, + calc.vla_70 * v_taux_tfu_ratio + + eb.nombre_piscine * v_tfu_piscine_unitaire) + + WHEN eb.categorie_usage IN ('PROFESSIONNELLE', 'MIXTE') + AND calc.vb <> 0 + THEN GREATEST(brb.tfu_minimum, + calc.vb * v_taux_vlp_ratio * v_taux_tfu_ratio) + + WHEN eb.categorie_usage IN ('PROFESSIONNELLE', 'MIXTE') + AND calc.vb = 0 + THEN GREATEST(brb.tfu_minimum, + calc.loyer * v_taux_tfu_ratio) + + ELSE brb.tfu_minimum + END + FROM calc + ), + + v_taux_tfu, + p.id, + b.id, + NULL + + FROM parcelle p + + -- Dernière enquête parcelle + LEFT JOIN LATERAL ( + SELECT + parcelle_id, + superficie, + personne_id, + numero_titre_foncier, + date_enquete, + representant_tel, + representant_nom, + representant_prenom, + representant_npi, + date_debut_exemption, + date_fin_exemption, + zone_rfu_id + FROM enquete + WHERE parcelle_id = p.id + ORDER BY date_enquete DESC, id DESC + LIMIT 1 + ) ep ON TRUE + + LEFT JOIN personne pers ON pers.id = ep.personne_id + + JOIN quartier q ON q.id = p.quartier_id + JOIN arrondissement a ON a.id = q.arrondissement_id + JOIN commune c ON c.id = a.commune_id + JOIN departement d ON d.id = c.departement_id + + -- Rattachement structure via secteur (DISTINCT ON → LATERAL plus lisible) + JOIN LATERAL ( + SELECT secteur_id + FROM secteur_decoupage + WHERE quartier_id = q.id + ORDER BY quartier_id + LIMIT 1 + ) sd ON TRUE + JOIN secteur sect ON sect.id = sd.secteur_id + JOIN section ses ON ses.id = sect.section_id + JOIN "structure" st ON st.id = ses.structure_id + + -- Bâtiments sans unités logement (anti-join via LEFT JOIN … IS NULL) + JOIN batiment b ON b.parcelle_id = p.id + LEFT JOIN unite_logement ul_filter ON ul_filter.batiment_id = b.id + + -- Dernière enquête bâtiment + JOIN LATERAL ( + SELECT + eb2.batiment_id, + eb2.superficie_au_sol, + eb2.nombre_piscine, + eb2.categorie_batiment_id, + eb2.date_enquete, + eb2.montant_locatif_annuel_declare, + eb2.montant_locatif_annuel_calcule, + eb2.montant_locatif_annuel_estime, + eb2.date_debut_excemption, + eb2.date_fin_excemption, + eb2.valeur_batiment_reel, + eb2.valeur_batiment_calcule, + eb2.valeur_batiment_estime, + u.categorie_usage + FROM enquete_batiment eb2 + JOIN usage u ON u.id = eb2.usage_id + WHERE eb2.batiment_id = b.id + ORDER BY eb2.date_enquete DESC, eb2.id DESC + LIMIT 1 + ) eb ON TRUE + + JOIN categorie_batiment cb ON cb.id = eb.categorie_batiment_id + + -- Barème RFU bâti (inchangé) + JOIN LATERAL ( + SELECT * + FROM barem_rfu_bati br + WHERE br.categorie_batiment_id = cb.id + AND br.arrondissement_id = a.id + AND (br.quartier_id = q.id OR br.quartier_id IS NULL) + ORDER BY br.quartier_id DESC NULLS LAST + LIMIT 1 + ) brb ON TRUE + + WHERE p.batie = TRUE + AND ul_filter.batiment_id IS NULL -- anti-join : pas d'unité logement + AND st.id = v_structure_id + + ON CONFLICT DO NOTHING; + + GET DIAGNOSTICS v_rows_inserted = ROW_COUNT; + + RETURN v_rows_inserted; +END; $$; + +select * from donnees_imposition_tfu +where batie =true; \ No newline at end of file diff --git a/src/main/java/io/gmss/fiscad/persistence/repositories/rfu/metier/DonneesImpositionTfuRepository.java b/src/main/java/io/gmss/fiscad/persistence/repositories/rfu/metier/DonneesImpositionTfuRepository.java index ed2fc1f..ea0bf2d 100755 --- a/src/main/java/io/gmss/fiscad/persistence/repositories/rfu/metier/DonneesImpositionTfuRepository.java +++ b/src/main/java/io/gmss/fiscad/persistence/repositories/rfu/metier/DonneesImpositionTfuRepository.java @@ -708,14 +708,18 @@ SELECT new io.gmss.fiscad.paylaods.request.crudweb.DonneesImpositionPaylaodWeb( ) FROM DonneesImpositionTfu d JOIN d.impositionsTfu itfu + JOIN d.parcelleImposee parc + JOIN parc.quartier quart LEFT join d.structure s LEFT join d.zoneRfu z WHERE itfu.exercice.id = :exerciceId and s.id= :structureId + and quart.id= :quartierId order by d.nomProp,d.nomProp asc """) List findAllByExericeIdStructureId( Long exerciceId, - Long structureId + Long structureId, + Long quartierId ); }