develop #203

Merged
judaur2005 merged 2 commits from develop into main 2026-04-24 13:55:42 +00:00
25 changed files with 4662 additions and 1251 deletions
Showing only changes of commit 49aea6e50a - Show all commits

View File

@@ -333,6 +333,59 @@ public class DonneesImpositionTfuController {
} }
@Operation(
summary = "Générer les données fiscales TFU pour une seule parcelle",
description = "Génère les impositions TFU pour une parcelle bâtie donnée"
)
@PostMapping("/generer-batie/{parcelleId}")
public ResponseEntity<?> genererDonneesFiscaleBatieUneParcelle(@CurrentUser UserPrincipal userPrincipal, @RequestBody ImpositionsTfuPaylaodWeb impositionsTfuPaylaodWeb,@PathVariable Long parcelleId) {
try {
Optional<ImpositionsTfu> optionalImpositionsTfu =impositionsTfuRepository.findById(impositionsTfuPaylaodWeb.getId());
if(optionalImpositionsTfu.isEmpty()){
return new ResponseEntity<>(
new ApiResponse<>(false, null, "L'instance d'imposition n'est pas trouvée."),
HttpStatus.OK
);
}
// if(!optionalImpositionsTfu.get().getStatusAvis().equals(StatusAvis.TFU_FNB_GENERE)){
// return new ResponseEntity<>(
// new ApiResponse<>(false, null, "l'état actuel : "+optionalImpositionsTfu.get().getStatusAvis()+" ne permet pas cette opération."),
// HttpStatus.OK
// );
// }
if(userPrincipal==null){
return new ResponseEntity<>(
new ApiResponse<>(false, null, "Vous n'êtes pas autorisé à accéder à cette ressource"),
HttpStatus.OK
);
}
impositionsTfuPaylaodWeb=donneesImpositionTfuService.genererDonneesFiscalesParcelleBatieUneParcelle(impositionsTfuPaylaodWeb,userPrincipal.getUser().getId(),parcelleId);
return new ResponseEntity<>(
new ApiResponse<>(true,impositionsTfuPaylaodWeb, "Données d'imposition des fonciers batis Générées avec succès."),
HttpStatus.OK
);
} catch (HttpClientErrorException.MethodNotAllowed e) {
logger.error(e.getLocalizedMessage());
return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
} catch (NotFoundException | BadRequestException | MyFileNotFoundException | ResourceNotFoundException |
FileStorageException e) {
logger.error(e.getLocalizedMessage());
return new ResponseEntity<>(new ApiResponse(false, null, e.getMessage()), HttpStatus.OK);
} catch (NullPointerException e) {
logger.error(e.getLocalizedMessage());
return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
} catch (Exception e) {
logger.error(e.getLocalizedMessage());
return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
}
}
@Operation(summary = "Générer les données fiscales TFU des parcelle baties") @Operation(summary = "Générer les données fiscales TFU des parcelle baties")
@@ -384,6 +437,59 @@ public class DonneesImpositionTfuController {
} }
} }
@Operation(
summary = "Générer les données fiscales TFU pour une seule parcelle",
description = "Génère les impositions TFU pour une parcelle non bâtie donnée"
)
@PostMapping("/generer-non-batie/{parcelleId}")
public ResponseEntity<?> genererDonneesImpositionNonBatiesUneParcelle(@CurrentUser UserPrincipal userPrincipal, @RequestBody ImpositionsTfuPaylaodWeb impositionsTfuPaylaodWeb, @PathVariable Long parcelleId) {
try {
Optional<ImpositionsTfu> optionalImpositionsTfu =impositionsTfuRepository.findById(impositionsTfuPaylaodWeb.getId());
if(optionalImpositionsTfu.isEmpty()){
return new ResponseEntity<>(
new ApiResponse<>(false, null, "L'instance d'imposition n'est pas trouvée."),
HttpStatus.OK
);
}
// if(!optionalImpositionsTfu.get().getStatusAvis().equals(StatusAvis.GENERATION_AUTORISE)){
// return new ResponseEntity<>(
// new ApiResponse<>(false, null, "l'état actuel : "+optionalImpositionsTfu.get().getStatusAvis()+" ne permet pas cette opération."),
// HttpStatus.OK
// );
// }
if(userPrincipal==null){
return new ResponseEntity<>(
new ApiResponse<>(false, null, "Vous n'êtes pas autorisé à accéder à cette ressource"),
HttpStatus.OK
);
}
impositionsTfuPaylaodWeb=donneesImpositionTfuService.genererDonneesFiscalesParcelleNonBatieUneParcelle(impositionsTfuPaylaodWeb,userPrincipal.getUser().getId(),parcelleId);
return new ResponseEntity<>(
new ApiResponse<>(true,impositionsTfuPaylaodWeb, "Données d'imposition pour les fonciers non batis Générées avec succès."),
HttpStatus.OK
);
} catch (HttpClientErrorException.MethodNotAllowed e) {
logger.error(e.getLocalizedMessage());
return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
} catch (NotFoundException | BadRequestException | MyFileNotFoundException | ResourceNotFoundException |
FileStorageException e) {
logger.error(e.getLocalizedMessage());
return new ResponseEntity<>(new ApiResponse(false, null, e.getMessage()), HttpStatus.OK);
} catch (NullPointerException e) {
logger.error(e.getLocalizedMessage());
return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
} catch (Exception e) {
logger.error(e.getLocalizedMessage());
return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
}
}
@Operation(summary = "Récuperer les avis d'id d'une imposition") @Operation(summary = "Récuperer les avis d'id d'une imposition")
@GetMapping("/by-impositions-id/{impositionsId}") @GetMapping("/by-impositions-id/{impositionsId}")
public ResponseEntity<?> getDonneesFiscale(@PathVariable Long impositionsId) { public ResponseEntity<?> getDonneesFiscale(@PathVariable Long impositionsId) {

View File

@@ -114,6 +114,7 @@ public class DonneesImpositionTfu extends BaseEntity implements Serializable {
private Float tauxTfu; private Float tauxTfu;
private Long tfuPiscine; private Long tfuPiscine;
private Float montantTaxe; private Float montantTaxe;
private Float montantTaxeBrut; //montant de la taxe calculée sans comparaisons avec TFU MINI
private Float tfuCalculeTauxPropParc; private Float tfuCalculeTauxPropParc;
private Float tfuSuperficieAuSolReel; private Float tfuSuperficieAuSolReel;
private Long valeurAdminParcelleNbMetreCarre; private Long valeurAdminParcelleNbMetreCarre;
@@ -146,5 +147,6 @@ public class DonneesImpositionTfu extends BaseEntity implements Serializable {
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
private Personne personne ; private Personne personne ;
private Boolean parcelleContact;
} }

View File

@@ -1,7 +1,8 @@
package io.gmss.fiscad.enums; package io.gmss.fiscad.enums;
public enum NatureImpot { public enum NatureImpot {
TFU, FB,
FNB,
IRF, IRF,
SRTB SRTB
} }

View File

@@ -109,21 +109,66 @@ public class DonneesImpositionTfuServiceImpl implements DonneesImpositionTfuServ
return impositionsTfuRepository.findByIdToDto(impositionsTfu.getId()).orElse(null); return impositionsTfuRepository.findByIdToDto(impositionsTfu.getId()).orElse(null);
} }
@Override
@Transactional
public ImpositionsTfuPaylaodWeb genererDonneesFiscalesParcelleNonBatieUneParcelle(ImpositionsTfuPaylaodWeb impositionsTfuPaylaodWeb, Long userId,Long parcelleId) {
Integer nb= donneesImpositionTfuRepository.genererDonneesTfuNonBatie(impositionsTfuPaylaodWeb.getId(),userId,parcelleId);
ImpositionsTfu impositionsTfu = entityFromPayLoadService.getImpositionsTfuFromPayLoadWeb(impositionsTfuPaylaodWeb);
impositionsTfu.setStatusAvis(StatusAvis.TFU_FNB_GENERE);
impositionsTfu.setNombreAvisFnb(nb);
impositionsTfuRepository.save(impositionsTfu);
return impositionsTfuRepository.findByIdToDto(impositionsTfu.getId()).orElse(null);
}
@Override @Override
@Transactional @Transactional
public ImpositionsTfuPaylaodWeb genererDonneesFiscalesParcelleBatie(ImpositionsTfuPaylaodWeb impositionsTfuPaylaodWeb, Long userId) { public ImpositionsTfuPaylaodWeb genererDonneesFiscalesParcelleBatie(ImpositionsTfuPaylaodWeb impositionsTfuPaylaodWeb, Long userId) {
Integer nbb= donneesImpositionTfuRepository.genererDonneesTfuBatie(impositionsTfuPaylaodWeb.getId(),userId); Integer nbb= donneesImpositionTfuRepository.genererDonneesTfuBatie(impositionsTfuPaylaodWeb.getId(),userId);
Integer nbirfbtPlusieursBati = donneesImpositionTfuRepository.majDonneesTfuBatiePlusieursBatiment(impositionsTfuPaylaodWeb.getId());
Integer nbulo= donneesImpositionTfuRepository.genererDonneesTfuBatieUniteLogement(impositionsTfuPaylaodWeb.getId(),userId); 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);
ImpositionsTfu impositionsTfu = entityFromPayLoadService.getImpositionsTfuFromPayLoadWeb(impositionsTfuPaylaodWeb);
impositionsTfu.setStatusAvis(StatusAvis.GENERE);
impositionsTfu.setNombreAvis(nbb+nbulo+ (impositionsTfu.getNombreAvisFnb()==null?0:impositionsTfu.getNombreAvisFnb()));
impositionsTfu.setNombreAvisBatiment(nbb);
impositionsTfu.setNombreAvisUniteLog(nbulo);
impositionsTfuRepository.save(impositionsTfu);
return impositionsTfuRepository.findByIdToDto(impositionsTfu.getId()).orElse(null);
}
@Override
@Transactional
public ImpositionsTfuPaylaodWeb genererDonneesFiscalesParcelleBatieUneParcelle(ImpositionsTfuPaylaodWeb impositionsTfuPaylaodWeb, Long userId, Long parcelleId) {
Integer nbb= donneesImpositionTfuRepository.genererDonneesTfuBatie(impositionsTfuPaylaodWeb.getId(),userId,parcelleId);
Integer nbirfbtPlusieursBati = donneesImpositionTfuRepository.majDonneesTfuBatiePlusieursBatiment(impositionsTfuPaylaodWeb.getId(),parcelleId);
Integer nbulo= donneesImpositionTfuRepository.genererDonneesTfuBatieUniteLogement(impositionsTfuPaylaodWeb.getId(),userId,parcelleId);
Integer nbirfbt= donneesImpositionTfuRepository.genererDonneesIrfBatie(impositionsTfuPaylaodWeb.getId(),userId,parcelleId);
Integer nbirfulo= donneesImpositionTfuRepository.genererDonneesIrfBatieUniteLogement(impositionsTfuPaylaodWeb.getId(),userId,parcelleId);
Integer nbsrtbbt= donneesImpositionTfuRepository.genererDonneesSrtbBatie(impositionsTfuPaylaodWeb.getId(),userId,parcelleId);
ImpositionsTfu impositionsTfu = entityFromPayLoadService.getImpositionsTfuFromPayLoadWeb(impositionsTfuPaylaodWeb); ImpositionsTfu impositionsTfu = entityFromPayLoadService.getImpositionsTfuFromPayLoadWeb(impositionsTfuPaylaodWeb);

View File

@@ -27,6 +27,7 @@ public interface DonneesImpositionTfuService {
ImpositionsTfuPaylaodWeb genererDonneesFiscalesParcelleBatie(ImpositionsTfuPaylaodWeb impositionsTfuPaylaodWeb,Long userId); ImpositionsTfuPaylaodWeb genererDonneesFiscalesParcelleBatie(ImpositionsTfuPaylaodWeb impositionsTfuPaylaodWeb,Long userId);
ImpositionsTfuPaylaodWeb genererDonneesFiscalesParcelleNonBatie(ImpositionsTfuPaylaodWeb impositionsTfuPaylaodWeb,Long userId); ImpositionsTfuPaylaodWeb genererDonneesFiscalesParcelleNonBatie(ImpositionsTfuPaylaodWeb impositionsTfuPaylaodWeb,Long userId);
public ImpositionsTfuPaylaodWeb genererDonneesFiscalesParcelleNonBatieUneParcelle(ImpositionsTfuPaylaodWeb impositionsTfuPaylaodWeb, Long userId,Long parcelleId);
List<DonneesImpositionPaylaodWeb> getDonneesFiscalesByImposition(Long impositionsId); List<DonneesImpositionPaylaodWeb> getDonneesFiscalesByImposition(Long impositionsId);
List<DonneesImpositionTfu> getDonneesFiscalesByImpositionArrondissement(Long impositionsId,Long arrondissementId); List<DonneesImpositionTfu> getDonneesFiscalesByImpositionArrondissement(Long impositionsId,Long arrondissementId);
Page<DonneesImpositionPaylaodWeb> getDonneesFiscalesByImpositionTfuIdPageable(Long impositionsTfuId, Pageable pageable); Page<DonneesImpositionPaylaodWeb> getDonneesFiscalesByImpositionTfuIdPageable(Long impositionsTfuId, Pageable pageable);
@@ -47,5 +48,7 @@ public interface DonneesImpositionTfuService {
List<DonneesImpositionPaylaodWeb> getDonneesFiscalesByPersonneId(Long personneId); List<DonneesImpositionPaylaodWeb> getDonneesFiscalesByPersonneId(Long personneId);
public ImpositionsTfuPaylaodWeb genererDonneesFiscalesParcelleBatieUneParcelle(ImpositionsTfuPaylaodWeb impositionsTfuPaylaodWeb, Long userId, Long parcelleId);
} }

View File

@@ -0,0 +1,497 @@
/*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;
BEGIN
-- récupération de l'anné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;
select value
into STRICT v_montant_srtb
from parameters
where name ='TAXE_SRTB';
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% de la surperficie au sol de la parcelle
valeur_locative_adm_taux_prop_parc,
tfu_calcule_taux_prop_parc, ----tfu correspondant au 70%
valeur_locative_adm_sup_reel,
valeur_locative_adm, ----------valeur locative administrative
tfu_superficie_au_sol_reel, ----tfu correspondant à la superficie au sol reelle
tfu_piscine,
montant_taxe, ----tfu finale
taux_tfu, ----taux tfu batie
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,
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,
(
CURRENT_DATE >= ep.date_debut_exemption
AND CURRENT_DATE <= COALESCE(ep.date_fin_exemption, CURRENT_DATE)
),
(
CURRENT_DATE >= eb.date_debut_excemption
AND CURRENT_DATE <= COALESCE(eb.date_fin_excemption, CURRENT_DATE)
),
cb.standing,
cb.nom,
eb.nombre_piscine,
eb.date_enquete,
st.id,
ep.zone_rfu_id,
'SRTB',
p.superficie,
eb.superficie_au_sol,
case -------valeur_batiment
WHEN eb.valeur_batiment_reel IS NOT NULL AND eb.valeur_batiment_reel <> 0 THEN eb.valeur_batiment_reel
WHEN eb.valeur_batiment_calcule IS NOT NULL AND eb.valeur_batiment_calcule <> 0 THEN eb.valeur_batiment_calcule
WHEN eb.valeur_batiment_estime IS NOT NULL AND eb.valeur_batiment_estime <> 0 THEN eb.valeur_batiment_estime
ELSE 0
END,
brb.valeur_locative,
case ----- montant_loyer_annuel
WHEN eb.montant_locatif_annuel_declare IS NOT NULL AND eb.montant_locatif_annuel_declare <> 0 THEN eb.montant_locatif_annuel_declare
WHEN eb.montant_locatif_annuel_calcule IS NOT NULL AND eb.montant_locatif_annuel_calcule <> 0 THEN eb.montant_locatif_annuel_calcule
WHEN eb.montant_locatif_annuel_estime IS NOT NULL AND eb.montant_locatif_annuel_estime <> 0 THEN eb.montant_locatif_annuel_estime
ELSE 0
END,
brb.tfu_metre_carre,
brb.tfu_minimum,
p_impositions_tfu_id,
false,
current_date ,
p_user_id ,
'FISCAD',
current_date ,
p_user_id,
eb.categorie_usage,
0,---superficie_au_sol_70pour100
0,
0,
eb.superficie_au_sol * brb.valeur_locative,
0, ------ valeur_locative_adm : en attente de update
0,
0,
v_montant_srtb,
0,
p.id,
b.id,
null,
eb.superficie_louee
FROM parcelle p
LEFT JOIN (
SELECT DISTINCT ON (parcelle_id)
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
ORDER BY parcelle_id, date_enquete DESC, id DESC
) ep ON ep.parcelle_id = p.id
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
--JOIN secteur_decoupage sd ON sd.quartier_id = q.id
JOIN (
SELECT DISTINCT ON (quartier_id)
quartier_id,
secteur_id
FROM secteur_decoupage
ORDER BY quartier_id
) sd ON sd.quartier_id = q.id
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 (
SELECT DISTINCT ON (batiment_id)
batiment_id,
superficie_au_sol,
nombre_piscine,
categorie_batiment_id,
date_enquete,
montant_locatif_annuel_declare,
montant_locatif_annuel_calcule,
montant_locatif_annuel_estime,
date_debut_excemption,
date_fin_excemption,
valeur_batiment_reel,
valeur_batiment_calcule,
valeur_batiment_estime,
u.categorie_usage,
superficie_louee
FROM enquete_batiment eb
join usage u on u.id=eb.usage_id
ORDER BY batiment_id, date_enquete DESC, eb.id DESC
) eb ON eb.batiment_id = b.id
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;
$$; */
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;
$$;

View File

@@ -0,0 +1,754 @@
/*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_valeur_locat_prof NUMERIC;
v_tfu_piscine_unitaire NUMERIC;
BEGIN
-- récupération de l'anné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;
select value
into strict v_taux_defaut_sup_sol
from parameters
where name ='TAUX_DEFAUT_SUPERFICIE_AU_SOL';
select value
into STRICT v_taux_tfu
from parameters
where name ='TAUX_TFU';
select value
into STRICT v_taux_valeur_locat_prof
from parameters
where name ='TAUX_VALEUR_LOCATIVE_PROFESSIONNELLE';
select value
into STRICT v_tfu_piscine_unitaire
from parameters
where name ='TFU_PAR_PISCINE';
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% de la surperficie au sol de la parcelle
valeur_locative_adm_taux_prop_parc,
tfu_calcule_taux_prop_parc, ----tfu correspondant au 70%
valeur_locative_adm_sup_reel,
valeur_locative_adm, ----------valeur locative administrative
tfu_superficie_au_sol_reel, ----tfu correspondant à la superficie au sol reelle
tfu_piscine,
montant_taxe, ----tfu finale
taux_tfu, ----taux tfu batie
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,
(
CURRENT_DATE >= ep.date_debut_exemption
AND CURRENT_DATE <= COALESCE(ep.date_fin_exemption, CURRENT_DATE)
),
(
CURRENT_DATE >= eb.date_debut_excemption
AND CURRENT_DATE <= COALESCE(eb.date_fin_excemption, CURRENT_DATE)
),
cb.standing,
cb.nom,
eb.nombre_piscine,
eb.date_enquete,
st.id,
ep.zone_rfu_id,
'TFU',
p.superficie,
eb.superficie_au_sol,
COALESCE(
NULLIF(eb.valeur_batiment_reel, 0),
NULLIF(eb.valeur_batiment_calcule, 0),
NULLIF(eb.valeur_batiment_estime, 0),
0
),
brb.valeur_locative,
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,
current_date ,
p_user_id ,
'FISCAD',
current_date ,
p_user_id,
eb.categorie_usage,
p.superficie*v_taux_defaut_sup_sol/100,---superficie_au_sol_70pour100
case ----valeur_locative_adm70pour100
when eb.categorie_usage = 'HABITATION' then (p.superficie * v_taux_defaut_sup_sol/100) * brb.valeur_locative
else 0
end,
case ----tfu calcule 70 pour 100 superficie parcelle
when eb.categorie_usage= 'HABITATION' then (p.superficie * v_taux_defaut_sup_sol/100) * brb.valeur_locative * v_taux_tfu/100
else 0
end,
case -----valeur_locative_adm_sup_reel
when eb.categorie_usage='HABITATION' then eb.superficie_au_sol * brb.valeur_locative
else 0
end,
0, ------ valeur_locative_adm : en attente de update
case -----tfu_superficie_au_sol_reel
when eb.categorie_usage='HABITATION' then eb.superficie_au_sol * brb.valeur_locative * v_taux_tfu/100 +eb.nombre_piscine * v_tfu_piscine_unitaire
else 0
end,
eb.nombre_piscine * v_tfu_piscine_unitaire,
0,
v_taux_tfu,
p.id,
b.id,
null
FROM parcelle p
LEFT JOIN (
SELECT DISTINCT ON (parcelle_id)
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
ORDER BY parcelle_id, date_enquete DESC, id DESC
) ep ON ep.parcelle_id = p.id
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
--JOIN secteur_decoupage sd ON sd.quartier_id = q.id
JOIN (
SELECT DISTINCT ON (quartier_id)
quartier_id,
secteur_id
FROM secteur_decoupage
ORDER BY quartier_id
) sd ON sd.quartier_id = q.id
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 (
SELECT DISTINCT ON (batiment_id)
batiment_id,
superficie_au_sol,
nombre_piscine,
categorie_batiment_id,
date_enquete,
montant_locatif_annuel_declare,
montant_locatif_annuel_calcule,
montant_locatif_annuel_estime,
date_debut_excemption,
date_fin_excemption,
valeur_batiment_reel,
valeur_batiment_calcule,
valeur_batiment_estime,
u.categorie_usage
FROM enquete_batiment eb
join usage u on u.id=eb.usage_id
ORDER BY batiment_id, date_enquete DESC, eb.id DESC
) eb ON eb.batiment_id = b.id
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;
UPDATE donnees_imposition_tfu dtfu
SET
valeur_locative_adm =
CASE
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_bat <> 0
THEN valeur_locative_adm_sup_reel
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_bat = 0
THEN valeur_locative_adm_taux_prop_parc
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment <> 0
THEN valeur_batiment * (v_taux_valeur_locat_prof/100)
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment = 0
THEN montant_loyer_annuel
END,
montant_taxe =
CASE
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_bat <> 0 THEN
CASE
WHEN tfu_minimum < valeur_locative_adm_sup_reel * (v_taux_tfu/100) + tfu_piscine
THEN valeur_locative_adm_sup_reel * (v_taux_tfu/100) + tfu_piscine
ELSE tfu_minimum
END
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_bat = 0 THEN
CASE
WHEN tfu_minimum < valeur_locative_adm_taux_prop_parc * (v_taux_tfu/100) + tfu_piscine
THEN valeur_locative_adm_taux_prop_parc * (v_taux_tfu/100) + tfu_piscine
ELSE tfu_minimum
END
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment <> 0 THEN
CASE
WHEN tfu_minimum < valeur_batiment * (v_taux_valeur_locat_prof/100) * (v_taux_tfu/100)
THEN valeur_batiment * (v_taux_valeur_locat_prof/100) * (v_taux_tfu/100)
ELSE tfu_minimum
END
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment = 0 THEN
CASE
WHEN tfu_minimum < montant_loyer_annuel * (v_taux_tfu/100)
THEN montant_loyer_annuel * (v_taux_tfu/100)
ELSE tfu_minimum
END
END
WHERE impositions_tfu_id = p_impositions_tfu_id
AND batie = TRUE
AND NOT EXISTS (
SELECT 1
FROM unite_logement ul
WHERE ul.batiment_id = dtfu.batiment_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,
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,
'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 * eb.nombre_piscine * v_tfu_piscine_unitaire
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,
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
-- 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;
$$;

View File

@@ -0,0 +1,855 @@
/*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_valeur_locat_prof NUMERIC;
v_tfu_piscine_unitaire NUMERIC;
BEGIN
-- récupération de l'anné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;
select value
into strict v_taux_defaut_sup_sol
from parameters
where name ='TAUX_DEFAUT_SUPERFICIE_AU_SOL';
select value
into STRICT v_taux_tfu
from parameters
where name ='TAUX_TFU';
RAISE NOTICE 'v_taux_tfu = %', v_taux_tfu;
select value
into STRICT v_taux_valeur_locat_prof
from parameters
where name ='TAUX_VALEUR_LOCATIVE_PROFESSIONNELLE';
select value
into STRICT v_tfu_piscine_unitaire
from parameters
where name ='TFU_PAR_PISCINE';
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% de la surperficie au sol de la parcelle
valeur_locative_adm_taux_prop_parc,
tfu_calcule_taux_prop_parc, ----tfu correspondant au 70%
valeur_locative_adm_sup_reel,
valeur_locative_adm, ----------valeur locative administrative
tfu_superficie_au_sol_reel, ----tfu correspondant à la superficie au sol reelle
tfu_piscine,
montant_taxe, ----tfu finale
taux_tfu, ----taux tfu batie
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,
(
CURRENT_DATE >= ep.date_debut_exemption
AND CURRENT_DATE <= COALESCE(ep.date_fin_exemption, CURRENT_DATE)
),
(
CURRENT_DATE >= eb.date_debut_excemption
AND CURRENT_DATE <= COALESCE(eb.date_fin_excemption, CURRENT_DATE)
),
(
CURRENT_DATE >= eul.date_debut_exemption
AND CURRENT_DATE <= COALESCE(eul.date_fin_exemption, CURRENT_DATE)
),
cb.standing,
cb.nom,
CASE
WHEN eul.nombre_piscine is null then 0
else eul.nombre_piscine
END,
eul.date_enquete,
st.id,
ep.zone_rfu_id,
'TFU',
p.superficie,
eb.superficie_au_sol,
eul.superficie_au_sol,
CASE -------valeur_batiment
WHEN eul.valeur_unite_logement_reel IS NOT NULL AND eul.valeur_unite_logement_reel <> 0 THEN eul.valeur_unite_logement_reel
WHEN eul.valeur_unite_logement_calcule IS NOT NULL AND eul.valeur_unite_logement_calcule <> 0 THEN eul.valeur_unite_logement_calcule
WHEN eul.valeur_unite_logement_estime IS NOT NULL AND eul.valeur_unite_logement_estime <> 0 THEN eul.valeur_unite_logement_estime
ELSE 0
END,
brb.valeur_locative,
CASE ----- montant_loyer_annuel
WHEN eul.montant_locatif_annuel_declare IS NOT NULL AND eul.montant_locatif_annuel_declare <> 0 THEN eul.montant_locatif_annuel_declare
WHEN eul.montant_locatif_annuel_calcule IS NOT NULL AND eul.montant_locatif_annuel_calcule <> 0 THEN eul.montant_locatif_annuel_calcule
WHEN eul.montant_locatif_annuel_estime IS NOT NULL AND eul.montant_locatif_annuel_estime <> 0 THEN eul.montant_locatif_annuel_estime
ELSE 0
END,
brb.tfu_metre_carre,
brb.tfu_minimum,
p_impositions_tfu_id,
false,
current_date,
p_user_id,
'FISCAD',
current_date,
p_user_id,
eul.categorie_usage,
p.superficie * v_taux_defaut_sup_sol/100,---superficie_au_sol_70pour100
case ----valeur_locative_adm70pour100
when eul.categorie_usage = 'HABITATION' then (p.superficie * v_taux_defaut_sup_sol/100) * brb.valeur_locative
else 0
end,
case ----tfu calcule 70 pour 100 superficie parcelle
when eul.categorie_usage= 'HABITATION' then (p.superficie * v_taux_defaut_sup_sol/100) * brb.valeur_locative * v_taux_tfu/100
else 0
end,
case -----valeur_locative_adm_sup_reel
when eul.categorie_usage='HABITATION' then eul.superficie_au_sol * brb.valeur_locative
else 0
end,
0, ------ valeur_locative_adm : en attente de update
case -----tfu_superficie_au_sol_reel
when eul.categorie_usage='HABITATION' then eul.superficie_au_sol * brb.valeur_locative * 6/100
else 0
end,
CASE
WHEN eul.nombre_piscine is null then 0
else eul.nombre_piscine * v_tfu_piscine_unitaire
END,
0,
v_taux_tfu,
p.id,
b.id,
ul.id
FROM parcelle p
LEFT JOIN (
SELECT DISTINCT ON (parcelle_id)
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
ORDER BY parcelle_id, date_enquete DESC, id DESC
) ep ON ep.parcelle_id = p.id
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
--JOIN secteur_decoupage sd ON sd.quartier_id = q.id
JOIN (
SELECT DISTINCT ON (quartier_id)
quartier_id,
secteur_id
FROM secteur_decoupage
ORDER BY quartier_id
) sd ON sd.quartier_id = q.id
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 (
SELECT DISTINCT ON (batiment_id)
batiment_id,
superficie_au_sol,
nombre_piscine,
categorie_batiment_id,
date_enquete,
montant_locatif_annuel_declare,
montant_locatif_annuel_calcule,
montant_locatif_annuel_estime,
date_debut_excemption,
date_fin_excemption,
valeur_batiment_reel,
valeur_batiment_calcule,
valeur_batiment_estime,
u.categorie_usage
FROM enquete_batiment eb
join usage u on u.id=eb.usage_id
ORDER BY batiment_id, date_enquete DESC, eb.id DESC
) eb ON eb.batiment_id = b.id
JOIN unite_logement ul on ul.batiment_id = b.id
JOIN (
SELECT DISTINCT ON (eult.unite_logement_id)
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
FROM enquete_unite_logement eult
join usage u on u.id=eult.usage_id
left join personne pers1 on pers1.id = eult.personne_id
ORDER BY unite_logement_id, date_enquete DESC, eult.id DESC
) eul ON eul.unite_logement_id = ul.id
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 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;
UPDATE donnees_imposition_tfu dtfu
SET
valeur_locative_adm =
CASE
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_ulog <> 0
THEN valeur_locative_adm_sup_reel
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_ulog = 0
THEN valeur_locative_adm_taux_prop_parc
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment <> 0
THEN valeur_batiment * (v_taux_valeur_locat_prof/100)
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment = 0
THEN montant_loyer_annuel
END,
montant_taxe =
CASE
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_ulog <> 0 THEN
CASE
WHEN tfu_minimum < valeur_locative_adm_sup_reel * (v_taux_tfu/100) + tfu_piscine
THEN valeur_locative_adm_sup_reel * (v_taux_tfu/100) + tfu_piscine
ELSE tfu_minimum
END
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_ulog = 0 THEN
CASE
WHEN tfu_minimum < valeur_locative_adm_taux_prop_parc * (v_taux_tfu/100) + tfu_piscine
THEN valeur_locative_adm_taux_prop_parc * (v_taux_tfu/100) + tfu_piscine
ELSE tfu_minimum
END
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment <> 0 THEN
CASE
WHEN tfu_minimum < valeur_batiment * (v_taux_valeur_locat_prof/100) * (v_taux_tfu/100)
THEN valeur_batiment * (v_taux_valeur_locat_prof/100) * (v_taux_tfu/100)
ELSE tfu_minimum
END
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment = 0 THEN
CASE
WHEN tfu_minimum < montant_loyer_annuel * (v_taux_tfu/100)
THEN montant_loyer_annuel * (v_taux_tfu/100)
ELSE tfu_minimum
END
END
WHERE impositions_tfu_id = p_impositions_tfu_id
AND batie = TRUE
AND EXISTS (
SELECT 1
FROM unite_logement ul
WHERE ul.batiment_id = dtfu.batiment_id
);
RETURN v_rows_inserted;
END;
$$;*/
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;
$$;

View File

@@ -70,20 +70,20 @@ FROM impositions_tfu imp
order by c.code,st.code,r_quartier_contact,i_contact,p_contact; order by c.code,st.code,r_quartier_contact,i_contact,p_contact;
select * from e_avis_view;
--left join structure st2 on st2.id=imp.structure_id; --left join structure st2 on st2.id=imp.structure_id; 8263
create or replace view e_avis_detail_view as create or replace view e_avis_detail_view as
WITH cca_unique AS ( WITH cca_unique AS (
SELECT DISTINCT ON (personne_id, commune_id) SELECT DISTINCT ON (personne_id, commune_id)
structure_id, structure_id,
personne_id, personne_id,
commune_id commune_id,
parcelle_id
FROM commune_centre_assignation FROM commune_centre_assignation
ORDER BY commune_id,personne_id,structure_id ORDER BY commune_id,personne_id,structure_id
) )
SELECT SELECT distinct on (exo.annee,dimp.parcelle_id,dimp.nature_impot)
null as id_avis_detail, null as id_avis_detail,
null as id_avis, null as id_avis,
dimp.id as id_externe_ligne_imposition, dimp.id as id_externe_ligne_imposition,
@@ -103,7 +103,11 @@ SELECT
end as montant_base_imposition, end as montant_base_imposition,
dimp.valeur_locative_adm as montant_valeur_locative, dimp.valeur_locative_adm as montant_valeur_locative,
dimp.taux_tfu as taux, dimp.taux_tfu as taux,
dimp.montant_taxe as montant_du dimp.montant_taxe as montant_du,
case
when cca.parcelle_id is not null then true
else false
end as booleen_parcelle_contact
FROM impositions_tfu imp FROM impositions_tfu imp
INNER JOIN donnees_imposition_tfu dimp INNER JOIN donnees_imposition_tfu dimp
ON dimp.impositions_tfu_id = imp.id ON dimp.impositions_tfu_id = imp.id
@@ -114,6 +118,13 @@ FROM impositions_tfu imp
LEFT JOIN cca_unique cca LEFT JOIN cca_unique cca
ON cca.personne_id = dimp.personne_id ON cca.personne_id = dimp.personne_id
AND cca.commune_id = imp.commune_id AND cca.commune_id = imp.commune_id
AND cca.parcelle_id = dimp.parcelle_id
LEFT JOIN structure st LEFT JOIN structure st
ON st.id = cca.structure_id ON st.id = cca.structure_id
where dimp.personne_id is not null ; where dimp.personne_id is not null ;
select * from e_avis_detail_view
where qip_quartier='6431' and qip_ilot='1656' and qip_parcelle='C' ;
'6431', '1656', 'C'

View File

@@ -597,7 +597,7 @@ BEGIN
JOIN usage u ON u.id = eb2.usage_id JOIN usage u ON u.id = eb2.usage_id
WHERE eb2.batiment_id = b.id WHERE eb2.batiment_id = b.id
-- 🔧 IRF : Filtre spécifique -- 🔧 IRF : Filtre spécifique
AND eb2.superficie_louee * eb2.montant_locatif_annuel_declare > 0 AND eb2.superficie_louee * eb2.montant_locatif_annuel_declare > 0 ---s'assurer que la superficie au sol loue est renseignée
ORDER BY eb2.date_enquete DESC, eb2.id DESC ORDER BY eb2.date_enquete DESC, eb2.id DESC
LIMIT 1 LIMIT 1
) eb ON TRUE ) eb ON TRUE

