Commit graph

164 commits

Author SHA1 Message Date
Alexandre Brandizzi
2c8ffaf10e
Merge pull request #173 from Sea-Haven-Industries/fix/ab/sh-383-media-contract
Some checks are pending
Backend CI / Build and test (push) Waiting to run
Backend CI / architecture (push) Waiting to run
Backend CI / review (push) Waiting to run
Backend CI / ci-complete (push) Blocked by required conditions
fix(media): lift the 1 MB proxy body cap and apply the SH-116 media contract
2026-09-25 06:02:21 +00:00
Alexandre Brandizzi
c1ed5dc98d
Merge pull request #181 from Sea-Haven-Industries/fix/ab/sh-400-vendor-readonly-uplifts
Keep work-order uplift requests read-only in the Vendor Portal
2026-09-25 05:58:38 +00:00
Alexandre Brandizzi
203fc92e4a
Merge pull request #172 from Sea-Haven-Industries/fix/ab/sh-391-adv-search-date-range
fix(board-search): make the Advanced Filters date range narrow results (SH-391)
2026-09-25 05:53:42 +00:00
Alexandre Brandizzi
e02f9774dc Keep work-order uplift requests read-only in the Vendor Portal
A vendor could withdraw (or cancel) an uplift a dispatcher raised from the work
order. Withdraw and its cancel alias now refuse requests with createdby set,
using the portal's not-found response, and the portal read model reports
RaisedByVendor so the portal can hide Revise and Withdraw on those requests.
2026-09-25 02:52:03 -03:00
Alexandre Brandizzi
eb2b442775 fix(uplifts): one per-path uplift amount for queue, approval and exposure
Work-order requests store the requested increase in RequestedNTE; vendor
portal requests store the requested NTE total. The queue Delta, the
pending and approved exposure totals, the work-order uplift list, the
board summary and the notification Delta now all read one definition
(UpliftAmount) that honours both meanings and translates to SQL.

Approving a work-order request now adds its increase to the dispatch NTE
instead of replacing the NTE with the increase; vendor requests still end
at their requested total.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 02:32:58 -03:00
Alexandre Brandizzi
f40ad7c1ef fix(uplifts): pending exposure header sums the row deltas
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>
2026-09-25 02:10:41 -03:00
Alexandre Brandizzi
f3ef11b504 Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	Api.SeaHavenIndustries/Controllers/VendorPortalController.cs
#	SeaHaven.Services/Implementation/VendorPortalService.cs
2026-09-24 23:05:17 -03:00
Alexandre Brandizzi
24ad21d7f2 Merge remote-tracking branch 'origin/main' into lane/sh-387 2026-09-24 22:25:54 -03:00
Alexandre Brandizzi
7b7df4463e
Merge pull request #174 from Sea-Haven-Industries/fix/ab/sh-393-uplift-scope
Some checks are pending
Backend CI / Build and test (push) Waiting to run
Backend CI / architecture (push) Waiting to run
Backend CI / review (push) Waiting to run
Backend CI / ci-complete (push) Blocked by required conditions
fix(uplifts): uplifts created from a work order show on that work order (SH-393)
2026-09-25 00:54:42 +00:00
Alexandre Brandizzi
e15de6e90b fix(media): enforce the per-work-order photo/video limit across both surfaces
The 10-photo / 3-video limit only counted dispatcher attachments, so vendor
portal uploads could push a work order past it (and vice versa). Count the
work order's current vendor documents alongside its attachments on both the
dispatcher media endpoint and the vendor portal. A new completion version
does not count the version it replaces.
2026-09-24 21:27:01 -03:00
Alexandre Brandizzi
89376e99e4 fix(uplifts): resolve work-order uplifts through owned dispatches (SH-393)
Board create left the new primary dispatch with no WorkOrderId, so uplifts
created on those work orders were written to a dispatch the work order's
uplift reads never resolve: not listed, allowance never consumed, queue WO
number blank. The same orphan made ApptDate/vendor patches fail with
"A primary dispatch is required".

- Board create backfills Dispatch.WorkOrderId after the first save.
- Uplift create resolves its dispatch through the read-side scope
  (non-deleted, owned or linked); otherwise the stable
  "no primary dispatch" error.
- Data-only migration assigns existing orphaned primaries to the single
  work order naming them primary; idempotent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 21:22:13 -03:00
Alexandre Brandizzi
dc251c42d4 fix(media): apply SH-116 media contract and lift the 1 MB proxy body cap
The Elastic Beanstalk nginx proxy kept its 1 MB default body limit, so every
media upload over ~1 MB got an nginx 413 before reaching the API. Ship a
.platform nginx override (120M) in the bundle and assert it in the bundle
contract.

