erp-retail/orchestration/planes/fase-2-analisis-modulos/ANALISIS-RT-003-inventario.md

11 KiB

ANALISIS MODULO RT-003: INVENTARIO MULTI-SUCURSAL

Fecha: 2025-12-18 Fase: 2 - Analisis por Modulo Modulo: RT-003 Inventario Herencia: 60% Story Points: 42 Prioridad: P0


1. DESCRIPCION GENERAL

1.1 Proposito

Gestion de inventario distribuido entre multiples sucursales con transferencias, conteos ciclicos y alertas de reorden.

1.2 Funcionalidades Principales

Funcionalidad Descripcion Criticidad
Stock por sucursal Inventario independiente Critica
Transferencias Entre sucursales Alta
Alertas reorden Stock minimo Alta
Conteos ciclicos ABC Media
Kardex Historial movimientos Media
Reservas Stock apartado Media

2. HERENCIA DEL CORE

2.1 Componentes Heredados (60%)

Componente Core % Uso Accion
inventory.products 100% HEREDAR
inventory.product_variants 100% HEREDAR
inventory.warehouses 100% HEREDAR
inventory.locations 100% HEREDAR
inventory.lots 100% HEREDAR
inventory.stock_moves 80% EXTENDER
inventory.pickings 60% EXTENDER

2.2 Servicios a Heredar

import { ProductsService } from '@erp-core/inventory';
import { WarehousesService } from '@erp-core/inventory';
import { LocationsService } from '@erp-core/inventory';
import { LotsService } from '@erp-core/inventory';

2.3 Servicios a Extender

// Extender para multi-sucursal
class RetailInventoryService extends InventoryService {
  // Stock por sucursal
  async getStockByBranch(branchId: string, productId: string): Promise<BranchStock>;

  // Transferencias
  async createTransfer(dto: CreateTransferDto): Promise<StockTransfer>;
  async confirmTransfer(id: string): Promise<StockTransfer>;
  async receiveTransfer(id: string, dto: ReceiveDto): Promise<StockTransfer>;
}

3. COMPONENTES NUEVOS

3.1 Entidades (TypeORM)

// 1. BranchStock - Stock por sucursal
@Entity('branch_stock', { schema: 'retail' })
export class BranchStock {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column('uuid')
  tenantId: string;

  @ManyToOne(() => Branch)
  branch: Branch;

  @ManyToOne(() => Product)
  product: Product;

  @Column({ type: 'decimal', precision: 12, scale: 4 })
  quantityOnHand: number;

  @Column({ type: 'decimal', precision: 12, scale: 4, default: 0 })
  quantityReserved: number;

  @Column({ type: 'decimal', precision: 12, scale: 4 })
  @Generated('quantityOnHand - quantityReserved')
  quantityAvailable: number;

  @Column({ type: 'decimal', precision: 12, scale: 4, nullable: true })
  reorderPoint: number;

  @Column({ type: 'decimal', precision: 12, scale: 4, nullable: true })
  maxStock: number;

  @Column({ type: 'date', nullable: true })
  lastCountDate: Date;
}

// 2. StockTransfer - Transferencia
@Entity('stock_transfers', { schema: 'retail' })
export class StockTransfer {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column('uuid')
  tenantId: string;

  @Column()
  transferNumber: string;

  @ManyToOne(() => Branch)
  sourceBranch: Branch;

  @ManyToOne(() => Branch)
  destinationBranch: Branch;

  @Column({ type: 'enum', enum: TransferStatus })
  status: TransferStatus;

  @Column({ type: 'timestamptz' })
  requestDate: Date;

  @Column({ type: 'timestamptz', nullable: true })
  shipDate: Date;

  @Column({ type: 'timestamptz', nullable: true })
  receiveDate: Date;

  @ManyToOne(() => User)
  requestedBy: User;

  @ManyToOne(() => User, { nullable: true })
  shippedBy: User;

