PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.0.2
Booking for Appointments and Events Calendar – Amelia v2.0.2
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 8 months ago QrCodeApplicationService.php 6 months ago StarterQrCodeApplicationService.php 8 months ago
QrCodeApplicationService.php
259 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'] = !empty($eventTranslations['name'][$locale])
53 ? $eventTranslations['name'][$locale]
54 : $eventData['name'];
55 $qrData['eventStartDateTime'] = $eventData['periods'][0]['periodStart'];
56
57 if (
58 $qrData['type'] === 'ticket' &&
59 array_key_exists('eventTicketId', $qrData) &&
60 isset($booking['ticketsData'])
61 ) {
62 foreach ($eventData['customTickets'] as $ticket) {
63 if ($ticket['id'] === $qrData['eventTicketId']) {
64 $ticketTranslations = $ticket['translations'] ? json_decode($ticket['translations'], true) : null;
65 $ticketName = !empty($ticketTranslations[$locale])
66 ? $ticketTranslations[$locale]
67 : $ticket['name'];
68 $qrData['eventTicketName'] = $ticketName;
69 break;
70 }
71 }
72 }
73
74 if (isset($eventData['customLocation']) && $eventData['customLocation']) {
75 $qrData['eventLocation'] = $eventData['customLocation'];
76 }
77 if (isset($eventData['location'])) {
78 $qrData['eventLocation'] = $eventData['location'];
79 }
80 if (isset($eventData['locationId'])) {
81 /** @var LocationRepository $locationRepository */
82 $locationRepository = $this->container->get('domain.locations.repository');
83 $location = $locationRepository->getById($eventData['locationId']);
84 if ($location) {
85 $locationTranslations = $location->getTranslations() ? json_decode($location->getTranslations()->getValue(), true) : null;
86 $locTranslation = $locationTranslations['name'][$locale] ?? $location->getName()->getValue();
87 $qrData['eventLocation'] = $location->getAddress()->getValue() ?: $locTranslation;
88 }
89 }
90 if ($ticketCode) {
91 return $qrService->generateQrCode($qrData);
92 }
93 $qrCodeItems[] = $qrService->generateQrCode($qrData);
94 }
95 }
96 }
97 }
98
99 return $qrCodeItems;
100 }
101
102 /**
103 * Create QR code data array for a booking and event
104 *
105 * @param $event
106 * @param $booking
107 * @return array
108 * @throws InvalidArgumentException
109 * @throws ContainerException
110 * @throws NotFoundException
111 * @throws QueryExecutionException
112 */
113 public function createQrCodeEventData($event, $booking): array
114 {
115 $qrCodes = [];
116 $qrNumberData = $this->getNumberOfQrCodes($booking, $event);
117
118 if ($qrNumberData['number'] > 0 && $event->getId()) {
119 // Common timestamp for generation moment (UTC ISO8601)
120 $generatedAt = DateTimeService::getNowDateTimeObjectInUtc()->format('Y-m-d H:i:s');
121
122 $bookingIdVal = $booking->getId()->getValue();
123 $eventIdVal = $event->getId()->getValue();
124 $customerIdVal = $booking->getCustomerId() ? $booking->getCustomerId()->getValue() : '';
125
126 // Booking-level
127 if ($qrNumberData['number'] > 1) {
128 $bookingManualCode = $this->generateManualCode([
129 'bookingId' => $bookingIdVal,
130 'eventId' => $eventIdVal,
131 'customerId' => $customerIdVal,
132 'generatedAt' => $generatedAt,
133 ]);
134
135 $bookingQrData = 'type: booking | bookingId:' . $bookingIdVal . ' | ticketManualCode:' . $bookingManualCode;
136
137 $qrCodes[] = array_merge([
138 'type' => 'booking',
139 'eventName' => $event->getName() ? $event->getName()->getValue() : '',
140 'ticketManualCode' => $bookingManualCode,
141 'qrCodeData' => $bookingQrData,
142 'generatedAt' => $generatedAt,
143 ], ['dates' => $this->qrCodeDateFlag($event)]);
144 }
145
146 // Person / ticket level
147 for ($i = 1; $i <= $qrNumberData['number']; $i++) {
148 $ticketIdForPerson = $qrNumberData['ticketIds'][$i - 1] ?? null;
149 $codePayload = [
150 'bookingId' => $bookingIdVal,
151 'eventId' => $eventIdVal,
152 'customerId' => $customerIdVal,
153 'ticketIndex' => $i,
154 'generatedAt' => $generatedAt,
155 ];
156
157 if ($ticketIdForPerson) {
158 $codePayload['ticketId'] = $ticketIdForPerson;
159 }
160
161 $manualTicketCode = $this->generateManualCode($codePayload);
162
163 $ticketQrData = 'type: ticket | bookingId:' . $bookingIdVal . ' ticketManualCode:' . $manualTicketCode;
164
165 $entry = [
166 'type' => 'ticket',
167 'eventName' => $event->getName() ? $event->getName()->getValue() : '',
168 'ticketManualCode' => $manualTicketCode,
169 'qrCodeData' => $ticketQrData,
170 'generatedAt' => $generatedAt,
171 ];
172
173 if ($ticketIdForPerson) {
174 /** @var EventTicketRepository $eventTicketRepository */
175 $eventTicketRepository = $this->container->get('domain.booking.event.ticket.repository');
176 $ticket = $eventTicketRepository->getById($ticketIdForPerson);
177 $entry['eventTicketId'] = $ticketIdForPerson;
178 if ($ticket && $ticket->getName()) {
179 $entry['eventTicketName'] = $ticket->getName()->getValue();
180 }
181 }
182
183 $qrCodes[] = array_merge($entry, ['dates' => $this->qrCodeDateFlag($event)]);
184 }
185 }
186
187 return $qrCodes;
188 }
189
190 /**
191 * Determine number of QR codes to generate for a booking, and build a sequence of ticket ids if applicable
192 *
193 * @param $booking
194 * @param $event
195 * @return array ['number' => int, 'ticketIds' => array|null]
196 */
197 private function getNumberOfQrCodes($booking, $event): array
198 {
199 $personsForQr = 0;
200 $ticketIdSequence = [];
201 if ($booking->getTicketsBooking() && $event->getCustomPricing()->getValue()) {
202 /** @var CustomerBookingEventTicket $ticketBooking */
203 foreach ($booking->getTicketsBooking()->getItems() as $ticketBooking) {
204 $ticketPersons = ($ticketBooking->getPersons() ? $ticketBooking->getPersons()->getValue() : 0);
205 $personsForQr += $ticketPersons;
206 // Build a flat sequence of ticket ids, one per person, to map each QR to a ticket
207 if ($ticketPersons && $ticketBooking->getEventTicketId()) {
208 for ($ti = 0; $ti < $ticketPersons; $ti++) {
209 $ticketIdSequence[] = $ticketBooking->getEventTicketId()->getValue();
210 }
211 }
212 }
213 } else {
214 $personsForQr = $booking->getPersons() ? $booking->getPersons()->getValue() : 0;
215 }
216
217 $qrCodesNumberData['number'] = $personsForQr;
218 $qrCodesNumberData['ticketIds'] = $ticketIdSequence ?: null;
219
220 return $qrCodesNumberData;
221 }
222
223 /**
224 * Create an array of event dates (Y-m-d) as keys, with false values, for QR code date flagging
225 *
226 * @param $event
227 * @return array
228 */
229 private function qrCodeDateFlag($event): array
230 {
231 $dates = [];
232 /** @var EventPeriod $p */
233 foreach ($event->getPeriods()->getItems() as $p) {
234 $start = (clone $p->getPeriodStart()->getValue())->setTime(0, 0, 0);
235 $end = (clone $p->getPeriodEnd()->getValue())->setTime(0, 0, 0);
236 while ($start <= $end) {
237 $dates[$start->format('Y-m-d')] = false;
238 $start->modify('+1 day');
239 }
240 }
241
242 return $dates;
243 }
244
245 /**
246 * Generate a short manual code from data array
247 *
248 * @param array $data
249 * @return string
250 */
251 private function generateManualCode($data): string
252 {
253 $raw = hash('sha256', json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), true);
254 $b64 = rtrim(strtr(base64_encode($raw), '+/', 'AZ'), '=');
255
256 return substr($b64, 0, 10);
257 }
258 }
259