erp-core/docs/03-fase-vertical/MGN-011-sales/especificaciones/ET-SALES-BACKEND.md
rckrdmrd 0086695b4c
Some checks failed
ERP Core CI / Backend Lint (push) Has been cancelled
ERP Core CI / Backend Unit Tests (push) Has been cancelled
ERP Core CI / Backend Integration Tests (push) Has been cancelled
ERP Core CI / Frontend Lint (push) Has been cancelled
ERP Core CI / Frontend Unit Tests (push) Has been cancelled
ERP Core CI / Frontend E2E Tests (push) Has been cancelled
ERP Core CI / Database DDL Validation (push) Has been cancelled
ERP Core CI / Backend Build (push) Has been cancelled
ERP Core CI / Frontend Build (push) Has been cancelled
ERP Core CI / CI Success (push) Has been cancelled
Performance Tests / Lighthouse CI (push) Has been cancelled
Performance Tests / Bundle Size Analysis (push) Has been cancelled
Performance Tests / k6 Load Tests (push) Has been cancelled
Performance Tests / Performance Summary (push) Has been cancelled
[SIMCO-V38] feat: Actualizar a SIMCO v3.8.0 + cambios backend
- HERENCIA-SIMCO.md actualizado con directivas v3.7 y v3.8
- Actualizaciones en modulos CRM y OpenAPI

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 08:53:05 -06:00

27 KiB

ET-SALES-BACKEND

Especificacion Tecnica Backend - Modulo Ventas


METADATOS

Campo Valor
Modulo MGN-011
Version 1.0.0
Fecha 2026-01-10
Estado Documentado
Autor Claude Code

1. SERVICIOS

1.1 CustomerGroupsService

Ubicacion: backend/src/modules/sales/customer-groups.service.ts

Metodo Parametros Retorno Descripcion
findAll tenantId: string, filters: CustomerGroupFilters Promise<{ data: CustomerGroup[]; total: number }> Lista grupos de clientes con paginacion y busqueda
findById id: string, tenantId: string Promise<CustomerGroup> Obtiene grupo por ID con sus miembros
create dto: CreateCustomerGroupDto, tenantId: string, userId: string Promise<CustomerGroup> Crea nuevo grupo de clientes
update id: string, dto: UpdateCustomerGroupDto, tenantId: string Promise<CustomerGroup> Actualiza grupo existente
delete id: string, tenantId: string Promise<void> Elimina grupo (solo si no tiene miembros)
addMember groupId: string, partnerId: string, tenantId: string Promise<CustomerGroupMember> Agrega cliente al grupo
removeMember groupId: string, memberId: string, tenantId: string Promise<void> Elimina cliente del grupo

1.2 SalesTeamsService

Ubicacion: backend/src/modules/sales/sales-teams.service.ts

Metodo Parametros Retorno Descripcion
findAll tenantId: string, filters: SalesTeamFilters Promise<{ data: SalesTeam[]; total: number }> Lista equipos de ventas con filtros
findById id: string, tenantId: string Promise<SalesTeam> Obtiene equipo por ID con miembros
create dto: CreateSalesTeamDto, tenantId: string, userId: string Promise<SalesTeam> Crea nuevo equipo de ventas
update id: string, dto: UpdateSalesTeamDto, tenantId: string, userId: string Promise<SalesTeam> Actualiza equipo existente
addMember teamId: string, userId: string, role: string, tenantId: string Promise<SalesTeamMember> Agrega usuario al equipo
removeMember teamId: string, memberId: string, tenantId: string Promise<void> Elimina usuario del equipo

1.3 PricelistsService

Ubicacion: backend/src/modules/sales/pricelists.service.ts

Metodo Parametros Retorno Descripcion
findAll tenantId: string, filters: PricelistFilters Promise<{ data: Pricelist[]; total: number }> Lista listas de precios
findById id: string, tenantId: string Promise<Pricelist> Obtiene lista de precios con items
create dto: CreatePricelistDto, tenantId: string, userId: string Promise<Pricelist> Crea nueva lista de precios
update id: string, dto: UpdatePricelistDto, tenantId: string, userId: string Promise<Pricelist> Actualiza lista de precios
addItem pricelistId: string, dto: CreatePricelistItemDto, tenantId: string, userId: string Promise<PricelistItem> Agrega item a lista de precios
removeItem pricelistId: string, itemId: string, tenantId: string Promise<void> Elimina item de lista de precios
getProductPrice productId: string, pricelistId: string, quantity: number Promise<number | null> Obtiene precio de producto segun lista y cantidad

