diff --git a/WorkflowEngine.php b/WorkflowEngine.php
index a1c5e48..712b0c2 100644
--- a/WorkflowEngine.php
+++ b/WorkflowEngine.php
@@ -173,13 +173,50 @@ class WorkflowEngine {
$stmt_meetings->execute(['today' => $today]);
$upcoming_meetings_flat = $stmt_meetings->fetchAll(PDO::FETCH_ASSOC);
- $spotkania_cols = [];
+
+$spotkania_cols = [];
+ $meeting_ids = [];
foreach ($upcoming_meetings_flat as $meeting) {
+ $meetingId = $this->getOrCreateMeeting($meeting['group_id'], $meeting['start_datetime']);
+ $meeting_ids[] = $meetingId;
$spotkania_cols[$meeting['group_id']]['group_id'] = $meeting['group_id'];
$spotkania_cols[$meeting['group_id']]['group_name'] = $meeting['group_name'];
- $spotkania_cols[$meeting['group_id']]['meetings'][] = $meeting['start_datetime'];
+ $spotkania_cols[$meeting['group_id']]['meetings'][] = [
+ 'datetime' => $meeting['start_datetime'],
+ 'meeting_id' => $meetingId
+ ];
}
+ // Fetch process states for these meetings
+ $meeting_processes = [];
+ if (!empty($meeting_ids)) {
+ $placeholders = implode(',', array_fill(0, count($meeting_ids), '?'));
+ $stmt_mp = $this->pdo->prepare(
+ "SELECT pi.*, pd.code as process_code, pd.definition_json as pd_definition_json
+ FROM process_instances pi
+ JOIN process_definitions pd ON pi.process_definition_id = pd.id
+ WHERE pi.subject_type = 'meeting' AND pi.subject_id IN ($placeholders)"
+ );
+ $stmt_mp->execute($meeting_ids);
+ $mp_data = $stmt_mp->fetchAll(\PDO::FETCH_ASSOC);
+
+ foreach ($mp_data as $instance) {
+ $def_id = $instance['process_definition_id'];
+ $node_id = $instance['current_node_id'];
+ $definition = !empty($instance['pd_definition_json']) ? json_decode($instance['pd_definition_json'], true) : ($definition_map[$def_id] ?? null);
+
+ if ($definition && isset($definition['nodes'][$node_id])) {
+ $node_info = $definition['nodes'][$node_id];
+ $instance['computed_status'] = $node_info['ui_hints']['status'] ?? $instance['current_status'];
+ } else {
+ $instance['computed_status'] = $instance['current_status'];
+ }
+
+ $meeting_processes[$instance['subject_id']][$instance['process_code']] = $instance;
+ }
+ }
+
+
return [
'people' => $people,
@@ -188,7 +225,8 @@ class WorkflowEngine {
'all_functions' => $all_functions,
'person_functions_map' => $person_functions_map,
'bni_groups' => $bni_groups,
- 'spotkania_cols' => $spotkania_cols, // Add this to the return array
+ 'spotkania_cols' => $spotkania_cols,
+ 'meeting_processes' => $meeting_processes, // Add this to the return array
];
}
@@ -234,9 +272,9 @@ class WorkflowEngine {
}
$stmt_insert = $this->pdo->prepare(
- "INSERT INTO process_instances (person_id, process_definition_id, current_node_id, current_status, last_activity_at, data_json) VALUES (?, ?, ?, 'in_progress', NOW(), ?)"
+ "INSERT INTO process_instances (person_id, subject_type, subject_id, process_definition_id, current_node_id, current_status, last_activity_at, data_json) VALUES (?, 'person', ?, ?, ?, 'in_progress', NOW(), ?)"
);
- $stmt_insert->execute([$personId, $definition['id'], $startNodeId, $initialDataJson]);
+ $stmt_insert->execute([$personId, $personId, $definition['id'], $startNodeId, $initialDataJson]);
$instanceId = $this->pdo->lastInsertId();
// 3. Create a system event for process start.
@@ -556,9 +594,9 @@ class WorkflowEngine {
$data_json = !empty($initial_data_map) ? json_encode($initial_data_map) : null;
$stmt = $this->pdo->prepare(
- "INSERT INTO process_instances (person_id, process_definition_id, current_node_id, current_status, data_json, last_activity_at) VALUES (?, ?, ?, 'in_progress', ?, NOW())"
+ "INSERT INTO process_instances (person_id, subject_type, subject_id, process_definition_id, current_node_id, current_status, data_json, last_activity_at) VALUES (?, 'person', ?, ?, ?, 'in_progress', ?, NOW())"
);
- $stmt->execute([$personId, $processDefinitionId, $start_node, $data_json]);
+ $stmt->execute([$personId, $personId, $processDefinitionId, $start_node, $data_json]);
$newInstanceId = $this->pdo->lastInsertId();
$this->logEvent($newInstanceId, 'process_started', 'Process started', $start_node, ['context' => $context], $userId);
@@ -990,4 +1028,129 @@ class WorkflowEngine {
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
-}
\ No newline at end of file
+
+ public function startProcessForSubject(string $processCode, string $subjectType, int $subjectId, int $userId, string $mode='resume_or_create', ?string $cycleKey=null): int {
+ $inTransaction = $this->pdo->inTransaction();
+ if (!$inTransaction) { $this->pdo->beginTransaction(); }
+ try {
+ $stmt_def = $this->pdo->prepare("SELECT * FROM process_definitions WHERE code = ? AND is_active = 1");
+ $stmt_def->execute([$processCode]);
+ $definition = $stmt_def->fetch(PDO::FETCH_ASSOC);
+
+ if (!$definition) {
+ // If no active definition by code, try by ID if it's a checklist fallback
+ $stmt_def = $this->pdo->prepare("SELECT * FROM process_definitions WHERE id = ?");
+ $stmt_def->execute([$processCode]);
+ $definition = $stmt_def->fetch(PDO::FETCH_ASSOC);
+
+ if (!$definition) {
+ throw new WorkflowNotFoundException("Process definition '$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 WorkflowNotAllowedException("Process definition '$processCode' not found or not a checklist.");
+ }
+ $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 WorkflowRuleFailedException("Process definition is missing start_node_id.");
+ }
+ $startNodeId = $definition_json['start_node_id'];
+ }
+
+ $initialDataJson = null;
+ if (isset($definition_json['initial_data'])) {
+ $initialDataJson = json_encode($definition_json['initial_data']);
+ }
+
+ // Map person_id for backward compatibility
+ $personId = ($subjectType === 'person') ? $subjectId : 0;
+
+ $stmt_insert = $this->pdo->prepare(
+ "INSERT INTO process_instances (person_id, subject_type, subject_id, cycle_key, process_definition_id, current_node_id, current_status, last_activity_at, data_json) VALUES (?, ?, ?, ?, ?, ?, 'in_progress', NOW(), ?)"
+ );
+ $stmt_insert->execute([$personId, $subjectType, $subjectId, $cycleKey, $definition['id'], $startNodeId, $initialDataJson]);
+ $instanceId = $this->pdo->lastInsertId();
+
+ $this->addEvent($instanceId, 'system', 'Process started.', $startNodeId, [], $userId);
+
+ if (!$inTransaction) { $this->pdo->commit(); }
+ return (int)$instanceId;
+ } catch (Exception $e) {
+ if (!$inTransaction) { $this->pdo->rollBack(); }
+ throw $e;
+ }
+ }
+
+ public function getOrCreateInstanceForSubject(int $processDefinitionId, string $subjectType, int $subjectId, int $userId, string $mode='resume_or_create', ?string $cycleKey=null): array {
+ $stmt_def = $this->pdo->prepare("SELECT code, is_active FROM process_definitions WHERE id = ?");
+ $stmt_def->execute([$processDefinitionId]);
+ $definition = $stmt_def->fetch(PDO::FETCH_ASSOC);
+
+ if (!$definition) {
+ throw new WorkflowNotFoundException("Process definition #$processDefinitionId not found.");
+ }
+
+ $code = $definition['code'];
+ $instance = null;
+
+ if ($mode !== 'create_new_run') {
+ $instance = $this->getActiveInstanceForSubject($code, $subjectType, $subjectId, $cycleKey);
+ }
+
+ if (!$instance) {
+ if (empty($definition['is_active'])) {
+ throw new WorkflowNotAllowedException("Process is not active and cannot be started.");
+ }
+ $instanceId = $this->startProcessForSubject($code, $subjectType, $subjectId, $userId, $mode, $cycleKey);
+ $stmt = $this->pdo->prepare("SELECT * FROM process_instances WHERE id = ?");
+ $stmt->execute([$instanceId]);
+ $instance = $stmt->fetch(PDO::FETCH_ASSOC);
+ }
+
+ return $instance;
+ }
+
+ public function getActiveInstanceForSubject(string $processCode, string $subjectType, int $subjectId, ?string $cycleKey=null): ?array {
+ $sql = "
+ SELECT pi.*
+ FROM process_instances pi
+ JOIN process_definitions pd ON pi.process_definition_id = pd.id
+ WHERE pi.subject_type = ? AND pi.subject_id = ? AND pd.code = ?
+ ";
+ $params = [$subjectType, $subjectId, $processCode];
+
+ if ($cycleKey !== null) {
+ $sql .= " AND pi.cycle_key = ?";
+ $params[] = $cycleKey;
+ }
+
+ $sql .= " ORDER BY pi.last_activity_at DESC, pi.id DESC LIMIT 1";
+
+ $stmt = $this->pdo->prepare($sql);
+ $stmt->execute($params);
+ $instance = $stmt->fetch(PDO::FETCH_ASSOC);
+ return $instance ?: null;
+ }
+
+ public function getInstancesHistoryForSubject(string $processCode, string $subjectType, int $subjectId, int $limit=5): array {
+ $sql = "
+ SELECT pi.*
+ FROM process_instances pi
+ JOIN process_definitions pd ON pi.process_definition_id = pd.id
+ WHERE pi.subject_type = ? AND pi.subject_id = ? AND pd.code = ?
+ ORDER BY pi.last_activity_at DESC, pi.id DESC
+ LIMIT ?
+ ";
+ $stmt = $this->pdo->prepare($sql);
+ $stmt->bindValue(1, $subjectType, PDO::PARAM_STR);
+ $stmt->bindValue(2, $subjectId, PDO::PARAM_INT);
+ $stmt->bindValue(3, $processCode, PDO::PARAM_STR);
+ $stmt->bindValue(4, $limit, PDO::PARAM_INT);
+ $stmt->execute();
+
+ return $stmt->fetchAll(PDO::FETCH_ASSOC);
+ }
+}
diff --git a/_get_instance_details.php b/_get_instance_details.php
index cf8d738..38c3305 100644
--- a/_get_instance_details.php
+++ b/_get_instance_details.php
@@ -25,38 +25,51 @@ if (!$process_definition_id && $process_code) {
$process_definition_id = $stmt->fetchColumn();
}
-if (!$person_id || !$process_definition_id) {
+if (!$subject_id || !$process_definition_id) {
http_response_code(400);
- echo json_encode(['error' => 'Missing person_id or process_id']);
+ echo json_encode(['error' => 'Missing subject_id or process_id']);
exit;
}
$userId = $_SESSION['user_id'];
$engine = new WorkflowEngine();
-// Fetch Person and Process Definition details first
-$stmt_person = $pdo->prepare("SELECT first_name, last_name FROM people WHERE id = ?");
-$stmt_person->execute([$person_id]);
-$person = $stmt_person->fetch();
+// Fetch Subject and Process Definition details first
+$subjectName = 'Unknown';
+if ($subject_type === 'person') {
+ $stmt_person = $pdo->prepare("SELECT first_name, last_name FROM people WHERE id = ?");
+ $stmt_person->execute([$subject_id]);
+ $person = $stmt_person->fetch();
+ if ($person) {
+ $subjectName = $person['first_name'] . ' ' . $person['last_name'];
+ }
+} elseif ($subject_type === 'meeting') {
+ $stmt_meeting = $pdo->prepare("SELECT m.meeting_datetime, bg.name as group_name FROM meetings m JOIN bni_groups bg ON m.bni_group_id = bg.id WHERE m.id = ?");
+ $stmt_meeting->execute([$subject_id]);
+ $meeting = $stmt_meeting->fetch();
+ if ($meeting) {
+ $subjectName = $meeting['group_name'] . ' - ' . date('d.m.Y', strtotime($meeting['meeting_datetime']));
+ }
+}
$stmt_process = $pdo->prepare("SELECT * FROM process_definitions WHERE id = ?");
$stmt_process->execute([$process_definition_id]);
$process = $stmt_process->fetch();
-if (!$person || !$process) {
+if (!$process) {
http_response_code(404);
- echo "
Could not find person or process.
";
+ echo "Could not find process.
";
exit;
}
// Try to find an existing instance
-$instance = $engine->getInstanceByDefId($person_id, $process_definition_id);
+$instance = $engine->getActiveInstanceForSubject($process['code'], $subject_type, $subject_id);
?>
- = htmlspecialchars($person['first_name']." ".$person['last_name']) ?> - = htmlspecialchars($process['name']) ?>
+ = htmlspecialchars($subjectName) ?> - = htmlspecialchars($process['name']) ?>
@@ -70,7 +83,7 @@ $instance = $engine->getInstanceByDefId($person_id, $process_definition_id);
= t('modal.process_completed', 'Proces zakończony.') ?>
Obecny status: = htmlspecialchars($instance['current_status']) ?>.
-