# 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 ```typescript 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 ```typescript // Extender para multi-sucursal class RetailInventoryService extends InventoryService { // Stock por sucursal async getStockByBranch(branchId: string, productId: string): Promise; // Transferencias async createTransfer(dto: CreateTransferDto): Promise; async confirmTransfer(id: string): Promise; async receiveTransfer(id: string, dto: ReceiveDto): Promise; } ``` --- ## 3. COMPONENTES NUEVOS ### 3.1 Entidades (TypeORM) ```typescript // 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 ```typescript @Controller('inventory') export class RetailInventoryController { // Stock por sucursal @Get('branches/:branchId/stock') getBranchStock(@Param('branchId') branchId: string): Promise; @Get('branches/:branchId/stock/:productId') getProductStock(@Param('branchId') branchId: string, @Param('productId') productId: string): Promise; @Get('stock/all/:productId') getStockAllBranches(@Param('productId') productId: string): Promise; // Transferencias @Post('transfers') createTransfer(@Body() dto: CreateTransferDto): Promise; @Post('transfers/:id/confirm') confirmTransfer(@Param('id') id: string): Promise; @Post('transfers/:id/ship') shipTransfer(@Param('id') id: string, @Body() dto: ShipDto): Promise; @Post('transfers/:id/receive') receiveTransfer(@Param('id') id: string, @Body() dto: ReceiveDto): Promise; // Alertas @Get('alerts/reorder') getReorderAlerts(): Promise; // Kardex @Get('kardex/:productId') getKardex(@Param('productId') productId: string, @Query() filters: KardexFilters): Promise; } ``` --- ## 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 ```sql -- 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 ```sql -- 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 ```sql -- 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 ```yaml 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)