37338-vm/_get_instance_details.php
2026-03-02 17:43:41 +00:00

319 lines
16 KiB
PHP

<?php
require_once 'WorkflowEngine.php';
require_once 'lib/i18n.php';
require_once 'lib/ErrorHandler.php';
require_once 'lib/WorkflowExceptions.php';
session_start();
// Security check
if (!isset($_SESSION['user_id'])) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit;
}
$person_id = $_GET['person_id'] ?? null;
$subject_id = $_GET['subject_id'] ?? $person_id;
$subject_type = $_GET['subject_type'] ?? 'person';
$cycle_key = $_GET['cycle_key'] ?? null;
$process_definition_id = $_GET['process_id'] ?? null;
$process_code = $_GET['process_code'] ?? null;
$pdo = db();
if (!$process_definition_id && $process_code) {
$stmt = $pdo->prepare("SELECT id FROM process_definitions WHERE code = ? AND is_latest = 1 LIMIT 1");
$stmt->execute([$process_code]);
$process_definition_id = $stmt->fetchColumn();
}
if (!$subject_id || !$process_definition_id) {
http_response_code(400);
echo json_encode(['error' => 'Missing subject_id or process_id']);
exit;
}
$userId = $_SESSION['user_id'];
$engine = new WorkflowEngine();
// 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 (!$process) {
http_response_code(404);
echo "<p class='text-danger'>Could not find process.</p>";
exit;
}
// Try to find an existing instance
$instance = $engine->getActiveInstanceForSubject($process['code'], $subject_type, $subject_id, $cycle_key);
?>
<!-- Title for the modal, to be grabbed by JS -->
<div id="instance-modal-title" class="d-none">
<?= htmlspecialchars($subjectName) ?> - <?= htmlspecialchars($process['name']) ?>
</div>
<?php if ($instance): // INSTANCE EXISTS ?>
<?php
$instanceId = $instance['id'];
$isCompleted = in_array($instance['current_status'], ['completed', 'positive', 'negative', 'error']);
?>
<?php if ($isCompleted): ?>
<div class="alert alert-info d-flex justify-content-between align-items-center">
<div>
<strong><?= t('modal.process_completed', 'Proces zakończony.') ?></strong>
Obecny status: <?= htmlspecialchars($instance['current_status']) ?>.
</div>
<button id="restartProcessBtn" class="btn btn-sm btn-primary" data-subject-type="<?= $subject_type ?>" data-subject-id="<?= $subject_id ?>" data-person-id="<?= $person_id ?>" data-process-code="<?= htmlspecialchars($process['code']) ?>" data-mode="create_new_run">
<?= t('modal.start_new_instance', 'Rozpocznij od nowa') ?>
</button>
</div>
<?php endif; ?>
<?php
$definition = $process['definition_json'] ? json_decode($process['definition_json'], true) : null;
$isChecklist = ($definition && isset($definition['type']) && $definition['type'] === 'checklist');
$events = $engine->getEvents($instanceId);
$instanceData = $instance['data_json'] ? json_decode($instance['data_json'], true) : [];
?>
<?php if ($isChecklist): ?>
<?php
$tasks = $definition['tasks'] ?? [];
?>
<div class="checklist-modal-container" data-instance-id="<?= $instanceId ?>">
<h5>Zadania do wykonania</h5>
<div class="checklist-container">
<?php foreach ($tasks as $task):
$isChecked = !empty($instanceData[$task['code']]);
?>
<div class="form-check mb-2" style="font-size: 1.15rem;">
<input class="form-check-input task-checkbox-modal" type="checkbox" value="" style="cursor: pointer; border-radius: 0.25em;"
data-task-code="<?= htmlspecialchars($task['code']) ?>" <?= $isChecked ? 'checked' : '' ?> id="chk_<?= htmlspecialchars($task['code']) ?>">
<label class="form-check-label pt-1" for="chk_<?= htmlspecialchars($task['code']) ?>" title="<?= htmlspecialchars($task['name']) ?>" style="cursor: pointer;">
<?= htmlspecialchars($task['name']) ?>
</label>
</div>
<?php endforeach; ?>
</div>
</div>
<?php else: ?>
<?php
$currentNodeId = $instance['current_node_id'];
$all_nodes = $engine->getProcessDefinitionNodes($process_definition_id);
$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['id']] = $t;
}
$visited_nodes = [];
foreach ($events as $event) {
if ($event['node_id']) {
$visited_nodes[$event['node_id']] = true;
}
}
?>
<div class="process-steps-container">
<h5>Kroki procesu</h5>
<ul class="list-group">
<?php foreach ($all_nodes as $nodeId => $node):
if (!isset($node['ui_hints']['title']) || $node['ui_hints']['title'] === '') continue;
$is_current = ($currentNodeId === $nodeId);
$is_completed = isset($visited_nodes[$nodeId]) && !$is_current;
$status_icon = '';
$li_class = '';
if ($is_current) {
$li_class = 'list-group-item-primary';
$status_icon = '<i class="bi bi-arrow-right-circle-fill text-primary me-2"></i>';
} elseif ($is_completed) {
$li_class = 'list-group-item-success';
$status_icon = '<i class="bi bi-check-circle-fill text-success me-2"></i>';
} else {
$li_class = 'text-muted';
$status_icon = '<i class="bi bi-circle me-2"></i>';
}
?>
<li class="list-group-item d-flex justify-content-between align-items-center <?= $li_class ?>">
<div>
<?= $status_icon ?>
<strong><?= htmlspecialchars($node['ui_hints']['title']) ?></strong>
</div>
</li>
<?php endforeach; ?>
</ul>
<div class="mt-3">
<h5><?= t('modal.available_actions', 'Dostępne akcje') ?></h5>
<?php
$currentNode = $all_nodes[$currentNodeId] ?? null;
if ($currentNode && isset($currentNode['ui_hints']['form_schema'])):
?>
<form id="transition-form">
<?php foreach ($currentNode['ui_hints']['form_schema'] as $field):
$fieldName = $field['name'];
$currentValue = $instanceData[$fieldName] ?? null;
?>
<?php if ($field['type'] === 'checkbox'): ?>
<div class="form-check mb-3" style="font-size: 1.15rem;">
<input type="hidden" name="<?= htmlspecialchars($fieldName) ?>" value="0">
<input type="checkbox" id="<?= htmlspecialchars($fieldName) ?>" name="<?= htmlspecialchars($fieldName) ?>" class="form-check-input" value="1" style="cursor: pointer; border-radius: 0.25em;" <?= (!empty($currentValue) || (!isset($instanceData[$fieldName]) && !empty($field['default']))) ? 'checked' : '' ?>/>
<label for="<?= htmlspecialchars($fieldName) ?>" class="form-check-label pt-1" style="cursor: pointer;"><?= htmlspecialchars($field['label']) ?></label>
</div>
<?php else: ?>
<div class="mb-3">
<label for="<?= htmlspecialchars($fieldName) ?>" class="form-label"><?= htmlspecialchars($field['label']) ?></label>
<?php if ($field['type'] === 'textarea'): ?>
<textarea id="<?= htmlspecialchars($fieldName) ?>" name="<?= htmlspecialchars($fieldName) ?>" class="form-control"><?= htmlspecialchars($currentValue ?? '') ?></textarea>
<?php elseif ($field['type'] === 'select'): ?>
<select id="<?= htmlspecialchars($fieldName) ?>" name="<?= htmlspecialchars($fieldName) ?>" class="form-select">
<?php foreach ($field['options'] as $option): ?>
<option value="<?= htmlspecialchars($option['value']) ?>" <?= $currentValue == $option['value'] ? 'selected' : '' ?>><?= htmlspecialchars($option['label']) ?></option>
<?php endforeach; ?>
</select>
<?php else: ?>
<input type="<?= htmlspecialchars($field['type']) ?>" id="<?= htmlspecialchars($fieldName) ?>" name="<?= htmlspecialchars($fieldName) ?>" class="form-control" value="<?= htmlspecialchars((string)($currentValue ?? (($field['default'] ?? '') === 'now' ? date('Y-m-d\TH:i') : ($field['default'] ?? '')))) ?>">
<?php endif; ?>
</div>
<?php endif; ?>
<?php endforeach; ?>
</form>
<?php endif; ?>
<?php if (empty($availableTransitions)): ?>
<p>No actions available.</p>
<?php else: ?>
<?php foreach ($availableTransitions as $transition): ?>
<button class="btn btn-sm btn-primary apply-transition-btn"
data-instance-id="<?= $instanceId ?>"
data-transition-id="<?= $transition['id'] ?>">
<?= htmlspecialchars($transition['name']) ?>
</button>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<hr>
<div class="add-note-container">
<h5><?= t('modal.add_note', 'Dodaj notatkę') ?></h5>
<div class="mb-3">
<textarea id="noteMessage" class="form-control" rows="2" placeholder="Wpisz treść notatki..."></textarea>
</div>
<button id="addNoteBtn" class="btn btn-secondary" data-instance-id="<?= $instanceId ?>"><?= t('modal.add_note', 'Dodaj notatkę') ?></button>
</div>
<hr>
<div class="history-container">
<h5><?= t('modal.history', 'Historia') ?></h5>
<?php if (empty($events)): ?>
<p>Brak zdarzeń.</p>
<?php else: ?>
<?php
// Prepare a map for outcome_status labels for readability
$outcomeStatusOptions = [];
if (isset($definition['nodes']['awaiting_call']['ui_hints']['form_schema'])) {
foreach ($definition['nodes']['awaiting_call']['ui_hints']['form_schema'] as $field) {
if ($field['name'] === 'outcome_status' && isset($field['options'])) {
foreach ($field['options'] as $option) {
if (!empty($option['value'])) {
$outcomeStatusOptions[$option['value']] = $option['label'];
}
}
break;
}
}
}
?>
<ul class="list-group">
<?php foreach ($events as $event): ?>
<?php
$payload = json_decode($event['payload_json'], true);
$isCallAttempt = $event['event_type'] === 'transition_completed' && isset($payload['transition_id']) && $payload['transition_id'] === 'submit_outcome';
?>
<li class="list-group-item">
<?php if ($isCallAttempt): ?>
<?php
$data = $payload['data'] ?? [];
$outcomeLabel = $outcomeStatusOptions[$data['outcome_status']] ?? ucfirst(str_replace('_', ' ', $data['outcome_status']));
?>
<div class="d-flex w-100 justify-content-between">
<h6 class="mb-1">Call Attempt</h6>
<small><?= date('d.m.Y, H:i', strtotime($data['call_date'])) ?></small>
</div>
<p class="mb-1"><strong>Outcome:</strong> <?= htmlspecialchars($outcomeLabel) ?></p>
<?php if (!empty($data['note'])): ?>
<p class="mb-1 fst-italic">"<?= nl2br(htmlspecialchars($data['note'])) ?>"</p>
<?php endif; ?>
<?php if (!empty($data['next_contact_date'])): ?>
<p class="mb-1"><strong>Next follow-up:</strong> <?= date('d.m.Y, H:i', strtotime($data['next_contact_date'])) ?></p>
<?php endif; ?>
<?php else: // Generic event display ?>
<strong><?= htmlspecialchars(ucfirst(str_replace('_', ' ', $event['event_type']))) ?></strong>
<?php
if (!empty($event['message'])) {
$message = $payload['message'] ?? $event['message'];
echo '<p class="mb-1 text-muted fst-italic">' . htmlspecialchars($message) . '</p>';
}
?>
<?php endif; ?>
<small class="text-muted">By <?= htmlspecialchars($event['first_name'] . ' ' . $event['last_name']) ?> on <?= date('d.m.Y, H:i', strtotime($event['created_at'])) ?></small>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
<?php else: // NO INSTANCE EXISTS ?>
<?php
$eligibility = ['is_eligible' => true, 'reasons' => []];
if ($subject_type === 'person') {
$eligibility = $engine->checkEligibility($subject_id, $process_definition_id);
}
?>
<div class="text-center">
<?php if ($eligibility['is_eligible']): ?>
<h4><?= t('modal.process_not_started', 'Proces nie został uruchomiony') ?></h4>
<p>This process has not been started for this person.</p>
<button id="startProcessBtn" class="btn btn-primary" data-subject-type="<?= $subject_type ?>" data-subject-id="<?= $subject_id ?>" data-process-id="<?= $process_definition_id ?>" data-process-code="<?= $process_code ?>" data-cycle-key="<?= $cycle_key ?>">
<?= t('modal.start_process', 'Uruchom proces') ?>
</button>
<?php else: ?>
<h4>Not Eligible</h4>
<p>This person is not eligible to start this process.</p>
<ul class="list-group list-group-flush text-start">
<?php foreach ($eligibility['reasons'] as $reason): ?>
<li class="list-group-item list-group-item-danger"><?= htmlspecialchars($reason) ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
<?php endif; ?>