542 lines
20 KiB
PHP
542 lines
20 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
namespace ESI_CRVI_AGENDA\models;
|
|
|
|
use WP_Error;
|
|
|
|
class CRVI_Intervenant_Model extends Main_Model {
|
|
public $id;
|
|
public $nom;
|
|
public $prenom;
|
|
public $email;
|
|
public $departements_ids; // array d'IDs CPT departement
|
|
public $types_intervention_ids; // array d'IDs CPT type_intervention
|
|
public $jours_de_disponibilite;
|
|
public $indisponibilites;
|
|
public $commentaires;
|
|
|
|
/**
|
|
* Schéma des champs ACF : nom => 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 '<pre>';
|
|
// print_r($data);
|
|
// echo '</pre>';
|
|
// 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 '<pre>';
|
|
print_r($user);
|
|
echo '</pre>';
|
|
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);
|
|
}
|
|
}
|