# FASE 5: Refinamiento del Plan de Correcciones **Fecha:** 2026-01-04 **Objetivo:** Refinar plan con scripts de migracion, tests y rollback **Estado:** Completado **Basado en:** FASE-4 (Validacion de Dependencias) --- ## 1. Plan de Ejecucion Refinado ### 1.1 Batch 1: Foundation (Correcciones Independientes) | Orden | Correccion | Archivo | Tipo Cambio | Riesgo | |-------|------------|---------|-------------|--------| | 1.1 | COR-001 | 06-purchase.sql | ALTER TYPE | MEDIO | | 1.2 | COR-002 | 05-inventory.sql | ALTER TYPE | MEDIO | | 1.3 | COR-004 | 04-financial.sql | ALTER TABLE + TYPE | MEDIO | | 1.4 | COR-005 | 04-financial.sql | CREATE TABLE | BAJO | | 1.5 | COR-006 | 07-sales.sql | ALTER TABLE | BAJO | | 1.6 | COR-007 | 05-inventory.sql | CREATE TABLE + ALTER | BAJO | | 1.7 | COR-008 | 05-inventory.sql | CREATE TABLEs | BAJO | | 1.8 | COR-010 | 07-sales.sql, 06-purchase.sql | ALTER TABLE | BAJO | | 1.9 | COR-011 | 07-sales.sql, 06-purchase.sql | ALTER TABLE | BAJO | ### 1.2 Batch 2: Dependencias Nivel 1 | Orden | Correccion | Depende De | Archivo | Tipo Cambio | |-------|------------|------------|---------|-------------| | 2.1 | COR-003 | COR-002 | 05-inventory.sql | CREATE TABLE | | 2.2 | COR-009 | COR-001 | 06-purchase.sql | CREATE FUNCTION | | 2.3 | COR-012 | COR-006 | 07-sales.sql | ALTER TABLE | ### 1.3 Batch 3: Dependencias Nivel 2 | Orden | Correccion | Depende De | Archivo | Tipo Cambio | |-------|------------|------------|---------|-------------| | 3.1 | COR-013 | COR-004 | 04-financial.sql | CREATE TABLEs | | 3.2 | COR-018 | COR-002, COR-003 | 05-inventory.sql | CREATE FUNCTION | ### 1.4 Batch 4: Features Avanzados | Orden | Correccion | Archivo | Tipo Cambio | |-------|------------|---------|-------------| | 4.1 | COR-014 | 11-crm.sql | CREATE TABLE + ALTER | | 4.2 | COR-015 | 03-analytics.sql | ALTER + CREATE | | 4.3 | COR-016 | 08-projects.sql | ALTER + CREATE | | 4.4 | COR-017 | 08-projects.sql | ALTER TABLE | | 4.5 | COR-019 | 11-crm.sql | CREATE TABLE | | 4.6 | COR-020 | 02-core.sql | CREATE TABLE + FUNCTION | --- ## 2. Scripts de Migracion ### 2.1 Migration: COR-001 (PO States) ```sql -- Migration: 20260104_001_po_to_approve_state.sql -- Correccion: COR-001 -- Descripcion: Agregar estado 'to_approve' a purchase orders BEGIN; -- 1. Agregar nuevo valor al ENUM ALTER TYPE purchase.order_status ADD VALUE IF NOT EXISTS 'to_approve' BEFORE 'confirmed'; -- 2. Renombrar 'confirmed' a 'purchase' (Odoo naming) -- Nota: PostgreSQL no permite renombrar valores de ENUM directamente -- Se debe crear nuevo tipo si se requiere renombrar -- 3. Agregar campos de aprobacion ALTER TABLE purchase.purchase_orders ADD COLUMN IF NOT EXISTS approval_required BOOLEAN DEFAULT FALSE, ADD COLUMN IF NOT EXISTS amount_approval_threshold DECIMAL(15, 2); -- 4. Actualizar comentarios COMMENT ON COLUMN purchase.purchase_orders.approval_required IS 'Indica si la PO requiere aprobacion segun threshold'; COMMIT; ``` ### 2.2 Migration: COR-002 (Move States) ```sql -- Migration: 20260104_002_move_states.sql -- Correccion: COR-002 -- Descripcion: Agregar estados 'waiting' y 'partially_available' a stock moves BEGIN; -- 1. Agregar nuevos valores al ENUM ALTER TYPE inventory.move_status ADD VALUE IF NOT EXISTS 'waiting' AFTER 'draft'; ALTER TYPE inventory.move_status ADD VALUE IF NOT EXISTS 'partially_available' AFTER 'confirmed'; -- 2. Actualizar comentarios COMMENT ON TYPE inventory.move_status IS 'Estados de movimiento: draft -> waiting -> confirmed -> partially_available -> assigned -> done/cancelled'; COMMIT; ``` ### 2.3 Migration: COR-003 (Move Lines) ```sql -- Migration: 20260104_003_stock_move_lines.sql -- Correccion: COR-003 -- Descripcion: Crear tabla stock_move_lines para granularidad lote/serie BEGIN; -- 1. Crear tabla stock_move_lines CREATE TABLE IF NOT EXISTS inventory.stock_move_lines ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, -- Relacion con move move_id UUID NOT NULL REFERENCES inventory.stock_moves(id) ON DELETE CASCADE, -- Producto product_id UUID NOT NULL REFERENCES inventory.products(id), product_uom_id UUID NOT NULL REFERENCES core.uom(id), -- Lote/Serie/Paquete lot_id UUID REFERENCES inventory.lots(id), package_id UUID, -- Futuro: packages table result_package_id UUID, -- Futuro: packages table owner_id UUID REFERENCES core.partners(id), -- Ubicaciones location_id UUID NOT NULL REFERENCES inventory.locations(id), location_dest_id UUID NOT NULL REFERENCES inventory.locations(id), -- Cantidades quantity DECIMAL(12, 4) NOT NULL, quantity_done DECIMAL(12, 4) DEFAULT 0, -- Estado state VARCHAR(20), -- Fechas date TIMESTAMP, -- Referencia reference VARCHAR(255), -- Auditoria created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, created_by UUID REFERENCES auth.users(id), updated_at TIMESTAMP, CONSTRAINT chk_move_lines_qty CHECK (quantity > 0), CONSTRAINT chk_move_lines_qty_done CHECK (quantity_done >= 0 AND quantity_done <= quantity) ); -- 2. Indices CREATE INDEX idx_stock_move_lines_tenant_id ON inventory.stock_move_lines(tenant_id); CREATE INDEX idx_stock_move_lines_move_id ON inventory.stock_move_lines(move_id); CREATE INDEX idx_stock_move_lines_product_id ON inventory.stock_move_lines(product_id); CREATE INDEX idx_stock_move_lines_lot_id ON inventory.stock_move_lines(lot_id); CREATE INDEX idx_stock_move_lines_location ON inventory.stock_move_lines(location_id, location_dest_id); -- 3. RLS ALTER TABLE inventory.stock_move_lines ENABLE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation_stock_move_lines ON inventory.stock_move_lines USING (tenant_id = get_current_tenant_id()); -- 4. Comentarios COMMENT ON TABLE inventory.stock_move_lines IS 'Lineas de movimiento de stock para granularidad a nivel lote/serie (equivalente a stock.move.line Odoo)'; COMMIT; ``` ### 2.4 Migration: COR-004 (Payment State) ```sql -- Migration: 20260104_004_invoice_payment_state.sql -- Correccion: COR-004 -- Descripcion: Agregar payment_state a facturas BEGIN; -- 1. Crear ENUM para payment_state CREATE TYPE financial.payment_state AS ENUM ( 'not_paid', 'in_payment', 'paid', 'partial', 'reversed' ); -- 2. Agregar columna ALTER TABLE financial.invoices ADD COLUMN IF NOT EXISTS payment_state financial.payment_state DEFAULT 'not_paid'; -- 3. Migrar datos existentes UPDATE financial.invoices SET payment_state = CASE WHEN status = 'paid' THEN 'paid'::financial.payment_state WHEN amount_paid > 0 AND amount_paid < amount_total THEN 'partial'::financial.payment_state ELSE 'not_paid'::financial.payment_state END WHERE payment_state IS NULL; -- 4. Comentarios COMMENT ON COLUMN financial.invoices.payment_state IS 'Estado de pago: not_paid, in_payment, paid, partial, reversed (independiente del estado contable)'; COMMIT; ``` ### 2.5 Migration: COR-005 (Tax Groups) ```sql -- Migration: 20260104_005_tax_groups.sql -- Correccion: COR-005 -- Descripcion: Implementar sistema de tax groups BEGIN; -- 1. Crear tabla tax_groups CREATE TABLE IF NOT EXISTS financial.tax_groups ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, name VARCHAR(100) NOT NULL, sequence INTEGER DEFAULT 10, country_id UUID, -- Futuro: countries table -- Auditoria created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, created_by UUID REFERENCES auth.users(id), CONSTRAINT uq_tax_groups_name_tenant UNIQUE (tenant_id, name) ); -- 2. Agregar campos a taxes ALTER TABLE financial.taxes ADD COLUMN IF NOT EXISTS tax_group_id UUID REFERENCES financial.tax_groups(id), ADD COLUMN IF NOT EXISTS amount_type VARCHAR(20) DEFAULT 'percent', -- percent, fixed, group, division ADD COLUMN IF NOT EXISTS include_base_amount BOOLEAN DEFAULT FALSE, ADD COLUMN IF NOT EXISTS price_include BOOLEAN DEFAULT FALSE, ADD COLUMN IF NOT EXISTS children_tax_ids UUID[] DEFAULT '{}'; -- 3. Indices y RLS CREATE INDEX idx_tax_groups_tenant_id ON financial.tax_groups(tenant_id); ALTER TABLE financial.tax_groups ENABLE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation_tax_groups ON financial.tax_groups USING (tenant_id = get_current_tenant_id()); -- 4. Constraint para amount_type ALTER TABLE financial.taxes ADD CONSTRAINT chk_taxes_amount_type CHECK (amount_type IN ('percent', 'fixed', 'group', 'division')); -- 5. Comentarios COMMENT ON TABLE financial.tax_groups IS 'Grupos de impuestos para clasificacion y reporte (equivalente a account.tax.group Odoo)'; COMMENT ON COLUMN financial.taxes.amount_type IS 'Tipo de calculo: percent (%), fixed (monto fijo), group (suma de hijos), division (100*price/100+rate)'; COMMIT; ``` ### 2.6 Migration: COR-006 (SO-Invoice Link) ```sql -- Migration: 20260104_006_sales_invoice_link.sql -- Correccion: COR-006 -- Descripcion: Vincular sales orders con invoices BEGIN; -- 1. Agregar campos a sales_orders ALTER TABLE sales.sales_orders ADD COLUMN IF NOT EXISTS invoice_ids UUID[] DEFAULT '{}'; -- 2. Agregar campo computed (simulado con trigger) ALTER TABLE sales.sales_orders ADD COLUMN IF NOT EXISTS invoice_count INTEGER DEFAULT 0; -- 3. Funcion para actualizar invoice_count CREATE OR REPLACE FUNCTION sales.update_invoice_count() RETURNS TRIGGER AS $$ BEGIN NEW.invoice_count := COALESCE(array_length(NEW.invoice_ids, 1), 0); RETURN NEW; END; $$ LANGUAGE plpgsql; -- 4. Trigger CREATE TRIGGER trg_sales_orders_invoice_count BEFORE INSERT OR UPDATE OF invoice_ids ON sales.sales_orders FOR EACH ROW EXECUTE FUNCTION sales.update_invoice_count(); -- 5. Comentarios COMMENT ON COLUMN sales.sales_orders.invoice_ids IS 'Array de UUIDs de facturas vinculadas a esta orden de venta'; COMMENT ON COLUMN sales.sales_orders.invoice_count IS 'Cantidad de facturas vinculadas (computed)'; COMMIT; ``` --- ## 3. Scripts de Rollback ### 3.1 Rollback: COR-001 ```sql -- Rollback: 20260104_001_po_to_approve_state_rollback.sql BEGIN; -- Nota: PostgreSQL no permite eliminar valores de ENUM -- Se deben migrar datos y recrear tipo si es necesario ALTER TABLE purchase.purchase_orders DROP COLUMN IF EXISTS approval_required, DROP COLUMN IF EXISTS amount_approval_threshold; COMMIT; ``` ### 3.2 Rollback: COR-003 ```sql -- Rollback: 20260104_003_stock_move_lines_rollback.sql BEGIN; DROP TABLE IF EXISTS inventory.stock_move_lines CASCADE; COMMIT; ``` ### 3.3 Rollback: COR-004 ```sql -- Rollback: 20260104_004_invoice_payment_state_rollback.sql BEGIN; ALTER TABLE financial.invoices DROP COLUMN IF EXISTS payment_state; DROP TYPE IF EXISTS financial.payment_state; COMMIT; ``` ### 3.4 Rollback: COR-005 ```sql -- Rollback: 20260104_005_tax_groups_rollback.sql BEGIN; ALTER TABLE financial.taxes DROP COLUMN IF EXISTS tax_group_id, DROP COLUMN IF EXISTS amount_type, DROP COLUMN IF EXISTS include_base_amount, DROP COLUMN IF EXISTS price_include, DROP COLUMN IF EXISTS children_tax_ids; DROP TABLE IF EXISTS financial.tax_groups; COMMIT; ``` ### 3.5 Rollback: COR-006 ```sql -- Rollback: 20260104_006_sales_invoice_link_rollback.sql BEGIN; DROP TRIGGER IF EXISTS trg_sales_orders_invoice_count ON sales.sales_orders; DROP FUNCTION IF EXISTS sales.update_invoice_count(); ALTER TABLE sales.sales_orders DROP COLUMN IF EXISTS invoice_ids, DROP COLUMN IF EXISTS invoice_count; COMMIT; ``` --- ## 4. Tests de Regresion ### 4.1 Test Suite: COR-001 (PO States) ```sql -- Test: test_cor001_po_states.sql -- Test 1: Verificar que nuevo estado existe DO $$ BEGIN ASSERT EXISTS ( SELECT 1 FROM pg_enum WHERE enumlabel = 'to_approve' AND enumtypid = 'purchase.order_status'::regtype ), 'Estado to_approve debe existir'; END $$; -- Test 2: Verificar transicion de estados DO $$ DECLARE v_po_id UUID; BEGIN -- Crear PO de prueba INSERT INTO purchase.purchase_orders (tenant_id, company_id, name, partner_id, order_date, currency_id, status) VALUES (get_current_tenant_id(), '...', 'TEST-001', '...', CURRENT_DATE, '...', 'draft') RETURNING id INTO v_po_id; -- Verificar transicion draft -> to_approve UPDATE purchase.purchase_orders SET status = 'to_approve' WHERE id = v_po_id; ASSERT (SELECT status FROM purchase.purchase_orders WHERE id = v_po_id) = 'to_approve'; -- Cleanup DELETE FROM purchase.purchase_orders WHERE id = v_po_id; END $$; ``` ### 4.2 Test Suite: COR-002 (Move States) ```sql -- Test: test_cor002_move_states.sql -- Test 1: Verificar nuevos estados DO $$ BEGIN ASSERT EXISTS ( SELECT 1 FROM pg_enum WHERE enumlabel = 'waiting' AND enumtypid = 'inventory.move_status'::regtype ), 'Estado waiting debe existir'; ASSERT EXISTS ( SELECT 1 FROM pg_enum WHERE enumlabel = 'partially_available' AND enumtypid = 'inventory.move_status'::regtype ), 'Estado partially_available debe existir'; END $$; ``` ### 4.3 Test Suite: COR-003 (Move Lines) ```sql -- Test: test_cor003_move_lines.sql -- Test 1: Verificar tabla existe DO $$ BEGIN ASSERT EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_schema = 'inventory' AND table_name = 'stock_move_lines' ), 'Tabla stock_move_lines debe existir'; END $$; -- Test 2: Verificar FK a stock_moves DO $$ BEGIN ASSERT EXISTS ( SELECT 1 FROM information_schema.table_constraints WHERE table_schema = 'inventory' AND table_name = 'stock_move_lines' AND constraint_type = 'FOREIGN KEY' ), 'FK a stock_moves debe existir'; END $$; ``` --- ## 5. Documentacion a Actualizar Post-Ejecucion ### 5.1 Por Batch | Batch | Documentos a Actualizar | |-------|------------------------| | Batch 1 | inventory-domain.md, financial-domain.md, sales-domain.md, INVENTARIO-OBJETOS-BD.yml | | Batch 2 | inventory-domain.md, purchase workflows, GRAFO-DEPENDENCIAS-SCHEMAS.md | | Batch 3 | financial-domain.md, MATRIZ-TRAZABILIDAD-RF-ET-BD.md | | Batch 4 | crm-domain.md, analytics-domain.md, projects-domain.md | ### 5.2 Checklist Post-Ejecucion - [ ] Actualizar domain models con nuevas entidades/campos - [ ] Sincronizar schema docs (docs/04-modelado/database-design/schemas/) - [ ] Actualizar INVENTARIO-OBJETOS-BD.yml - [ ] Actualizar GRAFO-DEPENDENCIAS-SCHEMAS.md - [ ] Crear nuevos workflows (WORKFLOW-PURCHASE-APPROVAL.md, etc.) - [ ] Actualizar VALIDACION-COBERTURA-ODOO.md - [ ] Regenerar documentacion de API si aplica --- ## 6. Plan de Rollback General ### 6.1 Criterios de Rollback | Criterio | Accion | |----------|--------| | Test de regresion falla | Rollback inmediato | | Error en produccion < 1 hora | Rollback script | | Error en produccion > 1 hora | Evaluar fix forward | | Datos corruptos | Restore de backup | ### 6.2 Orden de Rollback ``` Rollback debe ser en orden inverso: 1. Batch 4 -> Batch 3 -> Batch 2 -> Batch 1 Dentro de cada batch, rollback en orden inverso de ejecucion. ``` --- ## 7. Aprobacion del Plan Refinado ### 7.1 Checklist de Aprobacion - [x] Plan de ejecucion por batches definido - [x] Scripts de migracion creados (P0) - [x] Scripts de rollback creados - [x] Tests de regresion definidos - [x] Documentacion a actualizar identificada - [x] Plan de rollback general establecido ### 7.2 Resultado **PLAN REFINADO APROBADO** para proceder a FASE 6 (Ejecucion) --- ## 8. Proximos Pasos (FASE 6) 1. Crear branch `feature/odoo-alignment-batch1` 2. Ejecutar Batch 1 migrations 3. Ejecutar tests de regresion 4. Actualizar documentacion 5. Merge y continuar con Batch 2 --- **Generado:** 2026-01-04 **Herramienta:** Claude Code