Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 143
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
BuyerStats
0.00% covered (danger)
0.00%
0 / 143
0.00% covered (danger)
0.00%
0 / 4
992
0.00% covered (danger)
0.00%
0 / 1
 gatherDailyBuyerStatsArray
0.00% covered (danger)
0.00%
0 / 75
0.00% covered (danger)
0.00%
0 / 1
306
 gatherDailySorterStatsArray
0.00% covered (danger)
0.00%
0 / 66
0.00% covered (danger)
0.00%
0 / 1
156
 setBuyerStatsArray
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getBuyerStatsArray
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace BuyerKiosk\Core;
4
5/**
6 * Buyer Statistics Calculator
7 *
8 * Calculates buyer and sorter performance statistics based on completed buys.
9 * Updated to use the unified users table (kiosk_users.users) with store assignments
10 * (kiosk_users.userStoreAssignments) instead of per-store employee tables.
11 *
12 * @package BuyerKiosk\Core
13 */
14class BuyerStats extends CompletedBuys
15{
16
17    public $BuyerStatsArray = array();
18    public $SorterStatsArray = array();
19
20    /**
21     * Gather daily buyer statistics
22     *
23     * Queries buyQueue data joined with unified users table to calculate
24     * buyer performance metrics.
25     *
26     * @param Store $store Store object
27     * @param string|null $date Optional date (Y-m-d format)
28     */
29    public function gatherDailyBuyerStatsArray(Store $store, $date = null)
30    {
31        $storeDb = dbConnectByName($store->getDbName());
32        $centralDb = \dbConnectByName('kiosk_users');
33        $typeNum = $store->getTypeNum();
34
35        $this->gatherCompletedBuys($store, $date);
36        $buyArray = $this->getCompletedBuys();
37        $buyerArray = array();
38
39        foreach ($buyArray as $buy) {
40            if (!in_array($buy['buyerID'], $buyerArray)) {
41                $buyerArray[] = $buy['buyerID'];
42            }
43            $timeStarted = new \DateTime($buy['timestampStarted']);
44            $timeCompleted = new \DateTime($buy['timestampCompleted']);
45
46            $diffStartedCompleted = $timeCompleted->diff($timeStarted);
47        }
48
49        if($date !== null) {
50            $dateRange = getDateRange($date);
51        } else {
52            $dateRange = getCurrentDateRange();
53        }
54
55        foreach ($buyerArray as $buyer) {
56            // Query buyQueue from store database
57            $query = "SELECT * FROM buyQueue WHERE buyQueue.buyerID = :buyerId
58                      AND timeCompleted BETWEEN :dateStart AND :dateEnd
59                      AND buyQueue.isProcessed = 1";
60
61            $stmt = $storeDb->prepare($query);
62            $stmt->execute([
63                ':buyerId' => $buyer,
64                ':dateStart' => $dateRange['dateStart']->format("Y-m-d H:i:s"),
65                ':dateEnd' => $dateRange['dateEnd']->format("Y-m-d H:i:s")
66            ]);
67            $buys = $stmt;
68
69            if ($buys) {
70                $totalProcessTime = 0;
71                $totalWorkedBuys = 0;
72                $numBuys = 0;
73                $numContainers = 0;
74                $workedContainers = 0;
75                $buyerFullName = "";
76
77                // Fetch user info from central database once per buyer
78                $userStmt = $centralDb->prepare("
79                    SELECT u.firstName, u.lastName
80                    FROM users u
81                    INNER JOIN userStoreAssignments usa ON u.id = usa.userId
82                    WHERE u.id = :userId AND usa.typeNum = :typeNum
83                    LIMIT 1
84                ");
85                $userStmt->execute([':userId' => $buyer, ':typeNum' => $typeNum]);
86                $userInfo = $userStmt->fetch(\PDO::FETCH_ASSOC);
87
88                if ($userInfo) {
89                    $buyerFullName = $userInfo['firstName'] . ". " . substr($userInfo['lastName'], 0, 1);
90                }
91
92                while ($data = $buys->fetch(\PDO::FETCH_ASSOC)) {
93                    $timeDroppedOff = new \DateTime($data['timeEntered']);
94                    $timeStarted = new \DateTime($data['timeStarted']);
95                    $timeCompleted = new \DateTime($data['timeCompleted']);
96
97                    $diffStartedCompleted = $timeCompleted->diff($timeStarted);
98
99                    if ((int)$diffStartedCompleted->format("%h") > 0) {
100                        $processTime = $diffStartedCompleted->format('%hh %im %Ss');
101                    } else if ((int)$diffStartedCompleted->format("%i") > 0) {
102                        $processTime = $diffStartedCompleted->format('%im %Ss');
103                    } else {
104                        $processTime = $diffStartedCompleted->format('%Ss');
105                    }
106
107                    $secondsForProcessTime = ((int)$diffStartedCompleted->format('%h') * 60 * 60) + ((int)$diffStartedCompleted->format('%i') * 60) + ((int)$diffStartedCompleted->format('%s'));
108                    if ($secondsForProcessTime > 30) {
109                        $totalProcessTime += $secondsForProcessTime;
110                        if($data['sortStarted'] !== "0000-00-00 00:00:00" && $data['remainingContainers'] > 0) {
111                            $numContainers += $data['remainingContainers'];
112                        } else {
113                            $numContainers += $data['numContainers'];
114                        }
115                        $numBuys++;
116                    }
117                    if($data['sortStarted'] !== "0000-00-00 00:00:00" && $data['remainingContainers'] > 0) {
118                        $workedContainers += $data['remainingContainers'];
119                    } else {
120                        $workedContainers += $data['numContainers'];
121                    }
122                    $totalWorkedBuys++;
123                }
124
125                if ($numBuys > 0) {
126                    $averageProcessTime = secondsToReadable(floor($totalProcessTime / $numBuys));
127                    if ($totalProcessTime < 15) {
128                        $averageProcessTime = "Not Enough Data";
129                        $processTimePerContainer = "Not Enough Data";
130                    } else {
131                        $processTimePerContainer = secondsToReadable(floor($totalProcessTime / $numContainers));
132                    }
133                } else {
134                    $averageProcessTime = "Not Enough Data";
135                    $processTimePerContainer = "Not Enough Data";
136                }
137                $tempArray = array(
138                    'buyerFullName' => $buyerFullName,
139                    'averageProcessTime' => $averageProcessTime,
140                    'processTimePerContainer' => $processTimePerContainer,
141                    'totalContainers' => $workedContainers,
142                    'numBuys' => $totalWorkedBuys
143                );
144                $this->BuyerStatsArray[] = $tempArray;
145            }
146        }
147    }
148
149    /**
150     * Gather daily sorter statistics
151     *
152     * Queries buyQueue data joined with unified users table to calculate
153     * sorter performance metrics.
154     *
155     * @param Store $store Store object
156     * @param string|null $date Optional date (Y-m-d format)
157     */
158    public function gatherDailySorterStatsArray(Store $store, $date = null)
159    {
160        $storeDb = dbConnectByName($store->getDbName());
161        $centralDb = \dbConnectByName('kiosk_users');
162        $typeNum = $store->getTypeNum();
163
164        $this->gatherCompletedBuys($store, $date);
165        $buyArray = $this->getCompletedBuys();
166        $sorterArray = array();
167
168        foreach ($buyArray as $buy) {
169            if($buy['sortStarted'] !== "-") {
170                if (!in_array($buy['sorterID'], $sorterArray)) {
171                    $sorterArray[] = $buy['sorterID'];
172                }
173                $timeStarted = new \DateTime($buy['sortStarted']);
174                $timeCompleted = new \DateTime($buy['sortCompleted']);
175
176                $diffStartedCompleted = $timeCompleted->diff($timeStarted);
177            }
178        }
179
180        if($date !== null) {
181            $dateRange = getDateRange($date);
182        } else {
183            $dateRange = getCurrentDateRange();
184        }
185
186        foreach ($sorterArray as $sorter) {
187            // Query buyQueue from store database
188            $query = "SELECT * FROM buyQueue WHERE buyQueue.sorterID = :sorterId
189                      AND timeCompleted BETWEEN :dateStart AND :dateEnd
190                      AND buyQueue.isProcessed = 1";
191
192            $stmt = $storeDb->prepare($query);
193            $stmt->execute([
194                ':sorterId' => $sorter,
195                ':dateStart' => $dateRange['dateStart']->format("Y-m-d H:i:s"),
196                ':dateEnd' => $dateRange['dateEnd']->format("Y-m-d H:i:s")
197            ]);
198            $buys = $stmt;
199
200            if ($buys) {
201                $totalProcessTime = 0;
202                $totalWorkedBuys = 0;
203                $numBuys = 0;
204                $numContainers = 0;
205                $workedContainers = 0;
206                $sorterFullName = "";
207
208                // Fetch user info from central database once per sorter
209                $userStmt = $centralDb->prepare("
210                    SELECT u.firstName, u.lastName
211                    FROM users u
212                    INNER JOIN userStoreAssignments usa ON u.id = usa.userId
213                    WHERE u.id = :userId AND usa.typeNum = :typeNum
214                    LIMIT 1
215                ");
216                $userStmt->execute([':userId' => $sorter, ':typeNum' => $typeNum]);
217                $userInfo = $userStmt->fetch(\PDO::FETCH_ASSOC);
218
219                if ($userInfo) {
220                    $sorterFullName = $userInfo['firstName'] . " " . substr($userInfo['lastName'], 0, 1);
221                }
222
223                while ($data = $buys->fetch(\PDO::FETCH_ASSOC)) {
224                    $timeStarted = new \DateTime($data['sortStarted']);
225                    $timeCompleted = new \DateTime($data['sortCompleted']);
226
227                    $diffStartedCompleted = $timeCompleted->diff($timeStarted);
228
229                    $secondsForProcessTime = ((int)$diffStartedCompleted->format('%h') * 60 * 60) + ((int)$diffStartedCompleted->format('%i') * 60) + ((int)$diffStartedCompleted->format('%s'));
230                    if ($secondsForProcessTime > 30) {
231                        $totalProcessTime += $secondsForProcessTime;
232                        $numBuys++;
233                        $numContainers += $data['numContainers'];
234                    }
235                    $workedContainers += $data['numContainers'];
236                    $totalWorkedBuys++;
237                }
238
239                if ($numBuys > 0) {
240                    $averageSortTime = secondsToReadable(floor($totalProcessTime / $numBuys));
241                    if ($totalProcessTime < 15) {
242                        $averageSortTime = "Not Enough Data";
243                        $sortTimePerContainer = "Not Enough Data";
244                    } else {
245                        $sortTimePerContainer = secondsToReadable(floor($totalProcessTime / $numContainers));
246                    }
247                } else {
248                    $averageSortTime = "Not Enough Data";
249                    $sortTimePerContainer = "Not Enough Data";
250                }
251
252                $tempArray = array(
253                    'sorterFullName' => $sorterFullName,
254                    'averageSortTime' => $averageSortTime,
255                    'sortTimePerContainer' => $sortTimePerContainer,
256                    'totalContainers' => $workedContainers,
257                    'numBuys' => $totalWorkedBuys
258                );
259                $this->SorterStatsArray[] = $tempArray;
260            }
261        }
262    }
263
264public function setBuyerStatsArray($BuyerStatsArray)
265{
266    $this->BuyerStatsArray = $BuyerStatsArray;
267}
268
269public function getBuyerStatsArray()
270{
271    return $this->BuyerStatsArray;
272}
273
274
275}