shoc-backend/SeaHaven.Services/Helpers/VendorConflictPairs.cs
Alexandre Brandizzi da0b29f769 feat(notifications): serve the Notification Center feed grouped by reason
Adds GET /api/notifications, a per-user read model derived from live
work-order state: Unassigned (grouped, High), No Vendor and Aveta Missing
(per work order, Medium) and Vendor Conflict, account-scoped from claims
and ordered by section severity with a fixed reason tie-break.
2026-09-18 12:40:37 -03:00

34 lines
1.6 KiB
C#

using SeaHaven.DataServices.Models;
namespace SeaHaven.Services.Helpers
{
public static class VendorConflictPairs
{
// Group by vendor so cross-vendor intervals are never compared, then sweep the
// start-sorted windows within a vendor. Every overlapping pair is still emitted;
// output is O(n log n + p) where p is the number of emitted pairs, so the worst
// case stays quadratic only when a single vendor has many mutually-overlapping
// windows, which is inherent to enumerating all such pairs.
public static IEnumerable<(ScheduledDispatchReadModel Left, ScheduledDispatchReadModel Right)> Build(
IReadOnlyList<ScheduledDispatchReadModel> dispatches)
{
foreach (var group in dispatches.GroupBy(dispatch => dispatch.VendorId))
{
var sorted = group.OrderBy(dispatch => dispatch.Start).ToList();
for (var leftIndex = 0; leftIndex < sorted.Count; leftIndex++)
{
var left = sorted[leftIndex];
for (var rightIndex = leftIndex + 1; rightIndex < sorted.Count; rightIndex++)
{
var right = sorted[rightIndex];
// Sorted by start: once a window starts at or after left's end, none that follow can overlap it.
if (right.Start >= left.End)
break;
if (left.WorkOrderId != right.WorkOrderId)
yield return (left, right);
}
}
}
}
}
}