Files
tinker_tickets/models/WorkflowModel.php
Jared Vititoe 683420cdb9 Feature 3: Implement Status Transitions with Workflow Validation
Add comprehensive workflow management system for ticket status transitions:

- Created WorkflowModel.php for managing status transition rules
- Updated TicketController.php to load allowed transitions for each ticket
- Modified TicketView.php to display dynamic status dropdown with only allowed transitions
- Enhanced api/update_ticket.php with server-side workflow validation
- Added updateTicketStatus() JavaScript function for client-side status changes
- Included CSS styling for status select dropdown with color-coded states
- Transitions can require comments or admin privileges
- Status changes are validated against status_transitions table

This feature enforces proper ticket workflows and prevents invalid status changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 18:57:23 -05:00

118 lines
3.4 KiB
PHP

<?php
/**
* WorkflowModel - Handles status transition workflows and validation
*/
class WorkflowModel {
private $conn;
public function __construct($conn) {
$this->conn = $conn;
}
/**
* Get allowed status transitions for a given status
*
* @param string $currentStatus Current ticket status
* @return array Array of allowed transitions with requirements
*/
public function getAllowedTransitions($currentStatus) {
$sql = "SELECT to_status, requires_comment, requires_admin
FROM status_transitions
WHERE from_status = ? AND is_active = TRUE";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("s", $currentStatus);
$stmt->execute();
$result = $stmt->get_result();
$transitions = [];
while ($row = $result->fetch_assoc()) {
$transitions[] = $row;
}
$stmt->close();
return $transitions;
}
/**
* Check if a status transition is allowed
*
* @param string $fromStatus Current status
* @param string $toStatus Desired status
* @param bool $isAdmin Whether user is admin
* @return bool True if transition is allowed
*/
public function isTransitionAllowed($fromStatus, $toStatus, $isAdmin = false) {
// Allow same status (no change)
if ($fromStatus === $toStatus) {
return true;
}
$sql = "SELECT requires_admin FROM status_transitions
WHERE from_status = ? AND to_status = ? AND is_active = TRUE";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("ss", $fromStatus, $toStatus);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows === 0) {
$stmt->close();
return false; // Transition not defined
}
$row = $result->fetch_assoc();
$stmt->close();
if ($row['requires_admin'] && !$isAdmin) {
return false; // Admin required
}
return true;
}
/**
* Get all possible statuses from transitions table
*
* @return array Array of unique status values
*/
public function getAllStatuses() {
$sql = "SELECT DISTINCT from_status as status FROM status_transitions
UNION
SELECT DISTINCT to_status as status FROM status_transitions
ORDER BY status";
$result = $this->conn->query($sql);
$statuses = [];
while ($row = $result->fetch_assoc()) {
$statuses[] = $row['status'];
}
return $statuses;
}
/**
* Get transition requirements
*
* @param string $fromStatus Current status
* @param string $toStatus Desired status
* @return array|null Transition requirements or null if not found
*/
public function getTransitionRequirements($fromStatus, $toStatus) {
$sql = "SELECT requires_comment, requires_admin
FROM status_transitions
WHERE from_status = ? AND to_status = ? AND is_active = TRUE";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("ss", $fromStatus, $toStatus);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows === 0) {
$stmt->close();
return null;
}
$row = $result->fetch_assoc();
$stmt->close();
return $row;
}
}