View File

@@ -0,0 +1,350 @@
CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_irf_batie_une_parcelle(
p_impositions_tfu_id BIGINT,
p_user_id BIGINT,
p_parcelle_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 ---s'assurer que la superficie au sol loue est renseignée
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
AND p.id=p_parcelle_id
AND NOT EXISTS(select 1 from donnees_imposition_tfu dimptfu
where dimptfu.parcelle_id=p_parcelle_id
AND dimptfu.annee=v_annee
AND dimptfu.nature_impot='IRF'
AND dimptfu.batiment_id=b.id)
ON CONFLICT DO NOTHING;
GET DIAGNOSTICS v_rows_inserted = ROW_COUNT;
RETURN v_rows_inserted;
END;
$$;

View File

@@ -0,0 +1,305 @@
CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_irf_batie_ulo_une_parcelle(
p_impositions_tfu_id BIGINT,
p_user_id BIGINT,
p_parcelle_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
AND p.id=p_parcelle_id
AND NOT EXISTS(select 1 from donnees_imposition_tfu dimptfu
where dimptfu.parcelle_id=p_parcelle_id
AND dimptfu.annee=v_annee
AND dimptfu.nature_impot='IRF'
AND dimptfu.batiment_id=b.id
AND dimptfu.unite_logement_id=ul.id)
ON CONFLICT DO NOTHING;
GET DIAGNOSTICS v_rows_inserted = ROW_COUNT;
RETURN v_rows_inserted;
END;
$$;

View File

@@ -1,31 +1,34 @@
/*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_impositions_tfu_id BIGINT,
p_user_id BIGINT p_user_id BIGINT
) )
RETURNS INTEGER RETURNS INTEGER
LANGUAGE plpgsql LANGUAGE plpgsql
AS AS $$
$$
DECLARE DECLARE
v_rows_inserted INTEGER; v_rows_inserted INTEGER;
v_annee BIGINT; v_annee BIGINT;
v_structure_id BIGINT; v_structure_id BIGINT;
v_taux_defaut_sup_sol NUMERIC;
v_montant_srtb NUMERIC; v_montant_srtb NUMERIC;
v_today DATE;
BEGIN BEGIN
-- récupération de l'année v_today := CURRENT_DATE;
-- -------------------------------------------------------------------------
-- 1. Récupération de l'année et de la structure (inchangée)
-- -------------------------------------------------------------------------
SELECT ex.annee, it.structure_id SELECT ex.annee, it.structure_id
INTO STRICT v_annee, v_structure_id INTO STRICT v_annee, v_structure_id
FROM impositions_tfu it FROM impositions_tfu it
join exercice ex on ex.id =it.exercice_id JOIN exercice ex ON ex.id = it.exercice_id
WHERE it.id = p_impositions_tfu_id; WHERE it.id = p_impositions_tfu_id;
SELECT value
select value INTO STRICT v_montant_srtb
into STRICT v_montant_srtb FROM parameters
from parameters WHERE name = 'TAXE_SRTB';
where name ='TAXE_SRTB';
INSERT INTO donnees_imposition_tfu ( INSERT INTO donnees_imposition_tfu (
annee, annee,
@@ -81,264 +84,15 @@ INSERT INTO donnees_imposition_tfu(
updated_at, updated_at,
updated_by, updated_by,
categorie_usage, categorie_usage,
superficie_au_sol_taux_prop_parc, ---70% de la surperficie au sol de la parcelle superficie_au_sol_taux_prop_parc, -- 70 % superficie parcelle
valeur_locative_adm_taux_prop_parc, valeur_locative_adm_taux_prop_parc,
tfu_calcule_taux_prop_parc, ----tfu correspondant au 70% tfu_calcule_taux_prop_parc, -- 0 pour IRF
valeur_locative_adm_sup_reel, valeur_locative_adm_sup_reel,
valeur_locative_adm, ----------valeur locative administrative valeur_locative_adm, -- = montant_loyer_annuel pour IRF
tfu_superficie_au_sol_reel, ----tfu correspondant à la superficie au sol reelle tfu_superficie_au_sol_reel, -- 0 pour IRF
tfu_piscine, tfu_piscine, -- 0 pour IRF
montant_taxe, ----tfu finale montant_taxe, -- IRF finale = loyer * taux_irf
taux_tfu, ----taux tfu batie taux_tfu, -- = taux_irf pour IRF
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,
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,
(
CURRENT_DATE >= ep.date_debut_exemption
AND CURRENT_DATE <= COALESCE(ep.date_fin_exemption, CURRENT_DATE)
),
(
CURRENT_DATE >= eb.date_debut_excemption
AND CURRENT_DATE <= COALESCE(eb.date_fin_excemption, CURRENT_DATE)
),
cb.standing,
cb.nom,
eb.nombre_piscine,
eb.date_enquete,
st.id,
ep.zone_rfu_id,
'SRTB',
p.superficie,
eb.superficie_au_sol,
case -------valeur_batiment
WHEN eb.valeur_batiment_reel IS NOT NULL AND eb.valeur_batiment_reel <> 0 THEN eb.valeur_batiment_reel
WHEN eb.valeur_batiment_calcule IS NOT NULL AND eb.valeur_batiment_calcule <> 0 THEN eb.valeur_batiment_calcule
WHEN eb.valeur_batiment_estime IS NOT NULL AND eb.valeur_batiment_estime <> 0 THEN eb.valeur_batiment_estime
ELSE 0
END,
brb.valeur_locative,
case ----- montant_loyer_annuel
WHEN eb.montant_locatif_annuel_declare IS NOT NULL AND eb.montant_locatif_annuel_declare <> 0 THEN eb.montant_locatif_annuel_declare
WHEN eb.montant_locatif_annuel_calcule IS NOT NULL AND eb.montant_locatif_annuel_calcule <> 0 THEN eb.montant_locatif_annuel_calcule
WHEN eb.montant_locatif_annuel_estime IS NOT NULL AND eb.montant_locatif_annuel_estime <> 0 THEN eb.montant_locatif_annuel_estime
ELSE 0
END,
brb.tfu_metre_carre,
brb.tfu_minimum,
p_impositions_tfu_id,
false,
current_date ,
p_user_id ,
'FISCAD',
current_date ,
p_user_id,
eb.categorie_usage,
0,---superficie_au_sol_70pour100
0,
0,
eb.superficie_au_sol * brb.valeur_locative,
0, ------ valeur_locative_adm : en attente de update
0,
0,
v_montant_srtb,
0,
p.id,
b.id,
null,
eb.superficie_louee
FROM parcelle p
LEFT JOIN (
SELECT DISTINCT ON (parcelle_id)
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
ORDER BY parcelle_id, date_enquete DESC, id DESC
) ep ON ep.parcelle_id = p.id
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
--JOIN secteur_decoupage sd ON sd.quartier_id = q.id
JOIN (
SELECT DISTINCT ON (quartier_id)
quartier_id,
secteur_id
FROM secteur_decoupage
ORDER BY quartier_id
) sd ON sd.quartier_id = q.id
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 (
SELECT DISTINCT ON (batiment_id)
batiment_id,
superficie_au_sol,
nombre_piscine,
categorie_batiment_id,
date_enquete,
montant_locatif_annuel_declare,
montant_locatif_annuel_calcule,
montant_locatif_annuel_estime,
date_debut_excemption,
date_fin_excemption,
valeur_batiment_reel,
valeur_batiment_calcule,
valeur_batiment_estime,
u.categorie_usage,
superficie_louee
FROM enquete_batiment eb
join usage u on u.id=eb.usage_id
ORDER BY batiment_id, date_enquete DESC, eb.id DESC
) eb ON eb.batiment_id = b.id
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;
$$; */
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, parcelle_id,
batiment_id, batiment_id,
unite_logement_id, unite_logement_id,
@@ -346,146 +100,103 @@ BEGIN
personne_id personne_id
) )
SELECT SELECT
v_annee, dimp.annee,
d.code, d.nom, dimp.code_departement,
c.code, c.nom, dimp.nom_departement,
a.code, a.nom, dimp.code_commune,
q.code, q.nom, dimp.nom_commune,
p.q, p.i, p.p, p.nup, dimp.code_arrondissement,
ep.numero_titre_foncier, dimp.nom_arrondissement,
b.nub, dimp.code_quartier_village,
dimp.nom_quartier_village,
pers.ifu, pers.npi, pers.tel1, pers.email, dimp.q,
pers.nom, pers.prenom, pers.raison_sociale, pers.adresse, dimp. ilot,
ep.representant_tel, ep.representant_nom, ep.representant_prenom, dimp.parcelle,
dimp.nup,
p.longitude, p.latitude, dimp.titre_foncier,
dimp. num_batiment,
dimp.ifu,
dimp. npi,
dimp.tel_prop,
dimp.email_prop,
dimp.nom_prop,
dimp.prenom_prop,
dimp.raison_sociale,
dimp.adresse_prop,
dimp.tel_sc,
dimp.nom_sc,
dimp.prenom_sc,
dimp.longitude,
dimp.latitude,
TRUE, TRUE,
-- exonere parcelle
(v_today BETWEEN ep.date_debut_exemption AND COALESCE(ep.date_fin_exemption, v_today)), dimp.exonere,
(v_today BETWEEN eb.date_debut_excemption AND COALESCE(eb.date_fin_excemption, v_today)), -- exonere batiment
dimp.batiment_exonere,
cb.standing, dimp.standing_bat,
cb.nom, dimp.categorie_bat,
dimp.nombre_piscine,
COALESCE(eb.nombre_piscine, 0), dimp.date_enquete,
eb.date_enquete, dimp.structure_id,
dimp.zone_rfu_id,
st.id,
ep.zone_rfu_id,
'SRTB', 'SRTB',
dimp.superficie_parc,
p.superficie, dimp.superficie_au_sol_bat,
eb.superficie_au_sol, dimp.valeur_batiment,
dimp.tfu_metre_carre,
-- valeur bâtiment optimisée -- montant_loyer_annuel
COALESCE( dimp.montant_loyer_annuel,
NULLIF(eb.valeur_batiment_reel,0), -- 🔧 IRF : champs TFU mis à 0
NULLIF(eb.valeur_batiment_calcule,0), 0, -- tfu_metre_carre
NULLIF(eb.valeur_batiment_estime,0), 0, -- tfu_minimum
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, p_impositions_tfu_id,
FALSE, FALSE,
v_today, p_user_id, 'FISCAD', v_today,
v_today, p_user_id, p_user_id,
eb.categorie_usage, 'FISCAD',
v_today,
p_user_id,
dimp.categorie_usage,
0, 0, 0, -- superficie_au_sol_taux_prop_parc (70 % parcelle)
dimp.superficie_au_sol_taux_prop_parc,
eb.superficie_au_sol * brb.valeur_locative, -- valeur_locative_adm_taux_prop_parc
dimp.valeur_locative_adm_taux_prop_parc,
0, -- 🔧 IRF : tfu_calcule_taux_prop_parc → 0
0,
0, 0,
-- 🔥 SRTB = valeur directe (pas de calcul) -- valeur_locative_adm_sup_reel
dimp.valeur_locative_adm_sup_reel,
-- ---------------------------------------------------------------
-- 🔧 IRF : valeur_locative_adm = montant_loyer_annuel (calculé directement)
-- ---------------------------------------------------------------
dimp.valeur_locative_adm
,
-- 🔧 IRF : tfu_superficie_au_sol_reel → 0
0,
-- 🔧 IRF : tfu_piscine → 0
0,
-- ---------------------------------------------------------------
-- 🔧 IRF : montant_taxe = montant_loyer_annuel * taux_irf (calculé directement)
-- ---------------------------------------------------------------
v_montant_srtb, v_montant_srtb,
-- 🔧 IRF : taux_tfu → taux_irf
0, 0,
dimp.parcelle_id,
p.id, dimp.batiment_id,
b.id, dimp.unite_logement_id,
NULL, dimp.superficie_au_sol_loue,
eb.superficie_louee, dimp.personne_id
ep.personne_id FROM donnees_imposition_tfu dimp
WHERE dimp.nature_impot= 'IRF'
FROM parcelle p AND dimp.impositions_tfu_id=p_impositions_tfu_id
-- 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; ON CONFLICT DO NOTHING;
GET DIAGNOSTICS v_rows_inserted = ROW_COUNT; GET DIAGNOSTICS v_rows_inserted = ROW_COUNT;
@@ -494,4 +205,3 @@ BEGIN
END; END;
$$; $$;

View File

@@ -0,0 +1,213 @@
CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_srtb_batie_une_parcelle(
p_impositions_tfu_id BIGINT,
p_user_id BIGINT,
p_parcelle_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_montant_srtb 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;
SELECT value
INTO STRICT v_montant_srtb
FROM parameters
WHERE name = 'TAXE_SRTB';
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
dimp.annee,
dimp.code_departement,
dimp.nom_departement,
dimp.code_commune,
dimp.nom_commune,
dimp.code_arrondissement,
dimp.nom_arrondissement,
dimp.code_quartier_village,
dimp.nom_quartier_village,
dimp.q,
dimp. ilot,
dimp.parcelle,
dimp.nup,
dimp.titre_foncier,
dimp. num_batiment,
dimp.ifu,
dimp. npi,
dimp.tel_prop,
dimp.email_prop,
dimp.nom_prop,
dimp.prenom_prop,
dimp.raison_sociale,
dimp.adresse_prop,
dimp.tel_sc,
dimp.nom_sc,
dimp.prenom_sc,
dimp.longitude,
dimp.latitude,
TRUE,
-- exonere parcelle
dimp.exonere,
-- exonere batiment
dimp.batiment_exonere,
dimp.standing_bat,
dimp.categorie_bat,
dimp.nombre_piscine,
dimp.date_enquete,
dimp.structure_id,
dimp.zone_rfu_id,
'SRTB',
dimp.superficie_parc,
dimp.superficie_au_sol_bat,
dimp.valeur_batiment,
dimp.tfu_metre_carre,
-- montant_loyer_annuel
dimp.montant_loyer_annuel,
-- 🔧 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,
dimp.categorie_usage,
-- superficie_au_sol_taux_prop_parc (70 % parcelle)
dimp.superficie_au_sol_taux_prop_parc,
-- valeur_locative_adm_taux_prop_parc
dimp.valeur_locative_adm_taux_prop_parc,
-- 🔧 IRF : tfu_calcule_taux_prop_parc → 0
0,
-- valeur_locative_adm_sup_reel
dimp.valeur_locative_adm_sup_reel,
-- ---------------------------------------------------------------
-- 🔧 IRF : valeur_locative_adm = montant_loyer_annuel (calculé directement)
-- ---------------------------------------------------------------
dimp.valeur_locative_adm
,
-- 🔧 IRF : tfu_superficie_au_sol_reel → 0
0,
-- 🔧 IRF : tfu_piscine → 0
0,
-- ---------------------------------------------------------------
-- 🔧 IRF : montant_taxe = montant_loyer_annuel * taux_irf (calculé directement)
-- ---------------------------------------------------------------
v_montant_srtb,
-- 🔧 IRF : taux_tfu → taux_irf
0,
dimp.parcelle_id,
dimp.batiment_id,
dimp.unite_logement_id,
dimp.superficie_au_sol_loue,
dimp.personne_id
FROM donnees_imposition_tfu dimp
WHERE dimp.nature_impot= 'IRF'
AND dimp.impositions_tfu_id=p_impositions_tfu_id
AND dimp.parcelle_id=p_parcelle_id
AND NOT EXISTS(select 1 from donnees_imposition_tfu dimptfu
where dimptfu.parcelle_id=p_parcelle_id
AND dimptfu.nature_impot='SRTB'
AND dimptfu.batiment_id=dimp.batiment_id)
ON CONFLICT DO NOTHING;
GET DIAGNOSTICS v_rows_inserted = ROW_COUNT;
RETURN v_rows_inserted;
END;
$$;

View File

@@ -1,349 +1,3 @@
/*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_valeur_locat_prof NUMERIC;
v_tfu_piscine_unitaire NUMERIC;
BEGIN
-- récupération de l'anné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;
select value
into strict v_taux_defaut_sup_sol
from parameters
where name ='TAUX_DEFAUT_SUPERFICIE_AU_SOL';
select value
into STRICT v_taux_tfu
from parameters
where name ='TAUX_TFU';
select value
into STRICT v_taux_valeur_locat_prof
from parameters
where name ='TAUX_VALEUR_LOCATIVE_PROFESSIONNELLE';
select value
into STRICT v_tfu_piscine_unitaire
from parameters
where name ='TFU_PAR_PISCINE';
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% de la surperficie au sol de la parcelle
valeur_locative_adm_taux_prop_parc,
tfu_calcule_taux_prop_parc, ----tfu correspondant au 70%
valeur_locative_adm_sup_reel,
valeur_locative_adm, ----------valeur locative administrative
tfu_superficie_au_sol_reel, ----tfu correspondant à la superficie au sol reelle
tfu_piscine,
montant_taxe, ----tfu finale
taux_tfu, ----taux tfu batie
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,
(
CURRENT_DATE >= ep.date_debut_exemption
AND CURRENT_DATE <= COALESCE(ep.date_fin_exemption, CURRENT_DATE)
),
(
CURRENT_DATE >= eb.date_debut_excemption
AND CURRENT_DATE <= COALESCE(eb.date_fin_excemption, CURRENT_DATE)
),
cb.standing,
cb.nom,
eb.nombre_piscine,
eb.date_enquete,
st.id,
ep.zone_rfu_id,
'TFU',
p.superficie,
eb.superficie_au_sol,
COALESCE(
NULLIF(eb.valeur_batiment_reel, 0),
NULLIF(eb.valeur_batiment_calcule, 0),
NULLIF(eb.valeur_batiment_estime, 0),
0
),
brb.valeur_locative,
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,
current_date ,
p_user_id ,
'FISCAD',
current_date ,
p_user_id,
eb.categorie_usage,
p.superficie*v_taux_defaut_sup_sol/100,---superficie_au_sol_70pour100
case ----valeur_locative_adm70pour100
when eb.categorie_usage = 'HABITATION' then (p.superficie * v_taux_defaut_sup_sol/100) * brb.valeur_locative
else 0
end,
case ----tfu calcule 70 pour 100 superficie parcelle
when eb.categorie_usage= 'HABITATION' then (p.superficie * v_taux_defaut_sup_sol/100) * brb.valeur_locative * v_taux_tfu/100
else 0
end,
case -----valeur_locative_adm_sup_reel
when eb.categorie_usage='HABITATION' then eb.superficie_au_sol * brb.valeur_locative
else 0
end,
0, ------ valeur_locative_adm : en attente de update
case -----tfu_superficie_au_sol_reel
when eb.categorie_usage='HABITATION' then eb.superficie_au_sol * brb.valeur_locative * v_taux_tfu/100 +eb.nombre_piscine * v_tfu_piscine_unitaire
else 0
end,
eb.nombre_piscine * v_tfu_piscine_unitaire,
0,
v_taux_tfu,
p.id,
b.id,
null
FROM parcelle p
LEFT JOIN (
SELECT DISTINCT ON (parcelle_id)
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
ORDER BY parcelle_id, date_enquete DESC, id DESC
) ep ON ep.parcelle_id = p.id
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
--JOIN secteur_decoupage sd ON sd.quartier_id = q.id
JOIN (
SELECT DISTINCT ON (quartier_id)
quartier_id,
secteur_id
FROM secteur_decoupage
ORDER BY quartier_id
) sd ON sd.quartier_id = q.id
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 (
SELECT DISTINCT ON (batiment_id)
batiment_id,
superficie_au_sol,
nombre_piscine,
categorie_batiment_id,
date_enquete,
montant_locatif_annuel_declare,
montant_locatif_annuel_calcule,
montant_locatif_annuel_estime,
date_debut_excemption,
date_fin_excemption,
valeur_batiment_reel,
valeur_batiment_calcule,
valeur_batiment_estime,
u.categorie_usage
FROM enquete_batiment eb
join usage u on u.id=eb.usage_id
ORDER BY batiment_id, date_enquete DESC, eb.id DESC
) eb ON eb.batiment_id = b.id
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;
UPDATE donnees_imposition_tfu dtfu
SET
valeur_locative_adm =
CASE
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_bat <> 0
THEN valeur_locative_adm_sup_reel
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_bat = 0
THEN valeur_locative_adm_taux_prop_parc
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment <> 0
THEN valeur_batiment * (v_taux_valeur_locat_prof/100)
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment = 0
THEN montant_loyer_annuel
END,
montant_taxe =
CASE
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_bat <> 0 THEN
CASE
WHEN tfu_minimum < valeur_locative_adm_sup_reel * (v_taux_tfu/100) + tfu_piscine
THEN valeur_locative_adm_sup_reel * (v_taux_tfu/100) + tfu_piscine
ELSE tfu_minimum
END
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_bat = 0 THEN
CASE
WHEN tfu_minimum < valeur_locative_adm_taux_prop_parc * (v_taux_tfu/100) + tfu_piscine
THEN valeur_locative_adm_taux_prop_parc * (v_taux_tfu/100) + tfu_piscine
ELSE tfu_minimum
END
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment <> 0 THEN
CASE
WHEN tfu_minimum < valeur_batiment * (v_taux_valeur_locat_prof/100) * (v_taux_tfu/100)
THEN valeur_batiment * (v_taux_valeur_locat_prof/100) * (v_taux_tfu/100)
ELSE tfu_minimum
END
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment = 0 THEN
CASE
WHEN tfu_minimum < montant_loyer_annuel * (v_taux_tfu/100)
THEN montant_loyer_annuel * (v_taux_tfu/100)
ELSE tfu_minimum
END
END
WHERE impositions_tfu_id = p_impositions_tfu_id
AND batie = TRUE
AND NOT EXISTS (
SELECT 1
FROM unite_logement ul
WHERE ul.batiment_id = dtfu.batiment_id
);
RETURN v_rows_inserted;
END;
$$;*/
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_impositions_tfu_id BIGINT,
p_user_id BIGINT p_user_id BIGINT
@@ -466,12 +120,15 @@ BEGIN
valeur_locative_adm, -- valeur locative administrative finale valeur_locative_adm, -- valeur locative administrative finale
tfu_superficie_au_sol_reel, tfu_superficie_au_sol_reel,
tfu_piscine, tfu_piscine,
montant_taxe_brut,
montant_taxe, -- TFU finale montant_taxe, -- TFU finale
taux_tfu, taux_tfu,
parcelle_id, parcelle_id,
batiment_id, batiment_id,
unite_logement_id, unite_logement_id,
personne_id personne_id,
nombre_ulog,
nombre_bat
) )
SELECT SELECT
v_annee, v_annee,
@@ -515,7 +172,7 @@ BEGIN
eb.date_enquete, eb.date_enquete,
st.id, st.id,
ep.zone_rfu_id, ep.zone_rfu_id,
'TFU', 'FB',
p.superficie, p.superficie,
eb.superficie_au_sol, eb.superficie_au_sol,
-- valeur_batiment : première valeur non nulle non zéro -- valeur_batiment : première valeur non nulle non zéro
@@ -607,7 +264,48 @@ BEGIN
-- tfu_piscine -- tfu_piscine
eb.nombre_piscine * v_tfu_piscine_unitaire, eb.nombre_piscine * v_tfu_piscine_unitaire,
-- ---------------------------------------------------------------
-- montant_taxe_brut ← sans prise en compte du minimum
-- ---------------------------------------------------------------
(
-- 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 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 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 calc.vb * v_taux_vlp_ratio * v_taux_tfu_ratio
WHEN eb.categorie_usage IN ('PROFESSIONNELLE', 'MIXTE')
AND calc.vb = 0
THEN calc.loyer * v_taux_tfu_ratio
ELSE brb.tfu_minimum
END
FROM calc
),
-- --------------------------------------------------------------- -- ---------------------------------------------------------------
-- montant_taxe ← calculé directement (plus d'UPDATE) -- montant_taxe ← calculé directement (plus d'UPDATE)
-- Utilise des CTE inline via expression pour éviter la redondance -- Utilise des CTE inline via expression pour éviter la redondance
@@ -658,7 +356,13 @@ BEGIN
p.id, p.id,
b.id, b.id,
NULL, NULL,
ep.personne_id ep.personne_id,
(select count(*)
from unite_logement ulog
where ulog.batiment_id= b.id),
(select count(*)
from batiment bat
where bat.parcelle_id= p.id)
FROM parcelle p FROM parcelle p
-- Dernière enquête parcelle -- Dernière enquête parcelle
LEFT JOIN LATERAL ( LEFT JOIN LATERAL (
@@ -742,10 +446,10 @@ BEGIN
) brb ON TRUE ) brb ON TRUE
WHERE p.batie = TRUE WHERE p.batie = TRUE
AND ul_filter.batiment_id IS NULL -- anti-join : pas d'unité logement --AND ul_filter.batiment_id IS NULL -- anti-join : pas d'unité logement
AND st.id = v_structure_id AND st.id = v_structure_id ;
ON CONFLICT DO NOTHING; -- ON CONFLICT DO NOTHING;
GET DIAGNOSTICS v_rows_inserted = ROW_COUNT; GET DIAGNOSTICS v_rows_inserted = ROW_COUNT;