Apply the client-confirmed contract: photos up to 10 MB (JPEG/PNG/HEIC),
videos up to 100 MB (MP4/MOV), at most 10 photos and 3 videos per work order,
with stable generic rejection messages. The request ceiling (110 MB) sits
between the per-kind caps and the proxy so oversize files get the generic
message. The vendor portal accepts the same photo/video types and caps.
2026-09-24 20:52:44 -03:00
Alexandre Brandizzi
028908bd5a fix(board-search): make the Advanced Filters date range narrow results (SH-391)
An explicit date range let every undated, non-terminal work order through,
so Unassigned plus a range still returned all ~1,780 unassigned rows. The
range now matches Schedule On, or the Target Week for week-only rows
(overlap), the same date the weekly board groups by. Undated rows are added
only when the caller sends includeDateless, which the client uses for
searches with no range selected and for the Unassigned queue.
2026-09-24 20:51:44 -03:00
Alexandre Brandizzi
3b626cca58 fix: make team member creation atomic 2026-09-23 03:35:23 -03:00
Alexandre Brandizzi
0ca9b767ed fix: distinguish uplift request key conflicts 2026-09-23 01:39:16 -03:00
Alexandre Brandizzi
8af9ad076f fix: map concurrent uplift inserts to conflict 2026-09-23 01:26:15 -03:00
Alexandre Brandizzi
adb192cad7 Release uplift gate when transaction setup fails 2026-09-22 16:54:47 -03:00
Alexandre Brandizzi
d282799127 Fix SH-387 uplift creation without primary dispatch 2026-09-22 16:44:31 -03:00
Adam Moussa
019eb86894
Merge branch 'main' into feat/ab/sh-288-event-notifications 2026-09-18 19:11:15 -04:00
Alexandre Brandizzi
e1ce3e439b
Merge pull request #149 from Sea-Haven-Industries/feat/ab/sh-292-notification-center
SH-292: Notification Center feed endpoint
2026-09-18 22:54:54 +00:00
Alexandre Brandizzi
0b3084a274
Merge pull request #155 from Sea-Haven-Industries/fix/ab/sh-379-manual-poc-override
Persist manual POC override with audit and site-follow (SH-379)
2026-09-18 22:54:51 +00:00
Alexandre Brandizzi
cbecc7b4ea fix(workorders): persist manual POC override with audit and site-follow (SH-379)
Editing a work order's POC never reached the backend: no update path wrote
PocName/PocPhone/PocNotes, so the optimistic UI edit was lost on refetch and
the completion freeze captured the Site contact instead of the manual value,
and nothing was audited.

- Add tenant-scoped PATCH api/workorders/{id}/poc via new WorkOrderPocService
  + WorkOrderPocDataService: persists the override, stages FieldChanged audit
  entries (which also write field locks so sync never overwrites a manual POC),
  and enforces row-version concurrency and terminal-status read-only rules.
- Lock semantics (SH-190): a manual POC away from the Site's live contacts is
  stored WO-level; an edit equal to a live Site contact (or blanking name+phone)
  stores nothing so the WO follows the Site. PocCustomized exposes the state.
- Board projection, completion freeze and create now share one Site-contact
  fallback (first non-deleted contact by SiteContactOrder) so a never-overridden
  WO keeps following the Site, including at create when the wizard prefills it.
- Route contract baseline gains PATCH {id:int}/poc.
2026-09-18 14:30:54 -03:00
Alexandre Brandizzi
9784dcf895 Merge remote-tracking branch 'origin/feat/ab/sh-292-notification-center' into feat/ab/sh-288-event-notifications 2026-09-18 13:20:22 -03:00
Alexandre Brandizzi
e668e13912 feat(notifications): feed assignments, comments, mentions and uplift decisions to the user they concern
Adds the personal producers behind GET /api/notifications without changing its shape:
new assignments (SH-288), unanswered comments on work the user takes part in (SH-289),
@mentions, and decisions on uplifts the user requested (SH-215).
2026-09-18 13:15:33 -03:00
Alexandre Brandizzi
aad3facaf1 fix(notifications): ignore soft-deleted dispatches and cap conflicts by recency
No Vendor treated any non-terminal dispatch as an assigned vendor without
checking IsDeleted, so a soft-deleted dispatch hid the work order from both
No Vendor and Vendor Conflict (the conflict query already drops deleted
dispatches). GetNoVendorAsync and the vendor-reminder assigned-work-order rule
now skip soft-deleted dispatches, keeping the asserted parity between the feed
and the reminders.

