using System.Text.Json.Serialization; namespace SeaHaven.Services.DTOs { public class VendorRosterDTO { public int CompanyId { get; set; } public string Name { get; set; } = string.Empty; public string? CompanyPhone { get; set; } public string? Email { get; set; } public string? Address { get; set; } public string? City { get; set; } public string? State { get; set; } public string? Zip { get; set; } public string? GoogleMapsUrl { get; set; } public string? Notes { get; set; } public int? AreaId { get; set; } public string? AreaName { get; set; } public string? RowVersion { get; set; } public List Technicians { get; set; } = new(); } public class VendorRosterTechnicianDTO { public int? Id { get; set; } public string? ContactName { get; set; } public string? Phone { get; set; } public string? Email { get; set; } public string? PreferredContact { get; set; } public string? TradeSpecialties { get; set; } public bool IsActive { get; set; } public int TotalJobs { get; set; } } public class RosterTechnicianInputDTO { public int? Id { get; set; } public string? ContactName { get; set; } public string? Phone { get; set; } public string? Email { get; set; } public string? PreferredContact { get; set; } public string? TradeSpecialties { get; set; } public bool? IsActive { get; set; } } public class CreateVendorRosterDTO { public required string Name { get; set; } public string? CompanyPhone { get; set; } public string? Email { get; set; } public string? Address { get; set; } public string? City { get; set; } public string? State { get; set; } public string? Zip { get; set; } public string? GoogleMapsUrl { get; set; } public string? Notes { get; set; } // SH-278: optional Area id; null leaves the new company Unassigned. Assigning // an Area requires the Admin role. public int? AreaId { get; set; } public List Technicians { get; set; } = new(); } public class ReconcileVendorRosterDTO { public required string RowVersion { get; set; } public required string Name { get; set; } public string? CompanyPhone { get; set; } public string? Email { get; set; } public string? Address { get; set; } public string? City { get; set; } public string? State { get; set; } public string? Zip { get; set; } public string? GoogleMapsUrl { get; set; } public string? Notes { get; set; } // SH-278: an omitted areaId leaves the stored Area unchanged, so clients that // predate Area never clear it. An explicit null clears it to Unassigned. private int? _areaId; public int? AreaId { get => _areaId; set { _areaId = value; AreaIdProvided = true; } } [JsonIgnore] public bool AreaIdProvided { get; private set; } public List Technicians { get; set; } = new(); } // Partial, purely additive roster update (SH-250): technicians listed here are // inserted; any technician absent from the payload is never removed, soft-deleted // or deactivated. Company fields are optional; a null field means "unchanged". public class AddTechniciansVendorRosterDTO { public required string RowVersion { get; set; } public List AddTechnicians { get; set; } = new(); public VendorRosterCompanyFieldsDTO? CompanyFields { get; set; } } public class VendorRosterCompanyFieldsDTO { public string? Name { get; set; } public string? CompanyPhone { get; set; } public string? Email { get; set; } public string? Address { get; set; } public string? City { get; set; } public string? State { get; set; } public string? Zip { get; set; } public string? GoogleMapsUrl { get; set; } public string? Notes { get; set; } // SH-278: same presence semantics as ReconcileVendorRosterDTO.AreaId. private int? _areaId; public int? AreaId { get => _areaId; set { _areaId = value; AreaIdProvided = true; } } [JsonIgnore] public bool AreaIdProvided { get; private set; } } // SH-278: raised when a caller without the Admin role tries to change a vendor // company's Area. Mapped to a stable 403 by the API. public sealed class VendorAreaAssignmentForbiddenException : Exception { public VendorAreaAssignmentForbiddenException() : base("Only administrators can assign a vendor company Area.") { } } }