From 2c49c924aa8c15ce42901cbab8a35d2539f5891a Mon Sep 17 00:00:00 2001 From: fabiodalez-dev Date: Wed, 21 Oct 2026 16:48:26 +0000 Subject: [PATCH] Say "au plus tard" in French, pin the loan durations the suites rely on The French sentence said "retour avant le D", which excludes the day the server still accepts; "retour au plus tard le D" includes it, as the Italian "entro il" does. The two database-backed suites now pin the default and maximum loan durations for the run and restore the installation's values in their cleanup, so they no longer depend on what the environment configures. The browser spec snapshots the title's derived columns and restores them, since an auto-approved request recomputes them. --- locale/fr_FR.json | 4 ++-- ...n-request-capped-by-scheduled-loan.spec.js | 9 +++++++++ tests/loan-window-cap.unit.php | 19 ++++++++++++++++++- tests/loan-window-surfaces.unit.php | 11 ++++++++--- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/locale/fr_FR.json b/locale/fr_FR.json index a924a0cfb..f69906595 100644 --- a/locale/fr_FR.json +++ b/locale/fr_FR.json @@ -8374,9 +8374,9 @@ "Se lo stesso file è allegato anche ad altre schede, vale la visibilità più aperta tra quelle schede.": "Si le même fichier est aussi joint à d’autres notices, la visibilité la plus ouverte parmi ces notices s’applique.", "Gestione allegati digitali comprende anche l’apertura degli allegati riservati: chi può cambiare la visibilità di un file può comunque aprirlo, quindi i due permessi vengono salvati insieme.": "La gestion des pièces jointes numériques comprend aussi l’ouverture des pièces jointes réservées : qui peut modifier la visibilité d’un fichier peut de toute façon l’ouvrir, les deux autorisations sont donc enregistrées ensemble.", "Diritti esistenti": "Droits existants", - "Durata massima del prestito: %1$d giorni (restituzione entro il %2$s). Dal %3$s il libro è già prenotato.": "Durée maximale du prêt : %1$d jours (retour avant le %2$s). À partir du %3$s, le livre est déjà réservé.", + "Durata massima del prestito: %1$d giorni (restituzione entro il %2$s). Dal %3$s il libro è già prenotato.": "Durée maximale du prêt : %1$d jours (retour au plus tard le %2$s). À partir du %3$s, le livre est déjà réservé.", "Giorno non disponibile (%1$s): %2$s": "Jour non disponible (%1$s) : %2$s", "Il periodo richiesto supera la durata massima consentita.": "La période demandée dépasse la durée maximale de prêt autorisée.", "Da questa data di inizio non è possibile alcun prestito: dal %s il libro è già prenotato. Scegli un'altra data.": "Aucun prêt n'est possible à partir de cette date : à partir du %s, le livre est déjà réservé. Choisissez une autre date.", - "Durata massima del prestito: 1 giorno (restituzione entro il %1$s). Dal %2$s il libro è già prenotato.": "Durée maximale du prêt : 1 jour (retour avant le %1$s). À partir du %2$s, le livre est déjà réservé." + "Durata massima del prestito: 1 giorno (restituzione entro il %1$s). Dal %2$s il libro è già prenotato.": "Durée maximale du prêt : 1 jour (retour au plus tard le %1$s). À partir du %2$s, le livre est déjà réservé." } diff --git a/tests/loan-request-capped-by-scheduled-loan.spec.js b/tests/loan-request-capped-by-scheduled-loan.spec.js index 904eaf80d..d3f475266 100644 --- a/tests/loan-request-capped-by-scheduled-loan.spec.js +++ b/tests/loan-request-capped-by-scheduled-loan.spec.js @@ -84,6 +84,7 @@ test.describe('Book page: loan request capped by a scheduled loan', () => { let copyId = 0; let seededLoanId = 0; let borrowerId = 0; + let bookSnapshot = ''; let today = ''; const RUN = Date.now().toString(36).slice(-6); const BORROWER_EMAIL = `lw-cap-${RUN}@example.invalid`; @@ -109,6 +110,9 @@ test.describe('Book page: loan request capped by a scheduled loan', () => { ); if (!bookId) return; copyId = parseInt(dbQuery(`SELECT id FROM copie WHERE libro_id=${bookId} LIMIT 1`) || '0', 10); + // The request may be auto-approved (loans.auto_approve_requests), which + // recomputes the title's derived columns: restore them afterwards. + bookSnapshot = dbQuery(`SELECT CONCAT(IFNULL(copie_disponibili,'NULL'),'\t',IFNULL(stato,'')) FROM libri WHERE id=${bookId}`); // The application's clock (DateHelper::today(): app.timezone, default // Europe/Rome), not the database session's: near midnight they differ. const tz = dbQuery("SELECT setting_value FROM system_settings WHERE category='app' AND setting_key='timezone' LIMIT 1") || 'Europe/Rome'; @@ -140,6 +144,11 @@ test.describe('Book page: loan request capped by a scheduled loan', () => { dbQuery(`DELETE FROM prestiti WHERE id=${seededLoanId}`); dbQuery(`DELETE FROM prestiti WHERE libro_id=${bookId} AND utente_id=(SELECT id FROM utenti WHERE email='${ADMIN_EMAIL.replace(/'/g, "''")}' LIMIT 1) AND data_prestito>='${today}'`); dbQuery(`UPDATE copie SET stato='disponibile' WHERE id=${copyId}`); + const [avail, stato] = bookSnapshot.split('\t'); + if (avail !== undefined && stato !== undefined) { + const availSql = avail === 'NULL' ? 'NULL' : String(parseInt(avail, 10) || 0); + dbQuery(`UPDATE libri SET copie_disponibili=${availSql}, stato='${stato.replace(/'/g, "''")}' WHERE id=${bookId}`); + } } if (borrowerId) { dbQuery(`DELETE FROM prestiti WHERE utente_id=${borrowerId}`); diff --git a/tests/loan-window-cap.unit.php b/tests/loan-window-cap.unit.php index 6b50b60dd..c63f96ef1 100644 --- a/tests/loan-window-cap.unit.php +++ b/tests/loan-window-cap.unit.php @@ -66,7 +66,17 @@ $bookIds = []; /** @var int[] $userIds */ $userIds = []; -$cleanup = static function () use ($db, &$bookIds, &$userIds): void { +/** @var array $savedLoanSettings */ +$savedLoanSettings = []; +$cleanup = static function () use ($db, &$bookIds, &$userIds, &$savedLoanSettings): void { + $settings = new SettingsRepository($db); + foreach ($savedLoanSettings as $key => $value) { + if ($value === null) { + $settings->delete('loans', $key); + } else { + $settings->set('loans', $key, $value); + } + } foreach ($bookIds as $id) { $db->query("DELETE FROM prestiti WHERE libro_id = {$id}"); $db->query("DELETE FROM prenotazioni WHERE libro_id = {$id}"); @@ -138,6 +148,13 @@ }; $settings = new SettingsRepository($db); +// The scenario needs a default longer than the conflict offset: pin the two +// durations for the run (the installation's values are restored by $cleanup). +foreach (['loan_duration_days', 'max_loan_duration_days'] as $key) { + $savedLoanSettings[$key] = $settings->get('loans', $key); +} +$settings->set('loans', 'loan_duration_days', '30'); +$settings->set('loans', 'max_loan_duration_days', '90'); $defaultDays = $settings->loanDurationDays(); $maxDays = max(1, (int) ($settings->get('loans', 'max_loan_duration_days', '90') ?? 90)); $defaultDays = min($defaultDays, $maxDays); diff --git a/tests/loan-window-surfaces.unit.php b/tests/loan-window-surfaces.unit.php index 3753fc00b..9d470fe20 100644 --- a/tests/loan-window-surfaces.unit.php +++ b/tests/loan-window-surfaces.unit.php @@ -170,6 +170,13 @@ }; $settings = new SettingsRepository($db); +// The scenario needs a default longer than the conflict offset: pin the two +// durations for the run (the installation's values are restored by $cleanup). +foreach (['loan_duration_days', 'max_loan_duration_days'] as $key) { + $savedLoanSettings[$key] = $settings->get('loans', $key); +} +$settings->set('loans', 'loan_duration_days', '30'); +$settings->set('loans', 'max_loan_duration_days', '90'); $maxDays = max(1, (int) ($settings->get('loans', 'max_loan_duration_days', '90') ?? 90)); $defaultDays = min($settings->loanDurationDays(), $maxDays); $offset = max(2, min(5, $defaultDays - 1)); @@ -405,9 +412,7 @@ // A lower configured maximum must govern every default, including Mobile API // requests without end_date. A commitment at +10 must not reject a valid 7-day // request just because the configured standard duration is 30 days. -foreach (['loan_duration_days', 'max_loan_duration_days'] as $key) { - $savedLoanSettings[$key] = $settings->get('loans', $key); -} +// The installation's values were saved at the top; $cleanup restores them. $settings->set('loans', 'loan_duration_days', '30'); $settings->set('loans', 'max_loan_duration_days', '7'); [$boundedBook, $boundedCopies] = $mkBook(1, 3);