change: updated DurationMinutes SQL calculation

This commit is contained in:
2025-09-05 19:59:40 -06:00
parent d65e62af11
commit e0bac85aaf
6 changed files with 170 additions and 6 deletions

View File

@@ -123,7 +123,39 @@ CREATE OR REPLACE VIEW public.splash_wifi_connection_report
con."NetworkUsage",
con."FirstSeen",
con."LastSeen",
EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric AS "DurationMinutes",
-- Duración estimada: toma el menor entre cálculo por NetworkUsage y período bruto
CASE
WHEN con."LastSeen" >= con."FirstSeen"
THEN
LEAST(
-- Método 1: Duración bruta del período
EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric,
-- Método 2: Estimación basada en NetworkUsage
CASE
-- Si hay uso de red significativo, estimar tiempo activo real
WHEN CAST(con."NetworkUsage" AS bigint) > 1024 THEN -- > 1MB
LEAST(
-- Factor base: 0.1 minutos por MB (ajustable según patrones reales)
(CAST(con."NetworkUsage" AS bigint) / 1024.0) * 0.1,
-- Máximo 30% del período total como tiempo activo real
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.3
)
-- Uso menor: asumir 10% del período como tiempo activo
WHEN CAST(con."NetworkUsage" AS bigint) > 0 THEN
LEAST(
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.1,
480.0 -- Máximo 8 horas por sesión
)
-- Sin uso de red: tiempo mínimo estimado
ELSE
LEAST(
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.05,
30.0 -- Máximo 30 minutos para sesiones sin datos de uso
)
END
)
ELSE 0
END AS "DurationMinutes",
net."Name" AS "NetworkName",
net."MerakiId" AS "MerakiNetworkId",
org."Name" AS "Organization",
@@ -154,7 +186,116 @@ CREATE OR REPLACE VIEW public.splash_wifi_connection_report
-- Conexión histórica, usar la lógica original (días entre conexiones)
con."DaysInactive"
END AS "DaysInactive",
con."PostRecoveryRank" AS "PostRecoveryRank"
con."PostRecoveryRank" AS "PostRecoveryRank",
-- Métricas agregadas por usuario: promedio del menor entre ambos métodos
AVG(
CASE
WHEN con."LastSeen" >= con."FirstSeen"
THEN
LEAST(
-- Método 1: Duración bruta del período
EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric,
-- Método 2: Estimación basada en NetworkUsage
CASE
WHEN CAST(con."NetworkUsage" AS bigint) > 1024 THEN
LEAST(
(CAST(con."NetworkUsage" AS bigint) / 1024.0) * 0.1,
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.3
)
WHEN CAST(con."NetworkUsage" AS bigint) > 0 THEN
LEAST(
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.1,
480.0
)
ELSE
LEAST(
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.05,
30.0
)
END
)
ELSE NULL
END
) OVER (PARTITION BY con."SplashUserId") AS "UserAvgEstimatedMinutes",
-- Categorización basada en el menor entre ambos métodos
CASE
WHEN (CASE
WHEN con."LastSeen" >= con."FirstSeen"
THEN
LEAST(
EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric,
CASE
WHEN CAST(con."NetworkUsage" AS bigint) > 1024 THEN
LEAST(
(CAST(con."NetworkUsage" AS bigint) / 1024.0) * 0.1,
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.3
)
WHEN CAST(con."NetworkUsage" AS bigint) > 0 THEN
LEAST(
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.1,
480.0
)
ELSE
LEAST(
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.05,
30.0
)
END
)
ELSE 0
END) <= 30 THEN 'Quick (<30min)'
WHEN (CASE
WHEN con."LastSeen" >= con."FirstSeen"
THEN
LEAST(
EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric,
CASE
WHEN CAST(con."NetworkUsage" AS bigint) > 1024 THEN
LEAST(
(CAST(con."NetworkUsage" AS bigint) / 1024.0) * 0.1,
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.3
)
WHEN CAST(con."NetworkUsage" AS bigint) > 0 THEN
LEAST(
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.1,
480.0
)
ELSE
LEAST(
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.05,
30.0
)
END
)
ELSE 0
END) BETWEEN 30 AND 120 THEN 'Medium (30min-2h)'
WHEN (CASE
WHEN con."LastSeen" >= con."FirstSeen"
THEN
LEAST(
EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric,
CASE
WHEN CAST(con."NetworkUsage" AS bigint) > 1024 THEN
LEAST(
(CAST(con."NetworkUsage" AS bigint) / 1024.0) * 0.1,
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.3
)
WHEN CAST(con."NetworkUsage" AS bigint) > 0 THEN
LEAST(
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.1,
480.0
)
ELSE
LEAST(
(EXTRACT(epoch FROM con."LastSeen" - con."FirstSeen") / 60::numeric) * 0.05,
30.0
)
END
)
ELSE 0
END) > 120 THEN 'Extended (>2h)'
ELSE 'Invalid'
END AS "SessionDurationCategory"
FROM user_loyalty_calculation con
LEFT JOIN ( SELECT u."Id" AS "UserId",
u."Email",

View File

@@ -48,5 +48,9 @@ namespace SplashPage.Splash.Dto
public DateTime? RecoveryConnectionDate { get; set; }
public int DaysInactive { get; set; }
public int PostRecoveryRank { get; set; }
// New duration calculation fields
public decimal? UserAvgEstimatedMinutes { get; set; }
public string SessionDurationCategory { get; set; }
}
}

