using FluentValidation; using Data.SeaHavenIndustries.Enums; using SeaHaven.Services.DTOs; namespace SeaHaven.Services.Validation { public interface IWorkOrderBoardCreateValidation : IValidator { } public class WorkOrderBoardCreateValidation : AbstractValidator, IWorkOrderBoardCreateValidation { public WorkOrderBoardCreateValidation() { RuleFor(x => x.WorkOrderType) .IsInEnum().WithMessage("workOrderType is required and must be a valid value.") .Must(t => t != WorkOrderType.AddOn) .WithMessage("workOrderType AddOn is not allowed on create; use isAddOn with a real type."); RuleFor(x => x.SiteCode) .NotEmpty().WithMessage("siteCode is required.") .MaximumLength(32); RuleFor(x => x.TargetWeek) .NotNull().WithMessage("targetWeek is required when scheduleWeekOnly is true.") .When(x => x.ScheduleWeekOnly == true); RuleFor(x => x.Description) .MaximumLength(2000) .When(x => !string.IsNullOrEmpty(x.Description)); RuleFor(x => x.Trade) .MaximumLength(128) .When(x => !string.IsNullOrEmpty(x.Trade)); RuleFor(x => x.PrimaryService) .MaximumLength(128) .When(x => !string.IsNullOrEmpty(x.PrimaryService)); RuleFor(x => x.ServiceNotes) .MaximumLength(4000) .When(x => !string.IsNullOrEmpty(x.ServiceNotes)); RuleFor(x => x.PocName) .MaximumLength(200) .When(x => !string.IsNullOrEmpty(x.PocName)); RuleFor(x => x.PocPhone) .MaximumLength(50) .When(x => !string.IsNullOrEmpty(x.PocPhone)); RuleFor(x => x.PocNotes) .MaximumLength(2000) .When(x => !string.IsNullOrEmpty(x.PocNotes)); RuleFor(x => x.TechPhone) .MaximumLength(50) .When(x => !string.IsNullOrEmpty(x.TechPhone)); RuleFor(x => x.VendorNotes) .MaximumLength(2000) .When(x => !string.IsNullOrEmpty(x.VendorNotes)); RuleFor(x => x.LocationId) .NotNull().WithMessage("locationId is required.") .GreaterThan(0).WithMessage("locationId is required."); RuleFor(x => x.VendorId) .GreaterThan(0) .When(x => x.VendorId.HasValue); RuleFor(x => x.PocContactId) .GreaterThan(0) .When(x => x.PocContactId.HasValue); RuleFor(x => x) .Must(HasPrimaryWhenExtras) .WithMessage("primaryService (or trade) is required when extraServices is provided.") .WithName("extraServices"); RuleForEach(x => x.ExtraServices) .MaximumLength(128) .When(x => x.ExtraServices != null); RuleForEach(x => x.AdditionalContacts) .ChildRules(contact => { contact.RuleFor(c => c.Name) .MaximumLength(200) .When(c => !string.IsNullOrEmpty(c.Name)); contact.RuleFor(c => c.Phone) .MaximumLength(50) .When(c => !string.IsNullOrEmpty(c.Phone)); contact.RuleFor(c => c.Notes) .MaximumLength(2000) .When(c => !string.IsNullOrEmpty(c.Notes)); contact.RuleFor(c => c) .Must(HasNameAndPhoneWhenPresent) .WithMessage("Each additional contact must include a name and phone."); }) .When(x => x.AdditionalContacts != null); } private static bool HasPrimaryWhenExtras(WorkOrderBoardCreateRequestDto request) { var hasExtras = request.ExtraServices != null && request.ExtraServices.Any(s => !string.IsNullOrWhiteSpace(s)); if (!hasExtras) return true; return !string.IsNullOrWhiteSpace(request.PrimaryService) || !string.IsNullOrWhiteSpace(request.Trade); } private static bool HasNameAndPhoneWhenPresent(WorkOrderAdditionalContactDto contact) { var hasName = !string.IsNullOrWhiteSpace(contact.Name); var hasPhone = !string.IsNullOrWhiteSpace(contact.Phone); if (!hasName && !hasPhone) return true; return hasName && hasPhone; } } }