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:
@@ -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 :
|
||||
|
||||
Reference in New Issue
Block a user