The approvals header summed the whole RequestedNTE for work-order-path
requests, while each Pending row shows RequestedNTE - CurrentNTE. When a
work order already had an NTE the header overstated exposure by that NTE.
The header now sums the same Delta the rows display, over the same rows
the Pending tab lists (non-deleted request on a non-deleted dispatch).
The unused duplicate aggregate is removed so one definition remains.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The uplift detail modal needs the work order's assigned dispatcher, the
requesting vendor's technician and the scheduled date. They now resolve
from the same effective work order and vendor as the existing queue row,
so the modal no longer depends on a separate work-order fetch that
account-scoped staff cannot read.
#144 branched from the SH-210 decision-actions commit before the SH-207/SH-208
read-contract corrections landed, so it re-implemented workOrderClosed,
attachmentCount, decidedByName, and pendingExposureTotal with stale semantics:
it projected WorkerOrderNumber (the CRM external id) instead of InternalWONumber
(what the board renders) and summed raw RequestedNTE, which double-counts the new
NTE total on vendor-portal rows across sequential approvals.
Merge origin/feat/ab/sh-210-uplift-decisions (#141, what lands) in and resolve
every conflict in #141's favour, so those fields and their granted-amount
exposure math now come from #141 rather than being duplicated here. Keep only the
two deltas #144 actually adds on top of #141:
- attachmentCount counts non-deleted UpliftEvidence documents on the dispatch,
not every completion document, so completion photos no longer inflate the chip;
- the queue read resolves the effective work order via the primary-plus-linked
(DispatchWorkOrders) convention the sibling reads use, so a dispatch linked only
through that table surfaces its WO context, closed flag, and exposure. Covered
by an in-memory test and a SQLite relational test that proves the fallback
translates to SQL.
Drop the superseded attachment-count test that asserted completion documents
count, and align the relational test to seed InternalWONumber.
GetPagedAsync resolved WorkOrderNumber/Site/Service, WorkOrderClosed, and
WorkOrderId only through Dispatch.WorkOrderId, so a dispatch linked to its
work order solely through DispatchWorkOrders surfaced blank WO context,
workOrderClosed:false, and zero exposure. Resolve the effective work order
using the same primary-plus-linked convention as GetWorkOrderIdForUpliftAsync
and GetApprovedExposureForWorkOrdersAsync via a single work-order lookup.
The Document(...) helper object initializer was under-indented, failing the G3 dotnet format changed-file gate in the architecture and deployable-bundle checks. Reindented to satisfy dotnet format --verify-no-changes.
The approvals queue frontend needs four list-contract additions the read
contract PRs do not carry yet: workOrderClosed so the Approved tab can
disable Revoke on terminal work orders (mirroring the SH-196 revoke
guard), attachmentCount from non-deleted UpliftEvidence documents so the
+N chip renders, decidedByName for the Approved By column, and the
queue-wide pendingExposureTotal for the header total.
Behavior coverage for the new queue read fields so the contract cannot
regress silently: workOrderClosed follows terminal lifecycle statuses,
decidedByName resolves from the deciding user, attachmentCount counts
active dispatch documents, and pendingExposureTotal sums granted amounts
across all pending requests independent of paging.