shoc-backend/SeaHaven.DataServices/Models/VendorDirectoryReadModels.cs

148 lines
6.6 KiB
C#
Raw Normal View History

namespace SeaHaven.DataServices.Models
{
public sealed class VendorDirectoryRow
{
public int? VendorId { get; set; }
public int CompanyId { get; set; }
public string? CompanyName { get; set; }
public string? ContactName { get; set; }
public string? Email { get; set; }
public string? Phone { get; set; }
public string? CompanyPhone { get; set; }
public string? PreferredContact { get; set; }
public string? Address { get; set; }
public string? City { get; set; }
public string? State { get; set; }
public string? Zip { get; set; }
public string? TradeSpecialties { get; set; }
public string? GoogleMapsUrl { get; set; }
public string? Notes { get; set; }
public int? AreaId { get; set; }
public bool IsActive { get; set; }
public int TotalJobs { get; set; }
}
// SH-278: Area facet filter for the company directory. AreaIds are already
// resolved against the active catalogue; IncludeUnassigned selects groups with no
// Area (including unlinked legacy vendors). An empty filter matches nobody.
public sealed class VendorAreaFilter
{
public IReadOnlyCollection<int> AreaIds { get; init; } = Array.Empty<int>();
public bool IncludeUnassigned { get; init; }
}
// SH-281 company directory: per-row source for the grouped key query. Carries the
// company group key parts (CompanyId 0 = unlinked; NameKey groups unlinked legacy
// vendors by trimmed case-insensitive CompanyName; VendorKey isolates vendors with
// a missing name by vendor identity) plus one 0/1 match flag per facet filter so a
// group can be selected when any status-eligible row matches that facet.
internal sealed class VendorDirectoryGroupSourceRow
{
public int? VendorId { get; set; }
public int CompanyId { get; set; }
public string NameKey { get; set; } = string.Empty;
public int VendorKey { get; set; }
public int TotalJobs { get; set; }
public int SearchFlag { get; set; }
public int CompanyFlag { get; set; }
public int TradeFlag { get; set; }
public int LocationFlag { get; set; }
public int AreaFlag { get; set; }
}
// SH-281: one row per company group after SQL grouping — the bounded key page.
internal sealed class VendorCompanyGroupKeyRow
{
public int CompanyId { get; set; }
public string NameKey { get; set; } = string.Empty;
public int VendorKey { get; set; }
public int? MaxVendorId { get; set; }
public int TotalJobs { get; set; }
public int SearchMatch { get; set; }
public int CompanyMatch { get; set; }
public int TradeMatch { get; set; }
public int LocationMatch { get; set; }
public int AreaMatch { get; set; }
}
// SH-281: full status-eligible roster row (phase 2) carrying both the vendor's own
// technician fields and the linked VendorCompany canonical fields, so group
// assembly can apply the existing company-canonical projections in memory without
// reapplying search/trade/location filters.
internal sealed class VendorDirectoryRosterRow
{
public int VendorId { get; set; }
public int? CompanyId { get; set; }
public string? CompanyName { get; set; }
public string? CanonicalCompanyName { get; set; }
public string? CompanyEmail { get; set; }
public string? CompanyPhone { get; set; }
public string? CompanyAddress { get; set; }
public string? CompanyCity { get; set; }
public string? CompanyState { get; set; }
public string? CompanyNotes { get; set; }
public int? CompanyAreaId { get; set; }
public string? CompanyAreaName { get; set; }
public string? ContactName { get; set; }
public string? Email { get; set; }
public string? Phone { get; set; }
public string? PreferredContact { get; set; }
public string? VendorCompanyPhone { get; set; }
public string? Address { get; set; }
public string? City { get; set; }
public string? State { get; set; }
public string? Zip { get; set; }
public string? TradeSpecialties { get; set; }
public string? GoogleMapsUrl { get; set; }
public bool IsActive { get; set; }
public int TotalJobs { get; set; }
public string NameKey { get; set; } = string.Empty;
public int VendorKey { get; set; }
}
// SH-281: one technician inside a company group.
public sealed class VendorCompanyGroupTechnician
{
public int Id { get; set; }
public string? ContactName { get; set; }
public string? Email { get; set; }
public string? Phone { get; set; }
public string? PreferredContact { get; set; }
public string? TradeSpecialties { get; set; }
public bool IsActive { get; set; }
public int TotalJobs { get; set; }
}
// SH-281 company directory group: linked vendors collapse by real CompanyId;
// unlinked legacy vendors group by trimmed case-insensitive CompanyName (vendors
// with a missing name stay isolated by vendor identity); companies with zero
// non-deleted technicians remain as company-only groups. Top-level technician
// fields come from the primary technician (newest VendorId, promoted when a
// nonblank search matches a non-primary technician); company fields are
// company-canonical as the existing projections intend; TotalJobs is the sum of
// every status-eligible technician's distinct work-order count.
public sealed class VendorCompanyGroup
{
public int? Id { get; set; }
public int? CompanyId { get; set; }
public string? CompanyName { get; set; }
public string? ContactName { get; set; }
public string? Email { get; set; }
public string? Phone { get; set; }
public string? CompanyPhone { get; set; }
public string? PreferredContact { get; set; }
public string? Address { get; set; }
public string? City { get; set; }
public string? State { get; set; }
public string? Zip { get; set; }
public string? TradeSpecialties { get; set; }
public string? GoogleMapsUrl { get; set; }
public string? Notes { get; set; }
public int? AreaId { get; set; }
public string? AreaName { get; set; }
public bool IsActive { get; set; }
public int TotalJobs { get; set; }
public IReadOnlyList<VendorCompanyGroupTechnician> Technicians { get; set; } = Array.Empty<VendorCompanyGroupTechnician>();
}
}