mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 07:13:12 +00:00
* feat(vendors): add directory filters and details API * fix(vendors): preserve omitted status * fix(vendors): align facet filtering * fix(vendors): address directory review findings
207 lines
7.6 KiB
C#
207 lines
7.6 KiB
C#
using Data.SeaHavenIndustries;
|
|
using FluentValidation;
|
|
using SeaHaven.DataServices.Interfaces;
|
|
using SeaHaven.Services.DTOs;
|
|
using SeaHaven.Services.Interfaces;
|
|
using SeaHaven.Services.Validation;
|
|
|
|
namespace SeaHaven.Services.Implementation
|
|
{
|
|
/// <summary>
|
|
/// Vendor service implementation
|
|
/// Contains business logic, validation, and orchestration for Vendor operations
|
|
/// </summary>
|
|
public class VendorService : IVendorService
|
|
{
|
|
private readonly IVendorDataService _vendorDataService;
|
|
private readonly ICreateVendorValidation _createValidator;
|
|
private readonly IUpdateVendorValidation _updateValidator;
|
|
|
|
public VendorService(
|
|
IVendorDataService vendorDataService,
|
|
ICreateVendorValidation createValidator,
|
|
IUpdateVendorValidation updateValidator)
|
|
{
|
|
_vendorDataService = vendorDataService;
|
|
_createValidator = createValidator;
|
|
_updateValidator = updateValidator;
|
|
}
|
|
|
|
public async Task<VendorDTO?> GetVendorByIdAsync(int id)
|
|
{
|
|
var vendor = await _vendorDataService.GetByIdWithDetailsAsync(id);
|
|
return vendor == null ? null : MapToDTO(vendor);
|
|
}
|
|
|
|
public async Task<VendorDTO?> GetVendorByIdWithDetailsAsync(int id)
|
|
{
|
|
var vendor = await _vendorDataService.GetByIdWithDetailsAsync(id);
|
|
return vendor == null ? null : MapToDTO(vendor);
|
|
}
|
|
|
|
public async Task<IEnumerable<VendorDTO>> GetAllVendorsAsync()
|
|
{
|
|
var vendors = await _vendorDataService.GetAllAsync();
|
|
return vendors.Select(MapToDTO);
|
|
}
|
|
|
|
public async Task<PagedResult<VendorDTO>> GetVendorsPagedAsync(
|
|
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)
|
|
{
|
|
var (items, totalCount) = await _vendorDataService.GetPagedAsync(
|
|
page,
|
|
pageSize,
|
|
search,
|
|
isActive,
|
|
companies,
|
|
trades,
|
|
locations,
|
|
jobBuckets);
|
|
return new PagedResult<VendorDTO>
|
|
{
|
|
Items = items.Select(MapToDTO).ToList(),
|
|
TotalCount = totalCount,
|
|
Page = page,
|
|
PageSize = pageSize
|
|
};
|
|
}
|
|
|
|
public async Task<VendorDTO> CreateVendorAsync(CreateVendorDTO dto, string userId)
|
|
{
|
|
var validationResult = await _createValidator.ValidateAsync(dto);
|
|
if (!validationResult.IsValid)
|
|
{
|
|
throw new ValidationException(validationResult.Errors);
|
|
}
|
|
|
|
var vendor = new Vendor
|
|
{
|
|
CompanyName = dto.Name,
|
|
ContactName = dto.ContactName,
|
|
Email = dto.Email,
|
|
Phone = dto.Phone,
|
|
CompanyPhone = dto.CompanyPhone,
|
|
Address = dto.Address,
|
|
City = dto.City,
|
|
State = dto.State,
|
|
Zip = dto.Zipcode,
|
|
TradeSpecialties = dto.TradeSpecialties,
|
|
GoogleMapsUrl = dto.GoogleMapsUrl,
|
|
Notes = dto.Notes,
|
|
IsActive = dto.IsActive,
|
|
CreatedDate = DateTime.UtcNow,
|
|
createdby = userId
|
|
};
|
|
|
|
var created = await _vendorDataService.AddAsync(vendor);
|
|
return MapToDTO(created);
|
|
}
|
|
|
|
public async Task<VendorDTO> UpdateVendorAsync(int id, UpdateVendorDTO dto, string userId)
|
|
{
|
|
var validationResult = await _updateValidator.ValidateAsync(dto);
|
|
if (!validationResult.IsValid)
|
|
{
|
|
throw new ValidationException(validationResult.Errors);
|
|
}
|
|
|
|
var vendor = await _vendorDataService.GetByIdAsync(id);
|
|
if (vendor == null)
|
|
throw new InvalidOperationException($"Vendor with ID {id} not found");
|
|
|
|
if (dto.Name != null) vendor.CompanyName = dto.Name;
|
|
if (dto.ContactName != null) vendor.ContactName = dto.ContactName;
|
|
if (dto.Email != null) vendor.Email = dto.Email;
|
|
if (dto.Phone != null) vendor.Phone = dto.Phone;
|
|
if (dto.CompanyPhone != null) vendor.CompanyPhone = dto.CompanyPhone;
|
|
if (dto.Address != null) vendor.Address = dto.Address;
|
|
if (dto.City != null) vendor.City = dto.City;
|
|
if (dto.State != null) vendor.State = dto.State;
|
|
if (dto.Zipcode != null) vendor.Zip = dto.Zipcode;
|
|
if (dto.TradeSpecialties != null) vendor.TradeSpecialties = dto.TradeSpecialties;
|
|
if (dto.GoogleMapsUrl != null) vendor.GoogleMapsUrl = dto.GoogleMapsUrl;
|
|
if (dto.Notes != null) vendor.Notes = dto.Notes;
|
|
if (dto.IsActive.HasValue) vendor.IsActive = dto.IsActive.Value;
|
|
|
|
vendor.LastModificationTime = DateTime.UtcNow;
|
|
if (int.TryParse(userId, out int userIdInt))
|
|
vendor.LastModifierUserId = userIdInt;
|
|
|
|
await _vendorDataService.UpdateAsync(vendor);
|
|
return MapToDTO(vendor);
|
|
}
|
|
|
|
public async Task DeleteVendorAsync(int id, string userId)
|
|
{
|
|
var vendor = await _vendorDataService.GetByIdAsync(id);
|
|
if (vendor == null)
|
|
throw new InvalidOperationException($"Vendor with ID {id} not found");
|
|
|
|
vendor.IsActive = false;
|
|
vendor.LastModificationTime = DateTime.UtcNow;
|
|
if (int.TryParse(userId, out int userIdInt))
|
|
vendor.LastModifierUserId = userIdInt;
|
|
|
|
await _vendorDataService.UpdateAsync(vendor);
|
|
}
|
|
|
|
public async Task<bool> VendorExistsAsync(int id)
|
|
{
|
|
return await _vendorDataService.ExistsAsync(id);
|
|
}
|
|
|
|
public async Task<int> GetTotalVendorCountAsync()
|
|
{
|
|
return await _vendorDataService.CountAsync();
|
|
}
|
|
|
|
private VendorDTO MapToDTO(Vendor vendor)
|
|
{
|
|
return new VendorDTO
|
|
{
|
|
Id = vendor.Id,
|
|
Name = vendor.CompanyName,
|
|
ContactName = vendor.ContactName,
|
|
Email = vendor.Email,
|
|
Phone = vendor.Phone,
|
|
CompanyPhone = vendor.CompanyPhone,
|
|
Address = vendor.Address,
|
|
City = vendor.City,
|
|
State = vendor.State,
|
|
Zipcode = vendor.Zip,
|
|
TradeSpecialties = vendor.TradeSpecialties,
|
|
GoogleMapsUrl = vendor.GoogleMapsUrl,
|
|
Notes = vendor.Notes,
|
|
IsActive = vendor.IsActive,
|
|
TotalJobs = vendor.Dispatches == null
|
|
? vendor.TotalJobs
|
|
: CountDistinctWorkOrders(vendor)
|
|
};
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
}
|