workspace-v1/projects/erp-retail/orchestration/planes/fase-2-analisis-modulos/ANALISIS-RT-002-pos.md
rckrdmrd 66161b1566 feat: Workspace-v1 complete migration with NEXUS v3.4
Sistema NEXUS v3.4 migrado con:

Estructura principal:
- core/orchestration: Sistema SIMCO + CAPVED (27 directivas, 28 perfiles)
- core/catalog: Catalogo de funcionalidades reutilizables
- shared/knowledge-base: Base de conocimiento compartida
- devtools/scripts: Herramientas de desarrollo
- control-plane/registries: Control de servicios y CI/CD
- orchestration/: Configuracion de orquestacion de agentes

Proyectos incluidos (11):
- gamilit (submodule -> GitHub)
- trading-platform (OrbiquanTIA)
- erp-suite con 5 verticales:
  - erp-core, construccion, vidrio-templado
  - mecanicas-diesel, retail, clinicas
- betting-analytics
- inmobiliaria-analytics
- platform_marketing_content
- pos-micro, erp-basico

Configuracion:
- .gitignore completo para Node.js/Python/Docker
- gamilit como submodule (git@github.com:rckrdmrd/gamilit-workspace.git)
- Sistema de puertos estandarizado (3005-3199)

Generated with NEXUS v3.4 Migration System
EPIC-010: Configuracion Git y Repositorios
2026-01-04 03:37:42 -06:00

12 KiB

ANALISIS MODULO RT-002: PUNTO DE VENTA (POS)

Fecha: 2025-12-18 Fase: 2 - Analisis por Modulo Modulo: RT-002 POS Herencia: 20% Story Points: 55 Prioridad: P0 (Critico)


1. DESCRIPCION GENERAL

1.1 Proposito

Terminal de punto de venta para operacion en tienda fisica con soporte offline, integracion de hardware y venta rapida en mostrador.

1.2 Funcionalidades Principales

Funcionalidad Descripcion Criticidad
Venta rapida Escaneo y cobro < 30s Critica
Modo offline Operacion sin internet Critica
Multi-pago Efectivo, tarjeta, mixto Alta
Descuentos Manuales y automaticos Alta
Hardware Impresora, lector, cajon Alta
Tickets Impresion automatica Alta

2. HERENCIA DEL CORE

2.1 Componentes Heredados (20%)

Componente Core Uso en POS
inventory.products Catalogo de productos
sales.pricelists Precios base
core.partners Clientes
auth.users Cajeros

2.2 Tablas Reutilizadas

Tabla Core Relacion
inventory.products FK en pos_order_lines.product_id
core.partners FK en pos_orders.customer_id
auth.users FK en pos_sessions.user_id
sales.pricelists Consulta de precios

3. COMPONENTES NUEVOS

3.1 Entidades (TypeORM)

// 1. POSSession - Sesion de caja
@Entity('pos_sessions', { schema: 'retail' })
export class POSSession {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column('uuid')
  tenantId: string;

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

  @ManyToOne(() => CashRegister)
  cashRegister: CashRegister;

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

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

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

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

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

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

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

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

// 2. POSOrder - Venta
@Entity('pos_orders', { schema: 'retail' })
export class POSOrder {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column('uuid')
  tenantId: string;

  @ManyToOne(() => POSSession)
  session: POSSession;

  @Column()
  orderNumber: string;

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

  @ManyToOne(() => Partner, { nullable: true })
  customer: Partner;

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

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

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

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

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

  @Column({ type: 'enum', enum: PaymentMethod })
  paymentMethod: PaymentMethod;

  @OneToMany(() => POSOrderLine, line => line.order)
  lines: POSOrderLine[];
}

// 3. POSOrderLine - Linea de venta
@Entity('pos_order_lines', { schema: 'retail' })
export class POSOrderLine {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @ManyToOne(() => POSOrder)
  order: POSOrder;

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

  @Column()
  productName: string;

  @Column({ nullable: true })
  barcode: string;

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

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

