Información General
| Cliente | HPL Apollo (Logistics) |
| Versión Odoo | 18.0 Enterprise |
| Última actualización | 2026-03-12 |
| Módulos custom | purchase_approval_kanak, crm_custom_fields |
| Repositorio | hplapollo (rama main) |
Índice
- purchase_approval_kanak — Flujo de Aprobación de OC
- Descripción Funcional
- Flujo de Trabajo
- Arquitectura Técnica
- Configuración
- Navegación
- Pruebas Funcionales
- crm_custom_fields — Campos Logísticos en CRM
- Descripción Funcional
- Arquitectura Técnica
- Navegación
- Pruebas Funcionales
- Dependencias y Arquitectura Global
1. purchase_approval_kanak
Multi-level purchase order approval workflow. Odoo 18 Enterprise. Versión 18.0.1.0.
1.1 Descripción Funcional
Este módulo añade un sistema de aprobación secuencial a las órdenes de compra. En lugar de que cualquier usuario pueda confirmar una OC directamente, el flujo obliga a que uno o varios aprobadores validen la OC según su importe y categoría del producto. Mientras está en aprobación, los campos clave de la OC quedan bloqueados para evitar modificaciones.
¿Cuándo se activa el flujo? Solo cuando en Ajustes se habilita "Purchase Order Approval By Rule" y se asigna una regla a la empresa. Sin esa configuración, las OCs funcionan igual que Odoo estándar.
Características principales:
- Reglas de aprobación por rango de importe y categoría de producto
- Aprobación secuencial: niveles inferiores deben aprobar antes que los superiores
- Límites de gasto mensual por rol de aprobador
- Notificaciones por email a cada aprobador cuando le toca actuar
- Historial de aprobaciones y rechazos con motivo
- Seguimiento de monto recibido vs pendiente por recepción (reception tracking)
- Reporte PDF extendido con columna y totales de recepción
1.2 Flujo de Trabajo
BORRADOR
│
├─ Sin sistema de aprobación activo:
│ → Botón "Confirm Order" directo
│
└─ Con sistema de aprobación activo:
[Usuario] → "Send For Approval"
│
├─ Se generan instancias de approval.rules para esta OC
├─ Campos bloqueados (líneas, proveedor, fecha)
└─ Email enviado al aprobador del nivel 1 (menor sequence)
[Aprobador nivel 1] → "✅ Approve"
│
├─ Marca su línea is_approved = True
├─ ¿Quedan niveles pendientes?
│ Sí → notifica al siguiente aprobador
└─ No → ready_for_po = True
[Cualquier aprobador activo] → "❌ Reject"
│
├─ Wizard: ingresar motivo de rechazo
├─ OC vuelve a BORRADOR (editable)
└─ Se registra en historial
[Usuario] → "Confirm Order" (solo si ready_for_po = True)
└─ OC pasa a estado 'purchase' (orden confirmada)
1.3 Arquitectura Técnica
Modelos
| Modelo | Tipo | Descripción |
|---|---|---|
| purchase.order | Extensión | Campos de aprobación, reception tracking, visibilidad de botones, límites mensuales |
| purchase.order.approval.rule | Nuevo | Plantilla de regla a nivel empresa. Se configura en Ajustes. |
| purchase.order.approval.rule.lines | Nuevo | Líneas de la plantilla: sequence, rol, rango de monto, límite mensual |
| purchase.order.approval.rules | Nuevo | Instancias de regla POR orden de compra. Se generan al enviar para aprobación. |
| purchase.order.approval.history | Nuevo | Log inmutable de acciones: quién, qué, cuándo, motivo de rechazo |
| approval.role | Nuevo | Roles de aprobación. Se asignan a empleados (Many2many). |
| approval.categ | Nuevo | Categorías de aprobación. Se asignan a productos. |
| hr.employee | Extensión | Añade campos: approval_role (Many2many), warehouse_id (Many2one) |
| product.template | Extensión | Añade campo: approval_category (Many2one approval.categ) |
| res.company | Extensión | Añade: purchase_order_approval (Boolean), purchase_order_approval_rule_id |
Campos principales en purchase.order
| Campo | Tipo | Descripción |
|---|---|---|
| send_for_approval | Boolean | True desde que se envía para aprobación |
| ready_for_po | Boolean (computed) | True cuando todos los niveles han aprobado |
| is_rejected | Boolean | True si fue rechazada. Permite edición de campos. |
| show_confirm_button | Boolean (computed) | Oculta el botón Confirmar hasta que ready_for_po = True |
| show_send_approval_button | Boolean (computed) | Visible solo cuando la OC está en borrador y aún no enviada |
| show_approve_button | Boolean (computed) | Solo visible para el usuario con rol que coincide con el nivel activo |
| show_reject_button | Boolean (computed) | Solo visible para aprobadores del nivel activo |
| monthly_limit_warning | Char (computed) | Texto de alerta si el aprobador supera su límite mensual |
| monthly_limit_progress | Float (computed) | Porcentaje de uso del límite mensual |
| approval_status_summary | HTML (computed) | Resumen de estado de cada nivel con colores |
| amount_received | Monetary (computed) | Sum(qty_received × price_unit) por cada línea recibida |
| amount_pending | Monetary (computed) | amount_total − amount_received |
| supplier_rep_ids | Many2many res.users | Representantes del proveedor (campo adicional informativo) |
Métodos clave en purchase.py
| Método | Qué hace |
|---|---|
| _compute_approve_button | Determina qué usuario puede ver los botones Approve/Reject según su rol y el nivel activo |
| _compute_ready_for_po | True si no quedan líneas de aprobación sin aprobar |
| _get_data_purchase_order_approval_rule_ids | Genera las instancias de regla para una OC según su importe y categoría de productos |
| _get_monthly_spent / _get_monthly_spent_cached | Calcula el gasto mensual acumulado de un usuario. Usa SimpleCache con TTL 1 hora. |
| action_send_for_approval | Transición a estado "enviada para aprobación". Genera reglas y envía email nivel 1. |
| action_button_approve | Aprueba el nivel del usuario actual. Envía email al siguiente si aplica. |
| reject_purchase | Abre wizard de motivo de rechazo. Revierte OC a borrador. |
| action_refresh_approval_hierarchy | Regenera las reglas de aprobación desde cero (útil si cambia la configuración). |
| _validate_monthly_limit_for_approval | Verifica si el aprobador excede su límite mensual antes de aprobar. |
Valores especiales en configuración de reglas
-1en límite inferior / superior = sin límite (aplica a cualquier monto)-1en monthly_purchase_limit = sin control de límite mensual- Los rangos del mismo
sequenceNO pueden solaparse. Odoo lanza error de validación.
Caché de gasto mensual
El cálculo de gasto mensual por aprobador usa un SimpleCache propio con TTL de 1 hora. Clave: user_id + company_id + mes. Se invalida automáticamente al cambiar el amount_total de cualquier OC.
Seguridad (ir.model.access.csv)
- Managers: CRUD completo en todos los modelos de configuración
- Users: solo lectura en modelos de configuración; lectura + escritura + creación (sin eliminar) en instancias de regla e historial por OC
- Todos los usuarios pueden acceder a los wizards
1.4 Configuración
- Asignar roles a empleados: Empleados → [empleado] → pestaña RRHH → campo "Approval Role" (Many2many)
- Activar el sistema: Compras → Configuración → Ajustes → activar "Purchase Order Approval By Rule"
- Crear una regla: En el mismo Ajustes, crear o seleccionar una regla de aprobación con sus líneas:
- Sequence: orden de aprobación (1 = primero)
- Approval Role: qué rol aprueba este nivel
- Lower Limit / Upper Limit: rango de monto. Usar -1 en Upper para "sin límite superior"
- Monthly Limit: máximo mensual acumulado. Usar -1 para sin límite.
- (Opcional) Categorías por producto: Inventario → Productos → [producto] → campo "Approval Category"
- Verificar: Crear una OC de prueba y confirmar que aparece el botón "Send For Approval"
1.5 Navegación
| Acción | Ruta |
|---|---|
| Ver OCs pendientes de mi aprobación | Compras → Aprobaciones → PO to Approve |
| Configurar reglas de aprobación | Compras → Configuración → Ajustes → Aprobación de OC |
| Gestionar roles de aprobación | Compras → Configuración → Approval Roles |
| Gestionar categorías de aprobación | Compras → Configuración → Approval Categories |
| Ver jerarquía de una OC | OC → pestaña "Approval Hierarchy" |
| Ver historial de acciones de una OC | OC → pestaña "Approval History" |
| Ver monto recibido vs pendiente | OC → pestaña "Reception Tracking" |
| Ver alertas de límite mensual | OC → pestaña "Analytics" |
1.6 Pruebas Funcionales
F1 — Flujo completo 1 nivel
- Crear regla con 1 línea: sequence=1, rol=Gerente, límites 0 a -1
- Asignar rol Gerente a un empleado/usuario
- Crear OC con importe > 0 → clic "Send For Approval"
- Iniciar sesión como Gerente → Compras → PO to Approve
- Esperar: botón "Approve" visible. Aprobar.
- Verificar: botón "Confirm Order" aparece en la OC
F2 — Flujo multi-nivel secuencial (2 niveles)
- Crear regla: sequence=1 (Supervisor, 0-5000) y sequence=2 (Gerente, 0 a -1)
- OC por 3000 → enviar para aprobación
- Iniciar sesión como Gerente: verificar que botón Approve NO aparece aún
- Iniciar sesión como Supervisor: aprobar
- Volver como Gerente: ahora sí aparece botón Approve. Aprobar.
- Verificar: OC lista para confirmar
F3 — Rechazo con motivo
- OC en aprobación → aprobador activo clic "❌ Reject"
- Ingresar motivo en el wizard → clic "Reject"
- Verificar: OC vuelve a borrador, campos editables
- Verificar: motivo registrado en pestaña "Approval History"
F4 — Bloqueo de edición durante aprobación
- OC enviada para aprobación (sin rechazar)
- Intentar editar líneas de productos, proveedor o fecha
- Verificar: campos bloqueados (readonly). Solo se desbloquean si la OC es rechazada.
F5 — Límite mensual
- Configurar línea de regla con monthly_purchase_limit = 10000
- Aprobar OCs hasta acumular >10000 en el mes con ese aprobador
- Nueva OC → enviar para aprobación
- Verificar: pestaña Analytics muestra alerta naranja con % de uso
F6 — Reception Tracking
- OC confirmada con recepciones parciales registradas
- OC → pestaña "Reception Tracking"
- Verificar: Monto Recibido = sum(qty_received × price_unit), Monto Pendiente = total − recibido
- Imprimir reporte PDF: verificar columna "Monto Recibido" por línea y filas de totales de recepción
F7 — Refresh de jerarquía
- OC en borrador o enviada → clic "🔄 Refresh Approval Hierarchy"
- Confirmar en el diálogo
- Verificar: líneas en pestaña "Approval Hierarchy" regeneradas con configuración actual
F8 — Validación de rangos solapados
- Compras → Configuración → Reglas de aprobación
- Crear dos líneas con el mismo sequence y rangos solapados (ej. 0-5000 y 3000-10000)
- Verificar: error "Overlapping amount ranges detected" al guardar
2. crm_custom_fields
Campos logísticos para oportunidades CRM. Odoo 18. Versión 18.0.1.0.
2.1 Descripción Funcional
Extiende las oportunidades de CRM con campos específicos para el negocio de transporte y logística de HPL Apollo. Permite registrar volúmenes cotizados, tarifas de venta y costo, y calcular automáticamente márgenes de ganancia (GP) para 5 tipos de servicio: flete aéreo, marítimo, terrestre, almacenamiento y aduanas.
Características principales:
- Campos de cotización por tipo de flete con cálculo automático de margen
- GP global semanal/mensual/anual (el anual actualiza el campo expected_revenue de la oportunidad)
- Rutas de transporte (lanes) vinculadas a cada oportunidad
- Asociación a ferias comerciales (tradeshows) y visitas de campo
2.2 Arquitectura Técnica
Modelos
| Modelo | Tipo | Descripción |
|---|---|---|
| crm.lead | Extensión | Todos los campos logísticos por tipo de flete y GP global |
| crm.lane | Nuevo | Rutas de transporte (origen-destino) |
| crm.tradeshow | Nuevo | Ferias y eventos comerciales |
| crm.field_visits | Nuevo | Visitas de campo |
Campos en crm.lead — GP Global
| Campo | Tipo | Descripción |
|---|---|---|
| estimated_gp_week_shared | Float | GP semanal total (entrada manual) |
| estimated_gp_month_shared | Float (computed) | = semanal × 4.33 |
| estimated_gp_year_shared | Float (computed) | = mensual × 12. También escribe en expected_revenue. |
| actual_forwarder | Char | Forwarder actual del cliente |
| lane_ids | Many2many crm.lane | Rutas de transporte asociadas |
| commodity_detail | Text | Detalle de la mercancía |
| lead_source | Selection | Origen del lead |
| tradeshow_id | Many2one crm.tradeshow | Feria comercial asociada |
| field_visits_id | Many2one crm.field_visits | Visita de campo asociada |
Campos en crm.lead — Por Tipo de Flete
| Tipo | Volumen | Selling Rate | Buying/Airline Rate | Margen GP (computed) |
|---|---|---|---|---|
| Aéreo | air_volume_per_week_kgs | air_quoted_selling_rate | air_quoted_airline_rate | air_margin_expected_gp_kgs = selling − airline |
| Marítimo | sea_volume_per_week_teus | sea_quoted_selling_rate | sea_quoted_buying_rate | sea_margin_expected_gp_teu = selling − buying |
| Terrestre | road_volume_per_week_trailer | road_quoted_selling_rate | road_quoted_buying_rate | road_margin_expected_gp_trailer = selling − buying |
| Almacenamiento | warehousing_volume_per_week_kg | warehousing_quoted_selling_rate | warehousing_cost_rate | warehousing_margin_expected_gp_kg = selling − cost |
| Aduanas | — | customs_quoted_selling_rate | customs_cost_rate | customs_margin_expected_gp = selling − cost |
2.3 Navegación
| Acción | Ruta |
|---|---|
| Ver campos logísticos de una oportunidad | CRM → Oportunidades → [oportunidad] → pestañas Aéreo / Marítimo / Terrestre / Almacenamiento / Aduanas |
| Ver GP calculado | CRM → [oportunidad] → sección "GP Global" (pestaña principal o lateral) |
| Gestionar rutas de transporte | CRM → Configuración → Lanes |
| Gestionar ferias comerciales | CRM → Configuración → Tradeshows |
| Gestionar visitas de campo | CRM → Configuración → Field Visits |
2.4 Pruebas Funcionales
F9 — Cálculo de GP por tipo de flete
- CRM → Oportunidades → nueva oportunidad
- Pestaña Aéreo: ingresar volume=100 kgs, selling_rate=5, airline_rate=3
- Verificar: air_margin_expected_gp_kgs = 2 (selling − airline)
F10 — GP global actualiza expected_revenue
- En la oportunidad, ingresar estimated_gp_week_shared = 1000
- Verificar: estimated_gp_month_shared = 4330 (×4.33)
- Verificar: estimated_gp_year_shared = 51960 (×12)
- Verificar: campo "Expected Revenue" de la oportunidad = 51960
F11 — Asociación de rutas (lanes)
- CRM → Configuración → Lanes → crear ruta "Lima → Miami"
- CRM → Oportunidades → [oportunidad] → campo Lane → asignar "Lima → Miami"
- Verificar: la ruta queda vinculada y visible en la oportunidad
3. Dependencias y Arquitectura Global
purchase_approval_kanak (v18.0.1.0)
← purchase (Odoo nativo)
← hr (Odoo nativo)
← stock (Odoo nativo)
Extiende:
→ purchase.order (workflow de aprobación + reception tracking)
→ hr.employee (approval_role, warehouse_id)
→ product.template (approval_category)
→ res.company (configuración de reglas)
→ res.config.settings (UI de ajustes)
crm_custom_fields (v18.0.1.0)
← base (Odoo nativo)
← crm (Odoo nativo)
Extiende:
→ crm.lead (campos logísticos y GP)
Modelos nuevos:
→ crm.lane
→ crm.tradeshow
→ crm.field_visits
Los dos módulos son independientes entre sí.
Pueden instalarse por separado.
Documentación técnica HPL Apollo — ITC Services — 2026-03-12