Vendor Conflict applied the section cap in vendor-sweep order, so when overlaps
exceeded the limit newer conflicts could be dropped while Count still counted
every work order. VendorConflictsAsync now orders pairs by recency before the
cap, matching the other per-work-order sections.
2026-09-18 12:59:56 -03:00
Alexandre Brandizzi
fa979605b4 feat(uplifts): expose dispatcher, technician and schedule on queue read (SH-209)
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.
2026-09-18 12:49:25 -03:00
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
Adam Moussa
b9bcaea9f3
Merge branch 'dev' into feat/ab/sh-207-uplift-queue-flags 2026-09-17 13:17:04 -04:00
Alexandre Brandizzi
8a4de283dc Merge remote-tracking branch 'origin/dev' into feat/ab/sh-326-team-member
# Conflicts:
#	Api.SeaHavenIndustries.Tests/TeamMemberServiceTests.cs
#	SeaHaven.DataServices/Implementation/TeamPermissionOverrideDataService.cs
2026-09-17 14:06:12 -03:00
1a290ea2f7
Merge remote-tracking branch 'origin/dev' into HEAD 2026-09-17 12:50:09 -04:00
Alexandre Brandizzi
bc88ef0577 Merge remote-tracking branch 'origin/dev' into feat/ab/sh-326-team-member 2026-09-17 13:49:21 -03:00
Adam Moussa
1f905fc7dd
Merge branch 'dev' into feat/ab/sh-329-account-owner 2026-09-17 12:36:26 -04:00
Alexandre Brandizzi
7b94ab9455 Merge remote-tracking branch 'origin/dev' into feat/ab/sh-207-uplift-queue 2026-09-17 13:05:07 -03:00
Alexandre Brandizzi
41957d52a7 merge: rebase queue flags onto SH-210 decisions, drop duplicated contract fields
#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.
2026-09-17 12:52:13 -03:00
Alexandre Brandizzi
046dee99bf
Merge branch 'dev' into feat/ab/sh-207-uplift-queue 2026-09-17 12:44:15 -03:00
Alexandre Brandizzi
679822733a
Merge branch 'dev' into feat/ab/sh-210-uplift-decisions 2026-09-17 12:44:12 -03:00
Alexandre Brandizzi
f4860a3dd9
Merge branch 'dev' into feat/ab/sh-348-region-filter 2026-09-17 12:36:15 -03:00
Adam Moussa
ef371b5917
Merge branch 'dev' into feat/ab/sh-210-uplift-decisions 2026-09-17 11:35:00 -04:00
Alexandre Brandizzi
1eadb82f28
Merge branch 'dev' into feat/ab/sh-210-uplift-decisions 2026-09-17 12:30:20 -03:00
Alexandre Brandizzi
9388e7a987 style(uplift): fix comment indentation in queue list query 2026-09-17 03:56:18 -03:00
Alexandre Brandizzi
468522c3f7 fix(uplift): resolve linked-only work order in queue list read
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.
2026-09-17 03:47:09 -03:00
Alexandre Brandizzi
5c93e4ecec Merge remote-tracking branch 'origin/dev' into feat/ab/sh-348-region-filter
# Conflicts:
#	SeaHaven.Services/Helpers/DashboardRegions.cs
2026-09-17 02:20:44 -03:00
Alexandre Brandizzi
f564e1b112 Merge remote-tracking branch 'origin/dev' into feat/ab/sh-347-dashboard-contract
# Conflicts:
#	Api.SeaHavenIndustries.Tests/DashboardServiceTests.cs
2026-09-17 02:18:22 -03:00
Alexandre Brandizzi
2e983b1f6a
Merge branch 'dev' into feat/ab/sh-303-services-registry 2026-09-17 01:12:07 -03:00
albrand
dfd248cfcb feat(uplifts): expose queue closed flag, attachments, decider, pending exposure (SH-207, SH-208)
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.
2026-09-16 22:48:47 -03:00
Alexandre Brandizzi
bd98ea5629 merge: carry approval queue contract fields into decisions 2026-09-16 22:32:35 -03:00
Alexandre Brandizzi
e0e45d5ed3 feat(uplifts): expose approval queue contract fields (SH-208) 2026-09-16 22:32:23 -03:00
Alexandre Brandizzi
316d1e6a63 fix(uplifts): correct queue exposure projections (SH-210) 2026-09-16 22:19:43 -03:00
Alexandre Brandizzi
60e006e8d7 fix(uplifts): calculate granted exposure amounts (SH-207) 2026-09-16 22:17:59 -03:00
Alexandre Brandizzi
8acc580c5b
Merge branch 'dev' into feat/ab/sh-353-dashboard-kpis-stacked 2026-09-16 21:56:23 -03:00