Migration clients (uuid id, organization_id FK uuid CASCADE, name, email REQUIS, phone, address, siret, notes). Index sur organization_id. Modèle Client avec belongsTo Organization. La relation hasMany Invoice est volontairement omise tant que le domaine Invoice n'est pas câblé. Validators Vine alignés sur le contrat MSW : - create : name 2-120, email requis avec format, siret 14 chiffres si fourni - update : tout optionnel - email REQUIS au create — pivot produit, pas de relance possible sans Endpoints (auth requise, scopés par organizationId du user courant) : - GET /clients?withStats=1&q= : liste filtrée + recherche, enrichissement stats optionnel, tri par actionnabilité (retards d'abord) quand withStats - GET /clients/:id : détail (id en UUID via router.matchers.uuid()) - POST /clients : 201 + détection doublon par nom case-insensitive → 409 avec payload `existing` (le SPA peut proposer "voir le client existant") - PATCH /clients/:id : merge partiel Service ClientStats avec interface bulkComputeClientStats() qui retourne EMPTY pour l'instant — sera vraiment branché quand Invoice arrive. Le contrat reste stable côté SPA, juste les compteurs à 0. Sérialisation : pour les listes avec stats per-item, on instancie le transformer manuellement (`new ClientTransformer(c).toObject()`) plutôt que de passer par BaseTransformer.transform() qui retourne un Item nested non-unwrappable hors clé directe de serialize().
12 lines
425 B
TypeScript
12 lines
425 B
TypeScript
import { ClientSchema } from '#database/schema'
|
|
import { belongsTo } from '@adonisjs/lucid/orm'
|
|
import type { BelongsTo } from '@adonisjs/lucid/types/relations'
|
|
import Organization from '#models/organization'
|
|
|
|
export default class Client extends ClientSchema {
|
|
@belongsTo(() => Organization)
|
|
declare organization: BelongsTo<typeof Organization>
|
|
|
|
// hasMany Invoice — sera ajouté quand le domaine Invoice arrivera.
|
|
}
|