Commit graph

55 commits

Author SHA1 Message Date
Alexandre Brandizzi
fc3a29f399 Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	SeaHaven.Services/Implementation/WorkOrderCompletionService.cs
2026-09-25 16:40:36 -03:00
Alexandre Brandizzi
c3865e56ac Sites API: site code uniqueness, soft delete with role check, open work orders, site notes
- Reject duplicate site codes per client (case-insensitive); site code is immutable once set
- Delete tombstones the site and requires the DeleteSites permission (Admin, Scheduler)
- GET /api/locations/{id}/open-work-orders returns the open count and ids
- PATCH /api/locations/{id}/contact-info saves contacts and notes from the work-order Site dialog
- Add nullable Locations.Notes, used as the site-level POC notes fallback
2026-09-25 11:19:29 -03:00
Alexandre Brandizzi
b545d4a4fe feat(work-orders): add Overdue work order type
Overdue (8) is a dispatcher-assigned type, separate from the derived
past-due overlay. It takes no severity, resolves services and
completion-doc templates from the PM catalog, and filters as its own
type. The past-due flag now narrows a type filter instead of widening it,
and the dashboard breakdown partitions by stored type.
2026-09-25 10:57:34 -03:00
Alexandre Brandizzi
d6c5357fab fix(dashboard): count unassigned legacy rows with no lifecycle status (SH-392)
The legacy create paths (WorkOrderDTOs, SyncService, the Blazor
WorkorderService) still write Status without LifecycleStatus. The board
status filter only matched LifecycleStatus. So an open unassigned row of
that kind was left out of the Unassigned tile and its drill-down list,
even though the Open tile in the same response counted it.

