Create new address
POST/company/address/
Cria um novo endereço associado à empresa do usuário autenticado.
Este endpoint permite registrar localizações físicas como armazéns, escritórios ou pontos de carga/descarga.
Fluxo de operação:
- Autenticação via JWT válido
- Validação de campos obrigatórios e formatos
- Processamento dos dados do Google Maps (geocodificação reversa)
- Se isDefault=true, desmarca qualquer endereço principal existente
- Persistência no banco de dados
- Retorno do endereço criado com seu ID
Validações importantes:
- Requer token JWT válido com permissões de administrador/editor
- Campo 'name' obrigatório (3-100 caracteres)
- Dados do Google Maps devem incluir:
- formatted_address: Endereço completo formatado
- geometry.location: Coordenadas {lat, lng}
- Se isDefault=true, desmarca qualquer endereço principal existente
Casos de uso típicos:
- Registrar nova sede da empresa
- Adicionar armazém logístico
- Criar ponto de coleta para envios
Nota importante sobre telefones:
- Os números de telefone (phone) devem ter formato válido da Espanha, França ou Portugal
Requer assinatura ativa (validado pelo middleware isPaymentUpdate)
Timestamps são convertidos para UTC pelo middleware checkUTC
Exemplo de solicitação:
POST /company/address
Authorization: Bearer {token}
Content-Type: application/json
{
name: Armazém Logístico,
company_name: CargoOffer SL,
phone: +34912345678,
addressGoogleMaps: {
formatted_address: Calle de la Logística, 123, 28045 Madrid, Espanha,
geometry: {
location: {
lat: 40.123456,
lng: -3.987654
}
}
},
isDefault: false
}
Exemplo de resposta de sucesso:
\{
_id: 507
<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":"Dados necessários para criar um novo endereço","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":"Operação bem-sucedida","content":{"application/json":{"schema":{"type":"object","description":"Representa um endereço físico associado a uma empresa para operações de carga/descarga.\n**Funcionalidade**: - Ponto de origem (ETL - Tempo Esperado de Carregamento) ou destino (ETD - Tempo Esperado de Entrega) em leilões de transporte - Armazenado por empresa e reutilizável em múltiplas operações - Geocodificado automaticamente via Google Maps API ao criar - Validado contra uso em leilões/entregas ativas antes de excluir\n**Modelo**: `src/features/models/address.model.js`\n**Controlador**: `src/features/company/address/controller.js`","properties":{"_id":{"type":"string","description":"Identificador único MongoDB do endereço (24 caracteres hexadecimais). Gerado automaticamente pelo sistema ao criar o endereço. Utilizado como referência nos modelos de leilões (auction.etl_address, auction.etd_address) e entregas (delivery.etl_address, delivery.etd_address).","pattern":"^[a-f0-9]{24}$","example":"507f1f77bcf86cd799439011"},"name":{"type":"string","description":"Nome descritivo ou apelido personalizado da localização atribuído pelo usuário. Usado para identificação rápida em listas e seleção de endereços. **Obrigatório** - Mínimo de 3 caracteres, máximo de 100. Exemplos: Armazém Norte, Escritório Central, Cliente ABC - Fábrica Madrid","minLength":3,"maxLength":100,"example":"Oficina Central"},"company_name":{"type":"string","description":"Razão social ou nome comercial da empresa nesta localização. **Obrigatório** - Aparece em documentos oficiais (CMR, contratos). Pode diferir do nome da empresa principal se for um endereço de cliente/fornecedor. Mínimo de 2 caracteres, máximo de 100.","minLength":2,"maxLength":100,"example":"CargoOffer SL"},"phone":{"type":"string","description":"Número de telefone de contato para coordenação logística neste endereço. **Opcional** - Formato internacional recomendado (E.164 com +código do país). Usado por transportadoras para confirmar a chegada e resolver incidentes. Validado com padrão: 9-15 dígitos.","pattern":"^\\+?[0-9]{9,15}$","maxLength":20,"example":"+34912345678"},"street":{"type":"string","description":"Rua completa com número, gerada automaticamente a partir de addressGoogleMaps. Formato: 'Nome da Rua, Número'. Usado em visualização e exportações CSV. Campo legado combinado (ver street_address + street_number para separados).","example":"Calle Ejemplo 123"},"street_address":{"type":"string","description":"Nome da rua sem número (campo separado). Parseado da resposta da API do Google Maps (componente de rota).","example":"Calle de Alcalá"},"street_number":{"type":"string","description":"Número da rua como campo independente. Extraído da resposta da API do Google Maps (componente street_number).","example":"42"},"city":{"type":"string","description":"Cidade normalizada em minúsculas, extraída automaticamente de coordenadas via Google Maps Geocoding API. Usada em filtros de busca e agrupamento de endereços por zona. Tipo: locality ou administrative_area_level_2 do Google Maps.","example":"madrid"},"state":{"type":"string","description":"Estado, comunidade autónoma ou região administrativa (normalizado em minúsculas). Extraído de administrative_area_level_1 do Google Maps. Opcional - Pode estar vazio em países sem divisão regional.","example":"comunidad de madrid"},"zipcode":{"type":"string","description":"Código postal conforme ao formato do país correspondente. Extraído do componente postal_code da API do Google Maps. Utilizado em validações de zona e cálculos de tarifas.","example":"28045"},"country":{"type":"string","description":"Código do país ISO 3166-1 alpha-2 em MAIÚSCULAS (2 letras). **Crítico** para: validação de TaxID, formato de matrícula, cálculo de tarifas, restrições ADR. Extraído do componente de país (short_name) da API do Google Maps. Deve corresponder aos países ativos na collection 'countries'.","pattern":"^[A-Z]{2}$","example":"ES"},"neighborhood":{"type":"string","description":"Bairro ou zona dentro da cidade (opcional). Extraído de neighborhood ou sublocality do Google Maps. Usado para precisão em grandes zonas urbanas.","example":"centro"},"province":{"type":"string","description":"Província ou divisão administrativa provincial. Extraído de administrative_area_level_2 do Google Maps (em países com províncias). Opcional - Relevante principalmente na Espanha, Itália, etc.","example":"madrid"},"location":{"type":"object","description":"Coordenadas geográficas no formato GeoJSON Point conforme ao padrão RFC 7946. Sistema de referência: WGS84 (EPSG:4326). **OBRIGATÓRIO** - Usado pelo MongoDB para consultas geoespaciais ($near, $geoWithin). **CRÍTICO**: A ordem no array coordinates é [longitude, latitude] (X, Y) - NÃO inverter. Usado em: cálculo de distâncias, rotas ótimas, validação de zonas de serviço.","required":["type","coordinates"],"properties":{"type":{"type":"string","enum":["Point"],"description":"Tipo de geometria GeoJSON. Deve ser sempre Point para endereços. Outros tipos (LineString, Polygon) não são válidos neste contexto.","example":"Point"},"coordinates":{"type":"array","description":"Array de dois números: [longitude, latitude] em graus decimais. **ORDEM CRÍTICA**: longitude primeiro (eixo X, -180 a 180), latitude segundo (eixo Y, -90 a 90). Exemplo válido: [-3.70379, 40.416775] = 3.70° Oeste, 40.41° Norte (Madrid). **ERRO COMUM**: Inverter a ordem causa cálculos incorretos. Usado em: 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":"Identificador único e imutável do Google Place para esta localização. Usado para: geocodificação reversa, validação de alterações, obtenção de detalhes atualizados. Formato: String alfanumérica que geralmente começa com ChIJ. Persistido para evitar geocodificações repetidas (economia de custos de API).","example":"ChIJi-AoYTIoQg0RnHvWosEVABQ"},"name_address":{"type":"string","description":"Endereço completo formatado gerado pelo Google Maps (formatted_address). Inclui: rua, número, código postal, cidade, país no formato local. Usado em: exibição para usuários, exportações, documentos oficiais. Não editável manualmente - regenerado automaticamente ao atualizar coordenadas.","example":"Calle de Alcalá, 42, 28014 Madrid, España"},"isDefault":{"type":"boolean","description":"Indica se este é o endereço principal/padrão da empresa. **Restrição**: Só pode haver um endereço com isDefault=true por empresa. Ao definir isDefault=true em um endereço, o anterior com este flag é automaticamente alterado para false. Usado em: preenchimento automático de formulários, endereço padrão em novos leilões. Também armazenado em: company.address_default (referência ao _id deste endereço).","default":false,"example":true},"can_be_deleted":{"type":"boolean","description":"Flag calculado dinamicamente no momento da consulta (não armazenado no banco de dados). **false**: O endereço está referenciado em leilões ou entregas ativas (status != canceled/delivered). **true**: O endereço não tem dependências e pode ser excluído com segurança. Calculado em: controller.get() verificando a contagem de auction/delivery onde etl_address ou etd_address == this._id Previne: exclusão acidental de endereços em uso que causaria dados órfãos.","example":false},"destinations":{"type":"array","description":"Array de destinos frequentes com rotas pré-calculadas a partir deste endereço. **Otimização**: Evita recálculo de rotas repetitivas, melhora desempenho na busca de leilões. Populado em: cron noturno ou sob demanda para pares de endereços frequentes. Usado em: endpoint /company/minimal para cálculos de custo/distância sem chamar API externa. Estrutura: [{address: ObjectId, minimalRoute: {distance: Number(km), timeCost: Number(min)}}]","items":{"type":"object","properties":{"address":{"type":"string","description":"ObjectId do endereço de destino","example":"507f1f77bcf86cd799439012"},"minimalRoute":{"type":"object","properties":{"distance":{"type":"number","description":"Distância calculada em quilômetros (via API de rotas)","example":523.7},"timeCost":{"type":"number","description":"Tempo estimado de viagem em minutos (considerando velocidade média)","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":"Solicitação inválida","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":"Não Autorizado","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}},"headers":{}},"404":{"description":"Não encontrado","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}},"headers":{}}}}
>
</StatusCodes>