Files
components/LiteCharms.Features.TechShop/Leads/LeadService.cs
T
Khwezi Mngoma afc984f3bc
continuous-integration/drone/pr Build is passing
Fixed mdf file name hasher
2026-06-01 09:25:46 +02:00

118 lines
4.7 KiB
C#

using LiteCharms.Features.Hasher;
using LiteCharms.Features.Models;
using LiteCharms.Features.TechShop.Extensions;
using LiteCharms.Features.TechShop.Leads.Models;
using LiteCharms.Features.TechShop.Postgres;
namespace LiteCharms.Features.TechShop.Leads;
public class LeadService(IDbContextFactory<ShopDbContext> contextFactory)
{
public async ValueTask<Result<Guid>> CreateLeadAsync(CreateLead request, CancellationToken cancellationToken = default)
{
try
{
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
var newLead = context.Leads.Add(new Entities.Lead
{
WebClickId = request.WebClickId,
AppClickId = request.AppClickId,
Source = request.Source,
ClickId = request.ClickId,
AdGroupId = request.AdGroupId,
AdName = request.AdName,
CampaignId = request.CampaignId,
ClickLocation = request.ClickLocation,
CustomerId = request.CustomerId,
FeedItemId = request.FeedItemId,
Status = LeadStatus.New,
TargetId = request.TargetId,
AttributionHash = HashService.StringToSha256Hash($"{request.ClickId}{request.AppClickId}{request.WebClickId}")
});
return await context.SaveChangesAsync(cancellationToken) > 0
? Result.Ok(newLead.Entity.Id)
: Result.Fail<Guid>(new Error($"Failed to create lead -> Google ClickId: {request.ClickId}, App ClickId: {request.AppClickId}, Web ClickId: {request.WebClickId}"));
}
catch (Exception ex)
{
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
}
}
public async ValueTask<Result<Lead[]>> GetCustomerLeadsAsync(Guid customerId, DateRange range, CancellationToken cancellationToken = default)
{
try
{
var fromDate = range.From.ToDateTime(TimeOnly.MinValue);
var toDate = range.To.ToDateTime(TimeOnly.MaxValue);
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
var leads = await context.Leads.AsNoTracking()
.OrderByDescending(o => o.CreatedAt)
.Where(lead => lead.CustomerId == customerId)
.Where(lead => lead.CreatedAt.Date >= fromDate && lead.CreatedAt.Date <= toDate)
.ToArrayAsync(cancellationToken);
return leads?.Length > 0
? Result.Ok(leads.Select(l => l.ToModel()).ToArray())
: Result.Fail(new Error($"No customer {customerId} leads found for the specified date range {range.From} to {range.To}."));
}
catch (Exception ex)
{
return Result.Fail<Lead[]>(new Error(ex.Message).CausedBy(ex));
}
}
public async ValueTask<Result<Lead[]>> GetLeadsAsync(DateRange range, CancellationToken cancellationToken = default)
{
try
{
var fromDate = range.From.ToDateTime(TimeOnly.MinValue);
var toDate = range.To.ToDateTime(TimeOnly.MaxValue);
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
var leads = await context.Leads.AsNoTracking()
.OrderByDescending(o => o.CreatedAt)
.Where(l => l.CreatedAt.Date >= fromDate && l.CreatedAt.Date <= toDate)
.Take(range.MaxRecords)
.ToArrayAsync(cancellationToken);
return leads?.Length > 0
? Result.Ok(leads.Select(l => l.ToModel()).ToArray())
: Result.Fail(new Error($"No leads found for the specified date range {range.From} to {range.To}."));
}
catch (Exception ex)
{
return Result.Fail(new Error(ex.Message).CausedBy(ex));
}
}
public async ValueTask<Result> UpdateLeadAsync(Guid leadId, LeadStatus status, CancellationToken cancellationToken = default)
{
try
{
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
var lead = await context.Leads.FirstOrDefaultAsync(l => l.Id == leadId, cancellationToken);
if (lead is null)
return Result.Fail(new Error($"Lead with ID {leadId} not found."));
lead.Status = status;
lead.UpdatedAt = DateTime.UtcNow;
return await context.SaveChangesAsync(cancellationToken) > 0
? Result.Ok()
: Result.Fail(new Error($"Failed to update the lead {leadId}."));
}
catch (Exception ex)
{
return Result.Fail(new Error(ex.Message).CausedBy(ex));
}
}
}