openapi: 3.1.0
tags:
- name: Stations
  description: Todas las operaciones relacionadas con estaciones de servicio
- name: Geolocation
  description: Operaciones basadas en ubicación geográfica
- name: Pricing
  description: Operaciones relacionadas con precios de combustible
- name: Station Details
  description: Información detallada de estaciones específicas
- name: Utilities
  description: Endpoints de utilidad general e información del sistema.
- name: Discounts
  description: Gestión de descuentos en estaciones de servicio
info:
  title: Stations
  description: 'Este API es parte de **TransCend** y corresponde al módulo de estaciones
    de servicio. Proporciona información sobre ubicaciones, precios y disponibilidad
    de combustibles en estaciones de servicio.

    Su principal misión es ayudar a los transportistas a encontrar las mejores opciones
    de repostaje en sus rutas, considerando factores como ubicación, precios y tipos
    de combustible disponibles.

    '
  version: 1.05.210753
  contact:
    email: support@cargoffer.com
  license: Private API - Access by agreement only
security:
- BearerAuth: []
- ApiKeyAuth: []
servers:
- url: https://api.pro.cargoffer.com
  description: Producción
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Token JWT obtenido del servicio IAM
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: Clave API para la autenticación del servicio
  schemas:
    Error:
      type: object
      properties:
        error:
          type: string
          description: Mensaje descriptivo del error
          example: Invalid or missing parameters
      required:
      - error
    OilStation:
      type: object
      properties:
        _id:
          type: string
          description: Identificador único de la estación
          example: 5f8d3b7b3f6b8a1b9c3b7b3f
        label:
          type: string
          description: Nombre comercial de la estación
          example: Repsol Calle Mayor
        address:
          type: string
          description: Dirección completa
          example: Calle Mayor, 123, 28013 Madrid
        city:
          type: string
          description: Ciudad donde se encuentra la estación
          example: Madrid
        province:
          type: string
          description: Provincia donde se encuentra la estación
          example: Madrid
        country:
          type: string
          description: País donde se encuentra la estación
          example: es
        brand:
          type: string
          description: Marca de la estación de servicio
          example: Repsol
        location:
          type: object
          properties:
            type:
              type: string
              enum:
              - Point
              default: Point
            coordinates:
              type: array
              items:
                type: number
                format: float
              example:
              - -3.7038
              - 40.4168
          description: Coordenadas GPS en formato GeoJSON (longitud, latitud)
        fuelTypes:
          type: array
          items:
            type: object
            properties:
              code:
                type: string
                description: Código del tipo de combustible
                enum:
                - diesel_regular
                - diesel_premium
                - gasoline_95
                - gasoline_98
                - gnc
                - gnl
                - gpl
                - hydrogen
                - bioethanol
                - biodiesel
                example: diesel_regular
              price:
                type: number
                format: float
                minimum: 0
                description: Precio por litro en euros
                example: 1.459
              updatedAt:
                type: string
                format: date-time
                description: Fecha de última actualización del precio
                example: '2025-04-29T10:30:00Z'
        distance:
          type: number
          format: float
          description: Distancia desde el punto de referencia en metros
          example: 1250.5
    Discount:
      type: object
      properties:
        id_discount:
          type: string
          description: Identificador único del descuento
          example: '123456789'
        station:
          type: string
          description: Identificador de la estación asociada al descuento
          example: 5f8d3b7b3f6b8a1b9c3b7b3f
        type:
          type: string
          description: Tipo de descuento
          example: percentage
        percentValue:
          type: number
          format: float
          minimum: 0
          maximum: 100
          description: Valor del descuento en porcentaje
          example: 10.0
        centsValue:
          type: number
          format: float
          minimum: 0
          description: Valor del descuento en céntimos
          example: 0.15
        isActive:
          type: boolean
          description: Indica si el descuento está activo
          example: true
        selected:
          type: boolean
          description: Indica si el descuento está seleccionado
          example: false
        userId:
          type: string
          description: Identificador del usuario propietario del descuento
          example: user123
        createdAt:
          type: string
          format: date-time
          description: Fecha de creación del descuento
          example: '2025-04-29T10:30:00Z'
        updatedAt:
          type: string
          format: date-time
          description: Fecha de última actualización del descuento
          example: '2025-04-29T10:30:00Z'
      required:
      - id_discount
      - station
      - type
    DiscountResponse:
      type: object
      properties:
        success:
          type: boolean
          description: Indica si la operación fue exitosa
          example: true
        data:
          oneOf:
          - $ref: '#/components/schemas/Discount'
          - type: array
            items:
              $ref: '#/components/schemas/Discount'
        message:
          type: string
          description: Mensaje adicional de la operación
          example: Discount created successfully
        pagination:
          type: object
          properties:
            page:
              type: number
              description: Página actual
              example: 1
            pages:
              type: number
              description: Total de páginas
              example: 5
            total:
              type: number
              description: Total de documentos
              example: 50
            limit:
              type: number
              description: Límite por página
              example: 10
    SyncDiscountRequest:
      type: object
      required:
      - discounts
      - userId
      properties:
        discounts:
          type: array
          description: Array de descuentos a sincronizar
          items:
            type: object
            properties:
              id:
                type: string
                description: Identificador del descuento
                example: '123456789'
              station:
                type: string
                description: Identificador de la estación
                example: 5f8d3b7b3f6b8a1b9c3b7b3f
              type:
                type: string
                description: Tipo de descuento
                example: percentage
              percentValue:
                type: number
                format: float
                minimum: 0
                maximum: 100
                description: Valor del descuento en porcentaje
                example: 10.0
              centsValue:
                type: number
                format: float
                minimum: 0
                description: Valor del descuento en céntimos
                example: 0.15
              isActive:
                type: boolean
                description: Indica si el descuento está activo
                example: true
              selected:
                type: boolean
                description: Indica si el descuento está seleccionado
                example: false
        userId:
          type: string
          description: Identificador del usuario
          example: user123
  parameters:
    Latitude:
      name: lat
      in: query
      description: 'Latitud en grados decimales (estándar WGS84). Valores positivos
        son norte del ecuador, negativos son sur. Precisión mínima recomendada: 6
        decimales.'
      required: true
      schema:
        type: number
        format: float
        minimum: -90
        maximum: 90
        default: 40.4168
        example: 40.4168
    Longitude:
      name: lng
      in: query
      description: 'Longitud en grados decimales (estándar WGS84). Valores positivos
        son este de Greenwich, negativos son oeste. Precisión mínima recomendada:
        6 decimales.'
      required: true
      schema:
        type: number
        format: float
        minimum: -180
        maximum: 180
        default: -3.7038
        example: -3.7038
    Radius:
      name: radius
      in: query
      description: Radio de búsqueda en metros. Valor entre 1000 (1km) y 150000 (150km).
        Por defecto 25000 (25km).
      required: false
      schema:
        type: integer
        minimum: 1000
        maximum: 150000
        default: 25000
        example: 25000
    FuelType:
      name: fuel_type
      in: query
      description: 'Tipo de combustible a consultar. Puede ser un solo tipo o una
        lista separada por comas. Valores posibles según país: - diesel_regular: Gasóleo
        estándar - diesel_premium: Gasóleo premium - gasoline_95: Gasolina 95 octanos
        - gasoline_98: Gasolina 98 octanos - gnc: Gas Natural Comprimido - gnl: Gas
        Natural Licuado - gpl: Gas Licuado del Petróleo - hydrogen: Hidrógeno - bioethanol:
        Bioetanol - biodiesel: Biodiésel'
      required: false
      schema:
        oneOf:
        - type: string
          default: diesel_regular
          example: diesel_regular
          enum:
          - diesel_regular
          - diesel_premium
          - gasoline_95
          - gasoline_98
          - gnc
          - gnl
          - gpl
          - hydrogen
          - bioethanol
          - biodiesel
        - type: array
          items:
            type: string
            enum:
            - diesel_regular
            - diesel_premium
            - gasoline_95
            - gasoline_98
            - gnc
            - gnl
            - gpl
            - hydrogen
            - bioethanol
            - biodiesel
          example:
          - diesel_regular
          - gasoline_95
    Language:
      name: lang
      in: query
      description: Idioma para las respuestas. Código ISO 639-1 (2 letras). Por defecto
        "es".
      required: false
      schema:
        type: string
        minLength: 2
        maxLength: 2
        default: es
        example: es
        enum:
        - es
        - en
        - fr
        - it
        - de
        - pt
    StationId:
      name: id
      in: query
      description: Identificador único de la estación de servicio (MongoDB ObjectId)
      required: false
      schema:
        type: string
        pattern: ^[0-9a-fA-F]{24}$
        example: 5f8d3b7b3f6b8a1b9c3b7b3f
    SearchQuery:
      name: search
      in: query
      description: Texto para búsqueda por dirección, ciudad, provincia o nombre de
        estación. Búsqueda case-insensitive.
      required: false
      schema:
        type: string
        minLength: 3
        example: Repsol Madrid
    RoutePoints:
      name: points
      in: query
      description: Array de puntos GPS en formato [[lng,lat],...] para buscar estaciones
        a lo largo de una ruta. Máximo 100 puntos.
      required: false
      schema:
        type: array
        items:
          type: array
          items:
            type: number
            format: float
          minItems: 2
          maxItems: 2
        example:
        - - -3.7038
          - 40.4168
        - - -3.71
          - 40.42
        maxItems: 100
    Country:
      name: country
      in: query
      required: false
      schema:
        type: string
        default: es
        enum:
        - es
        - fr
        - de
        - pt
        example: es
      description: País en el que hacer la búsqueda
