feat(commercial) : géolocalisation des adresses Tiers (lat/lng + géocodage BAN + pin ajustable) (ERP-122)
Ajoute la géolocalisation aux adresses Client et Fournisseur, socle de la tournée commerciale (M6 field-sales). Back : - migration : latitude/longitude NUMERIC(10,7), geo_manual BOOLEAN, geocoded_at TIMESTAMPTZ sur client_address et supplier_address (+ COMMENT ON COLUMN FR) - GeolocatableAddressInterface (Shared/Domain/Contract) implémenté par les deux entités ; bornes WGS84 validées (Range -90/90, -180/180, messages FR) - GeocoderInterface + BanGeocoder (api-adresse.data.gouv.fr), branché via AddressGeocoder dans les processors ; géocodage auto au create/update - RG-6.08 : geo_manual=true fige les coordonnées (pas de réécriture auto) - symfony/http-client passe en dépendance de production Front : - AddressGeoPin (Leaflet + OSM) : marqueur déplaçable -> PATCH lat/lng + geoManual=true, bouton Re-géocoder, badges « à géolocaliser » / « pin manuel » - intégration dans les blocs adresse Client et Fournisseur Tests : PHPUnit (géocodage create, non-réécriture RG-6.08, mapping BAN, bornes) + Vitest (drag du pin, badges, re-géocodage).
This commit is contained in:
@@ -0,0 +1,322 @@
|
||||
---
|
||||
# === IDENTITÉ ===
|
||||
module: M6
|
||||
nom: "Tournées commerciales terrain"
|
||||
ecran: tournees-terrain
|
||||
owner_spec: Matthieu
|
||||
backup_spec: ""
|
||||
version: V0.2
|
||||
# Historique :
|
||||
# V0.2 (2026-06-11) — RÉDUCTION DE SCOPE : suppression du volet « rapport de visite »
|
||||
# (entité VisitReport, fichiers, offres de prix, note /5, saisie vocale, historique des
|
||||
# visites) et du mode terrain mobile dédié. Périmètre recentré sur : géolocalisation,
|
||||
# carte interactive, planification de tournées, et onglet « Carte » dans les fiches Tiers.
|
||||
# V0.1 (2026-06-11) — Rédaction initiale (inspirée de Badger Maps, SPOTIO, Portatour, Nomadia).
|
||||
date_redaction: 2026-06-11
|
||||
|
||||
# === LIENS ===
|
||||
spec_front: ./spec-front.md
|
||||
maquette_figma: ""
|
||||
|
||||
# === LIEN LESSTIME ===
|
||||
lesstime_taskgroup_id: 28 # M6 — Tournées commerciales terrain (projet STARSEED #6)
|
||||
lesstime_project_id: 6
|
||||
statut_global: en_dev
|
||||
|
||||
# === DÉPENDANCES AMONT ===
|
||||
depend_de:
|
||||
- M1-clients # Client / ClientAddress (cible de visite + onglet Carte)
|
||||
- M2-suppliers # Supplier / SupplierAddress (cible de visite + onglet Carte)
|
||||
- Sites # rattachement site d'une adresse (déjà en place)
|
||||
- Core # User (commercial), Role, Permission, JWT
|
||||
- Shared # TimestampableBlamableTrait + contrats inter-modules
|
||||
---
|
||||
|
||||
# Spec — Module 6 : Tournées commerciales terrain (`field_sales`)
|
||||
|
||||
> **Périmètre V0.2 (réduit)** : géolocalisation des adresses Tiers, carte interactive, planification
|
||||
> de tournées (étapes, optimisation, navigation Waze/Maps, feuille de route PDF) et onglet « Carte »
|
||||
> dans les fiches Client/Fournisseur. **Hors scope : tout rapport de visite** (compte-rendu, note,
|
||||
> offres de prix, fichiers, saisie vocale) et le mode terrain mobile dédié.
|
||||
|
||||
## 1. Contexte & objectif
|
||||
|
||||
Donner aux commerciaux terrain (technico-commerciaux agricoles : visites d'exploitations, coopératives,
|
||||
négoces) un outil de **planification de tournées** intégré à Starseed, reposant sur le référentiel Tiers
|
||||
existant (Clients M1 + Fournisseurs M2). Fonctionne sur **desktop et mobile/tablette** (responsive, pas
|
||||
d'offline en V1).
|
||||
|
||||
Le commercial doit pouvoir :
|
||||
|
||||
1. Voir ses Tiers sur une **carte interactive** (pins colorés par type : client / fournisseur / prospect / custom).
|
||||
2. **Construire une tournée lui-même** : ajouter des étapes (une étape = une adresse précise d'un Tiers ou un
|
||||
point libre), les **réordonner en drag & drop**, fixer une **heure de départ**.
|
||||
3. Obtenir le **temps total** et le **temps entre chaque étape** (calcul auto), avec heure d'arrivée estimée.
|
||||
4. Cliquer **« Trajet logique »** (V1, heuristique gratuite) puis **« Optimiser »** (V2, routier réel) pour
|
||||
ordonner les étapes au mieux.
|
||||
5. **Lancer la navigation** (Waze / Google Maps / Plan) vers une étape en un tap.
|
||||
6. **Dupliquer** une tournée et **exporter une feuille de route PDF**.
|
||||
7. Consulter un **onglet « Carte »** dans la fiche Client/Fournisseur affichant les adresses géolocalisées du Tiers.
|
||||
|
||||
## 2. Inspiration — logiciels de tournée de référence
|
||||
|
||||
| Logiciel | Pattern repris | Application Starseed |
|
||||
|---|---|---|
|
||||
| **Badger Maps** | *Lasso tool* : on entoure des Tiers sur la carte → route optimisée auto. Pins colorés par type. | Sélection lasso/rectangle sur la carte pour bâtir la tournée. Pins par type. |
|
||||
| **SPOTIO** | Réordonnancement **drag & drop**, lieu de départ + bouton *Optimize*. | Liste d'étapes draggable, point de départ paramétrable, boutons « Trajet logique » / « Optimiser ». |
|
||||
| **Portatour** | Optimisation en quelques secondes, temps entre RDV. | Durée de visite paramétrable par étape, intégrée au temps total. |
|
||||
| **Nomadia Field Sales** | Carte + tournée dans un outil mobile responsive. | Écran de planification responsive desktop + mobile. |
|
||||
|
||||
## 3. Décisions d'architecture
|
||||
|
||||
### 3.1 Nouveau module `field_sales`
|
||||
|
||||
La tournée est **transverse** : elle vise aussi bien des Clients (M1) que des Fournisseurs (M2). Module dédié
|
||||
`src/Module/FieldSales/` (ID `field_sales`, label « Tournées »), `REQUIRED = false` (activable via
|
||||
`config/modules.php`).
|
||||
|
||||
**Règle ABSOLUE n°1 respectée** : `FieldSales` n'importe **aucune** classe de `Commercial`. Il référence les
|
||||
Tiers visités via un **contrat partagé** `App\Shared\Domain\Contract\VisitableInterface` (`getId()`,
|
||||
`getDisplayName()`, `getVisitableType()` = `client|supplier`) résolu par `resolve_target_entities`, comme
|
||||
`ClientAddress` référence `SiteInterface` / `CategoryInterface`.
|
||||
|
||||
### 3.1.bis Une étape vise tout Tiers — et même un point libre
|
||||
|
||||
Une étape n'est pas limitée à Client/Fournisseur : elle vise **tout type de Tiers** (Client, Fournisseur,
|
||||
**Prestataire** à venir) via `VisitableInterface` (extensible sans toucher au module FieldSales), **ou un point
|
||||
`custom`** (prospect/RDV sans fiche : libellé + adresse + coordonnées saisis à la main). L'enum `tier_type` est
|
||||
volontairement **ouvert** (string + Assert\Choice = types Visitable enregistrés + `custom`).
|
||||
|
||||
### 3.2 Géolocalisation portée par l'adresse Tiers — **FAIT (ticket M6.1 / ERP-122)**
|
||||
|
||||
`latitude` / `longitude` / `geo_manual` / `geocoded_at` sur `client_address` et `supplier_address`, géocodage
|
||||
api-adresse.data.gouv.fr + pin ajustable. Prérequis routage : une étape sans coordonnées reste utilisable mais
|
||||
**exclue du calcul de trajet** (badge « à géolocaliser »).
|
||||
|
||||
### 3.3 Carte interactive — Leaflet + OpenStreetMap (pas Google Maps JS)
|
||||
|
||||
Pour l'**affichage** carte/pins : **Leaflet** + tuiles **OpenStreetMap** (ou IGN). Gratuit, RGPD-friendly, pas
|
||||
de clé facturée pour le rendu. Composant carte encapsulé dans `frontend/modules/field-sales/` ; côté
|
||||
formulaire/filtre on reste sur les composants `Malio*`. La carte est une **exception documentée** à
|
||||
`@malio/layer-ui` (type non couvert). Le **routing réel** (matrice de temps) est un service distinct (§ 3.4).
|
||||
|
||||
### 3.4 Stratégie de calcul de trajet — phasée
|
||||
|
||||
| Phase | Bouton | Moteur | Coût |
|
||||
|---|---|---|---|
|
||||
| **V1** | « Trajet logique » | Heuristique maison **plus proche voisin** (Haversine), départ fixé. Temps estimé = distance × vitesse moyenne paramétrable. | 0 € |
|
||||
| **V2** | « Optimiser » | **Matrix API** (temps routiers réels) + optimisation TSP (OpenRouteService / OSRM / Mapbox). | Par appel (cache, debounce) |
|
||||
|
||||
Contrat `RouteEngineInterface` (`computeMatrix`, `optimizeOrder`, `estimateLegDurations`) posé dès la V1 avec
|
||||
`HaversineRouteEngine`. La V2 ajoute `OrsRouteEngine` sans toucher au front. **On n'écrit jamais l'algo routier
|
||||
— on branche un fournisseur.**
|
||||
|
||||
### 3.5 IDs entier auto-increment, Audit, Timestampable/Blamable
|
||||
|
||||
Cohérent avec M0/M1/M2. Toutes les entités métier : `#[Auditable]`, `implements TimestampableInterface,
|
||||
BlamableInterface` + `use TimestampableBlamableTrait`. Entités auditées : `Tour`, `TourStop`.
|
||||
|
||||
## 4. Modèle de données
|
||||
|
||||
### 4.1 Adresses Tiers (M1 + M2) — **FAIT (ERP-122)**
|
||||
|
||||
Colonnes `latitude` NUMERIC(10,7), `longitude` NUMERIC(10,7), `geo_manual` BOOLEAN, `geocoded_at` TIMESTAMPTZ
|
||||
sur `client_address` et `supplier_address` ; contrat `GeolocatableAddressInterface` côté `Shared`.
|
||||
|
||||
### 4.2 `Tour` (tournée) — `tour`
|
||||
|
||||
| Champ | Type | Règle |
|
||||
|---|---|---|
|
||||
| `id` | int PK | |
|
||||
| `owner_id` | FK User | Commercial propriétaire. Tournée **personnelle** (RG-6.01). |
|
||||
| `label` | varchar(120) | Nom libre. NotBlank. |
|
||||
| `tour_date` | date | Date de réalisation. NotBlank. |
|
||||
| `departure_time` | time | Heure de départ (alimente les ETA). Défaut 08:00. |
|
||||
| `start_latitude` / `start_longitude` | numeric null | Point de départ (site commercial ou adresse libre). NULL → départ = 1re étape. |
|
||||
| `start_label` | varchar(180) null | Libellé du point de départ. |
|
||||
| `default_visit_minutes` | smallint default 30 | Durée de visite par défaut (temps total). |
|
||||
| `status` | enum `draft\|planned\|in_progress\|done` | Cycle de vie (RG-6.02). |
|
||||
| `total_distance_m` / `total_duration_s` | int null | Derniers totaux calculés (cache d'affichage). |
|
||||
|
||||
`#[Auditable]`, Timestampable/Blamable, soft delete (`deleted_at`). `GetCollection` paginée, filtrée par owner.
|
||||
|
||||
### 4.3 `TourStop` (étape) — `tour_stop`
|
||||
|
||||
| Champ | Type | Règle |
|
||||
|---|---|---|
|
||||
| `id` | int PK | |
|
||||
| `tour_id` | FK Tour | onDelete CASCADE. |
|
||||
| `tier_type` | string `client\|supplier\|…\|custom` | Cible (résolue via `VisitableInterface`). `custom` = point libre. |
|
||||
| `tier_id` | int null | ID du Tiers référentiel. NULL si `custom`. |
|
||||
| `address_id` | int null | Adresse précise visitée (un Tiers a plusieurs adresses — RG-6.03). NULL si `custom`. |
|
||||
| `custom_label` | varchar(180) null | Libellé du point libre (obligatoire ssi `custom`). |
|
||||
| `custom_address` | varchar(255) null | Adresse texte du point libre (ssi `custom`), géocodée. |
|
||||
| `custom_latitude` / `custom_longitude` | numeric null | Coordonnées du point libre (pin ajustable). |
|
||||
| `position` | smallint | Ordre dans la tournée (drag & drop). |
|
||||
| `visit_minutes` | smallint null | Durée de visite spécifique (sinon `tour.default_visit_minutes`). |
|
||||
| `leg_distance_m` / `leg_duration_s` | int null | Distance/temps **depuis l'étape précédente** (calculés). |
|
||||
| `eta` | time null | Heure d'arrivée estimée. |
|
||||
|
||||
`#[Auditable]`, Timestampable/Blamable. Unicité `(tour_id, position)`. **Pas** de rapport rattaché (scope réduit).
|
||||
|
||||
> Deux étapes peuvent viser le même Tiers (RG-6.07) — pas d'unicité sur `tier_id`.
|
||||
|
||||
## 5. API (API Platform — providers/processors, jamais de controller)
|
||||
|
||||
| Méthode | Endpoint | Sécurité | Note |
|
||||
|---|---|---|---|
|
||||
| GET | `/api/tours` | `field_sales.tours.view` | Paginé, filtré sur `owner` courant (admin/bureau voient tout). |
|
||||
| POST | `/api/tours` | `field_sales.tours.manage` | Crée une tournée draft. |
|
||||
| GET/PATCH/DELETE | `/api/tours/{id}` | view / manage | DELETE = soft delete. |
|
||||
| POST | `/api/tours/{tourId}/stops` | `field_sales.tours.manage` | Sous-ressource (Link toProperty `tour`, pattern ClientAddress). |
|
||||
| PATCH/DELETE | `/api/tour_stops/{id}` | `field_sales.tours.manage` | PATCH `position` = drag & drop. |
|
||||
| POST | `/api/tours/{id}/compute` | `field_sales.tours.manage` | Recalcule legs + ETA + totaux (`HaversineRouteEngine`). |
|
||||
| POST | `/api/tours/{id}/optimize` | `field_sales.tours.manage` | Réordonne via `optimizeOrder()` puis recompute. |
|
||||
| POST | `/api/tours/{id}/duplicate` | `field_sales.tours.manage` | Duplique étapes + départ à une nouvelle `tourDate` (RG-6.13). |
|
||||
| GET | `/api/tours/{id}/roadbook.pdf` | `field_sales.tours.view` | Feuille de route PDF (skill `pdf`). |
|
||||
| GET | `/api/visitable_tiers?bbox=...&q=...&type=client,supplier` | `field_sales.tours.view` | Pins dans la zone visible (carte). Paginé / `?pagination=false`. |
|
||||
|
||||
Toutes les collections sont **paginées** (règle ABSOLUE n°13). `/api/visitable_tiers` retourne un Paginator,
|
||||
borné par `bbox`.
|
||||
|
||||
## 6. Écrans
|
||||
|
||||
### 6.1 Planification de tournée (carte interactive — responsive desktop + mobile)
|
||||
|
||||
Layout **split** inspiré de Badger/SPOTIO :
|
||||
|
||||
- **Carte interactive Leaflet** : pins des Tiers de la zone (couleur par type, filtrables). Sélection
|
||||
**lasso/rectangle** → ajoute les Tiers entourés comme étapes. Clic pin → popup (nom, adresse, « + Ajouter »).
|
||||
Tracé de la tournée dessiné par-dessus (polyline numérotée).
|
||||
- **Panneau tournée** : nom, date, **heure de départ**, point de départ, liste d'**étapes draggable**
|
||||
(n° + nom + adresse + ETA + temps depuis étape précédente), totaux (distance / durée / nb visites).
|
||||
Boutons **« Trajet logique »**, **« Optimiser »**, **« Dupliquer »**, **« PDF »**.
|
||||
- Chaque étape : menu **« Y aller »** (Waze / Google Maps / Plan via deep links), « Voir le Tiers ».
|
||||
- Ajout d'un **point libre `custom`** (libellé + adresse + pin).
|
||||
- En mobile, layout empilé : la navigation se fait via le bouton « Y aller » de chaque étape (pas de mode
|
||||
terrain dédié).
|
||||
|
||||
### 6.2 Onglet « Carte » dans la fiche Client / Fournisseur
|
||||
|
||||
Nouvel onglet **« Carte »** dans la fiche **Client (M1)** et **Fournisseur (M2)** : **mini-carte Leaflet**
|
||||
affichant **toutes les adresses géolocalisées du Tiers** (un marqueur par adresse, popup avec le libellé de
|
||||
l'adresse). Vue d'ensemble des implantations du Tiers. Le **pin reste ajustable** par adresse (réutilise le
|
||||
composant de l'onglet Adresse, déjà livré en ERP-122). Adresses sans coordonnées listées comme
|
||||
« à géolocaliser ». Onglet visible sous `field_sales.tours.view` ; masqué si le module `field_sales` est désactivé.
|
||||
|
||||
### 6.3 Ajustement du pin (fiche adresse) — **FAIT (ERP-122)**
|
||||
|
||||
Mini-carte Leaflet avec marqueur déplaçable dans le bloc adresse M1/M2 ; drag → `latitude/longitude` +
|
||||
`geo_manual = true` ; bouton « Re-géocoder depuis l'adresse ».
|
||||
|
||||
## 7. Géocodage des adresses — **FAIT (ERP-122)**
|
||||
|
||||
Service `GeocoderInterface` / `BanGeocoder` (api-adresse.data.gouv.fr). Correction manuelle systématique via le
|
||||
pin (`geo_manual = true` fige — RG-6.08).
|
||||
|
||||
## 8. RBAC — 3 miroirs obligatoires
|
||||
|
||||
Permissions du module `field_sales` (méthode `permissions()` de `FieldSalesModule.php`) — **uniquement les
|
||||
tournées** (plus de permissions `reports.*` depuis la réduction de scope) :
|
||||
|
||||
| Permission | Sens | Admin | Commerciale | Bureau |
|
||||
|---|---|---|---|---|
|
||||
| `field_sales.tours.view` | Voir les tournées + l'onglet Carte. | ✅ (toutes) | ✅ (les siennes) | ✅ (consultation) |
|
||||
| `field_sales.tours.manage` | Créer/éditer/optimiser/dupliquer/supprimer une tournée. | ✅ | ✅ | ❌ |
|
||||
|
||||
Attribution : **Commerciale + Admin** = manage ; **Bureau** = view ; Compta exclue. À synchroniser dans les
|
||||
**3 miroirs** (règle ABSOLUE n°8) : `config/sidebar.php` (section « Tournées » : item `tours` + i18n
|
||||
`sidebar.field_sales.*`), `frontend/tests/e2e/_fixtures/personas.ts`, `SeedE2ECommand.php`. Sync :
|
||||
`app:sync-permissions`.
|
||||
|
||||
## 9. Conventions & garde-fous (rappel)
|
||||
|
||||
- `declare(strict_types=1);` partout ; commentaires FR, code EN.
|
||||
- Entités métier : `#[Auditable]` + Timestampable/Blamable. Libellés i18n `audit.entity.field_sales_tour` /
|
||||
`_tourstop` dans `fr.json` (sinon `AuditableEntitiesHaveI18nLabelTest` casse `make test`).
|
||||
- Migration modulaire : `COMMENT ON COLUMN` sur **chaque** colonne (FR ≤ 200 car.) + helper
|
||||
`addStandardTimestampableBlamableComments()`.
|
||||
- Toute collection paginée (`CollectionsArePaginatedTest`).
|
||||
- Front : `useApi()` uniquement, composants `Malio*`, `MalioDataTable` + `usePaginatedList` pour les listes,
|
||||
**pas d'état de tableau dans l'URL**. Carte Leaflet = exception documentée.
|
||||
|
||||
## 10. Règles de gestion (RG)
|
||||
|
||||
| RG | Règle | Garde-fou |
|
||||
|---|---|---|
|
||||
| **RG-6.01** | Tournée **personnelle** (`owner`). Commerciale ne voit/édite que les siennes ; Admin/Bureau voient tout en lecture. | Filtre Provider sur `owner` + RBAC. |
|
||||
| **RG-6.02** | Cycle de vie `draft → planned → in_progress → done` (transitions libres en V1). | Enum + Assert\Choice. |
|
||||
| **RG-6.03** | Une étape sur Tiers référentiel vise une adresse de ce Tiers (qui en a plusieurs). Ne s'applique pas aux `custom`. | Assert\Callback. |
|
||||
| **RG-6.05** | Une étape n'entre dans le calcul que si son adresse a `latitude` ET `longitude`. Sinon « à géolocaliser », exclue des totaux. | `RouteEngine` + signalement front. |
|
||||
| **RG-6.07** | Deux étapes peuvent viser le même Tiers (repasser plus tard). Unicité uniquement sur `(tour_id, position)`. | Index unique partiel. |
|
||||
| **RG-6.08** | `geo_manual = true` fige les coordonnées (le géocodage auto ne réécrit plus). | Garde dans le géocodeur (FAIT). |
|
||||
| **RG-6.11** | `eta` = `departure_time` + Σ(trajets précédents) + Σ(durées de visite précédentes). | `RouteEngine::estimateLegDurations()`. |
|
||||
| **RG-6.12** | Une étape vise tout Tiers ou un point `custom`. Si `custom` : `tier_id`/`address_id` NULL, `custom_label` + coordonnées obligatoires. | Assert\Choice + Assert\Callback. |
|
||||
| **RG-6.13** | Dupliquer copie départ + étapes (ordre/adresses/durées) à une nouvelle date ; ne copie pas les calculs (ETA/legs recalculés). | Service `TourDuplicator`. |
|
||||
|
||||
## 11. Tests à automatiser
|
||||
|
||||
- **Architecture (cassent `make test`)** : `ColumnsHaveSqlCommentTest`, `AuditableEntitiesHaveI18nLabelTest`
|
||||
(`audit.entity.field_sales_tour` / `_tourstop`), `EntitiesAreTimestampableBlamableTest` (Tour, TourStop),
|
||||
`CollectionsArePaginatedTest`, `EntityConstraintsHaveFrenchMessageTest`.
|
||||
- **Back (PHPUnit)** : RG-6.03 (adresse hors Tiers → 422), RG-6.05 (étape sans coord exclue), RG-6.07 (doublon
|
||||
Tiers accepté), RG-6.11 (ETA), RG-6.12 (custom cohérent), RG-6.13 (duplication sans calculs), filtre `owner`,
|
||||
`HaversineRouteEngine` (ordre plus proche voisin sur un jeu de coordonnées connu).
|
||||
- **Front (Vitest)** : `usePaginatedList` sur tournées, composable de planification (réordonnancement, totaux,
|
||||
deep links), onglet Carte (marqueurs des adresses). **Pas de E2E** (règle d'or).
|
||||
|
||||
## 12. Hors-périmètre (HP)
|
||||
|
||||
- **HP-M6-1** : **rapport de visite** (compte-rendu, note /5, offres de prix, fichiers, catégorie, saisie
|
||||
vocale, historique des visites) — **retiré du scope (V0.2)**, à réintroduire dans un module/lot ultérieur si besoin.
|
||||
- **HP-M6-2** : mode terrain mobile dédié (vue du jour + check-in) — retiré ; navigation via l'écran de
|
||||
planification responsive.
|
||||
- **HP-M6-3** : routing routier réel + optimisation TSP (Matrix API) — V2 (V1 = heuristique Haversine).
|
||||
- **HP-M6-4** : suggestion automatique des Tiers « à visiter » (façon Portatour) — V2.
|
||||
- **HP-M6-5** : offline réel (PWA + synchro) — V3.
|
||||
- **HP-M6-6** : partage / affectation de tournées entre commerciaux, planning d'équipe — V3.
|
||||
- **HP-M6-7** : navigation multi-étapes poussée dans Waze (impossible techniquement) — navigation étape par étape.
|
||||
|
||||
## 13. Phasage
|
||||
|
||||
- **V1 (livrable)** : géoloc adresses + pin (FAIT) ; carte interactive + lasso ; tournée (création, drag & drop,
|
||||
heure de départ, point de départ) sur tout Tiers + point `custom` ; **« Trajet logique »** + ETA + totaux ;
|
||||
deep links Waze/Maps ; **duplication** ; **feuille de route PDF** ; **onglet Carte** dans les fiches
|
||||
Client/Fournisseur ; responsive desktop + mobile.
|
||||
- **V2** : bouton **« Optimiser »** (routing routier réel ORS/OSRM), temps trafic, suggestion des Tiers proches.
|
||||
- **V3** : offline réel, partage/affectation de tournées.
|
||||
|
||||
## 14. Risques / points ouverts
|
||||
|
||||
- **Coût/quota routing en V2** : multi-tenant → cache, debounce, plafonds par tenant.
|
||||
- **Limite Waze multi-étapes** : Waze ne prend qu'une destination → navigation étape par étape (assumé).
|
||||
- **Reste à cadrer techniquement** : périmètre de visibilité Bureau (toutes les tournées vs les siennes).
|
||||
|
||||
---
|
||||
|
||||
## 📦 Tickets Lesstime (scope réduit V0.2)
|
||||
|
||||
TaskGroup Lesstime : **#28 — M6 Tournées commerciales terrain** (projet STARSEED #6). Tickets gros grain, chacun
|
||||
avec un **prompt Fable** prêt à coller (consigne « adapte-toi à la config actuelle » incluse).
|
||||
|
||||
| # | Réf | Ticket | Effort | Tag | État |
|
||||
|---|---|---|---|---|---|
|
||||
| M6.1 | ERP-122 | Géolocaliser les adresses Tiers (lat/lng + pin) | L | Back+Front | ✅ Fait |
|
||||
| M6.2 | ERP-123 | Fondations module field_sales + VisitableInterface + RBAC (tournées) | M | Back | Prêt à dev |
|
||||
| M6.3 | ERP-124 | Entités & API Tournée + Étape | L | Back | Prêt à dev |
|
||||
| M6.4 | ERP-125 | Calcul trajet, optimisation, duplication & roadbook PDF | L | Back | Prêt à dev |
|
||||
| M6.5 | ERP-127 | Carte interactive + écran planification (responsive) | L | Front | Prêt à dev |
|
||||
| M6.6 | ERP-129 | Onglet « Carte » dans les fiches Client & Fournisseur | M | Front | Prêt à dev |
|
||||
| M6.7 | ERP-130 | Vérification : garde-fous archi, tests RG & golden path | M | Back+Front | Prêt à dev |
|
||||
|
||||
Supprimés à la réduction de scope : **ERP-126** (rapport de visite) et **ERP-128** (mode terrain mobile + formulaire rapport).
|
||||
|
||||
Ordre d'exécution : M6.2 → M6.3 → M6.4 → M6.5 → M6.6 → M6.7.
|
||||
|
||||
---
|
||||
|
||||
### Sources d'inspiration (logiciels de référence)
|
||||
- Badger Maps — *Lasso* + carte : https://www.badgermapping.com/features/
|
||||
- SPOTIO — drag & drop des étapes + optimize : https://support.spotio.com/hc/en-us/articles/360061370754-Routing-How-to-Build-and-Manage-Routes
|
||||
- Portatour — multi-stop + recalcul auto : https://www.portatour.com/features/en
|
||||
- Nomadia Field Sales — carte + tournée mobile : https://www.nomadia.com/ressources/blog/logiciel-commerciaux-itinerants/
|
||||
Reference in New Issue
Block a user