Carrusel de Ofertas - bootcamp-uchile-2026/grupo-2-backend GitHub Wiki

Carrusel de Ofertas

La funcionalidad Carrusel de Ofertas permite que la página de inicio de BuenOrigen presente productos que actualmente poseen un precio de oferta.

Desde la perspectiva Backend, esta funcionalidad consiste en identificar los productos que poseen un precioOferta, calcular la información relacionada con el descuento y devolver los datos necesarios para que Frontend y Mobile puedan representarlos.

La construcción visual del carrusel, su navegación, animaciones y comportamiento corresponden a Frontend y Mobile.


Objetivo

Proporcionar a Frontend y Mobile la información necesaria para mostrar productos en oferta en la página de inicio de BuenOrigen.


Estado

Implementado

La funcionalidad se encuentra implementada actualmente mediante:

ProductosModule
      |
      v
ProductosController
      |
      v
ProductosService
      |
      v
ProductoOfertaDto[]

Responsabilidad Backend

Actualmente el Backend debe:

  • Consultar los productos disponibles en el catálogo.
  • Identificar los productos que poseen un precioOferta.
  • Obtener el precio original del producto.
  • Obtener el precio con descuento.
  • Calcular el porcentaje de descuento.
  • Transformar cada producto al contrato ProductoOfertaDto.
  • Retornar una lista con los productos en oferta.
  • Retornar una lista vacía si no existen productos en oferta.

Contrato de API

Endpoint

GET /productos/ofertas

Página relacionada:

Carrusel de Ofertas

Datos de entrada

La operación no requiere:

Body
Parámetros de ruta
Query Parameters

DTO de salida

ProductoOfertaDto[]

La definición general del endpoint se encuentra centralizada en:

Endpoints

La estructura completa del DTO se encuentra en:

DTOs


Criterio Actual para Determinar una Oferta

Actualmente un producto es considerado en oferta cuando:

producto.precioOferta !== null

Conceptualmente:

Producto
   |
   v
¿precioOferta !== null?
   |
 +---+---+
 |       |
Sí       No
 |       |
 v       v
Oferta   No se incluye

Por ejemplo:

{
  precio: 12990,
  precioOferta: 9990
}

corresponde a un producto en oferta.

Mientras que:

{
  precio: 12990,
  precioOferta: null
}

no será incluido en la respuesta del endpoint.


Flujo de la Operación

Conceptualmente:

GET /productos/ofertas
          |
          v
 ProductosController
          |
          v
  ProductosService
          |
          | filter()
          v
precioOferta !== null
          |
          | map()
          v
Calcular información
    de descuento
          |
          v
ProductoOfertaDto[]
          |
          v
       200 OK

Procesamiento en ProductosService

La operación principal corresponde a:

obtenerProductosEnOferta(): ProductoOfertaDto[]

Primero se seleccionan los productos cuyo precioOferta no sea null.

Conceptualmente:

const productosEnOferta = this.productos.filter(
  (producto) => producto.precioOferta !== null,
);

Posteriormente, cada producto se transforma a:

ProductoOfertaDto

Cálculo del Porcentaje de Descuento

El porcentaje de descuento se calcula utilizando:

precioOriginal
precioDescuento

Conceptualmente:

(precioOriginal - precioDescuento)
---------------------------------- × 100
          precioOriginal

El resultado se redondea al número entero más cercano.

En la implementación se utiliza:

Math.round(
  ((producto.precio - precioOferta) / producto.precio) * 100,
)

Ejemplo

Si un producto posee:

Precio original:    $12.990
Precio de oferta:    $9.990

la diferencia corresponde a:

12.990 - 9.990 = 3.000

Luego:

3.000
------ × 100 ≈ 23,09 %
12.990

Al aplicar:

Math.round()

el resultado será:

23 %

Por lo tanto, el DTO devolverá:

{
  "precioOriginal": 12990,
  "precioDescuento": 9990,
  "descuentoPorcentaje": 23
}

DTO de Salida

La operación utiliza:

ProductoOfertaDto

