feat(expeditions): transición Emitida → EnTransito con reserva de stock #7

Closed
opened 2026-03-12 21:07:26 +00:00 by leandro · 0 comments
Owner

feat(expeditions): transición Emitida → EnTransito con reserva de stock

Descripción funcional

Implementar la transición logística de una expedición desde estado
Emitida a EnTransito.

Esta transición representa el momento en que el material sale
físicamente del depósito
, por lo tanto el sistema debe:

  • validar nuevamente disponibilidad de stock
  • validar conflictos de stock serializado
  • crear reservas de stock
  • actualizar reserved_quantity
  • cambiar el estado de la expedición

La acción será disparada desde la UI mediante un botón "Pasar a
tránsito"
disponible en la consulta de expediciones.


Flujo funcional

  1. Usuario abre consulta de expediciones
  2. Expedición en estado Emitida
  3. Usuario presiona Pasar a tránsito
  4. Aparece ConfirmModal
  5. Usuario confirma
  6. API ejecuta transición
  7. Si todo es válido:
    • se crean reservas
    • se actualiza reserved_quantity
    • la expedición pasa a EnTransito
  8. UI refresca la grilla

Reglas de negocio

Transición permitida

Emitida → EnTransito

No se permiten otras transiciones en esta story.


Reservas de stock

Las reservas se crean en:

PhLSM_StockReservation

Con:

source_type = 'EXPEDITION'
source_id = expedition_id
status = Reserved


Impacto en stock

Cuando la expedición pasa a EnTransito:

Se incrementa:

PhLSM_StockItem.reserved_quantity

No se modifica aún:

quantity


Validaciones obligatorias

Antes de crear reservas:

  1. La expedición debe estar en Emitida
  2. Debe tener detalles
  3. No debe tener reservas activas
  4. Validar conflictos de serializados
  5. Validar disponibilidad de stock

Si alguna validación falla → abortar operación.


Alcance técnico por capa

DATA

Repositorio de reservas:

PhLSMStockReservationRepository

Operaciones mínimas:

  • crear reservas por expedición
  • consultar reservas activas por expedición

Repositorio de expediciones:

  • obtener expedición con detalles
  • actualizar estado

Repositorio de stock:

  • incrementar reserved_quantity por stockitem_id

DOMAIN

Usar entidades existentes:

  • ELSStockReservation
  • ELSExpedition
  • ELSExpeditionDetail

Convención de reservas:

source_type = EXPEDITION
status = Reserved


CORE

Agregar operación en:

ExpeditionService

Responsabilidades:

  1. cargar expedición + detalles
  2. validar estado
  3. validar stock
  4. crear reservas
  5. actualizar reserved_quantity
  6. cambiar estado a EnTransito
  7. confirmar transacción

API

Agregar endpoint:

POST /api/expeditions/{id}/in-transit

Responsabilidad:

  • invocar transición en Core
  • devolver resultado

UI (Blazor)

En la consulta de expediciones:

Agregar botón:

Pasar a tránsito

Visible solo si:

Status == Emitida

Al presionar:

  1. abrir ConfirmModal
  2. si confirma → llamar API
  3. refrescar grilla
  4. mostrar toast

Reutilizar:

Shared/Modals/ConfirmModal.razor


Criterios de aceptación

Caso exitoso

Dada una expedición Emitida

Cuando el usuario la pasa a EnTransito

Entonces:

  • se crean reservas en PhLSM_StockReservation
  • se incrementa reserved_quantity
  • la expedición cambia a EnTransito

Conflicto de stock serializado

Si algún stockitem_id serializado ya está reservado en otra
expedición:

→ la operación falla.


Falta de disponibilidad

Si:

quantity - reserved_quantity < cantidad solicitada

→ la operación falla.


Estado inválido

Si la expedición no está en Emitida

→ la operación se rechaza.


Fuera de alcance de esta story

No se implementa aún:

  • transición EnTransito → EnDestino
  • cierre de expedición
  • generación de StockOut
  • anulación
  • retorno
  • liberación de reservas
  • consumo de reservas

Estas serán stories posteriores.


Checklist técnico

Data

  • completar PhLSMStockReservationRepository
  • método para crear reservas
  • método para obtener reservas por expedición

Core

  • método MoveToInTransitAsync
  • validaciones
  • transacción

API

  • endpoint /expeditions/{id}/in-transit

UI

  • botón en consulta
  • ConfirmModal
  • llamada API
  • refresh + toast
