[bug] Devoluciones y ajustes de inventario cuentan como compras al proveedor #24

Open
opened 2026-10-02 19:21:58 +00:00 by Carlos · 0 comments
Member

Qué pasa

El sistema trata toda entrada de inventario como compra al proveedor:

  • apps/api/src/modules/inventory-movement/inventory-movement.service.ts:79-83 actualiza Supplier.lastSupply en cualquier movimiento in, incluidas las devoluciones de venta (historial/page.tsx, "Devolución venta #N") y los ajustes por conteo físico (inventario/[id]/page.tsx, "Ajuste por conteo físico").
  • La pantalla del proveedor (apps/web/src/app/admin/proveedores/[id]/page.tsx:24-29) lista como "compras" todas las entradas de sus productos, con las devoluciones y los ajustes incluidos.

El único dato para distinguirlas es el texto libre reason.

Entorno

local

Módulos

Proveedores, Inventario / almacenes, Punto de venta (POS), API / backend

Severidad

Molesta; hay workaround

Pasos para reproducir

  1. Tener un producto con proveedor asignado y anotar su "Último abastecimiento".
  2. Vender el producto y luego hacer la devolución desde Historial de ventas.
  3. Abrir el detalle del proveedor.
  4. Repetir con un conteo físico que aumente el stock del producto.

Esperado

La fecha de último abastecimiento y la lista de compras del proveedor solo reflejan entradas por compra.

Actual

La devolución y el ajuste cambian la fecha de último abastecimiento y aparecen en la lista de compras del proveedor.

Evidencia

Encontrado en auditoría de código; no reproducido en ejecución.

// inventory-movement.service.ts — en la rama de entrada, sin importar el motivo
const product = await this.productService.findById({ id: data.productId }).catch(() => null);
if (product?.supplierId) {
  await this.supplierService.update({ id: product.supplierId }, { lastSupply: new Date().toISOString() });
}

// proveedores/[id]/page.tsx:27
.filter((m) => m.type === "in" && supplierProductIds.has(m.productId))

Arreglo sugerido: agregar a InventoryMovement un campo de motivo con valores cerrados (purchase, sale, return, adjustment), como enum del contrato (#2). Actualizar lastSupply y listar compras solo con purchase. Workaround: revisar el texto de reason en la lista.

¿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 El sistema trata toda entrada de inventario como compra al proveedor: - `apps/api/src/modules/inventory-movement/inventory-movement.service.ts:79-83` actualiza `Supplier.lastSupply` en **cualquier** movimiento `in`, incluidas las devoluciones de venta (`historial/page.tsx`, "Devolución venta #N") y los ajustes por conteo físico (`inventario/[id]/page.tsx`, "Ajuste por conteo físico"). - La pantalla del proveedor (`apps/web/src/app/admin/proveedores/[id]/page.tsx:24-29`) lista como "compras" todas las entradas de sus productos, con las devoluciones y los ajustes incluidos. El único dato para distinguirlas es el texto libre `reason`. ### Entorno local ### Módulos Proveedores, Inventario / almacenes, Punto de venta (POS), API / backend ### Severidad Molesta; hay workaround ### Pasos para reproducir 1. Tener un producto con proveedor asignado y anotar su "Último abastecimiento". 2. Vender el producto y luego hacer la devolución desde **Historial de ventas**. 3. Abrir el detalle del proveedor. 4. Repetir con un conteo físico que aumente el stock del producto. ### Esperado La fecha de último abastecimiento y la lista de compras del proveedor solo reflejan entradas por compra. ### Actual La devolución y el ajuste cambian la fecha de último abastecimiento y aparecen en la lista de compras del proveedor. ### Evidencia ```shell Encontrado en auditoría de código; no reproducido en ejecución. // inventory-movement.service.ts — en la rama de entrada, sin importar el motivo const product = await this.productService.findById({ id: data.productId }).catch(() => null); if (product?.supplierId) { await this.supplierService.update({ id: product.supplierId }, { lastSupply: new Date().toISOString() }); } // proveedores/[id]/page.tsx:27 .filter((m) => m.type === "in" && supplierProductIds.has(m.productId)) ``` Arreglo sugerido: agregar a `InventoryMovement` un campo de motivo con valores cerrados (`purchase`, `sale`, `return`, `adjustment`), como enum del contrato (#2). Actualizar `lastSupply` y listar compras solo con `purchase`. Workaround: revisar el texto de `reason` en la lista. ### ¿Está también en producción? - [ ] Sí — este issue no basta; hay que abrir un Incidente / hotfix - [ ] No — solo local / staging - [x] No sé ### Antes de abrir - [x] Busqué un issue duplicado
Emmanuel was assigned by Carlos 2026-10-02 20:03:30 +00:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RynextTechnologies/PDV#24