paths:
  /stations/nearby:
    get:
      tags:
      - Geolocation
      summary: Obtener estaciones cercanas por ubicación
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      description: 'Busca estaciones de servicio dentro de un radio especificado alrededor
        de unas coordenadas GPS. Ideal para encontrar opciones de repostaje inmediatas.

        **Ejemplo de uso:** - Planificación de rutas de transporte - Localizar opciones
        de repostaje cercanas - Integración con sistemas de navegación

        '
      operationId: getNearbyStations
      parameters:
      - $ref: '#/components/parameters/Latitude'
      - $ref: '#/components/parameters/Longitude'
      - $ref: '#/components/parameters/Radius'
      - $ref: '#/components/parameters/Language'
      responses:
        '200':
          description: Lista de estaciones encontradas ordenadas por distancia
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/OilStation'
              example:
              - _id: 5f8d3b7b3f6b8a1b9c3b7b3f
                label: Repsol Calle Mayor
                address: Calle Mayor, 123, 28013 Madrid
                location:
                  type: Point
                  coordinates:
                  - -3.7038
                  - 40.4168
                fuelTypes:
                - code: diesel_regular
                  price: 1.459
                  updatedAt: '2025-04-29T10:30:00Z'
        '400':
          description: 'Error en los parámetros de entrada. Posibles causas:

            - Coordenadas inválidas o fuera de rango

            - Radio de búsqueda fuera de límites

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                INVALID_COORDINATES:
                  summary: Coordenadas Inválidas
                  value:
                    error: Invalid coordinates
                RADIUS_OUT_OF_BOUNDS:
                  summary: Radio Fuera de Límites
                  value:
                    error: Radius must be between 1000 and 150000 meters.
        '503':
          description: Error temporal del servidor. Intente nuevamente más tarde.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Error fetching nearby stations
  /stations/search:
    get:
      tags:
      - Geolocation
      summary: Buscar estaciones por filtros
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      description: 'Permite una búsqueda avanzada de estaciones de servicio aplicando
        múltiples criterios como tipo de combustible, ubicación geográfica (latitud,
        longitud, radio) y un término de búsqueda libre que puede coincidir con el
        nombre de la estación, dirección, ciudad o provincia. Los resultados se ordenan
        por distancia a las coordenadas proporcionadas.

        **Características especiales:** - Búsqueda por texto en dirección, ciudad,
        provincia o nombre - Filtrado por tipo de combustible disponible - Ordenación
        por distancia a las coordenadas proporcionadas

        '
      operationId: searchStations
      parameters:
      - $ref: '#/components/parameters/Latitude'
      - $ref: '#/components/parameters/Longitude'
      - $ref: '#/components/parameters/Radius'
      - $ref: '#/components/parameters/FuelType'
      - $ref: '#/components/parameters/Language'
      - $ref: '#/components/parameters/SearchQuery'
      responses:
        '200':
          description: Lista de estaciones que coinciden con los criterios de búsqueda
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/OilStation'
              example:
              - _id: 5f8d3b7b3f6b8a1b9c3b7b3f
                label: Repsol Calle Mayor
                address: Calle Mayor, 123, 28013 Madrid
                location:
                  type: Point
                  coordinates:
                  - -3.7038
                  - 40.4168
                fuelTypes:
                - code: diesel_regular
                  price: 1.459
                  updatedAt: '2025-04-29T10:30:00Z'
              - _id: 60a2c1b2d3e4f5a6b7c8d9e0
                label: Cepsa Av. de America
                address: Av. de América, 10, 28028 Madrid
                location:
                  type: Point
                  coordinates:
                  - -3.6738
                  - 40.4312
                fuelTypes:
                - code: gasoline_95
                  price: 1.52
                  updatedAt: '2025-04-29T11:00:00Z'
                - code: diesel_premium
                  price: 1.55
                  updatedAt: '2025-04-29T11:05:00Z'
        '400':
          description: Parámetros de búsqueda inválidos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                INVALID_FUEL_TYPE:
                  summary: Tipo de Combustible Inválido
                  value:
                    error: Invalid fuel type
                INVALID_COORDINATES:
                  summary: Coordenadas Inválidas
                  value:
                    error: Invalid coordinates
        '404':
          description: No se encontraron estaciones que coincidan
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: No nearby stations found
        '503':
          description: Error al procesar la búsqueda
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Error searching for stations
  /stations/{id}:
    get:
      tags:
      - Station Details
      summary: Obtener detalles de una estación específica
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      description: 'Recupera información detallada y actualizada de una estación de
        servicio específica, identificada por su ID único (MongoDB ObjectId). Esto
        incluye su ubicación precisa, la lista completa de combustibles que ofrece
        con sus precios actuales, y potencialmente horarios de apertura si están disponibles.

        **Incluye:** - Información de ubicación exacta - Lista completa de combustibles
        disponibles - Precios actualizados - Horarios de apertura (si disponibles)

        '
      operationId: getStationDetails
      parameters:
      - name: id
        in: path
        description: ID único de la estación (MongoDB ObjectId)
        required: true
        schema:
          type: string
          pattern: ^[0-9a-fA-F]{24}$
          example: 5f8d3b7b3f6b8a1b9c3b7b3f
      - $ref: '#/components/parameters/Language'
      responses:
        '200':
          description: Detalles completos de la estación solicitada
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OilStation'
              example:
                _id: 5f8d3b7b3f6b8a1b9c3b7b3f
                label: Repsol Calle Mayor
                address: Calle Mayor, 123, 28013 Madrid
                location:
                  type: Point
                  coordinates:
                  - -3.7038
                  - 40.4168
                fuelTypes:
                - code: diesel_regular
                  price: 1.459
                  updatedAt: '2025-04-29T10:30:00Z'
                - code: gasoline_95
                  price: 1.589
                  updatedAt: '2025-04-29T10:32:00Z'
        '400':
          description: ID de estación inválido o mal formado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Station ID required
        '404':
          description: Estación no encontrada
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Station not found
        '503':
          description: Error al recuperar los detalles
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Error fetching station details
  /stations/best-prices:
    get:
      tags:
      - Pricing
      summary: Obtener estaciones con mejores precios en un área
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      description: 'Identifica y devuelve un listado de hasta 3 estaciones de servicio
        que ofrecen los precios más competitivos para un tipo de combustible específico
        dentro de un área geográfica determinada por latitud, longitud y radio. Es
        útil para optimizar costes de repostaje.

        **Limitaciones:** - Radio mínimo: 15km - Radio máximo: 150km - Máximo 3 resultados
        por petición

        '
      operationId: getBestPrices
      parameters:
      - $ref: '#/components/parameters/Latitude'
      - $ref: '#/components/parameters/Longitude'
      - $ref: '#/components/parameters/Radius'
      - $ref: '#/components/parameters/FuelType'
      - $ref: '#/components/parameters/Language'
      responses:
        '200':
          description: Lista de hasta 3 estaciones con los mejores precios
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/OilStation'
              example:
              - _id: 5f8d3b7b3f6b8a1b9c3b7b3f
                label: Repsol Economica
                address: Poligono Industrial Sur, 1, 28906 Getafe
                location:
                  type: Point
                  coordinates:
                  - -3.732
                  - 40.3
                fuelTypes:
                - code: diesel_regular
                  price: 1.42
                  updatedAt: '2025-04-29T09:00:00Z'
              - _id: 60a2c1b2d3e4f5a6b7c8d9e1
                label: Galp Ahorro
                address: Carretera de Toledo, km 15, 28905 Getafe
                location:
                  type: Point
                  coordinates:
                  - -3.74
                  - 40.295
                fuelTypes:
                - code: diesel_regular
                  price: 1.425
                  updatedAt: '2025-04-29T09:15:00Z'
        '400':
          description: Radio fuera de límites o parámetros inválidos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                INVALID_RADIUS:
                  summary: Radio Inválido
                  value:
                    error: Radius must be between 15000 and 150000 meters.
                INVALID_COORDINATES:
                  summary: Coordenadas Inválidas
                  value:
                    error: Invalid coordinates
        '503':
          description: Error al calcular los mejores precios
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Error fetching best prices
  /stations/province:
    get:
      tags:
      - Pricing
      summary: Obtener precios más bajos por provincia
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      description: 'Analiza y devuelve los precios más bajos encontrados para un tipo
        de combustible específico en cada provincia del país seleccionado. Los resultados
        se presentan ordenados de menor a mayor precio, incluyendo el identificador
        de la provincia para facilitar su uso en integraciones.

        **Notas:** - Los resultados están ordenados de menor a mayor precio - Incluye
        identificador de provincia para facilitar integraciones

        '
      operationId: getCheapestProvince
      parameters:
      - $ref: '#/components/parameters/FuelType'
      - $ref: '#/components/parameters/Language'
      - $ref: '#/components/parameters/Country'
      responses:
        '200':
          description: Lista de provincias con sus precios mínimos
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    province:
                      type: string
                      description: Nombre de la provincia
                      example: Madrid
                    provinceId:
                      type: string
                      description: Identificador único de la provincia
                      example: '28'
                    price:
                      type: number
                      format: float
                      description: Precio mínimo encontrado en la provincia
                      example: 1.429
        '503':
          description: Error al calcular los precios por provincia
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Error fetching prices by province
  /stations/getAlongPath:
    post:
      tags:
      - Geolocation
      summary: Obtener estaciones a lo largo de una ruta
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      description: 'Busca y devuelve una lista de estaciones de servicio que se encuentran
        cercanas a una secuencia de puntos GPS que definen una ruta. El sistema optimiza
        la búsqueda filtrando puntos redundantes (aquellos que están a menos de 25km
        entre sí) y es especialmente útil para la planificación de repostajes en rutas
        largas de transporte.

        **Casos de uso:** - Planificación de rutas para transportistas - Optimización
        de paradas para repostaje - Integración con sistemas de navegación

        **Características:** - Filtra puntos redundantes (más cercanos de 25km) -
        Devuelve estaciones cercanas a cada punto de la ruta - Optimizado para rutas
        largas de transporte - Opción de optimizar paradas (solo estaciones con mejores
        precios)

        '
      operationId: getAlongPath
      parameters:
      - $ref: '#/components/parameters/Language'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - points
              - fuel_type
              properties:
                points:
                  type: array
                  description: Array de puntos GPS en formato `[[lng,lat],...]` que
                    definen la ruta. Máximo 100 puntos.
                  items:
                    type: array
                    items:
                      type: number
                      format: float
                    minItems: 2
                    maxItems: 2
                  maxItems: 100
                fuel_type:
                  type: string
                  description: Tipo de combustible a buscar. Requerido para filtrar
                    las estaciones a lo largo de la ruta.
                  default: diesel_regular
                  example: diesel_regular
                  enum:
                  - diesel_regular
                  - diesel_premium
                  - gasoline_95
                  - gasoline_98
                optimizedStops:
                  type: boolean
                  description: Si es `true`, solo devuelve las estaciones con los
                    precios más competitivos (en el 30% más bajo del rango encontrado).
                    Ideal para optimizar costes.
                  default: false
                  example: true
            example:
              points:
              - - -3.7038
                - 40.4168
              - - -0.1278
                - 51.5074
              fuel_type: diesel_regular
              optimizedStops: true
      responses:
        '200':
          description: Lista de estaciones encontradas a lo largo de la ruta
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/OilStation'
              example:
              - _id: 5f8d3b7b3f6b8a1b9c3b7b3f
                label: Repsol Ruta Norte
                address: Autovia A1, Km 100, 09001 Burgos
                location:
                  type: Point
                  coordinates:
                  - -3.688
                  - 42.343
                fuelTypes:
                - code: diesel_regular
                  price: 1.47
                  updatedAt: '2025-04-29T12:00:00Z'
              - _id: 60a2c1b2d3e4f5a6b7c8d9e2
                label: Cepsa Parada Viajero
                address: N-620, Km 50, 34001 Palencia
                location:
                  type: Point
                  coordinates:
                  - -4.526
                  - 42.01
                fuelTypes:
                - code: gasoline_98
                  price: 1.65
                  updatedAt: '2025-04-29T12:30:00Z'
        '400':
          description: 'Error en los parámetros. Posibles causas:

            - Formato incorrecto de puntos GPS

            - Número de puntos excede el límite

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: GPS points array is required
        '500':
          description: Error al procesar la ruta
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Unknown error
  /stations/fuel-types:
    get:
      summary: Obtener lista de tipos de combustible
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      description: 'Devuelve una lista de todos los tipos de combustible válidos y
        actualmente gestionados por el sistema. Esta lista puede ser utilizada para
        filtrar búsquedas o presentar opciones al usuario.

        '
      operationId: getFuelTypes
      tags:
      - Utilities
      parameters:
      - $ref: '#/components/parameters/Language'
      responses:
        '200':
          description: Lista de tipos de combustible disponibles
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
              example:
              - gnc
              - gnl
              - gpl
              - hydrogen
              - bioethanol
              - biodiesel
              - diesel_regular
              - diesel_premium
              - gasoline_95
              - gasoline_98
        '503':
          description: Error del servidor al obtener los tipos de combustible.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Server error fetching fuel types.
  /stations/brands:
    get:
      tags:
      - Utilities
      summary: Obtener listado de marcas de estaciones de servicio
      description: 'Devuelve una lista de todas las marcas de estaciones de servicio
        disponibles en el sistema, incluyendo sus nombres e iconos asociados.

        '
      operationId: getStationBrands
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Lista de marcas de estaciones de servicio
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    label:
                      type: string
                      description: Nombre de la marca
                      example: Repsol
                    icon:
                      type: string
                      description: Identificador del icono de la marca
                      example: iconorepsol
              example:
              - label: Repsol
                icon: iconorepsol
              - label: Cepsa
                icon: iconocepsa
        '503':
          description: Error al obtener las marcas de estaciones
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Error fetching station brands
  /stations/brand/{icon}:
    get:
      tags:
      - Utilities
      summary: Obtener icono de marca de estación de servicio
      description: 'Devuelve el archivo de icono PNG asociado a una marca específica
        de estación de servicio. Los iconos están disponibles en formato PNG.

        '
      operationId: getStationBrandIcon
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      parameters:
      - name: icon
        in: path
        description: Identificador del icono de la marca
        required: true
        schema:
          type: string
          example: iconorepsol
      responses:
        '200':
          description: Archivo PNG del icono de la marca
          content:
            image/png:
              schema:
                type: string
                format: binary
        '404':
          description: Icono no encontrado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Icon not found
        '503':
          description: Error al obtener el icono
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Internal server error
  /discounts:
    post:
      tags:
      - Discounts
      summary: Crear un nuevo descuento
      description: 'Crea un nuevo descuento asociado a una estación de servicio. Los
        descuentos pueden ser de tipo porcentaje o céntimos y pueden estar activos
        o inactivos.

        '
      operationId: createDiscount
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - station
              - type
              properties:
                id:
                  type: string
                  description: Identificador único del descuento (opcional, se genera
                    automáticamente)
                  example: '123456789'
                station:
                  type: string
                  description: Identificador de la estación asociada al descuento
                  example: 5f8d3b7b3f6b8a1b9c3b7b3f
                type:
                  type: string
                  description: Tipo de descuento
                  example: percentage
                percentValue:
                  type: number
                  format: float
                  minimum: 0
                  maximum: 100
                  description: Valor del descuento en porcentaje
                  example: 10.0
                centsValue:
                  type: number
                  format: float
                  minimum: 0
                  description: Valor del descuento en céntimos
                  example: 0.15
                isActive:
                  type: boolean
                  description: Indica si el descuento está activo
                  example: true
                selected:
                  type: boolean
                  description: Indica si el descuento está seleccionado
                  example: false
                userId:
                  type: string
                  description: Identificador del usuario propietario del descuento
                  example: user123
      responses:
        '200':
          description: Descuento creado exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DiscountResponse'
              example:
                success: true
                data:
                  id_discount: '123456789'
                  station: 5f8d3b7b3f6b8a1b9c3b7b3f
                  type: percentage
                  percentValue: 10.0
                  centsValue: 0
                  isActive: true
                  selected: false
                  userId: user123
                  createdAt: '2025-04-29T10:30:00Z'
                  updatedAt: '2025-04-29T10:30:00Z'
                message: Discount created successfully
        '400':
          description: Datos de descuento inválidos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Invalid discount data
        '500':
          description: Error al crear el descuento
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Error creating discount
    get:
      tags:
      - Discounts
      summary: Obtener todos los descuentos
      description: 'Recupera una lista paginada de descuentos con opciones de filtrado
        por estado, estación o usuario.

        '
      operationId: getAllDiscounts
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      parameters:
      - name: page
        in: query
        description: Número de página para paginación
        required: false
        schema:
          type: integer
          minimum: 1
          default: 1
          example: 1
      - name: limit
        in: query
        description: Límite de resultados por página
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 10
          example: 10
      - name: isActive
        in: query
        description: Filtrar por estado activo/inactivo
        required: false
        schema:
          type: boolean
          example: true
      - name: station
        in: query
        description: Filtrar por identificador de estación
        required: false
        schema:
          type: string
          example: 5f8d3b7b3f6b8a1b9c3b7b3f
      - name: userId
        in: query
        description: Filtrar por identificador de usuario
        required: false
        schema:
          type: string
          example: user123
      responses:
        '200':
          description: Lista de descuentos recuperada exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DiscountResponse'
              example:
                success: true
                data:
                - id_discount: '123456789'
                  station: 5f8d3b7b3f6b8a1b9c3b7b3f
                  type: percentage
                  percentValue: 10.0
                  centsValue: 0
                  isActive: true
                  selected: false
                  userId: user123
                  createdAt: '2025-04-29T10:30:00Z'
                  updatedAt: '2025-04-29T10:30:00Z'
                pagination:
                  page: 1
                  pages: 5
                  total: 50
                  limit: 10
        '500':
          description: Error al obtener los descuentos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Error fetching discounts
  /discounts/{id}:
    get:
      tags:
      - Discounts
      summary: Obtener descuento por ID
      description: 'Recupera un descuento específico por su identificador único.

        '
      operationId: getDiscountById
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      parameters:
      - name: id
        in: path
        description: Identificador único del descuento
        required: true
        schema:
          type: string
          example: '123456789'
      responses:
        '200':
          description: Descuento encontrado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DiscountResponse'
              example:
                success: true
                data:
                  id_discount: '123456789'
                  station: 5f8d3b7b3f6b8a1b9c3b7b3f
                  type: percentage
                  percentValue: 10.0
                  centsValue: 0
                  isActive: true
                  selected: false
                  userId: user123
                  createdAt: '2025-04-29T10:30:00Z'
                  updatedAt: '2025-04-29T10:30:00Z'
        '404':
          description: Descuento no encontrado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Discount not found
        '500':
          description: Error al obtener el descuento
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Error fetching discount
    put:
      tags:
      - Discounts
      summary: Actualizar descuento existente
      description: 'Actualiza un descuento existente identificado por su ID.

        '
      operationId: updateDiscount
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      parameters:
      - name: id
        in: path
        description: Identificador único del descuento
        required: true
        schema:
          type: string
          example: '123456789'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                station:
                  type: string
                  description: Identificador de la estación asociada al descuento
                  example: 5f8d3b7b3f6b8a1b9c3b7b3f
                type:
                  type: string
                  description: Tipo de descuento
                  example: percentage
                percentValue:
                  type: number
                  format: float
                  minimum: 0
                  maximum: 100
                  description: Valor del descuento en porcentaje
                  example: 10.0
                centsValue:
                  type: number
                  format: float
                  minimum: 0
                  description: Valor del descuento en céntimos
                  example: 0.15
                isActive:
                  type: boolean
                  description: Indica si el descuento está activo
                  example: true
                selected:
                  type: boolean
                  description: Indica si el descuento está seleccionado
                  example: false
                userId:
                  type: string
                  description: Identificador del usuario propietario del descuento
                  example: user123
      responses:
        '200':
          description: Descuento actualizado exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DiscountResponse'
              example:
                success: true
                data:
                  id_discount: '123456789'
                  station: 5f8d3b7b3f6b8a1b9c3b7b3f
                  type: percentage
                  percentValue: 10.0
                  centsValue: 0
                  isActive: true
                  selected: false
                  userId: user123
                  createdAt: '2025-04-29T10:30:00Z'
                  updatedAt: '2025-04-29T10:30:00Z'
                message: Discount updated successfully
        '404':
          description: Descuento no encontrado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Discount not found
        '500':
          description: Error al actualizar el descuento
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Error updating discount
    delete:
      tags:
      - Discounts
      summary: Eliminar descuento
      description: 'Elimina permanentemente un descuento identificado por su ID.

        '
      operationId: deleteDiscount
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      parameters:
      - name: id
        in: path
        description: Identificador único del descuento
        required: true
        schema:
          type: string
          example: '123456789'
      responses:
        '200':
          description: Descuento eliminado exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DiscountResponse'
              example:
                success: true
                message: Discount deleted successfully
                data:
                  id_discount: '123456789'
                  station: 5f8d3b7b3f6b8a1b9c3b7b3f
                  type: percentage
                  percentValue: 10.0
                  centsValue: 0
                  isActive: true
                  selected: false
                  userId: user123
                  createdAt: '2025-04-29T10:30:00Z'
                  updatedAt: '2025-04-29T10:30:00Z'
        '404':
          description: Descuento no encontrado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Discount not found
        '500':
          description: Error al eliminar el descuento
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Error deleting discount
  /discounts/sync:
    post:
      tags:
      - Discounts
      summary: Sincronizar descuentos desde almacenamiento local
      description: 'Sincroniza múltiples descuentos desde el almacenamiento local
        del cliente al servidor. Útil para mantener la consistencia entre dispositivos.

        '
      operationId: syncDiscountsFromLocalStorage
      security:
      - BearerAuth: []
      - ApiKeyAuth: []
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SyncDiscountRequest'
            example:
              discounts:
              - id: '123456789'
                station: 5f8d3b7b3f6b8a1b9c3b7b3f
                type: percentage
                percentValue: 10.0
                centsValue: 0
                isActive: true
                selected: false
              userId: user123
      responses:
        '200':
          description: Descuentos sincronizados exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DiscountResponse'
              example:
                success: true
                data:
                - id_discount: '123456789'
                  station: 5f8d3b7b3f6b8a1b9c3b7b3f
                  type: percentage
                  percentValue: 10.0
                  centsValue: 0
                  isActive: true
                  selected: false
                  userId: user123
                  createdAt: '2025-04-29T10:30:00Z'
                  updatedAt: '2025-04-29T10:30:00Z'
                synced: 1
                message: Discounts synced successfully
        '400':
          description: Datos de sincronización inválidos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Discounts must be an array
        '500':
          description: Error al sincronizar descuentos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Error syncing discounts
