This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
using LiteCharms.Features.Extensions;
|
||||
using LiteCharms.Features.Models;
|
||||
using LiteCharms.Features.TechShop.Customers.Models;
|
||||
using LiteCharms.Features.TechShop.Extensions;
|
||||
using LiteCharms.Features.TechShop.Postgres;
|
||||
|
||||
namespace LiteCharms.Features.TechShop.Customers;
|
||||
|
||||
public class CustomerService(IDbContextFactory<ShopDbContext> contextFactory)
|
||||
{
|
||||
public async ValueTask<Result<Guid>> CreateCustomerAsync(CreateCustomer request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var customerEmail = request.Email.ToLower().Trim();
|
||||
|
||||
if (await context.Customers.AnyAsync(c => c.Email == customerEmail, cancellationToken))
|
||||
return Result.Fail<Guid>(new Error($"A customer with the email {customerEmail} already exists"));
|
||||
|
||||
var newCustomer = context.Customers.Add(new Entities.Customer
|
||||
{
|
||||
Company = request.Company,
|
||||
Name = request.Name,
|
||||
LastName = request.LastName,
|
||||
Tax = request.Tax,
|
||||
Email = customerEmail,
|
||||
Discord = request.Discord,
|
||||
Slack = request.Slack,
|
||||
LinkedIn = request.LinkedIn,
|
||||
Whatsapp = request.Whatsapp,
|
||||
Website = request.Website,
|
||||
Phone = request.Phone,
|
||||
Address = request.Address,
|
||||
City = request.City,
|
||||
Region = request.Region,
|
||||
Country = request.Country,
|
||||
PostalCode = request.PostalCode,
|
||||
Active = true,
|
||||
});
|
||||
|
||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||
? Result.Ok(newCustomer.Entity.Id)
|
||||
: Result.Fail<Guid>(new Error($"Failed to create customer {customerEmail}"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<Result<Customer>> GetCustomerAsync(Guid customerId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var customer = await context.Customers.FirstOrDefaultAsync(c => c.Id == customerId, cancellationToken);
|
||||
|
||||
return customer is not null
|
||||
? Result.Ok(customer.ToModel())
|
||||
: Result.Fail<Customer>($"Customer not found with id {customerId}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result.Fail<Customer>(new Error(ex.Message).CausedBy(ex));
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<Result<Customer[]>> GetCustomersAsync(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 customers = await context.Customers.AsNoTracking()
|
||||
.OrderByDescending(o => o.CreatedAt)
|
||||
.Where(c => c.CreatedAt >= fromDate && c.CreatedAt <= toDate)
|
||||
.Take(range.MaxRecords)
|
||||
.ToArrayAsync(cancellationToken);
|
||||
|
||||
return customers?.Length > 0
|
||||
? Result.Ok(customers.Select(c => c.ToModel()).ToArray())
|
||||
: Result.Fail<Customer[]>(new Error("No customers found in the specified date range."));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result.Fail<Customer[]>(new Error(ex.Message).CausedBy(ex));
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<Result> UpdateCustomerAsync(UpdateCustomer request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||
|
||||
var customer = await context.Customers.FirstOrDefaultAsync(c => c.Id == request.CustomerId, cancellationToken);
|
||||
|
||||
if (customer is null)
|
||||
return Result.Fail(new Error($"Customer with ID {request.CustomerId} not found."));
|
||||
|
||||
customer.Name = request.Name;
|
||||
customer.LastName = request.LastName;
|
||||
customer.Email = request.Email;
|
||||
customer.Company = request.Company;
|
||||
customer.Address = request.Address;
|
||||
customer.City = request.City;
|
||||
customer.Region = request.Region;
|
||||
customer.Country = request.Country;
|
||||
customer.PostalCode = request.PostalCode;
|
||||
customer.Phone = request.Phone;
|
||||
customer.Tax = request.Tax;
|
||||
customer.City = request.City;
|
||||
customer.Discord = request.Discord;
|
||||
customer.Slack = request.Slack;
|
||||
customer.LinkedIn = request.LinkedIn;
|
||||
customer.Whatsapp = request.Whatsapp;
|
||||
|
||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||
? Result.Ok()
|
||||
: Result.Fail(new Error($"Failed to update the customer {request.CustomerId}."));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using LiteCharms.Features.TechShop.Leads.Entities;
|
||||
using LiteCharms.Features.TechShop.Orders.Entities;
|
||||
using LiteCharms.Features.TechShop.Quotes.Entities;
|
||||
using LiteCharms.Features.TechShop.ShoppingCarts.Entities;
|
||||
|
||||
namespace LiteCharms.Features.TechShop.Customers.Entities;
|
||||
|
||||
[EntityTypeConfiguration<CustomerConfiguration, Customer>]
|
||||
public class Customer : Models.Customer
|
||||
{
|
||||
public virtual ICollection<Lead>? Leads { get; set; }
|
||||
|
||||
public virtual ICollection<Order>? Orders { get; set; }
|
||||
|
||||
public virtual ICollection<Quote>? Quotes { get; set; }
|
||||
|
||||
public virtual ICollection<ShoppingCart>? ShoppingCarts { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace LiteCharms.Features.TechShop.Customers.Entities;
|
||||
|
||||
public class CustomerConfiguration : IEntityTypeConfiguration<Customer>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Customer> builder)
|
||||
{
|
||||
builder.ToTable("Customers");
|
||||
|
||||
builder.HasKey(f => f.Id);
|
||||
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd().HasDefaultValueSql("now()");
|
||||
builder.Property(f => f.UpdatedAt).IsRequired(false).HasDefaultValueSql(null);
|
||||
builder.Property(f => f.Company);
|
||||
builder.Property(f => f.Name).IsRequired();
|
||||
builder.Property(f => f.LastName).IsRequired();
|
||||
builder.Property(f => f.Email).IsRequired();
|
||||
builder.Property(f => f.Tax);
|
||||
builder.Property(f => f.Discord);
|
||||
builder.Property(f => f.Slack);
|
||||
builder.Property(f => f.LinkedIn);
|
||||
builder.Property(f => f.Whatsapp);
|
||||
builder.Property(f => f.Website);
|
||||
builder.Property(f => f.Phone);
|
||||
builder.Property(f => f.Address);
|
||||
builder.Property(f => f.City);
|
||||
builder.Property(f => f.Region);
|
||||
builder.Property(f => f.Country);
|
||||
builder.Property(f => f.PostalCode);
|
||||
builder.Property(f => f.Active).HasDefaultValue(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
namespace LiteCharms.Features.TechShop.Customers.Models;
|
||||
|
||||
public class Customer
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
public DateTime? UpdatedAt { get; set; }
|
||||
|
||||
public string? Company { get; set; }
|
||||
|
||||
public string? Name { get; set; }
|
||||
|
||||
public string? LastName { get; set; }
|
||||
|
||||
public string? Tax { get; set; }
|
||||
|
||||
public string? Email { get; set; }
|
||||
|
||||
public string? Discord { get; set; }
|
||||
|
||||
public string? Slack { get; set; }
|
||||
|
||||
public string? LinkedIn { get; set; }
|
||||
|
||||
public string? Whatsapp { get; set; }
|
||||
|
||||
public string? Website { get; set; }
|
||||
|
||||
public string? Phone { get; set; }
|
||||
|
||||
public string? Address { get; set; }
|
||||
|
||||
public string? City { get; set; }
|
||||
|
||||
public string? Region { get; set; }
|
||||
|
||||
public string? Country { get; set; }
|
||||
|
||||
public string? PostalCode { get; set; }
|
||||
|
||||
public bool Active { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
namespace LiteCharms.Features.TechShop.Customers.Models;
|
||||
|
||||
public record CreateCustomer
|
||||
{
|
||||
public string? Company { get; set; }
|
||||
|
||||
public required string Name { get; set; }
|
||||
|
||||
public required string LastName { get; set; }
|
||||
|
||||
public string? Tax { get; set; }
|
||||
|
||||
public required string Email { get; set; }
|
||||
|
||||
public string? Discord { get; set; }
|
||||
|
||||
public string? Slack { get; set; }
|
||||
|
||||
public string? LinkedIn { get; set; }
|
||||
|
||||
public string? Whatsapp { get; set; }
|
||||
|
||||
public string? Website { get; set; }
|
||||
|
||||
public string? Phone { get; set; }
|
||||
|
||||
public string? Address { get; set; }
|
||||
|
||||
public string? City { get; set; }
|
||||
|
||||
public string? Region { get; set; }
|
||||
|
||||
public string? Country { get; set; }
|
||||
|
||||
public string? PostalCode { get; set; }
|
||||
}
|
||||
|
||||
public record UpdateCustomer
|
||||
{
|
||||
public required Guid CustomerId { get; set; }
|
||||
|
||||
public string? Company { get; set; }
|
||||
|
||||
public string? Name { get; set; }
|
||||
|
||||
public string? LastName { get; set; }
|
||||
|
||||
public string? Tax { get; set; }
|
||||
|
||||
public string? Email { get; set; }
|
||||
|
||||
public string? Discord { get; set; }
|
||||
|
||||
public string? Slack { get; set; }
|
||||
|
||||
public string? LinkedIn { get; set; }
|
||||
|
||||
public string? Whatsapp { get; set; }
|
||||
|
||||
public string? Website { get; set; }
|
||||
|
||||
public string? Phone { get; set; }
|
||||
|
||||
public string? Address { get; set; }
|
||||
|
||||
public string? City { get; set; }
|
||||
|
||||
public string? Region { get; set; }
|
||||
|
||||
public string? Country { get; set; }
|
||||
|
||||
public string? PostalCode { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user