View File

@@ -0,0 +1,464 @@
CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_tfu_batie_une_parcelle(
p_impositions_tfu_id BIGINT,
p_user_id BIGINT,
p_parcelle_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_brut,
montant_taxe, -- TFU finale
taux_tfu,
parcelle_id,
batiment_id,
unite_logement_id,
personne_id,
nombre_ulog,
nombre_bat
)
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,
'FB',
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 * eb.nombre_piscine * v_tfu_piscine_unitaire
ELSE 0
END,
-- tfu_piscine
eb.nombre_piscine * v_tfu_piscine_unitaire,
-- ---------------------------------------------------------------
-- montant_taxe_brut ← sans prise en compte du minimum
-- ---------------------------------------------------------------
(
-- 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 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 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 calc.vb * v_taux_vlp_ratio * v_taux_tfu_ratio
WHEN eb.categorie_usage IN ('PROFESSIONNELLE', 'MIXTE')
AND calc.vb = 0
THEN calc.loyer * v_taux_tfu_ratio
ELSE brb.tfu_minimum
END
FROM calc
),
-- ---------------------------------------------------------------
-- 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,
ep.personne_id,
(select count(*)
from unite_logement ulog
where ulog.batiment_id= b.id),
(select count(*)
from batiment bat
where bat.parcelle_id= p.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
-- 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
AND p.id = p_parcelle_id
AND NOT EXISTS(select 1 from donnees_imposition_tfu dimptfu
where dimptfu.batiment_id=b.id
and dimptfu.annee=v_annee
and dimptfu.nature_impot='FB');
-- ON CONFLICT DO NOTHING;
GET DIAGNOSTICS v_rows_inserted = ROW_COUNT;
RETURN v_rows_inserted;
END;
$$;

View File

@@ -1,398 +1,3 @@
/*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_valeur_locat_prof NUMERIC;
v_tfu_piscine_unitaire NUMERIC;
BEGIN
-- récupération de l'anné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;
select value
into strict v_taux_defaut_sup_sol
from parameters
where name ='TAUX_DEFAUT_SUPERFICIE_AU_SOL';
select value
into STRICT v_taux_tfu
from parameters
where name ='TAUX_TFU';
RAISE NOTICE 'v_taux_tfu = %', v_taux_tfu;
select value
into STRICT v_taux_valeur_locat_prof
from parameters
where name ='TAUX_VALEUR_LOCATIVE_PROFESSIONNELLE';
select value
into STRICT v_tfu_piscine_unitaire
from parameters
where name ='TFU_PAR_PISCINE';
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% de la surperficie au sol de la parcelle
valeur_locative_adm_taux_prop_parc,
tfu_calcule_taux_prop_parc, ----tfu correspondant au 70%
valeur_locative_adm_sup_reel,
valeur_locative_adm, ----------valeur locative administrative
tfu_superficie_au_sol_reel, ----tfu correspondant à la superficie au sol reelle
tfu_piscine,
montant_taxe, ----tfu finale
taux_tfu, ----taux tfu batie
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,
(
CURRENT_DATE >= ep.date_debut_exemption
AND CURRENT_DATE <= COALESCE(ep.date_fin_exemption, CURRENT_DATE)
),
(
CURRENT_DATE >= eb.date_debut_excemption
AND CURRENT_DATE <= COALESCE(eb.date_fin_excemption, CURRENT_DATE)
),
(
CURRENT_DATE >= eul.date_debut_exemption
AND CURRENT_DATE <= COALESCE(eul.date_fin_exemption, CURRENT_DATE)
),
cb.standing,
cb.nom,
CASE
WHEN eul.nombre_piscine is null then 0
else eul.nombre_piscine
END,
eul.date_enquete,
st.id,
ep.zone_rfu_id,
'TFU',
p.superficie,
eb.superficie_au_sol,
eul.superficie_au_sol,
CASE -------valeur_batiment
WHEN eul.valeur_unite_logement_reel IS NOT NULL AND eul.valeur_unite_logement_reel <> 0 THEN eul.valeur_unite_logement_reel
WHEN eul.valeur_unite_logement_calcule IS NOT NULL AND eul.valeur_unite_logement_calcule <> 0 THEN eul.valeur_unite_logement_calcule
WHEN eul.valeur_unite_logement_estime IS NOT NULL AND eul.valeur_unite_logement_estime <> 0 THEN eul.valeur_unite_logement_estime
ELSE 0
END,
brb.valeur_locative,
CASE ----- montant_loyer_annuel
WHEN eul.montant_locatif_annuel_declare IS NOT NULL AND eul.montant_locatif_annuel_declare <> 0 THEN eul.montant_locatif_annuel_declare
WHEN eul.montant_locatif_annuel_calcule IS NOT NULL AND eul.montant_locatif_annuel_calcule <> 0 THEN eul.montant_locatif_annuel_calcule
WHEN eul.montant_locatif_annuel_estime IS NOT NULL AND eul.montant_locatif_annuel_estime <> 0 THEN eul.montant_locatif_annuel_estime
ELSE 0
END,
brb.tfu_metre_carre,
brb.tfu_minimum,
p_impositions_tfu_id,
false,
current_date,
p_user_id,
'FISCAD',
current_date,
p_user_id,
eul.categorie_usage,
p.superficie * v_taux_defaut_sup_sol/100,---superficie_au_sol_70pour100
case ----valeur_locative_adm70pour100
when eul.categorie_usage = 'HABITATION' then (p.superficie * v_taux_defaut_sup_sol/100) * brb.valeur_locative
else 0
end,
case ----tfu calcule 70 pour 100 superficie parcelle
when eul.categorie_usage= 'HABITATION' then (p.superficie * v_taux_defaut_sup_sol/100) * brb.valeur_locative * v_taux_tfu/100
else 0
end,
case -----valeur_locative_adm_sup_reel
when eul.categorie_usage='HABITATION' then eul.superficie_au_sol * brb.valeur_locative
else 0
end,
0, ------ valeur_locative_adm : en attente de update
case -----tfu_superficie_au_sol_reel
when eul.categorie_usage='HABITATION' then eul.superficie_au_sol * brb.valeur_locative * 6/100
else 0
end,
CASE
WHEN eul.nombre_piscine is null then 0
else eul.nombre_piscine * v_tfu_piscine_unitaire
END,
0,
v_taux_tfu,
p.id,
b.id,
ul.id
FROM parcelle p
LEFT JOIN (
SELECT DISTINCT ON (parcelle_id)
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
ORDER BY parcelle_id, date_enquete DESC, id DESC
) ep ON ep.parcelle_id = p.id
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
--JOIN secteur_decoupage sd ON sd.quartier_id = q.id
JOIN (
SELECT DISTINCT ON (quartier_id)
quartier_id,
secteur_id
FROM secteur_decoupage
ORDER BY quartier_id
) sd ON sd.quartier_id = q.id
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 (
SELECT DISTINCT ON (batiment_id)
batiment_id,
superficie_au_sol,
nombre_piscine,
categorie_batiment_id,
date_enquete,
montant_locatif_annuel_declare,
montant_locatif_annuel_calcule,
montant_locatif_annuel_estime,
date_debut_excemption,
date_fin_excemption,
valeur_batiment_reel,
valeur_batiment_calcule,
valeur_batiment_estime,
u.categorie_usage
FROM enquete_batiment eb
join usage u on u.id=eb.usage_id
ORDER BY batiment_id, date_enquete DESC, eb.id DESC
) eb ON eb.batiment_id = b.id
JOIN unite_logement ul on ul.batiment_id = b.id
JOIN (
SELECT DISTINCT ON (eult.unite_logement_id)
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
FROM enquete_unite_logement eult
join usage u on u.id=eult.usage_id
left join personne pers1 on pers1.id = eult.personne_id
ORDER BY unite_logement_id, date_enquete DESC, eult.id DESC
) eul ON eul.unite_logement_id = ul.id
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 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;
UPDATE donnees_imposition_tfu dtfu
SET
valeur_locative_adm =
CASE
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_ulog <> 0
THEN valeur_locative_adm_sup_reel
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_ulog = 0
THEN valeur_locative_adm_taux_prop_parc
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment <> 0
THEN valeur_batiment * (v_taux_valeur_locat_prof/100)
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment = 0
THEN montant_loyer_annuel
END,
montant_taxe =
CASE
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_ulog <> 0 THEN
CASE
WHEN tfu_minimum < valeur_locative_adm_sup_reel * (v_taux_tfu/100) + tfu_piscine
THEN valeur_locative_adm_sup_reel * (v_taux_tfu/100) + tfu_piscine
ELSE tfu_minimum
END
WHEN categorie_usage = 'HABITATION' AND superficie_au_sol_ulog = 0 THEN
CASE
WHEN tfu_minimum < valeur_locative_adm_taux_prop_parc * (v_taux_tfu/100) + tfu_piscine
THEN valeur_locative_adm_taux_prop_parc * (v_taux_tfu/100) + tfu_piscine
ELSE tfu_minimum
END
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment <> 0 THEN
CASE
WHEN tfu_minimum < valeur_batiment * (v_taux_valeur_locat_prof/100) * (v_taux_tfu/100)
THEN valeur_batiment * (v_taux_valeur_locat_prof/100) * (v_taux_tfu/100)
ELSE tfu_minimum
END
WHEN categorie_usage IN ('PROFESSIONNELLE','MIXTE') AND valeur_batiment = 0 THEN
CASE
WHEN tfu_minimum < montant_loyer_annuel * (v_taux_tfu/100)
THEN montant_loyer_annuel * (v_taux_tfu/100)
ELSE tfu_minimum
END
END
WHERE impositions_tfu_id = p_impositions_tfu_id
AND batie = TRUE
AND EXISTS (
SELECT 1
FROM unite_logement ul
WHERE ul.batiment_id = dtfu.batiment_id
);
RETURN v_rows_inserted;
END;
$$;*/
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_impositions_tfu_id BIGINT,
p_user_id BIGINT p_user_id BIGINT
@@ -446,6 +51,8 @@ BEGIN
'TFU_PAR_PISCINE' 'TFU_PAR_PISCINE'
); );
-- Ratios pré-calculés pour éviter la division répétée dans le SELECT -- 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_tfu_ratio := v_taux_tfu / 100.0;
v_taux_vlp_ratio := v_taux_valeur_locat_prof / 100.0; v_taux_vlp_ratio := v_taux_valeur_locat_prof / 100.0;
@@ -454,6 +61,27 @@ BEGIN
-- 3. INSERT avec calcul complet de valeur_locative_adm et montant_taxe -- 3. INSERT avec calcul complet de valeur_locative_adm et montant_taxe
-- → supprime l'UPDATE post-INSERT (économie d'un second scan de table) -- → supprime l'UPDATE post-INSERT (économie d'un second scan de table)
-- ------------------------------------------------------------------------- -- -------------------------------------------------------------------------
WITH uniteLogementSupTotal as (
WITH derniere_enquete_ulog AS (
SELECT
eul.*,
ROW_NUMBER() OVER (
PARTITION BY unite_logement_id
ORDER BY date_enquete DESC
) AS rn
FROM enquete_unite_logement eul
)
SELECT
ul.batiment_id,
dimp.montant_taxe,
SUM(ulog.superficie_au_sol) AS superficie_totale
FROM derniere_enquete_ulog ulog
inner join unite_logement ul on ul.id=ulog.unite_logement_id
inner join donnees_imposition_tfu dimp on dimp.batiment_id= ul.batiment_id
WHERE rn = 1
AND dimp.impositions_tfu_id = p_impositions_tfu_id
GROUP BY ul.batiment_id,dimp.montant_taxe
)
INSERT INTO donnees_imposition_tfu ( INSERT INTO donnees_imposition_tfu (
annee, annee,
code_departement, code_departement,
@@ -570,7 +198,7 @@ BEGIN
eul.date_enquete, eul.date_enquete,
st.id, st.id,
ep.zone_rfu_id, ep.zone_rfu_id,
'TFU', 'FB',
p.superficie, p.superficie,
eb.superficie_au_sol, eb.superficie_au_sol,
eul.superficie_au_sol, eul.superficie_au_sol,
@@ -620,7 +248,6 @@ BEGIN
THEN eul.superficie_au_sol * brb.valeur_locative THEN eul.superficie_au_sol * brb.valeur_locative
ELSE 0 ELSE 0
END, END,
-- --------------------------------------------------------------- -- ---------------------------------------------------------------
-- valeur_locative_adm avec tests explicites (corrigée) -- valeur_locative_adm avec tests explicites (corrigée)
-- --------------------------------------------------------------- -- ---------------------------------------------------------------
@@ -654,7 +281,6 @@ BEGIN
ELSE 0 ELSE 0
END, END,
-- 🔧 CORRECTION : tfu_superficie_au_sol_reel (était hardcodé à 6/100) -- 🔧 CORRECTION : tfu_superficie_au_sol_reel (était hardcodé à 6/100)
CASE WHEN eul.categorie_usage = 'HABITATION' CASE WHEN eul.categorie_usage = 'HABITATION'
THEN eul.superficie_au_sol * brb.valeur_locative * v_taux_tfu_ratio THEN eul.superficie_au_sol * brb.valeur_locative * v_taux_tfu_ratio
@@ -667,56 +293,16 @@ BEGIN
-- --------------------------------------------------------------- -- ---------------------------------------------------------------
-- montant_taxe ← calculé directement (plus d'UPDATE) -- montant_taxe ← calculé directement (plus d'UPDATE)
-- --------------------------------------------------------------- -- ---------------------------------------------------------------
( case when ulost.superficie_totale > 0
WITH calc AS ( then eul.superficie_au_sol * ulost.montant_taxe / ulost.superficie_totale
SELECT else 0
COALESCE(NULLIF(eul.valeur_unite_logement_reel, 0), end,
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, v_taux_tfu,
p.id, p.id,
b.id, b.id,
ul.id ul.id
FROM parcelle p FROM parcelle p
-- Dernière enquête parcelle -- Dernière enquête parcelle
LEFT JOIN LATERAL ( LEFT JOIN LATERAL (
SELECT SELECT
@@ -784,6 +370,7 @@ BEGIN
) eb ON TRUE ) eb ON TRUE
JOIN unite_logement ul ON ul.batiment_id = b.id JOIN unite_logement ul ON ul.batiment_id = b.id
INNER JOIN uniteLogementSupTotal ulost on ulost.batiment_id=ul.batiment_id
-- Dernière enquête unité logement -- Dernière enquête unité logement
JOIN LATERAL ( JOIN LATERAL (

View File

@@ -0,0 +1,448 @@
CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_tfu_batie_ulo_une_parcelle(
p_impositions_tfu_id BIGINT,
p_user_id BIGINT,
p_parcelle_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)
-- -------------------------------------------------------------------------
WITH uniteLogementSupTotal as (
WITH derniere_enquete_ulog AS (
SELECT
eul.*,
ROW_NUMBER() OVER (
PARTITION BY unite_logement_id
ORDER BY date_enquete DESC
) AS rn
FROM enquete_unite_logement eul
)
SELECT
ul.batiment_id,
dimp.montant_taxe,
SUM(ulog.superficie_au_sol) AS superficie_totale
FROM derniere_enquete_ulog ulog
inner join unite_logement ul on ul.id=ulog.unite_logement_id
inner join donnees_imposition_tfu dimp on dimp.batiment_id= ul.batiment_id
WHERE rn = 1
AND dimp.impositions_tfu_id = p_impositions_tfu_id
GROUP BY ul.batiment_id,dimp.montant_taxe
)
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,
'FB',
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)
-- ---------------------------------------------------------------
case when ulost.superficie_totale > 0
then eul.superficie_au_sol * ulost.montant_taxe / ulost.superficie_totale
else 0
end,
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
INNER JOIN uniteLogementSupTotal ulost on ulost.batiment_id=ul.batiment_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
AND p.id = p_parcelle_id
AND NOT exists(select 1 from donnees_imposition_tfu dimptfu
where dimptfu.annee=v_annee
and dimptfu.batiment_id=b.id
and dimptfu.unite_logement_id=ul.id
and dimptfu.nature_impot='FB')
ON CONFLICT DO NOTHING;
GET DIAGNOSTICS v_rows_inserted = ROW_COUNT;
RETURN v_rows_inserted;
END;
$$;

View File

@@ -268,7 +268,7 @@ BEGIN
ep.date_enquete, ep.date_enquete,
st.id, st.id,
ep.zone_rfu_id, ep.zone_rfu_id,
'TFU', 'FNB',
p.superficie, p.superficie,
p_impositions_tfu_id, p_impositions_tfu_id,
false, false,

View File

@@ -0,0 +1,190 @@
CREATE OR REPLACE FUNCTION public.generer_donnees_imposition_tfu_non_batie_une_parcelle(
p_impositions_tfu_id BIGINT,
p_user_id BIGINT,
p_parcelle_id BIGINT
)
RETURNS INTEGER
LANGUAGE plpgsql
AS
$$
DECLARE
v_rows_inserted INTEGER;
v_annee BIGINT;
v_structure_id BIGINT;
BEGIN
-- récupération de l'anné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;
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,
ifu,
npi,
tel_prop,
email_prop,
nom_prop,
prenom_prop,
raison_sociale,
adresse_prop,
tel_sc,
nom_sc,
prenom_sc,
longitude,
latitude,
batie,
exonere,
date_enquete,
structure_id,
zone_rfu_id,
nature_impot,
superficie_parc,
impositions_tfu_id,
deleted,
created_at,
created_by,
"source",
updated_at,
updated_by,
taux_tfu,
valeur_admin_parcelle_nb,
valeur_admin_parcelle_nb_metre_carre,
montant_taxe,
parcelle_id,
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,
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,
false,
(
CURRENT_DATE >= ep.date_debut_exemption
AND CURRENT_DATE <= COALESCE(ep.date_fin_exemption, CURRENT_DATE)
),
ep.date_enquete,
st.id,
ep.zone_rfu_id,
'FNB',
p.superficie,
p_impositions_tfu_id,
false,
current_date,
p_user_id,
'FISCAD',
current_date,
p_user_id,
brnb.taux,
CASE
WHEN brnb.au_metre_carre = true
THEN brnb.valeur_administrative_metre_carre * ep.superficie
ELSE brnb.valeur_administrative
END,
brnb.valeur_administrative_metre_carre,
CASE
WHEN brnb.au_metre_carre = true
THEN brnb.valeur_administrative_metre_carre * ep.superficie * brnb.taux / 100
ELSE brnb.valeur_administrative * brnb.taux / 100
END,
p.id,
ep.personne_id
FROM parcelle p
LEFT JOIN (
SELECT DISTINCT ON (parcelle_id)
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
ORDER BY parcelle_id, date_enquete DESC
) ep ON ep.parcelle_id = p.id
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
-- ✅ CORRECTION ICI
JOIN (
SELECT DISTINCT ON (quartier_id)
quartier_id,
secteur_id
FROM secteur_decoupage
ORDER BY quartier_id
) sd ON sd.quartier_id = q.id
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
LEFT JOIN barem_rfu_non_bati brnb
ON (brnb.commune_id = c.id AND brnb.zone_rfu_id = ep.zone_rfu_id)
WHERE p.batie = false
AND st.id = v_structure_id
AND p.id=p_parcelle_id
AND NOT EXISTS( select 1 from donnees_imposition_tfu dimptfu
where dimptfu.nature_impot='FNB'
and dimptfu.parcelle_id=p_parcelle_id
and dimptfu.annee=v_annee)
ON CONFLICT DO NOTHING;
GET DIAGNOSTICS v_rows_inserted = ROW_COUNT;
RETURN v_rows_inserted;
END;
$$;

View File

@@ -0,0 +1,51 @@
/**
- consider les parcelles avec plusieurs batiment
- faire la somme (som_tfu_calcule) des TFU calculées
- on recupere la tfu minimum (max_tfu_min) de la catégorie la plus élévée des batiment
- si montant_tfu= Max(som_tfu_calcule, max_tfu_min)
*/
CREATE OR REPLACE FUNCTION public.maj_donnees_imposition_tfu_batie_plusBati(
p_impositions_tfu_id BIGINT
)
RETURNS INTEGER
LANGUAGE plpgsql
AS $$
DECLARE
v_rows_inserted INTEGER;
BEGIN
------MAJ pour les parcelles ayants plusieurs batiment
WITH donnees_imposition_plusieurs_bat AS (
SELECT
dimp.parcelle_id,
GREATEST(
MAX(dimp.tfu_minimum),
SUM(dimp.montant_taxe_brut)
) AS montant_tfu_parcelle,
COUNT(*) AS nombre_bat
FROM donnees_imposition_tfu dimp
LEFT JOIN unite_logement ul_filter on dimp.unite_logement_id = ul_filter.id
where impositions_tfu_id=p_impositions_tfu_id
AND batie=true and ul_filter.id is null
AND nature_impot='FB'
GROUP BY dimp.parcelle_id
HAVING COUNT(*) > 1
)
UPDATE donnees_imposition_tfu dimp
SET
montant_taxe = dippb.montant_tfu_parcelle,
nombre_bat = dippb.nombre_bat
FROM donnees_imposition_plusieurs_bat dippb
WHERE dimp.parcelle_id = dippb.parcelle_id
AND dimp.impositions_tfu_id=p_impositions_tfu_id;
------FIN MAJ pour les parcelles ayants plusieurs batiment
GET DIAGNOSTICS v_rows_inserted = ROW_COUNT;
RETURN v_rows_inserted;
END;
$$;

View File

@@ -0,0 +1,53 @@
/**
- consider les parcelles avec plusieurs batiment
- faire la somme (som_tfu_calcule) des TFU calculées
- on recupere la tfu minimum (max_tfu_min) de la catégorie la plus élévée des batiment
- si montant_tfu= Max(som_tfu_calcule, max_tfu_min)
*/
CREATE OR REPLACE FUNCTION public.maj_donnees_imposition_tfu_batie_plusBati_une_parcelle(
p_impositions_tfu_id BIGINT,
p_parcelle_id BIGINT
)
RETURNS INTEGER
LANGUAGE plpgsql
AS $$
DECLARE
v_rows_inserted INTEGER;
BEGIN
------MAJ pour les parcelles ayants plusieurs batiment
WITH donnees_imposition_plusieurs_bat AS (
SELECT
dimp.parcelle_id,
GREATEST(
MAX(dimp.tfu_minimum),
SUM(dimp.montant_taxe_brut)
) AS montant_tfu_parcelle,
COUNT(*) AS nombre_bat
FROM donnees_imposition_tfu dimp
LEFT JOIN unite_logement ul_filter on dimp.unite_logement_id = ul_filter.id
where impositions_tfu_id=p_impositions_tfu_id
AND batie=true and ul_filter.id is null
AND nature_impot='FB'
AND dimp.parcelle_id=p_parcelle_id
GROUP BY dimp.parcelle_id
HAVING COUNT(*) > 1
)
UPDATE donnees_imposition_tfu dimp
SET
montant_taxe = dippb.montant_tfu_parcelle,
nombre_bat = dippb.nombre_bat
FROM donnees_imposition_plusieurs_bat dippb
WHERE dimp.parcelle_id = dippb.parcelle_id
AND dimp.impositions_tfu_id=p_impositions_tfu_id;
------FIN MAJ pour les parcelles ayants plusieurs batiment
GET DIAGNOSTICS v_rows_inserted = ROW_COUNT;
RETURN v_rows_inserted;
END;
$$;

View File

@@ -508,53 +508,115 @@ SELECT new io.gmss.fiscad.paylaods.request.crudweb.DonneesImpositionPaylaodWeb(
Pageable pageable Pageable pageable
); );
@Query(value = "SELECT generer_donnees_imposition_tfu_batie(:structureId, :impositionId)", nativeQuery = true) @Query(value = "SELECT generer_donnees_imposition_tfu_batie(:impositionId, :userId)", nativeQuery = true)
Integer genererDonneesTfuBatie( Integer genererDonneesTfuBatie(
@Param("structureId") Long structureId, @Param("impositionId") Long impositionId,
@Param("impositionId") Long impositionId @Param("userId") Long userId
);
@Query(value = "SELECT generer_donnees_imposition_tfu_batie_une_parcelle(:impositionId, :userId,:parcelleId)", nativeQuery = true)
Integer genererDonneesTfuBatie(
@Param("impositionId") Long impositionId,
@Param("userId") Long userId,
@Param("parcelleId") Long parcelleId
); );
@Query(value = "SELECT generer_donnees_imposition_tfu_batie_unite_logement(:structureId, :impositionId)", nativeQuery = true) @Query(value = "SELECT generer_donnees_imposition_tfu_batie_unite_logement(:impositionId, :userId)", nativeQuery = true)
Integer genererDonneesTfuBatieUniteLogement( Integer genererDonneesTfuBatieUniteLogement(
@Param("structureId") Long structureId, @Param("impositionId") Long impositionId,
@Param("impositionId") Long impositionId @Param("userId") Long userId
);
@Query(value = "SELECT generer_donnees_imposition_tfu_batie_ulo_une_parcelle(:impositionId, :userId,:parcelleId)", nativeQuery = true)
Integer genererDonneesTfuBatieUniteLogement(
@Param("impositionId") Long impositionId,
@Param("userId") Long userId,
@Param("parcelleId") Long parcelleId
); );
@Query(value = "SELECT generer_donnees_imposition_tfu_non_batie(:structureId, :impositionId)", nativeQuery = true) @Query(value = "SELECT generer_donnees_imposition_tfu_non_batie(:impositionId, :userId)", nativeQuery = true)
Integer genererDonneesTfuNonBatie( Integer genererDonneesTfuNonBatie(
@Param("structureId") Long structureId, @Param("impositionId") Long impositionId,
@Param("impositionId") Long impositionId @Param("userId") Long userId
); );
@Query(value = "SELECT generer_donnees_imposition_irf_batie(:structureId, :impositionId)", nativeQuery = true) @Query(value = "SELECT generer_donnees_imposition_tfu_non_batie_une_parcelle(:impositionId, :userId, :parcelleId)", nativeQuery = true)
Integer genererDonneesTfuNonBatie(
@Param("impositionId") Long impositionId,
@Param("userId") Long userId,
@Param("parcelleId") Long parcelleId
);
@Query(value = "SELECT generer_donnees_imposition_irf_batie(:impositionId, :userId)", nativeQuery = true)
Integer genererDonneesIrfBatie( Integer genererDonneesIrfBatie(
@Param("structureId") Long structureId, @Param("impositionId") Long impositionId,
@Param("impositionId") Long impositionId @Param("userId") Long userId
); );
@Query(value = "SELECT generer_donnees_imposition_srtb_batie(:structureId, :impositionId)", nativeQuery = true) @Query(value = "SELECT generer_donnees_imposition_irf_batie_une_parcelle(:impositionId, :userId, :parcelleId)", nativeQuery = true)
Integer genererDonneesIrfBatie(
@Param("impositionId") Long impositionId,
@Param("userId") Long userId,
@Param("parcelleId") Long parcelleId
);
@Query(value = "SELECT generer_donnees_imposition_srtb_batie(:impositionId, :userId)", nativeQuery = true)
Integer genererDonneesSrtbBatie( Integer genererDonneesSrtbBatie(
@Param("structureId") Long structureId, @Param("impositionId") Long impositionId,
@Param("impositionId") Long impositionId @Param("userId") Long userId
); );
@Query(value = "SELECT generer_donnees_imposition_irf_batie_unite_logement(:structureId, :impositionId)", nativeQuery = true) @Query(value = "SELECT generer_donnees_imposition_srtb_batie_une_parcelle(:impositionId, :userId, :parcelleId)", nativeQuery = true)
Integer genererDonneesSrtbBatie(
@Param("impositionId") Long impositionId,
@Param("userId") Long userId,
@Param("parcelleId") Long parcelleId
);
@Query(value = "SELECT generer_donnees_imposition_irf_batie_unite_logement(:impositionId, :userId)", nativeQuery = true)
Integer genererDonneesIrfBatieUniteLogement( Integer genererDonneesIrfBatieUniteLogement(
@Param("structureId") Long structureId, @Param("impositionId") Long impositionId,
@Param("userId") Long userId
);
@Query(value = "SELECT generer_donnees_imposition_irf_batie_ulo_une_parcelle(:impositionId, :userId, :parcelleId)", nativeQuery = true)
Integer genererDonneesIrfBatieUniteLogement(
@Param("impositionId") Long impositionId,
@Param("userId") Long userId,
@Param("parcelleId") Long parcelleId
);
// @Query(value = "SELECT generer_donnees_imposition_srtb_batie_unite_logement(:impositionId, :userId)", nativeQuery = true)
// Integer genererDonneesSrtbBatieUniteLogement(
// @Param("impositionId") Long impositionId,
// @Param("userId") Long userId
// );
// @Query(value = "SELECT generer_donnees_imposition_srtb_batie_u(:impositionId, :userId)", nativeQuery = true)
// Integer genererDonneesSrtbBatieUniteLogement(
// @Param("impositionId") Long impositionId,
// @Param("userId") Long userId
// );
@Query(value = "SELECT maj_donnees_imposition_tfu_batie_plusBati(:impositionId)", nativeQuery = true)
Integer majDonneesTfuBatiePlusieursBatiment(
@Param("impositionId") Long impositionId @Param("impositionId") Long impositionId
); );
@Query(value = "SELECT generer_donnees_imposition_srtb_batie_unite_logement(:structureId, :impositionId)", nativeQuery = true) @Query(value = "SELECT maj_donnees_imposition_tfu_batie_plusbati_une_parcelle(:impositionId,:parcelleId)", nativeQuery = true)
Integer genererDonneesSrtbBatieUniteLogement( Integer majDonneesTfuBatiePlusieursBatiment(
@Param("structureId") Long structureId, @Param("impositionId") Long impositionId,
@Param("impositionId") Long impositionId @Param("parcelleId") Long parcelleId
); );
@Query(value = """ @Query(value = """
SELECT new io.gmss.fiscad.paylaods.request.crudweb.DonneesImpositionPaylaodWeb( SELECT new io.gmss.fiscad.paylaods.request.crudweb.DonneesImpositionPaylaodWeb(
d.id, d.id,

View File

@@ -1,6 +1,6 @@
spring.profiles.active=${SPRING_PROFILES_ACTIVE} #spring.profiles.active=${SPRING_PROFILES_ACTIVE}
#spring.profiles.active=abomey #spring.profiles.active=abomey
#spring.profiles.active=test spring.profiles.active=test
spring.jpa.properties.hibernate.id.new_generator_mappings=false spring.jpa.properties.hibernate.id.new_generator_mappings=false
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
spring.jpa.open-in-view=false spring.jpa.open-in-view=false