longevity: anagrafica del gestionale — elenco, dettaglio, età, apertura fascicolo
elencoClienti/clienteDaCodice/etaDelCliente/apriFascicolo (versione operativa, sul singleton) affiancate alle rispettive versioni parametrizzate (elencoClientiParam/clienteDaCodiceParam/etaDelClienteParam), sullo stesso schema di codicePerUtente/codicePerUtenteLoggato: la parametrizzata resta testabile su un DB :memory:, l'operativa è quella che pagine ed endpoint del gestionale importano. apriFascicolo apre sempre senza user_id — l'accesso è #8, non questa unità — per costruzione del tipo di `dati`, non per convenzione. Refs #2 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
// risalga alla persona (richiesta del cliente, 21/08): un secondo punto di giunzione
|
||||
// la annullerebbe in silenzio. Un test in tests/longevity/anagrafica.test.ts lo verifica.
|
||||
import type Database from 'better-sqlite3';
|
||||
import { createIdentityDb } from './db';
|
||||
import { createIdentityDb, getLongevityDb } from './db';
|
||||
|
||||
// Connessione singola a identity, privata di questo modulo: non è esportata, quindi non
|
||||
// è raggiungibile da nessun'altra parte del codice, nemmeno con un re-export su più file
|
||||
@@ -94,3 +94,88 @@ export function etaAllaData(dataNascita: string, alla: string): number {
|
||||
if (m < 0 || (m === 0 && d.getDate() < n.getDate())) eta--;
|
||||
return eta;
|
||||
}
|
||||
|
||||
//
|
||||
// Gestionale del trainer (#2, unità 2a): tre letture sull'anagrafica e l'apertura di un
|
||||
// fascicolo, tutte sotto lo stesso vincolo di codicePerUtente/codicePerUtenteLoggato qui
|
||||
// sopra — una versione PARAMETRIZZATA (identity esplicita, esportata solo per i test e per
|
||||
// comporre da qui dentro) e una versione OPERATIVA (nessun argomento, apre da sola
|
||||
// getIdentityDb) che è quella che pagine ed endpoint del gestionale importano davvero. La
|
||||
// versione operativa non si può testare su un DB :memory: — il singleton è uno solo per
|
||||
// processo — quindi il test vero gira sulla parametrizzata, esattamente come
|
||||
// anagrafica.test.ts fa già con codicePerUtente invece di codicePerUtenteLoggato.
|
||||
//
|
||||
|
||||
export type ClienteElenco = {
|
||||
client_code: string;
|
||||
nome: string;
|
||||
cognome: string;
|
||||
data_nascita: string | null;
|
||||
/** True se il cliente ha già un account per vedere il proprio referto (user_id valorizzato
|
||||
* in identity.clienti). Creare quell'account è #8, fuori da questa unità: qui si legge
|
||||
* soltanto se esiste già. */
|
||||
ha_accesso: boolean;
|
||||
};
|
||||
|
||||
/** L'elenco dei clienti per la tabella del gestionale, ordinato per cognome poi nome —
|
||||
* l'ordine in cui un trainer cerca una persona, non l'ordine di creazione del fascicolo. */
|
||||
export function elencoClientiParam(identity: Database.Database): ClienteElenco[] {
|
||||
const righe = identity.prepare(
|
||||
`SELECT client_code, nome, cognome, data_nascita, user_id FROM clienti ORDER BY cognome, nome`
|
||||
).all() as { client_code: string; nome: string; cognome: string; data_nascita: string | null; user_id: number | null }[];
|
||||
return righe.map(({ user_id, ...resto }) => ({ ...resto, ha_accesso: user_id !== null }));
|
||||
}
|
||||
|
||||
export function elencoClienti(): ClienteElenco[] {
|
||||
return elencoClientiParam(getIdentityDb());
|
||||
}
|
||||
|
||||
export type ClienteDettaglio = ClienteElenco & {
|
||||
email: string | null;
|
||||
telefono: string | null;
|
||||
};
|
||||
|
||||
/** L'anagrafica di un cliente per la sua scheda nel gestionale, `null` se il codice non
|
||||
* esiste — la pagina lo traduce in un 404, non in uno schermo vuoto. */
|
||||
export function clienteDaCodiceParam(identity: Database.Database, code: string): ClienteDettaglio | null {
|
||||
const r = identity.prepare(
|
||||
`SELECT client_code, nome, cognome, data_nascita, email, telefono, user_id
|
||||
FROM clienti WHERE client_code = ?`
|
||||
).get(code) as
|
||||
{ client_code: string; nome: string; cognome: string; data_nascita: string | null;
|
||||
email: string | null; telefono: string | null; user_id: number | null } | undefined;
|
||||
if (!r) return null;
|
||||
const { user_id, ...resto } = r;
|
||||
return { ...resto, ha_accesso: user_id !== null };
|
||||
}
|
||||
|
||||
export function clienteDaCodice(code: string): ClienteDettaglio | null {
|
||||
return clienteDaCodiceParam(getIdentityDb(), code);
|
||||
}
|
||||
|
||||
/** L'età del cliente alla data indicata, `null` se non ha una data di nascita in anagrafica
|
||||
* (compilazione facoltativa: il fascicolo può nascere senza). Non è un ripiego a zero —
|
||||
* calcolaSessione tratta già `eta_alla_data: null` come "niente Fitness Age", stessa
|
||||
* barriera del motore (vedi l'intestazione di motore/index.ts). */
|
||||
export function etaDelClienteParam(identity: Database.Database, code: string, alla: string): number | null {
|
||||
const r = identity.prepare(`SELECT data_nascita FROM clienti WHERE client_code = ?`).get(code) as
|
||||
{ data_nascita: string | null } | undefined;
|
||||
if (!r?.data_nascita) return null;
|
||||
return etaAllaData(r.data_nascita, alla);
|
||||
}
|
||||
|
||||
export function etaDelCliente(code: string, alla: string): number | null {
|
||||
return etaDelClienteParam(getIdentityDb(), code, alla);
|
||||
}
|
||||
|
||||
/** Apre un fascicolo nuovo dal gestionale: SEMPRE senza user_id — creare l'account che
|
||||
* darebbe accesso al cliente è #8, non questa unità, e il tipo di `dati` qui sotto non
|
||||
* prevede quel campo (stessa garanzia strutturale di CorpoQuestionario nell'endpoint del
|
||||
* questionario: chi volesse passare uno user_id da qui non supererebbe `tsc --noEmit`).
|
||||
* Delega tutto a `creaCliente`, che è già la versione testabile con DB propri. */
|
||||
export function apriFascicolo(dati: {
|
||||
nome: string; cognome: string; sesso: 'M' | 'F';
|
||||
data_nascita?: string; email?: string; telefono?: string;
|
||||
}): string {
|
||||
return creaCliente(getIdentityDb(), getLongevityDb(), dati);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user