longevity: revisione finale - codice cliente non riusabile, ruoli allineati, middleware verificato
- creaCliente: il codice si deduce dal massimo fra identity E longevity (non piu' solo identity), cosi' un client_code cancellato dall'anagrafica non torna mai disponibile e non si attribuiscono le misure di un vecchio cliente a uno nuovo. Compensazione se la scrittura su longevity fallisce dopo quella su identity. - ROLES unica fonte in auth.ts (Role e isRole derivati); users.astro e users/new.astro usano quella lista invece di array scritti a mano che dimenticavano cliente/trainer. - Commento falso su cosa protegge il middleware, riscritto: rimanda a isProtectedPath. - vitest.config.ts: alias per astro:middleware (stesso bersaglio della pipeline vite di Astro), cosi' src/middleware.ts e' finalmente importabile e testabile in isolamento - prima nessun test lo caricava davvero. - export.test.ts: asserzione posizionale per colonna, non piu' solo intestazioni scritte a mano; intercetta un riordino della SELECT che disallinea etichette e valori. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,28 @@
|
||||
// la annullerebbe in silenzio. Un test in tests/longevity/anagrafica.test.ts lo verifica.
|
||||
import type Database from 'better-sqlite3';
|
||||
|
||||
/**
|
||||
* Il prossimo codice libero: il massimo fra quelli già usati in identity.clienti E in
|
||||
* longevity.soggetti. Dedurlo da una sola metà è il bug che permette di riassegnare il
|
||||
* codice di un cliente cancellato dall'anagrafica (le sue misure restano in longevity)
|
||||
* a una persona nuova: qui non torna mai disponibile.
|
||||
*/
|
||||
function prossimoCodice(identity: Database.Database, longevity: Database.Database): string {
|
||||
const numero = (code: string) => Number(code.slice(4));
|
||||
const ultimoIdentity = identity.prepare(
|
||||
`SELECT client_code FROM clienti ORDER BY client_code DESC LIMIT 1`
|
||||
).get() as { client_code: string } | undefined;
|
||||
const ultimoLongevity = longevity.prepare(
|
||||
`SELECT client_code FROM soggetti ORDER BY client_code DESC LIMIT 1`
|
||||
).get() as { client_code: string } | undefined;
|
||||
|
||||
const max = Math.max(
|
||||
ultimoIdentity ? numero(ultimoIdentity.client_code) : 0,
|
||||
ultimoLongevity ? numero(ultimoLongevity.client_code) : 0,
|
||||
);
|
||||
return `ISL-${String(max + 1).padStart(4, '0')}`;
|
||||
}
|
||||
|
||||
export function creaCliente(
|
||||
identity: Database.Database,
|
||||
longevity: Database.Database,
|
||||
@@ -13,11 +35,7 @@ export function creaCliente(
|
||||
data_nascita?: string; email?: string; telefono?: string; user_id?: number;
|
||||
}
|
||||
): string {
|
||||
const ultimo = identity.prepare(
|
||||
`SELECT client_code FROM clienti ORDER BY client_code DESC LIMIT 1`
|
||||
).get() as { client_code: string } | undefined;
|
||||
const n = ultimo ? Number(ultimo.client_code.slice(4)) + 1 : 1;
|
||||
const code = `ISL-${String(n).padStart(4, '0')}`;
|
||||
const code = prossimoCodice(identity, longevity);
|
||||
|
||||
identity.prepare(
|
||||
`INSERT INTO clienti (client_code, user_id, nome, cognome, data_nascita, email, telefono)
|
||||
@@ -25,7 +43,15 @@ export function creaCliente(
|
||||
).run(code, dati.user_id ?? null, dati.nome, dati.cognome,
|
||||
dati.data_nascita ?? null, dati.email ?? null, dati.telefono ?? null);
|
||||
|
||||
longevity.prepare(`INSERT INTO soggetti (client_code, sesso) VALUES (?, ?)`).run(code, dati.sesso);
|
||||
try {
|
||||
longevity.prepare(`INSERT INTO soggetti (client_code, sesso) VALUES (?, ?)`).run(code, dati.sesso);
|
||||
} catch (err) {
|
||||
// Compensazione: due database distinti, quindi nessuna transazione unica possibile.
|
||||
// Se longevity rifiuta il cliente non deve restarne uno orfano in identity, senza
|
||||
// corrispettivo nell'altro database.
|
||||
identity.prepare(`DELETE FROM clienti WHERE client_code = ?`).run(code);
|
||||
throw err;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user