'GET', 'callback' => [self::class, 'get_user_permissions'], 'permission_callback' => '__return_true', ], ]); register_rest_route('crvi/v1', '/agenda/disponibilites', [ [ 'methods' => 'GET', 'callback' => [self::class, 'get_disponibilites'], 'permission_callback' => '__return_true', ], [ 'methods' => 'POST', 'callback' => [self::class, 'get_disponibilites'], 'permission_callback' => '__return_true', ], ]); \register_rest_route('crvi/v1', '/events/(?P\\d+)/conflits', [ [ 'methods' => 'GET', 'callback' => [self::class, 'conflits_item'], 'permission_callback' => [self::class, 'can_edit'], ], ]); \register_rest_route('crvi/v1', '/events/export', [ [ 'methods' => 'GET', 'callback' => [self::class, 'export_items'], 'permission_callback' => [self::class, 'can_edit'], ], ]); // --- Filtres dynamiques --- \register_rest_route('crvi/v1', '/filters/departements', [ 'methods' => 'GET', 'callback' => [self::class, 'get_departements'], 'permission_callback' => '__return_true', ]); \register_rest_route('crvi/v1', '/filters/types-intervention', [ 'methods' => 'GET', 'callback' => [self::class, 'get_types_intervention'], 'permission_callback' => '__return_true', ]); \register_rest_route('crvi/v1', '/filters/langues', [ 'methods' => 'GET', 'callback' => [self::class, 'get_langues'], 'permission_callback' => '__return_true', ]); \register_rest_route('crvi/v1', '/filters/langues-beneficiaire', [ 'methods' => 'GET', 'callback' => [self::class, 'get_langues_beneficiaire'], 'permission_callback' => '__return_true', ]); \register_rest_route('crvi/v1', '/filters/statuts', [ 'methods' => 'GET', 'callback' => [self::class, 'get_statuts'], 'permission_callback' => '__return_true', ]); // --- CRUD Events --- \register_rest_route('crvi/v1', '/events', [ [ 'methods' => 'GET', 'callback' => [self::class, 'get_events'], 'permission_callback' => '__return_true', ], [ 'methods' => 'POST', 'callback' => [self::class, 'create_event'], 'permission_callback' => [self::class, 'can_edit'], ], ]); \register_rest_route('crvi/v1', '/events/(?P\\d+)', [ [ 'methods' => 'GET', 'callback' => [self::class, 'get_event'], 'permission_callback' => '__return_true', ], [ 'methods' => 'PUT,PATCH', 'callback' => [self::class, 'update_event'], 'permission_callback' => [self::class, 'can_edit'], ], [ 'methods' => 'DELETE', 'callback' => [self::class, 'delete_event'], 'permission_callback' => [self::class, 'can_edit'], ], ]); } /** * Endpoint global pour récupérer les entités disponibles à une date/créneau donné. * @param \WP_REST_Request $request * @return \WP_REST_Response */ public static function get_disponibilites($request) { // Récupérer les paramètres depuis query string ou JSON body $params = $request->get_params(); $json_params = $request->get_json_params() ?: []; // Fusionner les paramètres (JSON body a priorité sur query string) $all_params = array_merge($params, $json_params); $date = $all_params['date'] ?? $all_params['date_rdv'] ?? null; $heure = $all_params['heure'] ?? $all_params['heure_rdv'] ?? null; $langue = $all_params['langue'] ?? null; $departement = $all_params['departement'] ?? null; $specialisation = $all_params['specialisation'] ?? null; $type = $all_params['type'] ?? null; $event_id = $all_params['event_id'] ?? null; // Appel aux méthodes de chaque controller $traducteurs = \ESI_CRVI_AGENDA\models\CRVI_Traducteur_Model::filtrer_disponibles($date, $langue, $event_id); $intervenants = \ESI_CRVI_AGENDA\models\CRVI_Intervenant_Model::filtrer_disponibles($date, $departement, $specialisation, $event_id); // Récupérer les locaux selon le type de RDV $type_rdv = $all_params['type_rdv'] ?? null; if ($type_rdv && in_array($type_rdv, ['individuel', 'groupe'])) { $locaux = \ESI_CRVI_AGENDA\models\CRVI_Local_Model::get_locaux_par_type($type_rdv); } else { // Si pas de type spécifié, récupérer tous les locaux $locals_posts = get_posts([ 'post_type' => 'local', 'numberposts' => -1, 'post_status' => 'publish', ]); $locaux = []; foreach ($locals_posts as $local_post) { $type_local = get_post_meta($local_post->ID, 'type_de_local', true); $capacite = get_post_meta($local_post->ID, 'capacite', true); // Filtrer par type de RDV si spécifié if ($type_rdv && in_array($type_rdv, ['individuel', 'groupe'])) { // Logique de filtrage basée sur le type de local if ($type_rdv === 'individuel' && $type_local === 'individuel') { $locaux[] = [ 'id' => $local_post->ID, 'nom' => $local_post->post_title, 'type_de_local' => $type_local, 'capacite' => $capacite, ]; } elseif ($type_rdv === 'groupe' && $type_local === 'groupe') { $locaux[] = [ 'id' => $local_post->ID, 'nom' => $local_post->post_title, 'type_de_local' => $type_local, 'capacite' => $capacite, ]; } } else { // Si pas de type spécifié, récupérer tous les locaux $locaux[] = [ 'id' => $local_post->ID, 'nom' => $local_post->post_title, 'type_de_local' => $type_local, 'capacite' => $capacite, ]; } } } // Récupérer tous les bénéficiaires $beneficiaire_model = new \ESI_CRVI_AGENDA\models\CRVI_Beneficiaire_Model(); $beneficiaires_objects = $beneficiaire_model->get_all_beneficiaires(); $beneficiaires = []; foreach ($beneficiaires_objects as $beneficiaire) { $beneficiaires[] = [ 'id' => $beneficiaire->id, 'nom' => $beneficiaire->nom . ' ' . $beneficiaire->prenom, ]; } return Api_Helper::json_success([ 'traducteurs' => $traducteurs, 'intervenants' => $intervenants, 'locaux' => $locaux, 'beneficiaires' => $beneficiaires, ]); } /** * Endpoint pour récupérer les permissions de l'utilisateur courant. * @param WP_REST_Request $request * @return WP_REST_Response */ public static function get_user_permissions($request) { $permissions = Api_Helper::get_user_permissions(); return Api_Helper::json_success($permissions); } public static function conflits_item($request) { $id = (int) $request['id']; $date = $request->get_param('date'); $heure = $request->get_param('heure'); $id_intervenant = $request->get_param('id_intervenant'); $id_traducteur = $request->get_param('id_traducteur'); $id_local = $request->get_param('id_local'); $model = new CRVI_Event_Model(); $result = $model->get_conflits($date, $heure, $id_intervenant, $id_traducteur, $id_local); return Api_Helper::json_success($result); } public static function export_items($request) { $model = new CRVI_Event_Model(); $params = $request->get_params(); // Support de la pagination pour l'export $date_debut = $params['start'] ?? $params['date_debut'] ?? null; $date_fin = $params['end'] ?? $params['date_fin'] ?? null; // Filtrer les paramètres pour éviter les conflits $filters = array_diff_key($params, array_flip(['start', 'end', 'date_debut', 'date_fin'])); $result = $model->get_events_by('date_rdv', null, $filters, $date_debut, $date_fin); return Api_Helper::json_success($result); } // --- CRUD --- public static function get_events($request) { $params = $request->get_params(); $model = new CRVI_Event_Model(); $events = $model->get_events_by_filters($params); return Api_Helper::json_success($events); } public static function get_event($request) { $id = (int) $request['id']; $event = CRVI_Event_Model::load($id); if (!$event) { return Api_Helper::json_error('Événement introuvable', 404); } return Api_Helper::json_success($event); } public static function create_event($request) { $data = $request->get_json_params(); $model = new CRVI_Event_Model(); $result = $model->create_event($data); if (is_wp_error($result)) { return Api_Helper::json_error($result->get_error_message(), 400); } return Api_Helper::json_success(['id' => $result, 'message' => 'Événement créé avec succès']); } public static function update_event($request) { $id = (int) $request['id']; $data = $request->get_json_params(); $model = new CRVI_Event_Model(); $result = $model->update_event($id, $data); if (is_wp_error($result)) { return Api_Helper::json_error($result->get_error_message(), 400); } return Api_Helper::json_success(['id' => $id, 'message' => 'Événement modifié avec succès']); } public static function delete_event($request) { $id = (int) $request['id']; $model = new CRVI_Event_Model(); $result = $model->delete_event($id); if (is_wp_error($result)) { return Api_Helper::json_error($result->get_error_message(), 400); } return Api_Helper::json_success(['id' => $id, 'message' => 'Événement supprimé avec succès']); } // --- Avancés --- public static function cloture_event($request) { $id = (int) $request['id']; $data = $request->get_json_params(); $model = new CRVI_Event_Model(); $result = $model->cloture_event($id, $data['statut'] ?? ''); if (is_wp_error($result)) { return Api_Helper::json_error($result->get_error_message(), 400); } return Api_Helper::json_success(['id' => $id, 'message' => 'Événement clôturé avec succès']); } public static function change_statut($request) { $id = (int) $request['id']; $data = $request->get_json_params(); $model = new CRVI_Event_Model(); $result = $model->change_statut($id, $data); if (is_wp_error($result)) { return Api_Helper::json_error($result->get_error_message(), 400); } return Api_Helper::json_success(['id' => $id, 'message' => 'Statut modifié avec succès']); } /** * Retourne la couleur selon le statut */ private static function get_status_color($statut) { switch ($statut) { case 'prevu': return '#28a745'; // Vert case 'annule': return '#dc3545'; // Rouge case 'non_tenu': return '#ffc107'; // Jaune case 'cloture': return '#6c757d'; // Gris case 'absence': return '#fd7e14'; // Orange default: return '#007bff'; // Bleu } } public static function get_events_fullcalendar($request) { $model = new CRVI_Event_Model(); $params = $request->get_params(); // Support de la pagination FullCalendar $date_debut = $params['start'] ?? $params['date_debut'] ?? null; $date_fin = $params['end'] ?? $params['date_fin'] ?? null; // Filtrer les paramètres pour éviter les conflits $filters = array_diff_key($params, array_flip(['start', 'end', 'date_debut', 'date_fin'])); // Récupérer les événements pour cette période $events = $model->get_events_by('date_rdv', null, $filters, $date_debut, $date_fin); // Formater pour FullCalendar $formatted_events = []; foreach ($events as $event) { // Récupérer les détails des entités liées $details = $model->get_details($event['id']); $formatted_events[] = [ 'id' => $event['id'], 'title' => ($details->beneficiaire->nom ?? '') . ' ' . ($details->beneficiaire->prenom ?? '') . ' - ' . ($details->intervenant->nom ?? '') . ' ' . ($details->intervenant->prenom ?? ''), 'start' => $event['date_rdv'] . 'T' . $event['heure_rdv'], 'end' => $event['date_fin'] . 'T' . $event['heure_fin'], 'backgroundColor' => self::get_status_color($event['statut']), 'borderColor' => self::get_status_color($event['statut']), 'textColor' => $event['statut'] === 'non_tenu' ? '#000' : '#fff', 'extendedProps' => [ 'type' => $event['type'], 'statut' => $event['statut'], 'langue' => $event['langue'], 'beneficiaire' => ($details->beneficiaire->nom ?? '') . ' ' . ($details->beneficiaire->prenom ?? ''), 'intervenant' => ($details->intervenant->nom ?? '') . ' ' . ($details->intervenant->prenom ?? ''), 'traducteur' => ($details->traducteur->nom ?? '') . ' ' . ($details->traducteur->prenom ?? ''), 'local' => $details->local->nom ?? '', 'commentaire' => $event['commentaire'], 'id_beneficiaire' => $event['id_beneficiaire'], 'id_intervenant' => $event['id_intervenant'], 'id_traducteur' => $event['id_traducteur'], 'id_local' => $event['id_local'] ] ]; } return Api_Helper::json_success($formatted_events); } public static function get_events_stats($request) { $params = $request->get_params(); $model = new CRVI_Event_Model(); $stats = $model->get_events_stats($params); return Api_Helper::json_success($stats); } public static function get_event_historique($request) { $id = (int) $request['id']; $model = new CRVI_Event_Model(); $historique = $model->get_historique(); return Api_Helper::json_success($historique); } // --- Filtres dynamiques --- public static function get_departements($request) { $departements = get_terms([ 'taxonomy' => 'departement', 'hide_empty' => false, ]); $result = []; foreach ($departements as $departement) { $result[] = [ 'id' => $departement->term_id, 'name' => $departement->name, 'slug' => $departement->slug, ]; } return Api_Helper::json_success($result); } public static function get_types_intervention($request) { $types = get_terms([ 'taxonomy' => 'type_intervention', 'hide_empty' => false, ]); $result = []; foreach ($types as $type) { $result[] = [ 'id' => $type->term_id, 'name' => $type->name, 'slug' => $type->slug, ]; } return Api_Helper::json_success($result); } public static function get_langues($request) { $langues = get_terms([ 'taxonomy' => 'langue', 'hide_empty' => false, ]); $result = []; foreach ($langues as $langue) { $result[] = [ 'id' => $langue->term_id, 'name' => $langue->name, 'slug' => $langue->slug, ]; } return Api_Helper::json_success($result); } public static function get_langues_beneficiaire($request) { $langues = \ESI_CRVI_AGENDA\helpers\Api_Helper::get_languages(true); return Api_Helper::json_success($langues); } public static function get_statuts($request) { $statuts = [ ['id' => 'prevu', 'label' => 'Prévu'], ['id' => 'annule', 'label' => 'Annulé'], ['id' => 'non_tenu', 'label' => 'Non tenu'], ['id' => 'cloture', 'label' => 'Clôturé'], ['id' => 'absence', 'label' => 'Absence'], ]; return Api_Helper::json_success($statuts); } /** * Vérifie si l'utilisateur peut modifier un événement * @param \WP_REST_Request $request * @return bool */ public static function can_edit($request = null) { // Si admin ou rôle ayant edit_posts : accès total if (current_user_can('edit_posts')) { return true; } // Récupérer l'id_intervenant depuis la requête ou l'événement $id_intervenant = null; if ($request) { // Si on modifie un événement existant, récupérer l'ID depuis l'événement if ($request->get_param('id')) { $event = \ESI_CRVI_AGENDA\models\CRVI_Event_Model::load((int)$request->get_param('id')); if ($event && isset($event->id_intervenant)) { $id_intervenant = $event->id_intervenant; } } // Sinon, essayer de le prendre dans les paramètres de la requête (création) if (!$id_intervenant) { $data = $request->get_json_params(); if ($data && isset($data['id_intervenant'])) { $id_intervenant = $data['id_intervenant']; } } } // Appel à la logique intervenant return CRVI_Intervenant_Controller::can_edit_own_event($id_intervenant); } }