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 a75f9f2..245ffdd 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 @@ -117,13 +117,13 @@ public class DonneesImpositionTfuServiceImpl implements DonneesImpositionTfuServ Integer nbulo= donneesImpositionTfuRepository.genererDonneesTfuBatieUniteLogement(impositionsTfuPaylaodWeb.getId(),userId); -// Integer nbirfbt= donneesImpositionTfuRepository.genererDonneesIrfBatie(impositionsTfuPaylaodWeb.getId(),userId); + Integer nbirfbt= donneesImpositionTfuRepository.genererDonneesIrfBatie(impositionsTfuPaylaodWeb.getId(),userId); // -// Integer nbirfulo= donneesImpositionTfuRepository.genererDonneesIrfBatieUniteLogement(impositionsTfuPaylaodWeb.getId(),userId); + Integer nbirfulo= donneesImpositionTfuRepository.genererDonneesIrfBatieUniteLogement(impositionsTfuPaylaodWeb.getId(),userId); // -// Integer nbsrtbbt= donneesImpositionTfuRepository.genererDonneesSrtbBatie(impositionsTfuPaylaodWeb.getId(),userId); + Integer nbsrtbbt= donneesImpositionTfuRepository.genererDonneesSrtbBatie(impositionsTfuPaylaodWeb.getId(),userId); // -// Integer nbsrtbulo= donneesImpositionTfuRepository.genererDonneesSrtbBatieUniteLogement(impositionsTfuPaylaodWeb.getId(),userId); + Integer nbsrtbulo= donneesImpositionTfuRepository.genererDonneesSrtbBatieUniteLogement(impositionsTfuPaylaodWeb.getId(),userId); ImpositionsTfu impositionsTfu = entityFromPayLoadService.getImpositionsTfuFromPayLoadWeb(impositionsTfuPaylaodWeb); diff --git a/src/main/java/io/gmss/fiscad/implementations/rfu/metier/ImpositionsTfuServiceImpl.java b/src/main/java/io/gmss/fiscad/implementations/rfu/metier/ImpositionsTfuServiceImpl.java index 850becb..59b9aa4 100644 --- a/src/main/java/io/gmss/fiscad/implementations/rfu/metier/ImpositionsTfuServiceImpl.java +++ b/src/main/java/io/gmss/fiscad/implementations/rfu/metier/ImpositionsTfuServiceImpl.java @@ -47,7 +47,7 @@ public class ImpositionsTfuServiceImpl implements ImpositionsTfuService { } List impositionsTfus=impositionsTfuRepository.getImpositionsTfuByStructureAndExercice(impositionsTfuPaylaodWeb.getStructureId(), impositionsTfuPaylaodWeb.getExerciceId()); if (!impositionsTfus.isEmpty()) { - throw new BadRequestException("Une Imposition non annulée existe déjà"); + throw new BadRequestException("Une Imposition non annulée existe déjà ce centre et le même exercice "); } List statusAvis= new ArrayList<>(); statusAvis.add(StatusAvis.EN_COURS); diff --git a/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_irf_batie.sql b/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_irf_batie.sql index 44f6cac..668d400 100644 --- a/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_irf_batie.sql +++ b/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_irf_batie.sql @@ -1,4 +1,4 @@ -CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_irf_batie( +/*CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_irf_batie( p_impositions_tfu_id BIGINT, p_user_id BIGINT ) @@ -282,4 +282,348 @@ WHERE impositions_tfu_id = p_impositions_tfu_id ); RETURN v_rows_inserted; END; +$$;*/ + +CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_irf_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_valeur_locat_prof NUMERIC; + v_tfu_piscine_unitaire NUMERIC; + v_taux_irf NUMERIC; + v_taux_irf_ratio NUMERIC; -- v_taux_irf / 100 (pré-calculé) + 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_VALEUR_LOCATIVE_PROFESSIONNELLE'), + MAX(value) FILTER (WHERE name = 'TFU_PAR_PISCINE'), + MAX(value) FILTER (WHERE name = 'TAUX_IRF') + INTO STRICT + v_taux_defaut_sup_sol, + v_taux_valeur_locat_prof, + v_tfu_piscine_unitaire, + v_taux_irf + FROM parameters + WHERE name IN ( + 'TAUX_DEFAUT_SUPERFICIE_AU_SOL', + 'TAUX_VALEUR_LOCATIVE_PROFESSIONNELLE', + 'TFU_PAR_PISCINE', + 'TAUX_IRF' + ); + + -- Ratio pré-calculé pour éviter la division répétée dans le SELECT + v_taux_irf_ratio := v_taux_irf / 100.0; + + -- ------------------------------------------------------------------------- + -- 3. INSERT avec calcul direct 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, -- 0 pour IRF + valeur_locative_adm_sup_reel, + valeur_locative_adm, -- = montant_loyer_annuel pour IRF + tfu_superficie_au_sol_reel, -- 0 pour IRF + tfu_piscine, -- 0 pour IRF + montant_taxe, -- IRF finale = loyer * taux_irf + taux_tfu, -- = taux_irf pour IRF + parcelle_id, + batiment_id, + unite_logement_id, + superficie_au_sol_loue, + personne_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, + 'IRF', + 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 + ), + -- 🔧 IRF : champs TFU mis à 0 + 0, -- tfu_metre_carre + 0, -- 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 + (p.superficie * v_taux_defaut_sup_sol / 100.0) * brb.valeur_locative, + + -- 🔧 IRF : tfu_calcule_taux_prop_parc → 0 + 0, + + -- valeur_locative_adm_sup_reel + eb.superficie_au_sol * brb.valeur_locative, + + -- --------------------------------------------------------------- + -- 🔧 IRF : valeur_locative_adm = montant_loyer_annuel (calculé directement) + -- --------------------------------------------------------------- + COALESCE( + NULLIF(eb.montant_locatif_annuel_declare, 0), + NULLIF(eb.montant_locatif_annuel_calcule, 0), + NULLIF(eb.montant_locatif_annuel_estime, 0), + 0 + ), + + -- 🔧 IRF : tfu_superficie_au_sol_reel → 0 + 0, + + -- 🔧 IRF : tfu_piscine → 0 + 0, + + -- --------------------------------------------------------------- + -- 🔧 IRF : montant_taxe = montant_loyer_annuel * taux_irf (calculé directement) + -- --------------------------------------------------------------- + COALESCE( + NULLIF(eb.montant_locatif_annuel_declare, 0), + NULLIF(eb.montant_locatif_annuel_calcule, 0), + NULLIF(eb.montant_locatif_annuel_estime, 0), + 0 + ) * v_taux_irf_ratio, + + -- 🔧 IRF : taux_tfu → taux_irf + v_taux_irf, + p.id, + b.id, + NULL, + eb.superficie_louee, + ep.personne_id + 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 + + -- 🔧 IRF : Dernière enquête bâtiment avec filtre spécifique IRF + 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, + eb2.superficie_louee + FROM enquete_batiment eb2 + JOIN usage u ON u.id = eb2.usage_id + WHERE eb2.batiment_id = b.id + -- 🔧 IRF : Filtre spécifique + AND eb2.superficie_louee * eb2.montant_locatif_annuel_declare > 0 + 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; $$; + diff --git a/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_irf_batie_unite_logement.sql b/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_irf_batie_unite_logement.sql index 014a7bf..659a57b 100644 --- a/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_irf_batie_unite_logement.sql +++ b/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_irf_batie_unite_logement.sql @@ -1,4 +1,4 @@ -CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_irf_batie_unite_logement( +/*CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_irf_batie_unite_logement( p_impositions_tfu_id BIGINT, p_user_id BIGINT ) @@ -339,3 +339,303 @@ WHERE impositions_tfu_id = p_impositions_tfu_id RETURN v_rows_inserted; END; $$; + + */ + +CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_irf_batie_unite_logement( + 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_irf NUMERIC; + v_taux_irf_ratio NUMERIC; + + v_today DATE; +BEGIN + + v_today := CURRENT_DATE; + + -- 1. année + structure + 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. paramètres (UNE seule requête) + SELECT + MAX(value) FILTER (WHERE name = 'TAUX_DEFAUT_SUPERFICIE_AU_SOL'), + MAX(value) FILTER (WHERE name = 'TAUX_IRF') + INTO STRICT + v_taux_defaut_sup_sol, + v_taux_irf + FROM parameters + WHERE name IN ( + 'TAUX_DEFAUT_SUPERFICIE_AU_SOL', + 'TAUX_IRF' + ); + + v_taux_irf_ratio := v_taux_irf / 100.0; + + -- 3. INSERT optimisé + 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, + num_unite_logement, + 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, unite_logement_exonere, + standing_bat, categorie_bat, + nombre_piscine, + date_enquete, + structure_id, + zone_rfu_id, + nature_impot, + superficie_parc, + superficie_au_sol_bat, + superficie_au_sol_ulog, + 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, + valeur_locative_adm_taux_prop_parc, + tfu_calcule_taux_prop_parc, + valeur_locative_adm_sup_reel, + valeur_locative_adm, + tfu_superficie_au_sol_reel, + tfu_piscine, + montant_taxe, + taux_tfu, + parcelle_id, + batiment_id, + unite_logement_id, + superficie_au_sol_loue, + personne_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, ul.nul, + + eul.ifu, eul.npi, eul.tel1, eul.email, + eul.nom, eul.prenom, eul.raison_sociale, eul.adresse, + eul.representant_tel, eul.representant_nom, eul.representant_prenom, + + p.longitude, p.latitude, + TRUE, + + (v_today BETWEEN ep.date_debut_exemption AND COALESCE(ep.date_fin_exemption, v_today)), + (v_today BETWEEN eb.date_debut_excemption AND COALESCE(eb.date_fin_excemption, v_today)), + (v_today BETWEEN eul.date_debut_exemption AND COALESCE(eul.date_fin_exemption, v_today)), + + cb.standing, + cb.nom, + + COALESCE(eul.nombre_piscine, 0), + eul.date_enquete, + st.id, + ep.zone_rfu_id, + 'IRF', + + p.superficie, + eb.superficie_au_sol, + eul.superficie_au_sol, + + -- valeur logement + COALESCE( + NULLIF(eul.valeur_unite_logement_reel,0), + NULLIF(eul.valeur_unite_logement_calcule,0), + NULLIF(eul.valeur_unite_logement_estime,0), + 0 + ), + + brb.valeur_locative, + + -- loyer + COALESCE( + NULLIF(eul.montant_locatif_annuel_declare,0), + NULLIF(eul.montant_locatif_annuel_calcule,0), + NULLIF(eul.montant_locatif_annuel_estime,0), + 0 + ), + + 0, 0, + p_impositions_tfu_id, + FALSE, + v_today, p_user_id, 'FISCAD', + v_today, p_user_id, + eul.categorie_usage, + + p.superficie * v_taux_defaut_sup_sol / 100.0, + + (p.superficie * v_taux_defaut_sup_sol / 100.0) * brb.valeur_locative, + + 0, + + eul.superficie_au_sol * brb.valeur_locative, + + -- valeur locative = loyer + COALESCE( + NULLIF(eul.montant_locatif_annuel_declare,0), + NULLIF(eul.montant_locatif_annuel_calcule,0), + NULLIF(eul.montant_locatif_annuel_estime,0), + 0 + ), + + 0, 0, + + -- montant taxe direct (PLUS D'UPDATE) + COALESCE( + NULLIF(eul.montant_locatif_annuel_declare,0), + NULLIF(eul.montant_locatif_annuel_calcule,0), + NULLIF(eul.montant_locatif_annuel_estime,0), + 0 + ) * v_taux_irf_ratio, + + v_taux_irf, + p.id, + b.id, + ul.id, + eul.superficie_louee, + eul.personne_id + + FROM parcelle p + + LEFT JOIN LATERAL ( + SELECT * + FROM enquete e + WHERE e.parcelle_id = p.id + ORDER BY date_enquete DESC, id DESC + LIMIT 1 + ) ep ON TRUE + + 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 + + JOIN LATERAL ( + SELECT secteur_id + FROM secteur_decoupage + WHERE quartier_id = q.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 + + JOIN batiment b ON b.parcelle_id = p.id + JOIN unite_logement ul ON ul.batiment_id = b.id + + JOIN LATERAL ( + SELECT eult.unite_logement_id, + pers1.id, + pers1.ifu, + pers1.npi, + pers1.tel1, + pers1.email, + pers1.nom, + pers1.prenom, + pers1.raison_sociale, + pers1.adresse, + eult.nombre_piscine, + eult.categorie_batiment_id, + eult.superficie_au_sol, + eult.superficie_louee, + eult.nbre_piece, + eult.date_enquete, + eult.montant_locatif_annuel_calcule, + eult.montant_locatif_annuel_declare, + eult.montant_locatif_annuel_estime, + eult.date_debut_exemption, + eult.date_fin_exemption, + eult.representant_nom, + eult.representant_prenom, + eult.representant_tel, + eult.valeur_unite_logement_reel, + eult.valeur_unite_logement_calcule, + eult.valeur_unite_logement_estime, + u.categorie_usage, + pers1.id as personne_id + FROM enquete_unite_logement eult + LEFT JOIN personne pers1 ON pers1.id = eult.personne_id + join usage u on u.id=eult.usage_id + WHERE eult.unite_logement_id = ul.id + AND eult.superficie_louee * eult.montant_locatif_annuel_declare > 0 + ORDER BY date_enquete DESC, eult.id DESC + LIMIT 1 + ) eul ON TRUE + + JOIN LATERAL ( + SELECT * + FROM enquete_batiment eb2 + WHERE eb2.batiment_id = b.id + ORDER BY date_enquete DESC + LIMIT 1 + ) eb ON TRUE + + JOIN categorie_batiment cb ON cb.id = eul.categorie_batiment_id + + 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 st.id = v_structure_id + + ON CONFLICT DO NOTHING; + + GET DIAGNOSTICS v_rows_inserted = ROW_COUNT; + + RETURN v_rows_inserted; +END; +$$; diff --git a/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_srtb_batie.sql b/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_srtb_batie.sql index b9dffcd..b8cdcda 100644 --- a/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_srtb_batie.sql +++ b/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_srtb_batie.sql @@ -1,4 +1,4 @@ -CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_srtb_batie( +/*CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_srtb_batie( p_impositions_tfu_id BIGINT, p_user_id BIGINT ) @@ -259,6 +259,239 @@ GET DIAGNOSTICS v_rows_inserted = ROW_COUNT; RETURN v_rows_inserted; END; +$$; */ + +CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_srtb_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_montant_srtb NUMERIC; + v_today DATE; +BEGIN + + v_today := CURRENT_DATE; + + -- 1. année + structure + 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. paramètre (une seule requête) + SELECT value + INTO STRICT v_montant_srtb + FROM parameters + WHERE name = 'TAXE_SRTB'; + + -- 3. INSERT optimisé (SANS DISTINCT ON, SANS UPDATE) + 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, + valeur_locative_adm_taux_prop_parc, + tfu_calcule_taux_prop_parc, + valeur_locative_adm_sup_reel, + valeur_locative_adm, + tfu_superficie_au_sol_reel, + tfu_piscine, + montant_taxe, + taux_tfu, + parcelle_id, + batiment_id, + unite_logement_id, + superficie_au_sol_loue, + personne_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, + + (v_today BETWEEN ep.date_debut_exemption AND COALESCE(ep.date_fin_exemption, v_today)), + (v_today BETWEEN eb.date_debut_excemption AND COALESCE(eb.date_fin_excemption, v_today)), + + cb.standing, + cb.nom, + + COALESCE(eb.nombre_piscine, 0), + eb.date_enquete, + + st.id, + ep.zone_rfu_id, + 'SRTB', + + p.superficie, + eb.superficie_au_sol, + + -- valeur bâtiment optimisée + COALESCE( + NULLIF(eb.valeur_batiment_reel,0), + NULLIF(eb.valeur_batiment_calcule,0), + NULLIF(eb.valeur_batiment_estime,0), + 0 + ), + + brb.valeur_locative, + + -- loyer optimisé + 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, + + 0, 0, 0, + + eb.superficie_au_sol * brb.valeur_locative, + + 0, + 0, + 0, + + -- 🔥 SRTB = valeur directe (pas de calcul) + v_montant_srtb, + + 0, + + p.id, + b.id, + NULL, + eb.superficie_louee, + ep.personne_id + + FROM parcelle p + + -- dernière enquête parcelle + LEFT JOIN LATERAL ( + SELECT * + FROM enquete e + WHERE e.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 + + -- structure via secteur + JOIN LATERAL ( + SELECT secteur_id + FROM secteur_decoupage + WHERE quartier_id = q.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 + + JOIN batiment b ON b.parcelle_id = p.id + + -- 🔥 remplace DISTINCT ON + JOIN LATERAL ( + SELECT eb2.*,u.categorie_usage + FROM enquete_batiment eb2 + LEFT 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 + + 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 NOT EXISTS ( + SELECT 1 + FROM unite_logement ul + WHERE ul.batiment_id = b.id + ) + AND st.id = v_structure_id + + ON CONFLICT DO NOTHING; + + GET DIAGNOSTICS v_rows_inserted = ROW_COUNT; + + RETURN v_rows_inserted; +END; $$; diff --git a/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_srtb_batie_unite_logement.sql b/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_srtb_batie_unite_logement.sql index 18a81e3..868a3ad 100644 --- a/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_srtb_batie_unite_logement.sql +++ b/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_srtb_batie_unite_logement.sql @@ -1,4 +1,4 @@ -CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_srtb_batie_unite_logement( +/*CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_srtb_batie_unite_logement( p_impositions_tfu_id BIGINT, p_user_id BIGINT ) @@ -309,3 +309,239 @@ RETURN v_rows_inserted; END; $$; + */ + +CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_srtb_batie_unite_logement( + 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_montant_srtb NUMERIC; + v_today DATE; +BEGIN + + v_today := CURRENT_DATE; + + -- 1. année + structure + 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. paramètre + SELECT value + INTO STRICT v_montant_srtb + FROM parameters + WHERE name = 'TAXE_SRTB'; + + -- 3. INSERT optimisé + 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, num_unite_logement, + 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, unite_logement_exonere, + standing_bat, categorie_bat, + nombre_piscine, + date_enquete, + structure_id, + zone_rfu_id, + nature_impot, + superficie_parc, + superficie_au_sol_bat, + superficie_au_sol_ulog, + 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, + valeur_locative_adm_taux_prop_parc, + tfu_calcule_taux_prop_parc, + valeur_locative_adm_sup_reel, + valeur_locative_adm, + tfu_superficie_au_sol_reel, + tfu_piscine, + montant_taxe, + taux_tfu, + parcelle_id, + batiment_id, + unite_logement_id, + superficie_au_sol_loue + ) + 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, + ul.nul, + + eul.ifu, eul.npi, eul.tel1, eul.email, + eul.nom, eul.prenom, eul.raison_sociale, eul.adresse, + eul.representant_tel, eul.representant_nom, eul.representant_prenom, + + p.longitude, p.latitude, + TRUE, + + (v_today BETWEEN ep.date_debut_exemption AND COALESCE(ep.date_fin_exemption, v_today)), + (v_today BETWEEN eb.date_debut_excemption AND COALESCE(eb.date_fin_excemption, v_today)), + (v_today BETWEEN eul.date_debut_exemption AND COALESCE(eul.date_fin_exemption, v_today)), + + cb.standing, + cb.nom, + + COALESCE(eul.nombre_piscine, 0), + eul.date_enquete, + + st.id, + ep.zone_rfu_id, + 'SRTB', + + p.superficie, + eb.superficie_au_sol, + eul.superficie_au_sol, + + -- valeur logement optimisée + COALESCE( + NULLIF(eul.valeur_unite_logement_reel,0), + NULLIF(eul.valeur_unite_logement_calcule,0), + NULLIF(eul.valeur_unite_logement_estime,0), + 0 + ), + + brb.valeur_locative, + + -- loyer optimisé + COALESCE( + NULLIF(eul.montant_locatif_annuel_declare,0), + NULLIF(eul.montant_locatif_annuel_calcule,0), + NULLIF(eul.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, + + eul.categorie_usage, + + 0, 0, 0, + + eul.superficie_au_sol * brb.valeur_locative, + + 0, + 0, + 0, + + -- 🔥 SRTB direct + v_montant_srtb, + + 0, + + p.id, + b.id, + ul.id, + eul.superficie_louee + + FROM parcelle p + + LEFT JOIN LATERAL ( + SELECT * + FROM enquete e + WHERE e.parcelle_id = p.id + ORDER BY date_enquete DESC, id DESC + LIMIT 1 + ) ep ON TRUE + + 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 + + JOIN LATERAL ( + SELECT secteur_id + FROM secteur_decoupage + WHERE quartier_id = q.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 + + JOIN batiment b ON b.parcelle_id = p.id + JOIN unite_logement ul ON ul.batiment_id = b.id + + -- 🔥 remplace DISTINCT ON + JOIN LATERAL ( + SELECT eult.*, pers1.*,u.categorie_usage + FROM enquete_unite_logement eult + LEFT JOIN usage u on eult.usage_id = u.id + LEFT JOIN personne pers1 ON pers1.id = eult.personne_id + WHERE eult.unite_logement_id = ul.id + ORDER BY date_enquete DESC, eult.id DESC + LIMIT 1 + ) eul ON TRUE + + JOIN LATERAL ( + SELECT eb2.* + FROM enquete_batiment eb2 + WHERE eb2.batiment_id = b.id + ORDER BY date_enquete DESC + LIMIT 1 + )eb ON TRUE + JOIN categorie_batiment cb ON cb.id = eb.categorie_batiment_id + + 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 st.id = v_structure_id + + ON CONFLICT DO NOTHING; + + GET DIAGNOSTICS v_rows_inserted = ROW_COUNT; + + RETURN v_rows_inserted; +END; +$$; diff --git a/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_tfu_batie_unite_logement.sql b/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_tfu_batie_unite_logement.sql index 9b3989e..8bd6525 100644 --- a/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_tfu_batie_unite_logement.sql +++ b/src/main/java/io/gmss/fiscad/persistence/procedure_fonction_stocke/generer_donnees_imposition_tfu_batie_unite_logement.sql @@ -1,4 +1,4 @@ -CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_tfu_batie_unite_logement( +/*CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_tfu_batie_unite_logement( p_impositions_tfu_id BIGINT, p_user_id BIGINT ) @@ -392,4 +392,464 @@ WHERE impositions_tfu_id = p_impositions_tfu_id ); RETURN v_rows_inserted; END; -$$; \ No newline at end of file +$$;*/ +CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_tfu_batie_unite_logement( + 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, + num_unite_logement, + 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, + unite_logement_exonere, + standing_bat, + categorie_bat, + nombre_piscine, + date_enquete, + structure_id, + zone_rfu_id, + nature_impot, + superficie_parc, + superficie_au_sol_bat, + superficie_au_sol_ulog, + 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, + ul.nul, + eul.ifu, + eul.npi, + eul.tel1, + eul.email, + eul.nom, + eul.prenom, + eul.raison_sociale, + eul.adresse, + eul.representant_tel, + eul.representant_nom, + eul.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)), + -- exonere unite logement + (v_today BETWEEN eul.date_debut_exemption + AND COALESCE(eul.date_fin_exemption, v_today)), + cb.standing, + cb.nom, + COALESCE(eul.nombre_piscine, 0), + eul.date_enquete, + st.id, + ep.zone_rfu_id, + 'TFU', + p.superficie, + eb.superficie_au_sol, + eul.superficie_au_sol, + -- valeur_batiment (unité logement) : première valeur non nulle non zéro + COALESCE( + NULLIF(eul.valeur_unite_logement_reel, 0), + NULLIF(eul.valeur_unite_logement_calcule, 0), + NULLIF(eul.valeur_unite_logement_estime, 0), + 0 + ), + brb.valeur_locative, + -- montant_loyer_annuel + COALESCE( + NULLIF(eul.montant_locatif_annuel_declare, 0), + NULLIF(eul.montant_locatif_annuel_calcule, 0), + NULLIF(eul.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, + eul.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 eul.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 eul.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 eul.categorie_usage = 'HABITATION' + THEN eul.superficie_au_sol * brb.valeur_locative + ELSE 0 + END, + + -- --------------------------------------------------------------- + -- valeur_locative_adm avec tests explicites (corrigée) + -- --------------------------------------------------------------- + CASE + WHEN eul.categorie_usage = 'HABITATION' + AND eul.superficie_au_sol <> 0 + THEN eul.superficie_au_sol * brb.valeur_locative + + WHEN eul.categorie_usage = 'HABITATION' + AND eul.superficie_au_sol = 0 + THEN (p.superficie * v_taux_defaut_sup_sol / 100.0) * brb.valeur_locative + + -- ✅ Test explicite : valeur_unite_logement <> 0 + WHEN eul.categorie_usage IN ('PROFESSIONNELLE', 'MIXTE') + AND COALESCE(NULLIF(eul.valeur_unite_logement_reel, 0), + NULLIF(eul.valeur_unite_logement_calcule, 0), + NULLIF(eul.valeur_unite_logement_estime, 0), 0) <> 0 + THEN COALESCE(NULLIF(eul.valeur_unite_logement_reel, 0), + NULLIF(eul.valeur_unite_logement_calcule, 0), + NULLIF(eul.valeur_unite_logement_estime, 0), 0) + * v_taux_vlp_ratio + + -- ✅ Test explicite : valeur_unite_logement = 0 + WHEN eul.categorie_usage IN ('PROFESSIONNELLE', 'MIXTE') + AND COALESCE(NULLIF(eul.valeur_unite_logement_reel, 0), + NULLIF(eul.valeur_unite_logement_calcule, 0), + NULLIF(eul.valeur_unite_logement_estime, 0), 0) = 0 + THEN COALESCE(NULLIF(eul.montant_locatif_annuel_declare, 0), + NULLIF(eul.montant_locatif_annuel_calcule, 0), + NULLIF(eul.montant_locatif_annuel_estime, 0), 0) + + ELSE 0 + END, + + -- 🔧 CORRECTION : tfu_superficie_au_sol_reel (était hardcodé à 6/100) + CASE WHEN eul.categorie_usage = 'HABITATION' + THEN eul.superficie_au_sol * brb.valeur_locative * v_taux_tfu_ratio + ELSE 0 + END, + + -- tfu_piscine + COALESCE(eul.nombre_piscine, 0) * v_tfu_piscine_unitaire, + + -- --------------------------------------------------------------- + -- montant_taxe ← calculé directement (plus d'UPDATE) + -- --------------------------------------------------------------- + ( + WITH calc AS ( + SELECT + COALESCE(NULLIF(eul.valeur_unite_logement_reel, 0), + NULLIF(eul.valeur_unite_logement_calcule, 0), + NULLIF(eul.valeur_unite_logement_estime, 0), 0) AS valeur_ul, + COALESCE(NULLIF(eul.montant_locatif_annuel_declare, 0), + NULLIF(eul.montant_locatif_annuel_calcule, 0), + NULLIF(eul.montant_locatif_annuel_estime, 0), 0) AS loyer, + eul.superficie_au_sol * brb.valeur_locative AS vla_reel, + (p.superficie * v_taux_defaut_sup_sol / 100.0) + * brb.valeur_locative AS vla_70, + COALESCE(eul.nombre_piscine, 0) * v_tfu_piscine_unitaire AS piscine_montant + ) + SELECT + CASE + WHEN eul.categorie_usage = 'HABITATION' + AND eul.superficie_au_sol <> 0 + THEN GREATEST(brb.tfu_minimum, + calc.vla_reel * v_taux_tfu_ratio + + calc.piscine_montant) + + WHEN eul.categorie_usage = 'HABITATION' + AND eul.superficie_au_sol = 0 + THEN GREATEST(brb.tfu_minimum, + calc.vla_70 * v_taux_tfu_ratio + + calc.piscine_montant) + + WHEN eul.categorie_usage IN ('PROFESSIONNELLE', 'MIXTE') + AND calc.valeur_ul <> 0 + THEN GREATEST(brb.tfu_minimum, + calc.valeur_ul * v_taux_vlp_ratio * v_taux_tfu_ratio) + + WHEN eul.categorie_usage IN ('PROFESSIONNELLE', 'MIXTE') + AND calc.valeur_ul = 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, + ul.id + + 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 + 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 + + JOIN batiment b ON b.parcelle_id = p.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 unite_logement ul ON ul.batiment_id = b.id + + -- Dernière enquête unité logement + JOIN LATERAL ( + SELECT + eul2.unite_logement_id, + pers1.id, + pers1.ifu, + pers1.npi, + pers1.tel1, + pers1.email, + pers1.nom, + pers1.prenom, + pers1.raison_sociale, + pers1.adresse, + eul2.nombre_piscine, + eul2.categorie_batiment_id, + eul2.superficie_au_sol, + eul2.superficie_louee, + eul2.nbre_piece, + eul2.date_enquete, + eul2.montant_locatif_annuel_calcule, + eul2.montant_locatif_annuel_declare, + eul2.montant_locatif_annuel_estime, + eul2.date_debut_exemption, + eul2.date_fin_exemption, + eul2.representant_nom, + eul2.representant_prenom, + eul2.representant_tel, + eul2.valeur_unite_logement_reel, + eul2.valeur_unite_logement_calcule, + eul2.valeur_unite_logement_estime, + u.categorie_usage + FROM enquete_unite_logement eul2 + JOIN usage u ON u.id = eul2.usage_id + LEFT JOIN personne pers1 ON pers1.id = eul2.personne_id + WHERE eul2.unite_logement_id = ul.id + ORDER BY eul2.date_enquete DESC, eul2.id DESC + LIMIT 1 + ) eul ON TRUE + + JOIN categorie_batiment cb ON cb.id = eul.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 EXISTS ( + SELECT 1 + FROM unite_logement ul2 + WHERE ul2.batiment_id = b.id + ) + AND st.id = v_structure_id + + ON CONFLICT DO NOTHING; + + GET DIAGNOSTICS v_rows_inserted = ROW_COUNT; + + RETURN v_rows_inserted; +END; +$$; + diff --git a/src/main/java/io/gmss/fiscad/persistence/repositories/rfu/metier/ImpositionsTfuRepository.java b/src/main/java/io/gmss/fiscad/persistence/repositories/rfu/metier/ImpositionsTfuRepository.java index eec90a9..292c544 100755 --- a/src/main/java/io/gmss/fiscad/persistence/repositories/rfu/metier/ImpositionsTfuRepository.java +++ b/src/main/java/io/gmss/fiscad/persistence/repositories/rfu/metier/ImpositionsTfuRepository.java @@ -33,7 +33,7 @@ public interface ImpositionsTfuRepository extends JpaRepository getImpositionsTfuByStructureAndExercice(Long structureId,Long exerciceId);