1.4 OrdersService

Ubicacion: backend/src/modules/sales/orders.service.ts

Metodo Parametros Retorno Descripcion
findAll tenantId: string, filters: SalesOrderFilters Promise<{ data: SalesOrder[]; total: number }> Lista ordenes de venta con filtros avanzados
findById id: string, tenantId: string Promise<SalesOrder> Obtiene orden por ID con lineas
create dto: CreateSalesOrderDto, tenantId: string, userId: string Promise<SalesOrder> Crea nueva orden de venta
update id: string, dto: UpdateSalesOrderDto, tenantId: string, userId: string Promise<SalesOrder> Actualiza orden (solo en estado draft)
delete id: string, tenantId: string Promise<void> Elimina orden (solo en estado draft)
addLine orderId: string, dto: CreateSalesOrderLineDto, tenantId: string, userId: string Promise<SalesOrderLine> Agrega linea a orden
updateLine orderId: string, lineId: string, dto: UpdateSalesOrderLineDto, tenantId: string Promise<SalesOrderLine> Actualiza linea de orden
removeLine orderId: string, lineId: string, tenantId: string Promise<void> Elimina linea de orden
confirm id: string, tenantId: string, userId: string Promise<SalesOrder> Confirma orden (draft -> sent)
cancel id: string, tenantId: string, userId: string Promise<SalesOrder> Cancela orden
createInvoice id: string, tenantId: string, userId: string Promise<{ orderId: string; invoiceId: string }> Genera factura desde orden

1.5 QuotationsService

Ubicacion: backend/src/modules/sales/quotations.service.ts

Metodo Parametros Retorno Descripcion
findAll tenantId: string, filters: QuotationFilters Promise<{ data: Quotation[]; total: number }> Lista cotizaciones con filtros
findById id: string, tenantId: string Promise<Quotation> Obtiene cotizacion por ID con lineas
create dto: CreateQuotationDto, tenantId: string, userId: string Promise<Quotation> Crea nueva cotizacion
update id: string, dto: UpdateQuotationDto, tenantId: string, userId: string Promise<Quotation> Actualiza cotizacion (solo en draft)
delete id: string, tenantId: string Promise<void> Elimina cotizacion (solo en draft)
addLine quotationId: string, dto: CreateQuotationLineDto, tenantId: string, userId: string Promise<QuotationLine> Agrega linea a cotizacion
updateLine quotationId: string, lineId: string, dto: UpdateQuotationLineDto, tenantId: string Promise<QuotationLine> Actualiza linea de cotizacion
removeLine quotationId: string, lineId: string, tenantId: string Promise<void> Elimina linea de cotizacion
send id: string, tenantId: string, userId: string Promise<Quotation> Envia cotizacion al cliente (email)
confirm id: string, tenantId: string, userId: string Promise<{ quotation: Quotation; orderId: string }> Confirma cotizacion y crea orden de venta
cancel id: string, tenantId: string, userId: string Promise<Quotation> Cancela cotizacion

2. ENTIDADES

2.1 CustomerGroup

Schema: sales.customer_groups

Columna Tipo Nullable Descripcion
id UUID NO Identificador unico
tenant_id UUID NO Tenant (multi-tenancy)
name VARCHAR(255) NO Nombre del grupo
description TEXT SI Descripcion
discount_percentage DECIMAL NO Porcentaje de descuento (default: 0)
created_by UUID SI Usuario que creo
created_at TIMESTAMP NO Fecha de creacion

2.2 CustomerGroupMember

Schema: sales.customer_group_members

Columna Tipo Nullable Descripcion
id UUID NO Identificador unico
customer_group_id UUID NO FK a customer_groups
partner_id UUID NO FK a core.partners
joined_at TIMESTAMP NO Fecha de union

2.3 SalesTeam

Schema: sales.sales_teams

Columna Tipo Nullable Descripcion
id UUID NO Identificador unico
tenant_id UUID NO Tenant
company_id UUID NO FK a auth.companies
name VARCHAR(255) NO Nombre del equipo
code VARCHAR(50) SI Codigo unico por empresa
team_leader_id UUID SI FK a auth.users (lider)
target_monthly DECIMAL SI Meta mensual
target_annual DECIMAL SI Meta anual
active BOOLEAN NO Estado activo (default: true)
created_by UUID SI Usuario que creo
created_at TIMESTAMP NO Fecha de creacion
updated_by UUID SI Usuario que actualizo
updated_at TIMESTAMP SI Fecha de actualizacion

