# FASE 5: Refinamiento del Plan **ID:** EPIC-VAL-005 **Fecha:** 2026-01-04 **Estado:** Completado **Basado en:** FASE-4 (Validacion de Dependencias) --- ## 1. Ajustes al Plan Original ### 1.1 Correcciones Excluidas | ID Original | Razon de Exclusion | |-------------|-------------------| | COR-034 | `core.attachments` ya existe en linea 271 de 02-core.sql | ### 1.2 Correcciones Ajustadas | ID | Ajuste Realizado | |----|------------------| | COR-027 | Solo crear `hr.leave_allocations`. Tablas `leaves` y `leave_types` ya existen | | COR-030 | Cambiar referencia de `lead_activities` a `activities` | --- ## 2. Plan de Ejecucion Refinado ### 2.1 LOTE 1: Fundamentos Core (Sin Dependencias) **Archivo:** `02-core.sql` **Orden:** 1 ```sql -- COR-021: Estados/Provincias CREATE TABLE core.states ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), country_id UUID NOT NULL REFERENCES core.countries(id), name VARCHAR(100) NOT NULL, code VARCHAR(10) NOT NULL, is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), UNIQUE(country_id, code) ); CREATE INDEX idx_states_country ON core.states(country_id); COMMENT ON TABLE core.states IS 'States/Provinces - Equivalent to res.country.state'; ``` **Cambio en partners:** ```sql ALTER TABLE core.partners ADD COLUMN state_id UUID REFERENCES core.states(id); ALTER TABLE core.addresses ADD COLUMN state_id UUID REFERENCES core.states(id); ``` --- ### 2.2 LOTE 2: Sistema Bancario **Archivo:** `02-core.sql` **Orden:** 2 **Depende de:** LOTE 1 ```sql -- COR-022a: Bancos CREATE TABLE core.banks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(255) NOT NULL, bic VARCHAR(11), country_id UUID REFERENCES core.countries(id), street VARCHAR(255), city VARCHAR(100), zip VARCHAR(20), phone VARCHAR(50), email VARCHAR(255), is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_banks_country ON core.banks(country_id); CREATE UNIQUE INDEX idx_banks_bic ON core.banks(bic) WHERE bic IS NOT NULL; COMMENT ON TABLE core.banks IS 'Banks catalog - Equivalent to res.bank'; -- COR-022b: Cuentas bancarias de partners CREATE TABLE core.partner_banks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, partner_id UUID NOT NULL REFERENCES core.partners(id) ON DELETE CASCADE, bank_id UUID REFERENCES core.banks(id), acc_number VARCHAR(64) NOT NULL, acc_holder_name VARCHAR(255), sequence INTEGER DEFAULT 10, currency_id UUID REFERENCES core.currencies(id), is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_partner_banks_partner ON core.partner_banks(partner_id); CREATE INDEX idx_partner_banks_bank ON core.partner_banks(bank_id); COMMENT ON TABLE core.partner_banks IS 'Partner bank accounts - Equivalent to res.partner.bank'; ``` --- ### 2.3 LOTE 3: Financial - Tax Repartition **Archivo:** `04-financial.sql` **Orden:** 3 **Depende de:** Ninguno ```sql -- COR-024: Tax Repartition Lines CREATE TYPE financial.repartition_type AS ENUM ('invoice', 'refund'); CREATE TABLE financial.tax_repartition_lines ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, tax_id UUID NOT NULL REFERENCES financial.taxes(id) ON DELETE CASCADE, repartition_type financial.repartition_type NOT NULL, sequence INTEGER DEFAULT 1, factor_percent DECIMAL(10,4) DEFAULT 100, account_id UUID REFERENCES financial.accounts(id), tag_ids UUID[], use_in_tax_closing BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_tax_repartition_tax ON financial.tax_repartition_lines(tax_id); COMMENT ON TABLE financial.tax_repartition_lines IS 'Tax repartition lines - Equivalent to account.tax.repartition.line'; ``` --- ### 2.4 LOTE 4: Financial - Bank Statements **Archivo:** `04-financial.sql` **Orden:** 4 **Depende de:** LOTE 2 ```sql -- COR-023: Bank Statements CREATE TYPE financial.statement_status AS ENUM ('draft', 'open', 'confirm', 'cancelled'); CREATE TABLE financial.bank_statements ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, journal_id UUID NOT NULL REFERENCES financial.journals(id), name VARCHAR(100), reference VARCHAR(255), date DATE NOT NULL, date_done DATE, balance_start DECIMAL(20,6) DEFAULT 0, balance_end_real DECIMAL(20,6) DEFAULT 0, total_entry_encoding DECIMAL(20,6) DEFAULT 0, status financial.statement_status DEFAULT 'draft', currency_id UUID REFERENCES core.currencies(id), is_complete BOOLEAN DEFAULT FALSE, created_by UUID REFERENCES auth.users(id), created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE TABLE financial.bank_statement_lines ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, statement_id UUID NOT NULL REFERENCES financial.bank_statements(id) ON DELETE CASCADE, sequence INTEGER DEFAULT 10, date DATE NOT NULL, payment_ref VARCHAR(255), ref VARCHAR(255), partner_id UUID REFERENCES core.partners(id), amount DECIMAL(20,6) NOT NULL, amount_currency DECIMAL(20,6), foreign_currency_id UUID REFERENCES core.currencies(id), transaction_type VARCHAR(50), narration TEXT, is_reconciled BOOLEAN DEFAULT FALSE, partner_bank_id UUID REFERENCES core.partner_banks(id), account_number VARCHAR(64), created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_bank_statements_journal ON financial.bank_statements(journal_id); CREATE INDEX idx_bank_statements_date ON financial.bank_statements(date); CREATE INDEX idx_bank_statement_lines_statement ON financial.bank_statement_lines(statement_id); COMMENT ON TABLE financial.bank_statements IS 'Bank statements - Equivalent to account.bank.statement'; COMMENT ON TABLE financial.bank_statement_lines IS 'Bank statement lines - Equivalent to account.bank.statement.line'; ``` --- ### 2.5 LOTE 5: Financial - Fiscal Positions **Archivo:** `04-financial.sql` **Orden:** 5 **Depende de:** LOTE 1 ```sql -- COR-028: Fiscal Positions CREATE TABLE financial.fiscal_positions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, sequence INTEGER DEFAULT 10, is_active BOOLEAN DEFAULT TRUE, company_id UUID REFERENCES core.companies(id), country_id UUID REFERENCES core.countries(id), state_ids UUID[], -- Array of core.states IDs zip_from VARCHAR(20), zip_to VARCHAR(20), auto_apply BOOLEAN DEFAULT FALSE, vat_required BOOLEAN DEFAULT FALSE, note TEXT, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE TABLE financial.fiscal_position_taxes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), fiscal_position_id UUID NOT NULL REFERENCES financial.fiscal_positions(id) ON DELETE CASCADE, tax_src_id UUID NOT NULL REFERENCES financial.taxes(id), tax_dest_id UUID REFERENCES financial.taxes(id) ); CREATE TABLE financial.fiscal_position_accounts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), fiscal_position_id UUID NOT NULL REFERENCES financial.fiscal_positions(id) ON DELETE CASCADE, account_src_id UUID NOT NULL REFERENCES financial.accounts(id), account_dest_id UUID NOT NULL REFERENCES financial.accounts(id) ); CREATE INDEX idx_fiscal_positions_country ON financial.fiscal_positions(country_id); COMMENT ON TABLE financial.fiscal_positions IS 'Fiscal positions - Equivalent to account.fiscal.position'; ``` --- ### 2.6 LOTE 6: Inventory - Routes & Rules **Archivo:** `05-inventory.sql` **Orden:** 6 **Depende de:** Ninguno ```sql -- COR-025: Routes & Rules CREATE TYPE inventory.rule_action AS ENUM ('pull', 'push', 'pull_push', 'buy', 'manufacture'); CREATE TYPE inventory.procurement_type AS ENUM ('make_to_stock', 'make_to_order'); CREATE TABLE inventory.routes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, sequence INTEGER DEFAULT 10, is_active BOOLEAN DEFAULT TRUE, product_selectable BOOLEAN DEFAULT TRUE, product_categ_selectable BOOLEAN DEFAULT TRUE, warehouse_selectable BOOLEAN DEFAULT TRUE, supplied_wh_id UUID REFERENCES inventory.warehouses(id), supplier_wh_id UUID REFERENCES inventory.warehouses(id), company_id UUID REFERENCES core.companies(id), created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE TABLE inventory.stock_rules ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, route_id UUID NOT NULL REFERENCES inventory.routes(id) ON DELETE CASCADE, sequence INTEGER DEFAULT 20, action inventory.rule_action NOT NULL, procure_method inventory.procurement_type DEFAULT 'make_to_stock', location_src_id UUID REFERENCES inventory.locations(id), location_dest_id UUID NOT NULL REFERENCES inventory.locations(id), picking_type_id UUID REFERENCES inventory.picking_types(id), delay INTEGER DEFAULT 0, partner_address_id UUID REFERENCES core.partners(id), propagate_cancel BOOLEAN DEFAULT FALSE, warehouse_id UUID REFERENCES inventory.warehouses(id), is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE TABLE inventory.product_routes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), product_id UUID NOT NULL REFERENCES inventory.products(id) ON DELETE CASCADE, route_id UUID NOT NULL REFERENCES inventory.routes(id) ON DELETE CASCADE, UNIQUE(product_id, route_id) ); CREATE INDEX idx_routes_warehouse ON inventory.routes(supplied_wh_id); CREATE INDEX idx_rules_route ON inventory.stock_rules(route_id); COMMENT ON TABLE inventory.routes IS 'Stock routes - Equivalent to stock.route'; COMMENT ON TABLE inventory.stock_rules IS 'Stock rules - Equivalent to stock.rule'; ``` --- ### 2.7 LOTE 7: Inventory - Stock Scrap **Archivo:** `05-inventory.sql` **Orden:** 7 **Depende de:** Ninguno ```sql -- COR-031: Stock Scrap CREATE TYPE inventory.scrap_status AS ENUM ('draft', 'done'); CREATE TABLE inventory.stock_scrap ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, name VARCHAR(100), product_id UUID NOT NULL REFERENCES inventory.products(id), product_uom_id UUID REFERENCES core.uom(id), lot_id UUID REFERENCES inventory.lots(id), scrap_qty DECIMAL(20,6) NOT NULL, scrap_location_id UUID NOT NULL REFERENCES inventory.locations(id), location_id UUID NOT NULL REFERENCES inventory.locations(id), move_id UUID REFERENCES inventory.stock_moves(id), picking_id UUID REFERENCES inventory.pickings(id), origin VARCHAR(255), date_done TIMESTAMP, status inventory.scrap_status DEFAULT 'draft', created_by UUID REFERENCES auth.users(id), created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_stock_scrap_product ON inventory.stock_scrap(product_id); COMMENT ON TABLE inventory.stock_scrap IS 'Stock scrap - Equivalent to stock.scrap'; -- Funcion para validar scrap CREATE OR REPLACE FUNCTION inventory.validate_scrap(p_scrap_id UUID) RETURNS UUID AS $$ DECLARE v_scrap RECORD; v_move_id UUID; BEGIN SELECT * INTO v_scrap FROM inventory.stock_scrap WHERE id = p_scrap_id; IF NOT FOUND THEN RAISE EXCEPTION 'Scrap record % not found', p_scrap_id; END IF; IF v_scrap.status = 'done' THEN RETURN v_scrap.move_id; END IF; INSERT INTO inventory.stock_moves ( tenant_id, product_id, product_uom_id, quantity, location_id, location_dest_id, origin, status ) VALUES ( v_scrap.tenant_id, v_scrap.product_id, v_scrap.product_uom_id, v_scrap.scrap_qty, v_scrap.location_id, v_scrap.scrap_location_id, v_scrap.name, 'done' ) RETURNING id INTO v_move_id; UPDATE inventory.stock_scrap SET status = 'done', move_id = v_move_id, date_done = NOW() WHERE id = p_scrap_id; RETURN v_move_id; END; $$ LANGUAGE plpgsql; ``` --- ### 2.8 LOTE 8: Purchase Functions **Archivo:** `06-purchase.sql` **Orden:** 8 **Depende de:** Ninguno ```sql -- COR-029: Purchase Functions CREATE OR REPLACE FUNCTION purchase.button_cancel(p_order_id UUID) RETURNS VOID AS $$ DECLARE v_order RECORD; BEGIN SELECT * INTO v_order FROM purchase.purchase_orders WHERE id = p_order_id; IF NOT FOUND THEN RAISE EXCEPTION 'Purchase order % not found', p_order_id; END IF; IF v_order.locked THEN RAISE EXCEPTION 'Cannot cancel locked order'; END IF; IF v_order.status = 'cancelled' THEN RETURN; END IF; UPDATE inventory.pickings SET status = 'cancelled' WHERE origin_document_type = 'purchase_order' AND origin_document_id = p_order_id AND status != 'done'; UPDATE purchase.purchase_orders SET status = 'cancelled', updated_at = NOW() WHERE id = p_order_id; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION purchase.button_draft(p_order_id UUID) RETURNS VOID AS $$ DECLARE v_order RECORD; BEGIN SELECT * INTO v_order FROM purchase.purchase_orders WHERE id = p_order_id; IF NOT FOUND THEN RAISE EXCEPTION 'Purchase order % not found', p_order_id; END IF; IF v_order.status NOT IN ('cancelled', 'sent') THEN RAISE EXCEPTION 'Can only set to draft from cancelled or sent state'; END IF; UPDATE purchase.purchase_orders SET status = 'draft', updated_at = NOW() WHERE id = p_order_id; END; $$ LANGUAGE plpgsql; COMMENT ON FUNCTION purchase.button_cancel IS 'Cancel purchase order - COR-029'; COMMENT ON FUNCTION purchase.button_draft IS 'Set purchase order to draft - COR-029'; ``` --- ### 2.9 LOTE 9: Sales Templates **Archivo:** `07-sales.sql` **Orden:** 9 **Depende de:** Ninguno ```sql -- COR-033: Sales Order Templates CREATE TABLE sales.order_templates ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, note TEXT, number_of_days INTEGER DEFAULT 0, require_signature BOOLEAN DEFAULT FALSE, require_payment BOOLEAN DEFAULT FALSE, prepayment_percent DECIMAL(5,2) DEFAULT 0, is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE TABLE sales.order_template_lines ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), template_id UUID NOT NULL REFERENCES sales.order_templates(id) ON DELETE CASCADE, sequence INTEGER DEFAULT 10, product_id UUID REFERENCES inventory.products(id), name TEXT, quantity DECIMAL(20,6) DEFAULT 1, product_uom_id UUID REFERENCES core.uom(id), display_type VARCHAR(20) ); CREATE INDEX idx_order_templates_tenant ON sales.order_templates(tenant_id); COMMENT ON TABLE sales.order_templates IS 'Sale order templates - Equivalent to sale.order.template'; ``` --- ### 2.10 LOTE 10: Projects Updates **Archivo:** `08-projects.sql` **Orden:** 10 **Depende de:** Ninguno ```sql -- COR-032: Project Updates CREATE TYPE projects.update_status AS ENUM ('on_track', 'at_risk', 'off_track', 'done'); CREATE TABLE projects.project_updates ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, project_id UUID NOT NULL REFERENCES projects.projects(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, status projects.update_status DEFAULT 'on_track', progress INTEGER CHECK (progress >= 0 AND progress <= 100), date DATE NOT NULL DEFAULT CURRENT_DATE, description TEXT, user_id UUID NOT NULL REFERENCES auth.users(id), created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_project_updates_project ON projects.project_updates(project_id); CREATE INDEX idx_project_updates_date ON projects.project_updates(date DESC); COMMENT ON TABLE projects.project_updates IS 'Project updates - Equivalent to project.update'; ``` --- ### 2.11 LOTE 11: CRM Merge Leads **Archivo:** `11-crm.sql` **Orden:** 11 **Depende de:** Ninguno ```sql -- COR-030: Merge Leads (Ajustado) ALTER TABLE crm.leads ADD COLUMN IF NOT EXISTS merged_into_id UUID REFERENCES crm.leads(id); CREATE OR REPLACE FUNCTION crm.merge_leads( p_lead_ids UUID[], p_target_lead_id UUID ) RETURNS UUID AS $$ DECLARE v_lead_id UUID; v_target RECORD; BEGIN SELECT * INTO v_target FROM crm.leads WHERE id = p_target_lead_id; IF NOT FOUND THEN RAISE EXCEPTION 'Target lead % not found', p_target_lead_id; END IF; FOREACH v_lead_id IN ARRAY p_lead_ids LOOP IF v_lead_id != p_target_lead_id THEN -- Move activities UPDATE crm.activities SET lead_id = p_target_lead_id WHERE lead_id = v_lead_id; -- Accumulate expected revenue UPDATE crm.leads t SET expected_revenue = t.expected_revenue + COALESCE( (SELECT expected_revenue FROM crm.leads WHERE id = v_lead_id), 0 ) WHERE t.id = p_target_lead_id; -- Mark as merged UPDATE crm.leads SET is_deleted = TRUE, merged_into_id = p_target_lead_id, updated_at = NOW() WHERE id = v_lead_id; END IF; END LOOP; RETURN p_target_lead_id; END; $$ LANGUAGE plpgsql; COMMENT ON FUNCTION crm.merge_leads IS 'Merge multiple leads into one - COR-030'; ``` --- ### 2.12 LOTE 12: HR Attendances & Leave Allocations **Archivo:** `12-hr.sql` **Orden:** 12 **Depende de:** Ninguno ```sql -- COR-026: Attendances CREATE TABLE hr.attendances ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, employee_id UUID NOT NULL REFERENCES hr.employees(id) ON DELETE CASCADE, check_in TIMESTAMP NOT NULL, check_out TIMESTAMP, worked_hours DECIMAL(10,4), overtime_hours DECIMAL(10,4) DEFAULT 0, is_overtime BOOLEAN DEFAULT FALSE, notes TEXT, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), CONSTRAINT valid_checkout CHECK (check_out IS NULL OR check_out > check_in) ); CREATE INDEX idx_attendances_employee ON hr.attendances(employee_id); CREATE INDEX idx_attendances_checkin ON hr.attendances(check_in); COMMENT ON TABLE hr.attendances IS 'Employee attendances - Equivalent to hr.attendance'; -- COR-027: Leave Allocations (Solo tabla faltante) CREATE TABLE hr.leave_allocations ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, employee_id UUID NOT NULL REFERENCES hr.employees(id) ON DELETE CASCADE, leave_type_id UUID NOT NULL REFERENCES hr.leave_types(id), name VARCHAR(255), number_of_days DECIMAL(10,2) NOT NULL, date_from DATE, date_to DATE, status hr.leave_status DEFAULT 'draft', allocation_type VARCHAR(20) DEFAULT 'regular', notes TEXT, approved_by UUID REFERENCES auth.users(id), approved_at TIMESTAMP, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_leave_allocations_employee ON hr.leave_allocations(employee_id); COMMENT ON TABLE hr.leave_allocations IS 'Leave allocations - Equivalent to hr.leave.allocation'; ``` --- ## 3. Resumen de Ejecucion ### 3.1 Orden de Ejecucion | Lote | Archivo | Correcciones | Tablas | Funciones | |------|---------|--------------|--------|-----------| | 1 | 02-core.sql | COR-021 | 1 | 0 | | 2 | 02-core.sql | COR-022 | 2 | 0 | | 3 | 04-financial.sql | COR-024 | 1 | 0 | | 4 | 04-financial.sql | COR-023 | 2 | 0 | | 5 | 04-financial.sql | COR-028 | 3 | 0 | | 6 | 05-inventory.sql | COR-025 | 3 | 0 | | 7 | 05-inventory.sql | COR-031 | 1 | 1 | | 8 | 06-purchase.sql | COR-029 | 0 | 2 | | 9 | 07-sales.sql | COR-033 | 2 | 0 | | 10 | 08-projects.sql | COR-032 | 1 | 0 | | 11 | 11-crm.sql | COR-030 | 0 | 1 | | 12 | 12-hr.sql | COR-026, COR-027 | 2 | 0 | | **TOTAL** | **8 archivos** | **13 correcciones** | **18 tablas** | **4 funciones** | ### 3.2 Dependencias Criticas ``` LOTE 1 (states) ──→ LOTE 2 (banks) ──→ LOTE 4 (bank_statements) └──→ LOTE 5 (fiscal_positions) ``` ### 3.3 Lotes Independientes (Pueden Ejecutarse en Paralelo) - LOTE 3, 6, 7, 8, 9, 10, 11, 12 --- ## 4. Criterios de Validacion por Lote | Lote | Criterio | Validacion | |------|----------|------------| | 1 | core.states referenciable | SELECT FROM core.states | | 2 | partner_banks con FK validas | INSERT test | | 3 | tax_repartition con FK a taxes | INSERT test | | 4 | bank_statements con statement_lines | FK CASCADE test | | 5 | fiscal_position_taxes funcional | INSERT mapping test | | 6 | routes con rules | FK cascade test | | 7 | scrap crea move | CALL validate_scrap test | | 8 | button_cancel cancela pickings | Test con PO | | 9 | templates con lines | INSERT test | | 10 | updates con status | INSERT test | | 11 | merge actualiza activities | CALL merge_leads test | | 12 | attendances + allocations | INSERT test | --- ## 5. Proximos Pasos 1. **FASE 6:** Ejecutar correcciones por lotes 2. **FASE 7:** Validar cada lote despues de ejecucion 3. Actualizar documentacion downstream --- **Generado:** 2026-01-04 **Herramienta:** Claude Code **Metodologia:** SCRUM/SIMCO