Diagrama UML - Módulo Venta
Origin: produced by the original Mi Plante team. Received via the project repo (
files-they-shareme/DIAGRAMA_VENTA_UML.md). This is the most authoritative source on the intended class structure, method signatures, and relationships for the Venta module.How to use it: read this FIRST to understand architectural intent for sales. Then read
docs/onboarding/02-codebase-tour/03-trace-a-sale.mdto see how the runtime actually behaves. Compare. The trace doc is grounded in the audit (docs/audit/16-deep-validation-study.md), which validated the runtime against the code — so when the UML and the trace disagree, the trace doc reflects what production does today; the UML reflects what was designed.Confirmed by this diagram: the
Venta -> VentaDetalle -> Precio -> Producto -> Empresachain,OrdenCompra -> Venta -> Cuotahierarchy,VentaServiceorchestration withCerticamaraServiceinjection, the 8-valueEstadoVentaenum, the 4-valueOrdenCompraEstadoenum.See also:
docs/audit/01-er-diagram.md(full DB-level ER, 38 tables)docs/audit/08-sale-lifecycle-state-machine.md(state transitions in runtime)docs/onboarding/media/diagrams/sale-lifecycle.mmd(pedagogical state machine)docs/onboarding/media/diagrams/er-spine.mmd(simplified ER for onboarding)docs/onboarding/04-the-landmines/01-known-bugs.md— landmines inVentaService,ProcesarPagareDigital,GenerarCreditoDeVenta
classDiagram
class Venta {
-int id
-string id_externo
-int orden_compra_id
-int user_id
-int empleado_id
-int sucursal_id
-float subtotal
-float descuento_aplicado
-float total
-int numero_cuotas
-string causal
-EstadoVenta estado
-bool es_indeterminado
-string observaciones
-timestamp creado_en
-timestamp actualizado_en
+ordenCompra() BelongsTo
+user() BelongsTo
+empleado() BelongsTo
+sucursal() BelongsTo
+detalles() HasMany
+cuotas() HasMany
+ventasRelacionadas() HasMany
+scopeAprobadas() Scope
}
class VentaDetalle {
-int id
-int venta_id
-int precio_id
-float descuento_aplicado
-string descriptor
-float monto
-int cantidad
-timestamp creado_en
-timestamp actualizado_en
+venta() BelongsTo
+precio() BelongsTo
}
class EstadoVenta {
<<enumeration>>
PENDIENTE
APROBADA
ENTREGADA
DEVUELTA
LEGALIZADA
COMPLETADA
RECHAZADA
ABANDONADA
+values() static array
+label() string
+color() string
}
class VentaService {
-CerticamaraService certicamaraService
+obtenerVentas(filtros) LengthAwarePaginator
+obtenerVenta(id) Venta
+crearVenta(dto) Venta|Collection
+crearVentaUnica(dto, precios, subtotal, cliente, esIndeterminado) Venta
+crearVentasPorEmpresa(dto, precios, subtotal, cliente, esIndeterminado) Venta|Collection
+eliminarVenta(id) bool
+obtenerDetallesVenta(ventaId) Collection
+calcularTotalVenta(ventaId) float
+actualizarTotalVenta(ventaId) void
+generarCuotas(venta) void
+generarCuotasPorOrden(ordenCompra, ventas, numeroCuotas) void
+obtenerNumeroCuotasPorLineas(ventaId) int
+actualizarEstado(venta, nuevoEstado) Venta
+actualizar(venta, dto) Venta
+estadisticasMensuales(sucursalId) array
+estadisticasPorRango(sucursalId, fechaInicio, fechaFin) array
-registrarEnCerticamara(cliente, dto) bool
}
class CerticamaraService {
+crearPagare(datos) array
+verificarPagare(uuid) array
}
class OrdenCompra {
-int id
-int user_id
-OrdenCompraEstado estado
-float subtotal
-float descuento_aplicado
-float total
-string observaciones
-timestamp creado_en
-timestamp actualizado_en
+user() BelongsTo
+ventas() HasMany
+beneficiario() HasOne
}
class OrdenCompraEstado {
<<enumeration>>
PENDIENTE
PROCESADA
RECHAZADA
ABANDONADA
+values() static array
+label() string
}
class Cuota {
-int id
-int orden_compra_id
-int venta_id
-int numero_cuota
-float monto
-float monto_fianza
-float monto_pagado
-float interes
-float monto_seguro_vida
-EstadoCuota estado
-date fecha_vencimiento
-date fecha_pago
-string observaciones
+venta() BelongsTo
+getSaldoPendienteAttribute() float
+isPagada() bool
+isPendiente() bool
+isVencida() bool
+isParcial() bool
+marcarComoVencidaSiCorresponde() void
}
class EstadoCuota {
<<enumeration>>
PENDIENTE
PAGADA
VENCIDA
PARCIAL
}
class Sucursal {
-int id
-int empresa_id
-string nombre_oficial
-string nombre_interno
-string direccion
-string telefono
-string ciudad
+empresa() BelongsTo
+users() BelongsToMany
}
class User {
-int id
-int persona_id
-string nombres
-string apellidos
-string telefono
-date fecha_nacimiento
-string direccion
-string email
-timestamp email_verified_at
-string password
-string guard
+persona() BelongsTo
+carrito() HasMany
+listaDeseos() HasMany
+cliente() HasOne
+empresas() BelongsToMany
+sucursales() BelongsToMany
+compras() HasMany
}
class Precio {
-int id
-int producto_id
-string nombre
-string descripcion
-float precio
-int inventario
-int alerta_inventario
-timestamp eliminado_en
-timestamp creado_en
-timestamp actualizado_en
+producto() BelongsTo
+ventasDetalles() HasMany
}
class Producto {
-int id
-int empresa_id
-int linea_id
-string slug
-string nombre
-string descripcion
-string tipo_producto
-string sku
-json caracteristicas
-timestamp creado_en
-timestamp actualizado_en
+empresa() BelongsTo
+linea() BelongsTo
+precios() HasMany
}
class Empresa {
-int id
-string nombre
-string razon_social
-EmpresaType tipo
-string identificacion
-string tipo_identificacion
-string telefono
-string estado
-string canal_venta
-timestamp creado_en
-timestamp actualizado_en
+lineas() HasMany
+productos() HasMany
+sucursales() HasMany
+users() BelongsToMany
}
class Cliente {
-int id
-int user_id
-string direccion
-string barrio
-string ciudad
-string departamento
-int numero_contrato
-string estrato
-string ciclo
-float valor_promedio
-int dia_pago
-decimal cupo_asignado
-decimal cupo_disponible
-string estado_cuenta
-string certicamara_uuid
-timestamp pagare_firmado_en
-timestamp puede_intentar_firmar_pagare_en
-int acepta_terminos_condiciones
-int acepta_cobro_factura
-timestamp creado_en
-timestamp actualizado_en
+user() BelongsTo
}
class Beneficiario {
-int id
-int compra_id
-string primer_nombre
-string primer_apellido
-string segundo_apellido
-string tipo_identificacion
-string numero_identificacion
-BeneficiarioParentescto parentesco
-timestamp creado_en
-timestamp actualizado_en
+compra() BelongsTo
+getNombreCompletoAttribute() string
}
class BeneficiarioParentescto {
<<enumeration>>
}
class EmpresaType {
<<enumeration>>
}
Venta "1" --> "1" OrdenCompra : orden_compra_id
Venta "1" --> "1" User : user_id (cliente)
Venta "1" --> "1" User : empleado_id (aliado)
Venta "1" --> "1" Sucursal : sucursal_id
Venta "1" --> "*" VentaDetalle : detalles
Venta "1" --> "*" Cuota : cuotas
Venta "1" --> "*" Venta : ventasRelacionadas
VentaDetalle "1" --> "1" Venta : venta_id
VentaDetalle "1" --> "1" Precio : precio_id
Venta "1" --|> EstadoVenta : estado
OrdenCompra "1" --> "1" User : user_id
OrdenCompra "1" --> "*" Venta : ventas
OrdenCompra "1" --|> OrdenCompraEstado : estado
OrdenCompra "1" --> "*" Cuota : cuotas maestras
OrdenCompra "1" --> "1" Beneficiario : beneficiario
Cuota "1" --> "1" Venta : venta_id
Cuota "*" --> "1" OrdenCompra : orden_compra_id
Cuota "1" --|> EstadoCuota : estado
Sucursal "1" --> "1" Empresa : empresa_id
Sucursal "*" --|> "*" User : users
User "1" --> "*" OrdenCompra : compras
User "1" --> "1" Cliente : cliente
Precio "1" --> "1" Producto : producto_id
Producto "1" --> "1" Empresa : empresa_id
Producto "1" --> "*" Precio : precios
Empresa "1" --> "*" Sucursal : sucursales
Empresa "1" --> "*" Producto : productos
Empresa "*" --|> "*" User : users
Beneficiario "1" --> "1" OrdenCompra : compra_id
Beneficiario "1" --|> BeneficiarioParentescto : parentesco
Cliente "1" --|> EmpresaType : tipo
Empresa "1" --|> EmpresaType : tipo
VentaService --> Venta : manipula
VentaService --> VentaDetalle : manipula
VentaService --> OrdenCompra : manipula
VentaService --> Cuota : manipula
VentaService "1" --> "1" CerticamaraService : utiliza
Descripción de Relaciones
Modelo Venta
- HasMany → VentaDetalle: Una venta tiene muchos detalles (productos)
- HasMany → Cuota: Una venta genera múltiples cuotas de pago
- HasMany → Venta: Relaciona ventas de la misma orden de compra
- BelongsTo → OrdenCompra: Cada venta pertenece a una orden de compra
- BelongsTo → User: Venta realizada por un usuario cliente
- BelongsTo → User (empleado): Aliado que generó la venta
- BelongsTo → Sucursal: Sucursal donde se realizó la venta
- Cast → EstadoVenta: El estado siempre es un enum
Modelo VentaDetalle
- BelongsTo → Venta: Pertenece a una venta específica
- BelongsTo → Precio: Referencia al precio del producto
Modelo OrdenCompra
- HasMany → Venta: Una orden de compra puede generar múltiples ventas (una por empresa/sucursal)
- HasMany → Cuota: Cuotas maestras a nivel de orden
- BelongsTo → User: Usuario que realizó la orden
- Cast → OrdenCompraEstado: Estados: PENDIENTE, PROCESADA, RECHAZADA, ABANDONADA
Modelo Cuota
- BelongsTo → Venta: Cuota asociada a una venta específica (puede ser nula para cuotas maestras)
- BelongsTo → OrdenCompra: Cuota asociada a una orden de compra
- Cast → EstadoCuota: Estados: PENDIENTE, PAGADA, VENCIDA, PARCIAL
- Métodos de verificación: isPagada(), isPendiente(), isVencida(), isParcial()
- Cálculo automático: saldo pendiente y marcado de vencimiento
Modelo Sucursal
- BelongsTo → Empresa: Sucursal pertenece a una empresa
- BelongsToMany → User: Relación muchos-a-muchos con usuarios
Modelo User
- HasMany → OrdenCompra: Usuario realiza múltiples órdenes de compra
- BelongsToMany → Empresa: Relación muchos-a-muchos
- BelongsToMany → Sucursal: Relación muchos-a-muchos
VentaService
- Orquesta toda la lógica de negocio
- Crea ventas individuales o múltiples (por empresa)
- Genera cuotas de pago a nivel de venta y orden
- Calcula estadísticas (mensuales y por rango)
- Integra con CerticamaraService para pagarés digitales
CerticamaraService
- Crea pagarés digitales en la plataforma Certicámara
- Verifica el estado de pagarés creados
- Se inyecta por dependencia en VentaService
- Maneja la comunicación con la API de Certicámara
Modelo Cliente
- BelongsTo → User: Datos adicionales del cliente vinculados a un usuario
- Contiene información de ubicación, contrato, cupo, y datos de pagaré
- Relación 1-a-1 con User
- Gestiona estado de cuenta y cupo disponible
Modelo Beneficiario
- BelongsTo → OrdenCompra: Beneficiario asociado a una orden de compra
- Cast → BeneficiarioParentescto: Define relación (hijo, cónyuge, etc.)
- Contiene datos de identificación del beneficiario
- Método para obtener nombre completo
Modelo Producto
- BelongsTo → Empresa: Producto pertenece a una empresa
- BelongsTo → Linea: Clasificación por línea
- HasMany → Precio: Un producto puede tener múltiples precios/variantes
- Contiene SKU, características y descripción
Modelo Precio
- BelongsTo → Producto: Referencia al producto padre
- HasMany → VentaDetalle: Detalle de precios en ventas
- Maneja inventario y alertas
- Soft delete habilitado
Modelo Empresa
- HasMany → Producto: Empresa produce múltiples productos
- HasMany → Sucursal: Empresa tiene múltiples sucursales
- BelongsToMany → User: Relación muchos-a-muchos con usuarios
- HasMany → Linea: Productos organizados por líneas
- Cast → EmpresaType: Tipo de empresa (mayorista, distribuidor, etc.)
Flujo de Creación de Ventas
User (Cliente) → OrdenCompra → Venta(s) → VentaDetalle(s) → Cuota(s) ↓ Certicamara (Pagaré Digital)- Cliente realiza una orden de compra
- Se crea una OrdenCompra vinculada al usuario
- Si los productos son de múltiples empresas, se crean múltiples Ventas (una por empresa/sucursal)
- Cada Venta tiene VentaDetalles (productos específicos)
- Se generan Cuotas a nivel de orden y se distribuyen por venta
- Se registra un pagaré digital en Certicámara si aplica