-- ===================================================== -- FUNCTION: education.update_gamification_profile() -- ===================================================== -- Proyecto: OrbiQuant IA (Trading Platform) -- Módulo: OQI-002 - Education -- Especificación: Función adicional para gamificación -- Descripción: Actualiza el perfil de gamificación del usuario -- ===================================================== -- Función para actualizar XP y nivel CREATE OR REPLACE FUNCTION education.update_user_xp( p_user_id UUID, p_xp_to_add INTEGER ) RETURNS VOID AS $$ DECLARE v_profile RECORD; v_new_total_xp INTEGER; v_new_level INTEGER; v_xp_to_next INTEGER; BEGIN -- Obtener o crear perfil INSERT INTO education.user_gamification_profile (user_id) VALUES (p_user_id) ON CONFLICT (user_id) DO NOTHING; -- Obtener perfil actual SELECT * INTO v_profile FROM education.user_gamification_profile WHERE user_id = p_user_id; -- Calcular nuevo XP total v_new_total_xp := v_profile.total_xp + p_xp_to_add; -- Calcular nuevo nivel (cada nivel requiere 100 XP más que el anterior) -- Nivel 1: 0-99 XP, Nivel 2: 100-299 XP, Nivel 3: 300-599 XP, etc. v_new_level := FLOOR((-100 + SQRT(10000 + 800 * v_new_total_xp)) / 200) + 1; -- XP necesario para siguiente nivel v_xp_to_next := (v_new_level * 100 + (v_new_level * (v_new_level - 1) * 100)) - v_new_total_xp; -- Actualizar perfil UPDATE education.user_gamification_profile SET total_xp = v_new_total_xp, current_level = v_new_level, xp_to_next_level = v_xp_to_next, weekly_xp = weekly_xp + p_xp_to_add, monthly_xp = monthly_xp + p_xp_to_add, last_activity_date = CURRENT_DATE, updated_at = NOW() WHERE user_id = p_user_id; -- Si subió de nivel, crear achievement IF v_new_level > v_profile.current_level THEN INSERT INTO education.user_achievements ( user_id, achievement_type, title, description, xp_bonus ) VALUES ( p_user_id, 'level_up', 'Level Up! - Nivel ' || v_new_level, 'Has alcanzado el nivel ' || v_new_level, 50 ); END IF; END; $$ LANGUAGE plpgsql; COMMENT ON FUNCTION education.update_user_xp(UUID, INTEGER) IS 'Actualiza XP del usuario y recalcula nivel'; -- Función para actualizar streak CREATE OR REPLACE FUNCTION education.update_user_streak(p_user_id UUID) RETURNS VOID AS $$ DECLARE v_last_activity DATE; v_current_streak INTEGER; v_longest_streak INTEGER; BEGIN -- Obtener o crear perfil INSERT INTO education.user_gamification_profile (user_id) VALUES (p_user_id) ON CONFLICT (user_id) DO NOTHING; -- Obtener datos actuales SELECT last_activity_date, current_streak_days, longest_streak_days INTO v_last_activity, v_current_streak, v_longest_streak FROM education.user_gamification_profile WHERE user_id = p_user_id; -- Actualizar streak IF v_last_activity IS NULL THEN -- Primera actividad v_current_streak := 1; ELSIF v_last_activity = CURRENT_DATE THEN -- Ya tuvo actividad hoy, no hacer nada RETURN; ELSIF v_last_activity = CURRENT_DATE - INTERVAL '1 day' THEN -- Actividad día consecutivo v_current_streak := v_current_streak + 1; ELSE -- Se rompió el streak v_current_streak := 1; END IF; -- Actualizar longest streak si corresponde IF v_current_streak > v_longest_streak THEN v_longest_streak := v_current_streak; -- Crear achievement por streak milestones IF v_current_streak IN (7, 30, 100) THEN INSERT INTO education.user_achievements ( user_id, achievement_type, title, description, xp_bonus, metadata ) VALUES ( p_user_id, 'streak_milestone', 'Streak de ' || v_current_streak || ' días', 'Has mantenido una racha de ' || v_current_streak || ' días consecutivos', v_current_streak * 5, jsonb_build_object('streak_days', v_current_streak) ); END IF; END IF; -- Actualizar perfil UPDATE education.user_gamification_profile SET current_streak_days = v_current_streak, longest_streak_days = v_longest_streak, last_activity_date = CURRENT_DATE, updated_at = NOW() WHERE user_id = p_user_id; END; $$ LANGUAGE plpgsql; COMMENT ON FUNCTION education.update_user_streak(UUID) IS 'Actualiza streak del usuario basado en actividad diaria'; -- Trigger para actualizar streak en actividades CREATE OR REPLACE FUNCTION education.trigger_update_streak() RETURNS TRIGGER AS $$ BEGIN PERFORM education.update_user_streak(NEW.user_id); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER update_streak_on_activity AFTER INSERT ON education.user_activity_log FOR EACH ROW EXECUTE FUNCTION education.trigger_update_streak();