## feat(expeditions): transición Emitida → EnTransito con reserva de stock ### Descripción funcional Implementar la transición logística de una expedición desde estado **Emitida** a **EnTransito**. Esta transición representa el momento en que el material **sale físicamente del depósito**, por lo tanto el sistema debe: - validar nuevamente disponibilidad de stock - validar conflictos de stock serializado - crear reservas de stock - actualizar `reserved_quantity` - cambiar el estado de la expedición La acción será disparada desde la UI mediante un botón **"Pasar a tránsito"** disponible en la consulta de expediciones. ------------------------------------------------------------------------ # Flujo funcional 1. Usuario abre **consulta de expediciones** 2. Expedición en estado **Emitida** 3. Usuario presiona **Pasar a tránsito** 4. Aparece `ConfirmModal` 5. Usuario confirma 6. API ejecuta transición 7. Si todo es válido: - se crean reservas - se actualiza `reserved_quantity` - la expedición pasa a **EnTransito** 8. UI refresca la grilla ------------------------------------------------------------------------ # Reglas de negocio ## Transición permitida Emitida → EnTransito No se permiten otras transiciones en esta story. ------------------------------------------------------------------------ ## Reservas de stock Las reservas se crean en: `PhLSM_StockReservation` Con: source_type = 'EXPEDITION'\ source_id = expedition_id\ status = Reserved ------------------------------------------------------------------------ ## Impacto en stock Cuando la expedición pasa a **EnTransito**: Se incrementa: `PhLSM_StockItem.reserved_quantity` No se modifica aún: `quantity` ------------------------------------------------------------------------ # Validaciones obligatorias Antes de crear reservas: 1. La expedición debe estar en **Emitida** 2. Debe tener **detalles** 3. No debe tener **reservas activas** 4. Validar **conflictos de serializados** 5. Validar **disponibilidad de stock** Si alguna validación falla → abortar operación. ------------------------------------------------------------------------ # Alcance técnico por capa ## DATA Repositorio de reservas: `PhLSMStockReservationRepository` Operaciones mínimas: - crear reservas por expedición - consultar reservas activas por expedición Repositorio de expediciones: - obtener expedición con detalles - actualizar estado Repositorio de stock: - incrementar `reserved_quantity` por `stockitem_id` ------------------------------------------------------------------------ ## DOMAIN Usar entidades existentes: - `ELSStockReservation` - `ELSExpedition` - `ELSExpeditionDetail` Convención de reservas: source_type = EXPEDITION\ status = Reserved ------------------------------------------------------------------------ ## CORE Agregar operación en: `ExpeditionService` Responsabilidades: 1. cargar expedición + detalles 2. validar estado 3. validar stock 4. crear reservas 5. actualizar reserved_quantity 6. cambiar estado a EnTransito 7. confirmar transacción ------------------------------------------------------------------------ ## API Agregar endpoint: POST `/api/expeditions/{id}/in-transit` Responsabilidad: - invocar transición en Core - devolver resultado ------------------------------------------------------------------------ ## UI (Blazor) En la **consulta de expediciones**: Agregar botón: **Pasar a tránsito** Visible solo si: `Status == Emitida` Al presionar: 1. abrir `ConfirmModal` 2. si confirma → llamar API 3. refrescar grilla 4. mostrar toast Reutilizar: `Shared/Modals/ConfirmModal.razor` ------------------------------------------------------------------------ # Criterios de aceptación ## Caso exitoso Dada una expedición **Emitida** Cuando el usuario la pasa a **EnTransito** Entonces: - se crean reservas en `PhLSM_StockReservation` - se incrementa `reserved_quantity` - la expedición cambia a `EnTransito` ------------------------------------------------------------------------ ## Conflicto de stock serializado Si algún `stockitem_id` serializado ya está reservado en otra expedición: → la operación falla. ------------------------------------------------------------------------ ## Falta de disponibilidad Si: quantity - reserved_quantity \< cantidad solicitada → la operación falla. ------------------------------------------------------------------------ ## Estado inválido Si la expedición no está en **Emitida** → la operación se rechaza. ------------------------------------------------------------------------ # Fuera de alcance de esta story No se implementa aún: - transición `EnTransito → EnDestino` - cierre de expedición - generación de `StockOut` - anulación - retorno - liberación de reservas - consumo de reservas Estas serán stories posteriores. ------------------------------------------------------------------------ # Checklist técnico ### Data - [ ] completar `PhLSMStockReservationRepository` - [ ] método para crear reservas - [ ] método para obtener reservas por expedición ### Core - [ ] método `MoveToInTransitAsync` - [ ] validaciones - [ ] transacción ### API - [ ] endpoint `/expeditions/{id}/in-transit` ### UI - [ ] botón en consulta - [ ] ConfirmModal - [ ] llamada API - [ ] refresh + toast
leandro added the
STORY
label 2026-03-12 21:07:33 +00:00
leandro added this to the Expeditions milestone 2026-03-12 21:07:37 +00:00
leandro added this to the phronCare: Tablero DEV project 2026-03-12 21:07:42 +00:00
leandro self-assigned this 2026-03-12 21:07:47 +00:00
leandro pinned this 2026-03-12 21:08:02 +00:00
leandro unpinned this 2026-03-15 04:59:12 +00:00
leandro moved this to Done in phronCare: Tablero DEV on 2026-03-15 14:28:56 +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.
No Milestone Expeditions
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: leandro/phronCare#7
No description provided.