diff --git a/diagrams/pdf/D-CU-GEN-002 — Casos de Uso con extend e include.pdf b/diagrams/pdf/D-CU-GEN-002 — Casos de Uso con extend e include.pdf new file mode 100644 index 0000000..bc44158 Binary files /dev/null and b/diagrams/pdf/D-CU-GEN-002 — Casos de Uso con extend e include.pdf differ diff --git a/diagrams/plantuml/d_cu_gen_002_casos_uso_extend_include.puml b/diagrams/plantuml/d_cu_gen_002_casos_uso_extend_include.puml new file mode 100644 index 0000000..bb09828 --- /dev/null +++ b/diagrams/plantuml/d_cu_gen_002_casos_uso_extend_include.puml @@ -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 <> ─── +CU_VEN_001 ..> CU_AUTH : <> +CU_VEN_001 ..> CU_CALC : <> +CU_VEN_004 ..> CU_AUTH : <> +CU_VEN_004 ..> CU_GENPICK : <> +CU_FAC_001 ..> CU_VALLIN : <> +CU_FAC_002 ..> CU_GENJOUR : <> + +' ─── Extends (5) — flechas con <> ─── +CU_VEN_001_EMAIL ..> CU_VEN_001 : <> +CU_VEN_001_DISC ..> CU_VEN_001 : <> +CU_ENT_002_MTO ..> CU_ENT_002 : <> +CU_ENT_004_BACK ..> CU_ENT_004 : <> +CU_FAC_002_VAL ..> CU_FAC_002 : <> + +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 \ No newline at end of file diff --git a/diagrams/png/D-CU-GEN-002 — Casos de Uso con extend e include.png b/diagrams/png/D-CU-GEN-002 — Casos de Uso con extend e include.png new file mode 100644 index 0000000..a1ef1e8 Binary files /dev/null and b/diagrams/png/D-CU-GEN-002 — Casos de Uso con extend e include.png differ diff --git a/diagrams/svg/D-CU-GEN-002 — Casos de Uso con extend e include.svg b/diagrams/svg/D-CU-GEN-002 — Casos de Uso con extend e include.svg new file mode 100644 index 0000000..b5e00a1 --- /dev/null +++ b/diagrams/svg/D-CU-GEN-002 — Casos de Uso con extend e include.svg @@ -0,0 +1,181 @@ +SAP-TFI-2026 — Casos de Uso del Flujo Comercial (con extend e include)VendedorOperario de AlmacénFacturadorSistemaCU-VEN-001Crear presupuestoCU-VEN-004Confirmar pedidoCU-ENT-002Reservar productosCU-ENT-004Validar entregaCU-FAC-001Crear facturaCU-FAC-002Publicar facturaCU-FAC-003Registrar pagoCU-AUTH-001Validar sesiónde usuarioCU-CALC-001Calcular totalescon impuestosCU-GENPICK-001Generar pickingde entregaCU-VALLIN-001Validar líneaspendientesCU-GENJOUR-001Crear asientocontableCU-VEN-001-EMAILEnviar presupuestopor emailCU-VEN-001-DISCAplicar descuentoCU-ENT-002-MTOGenerar orden decompra (MTO)CU-ENT-004-BACKCrear backorderde entrega parcialCU-FAC-002-VALValidar asientoanormalcreaconfirmareservavalidafacturapublicacobraautentica%«include»«include»«include»«include»«include»«include»«extend»«extend»«extend»«extend»«extend»Proyecto: SAP-TFI-2026Agente: saptfi2026Metodologia: ICONIX (extend e include)Fuente: Ingenieria inversa de Odoo 19.05 includes + 5 extends \ No newline at end of file diff --git a/docs/02_casos_uso/cu_ent_002_reservar_productos.md b/docs/02_casos_uso/cu_ent_002_reservar_productos.md index 0031027..6fb871a 100644 --- a/docs/02_casos_uso/cu_ent_002_reservar_productos.md +++ b/docs/02_casos_uso/cu_ent_002_reservar_productos.md @@ -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`). +- **<> 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. \ No newline at end of file +| 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) | \ No newline at end of file diff --git a/docs/02_casos_uso/cu_ent_004_validar_entrega.md b/docs/02_casos_uso/cu_ent_004_validar_entrega.md index 40a47d8..a178b0b 100644 --- a/docs/02_casos_uso/cu_ent_004_validar_entrega.md +++ b/docs/02_casos_uso/cu_ent_004_validar_entrega.md @@ -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). +- **<> 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. \ No newline at end of file +| 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 | \ No newline at end of file diff --git a/docs/02_casos_uso/cu_fac_001_crear_factura.md b/docs/02_casos_uso/cu_fac_001_crear_factura.md index 79100e5..320a5a5 100644 --- a/docs/02_casos_uso/cu_fac_001_crear_factura.md +++ b/docs/02_casos_uso/cu_fac_001_crear_factura.md @@ -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). +- **<> 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. \ No newline at end of file +| 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 | \ No newline at end of file diff --git a/docs/02_casos_uso/cu_fac_002_publicar_factura.md b/docs/02_casos_uso/cu_fac_002_publicar_factura.md index 3d95def..1e39e10 100644 --- a/docs/02_casos_uso/cu_fac_002_publicar_factura.md +++ b/docs/02_casos_uso/cu_fac_002_publicar_factura.md @@ -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`. +- **<> CU-GENJOUR-001**: Crea el asiento contable al publicar. +- **<> 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. \ No newline at end of file +| 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 | \ No newline at end of file diff --git a/docs/02_casos_uso/cu_fac_003_registrar_pago.md b/docs/02_casos_uso/cu_fac_003_registrar_pago.md index 65a969a..b2a002b 100644 --- a/docs/02_casos_uso/cu_fac_003_registrar_pago.md +++ b/docs/02_casos_uso/cu_fac_003_registrar_pago.md @@ -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 `<>` o `<>` 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. \ No newline at end of file +| 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 | \ No newline at end of file diff --git a/docs/02_casos_uso/cu_ven_001_crear_presupuesto.md b/docs/02_casos_uso/cu_ven_001_crear_presupuesto.md index bf8b5de..f6b980c 100644 --- a/docs/02_casos_uso/cu_ven_001_crear_presupuesto.md +++ b/docs/02_casos_uso/cu_ven_001_crear_presupuesto.md @@ -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). +- **<> CU-AUTH-001**: Valida la sesión antes de crear el presupuesto. +- **<> CU-CALC-001**: Calcula los totales con impuestos. +- **<> CU-VEN-001-EMAIL**: Envía el presupuesto por email (opcional). +- **<> 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. \ No newline at end of file +| 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 | \ No newline at end of file diff --git a/docs/02_casos_uso/cu_ven_004_confirmar_pedido.md b/docs/02_casos_uso/cu_ven_004_confirmar_pedido.md index 02ac917..d9c3cd3 100644 --- a/docs/02_casos_uso/cu_ven_004_confirmar_pedido.md +++ b/docs/02_casos_uso/cu_ven_004_confirmar_pedido.md @@ -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). +- **<> CU-AUTH-001**: Valida la sesión. +- **<> 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. \ No newline at end of file +| 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 | \ No newline at end of file diff --git a/docs/09_trazabilidad/matriz_trazabilidad.md b/docs/09_trazabilidad/matriz_trazabilidad.md index bb743ff..d07a2b3 100644 --- a/docs/09_trazabilidad/matriz_trazabilidad.md +++ b/docs/09_trazabilidad/matriz_trazabilidad.md @@ -2,23 +2,46 @@ > Documento vivo. Última actualización: 2026-06-18. -**Versión Odoo analizada:** 19.0 Community -**Rama:** 19.0 -**Edición:** Community -**Path local código fuente:** `~/proyectos/odoo_src/odoo` -**Path local repo proyecto:** `~/proyectos/sap_tfi_2026` +## Diagrama de CU principal + +`D-CU-GEN-002` — Casos de Uso con extend/include +- **5 includes**: CU-AUTH-001, CU-CALC-001, CU-GENPICK-001, CU-VALLIN-001, CU-GENJOUR-001 +- **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 -| Requisito | Caso de uso | Regla | Pantalla | Robustez | Secuencia | Clase | Modelo Odoo | Evidencia | Estado | -|-----------|-------------|-------|----------|----------|-----------|-------|-------------|-----------|--------| -| 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-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-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-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-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-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-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 | +| 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, 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 | 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 | 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 | (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 | 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 | (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 | (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 | <> | CU-AUTH-001 | Validación de sesión | +| CU-VEN-001 | <> | CU-CALC-001 | Cálculo de totales | +| CU-VEN-004 | <> | CU-AUTH-001 | Validación de sesión | +| CU-VEN-004 | <> | CU-GENPICK-001 | Generación de picking | +| CU-FAC-001 | <> | CU-VALLIN-001 | Validación de líneas | +| CU-FAC-002 | <> | CU-GENJOUR-001 | Generación de asiento | +| CU-VEN-001 | <> | CU-VEN-001-EMAIL | Envío de email (opcional) | +| CU-VEN-001 | <> | CU-VEN-001-DISC | Aplicar descuento (opcional) | +| CU-ENT-002 | <> | CU-ENT-002-MTO | Generar PO (MTO) (opcional) | +| CU-ENT-004 | <> | CU-ENT-004-BACK | Crear backorder (opcional) | +| CU-FAC-002 | <> | CU-FAC-002-VAL | Validar asiento anormal (opcional) | ## Leyenda de estados @@ -63,59 +86,9 @@ | Obsoleto | 0 | 0% | | **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 -- [ ] Validar las 22 EV-INF en iteraciones siguientes. -- [ ] Leer `_action_confirm()` de `sale.order` para refinar CU-VEN-004. -- [ ] Agregar CU de cancelación de pedido y factura. -- [ ] Generar diagramas de robustez y secuencia para los CU que faltan. \ No newline at end of file +- [ ] Validar las 8 EV-INF en iteraciones siguientes. +- [ ] Agregar diagramas de robustez/secuencia para CU-FAC-002, CU-FAC-003, CU-ENT-004. +- [ ] Documentar los 10 CU secundarios (5 includes + 5 extends). +- [ ] Generar diagramas de robustez y secuencia para cada uno. \ No newline at end of file