mirror of
https://github.com/cursos-uai/sap_tfi_2026.git
synced 2026-07-31 20:48:30 -03:00
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:
@@ -1,146 +1,108 @@
|
||||
# CU-ENT-002 — Reservar productos
|
||||
# CU-ENT-002 — Reservar Productos
|
||||
|
||||
## Nombre
|
||||
|
||||
**Reservar Productos en Almacén**
|
||||
|
||||
## 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.
|
||||
- Vendedor (necesita saber si hay stock).
|
||||
- Cliente (recibe confirmación de entrega).
|
||||
### FA-02 — El sistema hace reserva parcial
|
||||
|
||||
## 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.
|
||||
- Botón manual "Reservar" en el picking (interfaz de inventario).
|
||||
### FA-03 — El operario fuerza la reserva manualmente
|
||||
|
||||
## 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`.
|
||||
- Los productos tienen stock disponible o se puede conseguir (vía reglas de abastecimiento).
|
||||
## Excepciones (en voz activa)
|
||||
|
||||
## 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`.
|
||||
- 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.
|
||||
1. El sistema **busca** stock y **no encuentra** cantidad.
|
||||
2. El sistema **consulta** reglas de reabastecimiento y **no encuentra** aplicables.
|
||||
3. El sistema **deja** el picking en estado `partially_available`.
|
||||
4. El operario **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
|
||||
## 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.
|
||||
- Estado del picking actualizado.
|
||||
- Posibles órdenes de compra generadas.
|
||||
`diagrams/plantuml/d_rob_ent_002_reservar_productos.puml`
|
||||
|
||||
## Estados involucrados
|
||||
## Verbos clave (para validar la voz activa)
|
||||
|
||||
- `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.
|
||||
| Verbo | Actor | Acción sobre |
|
||||
|-------|-------|--------------|
|
||||
| **dispara** | Sistema/Operario | Trigger de reserva |
|
||||
| **lee** | Sistema | Picking y líneas |
|
||||
| **invoca** | Sistema | `action_assign()` |
|
||||
| **recorre** | Sistema | Líneas del picking |
|
||||
| **busca** | Sistema | Stock en `stock.quant` |
|
||||
| **encuentra** | Sistema | Cantidad disponible |
|
||||
| **reserva** | Sistema | `stock.move.line` |
|
||||
| **actualiza** | Sistema | `reserved_availability`, estado |
|
||||
| **asigna** | Sistema | Estado `assigned` |
|
||||
| **consulta** | Sistema | `stock.warehouse.orderpoint` |
|
||||
| **extiende** | Sistema | `CU-ENT-002-MTO` |
|
||||
| **crea** | Sistema | `purchase.order` |
|
||||
| **programa** | Sistema | Recepción |
|
||||
| **marca** | Sistema | `partially_available` |
|
||||
| **deja** | Sistema | Estado sin cambio |
|
||||
| **presiona** | Operario | Botón "Reservar" |
|
||||
| **ejecuta** | Sistema | Pasos trascendentes |
|
||||
| **detecta** | Sistema | Movimientos / reglas |
|
||||
| **muestra** | Sistema | Error |
|
||||
| **libera** | Sistema | Reservas (al cancelar) |
|
||||
@@ -1,151 +1,104 @@
|
||||
# CU-ENT-004 — Validar entrega
|
||||
# CU-ENT-004 — Validar Entrega
|
||||
|
||||
## Nombre
|
||||
|
||||
**Validar Entrega de Productos**
|
||||
|
||||
## 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`.
|
||||
|
||||
## 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).
|
||||
- El picking está en estado `assigned` o `partially_available`.
|
||||
- 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`.
|
||||
- Stock actualizado (las cantidades reservadas se descuentan del stock disponible).
|
||||
- Posible creación automática de factura si está configurado.
|
||||
1. El operario **presiona** "Validar" en el form del picking.
|
||||
2. El sistema **invoca** `button_validate()`.
|
||||
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`).
|
||||
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`.
|
||||
### FA-01 — El operario hace entrega parcial (extiende CU-ENT-004-BACK)
|
||||
|
||||
## 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.
|
||||
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.
|
||||
1. El sistema **detecta** que está configurada la facturación automática al validar.
|
||||
2. El sistema **invoca** `_create_invoices()` desde el picking.
|
||||
3. El sistema **crea** la factura (`account.move`).
|
||||
4. El sistema **vincula** la salida de stock con la factura.
|
||||
|
||||
### FA-02 — Crear factura al validar
|
||||
### FA-03 — El sistema valida sin wizard
|
||||
|
||||
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.
|
||||
1. El operario **presiona** "Validar" sin necesidad de wizard (configuración).
|
||||
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.
|
||||
2. Sistema valida y rechaza si excede.
|
||||
3. Sistema muestra error claro.
|
||||
1. El operario **intenta** entregar más cantidad de la reservada.
|
||||
2. El sistema **valida** y **rechaza** si excede.
|
||||
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`.
|
||||
2. Sistema no permite validar.
|
||||
1. El picking está en estado `draft` o `cancel`.
|
||||
2. El sistema **detecta** el estado inválido.
|
||||
3. El sistema **impide** la validación.
|
||||
|
||||
## 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`.
|
||||
- **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`.
|
||||
- Cantidades reales (pueden diferir de las reservadas).
|
||||
- **<<extend>> CU-ENT-004-BACK**: Crea backorder cuando hay entrega parcial (opcional).
|
||||
|
||||
## Datos de salida
|
||||
## Diagrama de robustez asociado
|
||||
|
||||
- Picking en `done`.
|
||||
- Stock actualizado.
|
||||
- Posible factura generada.
|
||||
`diagrams/plantuml/d_rob_ven_001_crear_presupuesto.puml` (compartido conceptualmente; este CU no tiene ROB dedicado en la primera iteración)
|
||||
|
||||
## Estados involucrados
|
||||
## Verbos clave (para validar la voz activa)
|
||||
|
||||
- `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.
|
||||
| Verbo | Actor | Acción sobre |
|
||||
|-------|-------|--------------|
|
||||
| **presiona** | Operario | Botón "Validar" |
|
||||
| **invoca** | Sistema | `button_validate()` |
|
||||
| **abre** | Sistema | Wizard de validación |
|
||||
| **confirma** | Operario | Cantidades reales |
|
||||
| **actualiza** | Sistema | `stock.move`, `stock.quant` |
|
||||
| **crea** | Sistema | `stock.move.line`, backorder, factura |
|
||||
| **cambia** | Sistema | Estado del picking |
|
||||
| **muestra** | Sistema | Resultado |
|
||||
| **completa** | Sistema | Picking original |
|
||||
| **deja** | Sistema | Backorder |
|
||||
| **procesa** | Operario | Backorder |
|
||||
| **detecta** | Sistema | Configuración de facturación |
|
||||
| **vincula** | Sistema | Salida de stock con factura |
|
||||
| **ejecuta** | Sistema | Validación directa |
|
||||
| **intenta** | Operario | Entregar cantidad |
|
||||
| **rechaza** | Sistema | Cantidad excedida |
|
||||
| **impide** | Sistema | Validación |
|
||||
@@ -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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
## Pre-condición
|
||||
|
||||
- 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 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.
|
||||
|
||||
## Garantías de éxito
|
||||
|
||||
- Factura creada en estado `draft`.
|
||||
- Línea de factura con `quantity`, `price_unit`, `tax_ids` correctos.
|
||||
- Existe un `account.move` en estado `draft` con tipo `out_invoice`.
|
||||
- Las líneas tienen `quantity`, `price_unit`, `tax_ids` correctos.
|
||||
- `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`).
|
||||
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`.
|
||||
1. El facturador **presiona** "Crear Factura" en el form del pedido.
|
||||
2. El sistema **invoca** `_create_invoices()` sobre el pedido.
|
||||
3. El sistema **lee** el pedido (`sale.order` en estado `sale`).
|
||||
4. El sistema **verifica** el `invoice_status` del pedido.
|
||||
5. El sistema **lee** las líneas pendientes (`sale.order.line`).
|
||||
6. El sistema **aplica** los impuestos (`account.tax`) a cada línea.
|
||||
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`).
|
||||
2. Sistema crea una factura con líneas de todos los pedidos.
|
||||
3. Cada pedido referencia la factura agrupada.
|
||||
1. El facturador **selecciona** múltiples pedidos.
|
||||
2. El facturador **presiona** "Crear Factura" con `grouped=True`.
|
||||
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).
|
||||
2. Resto queda pendiente para futuras facturas.
|
||||
1. El facturador **selecciona** las líneas específicas a facturar.
|
||||
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`.
|
||||
2. Sistema retorna mensaje "Nothing to invoice".
|
||||
## Excepciones (en voz activa)
|
||||
|
||||
### EX-02 — Compañía sin diario configurado
|
||||
### EX-01 — No hay nada que facturar
|
||||
|
||||
1. Compañía no tiene `currency_id` o `journal_id` configurado.
|
||||
2. Sistema retorna error de configuración.
|
||||
1. El sistema **verifica** que `invoice_status` es `invoiced`.
|
||||
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
|
||||
|
||||
- **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`.
|
||||
- Cantidades a facturar (pueden ser parciales).
|
||||
- **<<include>> CU-VALLIN-001**: Valida líneas pendientes antes de facturar.
|
||||
|
||||
## Datos de salida
|
||||
## Diagrama de robustez asociado
|
||||
|
||||
- `account.move` (factura) en estado `draft`.
|
||||
- `account.move.line` (líneas de factura).
|
||||
`diagrams/plantuml/d_rob_fac_001_crear_factura.puml`
|
||||
|
||||
## Estados involucrados
|
||||
## Verbos clave (para validar la voz activa)
|
||||
|
||||
- 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.
|
||||
| Verbo | Actor | Acción sobre |
|
||||
|-------|-------|--------------|
|
||||
| **presiona** | Facturador | Botón "Crear Factura" |
|
||||
| **invoca** | Sistema | `_create_invoices()` |
|
||||
| **lee** | Sistema | Pedido, líneas, taxes |
|
||||
| **verifica** | Sistema | `invoice_status` |
|
||||
| **aplica** | Sistema | Impuestos a líneas |
|
||||
| **crea** | Sistema | `account.move`, `account.move.line` |
|
||||
| **construye** | Sistema | `_prepare_invoice()` |
|
||||
| **asocia** | Sistema | `invoice_ids` |
|
||||
| **actualiza** | Sistema | `invoice_status` |
|
||||
| **muestra** | Sistema | Factura al facturador |
|
||||
| **selecciona** | Facturador | Múltiples pedidos |
|
||||
| **agrupa** | Sistema | Líneas agrupadas |
|
||||
| **factura** | Sistema | Líneas específicas |
|
||||
| **deja** | Sistema | Líneas pendientes |
|
||||
| **detecta** | Sistema | Validación de entrega / config |
|
||||
| **ejecuta** | Sistema | Pasos trascendentes |
|
||||
| **muestra** | Sistema | Mensaje de error |
|
||||
@@ -1,152 +1,117 @@
|
||||
# CU-FAC-002 — Publicar factura
|
||||
# CU-FAC-002 — Publicar Factura
|
||||
|
||||
## Nombre
|
||||
|
||||
**Publicar Factura (Confirmar y Generar Asiento Contable)**
|
||||
|
||||
## 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
|
||||
|
||||
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
|
||||
## Pre-condición
|
||||
|
||||
- La factura está en estado `draft`.
|
||||
- Las líneas tienen impuestos y cuentas contables válidas.
|
||||
- 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`.
|
||||
- Asiento contable generado (`account.move` con `state='posted'`).
|
||||
- `invoice_date` con la fecha de publicación.
|
||||
- Número de factura asignado por secuencia.
|
||||
1. El facturador **presiona** "Confirmar" en el form de la factura.
|
||||
2. El sistema **invoca** `action_post()` sobre la factura.
|
||||
3. El sistema **valida** la factura (líneas, impuestos, cuentas).
|
||||
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`).
|
||||
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.
|
||||
### FA-01 — El facturador hace publicación masiva
|
||||
|
||||
## 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-01 — Publicación masiva
|
||||
### FA-02 — El facturador revierte a draft
|
||||
|
||||
1. Usuario selecciona múltiples facturas draft.
|
||||
2. Sistema itera y publica cada una.
|
||||
3. Si alguna falla, sistema muestra error y detiene.
|
||||
1. El facturador **detecta** un error en la factura publicada.
|
||||
2. El facturador **presiona** "Restablecer a borrador".
|
||||
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-02 — Reversión a draft
|
||||
### FA-03 — El sistema valida asientos anormales (extiende CU-FAC-002-VAL)
|
||||
|
||||
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.
|
||||
1. El sistema **detecta** montos o fechas anormales.
|
||||
2. El sistema **invoca** el wizard `validate.account.move`.
|
||||
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.
|
||||
2. Sistema muestra error "Cuenta contable requerida".
|
||||
1. El sistema **detecta** que alguna línea no tiene cuenta asignada.
|
||||
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.
|
||||
2. Sistema puede advertir o bloquear según configuración.
|
||||
1. El sistema **detecta** que los totales son 0.
|
||||
2. El sistema **advierte** o **bloquea** 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
|
||||
## 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`.
|
||||
- Asiento contable generado.
|
||||
- Número de factura asignado.
|
||||
(No tiene ROB dedicado en la primera iteración; consultar `d_rob_fac_001_crear_factura.puml` como referencia conceptual)
|
||||
|
||||
## Estados involucrados
|
||||
## Verbos clave (para validar la voz activa)
|
||||
|
||||
- `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.
|
||||
| Verbo | Actor | Acción sobre |
|
||||
|-------|-------|--------------|
|
||||
| **presiona** | Facturador | Botón "Confirmar" |
|
||||
| **invoca** | Sistema | `action_post()` |
|
||||
| **valida** | Sistema | Líneas, impuestos, cuentas |
|
||||
| **verifica** | Sistema | Cuentas contables, totales |
|
||||
| **genera** | Sistema | Asiento contable |
|
||||
| **asigna** | Sistema | Número de factura |
|
||||
| **actualiza** | Sistema | `state`, `invoice_date` |
|
||||
| **publica** | Sistema | Factura |
|
||||
| **selecciona** | Facturador | Múltiples facturas |
|
||||
| **iterar** | Sistema | Lista de facturas |
|
||||
| **ejecuta** | Sistema | Pasos trascendentes |
|
||||
| **muestra** | Sistema | Error |
|
||||
| **detiene** | Sistema | Proceso |
|
||||
| **detecta** | Facturador/Sistema | Error / monto anormal |
|
||||
| **revierte** | Sistema | Estado a `draft` |
|
||||
| **permite** | Sistema | Edición |
|
||||
| **corrige** | Facturador | Datos |
|
||||
| **vuelve** | Facturador | Publicar |
|
||||
| **abre** | Sistema | Wizard de validación |
|
||||
| **confirma** | Facturador | Validación |
|
||||
| **advierte** | Sistema | Totales en 0 |
|
||||
| **bloquea** | Sistema | Publicación |
|
||||
@@ -1,160 +1,112 @@
|
||||
# CU-FAC-003 — Registrar pago
|
||||
# CU-FAC-003 — Registrar Pago
|
||||
|
||||
## Nombre
|
||||
|
||||
**Registrar Pago de Factura**
|
||||
|
||||
## 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
|
||||
|
||||
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
|
||||
## Pre-condición
|
||||
|
||||
- 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.
|
||||
- Estado de pago de la factura: `paid` (si es pago completo) o `partial` (si parcial).
|
||||
- Asiento contable de pago generado.
|
||||
1. El facturador **presiona** "Registrar pago" en el form de la factura.
|
||||
2. El sistema **invoca** `action_register_payment()`.
|
||||
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`).
|
||||
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.).
|
||||
### FA-01 — El facturador hace pago parcial
|
||||
|
||||
## 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-01 — Pago parcial
|
||||
### FA-02 — El facturador hace pago múltiple
|
||||
|
||||
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.
|
||||
1. El facturador **registra** varios pagos para la misma factura.
|
||||
2. Para cada pago, el sistema **ejecuta** los pasos trascendentes.
|
||||
3. El sistema **acumula** los pagos.
|
||||
4. Cuando se completa el saldo, el sistema **actualiza** `payment_state` a `paid`.
|
||||
|
||||
### FA-02 — Pago múltiple
|
||||
### FA-03 — El sistema integra con pasarela de pago
|
||||
|
||||
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`.
|
||||
1. El sistema **detecta** que hay una pasarela configurada.
|
||||
2. El sistema **redirige** al cliente a la pasarela.
|
||||
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`.
|
||||
2. Sistema no permite registrar pago.
|
||||
1. La factura está en estado `draft` o `cancel`.
|
||||
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.
|
||||
2. Sistema advierte o rechaza según configuración.
|
||||
1. El facturador **intenta** pagar más de lo adeudado.
|
||||
2. El sistema **advierte** o **rechaza** según configuración.
|
||||
3. El sistema **muestra** el mensaje de error.
|
||||
|
||||
## 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.
|
||||
- **RN-FAC-006**: El estado `payment_state` se calcula automáticamente.
|
||||
|
||||
## Datos de entrada
|
||||
## Relaciones con otros CU
|
||||
|
||||
- Factura en estado `posted`.
|
||||
- Datos del pago (fecha, diario, método, monto).
|
||||
(No tiene relaciones `<<include>>` o `<<extend>>` explícitas en este CU; es terminal del flujo)
|
||||
|
||||
## Datos de salida
|
||||
## Diagrama de robustez asociado
|
||||
|
||||
- `account.payment` creado.
|
||||
- Asiento contable de pago.
|
||||
- `payment_state` actualizado.
|
||||
(No tiene ROB dedicado en la primera iteración)
|
||||
|
||||
## Estados involucrados
|
||||
## Verbos clave (para validar la voz activa)
|
||||
|
||||
- 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.
|
||||
| Verbo | Actor | Acción sobre |
|
||||
|-------|-------|--------------|
|
||||
| **presiona** | Facturador | Botón "Registrar pago" |
|
||||
| **invoca** | Sistema | `action_register_payment()` |
|
||||
| **abre** | Sistema | Wizard de pago |
|
||||
| **completa** | Facturador | Datos del pago |
|
||||
| **confirma** | Facturador | Wizard |
|
||||
| **crea** | Sistema | `account.payment` |
|
||||
| **genera** | Sistema | Asiento contable |
|
||||
| **reconcilia** | Sistema | Pago con factura |
|
||||
| **actualiza** | Sistema | `payment_state` |
|
||||
| **muestra** | Sistema | Pago registrado |
|
||||
| **ingresa** | Facturador | Monto parcial |
|
||||
| **deja** | Sistema | Saldo pendiente |
|
||||
| **registra** | Facturador | Más pagos |
|
||||
| **ejecuta** | Sistema | Pasos trascendentes |
|
||||
| **acumula** | Sistema | Pagos |
|
||||
| **detecta** | Sistema | Pasarela / estado |
|
||||
| **redirige** | Sistema | Cliente a pasarela |
|
||||
| **recibe** | Sistema | Confirmación de pago |
|
||||
| **impide** | Sistema | Registro de pago |
|
||||
| **intenta** | Facturador | Pagar de más |
|
||||
| **advierte** | Sistema | Pago excedido |
|
||||
| **rechaza** | Sistema | Pago excedido |
|
||||
@@ -1,186 +1,100 @@
|
||||
# CU-VEN-001 — Crear presupuesto
|
||||
# CU-VEN-001 — Crear Presupuesto
|
||||
|
||||
## Nombre
|
||||
|
||||
**Crear Presupuesto de Venta**
|
||||
|
||||
## 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`.
|
||||
|
||||
## 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`.
|
||||
- El vendedor tiene sesión iniciada (`CU-AUTH-001`).
|
||||
- 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`.
|
||||
- El catálogo contiene productos publicables en `product.product`.
|
||||
- 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`.
|
||||
- Los totales se calculan automáticamente con impuestos.
|
||||
- Se puede confirmar el presupuesto (cambio de estado a `sale`).
|
||||
1. El vendedor **presiona** "Nuevo" desde el menú Ventas → Presupuestos.
|
||||
2. El sistema **crea** un `sale.order` en estado `draft` con `name` provisional.
|
||||
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`.
|
||||
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).
|
||||
### FA-01 — El vendedor envía el presupuesto por email
|
||||
|
||||
## 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-01 — Aplicar descuento
|
||||
### FA-02 — El vendedor aplica un descuento (incluye CU-VEN-001-DISC)
|
||||
|
||||
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.
|
||||
1. El vendedor **edita** el campo `discount` en una línea.
|
||||
2. El sistema **recalcula** el subtotal de la línea.
|
||||
3. Si el descuento supera el máximo permitido, el sistema **bloquea** o **notifica**.
|
||||
|
||||
### FA-02 — Duplicar presupuesto
|
||||
### FA-03 — El vendedor duplica el 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".
|
||||
1. El vendedor **selecciona** un presupuesto existente.
|
||||
2. El vendedor **presiona** "Duplicar".
|
||||
3. El sistema **crea** un nuevo `sale.order` copiando las líneas.
|
||||
4. El sistema **asigna** estado `draft` al nuevo presupuesto.
|
||||
|
||||
## 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.
|
||||
- **RN-VEN-001**: El estado `state` solo puede pasar de `draft` → `sent` → `sale`, o a `cancel`.
|
||||
- **RN-VEN-002**: El campo `name` se genera por la secuencia configurada en la compañía.
|
||||
- **RN-VEN-003**: Los descuentos mayores al 10% pueden requerir aprobación.
|
||||
|
||||
## Datos de entrada
|
||||
## Relaciones con otros CU
|
||||
|
||||
- Cliente (`partner_id`).
|
||||
- Compañía (`company_id`).
|
||||
- Moneda (`currency_id`).
|
||||
- Lista de precios (`pricelist_id`, opcional).
|
||||
- Líneas (`order_line` con productos).
|
||||
- **<<include>> CU-AUTH-001**: Valida la sesión antes de crear el presupuesto.
|
||||
- **<<include>> CU-CALC-001**: Calcula los totales con impuestos.
|
||||
- **<<extend>> CU-VEN-001-EMAIL**: Envía el presupuesto por email (opcional).
|
||||
- **<<extend>> CU-VEN-001-DISC**: Aplica descuento (opcional).
|
||||
|
||||
## Datos de salida
|
||||
## Diagrama de robustez asociado
|
||||
|
||||
- Registro `sale.order` persistido.
|
||||
- Líneas `sale.order.line` relacionadas.
|
||||
- Correo enviado (opcional).
|
||||
`diagrams/plantuml/d_rob_ven_001_crear_presupuesto.puml`
|
||||
|
||||
## Estados involucrados
|
||||
## Verbos clave (para validar la voz activa)
|
||||
|
||||
- `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.
|
||||
| Verbo | Actor | Acción sobre |
|
||||
|-------|-------|--------------|
|
||||
| **presiona** | Vendedor | Botón "Nuevo" |
|
||||
| **crea** | Sistema | `sale.order` (draft) |
|
||||
| **abre** | Sistema | `view_sale_order_form` |
|
||||
| **selecciona** | Vendedor | Cliente |
|
||||
| **carga** | Sistema | Lista de precios |
|
||||
| **agrega** | Vendedor | Líneas |
|
||||
| **actualiza** | Sistema | `partner_id`, `order_line` |
|
||||
| **calcula** | Sistema | `_compute_amounts()` |
|
||||
| **muestra** | Sistema | Totales en form |
|
||||
| **guarda** | Vendedor | Presupuesto |
|
||||
| **invoca** | Sistema | `action_quotation_send()` |
|
||||
| **valida** | Sistema | Distribución analítica |
|
||||
| **marca** | Sistema | `mark_so_as_sent` |
|
||||
| **cambia** | Sistema | Estado `draft` → `sent` |
|
||||
| **genera** | Sistema | `mail.mail` |
|
||||
| **envía** | Sistema | Email al cliente |
|
||||
@@ -1,183 +1,111 @@
|
||||
# CU-VEN-004 — Confirmar pedido de venta
|
||||
# CU-VEN-004 — Confirmar Pedido
|
||||
|
||||
## Nombre
|
||||
|
||||
**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).
|
||||
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
|
||||
|
||||
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
|
||||
## Pre-condición
|
||||
|
||||
- El vendedor tiene sesión iniciada (`CU-AUTH-001`).
|
||||
- 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.
|
||||
- Cada línea tiene un `product_id` definido.
|
||||
- El cliente tiene una dirección de entrega válida (`partner_shipping_id`).
|
||||
|
||||
## Garantías mínimas
|
||||
## Post-condición
|
||||
|
||||
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.
|
||||
- El pedido queda en estado `sale`.
|
||||
- El campo `date_order` queda con la fecha/hora de confirmación.
|
||||
- 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()`.
|
||||
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`.
|
||||
1. El vendedor **presiona** "Confirmar" en el form del pedido.
|
||||
2. El sistema **invoca** `action_confirm()`.
|
||||
3. El sistema **valida** el pedido con `_confirmation_error_message()`.
|
||||
4. El sistema **lee** el estado y las líneas del pedido.
|
||||
5. El sistema **verifica** que cada línea tenga `product_id`.
|
||||
6. Si todo está OK, el sistema **prepara** los valores de confirmación con `_prepare_confirmation_values()`.
|
||||
7. El sistema **escribe** `state='sale'` y `date_order=now` en el pedido.
|
||||
8. El sistema **dispara** `_action_confirm()` que **genera** los pickings de stock.
|
||||
9. El sistema **genera** las entregas (`stock.picking`) con sus movimientos (`stock.move`).
|
||||
10. El sistema **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.
|
||||
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ó.
|
||||
1. El vendedor **selecciona** varios presupuestos desde la vista tree.
|
||||
2. El vendedor **presiona** "Confirmar" (acción masiva).
|
||||
3. El sistema **itera** sobre cada pedido.
|
||||
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.
|
||||
2. Después de confirmar, llama a `action_lock()`.
|
||||
3. Pedido queda `locked=True`, no se puede modificar.
|
||||
1. El sistema **detecta** que `sale.group_auto_done_setting` está activo.
|
||||
2. Después de confirmar, el sistema **invoca** `action_lock()` sobre los pedidos filtrados.
|
||||
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`.
|
||||
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.
|
||||
2. Sistema retorna `_("Some order lines are missing a product, you need to correct them before going further.")`.
|
||||
1. Alguna línea tiene `display_type` vacío, `is_downpayment=False` y `product_id` vacío.
|
||||
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
|
||||
|
||||
- **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).
|
||||
- **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`.
|
||||
- Contexto opcional: `send_email=True` (envía email de confirmación).
|
||||
- **<<include>> CU-AUTH-001**: Valida la sesión.
|
||||
- **<<include>> CU-GENPICK-001**: Genera los pickings de entrega.
|
||||
|
||||
## Datos de salida
|
||||
## Diagrama de robustez asociado
|
||||
|
||||
- Pedido en estado `sale`.
|
||||
- Reservas de stock (CU-ENT-002).
|
||||
- Programación de entregas (CU-ENT-004).
|
||||
`diagrams/plantuml/d_rob_ven_004_confirmar_pedido.puml`
|
||||
|
||||
## Estados involucrados
|
||||
## Verbos clave (para validar la voz activa)
|
||||
|
||||
- `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.
|
||||
| Verbo | Actor | Acción sobre |
|
||||
|-------|-------|--------------|
|
||||
| **presiona** | Vendedor | Botón "Confirmar" |
|
||||
| **invoca** | Sistema | `action_confirm()` |
|
||||
| **valida** | Sistema | `_confirmation_error_message()` |
|
||||
| **lee** | Sistema | Estado y líneas |
|
||||
| **verifica** | Sistema | `product_id` por línea |
|
||||
| **prepara** | Sistema | `_prepare_confirmation_values()` |
|
||||
| **escribe** | Sistema | `state='sale'`, `date_order` |
|
||||
| **dispara** | Sistema | `_action_confirm()` |
|
||||
| **genera** | Sistema | `stock.picking`, `stock.move` |
|
||||
| **retorna** | Sistema | `True` |
|
||||
| **iterar** | Sistema | Lista de pedidos |
|
||||
| **detecta** | Sistema | Estado / configuración |
|
||||
| **marca** | Sistema | `locked=True` |
|
||||
| **impide** | Sistema | Modificaciones |
|
||||
| **busca** | Sistema | Template de email |
|
||||
| **envía** | Sistema | Email de confirmación |
|
||||
| **muestra** | Sistema | Error |
|
||||
Reference in New Issue
Block a user