feat(c3): consulta de pedidos — schema, api, web (OrdersModule + ClientDetailPage)

- Prisma: Order, OrderItem, OrderStatusHistory + migration
- Seed: 17 pedidos em 7 clientes com itens, histórico e desnorm de clientes
- @sar/api-interface: contratos Zod (OrderSummary, OrderDetail, OrderListQuery, etc.)
- API: GET /orders, GET /orders/:id, GET /clients/:id/orders (últimos 10)
- Web: OrdersPage (lista + filtro status/número + pending_approval highlighted)
- Web: ClientDetailPage (ficha completa + últimos 10 pedidos)
- Web: /pedidos e /pedidos/$id adicionados ao router; ClientDetailPage substitui placeholder

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-27 23:31:18 +00:00
parent 14c8350216
commit c36451dd33
15 changed files with 1494 additions and 71 deletions

View File

@@ -6,9 +6,11 @@ import {
type ClientDetail,
type ClientListQuery,
type ClientListResponse,
type OrderSummary,
} from '@sar/api-interface';
import type { WorkspaceClsStore } from '../workspace/workspace.types';
import { ClientsService } from './clients.service';
import { OrdersService } from '../orders/orders.service';
class ClientListQueryDto extends createZodDto(ClientListQuerySchema) {}
@@ -16,6 +18,7 @@ class ClientListQueryDto extends createZodDto(ClientListQuerySchema) {}
export class ClientsController {
constructor(
private readonly clients: ClientsService,
private readonly orders: OrdersService,
private readonly cls: ClsService<WorkspaceClsStore>,
) {}
@@ -30,4 +33,14 @@ export class ClientsController {
findOne(@Param('id', ParseUUIDPipe) id: string): Promise<ClientDetail> {
return this.clients.findOne(id, this.cls.get('userId') ?? '', this.cls.get('role') ?? 'rep');
}
// Últimos 10 pedidos do cliente — exibidos na ficha (FR-2.4).
@Get(':id/orders')
clientOrders(@Param('id', ParseUUIDPipe) id: string): Promise<OrderSummary[]> {
return this.orders.listByClient(
id,
this.cls.get('userId') ?? '',
this.cls.get('role') ?? 'rep',
);
}
}