Al cambiar el precio de un producto (apps/web/src/app/admin/inventario/productos/page.tsx:164-168), primero se archiva el precio actual y después se crea el nuevo, en dos requests separados. Si el segundo falla, el producto queda sin precio activo y el POS no lo deja vender.
Lo mismo pasa al guardar un producto: primero se crea y luego se sincronizan las categorías con varios requests en paralelo (syncCategories). Si alguno falla, el producto queda guardado sin todas sus categorías y el formulario muestra error, así que un segundo intento crea un producto duplicado o falla por SKU repetido.
Entorno
local
Módulos
Productos / precios / categorías, Punto de venta (POS), Web / frontend
Severidad
Bloquea un flujo
Pasos para reproducir
Abrir Inventario → Productos y elegir un producto con precio.
Cambiar el precio con un valor que el API rechace, o cortar la red justo después del primer request.
Intentar vender el producto en el POS.
Esperado
El cambio de precio es atómico: o queda el precio nuevo activo, o se conserva el anterior.
Actual
El precio anterior queda archived y no hay precio active. El POS muestra "no tiene un precio configurado" y el producto no se puede vender hasta que alguien vuelva a capturar el precio.
Evidencia
Encontrado en auditoría de código; no reproducido en ejecución.
// productos/page.tsx:164-168
if(current){
await updateHistory.mutateAsync({ id: current.id, data: { status: "archived"}});}
await createHistory.mutateAsync({ productId: pricing.id, unitPrice, costUnit, status: "active"});
Arreglo sugerido: endpoint POST /products/:id/price que archive y cree en una transacción; mientras tanto, crear el nuevo antes de archivar el anterior. Para categorías, un PUT /products/:id/categories que reemplace la lista en una transacción.
¿Está también en producción?
Sí — este issue no basta; hay que abrir un Incidente / hotfix
No — solo local / staging
No sé
Antes de abrir
Busqué un issue duplicado
### Qué pasa
Al cambiar el precio de un producto (`apps/web/src/app/admin/inventario/productos/page.tsx:164-168`), primero se archiva el precio actual y después se crea el nuevo, en dos requests separados. Si el segundo falla, el producto queda sin precio activo y el POS no lo deja vender.
Lo mismo pasa al guardar un producto: primero se crea y luego se sincronizan las categorías con varios requests en paralelo (`syncCategories`). Si alguno falla, el producto queda guardado sin todas sus categorías y el formulario muestra error, así que un segundo intento crea un producto duplicado o falla por SKU repetido.
### Entorno
local
### Módulos
Productos / precios / categorías, Punto de venta (POS), Web / frontend
### Severidad
Bloquea un flujo
### Pasos para reproducir
1. Abrir **Inventario → Productos** y elegir un producto con precio.
2. Cambiar el precio con un valor que el API rechace, o cortar la red justo después del primer request.
3. Intentar vender el producto en el POS.
### Esperado
El cambio de precio es atómico: o queda el precio nuevo activo, o se conserva el anterior.
### Actual
El precio anterior queda `archived` y no hay precio `active`. El POS muestra "no tiene un precio configurado" y el producto no se puede vender hasta que alguien vuelva a capturar el precio.
### Evidencia
```shell
Encontrado en auditoría de código; no reproducido en ejecución.
// productos/page.tsx:164-168
if (current) {
await updateHistory.mutateAsync({ id: current.id, data: { status: "archived" } });
}
await createHistory.mutateAsync({ productId: pricing.id, unitPrice, costUnit, status: "active" });
```
Arreglo sugerido: endpoint `POST /products/:id/price` que archive y cree en una transacción; mientras tanto, crear el nuevo antes de archivar el anterior. Para categorías, un `PUT /products/:id/categories` que reemplace la lista en una transacción.
### ¿Está también en producción?
- [ ] Sí — este issue no basta; hay que abrir un Incidente / hotfix
- [x] No — solo local / staging
- [ ] No sé
### Antes de abrir
- [x] Busqué un issue duplicado
Jose
was assigned by Carlos2026-10-02 20:04:27 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Qué pasa
Al cambiar el precio de un producto (
apps/web/src/app/admin/inventario/productos/page.tsx:164-168), primero se archiva el precio actual y después se crea el nuevo, en dos requests separados. Si el segundo falla, el producto queda sin precio activo y el POS no lo deja vender.Lo mismo pasa al guardar un producto: primero se crea y luego se sincronizan las categorías con varios requests en paralelo (
syncCategories). Si alguno falla, el producto queda guardado sin todas sus categorías y el formulario muestra error, así que un segundo intento crea un producto duplicado o falla por SKU repetido.Entorno
local
Módulos
Productos / precios / categorías, Punto de venta (POS), Web / frontend
Severidad
Bloquea un flujo
Pasos para reproducir
Esperado
El cambio de precio es atómico: o queda el precio nuevo activo, o se conserva el anterior.
Actual
El precio anterior queda
archivedy no hay precioactive. El POS muestra "no tiene un precio configurado" y el producto no se puede vender hasta que alguien vuelva a capturar el precio.Evidencia
Arreglo sugerido: endpoint
POST /products/:id/priceque archive y cree en una transacción; mientras tanto, crear el nuevo antes de archivar el anterior. Para categorías, unPUT /products/:id/categoriesque reemplace la lista en una transacción.¿Está también en producción?
Antes de abrir