Migration invoices : uuid id, organization_id FK CASCADE, client_id FK RESTRICT (on n'efface pas les factures si l'utilisateur supprime un client par erreur — audit/comptable), plan_id FK SET NULL, numero, amount_ttc_cents (int, jamais float), issue_date, due_date, status ENUM PG natif (pending/awaiting_user_confirmation/in_relance/paid/litigation/cancelled), pdf_storage_key, notes, rubis_earned, paid_at. Indexes (org,status), (org,client_id), (org,due_date), unique (org,numero). Modèles : Invoice avec belongsTo Organization/Client/Plan. Client et Plan étendus avec hasMany Invoice maintenant que la table existe. Endpoints : - GET /invoices : filtres status/q/clientId/page, tri actionnable (awaiting_user_confirmation puis in_relance puis pending puis litigation puis paid puis cancelled), pagination simple 50/page (cursor-based en V2). - GET /invoices/counts : compteurs par statut pour les chips dashboard, requête agrégée groupBy. - GET /invoices/:id : détail enrichi avec client + plan préchargés + timeline composée par buildTimeline() (étapes du plan calées sur due_date, états past/current/future). - POST /invoices : saisie manuelle. Résolution client en 3 étapes (clientId → match par nom → création à la volée avec email REQUIS, sinon 422 client_email_required). Bonus +1 rubis à la création. - POST /invoices/:id/mark-paid : status=paid + paid_at + bonus +1 rubis (sur invoice + sur organization.rubis_count). Idempotent. L'ordre des routes /invoices/counts AVANT /invoices/:id est critique sinon `:id` matche "counts". Branche les vraies stats : - ClientStats : agrégation PG une seule requête (count, count actives, count en retard, paid_count, sum paid_cents, sum pending_cents, last_activity) avec FILTER clauses et casting enum::text. Plus de TODO/zéros. - PlansController : usageCount calculé pareil (factures actives référençant le plan). Skip pour l'instant (ImportBatch domain à venir) : POST /invoices/upload, GET /invoices/import-batch/*, validate/skip drafts.
26 lines
649 B
TypeScript
26 lines
649 B
TypeScript
import { type SchemaRules } from '@adonisjs/lucid/types/schema_generator'
|
|
|
|
/**
|
|
* Override de types pour les colonnes que Lucid n'arrive pas à inférer
|
|
* depuis l'introspection PG (ex. ENUMs natifs → tapés `any` par défaut).
|
|
*/
|
|
export default {
|
|
tables: {
|
|
plan_steps: {
|
|
columns: {
|
|
tone: {
|
|
tsType: "'amical' | 'courtois' | 'ferme' | 'mise_en_demeure'",
|
|
},
|
|
},
|
|
},
|
|
invoices: {
|
|
columns: {
|
|
status: {
|
|
tsType:
|
|
"'pending' | 'awaiting_user_confirmation' | 'in_relance' | 'paid' | 'litigation' | 'cancelled'",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
} satisfies SchemaRules
|