# Plan: Órdenes de Venta (Pedidos Internos)

**Fecha**: 2026-05-04  
**Actualizado**: 2026-05-05  
**Estado**: Fase 1–3 implementadas · Fase 4 pendiente

---

## Estado de implementación

| Fase | Descripción | Estado |
|------|-------------|--------|
| 1A | Migración SQL (enum + columnas) | ✅ Aplicada en BD |
| 1B | Schema Prisma + relación `condicion_pago` | ✅ |
| 1C | DTOs + Endpoints CRUD (crear, listar, detalle, editar) | ✅ |
| 1D | Endpoint confirmar (estado machine, auto-aprobación) | ✅ |
| 1E | Endpoint cancelar | ✅ |
| 2A | Endpoint aprobar | ✅ |
| 2B | Endpoint facturar (total) | ⏳ pendiente |
| 2C | Cron de vencimiento | ⏳ pendiente |
| 2D | Endpoint PDF vía msv-kude | ✅ |
| 3A | `ordenes.service.js` (API client) | ✅ |
| 3B | `OrdenesVentaTab.jsx` — lista con KPIs, filtros, responsive | ✅ |
| 3C | `OrdenVentaNueva.jsx` (formulario creación/edición) | ✅ |
| 3D | Tab en `Ventas.jsx` | ✅ |
| 4A | Anticipo (cobro a cuenta vinculado) | ⏳ pendiente |
| 4B | Facturación parcial por ítem | ⏳ pendiente |
| 4C | Notificaciones de vencimiento próximo | ⏳ pendiente |
| 4D | Configuraciones en pantalla empresa/sucursal | ⏳ pendiente |

### Pendiente crítico
- **`orden_tipo_facturacion`** (columna en `empresas`): migración `20260504_orden_tipo_facturacion` creada pero NO aplicada aún. Diferido por bug de Prisma con locale español que oculta el nombre del campo en errores FK. Aplicar y re-agregar a schema + service + DTO + `OrdenesVentaConfigTab` cuando se retome.

---

## Decisiones de diseño (Q&A confirmado)

| # | Tema | Decisión |
|---|------|----------|
| Q1 | Stock | Reserva **configurable por sucursal** (`orden_reserva_stock: boolean`) |
| Q2 | Facturación parcial | **Opciones B + C + Total**: parcial por ítem, parcial por monto, o total |
| Q3 | Estados | Enum en BD y código: `borrador → confirmada → aprobada → en_proceso → facturada_parcial → facturada → cancelada → vencida` |
| Q4 | Vencimiento | Cron que marca `vencida` y libera reservas, con notificación visual |
| Q5 | Aprobación | Configurable por empresa: `orden_requiere_aprobacion: boolean` + `orden_monto_aprobacion: number` |
| Q6 | Precios | Toma precio al momento de confirmar |
| Q7 | Anticipos | Anticipo registrado como cobro a cuenta vinculado a la orden |
| Q8 | Tabla | Extender tabla `pedidos` existente con columnas nuevas |
| Q9 | Numeración | `tipo_documento` código **200** — asignado server-side al confirmar |
| Q10 | Entrada / PDF | Desde módulo **Ventas** (tab). PDF A4 vía msv-kude |
| Q11 | Auto-aprobación | Si `orden_requiere_aprobacion = false` → confirmar va directo a `aprobada` (no `en_proceso`) |
| Q12 | `condicion_pago` | FK a `condiciones_pago` (por empresa), columna `condicion_pago_id`. Distinto de `condicion_operacion_id` (SIFEN global) |

---

## Arquitectura

### Por qué extender `pedidos` y no tabla nueva

La tabla `pedidos` ya tiene:
- `tipo_pedido` enum (`pedido_tipo`) — valor `orden_venta` agregado ✅
- Métodos de stock: `reservarStockPedido`, `liberarReservasPedido`, `descontarStockPedido`
- Estados (`confirmar`, `cancelar`, `marcarFacturado`) — extendidos ✅
- Relación con `factura_cab` (facturación parcial ya contemplada con `pedido_id`)

---

## Cambios de BD (✅ aplicados)

### Migración `20260504_ordenes_venta`
- Enum `pedido_tipo` → valor `orden_venta` agregado
- Enum `pedido_estado` creado
- Columnas en `pedidos`: `estado_orden`, `precio_tomado_al_confirmar`, `requiere_aprobacion`, `aprobado_por`, `fecha_aprobacion`, `fecha_venc_orden`, `monto_anticipo`, `monto_facturado`, `stock_reservado`, `numero_pedido`, `condicion_operacion_id`
- Índices en `estado_orden` y `tipo_pedido`

### Migración `20260504_pedidos_condicion_pago` ✅
```sql
ALTER TABLE pedidos
  ADD COLUMN IF NOT EXISTS condicion_pago_id UUID REFERENCES condiciones_pago(id) ON DELETE SET NULL;
CREATE INDEX IF NOT EXISTS idx_pedidos_condicion_pago ON pedidos(condicion_pago_id);
```

### Migración `20260504_orden_tipo_facturacion` ⏳ NO aplicada
```sql
ALTER TABLE empresas ADD COLUMN IF NOT EXISTS orden_tipo_facturacion VARCHAR(20) DEFAULT 'total';
```

