Skip to content

Costos de inventario - lote a descontar en preparación de quimicos

Documentación costos inventario

Implementación de Costos de Inventario y Previsualización de Lotes

1. Crear Producto Químico - Gestión de Costos por Lote

Descripción

Se implementó la funcionalidad para registrar el precio por unidad (unitPrice) al crear un producto químico. Este precio se almacena en cada registro de inventario dentro del array inventoryRecords, permitiendo llevar un control de costos por lote.

Cambios Técnicos

Modelo de Datos:

  • Se agregó el campo unitPrice al esquema de inventoryRecords en el modelo ChemicalProduct
  • Se implementó un virtual settUnitPrice que permite establecer el precio temporalmente durante el ciclo de vida del documento
  • Se agregó un hook post('save') que automáticamente agrega el registro de inventario con el precio al array inventoryRecords

Interfaz:

  • Se agregó settUnitPrice?: number a la interfaz IChemicalProduct (propiedad virtual, no persistente)
  • Se agregó _tempUnitPrice?: number para almacenar temporalmente el precio
  • El campo unitPrice se agregó a la interfaz IInventoryRecords

Uso para Frontend

Endpoint: POST /chemical-product

Body de la petición:

json
{
  "name": "HPS15%",
  "chemicalFunction": "Desinfectante",
  "availableQuantity": 100,
  "units": "litros",
  "lot": "LOTE-001",
  "expirationDate": "2025-12-31",
  "settUnitPrice": 25.50,
  // ... otros campos del producto
}

Campo importante:

  • settUnitPrice: Precio por unidad del inventario inicial. Este valor se guardará en el primer registro de inventoryRecords cuando se cree el producto.

Respuesta: El producto se crea normalmente y el hook post-save automáticamente agrega un registro en inventoryRecords con:

  • quantity: La cantidad disponible inicial
  • unitPrice: El precio establecido en settUnitPrice
  • lot: El lote del producto
  • expirationDate: La fecha de expiración
  • createdAt: Fecha de creación

Nota: El campo settUnitPrice es opcional. Si no se envía, el unitPrice en inventoryRecords será undefined.


2. Agregar Inventario - Registro de Costos por Lote

Descripción

Al agregar inventario a un producto químico existente, ahora es obligatorio incluir el precio por unidad (unitPrice). Este precio se almacena en el registro de inventario correspondiente, permitiendo rastrear el costo de cada lote individualmente.

Cambios Técnicos

Modelo de Datos:

  • Se agregó el campo unitPrice al esquema ChemicalInventorySchema
  • El hook post('save') de ChemicalInventory ahora incluye unitPrice al agregar o actualizar registros en inventoryRecords
  • Si el lote ya existe, se incrementa la cantidad pero se mantiene el precio original del lote
  • Si es un lote nuevo, se crea un nuevo registro con el precio proporcionado

Validaciones:

  • Se agregó validación en chemicalInventoryValidators que requiere unitPrice como campo obligatorio
  • El precio debe ser un número flotante mayor o igual a 0

Interfaz:

  • Se agregó unitPrice: number a la interfaz IChemicalInventory

Uso para Frontend

Endpoint: POST /chemical-inventory

Body de la petición:

json
{
  "chemicalName": "507f1f77bcf86cd799439011",
  "quantity": 50,
  "units": "litros",
  "lot": "LOTE-002",
  "expirationDate": "2025-12-31",
  "unitPrice": 28.75
}

Campos requeridos:

  • chemicalName: ID del producto químico
  • quantity: Cantidad a agregar
  • units: Unidades de medida
  • lot: Número de lote
  • expirationDate: Fecha de expiración
  • unitPrice: Precio por unidad (OBLIGATORIO)

Comportamiento:

  1. Si el lote ya existe en inventoryRecords del producto:

    • Se incrementa la cantidad del lote existente
    • El precio original del lote se mantiene (no se actualiza)
  2. Si es un lote nuevo:

    • Se crea un nuevo registro en inventoryRecords con el precio proporcionado
    • Se actualiza availableQuantity del producto sumando la nueva cantidad

