Affichage de historique de demande avec toutes lesétats et les information nécessaire et la pièce jointe s'il est type"arretMaladie"
This commit is contained in:
@@ -1,156 +1,106 @@
|
|||||||
<?php
|
<?php
|
||||||
// Récupération des demandes en attente pour un manager
|
|
||||||
header("Access-Control-Allow-Origin: *");
|
header("Access-Control-Allow-Origin: *");
|
||||||
header("Access-Control-Allow-Methods: GET, OPTIONS");
|
header("Access-Control-Allow-Methods: GET, OPTIONS");
|
||||||
header("Access-Control-Allow-Headers: Content-Type");
|
header("Access-Control-Allow-Headers: Content-Type");
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||||
http_response_code(200);
|
http_response_code(200);
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
header("Content-Type: application/json");
|
header("Content-Type: application/json");
|
||||||
|
|
||||||
// Log des erreurs pour debug
|
|
||||||
ini_set('display_errors', 1);
|
ini_set('display_errors', 1);
|
||||||
ini_set('display_startup_errors', 1);
|
ini_set('display_startup_errors', 1);
|
||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
// Connexion DB
|
||||||
$host = "192.168.0.4";
|
$host = "192.168.0.4";
|
||||||
$dbname = "DemandeConge";
|
$dbname = "DemandeConge";
|
||||||
$username = "wpuser";
|
$username = "wpuser";
|
||||||
$password = "-2b/)ru5/Bi8P[7_";
|
$password = "-2b/)ru5/Bi8P[7_";
|
||||||
|
|
||||||
$conn = new mysqli($host, $username, $password, $dbname);
|
$conn = new mysqli($host, $username, $password, $dbname);
|
||||||
|
|
||||||
if ($conn->connect_error) {
|
if ($conn->connect_error) {
|
||||||
error_log("Erreur connexion DB getPendingRequests: " . $conn->connect_error);
|
error_log("Erreur connexion DB: " . $conn->connect_error);
|
||||||
echo json_encode(["success" => false, "message" => "Erreur de connexion à la base de données"]);
|
echo json_encode(["success" => false, "message" => "Erreur de connexion DB"]);
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
$managerId = $_GET['manager_id'] ?? null;
|
|
||||||
|
|
||||||
if ($managerId === null) {
|
// Récupération ID manager
|
||||||
echo json_encode(["success" => false, "message" => "ID manager manquant"]);
|
$managerId = $_GET['SuperieurId'] ?? null;
|
||||||
|
if (!$managerId) {
|
||||||
|
echo json_encode(["success" => false, "message" => "Paramètre SuperieurId manquant"]);
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
error_log("getPendingRequests - Manager ID: $managerId");
|
$sql = "
|
||||||
|
SELECT
|
||||||
|
dc.Id,
|
||||||
|
dc.DateDebut,
|
||||||
|
dc.DateFin,
|
||||||
|
dc.Statut,
|
||||||
|
dc.DateDemande,
|
||||||
|
dc.Commentaire,
|
||||||
|
dc.DocumentJoint,
|
||||||
|
dc.EmployeeId,
|
||||||
|
CONCAT(u.Prenom, ' ', u.Nom) as employee_name,
|
||||||
|
u.Email as employee_email,
|
||||||
|
tc.Nom as type
|
||||||
|
FROM DemandeConge dc
|
||||||
|
JOIN Users u ON dc.EmployeeId = u.ID
|
||||||
|
JOIN TypeConge tc ON dc.TypeCongeId = tc.Id
|
||||||
|
JOIN HierarchieValidation hv ON hv.EmployeId = u.ID
|
||||||
|
WHERE hv.SuperieurId = ?
|
||||||
|
ORDER BY dc.DateDemande DESC
|
||||||
|
";
|
||||||
|
|
||||||
// Fonction pour calculer les jours ouvrés
|
$stmt = $conn->prepare($sql);
|
||||||
function getWorkingDays($startDate, $endDate) {
|
$stmt->bind_param("i", $managerId);
|
||||||
$workingDays = 0;
|
$stmt->execute();
|
||||||
$current = new DateTime($startDate);
|
|
||||||
$end = new DateTime($endDate);
|
|
||||||
|
|
||||||
while ($current <= $end) {
|
// ✅ Manquant dans ton code
|
||||||
$dayOfWeek = (int)$current->format('N');
|
$result = $stmt->get_result();
|
||||||
if ($dayOfWeek < 6) {
|
|
||||||
$workingDays++;
|
|
||||||
}
|
|
||||||
$current->modify('+1 day');
|
|
||||||
}
|
|
||||||
return $workingDays;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
$requests = [];
|
||||||
// D'abord, récupérer le service du manager
|
while ($row = $result->fetch_assoc()) {
|
||||||
$queryManagerService = "SELECT ServiceId FROM Users WHERE ID = ?";
|
$startDate = new DateTime($row['DateDebut']);
|
||||||
$stmtManager = $conn->prepare($queryManagerService);
|
$endDate = new DateTime($row['DateFin']);
|
||||||
$stmtManager->bind_param("i", $managerId);
|
$submittedDate = new DateTime($row['DateDemande']);
|
||||||
$stmtManager->execute();
|
$days = 0;
|
||||||
$resultManager = $stmtManager->get_result();
|
|
||||||
|
|
||||||
if ($managerRow = $resultManager->fetch_assoc()) {
|
$tmp = clone $startDate;
|
||||||
$serviceId = $managerRow['ServiceId'];
|
while ($tmp <= $endDate) {
|
||||||
error_log("getPendingRequests - Service ID du manager: $serviceId");
|
if ((int)$tmp->format('N') < 6) $days++;
|
||||||
|
$tmp->modify('+1 day');
|
||||||
// Récupérer les demandes en attente de l'équipe
|
|
||||||
$queryRequests = "
|
|
||||||
SELECT
|
|
||||||
dc.Id,
|
|
||||||
dc.DateDebut,
|
|
||||||
dc.DateFin,
|
|
||||||
dc.Statut,
|
|
||||||
dc.DateDemande,
|
|
||||||
dc.Commentaire,
|
|
||||||
dc.EmployeeId,
|
|
||||||
CONCAT(u.Prenom, ' ', u.Nom) as employee_name,
|
|
||||||
u.Email as employee_email,
|
|
||||||
tc.Nom as type
|
|
||||||
FROM DemandeConge dc
|
|
||||||
JOIN Users u ON dc.EmployeeId = u.ID
|
|
||||||
JOIN TypeConge tc ON dc.TypeCongeId = tc.Id
|
|
||||||
WHERE u.ServiceId = ?
|
|
||||||
AND dc.Statut = 'En attente'
|
|
||||||
AND u.ID != ?
|
|
||||||
ORDER BY dc.DateDemande ASC
|
|
||||||
";
|
|
||||||
|
|
||||||
$stmtRequests = $conn->prepare($queryRequests);
|
|
||||||
$stmtRequests->bind_param("ii", $serviceId, $managerId);
|
|
||||||
$stmtRequests->execute();
|
|
||||||
$resultRequests = $stmtRequests->get_result();
|
|
||||||
|
|
||||||
$requests = [];
|
|
||||||
while ($row = $resultRequests->fetch_assoc()) {
|
|
||||||
$workingDays = getWorkingDays($row['DateDebut'], $row['DateFin']);
|
|
||||||
|
|
||||||
$startDate = new DateTime($row['DateDebut']);
|
|
||||||
$endDate = new DateTime($row['DateFin']);
|
|
||||||
$submittedDate = new DateTime($row['DateDemande']);
|
|
||||||
|
|
||||||
if ($row['DateDebut'] === $row['DateFin']) {
|
|
||||||
$dateDisplay = $startDate->format('d/m/Y');
|
|
||||||
} else {
|
|
||||||
$dateDisplay = $startDate->format('d/m/Y') . ' - ' . $endDate->format('d/m/Y');
|
|
||||||
}
|
|
||||||
|
|
||||||
$requests[] = [
|
|
||||||
'id' => (int)$row['Id'],
|
|
||||||
'employee_id' => (int)$row['EmployeeId'],
|
|
||||||
'employee_name' => $row['employee_name'],
|
|
||||||
'employee_email' => $row['employee_email'],
|
|
||||||
'type' => $row['type'],
|
|
||||||
'start_date' => $row['DateDebut'],
|
|
||||||
'end_date' => $row['DateFin'],
|
|
||||||
'date_display' => $dateDisplay,
|
|
||||||
'days' => $workingDays,
|
|
||||||
'status' => $row['Statut'],
|
|
||||||
'reason' => $row['Commentaire'] ?: '',
|
|
||||||
'submitted_at' => $row['DateDemande'],
|
|
||||||
'submitted_display' => $submittedDate->format('d/m/Y')
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
error_log("getPendingRequests - Demandes en attente trouvées: " . count($requests));
|
|
||||||
|
|
||||||
echo json_encode([
|
|
||||||
"success" => true,
|
|
||||||
"message" => "Demandes en attente récupérées avec succès",
|
|
||||||
"requests" => $requests,
|
|
||||||
"service_id" => $serviceId
|
|
||||||
]);
|
|
||||||
|
|
||||||
$stmtRequests->close();
|
|
||||||
} else {
|
|
||||||
error_log("getPendingRequests - Manager non trouvé: $managerId");
|
|
||||||
echo json_encode([
|
|
||||||
"success" => false,
|
|
||||||
"message" => "Manager non trouvé"
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmtManager->close();
|
$requests[] = [
|
||||||
|
"id" => (int)$row['Id'],
|
||||||
} catch (Exception $e) {
|
"employee_id" => (int)$row['EmployeeId'],
|
||||||
error_log("Erreur getPendingRequests: " . $e->getMessage());
|
"employee_name" => $row['employee_name'],
|
||||||
echo json_encode([
|
"employee_email" => $row['employee_email'],
|
||||||
"success" => false,
|
"type" => $row['type'],
|
||||||
"message" => "Erreur lors de la récupération des demandes: " . $e->getMessage()
|
"start_date" => $row['DateDebut'],
|
||||||
]);
|
"end_date" => $row['DateFin'],
|
||||||
|
"date_display" => $row['DateDebut'] === $row['DateFin']
|
||||||
|
? $startDate->format('d/m/Y')
|
||||||
|
: $startDate->format('d/m/Y') . ' - ' . $endDate->format('d/m/Y'),
|
||||||
|
"days" => $days,
|
||||||
|
"status" => $row['Statut'],
|
||||||
|
"reason" => $row['Commentaire'] ?: '',
|
||||||
|
"file" => $row['DocumentJoint'] ?: null,
|
||||||
|
"submitted_at" => $row['DateDemande'],
|
||||||
|
"submitted_display" => $submittedDate->format('d/m/Y')
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
"success" => true,
|
||||||
|
"requests" => $requests
|
||||||
|
]);
|
||||||
|
|
||||||
|
$stmt->close();
|
||||||
$conn->close();
|
$conn->close();
|
||||||
?>
|
?>
|
||||||
@@ -76,7 +76,7 @@ const Manager = () => {
|
|||||||
|
|
||||||
const fetchAllTeamRequests = async () => {
|
const fetchAllTeamRequests = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`http://localhost/GTA/project/public/getAllTeamRequests.php?manager_id=${user.id}`);
|
const response = await fetch(`http://localhost/GTA/project/public/getAllTeamRequests.php?SuperieurId=${user.id}`);
|
||||||
const text = await response.text();
|
const text = await response.text();
|
||||||
console.log('Réponse toutes demandes équipe:', text);
|
console.log('Réponse toutes demandes équipe:', text);
|
||||||
|
|
||||||
@@ -85,7 +85,9 @@ const Manager = () => {
|
|||||||
setAllRequests(data.requests || []);
|
setAllRequests(data.requests || []);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
||||||
console.error('Erreur récupération toutes demandes:', error);
|
console.error('Erreur récupération toutes demandes:', error);
|
||||||
|
console.log('Réponse brute:', text);
|
||||||
setAllRequests([]);
|
setAllRequests([]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -384,10 +386,9 @@ const Manager = () => {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-3 max-h-80 overflow-y-auto">
|
<div className="space-y-3 max-h-80 overflow-y-auto">
|
||||||
{allRequests.map((request) => (
|
{allRequests.map((request) => (
|
||||||
<div key={request.id} className="flex items-center justify-between p-3 border border-gray-100 rounded-lg hover:bg-gray-50 transition-colors">
|
<div key={request.id} className="p-3 border border-gray-100 rounded-lg hover:bg-gray-50 transition-colors">
|
||||||
<div className="flex-1">
|
<div className="flex items-center gap-2 mb-2">
|
||||||
<div className="flex items-center gap-2 mb-1">
|
|
||||||
<p className="font-medium text-gray-900">{request.employee_name}</p>
|
<p className="font-medium text-gray-900">{request.employee_name}</p>
|
||||||
<span className={`px-2 py-1 rounded-full text-xs font-medium ${getTypeColor(request.type)}`}>
|
<span className={`px-2 py-1 rounded-full text-xs font-medium ${getTypeColor(request.type)}`}>
|
||||||
{request.type}
|
{request.type}
|
||||||
@@ -397,13 +398,33 @@ const Manager = () => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-gray-600">{request.date_display}</p>
|
<p className="text-sm text-gray-600">{request.date_display}</p>
|
||||||
<p className="text-xs text-gray-500">Soumis le {request.submitted_display}</p>
|
<p className="text-xs text-gray-500 mb-2">Soumis le {request.submitted_display}</p>
|
||||||
|
|
||||||
|
{request.reason && (
|
||||||
|
<p className="text-sm text-gray-700 mb-1"><strong>Motif :</strong> {request.reason}</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{request.file && (
|
||||||
|
<div className="text-sm mt-1">
|
||||||
|
<p className="text-gray-500">Document joint</p>
|
||||||
|
<a
|
||||||
|
href={`http://localhost/GTA/project/uploads/${request.file}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-blue-600 hover:underline flex items-center gap-1 mt-1"
|
||||||
|
>
|
||||||
|
<Eye className="w-4 h-4" />
|
||||||
|
Voir le fichier
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="text-right mt-2">
|
||||||
|
<p className="font-medium text-gray-900">{request.days}j</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-right">
|
))}
|
||||||
<p className="font-medium text-gray-900">{request.days}j</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -413,25 +434,51 @@ const Manager = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Modal de validation */}
|
{/* Modal de validation */}
|
||||||
|
|
||||||
{showValidationModal && selectedRequest && (
|
{showValidationModal && selectedRequest && (
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
|
||||||
<div className="bg-white rounded-xl shadow-xl max-w-md w-full">
|
<div className="bg-white rounded-xl shadow-xl max-w-md w-full">
|
||||||
|
{/* Header */}
|
||||||
<div className="p-6 border-b border-gray-100">
|
<div className="p-6 border-b border-gray-100">
|
||||||
<h3 className="text-lg font-semibold text-gray-900">
|
<h3 className="text-lg font-semibold text-gray-900">
|
||||||
{validationAction === 'approve' ? 'Approuver' : 'Refuser'} la demande
|
{validationAction === 'approve' ? 'Approuver' : 'Refuser'} la demande
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Corps du contenu */}
|
||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
<div className="mb-4 p-4 bg-gray-50 rounded-lg">
|
<div className="mb-4 p-4 bg-gray-50 rounded-lg">
|
||||||
<p className="font-medium text-gray-900">{selectedRequest.employee_name}</p>
|
<p className="font-medium text-gray-900">{selectedRequest.employee_name}</p>
|
||||||
<p className="text-sm text-gray-600">{selectedRequest.type} - {selectedRequest.date_display}</p>
|
<p className="text-sm text-gray-600">
|
||||||
|
{selectedRequest.type} - {selectedRequest.date_display}
|
||||||
|
</p>
|
||||||
<p className="text-sm text-gray-600">{selectedRequest.days} jour(s)</p>
|
<p className="text-sm text-gray-600">{selectedRequest.days} jour(s)</p>
|
||||||
|
|
||||||
{selectedRequest.reason && (
|
{selectedRequest.reason && (
|
||||||
<p className="text-sm text-gray-600 mt-2"><strong>Motif:</strong> {selectedRequest.reason}</p>
|
<p className="text-sm text-gray-600 mt-2">
|
||||||
|
<strong>Motif:</strong> {selectedRequest.reason}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{selectedRequest.file && (
|
||||||
|
<div>
|
||||||
|
<p className="text-gray-500">Document joint</p>
|
||||||
|
<a
|
||||||
|
href={`http://localhost/GTA/project/uploads/${selectedRequest.file}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-blue-600 hover:underline flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<Eye className="w-4 h-4" />
|
||||||
|
Voir le fichier
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Champ commentaire */}
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Commentaire {validationAction === 'reject' ? '(obligatoire)' : '(optionnel)'}
|
Commentaire {validationAction === 'reject' ? '(obligatoire)' : '(optionnel)'}
|
||||||
@@ -445,6 +492,7 @@ const Manager = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Boutons */}
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowValidationModal(false)}
|
onClick={() => setShowValidationModal(false)}
|
||||||
@@ -453,7 +501,9 @@ const Manager = () => {
|
|||||||
Annuler
|
Annuler
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleValidateRequest(selectedRequest.id, validationAction, validationComment)}
|
onClick={() =>
|
||||||
|
handleValidateRequest(selectedRequest.id, validationAction, validationComment)
|
||||||
|
}
|
||||||
disabled={validationAction === 'reject' && !validationComment.trim()}
|
disabled={validationAction === 'reject' && !validationComment.trim()}
|
||||||
className={`flex-1 px-4 py-2 text-white rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed ${validationAction === 'approve'
|
className={`flex-1 px-4 py-2 text-white rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed ${validationAction === 'approve'
|
||||||
? 'bg-green-600 hover:bg-green-700'
|
? 'bg-green-600 hover:bg-green-700'
|
||||||
|
|||||||
BIN
project/uploads/doc_6895efd7750ba.jpg
Normal file
BIN
project/uploads/doc_6895efd7750ba.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 161 KiB |
BIN
project/uploads/doc_6895f5df5fa2c.jpg
Normal file
BIN
project/uploads/doc_6895f5df5fa2c.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 501 KiB |
Reference in New Issue
Block a user