Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
73.91% covered (warning)
73.91%
102 / 138
50.00% covered (danger)
50.00%
2 / 4
CRAP
n/a
0 / 0
_duplicated_row_ticketlog
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
5
_log_action_ticketlog
93.02% covered (success)
93.02%
40 / 43
0.00% covered (danger)
0.00%
0 / 1
24.20
_log_hshchk_ticketlog
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
parse_line_ticketlog
93.33% covered (success)
93.33%
14 / 15
0.00% covered (danger)
0.00%
0 / 1
8.02
1<?php
2
3/**
4 * @file
5 * Place action: ticket activity log.
6 */
7
8declare(strict_types=1);
9
10require_once __DIR__.'/../../Legacy/common/session.php';
11
12/**
13 * @param array<string, mixed> $lastlog
14 * @param array<string, mixed> $currlog
15 */
16function _duplicated_row_ticketlog(array $lastlog, array $currlog): bool
17{
18    $skip = ['date', 'version', 'event', 'objid', 'hash', 'prev'];
19    foreach ($currlog as $field => $value) {
20        $previous = array_key_exists($field, $lastlog) ? $lastlog[$field] : null;
21        if (!in_array($field, $skip) && $previous != $value) {
22            return false;
23        }
24    }
25    return true;
26}
27
28/**
29 * @param array<string, mixed> $newentry
30 * @param array<string, mixed> $ticketlog
31 */
32function _log_action_ticketlog(array &$newentry, array &$ticketlog): ?string
33{
34    $action = null;
35    $_new_status = $newentry['status'] ?? null;
36    $_new_price = $newentry['price'] ?? null;
37    $_new_payment = $newentry['payment'] ?? null;
38    $_new_invoice = $newentry['invceno'] ?? null;
39
40    if (count($ticketlog) == 0) {
41        switch ($_new_status) {
42            case 'DE':
43            case 'CC':
44                return 'CANCELLED';
45            case 'PD':
46                return 'COMPLETED';
47            default:
48                return 'CREATED';
49        }
50    }
51    $lastlog = end($ticketlog);
52    $_old_status = $lastlog['status'] ?? null;
53    $_old_price = $lastlog['price'] ?? null;
54    $_old_payment = $lastlog['payment'] ?? null;
55    $_old_invoice = $lastlog['invceno'] ?? null;
56
57    if ($_old_payment != $_new_payment) {
58        return $_new_payment;
59    }
60    if ($_old_invoice != $_new_invoice) {
61        return 'INVOICE';
62    }
63    if ($_old_price != $_new_price) {
64        return ($_new_payment != '') ? 'RETURN' : 'MODIFIED';
65    }
66    if ($_old_status != $_new_status) {
67        switch ($_new_status) {
68            case 'AC':
69                switch ($_old_status) {
70                    case 'PR':
71                        return 'ACTIVE';
72                    case 'RD':
73                        return 'MODIFIED';
74                    default:
75                        return 'REOPEN';
76                }
77            case 'RD':
78                return 'READY';
79            case 'PP':
80                return ($_new_payment == 'PAYACCOUNT') ? 'TOACC' : 'TOPAY';
81            case 'PD':
82                return 'PAYMENT';
83            case 'CC':
84                return ($_new_payment != '') ? 'REFUND' : 'CANCELLED';
85            case 'DE':
86                return 'CANCELLED';
87        }
88    }
89    if (($_new_status == 'DE') || ($_new_price == 0)) {
90        return 'CANCELLED';
91    }
92    return $action;
93}
94
95/**
96 * @param array<string, mixed> $newentry
97 * @param array<string> $header
98 */
99function _log_hshchk_ticketlog(array &$newentry, array &$header, string $prvhash): bool
100{
101    $rowline = '';
102    foreach ($header as $field) {
103        if (in_array($field, ['hash', 'prev', 'action', 'hshchk'])) {
104            continue;
105        }
106        $rowline .= ($newentry[$field] ?? '').';';
107    }
108    return (md5($rowline) == ($newentry['hash'] ?? '')) && ($prvhash == ($newentry['prev'] ?? ''));
109}
110
111/**
112 * @param array<string> $header
113 * @param array<string> $fields
114 * @param array<int, array> $itmindex
115 */
116function parse_line_ticketlog(array &$header, array &$fields, array &$itmindex, string &$prvhash): array|false
117{
118    $result = [];
119    for ($i = 0; $i < count($header); $i++) {
120        if (!in_array($header[$i], ['action', 'hshchk'])) {
121            $result[$header[$i]] = $fields[$i] ?? '';
122        }
123    }
124    if (array_key_exists('objid', $result) && $result['objid']) {
125        if (!array_key_exists($result['objid'], $itmindex)) {
126            $itmindex[$result['objid']] = [];
127        }
128        $ticketlog = &$itmindex[$result['objid']];
129    } else {
130        $ticketlog = [];
131    }
132    $result['hshchk'] = _log_hshchk_ticketlog($result, $header, $prvhash);
133    if ((count($ticketlog) > 0) && _duplicated_row_ticketlog(end($ticketlog), $result)) {
134        return false;
135    }
136    $result['action'] = _log_action_ticketlog($result, $ticketlog);
137    $ticketlog[] = $result;
138    return $result;
139}
140
141/**
142 * Action callable: get ticket activity log for place.
143 *
144 * @param string $body Unused.
145 * @param array<string, mixed> $query Query params: device, session, place, ini, end.
146 * @param \ConxHelper $conx Connection helper.
147 * @param \Psr\Log\LoggerInterface $logger Logger.
148 * @param \UppServices\SessionService $sessionService Session service for check.
149 * @return array{output: string, contentType: string}
150 */
151return function (string $body, array $query, \ConxHelper $conx, \Psr\Log\LoggerInterface $logger, \UppServices\SessionService $sessionService): array {
152    $retval = \ApplicationError::Success;
153    $place = null;
154    $header = [];
155    $reglog = [];
156
157    $device = $query['device'] ?? null;
158    if (!$device) {
159        $logger->error("No device provided on URL. Operation cancelled.");
160        $retval = \ApplicationError::Parameters;
161    }
162
163    if (\success($retval)) {
164        $session = $query['session'] ?? null;
165        if (!$session) {
166            $logger->error("No session provided on URL. Operation cancelled.");
167            $retval = \ApplicationError::Parameters;
168        } else {
169            $userid = null;
170            $retval = $sessionService->checkSession($conx, (string) $session, (string) $device, $userid);
171        }
172    }
173
174    if (\success($retval)) {
175        $place = $query['place'] ?? null;
176        if (!$place) {
177            $logger->error("Mandatory parameter 'place' not provided on URL. Operation cancelled.");
178            $retval = \ApplicationError::Parameters;
179        }
180    }
181
182    $dateini = $query['ini'] ?? null;
183    $dateend = $query['end'] ?? null;
184
185    if (\success($retval)) {
186        $dstfile = sprintf('%s/%05d_ticket_activity.csv', \AppConstants::RegLogPath(), $place);
187        if (!file_exists($dstfile)) {
188            $logger->warning("No registry found for place. file '".$dstfile."'.");
189            $retval = \ApplicationError::NotFound;
190        } else {
191            $rawlog = file_get_contents($dstfile);
192            if (!$rawlog) {
193                $logger->error("Could not read contents for file '".$dstfile."'.");
194                $retval = \ApplicationError::Generic;
195            } else {
196                $itmindex = [];
197                $logitems = [];
198                $inidate = strtotime((string) $dateini);
199                $enddate = strtotime((string) $dateend);
200                $prvhash = '00000000000000000000000000000000';
201                $lines = explode(PHP_EOL, $rawlog, -1);
202                $hdrfl = true;
203                for ($i = 0; $i < count($lines); $i++) {
204                    $fields = explode(';', $lines[$i], -1);
205                    if (empty($lines[$i])) {
206                        $hdrfl = true;
207                        continue;
208                    }
209                    if ($hdrfl) {
210                        $hdrfl = false;
211                        $header = array_merge($fields, ['action', 'hshchk']);
212                        continue;
213                    }
214                    $logtime = strtotime($fields[0]);
215                    if ($logtime >= $inidate && $logtime <= $enddate) {
216                        $logitem = parse_line_ticketlog($header, $fields, $itmindex, $prvhash);
217                        if ($logitem !== false) {
218                            $logitems[] = $logitem;
219                        }
220                    }
221                    $prvhash = $fields[count($fields) - 2] ?? '';
222                }
223                foreach ($logitems as &$registry) {
224                    $regline = [];
225                    foreach ($header as $field) {
226                        $regline[] = $registry[$field] ?? '';
227                    }
228                    $reglog[] = $regline;
229                }
230                unset($registry);
231            }
232        }
233    }
234
235    $result = [
236        "errorcode" => $retval,
237        "header" => \success($retval) ? $header : [],
238        "reglog" => \success($retval) ? $reglog : [],
239    ];
240    return ['output' => json_encode($result), 'contentType' => 'application/json; charset=utf-8'];
241};