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
8.2 Performance
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)