shoc-backend/SeaHaven.Services/Implementation/ContactService.cs
2026-05-14 11:00:12 -05:00

231 lines
8.3 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>
/// Contact service implementation
/// Contains business logic, validation, and orchestration for Contact operations
/// </summary>
public class ContactService : IContactService
{
private readonly IContactDataService _contactDataService;
private readonly ICreateContactValidation _createValidator;
private readonly IUpdateContactValidation _updateValidator;
public ContactService(
IContactDataService contactDataService,
ICreateContactValidation createValidator,
IUpdateContactValidation updateValidator)
{
_contactDataService = contactDataService;
_createValidator = createValidator;
_updateValidator = updateValidator;
}
// Query operations
public async Task<ContactDTO?> GetContactByIdAsync(int id)
{
var contact = await _contactDataService.GetByIdAsync(id);
return contact == null ? null : MapToDTO(contact);
}
public async Task<ContactDTO?> GetContactByIdWithDetailsAsync(int id)
{
var contact = await _contactDataService.GetByIdWithDetailsAsync(id);
return contact == null ? null : MapToDTO(contact);
}
public async Task<IEnumerable<ContactDTO>> GetAllContactsAsync()
{
var contacts = await _contactDataService.GetAllAsync();
return contacts.Select(MapToDTO);
}
public async Task<IEnumerable<ContactDTO>> GetContactsByAccountIdAsync(int accountId)
{
var contacts = await _contactDataService.GetByAccountIdAsync(accountId);
return contacts.Select(MapToDTO);
}
public async Task<IEnumerable<ContactDTO>> GetContactsByTypeAsync(string type)
{
var contacts = await _contactDataService.GetByTypeAsync(type);
return contacts.Select(MapToDTO);
}
public async Task<ContactDTO?> GetContactByEmailAsync(string email)
{
var contact = await _contactDataService.GetByEmailAsync(email);
return contact == null ? null : MapToDTO(contact);
}
// Paged results
public async Task<PagedResult<ContactDTO>> GetContactsPagedAsync(
int page,
int pageSize,
string? search = null,
string? type = null)
{
var (items, totalCount) = await _contactDataService.GetPagedAsync(page, pageSize, search, type);
return new PagedResult<ContactDTO>
{
Items = items.Select(MapToDTO),
TotalCount = totalCount,
Page = page,
PageSize = pageSize
};
}
// Command operations
public async Task<ContactDTO> CreateContactAsync(CreateContactDTO dto, string userId)
{
var validationResult = await _createValidator.ValidateAsync(dto);
if (!validationResult.IsValid)
{
throw new ValidationException(validationResult.Errors);
}
if (await _contactDataService.EmailExistsAsync(dto.Email))
throw new InvalidOperationException($"Email '{dto.Email}' already exists");
var contact = new Contacts
{
FirstName = dto.FirstName,
LastName = dto.LastName,
Email = dto.Email,
PhoneNumber = dto.Phone ?? dto.Mobile,
Title = dto.Title,
ContactType = dto.Type,
AccountId = dto.AccountId,
createdby = userId,
CreatedDate = DateTime.Now
};
var savedContact = await _contactDataService.AddAsync(contact);
return MapToDTO(savedContact);
}
public async Task<ContactDTO> UpdateContactAsync(int id, UpdateContactDTO dto, string userId)
{
var validationResult = await _updateValidator.ValidateAsync(dto);
if (!validationResult.IsValid)
{
throw new ValidationException(validationResult.Errors);
}
var existingContact = await _contactDataService.GetByIdAsync(id);
if (existingContact == null)
throw new KeyNotFoundException($"Contact with ID {id} not found");
if (!string.IsNullOrWhiteSpace(dto.Email) && dto.Email != existingContact.Email)
{
if (await _contactDataService.EmailExistsAsync(dto.Email, id))
throw new InvalidOperationException($"Email '{dto.Email}' already exists");
}
if (!string.IsNullOrWhiteSpace(dto.FirstName))
existingContact.FirstName = dto.FirstName;
if (!string.IsNullOrWhiteSpace(dto.LastName))
existingContact.LastName = dto.LastName;
if (!string.IsNullOrWhiteSpace(dto.Email))
existingContact.Email = dto.Email;
if (dto.Phone != null || dto.Mobile != null)
existingContact.PhoneNumber = dto.Phone ?? dto.Mobile;
if (dto.Title != null)
existingContact.Title = dto.Title;
if (dto.Type != null)
existingContact.ContactType = dto.Type;
if (dto.AccountId.HasValue)
existingContact.AccountId = dto.AccountId;
existingContact.LastModificationTime = DateTime.Now;
await _contactDataService.UpdateAsync(existingContact);
return MapToDTO(existingContact);
}
public async Task DeleteContactAsync(int id, string userId)
{
// Check if exists
if (!await _contactDataService.ExistsAsync(id))
throw new KeyNotFoundException($"Contact with ID {id} not found");
// Business logic: Check if contact is being used (add your logic here)
// For example, check if contact is linked to work orders, etc.
await _contactDataService.DeleteAsync(id);
}
// Validation operations
public async Task<bool> ContactExistsAsync(int id)
{
return await _contactDataService.ExistsAsync(id);
}
public async Task<bool> EmailExistsAsync(string email, int? excludeId = null)
{
return await _contactDataService.EmailExistsAsync(email, excludeId);
}
public async Task<bool> PhoneExistsAsync(string phone, int? excludeId = null)
{
return await _contactDataService.PhoneExistsAsync(phone, excludeId);
}
// Statistics
public async Task<int> GetTotalContactCountAsync()
{
return await _contactDataService.CountAsync();
}
public async Task<int> GetContactCountByAccountAsync(int accountId)
{
return await _contactDataService.CountByAccountIdAsync(accountId);
}
public async Task<Dictionary<string, int>> GetContactCountByTypeAsync()
{
var contacts = await _contactDataService.GetAllAsync();
return contacts
.Where(c => !string.IsNullOrWhiteSpace(c.ContactType))
.GroupBy(c => c.ContactType!)
.ToDictionary(g => g.Key, g => g.Count());
}
// Private mapping methods
private static ContactDTO MapToDTO(Contacts contact)
{
return new ContactDTO
{
Id = contact.Id,
FirstName = contact.FirstName,
LastName = contact.LastName,
Email = contact.Email,
Phone = contact.PhoneNumber,
Mobile = contact.PhoneNumber, // Contacts only has one PhoneNumber field
Title = contact.Title,
Type = contact.ContactType,
AccountId = contact.AccountId,
AccountName = contact.Account?.Name,
CreatedDate = contact.CreatedDate,
CreatedBy = contact.createdby,
ModifiedDate = contact.LastModificationTime,
ModifiedBy = null // Not tracked in FullAuditEntity
};
}
}
}