mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 09:33:13 +00:00
160 lines
5.1 KiB
Markdown
160 lines
5.1 KiB
Markdown
|
|
# 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)
|