mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 18:53:12 +00:00
174 lines
5.5 KiB
Markdown
174 lines
5.5 KiB
Markdown
# Fase 3 — Criação e Cancelamento
|
||
|
||
**Programa:** Work Orders Board
|
||
**Objetivo:** Criação wizard/inline via contrato do board SHOC, cancelamento soft dedicado, ManualEditFlag na criação, e delete físico restrito a Admin.
|
||
|
||
**Depende de:** [Fase 0](../phase-0/README.md), [Fase 1](../phase-1/README.md), [Fase 2](../phase-2/README.md)
|
||
|
||
---
|
||
|
||
## Endpoints
|
||
|
||
### `POST /api/workorders/board`
|
||
|
||
Cria uma WO com contrato alinhado ao board. Suporta wizard (payload completo) e inline row (subset mínimo).
|
||
|
||
**Autenticação:** Bearer JWT (`[Authorize]`)
|
||
|
||
**Request body:**
|
||
|
||
```json
|
||
{
|
||
"woNumber": "12345",
|
||
"workOrderType": "PM",
|
||
"siteCode": "BK5",
|
||
"assignTo": "dispatcher-guid",
|
||
"dueDate": "2026-07-01",
|
||
"scheduledDate": "2026-06-25",
|
||
"targetWeek": "2026-06-22",
|
||
"scheduleWeekOnly": false,
|
||
"vendorId": 5,
|
||
"apptDate": "2026-06-26",
|
||
"apptTime": "09:00 – 11:00",
|
||
"docStatus": "No",
|
||
"description": "Leak in break room",
|
||
"trade": "HVAC PM",
|
||
"locationId": 12,
|
||
"pocContactId": 3,
|
||
"pocNotes": "Call before arrival"
|
||
}
|
||
```
|
||
|
||
| Campo | Obrigatório | Descrição |
|
||
|-------|-------------|-----------|
|
||
| `workOrderType` | Sim | Enum `WorkOrderType` |
|
||
| `siteCode` | Sim | Código do site |
|
||
| `woNumber` | Não | Se omitido, auto-gera sequencial normalizado 11 dígitos |
|
||
| `scheduleWeekOnly` | Não | Se `true`, `targetWeek` é obrigatório |
|
||
| `vendorId` | Condicional | Obrigatório quando `apptDate` ou `apptTime` informados |
|
||
|
||
**Responses:**
|
||
|
||
| HTTP | Body | Quando |
|
||
|------|------|--------|
|
||
| 200 | `WorkOrderBoardRowDto` | Sucesso — row pronto para inserir no board |
|
||
| 400 | `Response` | Validação FluentValidation |
|
||
| 409 | `WorkOrderBoardValidationErrorDto` | WO# duplicado |
|
||
| 422 | `WorkOrderBoardValidationErrorDto` | Regra de domínio |
|
||
|
||
**Exemplo (inline mínimo):**
|
||
|
||
```bash
|
||
curl -X POST -H "Authorization: Bearer <token>" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"workOrderType":"PM","siteCode":"BK5"}' \
|
||
"https://localhost:5001/api/workorders/board"
|
||
```
|
||
|
||
---
|
||
|
||
### `POST /api/workorders/{id}/cancel`
|
||
|
||
Soft cancel — transição para `LifecycleStatus.Canceled` com WO read-only.
|
||
|
||
**Autenticação:** Bearer JWT
|
||
|
||
**Responses:**
|
||
|
||
| HTTP | Body | Quando |
|
||
|------|------|--------|
|
||
| 200 | `WorkOrderBoardRowDto` | Cancelado (ou já estava cancelado — idempotente) |
|
||
| 422 | `WorkOrderBoardValidationErrorDto` | WO `Complete` ou `Closed` |
|
||
|
||
**Exemplo:**
|
||
|
||
```bash
|
||
curl -X POST -H "Authorization: Bearer <token>" \
|
||
"https://localhost:5001/api/workorders/42/cancel"
|
||
```
|
||
|
||
---
|
||
|
||
## Regras de domínio na criação
|
||
|
||
| Regra | Comportamento |
|
||
|-------|---------------|
|
||
| Status inicial | `Incomplete` |
|
||
| Auto-schedule | `scheduledDate` + `assignTo` → `Scheduled` |
|
||
| Set-once tracking | Primeira `scheduledDate` → `OriginalDate` / `OriginalWeek` |
|
||
| Week-only | `scheduleWeekOnly=true` + `targetWeek` → aparece na semana no GET board |
|
||
| WO# | Manual normalizado 11 dígitos; auto-gerado se omitido |
|
||
| Vendor | Cria dispatch primário quando `vendorId` informado |
|
||
| ManualEditFlag | Field locks criados para cada campo SHOC preenchido |
|
||
|
||
---
|
||
|
||
## Soft cancel vs hard delete
|
||
|
||
| Operação | Endpoint | Quem | Efeito |
|
||
|----------|----------|------|--------|
|
||
| Soft cancel | `POST /{id}/cancel` | Dispatcher | Status `Canceled`, WO permanece, PATCH bloqueado (422) |
|
||
| Hard delete | `DELETE DeleteWorkorder` | **Admin only** | Remove registro, anexos e contatos |
|
||
|
||
O legado `POST AddWorkorder` (form/Blazor) permanece inalterado.
|
||
|
||
---
|
||
|
||
## ManualEditFlag na criação
|
||
|
||
Campos preenchidos na criação SHOC recebem lock em `WorkOrderFieldLocks` via audit `FieldChanged`. Sync subsequente em campo lockado gera `SyncRejected` (ver [manual-edit-flag-design.md](../phase-0/manual-edit-flag-design.md)).
|
||
|
||
WO criada via Sync/Lambda continua sem locks até edição SHOC.
|
||
|
||
---
|
||
|
||
## Audit
|
||
|
||
| Evento | Action |
|
||
|--------|--------|
|
||
| Criação | 1× `Create` + `FieldChanged` por campo preenchido |
|
||
| Auto-schedule na criação | `StatusChanged` adicional |
|
||
| Cancel | `StatusChanged` → `Canceled` |
|
||
| Hard delete Admin | `Delete` |
|
||
|
||
---
|
||
|
||
## Código entregue
|
||
|
||
| Camada | Arquivo |
|
||
|--------|---------|
|
||
| DTOs | `SeaHaven.Services/DTOs/WorkOrderBoardDTOs.cs` |
|
||
| Validação | `SeaHaven.Services/Validation/WorkOrderBoardCreateValidation.cs` |
|
||
| Scheduling compartilhado | `SeaHaven.Services/Helpers/WorkOrderBoardFieldMutations.cs` |
|
||
| Create service | `SeaHaven.Services/Implementation/WorkOrderBoardCreateService.cs` |
|
||
| Cancel service | `SeaHaven.Services/Implementation/WorkOrderBoardCancelService.cs` |
|
||
| Audit | `IWorkOrderAuditService.StageCreated`, `LogCreatedAsync` |
|
||
| API | `WorkOrderController` — `POST board`, `POST {id}/cancel`, `DELETE` Admin |
|
||
| Testes | `WorkOrderBoardCreateServiceTests`, `WorkOrderBoardCancelServiceTests`, `WorkOrderBoardCreateSyncLockTests` |
|
||
|
||
---
|
||
|
||
## Gates de aceite
|
||
|
||
### Desenvolvimento
|
||
|
||
- [x] `POST /api/workorders/board` — Incomplete / auto-schedule / week-only
|
||
- [x] WO# auto ou manual 11 dígitos + unicidade (409)
|
||
- [x] Vendor/dispatch primário na criação
|
||
- [x] Field locks + SyncRejected pós-create SHOC
|
||
- [x] `POST /{id}/cancel` idempotente; PATCH bloqueado após cancel
|
||
- [x] `DELETE DeleteWorkorder` restrito a Admin
|
||
- [x] Legado `AddWorkorder` inalterado
|
||
- [x] 68 testes unitários total (17 Fase 3 + 51 Fases 0–2)
|
||
|
||
### Staging (pendente)
|
||
|
||
- [ ] UAT dispatcher: wizard + inline row
|
||
- [ ] Smoke Sync durante criação SHOC
|
||
- [ ] Confirmar navegação FE para semana do WO criado
|
||
|
||
---
|
||
|
||
## Próximo passo
|
||
|
||
**Fase 4** — Busca contextual na semana + advanced search cross-week conforme tier volume.
|