# MODELO DE DOMINIO: Ventas **Módulos:** MGN-007 (Ventas Básico) **Fecha:** 2025-11-24 **Referencia Odoo:** sale **Referencia Gamilit:** sales_management schema --- ## Diagrama de Entidades (Texto UML) ``` [SaleOrder] - id: UUID (PK) - tenant_id: UUID (FK) - company_id: UUID (FK) - partner_id: UUID (FK) - name: String - order_date: Date - validity_date: Date - expected_date: Date - status: ENUM (draft, sent, sale, done, cancelled) - amount_total: Decimal - amount_invoiced: Decimal - invoice_status: ENUM (to_invoice, invoiced) - delivery_status: ENUM (to_deliver, delivered) 1 <----> * [SaleOrderLine] 1 <----> * [Invoice] 1 <----> * [Picking] [SaleOrderLine] - id: UUID (PK) - order_id: UUID (FK) - product_id: UUID (FK) - description: String - quantity: Decimal - price_unit: Decimal - discount: Decimal - tax_ids: UUID[] - subtotal: Decimal - total: Decimal - analytic_account_id: UUID (FK) - qty_delivered: Decimal - qty_invoiced: Decimal [Quotation] - id: UUID (PK) - tenant_id: UUID (FK) - company_id: UUID (FK) - partner_id: UUID (FK) - name: String - date: Date - validity_date: Date - status: ENUM (draft, sent, approved, rejected, converted) - amount_total: Decimal - terms_conditions: Text - signature: String (base64) - signature_date: Timestamp 1 <----> * [SaleOrder] (conversión) [PaymentTerm] - id: UUID (PK) - tenant_id: UUID (FK) - name: String - days: Integer - description: Text [PriceList] - id: UUID (PK) - tenant_id: UUID (FK) - name: String - currency_id: UUID (FK) - active: Boolean 1 <----> * [PriceListItem] [PriceListItem] - id: UUID (PK) - pricelist_id: UUID (FK) - product_id: UUID (FK) - price: Decimal - min_quantity: Decimal ``` ## Entidades Principales ### 1. SaleOrder (Orden de Venta) **Descripción:** Orden de venta confirmada a cliente. **Atributos:** - `id`: UUID - `partner_id`: Cliente - `name`: Número de orden (ej: "SO001") - `order_date`: Fecha de orden - `validity_date`: Fecha de validez (opcional) - `expected_date`: Fecha esperada de entrega - `status`: draft, sent, sale, done, cancelled - `amount_total`: Monto total - `invoice_status`: to_invoice, invoiced - `delivery_status`: to_deliver, delivered **Relaciones:** - 1 SaleOrder → N SaleOrderLines - 1 SaleOrder → N Invoices - 1 SaleOrder → N Pickings **Patrón Odoo:** sale.order **Estados:** - draft: Borrador (editable) - sent: Enviada a cliente - sale: Confirmada (genera picking) - done: Completada (entregada y facturada) - cancelled: Cancelada ### 2. SaleOrderLine (Línea de Orden de Venta) **Descripción:** Línea de producto/servicio en orden de venta. **Atributos:** - `id`: UUID - `order_id`: Orden propietaria - `product_id`: Producto - `description`: Descripción - `quantity`: Cantidad ordenada - `price_unit`: Precio unitario - `discount`: Descuento (%) - `tax_ids`: Impuestos aplicados - `subtotal`: Subtotal sin impuestos - `total`: Total con impuestos - `qty_delivered`: Cantidad entregada - `qty_invoiced`: Cantidad facturada **Relaciones:** - N SaleOrderLines → 1 SaleOrder **Patrón Odoo:** sale.order.line **Cálculo:** total = ((quantity * price_unit) * (1 - discount/100)) + taxes ### 3. Quotation (Cotización) **Descripción:** Cotización enviada a cliente (pre-orden). **Atributos:** - `id`: UUID - `partner_id`: Cliente potencial - `name`: Número de cotización - `date`: Fecha de emisión - `validity_date`: Fecha de expiración - `status`: draft, sent, approved, rejected, converted - `amount_total`: Monto total - `terms_conditions`: Términos y condiciones - `signature`: Firma electrónica (base64) - `signature_date`: Fecha/hora de firma **Relaciones:** - 1 Quotation → 1 SaleOrder (conversión) **Patrón Odoo:** sale.order (state=draft/sent) **Flujo:** 1. Crear quotation 2. Enviar a cliente (sent) 3. Cliente aprueba/firma (approved) 4. Convertir a sale order (converted) ### 4. PaymentTerm (Término de Pago) **Descripción:** Condiciones de pago para cliente. **Atributos:** - `id`: UUID - `name`: Nombre (ej: "30 días") - `days`: Días de plazo - `description`: Descripción **Relaciones:** - 1 PaymentTerm → N SaleOrders **Patrón Odoo:** account.payment.term **Términos comunes:** - Inmediato (0 días) - 15 días - 30 días - 60 días ### 5. PriceList (Lista de Precios) **Descripción:** Lista de precios por cliente o segmento. **Atributos:** - `id`: UUID - `name`: Nombre (ej: "Precio Distribuidor") - `currency_id`: Moneda - `active`: Activa/Inactiva **Relaciones:** - 1 PriceList → N PriceListItems - 1 PriceList → N Partners **Patrón Odoo:** product.pricelist **Uso:** Precios diferenciados por tipo de cliente ### 6. PriceListItem (Item de Lista de Precios) **Descripción:** Precio específico de producto en lista. **Atributos:** - `id`: UUID - `pricelist_id`: Lista propietaria - `product_id`: Producto - `price`: Precio - `min_quantity`: Cantidad mínima **Relaciones:** - N PriceListItems → 1 PriceList **Patrón Odoo:** product.pricelist.item ## Reglas de Negocio ### RN-SAL-001: Flujo de Estados - Orden solo puede confirmarse (sale) desde draft o sent - Una vez en 'sale', no puede volver a draft - Cancelación posible desde cualquier estado excepto 'done' ### RN-SAL-002: Generación Automática de Picking - Al confirmar orden (status=sale), generar Picking de entrega - Picking tipo 'outgoing' - Solo para productos tipo 'storable' ### RN-SAL-003: Facturación - Facturar después de entrega (delivery → invoice) - Facturar antes de entrega (invoice → delivery) - Facturación parcial permitida ### RN-SAL-004: Control de Cantidades - qty_delivered: actualizada desde Picking - qty_invoiced: actualizada desde Invoice - delivery_status: 'delivered' cuando qty_delivered = quantity - invoice_status: 'invoiced' cuando qty_invoiced = quantity ### RN-SAL-005: Cotización con Firma - Cotización aprobada requiere firma electrónica - Firma incluye: canvas signature, timestamp, IP, user_agent - Firma es inmutable ### RN-SAL-006: Validez de Cotización - Cotización con validity_date vencida no puede confirmarse - Sistema alerta si cotización está por vencer ### RN-SAL-007: Descuentos - Descuento por línea (0-100%) - Descuento aplicado antes de impuestos - Subtotal = (quantity * price_unit) * (1 - discount/100) ## Casos de Uso Principales 1. **UC-SAL-001:** Usuario crea cotización y envía a cliente 2. **UC-SAL-002:** Cliente aprueba cotización online (portal) 3. **UC-SAL-003:** Cliente firma cotización electrónicamente 4. **UC-SAL-004:** Usuario convierte cotización a orden de venta 5. **UC-SAL-005:** Sistema genera picking al confirmar orden 6. **UC-SAL-006:** Usuario valida entrega de productos 7. **UC-SAL-007:** Usuario crea factura desde orden 8. **UC-SAL-008:** Usuario consulta reporte de ventas por cliente ## Validaciones y Constraints ```sql -- Sale order name único por company UNIQUE (tenant_id, company_id, name) -- Cantidades > 0 CHECK (quantity > 0) CHECK (price_unit >= 0) -- Descuento entre 0 y 100 CHECK (discount >= 0 AND discount <= 100) -- qty_delivered <= quantity CHECK (qty_delivered <= quantity) -- qty_invoiced <= quantity CHECK (qty_invoiced <= quantity) -- validity_date >= date (cotización) CHECK (validity_date >= date) ``` ## Índices Requeridos ```sql CREATE INDEX idx_sale_orders_partner_id ON sales.sale_orders(partner_id); CREATE INDEX idx_sale_orders_status ON sales.sale_orders(status); CREATE INDEX idx_sale_orders_order_date ON sales.sale_orders(order_date); CREATE INDEX idx_sale_order_lines_order_id ON sales.sale_order_lines(order_id); CREATE INDEX idx_sale_order_lines_product_id ON sales.sale_order_lines(product_id); CREATE INDEX idx_quotations_partner_id ON sales.quotations(partner_id); CREATE INDEX idx_quotations_status ON sales.quotations(status); CREATE INDEX idx_quotations_validity_date ON sales.quotations(validity_date); ``` ## Integración con Otros Módulos ### Con MGN-005 (Inventario) - Confirmar SO → genera Picking (outgoing) - Validar Picking → actualiza qty_delivered ### Con MGN-004 (Financiero) - Crear factura desde SO → copia líneas de SO - Validar factura → actualiza qty_invoiced ### Con MGN-008 (Analítica) - Líneas de SO pueden tener analytic_account_id - Al facturar, genera líneas analíticas ### Con MGN-009 (CRM) - Lead convertido → crea Quotation - Quotation vinculada a Opportunity ### Con MGN-013 (Portal) - Cliente ve quotations en portal - Cliente aprueba/firma desde portal ## Referencias - [ALCANCE-POR-MODULO.md - MGN-007](../../01-definicion-modulos/ALCANCE-POR-MODULO.md#mgn-007) - [ADR-007: Database Design](../../adr/ADR-007-database-design.md) - [odoo-sale-analysis.md](../../00-analisis-referencias/odoo/odoo-sale-analysis.md)