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);
}
}