feat(stock): reservar stock al pasar expedición a EnTransito #9

Closed
opened 2026-03-15 15:03:03 +00:00 by leandro · 0 comments
Owner

feat(stock): reservar stock al pasar expedición a EnTransito


Contexto

Actualmente el módulo Expeditions permite:

  • emitir expediciones
  • buscar expediciones
  • ver detalle
  • imprimir PDF
  • cambiar estado Emitida → EnTransito

Sin embargo, cuando una expedición pasa a EnTransito el sistema no reserva los productos utilizados, por lo que esos mismos stockitem_id podrían ser utilizados por otras expediciones.

Esto rompe el escenario operativo real:

Preparar múltiples cirugías en el depósito antes de su salida física.

Para resolverlo, al pasar una expedición a EnTransito se deben crear reservas de stock.


Objetivo

Cuando una expedición pase de:

Emitida → EnTransito

el sistema debe crear registros en:

PhLSM_StockReservation

para bloquear los stockitem_id utilizados en esa expedición.

Esto evitará que esos productos puedan ser utilizados por otras expediciones mientras están reservados para esa cirugía.


Modelo de datos involucrado

Tablas principales:

  • PhLSM_Expedition
  • PhLSM_ExpeditionDetails
  • PhLSM_StockItem
  • PhLSM_StockReservation

Cada ExpeditionDetail ya persiste:

stockitem_id
quantity

La tabla PhLSM_StockReservation contiene:

source_type
source_id
stockitem_id
reserved_quantity
status
createdat

Convenciones actuales del sistema:

source_type = 1 → Expedition
status = 1 → Reserved

Comportamiento esperado

Cuando se ejecute:

MarkInTransitAsync(expeditionId)

el sistema debe:

  1. Validar que la expedición esté en estado Emitida
  2. Obtener los ExpeditionDetails
  3. Para cada stockitem_id generar una reserva
  4. Asociar la reserva al origen Expedition
  5. Actualizar el estado de la expedición a EnTransito

Estructura de la reserva

Para cada ExpeditionDetail se debe crear:

source_type = 1
source_id = expedition_id
stockitem_id = detail.stockitem_id
reserved_quantity = detail.quantity
status = 1

Consistencia de stock

El sistema actualmente calcula disponibilidad usando:

PhLSM_StockItem.quantity
PhLSM_StockItem.reserved_quantity

Por lo tanto, además de crear el registro en PhLSM_StockReservation, la operación deberá:

incrementar PhLSM_StockItem.reserved_quantity

para reflejar correctamente la reserva en el cálculo de disponibilidad.


Reglas de negocio

  • una reserva por cada ExpeditionDetail
  • no se permiten duplicados de reservas activas para el mismo:
(source_type, source_id, stockitem_id)
  • la operación debe ser transaccional
  • si alguna reserva falla → rollback completo

Criterios de aceptación

✔ al ejecutar MarkInTransitAsync se crean reservas
✔ cada ExpeditionDetail genera una reserva
✔ no se crean duplicados
✔ las reservas quedan asociadas al stockitem_id
PhLSM_StockItem.reserved_quantity se actualiza correctamente
✔ la transición de estado y la reserva ocurren en una sola transacción
✔ los mensajes de error están en español


Alcance técnico

Capas afectadas:

Data

Crear repositorio:

IPhLSMStockReservationRepository
PhLSMStockReservationRepository

Responsabilidades:

  • insertar reservas
  • validar existencia previa
  • actualizar reserved_quantity

Domain

Usar entidad existente:

ELSStockReservation

(No modificar modelos EF scaffolded)


Core

Actualizar lógica en:

ExpeditionService.MarkInTransitAsync

La operación deberá:

  1. validar estado
  2. obtener detalles
  3. generar reservas
  4. actualizar reserved_quantity
  5. cambiar estado a EnTransito
  6. confirmar transacción

API

No requiere cambios.

Se reutiliza endpoint actual.


UI

No requiere cambios.

El botón Enviar / EnTransito ya existe en:

ExpeditionSearch

Fuera de alcance

No incluye:

  • consumo de reservas al cerrar expedición
  • liberación por cancelación
  • devolución de productos
  • recalcular disponibilidad usando solo StockReservation

Estas funcionalidades se abordarán en futuras stories.


Branch

feature/leandro/9-stock-reservation-on-transit

Checklist técnico

  • crear IPhLSMStockReservationRepository
  • implementar PhLSMStockReservationRepository
  • agregar método para crear reservas
  • integrar repositorio en ExpeditionService
  • extender MarkInTransitAsync
  • asegurar transacción completa
  • actualizar reserved_quantity
  • validar duplicados
  • probar flujo completo Emitida → EnTransito

Resultado esperado

Al pasar una expedición a EnTransito:

  • los productos quedan reservados
  • otras expediciones no pueden utilizarlos
  • el sistema permite preparar múltiples cirugías en depósito de forma segura.
