Files
maria_uslugi/public/praticien/modifier.php
T

812 lines
29 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
require_once __DIR__ . '/../includes/init_praticien.php';
$id = $_SESSION['reference_id'] ?? null;
if (! $id) {
http_response_code(403);
exit('Forbidden');
}
$currentLang = $lang ?? 'ru';
if (! in_array($currentLang, ['ru', 'fr', 'en'], true)) {
$currentLang = 'ru';
}
$isRu = ($currentLang === 'ru');
$ro = $isRu ? '' : 'readonly';
$dis = $isRu ? '' : 'disabled';
/**
* Upsert traduction
*/
function upsertPraticienTraduction(PDO $pdo, int $praticienId, string $langue, array $data): void
{
$sql = "
INSERT INTO praticien_traduction (
praticien_id,
langue,
nom_affiche,
prenom_affiche,
ville_affichee,
titre,
specialite,
presentation,
disponibilite,
statut,
created_at,
updated_at
) VALUES (
:praticien_id,
:langue,
:nom_affiche,
:prenom_affiche,
:ville_affichee,
:titre,
:specialite,
:presentation,
:disponibilite,
:statut,
NOW(),
NOW()
)
ON DUPLICATE KEY UPDATE
nom_affiche = VALUES(nom_affiche),
prenom_affiche = VALUES(prenom_affiche),
ville_affichee = VALUES(ville_affichee),
titre = VALUES(titre),
specialite = VALUES(specialite),
presentation = VALUES(presentation),
disponibilite = VALUES(disponibilite),
statut = VALUES(statut),
updated_at = NOW()
";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'praticien_id' => $praticienId,
'langue' => $langue,
'nom_affiche' => $data['nom_affiche'],
'prenom_affiche' => $data['prenom_affiche'],
'ville_affichee' => $data['ville_affichee'],
'titre' => $data['titre'],
'specialite' => $data['specialite'],
'presentation' => $data['presentation'],
'disponibilite' => $data['disponibilite'],
'statut' => $data['statut'],
]);
}
/**
* Lecture traduction par langue
*/
function getPraticienTraduction(PDO $pdo, int $praticienId, string $langue): ?array
{
$stmt = $pdo->prepare("
SELECT *
FROM praticien_traduction
WHERE praticien_id = ? AND langue = ?
LIMIT 1
");
$stmt->execute([$praticienId, $langue]);
$row = $stmt->fetch();
return $row ?: null;
}
/**
* Translittération simple cyrillique -> latin
* Suffisant pour test / affichage.
*/
function transliterateToLatin(string $text): string
{
$map = [
'А' => 'A', 'а' => 'a', 'Б' => 'B', 'б' => 'b', 'В' => 'V', 'в' => 'v', 'Г' => 'G', 'г' => 'g',
'Д' => 'D', 'д' => 'd', 'Е' => 'E', 'е' => 'e', 'Ё' => 'Yo', 'ё' => 'yo', 'Ж' => 'Zh', 'ж' => 'zh',
'З' => 'Z', 'з' => 'z', 'И' => 'I', 'и' => 'i', 'Й' => 'Y', 'й' => 'y', 'К' => 'K', 'к' => 'k',
'Л' => 'L', 'л' => 'l', 'М' => 'M', 'м' => 'm', 'Н' => 'N', 'н' => 'n', 'О' => 'O', 'о' => 'o',
'П' => 'P', 'п' => 'p', 'Р' => 'R', 'р' => 'r', 'С' => 'S', 'с' => 's', 'Т' => 'T', 'т' => 't',
'У' => 'U', 'у' => 'u', 'Ф' => 'F', 'ф' => 'f', 'Х' => 'Kh', 'х' => 'kh', 'Ц' => 'Ts', 'ц' => 'ts',
'Ч' => 'Ch', 'ч' => 'ch', 'Ш' => 'Sh', 'ш' => 'sh', 'Щ' => 'Shch', 'щ' => 'shch',
'Ы' => 'Y', 'ы' => 'y', 'Э' => 'E', 'э' => 'e', 'Ю' => 'Yu', 'ю' => 'yu', 'Я' => 'Ya', 'я' => 'ya',
'Ь' => '', 'ь' => '', 'Ъ' => '', 'ъ' => '',
];
return strtr($text, $map);
}
/**
* Stub traduction.
* Pour l’instant :
* - renvoie le texte tel quel si pas de vrai moteur branché
* - tu pourras remplacer ici par DeepL/API plus tard
*/
function translateText(string $text, string $sourceLang, string $targetLang): string
{
$text = trim($text);
if ($text === '') {
return '';
}
$sourceLang = strtoupper($sourceLang);
$targetLang = strtoupper($targetLang);
if ($sourceLang === $targetLang) {
return $text;
}
if (! defined('DEEPL_API_KEY') || DEEPL_API_KEY === '') {
throw new RuntimeException('Clé API DeepL manquante.');
}
$endpoint = 'https://api-free.deepl.com/v2/translate';
$postFields = http_build_query([
'text' => $text,
'source_lang' => $sourceLang,
'target_lang' => $targetLang,
]);
$ch = curl_init($endpoint);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postFields,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 20,
CURLOPT_HTTPHEADER => [
'Authorization: DeepL-Auth-Key ' . DEEPL_API_KEY,
'Content-Type: application/x-www-form-urlencoded',
],
]);
$response = curl_exec($ch);
$httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlErr = curl_error($ch);
curl_close($ch);
if ($response === false || $curlErr) {
throw new RuntimeException('Erreur réseau DeepL : ' . $curlErr);
}
if ($httpCode < 200 || $httpCode >= 300) {
throw new RuntimeException('Erreur DeepL HTTP ' . $httpCode . ' : ' . $response);
}
$data = json_decode($response, true);
if (
! is_array($data)
|| empty($data['translations'])
|| ! isset($data['translations'][0]['text'])
) {
throw new RuntimeException('Réponse DeepL invalide.');
}
return trim($data['translations'][0]['text']);
}
/**
* Détecte si une traduction est manuelle
*/
function isManualTranslation(?array $row): bool
{
return isset($row['statut']) && $row['statut'] === 'manuel';
}
/**
* Synchronise les traductions à partir de la source RU dans praticien
* - ru toujours sync
* - fr/en mis à jour seulement si absents ou non manuels
*/
function syncTranslationsFromSource(PDO $pdo, array $praticien): void
{
$praticienId = (int) $praticien['id'];
$ruData = [
'nom_affiche' => $praticien['nom'] ?? '',
'prenom_affiche' => $praticien['prenom'] ?? '',
'ville_affichee' => $praticien['ville'] ?? '',
'titre' => $praticien['titre'] ?? '',
'specialite' => $praticien['specialite'] ?? '',
'presentation' => $praticien['presentation'] ?? '',
'disponibilite' => $praticien['disponibilite'] ?? '',
'statut' => 'auto',
];
upsertPraticienTraduction($pdo, $praticienId, 'ru', $ruData);
foreach (['fr', 'en'] as $langue) {
$existing = getPraticienTraduction($pdo, $praticienId, $langue);
if ($existing && isManualTranslation($existing)) {
continue;
}
$nomLatin = transliterateToLatin((string) ($praticien['nom'] ?? ''));
$prenomLatin = transliterateToLatin((string) ($praticien['prenom'] ?? ''));
try {
$data = [
'nom_affiche' => $nomLatin,
'prenom_affiche' => $prenomLatin,
'ville_affichee' => translateText((string) ($praticien['ville'] ?? ''), 'RU', $langue),
'titre' => translateText((string) ($praticien['titre'] ?? ''), 'RU', $langue),
'specialite' => translateText((string) ($praticien['specialite'] ?? ''), 'RU', $langue),
'presentation' => translateText((string) ($praticien['presentation'] ?? ''), 'RU', $langue),
'disponibilite' => translateText((string) ($praticien['disponibilite'] ?? ''), 'RU', $langue),
'statut' => 'auto',
];
} catch (Throwable $e) {
error_log('DeepL translation error [' . $langue . '] praticien_id=' . $praticienId . ' : ' . $e->getMessage());
//die($e->getMessage());
$data = [
'nom_affiche' => $nomLatin,
'prenom_affiche' => $prenomLatin,
'ville_affichee' => (string) ($praticien['ville'] ?? ''),
'titre' => (string) ($praticien['titre'] ?? ''),
'specialite' => (string) ($praticien['specialite'] ?? ''),
'presentation' => (string) ($praticien['presentation'] ?? ''),
'disponibilite' => (string) ($praticien['disponibilite'] ?? ''),
'statut' => 'erreur',
];
}
upsertPraticienTraduction($pdo, $praticienId, $langue, $data);
}
}
// Base praticien
$stmt = $pdo->prepare("SELECT * FROM praticien WHERE id = ?");
$stmt->execute([$id]);
$praticien = $stmt->fetch();
if (! $praticien) {
die(htmlspecialchars($translations['praticien_introuvable'] ?? 'Introuvable.'));
}
// Traduction langue courante
$traduction = getPraticienTraduction($pdo, (int) $id, $currentLang);
// Valeurs formulaire avec fallback
$formNom = $traduction['nom_affiche'] ?? $praticien['nom'] ?? '';
$formPrenom = $traduction['prenom_affiche'] ?? $praticien['prenom'] ?? '';
$formVilleAffichee = $traduction['ville_affichee'] ?? $praticien['ville'] ?? '';
$formTitre = $traduction['titre'] ?? $praticien['titre'] ?? '';
$formSpecialite = $traduction['specialite'] ?? $praticien['specialite'] ?? '';
$formPresentation = $traduction['presentation'] ?? $praticien['presentation'] ?? '';
$formDispo = $traduction['disponibilite'] ?? $praticien['disponibilite'] ?? '';
// ==== POST ====
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
require_post_csrf();
$titre = trim($_POST['titre'] ?? '');
$nomAffiche = trim($_POST['nom'] ?? '');
$prenomAffiche = trim($_POST['prenom'] ?? '');
$telephone = trim($_POST['telephone'] ?? '');
$specialite = trim($_POST['specialite'] ?? '');
$adresse = trim($_POST['adresse'] ?? '');
$ville = trim($_POST['ville'] ?? '');
$code_postal = trim($_POST['code_postal'] ?? '');
$presentation = trim($_POST['presentation'] ?? '');
$duree_rdv = (int) ($_POST['duree_rdv'] ?? 60);
$disponibilite = trim($_POST['disponibilite'] ?? '');
$photo = $praticien['photo'] ?? null;
if ($specialite === '' || $presentation === '') {
die(htmlspecialchars($translations['err_champs_obligatoires'] ?? 'Merci de remplir les champs obligatoires.'));
}
// En FR/EN on ignore tout update des champs globaux même si quelqu’un bidouille le HTML
if (! $isRu) {
$telephone = $praticien['telephone'] ?? '';
$adresse = $praticien['adresse'] ?? '';
$ville = $praticien['ville'] ?? '';
$code_postal = $praticien['code_postal'] ?? '';
$duree_rdv = (int) ($praticien['duree_rdv'] ?? 60);
}
// Upload photo : uniquement RU
if ($isRu && ! empty($_FILES['photo']['tmp_name'])) {
$file = $_FILES['photo'];
$maxSize = 5 * 1024 * 1024;
if ($file['size'] > $maxSize) {
die("Erreur : Le fichier est trop volumineux (max 5 Mo).");
}
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($file['tmp_name']);
$allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (! in_array($mimeType, $allowedMimeTypes, true)) {
die("Erreur : Type de fichier non autorisé (Seuls JPG, PNG, GIF et WEBP sont acceptés).");
}
$nom_nettoye = strtolower(preg_replace('/[^A-Za-z0-9]/', '', transliterateToLatin($nomAffiche)));
$prenom_nettoye = strtolower(preg_replace('/[^A-Za-z0-9]/', '', transliterateToLatin($prenomAffiche)));
$nouveau_nom_fichier = $nom_nettoye . '_' . $prenom_nettoye . '_' . time() . '.png';
$chemin_destination = __DIR__ . '/../uploads/' . $nouveau_nom_fichier;
$image_source = @imagecreatefromstring(file_get_contents($file['tmp_name']));
if (! $image_source) {
die("Erreur : Le fichier image semble corrompu.");
}
[$largeur_orig, $hauteur_orig] = getimagesize($file['tmp_name']);
$largeur_max = 800;
if ($largeur_orig > $largeur_max) {
$ratio = $largeur_max / $largeur_orig;
$nouvelle_largeur = $largeur_max;
$nouvelle_hauteur = (int) ($hauteur_orig * $ratio);
} else {
$nouvelle_largeur = $largeur_orig;
$nouvelle_hauteur = $hauteur_orig;
}
$image_dest = imagecreatetruecolor($nouvelle_largeur, $nouvelle_hauteur);
imagealphablending($image_dest, false);
imagesavealpha($image_dest, true);
imagecopyresampled(
$image_dest,
$image_source,
0, 0, 0, 0,
$nouvelle_largeur,
$nouvelle_hauteur,
$largeur_orig,
$hauteur_orig
);
if (imagepng($image_dest, $chemin_destination, 7)) {
if (! empty($praticien['photo'])) {
$ancien_chemin = __DIR__ . '/../uploads/' . $praticien['photo'];
if (file_exists($ancien_chemin)) {
unlink($ancien_chemin);
}
}
$photo = $nouveau_nom_fichier;
}
imagedestroy($image_source);
imagedestroy($image_dest);
}
$pdo->beginTransaction();
try {
if ($isRu) {
$siret = preg_replace('/\D/', '', $_POST['siret'] ?? '');
if (strlen($siret) !== 14) {
throw new RuntimeException($translations['siret_format_invalide'] ?? 'SIRET invalide (14 chiffres).');
}
$luhnOk = (function ($num) {
$sum = 0;
$alt = false;
for ($i = strlen($num) - 1; $i >= 0; $i--) {
$n = (int) $num[$i];
if ($alt) {
$n *= 2;
if ($n > 9) {
$n -= 9;
}
}
$sum += $n;
$alt = ! $alt;
}
return $sum % 10 === 0;
})($siret);
if (! $luhnOk) {
throw new RuntimeException($translations['siret_format_invalide'] ?? 'SIRET invalide (Luhn).');
}
$chk = $pdo->prepare("SELECT id FROM praticien WHERE siret = :s AND id <> :id LIMIT 1");
$chk->execute(['s' => $siret, 'id' => $id]);
if ($chk->fetch()) {
throw new RuntimeException($translations['err_siret_deja_utilise'] ?? 'Ce SIRET est déjà utilisé.');
}
$stmt = $pdo->prepare("
UPDATE praticien SET
titre = :titre,
nom = :nom,
prenom = :prenom,
telephone = :telephone,
specialite = :specialite,
adresse = :adresse,
ville = :ville,
code_postal = :code_postal,
presentation = :presentation,
photo = :photo,
disponibilite = :disponibilite,
duree_rdv = :duree_rdv,
siret = :siret,
langue_source = 'ru'
WHERE id = :id
");
$stmt->execute([
'titre' => $titre,
'nom' => $nomAffiche,
'prenom' => $prenomAffiche,
'telephone' => $telephone,
'specialite' => $specialite,
'adresse' => $adresse,
'ville' => $ville,
'code_postal' => $code_postal,
'presentation' => $presentation,
'photo' => $photo,
'disponibilite' => $disponibilite,
'duree_rdv' => $duree_rdv,
'siret' => $siret,
'id' => $id,
]);
// Recharge la source après update
$stmt = $pdo->prepare("SELECT * FROM praticien WHERE id = ?");
$stmt->execute([$id]);
$praticien = $stmt->fetch();
if (! $praticien) {
throw new RuntimeException('Praticien introuvable après mise à jour.');
}
syncTranslationsFromSource($pdo, $praticien);
} else {
upsertPraticienTraduction($pdo, (int) $id, $currentLang, [
'nom_affiche' => $nomAffiche,
'prenom_affiche' => $prenomAffiche,
'ville_affichee' => $traduction['ville_affichee'] ?? $praticien['ville'] ?? '',
'titre' => $titre,
'specialite' => $specialite,
'presentation' => $presentation,
'disponibilite' => $disponibilite,
'statut' => 'manuel',
]);
}
$pdo->commit();
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
die(htmlspecialchars($e->getMessage()));
}
header('Location: /public/praticien/informations.php');
exit;
}
$PAGE_TITLE = $translations['modifier_infos_title'];
$HEAD_EXTRA = <<<HTML
<style>
.message-erreur {
color: red;
font-size: 0.9em;
display: none;
margin-bottom: 10px;
}
</style>
HTML;
require_once __DIR__ . '/../includes/header.php';
?>
<div class="main1">
<div class="container py-5">
<form id="form-praticien-edit" method="POST" enctype="multipart/form-data" class="shadow p-4 rounded bg-light">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars(ensure_csrf_token(), ENT_QUOTES, 'UTF-8'); ?>">
<h2 class="text-center mb-4"><?php echo htmlspecialchars($translations['modifier_infos_title']) ?></h2>
<div class="mb-3">
<label class="form-label"><?php echo htmlspecialchars($translations['label_nom']) ?> *</label>
<input type="text" name="nom" class="form-control" value="<?php echo htmlspecialchars($formNom) ?>" required>
</div>
<div class="mb-3">
<label class="form-label"><?php echo htmlspecialchars($translations['label_prenom']) ?> *</label>
<input type="text" name="prenom" class="form-control" value="<?php echo htmlspecialchars($formPrenom) ?>" required>
</div>
<div class="mb-3">
<label class="form-label"><?php echo htmlspecialchars($translations['label_telephone']) ?> *</label>
<input type="tel" name="telephone" id="telephone" class="form-control"
value="<?php echo htmlspecialchars($praticien['telephone'] ?? '') ?>"
required
placeholder="+33600000000"
pattern="^\+?[1-9]\d{6,14}$"
title="<?php echo htmlspecialchars($translations['telephone_format_message'] ?? '') ?>"
<?php echo $ro; ?>>
</div>
<div class="mb-3">
<label class="form-label"><?php echo htmlspecialchars($translations['placeholder_siret']) ?> *</label>
<input type="text"
name="siret"
id="siret"
class="form-control"
value="<?php echo htmlspecialchars($praticien['siret'] ?? '') ?>"
required
maxlength="17"
inputmode="numeric"
pattern="[0-9 ]+"
>
<div id="siret-feedback" class="message-erreur" style="display:none;"></div>
</div>
<div class="mb-3">
<label class="form-label"><?php echo htmlspecialchars($translations['label_specialite']) ?> *</label>
<input type="text" name="specialite" class="form-control" value="<?php echo htmlspecialchars($formSpecialite) ?>" required>
</div>
<div class="mb-3">
<label class="form-label"><?php echo htmlspecialchars($translations['tarif_consultation']) ?></label>
<input type="text" name="titre" class="form-control" value="<?php echo htmlspecialchars($formTitre) ?>">
</div>
<div class="mb-3">
<label class="form-label"><?php echo htmlspecialchars($translations['moyens_payement']) ?></label>
<input type="text" name="disponibilite" class="form-control" value="<?php echo htmlspecialchars($formDispo) ?>">
</div>
<div class="mb-3 position-relative">
<label class="form-label"><?php echo htmlspecialchars($translations['label_adresse']) ?></label>
<textarea name="adresse" id="adresse" class="form-control" <?php echo $ro; ?>><?php echo htmlspecialchars($praticien['adresse'] ?? '') ?></textarea>
<ul id="suggestions"></ul>
</div>
<div class="mb-3">
<label class="form-label"><?php echo htmlspecialchars($translations['label_ville']) ?></label>
<input type="text" name="ville" id="ville" class="form-control"
value="<?php echo htmlspecialchars($praticien['ville'] ?? '') ?>" readonly>
</div>
<div class="mb-3">
<label class="form-label"><?php echo htmlspecialchars($translations['label_code_postal']) ?></label>
<input type="text" name="code_postal" id="code_postal" class="form-control"
value="<?php echo htmlspecialchars($praticien['code_postal'] ?? '') ?>"
<?php echo $ro; ?>>
</div>
<div class="mb-3">
<label class="form-label"><?php echo htmlspecialchars($translations['label_presentation']) ?> *</label>
<textarea name="presentation" class="form-control" required><?php echo htmlspecialchars($formPresentation) ?></textarea>
</div>
<div class="mb-3">
<label class="form-label"><?php echo htmlspecialchars($translations['label_duree_rdv']) ?></label>
<input type="number" name="duree_rdv" class="form-control"
value="<?php echo (int) ($praticien['duree_rdv'] ?? 60); ?>"
min="15" max="180" required
<?php echo $ro; ?>>
</div>
<div class="mb-3">
<label class="form-label"><?php echo htmlspecialchars($translations['label_photo']) ?></label>
<input type="file" name="photo" class="form-control" accept="image/*" <?php echo $dis; ?>>
</div>
<?php if (! empty($praticien['photo'])): ?>
<div class="mb-3">
<p><?php echo htmlspecialchars($translations['photo_actuelle']) ?></p>
<img src="/public/uploads/<?php echo htmlspecialchars($praticien['photo']) ?>"
class="img-fluid rounded-4 shadow"
style="width:230px;height:auto;">
</div>
<?php endif; ?>
<div class="mt-4 text-center">
<button type="submit" class="btn btn-primary"><?php echo htmlspecialchars($translations['btn_enregistrer']) ?></button>
</div>
<?php echo $translations['champs_obligatoire'] ?>
</form>
</div>
<script>
const tel = document.getElementById('telephone');
tel?.addEventListener('input', function () {
const pos = this.selectionStart;
this.value = this.value.replace(/[\s\-._()/]/g, '');
try { this.setSelectionRange(pos, pos); } catch(_) {}
});
tel?.addEventListener('blur', function() {
let val = this.value.trim().replace(/[\s\-._()/]/g, '');
if (val.startsWith('00')) val = '+' + val.slice(2);
if (/^0\d{9}$/.test(val)) val = '+33' + val.substring(1);
if (val && !val.startsWith('+')) val = '+' + val;
this.value = val;
});
tel?.form?.addEventListener('submit', function (e) {
tel.dispatchEvent(new Event('blur'));
if (!tel.checkValidity()) {
e.preventDefault();
tel.reportValidity();
tel.focus();
}
});
document.addEventListener("DOMContentLoaded", function () {
const adresseInput = document.getElementById("adresse");
const villeInput = document.getElementById("ville");
const cpInput = document.getElementById("code_postal");
const suggestions = document.getElementById("suggestions");
if (adresseInput.hasAttribute('readonly')) {
return;
}
function buildStreet(props) {
const num = (props.housenumber || '').trim();
const street = (props.street || props.name || '').trim();
return [num, street].filter(Boolean).join(' ');
}
function getCity(props) {
if (props.city) return props.city;
if (props.context) {
const parts = props.context.split(',').map(s => s.trim());
return parts[1] || parts[0] || '';
}
return '';
}
let abortCtrl = null;
adresseInput.addEventListener("input", function () {
const query = adresseInput.value.trim();
if (query.length < 3) {
suggestions.innerHTML = '';
return;
}
try { abortCtrl?.abort(); } catch(_) {}
abortCtrl = new AbortController();
fetch("https://api-adresse.data.gouv.fr/search/?limit=5&q=" + encodeURIComponent(query), {
signal: abortCtrl.signal
})
.then(res => res.json())
.then(data => {
suggestions.innerHTML = '';
(data.features || []).forEach(feature => {
const props = feature.properties || {};
const li = document.createElement("li");
li.className = 'list-group-item list-group-item-action';
li.textContent = props.label || buildStreet(props);
li.addEventListener("click", function () {
adresseInput.value = buildStreet(props);
villeInput.value = getCity(props);
cpInput.value = props.postcode || '';
suggestions.innerHTML = '';
});
suggestions.appendChild(li);
});
})
.catch(() => {});
});
document.addEventListener("click", function (e) {
if (!suggestions.contains(e.target) && e.target !== adresseInput) {
suggestions.innerHTML = '';
}
});
});
</script>
<script>
function luhnCheck(num) {
const arr = (num + '').split('').reverse().map(x => parseInt(x, 10));
const sum = arr.reduce((acc, val, i) => {
if (i % 2) { val *= 2; if (val > 9) val -= 9; }
return acc + val;
}, 0);
return (sum % 10) === 0;
}
(function(){
const form = document.getElementById('form-praticien-edit');
const siretInput = document.getElementById('siret');
const feedback = document.getElementById('siret-feedback');
if (!siretInput || siretInput.hasAttribute('readonly')) {
return;
}
form.dataset.siretExists = '0';
let debounceId = null;
let lastQueried = '';
const MSG = {
invalide: '<?php echo addslashes($translations["siret_format_invalide"] ?? "Numéro SIRET invalide.") ?>',
valide: '<?php echo addslashes($translations["siret_valide_format"] ?? "Format SIRET valide.") ?>',
existe: '<?php echo addslashes($translations["siret_trouve"] ?? "Numéro reconnu dans la base INSEE.") ?>',
nexiste: '<?php echo addslashes($translations["siret_non_trouve"] ?? "Numéro introuvable dans la base INSEE.") ?>',
attente: '<?php echo addslashes($translations["siret_verification_en_cours"] ?? "Vérification en cours…") ?>'
};
function formatSiret(value) {
value = value.replace(/\D/g, '');
if (value.length > 3) value = value.slice(0,3) + ' ' + value.slice(3);
if (value.length > 7) value = value.slice(0,7) + ' ' + value.slice(7);
if (value.length > 11) value = value.slice(0,11) + ' ' + value.slice(11);
return value;
}
function setFeedback(text, color) {
feedback.textContent = text;
feedback.style.color = color;
feedback.style.display = 'block';
}
document.addEventListener('DOMContentLoaded', () => {
if (/^\d{14}$/.test(siretInput.value)) {
siretInput.value = formatSiret(siretInput.value);
}
});
function checkSiretImmediate() {
const formatted = formatSiret(siretInput.value);
if (siretInput.value !== formatted) siretInput.value = formatted;
const raw = siretInput.value.replace(/\s+/g, '');
if (raw.length === 0) { feedback.style.display = 'none'; form.dataset.siretExists = '0'; return; }
if (raw.length !== 14) { setFeedback(MSG.invalide, 'red'); form.dataset.siretExists = '0'; return; }
if (!luhnCheck(raw)) { setFeedback(MSG.invalide, 'red'); form.dataset.siretExists = '0'; return; }
setFeedback(MSG.attente, '#666');
form.dataset.siretExists = '0';
if (raw === lastQueried) return;
lastQueried = raw;
clearTimeout(debounceId);
debounceId = setTimeout(() => {
fetch('/../../js/ajax_verif_siret.php?siret=' + encodeURIComponent(raw))
.then(r => r.json())
.then(data => {
if (data && data.exists) {
setFeedback(MSG.existe, 'green');
form.dataset.siretExists = '1';
} else {
setFeedback(MSG.nexiste, 'red');
form.dataset.siretExists = '0';
}
})
.catch(() => {
setFeedback(MSG.nexiste, 'red');
form.dataset.siretExists = '0';
});
}, 500);
}
siretInput.addEventListener('input', checkSiretImmediate);
form.addEventListener('submit', function(e){
const raw = siretInput.value.replace(/\s+/g, '');
if (raw.length !== 14 || !luhnCheck(raw)) {
e.preventDefault();
setFeedback(MSG.invalide, 'red');
siretInput.focus();
return;
}
siretInput.value = raw;
});
})();
</script>
</div>
<footer class="site-footer">
<div class="container">
<p><?php echo $translations['copyr'] ?></p>
</div>
</footer>
</body>
</html>