michangarrito/database/schemas/13-referrals.sql
rckrdmrd 97f407c661 [MIGRATION-V2] feat: Migrar michangarrito a estructura v2
- Prefijo v2: MCH
- TRACEABILITY-MASTER.yml creado
- Listo para integracion como submodulo

Workspace: v2.0.0 | SIMCO: v4.0.0
2026-01-10 11:28:54 -06:00

144 lines
5.0 KiB
PL/PgSQL

-- =============================================================================
-- MICHANGARRITO - 13 REFERRALS
-- =============================================================================
-- Programa de referidos: codigos, referidos y recompensas
-- =============================================================================
-- Codigos de referido
CREATE TABLE IF NOT EXISTS subscriptions.referral_codes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
code VARCHAR(20) UNIQUE NOT NULL,
active BOOLEAN DEFAULT true,
uses_count INTEGER DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_referral_codes_tenant ON subscriptions.referral_codes(tenant_id);
CREATE INDEX idx_referral_codes_code ON subscriptions.referral_codes(code);
CREATE TRIGGER update_referral_codes_updated_at
BEFORE UPDATE ON subscriptions.referral_codes
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
-- Referidos
CREATE TABLE IF NOT EXISTS subscriptions.referrals (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
referrer_tenant_id UUID NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
referred_tenant_id UUID NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
code_used VARCHAR(20) NOT NULL,
status VARCHAR(20) DEFAULT 'pending',
-- pending: referido registrado, no ha pagado
-- converted: referido pago primer mes
-- rewarded: recompensa aplicada al referidor
-- expired: referido no pago en tiempo (30 dias)
referred_discount_applied BOOLEAN DEFAULT false,
referrer_reward_applied BOOLEAN DEFAULT false,
converted_at TIMESTAMPTZ,
reward_applied_at TIMESTAMPTZ,
expires_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(referred_tenant_id)
);
CREATE INDEX idx_referrals_referrer ON subscriptions.referrals(referrer_tenant_id);
CREATE INDEX idx_referrals_referred ON subscriptions.referrals(referred_tenant_id);
CREATE INDEX idx_referrals_status ON subscriptions.referrals(status);
CREATE TRIGGER update_referrals_updated_at
BEFORE UPDATE ON subscriptions.referrals
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
-- Recompensas de referidos
CREATE TABLE IF NOT EXISTS subscriptions.referral_rewards (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
referral_id UUID NOT NULL REFERENCES subscriptions.referrals(id) ON DELETE CASCADE,
type VARCHAR(20) NOT NULL DEFAULT 'free_month',
-- free_month: mes gratis de suscripcion
-- discount: descuento porcentual
months_earned INTEGER DEFAULT 0,
months_used INTEGER DEFAULT 0,
discount_percent INTEGER DEFAULT 0,
expires_at TIMESTAMPTZ,
status VARCHAR(20) DEFAULT 'available',
-- available: disponible para usar
-- used: ya se uso
-- expired: expiro sin usarse
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_referral_rewards_tenant ON subscriptions.referral_rewards(tenant_id);
CREATE INDEX idx_referral_rewards_status ON subscriptions.referral_rewards(status);
CREATE TRIGGER update_referral_rewards_updated_at
BEFORE UPDATE ON subscriptions.referral_rewards
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
-- Funcion para generar codigo de referido unico
CREATE OR REPLACE FUNCTION generate_referral_code(prefix TEXT DEFAULT 'MCH')
RETURNS TEXT AS $$
DECLARE
new_code TEXT;
code_exists BOOLEAN;
BEGIN
LOOP
-- Generar codigo alfanumerico de 6 caracteres
new_code := prefix || '-' || upper(substr(md5(random()::text), 1, 6));
-- Verificar si ya existe
SELECT EXISTS(
SELECT 1 FROM subscriptions.referral_codes WHERE code = new_code
) INTO code_exists;
-- Si no existe, salir del loop
EXIT WHEN NOT code_exists;
END LOOP;
RETURN new_code;
END;
$$ LANGUAGE plpgsql;
-- Funcion para obtener estadisticas de referidos
CREATE OR REPLACE FUNCTION get_referral_stats(p_tenant_id UUID)
RETURNS TABLE (
total_invited INTEGER,
total_converted INTEGER,
total_pending INTEGER,
total_expired INTEGER,
months_earned INTEGER,
months_available INTEGER
) AS $$
BEGIN
RETURN QUERY
SELECT
COUNT(*)::INTEGER as total_invited,
COUNT(*) FILTER (WHERE r.status IN ('converted', 'rewarded'))::INTEGER as total_converted,
COUNT(*) FILTER (WHERE r.status = 'pending')::INTEGER as total_pending,
COUNT(*) FILTER (WHERE r.status = 'expired')::INTEGER as total_expired,
COALESCE(SUM(rw.months_earned), 0)::INTEGER as months_earned,
COALESCE(SUM(rw.months_earned - rw.months_used) FILTER (WHERE rw.status = 'available'), 0)::INTEGER as months_available
FROM subscriptions.referrals r
LEFT JOIN subscriptions.referral_rewards rw ON rw.referral_id = r.id AND rw.tenant_id = p_tenant_id
WHERE r.referrer_tenant_id = p_tenant_id;
END;
$$ LANGUAGE plpgsql;