**feat(stock): reservar stock al pasar expedición a EnTransito** --- # Contexto Actualmente el módulo **Expeditions** permite: - emitir expediciones - buscar expediciones - ver detalle - imprimir PDF - cambiar estado **Emitida → EnTransito** Sin embargo, cuando una expedición pasa a **EnTransito** el sistema **no reserva los productos utilizados**, por lo que esos mismos `stockitem_id` podrían ser utilizados por otras expediciones. Esto rompe el escenario operativo real: > Preparar múltiples cirugías en el depósito antes de su salida física. Para resolverlo, al pasar una expedición a **EnTransito** se deben crear **reservas de stock**. --- # Objetivo Cuando una expedición pase de: **Emitida → EnTransito** el sistema debe crear registros en: **PhLSM_StockReservation** para bloquear los `stockitem_id` utilizados en esa expedición. Esto evitará que esos productos puedan ser utilizados por otras expediciones mientras están reservados para esa cirugía. --- # Modelo de datos involucrado Tablas principales: - `PhLSM_Expedition` - `PhLSM_ExpeditionDetails` - `PhLSM_StockItem` - `PhLSM_StockReservation` Cada `ExpeditionDetail` ya persiste: ``` stockitem_id quantity ``` La tabla `PhLSM_StockReservation` contiene: ``` source_type source_id stockitem_id reserved_quantity status createdat ``` Convenciones actuales del sistema: ``` source_type = 1 → Expedition status = 1 → Reserved ``` --- # Comportamiento esperado Cuando se ejecute: ``` MarkInTransitAsync(expeditionId) ``` el sistema debe: 1. Validar que la expedición esté en estado **Emitida** 2. Obtener los `ExpeditionDetails` 3. Para cada `stockitem_id` generar una reserva 4. Asociar la reserva al origen **Expedition** 5. Actualizar el estado de la expedición a **EnTransito** --- # Estructura de la reserva Para cada `ExpeditionDetail` se debe crear: ``` source_type = 1 source_id = expedition_id stockitem_id = detail.stockitem_id reserved_quantity = detail.quantity status = 1 ``` --- # Consistencia de stock El sistema actualmente calcula disponibilidad usando: ``` PhLSM_StockItem.quantity PhLSM_StockItem.reserved_quantity ``` Por lo tanto, además de crear el registro en `PhLSM_StockReservation`, la operación deberá: ``` incrementar PhLSM_StockItem.reserved_quantity ``` para reflejar correctamente la reserva en el cálculo de disponibilidad. --- # Reglas de negocio - una reserva por cada `ExpeditionDetail` - no se permiten duplicados de reservas activas para el mismo: ``` (source_type, source_id, stockitem_id) ``` - la operación debe ser **transaccional** - si alguna reserva falla → **rollback completo** --- # Criterios de aceptación ✔ al ejecutar `MarkInTransitAsync` se crean reservas ✔ cada `ExpeditionDetail` genera una reserva ✔ no se crean duplicados ✔ las reservas quedan asociadas al `stockitem_id` ✔ `PhLSM_StockItem.reserved_quantity` se actualiza correctamente ✔ la transición de estado y la reserva ocurren en **una sola transacción** ✔ los mensajes de error están en **español** --- # Alcance técnico Capas afectadas: ### Data Crear repositorio: ``` IPhLSMStockReservationRepository PhLSMStockReservationRepository ``` Responsabilidades: - insertar reservas - validar existencia previa - actualizar `reserved_quantity` --- ### Domain Usar entidad existente: ``` ELSStockReservation ``` (No modificar modelos EF scaffolded) --- ### Core Actualizar lógica en: ``` ExpeditionService.MarkInTransitAsync ``` La operación deberá: 1. validar estado 2. obtener detalles 3. generar reservas 4. actualizar `reserved_quantity` 5. cambiar estado a `EnTransito` 6. confirmar transacción --- ### API No requiere cambios. Se reutiliza endpoint actual. --- ### UI No requiere cambios. El botón **Enviar / EnTransito** ya existe en: ``` ExpeditionSearch ``` --- # Fuera de alcance No incluye: - consumo de reservas al cerrar expedición - liberación por cancelación - devolución de productos - recalcular disponibilidad usando solo `StockReservation` Estas funcionalidades se abordarán en futuras stories. --- # Branch ``` feature/leandro/9-stock-reservation-on-transit ``` --- # Checklist técnico - [ ] crear `IPhLSMStockReservationRepository` - [ ] implementar `PhLSMStockReservationRepository` - [ ] agregar método para crear reservas - [ ] integrar repositorio en `ExpeditionService` - [ ] extender `MarkInTransitAsync` - [ ] asegurar transacción completa - [ ] actualizar `reserved_quantity` - [ ] validar duplicados - [ ] probar flujo completo Emitida → EnTransito --- # Resultado esperado Al pasar una expedición a **EnTransito**: - los productos quedan **reservados** - otras expediciones **no pueden utilizarlos** - el sistema permite **preparar múltiples cirugías en depósito** de forma segura.
leandro added this to the Stock (Inventario Médico) milestone 2026-03-15 15:03:03 +00:00
leandro added the
STORY
label 2026-03-15 15:03:03 +00:00
leandro self-assigned this 2026-03-15 15:03:03 +00:00
leandro added this to the phronCare: Tablero DEV project 2026-03-15 15:03:03 +00:00
leandro pinned this 2026-03-15 22:16:12 +00:00
leandro unpinned this 2026-03-15 22:25:22 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-16 22:47:27 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-16 22:47:29 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-23 03:07:36 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-23 03:07:37 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-23 03:07:39 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-23 03:07:40 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-23 03:07:42 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-23 03:07:45 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-23 03:07:47 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-23 03:07:49 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-23 03:07:51 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-23 03:07:52 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-24 20:24:05 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-24 20:24:07 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-25 13:27:46 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: leandro/phronCare#9
No description provided.