Publier Globinours 1.0.0-rc.3
This commit is contained in:
parent
ea8c24d622
commit
9a2b4068da
325 changed files with 38230 additions and 20 deletions
305
app/Controllers/DeathController.php
Normal file
305
app/Controllers/DeathController.php
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
final class DeathController
|
||||
{
|
||||
public const CAUSES = [
|
||||
'disease' => 'Maladie',
|
||||
'accident' => 'Accident',
|
||||
'old_age' => 'Vieillesse',
|
||||
'congenital' => 'Malformation ou affection congénitale',
|
||||
'surgery_complication' => 'Complication médicale ou chirurgicale',
|
||||
'poisoning' => 'Empoisonnement',
|
||||
'unknown' => 'Cause inconnue',
|
||||
'other' => 'Autre cause',
|
||||
];
|
||||
public const PLACES = [
|
||||
'refuge' => 'Au refuge',
|
||||
'fa' => 'En famille d’accueil',
|
||||
'veterinaire' => 'Chez le vétérinaire',
|
||||
'exterieur' => 'À l’extérieur',
|
||||
'inconnu' => 'Lieu inconnu',
|
||||
'autre' => 'Autre lieu',
|
||||
];
|
||||
public const DISPOSITIONS = [
|
||||
'pending' => 'À organiser',
|
||||
'collective_cremation' => 'Crémation collective',
|
||||
'individual_cremation' => 'Crémation individuelle',
|
||||
'returned_family' => 'Corps ou cendres remis à la famille',
|
||||
'burial' => 'Inhumation',
|
||||
'other' => 'Autre prise en charge',
|
||||
];
|
||||
|
||||
public static function causeLabel(string $key): string
|
||||
{
|
||||
return t('death.cause.' . $key, [], self::CAUSES[$key] ?? $key);
|
||||
}
|
||||
public static function placeLabel(string $key): string
|
||||
{
|
||||
return t('death.place.' . $key, [], self::PLACES[$key] ?? $key);
|
||||
}
|
||||
public static function dispositionLabel(string $key): string
|
||||
{
|
||||
return t('death.disposition.' . $key, [], self::DISPOSITIONS[$key] ?? $key);
|
||||
}
|
||||
|
||||
public static function form(): void
|
||||
{
|
||||
$db = DB::pdo();
|
||||
$id = (int) ($_GET['id'] ?? 0);
|
||||
$animal = self::animal($db, $id);
|
||||
$stmt = $db->prepare(
|
||||
'SELECT ad.*,vet.name veterinarian_name,crem.name crematorium_name FROM animal_deaths ad LEFT JOIN directory_contacts vet ON vet.id=ad.veterinarian_contact_id LEFT JOIN directory_contacts crem ON crem.id=ad.crematorium_contact_id WHERE ad.animal_id=:id',
|
||||
);
|
||||
$stmt->execute([':id' => $id]);
|
||||
$death = $stmt->fetch(PDO::FETCH_ASSOC) ?: [
|
||||
'animal_id' => $id,
|
||||
'deceased_date' => date('Y-m-d'),
|
||||
'cause_code' => 'disease',
|
||||
'cause_details' => '',
|
||||
'occurred_in_care' => !in_array($animal['status'], ['adopte', 'adopté'], true) ? 1 : 0,
|
||||
'place_type' => 'refuge',
|
||||
'place_details' => '',
|
||||
'euthanized' => 0,
|
||||
'veterinarian_contact_id' => '',
|
||||
'crematorium_contact_id' => '',
|
||||
'body_disposition' => 'pending',
|
||||
'cremation_date' => '',
|
||||
'notes' => '',
|
||||
];
|
||||
$veterinarians = self::contacts($db, 'veterinaire');
|
||||
$crematoriums = self::contacts($db, 'crematorium');
|
||||
render('animal_death_form.php', [
|
||||
'title' => t('death.title', ['name' => $animal['name']]),
|
||||
'animal' => $animal,
|
||||
'death' => $death,
|
||||
'causes' => self::CAUSES,
|
||||
'places' => self::PLACES,
|
||||
'dispositions' => self::DISPOSITIONS,
|
||||
'veterinarians' => $veterinarians,
|
||||
'crematoriums' => $crematoriums,
|
||||
]);
|
||||
}
|
||||
|
||||
public static function save(): void
|
||||
{
|
||||
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
|
||||
http_response_code(405);
|
||||
return;
|
||||
}
|
||||
$db = DB::pdo();
|
||||
$id = (int) ($_POST['animal_id'] ?? 0);
|
||||
$animal = self::animal($db, $id);
|
||||
$date = trim((string) ($_POST['deceased_date'] ?? ''));
|
||||
$cause = (string) ($_POST['cause_code'] ?? '');
|
||||
$place = (string) ($_POST['place_type'] ?? '');
|
||||
$disposition = (string) ($_POST['body_disposition'] ?? 'pending');
|
||||
if (
|
||||
!self::validDate($date) ||
|
||||
$date > date('Y-m-d') ||
|
||||
!isset(self::CAUSES[$cause]) ||
|
||||
!isset(self::PLACES[$place]) ||
|
||||
!isset(self::DISPOSITIONS[$disposition])
|
||||
) {
|
||||
http_response_code(400);
|
||||
echo h(t('death.invalid'));
|
||||
return;
|
||||
}
|
||||
if ($cause === 'other' && trim((string) ($_POST['cause_details'] ?? '')) === '') {
|
||||
http_response_code(400);
|
||||
echo h(t('death.cause_required'));
|
||||
return;
|
||||
}
|
||||
$vet = self::validContact($db, (int) ($_POST['veterinarian_contact_id'] ?? 0), 'veterinaire');
|
||||
$crem = self::validContact($db, (int) ($_POST['crematorium_contact_id'] ?? 0), 'crematorium');
|
||||
$cremationDate = trim((string) ($_POST['cremation_date'] ?? ''));
|
||||
if ($cremationDate !== '' && (!self::validDate($cremationDate) || $cremationDate < $date)) {
|
||||
http_response_code(400);
|
||||
echo h(t('death.cremation_after'));
|
||||
return;
|
||||
}
|
||||
$check = $db->prepare('SELECT 1 FROM animal_deaths WHERE animal_id=:id');
|
||||
$check->execute([':id' => $id]);
|
||||
$isUpdate = (bool) $check->fetchColumn();
|
||||
$beforeLocation = LocationHistoryService::snapshot($animal);
|
||||
$params = [
|
||||
':animal' => $id,
|
||||
':date' => $date,
|
||||
':cause' => $cause,
|
||||
':details' => trim((string) ($_POST['cause_details'] ?? '')) ?: null,
|
||||
':care' => isset($_POST['occurred_in_care']) ? 1 : 0,
|
||||
':place' => $place,
|
||||
':place_details' => trim((string) ($_POST['place_details'] ?? '')) ?: null,
|
||||
':euthanized' => isset($_POST['euthanized']) ? 1 : 0,
|
||||
':vet' => $vet,
|
||||
':crem' => $crem,
|
||||
':disposition' => $disposition,
|
||||
':cremation_date' => $cremationDate ?: null,
|
||||
':notes' => trim((string) ($_POST['notes'] ?? '')) ?: null,
|
||||
':user' => Auth::id(),
|
||||
];
|
||||
$db->beginTransaction();
|
||||
try {
|
||||
$db->prepare(
|
||||
"INSERT INTO animal_deaths(animal_id,deceased_date,cause_code,cause_details,occurred_in_care,place_type,place_details,euthanized,veterinarian_contact_id,crematorium_contact_id,body_disposition,cremation_date,notes,created_by,updated_by) VALUES(:animal,:date,:cause,:details,:care,:place,:place_details,:euthanized,:vet,:crem,:disposition,:cremation_date,:notes,:user,:user) ON CONFLICT(animal_id) DO UPDATE SET deceased_date=excluded.deceased_date,cause_code=excluded.cause_code,cause_details=excluded.cause_details,occurred_in_care=excluded.occurred_in_care,place_type=excluded.place_type,place_details=excluded.place_details,euthanized=excluded.euthanized,veterinarian_contact_id=excluded.veterinarian_contact_id,crematorium_contact_id=excluded.crematorium_contact_id,body_disposition=excluded.body_disposition,cremation_date=excluded.cremation_date,notes=excluded.notes,updated_by=excluded.updated_by,updated_at=datetime('now')",
|
||||
)->execute($params);
|
||||
$db->prepare(
|
||||
"UPDATE animals SET status='decede',refuge_room=NULL,care_box_key=NULL,updated_at=datetime('now') WHERE id=:id",
|
||||
)->execute([':id' => $id]);
|
||||
LocationHistoryService::record(
|
||||
$db,
|
||||
$id,
|
||||
$beforeLocation,
|
||||
[
|
||||
'status' => 'decede',
|
||||
'refuge_room' => null,
|
||||
'care_box_key' => null,
|
||||
'current_address' => $animal['current_address'] ?? null,
|
||||
],
|
||||
'death',
|
||||
'Décès enregistré',
|
||||
$date . ' 12:00:00',
|
||||
);
|
||||
$db->prepare(
|
||||
'UPDATE treatments SET ongoing=0,end_date=COALESCE(end_date,:date) WHERE animal_id=:id AND ongoing=1',
|
||||
)->execute([':date' => $date, ':id' => $id]);
|
||||
$details =
|
||||
'Date : ' .
|
||||
self::frDate($date) .
|
||||
'\nCause : ' .
|
||||
self::CAUSES[$cause] .
|
||||
'\nContexte : ' .
|
||||
($params[':care'] ? 'Sous la responsabilité du refuge' : 'Après la prise en charge du refuge');
|
||||
if ($params[':euthanized']) {
|
||||
$details .= '\nEuthanasie : oui';
|
||||
}
|
||||
$db->prepare(
|
||||
"INSERT INTO animal_history(animal_id,type,label,details,user_id) VALUES(:id,'death',:label,:details,:user)",
|
||||
)->execute([
|
||||
':id' => $id,
|
||||
':label' => $isUpdate ? 'Informations de décès modifiées' : 'Décès enregistré',
|
||||
':details' => $details,
|
||||
':user' => Auth::id(),
|
||||
]);
|
||||
self::syncMovement(
|
||||
$db,
|
||||
$id,
|
||||
$date,
|
||||
$cause,
|
||||
$params[':details'],
|
||||
$place,
|
||||
$params[':place_details'],
|
||||
$params[':euthanized'] === 1,
|
||||
$vet,
|
||||
$crem,
|
||||
$disposition,
|
||||
);
|
||||
$db->commit();
|
||||
header('Location: /animal?id=' . $id);
|
||||
exit();
|
||||
} catch (Throwable $e) {
|
||||
if ($db->inTransaction()) {
|
||||
$db->rollBack();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private static function animal(PDO $db, int $id): array
|
||||
{
|
||||
$s = $db->prepare('SELECT * FROM animals WHERE id=:id AND deleted_at IS NULL');
|
||||
$s->execute([':id' => $id]);
|
||||
$a = $s->fetch(PDO::FETCH_ASSOC);
|
||||
if (!$a) {
|
||||
http_response_code(404);
|
||||
echo h(t('error.animal_not_found'));
|
||||
exit();
|
||||
}
|
||||
return $a;
|
||||
}
|
||||
private static function contacts(PDO $db, string $role): array
|
||||
{
|
||||
$s = $db->prepare(
|
||||
'SELECT dc.id,dc.name,dc.city FROM directory_contacts dc JOIN directory_contact_roles r ON r.contact_id=dc.id WHERE r.role=:role AND dc.deleted_at IS NULL ORDER BY dc.name COLLATE NOCASE',
|
||||
);
|
||||
$s->execute([':role' => $role]);
|
||||
return $s->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
private static function validContact(PDO $db, int $id, string $role): ?int
|
||||
{
|
||||
if (!$id) {
|
||||
return null;
|
||||
}
|
||||
$s = $db->prepare(
|
||||
'SELECT 1 FROM directory_contacts dc JOIN directory_contact_roles r ON r.contact_id=dc.id WHERE dc.id=:id AND r.role=:role AND dc.deleted_at IS NULL',
|
||||
);
|
||||
$s->execute([':id' => $id, ':role' => $role]);
|
||||
return $s->fetchColumn() ? $id : null;
|
||||
}
|
||||
private static function syncMovement(
|
||||
PDO $db,
|
||||
int $animalId,
|
||||
string $date,
|
||||
string $cause,
|
||||
?string $causeDetails,
|
||||
string $place,
|
||||
?string $placeDetails,
|
||||
bool $euthanized,
|
||||
?int $vetId,
|
||||
?int $cremId,
|
||||
string $disposition,
|
||||
): void {
|
||||
$names = [];
|
||||
if ($vetId || $cremId) {
|
||||
$s = $db->prepare('SELECT id,name FROM directory_contacts WHERE id IN (:vet,:crem)');
|
||||
$s->execute([':vet' => $vetId ?? 0, ':crem' => $cremId ?? 0]);
|
||||
foreach ($s->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
||||
$names[(int) $row['id']] = $row['name'];
|
||||
}
|
||||
}
|
||||
$noteParts = ['Cause : ' . self::CAUSES[$cause] . ($causeDetails ? ' — ' . $causeDetails : '')];
|
||||
if ($euthanized) {
|
||||
$noteParts[] = 'Euthanasie : oui';
|
||||
}
|
||||
if ($cremId && isset($names[$cremId])) {
|
||||
$noteParts[] = 'Crématorium : ' . $names[$cremId];
|
||||
}
|
||||
$noteParts[] = 'Prise en charge : ' . self::DISPOSITIONS[$disposition];
|
||||
$s = $db->prepare(
|
||||
"SELECT id FROM animal_movements WHERE animal_id=:animal AND kind='exit' AND lower(lieu) IN ('décès','deces','décès de l''animal','deces de l''animal') ORDER BY id DESC LIMIT 1",
|
||||
);
|
||||
$s->execute([':animal' => $animalId]);
|
||||
$movementId = (int) $s->fetchColumn();
|
||||
$values = [
|
||||
':animal' => $animalId,
|
||||
':place' => self::PLACES[$place] . ($placeDetails ? ' — ' . $placeDetails : ''),
|
||||
':contact' => $vetId && isset($names[$vetId]) ? $names[$vetId] : null,
|
||||
':note' => implode("\n", $noteParts),
|
||||
':at' => $date . ' 12:00:00',
|
||||
];
|
||||
if ($movementId) {
|
||||
$values[':movement'] = $movementId;
|
||||
$db->prepare(
|
||||
"UPDATE animal_movements SET place=:place,lieu='Décès de l''animal',contact_name=:contact,note=:note,created_at=:at WHERE id=:movement AND animal_id=:animal",
|
||||
)->execute($values);
|
||||
} else {
|
||||
$db->prepare(
|
||||
"INSERT INTO animal_movements(animal_id,kind,place,lieu,contact_name,note,created_at) VALUES(:animal,'exit',:place,'Décès de l''animal',:contact,:note,:at)",
|
||||
)->execute($values);
|
||||
}
|
||||
}
|
||||
private static function validDate(string $date): bool
|
||||
{
|
||||
$d = DateTimeImmutable::createFromFormat('!Y-m-d', $date);
|
||||
$errors = DateTimeImmutable::getLastErrors();
|
||||
return $d !== false &&
|
||||
($errors === false || ((int) $errors['warning_count'] === 0 && (int) $errors['error_count'] === 0)) &&
|
||||
$d->format('Y-m-d') === $date;
|
||||
}
|
||||
private static function frDate(string $date): string
|
||||
{
|
||||
$d = DateTimeImmutable::createFromFormat('Y-m-d', $date);
|
||||
return $d ? $d->format('d/m/Y') : $date;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue