type (ex : group, repeater, taxonomy, text...) */ public static $acf_schema = [ 'telephone' => 'text', 'departements' => 'taxonomy', 'specialisations' => 'taxonomy', 'commentaires' => 'textarea', 'jours_de_disponibilite' => 'checkbox', 'indisponibilitee_ponctuelle' => 'repeater', ]; public function __construct($data = []) { foreach ($data as $key => $value) { if (property_exists($this, $key)) { $this->$key = $value; } } } public static function load($user_id, $fields = []) { $user = get_user_by('id', $user_id); if (!$user || !in_array('intervenant', (array) $user->roles, true)) { return null; } // Fonction helper pour récupérer les champs ACF ou meta $get_field_value = function($user_id, $field_name) { if (function_exists('get_field')) { return get_field($field_name, 'user_' . $user_id) ?: []; } else { return get_user_meta($user_id, $field_name, true) ?: []; } }; // Si des champs spécifiques sont demandés, ne charger que ceux-ci if (!empty($fields)) { $data = []; foreach ($fields as $field) { if ($field === 'id') { $data['id'] = $user->ID; } elseif ($field === 'nom') { $data['nom'] = $user->last_name; } elseif ($field === 'prenom') { $data['prenom'] = $user->first_name; } elseif ($field === 'email') { $data['email'] = $user->user_email; } elseif (property_exists(self::class, $field)) { $data[$field] = $get_field_value($user->ID, $field); } } return new self($data); } // Sinon, charger tous les champs par défaut return new self([ 'id' => $user->ID, 'nom' => $user->last_name, 'prenom' => $user->first_name, 'email' => $user->user_email, 'departements_ids' => $get_field_value($user->ID, 'departements_ids'), 'types_intervention_ids' => $get_field_value($user->ID, 'types_intervention_ids'), 'jours_de_disponibilite' => $get_field_value($user->ID, 'jours_de_disponibilite'), 'indisponibilites' => $get_field_value($user->ID, 'indisponibilites'), 'commentaires' => $get_field_value($user->ID, 'commentaires'), ]); } public static function get_intervenants($filters = [],$simple_list = false) { $users = get_users([ 'role' => 'intervenant', 'number' => -1, 'meta_query' => $filters, ]); if ($simple_list) { $users = array_map(function($user) { return [ 'id' => $user->ID, 'nom' => $user->last_name, 'prenom' => $user->first_name, ]; }, $users); } return $users; } /** * Retourne les intervenants disponibles à une date donnée, avec filtres optionnels. * @param string $date au format Y-m-d * @param int|null $departement_id (ID CPT departement) * @param int|null $type_intervention_id (ID CPT type_intervention) * @param int|null $event_id ID de l'événement en cours d'édition (pour inclure l'intervenant actuel) * @return array Liste des intervenants disponibles (CRVI_Intervenant_Model) */ public static function filtrer_disponibles($date, $departement_id = null, $type_intervention_id = null, $event_id = null) { if (empty($date)) { return []; } $meta_query = [ [ 'key' => 'jours_de_disponibilite', 'compare' => 'EXISTS', ], ]; if ($departement_id) { $meta_query[] = [ 'key' => 'departements_ids', 'value' => $departement_id, 'compare' => 'LIKE', ]; } if ($type_intervention_id) { $meta_query[] = [ 'key' => 'types_intervention_ids', 'value' => $type_intervention_id, 'compare' => 'LIKE', ]; } $args = [ 'role' => 'intervenant', 'number' => -1, 'meta_query' => $meta_query, ]; $users = get_users($args); $disponibles = []; foreach ($users as $user) { $intervenant = self::load($user->ID); if ($intervenant) { $is_disponible = $intervenant->is_disponible($user->ID ,$date, $departement_id, $type_intervention_id); // Vérifier les conflits d'événements existants if ($is_disponible) { $conflits = self::verifier_conflits_intervenant($intervenant->id, $date, $event_id); if (!empty($conflits)) { $is_disponible = false; } } // Si c'est l'événement en cours d'édition, inclure l'intervenant même s'il est "pris" if ($event_id && self::is_intervenant_of_event($intervenant->id, $event_id)) { $is_disponible = true; } if ($is_disponible) { $disponibles[] = $intervenant; } } } // error_log("CRVI_Intervenant_Model::filtrer_disponibles - Intervenants disponibles: " . count($disponibles)); return $disponibles; } /** * Vérifie si un intervenant est associé à un événement donné * @param int $intervenant_id * @param int $event_id * @return bool */ private static function is_intervenant_of_event($intervenant_id, $event_id) { global $wpdb; $table_name = $wpdb->prefix . 'crvi_agenda'; $result = $wpdb->get_var($wpdb->prepare( "SELECT id FROM $table_name WHERE id = %d AND id_intervenant = %d", $event_id, $intervenant_id )); return !empty($result); } /** * Vérifie si cet intervenant est disponible à une date donnée, avec filtres optionnels. * @param string $date au format Y-m-d * @param int|null $departement_id * @param int|null $type_intervention_id * @return bool */ public function is_disponible($intervenant_id, $date, $departement_id = null, $type_intervention_id = null) { // Vérifier que la date n'est pas null ou vide if (empty($date)) { return false; } $timestamp = strtotime($date); if ($timestamp === false) { return false; } $jour = strtolower(date('l', $timestamp)); $jours_fr = [ 'monday' => 'lundi', 'tuesday' => 'mardi', 'wednesday' => 'mercredi', 'thursday' => 'jeudi', 'friday' => 'vendredi', 'saturday' => 'samedi', 'sunday' => 'dimanche', ]; $jour_semaine = $jours_fr[$jour] ?? ''; $jours_disponibles = get_field('jours_de_disponibilite', 'user_' . $intervenant_id); if (!is_array($jours_disponibles) || !in_array($jour_semaine, $jours_disponibles, true)) { return false; } $indisponibilites = get_field('indisponibilitee_ponctuelle', 'user_' . $intervenant_id); if (is_array($indisponibilites)) { foreach ($indisponibilites as $absence) { $debut = isset($absence['debut']) ? strtotime($absence['debut']) : null; $fin = isset($absence['fin']) ? strtotime($absence['fin']) : null; if ($debut && $fin && $timestamp >= $debut && $timestamp <= $fin) { return false; } } } if ($departement_id && (!is_array($this->departements_ids) || !in_array($departement_id, $this->departements_ids))) { return false; } if ($type_intervention_id && (!is_array($this->types_intervention_ids) || !in_array($type_intervention_id, $this->types_intervention_ids))) { return false; } return true; } public function get_relations() { // À adapter selon la nouvelle structure (ex : récupérer les rendez-vous liés via user_id) return []; } /** * Créer un intervenant (user avec rôle intervenant). * @param array $data * @return array|WP_Error */ public static function create(array $data, bool $as_rest = false) { // Suppression du debug // echo '
';
        // print_r($data);
        // echo '
'; // die(); if (!is_user_logged_in() || !get_current_user_id()) { if ($as_rest) { return [ 'success' => false, 'code' => 401, 'message' => 'Authentification requise', 'data' => null ]; } return new WP_Error('auth_required', 'Authentification requise', ['status' => 401]); } if (!current_user_can('edit_users')) { if ($as_rest) { return [ 'success' => false, 'code' => 403, 'message' => 'Non autorisé', 'data' => null ]; } return new WP_Error('not_allowed', 'Non autorisé', ['status' => 403]); } if (empty($data['nom']) || empty($data['prenom']) || empty($data['email'])) { if ($as_rest) { return [ 'success' => false, 'code' => 400, 'message' => 'Champs obligatoires manquants', 'data' => null ]; } return new WP_Error('missing_fields', 'Champs obligatoires manquants', ['status' => 400]); } $user = get_user_by('email', $data['email']); /* echo '
';
        print_r($user);
        echo '
'; die(); */ if ($user && in_array('intervenant', (array)$user->roles, true)) { // Mise à jour $user_id = $user->ID; $user_data = [ 'ID' => $user_id, 'user_email' => $data['email'], 'first_name' => $data['prenom'], 'last_name' => $data['nom'], ]; $result = wp_update_user($user_data); if (is_wp_error($result)) { if ($as_rest) { return [ 'success' => false, 'code' => 500, 'message' => 'Erreur lors de la mise à jour', 'data' => json_encode($result) ]; } return $result; } // Mettre à jour les champs ACF foreach ($data as $key => $value) { // Pour departements et types_intervention, on attend des IDs de posts CPT (séparés par pipe si string) if ($key === 'departements') { $ids = is_array($value) ? $value : explode('|', $value); $ids = array_filter(array_map('intval', $ids)); \update_field('departements', $ids, 'user_' . $user_id); } else if ($key === 'types_intervention' || $key === 'specialisations') { $ids = is_array($value) ? $value : explode('|', $value); $ids = array_filter(array_map('intval', $ids)); \update_field('specialisations', $ids, 'user_' . $user_id); } else if (isset(self::$acf_schema[$key])) { self::set_acf_field('user_' . $user_id, $key, $value, self::$acf_schema); } else { // Pour les autres champs non ACF, on ignore ou on peut loguer } } if ($as_rest) { return [ 'success' => true, 'code' => 200, 'message' => 'Intervenant mis à jour', 'data' => [ 'user_id' => $user_id ] ]; } return ['user_id' => $user_id, 'updated' => true]; } else if($user) { // L'utilisateur existe mais n'a pas le rôle intervenant if ($as_rest) { return [ 'success' => false, 'code' => 409, 'message' => 'Email déjà utilisé par un autre rôle', 'data' => null ]; } return new WP_Error('email_exists', 'Email déjà utilisé par un autre rôle', ['status' => 409]); } echo 'vhvh'; die(); // Création $user_id = wp_insert_user([ 'user_login' => $data['email'], 'user_email' => $data['email'], 'first_name' => $data['prenom'], 'last_name' => $data['nom'], 'role' => 'intervenant', 'user_pass' => wp_generate_password(12, true), ]); if (is_wp_error($user_id)) { if ($as_rest) { return [ 'success' => false, 'code' => 500, 'message' => 'Erreur lors de la création', 'data' => null ]; } return $user_id; } // Générer un mot de passe applicatif (Application Password) if (!class_exists('WP_Application_Passwords') && file_exists(ABSPATH . 'wp-includes/class-wp-application-passwords.php')) { require_once ABSPATH . 'wp-includes/class-wp-application-passwords.php'; } if (class_exists('WP_Application_Passwords')) { $app_pass_result = \WP_Application_Passwords::create_new_application_password($user_id, [ 'name' => 'CRVI API', ]); if (is_array($app_pass_result) && isset($app_pass_result[0], $app_pass_result[1]['new_password'])) { $application_password = $app_pass_result[1]['new_password']; } else { $application_password = null; } } else { $application_password = null; } // Stocker les champs ACF foreach ($data as $key => $value) { if ($key === 'departements') { $ids = is_array($value) ? $value : explode('|', $value); $ids = array_filter(array_map('intval', $ids)); \update_field('departements', $ids, 'user_' . $user_id); } else if ($key === 'types_intervention' || $key === 'specialisations') { $ids = is_array($value) ? $value : explode('|', $value); $ids = array_filter(array_map('intval', $ids)); \update_field('specialisations', $ids, 'user_' . $user_id); } else if (isset(self::$acf_schema[$key])) { self::set_acf_field('user_' . $user_id, $key, $value, self::$acf_schema); } else { // Pour les autres champs non ACF, on ignore ou on peut loguer } } if ($as_rest) { return [ 'success' => true, 'code' => 201, 'message' => 'Intervenant créé', 'data' => [ 'user_id' => $user_id, 'application_password' => $application_password ] ]; } return ['user_id' => $user_id, 'created' => true, 'application_password' => $application_password]; } /** * Mettre à jour un intervenant (user). * @param int $user_id * @param array $data * @return bool|WP_Error */ public static function update(int $user_id, array $data) { if (!current_user_can('edit_users')) { return new WP_Error('not_allowed', 'Non autorisé', ['status' => 403]); } $user = get_user_by('id', $user_id); if (!$user || !in_array('intervenant', (array) $user->roles, true)) { return new WP_Error('not_found', 'Intervenant introuvable', ['status' => 404]); } $user_data = ['ID' => $user_id]; if (!empty($data['email'])) { if (email_exists($data['email']) && $data['email'] !== $user->user_email) { return new WP_Error('email_exists', 'Email déjà utilisé', ['status' => 409]); } $user_data['user_email'] = $data['email']; } if (!empty($data['prenom'])) { $user_data['first_name'] = $data['prenom']; } if (!empty($data['nom'])) { $user_data['last_name'] = $data['nom']; } $user_update = wp_update_user($user_data); if (is_wp_error($user_update)) { return $user_update; } // Mettre à jour les meta foreach (['departements_ids', 'types_intervention_ids', 'jours_de_disponibilite', 'indisponibilites', 'commentaires'] as $meta_key) { if (isset($data[$meta_key])) { \update_field($meta_key, $data[$meta_key], 'user_' . $user_id); } } return true; } /** * Supprimer un intervenant (user). * @param int $user_id * @return bool|WP_Error */ public function delete(int $user_id) { if (!current_user_can('delete_users')) { return new WP_Error('not_allowed', 'Non autorisé', ['status' => 403]); } $user = get_user_by('id', $user_id); if (!$user || !in_array('intervenant', (array) $user->roles, true)) { return new WP_Error('not_found', 'Intervenant introuvable', ['status' => 404]); } require_once ABSPATH . 'wp-admin/includes/user.php'; $result = wp_delete_user($user_id); if (!$result) { return new WP_Error('delete_failed', 'Erreur lors de la suppression', ['status' => 500]); } return true; } public static function all() { $users = get_users([ 'role' => 'intervenant', 'number' => -1, ]); return $users; } /** * Vérifie s'il y a des conflits d'événements pour un intervenant donné * @param int $intervenant_id * @param string $date * @param int|null $event_id - ID de l'événement à exclure (pour l'édition) * @return array */ private static function verifier_conflits_intervenant($intervenant_id, $date, $event_id = null) { global $wpdb; $table_events = $wpdb->prefix . 'crvi_agenda'; $where_conditions = ['id_intervenant = %d']; $where_values = [$intervenant_id]; // Exclure l'événement en cours d'édition si spécifié if ($event_id) { $where_conditions[] = 'id != %d'; $where_values[] = $event_id; } // Ajouter la condition de date $where_conditions[] = 'date_rdv = %s'; $where_values[] = $date; // Exclure les événements annulés ou terminés $where_conditions[] = 'statut NOT IN (%s, %s)'; $where_values[] = 'annule'; $where_values[] = 'termine'; $where_clause = implode(' AND ', $where_conditions); $query = $wpdb->prepare( "SELECT * FROM {$table_events} WHERE {$where_clause}", $where_values ); return $wpdb->get_results($query, ARRAY_A); } }