-- ============================================================= -- ARCHIVO: 56-financial-taxes.sql -- DESCRIPCION: Impuestos contables (IVA, retenciones, etc.) -- VERSION: 1.0.0 -- PROYECTO: ERP-Core V2 -- FECHA: 2026-01-20 -- DEPENDE DE: 50-financial-schema.sql, 51-financial-accounts.sql -- ============================================================= -- ===================== -- TABLA: taxes -- Catalogo de impuestos -- ===================== CREATE TABLE IF NOT EXISTS financial.taxes ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), -- Multi-tenant tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, company_id UUID, -- Identificacion name VARCHAR(100) NOT NULL, -- Ej: "IVA 16%", "Retencion ISR 10%" code VARCHAR(20) NOT NULL, -- Ej: "IVA16", "RET_ISR10" -- Tipo de impuesto tax_type financial.tax_type_enum NOT NULL DEFAULT 'all', -- Tasa amount DECIMAL(5, 2) NOT NULL, -- Porcentaje (ej: 16.00 para 16%) -- Configuracion included_in_price BOOLEAN DEFAULT FALSE, -- TRUE si el precio ya incluye el impuesto -- Estado active BOOLEAN DEFAULT TRUE, -- Cuentas contables asociadas (opcional) account_id UUID REFERENCES financial.accounts(id) ON DELETE SET NULL, -- Cuenta de impuesto refund_account_id UUID REFERENCES financial.accounts(id) ON DELETE SET NULL, -- Cuenta para devoluciones -- Audit columns created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, created_by UUID REFERENCES auth.users(id), updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, updated_by UUID REFERENCES auth.users(id), -- Unicidad por tenant UNIQUE(tenant_id, code) ); -- Indices para taxes CREATE INDEX IF NOT EXISTS idx_financial_taxes_tenant ON financial.taxes(tenant_id); CREATE INDEX IF NOT EXISTS idx_financial_taxes_company ON financial.taxes(company_id); CREATE INDEX IF NOT EXISTS idx_financial_taxes_code ON financial.taxes(code); CREATE INDEX IF NOT EXISTS idx_financial_taxes_type ON financial.taxes(tax_type); CREATE INDEX IF NOT EXISTS idx_financial_taxes_active ON financial.taxes(tenant_id) WHERE active = TRUE; CREATE INDEX IF NOT EXISTS idx_financial_taxes_sales ON financial.taxes(tenant_id, tax_type) WHERE tax_type IN ('sales', 'all') AND active = TRUE; CREATE INDEX IF NOT EXISTS idx_financial_taxes_purchase ON financial.taxes(tenant_id, tax_type) WHERE tax_type IN ('purchase', 'all') AND active = TRUE; CREATE INDEX IF NOT EXISTS idx_financial_taxes_account ON financial.taxes(account_id) WHERE account_id IS NOT NULL; -- ===================== -- TABLA: tax_groups (opcional, para agrupar impuestos) -- Grupos de impuestos para aplicacion conjunta -- ===================== CREATE TABLE IF NOT EXISTS financial.tax_groups ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), -- Multi-tenant tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE, -- Identificacion name VARCHAR(100) NOT NULL, code VARCHAR(20) NOT NULL, -- Descripcion description TEXT, -- Impuestos en el grupo (array de IDs) tax_ids UUID[] DEFAULT '{}', -- Estado active BOOLEAN DEFAULT TRUE, -- Audit columns created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, created_by UUID REFERENCES auth.users(id), updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, updated_by UUID REFERENCES auth.users(id), UNIQUE(tenant_id, code) ); -- Indices para tax_groups CREATE INDEX IF NOT EXISTS idx_financial_tax_groups_tenant ON financial.tax_groups(tenant_id); CREATE INDEX IF NOT EXISTS idx_financial_tax_groups_code ON financial.tax_groups(code); CREATE INDEX IF NOT EXISTS idx_financial_tax_groups_active ON financial.tax_groups(tenant_id) WHERE active = TRUE; CREATE INDEX IF NOT EXISTS idx_financial_tax_groups_tax_ids ON financial.tax_groups USING GIN(tax_ids); -- ===================== -- DATOS SEMILLA: Impuestos comunes de Mexico -- ===================== -- Nota: Estos se insertan condicionalmente. En produccion, los impuestos -- se crean por tenant desde la aplicacion. -- Funcion para insertar impuestos semilla CREATE OR REPLACE FUNCTION financial.seed_default_taxes(p_tenant_id UUID) RETURNS void AS $$ BEGIN -- IVA 16% (tasa general) INSERT INTO financial.taxes (tenant_id, code, name, tax_type, amount, included_in_price, active) VALUES (p_tenant_id, 'IVA16', 'IVA 16%', 'all', 16.00, FALSE, TRUE) ON CONFLICT (tenant_id, code) DO NOTHING; -- IVA 8% (frontera) INSERT INTO financial.taxes (tenant_id, code, name, tax_type, amount, included_in_price, active) VALUES (p_tenant_id, 'IVA8', 'IVA 8% (Frontera)', 'all', 8.00, FALSE, TRUE) ON CONFLICT (tenant_id, code) DO NOTHING; -- IVA 0% (tasa cero) INSERT INTO financial.taxes (tenant_id, code, name, tax_type, amount, included_in_price, active) VALUES (p_tenant_id, 'IVA0', 'IVA 0%', 'all', 0.00, FALSE, TRUE) ON CONFLICT (tenant_id, code) DO NOTHING; -- IVA Exento INSERT INTO financial.taxes (tenant_id, code, name, tax_type, amount, included_in_price, active) VALUES (p_tenant_id, 'EXENTO', 'Exento de IVA', 'all', 0.00, FALSE, TRUE) ON CONFLICT (tenant_id, code) DO NOTHING; -- Retencion ISR 10% INSERT INTO financial.taxes (tenant_id, code, name, tax_type, amount, included_in_price, active) VALUES (p_tenant_id, 'RET_ISR10', 'Retencion ISR 10%', 'purchase', -10.00, FALSE, TRUE) ON CONFLICT (tenant_id, code) DO NOTHING; -- Retencion IVA 10.67% INSERT INTO financial.taxes (tenant_id, code, name, tax_type, amount, included_in_price, active) VALUES (p_tenant_id, 'RET_IVA', 'Retencion IVA 2/3', 'purchase', -10.67, FALSE, TRUE) ON CONFLICT (tenant_id, code) DO NOTHING; END; $$ LANGUAGE plpgsql; -- ===================== -- COMENTARIOS -- ===================== COMMENT ON TABLE financial.taxes IS 'Catalogo de impuestos (IVA, retenciones, etc.)'; COMMENT ON COLUMN financial.taxes.code IS 'Codigo unico del impuesto (ej: IVA16, RET_ISR10)'; COMMENT ON COLUMN financial.taxes.tax_type IS 'Aplicacion: sales (solo ventas), purchase (solo compras), all (ambos)'; COMMENT ON COLUMN financial.taxes.amount IS 'Tasa del impuesto en porcentaje (ej: 16.00 para 16%). Negativo para retenciones.'; COMMENT ON COLUMN financial.taxes.included_in_price IS 'TRUE si el precio del producto ya incluye este impuesto'; COMMENT ON COLUMN financial.taxes.account_id IS 'Cuenta contable donde se registra el impuesto'; COMMENT ON COLUMN financial.taxes.refund_account_id IS 'Cuenta contable para devoluciones/notas de credito'; COMMENT ON TABLE financial.tax_groups IS 'Grupos de impuestos para aplicacion conjunta (ej: IVA + Retenciones)'; COMMENT ON COLUMN financial.tax_groups.tax_ids IS 'Array de IDs de impuestos que componen el grupo'; COMMENT ON FUNCTION financial.seed_default_taxes(UUID) IS 'Inserta impuestos predeterminados de Mexico para un tenant';