Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
16.50% covered (danger)
16.50%
50 / 303
0.00% covered (danger)
0.00%
0 / 8
CRAP
n/a
0 / 0
_set_qrcodes_till
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
72
_del_tickets_audit
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
42
_set_tickets_audit
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
132
_set_audits_till
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 1
756
_set_multiplepos
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
_del_multiplepos
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
_set_multiplepos_ready
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
156
enable_disable_multiplepos
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3/**
4 * @file
5 * Place action: enable/disable multiple POS for place.
6 */
7
8declare(strict_types=1);
9
10require_once __DIR__.'/../../Legacy/common/session.php';
11require_once __DIR__.'/../legacy/model/conncontrol.php';
12
13/**
14 * Set QRCODE till for all place tables.
15 *
16 * @param \ConxHelper $conx Connection helper (tenant must be set).
17 * @param \transaction $transaction Active transaction.
18 * @param mixed $place Place identifier (unused; tenant scope defines place).
19 * @param string|null $till Till objid or null to clear.
20 * @return int ApplicationError code.
21 */
22function _set_qrcodes_till($conx, $transaction, $place, $till): int
23{
24    $retval = \ApplicationError::Success;
25    if ($conx->tenant === null) {
26        return \ApplicationError::Database;
27    }
28
29    $qrcodes = [];
30    $res = $conx->tenant->query('QRCODE', [], $qrcodes);
31    if (!$res) {
32        $retval = \ApplicationError::Database;
33    } else {
34        \addlog(__FILE__, \LogLevel::Information, "Setting ".count($qrcodes)." tables till, to be '".$till."'");
35
36        $toupdate = [];
37        foreach ($qrcodes as &$qrcode) {
38            if ($qrcode['till'] == $till) {
39                continue;
40            }
41
42            $qrcode['till'] = $till;
43
44            if ($till && $till != '') {
45                \addlog(__FILE__, \LogLevel::Debug, "Asigned till '".$till."' to table '".$qrcode['objid']."'");
46            } else {
47                \addlog(__FILE__, \LogLevel::Debug, "Removed till relation from qrcode '".$qrcode['objid']."'");
48            }
49
50            array_push($toupdate, $qrcode);
51        }
52        unset($qrcode);
53
54        $res = $transaction->batchupdate('QRCODE', $toupdate);
55        if (!$res) {
56            $retval = \ApplicationError::Database;
57        }
58    }
59
60    return $retval;
61}
62
63/**
64 * Delete ticket audits (mark DE) for place.
65 *
66 * @param \ConxHelper $conx Connection helper (tenant must be set).
67 * @param mixed $place Place identifier (unused).
68 * @param array<int, array> $toupdate Output: items to batch update.
69 * @return int ApplicationError code.
70 */
71function _del_tickets_audit($conx, $place, &$toupdate): int
72{
73    $retval = \ApplicationError::Success;
74    if ($conx->tenant === null) {
75        return \ApplicationError::Database;
76    }
77
78    $ticketaudits = [];
79    if (\success($retval)) {
80        $sql = "select TICKETAUDIT.* from TICKETAUDIT ";
81        $sql .= "inner join TICKET on TICKETAUDIT.TICKET = TICKET.objid ";
82        $sql .= "where TICKETAUDIT.status ='AC'";
83
84        $res = $conx->tenant->runsql(['TICKET', 'TICKETAUDIT'], $sql, $ticketaudits);
85        if (!$res) {
86            $retval = \ApplicationError::Database;
87        } else {
88            \addlog(__FILE__, \LogLevel::Information, "Removing ".count($ticketaudits)." ticket audits");
89
90            foreach ($ticketaudits as &$ticketaudit) {
91                if ($ticketaudit['status'] == 'DE') {
92                    continue;
93                }
94
95                $ticketaudit['status'] = 'DE';
96                \addlog(__FILE__, \LogLevel::Debug, "Removed audit [".$ticketaudit['objid']."] from ticket '".$ticketaudit['ticket']."'");
97                array_push($toupdate, $ticketaudit);
98            }
99            unset($ticketaudit);
100        }
101    }
102
103    return $retval;
104}
105
106/**
107 * Set ticket audits for audit period.
108 *
109 * @param \ConxHelper $conx Connection helper (tenant must be set).
110 * @param string $prev Previous audit created timestamp.
111 * @param array $audit Current audit row.
112 * @param array<int, array> $toinsert Output: items to batch insert.
113 * @param array<int, array> $toupdate Output: items to batch update.
114 * @return int ApplicationError code.
115 */
116function _set_tickets_audit($conx, &$prev, &$audit, &$toinsert, &$toupdate): int
117{
118    $retval = \ApplicationError::Success;
119    if ($conx->tenant === null) {
120        return \ApplicationError::Database;
121    }
122
123    $tickets = [];
124    if (\success($retval)) {
125        $next = $audit['created'];
126
127        $sql = "select * from TICKET where (";
128        $sql .= "   TICKET.status not in ('DE', 'CC') and ";
129        $sql .= "   TICKET.paidon is not null and";
130        $sql .= "   TICKET.paidon > '".$prev."' and TICKET.paidon <= '".$next."'";
131        $sql .= ") or (";
132        $sql .= "   TICKET.status in ('DE', 'CC') and ";
133        $sql .= "   TICKET.updated > '".$prev."' and TICKET.updated <= '".$next."'";
134        $sql .= ")";
135
136        $prev = $next;
137
138        $res = $conx->tenant->runsql(['TICKET'], $sql, $tickets);
139        if (!$res) {
140            $retval = \ApplicationError::Database;
141        } else {
142            \addlog(__FILE__, \LogLevel::Information, "Setting ".count($tickets)." tickets audit, to be '".$audit['objid']."'");
143
144            $tckmap = [];
145            if (count($tickets) > 0) {
146                $tckids = array_column($tickets, 'objid');
147                $tcksql = implode(',', $tckids);
148
149                $ticketaudits = [];
150                $sql = "select * from TICKETAUDIT where ticket in (".$tcksql.")";
151                $res = $conx->tenant->runsql(['TICKETAUDIT'], $sql, $ticketaudits);
152                if ($res) {
153                    foreach ($ticketaudits as &$ticketaudit) {
154                        $tckmap[$ticketaudit['ticket']][] = &$ticketaudit;
155                    }
156                    unset($ticketaudit);
157                } else {
158                    $retval = \ApplicationError::Database;
159                }
160            }
161
162            foreach ($tickets as &$ticket) {
163                if (\success($retval)) {
164                    \addlog(__FILE__, \LogLevel::Debug, "Asigned audit '".$audit['objid']."' to ticket '".$ticket['objid']."'");
165
166                    if (isset($tckmap[$ticket['objid']]) && (count($tckmap[$ticket['objid']]) > 0)) {
167                        $tckaudit = $tckmap[$ticket['objid']][0];
168
169                        $iteminfo = [
170                            "objid" => $tckaudit['objid'],
171                            "status" => 'AC',
172                            "ticket" => $ticket['objid'],
173                            "audit" => $audit['objid']
174                        ];
175
176                        array_push($toupdate, $iteminfo);
177                    } else {
178                        $iteminfo = [
179                            "status" => 'AC',
180                            "ticket" => $ticket['objid'],
181                            "audit" => $audit['objid'],
182                        ];
183
184                        array_push($toinsert, $iteminfo);
185                    }
186                }
187            }
188            unset($ticket);
189        }
190    }
191
192    return $retval;
193}
194
195/**
196 * Set AUDITTILL for all place audits.
197 *
198 * @param \ConxHelper $conx Connection helper (tenant must be set).
199 * @param \transaction $transaction Active transaction.
200 * @param int $place Place objid.
201 * @param string|null $till Till objid or null to clear.
202 * @return int ApplicationError code.
203 */
204function _set_audits_till($conx, $transaction, $place, $till): int
205{
206    $retval = \ApplicationError::Success;
207    if ($conx->tenant === null) {
208        return \ApplicationError::Database;
209    }
210
211    $audits = [];
212    $res = $conx->tenant->query('AUDIT', ['place' => $place], $audits, "ORDER BY AUDIT.created ASC");
213    if (!$res) {
214        $retval = \ApplicationError::Database;
215    } else {
216        if (\success($retval)) {
217            $toinsert = [];
218            $toupdate = [];
219
220            if ($till == null) {
221                $retval = _del_tickets_audit($conx, $place, $toupdate);
222            } else {
223                $prev = date("Y-m-d H:i:s", 0);
224                foreach ($audits as &$audit) {
225                    $retval = _set_tickets_audit($conx, $prev, $audit, $toinsert, $toupdate);
226                }
227                unset($audit);
228            }
229
230            if (\success($retval) && (count($toinsert) > 0)) {
231                $res = $transaction->batchinsert('TICKETAUDIT', $toinsert);
232                if (!$res) {
233                    $retval = \ApplicationError::Database;
234                }
235            }
236
237            if (\success($retval) && (count($toupdate) > 0)) {
238                $res = $transaction->batchupdate('TICKETAUDIT', $toupdate);
239                if (!$res) {
240                    $retval = \ApplicationError::Database;
241                }
242            }
243        }
244
245        if (\success($retval)) {
246            $indexed = [];
247
248            $sql = "select AUDITTILL.* from AUDITTILL ";
249            $sql .= "inner join AUDIT on AUDITTILL.audit = AUDIT.objid ";
250            $sql .= "where AUDIT.place = ".$place;
251
252            $audittills = [];
253            $res = $conx->tenant->runsql(['AUDITTILL', 'AUDIT'], $sql, $audittills);
254            if ($res) {
255                foreach ($audittills as &$audittill) {
256                    if (!isset($indexed[$audittill['audit']])) {
257                        $indexed[$audittill['audit']] = [];
258                    }
259                    array_push($indexed[$audittill['audit']], $audittill);
260                }
261                unset($audittill);
262            } else {
263                $retval = \ApplicationError::Database;
264            }
265        }
266
267        if (\success($retval)) {
268            $toinsert = [];
269            $toupdate = [];
270
271            \addlog(__FILE__, \LogLevel::Information, "Setting ".count($audits)." audits till, to be '".$till."'");
272            foreach ($audits as &$audit) {
273                if ($till && $till != '') {
274                    \addlog(__FILE__, \LogLevel::Debug, "Asigned till '".$till."' to audit '".$audit['objid']."'");
275                } else {
276                    \addlog(__FILE__, \LogLevel::Debug, "Removed till relation from audit '".$audit['objid']."'");
277                }
278
279                if (!isset($indexed[$audit['objid']])) {
280                    $iteminfo = [
281                        "status" => 'AC',
282                        "audit" => $audit['objid'],
283                        "rasppi" => $till
284                    ];
285
286                    array_push($toinsert, $iteminfo);
287                } else {
288                    $iteminfo = [
289                        "objid" => $indexed[$audit['objid']][0]['objid'],
290                        "status" => 'AC',
291                        "audit" => $audit['objid'],
292                        "rasppi" => $till
293                    ];
294
295                    array_push($toupdate, $iteminfo);
296                }
297            }
298            unset($audit);
299        }
300
301        if (\success($retval) && (count($toinsert) > 0)) {
302            $res = $transaction->batchinsert('AUDITTILL', $toinsert);
303            if (!$res) {
304                $retval = \ApplicationError::Database;
305            }
306        }
307
308        if (\success($retval) && (count($toupdate) > 0)) {
309            $res = $transaction->batchupdate('AUDITTILL', $toupdate);
310            if (!$res) {
311                $retval = \ApplicationError::Database;
312            }
313        }
314    }
315
316    return $retval;
317}
318
319/**
320 * Enable multiple POS: assign all place tables and audits to till.
321 *
322 * @param \ConxHelper $conx Connection helper (tenant must be set).
323 * @param \transaction $transaction Active transaction.
324 * @param int $place Place objid.
325 * @param int $rasppi Till objid.
326 * @return int ApplicationError code.
327 */
328function _set_multiplepos($conx, $transaction, $place, $rasppi): int
329{
330    $retval = \ApplicationError::Success;
331
332    \addlog(__FILE__, \LogLevel::Information, "Enabling multiple POS for place [".$place."] and till [".$rasppi."]");
333
334    if (\success($retval)) {
335        $retval = _set_qrcodes_till($conx, $transaction, $place, (string) $rasppi);
336    }
337
338    if (\success($retval)) {
339        $retval = _set_audits_till($conx, $transaction, $place, (string) $rasppi);
340    }
341
342    \addlog(__FILE__, \LogLevel::Information, "Enabling multiple POS for place [".$place."] completed OK.");
343
344    return $retval;
345}
346
347/**
348 * Disable multiple POS: remove all place tables from till.
349 *
350 * @param \ConxHelper $conx Connection helper (tenant must be set).
351 * @param \transaction $transaction Active transaction.
352 * @param int $place Place objid.
353 * @return int ApplicationError code.
354 */
355function _del_multiplepos($conx, $transaction, $place): int
356{
357    $retval = \ApplicationError::Success;
358
359    \addlog(__FILE__, \LogLevel::Information, "Disabling multiple POS for place [".$place."]");
360
361    if (\success($retval)) {
362        $retval = _set_qrcodes_till($conx, $transaction, $place, null);
363    }
364
365    \addlog(__FILE__, \LogLevel::Information, "Disabling multiple POS for place [".$place."] completed OK.");
366
367    return $retval;
368}
369
370/**
371 * Set readyMultiplePOS flag in PLACEOPT.
372 *
373 * @param \ConxHelper $conx Connection helper (tenant must be set).
374 * @param array $place Place row.
375 * @param bool $value Ready flag value.
376 * @return int ApplicationError code.
377 */
378function _set_multiplepos_ready($conx, &$place, bool $value): int
379{
380    $retval = \ApplicationError::Success;
381    if ($conx->tenant === null) {
382        return \ApplicationError::Database;
383    }
384
385    $placeopt = null;
386    if (\success($retval)) {
387        $results = [];
388        $res = $conx->tenant->query('PLACEOPT', ["place" => $place['objid'], "opkey" => 'readyMultiplePOS'], $results);
389        if ($res) {
390            if (count($results) > 0) {
391                $placeopt = $results[0];
392            }
393        } else {
394            $retval = \ApplicationError::Database;
395        }
396    }
397
398    if (\success($retval)) {
399        $transaction = $conx->tenant->begin();
400        if ($transaction) {
401            if ($placeopt) {
402                $iteminfo = [
403                    "objid" => $placeopt['objid'],
404                    "value" => $value ? '1' : '0'
405                ];
406
407                $res = $transaction->update('PLACEOPT', $iteminfo);
408                if (!$res) {
409                    $retval = \ApplicationError::Database;
410                }
411            } else {
412                $iteminfo = [
413                    "place" => $place['objid'],
414                    "opkey" => 'readyMultiplePOS',
415                    "value" => $value ? '1' : '0'
416                ];
417
418                $res = $transaction->insert('PLACEOPT', $iteminfo);
419                if (!$res) {
420                    $retval = \ApplicationError::Database;
421                }
422            }
423
424            $transaction->flush(\success($retval));
425        } else {
426            $retval = \ApplicationError::Database;
427        }
428    }
429
430    return $retval;
431}
432
433/**
434 * Enable or disable multiple POS for place.
435 *
436 * @param \ConxHelper $conx Connection helper (tenant must be set).
437 * @param bool $enable True to enable, false to disable.
438 * @param array $place Place row.
439 * @param array $rasppi Till row.
440 * @return int ApplicationError code.
441 */
442function enable_disable_multiplepos($conx, bool $enable, &$place, &$rasppi): int
443{
444    $retval = \ApplicationError::Success;
445    if ($conx->tenant === null) {
446        return \ApplicationError::Database;
447    }
448
449    if (\success($retval)) {
450        $transaction = $conx->tenant->begin();
451        if ($transaction) {
452            if ($enable) {
453                $retval = _set_multiplepos($conx, $transaction, (int) $place['objid'], (int) $rasppi['objid']);
454            } else {
455                $retval = _del_multiplepos($conx, $transaction, (int) $place['objid']);
456            }
457
458            $transaction->flush(\success($retval));
459        } else {
460            $retval = \ApplicationError::Database;
461        }
462    }
463
464    return $retval;
465}
466
467/**
468 * Action callable: enable/disable multiple POS for place.
469 *
470 * @param string $body Unused.
471 * @param array<string, mixed> $query Query params: device, session, enable, place.
472 * @param \ConxHelper $conx Connection helper.
473 * @param \Psr\Log\LoggerInterface $logger Logger.
474 * @param \UppServices\SessionService $sessionService Session service for check.
475 * @return array{output: string, contentType: string}
476 */
477return function (string $body, array $query, \ConxHelper $conx, \Psr\Log\LoggerInterface $logger, \UppServices\SessionService $sessionService): array {
478    $retval = \ApplicationError::Success;
479    $place = null;
480    $rasppi = null;
481    $session = null;
482    $enable = false;
483    $placeParam = null;
484
485    $device = $query['device'] ?? null;
486    if (!$device) {
487        $logger->error("No device provided on URL. Operation cancelled.");
488        $retval = \ApplicationError::Parameters;
489    }
490
491    if (\success($retval)) {
492        $session = $query['session'] ?? null;
493        if (!$session) {
494            $logger->error("No session provided on URL. Operation cancelled.");
495            $retval = \ApplicationError::Parameters;
496        } else {
497            $userid = null;
498            $retval = $sessionService->checkSession($conx, (string) $session, (string) $device, $userid);
499        }
500    }
501
502    if (\success($retval)) {
503        $enable = $query['enable'] ?? null;
504        if ($enable === null || $enable === '') {
505            $logger->error("Mandatory argument 'enable' not provided in url parameters.");
506            $retval = \ApplicationError::Parameters;
507        } else {
508            $enable = ($enable === 'true');
509        }
510    }
511
512    if (\success($retval)) {
513        $placeParam = $query['place'] ?? null;
514        if (!$placeParam) {
515            $logger->error("Mandatory argument 'place' not provided in url parameters.");
516            $retval = \ApplicationError::Parameters;
517        }
518    }
519
520    if (\success($retval) && $conx->global === null) {
521        $logger->error("Connection to central database failed.");
522        $retval = \ApplicationError::Database;
523    }
524
525    if (\success($retval)) {
526        $results = [];
527        $res = $conx->global->query('PLACE', ["objid" => $placeParam, "status" => 'AC'], $results);
528        if ($res) {
529            if (count($results) > 0) {
530                $place = $results[0];
531            } else {
532                $logger->error("Cannot find active place with objid [".$placeParam."].");
533                $retval = \ApplicationError::NotFound;
534            }
535        } else {
536            $logger->error("Query failed for PLACE objid ".$placeParam);
537            $retval = \ApplicationError::Database;
538        }
539    }
540
541    if (\success($retval)) {
542        $conx->tenant = $placeParam;
543        if ($conx->tenant === null) {
544            $logger->error("Connection to place database failed.");
545            $retval = \ApplicationError::Database;
546        }
547    }
548
549    if (\success($retval)) {
550        $results = [];
551        $sql = "select * from RASPPI where place=".$place['objid']." and status != 'DE' ORDER BY objid desc";
552        $res = $conx->tenant->runsql(['RASPPI'], $sql, $results);
553        if ($res) {
554            if (count($results) > 0) {
555                $rasppi = $results[0];
556            } else {
557                $logger->error("No active rasppi instances found for place [".$place['objid']."]");
558                $retval = \ApplicationError::NotFound;
559            }
560        } else {
561            $logger->error("Query failed for RASPPI place ".$place['objid']);
562            $retval = \ApplicationError::Database;
563        }
564    }
565
566    if (\success($retval)) {
567        $retval = _set_multiplepos_ready($conx, $place, false);
568    }
569
570    if (\success($retval)) {
571        $retval = enable_disable_multiplepos($conx, $enable, $place, $rasppi);
572    }
573
574    if (\success($retval)) {
575        $retval = _set_multiplepos_ready($conx, $place, true);
576    }
577
578    if (\success($retval)) {
579        $placeNotify = [
580            "table" => "PLACE",
581            "objid" => $place['objid']
582        ];
583
584        $updates = [$placeNotify];
585
586        $logger->debug("Changes are provided: notify to connected instances.");
587        $retval = \connection_notify($conx, (string) $session, $updates, true);
588        if (!\success($retval)) {
589            $logger->error("Error notifying to connected instances.");
590        }
591    }
592
593    $result = [
594        "errorcode" => $retval
595    ];
596
597    return ['output' => json_encode($result), 'contentType' => 'application/json; charset=utf-8'];
598};