con la siguiente estructura:

export class ProductoOfertaDto {
  id: number;
  marca: string;
  nombre: string;
  precioOriginal: number;
  precioDescuento: number;
  descuentoPorcentaje: number;
  imagenUrl: string;
}

El endpoint no devuelve directamente el modelo completo Producto.

Conceptualmente:

Producto
   |
   | seleccionar y transformar datos
   v
ProductoOfertaDto
   |
   v
Frontend / Mobile

Ejemplo de Solicitud

GET /productos/ofertas

Ejemplo de Respuesta

[
  {
    "id": 1,
    "marca": "EcoWear",
    "nombre": "Polera de algodón",
    "precioOriginal": 12990,
    "precioDescuento": 9990,
    "descuentoPorcentaje": 23,
    "imagenUrl": "https://ejemplo.cl/imagenes/productos/polera.jpg"
  }
]

Respuesta HTTP:

200 OK

Resultado sin Productos en Oferta

Si ningún producto posee:

precioOferta !== null

el Backend devuelve:

[]

Esto corresponde a una respuesta válida y no a un error.

La respuesta HTTP continúa siendo:

200 OK

Conceptualmente:

Productos
    |
    v
¿Existen productos con precioOferta?
    |
 +--+--+
 |     |
Sí     No
 |     |
 v     v
DTO[]  []
  \     /
   \   /
    v v
  200 OK

Reglas de Negocio Actuales

Actualmente las reglas implementadas son:

  1. El producto debe poseer un precioOferta distinto de null.
  2. precio corresponde al precio original.
  3. precioOferta corresponde al precio con descuento.
  4. El porcentaje de descuento es calculado por el Backend.
  5. El porcentaje se redondea al entero más cercano.

Vigencia de las Ofertas

Actualmente el modelo y la lógica implementada no utilizan fechas de inicio o término de una oferta.

Por lo tanto, en la implementación actual:

precioOferta !== null
        |
        v
Producto en oferta

No se comprueba todavía:

fechaInicioOferta
fechaTerminoOferta
estadoOferta

Por esta razón, el concepto de "oferta vigente" corresponde actualmente a la existencia de un precioOferta.


Posibles Mejoras Futuras

Si posteriormente las reglas de negocio necesitan controlar temporalmente las ofertas, podrán incorporarse propiedades como:

fechaInicioOferta: Date;
fechaTerminoOferta: Date;

Entonces la lógica podría evolucionar conceptualmente hacia:

precioOferta existe
        +
fecha actual >= fechaInicioOferta
        +
fecha actual <= fechaTerminoOferta
        |
        v
 Oferta vigente

También podrán evaluarse reglas adicionales como:

  • Estado de publicación del producto.
  • Stock disponible.
  • Estado activo de la oferta.
  • Cantidad máxima de productos del carrusel.
  • Priorización de determinadas ofertas.

Estas reglas deberán incorporarse únicamente cuando sean requeridas por BuenOrigen.


Documentación Swagger

El endpoint se encuentra documentado en Swagger mediante:

@ApiOperation()
@ApiOkResponse()

La respuesta exitosa se encuentra documentada como:

ProductoOfertaDto[]

Conceptualmente:

@ApiOperation()
      |
      v
Describe la operación


@ApiOkResponse()
      |
      v
Documenta 200 OK
      |
      v
ProductoOfertaDto[]

Para mayor información consultar:

OpenAPI y Swagger


Relación con la Página de Inicio

La funcionalidad puede representarse de la siguiente forma:

Página de Inicio
      |
      v
Carrusel de Ofertas
      |
      v
GET /productos/ofertas
      |
      v
ProductosController
      |
      v
ProductosService
      |
      v
ProductoOfertaDto[]
      |
      v
Frontend / Mobile

Relación con la Arquitectura

La funcionalidad pertenece al dominio:

Productos

y utiliza:

ProductosModule
      |
      v
ProductosController
      |
      v
ProductosService
      |
      v
ProductoOfertaDto[]

Páginas relacionadas: