325 lines
8.6 KiB
Markdown
325 lines
8.6 KiB
Markdown
# 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)
|