2.4 SalesTeamMember

Schema: sales.sales_team_members

Columna Tipo Nullable Descripcion
id UUID NO Identificador unico
sales_team_id UUID NO FK a sales_teams
user_id UUID NO FK a auth.users
role VARCHAR(100) SI Rol en el equipo
joined_at TIMESTAMP NO Fecha de union

2.5 Pricelist

Schema: sales.pricelists

Columna Tipo Nullable Descripcion
id UUID NO Identificador unico
tenant_id UUID NO Tenant
company_id UUID SI FK a auth.companies
name VARCHAR(255) NO Nombre de la lista
currency_id UUID NO FK a core.currencies
active BOOLEAN NO Estado activo (default: true)
created_by UUID SI Usuario que creo
created_at TIMESTAMP NO Fecha de creacion
updated_by UUID SI Usuario que actualizo
updated_at TIMESTAMP SI Fecha de actualizacion

2.6 PricelistItem

Schema: sales.pricelist_items

Columna Tipo Nullable Descripcion
id UUID NO Identificador unico
pricelist_id UUID NO FK a pricelists
product_id UUID SI FK a inventory.products
product_category_id UUID SI FK a core.product_categories
price DECIMAL NO Precio
min_quantity INTEGER NO Cantidad minima (default: 1)
valid_from DATE SI Fecha inicio validez
valid_to DATE SI Fecha fin validez
active BOOLEAN NO Estado activo (default: true)
created_by UUID SI Usuario que creo

2.7 SalesOrder

Schema: sales.sales_orders

Columna Tipo Nullable Descripcion
id UUID NO Identificador unico
tenant_id UUID NO Tenant
company_id UUID NO FK a auth.companies
name VARCHAR(50) NO Numero de orden (SO-XXXXXX)
client_order_ref VARCHAR(100) SI Referencia del cliente
partner_id UUID NO FK a core.partners
order_date DATE NO Fecha de orden
validity_date DATE SI Fecha de validez
commitment_date DATE SI Fecha de compromiso
currency_id UUID NO FK a core.currencies
pricelist_id UUID SI FK a pricelists
payment_term_id UUID SI FK a financial.payment_terms
user_id UUID SI FK a auth.users (vendedor)
sales_team_id UUID SI FK a sales_teams
amount_untaxed DECIMAL NO Subtotal sin impuestos
amount_tax DECIMAL NO Total impuestos
amount_total DECIMAL NO Total
status ENUM NO draft, sent, sale, done, cancelled
invoice_status ENUM NO pending, partial, invoiced
delivery_status ENUM NO pending, partial, delivered
invoice_policy ENUM NO order, delivery
picking_id UUID SI FK a inventory.pickings
notes TEXT SI Notas internas
terms_conditions TEXT SI Terminos y condiciones
created_by UUID SI Usuario que creo
created_at TIMESTAMP NO Fecha de creacion
confirmed_at TIMESTAMP SI Fecha de confirmacion
confirmed_by UUID SI Usuario que confirmo
cancelled_at TIMESTAMP SI Fecha de cancelacion
cancelled_by UUID SI Usuario que cancelo
updated_by UUID SI Usuario que actualizo
updated_at TIMESTAMP SI Fecha de actualizacion

2.8 SalesOrderLine

Schema: sales.sales_order_lines

Columna Tipo Nullable Descripcion
id UUID NO Identificador unico
order_id UUID NO FK a sales_orders
tenant_id UUID NO Tenant
product_id UUID NO FK a inventory.products
description TEXT NO Descripcion
quantity DECIMAL NO Cantidad
qty_delivered DECIMAL NO Cantidad entregada
qty_invoiced DECIMAL NO Cantidad facturada
uom_id UUID NO FK a core.uom
price_unit DECIMAL NO Precio unitario
discount DECIMAL NO Porcentaje descuento
tax_ids UUID[] NO Array de FK a financial.taxes
amount_untaxed DECIMAL NO Subtotal sin impuestos
amount_tax DECIMAL NO Total impuestos
amount_total DECIMAL NO Total
analytic_account_id UUID SI FK a financial.analytic_accounts
created_at TIMESTAMP NO Fecha de creacion
updated_at TIMESTAMP SI Fecha de actualizacion

2.9 Quotation

Schema: sales.quotations

