From a0ea338292ed1be0bc0bcb12e42080544c1efc45 Mon Sep 17 00:00:00 2001 From: oversu <95a7002b-481b-4ef3-b578-f9c421550aa4@localhost> Date: Sun, 13 Sep 2026 14:28:12 +0200 Subject: [PATCH] =?UTF-8?q?Horodate=20pr=C3=A9cis=C3=A9ment=20les=20contr?= =?UTF-8?q?=C3=B4les=20de=20soins?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 8 ++++++++ HISTORIQUE.md | 4 ++++ README.md | 2 +- VERSION | 2 +- app/Controllers/AnimalMedicalActions.php | 25 +++++++++++++++++++----- app/Views/_animal_show_modals.php | 13 +++++++++++- app/Views/evolutions.php | 8 ++++---- resources/lang/en.php | 1 + resources/lang/fr.php | 1 + tests/run.php | 8 ++++++++ 10 files changed, 60 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d4d7d8..c3aa7e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ Toutes les modifications importantes du projet sont consignées ici. Le format s’inspire de [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/) et le projet suit le [versionnage sémantique](https://semver.org/lang/fr/). +## [1.0.0-rc.19] — 2026-09-13 + +### Horodatage des contrôles de soins + +- ajout d’une date et d’une heure aux notes médicales, proposées à l’instant de la saisie et librement modifiables ; +- utilisation du même horodatage pour la note, la mesure de poids, le tarif associé et la date d’une éventuelle stérilisation ; +- validation stricte des dates et heures transmises avant enregistrement. + ## [1.0.0-rc.18] — 2026-09-09 ### Finitions du site public diff --git a/HISTORIQUE.md b/HISTORIQUE.md index bfbf5b0..e7efa40 100644 --- a/HISTORIQUE.md +++ b/HISTORIQUE.md @@ -81,3 +81,7 @@ Remplacement de la barre de navigation horizontale par un menu mobile repliable ## `1.0.0-rc.18` — Finitions du site public Déplacement des informations légales dans le pied de page, insertion guidée des images sans perdre les textes en cours d’édition et identification visuelle des réseaux sociaux. + +## `1.0.0-rc.19` — Contrôles de soins horodatés + +Ajout d’une date et d’une heure modifiables aux contrôles médicaux, avec reprise cohérente de l’instant choisi dans les mesures de poids et les données associées. diff --git a/README.md b/README.md index aa0a1fb..1800b24 100644 --- a/README.md +++ b/README.md @@ -200,7 +200,7 @@ L’option `--apply` ne doit être utilisée qu’après lecture des rapports. L ## État du projet -La candidate actuelle est `1.0.0-rc.18`. La branche 1.0 est gelée fonctionnellement : seuls les défauts bloquants découverts pendant les validations terrain sont corrigés avant `1.0.0`. +La candidate actuelle est `1.0.0-rc.19`. La branche 1.0 est gelée fonctionnellement : seuls les défauts bloquants découverts pendant les validations terrain sont corrigés avant `1.0.0`. Le contrôle de stabilisation est disponible dans [docs/AUDIT-1.0.md](docs/AUDIT-1.0.md). diff --git a/VERSION b/VERSION index 4744cd3..784e940 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0-rc.18 +1.0.0-rc.19 diff --git a/app/Controllers/AnimalMedicalActions.php b/app/Controllers/AnimalMedicalActions.php index 25452ab..3cd6172 100644 --- a/app/Controllers/AnimalMedicalActions.php +++ b/app/Controllers/AnimalMedicalActions.php @@ -221,6 +221,20 @@ trait AnimalMedicalActions $temperature = $_POST['temperature_c'] ?? null; $weight = $_POST['weight_kg'] ?? null; + $notedDate = trim((string) ($_POST['noted_date'] ?? date('Y-m-d'))); + $notedTime = trim((string) ($_POST['noted_time'] ?? date('H:i'))); + $observedAt = DateTimeImmutable::createFromFormat('!Y-m-d H:i', $notedDate . ' ' . $notedTime); + $dateErrors = DateTimeImmutable::getLastErrors(); + if ( + !$observedAt || + ($dateErrors !== false && ($dateErrors['warning_count'] > 0 || $dateErrors['error_count'] > 0)) || + $observedAt->format('Y-m-d H:i') !== $notedDate . ' ' . $notedTime + ) { + http_response_code(400); + echo h(t('error.invalid_medical_datetime')); + return; + } + $observedAtSql = $observedAt->format('Y-m-d H:i:s'); $clinicId = (int) ($_POST['clinic_id'] ?? 0); $clinicId = $clinicId > 0 ? $clinicId : null; @@ -251,13 +265,14 @@ trait AnimalMedicalActions // Enregistre la note médicale avant ses éventuelles pièces jointes. $stmt = $db->prepare(' INSERT INTO medical_notes - (animal_id, kind, reason, symptoms, exam, diagnosis, plan, temperature_c, weight_kg, clinic_id, vet_name, clinic_contact_id, vet_contact_id, created_by, created_at) + (animal_id, noted_at, kind, reason, symptoms, exam, diagnosis, plan, temperature_c, weight_kg, clinic_id, vet_name, clinic_contact_id, vet_contact_id, created_by, created_at) VALUES - (:aid, :kind, :reason, :symptoms, :exam, :diagnosis, :plan, :temp, :weight, :clinic, :vet, :clinic_contact, :vet_contact, :created_by, :created) + (:aid, :noted_at, :kind, :reason, :symptoms, :exam, :diagnosis, :plan, :temp, :weight, :clinic, :vet, :clinic_contact, :vet_contact, :created_by, :created) '); $stmt->execute([ ':aid' => $animalId, + ':noted_at' => $observedAtSql, ':kind' => $kind, ':reason' => $reason, ':symptoms' => $symptoms, @@ -282,7 +297,7 @@ trait AnimalMedicalActions $animalId, (int) $_POST['tariff_id'], 1, - substr(self::now(), 0, 10), + $observedAt->format('Y-m-d'), 'Ajoutée avec la note médicale', ); } @@ -344,7 +359,7 @@ trait AnimalMedicalActions ", )->execute([ ':aid' => $animalId, - ':at' => self::now(), + ':at' => $observedAtSql, ':v' => (float) $weight, ':created_by' => Auth::id(), ]); @@ -358,7 +373,7 @@ trait AnimalMedicalActions $db->prepare( "UPDATE animals SET sterilized=1,sterilization_status='yes',sterilization_date=COALESCE(sterilization_date,date(:date)),sterilization_vet_contact_id=COALESCE(:vet,sterilization_vet_contact_id),sterilization_clinic_contact_id=COALESCE(:clinic,sterilization_clinic_contact_id) WHERE id=:id", )->execute([ - ':date' => self::now(), + ':date' => $observedAtSql, ':vet' => $vetContact['id'] ?? null, ':clinic' => $clinicContact['id'] ?? null, ':id' => $animalId, diff --git a/app/Views/_animal_show_modals.php b/app/Views/_animal_show_modals.php index 4792870..7df107c 100644 --- a/app/Views/_animal_show_modals.php +++ b/app/Views/_animal_show_modals.php @@ -7,6 +7,7 @@ /** @var array $vaccines */ $defaultDue = date('Y-m-d', strtotime('+1 year')); $today = date('Y-m-d'); +$currentTime = date('H:i'); ?> @@ -612,6 +613,16 @@ $today = date('Y-m-d');
+
+ + +
+ +
+ + +
+
-
+
diff --git a/app/Views/evolutions.php b/app/Views/evolutions.php index 00b7f17..6df0f1c 100644 --- a/app/Views/evolutions.php +++ b/app/Views/evolutions.php @@ -31,10 +31,10 @@
- 1.0.0-rc.18 -

Site public

-

Informations légales accessibles sur chaque page, insertion guidée des images - dans les contenus et liens sociaux plus lisibles.

+ 1.0.0-rc.19 +

Suivi des soins

+

Date et heure modifiables pour distinguer précisément plusieurs contrôles et + mesures réalisés au cours d’une même journée.

diff --git a/resources/lang/en.php b/resources/lang/en.php index 9626db6..85d8c68 100644 --- a/resources/lang/en.php +++ b/resources/lang/en.php @@ -198,4 +198,5 @@ return [ 'updates.directory_failed'=>'Unable to prepare directory :path.', 'updates.download_log'=>'Download technical log', 'updates.log_missing'=>'No update log is available.', + 'error.invalid_medical_datetime'=>'Enter a valid check-up date and time.', ]; diff --git a/resources/lang/fr.php b/resources/lang/fr.php index febc145..928c849 100644 --- a/resources/lang/fr.php +++ b/resources/lang/fr.php @@ -198,4 +198,5 @@ return [ 'updates.directory_failed'=>'Impossible de préparer le dossier :path.', 'updates.download_log'=>'Télécharger le journal technique', 'updates.log_missing'=>'Aucun journal de mise à jour n’est disponible.', + 'error.invalid_medical_datetime'=>'Indiquez une date et une heure de contrôle valides.', ]; diff --git a/tests/run.php b/tests/run.php index 33457c5..2d29660 100644 --- a/tests/run.php +++ b/tests/run.php @@ -360,6 +360,14 @@ try { $assert((int) $db->query('SELECT COUNT(*) FROM adoptions')->fetchColumn() === 1); $assert(!$db->query('PRAGMA foreign_key_check')->fetchAll()); }); + $test('Les contrôles médicaux conservent leur date et leur heure', function () use ($assert): void { + $view = file_get_contents(__DIR__ . '/../app/Views/_animal_show_modals.php'); + $controller = file_get_contents(__DIR__ . '/../app/Controllers/AnimalMedicalActions.php'); + $assert(str_contains($view, 'name="noted_date"'), 'Le champ de date du contrôle est absent'); + $assert(str_contains($view, 'name="noted_time"'), 'Le champ d’heure du contrôle est absent'); + $assert(str_contains($controller, "':noted_at' => \$observedAtSql"), 'La note ne reprend pas l’instant choisi'); + $assert(str_contains($controller, "':at' => \$observedAtSql"), 'La courbe de poids ne reprend pas l’instant choisi'); + }); $test('La fiche annuaire agrège adoptions et dépenses', function () use ($db, $assert): void { $db->exec("INSERT INTO directory_contacts(kind,name) VALUES('organization','Structure test')"); $contact = (int) $db->lastInsertId();