diff --git a/includes/lang/ca.php b/includes/lang/ca.php
index 04210d6..8cb568d 100644
--- a/includes/lang/ca.php
+++ b/includes/lang/ca.php
@@ -220,6 +220,7 @@ return [
'weather_cloudy' => 'Ennuvolat',
'weather_rainy' => 'Plujós',
'weather_snowy' => 'Nevat',
+ 'weather_historical' => 'Basat en l\'històric (estimació)',
// Anciennes clés Holidays non préfixées (conservades)
'outbound_trip' => 'Anada',
diff --git a/includes/lang/fr.php b/includes/lang/fr.php
index 416ed2b..faccd72 100644
--- a/includes/lang/fr.php
+++ b/includes/lang/fr.php
@@ -220,6 +220,7 @@ return [
'weather_cloudy' => 'Nuageux',
'weather_rainy' => 'Pluvieux',
'weather_snowy' => 'Neigeux',
+ 'weather_historical' => 'Basé sur l\'historique (estimation)',
// Anciennes clés Holidays non préfixées (conservées pour compatibilité si utilisées)
'outbound_trip' => 'Aller',
diff --git a/modules/holidays/holidays.js b/modules/holidays/holidays.js
index 99a6abf..75acdbc 100644
--- a/modules/holidays/holidays.js
+++ b/modules/holidays/holidays.js
@@ -49,10 +49,20 @@ async function loadWeatherForStep(pt) {
if (res.success) {
const info = getWeatherInfo(res.data.code);
+
+ // Si c'est une estimation basée sur le passé, on adapte l'affichage
+ const approxSymbol = res.data.is_historical ? "~" : "";
+ const badgeTitle = res.data.is_historical
+ ? `${info.label} (${tr("weather_historical")})`
+ : info.label;
+ const opacityStyle = res.data.is_historical
+ ? "opacity: 0.85; font-style: italic;"
+ : "";
+
container.innerHTML = `
-
+
${info.icon}
- ${Math.round(res.data.temp_min)}° / ${Math.round(res.data.temp_max)}°C
+ ${approxSymbol}${Math.round(res.data.temp_min)}° / ${Math.round(res.data.temp_max)}°C
`;
}
} catch (e) {
diff --git a/modules/holidays/includes/api/get_weather.php b/modules/holidays/includes/api/get_weather.php
index 3ac0012..c308b91 100644
--- a/modules/holidays/includes/api/get_weather.php
+++ b/modules/holidays/includes/api/get_weather.php
@@ -1,19 +1,18 @@
diff($targetDate);
$daysDiff = (int)$interval->format('%R%a');
-// 4. Choix du bon modèle météo (Prévisions vs Historique)
-if ($daysDiff < -2) {
+// --- 🧠 GESTION INTELLIGENTE DU TEMPS (Prévisions vs Historique) ---
+if ($daysDiff > 16) {
+ // 1. VOYAGE LOINTAIN : Calcul de la moyenne sur 3 ans
+ $currentYear = (int)$today->format('Y');
+ $monthDay = $targetDate->format('m-d');
+ if ($monthDay === '02-29') $monthDay = '02-28'; // Sécurité année bissextile
+
+ $tempMaxSum = 0;
+ $tempMinSum = 0;
+ $validYearsCount = 0;
+ $representativeCode = 0; // On gardera le code de l'année N-1
+
+ for ($i = 1; $i <= 3; $i++) {
+ $pastYear = $currentYear - $i;
+ $searchDate = $pastYear . '-' . $monthDay;
+
+ $url = "https://archive-api.open-meteo.com/v1/archive?latitude=$lat&longitude=$lng&daily=weather_code,temperature_2m_max,temperature_2m_min&timezone=auto&start_date=$searchDate&end_date=$searchDate";
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 2); // Timeout court pour ne pas ralentir le serveur
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ $res = curl_exec($ch);
+ curl_close($ch);
+
+ if ($res) {
+ $data = json_decode($res, true);
+ if (isset($data['daily']['temperature_2m_max'][0])) {
+ $tempMaxSum += $data['daily']['temperature_2m_max'][0];
+ $tempMinSum += $data['daily']['temperature_2m_min'][0];
+
+ if ($i === 1) { // On prend le temps qu'il a fait à N-1 pour l'icône
+ $representativeCode = $data['daily']['weather_code'][0];
+ }
+ $validYearsCount++;
+ }
+ }
+ }
+
+ // Si on a pu récupérer au moins une année de données
+ if ($validYearsCount > 0) {
+ echo json_encode([
+ 'success' => true,
+ 'data' => [
+ 'code' => $representativeCode,
+ 'temp_max' => round($tempMaxSum / $validYearsCount, 1), // Moyenne arrondie à 1 décimale
+ 'temp_min' => round($tempMinSum / $validYearsCount, 1),
+ 'is_historical' => true
+ ]
+ ]);
+ } else {
+ echo json_encode(['success' => false, 'message' => 'Archives indisponibles']);
+ }
+ exit; // On arrête l'exécution ici pour les voyages lointains
+
+} elseif ($daysDiff < -2) {
+ // 2. VOYAGE PASSÉ : On interroge les archives pour cette date précise
$baseUrl = "https://archive-api.open-meteo.com/v1/archive";
+ $searchDate = $date;
} else {
+ // 3. FUTUR PROCHE (Prévisions fiables) : On interroge les prévisions
$baseUrl = "https://api.open-meteo.com/v1/forecast";
+ $searchDate = $date;
}
-$url = "$baseUrl?latitude=$lat&longitude=$lng&daily=weather_code,temperature_2m_max,temperature_2m_min&timezone=auto&start_date=$date&end_date=$date";
+// --- APPEL API CLASSIQUE (Pour les prévisions et les voyages passés) ---
+$url = "$baseUrl?latitude=$lat&longitude=$lng&daily=weather_code,temperature_2m_max,temperature_2m_min&timezone=auto&start_date=$searchDate&end_date=$searchDate";
-// 5. Interrogation d'Open-Meteo via cURL (plus robuste)
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-curl_setopt($ch, CURLOPT_TIMEOUT, 5); // Timeout de 5 secondes max
-curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Contourne les erreurs SSL en local
-
+curl_setopt($ch, CURLOPT_TIMEOUT, 5);
+curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$res = curl_exec($ch);
-$curlError = curl_error($ch); // On capture l'erreur exacte au cas où
curl_close($ch);
if (!$res) {
- echo json_encode([
- 'success' => false,
- 'message' => 'Erreur API Open-Meteo',
- 'debug' => $curlError, // L'inspecteur JS nous donnera la vraie raison !
- 'url' => $url
- ]);
+ echo json_encode(['success' => false, 'message' => 'Erreur API Open-Meteo']);
exit;
}
-// 6. Formatage et envoi au Javascript
+
+$data = json_decode($res, true);
+
if (isset($data['daily']['weather_code'][0])) {
echo json_encode([
'success' => true,
'data' => [
'code' => $data['daily']['weather_code'][0],
'temp_max' => $data['daily']['temperature_2m_max'][0],
- 'temp_min' => $data['daily']['temperature_2m_min'][0]
+ 'temp_min' => $data['daily']['temperature_2m_min'][0],
+ 'is_historical' => false
]
]);
} else {
diff --git a/modules/holidays/views/detail.php b/modules/holidays/views/detail.php
index 510527b..7c4048a 100644
--- a/modules/holidays/views/detail.php
+++ b/modules/holidays/views/detail.php
@@ -386,7 +386,8 @@ window.I18N = {
'weather_cloudy': "= tr('weather_cloudy') ?>",
'weather_rainy': "= tr('weather_rainy') ?>",
'weather_snowy': "= tr('weather_snowy') ?>",
- 'weather_forecast': "= tr('weather_forecast') ?>"
+ 'weather_forecast': "= tr('weather_forecast') ?>",
+ 'weather_historical': "= tr('weather_historical') ?>"
};
// Fallback de sécurité pour s'assurer que les modales peuvent toujours se fermer