Respuesta exitosa (201):

json
{
  "msg": "Inventario agregado exitosamente"
}

Errores posibles:

  • 400: Si falta el campo unitPrice o es inválido
  • 400: Si el precio es negativo
  • 404: Si el producto químico no existe

3. Preparación de Químicos - Previsualización de Lotes a Descontar

Descripción

Se implementó un nuevo endpoint que permite previsualizar qué lotes se van a descontar antes de confirmar una preparación de químico. Esto permite al usuario ver información sobre los lotes que se utilizarán, incluyendo la fecha de expiración más cercana y si hay inventario suficiente.

Cambios Técnicos

Nuevo Endpoint:

  • Ruta: POST /chemical-preparation-by-product
  • Controlador: chemicalPreparationByProduct
  • Validador: chemicalPreparationPreviewValidator

Funcionalidad:

  • Recibe el ID del producto químico y la cantidad a preparar
  • Calcula qué lotes se descontarían usando la función lotsToDeduct
  • Retorna información sobre los lotes sin modificar la base de datos
  • Utiliza el algoritmo FIFO (First In First Out) basado en fechas de expiración

Interfaz de Respuesta:

typescript
interface IBatchesToDeduct {
  batchesToDeduct: string[];
  nearestExpirationDate: string;
  inventorySufficient: boolean;
}

Uso para Frontend

Endpoint: POST /chemical-preparation-by-product

Headers requeridos:

  • Authorization: JWT token
  • Headers de tenant (según configuración)

Body de la petición:

json
{
  "chemicalProductId": "507f1f77bcf86cd799439011",
  "quantityToPrepare": 100
}

Campos:

  • chemicalProductId: ID del producto químico (ObjectId válido, requerido)
  • quantityToPrepare: Cantidad a preparar (número mayor que 0, requerido)

Respuesta exitosa (200):

json
{
  "batchesToDeduct": ["LOTE-001", "LOTE-002"],
  "nearestExpirationDate": "2025-12-31T00:00:00.000Z",
  "inventorySufficient": true
}

Campos de respuesta:

  • batchesToDeduct: Array de strings con los números de lote que se descontarían
  • nearestExpirationDate: Fecha de expiración más cercana entre los lotes que se usarían (formato ISO)
  • inventorySufficient: Boolean que indica si hay inventario suficiente para la cantidad solicitada

Errores posibles:

  • 400: Si falta algún campo requerido o es inválido
  • 400: Si el producto no tiene registros de inventario disponibles
  • 404: Si el producto químico no existe
  • 500: Error interno del servidor

Flujo recomendado en Frontend:

  1. Usuario ingresa la cantidad a preparar en el formulario
  2. Frontend llama al endpoint /chemical-preparation-by-product
  3. Frontend muestra la información recibida:
    • Lista de lotes que se descontarían (batchesToDeduct)
    • Fecha de expiración más cercana (nearestExpirationDate)
    • Advertencia si inventorySufficient es false
  4. Usuario confirma la preparación
  5. Frontend llama al endpoint POST /chemical-preparation para guardar la preparación y descontar el inventario

Resumen de Cambios por Módulo

Crear Producto Químico:

  • Campo settUnitPrice agregado (opcional)
  • Precio se guarda automáticamente en inventoryRecords mediante hook post-save (unitPrice)

Agregar Inventario:

  • Campo unitPrice agregado (obligatorio)
  • Precio se guarda en cada registro de inventoryRecords
  • Validación de precio mayor o igual a 0

Preparación de Químicos:

  • Nuevo endpoint de previsualización implementado
  • Retorna información de lotes sin modificar la base de datos
  • Permite mostrar información al usuario antes de confirmar
  • Endpoint de confirmación que descuenta inventario y registra costos
  • Sistema de notificaciones para inventario bajo
  • Registro de historial de movimientos (BalanceHistory)

Preparación de quimicos:

  • Se creo un campo nuevo en el documento ChemicalPreparation llamado totalCost que permite identificar el costo total de la preparacion de quimicos actual