ApplyStatusFilter now reads a row with no LifecycleStatus by its legacy
status (LegacyStatus ?? Status), using the Phase0 backfill rules: known
text maps as LifecycleStatusMapper does, and anything else, blank
included, counts as Incomplete. The tile and /board/search share the
predicate, so the count still matches the list it opens.
2026-09-25 03:34:24 -03:00
Alexandre Brandizzi
c49a98db18
Merge branch 'main' into feat/ab/sh-392-dashboard-unassigned 2026-09-25 03:27:33 -03: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
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
7297e30212 fix(dashboard): count All time over the same window the board lists (SH-392)
The Unassigned drill-down opens the board with no range, which searches
2000-01-01..2099-12-31 plus undated work. The All time count had no
bounds, so a work order dated outside that window was counted but not
listed. The count now uses the same window.
2026-09-24 21:45:06 -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
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
146fe6fdb0 style: satisfy dotnet format whitespace gate for region board files
Break collection initializer entries onto one line each in
WorkOrderBoardRegions and WorkOrderBoardSearchTests so the changed-file
formatting gate (dotnet format --verify-no-changes) passes.
2026-09-17 02:26:19 -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
738c9eaf45 feat(work-orders): add region filtering (SH-348) 2026-09-16 21:27:05 -03:00
Alexandre Brandizzi
33f517620b feat(work-orders): link service selections to registry 2026-09-16 18:02:57 -03:00
Alexandre Brandizzi
802b7a414e
SH-338: filter unscheduled work orders before pagination (#116)
Some checks are pending
Validate and deploy / Validate deployable source bundle (push) Waiting to run
Validate and deploy / Deploy shoc-backend-dev through Terraform (push) Blocked by required conditions
Validate and deploy / Deploy shoc-backend-staging to Elastic Beanstalk (push) Blocked by required conditions
* fix(work-orders): filter unscheduled search server-side

* fix(work-orders): preserve unscheduled status scope
2026-09-15 16:46:40 -03:00
Arthur Bassi
e0139d4601 feat(work-orders): capture Site/Vendor/POC snapshot on Completed
Freeze effective live values on first Completed transition and project them on GET.
2026-09-10 15:46:25 -03:00
Arthur Bassi
a0fdd19934
fix(work-orders): accept image/jpg MIME and expose board MediaCount (#107)
Some checks are pending
Validate and deploy / Validate deployable source bundle (push) Waiting to run
Validate and deploy / Deploy shoc-backend-dev through Terraform (push) Blocked by required conditions
Validate and deploy / Deploy shoc-backend-staging to Elastic Beanstalk (push) Blocked by required conditions
Co-authored-by: Alexandre Brandizzi <alex_brandizzi@hotmail.com>
2026-09-09 00:10:52 +00:00
Arthur Bassi
7a0b91bcd6 feat(work-orders): persist board severity on create, patch, and search 2026-09-07 11:46:13 -03:00
Arthur Bassi
14b85c64a8
Merge branch 'dev' into feat/sh-117-aveta-required 2026-08-25 17:19:30 -03:00
Arthur Bassi
7c7c6bc525 feat(work-orders): persist Aveta Extra Docs media category
Round-trip category 5 on media POST/PATCH/GET and project hasAvetaDocument so pending vs attached survives reopen.
2026-08-25 15:10:45 -03:00
Arthur Bassi
04958e6121 fix(work-orders): keep GET /board to scheduled-in-week rows only (SH-165) 2026-08-24 18:29:18 -03:00
Arthur Bassi
15315edf08 feat(work-orders): persist avetaRequired on board create, patch, and search
Expose avetaRequired and originalDate on list rows so the frontend can round-trip the Aveta checkbox and Reschedule hover.
2026-08-24 15:14:31 -03:00
Arthur Bassi
75d337df0f fix(work-orders): omit inactive primary vendor from board rows (SH-183)
Do not project VendorId/VendorName for Cancelled, Canceled, or Refused primary dispatches, and expose PrimaryDispatchStatus on the board DTO.
2026-08-20 13:22:12 -03:00
arthur.bassi
2222d04fcb Merge remote-tracking branch 'origin/dev' into feature/sh-218-additional-contacts 2026-08-18 20:52:34 -03:00
Alexandre Brandizzi
5386d6129d
Merge branch 'dev' into feature/sh-196-wo-uplifts 2026-08-18 17:46:38 -03:00
Arthur Bassi
92a3b3f045 chore(work-orders): merge origin/dev into SH-218 additional contacts
Keep IsAddOn create tests from dev alongside additional-contacts coverage.
2026-08-18 11:53:26 -03:00
Arthur Bassi
c9a80f5c79 fix(work-orders): restore SH-185 Schedule On Past Due and assert IsAddOn audit
Past Due follows ScheduledDate so Due Date alone cannot set or clear it. Auto-schedule and reschedule tests now expect the third IsAddOn audit field.
2026-08-17 10:36:03 -03:00
Arthur Bassi
fa05b22df6 chore(work-orders): merge SH-121 facets and keep SH-184 IsAddOn migration 2026-08-17 10:28:03 -03:00
Arthur Bassi
17c2e968cd feat(work-orders): board search facets for SH-121/SH-196 2026-08-13 16:34:21 -03:00
Arthur Bassi
36ef0b00f5 feat(work-orders): persist additionalContacts on create, board GET and PATCH (SH-218)
Add JSON column, DTO/mapper, create + PATCH field, board projection, FluentValidation,
and regression tests for additional POC contacts round-trip.
2026-08-13 16:11:36 -03:00
arthur.bassi
b81cfbb005 feat(work-orders): WO-scoped uplift endpoints and board summary (SH-196)
Expose workorders/{id}/uplifts list/create/cancel/revoke for the SH-196 dialog, aggregate upliftSummary on board rows, and add service/controller regression tests.
2026-08-13 14:49:56 -03:00
Arthur Bassi
97e042f552 feat(work-orders): persist IsAddOn frozen at create (SH-126)
Add set-once IsAddOn with server cutoff at create, board DTO exposure, legacy type-7 backfill, and Types=AddOn search compat. Aligns with FE PR #61 frozen contract.
2026-08-13 13:30:09 -03:00
Arthur Bassi
05dd262e80 fix(work-orders): derive Past Due from DueDate instead of ScheduledDate
Past Due must track the deadline (Due Date), not Schedule On. Keep dueDate and scheduledDate PATCH mutations independent so rescheduling alone does not clear Past Due.
2026-08-13 13:28:25 -03:00
Arthur Bassi
29dec00790 fix(work-orders): keep pendingUpliftCount on detail and exclude deleted dispatches
Map board PendingUpliftCount through WorkOrderDetailService.MapInfo and ignore soft-deleted dispatches in the aggregate so SH-188 gating is authoritative for board/search/detail.
2026-08-12 11:50:56 -03:00
Arthur Bassi
aaeeb90f1a feat(work-orders): expose pendingUpliftCount on board rows (SH-188)
Aggregate Pending uplift requests across all dispatches tied to a work
order so the board/search/detail contract can drive the Completed gate.
2026-08-12 09:43:10 -03:00
Arthur Bassi
ea2dedf579 !fix(work-orders): fail-closed media account scope with org_scope claim [SH-221] 2026-08-06 10:26:04 -03:00
Arthur Bassi
fdc315d8fe !feat(work-orders): enforce media account scope and AddMedia freshness [SH-221] 2026-08-06 09:47:34 -03:00
Alexandre Brandizzi
d073a503d1 feat(work-orders): board completedDate + media categorize contract
Expose completedDate on PATCH /workorders/{id}/board so CompDoc can leave legacy EditWorkorder. Allow optional media category on upload, PATCH category afterward, and enforce JPG/PNG/MP4/MOV allowlist (SH-116).
2026-08-04 11:08:18 -03:00
Arthur Bassi
620a36af54
feat(work-orders): enrich board search overdue filters and 0-based paging (#23)
* feat(work-orders): enrich board search overdue filters and 0-based paging

* fix(work-orders): align stacked services with CI build

* fix(tests): pass userDataService in comment service unit test

* fix(work-orders): use dedicated overdue query flag

Stop treating WorkOrderType.Other as an overdue sentinel. Board and advanced search now accept overdue=true while types=Other filters real Other rows; combining both uses OR.

* test(work-orders): cover overdue date/status boundary and Other type-filter

Lock the PR #23 overdue regression boundary through the public advanced
search service. Prove overdue filtering is driven by past-due date plus
non-terminal status, not by the WorkOrderType.Other sentinel:
- Other + future/not-completed excluded from overdue
- past-due + Scheduled included; past-due + Completed/Canceled excluded
- types=[PM, Other] keeps real Other rows and does not pull past-due rows
- assert 0-based paging (Page=0) is preserved alongside overdue/type filters

---------

Co-authored-by: Arthur Bassi <arthur.winiarski.ranger@outlook.com>
Co-authored-by: Alexandre Brandizzi <alex_brandizzi@hotmail.com>
2026-07-24 21:12:03 +00:00
Alexandre Brandizzi
e5cf4cec09 merge: integrate origin/dev into PR #22 flag-color base
Brings in dev's Phase 5 (PR #17) + vendor PRs (#25/#28/#29) atop the
Phase 6/7 + flagColor base (PR #22). Preserves dev Phase 1-5 behavior and
PR #22 Phase 6/7 + flagColor behavior.

Conflict resolutions (16 files):
- Migrations Phase4_SearchIndexes/.Designer + Phase5_DomainEvents/.Designer:
  take dev (Phase4 incl. SQL Server SiteCode/InternalWONumber index-compat
  shrink fix; Phase5 identical). ModelSnapshot union: Vendor CompanyId index
  + Phase7 ServiceNotes/ExternalWorkOrderId index.
- ApplicationDbContext: keep dev SiteCode/InternalWONumber MaxLength (Phase1-5
  + unguarded model test) + HEAD CompletionDocTemplate/ExternalWorkOrderId.
- WorkOrderAuditService: unify on dev async staging API; convert Phase6
  CompletionService 2 call sites to await StageFieldChangedAsync (drops
  HEAD sync duplicate; only callers, no test refs).
- Hosted services: take HEAD (retry-on-failure, coherent with Phase7
  WorkOrderJobRunStateAccessor/OpsHealth). Program.cs keeps dev vendor DI
  (ClamAV/VendorDocumentScanWorker/ArgumentExceptionFilter) + HEAD Phase7.
- WorkOrderController: keep HEAD Phase6/7 service params + dev doc comment.
- VendorController/WorkOrderBoardCreateService/QueryFilters/appsettings:
  union / dev-correct.
- WorkOrderBoardUpdateServiceTests: union of HEAD (Phase6/7+flagColor) and
  dev (Phase1-5) test methods.

Verified WorkOrderType.Other (enum 99) is a legit category, not an overdue
sentinel; overdue uses dedicated OperationalFlags.PastDue + IsPastDue, and
'Overdue' is rejected as a WorkOrderType (no PR #23 import needed).

Removed dev duplicate Api.Options.WorkOrderJobRunState (HEAD defines it in
Services.Implementation alongside the Accessor; Services cannot reference Api).
2026-07-24 14:20:16 -03:00
Alexandre Brandizzi
a9dee0bb84 merge: integrate origin/dev into work-orders-phase-4
Merge origin/dev (vendor roadmap PRs #28/#29, phases 1-3 PRs #13-15)
into work-orders-phase-4. Conflict in WorkOrderController.cs resolved by
keeping both the Phase 4 board/search endpoint and the dev-side XML doc
comment on GetDispatcherLookups (both additions at the same site).

Migration timestamps remain monotonic and non-overlapping. Phase 4 global
advanced search, search index migrations, and the cross-platform LocalDB
test guard are preserved alongside the merged vendor roadmap and phases 1-3.

Validation (Docker .NET 8 SDK): build 0 errors; 191 tests pass across
all three test projects (64 + 18 + 109).
2026-07-24 13:38:20 -03:00
Alexandre Brandizzi
df828cf48c
Merge pull request #14 from Sea-Haven-Industries/feat/work-orders-phase-2
Feat/work orders phase 2
2026-07-24 13:32:25 -03:00
Arthur Bassi
11fed06f03 feat(work-orders): add Phase 4 board search and advanced search API
Harden contextual search on the weekly board and expose paginated cross-week GET /board/search with date presets, FE filter params, SQL indexes, and unit tests.
2026-07-24 09:58:39 -03:00
Arthur Bassi
cc37a0283b fix(work-orders): keep FlagColor feature on this slice with its migration
Restore FlagColor model/API/tests here after the parent structured-notes PR dropped them, so this PR remains the coherent home for the FlagColor column and palette.
2026-07-21 09:42:10 -03:00
Arthur Bassi
33574c233b fix(work-orders): keep FlagColor out of structured-notes slice
Remove FlagColor model/API/tests from this PR so schema and EF model stay aligned with the structured-fields migration. FlagColor remains in the follow-on PR that adds its migration.
2026-07-21 09:38:34 -03:00
Arthur Bassi
75969a1e3d docs(work-orders): clarify board filter precedence and dispatcher lookup
Document myWorkOrders overriding dispatchers, weekend dayGroup null contract, and that dispatcher lookups currently return all users. Map service ArgumentException to 400 for consistency.
2026-07-21 09:33:24 -03:00
Arthur Bassi
ecc1db3726 feat(work-orders): add structured service notes POC and vendor fields
Persist primary/extra services, service notes, free-text POC, and
tech/vendor notes on create/patch/board/detail instead of embedding
them in description.
2026-07-17 10:37:23 -03:00
Arthur Bassi
88f9245fbf merge: sync Phase 1 board review fixes into Phase 2
Resolve conflicts in WorkOrderController and WorkOrderBoardService so Phase 2 merges cleanly into the Phase 1 base.
2026-07-10 10:41:36 -03:00
Arthur Bassi
c2d0bd45e3 fix(work-orders): address PR #13 review feedback
Return BadRequest for invalid board week window, remove duplicate unused board types, fix POC null guard, and document appt precedence and UTC Phase 1 assumptions.
2026-07-09 10:06:36 -03:00
Arthur Bassi
4617e8ba83 feat(work-orders): add Phase 4 board search and advanced search API
Harden contextual search on the weekly board and expose paginated cross-week GET /board/search with date presets, FE filter params, SQL indexes, and unit tests.
2026-07-08 14:58:59 -03:00