erp-core/docs/05-user-stories/mgn-007/US-MGN-007-002-001-crear-sales-order-desde-cotizacion.md

8.6 KiB

US-MGN-007-002-001: Crear Sales Order desde Cotización

RF Asociado: RF-MGN-007-002 Módulo: MGN-007 - Ventas Básico Epic: Órdenes de Venta Prioridad: P0 Story Points: 5 Sprint: Sprint 16 Estado: Ready for Development Fecha: 2025-11-24


User Story

Como vendedor, Quiero convertir una cotización confirmada en una orden de venta (Sales Order), Para formalizar la venta y poder continuar con entregas y facturación.


Descripción Detallada

Una Sales Order (SO) es el documento formal que confirma la venta. Se crea desde una cotización aceptada copiando:

  • Datos del cliente
  • Líneas de productos con cantidades y precios
  • Descuentos e impuestos
  • Términos de pago
  • Fecha de entrega esperada

Estados de SO: draft, confirmed, done (entregado y facturado), cancelled.

La conversión de cotización → SO:

  1. Valida que cotización esté en estado sent o draft
  2. Crea nueva SO copiando todos los datos
  3. Genera número secuencial SO/YYYY/NNNN
  4. Cambia estado de cotización a sale (convertida)
  5. Vincula quotation_id en sales.orders

Criterios de Aceptación

Escenario 1: Convertir cotización a SO (Camino Feliz)

Dado que cotización id=1 está en estado sent con total=1000, Cuando ejecuto action "Convert to Sales Order", Entonces sistema crea SO con número SO/2024/0001, copia todas las líneas, marca cotización como sale, vincula quotation_id=1.

Escenario 2: Validar que cotización no está convertida

Dado que cotización ya está en estado sale (convertida), Cuando intento convertir nuevamente, Entonces sistema retorna error 400 "Cotización ya fue convertida a orden de venta".

Escenario 3: Validar que cotización no está cancelada

Dado que cotización está en estado cancelled, Cuando intento convertir, Entonces sistema retorna error 400 "No se puede convertir cotización cancelada".

Escenario 4: Copiar líneas correctamente

Dado que cotización tiene 3 líneas con productos, cantidades, precios, Cuando se convierte a SO, Entonces sistema copia las 3 líneas manteniendo todos los valores exactos.

Escenario 5: Generar número secuencial de SO

Dado que última SO fue SO/2024/0005, Cuando creo nueva SO desde cotización, Entonces sistema genera número SO/2024/0006.

Escenario 6: Vincular cotización y SO

Dado que cotización id=1 se convierte a SO id=10, Cuando se completa conversión, Entonces SO.quotation_id=1 y Quotation.state=sale.


Reglas de Negocio

  • RN-1: Solo cotizaciones en draft o sent pueden convertirse.
  • RN-2: Una cotización solo puede convertirse una vez.
  • RN-3: SO se crea en estado draft inicialmente.
  • RN-4: Número secuencial: SO/{year}/{seq:04d}.
  • RN-5: Todos los datos (líneas, impuestos, descuentos, totales) se copian exactamente.
  • RN-6: Estado de cotización cambia a sale (no editable después).
  • RN-7: Se crea mensaje en chatter: "Cotización convertida a SO/2024/NNNN".

Tareas Técnicas

Backend

  • Endpoint: POST /api/v1/sales/quotations/:id/convert-to-order
  • Service: QuotationService.convertToSalesOrder(id)
  • Service: SalesOrderService.createFromQuotation(quotation)
  • Validar estado de cotización (draft o sent)
  • Validar que no esté ya convertida
  • Copiar header de cotización
  • Copiar líneas con todos los campos
  • Generar número secuencial SO
  • Actualizar quotation.state = sale
  • Crear mensaje en chatter
  • Unit tests (>80%)
  • Integration tests
  • Swagger docs

Frontend

  • Botón: "Convert to Sales Order" en vista de cotización
  • Confirmación modal antes de convertir
  • Navegación automática a SO creada después de conversión
  • API client: quotationApi.convertToOrder(id)
  • Notificación toast de éxito
  • Deshabilitar botón si ya está convertida
  • Component tests
  • E2E test: "should convert quotation to sales order"

Database

  • Tabla: sales.orders (id, company_id, quotation_id, number, customer_id, state, total)
  • Tabla: sales.order_lines (id, order_id, product_id, quantity, price_unit, subtotal)
  • FK: sales.orders.quotation_id → sales.quotations.id
  • Índices: idx_orders_quotation_id, idx_orders_customer_id, idx_orders_state
  • RLS policy: company_isolation_sales_orders

Mockups / Wireframes

Vista Cotización con botón Convertir:

┌─────────────────────────────────────────────┐
│ Cotización QT/2024/0001     [sent]          │
├─────────────────────────────────────────────┤
│ Cliente: ABC Corp                           │
│ Total: $1,000.00                            │
│                                             │
│ [Líneas de productos...]                    │
├─────────────────────────────────────────────┤
│ [Edit] [Send Email] [Convert to SO] [Cancel]│
└─────────────────────────────────────────────┘

Modal de Confirmación:

┌─────────────────────────────────────────────┐
│ Confirmar Conversión                        │
├─────────────────────────────────────────────┤
│ ¿Desea convertir la cotización QT/2024/0001│
│ en una orden de venta?                      │
│                                             │
│ Esta acción:                                │
│ • Creará una nueva Sales Order              │
│ • Marcará la cotización como convertida     │
│ • No es reversible                          │
│                                             │
│ [Confirmar] [Cancelar]                      │
└─────────────────────────────────────────────┘

Casos de Prueba

Funcionales

  1. TC-001: Convertir cotización sent exitosamente
  2. TC-002: Convertir cotización draft exitosamente
  3. TC-003: Error al convertir cotización ya convertida
  4. TC-004: Error al convertir cotización cancelada
  5. TC-005: Todas las líneas se copian correctamente
  6. TC-006: Totales coinciden entre cotización y SO
  7. TC-007: Número secuencial se genera correctamente
  8. TC-008: quotation_id se vincula correctamente
  9. TC-009: Estado de cotización cambia a sale
  10. TC-010: Mensaje se crea en chatter

No Funcionales

  1. Performance: < 500ms para convertir cotización con 20 líneas
  2. Seguridad: JWT + permiso sales_user

Dependencias

  • US bloqueantes:
    • US-MGN-007-001-001 (Crear Cotización)
  • Módulos requeridos: MGN-003 (Partners), MGN-005 (Productos)

Notas de Implementación

  • Usar transacción para garantizar atomicidad (crear SO + actualizar quotation)
  • Copiar campos: customer_id, payment_term_id, delivery_date, notes, etc.
  • Validar que productos de las líneas sigan existiendo y activos
  • Considerar copiar también adjuntos de la cotización
  • Frontend: Mostrar toast con link a nueva SO creada

Estimación Detallada

Tarea Horas
Backend 2.5
Frontend 1.5
Testing 2
Code Review 1
TOTAL 7 horas = 5 SP

Definition of Done

  • Código implementado según ET
  • Tests pasando (>80%)
  • Code review aprobado
  • Conversión funciona correctamente
  • Validaciones aplicadas
  • Número secuencial generado
  • Estado de cotización actualizado
  • Mensaje en chatter creado
  • Swagger docs actualizado
  • QA validado
  • PO aprobado

Referencias