View File

@@ -242,7 +242,11 @@ namespace SplashPage.Splash
IsRecoveredUser = entity.IsRecoveredUser,
RecoveryConnectionDate = entity.RecoveryConnectionDate,
DaysInactive = entity.DaysInactive,
PostRecoveryRank = entity.PostRecoveryRank
PostRecoveryRank = entity.PostRecoveryRank,
// New duration calculation fields
UserAvgEstimatedMinutes = entity.UserAvgEstimatedMinutes,
SessionDurationCategory = entity.SessionDurationCategory
}).ToList();
}
}

View File

@@ -32,7 +32,7 @@ namespace SplashPage.Splash
public string NetworkUsage { get; set; }
public DateTime FirstSeen { get; set; }
public DateTime LastSeen { get; set; }
public int DurationMinutes { get; set; }
public decimal DurationMinutes { get; set; }
public string NetworkName { get; set; } = string.Empty;
public string MerakiNetworkId { get; set; } = string.Empty;
public string Organization { get; set; } = string.Empty;
@@ -53,5 +53,9 @@ namespace SplashPage.Splash
public DateTime? RecoveryConnectionDate { get; set; }
public int DaysInactive { get; set; }
public int PostRecoveryRank { get; set; }
// New duration calculation fields
public decimal? UserAvgEstimatedMinutes { get; set; }
public string SessionDurationCategory { get; set; } = string.Empty;
}
}

View File

@@ -52,6 +52,18 @@ namespace SplashPage.Configurations
builder.Property(e => e.ConnectionStatus).HasColumnName("ConnectionStatus").HasMaxLength(50);
builder.Property(e => e.Description).HasColumnName("Description").HasMaxLength(500);
builder.Property(e => e.DeviceIdentifier).HasColumnName("DeviceIdentifier").HasMaxLength(100);
// New fields from SQL view update
builder.Property(e => e.IsRecoveredUser).HasColumnName("IsRecoveredUser");
builder.Property(e => e.RecoveryConnectionDate).HasColumnName("RecoveryConnectionDate");
builder.Property(e => e.DaysInactive).HasColumnName("DaysInactive");
builder.Property(e => e.PostRecoveryRank).HasColumnName("PostRecoveryRank");
builder.Property(e => e.ConnectionRank).HasColumnName("ConnectionRank");
builder.Property(e => e.NetworkId).HasColumnName("NetworkId");
// New duration calculation fields
builder.Property(e => e.UserAvgEstimatedMinutes).HasColumnName("UserAvgEstimatedMinutes").HasColumnType("decimal(18,6)");
builder.Property(e => e.SessionDurationCategory).HasColumnName("SessionDurationCategory").HasMaxLength(50);
}
}
}

View File

@@ -270,8 +270,7 @@ $(function () {
orderable: true,
type: 'num',
render: function (data) {
//return formatDuration(data);
return data ? parseFloat(data).toFixed(1) + ' min' : '0 min';
return formatDuration(data);
}
},
{