2025-12-23 15:12:57 -03:00
|
|
|
using Dapper;
|
|
|
|
|
using SIGCM.Domain.Entities;
|
|
|
|
|
using SIGCM.Infrastructure.Data;
|
|
|
|
|
|
|
|
|
|
namespace SIGCM.Infrastructure.Repositories;
|
|
|
|
|
|
|
|
|
|
public class ClientRepository
|
|
|
|
|
{
|
|
|
|
|
private readonly IDbConnectionFactory _db;
|
|
|
|
|
|
|
|
|
|
public ClientRepository(IDbConnectionFactory db)
|
|
|
|
|
{
|
|
|
|
|
_db = db;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-06 10:34:06 -03:00
|
|
|
// Búsqueda inteligente redireccionada a Users
|
2025-12-23 15:12:57 -03:00
|
|
|
public async Task<IEnumerable<Client>> SearchAsync(string query)
|
|
|
|
|
{
|
|
|
|
|
using var conn = _db.CreateConnection();
|
|
|
|
|
var sql = @"
|
2026-01-05 10:30:04 -03:00
|
|
|
SELECT TOP 10
|
|
|
|
|
Id,
|
2026-01-06 10:34:06 -03:00
|
|
|
ISNULL(BillingName, Username) as Name,
|
|
|
|
|
ISNULL(BillingTaxId, '') as DniOrCuit,
|
|
|
|
|
Email, Phone, BillingAddress as Address
|
|
|
|
|
FROM Users
|
|
|
|
|
WHERE BillingName LIKE @Query OR BillingTaxId LIKE @Query OR Username LIKE @Query
|
|
|
|
|
ORDER BY BillingName";
|
2025-12-23 15:12:57 -03:00
|
|
|
return await conn.QueryAsync<Client>(sql, new { Query = $"%{query}%" });
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-06 10:34:06 -03:00
|
|
|
// Asegurar existencia (Upsert en la tabla Users)
|
2025-12-23 15:12:57 -03:00
|
|
|
public async Task<int> EnsureClientExistsAsync(string name, string dni)
|
|
|
|
|
{
|
|
|
|
|
using var conn = _db.CreateConnection();
|
|
|
|
|
|
|
|
|
|
var existingId = await conn.ExecuteScalarAsync<int?>(
|
2026-01-06 10:34:06 -03:00
|
|
|
"SELECT Id FROM Users WHERE BillingTaxId = @Dni", new { Dni = dni });
|
2025-12-23 15:12:57 -03:00
|
|
|
|
|
|
|
|
if (existingId.HasValue)
|
|
|
|
|
{
|
2026-01-06 10:34:06 -03:00
|
|
|
await conn.ExecuteAsync("UPDATE Users SET BillingName = @Name WHERE Id = @Id", new { Name = name, Id = existingId });
|
2025-12-23 15:12:57 -03:00
|
|
|
return existingId.Value;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-01-06 10:34:06 -03:00
|
|
|
// Si no existe, creamos un usuario con rol Cliente (sin password por ahora, es solo para gestión de mostrador)
|
2025-12-23 15:12:57 -03:00
|
|
|
var sql = @"
|
2026-01-06 10:34:06 -03:00
|
|
|
INSERT INTO Users (Username, Role, BillingName, BillingTaxId, PasswordHash, MustChangePassword)
|
|
|
|
|
VALUES (@Username, 'Client', @Name, @Dni, 'N/A', 0);
|
2025-12-23 15:12:57 -03:00
|
|
|
SELECT CAST(SCOPE_IDENTITY() as int);";
|
2026-01-06 10:34:06 -03:00
|
|
|
// El username será el DNI para asegurar unicidad si no hay otro dato
|
|
|
|
|
return await conn.QuerySingleAsync<int>(sql, new { Username = dni, Name = name, Dni = dni });
|
2025-12-23 15:12:57 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-06 10:34:06 -03:00
|
|
|
// Obtener todos con estadísticas desde Users
|
2025-12-23 15:12:57 -03:00
|
|
|
public async Task<IEnumerable<dynamic>> GetAllWithStatsAsync()
|
|
|
|
|
{
|
|
|
|
|
using var conn = _db.CreateConnection();
|
|
|
|
|
var sql = @"
|
2026-01-05 10:30:04 -03:00
|
|
|
SELECT
|
2026-01-06 10:34:06 -03:00
|
|
|
u.Id as id,
|
|
|
|
|
ISNULL(u.BillingName, u.Username) as name,
|
|
|
|
|
ISNULL(u.BillingTaxId, 'S/D') as dniOrCuit,
|
|
|
|
|
ISNULL(u.Email, 'Sin correo') as email,
|
|
|
|
|
ISNULL(u.Phone, 'Sin teléfono') as phone,
|
|
|
|
|
(SELECT COUNT(1) FROM Listings l WHERE l.ClientId = u.Id) as totalAds,
|
|
|
|
|
ISNULL((SELECT SUM(AdFee) FROM Listings l WHERE l.ClientId = u.Id), 0) as totalSpent
|
|
|
|
|
FROM Users u
|
|
|
|
|
WHERE Role IN ('Client', 'User') -- Mostramos tanto clientes puros como usuarios web
|
|
|
|
|
ORDER BY name";
|
2025-12-23 15:12:57 -03:00
|
|
|
return await conn.QueryAsync(sql);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-05 10:30:04 -03:00
|
|
|
public async Task UpdateAsync(Client client)
|
2025-12-23 15:12:57 -03:00
|
|
|
{
|
|
|
|
|
using var conn = _db.CreateConnection();
|
2026-01-05 10:30:04 -03:00
|
|
|
var sql = @"
|
2026-01-06 10:34:06 -03:00
|
|
|
UPDATE Users
|
|
|
|
|
SET BillingName = @Name,
|
|
|
|
|
BillingTaxId = @DniOrCuit,
|
2026-01-05 10:30:04 -03:00
|
|
|
Email = @Email,
|
|
|
|
|
Phone = @Phone,
|
2026-01-06 10:34:06 -03:00
|
|
|
BillingAddress = @Address
|
2026-01-05 10:30:04 -03:00
|
|
|
WHERE Id = @Id";
|
|
|
|
|
await conn.ExecuteAsync(sql, client);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<dynamic?> GetClientSummaryAsync(int clientId)
|
|
|
|
|
{
|
|
|
|
|
using var conn = _db.CreateConnection();
|
|
|
|
|
var sql = @"
|
|
|
|
|
SELECT
|
2026-01-06 10:34:06 -03:00
|
|
|
u.Id,
|
|
|
|
|
ISNULL(u.BillingName, u.Username) as Name,
|
|
|
|
|
u.BillingTaxId as DniOrCuit, u.Email, u.Phone, u.BillingAddress as Address,
|
|
|
|
|
(SELECT COUNT(1) FROM Listings WHERE ClientId = u.Id) as TotalAds,
|
|
|
|
|
ISNULL((SELECT SUM(AdFee) FROM Listings WHERE ClientId = u.Id), 0) as TotalInvested,
|
|
|
|
|
(SELECT MAX(CreatedAt) FROM Listings WHERE ClientId = u.Id) as LastAdDate,
|
|
|
|
|
(SELECT COUNT(1) FROM Listings WHERE ClientId = u.Id AND Status = 'Published') as ActiveAds,
|
2026-01-05 10:30:04 -03:00
|
|
|
ISNULL((
|
|
|
|
|
SELECT TOP 1 cat.Name
|
|
|
|
|
FROM Listings l
|
|
|
|
|
JOIN Categories cat ON l.CategoryId = cat.Id
|
2026-01-06 10:34:06 -03:00
|
|
|
WHERE l.ClientId = u.Id
|
2026-01-05 10:30:04 -03:00
|
|
|
GROUP BY cat.Name
|
|
|
|
|
ORDER BY COUNT(l.Id) DESC
|
|
|
|
|
), 'N/A') as PreferredCategory
|
2026-01-06 10:34:06 -03:00
|
|
|
FROM Users u
|
|
|
|
|
WHERE u.Id = @Id";
|
2026-01-05 10:30:04 -03:00
|
|
|
|
|
|
|
|
return await conn.QuerySingleOrDefaultAsync<dynamic>(sql, new { Id = clientId });
|
2025-12-23 15:12:57 -03:00
|
|
|
}
|
|
|
|
|
}
|