2026-07-17 11:48:47 -03:00
|
|
|
|
# Work Orders Board & Search API
|
|
|
|
|
|
|
|
|
|
|
|
Frontend integration contract for weekly board and advanced search filters.
|
|
|
|
|
|
|
|
|
|
|
|
## Base
|
|
|
|
|
|
|
|
|
|
|
|
| Item | Valor |
|
|
|
|
|
|
| ------------ | ------------------------------------------- |
|
|
|
|
|
|
| Prefixo | `/api/workorders` (alias: `/api/WorkOrder`) |
|
|
|
|
|
|
| Auth | `Authorization: Bearer {token}` (JWT) |
|
|
|
|
|
|
| Content-Type | Não necessário (GET) |
|
|
|
|
|
|
|
|
|
|
|
|
Paths no FE: `API_PATHS.workOrder.board`, `boardSearch`, `lookupsDispatchers`.
|
|
|
|
|
|
|
|
|
|
|
|
## Quando usar qual endpoint
|
|
|
|
|
|
|
|
|
|
|
|
| Modo FE | Endpoint | Quando |
|
|
|
|
|
|
| --------------------------------------- | -------------------------- | ------------------------------------------------ |
|
|
|
|
|
|
| Barra principal (`advApplied === null`) | `GET /board` | Semana + dispatchers + tipo segment + search |
|
|
|
|
|
|
| Filtros avançados aplicados | `GET /board/search` | Todos os filtros avançados + paginação/ordenação |
|
|
|
|
|
|
| Lookup dispatchers | `GET /lookups/dispatchers` | Popular multi-select de dispatchers |
|
|
|
|
|
|
|
|
|
|
|
|
**Não misture parâmetros:** `weekStart`/`weekEnd` só no `/board`; `datePreset` só no `/search`.
|
|
|
|
|
|
|
|
|
|
|
|
## Query builders (FE)
|
|
|
|
|
|
|
|
|
|
|
|
- [`board-query-params.ts`](../../src/domain/work-orders/utils/board-query-params.ts) — `toBoardQueryParams`, `toBoardSearchQueryParams`
|
|
|
|
|
|
- Arrays na query: repetição simples (`types=2&types=6`), via `toUrlSearchParams` em `work-orders-api.ts`
|
|
|
|
|
|
|
|
|
|
|
|
## Barra → `GET /board`
|
|
|
|
|
|
|
|
|
|
|
|
| FE state | API param | Regra |
|
|
|
|
|
|
| --------------- | ---------------------- | ----------------------------------------------------------- |
|
|
|
|
|
|
| `search` | `search` | Enviar só se `length >= 2`; com 1 char, filtrar client-side |
|
|
|
|
|
|
| `weekMonday` | `weekStart` | ISO `YYYY-MM-DD` (segunda) |
|
|
|
|
|
|
| — | `weekEnd` | `weekStart + 4` (sexta) |
|
|
|
|
|
|
| `dispatcherIds` | `dispatchers` | `__unassigned` → `__unassigned__` |
|
|
|
|
|
|
| "My WOs" | `dispatchers={userId}` | Equivalente a `myWorkOrders=true` |
|
2026-07-21 14:31:58 -03:00
|
|
|
|
| `typeFilter` | `types` / `overdue` | Tipos reais em `types`; past-due via `overdue=true` (OR) |
|
2026-07-17 11:48:47 -03:00
|
|
|
|
|
|
|
|
|
|
## Advanced → `GET /board/search`
|
|
|
|
|
|
|
2026-07-21 14:31:58 -03:00
|
|
|
|
| FE state | API param | Regra |
|
|
|
|
|
|
| ---------------- | --------------------- | ------------------------------------------- |
|
|
|
|
|
|
| `page` | `page` | **0-based** (primeira página = `0`) |
|
|
|
|
|
|
| `pageSize` | `pageSize` | Default `100`, max `100` |
|
|
|
|
|
|
| `sortBy` | `sortBy` | `scheduledDate` \| `woNumber` \| `dueDate` |
|
|
|
|
|
|
| `sortDir` | `sortDir` | `asc` \| `desc` |
|
|
|
|
|
|
| `search` | `search` | `>= 2` chars |
|
|
|
|
|
|
| `dateRange` | `datePreset` | PascalCase (ver abaixo) |
|
|
|
|
|
|
| `customFrom/To` | `dateFrom` / `dateTo` | Obrigatórios se `datePreset=Custom` |
|
|
|
|
|
|
| `sites` (IDs UI) | `sites` | **Site codes**, não location ID |
|
|
|
|
|
|
| `types` | `types` | Integers de `WorkOrderType` reais |
|
|
|
|
|
|
| overdue (UI) | `overdue` | `true` = past-due (`isPastDue`); ver abaixo |
|
|
|
|
|
|
| `dispatchers` | `dispatchers` | `__unassigned` → `__unassigned__` |
|
|
|
|
|
|
| `statuses` | `statuses` | Integers 1–10 |
|
|
|
|
|
|
| `pmTypes` | `pmTypes` | Strings (labels Problem dropdown) |
|
|
|
|
|
|
| `vendorTechs` | `vendorIds` | Integers (resolvidos por companyName) |
|
|
|
|
|
|
| `docs` | `docStatuses` | No=2, Yes=1, NN=3 |
|
2026-07-17 11:48:47 -03:00
|
|
|
|
|
|
|
|
|
|
### `datePreset`
|
|
|
|
|
|
|
|
|
|
|
|
| FE key | API value |
|
|
|
|
|
|
| --------------- | ------------- |
|
|
|
|
|
|
| `this-week` | `ThisWeek` |
|
|
|
|
|
|
| `last-week` | `LastWeek` |
|
|
|
|
|
|
| `this-month` | `ThisMonth` |
|
|
|
|
|
|
| `last-3-months` | `Last3Months` |
|
|
|
|
|
|
| `next-week` | `NextWeek` |
|
|
|
|
|
|
| `next-month` | `NextMonth` |
|
|
|
|
|
|
| `custom` | `Custom` |
|
|
|
|
|
|
|
2026-07-21 14:31:58 -03:00
|
|
|
|
### `types` — WorkOrderType
|
2026-07-17 11:48:47 -03:00
|
|
|
|
|
2026-07-21 14:31:58 -03:00
|
|
|
|
Somente tipos reais de work order. **Não** use sentinel `99` para overdue.
|
|
|
|
|
|
|
|
|
|
|
|
| Label FE | API |
|
|
|
|
|
|
| --------- | -------------------------------------------- |
|
|
|
|
|
|
| PM | `2` |
|
|
|
|
|
|
| Emergency | `3` |
|
|
|
|
|
|
| Reactive | `6` |
|
|
|
|
|
|
| Add-On | `7` |
|
|
|
|
|
|
| Other | tipo real do enum (não é filtro de past-due) |
|
|
|
|
|
|
|
|
|
|
|
|
### `overdue` — past-due
|
|
|
|
|
|
|
|
|
|
|
|
| FE / UI | API param | Regra |
|
|
|
|
|
|
| ------- | -------------- | ----------------------------------------- |
|
|
|
|
|
|
| Overdue | `overdue=true` | Filtra work orders past-due (`isPastDue`) |
|
|
|
|
|
|
|
|
|
|
|
|
`types` e `overdue` combinam com **OR**: uma WO entra no resultado se corresponder a algum `types` **ou** estiver overdue (quando `overdue=true`).
|
|
|
|
|
|
|
|
|
|
|
|
Exemplos:
|
|
|
|
|
|
|
|
|
|
|
|
- Só PM e Emergency: `types=2&types=3`
|
|
|
|
|
|
- Só past-due: `overdue=true`
|
|
|
|
|
|
- PM **ou** past-due: `types=2&overdue=true`
|
2026-07-17 11:48:47 -03:00
|
|
|
|
|
|
|
|
|
|
### `statuses` — LifecycleStatus
|
|
|
|
|
|
|
|
|
|
|
|
Incomplete=1, Pending=2, Scheduled=3, En Route=4, On Site=5, In Progress=6, Completed=7, Rescheduled=8, Canceled=9, Pending Quote=10.
|
|
|
|
|
|
|
|
|
|
|
|
### `docStatuses`
|
|
|
|
|
|
|
|
|
|
|
|
Pending (`No`)=2, Uploaded (`Yes`)=1, N/N (`NN`)=3.
|
|
|
|
|
|
|
|
|
|
|
|
## Respostas
|
|
|
|
|
|
|
|
|
|
|
|
### `/board`
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"weekStart": "2026-07-14",
|
|
|
|
|
|
"weekEnd": "2026-07-18",
|
|
|
|
|
|
"counts": { "total": 42, "returned": 10 },
|
|
|
|
|
|
"scheduled": [],
|
|
|
|
|
|
"unscheduled": []
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### `/board/search`
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"items": [],
|
|
|
|
|
|
"totalCount": 150,
|
|
|
|
|
|
"page": 0,
|
|
|
|
|
|
"pageSize": 100,
|
|
|
|
|
|
"totalPages": 2,
|
|
|
|
|
|
"hasPrevious": false,
|
|
|
|
|
|
"hasNext": true
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Erros HTTP
|
|
|
|
|
|
|
|
|
|
|
|
| Situação | Status |
|
|
|
|
|
|
| --------------------------------------------------- | ------ |
|
|
|
|
|
|
| `weekEnd < weekStart` ou janela > 7 dias | 400 |
|
|
|
|
|
|
| `datePreset=Custom` sem datas / `dateTo < dateFrom` | 400 |
|
|
|
|
|
|
| `sortBy` inválido | 400 |
|
|
|
|
|
|
| Sem token / expirado | 401 |
|
|
|
|
|
|
|
|
|
|
|
|
Body típico: `{ "status": "Error", "message": "..." }` — o FE exibe `message` via `ApiError`.
|
|
|
|
|
|
|
2026-08-10 17:12:15 -03:00
|
|
|
|
## Add-On indicator
|
|
|
|
|
|
|
|
|
|
|
|
See [addon-indicator.md](./addon-indicator.md) (SH-184): backend recalculates
|
|
|
|
|
|
`isAddOn` on schedule move/clear with audit; FE only reflects the API value.
|
|
|
|
|
|
|
2026-07-17 11:48:47 -03:00
|
|
|
|
## Validação UI
|
|
|
|
|
|
|
|
|
|
|
|
O side sheet de filtros avançados valida Custom (From/To obrigatórios e `dateTo >= dateFrom`) antes de aplicar, para evitar 400 desnecessário.
|