diff --git a/WorkflowEngine.php b/WorkflowEngine.php
index f4071b8..98ed786 100644
--- a/WorkflowEngine.php
+++ b/WorkflowEngine.php
@@ -1,4 +1,5 @@
pdo->beginTransaction();
try {
// 1. Find active process definition by code.
$stmt_def = $this->pdo->prepare("SELECT * FROM process_definitions WHERE code = ? AND active = 1");
$stmt_def->execute([$processCode]);
$definition = $stmt_def->fetch(PDO::FETCH_ASSOC);
- error_log("startProcess: definition=" . print_r($definition, true));
if (!$definition) {
- throw new Exception("Active process definition with code '$processCode' not found.");
- }
+ // If no process definition is found, check if there is a definition for a checklist
+ $stmt_def = $this->pdo->prepare("SELECT * FROM process_definitions WHERE id = ?");
+ $stmt_def->execute([$processCode]);
+ $definition = $stmt_def->fetch(PDO::FETCH_ASSOC);
- $definition_json = json_decode($definition['definition_json'], true);
- if (!$definition_json || !isset($definition_json['start_node_id'])) {
- throw new Exception("Process definition is missing start_node_id.");
+ if (!$definition) {
+ throw new Exception("Process definition with code or id '$processCode' not found.");
+ }
+
+ $definition_json = !empty($definition['definition_json']) ? json_decode($definition['definition_json'], true) : [];
+ if (empty($definition_json) || $definition_json['type'] !== 'checklist') {
+ throw new Exception("Process definition with code '$processCode' not found or not a checklist.");
+ }
+
+ // For checklists, there's no start_node_id, so we can proceed with instance creation
+ $startNodeId = null;
+
+ } else {
+ $definition_json = !empty($definition['definition_json']) ? json_decode($definition['definition_json'], true) : [];
+ if (empty($definition_json) || !isset($definition_json['start_node_id'])) {
+ throw new Exception("Process definition is missing start_node_id.");
+ }
+ $startNodeId = $definition_json['start_node_id'];
}
- $startNodeId = $definition_json['start_node_id'];
// 2. Create a new process instance.
$stmt_insert = $this->pdo->prepare(
- "INSERT INTO process_instances (personId, processDefinitionId, current_node_id, current_status, lastActivityAt) VALUES (?, ?, ?, 'in_progress', NOW())"
+ "INSERT INTO process_instances (person_id, process_definition_id, current_node_id, current_status, lastActivityAt) VALUES (?, ?, ?, 'in_progress', NOW())"
);
$stmt_insert->execute([$personId, $definition['id'], $startNodeId]);
- error_log("startProcess: affected rows=" . $stmt_insert->rowCount());
$instanceId = $this->pdo->lastInsertId();
- error_log("startProcess: instanceId=$instanceId");
// 3. Create a system event for process start.
$this->addEvent($instanceId, 'system', 'Process started.', $startNodeId, [], $userId);
@@ -88,9 +101,9 @@ class WorkflowEngine {
}
$stmt_def = $this->pdo->prepare("SELECT definition_json FROM process_definitions WHERE id = ?");
- $stmt_def->execute([$instance['processDefinitionId']]);
+ $stmt_def->execute([$instance['process_definition_id']]);
$definition_json = $stmt_def->fetchColumn();
- $definition = json_decode($definition_json, true);
+ $definition = !empty($definition_json) ? json_decode($definition_json, true) : [];
$currentNodeId = $instance['current_node_id'];
$nodeInfo = $definition['nodes'][$currentNodeId] ?? null;
@@ -157,22 +170,45 @@ class WorkflowEngine {
}
}
+ public function addNote(int $instanceId, string $message, int $userId): bool {
+ $state = $this->getProcessState($instanceId);
+ if (!$state) {
+ // Even if the instance isn't found, we shouldn't crash. Log and return false.
+ error_log("addNote failed: Process instance $instanceId not found.");
+ return false;
+ }
+ $currentNodeId = $state['instance']['current_node_id'];
+ $payload = ['message' => $message];
+ $this->addEvent($instanceId, 'note', $message, $currentNodeId, $payload, $userId);
+ return true;
+ }
+
private function addEvent(int $instanceId, string $eventType, string $message, ?string $nodeId, array $payload, int $userId): void {
$stmt = $this->pdo->prepare(
- "INSERT INTO process_events (processInstanceId, eventType, message, node_id, payload_json, createdById) VALUES (?, ?, ?, ?, ?, ?)"
+ "INSERT INTO process_events (processInstanceId, event_type, message, node_id, payload_json, createdBy, createdAt) VALUES (?, ?, ?, ?, ?, ?, NOW())"
);
$stmt->execute([$instanceId, $eventType, $message, $nodeId, json_encode($payload), $userId]);
}
public function getOrCreateInstanceByDefId(int $personId, int $processDefinitionId, int $userId): ?array {
- $stmt = $this->pdo->prepare("SELECT * FROM process_instances WHERE personId = ? AND processDefinitionId = ?");
+ $stmt = $this->pdo->prepare("SELECT * FROM process_instances WHERE `person_id` = ? AND `process_definition_id` = ?");
$stmt->execute([$personId, $processDefinitionId]);
$instance = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$instance) {
- $stmt_def = $this->pdo->prepare("SELECT code FROM process_definitions WHERE id = ?");
+ // For checklists, the process code is the process definition ID
+ $stmt_def = $this->pdo->prepare("SELECT definition_json FROM process_definitions WHERE id = ?");
$stmt_def->execute([$processDefinitionId]);
- $processCode = $stmt_def->fetchColumn();
+ $definition_json = $stmt_def->fetchColumn();
+ $definition = !empty($definition_json) ? json_decode($definition_json, true) : [];
+
+ if ($definition && isset($definition['type']) && $definition['type'] === 'checklist') {
+ $processCode = (string) $processDefinitionId;
+ } else {
+ $stmt_def = $this->pdo->prepare("SELECT code FROM process_definitions WHERE id = ?");
+ $stmt_def->execute([$processDefinitionId]);
+ $processCode = $stmt_def->fetchColumn();
+ }
if($processCode) {
$instanceId = $this->startProcess($processCode, $personId, $userId);
@@ -187,7 +223,7 @@ class WorkflowEngine {
}
public function getEvents(int $instanceId): array {
- $stmt_events = $this->pdo->prepare("SELECT pe.*, p.email as user_email, p.firstName, p.lastName FROM process_events pe JOIN people p ON pe.createdById = p.id WHERE pe.processInstanceId = ? ORDER BY pe.createdAt DESC");
+ $stmt_events = $this->pdo->prepare("SELECT pe.*, p.email as user_email, p.firstName, p.lastName FROM process_events pe JOIN people p ON pe.createdBy = p.id WHERE pe.processInstanceId = ? ORDER BY pe.createdAt DESC");
$stmt_events->execute([$instanceId]);
return $stmt_events->fetchAll(PDO::FETCH_ASSOC);
}
@@ -212,4 +248,17 @@ class WorkflowEngine {
return $transitions;
}
-}
+
+ public function getProcessDefinitionNodes(int $processDefinitionId): array {
+ $stmt = $this->pdo->prepare("SELECT definition_json FROM process_definitions WHERE id = ?");
+ $stmt->execute([$processDefinitionId]);
+ $json = $stmt->fetchColumn();
+
+ if (!$json) {
+ return [];
+ }
+
+ $definition = !empty($json) ? json_decode($json, true) : [];
+ return $definition['nodes'] ?? [];
+ }
+}
\ No newline at end of file
diff --git a/_apply_transition.php b/_apply_transition.php
index 34621ca..fced8b8 100644
--- a/_apply_transition.php
+++ b/_apply_transition.php
@@ -1,43 +1,67 @@
false, 'message' => 'Wystąpił nieoczekiwany błąd.'];
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
- header('Location: process_dashboard.php');
+ http_response_code(405);
+ $response['message'] = 'Invalid request method.';
+ echo json_encode($response);
exit;
}
require_once 'WorkflowEngine.php';
if (!isset($_POST['instanceId']) || !isset($_POST['transitionId'])) {
- $_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'Błąd: Brak wymaganych parametrów.'];
- header('Location: process_dashboard.php');
+ http_response_code(400);
+ $response['message'] = 'Błąd: Brak wymaganych parametrów.';
+ echo json_encode($response);
exit;
}
$instanceId = (int)$_POST['instanceId'];
$transitionId = $_POST['transitionId'];
$userId = $_SESSION['user_id'] ?? null;
-$payload = $_POST['payload'] ?? null;
+$payload = $_POST['payload'] ?? [];
if (!$userId) {
- $_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'Błąd: Sesja wygasła.'];
- header('Location: login.php');
+ http_response_code(401);
+ $response['message'] = 'Błąd: Sesja wygasła.';
+ echo json_encode($response);
exit;
}
try {
$engine = new WorkflowEngine();
- $success = $engine->applyTransition($instanceId, $transitionId, $payload, $userId);
+ $success = false;
+
+ if ($transitionId === 'note') {
+ // Special case: Just add a note, don't change state.
+ $message = $payload['message'] ?? '';
+ if (!empty($message)) {
+ $success = $engine->addNote($instanceId, $message, $userId);
+ if ($success) {
+ $response['message'] = 'Notatka została dodana.';
+ }
+ }
+ } else {
+ // Standard transition logic
+ $success = $engine->applyTransition($instanceId, $transitionId, $payload, $userId);
+ if ($success) {
+ $response['message'] = 'Akcja została wykonana pomyślnie.';
+ }
+ }
if ($success) {
- $_SESSION['flash_message'] = ['type' => 'success', 'message' => 'Akcja została wykonana pomyślnie.'];
- } else {
- $_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'Błąd: Nie udało się wykonać akcji.'];
+ $response['success'] = true;
}
+
} catch (Exception $e) {
error_log("Error applying transition: " . $e->getMessage());
- $_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'Wystąpił krytyczny błąd: ' . $e->getMessage()];
+ http_response_code(500);
+ $response['message'] = 'Wystąpił krytyczny błąd: ' . $e->getMessage();
}
-header('Location: process_dashboard.php');
+echo json_encode($response);
exit;
\ No newline at end of file
diff --git a/_get_instance_details.php b/_get_instance_details.php
index b19d060..514a6e8 100644
--- a/_get_instance_details.php
+++ b/_get_instance_details.php
@@ -1,17 +1,15 @@
getOrCreateInstanceByDefId($personId, $processDefinitionId, $userId);
-
if (!$instance) {
http_response_code(500);
- die("Nie można pobrać lub utworzyć instancji procesu. personId: $personId, processDefinitionId: $processDefinitionId, userId: $userId");
+ die("Nie można pobrać lub utworzyć instancji procesu.");
}
$instanceId = $instance['id'];
-// 2. Pobierz powiązane dane przez silnik
-$events = $engine->getEvents($instanceId);
-$availableTransitions = $engine->getAvailableTransitions($instanceId);
-
-// 3. Pobierz nazwy do wyświetlenia
-$pdo = db();
+// 2. Fetch all related data
$stmt_person = $pdo->prepare("SELECT firstName, lastName FROM people WHERE id = ?");
$stmt_person->execute([$personId]);
$person = $stmt_person->fetch();
-$stmt_process = $pdo->prepare("SELECT name FROM process_definitions WHERE id = ?");
+$stmt_process = $pdo->prepare("SELECT * FROM process_definitions WHERE id = ?");
$stmt_process->execute([$processDefinitionId]);
$process = $stmt_process->fetch();
+$definition = $process && $process['definition_json'] ? json_decode($process['definition_json'], true) : null;
+$isChecklist = ($definition && isset($definition['type']) && $definition['type'] === 'checklist');
+
+$events = $engine->getEvents($instanceId);
+
?>
-
= htmlspecialchars($person['firstName'] . ' ' . $person['lastName']) ?> - = htmlspecialchars($process['name']) ?>
-Status: = htmlspecialchars($instance['current_status']) ?>
-
+
+
+ = htmlspecialchars($person['firstName'] . ' ' . $person['lastName']) ?> - = htmlspecialchars($process['name']) ?>
+
-Wykonaj akcję
-
-
-
-
-Historia
-
- Brak zdarzeń.
-
-
-
-
- = htmlspecialchars(ucfirst(str_replace('_', ' ', $event['event_type']))) ?>
-
+
+
+
Zadania do wykonania
+
+
-
= htmlspecialchars($message) ?>
-
-
Przez = htmlspecialchars($event['firstName'] . ' ' . $event['lastName']) ?> dnia = date('d.m.Y, H:i', strtotime($event['createdAt'])) ?>
-
-
-
-
\ No newline at end of file
+
+ >
+
+ = htmlspecialchars($task['name']) ?>
+
+
+
+
+
+
+
+ getProcessDefinitionNodes($processDefinitionId);
+ $availableTransitions = $engine->getAvailableTransitions($instanceId);
+
+ $available_target_node_ids = array_map(function($t) { return $t['to']; }, $availableTransitions);
+ $available_transitions_map = [];
+ foreach ($availableTransitions as $t) {
+ $available_transitions_map[$t['to']] = $t;
+ }
+
+ $visited_nodes = [];
+ foreach ($events as $event) {
+ if ($event['node_id']) {
+ $visited_nodes[$event['node_id']] = true;
+ }
+ }
+ ?>
+
+
+
+
+
+
+
Dodaj notatkę
+
+
+
+
Dodaj notatkę
+
+
+
+
+
+
Historia
+
+
Brak zdarzeń.
+
+
+
+
+ = htmlspecialchars(ucfirst(str_replace('_', ' ', $event['event_type']))) ?>
+ ' . htmlspecialchars($message) . '';
+ }
+ ?>
+ Przez = htmlspecialchars($event['firstName'] . ' ' . $event['lastName']) ?> dnia = date('d.m.Y, H:i', strtotime($event['created_at'])) ?>
+
+
+
+
+
+
+
+
diff --git a/_get_process_bulk_details.php b/_get_process_bulk_details.php
new file mode 100644
index 0000000..05ed8e5
--- /dev/null
+++ b/_get_process_bulk_details.php
@@ -0,0 +1,96 @@
+ 'Process ID is required.']);
+ exit;
+}
+
+$process_id = $_GET['process_id'];
+
+try {
+ $pdo = db();
+
+ // 1. Get process definition details
+ $stmt_def = $pdo->prepare("SELECT * FROM process_definitions WHERE id = ?");
+ $stmt_def->execute([$process_id]);
+ $process_definition = $stmt_def->fetch(PDO::FETCH_ASSOC);
+
+ if (!$process_definition) {
+ http_response_code(404);
+ echo json_encode(['error' => 'Process definition not found.']);
+ exit;
+ }
+
+ if (!empty($process_definition['definition_json'])) {
+ $process_definition['definition_json'] = json_decode($process_definition['definition_json'], true);
+ if (json_last_error() !== JSON_ERROR_NONE) {
+ throw new Exception("Failed to decode process definition JSON. Error: " . json_last_error_msg());
+ }
+ } else {
+ $process_definition['definition_json'] = [];
+ }
+
+ // 2. Get all instances for this process
+ $stmt_instances = $pdo->prepare("SELECT * FROM process_instances WHERE processDefinitionId = ?");
+ $stmt_instances->execute([$process_id]);
+ $instances = $stmt_instances->fetchAll(PDO::FETCH_ASSOC);
+
+ $instance_ids = array_map(function($i) { return $i['id']; }, $instances);
+
+ // 3. Get all events for these instances
+ $events = [];
+ if (!empty($instance_ids)) {
+ $placeholders = implode(',', array_fill(0, count($instance_ids), '?'));
+ $stmt_events = $pdo->prepare("SELECT * FROM process_events WHERE processInstanceId IN ($placeholders) ORDER BY createdAt, id");
+ $stmt_events->execute($instance_ids);
+ $all_events = $stmt_events->fetchAll(PDO::FETCH_ASSOC);
+ // Group events by instance_id
+ foreach ($all_events as $event) {
+ $events[$event['processInstanceId']][] = $event;
+ }
+ }
+
+ // 4. Get People details
+ $people_ids = array_unique(array_column($instances, 'personId'));
+ $people = [];
+ if (!empty($people_ids)) {
+ $valid_people_ids = array_filter($people_ids, 'is_numeric');
+
+ if (!empty($valid_people_ids)) {
+ $placeholders = implode(',', array_fill(0, count($valid_people_ids), '?'));
+ $stmt_people = $pdo->prepare("SELECT id, firstName, lastName FROM people WHERE id IN ($placeholders)");
+ $stmt_people->execute(array_values($valid_people_ids));
+ $people_results = $stmt_people->fetchAll(PDO::FETCH_ASSOC);
+ foreach ($people_results as $person) {
+ $people[$person['id']] = $person;
+ $people[$person['id']]['name'] = trim($person['firstName'] . ' ' . $person['lastName']);
+ }
+ }
+ }
+
+ // Assemble the response
+ // Ensure steps are available, even if the JSON is empty or malformed.
+ $steps = !empty($process_definition['definition_json']['steps']) ? $process_definition['definition_json']['steps'] : [];
+
+ $response = [
+ 'process' => $process_definition,
+ 'steps' => $steps,
+ 'instances' => $instances,
+ 'events' => $events,
+ 'people' => $people
+ ];
+
+ echo json_encode($response);
+
+} catch (PDOException $e) {
+ http_response_code(500);
+ echo json_encode(['error' => 'A database error occurred.', 'details' => $e->getMessage()]);
+} catch (Exception $e) {
+ http_response_code(500);
+ echo json_encode(['error' => 'A general error occurred.', 'details' => $e->getMessage()]);
+}
+?>
\ No newline at end of file
diff --git a/_init_single_instance.php b/_init_single_instance.php
new file mode 100644
index 0000000..5e612c2
--- /dev/null
+++ b/_init_single_instance.php
@@ -0,0 +1,31 @@
+getOrCreateInstanceByDefId($personId, $processDefinitionId, $userId);
+
+if ($instance) {
+ $_SESSION['success_message'] = "Process initialized successfully.";
+} else {
+ $_SESSION['error_message'] = "Failed to initialize process.";
+}
+
+header('Location: index.php');
+exit();
diff --git a/_update_training_checklist_status.php b/_update_training_checklist_status.php
new file mode 100644
index 0000000..e8c6852
--- /dev/null
+++ b/_update_training_checklist_status.php
@@ -0,0 +1,81 @@
+ false, 'error' => 'Unauthorized']);
+ exit;
+}
+
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ http_response_code(405);
+ echo json_encode(['error' => 'Method Not Allowed']);
+ exit;
+}
+
+$inputJSON = file_get_contents('php://input');
+$input = json_decode($inputJSON, true);
+
+if (json_last_error() !== JSON_ERROR_NONE) {
+ http_response_code(400);
+ echo json_encode(['error' => 'Invalid JSON']);
+ exit;
+}
+
+$instanceId = $input['instance_id'] ?? null;
+$taskCode = $input['task_code'] ?? null;
+$isChecked = $input['is_checked'] ?? null;
+
+if (!$instanceId || !$taskCode || $isChecked === null) {
+ http_response_code(400);
+ echo json_encode(['error' => 'Missing required parameters: instance_id, task_code, is_checked']);
+ exit;
+}
+
+try {
+ $pdo = db();
+
+ // Get current data_json
+ $stmt = $pdo->prepare("SELECT data_json FROM process_instances WHERE id = ?");
+ $stmt->execute([$instanceId]);
+ $currentDataJson = $stmt->fetchColumn();
+
+ $data = $currentDataJson ? json_decode($currentDataJson, true) : [];
+
+ // Update the specific task status
+ $data[$taskCode] = (bool)$isChecked;
+ $newDataJson = json_encode($data);
+
+ // Save new data_json and update timestamp
+ $stmt = $pdo->prepare("UPDATE process_instances SET data_json = ?, lastActivityAt = CURRENT_TIMESTAMP WHERE id = ?");
+ $success = $stmt->execute([$newDataJson, $instanceId]);
+
+ if ($success) {
+ // Calculate progress
+ $stmt = $pdo->prepare("SELECT pd.definition_json FROM process_definitions pd JOIN process_instances pi ON pd.id = pi.process_definition_id WHERE pi.id = ?");
+ $stmt->execute([$instanceId]);
+ $definitionJson = $stmt->fetchColumn();
+ $definition = json_decode($definitionJson, true);
+ $totalTasks = count($definition['tasks'] ?? []);
+ $completedTasks = count(array_filter($data));
+
+ echo json_encode([
+ 'success' => true,
+ 'message' => 'Status updated successfully.',
+ 'progress' => [
+ 'completed' => $completedTasks,
+ 'total' => $totalTasks
+ ],
+ 'lastActivityAt' => date('d/m/y')
+ ]);
+ } else {
+ http_response_code(500);
+ echo json_encode(['error' => 'Failed to update status.']);
+ }
+
+} catch (PDOException $e) {
+ http_response_code(500);
+ echo json_encode(['error' => 'Database error: ' . $e->getMessage()]);
+}
+?>
\ No newline at end of file
diff --git a/assets/js/main.js b/assets/js/main.js
index 3a2a7cf..9011386 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -10,3 +10,151 @@ document.addEventListener('DOMContentLoaded', function () {
});
}
});
+
+$(document).ready(function() {
+ // Handler for showing the edit person modal
+ $('#editPersonModal').on('show.bs.modal', function (event) {
+ var button = $(event.relatedTarget); // Button that triggered the modal
+ var personId = button.data('person-id'); // Extract info from data-* attributes
+ var modal = $(this);
+
+ // Clear previous data
+ modal.find('form').trigger('reset');
+ modal.find('#editPersonId').val('');
+ modal.find('#editRoles').empty();
+ // Clear file paths
+ modal.find('#editCompanyLogoPath, #editPersonPhotoPath, #editGainsSheetPath, #editTopWantedPath, #editTopOwnedPath').text('');
+
+ if (personId) {
+ // AJAX request to get person details
+ $.ajax({
+ url: '_get_person_details.php',
+ type: 'GET',
+ data: { id: personId },
+ dataType: 'json',
+ success: function(response) {
+ if (response.error) {
+ alert('Error fetching person details: ' + response.error);
+ return;
+ }
+
+ var person = response.person;
+ var all_functions = response.all_functions;
+ var person_functions = response.person_functions;
+
+ if (!person) {
+ alert('Could not find person data.');
+ return;
+ }
+
+ // Populate the form fields
+ modal.find('#editPersonId').val(person.id);
+ modal.find('#editFirstName').val(person.firstName);
+ modal.find('#editLastName').val(person.lastName);
+ modal.find('#editPhone').val(person.phone);
+ modal.find('#editEmail').val(person.email);
+ modal.find('#editRole').val(person.role);
+ modal.find('#editBniGroup').val(person.bni_group_id);
+ modal.find('#editCompanyName').val(person.companyName);
+ modal.find('#editNip').val(person.nip);
+ modal.find('#editIndustry').val(person.industry);
+ modal.find('#editCompanySize').val(person.company_size_revenue);
+ modal.find('#editBusinessDescription').val(person.business_description);
+
+ // Populate file paths
+ if (person.company_logo_path) {
+ modal.find('#editCompanyLogoPath').text('Current file: ' + person.company_logo_path.split('/').pop());
+ }
+ if (person.person_photo_path) {
+ modal.find('#editPersonPhotoPath').text('Current file: ' + person.person_photo_path.split('/').pop());
+ }
+ if (person.gains_sheet_path) {
+ modal.find('#editGainsSheetPath').text('Current file: ' + person.gains_sheet_path.split('/').pop());
+ }
+ if (person.top_wanted_contacts_path) {
+ modal.find('#editTopWantedPath').text('Current file: ' + person.top_wanted_contacts_path.split('/').pop());
+ }
+ if (person.top_owned_contacts_path) {
+ modal.find('#editTopOwnedPath').text('Current file: ' + person.top_owned_contacts_path.split('/').pop());
+ }
+
+ // Populate functions/roles dropdown and select assigned ones
+ var rolesSelect = modal.find('#editRoles');
+ rolesSelect.empty(); // Clear existing options
+
+ if (all_functions && all_functions.length > 0) {
+ const groupedFunctions = all_functions.reduce((acc, func) => {
+ const groupName = func.group_name || 'General';
+ if (!acc[groupName]) {
+ acc[groupName] = [];
+ }
+ acc[groupName].push(func);
+ return acc;
+ }, {});
+
+ for (const groupName in groupedFunctions) {
+ const optgroup = $('').attr('label', groupName);
+ groupedFunctions[groupName].forEach(function(func) {
+ var option = $(' ').val(func.id).text(func.name);
+ if (person_functions && person_functions.includes(String(func.id))) {
+ option.prop('selected', true);
+ }
+ optgroup.append(option);
+ });
+ rolesSelect.append(optgroup);
+ }
+ }
+
+ // Trigger change to show/hide conditional fields
+ modal.find('#editRole').trigger('change');
+
+ // Also set up the delete button
+ $('#deleteUserBtn').data('person-id', person.id);
+ $('#personNameToDelete').text(person.firstName + ' ' + person.lastName);
+
+ },
+ error: function(xhr, status, error) {
+ alert('An error occurred while fetching person data. Please try again.');
+ console.error("AJAX Error:", status, error);
+ }
+ });
+ }
+ });
+
+ // Show/hide group selection based on role for both Edit and Create modals
+ $(document).on('change', '#editRole, #createRole', function() {
+ const role = $(this).val();
+ const isMember = role === 'member';
+
+ // Find the correct context (modal) for the elements
+ const modal = $(this).closest('.modal-content');
+
+ modal.find('.member-only-fields').toggle(isMember);
+ modal.find('#edit-group-selection-div, #create-group-selection-div').toggle(isMember);
+ });
+
+ // Handle Delete Person confirmation
+ $('#confirmDeleteBtn').on('click', function() {
+ var personId = $('#deleteUserBtn').data('person-id');
+ if (personId) {
+ // Use a form submission to perform the delete
+ var form = $(' ');
+ form.attr("method", "post");
+ form.attr("action", "_delete_person.php");
+
+ var field = $(' ');
+ field.attr("type", "hidden");
+ field.attr("name", "id");
+ field.attr("value", personId);
+ form.append(field);
+
+ $(document.body).append(form);
+ form.submit();
+ }
+ });
+
+ // Set initial state for create form
+ $('#createPersonModal').on('show.bs.modal', function () {
+ $('#createRole').trigger('change');
+ });
+});
\ No newline at end of file
diff --git a/cookie.txt b/cookie.txt
index 82d4cef..23d0714 100644
--- a/cookie.txt
+++ b/cookie.txt
@@ -2,4 +2,4 @@
# https://curl.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
-localhost FALSE / FALSE 0 PHPSESSID u19ekrhqoemk4c5avca3umanfb
+127.0.0.1 FALSE / FALSE 0 PHPSESSID abf9a8g0sidv8idojcrr65jetp
diff --git a/db_setup.php b/db_setup.php
index ced3af6..2a4fe95 100644
--- a/db_setup.php
+++ b/db_setup.php
@@ -67,17 +67,17 @@ try {
// 3. Process Instances table (updated FK)
$pdo->exec("CREATE TABLE IF NOT EXISTS `process_instances` (
`id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
- `personId` INT(11) UNSIGNED NOT NULL,
- `processDefinitionId` INT(11) UNSIGNED NOT NULL,
+ `person_id` INT(11) UNSIGNED NOT NULL,
+ `process_definition_id` INT(11) UNSIGNED NOT NULL,
`current_status` VARCHAR(255) NOT NULL DEFAULT 'none',
`current_node_id` VARCHAR(255),
`current_reason` TEXT,
`suggested_next_step` TEXT,
`data_json` TEXT,
`lastActivityAt` TIMESTAMP NULL,
- FOREIGN KEY (personId) REFERENCES people(id) ON DELETE CASCADE,
- FOREIGN KEY (processDefinitionId) REFERENCES process_definitions(id) ON DELETE CASCADE,
- UNIQUE KEY `person_process` (`personId`, `processDefinitionId`)
+ FOREIGN KEY (person_id) REFERENCES people(id) ON DELETE CASCADE,
+ FOREIGN KEY (process_definition_id) REFERENCES process_definitions(id) ON DELETE CASCADE,
+ UNIQUE KEY `person_process` (`person_id`, `process_definition_id`)
)");
echo "Process instances table created or already exists.\n";
@@ -121,6 +121,7 @@ try {
$pdo->exec("ALTER TABLE `process_instances` CHANGE `contactId` `personId` INT(11) UNSIGNED NOT NULL;");
echo "Migrated process_instances: contactId -> personId.\n";
}
+
// Drop old tables if they exist
$pdo->exec("DROP TABLE IF EXISTS `users`, `contacts`;");
diff --git a/index.php b/index.php
index e4456b8..5eb3fe5 100644
--- a/index.php
+++ b/index.php
@@ -1,4 +1,5 @@
query("
$people = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Fetch process definitions
-$stmt = $pdo->prepare("SELECT * FROM process_definitions WHERE name NOT IN (?, ?) ORDER BY name");
+$stmt = $pdo->prepare("SELECT * FROM process_definitions WHERE name NOT IN (?, ?)"
+ . " ORDER BY name");
$stmt->execute(['Obsluga goscia', 'Przygotowanie spotkania grupy']);
$processes = $stmt->fetchAll(PDO::FETCH_ASSOC);
@@ -31,10 +33,14 @@ foreach ($all_instances as $instance) {
$status_colors = [
- 'none' => 'secondary',
- 'negative' => 'danger',
- 'in_progress' => 'warning',
- 'positive' => 'success',
+ 'completed' => '#28a745',
+ 'positive' => '#28a745',
+ 'in_progress' => '#fd7e14',
+ 'negative' => '#dc3545',
+ 'error' => '#dc3545',
+ 'none' => '#808080',
+ 'not_started' => '#808080',
+ 'inactive' => '#808080',
];
$pdo = db();
@@ -65,167 +71,216 @@ $bni_groups = $stmt_bni_groups->fetchAll(PDO::FETCH_ASSOC);
-
-
- = $_SESSION['success_message']; ?>
-
-
-
-
+
+
+
+ = $_SESSION['success_message']; ?>
+
+
+
+
-
-
- = $_SESSION['error_message']; ?>
-
-
-
-
+
+
+ = $_SESSION['error_message']; ?>
+
+
+
+
-
-
Dashboard
-
-
+
Process
@@ -735,7 +989,7 @@ document.addEventListener('DOMContentLoaded', function () {
-
+
Process
@@ -765,7 +1019,7 @@ document.addEventListener('DOMContentLoaded', function () {
-
+
Process
@@ -779,4 +1033,4 @@ document.addEventListener('DOMContentLoaded', function () {
-
\ No newline at end of file
+
diff --git a/test_workflow.php b/test_workflow.php
new file mode 100644
index 0000000..f59ae67
--- /dev/null
+++ b/test_workflow.php
@@ -0,0 +1,54 @@
+";
+
+// Establish a direct database connection for setup
+$pdo = db();
+
+// 1. Get the first person from the database
+$stmt = $pdo->query("SELECT id FROM people LIMIT 1");
+$person = $stmt->fetch(PDO::FETCH_ASSOC);
+if (!$person) {
+ die("
Error: No people found in the database. Please run `db_setup.php` or ensure the database is seeded correctly.
");
+}
+$personId = $person['id'];
+echo "Prerequisite check: Using person with ID $personId.
";
+
+// 2. Get the first process definition from the database
+$stmt = $pdo->query("SELECT id FROM process_definitions LIMIT 1");
+$process = $stmt->fetch(PDO::FETCH_ASSOC);
+if (!$process) {
+ die("
Error: No process definitions found in the database. Please run `db_setup.php` or ensure the database is seeded correctly.
");
+}
+$processDefinitionId = $process['id'];
+echo "Prerequisite check: Using process definition with ID $processDefinitionId.
";
+
+
+$engine = new WorkflowEngine();
+$userId = $personId;
+
+echo "Attempting to get or create instance with personId: $personId and processDefinitionId: $processDefinitionId
";
+
+try {
+ $instance = $engine->getOrCreateInstanceByDefId($personId, $processDefinitionId, $userId);
+
+ if ($instance) {
+ echo "
Success! Successfully got or created instance:
";
+ echo "
";
+ print_r($instance);
+ echo " ";
+ } else {
+ echo "
Error: Failed to get or create instance, but no exception was thrown.
";
+ echo "This might happen if the process definition exists, but `startProcess` fails internally.
";
+ echo "Check PHP error logs for more details.
";
+ }
+} catch (Exception $e) {
+ echo "An exception occurred: " . $e->getMessage() . "
";
+ echo "Stack trace:
" . $e->getTraceAsString() . " ";
+}
\ No newline at end of file