- HERENCIA-SIMCO.md actualizado con directivas v3.7 y v3.8 - Cambios en backend y frontend Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
144 lines
5.0 KiB
PL/PgSQL
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;
|