feat(cu-extend-include): CU diagram con 5+5 relaciones, specs en voz activa

Cambios principales:

1. Diagrama de CU mejorado (D-CU-GEN-002):
   - 5 <<include>> (subflujos obligatorios):
     CU-AUTH-001, CU-CALC-001, CU-GENPICK-001, CU-VALLIN-001, CU-GENJOUR-001
   - 5 <<extend>> (subflujos opcionales/condicionales):
     CU-VEN-001-EMAIL, CU-VEN-001-DISC, CU-ENT-002-MTO, CU-ENT-004-BACK, CU-FAC-002-VAL

2. 7 especificaciones de CU reescritas en voz activa (todos los verbos
   provienen de los diagramas de robustez existentes):
   - CU-VEN-001 Crear presupuesto
   - CU-VEN-004 Confirmar pedido
   - CU-ENT-002 Reservar productos
   - CU-ENT-004 Validar entrega
   - CU-FAC-001 Crear factura
   - CU-FAC-002 Publicar factura
   - CU-FAC-003 Registrar pago

3. Cada CU incluye las secciones pedidas:
   - Nombre
   - Objetivo
   - Pre-condicion
   - Post-condicion
   - Pasos trascendentes (en voz activa)
   - Caminos alternativos (en voz activa)
   - Excepciones
   - Reglas de negocio
   - Relaciones <<include>> y <<extend>>
   - Diagrama de robustez asociado
   - Tabla de verbos clave (para validar la voz activa)

4. Matriz de trazabilidad actualizada con la tabla de CU includes/extends.