  @Column({ type: 'decimal', precision: 5, scale: 2, default: 0 })
  discountPercent: number;

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

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

3.2 Servicios Backend

Servicio Metodos Principales
POSSessionService openSession(), closeSession(), getActiveSession()
POSOrderService createOrder(), addLine(), removeLine(), applyDiscount(), pay()
POSPaymentService processPayment(), processMixedPayment(), refund()
POSPrintService printTicket(), openCashDrawer()
POSSyncService syncOfflineOrders(), resolveConflicts()

3.3 Controladores

@Controller('pos')
export class POSController {
  // Sessions
  @Post('sessions/open')
  openSession(@Body() dto: OpenSessionDto): Promise<POSSession>;

  @Post('sessions/:id/close')
  closeSession(@Param('id') id: string, @Body() dto: CloseSessionDto): Promise<POSSession>;

  @Get('sessions/active')
  getActiveSession(): Promise<POSSession>;

  // Orders
  @Post('orders')
  createOrder(@Body() dto: CreateOrderDto): Promise<POSOrder>;

  @Post('orders/:id/lines')
  addLine(@Param('id') id: string, @Body() dto: AddLineDto): Promise<POSOrderLine>;

  @Delete('orders/:id/lines/:lineId')
  removeLine(@Param('id') id: string, @Param('lineId') lineId: string): Promise<void>;

  @Post('orders/:id/discount')
  applyDiscount(@Param('id') id: string, @Body() dto: DiscountDto): Promise<POSOrder>;

  @Post('orders/:id/pay')
  pay(@Param('id') id: string, @Body() dto: PaymentDto): Promise<POSOrder>;

  // Products
  @Get('products/search')
  searchProducts(@Query('q') query: string): Promise<Product[]>;

  @Get('products/barcode/:code')
  getByBarcode(@Param('code') code: string): Promise<Product>;

  // Sync
  @Post('sync')
  syncOfflineOrders(@Body() dto: SyncDto): Promise<SyncResult>;
}

3.4 Frontend (PWA)

Pagina/Componente Descripcion
POSPage Pantalla principal de venta
ProductSearch Busqueda de productos
Cart Carrito de compra
PaymentModal Modal de pago
TicketPreview Vista previa de ticket
SessionStatus Estado de sesion
OfflineIndicator Indicador modo offline
HardwareStatus Estado de hardware

4. REQUERIMIENTOS TECNICOS

4.1 PWA y Modo Offline

pwa_config:
  manifest:
    name: "Retail POS"
    short_name: "POS"
    display: "fullscreen"
    orientation: "landscape"

  service_worker:
    cache_strategy: "cache-first"
    assets_to_cache:
      - "/pos/**"
      - "/api/products"
      - "/api/pricelists"

  indexed_db:
    stores:
      - products
      - prices
      - customers
      - offline_orders
      - pending_sync

