mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 22:23:12 +00:00
fix(vendors): preserve technician list contract
This commit is contained in:
parent
3eb56a690b
commit
35b647c0f2
7 changed files with 371 additions and 15 deletions
|
|
@ -39,7 +39,7 @@ public class VendorControllerTests
|
|||
var service = new Mock<IVendorService>();
|
||||
using var cancellation = new CancellationTokenSource();
|
||||
var token = cancellation.Token;
|
||||
service.Setup(x => x.GetVendorDirectoryPagedAsync(
|
||||
service.Setup(x => x.GetVendorTechnicianDirectoryPagedAsync(
|
||||
1,
|
||||
10,
|
||||
"clayton",
|
||||
|
|
@ -53,7 +53,7 @@ public class VendorControllerTests
|
|||
|
||||
await NewController(service).GetVendorList(search: "clayton", cancellationToken: token);
|
||||
|
||||
service.Verify(x => x.GetVendorDirectoryPagedAsync(
|
||||
service.Verify(x => x.GetVendorTechnicianDirectoryPagedAsync(
|
||||
1,
|
||||
10,
|
||||
"clayton",
|
||||
|
|
@ -63,6 +63,175 @@ public class VendorControllerTests
|
|||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
token), Times.Once);
|
||||
service.Verify(x => x.GetVendorCompanyDirectoryPagedAsync(
|
||||
It.IsAny<int>(),
|
||||
It.IsAny<int>(),
|
||||
It.IsAny<string?>(),
|
||||
It.IsAny<bool?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<CancellationToken>()), Times.Never);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetVendorList_ReturnsIndividualTechnicianRowsWithoutGroupedTechnicians()
|
||||
{
|
||||
var service = new Mock<IVendorService>();
|
||||
service.Setup(x => x.GetVendorTechnicianDirectoryPagedAsync(
|
||||
It.IsAny<int>(),
|
||||
It.IsAny<int>(),
|
||||
It.IsAny<string?>(),
|
||||
It.IsAny<bool?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new PagedResult<VendorDirectoryItemDTO>
|
||||
{
|
||||
Items = new List<VendorDirectoryItemDTO>
|
||||
{
|
||||
new() { Id = 7, CompanyId = 3, CompanyName = "Gateway Plumbing", ContactName = "Tech A" },
|
||||
new() { Id = 9, CompanyId = 3, CompanyName = "Gateway Plumbing", ContactName = "Tech B" }
|
||||
},
|
||||
TotalCount = 2,
|
||||
Page = 1,
|
||||
PageSize = 10
|
||||
});
|
||||
|
||||
var result = await NewController(service).GetVendorList();
|
||||
|
||||
var ok = result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var paged = ok.Value.Should().BeOfType<Pagination_DTO>().Subject;
|
||||
var rows = ((System.Collections.IEnumerable)paged.Data!).Cast<object>().ToList();
|
||||
|
||||
// Legacy contract: same-company technicians stay as distinct top-level rows
|
||||
// carrying their own vendor ids, and the response shape has no grouped
|
||||
// Technicians property.
|
||||
rows.Should().HaveCount(2);
|
||||
rows.Select(r => r.GetType().GetProperty("Id")!.GetValue(r)).Should().BeEquivalentTo(new[] { 7, 9 });
|
||||
rows.Should().OnlyContain(r => r.GetType().GetProperty("Technicians") == null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetVendorList_PreservesLegacyPageSizeAboveGroupedDirectoryBound()
|
||||
{
|
||||
var service = new Mock<IVendorService>();
|
||||
service.Setup(x => x.GetVendorTechnicianDirectoryPagedAsync(
|
||||
1,
|
||||
500,
|
||||
It.IsAny<string?>(),
|
||||
It.IsAny<bool?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new PagedResult<VendorDirectoryItemDTO> { TotalCount = 420, Page = 1, PageSize = 500 });
|
||||
|
||||
var result = await NewController(service).GetVendorList(page: 1, pageSize: 500);
|
||||
|
||||
var ok = result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var paged = ok.Value.Should().BeOfType<Pagination_DTO>().Subject;
|
||||
paged.PageSize.Should().Be(500);
|
||||
paged.TotalPages.Should().Be(1);
|
||||
service.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetVendorDirectoryList_DelegatesToCompanyDirectoryServiceWithNestedTechnicians()
|
||||
{
|
||||
var service = new Mock<IVendorService>();
|
||||
using var cancellation = new CancellationTokenSource();
|
||||
var token = cancellation.Token;
|
||||
service.Setup(x => x.GetVendorCompanyDirectoryPagedAsync(
|
||||
1,
|
||||
10,
|
||||
"clayton",
|
||||
true,
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
token))
|
||||
.ReturnsAsync(new PagedResult<VendorDirectoryItemDTO>
|
||||
{
|
||||
Items = new List<VendorDirectoryItemDTO>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Id = 9,
|
||||
CompanyId = 3,
|
||||
CompanyName = "Gateway Plumbing",
|
||||
Email = "company@gatewayplumbing.example",
|
||||
TotalJobs = 6,
|
||||
Technicians = new List<VendorDirectoryTechnicianDTO>
|
||||
{
|
||||
new() { Id = 7, ContactName = "Tech A", Email = "tech.a@example.com" },
|
||||
new() { Id = 9, ContactName = "Tech B", Email = "tech.b@example.com" }
|
||||
}
|
||||
}
|
||||
},
|
||||
TotalCount = 1,
|
||||
Page = 1,
|
||||
PageSize = 10
|
||||
});
|
||||
|
||||
var result = await NewController(service).GetVendorDirectoryList(search: "clayton", cancellationToken: token);
|
||||
|
||||
var ok = result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var paged = ok.Value.Should().BeOfType<Pagination_DTO>().Subject;
|
||||
var company = ((System.Collections.IEnumerable)paged.Data!).Cast<object>().Single();
|
||||
|
||||
// SH-281: company row with nested technicians; top-level Email stays the
|
||||
// company email while technician emails stay on the nested rows.
|
||||
company.GetType().GetProperty("Email")!.GetValue(company).Should().Be("company@gatewayplumbing.example");
|
||||
var technicians = (System.Collections.IEnumerable)company.GetType().GetProperty("Technicians")!.GetValue(company)!;
|
||||
technicians.Cast<object>().Select(t => t.GetType().GetProperty("Id")!.GetValue(t))
|
||||
.Should().BeEquivalentTo(new[] { 7, 9 });
|
||||
technicians.Cast<object>().Select(t => t.GetType().GetProperty("Email")!.GetValue(t))
|
||||
.Should().BeEquivalentTo(new[] { "tech.a@example.com", "tech.b@example.com" });
|
||||
|
||||
service.Verify(x => x.GetVendorCompanyDirectoryPagedAsync(
|
||||
1,
|
||||
10,
|
||||
"clayton",
|
||||
true,
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
token), Times.Once);
|
||||
service.Verify(x => x.GetVendorTechnicianDirectoryPagedAsync(
|
||||
It.IsAny<int>(),
|
||||
It.IsAny<int>(),
|
||||
It.IsAny<string?>(),
|
||||
It.IsAny<bool?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<CancellationToken>()), Times.Never);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VendorDirectoryEndpoints_AdvertiseDistinctCompatibilityAndCompanyRoutes()
|
||||
{
|
||||
var legacyRoutes = typeof(VendorController)
|
||||
.GetMethod(nameof(VendorController.GetVendorList))!
|
||||
.GetCustomAttributes(typeof(HttpGetAttribute), inherit: false)
|
||||
.Cast<HttpGetAttribute>()
|
||||
.Select(attribute => attribute.Template);
|
||||
var companyRoutes = typeof(VendorController)
|
||||
.GetMethod(nameof(VendorController.GetVendorDirectoryList))!
|
||||
.GetCustomAttributes(typeof(HttpGetAttribute), inherit: false)
|
||||
.Cast<HttpGetAttribute>()
|
||||
.Select(attribute => attribute.Template);
|
||||
|
||||
legacyRoutes.Should().BeEquivalentTo("GetVendorList");
|
||||
companyRoutes.Should().BeEquivalentTo("GetVendorDirectoryList");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ public class VendorServiceTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetVendorDirectoryPaged_ForwardsCancellationToken()
|
||||
public async Task GetVendorCompanyDirectoryPaged_ForwardsCancellationTokenAndMapsNestedTechnicians()
|
||||
{
|
||||
var data = new Mock<IVendorDataService>();
|
||||
using var cancellation = new CancellationTokenSource();
|
||||
|
|
@ -175,6 +175,7 @@ public class VendorServiceTests
|
|||
CompanyId = 3,
|
||||
CompanyName = "Gateway Plumbing",
|
||||
ContactName = "Primary Tech",
|
||||
Email = "company@gatewayplumbing.example",
|
||||
TotalJobs = 4,
|
||||
Technicians = new[]
|
||||
{
|
||||
|
|
@ -190,14 +191,16 @@ public class VendorServiceTests
|
|||
}
|
||||
}.AsEnumerable().ToList(), 1));
|
||||
|
||||
var result = await NewService(data).GetVendorDirectoryPagedAsync(
|
||||
var result = await NewService(data).GetVendorCompanyDirectoryPagedAsync(
|
||||
1,
|
||||
12,
|
||||
"clayton",
|
||||
true,
|
||||
cancellationToken: token);
|
||||
|
||||
result.Items.Single().Technicians.Should().ContainSingle()
|
||||
var group = result.Items.Single();
|
||||
group.Email.Should().Be("company@gatewayplumbing.example");
|
||||
group.Technicians.Should().ContainSingle()
|
||||
.Which.Email.Should().Be("primary@example.com");
|
||||
|
||||
data.Verify(x => x.GetCompanyDirectoryPagedAsync(
|
||||
|
|
@ -213,7 +216,7 @@ public class VendorServiceTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetVendorDirectoryPaged_BoundsPageInputsBeforeBuildingTheGroupKeyPredicate()
|
||||
public async Task GetVendorCompanyDirectoryPaged_BoundsPageInputsBeforeBuildingTheGroupKeyPredicate()
|
||||
{
|
||||
var data = new Mock<IVendorDataService>();
|
||||
data.Setup(x => x.GetCompanyDirectoryPagedAsync(
|
||||
|
|
@ -228,13 +231,62 @@ public class VendorServiceTests
|
|||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((new List<VendorCompanyGroup>(), 0));
|
||||
|
||||
var result = await NewService(data).GetVendorDirectoryPagedAsync(0, 500);
|
||||
var result = await NewService(data).GetVendorCompanyDirectoryPagedAsync(0, 500);
|
||||
|
||||
result.Page.Should().Be(1);
|
||||
result.PageSize.Should().Be(100);
|
||||
data.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetVendorTechnicianDirectoryPaged_ForwardsRawPaginationAndCancellationToken()
|
||||
{
|
||||
var data = new Mock<IVendorDataService>();
|
||||
using var cancellation = new CancellationTokenSource();
|
||||
var token = cancellation.Token;
|
||||
data.Setup(x => x.GetDirectoryPagedAsync(
|
||||
2,
|
||||
500,
|
||||
"clayton",
|
||||
true,
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
token))
|
||||
.ReturnsAsync((new[]
|
||||
{
|
||||
new VendorDirectoryRow { VendorId = 7, CompanyId = 3, CompanyName = "Gateway Plumbing", ContactName = "Tech A" },
|
||||
new VendorDirectoryRow { VendorId = 9, CompanyId = 3, CompanyName = "Gateway Plumbing", ContactName = "Tech B" }
|
||||
}.AsEnumerable().ToList(), 2));
|
||||
|
||||
var result = await NewService(data).GetVendorTechnicianDirectoryPagedAsync(
|
||||
2,
|
||||
500,
|
||||
"clayton",
|
||||
true,
|
||||
cancellationToken: token);
|
||||
|
||||
// Legacy pagination semantics: page and pageSize (including 500) pass through
|
||||
// unclamped, and same-company technicians stay as distinct rows.
|
||||
result.Page.Should().Be(2);
|
||||
result.PageSize.Should().Be(500);
|
||||
result.Items.Should().HaveCount(2);
|
||||
result.Items.Select(v => v.Id).Should().BeEquivalentTo(new[] { 7, 9 });
|
||||
result.Items.Should().OnlyContain(v => v.Technicians.Count == 0);
|
||||
|
||||
data.Verify(x => x.GetDirectoryPagedAsync(
|
||||
2,
|
||||
500,
|
||||
"clayton",
|
||||
true,
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
It.IsAny<IReadOnlyCollection<string>?>(),
|
||||
token), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetVendorById_CountsDistinctHistoricalWorkOrders()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
// SH-198 legacy per-technician directory contract. Existing consumers depend
|
||||
// on one row per technician (no grouped Technicians) and on raw pagination
|
||||
// semantics, including pageSize values above the grouped-directory bound.
|
||||
[HttpGet("GetVendorList")]
|
||||
public async Task<IActionResult> GetVendorList(
|
||||
string? search = "",
|
||||
|
|
@ -38,7 +41,65 @@ namespace Api.SeaHavenIndustries.Controllers
|
|||
[FromQuery] string[]? jobBuckets = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var pagedResult = await _vendorService.GetVendorDirectoryPagedAsync(
|
||||
var pagedResult = await _vendorService.GetVendorTechnicianDirectoryPagedAsync(
|
||||
page,
|
||||
pageSize,
|
||||
search,
|
||||
isActive,
|
||||
companies,
|
||||
trades,
|
||||
locations,
|
||||
jobBuckets,
|
||||
cancellationToken);
|
||||
|
||||
var data = pagedResult.Items.Select(v => new
|
||||
{
|
||||
v.Id,
|
||||
CompanyName = v.CompanyName,
|
||||
v.CompanyId,
|
||||
v.ContactName,
|
||||
v.Email,
|
||||
v.Phone,
|
||||
v.CompanyPhone,
|
||||
v.PreferredContact,
|
||||
v.Address,
|
||||
v.City,
|
||||
v.State,
|
||||
Zip = v.Zipcode,
|
||||
v.TradeSpecialties,
|
||||
v.GoogleMapsUrl,
|
||||
v.Notes,
|
||||
v.IsActive,
|
||||
v.TotalJobs
|
||||
});
|
||||
|
||||
return Ok(new Pagination_DTO
|
||||
{
|
||||
Data = data,
|
||||
PageNumber = page,
|
||||
PageSize = pageSize,
|
||||
TotalCount = pagedResult.TotalCount,
|
||||
TotalPages = (int)Math.Ceiling(pagedResult.TotalCount / (double)pageSize)
|
||||
});
|
||||
}
|
||||
|
||||
// SH-281 company-grouped directory: one row per company with the full
|
||||
// status-eligible technician roster nested under Technicians and bounded
|
||||
// page sizes. Top-level Email is the company email; technician emails stay
|
||||
// on the nested rows.
|
||||
[HttpGet("GetVendorDirectoryList")]
|
||||
public async Task<IActionResult> GetVendorDirectoryList(
|
||||
string? search = "",
|
||||
int page = 1,
|
||||
int pageSize = 10,
|
||||
bool? isActive = true,
|
||||
[FromQuery] string[]? companies = null,
|
||||
[FromQuery] string[]? trades = null,
|
||||
[FromQuery] string[]? locations = null,
|
||||
[FromQuery] string[]? jobBuckets = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var pagedResult = await _vendorService.GetVendorCompanyDirectoryPagedAsync(
|
||||
page,
|
||||
pageSize,
|
||||
search,
|
||||
|
|
|
|||
|
|
@ -35,8 +35,9 @@ namespace SeaHaven.DataServices.Interfaces
|
|||
IReadOnlyCollection<string>? locations = null,
|
||||
IReadOnlyCollection<string>? jobBuckets = null);
|
||||
|
||||
// Compatibility path for existing per-technician consumers and behavior
|
||||
// tests. Vendor/GetVendorList uses the company-grouped path below.
|
||||
// Compatibility path for existing per-technician consumers (GetVendorList)
|
||||
// and behavior tests. GetVendorDirectoryList uses the company-grouped path
|
||||
// below.
|
||||
Task<(IReadOnlyList<VendorDirectoryRow> Items, int TotalCount)> GetDirectoryPagedAsync(
|
||||
int page,
|
||||
int pageSize,
|
||||
|
|
|
|||
|
|
@ -21,8 +21,11 @@ namespace SeaHaven.Services.DTOs
|
|||
public bool IsActive { get; set; }
|
||||
}
|
||||
|
||||
// SH-281 company directory row. Id is the primary technician's vendor id (null
|
||||
// for company-only groups that have zero technicians); CompanyId is populated for
|
||||
// Shared directory row. On the SH-198 legacy per-technician path (GetVendorList)
|
||||
// Id is the technician's own vendor id and Technicians stays empty — the legacy
|
||||
// response shape does not project it. On the SH-281 company-grouped path
|
||||
// (GetVendorDirectoryList) Id is the primary technician's vendor id (null for
|
||||
// company-only groups that have zero technicians); CompanyId is populated for
|
||||
// linked and company-only groups. Technicians carries the full status-eligible
|
||||
// roster of the company group.
|
||||
public class VendorDirectoryItemDTO
|
||||
|
|
|
|||
|
|
@ -95,7 +95,63 @@ namespace SeaHaven.Services.Implementation
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<PagedResult<VendorDirectoryItemDTO>> GetVendorDirectoryPagedAsync(
|
||||
// SH-198 legacy per-technician directory contract (GetVendorList): raw
|
||||
// pagination semantics are part of the compatibility surface, so pageSize
|
||||
// is forwarded unclamped.
|
||||
public async Task<PagedResult<VendorDirectoryItemDTO>> GetVendorTechnicianDirectoryPagedAsync(
|
||||
int page,
|
||||
int pageSize,
|
||||
string? search = null,
|
||||
bool? isActive = true,
|
||||
IReadOnlyCollection<string>? companies = null,
|
||||
IReadOnlyCollection<string>? trades = null,
|
||||
IReadOnlyCollection<string>? locations = null,
|
||||
IReadOnlyCollection<string>? jobBuckets = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var (items, totalCount) = await _vendorDataService.GetDirectoryPagedAsync(
|
||||
page,
|
||||
pageSize,
|
||||
search,
|
||||
isActive,
|
||||
companies,
|
||||
trades,
|
||||
locations,
|
||||
jobBuckets,
|
||||
cancellationToken);
|
||||
|
||||
return new PagedResult<VendorDirectoryItemDTO>
|
||||
{
|
||||
Items = items.Select(MapToDirectoryItem).ToList(),
|
||||
TotalCount = totalCount,
|
||||
Page = page,
|
||||
PageSize = pageSize
|
||||
};
|
||||
}
|
||||
|
||||
private static VendorDirectoryItemDTO MapToDirectoryItem(VendorDirectoryRow row) => new()
|
||||
{
|
||||
Id = row.VendorId,
|
||||
CompanyId = row.CompanyId == 0 ? null : row.CompanyId,
|
||||
CompanyName = row.CompanyName,
|
||||
ContactName = row.ContactName,
|
||||
Email = row.Email,
|
||||
Phone = row.Phone,
|
||||
CompanyPhone = row.CompanyPhone,
|
||||
PreferredContact = row.PreferredContact,
|
||||
Address = row.Address,
|
||||
City = row.City,
|
||||
State = row.State,
|
||||
Zipcode = row.Zip,
|
||||
TradeSpecialties = row.TradeSpecialties,
|
||||
GoogleMapsUrl = row.GoogleMapsUrl,
|
||||
Notes = row.Notes,
|
||||
IsActive = row.IsActive,
|
||||
TotalJobs = row.TotalJobs
|
||||
};
|
||||
|
||||
// SH-281 company-grouped directory (GetVendorDirectoryList).
|
||||
public async Task<PagedResult<VendorDirectoryItemDTO>> GetVendorCompanyDirectoryPagedAsync(
|
||||
int page,
|
||||
int pageSize,
|
||||
string? search = null,
|
||||
|
|
|
|||
|
|
@ -17,8 +17,22 @@ namespace SeaHaven.Services.Interfaces
|
|||
IReadOnlyCollection<string>? locations = null,
|
||||
IReadOnlyCollection<string>? jobBuckets = null);
|
||||
|
||||
// SH-198 vendor directory: per-technician rows UNION company-only rows.
|
||||
Task<PagedResult<VendorDirectoryItemDTO>> GetVendorDirectoryPagedAsync(
|
||||
// SH-198 legacy vendor directory contract backing GetVendorList: one row per
|
||||
// technician (per-technician rows UNION company-only rows), raw pagination.
|
||||
Task<PagedResult<VendorDirectoryItemDTO>> GetVendorTechnicianDirectoryPagedAsync(
|
||||
int page,
|
||||
int pageSize,
|
||||
string? search = null,
|
||||
bool? isActive = true,
|
||||
IReadOnlyCollection<string>? companies = null,
|
||||
IReadOnlyCollection<string>? trades = null,
|
||||
IReadOnlyCollection<string>? locations = null,
|
||||
IReadOnlyCollection<string>? jobBuckets = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
// SH-281 company directory backing GetVendorDirectoryList: company-grouped
|
||||
// rows with nested technicians and bounded page sizes.
|
||||
Task<PagedResult<VendorDirectoryItemDTO>> GetVendorCompanyDirectoryPagedAsync(
|
||||
int page,
|
||||
int pageSize,
|
||||
string? search = null,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue