mirror of
https://github.com/cursos-uai/sap_tfi_2026.git
synced 2026-07-31 20:48:30 -03:00
feat(initial-iteration): primera iteración ICONIX del flujo venta→factura→pago
Documentación generada: - 7 casos de uso (CU-VEN-001, CU-VEN-004, CU-ENT-002, CU-ENT-004, CU-FAC-001, CU-FAC-002, CU-FAC-003) - Modelo de dominio inicial (12 conceptos, 9 reglas de negocio) - Arquitectura general (C4 contexto + contenedores) - Prototipo del formulario de presupuesto - 5 diagramas PlantUML (.puml): - Diagrama general de casos de uso - Modelo de dominio conceptual - Diagrama de robustez de CU-VEN-004 - Diagrama de secuencia de CU-VEN-004 - Diagrama de clases técnicas (integración Venta/Stock/Contabilidad) - Matriz de trazabilidad con 20 EV-COD y 22 EV-INF Odoo analizado: 19.0 Community (rama 19.0) Método: ingeniería inversa con verificación de código fuente Nota: NO pushear (gate S2). Ale debe revisar antes de merge a main.
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
# CU-ENT-002 — Reservar productos
|
||||
|
||||
## Objetivo
|
||||
|
||||
Reservar las cantidades pedidas de cada producto en el almacén, asegurando disponibilidad antes de la entrega.
|
||||
|
||||
## Alcance
|
||||
|
||||
Módulo `stock` de Odoo 19.0. Aplica al modelo `stock.picking`.
|
||||
|
||||
## Nivel
|
||||
|
||||
Primario (esencial para garantizar disponibilidad).
|
||||
|
||||
## Actor principal
|
||||
|
||||
Sistema (operador de inventario puede forzarlo manualmente).
|
||||
|
||||
## Actores secundarios
|
||||
|
||||
- Sistema de Odoo (acción automática al confirmar pedido de venta).
|
||||
|
||||
## Interesados
|
||||
|
||||
- Operador de inventario.
|
||||
- Vendedor (necesita saber si hay stock).
|
||||
- Cliente (recibe confirmación de entrega).
|
||||
|
||||
## Disparador
|
||||
|
||||
- Confirmación de un pedido de venta (CU-VEN-004) — sistema dispara automáticamente.
|
||||
- Botón manual "Reservar" en el picking (interfaz de inventario).
|
||||
|
||||
## Precondiciones
|
||||
|
||||
- El picking está en estado `draft` o `waiting` o `confirmed`.
|
||||
- Los productos tienen stock disponible o se puede conseguir (vía reglas de abastecimiento).
|
||||
|
||||
## Garantías mínimas
|
||||
|
||||
El sistema intenta reservar las cantidades; si no puede, deja el picking en `partially_available` o `confirmed`.
|
||||
|
||||
## Garantías de éxito
|
||||
|
||||
- Estado del picking: `assigned`.
|
||||
- Las cantidades reservadas se reflejan en `stock.move.line` con `reserved_availability`.
|
||||
|
||||
## Flujo principal
|
||||
|
||||
1. Sistema invoca `action_assign()` sobre el picking (ver `addons/stock/models/stock_picking.py:1195`).
|
||||
2. Sistema busca cantidades disponibles por cada línea.
|
||||
3. Si hay stock disponible, sistema crea `stock.move.line` con `product_qty = reserved_availability`.
|
||||
4. Si NO hay stock, sistema busca reglas de reabastecimiento (MTO, MTS, etc.).
|
||||
5. Si se reabastece, sistema programa una orden de compra.
|
||||
6. Si nada funciona, sistema deja el picking en estado `partially_available`.
|
||||
7. Estado del picking cambia a `assigned` cuando todas las líneas tienen reserva.
|
||||
|
||||
## Flujos alternativos
|
||||
|
||||
### FA-01 — Reserva parcial
|
||||
|
||||
1. Sistema reserva parte de las cantidades.
|
||||
2. Líneas con reserva quedan con `assigned`.
|
||||
3. Líneas sin reserva quedan con `partially_available`.
|
||||
4. El picking NO cambia a `assigned` global.
|
||||
|
||||
### FA-02 — Backorder automático
|
||||
|
||||
1. Al validar (CU-ENT-004), si hay líneas pendientes, sistema crea un nuevo picking con backorder.
|
||||
|
||||
## Excepciones
|
||||
|
||||
### EX-01 — Sin stock y sin regla de reabastecimiento
|
||||
|
||||
1. Sistema no encuentra stock ni reglas aplicables.
|
||||
2. Sistema deja el picking en `partially_available` o `confirmed`.
|
||||
3. Operador debe decidir acción manual.
|
||||
|
||||
## Reglas de negocio
|
||||
|
||||
- **RN-ENT-002**: La reserva no afecta disponibilidad para otros pedidos hasta que se confirme el picking.
|
||||
- **RN-ENT-003**: Las reservas se liberan automáticamente al cancelar el pedido o el picking.
|
||||
|
||||
## Datos de entrada
|
||||
|
||||
- Picking con líneas (`stock.move`).
|
||||
|
||||
## Datos de salida
|
||||
|
||||
- Stock.move.line con reservas.
|
||||
- Estado del picking actualizado.
|
||||
- Posibles órdenes de compra generadas.
|
||||
|
||||
## Estados involucrados
|
||||
|
||||
- `draft` → `confirmed` → `assigned` (reserva completa).
|
||||
- `draft` → `confirmed` → `partially_available` (reserva parcial).
|
||||
|
||||
## Pantallas involucradas
|
||||
|
||||
- `view_picking_form` — form del picking.
|
||||
- `view_stock_move_line_tree` — vista tree de movimientos reservados.
|
||||
|
||||
## Modelos de Odoo relacionados
|
||||
|
||||
- `stock.picking` (principal).
|
||||
- `stock.move` (líneas del picking).
|
||||
- `stock.move.line` (reservas).
|
||||
- `stock.warehouse.orderpoint` (reglas de reabastecimiento).
|
||||
- `procurement.order` (orden de compra generada).
|
||||
|
||||
## Métodos de Odoo relacionados
|
||||
|
||||
- `action_assign()` — entry point (ver `addons/stock/models/stock_picking.py:1195`).
|
||||
- `action_confirm()` — confirma el picking (ver `addons/stock/models/stock_picking.py:1186`).
|
||||
|
||||
## Permisos requeridos
|
||||
|
||||
- `stock.group_stock_user` — para reservar.
|
||||
- Sistema automático al confirmar pedido.
|
||||
|
||||
## Configuraciones relevantes
|
||||
|
||||
- Reglas de reabastecimiento (`stock.warehouse.orderpoint`).
|
||||
- Política de stock (MTO, MTS, etc.).
|
||||
|
||||
## Casos de uso relacionados
|
||||
|
||||
- CU-VEN-004 Confirmar pedido de venta (disparador).
|
||||
- CU-ENT-004 Validar entrega (siguiente paso).
|
||||
|
||||
## Criterios de aceptación
|
||||
|
||||
- [ ] Al confirmar un pedido, el picking cambia a `assigned` si hay stock.
|
||||
- [ ] Si no hay stock, el picking queda en `partially_available`.
|
||||
- [ ] Las reservas se reflejan en `stock.move.line`.
|
||||
|
||||
## Evidencias de ingeniería inversa
|
||||
|
||||
- **EV-COD-010**: `addons/stock/models/stock_picking.py:1195` — método `action_assign`.
|
||||
- **EV-COD-011**: `addons/stock/models/stock_picking.py:1186` — método `action_confirm`.
|
||||
|
||||
## Supuestos y aspectos pendientes de validación
|
||||
|
||||
- **EV-INF-006**: La lógica interna de `action_assign()` (cómo busca stock, cómo aplica reglas de reabastecimiento) no fue leída en detalle. Solo se confirmó que existe.
|
||||
- **EV-INF-007**: La integración con `procurement.order` requiere verificación adicional.
|
||||
@@ -0,0 +1,151 @@
|
||||
# CU-ENT-004 — Validar entrega
|
||||
|
||||
## Objetivo
|
||||
|
||||
Confirmar la salida física de los productos del almacén, completando el picking y disparando los efectos downstream (actualización de stock, facturación).
|
||||
|
||||
## Alcance
|
||||
|
||||
Módulo `stock` de Odoo 19.0. Aplica al modelo `stock.picking`.
|
||||
|
||||
## Nivel
|
||||
|
||||
Primario (esencial para cerrar el flujo de inventario).
|
||||
|
||||
## Actor principal
|
||||
|
||||
Operador de almacén (usuario con permisos `stock.group_stock_user` o `stock.group_stock_manager`).
|
||||
|
||||
## Actores secundarios
|
||||
|
||||
- Sistema de cuenta (puede disparar facturación al validar).
|
||||
|
||||
## Interesados
|
||||
|
||||
- Operador de almacén.
|
||||
- Cliente (recibe productos).
|
||||
- Responsable de facturación (recibe señal para facturar).
|
||||
|
||||
## Disparador
|
||||
|
||||
El operador hace clic en "Validar" en la vista form del picking.
|
||||
|
||||
## Precondiciones
|
||||
|
||||
- El picking está en estado `assigned` (con todas las reservas) o `partially_available` (parcial).
|
||||
- Las cantidades reservadas o a entregar son válidas.
|
||||
|
||||
## Garantías mínimas
|
||||
|
||||
El sistema cambia el estado del picking a `done` o muestra un error explicativo.
|
||||
|
||||
## Garantías de éxito
|
||||
|
||||
- Estado del picking: `done`.
|
||||
- Stock actualizado (las cantidades reservadas se descuentan del stock disponible).
|
||||
- Posible creación automática de factura si está configurado.
|
||||
|
||||
## Flujo principal
|
||||
|
||||
1. Operador hace clic en "Validar" → sistema invoca `button_validate()` (ver `addons/stock/models/stock_picking.py:1398`).
|
||||
2. Sistema muestra wizard de validación con cantidades (permite ajustar).
|
||||
3. Operador confirma las cantidades reales entregadas.
|
||||
4. Sistema actualiza `stock.move` con las cantidades reales.
|
||||
5. Sistema crea `stock.move.line` definitivos.
|
||||
6. Sistema actualiza el stock cuantitativo (`stock.quant`).
|
||||
7. Estado del picking cambia a `done`.
|
||||
|
||||
## Flujos alternativos
|
||||
|
||||
### FA-01 — Entrega parcial con backorder
|
||||
|
||||
1. Operador entrega solo una parte de las cantidades.
|
||||
2. Sistema crea un nuevo picking (backorder) con las cantidades pendientes.
|
||||
3. Picking original queda en `done` con las cantidades entregadas.
|
||||
4. Backorder queda en `assigned` o `confirmed` para entrega posterior.
|
||||
|
||||
### FA-02 — Crear factura al validar
|
||||
|
||||
1. Si está configurado, al validar, sistema crea automáticamente una factura (`account.move`).
|
||||
2. Esto vincula la salida de stock con la facturación inmediata.
|
||||
|
||||
## Excepciones
|
||||
|
||||
### EX-01 — Cantidad excede lo reservado
|
||||
|
||||
1. Operador intenta entregar más cantidad de la que está reservada.
|
||||
2. Sistema valida y rechaza si excede.
|
||||
3. Sistema muestra error claro.
|
||||
|
||||
### EX-02 — Picking no asignable
|
||||
|
||||
1. Picking en estado `draft` o `cancel`.
|
||||
2. Sistema no permite validar.
|
||||
|
||||
## Reglas de negocio
|
||||
|
||||
- **RN-ENT-004**: Al validar, las cantidades reservadas pasan a `done`.
|
||||
- **RN-ENT-005**: Backorder automático configurable vía `stock.backorder_confirmation_policy`.
|
||||
|
||||
## Datos de entrada
|
||||
|
||||
- Picking en estado `assigned` o `partially_available`.
|
||||
- Cantidades reales (pueden diferir de las reservadas).
|
||||
|
||||
## Datos de salida
|
||||
|
||||
- Picking en `done`.
|
||||
- Stock actualizado.
|
||||
- Posible factura generada.
|
||||
|
||||
## Estados involucrados
|
||||
|
||||
- `assigned` → `done` (validación completa).
|
||||
- `partially_available` → `done` (validación parcial, genera backorder).
|
||||
|
||||
## Pantallas involucradas
|
||||
|
||||
- `view_picking_form` — botón "Validar".
|
||||
- `view_stock_immediate_transfer` — wizard de validación.
|
||||
|
||||
## Modelos de Odoo relacionados
|
||||
|
||||
- `stock.picking` (principal).
|
||||
- `stock.move` (movimientos).
|
||||
- `stock.move.line` (líneas definitivas).
|
||||
- `stock.quant` (stock cuantitativo actualizado).
|
||||
- `stock.backorder.confirmation` (wizard de backorder).
|
||||
|
||||
## Métodos de Odoo relacionados
|
||||
|
||||
- `button_validate()` — entry point (ver `addons/stock/models/stock_picking.py:1398`).
|
||||
|
||||
## Permisos requeridos
|
||||
|
||||
- `stock.group_stock_user` (puede validar pickings simples).
|
||||
- `stock.group_stock_manager` (puede validar pickings complejos o cancelar reservas).
|
||||
|
||||
## Configuraciones relevantes
|
||||
|
||||
- `stock.backorder_confirmation_policy` — política de backorder.
|
||||
- `stock.move.auto_fill` — auto-llenar cantidades.
|
||||
|
||||
## Casos de uso relacionados
|
||||
|
||||
- CU-ENT-002 Reservar productos (precondición).
|
||||
- CU-FAC-001 Crear factura (downstream, opcional).
|
||||
|
||||
## Criterios de aceptación
|
||||
|
||||
- [ ] Al validar un picking completo, el stock se descuenta correctamente.
|
||||
- [ ] Al validar parcialmente, se crea un backorder automático.
|
||||
- [ ] El estado del picking cambia a `done`.
|
||||
|
||||
## Evidencias de ingeniería inversa
|
||||
|
||||
- **EV-COD-012**: `addons/stock/models/stock_picking.py:1398` — método `button_validate`.
|
||||
|
||||
## Supuestos y aspectos pendientes de validación
|
||||
|
||||
- **EV-INF-008**: La lógica interna de `button_validate()` (cómo ajusta cantidades, cómo crea backorder) no fue leída en detalle.
|
||||
- **EV-INF-009**: La integración con facturación automática al validar requiere verificación.
|
||||
@@ -0,0 +1,154 @@
|
||||
# CU-FAC-001 — Crear factura desde pedido
|
||||
|
||||
## Objetivo
|
||||
|
||||
Generar una factura (`account.move`) basada en un pedido de venta confirmado, para registrar la venta en el sistema contable.
|
||||
|
||||
## Alcance
|
||||
|
||||
Módulo `sale` (Odoo 19.0) que invoca a `account` para crear la factura. Aplica al modelo `sale.order`.
|
||||
|
||||
## Nivel
|
||||
|
||||
Primario (esencial para el circuito contable).
|
||||
|
||||
## Actor principal
|
||||
|
||||
Responsable de facturación o sistema (acción automática configurable).
|
||||
|
||||
## Actores secundarios
|
||||
|
||||
- Vendedor (solicita facturación).
|
||||
- Sistema contable (registra el asiento).
|
||||
|
||||
## Interesados
|
||||
|
||||
- Responsable de facturación.
|
||||
- Contador (visualiza asientos).
|
||||
- Cliente (recibe factura).
|
||||
|
||||
## Disparador
|
||||
|
||||
- Manual: vendedor o facturador hace clic en "Crear factura" en el pedido.
|
||||
- Automático: al validar la entrega (CU-ENT-004), si está configurado.
|
||||
- Automático: al alcanzar la política de facturación del pedido (`invoice_status`).
|
||||
|
||||
## Precondiciones
|
||||
|
||||
- El pedido está en estado `sale`.
|
||||
- Hay productos a facturar (no todo está ya facturado).
|
||||
- El cliente y la compañía tienen configurados los diarios contables.
|
||||
|
||||
## Garantías mínimas
|
||||
|
||||
El sistema crea un `account.move` en estado `draft` o muestra un error.
|
||||
|
||||
## Garantías de éxito
|
||||
|
||||
- Factura creada en estado `draft`.
|
||||
- Línea de factura con `quantity`, `price_unit`, `tax_ids` correctos.
|
||||
- `invoice_origin` apunta al pedido original.
|
||||
|
||||
## Flujo principal
|
||||
|
||||
1. Usuario hace clic en "Crear factura" → sistema invoca `_create_invoices()` (ver `addons/sale/models/sale_order.py:1550`).
|
||||
2. Sistema prepara las líneas de factura con `_prepare_invoice()` (ver `addons/sale/models/sale_order.py:1411`).
|
||||
3. Sistema crea un nuevo `account.move` con tipo `out_invoice` (factura de cliente).
|
||||
4. Sistema crea las `account.move.line` correspondientes.
|
||||
5. Sistema vincula el pedido con la factura vía `invoice_ids` (Many2many).
|
||||
6. Sistema actualiza `invoice_status` del pedido según corresponda.
|
||||
7. Factura queda en estado `draft`.
|
||||
|
||||
## Flujos alternativos
|
||||
|
||||
### FA-01 — Facturación agrupada
|
||||
|
||||
1. Sistema agrupa múltiples pedidos en una sola factura (cuando `grouped=True`).
|
||||
2. Sistema crea una factura con líneas de todos los pedidos.
|
||||
3. Cada pedido referencia la factura agrupada.
|
||||
|
||||
### FA-02 — Facturación parcial
|
||||
|
||||
1. Sistema factura solo una parte de las cantidades (parcial o downpayment).
|
||||
2. Resto queda pendiente para futuras facturas.
|
||||
|
||||
## Excepciones
|
||||
|
||||
### EX-01 — Todo ya facturado
|
||||
|
||||
1. Sistema detecta que `invoice_status` es `invoiced`.
|
||||
2. Sistema retorna mensaje "Nothing to invoice".
|
||||
|
||||
### EX-02 — Compañía sin diario configurado
|
||||
|
||||
1. Compañía no tiene `currency_id` o `journal_id` configurado.
|
||||
2. Sistema retorna error de configuración.
|
||||
|
||||
## Reglas de negocio
|
||||
|
||||
- **RN-FAC-001**: Solo se puede facturar un pedido en estado `sale`.
|
||||
- **RN-FAC-002**: Una factura no se puede modificar después de publicarse (CU-FAC-002), solo cancelar.
|
||||
|
||||
## Datos de entrada
|
||||
|
||||
- Pedido en estado `sale`.
|
||||
- Cantidades a facturar (pueden ser parciales).
|
||||
|
||||
## Datos de salida
|
||||
|
||||
- `account.move` (factura) en estado `draft`.
|
||||
- `account.move.line` (líneas de factura).
|
||||
|
||||
## Estados involucrados
|
||||
|
||||
- Factura: `draft` → `posted` (después de CU-FAC-002).
|
||||
|
||||
## Pantallas involucradas
|
||||
|
||||
- `view_sale_order_form` — botón "Crear factura".
|
||||
- `account.view_move_form` — form de la factura creada.
|
||||
|
||||
## Modelos de Odoo relacionados
|
||||
|
||||
- `sale.order` (origen).
|
||||
- `sale.order.line` (líneas a facturar).
|
||||
- `account.move` (factura creada).
|
||||
- `account.move.line` (líneas de factura).
|
||||
- `account.tax` (impuestos aplicados).
|
||||
|
||||
## Métodos de Odoo relacionados
|
||||
|
||||
- `_create_invoices()` — entry point (ver `addons/sale/models/sale_order.py:1550`).
|
||||
- `_prepare_invoice()` — prepara valores (ver `addons/sale/models/sale_order.py:1411`).
|
||||
|
||||
## Permisos requeridos
|
||||
|
||||
- `sales_team.group_sale_salesman_all` o `account.group_account_invoice` — para crear facturas.
|
||||
|
||||
## Configuraciones relevantes
|
||||
|
||||
- Política de facturación del pedido (`invoice_policy`).
|
||||
- Diarios contables en `res.company`.
|
||||
|
||||
## Casos de uso relacionados
|
||||
|
||||
- CU-VEN-004 Confirmar pedido de venta (precondición).
|
||||
- CU-ENT-004 Validar entrega (puede disparar).
|
||||
- CU-FAC-002 Publicar factura (siguiente paso).
|
||||
|
||||
## Criterios de aceptación
|
||||
|
||||
- [ ] Al facturar un pedido confirmado, se crea una factura en estado `draft`.
|
||||
- [ ] La factura referencia correctamente al pedido origen.
|
||||
- [ ] Los totales coinciden con las líneas facturadas.
|
||||
|
||||
## Evidencias de ingeniería inversa
|
||||
|
||||
- **EV-COD-013**: `addons/sale/models/sale_order.py:1550` — método `_create_invoices`.
|
||||
- **EV-COD-014**: `addons/sale/models/sale_order.py:1411` — método `_prepare_invoice`.
|
||||
- **EV-COD-015**: `addons/account/models/account_move.py:72-73` — definición de `AccountMove` con `_name = 'account.move'`.
|
||||
|
||||
## Supuestos y aspectos pendientes de validación
|
||||
|
||||
- **EV-INF-010**: La lógica de agrupación de facturas (`grouped=True`) no fue leída en detalle.
|
||||
- **EV-INF-011**: La integración con `_action_invoice_create` (versión legacy) requiere verificación.
|
||||
@@ -0,0 +1,152 @@
|
||||
# CU-FAC-002 — Publicar factura
|
||||
|
||||
## Objetivo
|
||||
|
||||
Publicar (confirmar) una factura en estado `draft`, generando el asiento contable y haciendo la factura oficial.
|
||||
|
||||
## Alcance
|
||||
|
||||
Módulo `account` de Odoo 19.0. Aplica al modelo `account.move`.
|
||||
|
||||
## Nivel
|
||||
|
||||
Primario (esencial — la factura no tiene valor contable hasta publicarse).
|
||||
|
||||
## Actor principal
|
||||
|
||||
Responsable de facturación o Contador (usuario con permisos `account.group_account_invoice`).
|
||||
|
||||
## Actores secundarios
|
||||
|
||||
- Sistema contable (genera asiento).
|
||||
|
||||
## Interesados
|
||||
|
||||
- Contador (visualiza asientos).
|
||||
- Cliente (recibe factura oficial).
|
||||
- Administración (reportes contables).
|
||||
|
||||
## Disparador
|
||||
|
||||
El usuario hace clic en "Confirmar" en la vista form de la factura.
|
||||
|
||||
## Precondiciones
|
||||
|
||||
- La factura está en estado `draft`.
|
||||
- Las líneas tienen impuestos y cuentas contables válidas.
|
||||
- El diario contable está configurado.
|
||||
|
||||
## Garantías mínimas
|
||||
|
||||
El sistema cambia el estado de la factura o muestra un error explicativo.
|
||||
|
||||
## Garantías de éxito
|
||||
|
||||
- Estado de la factura: `posted`.
|
||||
- Asiento contable generado (`account.move` con `state='posted'`).
|
||||
- `invoice_date` con la fecha de publicación.
|
||||
- Número de factura asignado por secuencia.
|
||||
|
||||
## Flujo principal
|
||||
|
||||
1. Usuario hace clic en "Confirmar" → sistema invoca `action_post()` (ver `addons/account/models/account_move.py:6101`).
|
||||
2. Sistema valida la factura:
|
||||
- Líneas con productos y precios válidos.
|
||||
- Impuestos aplicados correctamente.
|
||||
- Cuentas contables válidas.
|
||||
3. Si pasa validación, sistema genera el asiento contable (una línea por cada movimiento).
|
||||
4. Sistema asigna número de factura por secuencia del diario.
|
||||
5. Sistema actualiza `state` a `posted`.
|
||||
6. Sistema actualiza `invoice_date` a la fecha actual.
|
||||
|
||||
## Flujos alternativos
|
||||
|
||||
### FA-01 — Publicación masiva
|
||||
|
||||
1. Usuario selecciona múltiples facturas draft.
|
||||
2. Sistema itera y publica cada una.
|
||||
3. Si alguna falla, sistema muestra error y detiene.
|
||||
|
||||
### FA-02 — Reversión a draft
|
||||
|
||||
1. Si la factura necesita corrección, usuario con permisos puede invocar `action_post_draft()`.
|
||||
2. Sistema revierte a `draft`, permite edición.
|
||||
3. Vuelve a publicar cuando esté listo.
|
||||
|
||||
## Excepciones
|
||||
|
||||
### EX-01 — Líneas sin cuenta contable
|
||||
|
||||
1. Alguna línea no tiene cuenta contable asignada.
|
||||
2. Sistema muestra error "Cuenta contable requerida".
|
||||
|
||||
### EX-02 — Factura con totales en cero
|
||||
|
||||
1. Factura con líneas pero totales son 0.
|
||||
2. Sistema puede advertir o bloquear según configuración.
|
||||
|
||||
## Reglas de negocio
|
||||
|
||||
- **RN-FAC-003**: Una factura publicada no se puede borrar, solo revertir a draft.
|
||||
- **RN-FAC-004**: Al publicar, se crea un asiento contable con la fecha del día.
|
||||
|
||||
## Datos de entrada
|
||||
|
||||
- Factura en estado `draft`.
|
||||
|
||||
## Datos de salida
|
||||
|
||||
- Factura en estado `posted`.
|
||||
- Asiento contable generado.
|
||||
- Número de factura asignado.
|
||||
|
||||
## Estados involucrados
|
||||
|
||||
- `draft` → `posted` (transición principal).
|
||||
- `posted` → `draft` (reversión, vía `action_post_draft()`).
|
||||
|
||||
## Pantallas involucradas
|
||||
|
||||
- `account.view_move_form` — botón "Confirmar".
|
||||
|
||||
## Modelos de Odoo relacionados
|
||||
|
||||
- `account.move` (factura + asiento).
|
||||
- `account.move.line` (líneas, ahora con cuenta contable).
|
||||
- `account.journal` (diario contable).
|
||||
|
||||
## Métodos de Odoo relacionados
|
||||
|
||||
- `action_post()` — entry point (ver `addons/account/models/account_move.py:6101`).
|
||||
- `action_post_draft()` — reversión.
|
||||
|
||||
## Permisos requeridos
|
||||
|
||||
- `account.group_account_invoice` — para publicar.
|
||||
|
||||
## Configuraciones relevantes
|
||||
|
||||
- Secuencia de facturas en el diario (`account.journal.sequence_id`).
|
||||
- Configuración de impuestos y cuentas.
|
||||
|
||||
## Casos de uso relacionados
|
||||
|
||||
- CU-FAC-001 Crear factura (precondición).
|
||||
- CU-FAC-003 Registrar pago (siguiente paso).
|
||||
|
||||
## Criterios de aceptación
|
||||
|
||||
- [ ] Una factura en `draft` puede publicarse si pasa las validaciones.
|
||||
- [ ] Al publicar, se genera el asiento contable.
|
||||
- [ ] El número de factura es único y secuencial.
|
||||
|
||||
## Evidencias de ingeniería inversa
|
||||
|
||||
- **EV-COD-016**: `addons/account/models/account_move.py:6101` — método `action_post`.
|
||||
- **EV-COD-017**: `addons/account/models/account_move.py:72-73` — definición de `AccountMove` con `_name = 'account.move'`.
|
||||
- **EV-COD-018**: `addons/account/models/account_move.py:129` — campo `state = fields.Selection(...)`.
|
||||
|
||||
## Supuestos y aspectos pendientes de validación
|
||||
|
||||
- **EV-INF-012**: La lógica interna de `action_post()` (cómo genera el asiento, cómo asigna cuentas) no fue leída en detalle.
|
||||
- **EV-INF-013**: Las validaciones específicas (impuestos, cuentas, totales) requieren lectura adicional.
|
||||
@@ -0,0 +1,160 @@
|
||||
# CU-FAC-003 — Registrar pago
|
||||
|
||||
## Objetivo
|
||||
|
||||
Registrar el pago de una factura, marcando el saldo como cobrado y actualizando el estado de pago del cliente.
|
||||
|
||||
## Alcance
|
||||
|
||||
Módulo `account` de Odoo 19.0. Aplica al modelo `account.move`.
|
||||
|
||||
## Nivel
|
||||
|
||||
Primario (cierra el circuito de venta).
|
||||
|
||||
## Actor principal
|
||||
|
||||
Responsable de facturación o Contador (usuario con permisos `account.group_account_invoice` o `account.group_account_user`).
|
||||
|
||||
## Actores secundarios
|
||||
|
||||
- Sistema bancario (si hay integración).
|
||||
- Cliente (origen del pago).
|
||||
|
||||
## Interesados
|
||||
|
||||
- Contador (visualiza estado de pagos).
|
||||
- Cliente (ve su saldo actualizado).
|
||||
|
||||
## Disparador
|
||||
|
||||
El usuario hace clic en "Registrar pago" en la factura.
|
||||
|
||||
## Precondiciones
|
||||
|
||||
- La factura está en estado `posted`.
|
||||
- La factura no está completamente pagada (o se requiere un pago parcial).
|
||||
|
||||
## Garantías mínimas
|
||||
|
||||
El sistema crea un `account.payment` o equivalente y actualiza el estado de pago.
|
||||
|
||||
## Garantías de éxito
|
||||
|
||||
- Pago registrado en el sistema.
|
||||
- Estado de pago de la factura: `paid` (si es pago completo) o `partial` (si parcial).
|
||||
- Asiento contable de pago generado.
|
||||
|
||||
## Flujo principal
|
||||
|
||||
1. Usuario hace clic en "Registrar pago" → sistema invoca `action_register_payment()` (ver `addons/account/models/account_move.py:6022`).
|
||||
2. Sistema abre wizard de registro de pago (`account.payment.register`).
|
||||
3. Usuario completa:
|
||||
- Fecha del pago.
|
||||
- Diario de banco/caja.
|
||||
- Método de pago.
|
||||
- Monto (por defecto, saldo pendiente).
|
||||
4. Usuario confirma.
|
||||
5. Sistema crea `account.payment` con el monto y método.
|
||||
6. Sistema genera el asiento contable del pago (débito a banco, crédito a cuenta del cliente).
|
||||
7. Sistema reconcilia el pago con la factura.
|
||||
8. Sistema actualiza `payment_state` de la factura:
|
||||
- `paid` si el pago completa el saldo.
|
||||
- `partial` si es parcial.
|
||||
- `in_payment` si está en proceso (cheques, etc.).
|
||||
|
||||
## Flujos alternativos
|
||||
|
||||
### FA-01 — Pago parcial
|
||||
|
||||
1. Usuario registra un pago menor al saldo.
|
||||
2. Sistema crea el pago parcial.
|
||||
3. `payment_state` queda en `partial`.
|
||||
4. Queda saldo pendiente para pagos futuros.
|
||||
|
||||
### FA-02 — Pago múltiple
|
||||
|
||||
1. Usuario registra varios pagos para la misma factura.
|
||||
2. Cada pago genera un `account.payment` separado.
|
||||
3. Cuando se completa el saldo, `payment_state` pasa a `paid`.
|
||||
|
||||
## Excepciones
|
||||
|
||||
### EX-01 — Factura no posted
|
||||
|
||||
1. Factura en estado `draft` o `cancel`.
|
||||
2. Sistema no permite registrar pago.
|
||||
|
||||
### EX-02 — Pago mayor al saldo
|
||||
|
||||
1. Usuario intenta pagar más de lo adeudado.
|
||||
2. Sistema advierte o rechaza según configuración.
|
||||
|
||||
## Reglas de negocio
|
||||
|
||||
- **RN-FAC-005**: Una factura pagada no puede recibir más pagos (saldo = 0).
|
||||
- **RN-FAC-006**: El estado `payment_state` se calcula automáticamente en función de los pagos.
|
||||
|
||||
## Datos de entrada
|
||||
|
||||
- Factura en estado `posted`.
|
||||
- Datos del pago (fecha, diario, método, monto).
|
||||
|
||||
## Datos de salida
|
||||
|
||||
- `account.payment` creado.
|
||||
- Asiento contable de pago.
|
||||
- `payment_state` actualizado.
|
||||
|
||||
## Estados involucrados
|
||||
|
||||
- Factura: `posted` → `payment_state=in_payment` → `payment_state=paid`.
|
||||
- O `posted` → `payment_state=partial` → `payment_state=paid` (pagos múltiples).
|
||||
|
||||
## Pantallas involucradas
|
||||
|
||||
- `account.view_move_form` — botón "Registrar pago".
|
||||
- `account.view_account_payment_form` — wizard.
|
||||
|
||||
## Modelos de Odoo relacionados
|
||||
|
||||
- `account.move` (factura).
|
||||
- `account.payment` (pago).
|
||||
- `account.payment.register` (wizard).
|
||||
- `account.journal` (diario de banco).
|
||||
- `account.account` (cuentas contables).
|
||||
|
||||
## Métodos de Odoo relacionados
|
||||
|
||||
- `action_register_payment()` — entry point (ver `addons/account/models/account_move.py:6022`).
|
||||
|
||||
## Permisos requeridos
|
||||
|
||||
- `account.group_account_invoice` o `account.group_account_user`.
|
||||
|
||||
## Configuraciones relevantes
|
||||
|
||||
- Diarios de banco/caja.
|
||||
- Métodos de pago disponibles.
|
||||
- Configuración de reconciliación.
|
||||
|
||||
## Casos de uso relacionados
|
||||
|
||||
- CU-FAC-002 Publicar factura (precondición).
|
||||
|
||||
## Criterios de aceptación
|
||||
|
||||
- [ ] Una factura posted puede recibir un pago.
|
||||
- [ ] Al pagar el saldo completo, `payment_state` cambia a `paid`.
|
||||
- [ ] Los pagos parciales dejan `payment_state=partial`.
|
||||
|
||||
## Evidencias de ingeniería inversa
|
||||
|
||||
- **EV-COD-019**: `addons/account/models/account_move.py:6022` — método `action_register_payment`.
|
||||
- **EV-COD-020**: `addons/account/models/account_move.py:600` — campo `payment_state = fields.Selection(...)` (probablemente con valores como `not_paid`, `in_payment`, `paid`, `partial`, `reversed`).
|
||||
|
||||
## Supuestos y aspectos pendientes de validación
|
||||
|
||||
- **EV-INF-014**: Los valores exactos de `payment_state` requieren verificación leyendo las opciones del campo.
|
||||
- **EV-INF-015**: La lógica de reconciliación requiere lectura adicional.
|
||||
- **EV-INF-016**: El método `action_register_payment` puede haber cambiado entre versiones.
|
||||
@@ -0,0 +1,186 @@
|
||||
# CU-VEN-001 — Crear presupuesto
|
||||
|
||||
## Objetivo
|
||||
|
||||
Crear un presupuesto de venta (sales quotation) para un cliente en estado `draft`.
|
||||
|
||||
## Alcance
|
||||
|
||||
Módulo `sale` de Odoo 19.0. Aplica al modelo `sale.order`.
|
||||
|
||||
## Nivel
|
||||
|
||||
Primario (esencial para el proceso de ventas).
|
||||
|
||||
## Actor principal
|
||||
|
||||
Vendedor (usuario con permisos `sales_team.group_sale_salesman`).
|
||||
|
||||
## Actores secundarios
|
||||
|
||||
- Cliente (consulta estado).
|
||||
- Servicio de correo (envía presupuesto).
|
||||
|
||||
## Interesados
|
||||
|
||||
- Responsable de ventas (aprueba descuentos).
|
||||
- Administración (visualiza pipeline).
|
||||
|
||||
## Disparador
|
||||
|
||||
El vendedor hace clic en "Nuevo" desde la vista kanban o tree de `sale.order`, o desde el menú Ventas → Presupuestos.
|
||||
|
||||
## Precondiciones
|
||||
|
||||
- El usuario tiene acceso al módulo `sale`.
|
||||
- Existe al menos un cliente activo en `res.partner`.
|
||||
- El catálogo de productos contiene productos publicables.
|
||||
- La compañía del usuario tiene configurada la secuencia de presupuestos en `ir.sequence`.
|
||||
|
||||
## Garantías mínimas
|
||||
|
||||
El sistema crea un registro `sale.order` en estado `draft` sin errores.
|
||||
|
||||
## Garantías de éxito
|
||||
|
||||
- El presupuesto tiene un `name` único asignado por la secuencia `sale.order`.
|
||||
- Los totales se calculan automáticamente con impuestos.
|
||||
- Se puede confirmar el presupuesto (cambio de estado a `sale`).
|
||||
|
||||
## Flujo principal
|
||||
|
||||
1. Vendedor hace clic en "Nuevo" → sistema crea `sale.order` en estado `draft`.
|
||||
2. Sistema asigna `name` con valor por defecto `_("New")` (será reemplazado por la secuencia al guardar).
|
||||
3. Vendedor selecciona `partner_id` → sistema carga `pricelist_id` por defecto del cliente.
|
||||
4. Vendedor agrega líneas en `sale.order.line` con productos.
|
||||
5. Sistema calcula `amount_untaxed`, `amount_tax`, `amount_total` (método `_compute_amounts()`).
|
||||
6. Vendedor hace clic en "Enviar por email" → sistema invoca `action_quotation_send()` que abre un wizard de email.
|
||||
7. Estado cambia de `draft` a `sent` (al confirmar el envío).
|
||||
8. Vendedor confirma → estado cambia a `sale` (ver CU-VEN-004).
|
||||
|
||||
## Flujos alternativos
|
||||
|
||||
### FA-01 — Aplicar descuento
|
||||
|
||||
1. Vendedor edita `discount` en una línea de `sale.order.line`.
|
||||
2. Sistema recalcula el monto de la línea.
|
||||
3. Si supera el descuento máximo permitido, sistema puede bloquear o notificar.
|
||||
|
||||
### FA-02 — Duplicar presupuesto
|
||||
|
||||
1. Vendedor selecciona un presupuesto existente y elige "Duplicar".
|
||||
2. Sistema crea un nuevo `sale.order` copiando las líneas.
|
||||
3. Estado del nuevo registro: `draft`.
|
||||
|
||||
## Excepciones
|
||||
|
||||
### EX-01 — Cliente sin dirección de entrega
|
||||
|
||||
1. Al intentar confirmar (estado `sale`), sistema valida que exista `partner_shipping_id`.
|
||||
2. Si no existe, sistema muestra error "Configure la dirección de entrega".
|
||||
|
||||
### EX-02 — Líneas sin producto
|
||||
|
||||
1. Al confirmar, sistema valida que cada línea tenga `product_id`.
|
||||
2. Si falta, sistema muestra error "Some order lines are missing a product".
|
||||
|
||||
## Reglas de negocio
|
||||
|
||||
- **RN-VEN-001**: `state` solo puede pasar de `draft` → `sent` → `sale`, o a `cancel`.
|
||||
- **RN-VEN-002**: El campo `name` se genera automáticamente por la secuencia configurada en la compañía.
|
||||
- **RN-VEN-003**: Descuentos mayores al 10% (configurable) pueden requerir aprobación.
|
||||
|
||||
## Datos de entrada
|
||||
|
||||
- Cliente (`partner_id`).
|
||||
- Compañía (`company_id`).
|
||||
- Moneda (`currency_id`).
|
||||
- Lista de precios (`pricelist_id`, opcional).
|
||||
- Líneas (`order_line` con productos).
|
||||
|
||||
## Datos de salida
|
||||
|
||||
- Registro `sale.order` persistido.
|
||||
- Líneas `sale.order.line` relacionadas.
|
||||
- Correo enviado (opcional).
|
||||
|
||||
## Estados involucrados
|
||||
|
||||
- `draft` (Quotation) — estado inicial.
|
||||
- `sent` (Quotation Sent) — al enviar por email.
|
||||
- `sale` (Sales Order) — al confirmar.
|
||||
- `cancel` (Cancelled) — al cancelar.
|
||||
|
||||
## Pantallas involucradas
|
||||
|
||||
- `view_sale_order_form` — form principal (ver `addons/sale/views/sale_order_view.xml`).
|
||||
- `view_sale_order_kanban` — vista kanban (ver mismo archivo).
|
||||
- `view_sale_order_tree` — vista tree (listado).
|
||||
|
||||
## Modelos de Odoo relacionados
|
||||
|
||||
- `sale.order` (principal, `_name = 'sale.order'`).
|
||||
- `sale.order.line` (líneas).
|
||||
- `res.partner` (cliente).
|
||||
- `product.product` (productos).
|
||||
- `account.tax` (impuestos).
|
||||
- `product.pricelist` (lista de precios).
|
||||
|
||||
## Métodos de Odoo relacionados
|
||||
|
||||
- `action_quotation_send()` — abre wizard de email (ver `addons/sale/models/sale_order.py:1067`).
|
||||
- `action_confirm()` — confirma el pedido (ver `addons/sale/models/sale_order.py:1166`).
|
||||
- `action_cancel()` — cancela el pedido (ver `addons/sale/models/sale_order.py:1324`).
|
||||
- `_compute_amounts()` — calcula totales (ver `addons/sale/models/sale_order.py:513`).
|
||||
|
||||
## Permisos requeridos
|
||||
|
||||
- `sales_team.group_sale_salesman` — para crear y editar presupuestos.
|
||||
- `sales_team.group_sale_manager` — para aprobar descuentos y confirmar pedidos.
|
||||
|
||||
## Configuraciones relevantes
|
||||
|
||||
- Política de facturación en `res.company` (`sale_order_template_id`).
|
||||
- Secuencia de presupuestos en `ir.sequence` (`sale.order.template` o equivalente según versión).
|
||||
- Configuración de descuentos máximos.
|
||||
|
||||
## Casos de uso relacionados
|
||||
|
||||
- CU-VEN-002 Modificar presupuesto.
|
||||
- CU-VEN-003 Enviar presupuesto al cliente.
|
||||
- CU-VEN-004 Confirmar pedido de venta.
|
||||
|
||||
## Criterios de aceptación
|
||||
|
||||
- [ ] El vendedor puede crear un presupuesto en menos de 5 clicks.
|
||||
- [ ] El sistema valida la dirección de entrega antes de confirmar.
|
||||
- [ ] El correo al cliente incluye el PDF del presupuesto.
|
||||
- [ ] Los totales se calculan automáticamente.
|
||||
|
||||
## Evidencias de ingeniería inversa
|
||||
|
||||
- **EV-COD-001**: `addons/sale/models/sale_order.py:34-36` — definición de la clase `SaleOrder` con `_name = 'sale.order'`.
|
||||
```python
|
||||
class SaleOrder(models.Model):
|
||||
_name = 'sale.order'
|
||||
_inherit = ['portal.mixin', 'product.catalog.mixin', 'mail.thread', 'mail.activity.mixin', 'utm.mixin', 'account.document.import.mixin']
|
||||
_description = "Sales Order"
|
||||
```
|
||||
- **EV-COD-002**: `addons/sale/models/sale_order.py:26-31` — definición de `SALE_ORDER_STATE`.
|
||||
```python
|
||||
SALE_ORDER_STATE = [
|
||||
('draft', "Quotation"),
|
||||
('sent', "Quotation Sent"),
|
||||
('sale', "Sales Order"),
|
||||
('cancel', "Cancelled"),
|
||||
]
|
||||
```
|
||||
- **EV-COD-003**: `addons/sale/models/sale_order.py:1067` — método `action_quotation_send`.
|
||||
- **EV-COD-004**: `addons/sale/models/sale_order.py:1166` — método `action_confirm`.
|
||||
- **EV-COD-005**: `addons/sale/models/sale_order.py:54-58` — campo `name` con default `_("New")`.
|
||||
|
||||
## Supuestos y aspectos pendientes de validación
|
||||
|
||||
- **EV-INF-001**: El wizard de email usa `mail.compose.message` (verificado por contexto en `action_quotation_send`).
|
||||
- **EV-INF-002**: La secuencia `sale.order` puede variar según configuración de la compañía.
|
||||
- **EV-INF-003**: La validación de descuento máximo depende de configuración que requiere verificación.
|
||||
@@ -0,0 +1,183 @@
|
||||
# CU-VEN-004 — Confirmar pedido de venta
|
||||
|
||||
## Objetivo
|
||||
|
||||
Confirmar un presupuesto, transformándolo de `draft`/`sent` a `sale` (Sales Order) y disparando el flujo downstream (reserva de stock, preparación, facturación).
|
||||
|
||||
## Alcance
|
||||
|
||||
Módulo `sale` de Odoo 19.0. Aplica al modelo `sale.order`.
|
||||
|
||||
## Nivel
|
||||
|
||||
Primario (esencial — dispara todo el flujo operativo).
|
||||
|
||||
## Actor principal
|
||||
|
||||
Vendedor o Responsable de ventas (usuario con permisos `sales_team.group_sale_salesman` o `sales_team.group_sale_manager`).
|
||||
|
||||
## Actores secundarios
|
||||
|
||||
- Sistema de stock (reserva cantidades).
|
||||
- Sistema de cuenta (crea factura al confirmar).
|
||||
|
||||
## Interesados
|
||||
|
||||
- Operador de inventario (debe preparar pedidos).
|
||||
- Responsable de facturación (debe emitir facturas).
|
||||
- Administración (visualiza pipeline confirmado).
|
||||
|
||||
## Disparador
|
||||
|
||||
El vendedor hace clic en "Confirmar" en la vista form del pedido.
|
||||
|
||||
## Precondiciones
|
||||
|
||||
- El pedido está en estado `draft` o `sent`.
|
||||
- Cada línea tiene un `product_id` definido (validado por `_confirmation_error_message()`).
|
||||
- El cliente tiene una dirección de entrega válida.
|
||||
- Si `sale.group_auto_done_setting` está activo, el pedido se lockea automáticamente al confirmar.
|
||||
|
||||
## Garantías mínimas
|
||||
|
||||
El sistema cambia el estado del pedido de `draft`/`sent` a `sale` o muestra un error explicativo.
|
||||
|
||||
## Garantías de éxito
|
||||
|
||||
- Estado del pedido: `sale`.
|
||||
- `date_order` queda con la fecha/hora actual.
|
||||
- Si `sale.group_auto_done_setting` está activo, el pedido queda `locked=True`.
|
||||
- Se ejecutan los efectos downstream (`_action_confirm`): reserva de stock, programación de entregas.
|
||||
|
||||
## Flujo principal
|
||||
|
||||
1. Vendedor hace clic en "Confirmar" → sistema invoca `action_confirm()`.
|
||||
2. Sistema valida cada pedido con `_confirmation_error_message()`:
|
||||
- Si el estado no es `draft` o `sent`, retorna error.
|
||||
- Si alguna línea no tiene `product_id`, retorna error.
|
||||
3. Si pasa validación, sistema prepara valores con `_prepare_confirmation_values()`:
|
||||
- `state = 'sale'`
|
||||
- `date_order = fields.Datetime.now()`
|
||||
4. Sistema escribe esos valores con `self.write(...)`.
|
||||
5. Sistema llama a `self.with_context(context)._action_confirm()` que dispara el flujo downstream.
|
||||
6. Si `sale.group_auto_done_setting` está activo, sistema invoca `action_lock()` sobre los pedidos filtrados.
|
||||
7. Si el contexto trae `send_email=True`, sistema envía email de confirmación.
|
||||
8. Retorna `True`.
|
||||
|
||||
## Flujos alternativos
|
||||
|
||||
### FA-01 — Confirmación masiva
|
||||
|
||||
1. Vendedor selecciona múltiples presupuestos desde vista tree.
|
||||
2. Hace clic en "Confirmar" (acción masiva).
|
||||
3. Sistema itera sobre cada pedido y aplica el flujo principal.
|
||||
4. Si alguno falla, sistema retorna UserError con el mensaje del primer pedido que falló.
|
||||
|
||||
### FA-02 — Lock automático
|
||||
|
||||
1. Sistema detecta que `sale.group_auto_done_setting` está activo.
|
||||
2. Después de confirmar, llama a `action_lock()`.
|
||||
3. Pedido queda `locked=True`, no se puede modificar.
|
||||
|
||||
## Excepciones
|
||||
|
||||
### EX-01 — Estado inválido
|
||||
|
||||
1. El pedido está en estado `sale` o `cancel`.
|
||||
2. Sistema retorna `_("Some orders are not in a state requiring confirmation.")`.
|
||||
|
||||
### EX-02 — Líneas sin producto
|
||||
|
||||
1. Alguna línea tiene `display_type` vacío y `is_downpayment=False` y `product_id` vacío.
|
||||
2. Sistema retorna `_("Some order lines are missing a product, you need to correct them before going further.")`.
|
||||
|
||||
## Reglas de negocio
|
||||
|
||||
- **RN-VEN-004**: Solo se puede confirmar un pedido en estado `draft` o `sent`.
|
||||
- **RN-VEN-005**: Toda línea debe tener un producto antes de confirmar.
|
||||
- **RN-VEN-006**: Al confirmar, se dispara el flujo de stock (CU-ENT-002) y luego de cuenta (CU-FAC-001).
|
||||
|
||||
## Datos de entrada
|
||||
|
||||
- Pedido en estado `draft` o `sent`.
|
||||
- Contexto opcional: `send_email=True` (envía email de confirmación).
|
||||
|
||||
## Datos de salida
|
||||
|
||||
- Pedido en estado `sale`.
|
||||
- Reservas de stock (CU-ENT-002).
|
||||
- Programación de entregas (CU-ENT-004).
|
||||
|
||||
## Estados involucrados
|
||||
|
||||
- `draft` → `sale` (transición principal).
|
||||
- `sent` → `sale` (transición alternativa).
|
||||
- Opcionalmente `locked=True` si `sale.group_auto_done_setting` está activo.
|
||||
|
||||
## Pantallas involucradas
|
||||
|
||||
- `view_sale_order_form` — botón "Confirmar" en el header del form.
|
||||
|
||||
## Modelos de Odoo relacionados
|
||||
|
||||
- `sale.order` (principal).
|
||||
- `sale.order.line` (líneas validadas).
|
||||
- `stock.picking` (entregas generadas).
|
||||
- `account.move` (facturas generadas).
|
||||
|
||||
## Métodos de Odoo relacionados
|
||||
|
||||
- `action_confirm()` — entry point (ver `addons/sale/models/sale_order.py:1166`).
|
||||
- `_confirmation_error_message()` — valida (ver `addons/sale/models/sale_order.py:1203`).
|
||||
- `_prepare_confirmation_values()` — prepara valores (ver `addons/sale/models/sale_order.py:1218`).
|
||||
- `_action_confirm()` — lógica de confirmación (interno, dispara stock y cuenta).
|
||||
- `_should_be_locked()` — determina si lockea (ver `addons/sale/models/sale_order.py:1198`).
|
||||
- `action_lock()` — lockea el pedido.
|
||||
|
||||
## Permisos requeridos
|
||||
|
||||
- `sales_team.group_sale_salesman` (puede confirmar sus propios pedidos).
|
||||
- `sales_team.group_sale_manager` (puede confirmar cualquier pedido).
|
||||
|
||||
## Configuraciones relevantes
|
||||
|
||||
- `sale.group_auto_done_setting` — si está activo, lockea automáticamente al confirmar.
|
||||
|
||||
## Casos de uso relacionados
|
||||
|
||||
- CU-VEN-001 Crear presupuesto (precondición).
|
||||
- CU-ENT-002 Reservar productos (downstream).
|
||||
- CU-FAC-001 Crear factura (downstream).
|
||||
|
||||
## Criterios de aceptación
|
||||
|
||||
- [ ] Un pedido en `draft` puede confirmarse si todas las líneas tienen producto.
|
||||
- [ ] Un pedido sin productos en alguna línea muestra error claro.
|
||||
- [ ] El estado cambia correctamente a `sale`.
|
||||
- [ ] Si auto_done está activo, el pedido queda `locked=True`.
|
||||
- [ ] Las reservas de stock se generan automáticamente.
|
||||
|
||||
## Evidencias de ingeniería inversa
|
||||
|
||||
- **EV-COD-006**: `addons/sale/models/sale_order.py:1166-1196` — método `action_confirm` completo.
|
||||
```python
|
||||
def action_confirm(self):
|
||||
for order in self:
|
||||
error_msg = order._confirmation_error_message()
|
||||
if error_msg:
|
||||
raise UserError(error_msg)
|
||||
self.order_line._validate_analytic_distribution()
|
||||
self.write(self._prepare_confirmation_values())
|
||||
...
|
||||
self.with_context(context)._action_confirm()
|
||||
self.filtered(lambda so: so._should_be_locked()).action_lock()
|
||||
...
|
||||
```
|
||||
- **EV-COD-007**: `addons/sale/models/sale_order.py:1203-1216` — método `_confirmation_error_message` (validaciones).
|
||||
- **EV-COD-008**: `addons/sale/models/sale_order.py:1218-1229` — método `_prepare_confirmation_values` (devuelve `{'state': 'sale', 'date_order': fields.Datetime.now()}`).
|
||||
- **EV-COD-009**: `addons/sale/models/sale_order.py:1198-1201` — método `_should_be_locked` (chequea `sale.group_auto_done_setting`).
|
||||
|
||||
## Supuestos y aspectos pendientes de validación
|
||||
|
||||
- **EV-INF-004**: `_action_confirm()` (sin guion bajo prefijo público) es el método que dispara el flujo downstream de stock y cuenta. Su implementación interna no fue leída en detalle.
|
||||
- **EV-INF-005**: El efecto sobre `stock.picking` y `account.move` se valida en CU-ENT-002 y CU-FAC-001 respectivamente.
|
||||
Reference in New Issue
Block a user