Procesy obsługi spotkań

This commit is contained in:
Flatlogic Bot 2026-01-11 15:45:15 +00:00
parent 2cc2c42b57
commit eb3e723258
4 changed files with 88 additions and 32 deletions

View File

@ -763,15 +763,15 @@ class WorkflowEngine {
} }
} }
public function getOrCreateMeeting(int $groupId, string $meetingDatetime): int { public function getOrCreateMeeting(int $bniGroupId, string $meetingDatetime): int {
$meetingKey = $groupId . '_' . $meetingDatetime; $meetingKey = $bniGroupId . '_' . $meetingDatetime;
$stmt = $this->pdo->prepare("SELECT id FROM meetings WHERE meeting_key = ?"); $stmt = $this->pdo->prepare("SELECT id FROM meetings WHERE meeting_key = ?");
$stmt->execute([$meetingKey]); $stmt->execute([$meetingKey]);
$meetingId = $stmt->fetchColumn(); $meetingId = $stmt->fetchColumn();
if (!$meetingId) { if (!$meetingId) {
$stmt = $this->pdo->prepare("INSERT INTO meetings (bni_group_id, meeting_datetime, meeting_key) VALUES (?, ?, ?)"); $stmt = $this->pdo->prepare("INSERT INTO meetings (bni_group_id, meeting_date, meeting_datetime, meeting_key) VALUES (?, DATE(?), ?, ?)");
$stmt->execute([$groupId, $meetingDatetime, $meetingKey]); $stmt->execute([$bniGroupId, $meetingDatetime, $meetingDatetime, $meetingKey]);
$meetingId = $this->pdo->lastInsertId(); $meetingId = $this->pdo->lastInsertId();
} }
@ -793,8 +793,14 @@ class WorkflowEngine {
public function updateMeetingAttendance(int $meetingId, int $personId, int $bniGroupId, string $status, int $userId, ?string $guestSurvey = null): void { public function updateMeetingAttendance(int $meetingId, int $personId, int $bniGroupId, string $status, int $userId, ?string $guestSurvey = null): void {
$sql = "INSERT INTO meeting_attendance (meeting_id, person_id, bni_group_id, attendance_status, guest_survey, updated_by) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE attendance_status = VALUES(attendance_status), guest_survey = VALUES(guest_survey), updated_by = VALUES(updated_by), bni_group_id = VALUES(bni_group_id)"; $sql = "INSERT INTO meeting_attendance (meeting_id, person_id, bni_group_id, attendance_status, guest_survey, updated_by) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE attendance_status = VALUES(attendance_status), guest_survey = VALUES(guest_survey), updated_by = VALUES(updated_by), bni_group_id = VALUES(bni_group_id)";
// Log query and params
$params = [$meetingId, $personId, $bniGroupId, $status, $guestSurvey, $userId];
error_log("SQL: $sql");
error_log("Params: " . json_encode($params));
$stmt = $this->pdo->prepare($sql); $stmt = $this->pdo->prepare($sql);
$stmt->execute([$meetingId, $personId, $bniGroupId, $status, $guestSurvey, $userId]); $stmt->execute($params);
} }
public function getMeetingAttendanceByGroupAndDate(int $groupId, string $meetingDatetime): array { public function getMeetingAttendanceByGroupAndDate(int $groupId, string $meetingDatetime): array {

View File

@ -1,47 +1,47 @@
<?php <?php
require_once 'lib/ErrorHandler.php';
register_error_handler();
require_once 'db/config.php';
require_once 'WorkflowEngine.php'; require_once 'WorkflowEngine.php';
session_start(); session_start();
header('Content-Type: application/json'); header('Content-Type: application/json');
$response = ['success' => false, 'message' => 'An error occurred.'];
if (!isset($_SESSION['user_id'])) { if (!isset($_SESSION['user_id'])) {
$response['message'] = 'You must be logged in to perform this action.'; throw new WorkflowException('You must be logged in to perform this action.', 401);
echo json_encode($response);
exit;
} }
if ($_SERVER['REQUEST_METHOD'] !== 'POST') { if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$response['message'] = 'Invalid request method.'; throw new WorkflowException('Invalid request method.', 405);
echo json_encode($response);
exit;
} }
$personId = $_POST['person_id'] ?? null; $personId = $_POST['person_id'] ?? null;
$groupId = $_POST['group_id'] ?? null; $bniGroupId = $_POST['bni_group_id'] ?? $_POST['group_id'] ?? null;
$meetingDate = $_POST['meeting_date'] ?? null; $meetingDate = $_POST['meeting_date'] ?? null;
$status = $_POST['attendance_status'] ?? null; $status = $_POST['attendance_status'] ?? null;
$guestSurvey = $_POST['guest_survey'] ?? null; $guestSurvey = $_POST['guest_survey'] ?? null;
$userId = $_SESSION['user_id']; $userId = $_SESSION['user_id'];
if (!$personId || !$groupId || !$meetingDate || !$status) { if (!$personId || !$bniGroupId || !$meetingDate || !$status) {
$response['message'] = 'Missing required parameters.'; $missing_params = [];
echo json_encode($response); if (!$personId) $missing_params[] = 'person_id';
exit; if (!$bniGroupId) $missing_params[] = 'bni_group_id';
if (!$meetingDate) $missing_params[] = 'meeting_date';
if (!$status) $missing_params[] = 'status';
throw new WorkflowException('Missing required parameters: ' . implode(', ', $missing_params), 400);
} }
try {
$workflowEngine = new WorkflowEngine(); $workflowEngine = new WorkflowEngine();
$meetingId = $workflowEngine->getOrCreateMeeting((int)$groupId, $meetingDate);
$workflowEngine->updateMeetingAttendance($meetingId, (int)$personId, (int)$groupId, $status, (int)$userId, $guestSurvey);
$response['success'] = true; $meetingId = $workflowEngine->getOrCreateMeeting((int)$bniGroupId, $meetingDate);
$response['message'] = 'Attendance updated successfully.'; $workflowEngine->updateMeetingAttendance($meetingId, (int)$personId, (int)$bniGroupId, $status, (int)$userId, $guestSurvey);
} catch (Exception $e) {
error_log($e->getMessage()); $response = [
$response['message'] = 'Error updating attendance: ' . $e->getMessage(); 'success' => true,
} 'message' => 'Attendance updated successfully.'
];
echo json_encode($response); echo json_encode($response);

View File

@ -0,0 +1,18 @@
<?php
require_once __DIR__ . '/../../db/config.php';
$db = db();
// Step 1: Back-fill bni_group_id from group_id where bni_group_id is NULL
$db->exec("UPDATE meetings SET bni_group_id = group_id WHERE bni_group_id IS NULL");
// Step 2: Modify bni_group_id to be NOT NULL
$db->exec("ALTER TABLE meetings MODIFY COLUMN bni_group_id INT(11) NOT NULL");
// Step 3: Find and drop the foreign key constraint on group_id
$db->exec("ALTER TABLE meetings DROP FOREIGN KEY `meetings_ibfk_1`");
// Step 4: Drop the old group_id column
$db->exec("ALTER TABLE meetings DROP COLUMN group_id");
echo "Migration 035 cleanup meetings table applied successfully.";

View File

@ -510,7 +510,7 @@ $status_colors = [
</div> </div>
<div class="modal-body"> <div class="modal-body">
<input type="hidden" name="person_id" id="meetingPersonId"> <input type="hidden" name="person_id" id="meetingPersonId">
<input type="hidden" name="group_id" id="meetingGroupId"> <input type="hidden" name="bni_group_id" id="meetingGroupId">
<input type="hidden" name="meeting_date" id="meetingDate"> <input type="hidden" name="meeting_date" id="meetingDate">
<p><strong>Person:</strong> <span id="meetingPersonName"></span></p> <p><strong>Person:</strong> <span id="meetingPersonName"></span></p>
<div class="mb-3"> <div class="mb-3">
@ -645,13 +645,38 @@ document.addEventListener('DOMContentLoaded', function () {
e.preventDefault(); e.preventDefault();
const formData = new FormData(this); const formData = new FormData(this);
const personId = formData.get('person_id'); const personId = formData.get('person_id');
const bniGroupId = formData.get('group_id'); const bniGroupId = formData.get('bni_group_id');
fetch('_update_meeting_attendance.php', { fetch('_update_meeting_attendance.php', {
method: 'POST', method: 'POST',
body: formData body: formData
}) })
.then(response => response.json()) .then(response => {
// We need to handle the body carefully to avoid "body already consumed" errors.
// We'll get the text first, then try to parse it.
return response.text().then(text => {
// If the response wasn't OK, we always treat it as an error.
if (!response.ok) {
try {
// See if the error response is JSON
const data = JSON.parse(text);
const errorMessage = data.error || 'Unknown server error.';
const correlationId = data.correlation_id || 'N/A';
throw new Error(`Server Error: ${errorMessage} (Correlation ID: ${correlationId})`);
} catch (e) {
// If it's not JSON, throw the raw text.
throw new Error('Server error: ' + response.status + ' ' + response.statusText + '. Response: ' + text.substring(0, 200));
}
}
// If the response was OK, parse the text as JSON.
// It might still fail if the OK response is not valid JSON.
try {
return JSON.parse(text);
} catch (e) {
throw new Error('Failed to parse successful response as JSON. Raw response: ' + text.substring(0, 200));
}
});
})
.then(data => { .then(data => {
if (data.success) { if (data.success) {
meetingModal.hide(); meetingModal.hide();
@ -661,8 +686,15 @@ document.addEventListener('DOMContentLoaded', function () {
updateDot(dot, formData.get('attendance_status')); updateDot(dot, formData.get('attendance_status'));
} }
} else { } else {
alert(data.message || 'An error occurred.'); // Handle structured errors from a successful (e.g. 200) response
const errorMessage = data.error || 'An unknown error occurred.';
const correlationId = data.correlation_id || 'N/A';
alert(`Error: ${errorMessage}\nCorrelation ID: ${correlationId}`);
} }
})
.catch(error => {
console.error('Fetch Error:', error);
alert('An error occurred while submitting the form. ' + error.message);
}); });
}); });