Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
85.48% covered (warning)
85.48%
53 / 62
60.00% covered (warning)
60.00%
3 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
TaskCompletion
85.48% covered (warning)
85.48%
53 / 62
60.00% covered (warning)
60.00%
3 / 5
17.88
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 save
72.73% covered (warning)
72.73%
16 / 22
0.00% covered (danger)
0.00%
0 / 1
7.99
 getForTaskAndDate
85.71% covered (warning)
85.71%
18 / 21
0.00% covered (danger)
0.00%
0 / 1
4.05
 fromArray
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 toArray
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace BuyerKiosk\Workbook;
4
5use \PDO;
6use \PDOException;
7
8/**
9 * TaskCompletion - Model for task completion tracking
10 *
11 * Tracks the daily completion status of tasks with UPSERT pattern
12 * to ensure only one completion record per task per day.
13 */
14class TaskCompletion
15{
16    /**
17     * @var PDO Database connection
18     */
19    private $db;
20
21    /**
22     * @var int|null Completion ID
23     */
24    public $id;
25
26    /**
27     * @var int Task ID
28     */
29    public $taskId;
30
31    /**
32     * @var string Date (Y-m-d format)
33     */
34    public $date;
35
36    /**
37     * @var int Status: 0=Not Started, 1=In Progress, 2=Completed
38     */
39    public $status;
40
41    /**
42     * @var int|null Employee ID who completed the task
43     */
44    public $completedBy;
45
46    /**
47     * @var string|null Timestamp when completed
48     */
49    public $completedAt;
50
51    /**
52     * @var string|null Notes about completion
53     */
54    public $notes;
55
56    /**
57     * Constructor
58     *
59     * @param PDO $db Database connection
60     */
61    public function __construct(PDO $db)
62    {
63        $this->db = $db;
64    }
65
66    /**
67     * Save task completion (UPSERT pattern)
68     *
69     * Uses INSERT ON DUPLICATE KEY UPDATE to ensure only one
70     * completion record exists per task per date
71     *
72     * @return bool True if successful
73     */
74    public function save(): bool
75    {
76        if (!isset($this->taskId) || !isset($this->date)) {
77            error_log("TaskCompletion::save error: taskId and date are required");
78            return false;
79        }
80
81        // Ensure status is set
82        if (!isset($this->status)) {
83            $this->status = 0;
84        }
85
86        error_log("TaskCompletion::save - taskId: {$this->taskId}, date: {$this->date}, status: {$this->status}, completedBy: " . ($this->completedBy ?? 'null'));
87
88        try {
89            $stmt = $this->db->prepare("
90                INSERT INTO workbook_task_completions
91                (taskId, date, status, completedBy, completedAt, notes)
92                VALUES
93                (:taskId, :date, :status, :completedBy, :completedAt, :notes)
94                ON DUPLICATE KEY UPDATE
95                    status = VALUES(status),
96                    completedBy = VALUES(completedBy),
97                    completedAt = VALUES(completedAt),
98                    notes = VALUES(notes)
99            ");
100
101            $result = $stmt->execute([
102                ':taskId' => $this->taskId,
103                ':date' => $this->date,
104                ':status' => $this->status,
105                ':completedBy' => $this->completedBy,
106                ':completedAt' => $this->completedAt,
107                ':notes' => $this->notes
108            ]);
109
110            // Set the ID if this was a new insert
111            if ($result && $this->id === null) {
112                $this->id = (int) $this->db->lastInsertId();
113            }
114
115            return $result;
116        } catch (PDOException $e) {
117            error_log("TaskCompletion::save error: " . $e->getMessage());
118            return false;
119        }
120    }
121
122    /**
123     * Get task completion for a specific task and date
124     *
125     * @param PDO $db Database connection
126     * @param int $taskId Task ID
127     * @param string $date Date (Y-m-d format)
128     * @return self|null TaskCompletion object or null if not found
129     */
130    public static function getForTaskAndDate(PDO $db, int $taskId, string $date): ?self
131    {
132        try {
133            $stmt = $db->prepare("
134                SELECT * FROM workbook_task_completions
135                WHERE taskId = :taskId AND date = :date
136            ");
137            $stmt->execute([
138                ':taskId' => $taskId,
139                ':date' => $date
140            ]);
141
142            $row = $stmt->fetch(PDO::FETCH_ASSOC);
143            if (!$row) {
144                return null;
145            }
146
147            $completion = new self($db);
148            $completion->id = (int) $row['id'];
149            $completion->taskId = (int) $row['taskId'];
150            $completion->date = $row['date'];
151            $completion->status = (int) $row['status'];
152            $completion->completedBy = $row['completedBy'] ? (int) $row['completedBy'] : null;
153            $completion->completedAt = $row['completedAt'];
154            $completion->notes = $row['notes'];
155
156            return $completion;
157        } catch (PDOException $e) {
158            error_log("TaskCompletion::getForTaskAndDate error: " . $e->getMessage());
159            return null;
160        }
161    }
162
163    /**
164     * Create a TaskCompletion object from an array
165     *
166     * @param PDO $db Database connection
167     * @param array $data Associative array of task completion data
168     * @return self
169     */
170    public static function fromArray(PDO $db, array $data): self
171    {
172        $completion = new self($db);
173        $completion->id = isset($data['id']) ? (int) $data['id'] : null;
174        $completion->taskId = (int) $data['taskId'];
175        $completion->date = $data['date'];
176        $completion->status = isset($data['status']) ? (int) $data['status'] : 0;
177        $completion->completedBy = isset($data['completedBy']) ? (int) $data['completedBy'] : null;
178        $completion->completedAt = $data['completedAt'] ?? null;
179        $completion->notes = $data['notes'] ?? null;
180
181        return $completion;
182    }
183
184    /**
185     * Convert TaskCompletion to array
186     *
187     * @return array Associative array representation
188     */
189    public function toArray(): array
190    {
191        return [
192            'id' => $this->id,
193            'taskId' => $this->taskId,
194            'date' => $this->date,
195            'status' => $this->status,
196            'completedBy' => $this->completedBy,
197            'completedAt' => $this->completedAt,
198            'notes' => $this->notes
199        ];
200    }
201}