  sync:
    strategy: "background-sync"
    retry_interval: "30s"
    max_retries: 10

4.2 Performance

Operacion Objetivo Implementacion
Busqueda producto < 50ms Indice + Cache Redis
Agregar al carrito < 100ms Operacion local
Calcular total < 10ms Calculo en memoria
Procesar pago < 3s Async + optimistic UI

4.3 Integracion Hardware

// Interfaz de Hardware
interface POSHardware {
  printer: TicketPrinter;
  scanner: BarcodeScanner;
  drawer: CashDrawer;
  cardReader?: CardReader;
}

// Impresora ESC/POS
interface TicketPrinter {
  connect(): Promise<boolean>;
  print(ticket: TicketData): Promise<void>;
  openDrawer(): Promise<void>;
  cut(): Promise<void>;
}

// Lector de codigo de barras
interface BarcodeScanner {
  onScan(callback: (barcode: string) => void): void;
}

5. TABLAS DDL

5.1 Tablas Nuevas

-- Ya definidas en 03-retail-tables.sql
CREATE TABLE retail.pos_sessions (...);
CREATE TABLE retail.pos_orders (...);
CREATE TABLE retail.pos_order_lines (...);
CREATE TABLE retail.pos_payments (...);
CREATE TABLE retail.cash_registers (...);

5.2 ENUMs

CREATE TYPE retail.pos_session_status AS ENUM ('opening', 'open', 'closing', 'closed');
CREATE TYPE retail.pos_order_status AS ENUM ('draft', 'paid', 'done', 'cancelled', 'refunded');
CREATE TYPE retail.payment_method AS ENUM ('cash', 'card', 'transfer', 'credit', 'mixed');

5.3 Indices Criticos

-- Performance para busqueda
CREATE INDEX idx_pos_orders_session ON retail.pos_orders(session_id);
CREATE INDEX idx_pos_orders_date ON retail.pos_orders(order_date);
CREATE INDEX idx_pos_order_lines_order ON retail.pos_order_lines(order_id);
CREATE INDEX idx_pos_order_lines_product ON retail.pos_order_lines(product_id);

-- Busqueda por codigo de barras
CREATE INDEX idx_product_barcodes_code ON retail.product_barcodes(barcode);

6. DEPENDENCIAS

6.1 Dependencias de Core

Modulo Requerido Para
MGN-001 Auth Autenticacion cajeros
MGN-011 Inventory Productos y stock
MGN-013 Sales Precios
MGN-005 Catalogs Partners (clientes)

6.2 Dependencias de Retail

Modulo Tipo
RT-001 Fundamentos Prerequisito
RT-003 Inventario Stock por sucursal
RT-006 Precios Promociones
RT-005 Clientes Programa lealtad

6.3 Dependencias Externas

Servicio Proposito
Redis Cache de productos
WebSocket Sync tiempo real

7. FLUJOS DE NEGOCIO

7.1 Flujo de Venta

1. Cajero abre sesion (fondo inicial)
      ↓
2. Cliente presenta productos
      ↓
3. Escanear/buscar productos
      ↓
4. Agregar al carrito
      ↓
5. Aplicar descuentos (si aplica)
      ↓
6. Seleccionar forma de pago
      ↓
7. Procesar pago
      ↓
8. Imprimir ticket
      ↓
9. Abrir cajon (si efectivo)
      ↓
10. Entregar cambio y productos

7.2 Flujo Offline

1. Detectar perdida de conexion
      ↓
2. Activar modo offline
      ↓
3. Usar cache local (IndexedDB)
      ↓
4. Almacenar ventas en cola
      ↓
5. Detectar reconexion
      ↓
6. Sincronizar cola con servidor
      ↓
7. Resolver conflictos (si existen)
      ↓
8. Confirmar sincronizacion

8. CRITERIOS DE ACEPTACION

8.1 Funcionales

  • Abrir sesion con fondo inicial
  • Buscar productos por nombre/SKU
  • Escanear codigo de barras
  • Agregar/quitar productos del carrito
  • Calcular subtotal, descuento, impuesto, total
  • Aplicar descuento manual (con limite)
  • Procesar pago efectivo con cambio
  • Procesar pago tarjeta
  • Procesar pago mixto
  • Imprimir ticket automaticamente
  • Cerrar sesion con arqueo

8.2 Modo Offline

  • Funcionar sin conexion 24+ horas
  • Cache de productos disponible
  • Almacenar ventas localmente
  • Sincronizar al reconectar
  • No perder transacciones

8.3 Performance

  • Busqueda < 50ms
  • Calculo totales < 10ms
  • Registro venta < 100ms
  • Venta completa < 30s

9. RIESGOS

Riesgo Probabilidad Impacto Mitigacion
PWA complejo Alta Alto Spike tecnico primero
Hardware variado Media Medio Drivers genericos
Sync conflicts Media Alto Estrategia last-write-wins
Performance Media Critico Indices + Cache

10. ESTIMACION DETALLADA

Componente SP Backend SP Frontend Total
Entities + Migrations 3 - 3
POSSessionService 5 - 5
POSOrderService 8 - 8
POSPaymentService 5 - 5
POSController 3 - 3
PWA Setup - 5 5
POSPage + Cart - 8 8
PaymentModal - 3 3
Offline Sync 5 5 10
Hardware Integration 5 - 5
TOTAL 34 21 55

11. REFERENCIAS

Documento Ubicacion
Epica RT-002 docs/08-epicas/EPIC-RT-002-pos.md
Modulo definicion docs/02-definicion-modulos/RT-002-pos/
DDL Retail database/init/03-retail-tables.sql
Directiva POS orchestration/directivas/DIRECTIVA-PUNTO-VENTA.md

Estado: ANALISIS COMPLETO Bloqueado por: RT-001 Fundamentos, RT-006 Precios