Aller au contenu principal

Create new address

POST 

/company/address/

Crée une nouvelle adresse associée à l'entreprise de l'utilisateur authentifié.
Cet endpoint permet d'enregistrer des emplacements physiques tels que des entrepôts, des bureaux ou des points de chargement/déchargement.

Flux d'opération :

  1. Authentification via un JWT valide
  2. Validation des champs obligatoires et des formats
  3. Traitement des données Google Maps (géocodage inversé)
  4. Si isDefault=true, désactive toute adresse principale existante
  5. Persistance en base de données
  6. Retour de l'adresse créée avec son ID

Validations importantes :

  • Requiert un token JWT valide avec des permissions administrateur/éditeur
  • Champ 'name' obligatoire (3-100 caractères)
  • Les données Google Maps doivent inclure :
    • formatted_address : Adresse complète formatée
    • geometry.location : Coordonnées {lat, lng}
  • Si isDefault=true, désactive toute adresse principale existante

Cas d'utilisation typiques :

  • Enregistrer un nouveau siège de l'entreprise
  • Ajouter un entrepôt logistique
  • Créer un point de collecte pour les expéditions

Note importante sur les téléphones :

  • Les numéros de téléphone (phone) doivent avoir un format valide pour l'Espagne, la France ou le Portugal

Requiert un abonnement actif (validé par le middleware isPaymentUpdate)

Les timestamps sont convertis en UTC par le middleware checkUTC

Exemple de requête :

POST /company/address  
Authorization: Bearer \{token\}
Content-Type: application/json

