mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-01 07:33:14 +00:00
* fix(migrations): make Phase6 completion slide-over migration idempotent Use IF EXISTS / IF COL_LENGTH guards and explicit EF migration metadata so partial environments can apply Phase 6 safely. * feat(locations): add sites options endpoint and vendor contactName Expose GET /api/locations/sites for the WO create wizard and include vendor contactName on dropdown responses. * feat(work-orders): add structured service notes POC and vendor fields Persist primary/extra services, service notes, free-text POC, and tech/vendor notes on create/patch/board/detail instead of embedding them in description. * fix(work-orders): make stacked tip build for CI quality gates * fix(work-orders): align stacked services with CI build * fix(work-orders): keep FlagColor out of structured-notes slice Remove FlagColor model/API/tests from this PR so schema and EF model stay aligned with the structured-fields migration. FlagColor remains in the follow-on PR that adds its migration. --------- Co-authored-by: Arthur Bassi <arthur.winiarski.ranger@outlook.com>
94 lines
3.2 KiB
C#
94 lines
3.2 KiB
C#
using FluentValidation;
|
|
using SeaHaven.Services.DTOs;
|
|
|
|
namespace SeaHaven.Services.Validation
|
|
{
|
|
public interface IWorkOrderBoardCreateValidation : IValidator<WorkOrderBoardCreateRequestDto>
|
|
{
|
|
}
|
|
|
|
public class WorkOrderBoardCreateValidation : AbstractValidator<WorkOrderBoardCreateRequestDto>, IWorkOrderBoardCreateValidation
|
|
{
|
|
public WorkOrderBoardCreateValidation()
|
|
{
|
|
RuleFor(x => x.WorkOrderType)
|
|
.IsInEnum().WithMessage("workOrderType is required and must be a valid value.");
|
|
|
|
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)
|
|
.GreaterThan(0)
|
|
.When(x => x.LocationId.HasValue);
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|