155 lines
6.0 KiB
C#
155 lines
6.0 KiB
C#
using LiteCharms.Features.Extensions;
|
|
using LiteCharms.Features.Models;
|
|
using LiteCharms.Features.Shop.Postgres;
|
|
using LiteCharms.Features.Shop.Quotes.Models;
|
|
using static LiteCharms.Features.Extensions.Timezones;
|
|
|
|
namespace LiteCharms.Features.Shop.Quotes;
|
|
|
|
public class QuoteService(IDbContextFactory<ShopDbContext> contextFactory)
|
|
{
|
|
public async ValueTask<Result> AssignQuoteToOrderAsync(Guid quoteId, Guid orderId, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
|
|
|
var quote = await context.Quotes.FirstOrDefaultAsync(o => o.Id == quoteId, cancellationToken);
|
|
|
|
if (quote is null)
|
|
return Result.Fail(new Error($"Quote with id {orderId} not found"));
|
|
|
|
if (!await context.Orders.AnyAsync(q => q.Id == orderId, cancellationToken))
|
|
return Result.Fail(new Error($"Order with id {quoteId} not found"));
|
|
|
|
if (quote.OrderId == orderId)
|
|
return Result.Fail(new Error($"Quote with id {quoteId} is already assigned to order with id {orderId}"));
|
|
|
|
quote.OrderId = orderId;
|
|
|
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
? Result.Ok()
|
|
: Result.Fail(new Error($"Failed to assign quote with id {quoteId} to order with id {orderId}"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
|
}
|
|
}
|
|
|
|
public async ValueTask<Result> AssignQuoteToShoppingCartAsync(Guid quoteId, Guid shoppingCartId, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
|
|
|
var quote = await context.Quotes.FirstOrDefaultAsync(o => o.Id == quoteId, cancellationToken);
|
|
|
|
if (quote is null)
|
|
return Result.Fail(new Error($"Quote with id {quoteId} not found"));
|
|
|
|
if (!await context.ShoppingCarts.AnyAsync(q => q.Id == shoppingCartId, cancellationToken))
|
|
return Result.Fail(new Error($"Shopping Cart with id {shoppingCartId} not found"));
|
|
|
|
quote.ShoppingCartId = shoppingCartId;
|
|
|
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
? Result.Ok()
|
|
: Result.Fail(new Error("Failed to assign quote to shopping cart"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
|
}
|
|
}
|
|
|
|
public async ValueTask<Result<Quote[]>> GetCustomerQuotesAsync(Guid customerId, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
|
|
|
if (!await context.Customers.AnyAsync(c => c.Id == customerId, cancellationToken))
|
|
return Result.Fail<Quote[]>(new Error($"Customer with Id {customerId} does not exist."));
|
|
|
|
var quotes = await context.Quotes.AsNoTracking()
|
|
.Where(q => q.CustomerId == customerId).ToArrayAsync(cancellationToken);
|
|
|
|
return quotes?.Length > 0
|
|
? Result.Ok(quotes.Select(q => q.ToModel()).ToArray())
|
|
: Result.Fail<Quote[]>(new Error($"No quotes found for customer with Id {customerId}."));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Result.Fail<Quote[]>(new Error(ex.Message).CausedBy(ex));
|
|
}
|
|
}
|
|
|
|
public async ValueTask<Result<Quote>> GetQuoteAsync(Guid quoteId, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
|
|
|
var quote = await context.Quotes.AsNoTracking().FirstOrDefaultAsync(q => q.Id == quoteId, cancellationToken);
|
|
|
|
return quote is not null
|
|
? Result.Ok(quote.ToModel())
|
|
: Result.Fail<Quote>(new Error($"Quote with ID {quoteId} not found."));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Result.Fail<Quote>(new Error(ex.Message).CausedBy(ex));
|
|
}
|
|
}
|
|
|
|
public async ValueTask<Result<Quote[]>> GetQuotesAsync(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 quotes = await context.Quotes.AsNoTracking()
|
|
.OrderByDescending(o => o.CreatedAt)
|
|
.Where(o => o.CreatedAt >= fromDate && o.CreatedAt <= toDate)
|
|
.Take(range.MaxRecords)
|
|
.ToArrayAsync(cancellationToken);
|
|
|
|
return quotes?.Length > 0
|
|
? Result.Ok(quotes.Select(o => o.ToModel()).ToArray())
|
|
: Result.Fail<Quote[]>(new Error($"No quotes found for the specified date range {range.From} - {range.To}."));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Result.Fail<Quote[]>(new Error(ex.Message).CausedBy(ex));
|
|
}
|
|
}
|
|
|
|
public async ValueTask<Result> UpdateQuoteStatusAsync(Guid quoteId, QuoteStatus status, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
|
|
|
var quote = await context.Quotes.FirstOrDefaultAsync(q => q.Id == quoteId, cancellationToken);
|
|
|
|
if (quote is null)
|
|
return Result.Fail(new Error("Quote not found."));
|
|
|
|
quote.Status = status;
|
|
quote.UpdatedAt = SouthAfricanTimeZone.UtcNow();
|
|
|
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
? Result.Ok()
|
|
: Result.Fail(new Error("Failed to update quote status."));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
|
}
|
|
}
|
|
}
|