-- =============================================================
-- ARCHIVO: 21-fiscal-catalogs.sql
-- DESCRIPCION: Catalogos fiscales - SAT Mexico, regimenes, CFDI
-- VERSION: 1.0.0
-- PROYECTO: ERP-Core V2
-- FECHA: 2026-01-18
-- =============================================================

-- =====================
-- SCHEMA: fiscal
-- =====================
CREATE SCHEMA IF NOT EXISTS fiscal;

-- =====================
-- TABLA: tax_categories
-- Categorias de impuestos (IVA, ISR, IEPS, etc.)
-- =====================
CREATE TABLE IF NOT EXISTS fiscal.tax_categories (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    code VARCHAR(20) NOT NULL UNIQUE,     -- IVA, ISR, IEPS, etc.
    name VARCHAR(100) NOT NULL,
    description TEXT,

    -- Tipo de impuesto
    tax_nature VARCHAR(20) NOT NULL DEFAULT 'tax',  -- tax, withholding, both

    -- Configuracion SAT Mexico
    sat_code VARCHAR(10),                 -- Codigo SAT (002=IVA, 001=ISR, etc.)

    is_active BOOLEAN DEFAULT TRUE,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_tax_categories_code ON fiscal.tax_categories(code);
CREATE INDEX IF NOT EXISTS idx_tax_categories_sat ON fiscal.tax_categories(sat_code);
CREATE INDEX IF NOT EXISTS idx_tax_categories_active ON fiscal.tax_categories(is_active) WHERE is_active = TRUE;

COMMENT ON TABLE fiscal.tax_categories IS 'Categorias de impuestos (IVA, ISR, IEPS, etc.)';

-- =====================
-- TABLA: fiscal_regimes
-- Regimenes fiscales SAT Mexico (Catalogo c_RegimenFiscal)
-- =====================
CREATE TABLE IF NOT EXISTS fiscal.fiscal_regimes (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    code VARCHAR(10) NOT NULL UNIQUE,     -- Codigo SAT (601, 603, 612, etc.)
    name VARCHAR(255) NOT NULL,
    description TEXT,

    -- Aplica a persona fisica o moral
    applies_to VARCHAR(20) NOT NULL DEFAULT 'both',  -- natural (fisica), legal (moral), both

    is_active BOOLEAN DEFAULT TRUE,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_fiscal_regimes_code ON fiscal.fiscal_regimes(code);
CREATE INDEX IF NOT EXISTS idx_fiscal_regimes_applies ON fiscal.fiscal_regimes(applies_to);
CREATE INDEX IF NOT EXISTS idx_fiscal_regimes_active ON fiscal.fiscal_regimes(is_active) WHERE is_active = TRUE;

COMMENT ON TABLE fiscal.fiscal_regimes IS 'Catalogo de regimenes fiscales SAT (c_RegimenFiscal)';

-- =====================
-- TABLA: cfdi_uses
-- Uso del CFDI SAT Mexico (Catalogo c_UsoCFDI)
-- =====================
CREATE TABLE IF NOT EXISTS fiscal.cfdi_uses (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    code VARCHAR(10) NOT NULL UNIQUE,     -- Codigo SAT (G01, G02, G03, etc.)
    name VARCHAR(255) NOT NULL,
    description TEXT,

    -- Aplica a persona fisica o moral
    applies_to VARCHAR(20) NOT NULL DEFAULT 'both',  -- natural, legal, both

    -- Regimenes fiscales permitidos (NULL = todos)
    allowed_regimes VARCHAR[] DEFAULT NULL,

    is_active BOOLEAN DEFAULT TRUE,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_cfdi_uses_code ON fiscal.cfdi_uses(code);
CREATE INDEX IF NOT EXISTS idx_cfdi_uses_applies ON fiscal.cfdi_uses(applies_to);
CREATE INDEX IF NOT EXISTS idx_cfdi_uses_active ON fiscal.cfdi_uses(is_active) WHERE is_active = TRUE;

COMMENT ON TABLE fiscal.cfdi_uses IS 'Catalogo de uso del CFDI SAT (c_UsoCFDI)';

-- =====================
-- TABLA: payment_methods
-- Formas de pago SAT Mexico (Catalogo c_FormaPago)
-- =====================
CREATE TABLE IF NOT EXISTS fiscal.payment_methods (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    code VARCHAR(10) NOT NULL UNIQUE,     -- Codigo SAT (01, 02, 03, etc.)
    name VARCHAR(100) NOT NULL,
    description TEXT,

    -- Configuracion
    requires_bank_info BOOLEAN DEFAULT FALSE,  -- Requiere info bancaria

    is_active BOOLEAN DEFAULT TRUE,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_payment_methods_code ON fiscal.payment_methods(code);
CREATE INDEX IF NOT EXISTS idx_payment_methods_active ON fiscal.payment_methods(is_active) WHERE is_active = TRUE;

COMMENT ON TABLE fiscal.payment_methods IS 'Catalogo de formas de pago SAT (c_FormaPago)';

-- =====================
-- TABLA: payment_types
-- Metodos de pago SAT Mexico (Catalogo c_MetodoPago)
-- =====================
CREATE TABLE IF NOT EXISTS fiscal.payment_types (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    code VARCHAR(10) NOT NULL UNIQUE,     -- PUE, PPD
    name VARCHAR(100) NOT NULL,
    description TEXT,

    is_active BOOLEAN DEFAULT TRUE,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_payment_types_code ON fiscal.payment_types(code);
CREATE INDEX IF NOT EXISTS idx_payment_types_active ON fiscal.payment_types(is_active) WHERE is_active = TRUE;

COMMENT ON TABLE fiscal.payment_types IS 'Catalogo de metodos de pago SAT (c_MetodoPago)';

-- =====================
-- TABLA: withholding_types
-- Tipos de retencion
-- =====================
CREATE TABLE IF NOT EXISTS fiscal.withholding_types (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    code VARCHAR(20) NOT NULL UNIQUE,
    name VARCHAR(100) NOT NULL,
    description TEXT,

    -- Tasa de retencion por defecto
    default_rate DECIMAL(5, 2) NOT NULL DEFAULT 0,

    -- Categoria de impuesto asociada
    tax_category_id UUID REFERENCES fiscal.tax_categories(id),

    is_active BOOLEAN DEFAULT TRUE,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_withholding_types_code ON fiscal.withholding_types(code);
CREATE INDEX IF NOT EXISTS idx_withholding_types_category ON fiscal.withholding_types(tax_category_id);
CREATE INDEX IF NOT EXISTS idx_withholding_types_active ON fiscal.withholding_types(is_active) WHERE is_active = TRUE;

COMMENT ON TABLE fiscal.withholding_types IS 'Tipos de retencion fiscal';

-- =====================
-- DATOS INICIALES: tax_categories
-- =====================
INSERT INTO fiscal.tax_categories (code, name, description, tax_nature, sat_code) VALUES
    ('IVA', 'Impuesto al Valor Agregado', 'Impuesto al consumo aplicado a bienes y servicios', 'tax', '002'),
    ('ISR', 'Impuesto Sobre la Renta', 'Impuesto a los ingresos', 'withholding', '001'),
    ('IEPS', 'Impuesto Especial sobre Produccion y Servicios', 'Impuesto a productos especiales', 'tax', '003'),
    ('IVA_RET', 'IVA Retenido', 'Retencion de IVA', 'withholding', '002'),
    ('ISR_RET', 'ISR Retenido', 'Retencion de ISR', 'withholding', '001'),
    ('CEDULAR', 'Impuesto Cedular', 'Impuesto local sobre ingresos', 'tax', NULL),
    ('ISH', 'Impuesto Sobre Hospedaje', 'Impuesto estatal al hospedaje', 'tax', NULL)
ON CONFLICT (code) DO NOTHING;

-- =====================
-- DATOS INICIALES: fiscal_regimes (SAT Mexico c_RegimenFiscal)
-- =====================
INSERT INTO fiscal.fiscal_regimes (code, name, applies_to) VALUES
    ('601', 'General de Ley Personas Morales', 'legal'),
    ('603', 'Personas Morales con Fines no Lucrativos', 'legal'),
    ('605', 'Sueldos y Salarios e Ingresos Asimilados a Salarios', 'natural'),
    ('606', 'Arrendamiento', 'natural'),
    ('607', 'Régimen de Enajenación o Adquisición de Bienes', 'natural'),
    ('608', 'Demás ingresos', 'natural'),
    ('609', 'Consolidación', 'legal'),
    ('610', 'Residentes en el Extranjero sin Establecimiento Permanente en México', 'both'),
    ('611', 'Ingresos por Dividendos (socios y accionistas)', 'natural'),
    ('612', 'Personas Físicas con Actividades Empresariales y Profesionales', 'natural'),
    ('614', 'Ingresos por intereses', 'natural'),
    ('615', 'Régimen de los ingresos por obtención de premios', 'natural'),
    ('616', 'Sin obligaciones fiscales', 'both'),
    ('620', 'Sociedades Cooperativas de Producción que optan por diferir sus ingresos', 'legal'),
    ('621', 'Incorporación Fiscal', 'natural'),
    ('622', 'Actividades Agrícolas, Ganaderas, Silvícolas y Pesqueras', 'both'),
    ('623', 'Opcional para Grupos de Sociedades', 'legal'),
    ('624', 'Coordinados', 'legal'),
    ('625', 'Régimen de las Actividades Empresariales con ingresos a través de Plataformas Tecnológicas', 'natural'),
    ('626', 'Régimen Simplificado de Confianza', 'both')
ON CONFLICT (code) DO NOTHING;

-- =====================
-- DATOS INICIALES: cfdi_uses (SAT Mexico c_UsoCFDI)
-- =====================
INSERT INTO fiscal.cfdi_uses (code, name, applies_to) VALUES
    ('G01', 'Adquisición de mercancías', 'both'),
    ('G02', 'Devoluciones, descuentos o bonificaciones', 'both'),
    ('G03', 'Gastos en general', 'both'),
    ('I01', 'Construcciones', 'both'),
    ('I02', 'Mobiliario y equipo de oficina por inversiones', 'both'),
    ('I03', 'Equipo de transporte', 'both'),
    ('I04', 'Equipo de cómputo y accesorios', 'both'),
    ('I05', 'Dados, troqueles, moldes, matrices y herramental', 'both'),
    ('I06', 'Comunicaciones telefónicas', 'both'),
    ('I07', 'Comunicaciones satelitales', 'both'),
    ('I08', 'Otra maquinaria y equipo', 'both'),
    ('D01', 'Honorarios médicos, dentales y gastos hospitalarios', 'natural'),
    ('D02', 'Gastos médicos por incapacidad o discapacidad', 'natural'),
    ('D03', 'Gastos funerales', 'natural'),
    ('D04', 'Donativos', 'natural'),
    ('D05', 'Intereses reales efectivamente pagados por créditos hipotecarios (casa habitación)', 'natural'),
    ('D06', 'Aportaciones voluntarias al SAR', 'natural'),
    ('D07', 'Primas por seguros de gastos médicos', 'natural'),
    ('D08', 'Gastos de transportación escolar obligatoria', 'natural'),
    ('D09', 'Depósitos en cuentas para el ahorro, primas que tengan como base planes de pensiones', 'natural'),
    ('D10', 'Pagos por servicios educativos (colegiaturas)', 'natural'),
    ('S01', 'Sin efectos fiscales', 'both'),
    ('CP01', 'Pagos', 'both'),
    ('CN01', 'Nómina', 'natural')
ON CONFLICT (code) DO NOTHING;

-- =====================
-- DATOS INICIALES: payment_methods (SAT Mexico c_FormaPago)
-- =====================
INSERT INTO fiscal.payment_methods (code, name, requires_bank_info) VALUES
    ('01', 'Efectivo', false),
    ('02', 'Cheque nominativo', true),
    ('03', 'Transferencia electrónica de fondos', true),
    ('04', 'Tarjeta de crédito', true),
    ('05', 'Monedero electrónico', false),
    ('06', 'Dinero electrónico', false),
    ('08', 'Vales de despensa', false),
    ('12', 'Dación en pago', false),
    ('13', 'Pago por subrogación', false),
    ('14', 'Pago por consignación', false),
    ('15', 'Condonación', false),
    ('17', 'Compensación', false),
    ('23', 'Novación', false),
    ('24', 'Confusión', false),
    ('25', 'Remisión de deuda', false),
    ('26', 'Prescripción o caducidad', false),
    ('27', 'A satisfacción del acreedor', false),
    ('28', 'Tarjeta de débito', true),
    ('29', 'Tarjeta de servicios', true),
    ('30', 'Aplicación de anticipos', false),
    ('31', 'Intermediario pagos', false),
    ('99', 'Por definir', false)
ON CONFLICT (code) DO NOTHING;

-- =====================
-- DATOS INICIALES: payment_types (SAT Mexico c_MetodoPago)
-- =====================
INSERT INTO fiscal.payment_types (code, name, description) VALUES
    ('PUE', 'Pago en una sola exhibición', 'El pago se realiza en una sola exhibición al momento de emitir el CFDI'),
    ('PPD', 'Pago en parcialidades o diferido', 'El pago se realiza en parcialidades o de forma diferida')
ON CONFLICT (code) DO NOTHING;

-- =====================
-- DATOS INICIALES: withholding_types
-- =====================
INSERT INTO fiscal.withholding_types (code, name, description, default_rate, tax_category_id) VALUES
    ('ISR_10', 'Retención ISR 10%', 'Retención de ISR al 10% para servicios profesionales', 10.00,
        (SELECT id FROM fiscal.tax_categories WHERE code = 'ISR')),
    ('ISR_10.67', 'Retención ISR 10.67%', 'Retención de ISR al 10.67% para arrendamiento', 10.67,
        (SELECT id FROM fiscal.tax_categories WHERE code = 'ISR')),
    ('IVA_RET_10.67', 'Retención IVA 10.67%', 'Retención de IVA para servicios profesionales persona moral', 10.67,
        (SELECT id FROM fiscal.tax_categories WHERE code = 'IVA_RET')),
    ('IVA_RET_4', 'Retención IVA 4%', 'Retención de IVA al 4% para autotransporte', 4.00,
        (SELECT id FROM fiscal.tax_categories WHERE code = 'IVA_RET'))
ON CONFLICT (code) DO NOTHING;

-- =====================
-- FIN DEL ARCHIVO
-- =====================
