725 lines
33 KiB
PHP
725 lines
33 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace ESI_CRVI_AGENDA\models;
|
|
|
|
/**
|
|
* Modèle pour la table crvi_event_permission
|
|
*
|
|
* Cette table stocke les DISPONIBILITÉS de l'intervenant pour un événement :
|
|
* - Jours de la semaine disponibles (lundi, mardi, etc. - PAS des dates spécifiques)
|
|
* - Plages horaires disponibles
|
|
* - Indisponibilités ponctuelles (dates spécifiques où l'intervenant n'est pas disponible)
|
|
*
|
|
* OPTIMISATION : Permet de vérifier rapidement les disponibilités sans charger l'intervenant
|
|
*/
|
|
class Event_Permission_Model extends Main_Model {
|
|
public $id;
|
|
public $event_id;
|
|
public $jours_permis; // JSON array ["lundi", "mardi"] - JOURS DE LA SEMAINE de l'intervenant
|
|
public $plages_horaires; // JSON array [{"debut":"09:00","fin":"17:00"}] - Heures disponibles (intervenant)
|
|
public $indisponibilites; // JSON array - Indisponibilités ponctuelles de l'intervenant
|
|
public $traducteur_jours_permis; // JSON array - Jours de la semaine du traducteur (si présent)
|
|
public $traducteur_indisponibilites; // JSON array - Indisponibilités ponctuelles du traducteur (si présent)
|
|
public $local_indisponibilites; // JSON array - Indisponibilités ponctuelles du local
|
|
public $locaux_autories; // JSON array [1,2,3] (IDs de locaux)
|
|
public $departements_autories; // JSON array [1,2,3] (IDs de départements)
|
|
public $types_intervention_autories; // JSON array [1,2,3]
|
|
public $traducteurs_disponibles_par_langue; // JSON object {"fr": [1,2,3], "en": [4,5]} - IDs des traducteurs disponibles par langue
|
|
public $date_creation;
|
|
public $date_modification;
|
|
public $cree_par;
|
|
public $modifie_par;
|
|
|
|
/**
|
|
* Crée la table crvi_event_permission
|
|
*
|
|
* Stocke les disponibilités de l'intervenant pour chaque événement :
|
|
* - Jours de la semaine (lundi, mardi, etc.)
|
|
* - Plages horaires (heures disponibles)
|
|
* - Indisponibilités ponctuelles (dates spécifiques)
|
|
*/
|
|
public static function create_table() {
|
|
global $wpdb;
|
|
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
|
|
|
|
$table_name = $wpdb->prefix . 'crvi_event_permission';
|
|
$charset_collate = $wpdb->get_charset_collate();
|
|
|
|
// Vérifier si la table existe déjà
|
|
if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name) {
|
|
return; // La table existe déjà
|
|
}
|
|
|
|
$sql = "CREATE TABLE $table_name (
|
|
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
event_id BIGINT(20) UNSIGNED NOT NULL,
|
|
jours_permis TEXT DEFAULT NULL,
|
|
plages_horaires TEXT DEFAULT NULL,
|
|
indisponibilites TEXT DEFAULT NULL,
|
|
-- Disponibilités traducteur (si présent)
|
|
traducteur_jours_permis TEXT DEFAULT NULL,
|
|
traducteur_indisponibilites TEXT DEFAULT NULL,
|
|
-- Disponibilités local
|
|
local_indisponibilites TEXT DEFAULT NULL,
|
|
locaux_autories TEXT DEFAULT NULL,
|
|
departements_autories TEXT DEFAULT NULL,
|
|
types_intervention_autories TEXT DEFAULT NULL,
|
|
traducteurs_disponibles_par_langue TEXT DEFAULT NULL COMMENT 'Présets traducteurs disponibles par langue (JSON)',
|
|
date_creation DATETIME NOT NULL,
|
|
date_modification DATETIME DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
|
cree_par BIGINT(20) UNSIGNED DEFAULT NULL,
|
|
modifie_par BIGINT(20) UNSIGNED DEFAULT NULL,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY event_id (event_id),
|
|
KEY event_id_index (event_id)
|
|
) $charset_collate;";
|
|
|
|
// Si la table existe déjà, ajouter les nouvelles colonnes si nécessaire
|
|
if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name) {
|
|
// Ajouter les colonnes pour traducteur et local si elles n'existent pas
|
|
$columns_to_add = [
|
|
'traducteur_jours_permis' => 'ALTER TABLE ' . $table_name . ' ADD COLUMN traducteur_jours_permis TEXT DEFAULT NULL',
|
|
'traducteur_indisponibilites' => 'ALTER TABLE ' . $table_name . ' ADD COLUMN traducteur_indisponibilites TEXT DEFAULT NULL',
|
|
'local_indisponibilites' => 'ALTER TABLE ' . $table_name . ' ADD COLUMN local_indisponibilites TEXT DEFAULT NULL',
|
|
'traducteurs_disponibles_par_langue' => 'ALTER TABLE ' . $table_name . ' ADD COLUMN traducteurs_disponibles_par_langue TEXT DEFAULT NULL',
|
|
];
|
|
|
|
foreach ($columns_to_add as $column => $sql_add) {
|
|
$column_exists = $wpdb->get_results($wpdb->prepare(
|
|
"SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
|
|
WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s AND COLUMN_NAME = %s",
|
|
DB_NAME, $table_name, $column
|
|
));
|
|
|
|
if (empty($column_exists)) {
|
|
$wpdb->query($sql_add);
|
|
}
|
|
}
|
|
|
|
return; // Table existe, colonnes ajoutées si nécessaire
|
|
}
|
|
|
|
dbDelta($sql);
|
|
}
|
|
|
|
/**
|
|
* Crée les disponibilités à partir de l'intervenant, traducteur et local lors de la création d'un événement
|
|
*
|
|
* Stocke :
|
|
* - Les jours de la semaine disponibles (intervenant, traducteur)
|
|
* - Les plages horaires disponibles (intervenant)
|
|
* - Les indisponibilités ponctuelles (intervenant, traducteur, local)
|
|
* - Les traducteurs disponibles par langue (preset pour optimisation)
|
|
*
|
|
* @param int $event_id ID de l'événement
|
|
* @param int $intervenant_id ID de l'intervenant
|
|
* @param array|null $plages_horaires Plages horaires spécifiques (optionnel, pour les permanences)
|
|
* @param int|null $traducteur_id ID du traducteur (optionnel)
|
|
* @param int|null $local_id ID du local (optionnel)
|
|
* @param string|null $langue_slug Slug de la langue de l'événement (pour précalculer traducteurs disponibles)
|
|
* @param string|null $date_rdv Date de l'événement (pour précalculer traducteurs disponibles)
|
|
* @return bool|WP_Error
|
|
*/
|
|
public static function create_from_intervenant($event_id, $intervenant_id, $plages_horaires = null, $traducteur_id = null, $local_id = null, $langue_slug = null, $date_rdv = null) {
|
|
global $wpdb;
|
|
|
|
$intervenant = CRVI_Intervenant_Model::load($intervenant_id);
|
|
if (!$intervenant) {
|
|
return new \WP_Error('intervenant_not_found', 'Intervenant introuvable', ['status' => 404]);
|
|
}
|
|
|
|
// Extraire les jours de la semaine disponibles de l'intervenant (lundi, mardi, etc. - PAS des dates)
|
|
$jours_disponibles = get_field('jours_de_disponibilite', 'user_' . $intervenant_id);
|
|
$jours_permis = is_array($jours_disponibles) ? json_encode($jours_disponibles) : json_encode([]);
|
|
|
|
// Extraire les indisponibilités ponctuelles de l'intervenant
|
|
$indisponibilites_acf = get_field('indisponibilitee_ponctuelle', 'user_' . $intervenant_id);
|
|
$indisponibilites = is_array($indisponibilites_acf) ? json_encode($indisponibilites_acf) : json_encode([]);
|
|
|
|
// Extraire les départements et types d'intervention
|
|
$departements_autories = !empty($intervenant->departements_ids)
|
|
? json_encode($intervenant->departements_ids)
|
|
: json_encode([]);
|
|
|
|
$types_intervention_autories = !empty($intervenant->types_intervention_ids)
|
|
? json_encode($intervenant->types_intervention_ids)
|
|
: json_encode([]);
|
|
|
|
// Plages horaires : si fournies, les utiliser, sinon null
|
|
$plages_horaires_json = null;
|
|
if ($plages_horaires !== null && is_array($plages_horaires)) {
|
|
$plages_horaires_json = json_encode($plages_horaires);
|
|
}
|
|
|
|
// Traducteur : jours et indisponibilités (si présent)
|
|
$traducteur_jours_permis = null;
|
|
$traducteur_indisponibilites = null;
|
|
if ($traducteur_id) {
|
|
$traducteur = CRVI_Traducteur_Model::load($traducteur_id);
|
|
if ($traducteur) {
|
|
// Jours de disponibilité du traducteur
|
|
$traducteur_jours = get_field('jours_de_disponibilite', $traducteur_id);
|
|
$traducteur_jours_permis = is_array($traducteur_jours) ? json_encode($traducteur_jours) : json_encode([]);
|
|
|
|
// Indisponibilités ponctuelles du traducteur
|
|
$traducteur_indispo_acf = get_field('indisponibilitee_ponctuelle', $traducteur_id);
|
|
$traducteur_indisponibilites = is_array($traducteur_indispo_acf) ? json_encode($traducteur_indispo_acf) : json_encode([]);
|
|
}
|
|
}
|
|
|
|
// Local : indisponibilités (si présent)
|
|
$local_indisponibilites = null;
|
|
if ($local_id) {
|
|
$local = CRVI_Local_Model::load($local_id);
|
|
if ($local) {
|
|
// Indisponibilités ponctuelles du local (si le champ existe)
|
|
$local_indispo_acf = get_field('indisponibilitee_ponctuelle', $local_id);
|
|
$local_indisponibilites = is_array($local_indispo_acf) ? json_encode($local_indispo_acf) : json_encode([]);
|
|
}
|
|
}
|
|
|
|
// Précalculer les traducteurs disponibles par langue (preset pour optimisation)
|
|
$traducteurs_disponibles_par_langue = null;
|
|
if ($langue_slug && $date_rdv) {
|
|
$traducteurs_disponibles_par_langue = self::precalculate_traducteurs_par_langue($date_rdv, $langue_slug);
|
|
}
|
|
|
|
// Créer l'entrée de permission
|
|
$table_name = $wpdb->prefix . 'crvi_event_permission';
|
|
|
|
$result = $wpdb->insert($table_name, [
|
|
'event_id' => $event_id,
|
|
'jours_permis' => $jours_permis,
|
|
'plages_horaires' => $plages_horaires_json,
|
|
'indisponibilites' => $indisponibilites,
|
|
'traducteur_jours_permis' => $traducteur_jours_permis,
|
|
'traducteur_indisponibilites' => $traducteur_indisponibilites,
|
|
'local_indisponibilites' => $local_indisponibilites,
|
|
'departements_autories' => $departements_autories,
|
|
'types_intervention_autories' => $types_intervention_autories,
|
|
'traducteurs_disponibles_par_langue' => $traducteurs_disponibles_par_langue,
|
|
'date_creation' => current_time('mysql'),
|
|
'cree_par' => get_current_user_id(),
|
|
], [
|
|
'%d', // event_id
|
|
'%s', // jours_permis
|
|
'%s', // plages_horaires
|
|
'%s', // indisponibilites
|
|
'%s', // traducteur_jours_permis
|
|
'%s', // traducteur_indisponibilites
|
|
'%s', // local_indisponibilites
|
|
'%s', // departements_autories
|
|
'%s', // types_intervention_autories
|
|
'%s', // traducteurs_disponibles_par_langue
|
|
'%s', // date_creation
|
|
'%d', // cree_par
|
|
]);
|
|
|
|
return $result !== false;
|
|
}
|
|
|
|
/**
|
|
* Précalcule les IDs des traducteurs disponibles par langue pour une date donnée
|
|
*
|
|
* Retourne un tableau JSON avec les IDs des traducteurs disponibles pour chaque langue :
|
|
* {"fr": [1,2,3], "en": [4,5], "es": [2,6]}
|
|
*
|
|
* @param string $date_rdv Date au format Y-m-d
|
|
* @param string|null $langue_slug Slug de la langue principale (si null, calcule pour toutes les langues)
|
|
* @return string|null JSON string ou null
|
|
*/
|
|
private static function precalculate_traducteurs_par_langue($date_rdv, $langue_slug = null) {
|
|
// Récupérer toutes les langues ou seulement celle demandée
|
|
$langues_to_check = [];
|
|
if ($langue_slug) {
|
|
$term = get_term_by('slug', $langue_slug, 'langue');
|
|
if ($term) {
|
|
$langues_to_check[] = [
|
|
'slug' => $langue_slug,
|
|
'term_id' => $term->term_id,
|
|
];
|
|
}
|
|
} else {
|
|
// Récupérer toutes les langues
|
|
$terms = get_terms([
|
|
'taxonomy' => 'langue',
|
|
'hide_empty' => false,
|
|
]);
|
|
foreach ($terms as $term) {
|
|
$langues_to_check[] = [
|
|
'slug' => $term->slug,
|
|
'term_id' => $term->term_id,
|
|
];
|
|
}
|
|
}
|
|
|
|
if (empty($langues_to_check)) {
|
|
return null;
|
|
}
|
|
|
|
// Pour chaque langue, récupérer les traducteurs disponibles
|
|
$result = [];
|
|
foreach ($langues_to_check as $langue_info) {
|
|
$traducteurs_disponibles = CRVI_Traducteur_Model::filtrer_disponibles(
|
|
$date_rdv,
|
|
$langue_info['slug']
|
|
);
|
|
|
|
// Extraire les IDs des traducteurs disponibles
|
|
$ids = [];
|
|
foreach ($traducteurs_disponibles as $traducteur) {
|
|
if (isset($traducteur->id)) {
|
|
$ids[] = (int)$traducteur->id;
|
|
}
|
|
}
|
|
|
|
if (!empty($ids)) {
|
|
$result[$langue_info['slug']] = $ids;
|
|
}
|
|
}
|
|
|
|
return !empty($result) ? json_encode($result) : null;
|
|
}
|
|
|
|
/**
|
|
* Crée les disponibilités pour une permanence à partir des jours et heures sélectionnés dans le formulaire
|
|
*
|
|
* Stocke directement les jours et plages horaires sélectionnés dans le formulaire de création de permanences,
|
|
* sans charger les disponibilités générales de l'intervenant.
|
|
*
|
|
* @param int $event_id ID de l'événement (permanence)
|
|
* @param int $intervenant_id ID de l'intervenant
|
|
* @param array $jours_permis Jours de la semaine sélectionnés (ex: ["lundi", "mardi"])
|
|
* @param array $plages_horaires Plages horaires sélectionnées (ex: [{"debut":"11:00","fin":"15:00"}])
|
|
* @return bool|WP_Error
|
|
*/
|
|
public static function create_for_permanence($event_id, $intervenant_id, $jours_permis = [], $plages_horaires = []) {
|
|
global $wpdb;
|
|
|
|
// Vérifier que l'intervenant existe
|
|
$intervenant = CRVI_Intervenant_Model::load($intervenant_id);
|
|
if (!$intervenant) {
|
|
return new \WP_Error('intervenant_not_found', 'Intervenant introuvable', ['status' => 404]);
|
|
}
|
|
|
|
// Convertir les jours et plages horaires en JSON
|
|
$jours_permis_json = is_array($jours_permis) ? json_encode($jours_permis) : json_encode([]);
|
|
$plages_horaires_json = is_array($plages_horaires) ? json_encode($plages_horaires) : json_encode([]);
|
|
|
|
// Charger les indisponibilités ponctuelles de l'intervenant (pour les vérifications)
|
|
$indisponibilites_acf = get_field('indisponibilitee_ponctuelle', 'user_' . $intervenant_id);
|
|
$indisponibilites = is_array($indisponibilites_acf) ? json_encode($indisponibilites_acf) : json_encode([]);
|
|
|
|
// Extraire les départements et types d'intervention
|
|
$departements_autories = !empty($intervenant->departements_ids)
|
|
? json_encode($intervenant->departements_ids)
|
|
: json_encode([]);
|
|
|
|
$types_intervention_autories = !empty($intervenant->types_intervention_ids)
|
|
? json_encode($intervenant->types_intervention_ids)
|
|
: json_encode([]);
|
|
|
|
// Créer l'entrée de permission avec les jours et heures sélectionnés
|
|
$table_name = $wpdb->prefix . 'crvi_event_permission';
|
|
|
|
$result = $wpdb->insert($table_name, [
|
|
'event_id' => $event_id,
|
|
'jours_permis' => $jours_permis_json,
|
|
'plages_horaires' => $plages_horaires_json,
|
|
'indisponibilites' => $indisponibilites,
|
|
'traducteur_jours_permis' => null,
|
|
'traducteur_indisponibilites' => null,
|
|
'local_indisponibilites' => null,
|
|
'departements_autories' => $departements_autories,
|
|
'types_intervention_autories' => $types_intervention_autories,
|
|
'date_creation' => current_time('mysql'),
|
|
'cree_par' => get_current_user_id(),
|
|
], [
|
|
'%d', // event_id
|
|
'%s', // jours_permis
|
|
'%s', // plages_horaires
|
|
'%s', // indisponibilites
|
|
'%s', // traducteur_jours_permis
|
|
'%s', // traducteur_indisponibilites
|
|
'%s', // local_indisponibilites
|
|
'%s', // departements_autories
|
|
'%s', // types_intervention_autories
|
|
'%s', // date_creation
|
|
'%d', // cree_par
|
|
]);
|
|
|
|
return $result !== false;
|
|
}
|
|
|
|
/**
|
|
* Vérifie rapidement si une date/heure est disponible selon les disponibilités stockées
|
|
*
|
|
* Vérifie :
|
|
* - Si le jour de la semaine de la date correspond aux jours disponibles
|
|
* - Si l'heure est dans les plages horaires autorisées
|
|
* - Si la date n'est pas dans une période d'indisponibilité
|
|
*
|
|
* OPTIMISÉ : Une seule requête SQL, pas de chargement de modèle Intervenant
|
|
*
|
|
* @param int $event_id ID de l'événement
|
|
* @param string $date Date au format Y-m-d
|
|
* @param string $heure Heure au format H:i (optionnel, pour vérifier les plages horaires)
|
|
* @return bool|null true=disponible, false=non disponible, null=pas de disponibilité définie (fallback requis)
|
|
*/
|
|
public static function is_date_heure_authorized($event_id, $date, $heure = null) {
|
|
global $wpdb;
|
|
$table_name = $wpdb->prefix . 'crvi_event_permission';
|
|
|
|
// Requête optimisée : une seule requête SQL pour toutes les disponibilités
|
|
// Récupère intervenant, traducteur et local en une seule fois (si présents dans la table)
|
|
$permission = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT jours_permis, plages_horaires, indisponibilites,
|
|
traducteur_jours_permis, traducteur_indisponibilites,
|
|
local_indisponibilites
|
|
FROM $table_name
|
|
WHERE event_id = %d",
|
|
$event_id
|
|
), ARRAY_A);
|
|
|
|
if (!$permission) {
|
|
// Pas de permission définie, fallback vers l'intervenant
|
|
return null;
|
|
}
|
|
|
|
// Vérifier le jour de la semaine (lundi, mardi, etc. - pas une date spécifique)
|
|
$timestamp = strtotime($date);
|
|
if ($timestamp === false) {
|
|
return false;
|
|
}
|
|
|
|
$jour_semaine = (int)date('w', $timestamp); // 0=dimanche, 1=lundi, etc.
|
|
|
|
// Mapping jours français vers numériques (jours de la semaine)
|
|
$jours_mapping = [
|
|
'dimanche' => 0,
|
|
'lundi' => 1,
|
|
'mardi' => 2,
|
|
'mercredi' => 3,
|
|
'jeudi' => 4,
|
|
'vendredi' => 5,
|
|
'samedi' => 6,
|
|
];
|
|
|
|
// Vérifier si ce jour de la semaine est disponible
|
|
$jours_permis_json = $permission['jours_permis'] ?? '[]';
|
|
$jours_permis = json_decode($jours_permis_json, true) ?? [];
|
|
|
|
if (!empty($jours_permis)) {
|
|
$jours_permis_numeriques = [];
|
|
foreach ($jours_permis as $jour) {
|
|
$jour_lower = strtolower($jour);
|
|
if (isset($jours_mapping[$jour_lower])) {
|
|
$jours_permis_numeriques[] = $jours_mapping[$jour_lower];
|
|
}
|
|
}
|
|
|
|
// Vérifier si le jour de la semaine de la date est dans les jours disponibles
|
|
if (!in_array($jour_semaine, $jours_permis_numeriques, true)) {
|
|
return false; // Ce jour de la semaine n'est pas disponible
|
|
}
|
|
}
|
|
|
|
// Vérifier les indisponibilités ponctuelles
|
|
$indisponibilites_json = $permission['indisponibilites'] ?? '[]';
|
|
$indisponibilites = json_decode($indisponibilites_json, true) ?? [];
|
|
|
|
foreach ($indisponibilites as $indispo) {
|
|
$debut_str = $indispo['debut'] ?? $indispo['date_debut'] ?? '';
|
|
$fin_str = $indispo['fin'] ?? $indispo['date_fin'] ?? '';
|
|
|
|
if (empty($debut_str) || empty($fin_str)) {
|
|
continue;
|
|
}
|
|
|
|
// Convertir les dates ACF (format d/m/Y) en timestamp
|
|
$debut_timestamp = self::parse_acf_date($debut_str);
|
|
$fin_timestamp = self::parse_acf_date($fin_str);
|
|
|
|
if ($debut_timestamp && $fin_timestamp && $timestamp >= $debut_timestamp && $timestamp <= $fin_timestamp) {
|
|
return false; // Date dans une période d'indisponibilité
|
|
}
|
|
}
|
|
|
|
// Vérifier les plages horaires si une heure est fournie
|
|
if ($heure !== null && !empty($permission['plages_horaires'])) {
|
|
$plages_json = $permission['plages_horaires'];
|
|
$plages = json_decode($plages_json, true) ?? [];
|
|
|
|
if (!empty($plages)) {
|
|
$heure_timestamp = strtotime($heure);
|
|
$heure_autorisee = false;
|
|
|
|
foreach ($plages as $plage) {
|
|
$debut_plage = strtotime($plage['debut'] ?? '');
|
|
$fin_plage = strtotime($plage['fin'] ?? '');
|
|
|
|
if ($debut_plage && $fin_plage && $heure_timestamp >= $debut_plage && $heure_timestamp <= $fin_plage) {
|
|
$heure_autorisee = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$heure_autorisee) {
|
|
return false; // Heure non dans les plages autorisées
|
|
}
|
|
}
|
|
}
|
|
|
|
// Vérifier les disponibilités du traducteur (si présent dans les permissions stockées)
|
|
// OPTIMISATION : Si les données sont dans la table, on les utilise, sinon on laisse fallback
|
|
if (!empty($permission['traducteur_jours_permis']) || !empty($permission['traducteur_indisponibilites'])) {
|
|
// Vérifier le jour de la semaine pour le traducteur
|
|
$traducteur_jours_json = $permission['traducteur_jours_permis'] ?? '[]';
|
|
$traducteur_jours = json_decode($traducteur_jours_json, true) ?? [];
|
|
|
|
if (!empty($traducteur_jours)) {
|
|
$traducteur_jours_numeriques = [];
|
|
foreach ($traducteur_jours as $jour) {
|
|
$jour_lower = strtolower($jour);
|
|
if (isset($jours_mapping[$jour_lower])) {
|
|
$traducteur_jours_numeriques[] = $jours_mapping[$jour_lower];
|
|
}
|
|
}
|
|
|
|
if (!in_array($jour_semaine, $traducteur_jours_numeriques, true)) {
|
|
return false; // Ce jour de la semaine n'est pas disponible pour le traducteur
|
|
}
|
|
}
|
|
|
|
// Vérifier les indisponibilités ponctuelles du traducteur
|
|
$traducteur_indispo_json = $permission['traducteur_indisponibilites'] ?? '[]';
|
|
$traducteur_indispo = json_decode($traducteur_indispo_json, true) ?? [];
|
|
|
|
foreach ($traducteur_indispo as $indispo) {
|
|
$debut_str = $indispo['debut'] ?? $indispo['date_debut'] ?? '';
|
|
$fin_str = $indispo['fin'] ?? $indispo['date_fin'] ?? '';
|
|
|
|
if (empty($debut_str) || empty($fin_str)) {
|
|
continue;
|
|
}
|
|
|
|
$debut_timestamp = self::parse_acf_date($debut_str);
|
|
$fin_timestamp = self::parse_acf_date($fin_str);
|
|
|
|
if ($debut_timestamp && $fin_timestamp && $timestamp >= $debut_timestamp && $timestamp <= $fin_timestamp) {
|
|
return false; // Date dans une période d'indisponibilité du traducteur
|
|
}
|
|
}
|
|
}
|
|
// Si traducteur pas dans la table, on laisse le fallback dans update_event() le gérer
|
|
|
|
// Vérifier les disponibilités du local (si présent dans les permissions stockées)
|
|
// OPTIMISATION : Si les données sont dans la table, on les utilise, sinon on laisse fallback
|
|
if (!empty($permission['local_indisponibilites'])) {
|
|
$local_indispo_json = $permission['local_indisponibilites'] ?? '[]';
|
|
$local_indispo = json_decode($local_indispo_json, true) ?? [];
|
|
|
|
foreach ($local_indispo as $indispo) {
|
|
$debut_str = $indispo['debut'] ?? $indispo['date_debut'] ?? '';
|
|
$fin_str = $indispo['fin'] ?? $indispo['date_fin'] ?? '';
|
|
|
|
if (empty($debut_str) || empty($fin_str)) {
|
|
continue;
|
|
}
|
|
|
|
$debut_timestamp = self::parse_acf_date($debut_str);
|
|
$fin_timestamp = self::parse_acf_date($fin_str);
|
|
|
|
if ($debut_timestamp && $fin_timestamp && $timestamp >= $debut_timestamp && $timestamp <= $fin_timestamp) {
|
|
return false; // Date dans une période d'indisponibilité du local
|
|
}
|
|
}
|
|
}
|
|
// Si local pas dans la table, on laisse le fallback dans update_event() le gérer
|
|
|
|
return true; // Autorisé (intervenant, traducteur et local disponibles)
|
|
}
|
|
|
|
/**
|
|
* Parse une date ACF (format d/m/Y ou Y-m-d)
|
|
* @param string $date_str
|
|
* @return int|false Timestamp ou false
|
|
*/
|
|
private static function parse_acf_date($date_str) {
|
|
// Essayer le format ACF (d/m/Y)
|
|
$date = \DateTime::createFromFormat('d/m/Y', $date_str);
|
|
if ($date) {
|
|
return $date->getTimestamp();
|
|
}
|
|
|
|
// Essayer le format standard (Y-m-d)
|
|
$date = \DateTime::createFromFormat('Y-m-d', $date_str);
|
|
if ($date) {
|
|
return $date->getTimestamp();
|
|
}
|
|
|
|
// Fallback : strtotime
|
|
$timestamp = strtotime($date_str);
|
|
return $timestamp !== false ? $timestamp : false;
|
|
}
|
|
|
|
/**
|
|
* Met à jour les disponibilités d'un événement (ex: après modification de l'intervenant, traducteur ou local)
|
|
*
|
|
* Met à jour :
|
|
* - Les jours de la semaine disponibles (intervenant, traducteur)
|
|
* - Les indisponibilités ponctuelles (intervenant, traducteur, local)
|
|
* - Les départements/types d'intervention
|
|
* - Les traducteurs disponibles par langue (preset)
|
|
*
|
|
* Les plages horaires existantes sont conservées par défaut (utile pour les permanences)
|
|
*
|
|
* @param int $event_id
|
|
* @param int|null $intervenant_id Si null, utilise l'intervenant de l'événement
|
|
* @param bool $preserve_plages_horaires Si true, conserve les plages horaires existantes (défaut: true)
|
|
* @param int|null $traducteur_id ID du traducteur (si changé)
|
|
* @param int|null $local_id ID du local (si changé)
|
|
* @param string|null $langue_slug Slug de la langue de l'événement (pour précalculer traducteurs disponibles)
|
|
* @param string|null $date_rdv Date de l'événement (pour précalculer traducteurs disponibles)
|
|
* @return bool
|
|
*/
|
|
public static function update_from_intervenant($event_id, $intervenant_id = null, $preserve_plages_horaires = true, $traducteur_id = null, $local_id = null, $langue_slug = null, $date_rdv = null) {
|
|
global $wpdb;
|
|
|
|
// Si pas d'intervenant fourni, le récupérer depuis l'événement
|
|
if ($intervenant_id === null) {
|
|
$event = CRVI_Event_Model::load($event_id);
|
|
if (!$event || !$event->id_intervenant) {
|
|
return false;
|
|
}
|
|
$intervenant_id = $event->id_intervenant;
|
|
}
|
|
|
|
// Si traducteur/local non fournis, les récupérer depuis l'événement
|
|
if ($traducteur_id === null || $local_id === null) {
|
|
if (!$event) {
|
|
$event = CRVI_Event_Model::load($event_id);
|
|
}
|
|
if ($event) {
|
|
if ($traducteur_id === null) {
|
|
$traducteur_id = $event->id_traducteur ?? null;
|
|
}
|
|
if ($local_id === null) {
|
|
$local_id = $event->id_local ?? null;
|
|
}
|
|
}
|
|
}
|
|
|
|
$table_name = $wpdb->prefix . 'crvi_event_permission';
|
|
|
|
// Vérifier si la permission existe déjà
|
|
$existing = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT id, plages_horaires, traducteur_jours_permis, traducteur_indisponibilites, local_indisponibilites
|
|
FROM $table_name WHERE event_id = %d",
|
|
$event_id
|
|
), ARRAY_A);
|
|
|
|
$intervenant = CRVI_Intervenant_Model::load($intervenant_id);
|
|
if (!$intervenant) {
|
|
return false;
|
|
}
|
|
|
|
// Récupérer les nouvelles données depuis l'intervenant
|
|
$jours_disponibles = get_field('jours_de_disponibilite', 'user_' . $intervenant_id);
|
|
$jours_permis = is_array($jours_disponibles) ? json_encode($jours_disponibles) : json_encode([]);
|
|
|
|
$indisponibilites_acf = get_field('indisponibilitee_ponctuelle', 'user_' . $intervenant_id);
|
|
$indisponibilites = is_array($indisponibilites_acf) ? json_encode($indisponibilites_acf) : json_encode([]);
|
|
|
|
$departements_autories = !empty($intervenant->departements_ids)
|
|
? json_encode($intervenant->departements_ids)
|
|
: json_encode([]);
|
|
|
|
$types_intervention_autories = !empty($intervenant->types_intervention_ids)
|
|
? json_encode($intervenant->types_intervention_ids)
|
|
: json_encode([]);
|
|
|
|
// Récupérer les disponibilités du traducteur si présent
|
|
$traducteur_jours_permis = null;
|
|
$traducteur_indisponibilites = null;
|
|
if ($traducteur_id) {
|
|
$traducteur = CRVI_Traducteur_Model::load($traducteur_id);
|
|
if ($traducteur) {
|
|
$traducteur_jours = get_field('jours_de_disponibilite', $traducteur_id);
|
|
$traducteur_jours_permis = is_array($traducteur_jours) ? json_encode($traducteur_jours) : json_encode([]);
|
|
|
|
$traducteur_indispo_acf = get_field('indisponibilitee_ponctuelle', $traducteur_id);
|
|
$traducteur_indisponibilites = is_array($traducteur_indispo_acf) ? json_encode($traducteur_indispo_acf) : json_encode([]);
|
|
}
|
|
}
|
|
|
|
// Récupérer les indisponibilités du local si présent
|
|
$local_indisponibilites = null;
|
|
if ($local_id) {
|
|
$local = CRVI_Local_Model::load($local_id);
|
|
if ($local) {
|
|
$local_indispo_acf = get_field('indisponibilitee_ponctuelle', $local_id);
|
|
$local_indisponibilites = is_array($local_indispo_acf) ? json_encode($local_indispo_acf) : json_encode([]);
|
|
}
|
|
}
|
|
|
|
// Précalculer les traducteurs disponibles par langue si langue et date fournies
|
|
$traducteurs_disponibles_par_langue = null;
|
|
if ($langue_slug && $date_rdv) {
|
|
$traducteurs_disponibles_par_langue = self::precalculate_traducteurs_par_langue($date_rdv, $langue_slug);
|
|
}
|
|
|
|
if ($existing) {
|
|
// Mettre à jour l'existant
|
|
$update_data = [
|
|
'jours_permis' => $jours_permis,
|
|
'indisponibilites' => $indisponibilites,
|
|
'traducteur_jours_permis' => $traducteur_jours_permis,
|
|
'traducteur_indisponibilites' => $traducteur_indisponibilites,
|
|
'local_indisponibilites' => $local_indisponibilites,
|
|
'departements_autories' => $departements_autories,
|
|
'types_intervention_autories' => $types_intervention_autories,
|
|
'traducteurs_disponibles_par_langue' => $traducteurs_disponibles_par_langue,
|
|
'date_modification' => current_time('mysql'),
|
|
'modifie_par' => get_current_user_id(),
|
|
];
|
|
|
|
// Conserver les plages horaires existantes si demandé
|
|
if ($preserve_plages_horaires && !empty($existing['plages_horaires'])) {
|
|
$update_data['plages_horaires'] = $existing['plages_horaires'];
|
|
$formats = ['%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d']; // Avec plages_horaires
|
|
} else {
|
|
$formats = ['%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d']; // Sans plages_horaires
|
|
}
|
|
|
|
$result = $wpdb->update(
|
|
$table_name,
|
|
$update_data,
|
|
['event_id' => $event_id],
|
|
$formats,
|
|
['%d'] // Format pour WHERE
|
|
);
|
|
|
|
return $result !== false;
|
|
} else {
|
|
// Créer une nouvelle entrée
|
|
return self::create_from_intervenant($event_id, $intervenant_id, null, $traducteur_id, $local_id, $langue_slug, $date_rdv) !== false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Supprime les permissions d'un événement (lors de la suppression de l'événement)
|
|
* @param int $event_id
|
|
* @return bool
|
|
*/
|
|
public static function delete_by_event_id($event_id) {
|
|
global $wpdb;
|
|
$table_name = $wpdb->prefix . 'crvi_event_permission';
|
|
|
|
return $wpdb->delete($table_name, ['event_id' => $event_id], ['%d']) !== false;
|
|
}
|
|
}
|
|
|