Columna Tipo Nullable Descripcion
id UUID NO Identificador unico
tenant_id UUID NO Tenant
company_id UUID NO FK a auth.companies
name VARCHAR(50) NO Numero de cotizacion (QUO-XXXXXX)
partner_id UUID NO FK a core.partners
quotation_date DATE NO Fecha de cotizacion
validity_date DATE NO Fecha de validez
currency_id UUID NO FK a core.currencies
pricelist_id UUID SI FK a pricelists
user_id UUID SI FK a auth.users (vendedor)
sales_team_id UUID SI FK a sales_teams
amount_untaxed DECIMAL NO Subtotal sin impuestos
amount_tax DECIMAL NO Total impuestos
amount_total DECIMAL NO Total
status ENUM NO draft, sent, confirmed, cancelled, expired
sale_order_id UUID SI FK a sales_orders (orden generada)
notes TEXT SI Notas internas
terms_conditions TEXT SI Terminos y condiciones
created_by UUID SI Usuario que creo
created_at TIMESTAMP NO Fecha de creacion
updated_by UUID SI Usuario que actualizo
updated_at TIMESTAMP SI Fecha de actualizacion

2.10 QuotationLine

Schema: sales.quotation_lines

Columna Tipo Nullable Descripcion
id UUID NO Identificador unico
quotation_id UUID NO FK a quotations
tenant_id UUID NO Tenant
product_id UUID SI FK a inventory.products
description TEXT NO Descripcion
quantity DECIMAL NO Cantidad
uom_id UUID NO FK a core.uom
price_unit DECIMAL NO Precio unitario
discount DECIMAL NO Porcentaje descuento
tax_ids UUID[] NO Array de FK a financial.taxes
amount_untaxed DECIMAL NO Subtotal sin impuestos
amount_tax DECIMAL NO Total impuestos
amount_total DECIMAL NO Total
created_at TIMESTAMP NO Fecha de creacion

3. DTOs

3.1 CustomerGroups DTOs

interface CreateCustomerGroupDto {
  name: string;                    // Requerido, max 255
  description?: string;            // Opcional
  discount_percentage?: number;    // 0-100, default: 0
}

interface UpdateCustomerGroupDto {
  name?: string;                   // max 255
  description?: string | null;
  discount_percentage?: number;    // 0-100
}

interface CustomerGroupFilters {
  search?: string;
  page?: number;                   // default: 1
  limit?: number;                  // default: 20, max: 100
}

3.2 SalesTeams DTOs

interface CreateSalesTeamDto {
  company_id: string;              // UUID, requerido
  name: string;                    // Requerido, max 255
  code?: string;                   // max 50
  team_leader_id?: string;         // UUID
  target_monthly?: number;         // > 0
  target_annual?: number;          // > 0
}

interface UpdateSalesTeamDto {
  name?: string;
  code?: string;
  team_leader_id?: string | null;
  target_monthly?: number | null;
  target_annual?: number | null;
  active?: boolean;
}

interface SalesTeamFilters {
  company_id?: string;
  active?: boolean;
  page?: number;
  limit?: number;
}

3.3 Pricelists DTOs

interface CreatePricelistDto {
  company_id?: string;             // UUID
  name: string;                    // Requerido, max 255
  currency_id: string;             // UUID, requerido
}

interface UpdatePricelistDto {
  name?: string;
  currency_id?: string;
  active?: boolean;
}

interface CreatePricelistItemDto {
  product_id?: string;             // UUID (uno de product_id o product_category_id)
  product_category_id?: string;    // UUID
  price: number;                   // >= 0
  min_quantity?: number;           // > 0, default: 1
  valid_from?: string;             // ISO date
  valid_to?: string;               // ISO date
}

interface PricelistFilters {
  company_id?: string;
  active?: boolean;
  page?: number;
  limit?: number;
}

3.4 Orders DTOs

interface CreateSalesOrderDto {
  company_id: string;              // UUID, requerido
  partner_id: string;              // UUID, requerido
  client_order_ref?: string;       // max 100
  order_date?: string;             // ISO date
  validity_date?: string;          // ISO date
  commitment_date?: string;        // ISO date
  currency_id: string;             // UUID, requerido
  pricelist_id?: string;           // UUID
  payment_term_id?: string;        // UUID
  sales_team_id?: string;          // UUID
  invoice_policy?: 'order' | 'delivery';  // default: 'order'
  notes?: string;
  terms_conditions?: string;
}

interface UpdateSalesOrderDto {
  partner_id?: string;
  client_order_ref?: string | null;
  order_date?: string;
  validity_date?: string | null;
  commitment_date?: string | null;
  currency_id?: string;
  pricelist_id?: string | null;
  payment_term_id?: string | null;
  sales_team_id?: string | null;
  invoice_policy?: 'order' | 'delivery';
  notes?: string | null;
  terms_conditions?: string | null;
}