### Config por empresa/sucursal ⏳ pendiente
```sql
ALTER TABLE empresa_configuracion
  ADD COLUMN IF NOT EXISTS orden_requiere_aprobacion BOOLEAN DEFAULT false,
  ADD COLUMN IF NOT EXISTS orden_monto_aprobacion NUMERIC(18,2) DEFAULT 0;

ALTER TABLE sucursal
  ADD COLUMN IF NOT EXISTS orden_reserva_stock BOOLEAN DEFAULT false;
```

### Tabla `pedido_facturacion_parcial` ⏳ pendiente
```sql
CREATE TABLE IF NOT EXISTS pedido_facturacion_parcial (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  pedido_id UUID NOT NULL REFERENCES pedidos(id) ON DELETE CASCADE,
  factura_id UUID NOT NULL REFERENCES factura_cab(id) ON DELETE RESTRICT,
  monto_facturado NUMERIC(18,2) NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);
```

---

## Backend (NestJS) — estado actual

### Archivos implementados ✅
| Archivo | Estado |
|---------|--------|
| `prisma/migrations/20260504_ordenes_venta/migration.sql` | ✅ |
| `prisma/migrations/20260504_pedidos_condicion_pago/migration.sql` | ✅ |
| `prisma/schema.prisma` — enum + model `pedidos` + relación `condicion_pago` | ✅ |
| `src/pedidos/pedidos.service.ts` — `crearOrden`, `findAllOrdenes`, `findOneOrden`, `updateOrden`, `confirmarOrden`, `aprobarOrden`, `cancelarOrden`, `statsOrdenes` | ✅ |
| `src/pedidos/ordenes-venta.controller.ts` — 8 endpoints incl. `GET /stats` | ✅ |
| `src/pedidos/dto/create-orden-venta.dto.ts` — con `condicion_pago_id` | ✅ |
| `src/pedidos/dto/query-ordenes-venta.dto.ts` | ✅ |

### Lógica de confirmación implementada ✅
1. Asigna número via `reservarNumeroPedido()`
2. Si `requiereAprobacion` → estado `CONFIRMADA` (espera supervisor)
3. Si no requiere aprobación → estado `APROBADA` directamente
4. Reserva stock si `sucursal.orden_reserva_stock = true`
5. Fija precios al momento de confirmar

### Endpoints pendientes ⏳
```
POST /ordenes-venta/:id/facturar      ← generar factura(s) desde orden
GET  /ordenes-venta/:id/pdf           ← PDF A4 vía msv-kude
```

### Cron de vencimiento ⏳
```typescript
@Cron('0 6 * * *')
async vencerOrdenesExpiradas() { ... }
```

---

## Frontend (React) — estado actual

### Archivos implementados ✅
| Archivo | Estado |
|---------|--------|
| `src/api/ordenes.service.js` — CRUD + stats + confirmar/aprobar/cancelar | ✅ |
| `src/components/ventas/OrdenesVentaTab.jsx` — KPIs, chips de estado, filtros rápidos/avanzados, responsive (card mobile + tabla desktop) | ✅ |
| `src/pages/OrdenVentaNueva.jsx` — formulario creación/edición | ✅ |
| `src/pages/Ventas.jsx` — tab "Órdenes de Venta" | ✅ |

### Features del tab ✅
- KPI cards clickables (filtran por estado)
- Chips de fecha rápida: Hoy / Ayer / Esta semana / Este mes
- Panel de filtros avanzados: Fecha desde/hasta + Estado
- Chips de estado con contadores y tooltips descriptivos
- Columna Fecha con fecha + hora (hh:mm:ss)
- Búsqueda local por número y cliente
- Vista móvil: `OrdenCard` con layout vertical
- Vista desktop: tabla completa con 8 columnas
- Auto-aprobación reflejada en UI (estado `aprobada` sin pasar por `confirmada`)

### Pendiente ⏳
- `OrdenesStack.jsx` (TanStack queries centralizadas — actualmente inline en el componente)
- Detalle de orden con acciones de facturación
- Anticipo (modal cobro a cuenta)
- Facturación parcial por ítem
- PDF A4 (botón en detalle)
- Configuraciones empresa/sucursal en pantalla

---

## Verificación (checklist)

- [x] Migración SQL ejecutada sin errores
- [x] Crear orden → aparece en lista con estado `borrador`
- [x] Confirmar orden (sin aprobación) → estado `aprobada` directamente
- [x] Confirmar orden (con aprobación) → estado `confirmada`, botón aprobar visible
- [x] Aprobar orden → estado `aprobada`
- [x] Cancelar orden → estado `cancelada`
- [x] KPIs reflejan contadores y monto activo
- [x] Filtros de fecha y estado funcionan
- [x] Layout responsive (card en mobile, tabla en desktop)
- [ ] Facturar total → genera factura, estado `facturada`
- [ ] Facturar parcial por ítem → estado `facturada_parcial`, segunda factura → `facturada`
- [ ] Cron → orden con `fecha_venc_orden` pasada → estado `vencida`
- [ ] PDF A4 → se genera correctamente con datos de la orden
- [ ] Config `orden_reserva_stock = false` → confirmar no reserva stock
- [ ] `orden_tipo_facturacion` migración aplicada y UI configurada