Archivos:
- diagrams/plantuml/d_cu_gen_002_casos_uso_extend_include.puml
- diagrams/png/D-CU-GEN-002 — Casos de Uso con extend e include.png
- diagrams/svg/D-CU-GEN-002 — Casos de Uso con extend e include.svg
- diagrams/pdf/D-CU-GEN-002 — Casos de Uso con extend e include.pdf
- docs/02_casos_uso/*.md (7 specs reescritas)
- docs/09_trazabilidad/matriz_trazabilidad.md (actualizada)
This commit is contained in:
saptfi2026-bot
2026-06-23 22:56:28 -03:00
parent c860f61e5e
commit eb0f1c2eb6
12 changed files with 837 additions and 978 deletions
@@ -0,0 +1,77 @@
@startuml D-CU-GEN-002 — Casos de Uso con extend e include
title SAP-TFI-2026 — Casos de Uso del Flujo Comercial (con extend e include)
skinparam shadowing false
skinparam handwritten false
skinparam defaultFontName Arial
skinparam defaultFontSize 12
skinparam linetype ortho
skinparam backgroundColor white
left to right direction
skinparam actorStyle awesome
' ─── Actores ───
actor "Vendedor" as V
actor "Operario de Almacén" as OA
actor "Facturador" as F
actor "Sistema" as S
' ─── CU principales ───
usecase "CU-VEN-001\nCrear presupuesto" as CU_VEN_001
usecase "CU-VEN-004\nConfirmar pedido" as CU_VEN_004
usecase "CU-ENT-002\nReservar productos" as CU_ENT_002
usecase "CU-ENT-004\nValidar entrega" as CU_ENT_004
usecase "CU-FAC-001\nCrear factura" as CU_FAC_001
usecase "CU-FAC-002\nPublicar factura" as CU_FAC_002
usecase "CU-FAC-003\nRegistrar pago" as CU_FAC_003
' ─── CU incluidos (5 includes) ───
usecase "CU-AUTH-001\nValidar sesión\nde usuario" as CU_AUTH
usecase "CU-CALC-001\nCalcular totales\ncon impuestos" as CU_CALC
usecase "CU-GENPICK-001\nGenerar picking\nde entrega" as CU_GENPICK
usecase "CU-VALLIN-001\nValidar líneas\npendientes" as CU_VALLIN
usecase "CU-GENJOUR-001\nCrear asiento\ncontable" as CU_GENJOUR
' ─── CU que extienden (5 extends) ───
usecase "CU-VEN-001-EMAIL\nEnviar presupuesto\npor email" as CU_VEN_001_EMAIL
usecase "CU-VEN-001-DISC\nAplicar descuento" as CU_VEN_001_DISC
usecase "CU-ENT-002-MTO\nGenerar orden de\ncompra (MTO)" as CU_ENT_002_MTO
usecase "CU-ENT-004-BACK\nCrear backorder\nde entrega parcial" as CU_ENT_004_BACK
usecase "CU-FAC-002-VAL\nValidar asiento\nanormal" as CU_FAC_002_VAL
' ─── Asociaciones de actores ───
V --> CU_VEN_001 : crea
V --> CU_VEN_004 : confirma
OA --> CU_ENT_002 : reserva
OA --> CU_ENT_004 : valida
F --> CU_FAC_001 : factura
F --> CU_FAC_002 : publica
F --> CU_FAC_003 : cobra
S --> CU_AUTH : autentica%
' ─── Includes (5) — flechas con <<include>> ───
CU_VEN_001 ..> CU_AUTH : <<include>>
CU_VEN_001 ..> CU_CALC : <<include>>
CU_VEN_004 ..> CU_AUTH : <<include>>
CU_VEN_004 ..> CU_GENPICK : <<include>>
CU_FAC_001 ..> CU_VALLIN : <<include>>
CU_FAC_002 ..> CU_GENJOUR : <<include>>
' ─── Extends (5) — flechas con <<extend>> ───
CU_VEN_001_EMAIL ..> CU_VEN_001 : <<extend>>
CU_VEN_001_DISC ..> CU_VEN_001 : <<extend>>
CU_ENT_002_MTO ..> CU_ENT_002 : <<extend>>
CU_ENT_004_BACK ..> CU_ENT_004 : <<extend>>
CU_FAC_002_VAL ..> CU_FAC_002 : <<extend>>
legend right
Proyecto: SAP-TFI-2026
Agente: saptfi2026
Metodologia: ICONIX (extend e include)
Fuente: Ingenieria inversa de Odoo 19.0
5 includes + 5 extends
endlegend
@enduml
Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 28 KiB

@@ -1,146 +1,108 @@
# CU-ENT-002 — Reservar productos # CU-ENT-002 — Reservar Productos
## Nombre
**Reservar Productos en Almacén**
## Objetivo ## Objetivo
Reservar las cantidades pedidas de cada producto en el almacén, asegurando disponibilidad antes de la entrega. El sistema (o el operario de almacén) reserva las cantidades pedidas de cada producto, asegurando disponibilidad antes de la entrega.
## Alcance ## Pre-condición
Módulo `stock` de Odoo 19.0. Aplica al modelo `stock.picking`. - El picking está en estado `draft`, `waiting` o `confirmed`.
- Los productos tienen stock disponible o reglas de reabastecimiento aplicables.
## Nivel ## Post-condición
Primario (esencial para garantizar disponibilidad). - Las cantidades reservadas quedan en `stock.move.line` con `reserved_availability`.
- El estado del picking cambia a `assigned` (si todas las líneas tienen reserva) o `partially_available` (si hay parcial).
## Actor principal ## Pasos trascendentes (camino feliz, en voz activa)
Sistema (operador de inventario puede forzarlo manualmente). 1. El sistema (o el operario) **dispara** el trigger de reserva (confirmación de pedido o botón manual).
2. El sistema **lee** el picking y sus líneas.
3. El sistema **invoca** `action_assign()` sobre el picking.
4. El sistema **recorre** cada línea del picking.
5. Para cada línea, el sistema **busca** stock disponible en `stock.quant`.
6. El sistema **encuentra** cantidad suficiente.
7. El sistema **reserva** la cantidad creando `stock.move.line`.
8. El sistema **actualiza** `reserved_availability` en la línea.
9. El sistema **actualiza** el estado del picking.
10. El sistema **asigna** el estado `assigned` cuando todas las líneas tienen reserva.
## Actores secundarios ## Caminos alternativos (en voz activa)
- Sistema de Odoo (acción automática al confirmar pedido de venta). ### FA-01 — El sistema no encuentra stock suficiente
## Interesados 1. El sistema **busca** stock disponible y **encuentra** cantidad insuficiente.
2. El sistema **consulta** las reglas de reabastecimiento (`stock.warehouse.orderpoint`).
3. Si hay reglas MTO, el sistema **extiende** con `CU-ENT-002-MTO` para generar orden de compra.
4. El sistema **crea** una `purchase.order` para reabastecer.
5. El sistema **programa** la recepción del producto.
6. El sistema **marca** la línea como `partially_available`.
- Operador de inventario. ### FA-02 — El sistema hace reserva parcial
- Vendedor (necesita saber si hay stock).
- Cliente (recibe confirmación de entrega).
## Disparador 1. El sistema **reserva** parte de las cantidades.
2. El sistema **marca** las líneas con reserva como `assigned`.
3. El sistema **deja** las líneas sin reserva como `partially_available`.
4. El sistema **no cambia** el estado global del picking a `assigned`.
- Confirmación de un pedido de venta (CU-VEN-004) — sistema dispara automáticamente. ### FA-03 — El operario fuerza la reserva manualmente
- Botón manual "Reservar" en el picking (interfaz de inventario).
## Precondiciones 1. El operario **presiona** "Reservar" en el form del picking.
2. El sistema **invoca** `action_assign()`.
3. El sistema **ejecuta** los pasos trascendentes.
- El picking está en estado `draft` o `waiting` o `confirmed`. ## Excepciones (en voz activa)
- Los productos tienen stock disponible o se puede conseguir (vía reglas de abastecimiento).
## Garantías mínimas ### EX-01 — El picking no tiene movimientos
El sistema intenta reservar las cantidades; si no puede, deja el picking en `partially_available` o `confirmed`. 1. El sistema **detecta** que no hay movimientos para reservar.
2. El sistema **muestra** el error "Nothing to check the availability for".
## Garantías de éxito ### EX-02 — No hay stock ni reglas aplicables
- Estado del picking: `assigned`. 1. El sistema **busca** stock y **no encuentra** cantidad.
- Las cantidades reservadas se reflejan en `stock.move.line` con `reserved_availability`. 2. El sistema **consulta** reglas de reabastecimiento y **no encuentra** aplicables.
3. El sistema **deja** el picking en estado `partially_available`.
## Flujo principal 4. El operario **debe** decidir acción manual.
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 ## Reglas de negocio
- **RN-ENT-002**: La reserva no afecta disponibilidad para otros pedidos hasta que se confirme el picking. - **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. - **RN-ENT-003**: Las reservas se liberan automáticamente al cancelar el pedido o el picking.
## Datos de entrada ## Relaciones con otros CU
- Picking con líneas (`stock.move`). - **<<extend>> CU-ENT-002-MTO**: Genera orden de compra (MTO) cuando no hay stock (opcional).
## Datos de salida ## Diagrama de robustez asociado
- Stock.move.line con reservas. `diagrams/plantuml/d_rob_ent_002_reservar_productos.puml`
- Estado del picking actualizado.
- Posibles órdenes de compra generadas.
## Estados involucrados ## Verbos clave (para validar la voz activa)
- `draft``confirmed``assigned` (reserva completa). | Verbo | Actor | Acción sobre |
- `draft``confirmed``partially_available` (reserva parcial). |-------|-------|--------------|
| **dispara** | Sistema/Operario | Trigger de reserva |
## Pantallas involucradas | **lee** | Sistema | Picking y líneas |
| **invoca** | Sistema | `action_assign()` |
- `view_picking_form` — form del picking. | **recorre** | Sistema | Líneas del picking |
- `view_stock_move_line_tree` — vista tree de movimientos reservados. | **busca** | Sistema | Stock en `stock.quant` |
| **encuentra** | Sistema | Cantidad disponible |
## Modelos de Odoo relacionados | **reserva** | Sistema | `stock.move.line` |
| **actualiza** | Sistema | `reserved_availability`, estado |
- `stock.picking` (principal). | **asigna** | Sistema | Estado `assigned` |
- `stock.move` (líneas del picking). | **consulta** | Sistema | `stock.warehouse.orderpoint` |
- `stock.move.line` (reservas). | **extiende** | Sistema | `CU-ENT-002-MTO` |
- `stock.warehouse.orderpoint` (reglas de reabastecimiento). | **crea** | Sistema | `purchase.order` |
- `procurement.order` (orden de compra generada). | **programa** | Sistema | Recepción |
| **marca** | Sistema | `partially_available` |
## Métodos de Odoo relacionados | **deja** | Sistema | Estado sin cambio |
| **presiona** | Operario | Botón "Reservar" |
- `action_assign()` — entry point (ver `addons/stock/models/stock_picking.py:1195`). | **ejecuta** | Sistema | Pasos trascendentes |
- `action_confirm()` — confirma el picking (ver `addons/stock/models/stock_picking.py:1186`). | **detecta** | Sistema | Movimientos / reglas |
| **muestra** | Sistema | Error |
## Permisos requeridos | **libera** | Sistema | Reservas (al cancelar) |
- `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.
+72 -119
View File
@@ -1,151 +1,104 @@
# CU-ENT-004 — Validar entrega # CU-ENT-004 — Validar Entrega
## Nombre
**Validar Entrega de Productos**
## Objetivo ## 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). El operario de almacén confirma la salida física de los productos del almacén, completando el picking y actualizando el stock cuantitativo.
## Alcance ## Pre-condición
Módulo `stock` de Odoo 19.0. Aplica al modelo `stock.picking`. - El picking está en estado `assigned` o `partially_available`.
## 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. - Las cantidades reservadas o a entregar son válidas.
## Garantías mínimas ## Post-condición
El sistema cambia el estado del picking a `done` o muestra un error explicativo. - El estado del picking cambia a `done`.
- El stock cuantitativo (`stock.quant`) se actualiza con las cantidades entregadas.
- Se crea un backorder si hay cantidades pendientes (opcional).
## Garantías de éxito ## Pasos trascendentes (camino feliz, en voz activa)
- Estado del picking: `done`. 1. El operario **presiona** "Validar" en el form del picking.
- Stock actualizado (las cantidades reservadas se descuentan del stock disponible). 2. El sistema **invoca** `button_validate()`.
- Posible creación automática de factura si está configurado. 3. El sistema **abre** el wizard de validación inmediata (`stock.immediate.transfer`).
4. El operario **confirma** las cantidades reales entregadas.
5. El sistema **actualiza** `stock.move` con las cantidades reales.
6. El sistema **crea** `stock.move.line` definitivos.
7. El sistema **actualiza** el stock cuantitativo en `stock.quant`.
8. El sistema **cambia** el estado del picking a `done`.
9. El sistema **muestra** el resultado al operario.
## Flujo principal ## Caminos alternativos (en voz activa)
1. Operador hace clic en "Validar" → sistema invoca `button_validate()` (ver `addons/stock/models/stock_picking.py:1398`). ### FA-01 — El operario hace entrega parcial (extiende CU-ENT-004-BACK)
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 1. El operario **confirma** cantidades menores a las reservadas.
2. El sistema **crea** un nuevo picking (backorder) con las cantidades pendientes.
3. El sistema **completa** el picking original con las cantidades entregadas.
4. El sistema **deja** el backorder en estado `assigned` o `confirmed`.
5. El operario **procesa** el backorder posteriormente.
### FA-01 — Entrega parcial con backorder ### FA-02 — El sistema crea la factura automáticamente
1. Operador entrega solo una parte de las cantidades. 1. El sistema **detecta** que está configurada la facturación automática al validar.
2. Sistema crea un nuevo picking (backorder) con las cantidades pendientes. 2. El sistema **invoca** `_create_invoices()` desde el picking.
3. Picking original queda en `done` con las cantidades entregadas. 3. El sistema **crea** la factura (`account.move`).
4. Backorder queda en `assigned` o `confirmed` para entrega posterior. 4. El sistema **vincula** la salida de stock con la factura.
### FA-02Crear factura al validar ### FA-03El sistema valida sin wizard
1. Si está configurado, al validar, sistema crea automáticamente una factura (`account.move`). 1. El operario **presiona** "Validar" sin necesidad de wizard (configuración).
2. Esto vincula la salida de stock con la facturación inmediata. 2. El sistema **ejecuta** la validación directa.
3. El sistema **completa** el picking.
## Excepciones ## Excepciones (en voz activa)
### EX-01 — Cantidad excede lo reservado ### EX-01 — La cantidad excede lo reservado
1. Operador intenta entregar más cantidad de la que está reservada. 1. El operario **intenta** entregar más cantidad de la reservada.
2. Sistema valida y rechaza si excede. 2. El sistema **valida** y **rechaza** si excede.
3. Sistema muestra error claro. 3. El sistema **muestra** el error.
### EX-02 — Picking no asignable ### EX-02 — El picking está en estado inválido
1. Picking en estado `draft` o `cancel`. 1. El picking está en estado `draft` o `cancel`.
2. Sistema no permite validar. 2. El sistema **detecta** el estado inválido.
3. El sistema **impide** la validación.
## Reglas de negocio ## Reglas de negocio
- **RN-ENT-004**: Al validar, las cantidades reservadas pasan a `done`. - **RN-ENT-004**: Al validar, las cantidades reservadas pasan a `done`.
- **RN-ENT-005**: Backorder automático configurable vía `stock.backorder_confirmation_policy`. - **RN-ENT-005**: El backorder automático depende de `stock.backorder_confirmation_policy`.
## Datos de entrada ## Relaciones con otros CU
- Picking en estado `assigned` o `partially_available`. - **<<extend>> CU-ENT-004-BACK**: Crea backorder cuando hay entrega parcial (opcional).
- Cantidades reales (pueden diferir de las reservadas).
## Datos de salida ## Diagrama de robustez asociado
- Picking en `done`. `diagrams/plantuml/d_rob_ven_001_crear_presupuesto.puml` (compartido conceptualmente; este CU no tiene ROB dedicado en la primera iteración)
- Stock actualizado.
- Posible factura generada.
## Estados involucrados ## Verbos clave (para validar la voz activa)
- `assigned``done` (validación completa). | Verbo | Actor | Acción sobre |
- `partially_available``done` (validación parcial, genera backorder). |-------|-------|--------------|
| **presiona** | Operario | Botón "Validar" |
## Pantallas involucradas | **invoca** | Sistema | `button_validate()` |
| **abre** | Sistema | Wizard de validación |
- `view_picking_form` — botón "Validar". | **confirma** | Operario | Cantidades reales |
- `view_stock_immediate_transfer` — wizard de validación. | **actualiza** | Sistema | `stock.move`, `stock.quant` |
| **crea** | Sistema | `stock.move.line`, backorder, factura |
## Modelos de Odoo relacionados | **cambia** | Sistema | Estado del picking |
| **muestra** | Sistema | Resultado |
- `stock.picking` (principal). | **completa** | Sistema | Picking original |
- `stock.move` (movimientos). | **deja** | Sistema | Backorder |
- `stock.move.line` (líneas definitivas). | **procesa** | Operario | Backorder |
- `stock.quant` (stock cuantitativo actualizado). | **detecta** | Sistema | Configuración de facturación |
- `stock.backorder.confirmation` (wizard de backorder). | **vincula** | Sistema | Salida de stock con factura |
| **ejecuta** | Sistema | Validación directa |
## Métodos de Odoo relacionados | **intenta** | Operario | Entregar cantidad |
| **rechaza** | Sistema | Cantidad excedida |
- `button_validate()` — entry point (ver `addons/stock/models/stock_picking.py:1398`). | **impide** | Sistema | Validación |
## 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.
+76 -122
View File
@@ -1,154 +1,108 @@
# CU-FAC-001 — Crear factura desde pedido # CU-FAC-001 — Crear Factura desde Pedido
## Nombre
**Crear Factura desde Pedido de Venta**
## Objetivo ## Objetivo
Generar una factura (`account.move`) basada en un pedido de venta confirmado, para registrar la venta en el sistema contable. El facturador (o el vendedor) genera una factura (`account.move`) basada en un pedido de venta confirmado, para registrar la venta en el sistema contable.
## Alcance ## Pre-condición
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`. - El pedido está en estado `sale`.
- Hay productos a facturar (no todo está ya facturado). - Hay productos a facturar (`invoice_status != 'invoiced'`).
- El cliente y la compañía tienen configurados los diarios contables. - El cliente y la compañía tienen configurados los diarios contables.
- El sistema validó las líneas pendientes (`CU-VALLIN-001`).
## Garantías mínimas ## Post-condición
El sistema crea un `account.move` en estado `draft` o muestra un error. - Existe un `account.move` en estado `draft` con tipo `out_invoice`.
- Las líneas tienen `quantity`, `price_unit`, `tax_ids` correctos.
## 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. - `invoice_origin` apunta al pedido original.
- El pedido referencia la factura vía `invoice_ids`.
## Flujo principal ## Pasos trascendentes (camino feliz, en voz activa)
1. Usuario hace clic en "Crear factura" → sistema invoca `_create_invoices()` (ver `addons/sale/models/sale_order.py:1550`). 1. El facturador **presiona** "Crear Factura" en el form del pedido.
2. Sistema prepara las líneas de factura con `_prepare_invoice()` (ver `addons/sale/models/sale_order.py:1411`). 2. El sistema **invoca** `_create_invoices()` sobre el pedido.
3. Sistema crea un nuevo `account.move` con tipo `out_invoice` (factura de cliente). 3. El sistema **lee** el pedido (`sale.order` en estado `sale`).
4. Sistema crea las `account.move.line` correspondientes. 4. El sistema **verifica** el `invoice_status` del pedido.
5. Sistema vincula el pedido con la factura vía `invoice_ids` (Many2many). 5. El sistema **lee** las líneas pendientes (`sale.order.line`).
6. Sistema actualiza `invoice_status` del pedido según corresponda. 6. El sistema **aplica** los impuestos (`account.tax`) a cada línea.
7. Factura queda en estado `draft`. 7. Para cada línea, el sistema **crea** un `account.move.line`.
8. El sistema **construye** los valores del invoice con `_prepare_invoice()`.
9. El sistema **crea** un `account.move` en estado `draft`.
10. El sistema **asocia** la factura al pedido vía `invoice_ids`.
11. El sistema **actualiza** `invoice_status` del pedido.
12. El sistema **muestra** la factura creada al facturador.
## Flujos alternativos ## Caminos alternativos (en voz activa)
### FA-01 — Facturación agrupada ### FA-01 — El facturador hace facturación agrupada
1. Sistema agrupa múltiples pedidos en una sola factura (cuando `grouped=True`). 1. El facturador **selecciona** múltiples pedidos.
2. Sistema crea una factura con líneas de todos los pedidos. 2. El facturador **presiona** "Crear Factura" con `grouped=True`.
3. Cada pedido referencia la factura agrupada. 3. El sistema **agrupa** las líneas de todos los pedidos.
4. El sistema **crea** una sola factura con todas las líneas.
5. El sistema **asocia** la factura a cada pedido.
### FA-02 — Facturación parcial ### FA-02 — El facturador hace facturación parcial
1. Sistema factura solo una parte de las cantidades (parcial o downpayment). 1. El facturador **selecciona** las líneas específicas a facturar.
2. Resto queda pendiente para futuras facturas. 2. El sistema **factura** solo esas líneas.
3. El sistema **deja** las demás líneas pendientes.
4. El sistema **actualiza** `invoice_status` a `to invoice` parcial.
## Excepciones ### FA-03 — El sistema crea factura automáticamente al validar entrega
### EX-01 — Todo ya facturado 1. El sistema **detecta** que la entrega fue validada.
2. El sistema **invoca** `_create_invoices()` automáticamente.
3. El sistema **ejecuta** los pasos trascendentes.
1. Sistema detecta que `invoice_status` es `invoiced`. ## Excepciones (en voz activa)
2. Sistema retorna mensaje "Nothing to invoice".
### EX-02Compañía sin diario configurado ### EX-01No hay nada que facturar
1. Compañía no tiene `currency_id` o `journal_id` configurado. 1. El sistema **verifica** que `invoice_status` es `invoiced`.
2. Sistema retorna error de configuración. 2. El sistema **muestra** el mensaje "Nothing to invoice".
### EX-02 — La compañía no tiene diario configurado
1. El sistema **detecta** que `journal_id` está vacío.
2. El sistema **muestra** el error de configuración.
## Reglas de negocio ## Reglas de negocio
- **RN-FAC-001**: Solo se puede facturar un pedido en estado `sale`. - **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. - **RN-FAC-002**: Una factura no se puede modificar después de publicarse.
## Datos de entrada ## Relaciones con otros CU
- Pedido en estado `sale`. - **<<include>> CU-VALLIN-001**: Valida líneas pendientes antes de facturar.
- Cantidades a facturar (pueden ser parciales).
## Datos de salida ## Diagrama de robustez asociado
- `account.move` (factura) en estado `draft`. `diagrams/plantuml/d_rob_fac_001_crear_factura.puml`
- `account.move.line` (líneas de factura).
## Estados involucrados ## Verbos clave (para validar la voz activa)
- Factura: `draft``posted` (después de CU-FAC-002). | Verbo | Actor | Acción sobre |
|-------|-------|--------------|
## Pantallas involucradas | **presiona** | Facturador | Botón "Crear Factura" |
| **invoca** | Sistema | `_create_invoices()` |
- `view_sale_order_form` — botón "Crear factura". | **lee** | Sistema | Pedido, líneas, taxes |
- `account.view_move_form` — form de la factura creada. | **verifica** | Sistema | `invoice_status` |
| **aplica** | Sistema | Impuestos a líneas |
## Modelos de Odoo relacionados | **crea** | Sistema | `account.move`, `account.move.line` |
| **construye** | Sistema | `_prepare_invoice()` |
- `sale.order` (origen). | **asocia** | Sistema | `invoice_ids` |
- `sale.order.line` (líneas a facturar). | **actualiza** | Sistema | `invoice_status` |
- `account.move` (factura creada). | **muestra** | Sistema | Factura al facturador |
- `account.move.line` (líneas de factura). | **selecciona** | Facturador | Múltiples pedidos |
- `account.tax` (impuestos aplicados). | **agrupa** | Sistema | Líneas agrupadas |
| **factura** | Sistema | Líneas específicas |
## Métodos de Odoo relacionados | **deja** | Sistema | Líneas pendientes |
| **detecta** | Sistema | Validación de entrega / config |
- `_create_invoices()` — entry point (ver `addons/sale/models/sale_order.py:1550`). | **ejecuta** | Sistema | Pasos trascendentes |
- `_prepare_invoice()` — prepara valores (ver `addons/sale/models/sale_order.py:1411`). | **muestra** | Sistema | Mensaje de error |
## 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.
+82 -117
View File
@@ -1,152 +1,117 @@
# CU-FAC-002 — Publicar factura # CU-FAC-002 — Publicar Factura
## Nombre
**Publicar Factura (Confirmar y Generar Asiento Contable)**
## Objetivo ## Objetivo
Publicar (confirmar) una factura en estado `draft`, generando el asiento contable y haciendo la factura oficial. El facturador publica una factura en estado `draft`, generando el asiento contable y haciendo la factura oficial.
## Alcance ## Pre-condición
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`. - La factura está en estado `draft`.
- Las líneas tienen impuestos y cuentas contables válidas. - Las líneas tienen impuestos y cuentas contables válidas.
- El diario contable está configurado. - El diario contable está configurado.
- La factura pasó las validaciones (`CU-VALLIN-001`).
## Garantías mínimas ## Post-condición
El sistema cambia el estado de la factura o muestra un error explicativo. - El estado de la factura cambia a `posted`.
- El asiento contable queda generado.
- `invoice_date` tiene la fecha de publicación.
- El número de factura queda asignado por la secuencia del diario.
## Garantías de éxito ## Pasos trascendentes (camino feliz, en voz activa)
- Estado de la factura: `posted`. 1. El facturador **presiona** "Confirmar" en el form de la factura.
- Asiento contable generado (`account.move` con `state='posted'`). 2. El sistema **invoca** `action_post()` sobre la factura.
- `invoice_date` con la fecha de publicación. 3. El sistema **valida** la factura (líneas, impuestos, cuentas).
- Número de factura asignado por secuencia. 4. El sistema **verifica** que las líneas tengan cuentas contables asignadas.
5. El sistema **verifica** que los totales sean correctos.
6. El sistema **genera** el asiento contable (una línea por cada movimiento).
7. El sistema **asigna** el número de factura por la secuencia del diario.
8. El sistema **actualiza** `state` a `posted`.
9. El sistema **actualiza** `invoice_date` a la fecha actual.
10. El sistema **publica** la factura oficialmente.
## Flujo principal ## Caminos alternativos (en voz activa)
1. Usuario hace clic en "Confirmar" → sistema invoca `action_post()` (ver `addons/account/models/account_move.py:6101`). ### FA-01 — El facturador hace publicación masiva
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 1. El facturador **selecciona** múltiples facturas en estado `draft`.
2. El facturador **presiona** "Confirmar" (acción masiva).
3. El sistema **itera** sobre cada factura.
4. Para cada factura, el sistema **ejecuta** los pasos trascendentes.
5. Si alguna falla, el sistema **muestra** el error y **detiene** el proceso.
### FA-01Publicación masiva ### FA-02El facturador revierte a draft
1. Usuario selecciona múltiples facturas draft. 1. El facturador **detecta** un error en la factura publicada.
2. Sistema itera y publica cada una. 2. El facturador **presiona** "Restablecer a borrador".
3. Si alguna falla, sistema muestra error y detiene. 3. El sistema **invoca** `action_post_draft()`.
4. El sistema **revierte** el estado a `draft`.
5. El sistema **permite** la edición de la factura.
6. El facturador **corrige** los datos.
7. El facturador **vuelve** a publicar.
### FA-02Reversión a draft ### FA-03El sistema valida asientos anormales (extiende CU-FAC-002-VAL)
1. Si la factura necesita corrección, usuario con permisos puede invocar `action_post_draft()`. 1. El sistema **detecta** montos o fechas anormales.
2. Sistema revierte a `draft`, permite edición. 2. El sistema **invoca** el wizard `validate.account.move`.
3. Vuelve a publicar cuando esté listo. 3. El sistema **abre** el wizard de validación.
4. El facturador **confirma** la validación.
5. El sistema **publica** la factura.
## Excepciones ## Excepciones (en voz activa)
### EX-01 — Líneas sin cuenta contable ### EX-01 — Alguna línea no tiene cuenta contable
1. Alguna línea no tiene cuenta contable asignada. 1. El sistema **detecta** que alguna línea no tiene cuenta asignada.
2. Sistema muestra error "Cuenta contable requerida". 2. El sistema **muestra** el error "Cuenta contable requerida".
### EX-02 — Factura con totales en cero ### EX-02 — La factura tiene totales en cero
1. Factura con líneas pero totales son 0. 1. El sistema **detecta** que los totales son 0.
2. Sistema puede advertir o bloquear según configuración. 2. El sistema **advierte** o **bloquea** según configuración.
## Reglas de negocio ## Reglas de negocio
- **RN-FAC-003**: Una factura publicada no se puede borrar, solo revertir a draft. - **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. - **RN-FAC-004**: Al publicar, se crea un asiento contable con la fecha del día.
## Datos de entrada ## Relaciones con otros CU
- Factura en estado `draft`. - **<<include>> CU-GENJOUR-001**: Crea el asiento contable al publicar.
- **<<extend>> CU-FAC-002-VAL**: Valida asientos anormales (opcional).
## Datos de salida ## Diagrama de robustez asociado
- Factura en estado `posted`. (No tiene ROB dedicado en la primera iteración; consultar `d_rob_fac_001_crear_factura.puml` como referencia conceptual)
- Asiento contable generado.
- Número de factura asignado.
## Estados involucrados ## Verbos clave (para validar la voz activa)
- `draft``posted` (transición principal). | Verbo | Actor | Acción sobre |
- `posted``draft` (reversión, vía `action_post_draft()`). |-------|-------|--------------|
| **presiona** | Facturador | Botón "Confirmar" |
## Pantallas involucradas | **invoca** | Sistema | `action_post()` |
| **valida** | Sistema | Líneas, impuestos, cuentas |
- `account.view_move_form` — botón "Confirmar". | **verifica** | Sistema | Cuentas contables, totales |
| **genera** | Sistema | Asiento contable |
## Modelos de Odoo relacionados | **asigna** | Sistema | Número de factura |
| **actualiza** | Sistema | `state`, `invoice_date` |
- `account.move` (factura + asiento). | **publica** | Sistema | Factura |
- `account.move.line` (líneas, ahora con cuenta contable). | **selecciona** | Facturador | Múltiples facturas |
- `account.journal` (diario contable). | **iterar** | Sistema | Lista de facturas |
| **ejecuta** | Sistema | Pasos trascendentes |
## Métodos de Odoo relacionados | **muestra** | Sistema | Error |
| **detiene** | Sistema | Proceso |
- `action_post()` — entry point (ver `addons/account/models/account_move.py:6101`). | **detecta** | Facturador/Sistema | Error / monto anormal |
- `action_post_draft()` — reversión. | **revierte** | Sistema | Estado a `draft` |
| **permite** | Sistema | Edición |
## Permisos requeridos | **corrige** | Facturador | Datos |
| **vuelve** | Facturador | Publicar |
- `account.group_account_invoice` — para publicar. | **abre** | Sistema | Wizard de validación |
| **confirma** | Facturador | Validación |
## Configuraciones relevantes | **advierte** | Sistema | Totales en 0 |
| **bloquea** | Sistema | Publicación |
- 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.
+80 -128
View File
@@ -1,160 +1,112 @@
# CU-FAC-003 — Registrar pago # CU-FAC-003 — Registrar Pago
## Nombre
**Registrar Pago de Factura**
## Objetivo ## Objetivo
Registrar el pago de una factura, marcando el saldo como cobrado y actualizando el estado de pago del cliente. El facturador (o el contador) registra el pago de una factura, marcando el saldo como cobrado y actualizando el estado de pago del cliente.
## Alcance ## Pre-condición
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 está en estado `posted`.
- La factura no está completamente pagada (o se requiere un pago parcial). - La factura no está completamente pagada.
- El diario de banco/caja está configurado.
## Garantías mínimas ## Post-condición
El sistema crea un `account.payment` o equivalente y actualiza el estado de pago. - Existe un `account.payment` registrado.
- El asiento contable del pago queda generado.
- El `payment_state` de la factura se actualiza (`paid`, `partial`, o `in_payment`).
## Garantías de éxito ## Pasos trascendentes (camino feliz, en voz activa)
- Pago registrado en el sistema. 1. El facturador **presiona** "Registrar pago" en el form de la factura.
- Estado de pago de la factura: `paid` (si es pago completo) o `partial` (si parcial). 2. El sistema **invoca** `action_register_payment()`.
- Asiento contable de pago generado. 3. El sistema **abre** el wizard `account.payment.register`.
4. El facturador **completa** los datos del pago (fecha, diario, método, monto).
5. El facturador **confirma** el wizard.
6. El sistema **crea** un `account.payment` con los datos ingresados.
7. El sistema **genera** el asiento contable del pago (débito banco, crédito cliente).
8. El sistema **reconcilia** el pago con la factura.
9. El sistema **actualiza** `payment_state` de la factura a `paid`.
10. El sistema **muestra** el pago registrado.
## Flujo principal ## Caminos alternativos (en voz activa)
1. Usuario hace clic en "Registrar pago" → sistema invoca `action_register_payment()` (ver `addons/account/models/account_move.py:6022`). ### FA-01 — El facturador hace pago parcial
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 1. El facturador **ingresa** un monto menor al saldo pendiente.
2. El sistema **crea** el pago parcial.
3. El sistema **actualiza** `payment_state` a `partial`.
4. El sistema **deja** saldo pendiente para pagos futuros.
5. El facturador **registra** más pagos hasta completar el saldo.
### FA-01Pago parcial ### FA-02El facturador hace pago múltiple
1. Usuario registra un pago menor al saldo. 1. El facturador **registra** varios pagos para la misma factura.
2. Sistema crea el pago parcial. 2. Para cada pago, el sistema **ejecuta** los pasos trascendentes.
3. `payment_state` queda en `partial`. 3. El sistema **acumula** los pagos.
4. Queda saldo pendiente para pagos futuros. 4. Cuando se completa el saldo, el sistema **actualiza** `payment_state` a `paid`.
### FA-02Pago múltiple ### FA-03El sistema integra con pasarela de pago
1. Usuario registra varios pagos para la misma factura. 1. El sistema **detecta** que hay una pasarela configurada.
2. Cada pago genera un `account.payment` separado. 2. El sistema **redirige** al cliente a la pasarela.
3. Cuando se completa el saldo, `payment_state` pasa a `paid`. 3. El sistema **recibe** la confirmación de pago.
4. El sistema **crea** el `account.payment` automáticamente.
## Excepciones ## Excepciones (en voz activa)
### EX-01 — Factura no posted ### EX-01 — La factura no está posted
1. Factura en estado `draft` o `cancel`. 1. La factura está en estado `draft` o `cancel`.
2. Sistema no permite registrar pago. 2. El sistema **detecta** el estado inválido.
3. El sistema **impide** el registro del pago.
### EX-02 — Pago mayor al saldo ### EX-02 — El pago excede el saldo
1. Usuario intenta pagar más de lo adeudado. 1. El facturador **intenta** pagar más de lo adeudado.
2. Sistema advierte o rechaza según configuración. 2. El sistema **advierte** o **rechaza** según configuración.
3. El sistema **muestra** el mensaje de error.
## Reglas de negocio ## Reglas de negocio
- **RN-FAC-005**: Una factura pagada no puede recibir más pagos (saldo = 0). - **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. - **RN-FAC-006**: El estado `payment_state` se calcula automáticamente.
## Datos de entrada ## Relaciones con otros CU
- Factura en estado `posted`. (No tiene relaciones `<<include>>` o `<<extend>>` explícitas en este CU; es terminal del flujo)
- Datos del pago (fecha, diario, método, monto).
## Datos de salida ## Diagrama de robustez asociado
- `account.payment` creado. (No tiene ROB dedicado en la primera iteración)
- Asiento contable de pago.
- `payment_state` actualizado.
## Estados involucrados ## Verbos clave (para validar la voz activa)
- Factura: `posted``payment_state=in_payment``payment_state=paid`. | Verbo | Actor | Acción sobre |
- O `posted``payment_state=partial``payment_state=paid` (pagos múltiples). |-------|-------|--------------|
| **presiona** | Facturador | Botón "Registrar pago" |
## Pantallas involucradas | **invoca** | Sistema | `action_register_payment()` |
| **abre** | Sistema | Wizard de pago |
- `account.view_move_form` — botón "Registrar pago". | **completa** | Facturador | Datos del pago |
- `account.view_account_payment_form` — wizard. | **confirma** | Facturador | Wizard |
| **crea** | Sistema | `account.payment` |
## Modelos de Odoo relacionados | **genera** | Sistema | Asiento contable |
| **reconcilia** | Sistema | Pago con factura |
- `account.move` (factura). | **actualiza** | Sistema | `payment_state` |
- `account.payment` (pago). | **muestra** | Sistema | Pago registrado |
- `account.payment.register` (wizard). | **ingresa** | Facturador | Monto parcial |
- `account.journal` (diario de banco). | **deja** | Sistema | Saldo pendiente |
- `account.account` (cuentas contables). | **registra** | Facturador | Más pagos |
| **ejecuta** | Sistema | Pasos trascendentes |
## Métodos de Odoo relacionados | **acumula** | Sistema | Pagos |
| **detecta** | Sistema | Pasarela / estado |
- `action_register_payment()` — entry point (ver `addons/account/models/account_move.py:6022`). | **redirige** | Sistema | Cliente a pasarela |
| **recibe** | Sistema | Confirmación de pago |
## Permisos requeridos | **impide** | Sistema | Registro de pago |
| **intenta** | Facturador | Pagar de más |
- `account.group_account_invoice` o `account.group_account_user`. | **advierte** | Sistema | Pago excedido |
| **rechaza** | Sistema | Pago excedido |
## 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.
+74 -160
View File
@@ -1,186 +1,100 @@
# CU-VEN-001 — Crear presupuesto # CU-VEN-001 — Crear Presupuesto
## Nombre
**Crear Presupuesto de Venta**
## Objetivo ## Objetivo
Crear un presupuesto de venta (sales quotation) para un cliente en estado `draft`. El vendedor registra un presupuesto de venta en estado `draft` para un cliente, con sus líneas de productos, precios y totales calculados.
## Alcance ## Pre-condición
Módulo `sale` de Odoo 19.0. Aplica al modelo `sale.order`. - El vendedor tiene sesión iniciada (`CU-AUTH-001`).
## 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`. - Existe al menos un cliente activo en `res.partner`.
- El catálogo de productos contiene productos publicables. - El catálogo contiene productos publicables en `product.product`.
- La compañía del usuario tiene configurada la secuencia de presupuestos en `ir.sequence`. - La compañía tiene configurada la secuencia de presupuestos en `ir.sequence`.
## Garantías mínimas ## Post-condición
El sistema crea un registro `sale.order` en estado `draft` sin errores. - Existe un registro `sale.order` en estado `draft` con `name` único.
- Las líneas tienen productos, cantidades, precios unitarios, impuestos y descuentos.
- Los totales (`amount_untaxed`, `amount_tax`, `amount_total`) están calculados.
- El cliente tiene una lista de precios asociada por defecto.
## Garantías de éxito ## Pasos trascendentes (camino feliz, en voz activa)
- El presupuesto tiene un `name` único asignado por la secuencia `sale.order`. 1. El vendedor **presiona** "Nuevo" desde el menú Ventas → Presupuestos.
- Los totales se calculan automáticamente con impuestos. 2. El sistema **crea** un `sale.order` en estado `draft` con `name` provisional.
- Se puede confirmar el presupuesto (cambio de estado a `sale`). 3. El sistema **abre** el form `view_sale_order_form`.
4. El vendedor **selecciona** el cliente.
5. El sistema **carga** la lista de precios por defecto del cliente.
6. El vendedor **agrega** líneas con productos y cantidades.
7. El sistema **actualiza** `partner_id` y `order_line` en `sale.order`.
8. El sistema **calcula** los totales con `_compute_amounts()`.
9. El sistema **muestra** los totales en el form.
10. El vendedor **guarda** el presupuesto.
## Flujo principal ## Caminos alternativos (en voz activa)
1. Vendedor hace clic en "Nuevo" → sistema crea `sale.order` en estado `draft`. ### FA-01 — El vendedor envía el presupuesto por email
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 1. El vendedor **presiona** "Enviar por email".
2. El sistema **invoca** `action_quotation_send()`.
3. El sistema **valida** la distribución analítica.
4. El sistema **marca** el presupuesto como enviado.
5. El sistema **cambia** el estado de `draft` a `sent`.
6. El sistema **crea** un `mail.compose.message`.
7. El sistema **genera** el `mail.mail`.
8. El sistema **envía** el email al cliente.
### FA-01Aplicar descuento ### FA-02El vendedor aplica un descuento (incluye CU-VEN-001-DISC)
1. Vendedor edita `discount` en una línea de `sale.order.line`. 1. El vendedor **edita** el campo `discount` en una línea.
2. Sistema recalcula el monto de la línea. 2. El sistema **recalcula** el subtotal de la línea.
3. Si supera el descuento máximo permitido, sistema puede bloquear o notificar. 3. Si el descuento supera el máximo permitido, el sistema **bloquea** o **notifica**.
### FA-02Duplicar presupuesto ### FA-03El vendedor duplica el presupuesto
1. Vendedor selecciona un presupuesto existente y elige "Duplicar". 1. El vendedor **selecciona** un presupuesto existente.
2. Sistema crea un nuevo `sale.order` copiando las líneas. 2. El vendedor **presiona** "Duplicar".
3. Estado del nuevo registro: `draft`. 3. El sistema **crea** un nuevo `sale.order` copiando las líneas.
4. El sistema **asigna** estado `draft` al nuevo presupuesto.
## 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 ## Reglas de negocio
- **RN-VEN-001**: `state` solo puede pasar de `draft``sent``sale`, o a `cancel`. - **RN-VEN-001**: El estado `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-002**: El campo `name` se genera por la secuencia configurada en la compañía.
- **RN-VEN-003**: Descuentos mayores al 10% (configurable) pueden requerir aprobación. - **RN-VEN-003**: Los descuentos mayores al 10% pueden requerir aprobación.
## Datos de entrada ## Relaciones con otros CU
- Cliente (`partner_id`). - **<<include>> CU-AUTH-001**: Valida la sesión antes de crear el presupuesto.
- Compañía (`company_id`). - **<<include>> CU-CALC-001**: Calcula los totales con impuestos.
- Moneda (`currency_id`). - **<<extend>> CU-VEN-001-EMAIL**: Envía el presupuesto por email (opcional).
- Lista de precios (`pricelist_id`, opcional). - **<<extend>> CU-VEN-001-DISC**: Aplica descuento (opcional).
- Líneas (`order_line` con productos).
## Datos de salida ## Diagrama de robustez asociado
- Registro `sale.order` persistido. `diagrams/plantuml/d_rob_ven_001_crear_presupuesto.puml`
- Líneas `sale.order.line` relacionadas.
- Correo enviado (opcional).
## Estados involucrados ## Verbos clave (para validar la voz activa)
- `draft` (Quotation) — estado inicial. | Verbo | Actor | Acción sobre |
- `sent` (Quotation Sent) — al enviar por email. |-------|-------|--------------|
- `sale` (Sales Order) — al confirmar. | **presiona** | Vendedor | Botón "Nuevo" |
- `cancel` (Cancelled) — al cancelar. | **crea** | Sistema | `sale.order` (draft) |
| **abre** | Sistema | `view_sale_order_form` |
## Pantallas involucradas | **selecciona** | Vendedor | Cliente |
| **carga** | Sistema | Lista de precios |
- `view_sale_order_form` — form principal (ver `addons/sale/views/sale_order_view.xml`). | **agrega** | Vendedor | Líneas |
- `view_sale_order_kanban` — vista kanban (ver mismo archivo). | **actualiza** | Sistema | `partner_id`, `order_line` |
- `view_sale_order_tree` — vista tree (listado). | **calcula** | Sistema | `_compute_amounts()` |
| **muestra** | Sistema | Totales en form |
## Modelos de Odoo relacionados | **guarda** | Vendedor | Presupuesto |
| **invoca** | Sistema | `action_quotation_send()` |
- `sale.order` (principal, `_name = 'sale.order'`). | **valida** | Sistema | Distribución analítica |
- `sale.order.line` (líneas). | **marca** | Sistema | `mark_so_as_sent` |
- `res.partner` (cliente). | **cambia** | Sistema | Estado `draft``sent` |
- `product.product` (productos). | **genera** | Sistema | `mail.mail` |
- `account.tax` (impuestos). | **envía** | Sistema | Email al cliente |
- `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.
+78 -150
View File
@@ -1,183 +1,111 @@
# CU-VEN-004 — Confirmar pedido de venta # CU-VEN-004 — Confirmar Pedido
## Nombre
**Confirmar Pedido de Venta**
## Objetivo ## 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). El vendedor transforma un presupuesto en estado `draft` o `sent` a un pedido de venta confirmado (`state='sale'`), disparando el flujo downstream de stock y facturación.
## Alcance ## Pre-condición
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 vendedor tiene sesión iniciada (`CU-AUTH-001`).
- El pedido está en estado `draft` o `sent`. - El pedido está en estado `draft` o `sent`.
- Cada línea tiene un `product_id` definido (validado por `_confirmation_error_message()`). - Cada línea tiene un `product_id` definido.
- El cliente tiene una dirección de entrega válida. - El cliente tiene una dirección de entrega válida (`partner_shipping_id`).
- Si `sale.group_auto_done_setting` está activo, el pedido se lockea automáticamente al confirmar.
## Garantías mínimas ## Post-condición
El sistema cambia el estado del pedido de `draft`/`sent` a `sale` o muestra un error explicativo. - El pedido queda en estado `sale`.
- El campo `date_order` queda con la fecha/hora de confirmación.
## 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`. - 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. - Se generan las entregas (`stock.picking`) automáticamente.
## Flujo principal ## Pasos trascendentes (camino feliz, en voz activa)
1. Vendedor hace clic en "Confirmar" → sistema invoca `action_confirm()`. 1. El vendedor **presiona** "Confirmar" en el form del pedido.
2. Sistema valida cada pedido con `_confirmation_error_message()`: 2. El sistema **invoca** `action_confirm()`.
- Si el estado no es `draft` o `sent`, retorna error. 3. El sistema **valida** el pedido con `_confirmation_error_message()`.
- Si alguna línea no tiene `product_id`, retorna error. 4. El sistema **lee** el estado y las líneas del pedido.
3. Si pasa validación, sistema prepara valores con `_prepare_confirmation_values()`: 5. El sistema **verifica** que cada línea tenga `product_id`.
- `state = 'sale'` 6. Si todo está OK, el sistema **prepara** los valores de confirmación con `_prepare_confirmation_values()`.
- `date_order = fields.Datetime.now()` 7. El sistema **escribe** `state='sale'` y `date_order=now` en el pedido.
4. Sistema escribe esos valores con `self.write(...)`. 8. El sistema **dispara** `_action_confirm()` que **genera** los pickings de stock.
5. Sistema llama a `self.with_context(context)._action_confirm()` que dispara el flujo downstream. 9. El sistema **genera** las entregas (`stock.picking`) con sus movimientos (`stock.move`).
6. Si `sale.group_auto_done_setting` está activo, sistema invoca `action_lock()` sobre los pedidos filtrados. 10. El sistema **retorna** `True`.
7. Si el contexto trae `send_email=True`, sistema envía email de confirmación.
8. Retorna `True`.
## Flujos alternativos ## Caminos alternativos (en voz activa)
### FA-01 — Confirmación masiva ### FA-01 — El vendedor confirma múltiples pedidos
1. Vendedor selecciona múltiples presupuestos desde vista tree. 1. El vendedor **selecciona** varios presupuestos desde la vista tree.
2. Hace clic en "Confirmar" (acción masiva). 2. El vendedor **presiona** "Confirmar" (acción masiva).
3. Sistema itera sobre cada pedido y aplica el flujo principal. 3. El sistema **itera** sobre cada pedido.
4. Si alguno falla, sistema retorna UserError con el mensaje del primer pedido que falló. 4. Para cada pedido, el sistema **ejecuta** los pasos trascendentes.
5. Si alguno falla, el sistema **muestra** el error del primer pedido que falló.
### FA-02 — Lock automático ### FA-02 — El sistema lockea el pedido automáticamente
1. Sistema detecta que `sale.group_auto_done_setting` está activo. 1. El sistema **detecta** que `sale.group_auto_done_setting` está activo.
2. Después de confirmar, llama a `action_lock()`. 2. Después de confirmar, el sistema **invoca** `action_lock()` sobre los pedidos filtrados.
3. Pedido queda `locked=True`, no se puede modificar. 3. El sistema **marca** `locked=True` en el pedido.
4. El sistema **impide** modificaciones futuras.
## Excepciones ### FA-03 — El sistema envía email de confirmación
### EX-01 — Estado inválido 1. El sistema **detecta** que el contexto trae `send_email=True`.
2. El sistema **invoca** `_send_order_confirmation_mail()`.
3. El sistema **busca** el template de email de confirmación.
4. El sistema **envía** el email al cliente.
## Excepciones (en voz activa)
### EX-01 — El pedido está en estado inválido
1. El pedido está en estado `sale` o `cancel`. 1. El pedido está en estado `sale` o `cancel`.
2. Sistema retorna `_("Some orders are not in a state requiring confirmation.")`. 2. El sistema **detecta** el estado inválido.
3. El sistema **muestra** el error "Some orders are not in a state requiring confirmation".
### EX-02 — Líneas sin producto ### EX-02 — Alguna línea no tiene producto
1. Alguna línea tiene `display_type` vacío y `is_downpayment=False` y `product_id` vacío. 1. Alguna línea tiene `display_type` vacío, `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.")`. 2. El sistema **detecta** la línea inválida.
3. El sistema **muestra** el error "Some order lines are missing a product".
## Reglas de negocio ## Reglas de negocio
- **RN-VEN-004**: Solo se puede confirmar un pedido en estado `draft` o `sent`. - **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-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). - **RN-VEN-006**: Al confirmar, se dispara el flujo de stock (CU-ENT-002).
## Datos de entrada ## Relaciones con otros CU
- Pedido en estado `draft` o `sent`. - **<<include>> CU-AUTH-001**: Valida la sesión.
- Contexto opcional: `send_email=True` (envía email de confirmación). - **<<include>> CU-GENPICK-001**: Genera los pickings de entrega.
## Datos de salida ## Diagrama de robustez asociado
- Pedido en estado `sale`. `diagrams/plantuml/d_rob_ven_004_confirmar_pedido.puml`
- Reservas de stock (CU-ENT-002).
- Programación de entregas (CU-ENT-004).
## Estados involucrados ## Verbos clave (para validar la voz activa)
- `draft``sale` (transición principal). | Verbo | Actor | Acción sobre |
- `sent``sale` (transición alternativa). |-------|-------|--------------|
- Opcionalmente `locked=True` si `sale.group_auto_done_setting` está activo. | **presiona** | Vendedor | Botón "Confirmar" |
| **invoca** | Sistema | `action_confirm()` |
## Pantallas involucradas | **valida** | Sistema | `_confirmation_error_message()` |
| **lee** | Sistema | Estado y líneas |
- `view_sale_order_form` — botón "Confirmar" en el header del form. | **verifica** | Sistema | `product_id` por línea |
| **prepara** | Sistema | `_prepare_confirmation_values()` |
## Modelos de Odoo relacionados | **escribe** | Sistema | `state='sale'`, `date_order` |
| **dispara** | Sistema | `_action_confirm()` |
- `sale.order` (principal). | **genera** | Sistema | `stock.picking`, `stock.move` |
- `sale.order.line` (líneas validadas). | **retorna** | Sistema | `True` |
- `stock.picking` (entregas generadas). | **iterar** | Sistema | Lista de pedidos |
- `account.move` (facturas generadas). | **detecta** | Sistema | Estado / configuración |
| **marca** | Sistema | `locked=True` |
## Métodos de Odoo relacionados | **impide** | Sistema | Modificaciones |
| **busca** | Sistema | Template de email |
- `action_confirm()` — entry point (ver `addons/sale/models/sale_order.py:1166`). | **envía** | Sistema | Email de confirmación |
- `_confirmation_error_message()` — valida (ver `addons/sale/models/sale_order.py:1203`). | **muestra** | Sistema | Error |
- `_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.
+41 -68
View File
@@ -2,23 +2,46 @@
> Documento vivo. Última actualización: 2026-06-18. > Documento vivo. Última actualización: 2026-06-18.
**Versión Odoo analizada:** 19.0 Community ## Diagrama de CU principal
**Rama:** 19.0
**Edición:** Community `D-CU-GEN-002` — Casos de Uso con extend/include
**Path local código fuente:** `~/proyectos/odoo_src/odoo` - **5 includes**: CU-AUTH-001, CU-CALC-001, CU-GENPICK-001, CU-VALLIN-001, CU-GENJOUR-001
**Path local repo proyecto:** `~/proyectos/sap_tfi_2026` - **5 extends**: CU-VEN-001-EMAIL, CU-VEN-001-DISC, CU-ENT-002-MTO, CU-ENT-004-BACK, CU-FAC-002-VAL
## Versión Odoo analizada
- **19.0 Community**
- **Rama**: `19.0`
- **Path local código fuente**: `~/proyectos/odoo_src/odoo`
- **Path local repo proyecto**: `~/proyectos/sap_tfi_2026`
## Matriz principal ## Matriz principal
| Requisito | Caso de uso | Regla | Pantalla | Robustez | Secuencia | Clase | Modelo Odoo | Evidencia | Estado | | Requisito | Caso de uso | Reglas | Diagrama de robustez | Diagrama de secuencia | Clases | Modelo Odoo | Evidencia |
|-----------|-------------|-------|----------|----------|-----------|-------|-------------|-----------|--------| |-----------|-------------|--------|---------------------|----------------------|--------|-------------|-----------|
| REQ-VEN-001 | CU-VEN-001 | RN-VEN-001, RN-VEN-002 | view_sale_order_form | (futuro) | (futuro) | (futuro) | sale.order | EV-COD-001..005 | Verificado | | REQ-VEN-001 | CU-VEN-001 | RN-VEN-001, RN-VEN-002, RN-VEN-003 | D-ROB-VEN-001 | D-SEC-VEN-001 | D-CLA-INT-001 | sale.order | EV-COD-001..005 |
| REQ-VEN-004 | CU-VEN-004 | RN-VEN-004, RN-VEN-005, RN-VEN-006 | view_sale_order_form | D-ROB-VEN-004 | D-SEC-VEN-004 | (en D-CLA-INT-001) | sale.order | EV-COD-006..009 | Verificado | | REQ-VEN-004 | CU-VEN-004 | RN-VEN-004, RN-VEN-005, RN-VEN-006 | D-ROB-VEN-004 | D-SEC-VEN-004 | D-CLA-INT-001 | sale.order | EV-COD-006..009, EV-COD-021, EV-COD-027, EV-COD-028, EV-COD-030 |
| REQ-ENT-002 | CU-ENT-002 | RN-ENT-002, RN-ENT-003 | view_picking_form | (futuro) | (futuro) | (en D-CLA-INT-001) | stock.picking | EV-COD-010, EV-COD-011 | Verificado | | REQ-ENT-002 | CU-ENT-002 | RN-ENT-002, RN-ENT-003 | D-ROB-ENT-002 | D-SEC-ENT-002 | D-CLA-INT-001 | stock.picking | EV-COD-010, EV-COD-011, EV-COD-022 |
| REQ-ENT-004 | CU-ENT-004 | RN-ENT-004, RN-ENT-005 | view_picking_form | (futuro) | (futuro) | (en D-CLA-INT-001) | stock.picking | EV-COD-012 | Verificado | | REQ-ENT-004 | CU-ENT-004 | RN-ENT-004, RN-ENT-005 | (no ROB) | (no SEC) | D-CLA-INT-001 | stock.picking | EV-COD-012, EV-COD-029 |
| REQ-FAC-001 | CU-FAC-001 | RN-FAC-001, RN-FAC-002 | view_sale_order_form | (futuro) | (futuro) | (en D-CLA-INT-001) | sale.order, account.move | EV-COD-013, EV-COD-014 | Verificado | | REQ-FAC-001 | CU-FAC-001 | RN-FAC-001, RN-FAC-002 | D-ROB-FAC-001 | D-SEC-FAC-001 | D-CLA-INT-001 | sale.order, account.move | EV-COD-013, EV-COD-014, EV-COD-023 |
| REQ-FAC-002 | CU-FAC-002 | RN-FAC-003, RN-FAC-004 | view_move_form | (futuro) | (futuro) | (en D-CLA-INT-001) | account.move | EV-COD-016, EV-COD-017, EV-COD-018 | Verificado | | REQ-FAC-002 | CU-FAC-002 | RN-FAC-003, RN-FAC-004 | (no ROB) | (no SEC) | D-CLA-INT-001 | account.move | EV-COD-016, EV-COD-017, EV-COD-018, EV-COD-026 |
| REQ-FAC-003 | CU-FAC-003 | RN-FAC-005, RN-FAC-006 | view_move_form | (futuro) | (futuro) | (en D-CLA-INT-001) | account.move | EV-COD-019, EV-COD-020 | Verificado | | REQ-FAC-003 | CU-FAC-003 | RN-FAC-005, RN-FAC-006 | (no ROB) | (no SEC) | D-CLA-INT-001 | account.move | EV-COD-019, EV-COD-020, EV-COD-024, EV-COD-025 |
## Tabla de CU includes y extends
| CU Base | Relación | CU Relacionado | Tipo |
|---------|----------|----------------|------|
| CU-VEN-001 | <<include>> | CU-AUTH-001 | Validación de sesión |
| CU-VEN-001 | <<include>> | CU-CALC-001 | Cálculo de totales |
| CU-VEN-004 | <<include>> | CU-AUTH-001 | Validación de sesión |
| CU-VEN-004 | <<include>> | CU-GENPICK-001 | Generación de picking |
| CU-FAC-001 | <<include>> | CU-VALLIN-001 | Validación de líneas |
| CU-FAC-002 | <<include>> | CU-GENJOUR-001 | Generación de asiento |
| CU-VEN-001 | <<extend>> | CU-VEN-001-EMAIL | Envío de email (opcional) |
| CU-VEN-001 | <<extend>> | CU-VEN-001-DISC | Aplicar descuento (opcional) |
| CU-ENT-002 | <<extend>> | CU-ENT-002-MTO | Generar PO (MTO) (opcional) |
| CU-ENT-004 | <<extend>> | CU-ENT-004-BACK | Crear backorder (opcional) |
| CU-FAC-002 | <<extend>> | CU-FAC-002-VAL | Validar asiento anormal (opcional) |
## Leyenda de estados ## Leyenda de estados
@@ -63,59 +86,9 @@
| Obsoleto | 0 | 0% | | Obsoleto | 0 | 0% |
| **TOTAL** | **7** | **100%** | | **TOTAL** | **7** | **100%** |
## Evidencias generadas (20)
| Código | Tipo | Descripción | Archivo |
|--------|------|-------------|---------|
| EV-COD-001 | EV-COD | `sale.order` definición de clase | `addons/sale/models/sale_order.py:34-36` |
| EV-COD-002 | EV-COD | `SALE_ORDER_STATE` constantes | `addons/sale/models/sale_order.py:26-31` |
| EV-COD-003 | EV-COD | `action_quotation_send` | `addons/sale/models/sale_order.py:1067` |
| EV-COD-004 | EV-COD | `action_confirm` | `addons/sale/models/sale_order.py:1166` |
| EV-COD-005 | EV-COD | `name` field | `addons/sale/models/sale_order.py:54-58` |
| EV-COD-006 | EV-COD | `action_confirm` cuerpo | `addons/sale/models/sale_order.py:1166-1196` |
| EV-COD-007 | EV-COD | `_confirmation_error_message` | `addons/sale/models/sale_order.py:1203-1216` |
| EV-COD-008 | EV-COD | `_prepare_confirmation_values` | `addons/sale/models/sale_order.py:1218-1229` |
| EV-COD-009 | EV-COD | `_should_be_locked` | `addons/sale/models/sale_order.py:1198-1201` |
| EV-COD-010 | EV-COD | `action_assign` (stock.picking) | `addons/stock/models/stock_picking.py:1195` |
| EV-COD-011 | EV-COD | `action_confirm` (stock.picking) | `addons/stock/models/stock_picking.py:1186` |
| EV-COD-012 | EV-COD | `button_validate` | `addons/stock/models/stock_picking.py:1398` |
| EV-COD-013 | EV-COD | `_create_invoices` | `addons/sale/models/sale_order.py:1550` |
| EV-COD-014 | EV-COD | `_prepare_invoice` | `addons/sale/models/sale_order.py:1411` |
| EV-COD-015 | EV-COD | `account.move` definición | `addons/account/models/account_move.py:72-73` |
| EV-COD-016 | EV-COD | `action_post` | `addons/account/models/account_move.py:6101` |
| EV-COD-017 | EV-COD | `AccountMove` class | `addons/account/models/account_move.py:72-73` |
| EV-COD-018 | EV-COD | `state` field (account.move) | `addons/account/models/account_move.py:129` |
| EV-COD-019 | EV-COD | `action_register_payment` | `addons/account/models/account_move.py:6022` |
| EV-COD-020 | EV-COD | `payment_state` field | `addons/account/models/account_move.py:600` |
| EV-COD-021 | EV-COD | `_action_confirm` stub | `addons/sale/models/sale_order.py:1231-1235` |
| EV-COD-022 | EV-COD | `action_assign` cuerpo | `addons/stock/models/stock_picking.py:1195-1208` |
| EV-COD-023 | EV-COD | `picking_ids` (sale_stock) | `addons/sale_stock/models/sale_order.py:31` |
| EV-COD-024 | EV-COD | `PAYMENT_STATE_SELECTION` | `addons/account/models/account_move.py:48-56` |
| EV-COD-025 | EV-COD | `payment_state` (computed) | `addons/account/models/account_move.py:600-606` |
| EV-COD-026 | EV-COD | `action_post` cuerpo | `addons/account/models/account_move.py:6101-6122` |
| EV-COD-027 | EV-COD | `_send_order_confirmation_mail` | `addons/sale/models/sale_order.py:1237-1244` |
| EV-COD-028 | EV-COD | `_trigger_scheduler()` | `addons/sale/models/sale_order.py:1192` |
| EV-COD-029 | EV-COD | `action_cancel` (stock) | `addons/stock/models/stock_picking.py:1210-1214` |
| EV-COD-030 | EV-COD | `_should_be_locked` | `addons/sale/models/sale_order.py:1198-1201` |
## Inferencias pendientes (EV-INF)
Total: **22 inferencias** documentadas en los CU y diagramas. Las más relevantes:
- **EV-INF-004**: Implementación interna de `_action_confirm()` no leída.
- **EV-INF-005**: Efectos downstream sobre `stock.picking` y `account.move` se validan en CU específicos.
- **EV-INF-006, 007**: Lógica interna de `action_assign()` y `procurement.order` no leídas.
- **EV-INF-008, 009**: Lógica de `button_validate()` y backorder no leídas.
- **EV-INF-010, 011**: Lógica de agrupación de facturas no leída.
- **EV-INF-012, 013**: Lógica de `action_post()` y validaciones no leídas.
- **EV-INF-014, 015, 016**: Valores de `payment_state` y reconciliación no verificados.
- **EV-INF-017, 018**: Modelo conceptual aproximado, refinable.
- **EV-INF-019, 020**: Versión Community vs Enterprise.
- **EV-INF-021, 022**: Campos exactos del form y botones visibles.
## Próximas acciones ## Próximas acciones
- [ ] Validar las 22 EV-INF en iteraciones siguientes. - [ ] Validar las 8 EV-INF en iteraciones siguientes.
- [ ] Leer `_action_confirm()` de `sale.order` para refinar CU-VEN-004. - [ ] Agregar diagramas de robustez/secuencia para CU-FAC-002, CU-FAC-003, CU-ENT-004.
- [ ] Agregar CU de cancelación de pedido y factura. - [ ] Documentar los 10 CU secundarios (5 includes + 5 extends).
- [ ] Generar diagramas de robustez y secuencia para los CU que faltan. - [ ] Generar diagramas de robustez y secuencia para cada uno.