mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-07 16:19:07 +00:00
221 lines
8.3 KiB
C#
221 lines
8.3 KiB
C#
using Data.SeaHavenIndustries;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using System.Linq.Expressions;
|
|
using SeaHaven.DataServices.Interfaces;
|
|
|
|
namespace SeaHaven.DataServices.Implementation
|
|
{
|
|
public class VendorDataService : IVendorDataService
|
|
{
|
|
private readonly ApplicationDbContext _context;
|
|
|
|
public VendorDataService(ApplicationDbContext context)
|
|
{
|
|
_context = context;
|
|
}
|
|
|
|
public async Task<Vendor?> GetByIdAsync(int id)
|
|
{
|
|
return await _context.Vendors
|
|
.Include(v => v.Dispatches!)
|
|
.ThenInclude(dispatch => dispatch.DispatchWorkOrders)
|
|
.FirstOrDefaultAsync(v => v.Id == id);
|
|
}
|
|
|
|
public async Task<Vendor?> GetByIdWithDetailsAsync(int id)
|
|
{
|
|
return await _context.Vendors
|
|
.Include(v => v.Dispatches!)
|
|
.ThenInclude(dispatch => dispatch.DispatchWorkOrders)
|
|
.FirstOrDefaultAsync(v => v.Id == id);
|
|
}
|
|
|
|
public async Task<IEnumerable<Vendor>> GetAllAsync()
|
|
{
|
|
return await _context.Vendors.ToListAsync();
|
|
}
|
|
|
|
public async Task<(IEnumerable<Vendor> Items, int TotalCount)> GetPagedAsync(
|
|
int page,
|
|
int pageSize,
|
|
string? search = null,
|
|
bool? isActive = true,
|
|
IReadOnlyCollection<string>? companies = null,
|
|
IReadOnlyCollection<string>? trades = null,
|
|
IReadOnlyCollection<string>? locations = null,
|
|
IReadOnlyCollection<string>? jobBuckets = null)
|
|
{
|
|
search ??= "";
|
|
|
|
var query = _context.Vendors.Where(v => v.IsDeleted == null || v.IsDeleted == false);
|
|
|
|
if (isActive.HasValue)
|
|
query = query.Where(v => v.IsActive == isActive.Value);
|
|
|
|
if (!string.IsNullOrWhiteSpace(search))
|
|
{
|
|
var s = search.ToLower();
|
|
query = query.Where(v =>
|
|
(v.CompanyName ?? "").ToLower().Contains(s) ||
|
|
(v.ContactName ?? "").ToLower().Contains(s) ||
|
|
(v.Email ?? "").ToLower().Contains(s) ||
|
|
(v.TradeSpecialties ?? "").ToLower().Contains(s) ||
|
|
(v.City ?? "").ToLower().Contains(s) ||
|
|
(v.State ?? "").ToLower().Contains(s) ||
|
|
(v.Zip ?? "").ToLower().Contains(s));
|
|
}
|
|
|
|
var selectedCompanies = companies?
|
|
.Where(value => !string.IsNullOrWhiteSpace(value))
|
|
.Select(value => value.Trim().ToLower())
|
|
.Distinct()
|
|
.ToArray() ?? Array.Empty<string>();
|
|
if (selectedCompanies.Length > 0)
|
|
query = query.Where(v => selectedCompanies.Contains((v.CompanyName ?? "").ToLower()));
|
|
|
|
var selectedTrades = trades?
|
|
.Where(value => !string.IsNullOrWhiteSpace(value))
|
|
.Select(value => value.Trim().ToLower())
|
|
.Distinct()
|
|
.ToArray() ?? Array.Empty<string>();
|
|
if (selectedTrades.Length > 0)
|
|
query = query.Where(BuildTradePredicate(selectedTrades));
|
|
|
|
var selectedLocations = locations?
|
|
.Where(value => !string.IsNullOrWhiteSpace(value))
|
|
.Select(value => value.Trim().ToLower())
|
|
.Distinct()
|
|
.ToArray() ?? Array.Empty<string>();
|
|
if (selectedLocations.Length > 0)
|
|
query = query.Where(v => selectedLocations.Contains(((v.City ?? "") + ", " + (v.State ?? "")).ToLower()));
|
|
|
|
var selectedJobBuckets = jobBuckets?
|
|
.Where(value => !string.IsNullOrWhiteSpace(value))
|
|
.Select(value => value.Trim().ToLower())
|
|
.Distinct()
|
|
.ToArray() ?? Array.Empty<string>();
|
|
if (selectedJobBuckets.Length > 0)
|
|
{
|
|
var under50 = selectedJobBuckets.Contains("under-50");
|
|
var from50To99 = selectedJobBuckets.Contains("50-99");
|
|
var from100To149 = selectedJobBuckets.Contains("100-149");
|
|
var from150 = selectedJobBuckets.Contains("150-plus");
|
|
|
|
var vendorsWithDispatches = await query
|
|
.Include(v => v.Dispatches!)
|
|
.ThenInclude(dispatch => dispatch.DispatchWorkOrders)
|
|
.OrderByDescending(v => v.Id)
|
|
.ToListAsync();
|
|
var filtered = vendorsWithDispatches.Where(vendor =>
|
|
{
|
|
var totalJobs = CountDistinctWorkOrders(vendor);
|
|
return (under50 && totalJobs < 50) ||
|
|
(from50To99 && totalJobs is >= 50 and <= 99) ||
|
|
(from100To149 && totalJobs is >= 100 and <= 149) ||
|
|
(from150 && totalJobs >= 150);
|
|
}).ToList();
|
|
|
|
return (
|
|
filtered.Skip((page - 1) * pageSize).Take(pageSize),
|
|
filtered.Count);
|
|
}
|
|
|
|
var totalCount = await query.CountAsync();
|
|
var items = await query
|
|
.Include(v => v.Dispatches!)
|
|
.ThenInclude(dispatch => dispatch.DispatchWorkOrders)
|
|
.OrderByDescending(v => v.Id)
|
|
.Skip((page - 1) * pageSize)
|
|
.Take(pageSize)
|
|
.ToListAsync();
|
|
|
|
return (items, totalCount);
|
|
}
|
|
|
|
private static int CountDistinctWorkOrders(Vendor vendor)
|
|
{
|
|
if (vendor.Dispatches == null)
|
|
return 0;
|
|
|
|
return vendor.Dispatches
|
|
.SelectMany(dispatch =>
|
|
{
|
|
var linked = dispatch.DispatchWorkOrders?.Select(item => item.WorkOrderId)
|
|
?? Enumerable.Empty<int>();
|
|
return dispatch.WorkOrderId.HasValue
|
|
? linked.Append(dispatch.WorkOrderId.Value)
|
|
: linked;
|
|
})
|
|
.Distinct()
|
|
.Count();
|
|
}
|
|
|
|
private static Expression<Func<Vendor, bool>> BuildTradePredicate(
|
|
IReadOnlyCollection<string> selectedTrades)
|
|
{
|
|
var vendor = Expression.Parameter(typeof(Vendor), "vendor");
|
|
var specialties = Expression.Coalesce(
|
|
Expression.Property(vendor, nameof(Vendor.TradeSpecialties)),
|
|
Expression.Constant(string.Empty));
|
|
var lowered = Expression.Call(specialties, nameof(string.ToLower), Type.EmptyTypes);
|
|
Expression? body = null;
|
|
|
|
foreach (var trade in selectedTrades)
|
|
{
|
|
var contains = Expression.Call(
|
|
lowered,
|
|
nameof(string.Contains),
|
|
Type.EmptyTypes,
|
|
Expression.Constant(trade));
|
|
body = body == null ? contains : Expression.OrElse(body, contains);
|
|
}
|
|
|
|
return Expression.Lambda<Func<Vendor, bool>>(body ?? Expression.Constant(false), vendor);
|
|
}
|
|
|
|
public async Task<Vendor> AddAsync(Vendor vendor)
|
|
{
|
|
await _context.Vendors.AddAsync(vendor);
|
|
await _context.SaveChangesAsync();
|
|
return vendor;
|
|
}
|
|
|
|
public async Task UpdateAsync(Vendor vendor)
|
|
{
|
|
_context.Vendors.Update(vendor);
|
|
await _context.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task DeleteAsync(int id)
|
|
{
|
|
var entity = await GetByIdAsync(id);
|
|
if (entity != null)
|
|
{
|
|
_context.Vendors.Remove(entity);
|
|
await _context.SaveChangesAsync();
|
|
}
|
|
}
|
|
|
|
public async Task<bool> ExistsAsync(int id)
|
|
{
|
|
return await _context.Vendors.AnyAsync(v => v.Id == id);
|
|
}
|
|
|
|
public async Task<VendorAccessToken?> GetActiveTokenAsync(int vendorId)
|
|
{
|
|
return await _context.VendorAccessTokens
|
|
.FirstOrDefaultAsync(t => t.VendorId == vendorId);
|
|
}
|
|
|
|
public async Task<VendorAccessToken?> GetTokenByStringAsync(string token)
|
|
{
|
|
return await _context.VendorAccessTokens
|
|
.FirstOrDefaultAsync(t => t.Token == token);
|
|
}
|
|
|
|
public async Task<int> CountAsync()
|
|
{
|
|
return await _context.Vendors.CountAsync();
|
|
}
|
|
}
|
|
}
|