shoc-backend/docs/work-orders/phase-6/README.md

160 lines
5.1 KiB
Markdown
Raw Normal View History

# Fase 6 — Completion Doc e Slide-over
**Programa:** Work Orders Board
**Objetivo:** Contrato SHOC para slide-over (`WOSlideOver`): detalhe unificado, `docStatus` WO-level com templates por serviço, e tabs Comments/Audit/Media alinhadas ao frontend.
**Depende de:** [Fase 0](../phase-0/README.md) … [Fase 5](../phase-5/README.md)
---
## Endpoints
### `GET /api/workorders/{id}/detail`
Payload único para abrir o slide-over.
**Autenticação:** Bearer JWT (`[Authorize]`)
**Response:**
```json
{
"info": { /* WorkOrderDetailInfoDto — board row + description/trade/original* */ },
"completion": {
"docStatus": "No",
"template": { "id": 1, "name": "HVAC PM Completion", "serviceKey": "HVAC PM", "templateUrl": "..." },
"signOffName": null,
"signOffAttachment": null,
"signOffSignature": null,
"dispatchSignoffs": []
},
"comments": [{ "id": 1, "authorId": "guid", "text": "...", "time": "2026-06-01T12:00:00.0000000Z" }],
"audit": [{ "type": "manual", "dispatcherId": "guid", "action": "FieldChanged", "fieldName": "DocStatus", "oldValue": "No", "newValue": "Yes", "time": "..." }],
"media": [{ "id": 5, "category": "Extra", "url": "...", "isLegacy": false }]
}
```
```bash
curl -H "Authorization: Bearer <token>" \
"https://localhost:5001/api/workorders/42/detail"
```
---
### `GET /api/workorders/{id}/audit?limit=50`
Audit tab lazy refresh. Schema FE: `{ type, dispatcherId?, action, fieldName?, oldValue, newValue, time, dispatchId? }`.
---
### `GET /api/workorders/{id}/comments`
### `POST /api/workorders/{id}/comments`
```json
{ "text": "Called vendor" }
```
Response: `{ id, authorId, text, time, documents? }`.
---
### Completion templates
| Método | Rota | Auth | Descrição |
|--------|------|------|-----------|
| GET | `/api/workorders/completion-templates` | JWT | Query `serviceKey`, `workOrderType` |
| GET | `/api/workorders/completion-templates/{id}` | JWT | Detalhe |
| POST | `/api/workorders/completion-templates` | Admin | Criar template |
| PUT | `/api/workorders/completion-templates/{id}` | Admin | Atualizar |
| DELETE | `/api/workorders/completion-templates/{id}` | Admin | Soft delete |
Lookup na WO: `Trade` → fallback `WorkOrderType`.
---
### `POST /api/workorders/{id}/completion-doc`
Upload PDF preenchido (multipart).
| Campo form | Obrigatório |
|------------|-------------|
| `file` | Sim |
| `signOffName` | Não |
| `signOffSignature` | Não |
| `workOrderVersion` | Recomendado (Base64 RowVersion) |
**Regras:**
- WO read-only (`Canceled`/`Complete`/`Closed`) → 422
- Sucesso → `SignOffAttachment` + `DocStatus=Yes` + audit `FieldChanged`
- Dispatch signoffs → somente leitura no slide-over
```bash
curl -X POST -H "Authorization: Bearer <token>" \
-F "file=@completion.pdf" \
-F "signOffName=Jane Doe" \
"https://localhost:5001/api/workorders/42/completion-doc"
```
**Inline toggle:** `PATCH /api/workorders/{id}/board` com `field=docStatus` (Fase 2).
---
### Media
| Método | Rota | Descrição |
|--------|------|-----------|
| GET | `/api/workorders/{id}/media` | Lista unificada com `category` |
| POST | `/api/workorders/{id}/media` | multipart: `category` (Before/After/Extra/Completion) + `file` |
| DELETE | `/api/workorders/{id}/media/{mediaId}` | Soft delete (somente attachments com `id > 0`) |
Legacy columns (`BeforPhotoAttachment`, `AfterPhotoAttachment`, `SignOffAttachment`) aparecem na projeção com `isLegacy: true`.
---
## Schema
Migration `Phase6_CompletionSlideOver`:
- Tabela `CompletionDocTemplates`
- Coluna `Category` em `workOrderAttachments`
- Backfill SQL: `SignOffAttachment` preenchido → `DocStatus=Yes`
Script ops: [`scripts/backfill-docstatus.ps1`](../../scripts/backfill-docstatus.ps1)
---
## Código entregue
| Camada | Arquivo |
|--------|---------|
| Model | `CompletionDocTemplate.cs`, `WorkOrderMediaCategory` enum |
| Migration | `20260625120000_Phase6_CompletionSlideOver.cs` |
| Data | `WorkOrderDetailDataService`, `CompletionDocTemplateDataService` |
| Services | `WorkOrderDetailService`, `WorkOrderCommentService`, `WorkOrderCompletionService`, `WorkOrderMediaService` |
| DTOs | `WorkOrderDetailDTOs.cs` |
| Helpers | `WorkOrderAuditProjection`, `WorkOrderCommentProjection`, `WorkOrderMediaProjection` |
| API | `WorkOrderController` — rotas `/detail`, `/comments`, `/audit`, `/completion-doc`, `/media`, `/completion-templates` |
| Testes | `WorkOrderPhase6Tests.cs` |
---
## Critérios de aceite
- [x] `GET /detail` retorna Info + Completion + Comments + Audit + Media no contrato FE
- [x] Coluna COMP DOC do board via `docStatus` no `WorkOrderBoardRowDto` (Fase 1)
- [x] `CompletionDocTemplate` CRUD admin + lookup por `serviceKey`/`workOrderType`
- [x] `POST completion-doc` persiste attachment, define `DocStatus=Yes`, audit
- [x] Comments/Audit tabs sem adapter no FE
- [x] Media com `category`; legado mapeado
- [x] Endpoints legados (`GetWorkorderById`, `GetCommentsByWorkorderId`) inalterados
- [x] Testes: DocStatus PATCH, detail, completion upload, comments, media
---
## Fora de escopo
- Geração de PDF server-side
- Alteração Vendor Portal checklist/signoff
- Rollout / sunset Blazor (Fase 7)