Este artículo cubre los endpoints núcleo de lectura y escritura de existencias: listado general, consulta por SKU o por ubicación, actualización individual, actualización masiva, estadísticas y reportes.
lowStock=true filtra registros con stock < 10. Este umbral está hardcodeado en el servicio — no es configurable por tenant ni por SKU desde este endpoint.
Este endpoint hace un findOne({tenantId, sku}) — devuelve el primer registro que Mongo encuentre para ese SKU, sin orden determinístico. Como un SKU puede tener un registro de inventario por cada ubicación (índice único {tenantId, sku, locationId}), este endpoint no consolida ni suma el stock de todas las ubicaciones de un SKU multi-ubicación. Si necesitas el stock de un SKU en una ubicación específica, usa GET /inventory/location/:id/product/:sku (más abajo en esta misma página).
Si envías un stock que resultaría negativo, la API responde 500 con {"code":"internal-error","message":"Stock cannot be negative"} — no un 400 estructurado. Este es el comportamiento actual en producción: la validación de negativos ocurre en una capa que no distingue error de negocio de error interno. Trátalo como una respuesta de error de negocio (rechaza el intento), pero no esperes el status HTTP habitual para validaciones.
Un registro cuyo stock es controlado por una integración o canal (handlerType: 'integration' | 'channel') puede rechazar la escritura manual con 403 forbidden/inventory-handler.
200 no significa que todos los items se actualizaron
Esta respuesta es siempre 200 si el body es válido, incluso si algunos (o todos) los items individuales fallan. No hay una bandera de éxito a nivel raíz. Debes iterar el arreglo de resultados y revisar success en cada elemento — un 200 global nunca garantiza que tu lote completo se aplicó.
productsLowStock usa un umbral fijo de 5 unidades (DEFAULT_MIN_ALERT_STOCK), distinto del umbral < 10 que usa el filtro lowStock de GET /inventory. No confundas ambos — son dos umbrales hardcodeados independientes.
El reporte de valuación (reportType=valuation) está roto
El reporte de valuación lee unitCost directamente del documento de Inventory, pero ese campo no existe en el esquema de inventario — siempre es undefined. Como resultado, totalValue y averageUnitCost de este reporte son efectivamente 0 para cualquier tenant. No lo uses como fuente de valuación de inventario.
format=csv no hace nada
El parámetro format se acepta pero se ignora: la respuesta siempre es JSON, sin importar el valor enviado.
No se valida ni se lee ningún cuerpo — la ruta responde 501 sin importar el body enviado.
{}
501
{ "code": "not-implemented" }
GET /inventory (ruta raíz) es equivalente al listado documentado arriba. POST /inventory sobre esa misma ruta responde 501 not-implemented — no existe una operación de "crear inventario" genérica; los registros de inventario se crean implícitamente al escribir stock (PUT/bulk-update) o mediante los flujos internos de producto.