\{
name: Entrepôt Logistique,
company_name: CargoOffer SL,
phone: +34912345678,
addressGoogleMaps: \{
formatted_address: Calle de la Logística, 123, 28045 Madrid, España,
geometry: \{
location: \{
lat: 40.123456,
lng: -3.987654

<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>

<ParamsDetails
parameters={[]}
>

</ParamsDetails>

<RequestSchema
title={"Body"}
body={{"content":{"application/json":{"schema":{"properties":{},"type":"object","description":"Données requises pour créer une nouvelle adresse","required":["name","addressGoogleMaps"],"example":{"_id":"507f1f77bcf86cd799439011","name":"Almacén Logístico","company_name":"CargoOffer SL","phone":"+34912345678","addressGoogleMaps":{"formatted_address":"Calle de la Logística, 123, 28045 Madrid, España","geometry":{"location":{"lat":40.123456,"lng":-3.987654}}},"is_default":false},"title":"CreateAddressRequest"},"example":{"name":"Almacén Logístico","company_name":"CargoOffer SL","phone":"+34912345678","addressGoogleMaps":{"formatted_address":"Calle de la Logística, 123, 28045 Madrid, España","geometry":{"location":{"lat":40.123456,"lng":-3.987654}}},"is_default":false}}},"required":true}}
>

</RequestSchema>

<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Opération réussie","content":{"application/json":{"schema":{"type":"object","description":"Représente une adresse physique associée à une entreprise pour les opérations de chargement/déchargement.\n**Fonctionnalité** : - Point d'origine (ETL - Heure de chargement prévue) ou de destination (ETD - Heure de livraison prévue) dans les enchères de transport - Stockée par entreprise et réutilisable dans de multiples opérations - Géocodée automatiquement via l'API Google Maps lors de la création - Validée par rapport à son utilisation dans des enchères/livraisons actives avant suppression\n**Modèle** : `src/features/models/address.model.js`\n**Contrôleur** : `src/features/company/address/controller.js`","properties":{"_id":{"type":"string","description":"Identifiant unique MongoDB de l'adresse (24 caractères hexadécimaux). Généré automatiquement par le système lors de la création de l'adresse. Utilisé comme référence dans les modèles d'enchères (auction.etl_address, auction.etd_address) et de livraisons (delivery.etl_address, delivery.etd_address).","pattern":"^[a-f0-9]{24}$","example":"507f1f77bcf86cd799439011"},"name":{"type":"string","description":"Nom descriptif ou alias personnalisé de l'emplacement attribué par l'utilisateur. Utilisé pour une identification rapide dans les listes et la sélection d'adresses. **Obligatoire** - Minimum 3 caractères, maximum 100. Exemples : Entrepôt Nord, Siège Social, Client ABC - Usine Madrid","minLength":3,"maxLength":100,"example":"Oficina Central"},"company_name":{"type":"string","description":"Raison sociale ou nom commercial de l'entreprise à cette adresse. **Requis** - Apparaît sur les documents officiels (CMR, contrats). Peut différer du nom de la société principale s'il s'agit d'une adresse client/fournisseur. Minimum 2 caractères, maximum 100.","minLength":2,"maxLength":100,"example":"CargoOffer SL"},"phone":{"type":"string","description":"Numéro de téléphone de contact pour la coordination logistique à cette adresse. **Optionnel** - Format international recommandé (E.164 avec +code pays). Utilisé par les transporteurs pour confirmer l'arrivée et résoudre les incidents. Validé avec le motif : 9-15 chiffres.","pattern":"^\\+?[0-9]{9,15}$","maxLength":20,"example":"+34912345678"},"street":{"type":"string","description":"Rue complète avec numéro, générée automatiquement à partir de addressGoogleMaps. Format : Nom de Rue, Numéro. Utilisé pour l'affichage et les exportations CSV. Champ hérité combiné (voir street_address + street_number pour les champs séparés).","example":"Calle Ejemplo 123"},"street_address":{"type":"string","description":"Nom de la rue sans numéro (champ séparé). Parsé depuis la réponse de l'API Google Maps (composant route).","example":"Calle de Alcalá"},"street_number":{"type":"string","description":"Numéro de rue en tant que champ indépendant. Parsé à partir de la réponse de l'API Google Maps (composant street_number).","example":"42"},"city":{"type":"string","description":"Ville normalisée en minuscules, extraite automatiquement des coordonnées via l'API Google Maps Geocoding. Utilisée dans les filtres de recherche et le regroupement d'adresses par zone. Type : locality ou administrative_area_level_2 de Google Maps.","example":"madrid"},"state":{"type":"string","description":"État, communauté autonome ou région administrative (normalisé en minuscules). Extrait de administrative_area_level_1 de Google Maps. Optionnel - Peut être vide dans les pays sans division régionale.","example":"comunidad de madrid"},"zipcode":{"type":"string","description":"Code postal selon le format du pays correspondant. Extrait du composant postal_code de l'API Google Maps. Utilisé pour les validations de zone et les calculs de tarifs.","example":"28045"},"country":{"type":"string","description":"Code pays ISO 3166-1 alpha-2 en MAJUSCULES (2 lettres). **Critique** pour : validation du TaxID, format d'immatriculation, calcul des tarifs, restrictions ADR. Extrait du composant country (short_name) de l'API Google Maps. Doit correspondre aux pays actifs dans la collection 'countries'.","pattern":"^[A-Z]{2}$","example":"ES"},"neighborhood":{"type":"string","description":"Quartier ou zone à l'intérieur de la ville (facultatif). Tiré de neighborhood ou sublocality de Google Maps. Utilisé pour la précision dans les grandes zones urbaines.","example":"centro"},"province":{"type":"string","description":"Province ou division administrative provinciale. Tiré de administrative_area_level_2 de Google Maps (dans les pays ayant des provinces). Optionnel - Principalement pertinent en Espagne, Italie, etc.","example":"madrid"},"location":{"type":"object","description":"Coordonnées géographiques au format GeoJSON Point selon la norme RFC 7946. Système de référence : WGS84 (EPSG:4326). **REQUIS** - Utilisé par MongoDB pour les requêtes géospatiales ($near, $geoWithin). **CRITIQUE** : L'ordre dans le tableau `coordinates` est [longitude, latitude] (X, Y) - NE PAS inverser. Utilisé pour : le calcul des distances, les itinéraires optimaux, la validation des zones de service.","required":["type","coordinates"],"properties":{"type":{"type":"string","enum":["Point"],"description":"Type de géométrie GeoJSON. Doit toujours être Point pour les adresses. Les autres types (LineString, Polygon) ne sont pas valides dans ce contexte.","example":"Point"},"coordinates":{"type":"array","description":"Tableau de deux nombres : [longitude, latitude] en degrés décimaux. **ORDRE CRITIQUE** : longitude d'abord (axe X, -180 à 180), latitude ensuite (axe Y, -90 à 90). Exemple valide : [-3.70379, 40.416775] = 3.70° Ouest, 40.41° Nord (Madrid). **ERREUR FRÉQUENTE** : Inverser l'ordre entraîne des calculs incorrects. Utilisé dans : model.find({location: {$near: {$geometry: {type: 'Point', coordinates: [lng, lat]}}}})","items":{"type":"number"},"minItems":2,"maxItems":2,"example":[-3.70379,40.416775]}}},"placeId":{"type":"string","description":"Identifiant Google Place unique et immuable pour cet emplacement. Utilisé pour : géocodage inversé, validation des modifications, obtention de détails actualisés. Format : Chaîne alphanumérique commençant généralement par ChIJ. Conservé pour éviter les géocodages répétés (économie de coûts API).","example":"ChIJi-AoYTIoQg0RnHvWosEVABQ"},"name_address":{"type":"string","description":"Adresse complète formatée générée par Google Maps (formatted_address). Inclut : rue, numéro, code postal, ville, pays au format local. Utilisée pour : l'affichage aux utilisateurs, les exportations, les documents officiels. Non modifiable manuellement - régénérée automatiquement lors de la mise à jour des coordonnées.","example":"Calle de Alcalá, 42, 28014 Madrid, España"},"isDefault":{"type":"boolean","description":"Indiquez si c'est l'adresse principale/par défaut de l'entreprise. **Contrainte** : Une seule adresse par entreprise peut avoir isDefault=true. Lorsque vous définissez isDefault=true sur une adresse, l'adresse précédente avec ce drapeau passe automatiquement à false. Utilisée dans : autocomplétion de formulaires, adresse par défaut pour les nouvelles enchères. Également stockée dans : company.address_default (référence au _id de cette adresse).","default":false,"example":true},"can_be_deleted":{"type":"boolean","description":"Drapeau calculé dynamiquement au moment de la requête (non stocké en base de données). **false** : L'adresse est référencée dans des enchères ou des livraisons actives (statut != annulé/livré). **true** : L'adresse n'a aucune dépendance et peut être supprimée en toute sécurité. Calculé dans : controller.get() en vérifiant le comptage des auction/delivery où etl_address ou etd_address == this._id. Empêche : la suppression accidentelle d'adresses en cours d'utilisation, ce qui créerait des données orphelines.","example":false},"destinations":{"type":"array","description":"Tableau de destinations fréquentes avec des itinéraires précalculés depuis cette adresse. **Optimisation** : Évite de recalculer des itinéraires répétitifs, améliore les performances lors de la recherche d'enchères. Rempli par : un cron nocturne ou à la demande pour des paires d'adresses fréquentes. Utilisé dans : le endpoint /company/minimal pour les calculs de coût/distance sans appeler une API externe. Structure : [{address: ObjectId, minimalRoute: {distance: Number(km), timeCost: Number(min)}}]","items":{"type":"object","properties":{"address":{"type":"string","description":"ObjectId de l'adresse de destination","example":"507f1f77bcf86cd799439012"},"minimalRoute":{"type":"object","properties":{"distance":{"type":"number","description":"Distance calculée en kilomètres (via API d'itinéraires)","example":523.7},"timeCost":{"type":"number","description":"Temps de trajet estimé en minutes (en tenant compte de la vitesse moyenne)","example":360}}}}}}},"required":["_id","name","location","isDefault","can_be_deleted"],"title":"Address"},"example":{"status":200,"data":{"location":{"type":"Point","coordinates":[0,0]},"phone":"+34912345678","street_number":"","street_address":"","_id":"68f9f8bf0e38c035ea821e58","deleted":false,"destinations":[],"name":"Almacén Logístico","company_name":"CargoOffer SL","createdAt":"2025-10-23T09:43:27.719Z"}}}},"headers":{}},"400":{"description":"Requête invalide","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["MISSING_FIELD_NAME","INVALID_GOOGLE_MAPS_DATA","INVALID_ADDRESS_FORMAT"],"example":"INVALID_GOOGLE_MAPS_DATA"}}}}},"headers":{}},"401":{"description":"Non autorisé","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}},"headers":{}},"404":{"description":"Non trouvé","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}},"headers":{}}}}
>

</StatusCodes>