-- ============================================================================ -- INVESTMENT SCHEMA - Tabla: withdrawal_requests -- ============================================================================ -- Solicitudes de retiro de cuentas PAMM -- Requiere aprobacion manual para montos grandes -- ============================================================================ -- Enum para estado de solicitud DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'withdrawal_status' AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'investment')) THEN CREATE TYPE investment.withdrawal_status AS ENUM ( 'pending', 'under_review', 'approved', 'processing', 'completed', 'rejected', 'cancelled' ); END IF; END$$; CREATE TABLE IF NOT EXISTS investment.withdrawal_requests ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- Relaciones account_id UUID NOT NULL REFERENCES investment.accounts(id) ON DELETE RESTRICT, user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE RESTRICT, -- Solicitud request_number VARCHAR(20) NOT NULL UNIQUE, amount DECIMAL(20, 8) NOT NULL, currency VARCHAR(10) NOT NULL DEFAULT 'USD', -- Estado status investment.withdrawal_status NOT NULL DEFAULT 'pending', -- Destino del retiro destination_type VARCHAR(20) NOT NULL, -- 'wallet', 'bank', 'crypto' destination_details JSONB NOT NULL DEFAULT '{}', -- Fees fee_amount DECIMAL(20, 8) NOT NULL DEFAULT 0, fee_percentage DECIMAL(5, 2) NOT NULL DEFAULT 0, net_amount DECIMAL(20, 8) GENERATED ALWAYS AS (amount - fee_amount) STORED, -- Aprobacion requires_approval BOOLEAN NOT NULL DEFAULT FALSE, reviewed_by UUID REFERENCES auth.users(id), reviewed_at TIMESTAMPTZ, review_notes TEXT, -- Procesamiento processed_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, transaction_reference VARCHAR(100), -- Rechazo/Cancelacion rejection_reason TEXT, cancelled_at TIMESTAMPTZ, cancellation_reason TEXT, -- Metadata ip_address INET, user_agent TEXT, metadata JSONB DEFAULT '{}', -- Timestamps created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Constraints CONSTRAINT chk_positive_amount CHECK (amount > 0), CONSTRAINT chk_valid_fee CHECK (fee_amount >= 0 AND fee_amount <= amount), CONSTRAINT chk_fee_percentage CHECK (fee_percentage >= 0 AND fee_percentage <= 100), CONSTRAINT chk_destination_type CHECK (destination_type IN ('wallet', 'bank', 'crypto')) ); -- Indices CREATE INDEX idx_withdrawal_requests_account ON investment.withdrawal_requests(account_id); CREATE INDEX idx_withdrawal_requests_user ON investment.withdrawal_requests(user_id); CREATE INDEX idx_withdrawal_requests_status ON investment.withdrawal_requests(status); CREATE INDEX idx_withdrawal_requests_created ON investment.withdrawal_requests(created_at DESC); CREATE INDEX idx_withdrawal_requests_pending ON investment.withdrawal_requests(status, created_at) WHERE status IN ('pending', 'under_review'); -- Comentarios COMMENT ON TABLE investment.withdrawal_requests IS 'Solicitudes de retiro de cuentas PAMM'; COMMENT ON COLUMN investment.withdrawal_requests.request_number IS 'Numero unico de solicitud (WR-YYYYMMDD-XXXX)'; COMMENT ON COLUMN investment.withdrawal_requests.requires_approval IS 'True si el monto requiere aprobacion manual'; COMMENT ON COLUMN investment.withdrawal_requests.destination_details IS 'Detalles del destino (IBAN, wallet address, etc.)'; -- Funcion para generar numero de solicitud CREATE OR REPLACE FUNCTION investment.generate_withdrawal_request_number() RETURNS TRIGGER AS $$ DECLARE v_date TEXT; v_seq INTEGER; BEGIN v_date := TO_CHAR(NOW(), 'YYYYMMDD'); SELECT COALESCE(MAX( CAST(SUBSTRING(request_number FROM 'WR-[0-9]{8}-([0-9]+)') AS INTEGER) ), 0) + 1 INTO v_seq FROM investment.withdrawal_requests WHERE request_number LIKE 'WR-' || v_date || '-%'; NEW.request_number := 'WR-' || v_date || '-' || LPAD(v_seq::TEXT, 4, '0'); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER tr_generate_withdrawal_request_number BEFORE INSERT ON investment.withdrawal_requests FOR EACH ROW WHEN (NEW.request_number IS NULL) EXECUTE FUNCTION investment.generate_withdrawal_request_number();