interface CreateSalesOrderLineDto {
  product_id: string;              // UUID, requerido
  description: string;             // Requerido
  quantity: number;                // > 0
  uom_id: string;                  // UUID, requerido
  price_unit: number;              // >= 0
  discount?: number;               // 0-100, default: 0
  tax_ids?: string[];              // UUID[]
  analytic_account_id?: string;    // UUID
}

interface UpdateSalesOrderLineDto {
  description?: string;
  quantity?: number;
  uom_id?: string;
  price_unit?: number;
  discount?: number;
  tax_ids?: string[];
  analytic_account_id?: string | null;
}

interface SalesOrderFilters {
  company_id?: string;
  partner_id?: string;
  status?: 'draft' | 'sent' | 'sale' | 'done' | 'cancelled';
  invoice_status?: 'pending' | 'partial' | 'invoiced';
  delivery_status?: 'pending' | 'partial' | 'delivered';
  date_from?: string;
  date_to?: string;
  search?: string;
  page?: number;
  limit?: number;
}

3.5 Quotations DTOs

interface CreateQuotationDto {
  company_id: string;              // UUID, requerido
  partner_id: string;              // UUID, requerido
  quotation_date?: string;         // ISO date
  validity_date: string;           // ISO date, requerido
  currency_id: string;             // UUID, requerido
  pricelist_id?: string;           // UUID
  sales_team_id?: string;          // UUID
  notes?: string;
  terms_conditions?: string;
}

interface UpdateQuotationDto {
  partner_id?: string;
  quotation_date?: string;
  validity_date?: string;
  currency_id?: string;
  pricelist_id?: string | null;
  sales_team_id?: string | null;
  notes?: string | null;
  terms_conditions?: string | null;
}

interface CreateQuotationLineDto {
  product_id?: string;             // UUID
  description: string;             // Requerido
  quantity: number;                // > 0
  uom_id: string;                  // UUID, requerido
  price_unit: number;              // >= 0
  discount?: number;               // 0-100, default: 0
  tax_ids?: string[];              // UUID[]
}

interface UpdateQuotationLineDto {
  description?: string;
  quantity?: number;
  uom_id?: string;
  price_unit?: number;
  discount?: number;
  tax_ids?: string[];
}

interface QuotationFilters {
  company_id?: string;
  partner_id?: string;
  status?: 'draft' | 'sent' | 'confirmed' | 'cancelled' | 'expired';
  date_from?: string;
  date_to?: string;
  search?: string;
  page?: number;
  limit?: number;
}

4. ENDPOINTS

4.1 Customer Groups

Metodo Endpoint Descripcion
GET /api/sales/customer-groups Listar grupos de clientes
GET /api/sales/customer-groups/:id Obtener grupo por ID
POST /api/sales/customer-groups Crear grupo de clientes
PATCH /api/sales/customer-groups/:id Actualizar grupo
DELETE /api/sales/customer-groups/:id Eliminar grupo
POST /api/sales/customer-groups/:id/members Agregar miembro
DELETE /api/sales/customer-groups/:id/members/:memberId Eliminar miembro

4.2 Sales Teams

Metodo Endpoint Descripcion
GET /api/sales/teams Listar equipos de ventas
GET /api/sales/teams/:id Obtener equipo por ID
POST /api/sales/teams Crear equipo de ventas
PATCH /api/sales/teams/:id Actualizar equipo
POST /api/sales/teams/:id/members Agregar miembro
DELETE /api/sales/teams/:id/members/:memberId Eliminar miembro

4.3 Pricelists

Metodo Endpoint Descripcion
GET /api/sales/pricelists Listar listas de precios
GET /api/sales/pricelists/:id Obtener lista por ID
POST /api/sales/pricelists Crear lista de precios
PATCH /api/sales/pricelists/:id Actualizar lista
POST /api/sales/pricelists/:id/items Agregar item
DELETE /api/sales/pricelists/:id/items/:itemId Eliminar item

4.4 Sales Orders