  @ManyToOne(() => User, { nullable: true })
  receivedBy: User;

  @OneToMany(() => StockTransferLine, line => line.transfer)
  lines: StockTransferLine[];
}

// 3. StockTransferLine
@Entity('stock_transfer_lines', { schema: 'retail' })
export class StockTransferLine {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @ManyToOne(() => StockTransfer)
  transfer: StockTransfer;

  @ManyToOne(() => Product)
  product: Product;

  @Column({ type: 'decimal', precision: 12, scale: 4 })
  quantityRequested: number;

  @Column({ type: 'decimal', precision: 12, scale: 4, nullable: true })
  quantityShipped: number;

  @Column({ type: 'decimal', precision: 12, scale: 4, nullable: true })
  quantityReceived: number;
}

3.2 Servicios Backend

Servicio Metodos Principales
BranchStockService getStock(), updateStock(), reserveStock(), releaseStock()
TransferService create(), confirm(), ship(), receive(), cancel()
ReorderService checkReorderPoints(), generateSuggestions()
CycleCountService createCount(), recordCount(), approveAdjustment()
KardexService getMovements(), getProductHistory()

3.3 Controladores

@Controller('inventory')
export class RetailInventoryController {
  // Stock por sucursal
  @Get('branches/:branchId/stock')
  getBranchStock(@Param('branchId') branchId: string): Promise<BranchStock[]>;

  @Get('branches/:branchId/stock/:productId')
  getProductStock(@Param('branchId') branchId: string,
                  @Param('productId') productId: string): Promise<BranchStock>;

  @Get('stock/all/:productId')
  getStockAllBranches(@Param('productId') productId: string): Promise<BranchStock[]>;

  // Transferencias
  @Post('transfers')
  createTransfer(@Body() dto: CreateTransferDto): Promise<StockTransfer>;

  @Post('transfers/:id/confirm')
  confirmTransfer(@Param('id') id: string): Promise<StockTransfer>;

  @Post('transfers/:id/ship')
  shipTransfer(@Param('id') id: string, @Body() dto: ShipDto): Promise<StockTransfer>;

  @Post('transfers/:id/receive')
  receiveTransfer(@Param('id') id: string, @Body() dto: ReceiveDto): Promise<StockTransfer>;

  // Alertas
  @Get('alerts/reorder')
  getReorderAlerts(): Promise<ReorderAlert[]>;

  // Kardex
  @Get('kardex/:productId')
  getKardex(@Param('productId') productId: string,
            @Query() filters: KardexFilters): Promise<KardexEntry[]>;
}

4. FLUJOS DE NEGOCIO

4.1 Flujo de Transferencia

1. Sucursal destino solicita transferencia
      ↓
2. Estado: DRAFT → PENDING (pendiente aprobacion)
      ↓
3. Sucursal origen aprueba
      ↓
4. Estado: PENDING → APPROVED
      ↓
5. Sucursal origen prepara y envia
      ↓
6. Estado: APPROVED → IN_TRANSIT
      ↓
7. Stock origen: - cantidad_enviada
      ↓
8. Sucursal destino recibe
      ↓
9. Validar cantidades (diferencias)
      ↓
10. Estado: IN_TRANSIT → RECEIVED
      ↓
11. Stock destino: + cantidad_recibida

4.2 Flujo de Conteo Ciclico

1. Generar conteo (clasificacion ABC)
      ↓
2. Asignar a contador
      ↓
3. Conteo ciego (sin ver stock sistema)
      ↓
4. Registrar cantidades
      ↓
5. Comparar vs sistema
      ↓
6. Si diferencia:
   a. Registrar motivo
   b. Aprobar ajuste (supervisor)
   c. Aplicar ajuste
      ↓
7. Actualizar fecha ultimo conteo

5. TABLAS DDL

5.1 Tablas Nuevas

