feat: Version 3.5.2 - Configuration Stripe et gestion des immeubles

- Configuration complète Stripe pour les 3 environnements (DEV/REC/PROD)
  * DEV: Clés TEST Pierre (mode test)
  * REC: Clés TEST Client (mode test)
  * PROD: Clés LIVE Client (mode live)
- Ajout de la gestion des bases de données immeubles/bâtiments
  * Configuration buildings_database pour DEV/REC/PROD
  * Service BuildingService pour enrichissement des adresses
- Optimisations pages et améliorations ergonomie
- Mises à jour des dépendances Composer
- Nettoyage des fichiers obsolètes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
pierre
2025-11-09 18:26:27 +01:00
parent 21657a3820
commit 2f5946a184
812 changed files with 142105 additions and 25992 deletions

View File

@@ -24,24 +24,78 @@ Ce document décrit le système de gestion des secteurs dans l'API Geosector, in
- Contient toutes les tables de l'application
- Tables concernées : `ope_sectors`, `sectors_adresses`, `ope_pass`, `ope_users_sectors`, `x_departements_contours`
2. **Base adresses** (dans conteneurs Incus séparés)
- DVA : `dva-maria` (13.23.33.46) - base `adresses`
- RCA : `rca-maria` (13.23.33.36) - base `adresses`
- PRA : `pra-maria` (13.23.33.26) - base `adresses`
- Credentials : `adr_geo_user` / `d66,AdrGeoDev.User`
2. **Base adresses** (dans conteneurs maria3/maria4)
- **DVA** : maria3 (13.23.33.4) - base `adresses`
- User : `adr_geo_user` / `d66,AdrGeoDev.User`
- **RCA** : maria3 (13.23.33.4) - base `adresses`
- User : `adr_geo_user` / `d66,AdrGeoRec.User`
- **PROD** : maria4 (13.23.33.4) - base `adresses`
- User : `adr_geo_user` / `d66,AdrGeoPrd.User`
- Tables par département : `cp22`, `cp23`, etc.
3. **Base bâtiments** (dans conteneurs maria3/maria4)
- **DVA** : maria3 (13.23.33.4) - base `batiments`
- User : `adr_geo_user` / `d66,AdrGeoDev.User`
- **RCA** : maria3 (13.23.33.4) - base `batiments`
- User : `adr_geo_user` / `d66,AdrGeoRec.User`
- **PROD** : maria4 (13.23.33.4) - base `batiments`
- User : `adr_geo_user` / `d66,AdrGeoPrd.User`
- Tables par département : `bat22`, `bat23`, etc.
- Colonnes principales : `batiment_groupe_id`, `cle_interop_adr`, `nb_log`, `nb_niveau`, `residence`, `altitude_sol_mean`
- Lien avec adresses : `bat{dept}.cle_interop_adr = cp{dept}.id`
### Configuration
Dans `src/Config/AppConfig.php` :
```php
// DÉVELOPPEMENT
'addresses_database' => [
'host' => '13.23.33.46', // Varie selon l'environnement
'host' => '13.23.33.4', // Container maria3 sur IN3
'name' => 'adresses',
'username' => 'adr_geo_user',
'password' => 'd66,AdrGeoDev.User',
],
// RECETTE
'addresses_database' => [
'host' => '13.23.33.4', // Container maria3 sur IN3
'name' => 'adresses',
'username' => 'adr_geo_user',
'password' => 'd66,AdrGeoRec.User',
],
// PRODUCTION
'addresses_database' => [
'host' => '13.23.33.4', // Container maria4 sur IN4
'name' => 'adresses',
'username' => 'adr_geo_user',
'password' => 'd66,AdrGeoPrd.User',
],
// DÉVELOPPEMENT - Bâtiments
'buildings_database' => [
'host' => '13.23.33.4', // Container maria3 sur IN3
'name' => 'batiments',
'username' => 'adr_geo_user',
'password' => 'd66,AdrGeoDev.User',
],
// RECETTE - Bâtiments
'buildings_database' => [
'host' => '13.23.33.4', // Container maria3 sur IN3
'name' => 'batiments',
'username' => 'adr_geo_user',
'password' => 'd66,AdrGeoRec.User',
],
// PRODUCTION - Bâtiments
'buildings_database' => [
'host' => '13.23.33.4', // Container maria4 sur IN4
'name' => 'batiments',
'username' => 'adr_geo_user',
'password' => 'd66,AdrGeoPrd.User',
],
```
## Gestion des contours départementaux
@@ -100,7 +154,7 @@ Vérifie les limites départementales des secteurs :
class DepartmentBoundaryService {
// Vérifie si un secteur est contenu dans un département
public function checkSectorInDepartment(array $sectorCoordinates, string $departmentCode): array
// Liste tous les départements touchés par un secteur
public function getDepartmentsForSector(array $sectorCoordinates): array
}
@@ -118,6 +172,46 @@ class DepartmentBoundaryService {
]
```
### BuildingService
Enrichit les adresses avec les données bâtiments :
```php
namespace App\Services;
class BuildingService {
// Enrichit une liste d'adresses avec les métadonnées des bâtiments
public function enrichAddresses(array $addresses): array
}
```
**Fonctionnement** :
- Connexion à la base `batiments` externe
- Interrogation des tables `bat{dept}` par département
- JOIN sur `bat{dept}.cle_interop_adr = cp{dept}.id`
- Ajout des métadonnées : `fk_batiment`, `fk_habitat`, `nb_niveau`, `nb_log`, `residence`, `alt_sol`
- Fallback : `fk_habitat=1` (maison individuelle) si pas de bâtiment trouvé
**Données retournées** :
```php
[
'id' => 'cp22.123456',
'numero' => '10',
'voie' => 'Rue Victor Hugo',
'code_postal' => '22000',
'commune' => 'Saint-Brieuc',
'latitude' => 48.5149,
'longitude' => -2.7658,
// Données bâtiment enrichies :
'fk_batiment' => 'BAT_123456', // null si maison
'fk_habitat' => 2, // 1=individuel, 2=collectif
'nb_niveau' => 4, // null si maison
'nb_log' => 12, // null si maison
'residence' => 'Résidence Les Pins', // '' si maison
'alt_sol' => 25.5 // null si maison
]
```
## Processus de création de secteur
### 1. Structure du payload
@@ -150,13 +244,77 @@ class DepartmentBoundaryService {
- Recherche des passages avec `fk_sector = 0` dans le polygone
- Mise à jour de leur `fk_sector` vers le nouveau secteur
- Exclusion des passages ayant déjà une `fk_adresse`
7. **Récupération** des adresses via `AddressService`
8. **Stockage** des adresses dans `sectors_adresses`
9. **Création** des passages dans `ope_pass` pour chaque adresse :
7. **Récupération** des adresses via `AddressService::getAddressesInPolygon()`
8. **Enrichissement** avec données bâtiments via `AddressService::enrichAddressesWithBuildings()`
9. **Stockage** des adresses dans `sectors_adresses` avec colonnes bâtiment :
- `fk_batiment`, `fk_habitat`, `nb_niveau`, `nb_log`, `residence`, `alt_sol`
10. **Création** des passages dans `ope_pass` :
- **Maisons individuelles** (fk_habitat=1) : 1 passage par adresse
- **Immeubles** (fk_habitat=2) : nb_log passages par adresse (1 par appartement)
- Champs ajoutés : `residence`, `appt` (numéro 1 à nb_log), `fk_habitat`
- Affectés au premier utilisateur de la liste
- Avec toutes les FK nécessaires (entité, opération, secteur, user)
- Données d'adresse complètes
10. **Commit** de la transaction ou **rollback** en cas d'erreur
11. **Commit** de la transaction ou **rollback** en cas d'erreur
## Processus de modification de secteur
### 1. Structure du payload UPDATE
```json
{
"libelle": "Secteur Centre-Ville Modifié",
"color": "#00FF00",
"sector": "48.117266/-1.6777926#48.118500/-1.6750000#...",
"users": [12, 34],
"chk_adresses_change": 1
}
```
### 2. Paramètre chk_adresses_change
**Valeurs** :
- `0` : Ne pas recalculer les adresses et passages (modification simple)
- `1` : Recalculer les adresses et passages (défaut)
**Cas d'usage** :
#### chk_adresses_change = 0
Modification rapide sans toucher aux adresses/passages :
- ✅ Modification du libellé
- ✅ Modification de la couleur
- ✅ Modification des coordonnées du polygone (visuel uniquement)
- ✅ Modification des membres affectés
- ❌ Pas de recalcul des adresses dans sectors_adresses
- ❌ Pas de mise à jour des passages (orphelins, créés, supprimés)
-**Réponse sans passages_sector** (tableau vide)
**Utilité** : Permet aux admins de corriger rapidement un libellé, une couleur, ou d'ajuster légèrement le périmètre visuel sans déclencher un recalcul complet qui pourrait prendre plusieurs secondes.
**Réponse API** :
```json
{
"status": "success",
"message": "Secteur modifié avec succès",
"sector": { "id": 123, "libelle": "...", "color": "...", "sector": "..." },
"passages_sector": [], // Vide car chk_adresses_change = 0
"passages_orphaned": 0,
"passages_deleted": 0,
"passages_updated": 0,
"passages_created": 0,
"passages_total": 0,
"users_sectors": [...]
}
```
#### chk_adresses_change = 1 (défaut)
Modification complète avec recalcul :
- ✅ Modification du libellé/couleur/polygone
- ✅ Modification des membres
- ✅ Suppression et recréation de sectors_adresses
- ✅ Application des règles de gestion des bâtiments
- ✅ Mise en orphelin des passages hors périmètre
- ✅ Création de nouveaux passages pour nouvelles adresses
### 3. Réponse API pour CREATE
@@ -287,14 +445,28 @@ $coordinates = [
### sectors_adresses
- `fk_sector` : Lien vers le secteur
- `fk_address` : ID de l'adresse dans la base externe
- `numero`, `voie`, `code_postal`, `commune`
- `latitude`, `longitude`
- `fk_adresse` : ID de l'adresse dans la base externe
- `numero`, `rue`, `rue_bis`, `cp`, `ville`
- `gps_lat`, `gps_lng`
- **Colonnes bâtiment** :
- `fk_batiment` : ID bâtiment (VARCHAR 50, null si maison)
- `fk_habitat` : 1=individuel, 2=collectif (TINYINT UNSIGNED)
- `nb_niveau` : Nombre d'étages (INT, null)
- `nb_log` : Nombre de logements (INT, null)
- `residence` : Nom résidence/copropriété (VARCHAR 75)
- `alt_sol` : Altitude sol en mètres (DECIMAL 10,2, null)
### ope_pass (passages)
- `fk_entite`, `fk_operation`, `fk_sector`, `fk_user`
- `numero`, `voie`, `code_postal`, `commune`
- `latitude`, `longitude`
- `fk_operation`, `fk_sector`, `fk_user`, `fk_adresse`
- `numero`, `rue`, `rue_bis`, `ville`
- `gps_lat`, `gps_lng`
- **Colonnes bâtiment** :
- `residence` : Nom résidence (VARCHAR 75)
- `appt` : Numéro appartement (VARCHAR 10, saisie libre)
- `niveau` : Étage (VARCHAR 10, saisie libre)
- `fk_habitat` : 1=individuel, 2=collectif (TINYINT UNSIGNED)
- `fk_type` : Type passage (2=à faire, autres valeurs pour fait/refus)
- `encrypted_name`, `encrypted_email`, `encrypted_phone` : Données cryptées
- `created_at`, `fk_user_creat`, `chk_active`
### ope_users_sectors
@@ -303,6 +475,103 @@ $coordinates = [
- `fk_sector` : Lien vers le secteur
- `created_at`, `fk_user_creat`, `chk_active`
## Règles de gestion des bâtiments lors de l'UPDATE
### Principe général
Lors de la mise à jour d'un secteur, le système applique une logique intelligente pour gérer les passages en fonction du type d'habitat (maison/immeuble) et du nombre de logements.
### Clé d'identification unique
**Tous les passages** sont identifiés par la clé : `numero|rue|rue_bis|ville`
Cette clé ne contient **pas** `residence` ni `appt` car ces champs sont en **saisie libre** par l'utilisateur.
### Cas 1 : Maison individuelle (fk_habitat=1)
#### Si 0 passage existant :
```
→ INSERT 1 nouveau passage
- fk_habitat = 1
- residence = ''
- appt = ''
```
#### Si 1+ passages existants :
```
→ UPDATE le premier passage
- fk_habitat = 1
- residence = ''
→ Les autres passages restent INTACTS
(peuvent correspondre à plusieurs habitants saisis manuellement)
```
### Cas 2 : Immeuble (fk_habitat=2)
#### Étape 1 : UPDATE systématique
```
→ UPDATE TOUS les passages existants à cette adresse
- fk_habitat = 2
- residence = sectors_adresses.residence (si non vide)
```
#### Étape 2a : Si nb_existants < nb_log (ex: 3 passages, nb_log=6)
```
→ INSERT (nb_log - nb_existants) nouveaux passages
- fk_habitat = 2
- residence = sectors_adresses.residence
- appt = '' (pas de numéro prédéfini)
- fk_type = 2 (à faire)
Résultat : 6 passages total (3 conservés + 3 créés)
```
#### Étape 2b : Si nb_existants > nb_log (ex: 10 passages, nb_log=6)
```
→ DELETE max (nb_existants - nb_log) passages
Conditions de suppression :
- fk_type = 2 (à faire)
- ET encrypted_name vide (non visité)
- Tri par created_at ASC (les plus anciens d'abord)
Résultat : Entre 6 et 10 passages (selon combien sont visités)
```
### Points importants
**Préservation des données utilisateur** :
- `appt` et `niveau` ne sont **JAMAIS modifiés** (saisie libre conservée)
- Les passages visités (encrypted_name rempli) ne sont **JAMAIS supprimés**
**Mise à jour conditionnelle** :
- `residence` est mis à jour **uniquement si non vide** dans sectors_adresses
- Permet de conserver une saisie manuelle si la base bâtiments n'a pas l'info
**Gestion des transitions** :
- Une adresse peut passer de maison (fk_habitat=1) à immeuble (fk_habitat=2) ou inversement
- La logique s'adapte automatiquement au nouveau type d'habitat
**Uniformisation GPS** :
- **Tous les passages d'une même adresse partagent les mêmes coordonnées GPS** (gps_lat, gps_lng)
- Ces coordonnées proviennent de `sectors_adresses` (enrichies depuis la base externe `adresses`)
- Cette règle s'applique lors de la **création** et de la **mise à jour** avec `chk_adresses_change=1`
- Garantit la cohérence géographique pour tous les passages d'un même immeuble
### Exemple concret
**Situation initiale** :
- Adresse : "10 rue Victor Hugo, 22000 Saint-Brieuc"
- 8 passages existants (dont 3 visités)
- nb_log passe de 8 à 5
**Actions** :
1. UPDATE les 8 passages → fk_habitat=2, residence="Les Chênes"
2. Tentative suppression de (8-5) = 3 passages
3. Recherche des passages avec fk_type=2 ET encrypted_name vide
4. Suppose 5 passages non visités trouvés
5. Suppression des 3 plus anciens non visités
6. **Résultat** : 5 passages restants (3 visités + 2 non visités)
## Logs et monitoring
Le système génère des logs détaillés pour :