Metodo Endpoint Descripcion
GET /api/sales/orders Listar ordenes de venta
GET /api/sales/orders/:id Obtener orden por ID
POST /api/sales/orders Crear orden de venta
PATCH /api/sales/orders/:id Actualizar orden
DELETE /api/sales/orders/:id Eliminar orden
POST /api/sales/orders/:id/lines Agregar linea
PATCH /api/sales/orders/:id/lines/:lineId Actualizar linea
DELETE /api/sales/orders/:id/lines/:lineId Eliminar linea
POST /api/sales/orders/:id/confirm Confirmar orden
POST /api/sales/orders/:id/cancel Cancelar orden
POST /api/sales/orders/:id/invoice Crear factura

4.5 Quotations

Metodo Endpoint Descripcion
GET /api/sales/quotations Listar cotizaciones
GET /api/sales/quotations/:id Obtener cotizacion por ID
POST /api/sales/quotations Crear cotizacion
PATCH /api/sales/quotations/:id Actualizar cotizacion
DELETE /api/sales/quotations/:id Eliminar cotizacion
POST /api/sales/quotations/:id/lines Agregar linea
PATCH /api/sales/quotations/:id/lines/:lineId Actualizar linea
DELETE /api/sales/quotations/:id/lines/:lineId Eliminar linea
POST /api/sales/quotations/:id/send Enviar cotizacion
POST /api/sales/quotations/:id/confirm Confirmar y crear orden
POST /api/sales/quotations/:id/cancel Cancelar cotizacion

5. TESTS

5.1 Estado de Tests

Servicio Archivo Estado
CustomerGroupsService __tests__/customer-groups.service.spec.ts Implementado
SalesTeamsService __tests__/sales-teams.service.spec.ts Implementado
PricelistsService __tests__/pricelists.service.spec.ts Implementado
OrdersService __tests__/orders.service.spec.ts Implementado
QuotationsService __tests__/quotations.service.spec.ts Implementado

5.2 Cobertura

Todos los servicios cuentan con tests unitarios que cubren:

  • CRUD basico
  • Validaciones de negocio
  • Manejo de errores
  • Flujos de estado (confirmar, cancelar, etc.)

6. DEPENDENCIAS

6.1 Modulos Internos

Modulo Uso
auth Usuarios, empresas, autenticacion
core Partners, currencies, UoM, product_categories, sequences
inventory Products
financial Taxes (calculo impuestos), invoices, payment_terms, analytic_accounts

6.2 Servicios Externos

Servicio Uso
taxesService Calculo de impuestos en lineas de orden/cotizacion
sequencesService Generacion de numeros de secuencia (SO-XXXXXX)
emailService Envio de cotizaciones por email

6.3 Dependencias de Base de Datos

sales.customer_groups
  └── core.partners (via customer_group_members)

sales.sales_teams
  ├── auth.companies
  └── auth.users (team_leader, members)

sales.pricelists
  ├── auth.companies
  ├── core.currencies
  ├── inventory.products (items)
  └── core.product_categories (items)

sales.sales_orders
  ├── auth.companies
  ├── core.partners
  ├── core.currencies
  ├── sales.pricelists
  ├── sales.sales_teams
  ├── auth.users
  ├── financial.payment_terms
  ├── inventory.products (lines)
  ├── core.uom (lines)
  └── financial.taxes (lines)

sales.quotations
  ├── (mismas dependencias que sales_orders)
  └── sales.sales_orders (sale_order_id)

7. FLUJOS DE NEGOCIO

7.1 Flujo de Cotizacion

draft -> sent -> confirmed -> [crea sales_order]
              -> cancelled
              -> expired

7.2 Flujo de Orden de Venta

draft -> sent -> sale -> done
              -> cancelled

invoice_status: pending -> partial -> invoiced
delivery_status: pending -> partial -> delivered

7.3 Reglas de Negocio

  1. Ordenes/Cotizaciones: Solo se pueden editar/eliminar en estado draft
  2. Grupos de clientes: No se pueden eliminar si tienen miembros
  3. Equipos de ventas: Codigo unico por empresa
  4. Listas de precios: Nombre unico por tenant
  5. Facturacion: Segun invoice_policy (order: al confirmar, delivery: al entregar)
  6. Impuestos: Calculados automaticamente usando taxesService

8. VALIDACIONES

8.1 Validaciones con Zod

Todas las validaciones de entrada se realizan usando Zod en el controlador:

  • Tipos de datos
  • Campos requeridos
  • Rangos (min, max)
  • Formatos (UUID, email, fechas)
  • Valores permitidos (enums)

8.2 Validaciones de Negocio

Las validaciones de negocio se realizan en los servicios:

  • Unicidad de nombres/codigos
  • Estados validos para operaciones
  • Existencia de entidades relacionadas
  • Restricciones de eliminacion