PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 1.2.38
Booking for Appointments and Events Calendar – Amelia v1.2.38
2.4.9 2.4.8 2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / src / Application / Services / QrCode / QrCodeApplicationService.php
ameliabooking / src / Application / Services / QrCode Last commit date
AbstractQrCodeApplicationService.php 9 months ago QrCodeApplicationService.php 9 months ago StarterQrCodeApplicationService.php 9 months ago
QrCodeApplicationService.php
255 lines
1 <?php
2
3 namespace AmeliaBooking\Application\Services\QrCode;
4
5 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
6 use AmeliaBooking\Domain\Entity\Booking\Event\CustomerBookingEventTicket;
7 use AmeliaBooking\Domain\Entity\Booking\Event\EventPeriod;
8 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
9 use AmeliaBooking\Infrastructure\Common\Exceptions\NotFoundException;
10 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
11 use AmeliaBooking\Infrastructure\Repository\Booking\Event\EventTicketRepository;
12 use AmeliaBooking\Infrastructure\Repository\Location\LocationRepository;
13 use AmeliaBooking\Infrastructure\Services\QrCode\QrCodeInfrastructureService;
14 use Interop\Container\Exception\ContainerException;
15
16 /**
17 * Class QrCodeApplicationService
18 *
19 * @package AmeliaBooking\Application\Services\QrCode
20 */
21 class QrCodeApplicationService extends AbstractQrCodeApplicationService
22 {
23 /**
24 * @param array $eventData
25 * @param array $booking
26 * @param string $ticketCode
27 *
28 * @return array
29 *
30 * @throws NotFoundException
31 * @throws QueryExecutionException
32 * @throws ContainerException
33 * @throws InvalidArgumentException
34 */
35 public function createQrCodeEventTickets($eventData, $booking, $ticketCode = ''): array
36 {
37 /** @var QrCodeInfrastructureService $qrService */
38 $qrService = $this->container->get('infrastructure.qrcode.service');
39
40 $locale = is_string($booking['info']) ? json_decode($booking['info'], true)['locale'] : '';
41 $qrCodeItems = [];
42 $qrJson = $booking['qrCodes'];
43 $qrArr = is_string($qrJson) ? json_decode($qrJson, true) : (is_array($qrJson) ? $qrJson : []);
44
45 if (is_array($qrArr)) {
46 foreach ($qrArr as $qr) {
47 if (!$ticketCode || hash_equals($qr['ticketManualCode'], $ticketCode)) {
48 $qrData = $qr;
49 if (!empty($qr['qrCodeData'])) {
50 $eventTranslations = $eventData['translations'] ? json_decode($eventData['translations'], true) : null;
51 $qrData['bookingId'] = $booking['id'];
52 $qrData['eventName'] = $eventTranslations['name'][$locale] ?: $eventData['name'];
53 $qrData['eventStartDateTime'] = $eventData['periods'][0]['periodStart'];
54
55 if (
56 $qrData['type'] === 'ticket' &&
57 array_key_exists('eventTicketId', $qrData) &&
58 isset($booking['ticketsData'])
59 ) {
60 foreach ($eventData['customTickets'] as $ticket) {
61 if ($ticket['id'] === $qrData['eventTicketId']) {
62 $ticketTranslations = $ticket['translations'] ? json_decode($ticket['translations'], true) : null;
63 $ticketName = $ticketTranslations[$locale] ?: $ticket['name'];
64 $qrData['eventTicketName'] = $ticketName;
65 break;
66 }
67 }
68 }
69
70 if (isset($eventData['customLocation']) && $eventData['customLocation']) {
71 $qrData['eventLocation'] = $eventData['customLocation'];
72 }
73 if (isset($eventData['location'])) {
74 $qrData['eventLocation'] = $eventData['location'];
75 }
76 if (isset($eventData['locationId'])) {
77 /** @var LocationRepository $locationRepository */
78 $locationRepository = $this->container->get('domain.locations.repository');
79 $location = $locationRepository->getById($eventData['locationId']);
80 if ($location) {
81 $locationTranslations = $location->getTranslations() ? json_decode($location->getTranslations()->getValue(), true) : null;
82 $locTranslation = $locationTranslations['name'][$locale] ?? $location->getName()->getValue();
83 $qrData['eventLocation'] = $location->getAddress()->getValue() ?: $locTranslation;
84 }
85 }
86 if ($ticketCode) {
87 return $qrService->generateQrCode($qrData);
88 }
89 $qrCodeItems[] = $qrService->generateQrCode($qrData);
90 }
91 }
92 }
93 }
94
95 return $qrCodeItems;
96 }
97
98 /**
99 * Create QR code data array for a booking and event
100 *
101 * @param $event
102 * @param $booking
103 * @return array
104 * @throws InvalidArgumentException
105 * @throws ContainerException
106 * @throws NotFoundException
107 * @throws QueryExecutionException
108 */
109 public function createQrCodeEventData($event, $booking): array
110 {
111 $qrCodes = [];
112 $qrNumberData = $this->getNumberOfQrCodes($booking, $event);
113
114 if ($qrNumberData['number'] > 0 && $event->getId()) {
115 // Common timestamp for generation moment (UTC ISO8601)
116 $generatedAt = DateTimeService::getNowDateTimeObjectInUtc()->format('Y-m-d H:i:s');
117
118 $bookingIdVal = $booking->getId()->getValue();
119 $eventIdVal = $event->getId()->getValue();
120 $customerIdVal = $booking->getCustomerId() ? $booking->getCustomerId()->getValue() : '';
121
122 // Booking-level
123 if ($qrNumberData['number'] > 1) {
124 $bookingManualCode = $this->generateManualCode([
125 'bookingId' => $bookingIdVal,
126 'eventId' => $eventIdVal,
127 'customerId' => $customerIdVal,
128 'generatedAt' => $generatedAt,
129 ]);
130
131 $bookingQrData = 'type: booking | bookingId:' . $bookingIdVal . ' | ticketManualCode:' . $bookingManualCode;
132
133 $qrCodes[] = array_merge([
134 'type' => 'booking',
135 'eventName' => $event->getName() ? $event->getName()->getValue() : '',
136 'ticketManualCode' => $bookingManualCode,
137 'qrCodeData' => $bookingQrData,
138 'generatedAt' => $generatedAt,
139 ], ['dates' => $this->qrCodeDateFlag($event)]);
140 }
141
142 // Person / ticket level
143 for ($i = 1; $i <= $qrNumberData['number']; $i++) {
144 $ticketIdForPerson = $qrNumberData['ticketIds'][$i - 1] ?? null;
145 $codePayload = [
146 'bookingId' => $bookingIdVal,
147 'eventId' => $eventIdVal,
148 'customerId' => $customerIdVal,
149 'ticketIndex' => $i,
150 'generatedAt' => $generatedAt,
151 ];
152
153 if ($ticketIdForPerson) {
154 $codePayload['ticketId'] = $ticketIdForPerson;
155 }
156
157 $manualTicketCode = $this->generateManualCode($codePayload);
158
159 $ticketQrData = 'type: ticket | bookingId:' . $bookingIdVal . ' ticketManualCode:' . $manualTicketCode;
160
161 $entry = [
162 'type' => 'ticket',
163 'eventName' => $event->getName() ? $event->getName()->getValue() : '',
164 'ticketManualCode' => $manualTicketCode,
165 'qrCodeData' => $ticketQrData,
166 'generatedAt' => $generatedAt,
167 ];
168
169 if ($ticketIdForPerson) {
170 /** @var EventTicketRepository $eventTicketRepository */
171 $eventTicketRepository = $this->container->get('domain.booking.event.ticket.repository');
172 $ticket = $eventTicketRepository->getById($ticketIdForPerson);
173 $entry['eventTicketId'] = $ticketIdForPerson;
174 if ($ticket && $ticket->getName()) {
175 $entry['eventTicketName'] = $ticket->getName()->getValue();
176 }
177 }
178
179 $qrCodes[] = array_merge($entry, ['dates' => $this->qrCodeDateFlag($event)]);
180 }
181 }
182
183 return $qrCodes;
184 }
185
186 /**
187 * Determine number of QR codes to generate for a booking, and build a sequence of ticket ids if applicable
188 *
189 * @param $booking
190 * @param $event
191 * @return array ['number' => int, 'ticketIds' => array|null]
192 */
193 private function getNumberOfQrCodes($booking, $event): array
194 {
195 $personsForQr = 0;
196 $ticketIdSequence = [];
197 if ($booking->getTicketsBooking() && $event->getCustomPricing()->getValue()) {
198 /** @var CustomerBookingEventTicket $ticketBooking */
199 foreach ($booking->getTicketsBooking()->getItems() as $ticketBooking) {
200 $ticketPersons = ($ticketBooking->getPersons() ? $ticketBooking->getPersons()->getValue() : 0);
201 $personsForQr += $ticketPersons;
202 // Build a flat sequence of ticket ids, one per person, to map each QR to a ticket
203 if ($ticketPersons && $ticketBooking->getEventTicketId()) {
204 for ($ti = 0; $ti < $ticketPersons; $ti++) {
205 $ticketIdSequence[] = $ticketBooking->getEventTicketId()->getValue();
206 }
207 }
208 }
209 } else {
210 $personsForQr = $booking->getPersons() ? $booking->getPersons()->getValue() : 0;
211 }
212
213 $qrCodesNumberData['number'] = $personsForQr;
214 $qrCodesNumberData['ticketIds'] = $ticketIdSequence ?: null;
215
216 return $qrCodesNumberData;
217 }
218
219 /**
220 * Create an array of event dates (Y-m-d) as keys, with false values, for QR code date flagging
221 *
222 * @param $event
223 * @return array
224 */
225 private function qrCodeDateFlag($event): array
226 {
227 $dates = [];
228 /** @var EventPeriod $p */
229 foreach ($event->getPeriods()->getItems() as $p) {
230 $start = (clone $p->getPeriodStart()->getValue())->setTime(0, 0, 0);
231 $end = (clone $p->getPeriodEnd()->getValue())->setTime(0, 0, 0);
232 while ($start <= $end) {
233 $dates[$start->format('Y-m-d')] = false;
234 $start->modify('+1 day');
235 }
236 }
237
238 return $dates;
239 }
240
241 /**
242 * Generate a short manual code from data array
243 *
244 * @param array $data
245 * @return string
246 */
247 private function generateManualCode($data): string
248 {
249 $raw = hash('sha256', json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), true);
250 $b64 = rtrim(strtr(base64_encode($raw), '+/', 'AZ'), '=');
251
252 return substr($b64, 0, 10);
253 }
254 }
255