-- Definidas en 03-retail-tables.sql
CREATE TABLE retail.branch_stock (...);
CREATE TABLE retail.stock_transfers (...);
CREATE TABLE retail.stock_transfer_lines (...);

5.2 Indices

-- Stock por sucursal
CREATE UNIQUE INDEX idx_branch_stock_branch_product
  ON retail.branch_stock(branch_id, product_id);

-- Transferencias
CREATE INDEX idx_transfers_source ON retail.stock_transfers(source_branch_id);
CREATE INDEX idx_transfers_dest ON retail.stock_transfers(destination_branch_id);
CREATE INDEX idx_transfers_status ON retail.stock_transfers(status);

5.3 Triggers

-- Actualizar stock al confirmar venta
CREATE OR REPLACE FUNCTION retail.update_stock_on_sale()
RETURNS TRIGGER AS $$
BEGIN
  UPDATE retail.branch_stock
  SET quantity_on_hand = quantity_on_hand - NEW.quantity
  WHERE branch_id = (SELECT branch_id FROM retail.pos_sessions WHERE id =
    (SELECT session_id FROM retail.pos_orders WHERE id = NEW.order_id))
  AND product_id = NEW.product_id;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

6. DEPENDENCIAS

6.1 Dependencias de Core

Modulo Estado Requerido Para
MGN-011 Inventory 60% Base de productos y stock
MGN-005 Catalogs 0% Productos base

6.2 Dependencias de Retail

Modulo Tipo
RT-001 Fundamentos Prerequisito
RT-004 Compras Recepciones

6.3 Bloquea a

Modulo Razon
RT-002 POS Stock disponible
RT-009 E-commerce Stock online

7. ESPECIFICACIONES APLICABLES

7.1 Del Core

SPEC Aplicacion
SPEC-INVENTARIOS-CICLICOS Conteos
SPEC-TRAZABILIDAD-LOTES-SERIES Productos con lote
SPEC-VALORACION-INVENTARIO Costeo

7.2 Configuracion

inventory_config:
  reorder:
    check_interval: "1h"
    notification: ["email", "push"]

  cycle_count:
    classification:
      A: { frequency: "weekly", threshold: 0.8 }  # 80% del valor
      B: { frequency: "monthly", threshold: 0.15 }
      C: { frequency: "quarterly", threshold: 0.05 }

  transfers:
    require_approval: true
    auto_reserve_on_request: true

8. CRITERIOS DE ACEPTACION

8.1 Funcionales

  • Consultar stock por sucursal
  • Ver stock en todas las sucursales
  • Crear solicitud de transferencia
  • Aprobar transferencia
  • Enviar transferencia (actualiza stock origen)
  • Recibir transferencia (actualiza stock destino)
  • Registrar diferencias en recepcion
  • Alertas de stock bajo automaticas
  • Conteo ciclico con clasificacion ABC
  • Ver kardex de movimientos

8.2 Performance

  • Consulta stock < 500ms
  • Listado sucursales < 1s

9. RIESGOS

Riesgo Probabilidad Impacto Mitigacion
Inconsistencia stock Media Critico Transacciones atomicas
Performance en listados Media Medio Indices + paginacion

10. ESTIMACION DETALLADA

Componente SP Backend SP Frontend Total
Entities + Migrations 3 - 3
BranchStockService 5 - 5
TransferService 8 - 8
ReorderService 3 - 3
CycleCountService 5 - 5
Controllers 3 - 3
Stock Pages - 8 8
Transfer Pages - 5 5
Alerts UI - 2 2
TOTAL 27 15 42

11. REFERENCIAS

Documento Ubicacion
Epica RT-003 docs/08-epicas/EPIC-RT-003-inventario.md
Modulo Core Inventory erp-core/backend/src/modules/inventory/
SPEC Conteos erp-core/docs/04-modelado/especificaciones-tecnicas/

Estado: ANALISIS COMPLETO Bloqueado por: RT-001 Fundamentos, MGN-011 Inventory (core)