PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / trunk
Booking for Appointments and Events Calendar – Amelia vtrunk
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 / Infrastructure / Repository / Payment / PaymentRepository.php
ameliabooking / src / Infrastructure / Repository / Payment Last commit date
PaymentRepository.php 2 weeks ago
PaymentRepository.php
1534 lines
1 <?php
2
3 /**
4 * @copyright © Melograno Ventures. All rights reserved.
5 * @licence See LICENCE.md for license details.
6 */
7
8 namespace AmeliaBooking\Infrastructure\Repository\Payment;
9
10 use AmeliaBooking\Domain\Collection\Collection;
11 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
12 use AmeliaBooking\Domain\Entity\Payment\Payment;
13 use AmeliaBooking\Domain\Factory\Payment\PaymentFactory;
14 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
15 use AmeliaBooking\Infrastructure\Repository\AbstractRepository;
16 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
17 use AmeliaBooking\Infrastructure\Connection;
18 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Bookable\PackagesCustomersServicesTable;
19 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\CustomerBookingsToExtrasTable;
20 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Coupon\CouponsTable;
21 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Location\LocationsTable;
22
23 /**
24 * Class PaymentRepository
25 *
26 * @package AmeliaBooking\Infrastructure\Repository\Payment
27 */
28 class PaymentRepository extends AbstractRepository
29 {
30 /** @var string */
31 protected $appointmentsTable;
32
33 /** @var string */
34 protected $bookingsTable;
35
36 /** @var string */
37 protected $servicesTable;
38
39 /** @var string */
40 protected $usersTable;
41
42 /** @var string */
43 protected $eventsTable;
44
45 /** @var string */
46 protected $eventsProvidersTable;
47
48 /** @var string */
49 protected $eventsPeriodsTable;
50
51 /** @var string */
52 protected $customerBookingsToEventsPeriodsTable;
53
54 /** @var string */
55 protected $packagesTable;
56
57 /** @var string */
58 protected $packagesCustomersTable;
59
60 /** @var string */
61 protected $packagesCustomersServiceTable;
62
63
64 /**
65 * @param Connection $connection
66 * @param string $table
67 * @param string $appointmentsTable
68 * @param string $bookingsTable
69 * @param string $servicesTable
70 * @param string $usersTable
71 * @param string $eventsTable
72 * @param string $eventsProvidersTable
73 * @param string $eventsPeriodsTable
74 * @param string $customerBookingsToEventsPeriodsTable
75 * @param string $packagesTable
76 * @param string $packagesCustomersTable
77 */
78 public function __construct(
79 Connection $connection,
80 $table,
81 $appointmentsTable,
82 $bookingsTable,
83 $servicesTable,
84 $usersTable,
85 $eventsTable,
86 $eventsProvidersTable,
87 $eventsPeriodsTable,
88 $customerBookingsToEventsPeriodsTable,
89 $packagesTable,
90 $packagesCustomersTable
91 ) {
92 parent::__construct($connection, $table);
93
94 $this->appointmentsTable = $appointmentsTable;
95 $this->bookingsTable = $bookingsTable;
96 $this->servicesTable = $servicesTable;
97 $this->usersTable = $usersTable;
98 $this->eventsTable = $eventsTable;
99 $this->eventsProvidersTable = $eventsProvidersTable;
100 $this->eventsPeriodsTable = $eventsPeriodsTable;
101 $this->customerBookingsToEventsPeriodsTable = $customerBookingsToEventsPeriodsTable;
102 $this->packagesTable = $packagesTable;
103 $this->packagesCustomersTable = $packagesCustomersTable;
104 $this->packagesCustomersServiceTable = PackagesCustomersServicesTable::getTableName();
105 }
106
107 public const FACTORY = PaymentFactory::class;
108
109 /**
110 * @param Payment $entity
111 *
112 * @return int
113 * @throws QueryExecutionException
114 */
115 public function add($entity)
116 {
117 $data = $entity->toArray();
118
119 $params = [
120 ':customerBookingId' => $data['customerBookingId'] ? $data['customerBookingId'] : null,
121 ':packageCustomerId' => $data['packageCustomerId'] ? $data['packageCustomerId'] : null,
122 ':parentId' => $data['parentId'] ? $data['parentId'] : null,
123 ':amount' => $data['amount'],
124 ':dateTime' => DateTimeService::getCustomDateTimeInUtc($data['dateTime']),
125 ':status' => $data['status'],
126 ':gateway' => $data['gateway'],
127 ':gatewayTitle' => $data['gatewayTitle'],
128 ':data' => $data['data'],
129 ':entity' => $data['entity'],
130 ':created' => DateTimeService::getNowDateTimeInUtc(),
131 ':wcOrderId' => !empty($data['wcOrderId']) ? $data['wcOrderId'] : null,
132 ':transactionId' => !empty($data['transactionId']) ? $data['transactionId'] : null,
133 ':wcOrderItemId' => !empty($data['wcOrderItemId']) ? $data['wcOrderItemId'] : null,
134 ];
135
136 if (!empty($data['invoiceNumber'])) {
137 $params[':invoiceNumber'] = $data['invoiceNumber'];
138
139 $invoiceNumberText = ":invoiceNumber";
140 } else {
141 $invoiceNumberText = "(SELECT COALESCE(MAX(invoiceNumber), 0) + 1 FROM {$this->table} p)";
142 }
143
144 if ($data['parentId']) {
145 $params[':actionsCompleted'] = null;
146 } else {
147 $params[':actionsCompleted'] = !empty($data['actionsCompleted']) ? 1 : 0;
148 }
149
150 try {
151 $statement = $this->connection->prepare(
152 "INSERT INTO
153 {$this->table}
154 (
155 `customerBookingId`,
156 `packageCustomerId`,
157 `parentId`,
158 `amount`,
159 `dateTime`,
160 `status`,
161 `gateway`,
162 `gatewayTitle`,
163 `data`, `entity`,
164 `actionsCompleted`,
165 `created`,
166 `wcOrderId`,
167 `wcOrderItemId`,
168 `transactionId`,
169 `invoiceNumber`
170 ) VALUES (
171 :customerBookingId,
172 :packageCustomerId,
173 :parentId,
174 :amount,
175 :dateTime,
176 :status,
177 :gateway,
178 :gatewayTitle,
179 :data,
180 :entity,
181 :actionsCompleted,
182 :created,
183 :wcOrderId,
184 :wcOrderItemId,
185 :transactionId,
186 {$invoiceNumberText}
187 )"
188 );
189
190 $statement->execute($params);
191 } catch (\Exception $e) {
192 throw new QueryExecutionException('Unable to add data in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
193 }
194
195 return $this->connection->lastInsertId();
196 }
197
198 /**
199 * @param int $id
200 * @param Payment $entity
201 *
202 * @return bool
203 * @throws QueryExecutionException
204 */
205 public function update($id, $entity)
206 {
207 $data = $entity->toArray();
208
209 $params = [
210 ':customerBookingId' => $data['customerBookingId'] ? $data['customerBookingId'] : null,
211 ':packageCustomerId' => $data['packageCustomerId'] ? $data['packageCustomerId'] : null,
212 ':parentId' => $data['parentId'] ? $data['parentId'] : null,
213 ':amount' => $data['amount'],
214 ':dateTime' => DateTimeService::getCustomDateTimeInUtc($data['dateTime']),
215 ':status' => $data['status'],
216 ':gateway' => $data['gateway'],
217 ':gatewayTitle' => $data['gatewayTitle'],
218 ':data' => $data['data'],
219 ':transactionId' => $data['transactionId'],
220 ':id' => $id,
221 ];
222
223 try {
224 $statement = $this->connection->prepare(
225 "UPDATE {$this->table}
226 SET
227 `customerBookingId` = :customerBookingId,
228 `packageCustomerId` = :packageCustomerId,
229 `parentId` = :parentId,
230 `amount` = :amount,
231 `dateTime` = :dateTime,
232 `status` = :status,
233 `gateway` = :gateway,
234 `gatewayTitle` = :gatewayTitle,
235 `data` = :data,
236 `transactionId` = :transactionId
237 WHERE
238 id = :id"
239 );
240
241 $statement->execute($params);
242 } catch (\Exception $e) {
243 throw new QueryExecutionException('Unable to save data in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
244 }
245
246 return true;
247 }
248
249 /**
250 * @param array $criteria
251 *
252 * @return Collection
253 * @throws QueryExecutionException
254 */
255 public function getByCriteria($criteria)
256 {
257 $result = new Collection();
258
259 $params = [];
260
261 $where = [];
262
263 if (!empty($criteria['bookingIds'])) {
264 $queryBookings = [];
265
266 foreach ($criteria['bookingIds'] as $index => $value) {
267 $param = ':id' . $index;
268
269 $queryBookings[] = $param;
270
271 $params[$param] = $value;
272 }
273
274 $where[] = 'customerBookingId IN (' . implode(', ', $queryBookings) . ')';
275 }
276
277
278 if (!empty($criteria['packageCustomerId'])) {
279 $params[':packageCustomerId'] = $criteria['packageCustomerId'];
280 $where[] = 'packageCustomerId = :packageCustomerId';
281 }
282
283 if (!empty($criteria['ids'])) {
284 $queryIds = [];
285
286 foreach ($criteria['ids'] as $index => $value) {
287 $param = ':id' . $index;
288
289 $queryIds[] = $param;
290
291 $params[$param] = $value;
292 }
293
294 $where[] = 'id IN (' . implode(', ', $queryIds) . ')';
295 }
296
297 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
298
299 try {
300 $statement = $this->connection->prepare(
301 "SELECT
302 id AS id,
303 customerBookingId AS customerBookingId,
304 packageCustomerId AS packageCustomerId,
305 parentId AS parentId,
306 invoiceNumber AS invoiceNumber,
307 amount AS amount,
308 dateTime AS dateTime,
309 status AS status,
310 gateway AS gateway,
311 gatewayTitle AS gatewayTitle,
312 data AS data
313 FROM {$this->table}
314 {$where}"
315 );
316
317 $statement->execute($params);
318
319 while ($row = $statement->fetch()) {
320 $result->addItem(call_user_func([static::FACTORY, 'create'], $row), $row['id']);
321 }
322 } catch (\Exception $e) {
323 throw new QueryExecutionException('Unable to find by id in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
324 }
325
326 return $result;
327 }
328
329 /**
330 * @param array $criteria
331 * @param int $itemsPerPage
332 * @param boolean $invoice
333 *
334 * @return array
335 * @throws QueryExecutionException
336 */
337 public function getFilteredIds($criteria, $itemsPerPage = null, $invoice = false)
338 {
339 $params = [];
340 $appointmentParams1 = [];
341 $appointmentParams2 = [];
342 $eventParams = [];
343 $whereAppointment1 = [];
344 $whereAppointment2 = [];
345 $whereEvent = [];
346
347 if ($invoice) {
348 $whereAppointment1[] = 'p.parentId IS NULL';
349 $whereAppointment2[] = 'p.parentId IS NULL';
350 $whereEvent[] = 'p.parentId IS NULL';
351 }
352
353 $basedOnDate = 'created';
354
355 if (!empty($criteria['ids'])) {
356 $queryIds1 = [];
357 $queryIds2 = [];
358 $queryIds3 = [];
359
360 foreach ($criteria['ids'] as $index => $value) {
361 $param1 = ':id0' . $index;
362 $param2 = ':id1' . $index;
363 $param3 = ':id2' . $index;
364 $queryIds1[] = $param1;
365 $queryIds2[] = $param2;
366 $queryIds3[] = $param3;
367 $appointmentParams1[$param1] = $value;
368 $appointmentParams2[$param2] = $value;
369 $eventParams[$param3] = $value;
370 }
371
372 $whereAppointment1[] = 'p.id IN (' . implode(', ', $queryIds1) . ')';
373 $whereAppointment2[] = 'p.id IN (' . implode(', ', $queryIds2) . ')';
374 $whereEvent[] = 'p.id IN (' . implode(', ', $queryIds3) . ')';
375 }
376
377 if (!empty($criteria['dates'])) {
378 $whereAppointment1[] = "(p.{$basedOnDate} BETWEEN :paymentAppointmentFrom1 AND :paymentAppointmentTo1)";
379 $whereAppointment2[] = "(p.{$basedOnDate} BETWEEN :paymentAppointmentFrom2 AND :paymentAppointmentTo2)";
380 $appointmentParams1[':paymentAppointmentFrom1'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][0]);
381 $appointmentParams2[':paymentAppointmentFrom2'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][0]);
382 $appointmentParams1[':paymentAppointmentTo1'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][1]);
383 $appointmentParams2[':paymentAppointmentTo2'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][1]);
384
385 $whereEvent[] = "(p.{$basedOnDate} BETWEEN :paymentEventFrom AND :paymentEventTo)";
386 $eventParams[':paymentEventFrom'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][0]);
387 $eventParams[':paymentEventTo'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][1]);
388 }
389
390 if (!empty($criteria['customerId'])) {
391 $criteria['customers'][] = $criteria['customerId'];
392 }
393
394 if (!empty($criteria['customers'])) {
395 $queryCustomers1 = [];
396 $queryCustomers2 = [];
397 $queryCustomers3 = [];
398
399 foreach ((array)$criteria['customers'] as $index => $value) {
400 $param1 = ':customer0' . $index;
401 $param2 = ':customer1' . $index;
402 $param3 = ':customer2' . $index;
403 $queryCustomers1[] = $param1;
404 $queryCustomers2[] = $param2;
405 $queryCustomers3[] = $param3;
406 $appointmentParams1[$param1] = $value;
407 $appointmentParams2[$param2] = $value;
408 $eventParams[$param3] = $value;
409 }
410
411 $whereAppointment1[] = 'cb.customerId IN (' . implode(', ', $queryCustomers1) . ')';
412 $whereAppointment2[] = 'pc.customerId IN (' . implode(', ', $queryCustomers2) . ')';
413 $whereEvent[] = 'cb.customerId IN (' . implode(', ', $queryCustomers3) . ')';
414 }
415
416 $eventsProvidersJoin = '';
417
418 if (!empty($criteria['providerId'])) {
419 $criteria['providers'][] = $criteria['providerId'];
420 }
421
422 if (!empty($criteria['providers'])) {
423 $queryProviders1 = [];
424 $queryProviders2 = [];
425 $queryProviders3 = [];
426
427 foreach ((array)$criteria['providers'] as $index => $value) {
428 $param1 = ':provider0' . $index;
429 $param2 = ':provider1' . $index;
430 $param3 = ':provider2' . $index;
431 $queryProviders1[] = $param1;
432 $queryProviders2[] = $param2;
433 $queryProviders3[] = $param3;
434 $appointmentParams1[$param1] = $value;
435 $appointmentParams2[$param2] = $value;
436 $eventParams[$param3] = $value;
437 }
438
439 $whereAppointment1[] = 'a.providerId IN (' . implode(', ', $queryProviders1) . ')';
440 $whereAppointment2[] = 'a.providerId IN (' . implode(', ', $queryProviders2) . ')';
441 $whereEvent[] = 'epu.userId IN (' . implode(', ', $queryProviders3) . ')';
442
443 $eventsProvidersJoin = "
444 INNER JOIN {$this->eventsPeriodsTable} ep ON ep.id = cbe.eventPeriodId
445 INNER JOIN {$this->eventsProvidersTable} epu ON epu.eventId = ep.eventId
446 ";
447 }
448
449 if (!empty($criteria['services'])) {
450 $queryServices1 = [];
451 $queryServices2 = [];
452
453 foreach ((array)$criteria['services'] as $index => $value) {
454 $param1 = ':service0' . $index;
455 $param2 = ':service1' . $index;
456 $queryServices1[] = $param1;
457 $queryServices2[] = $param2;
458 $appointmentParams1[$param1] = $value;
459 $appointmentParams2[$param2] = $value;
460 }
461
462 $whereAppointment1[] = 'a.serviceId IN (' . implode(', ', $queryServices1) . ')';
463 $whereAppointment2[] = 'a.serviceId IN (' . implode(', ', $queryServices2) . ')';
464 }
465
466 $appointments2ProvidersServicesJoin = '';
467
468 if (!empty($criteria['providers']) || !empty($criteria['services'])) {
469 $appointments2ProvidersServicesJoin = "
470 INNER JOIN {$this->packagesCustomersServiceTable} pcs ON pc.id = pcs.packageCustomerId
471 INNER JOIN {$this->bookingsTable} cb ON cb.packageCustomerServiceId = pcs.id
472 INNER JOIN {$this->appointmentsTable} a ON a.id = cb.appointmentId
473 ";
474 }
475
476 if (!empty($criteria['status'])) {
477 $criteria['statuses'][] = $criteria['status'];
478 }
479
480 if (!empty($criteria['statuses'])) {
481 $queryStatuses1 = [];
482 $queryStatuses2 = [];
483 $queryStatuses3 = [];
484
485 foreach ($criteria['statuses'] as $index => $value) {
486 $param1 = ':status0' . $index;
487 $param2 = ':status1' . $index;
488 $param3 = ':status2' . $index;
489 $queryStatuses1[] = $param1;
490 $queryStatuses2[] = $param2;
491 $queryStatuses3[] = $param3;
492 $appointmentParams1[$param1] = $value;
493 $appointmentParams2[$param2] = $value;
494 $eventParams[$param3] = $value;
495 }
496
497 $whereAppointment1[] = 'p.status IN (' . implode(', ', $queryStatuses1) . ')';
498 $whereAppointment2[] = 'p.status IN (' . implode(', ', $queryStatuses2) . ')';
499 $whereEvent[] = 'p.status IN (' . implode(', ', $queryStatuses3) . ')';
500 }
501
502 if (!empty($criteria['packages'])) {
503 $queryPackages = [];
504
505 foreach ((array)$criteria['packages'] as $index => $value) {
506 $param = ':package' . $index;
507 $queryPackages[] = $param;
508 $appointmentParams2[$param] = $value;
509 }
510
511 $whereAppointment2[] = "p.packageCustomerId IN (SELECT pc.id
512 FROM {$this->packagesCustomersTable} pc
513 WHERE pc.packageId IN (" . implode(', ', $queryPackages) . '))';
514 }
515
516 if (!empty($criteria['events'])) {
517 $queryEvents = [];
518
519 foreach ((array)$criteria['events'] as $index => $value) {
520 $param = ':event' . $index;
521 $queryEvents[] = $param;
522 $eventParams[$param] = $value;
523 }
524
525 $whereEvent[] = "p.customerBookingId IN (SELECT cbe.customerBookingId
526 FROM {$this->eventsTable} e
527 INNER JOIN {$this->eventsPeriodsTable} ep ON ep.eventId = e.id
528 INNER JOIN {$this->customerBookingsToEventsPeriodsTable} cbe ON cbe.eventPeriodId = ep.id
529 WHERE e.id IN (" . implode(', ', $queryEvents) . '))';
530 }
531
532 $whereAppointment1 = $whereAppointment1 ? ' AND ' . implode(' AND ', $whereAppointment1) : '';
533 $whereAppointment2 = $whereAppointment2 ? ' AND ' . implode(' AND ', $whereAppointment2) : '';
534 $whereEvent = $whereEvent ? ' AND ' . implode(' AND ', $whereEvent) : '';
535
536 $groupBy = '';
537 $groupByAppointment1Clause = empty($criteria['separateRows']) ? "GROUP BY p.customerBookingId" : "";
538 $groupByAppointment2Clause = empty($criteria['separateRows']) ? "GROUP BY p.packageCustomerId" : "";
539 $groupByEventClause = empty($criteria['separateRows']) ? "GROUP BY p.customerBookingId" : "";
540 if ($invoice) {
541 $groupBy = 'GROUP BY IFNULL(invoiceNumber, id)';
542 $groupByAppointment1Clause = '';
543 $groupByAppointment2Clause = '';
544 $groupByEventClause = '';
545 }
546
547 $appointmentQuery1 = "SELECT
548 p.id AS id,
549 p.dateTime AS dateTime,
550 p.created AS created,
551 p.status AS status,
552 p.amount AS amount,
553 p.invoiceNumber AS invoiceNumber,
554 'appointment' AS type
555 FROM {$this->table} p
556 INNER JOIN {$this->bookingsTable} cb ON cb.id = p.customerBookingId
557 INNER JOIN {$this->appointmentsTable} a ON a.id = cb.appointmentId
558 WHERE 1=1 {$whereAppointment1} {$groupByAppointment1Clause} ORDER BY p.id ASC";
559
560 $appointmentQuery2 = "SELECT
561 p.id AS id,
562 p.dateTime AS dateTime,
563 p.created AS created,
564 p.status AS status,
565 p.amount AS amount,
566 p.invoiceNumber AS invoiceNumber,
567 'package' AS type
568 FROM {$this->table} p
569 INNER JOIN {$this->packagesCustomersTable} pc ON p.packageCustomerId = pc.id
570 {$appointments2ProvidersServicesJoin}
571 WHERE 1=1 {$whereAppointment2} {$groupByAppointment2Clause} ORDER BY p.id ASC";
572
573 $eventQuery = "SELECT
574 p.id AS id,
575 p.dateTime AS dateTime,
576 p.created AS created,
577 p.status AS status,
578 p.amount AS amount,
579 p.invoiceNumber AS invoiceNumber,
580 'event' AS type
581 FROM {$this->table} p
582 INNER JOIN {$this->bookingsTable} cb ON cb.id = p.customerBookingId
583 INNER JOIN {$this->customerBookingsToEventsPeriodsTable} cbe ON cbe.customerBookingId = cb.id
584 {$eventsProvidersJoin}
585 WHERE 1=1 {$whereEvent} {$groupByEventClause} ORDER BY p.id ASC";
586
587 $result = [];
588
589 if (isset($criteria['events'], $criteria['services'])) {
590 return $result;
591 } elseif (isset($criteria['services'])) {
592 $paymentQuery = "({$appointmentQuery1}) UNION ALL ({$appointmentQuery2})";
593 $params = array_merge($params, $appointmentParams1, $appointmentParams2);
594 } elseif (isset($criteria['events'])) {
595 $paymentQuery = "({$eventQuery})";
596 $params = array_merge($params, $eventParams);
597 } elseif (isset($criteria['packages'])) {
598 $paymentQuery = "({$appointmentQuery2})";
599 $params = array_merge($params, $appointmentParams2);
600 } else {
601 $paymentQuery = "({$appointmentQuery1}) UNION ALL ({$appointmentQuery2}) UNION ALL ({$eventQuery})";
602 $params = array_merge($params, $appointmentParams1, $appointmentParams2, $eventParams);
603 }
604
605 $limit = $this->getLimit(
606 !empty($criteria['page']) ? (int)$criteria['page'] : 0,
607 $itemsPerPage ?: (!empty($criteria['limit']) ? (int)$criteria['limit'] : 0)
608 );
609
610 $bookingTypeCondition = '';
611 if (!empty($criteria['bookingTypes'])) {
612 $bookingTypeCondition = 'WHERE type IN ("' . implode('", "', $criteria['bookingTypes']) . '")';
613 }
614
615 try {
616 $order = "ORDER BY id, {$basedOnDate}";
617 if (!empty($criteria['sort'])) {
618 $order = "ORDER BY {$criteria['sort']['field']} {$criteria['sort']['order']}";
619 }
620
621 $statement = $this->connection->prepare(
622 "SELECT * FROM ({$paymentQuery}) payments
623 {$bookingTypeCondition}
624 {$groupBy}
625 {$order}
626 {$limit}"
627 );
628
629 $statement->execute($params);
630
631 $rows = $statement->fetchAll();
632 } catch (\Exception $e) {
633 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
634 }
635
636 foreach ($rows as $row) {
637 $result[(int)$row['id']] = $row['type'];
638 }
639
640 return $result;
641 }
642
643 /**
644 * @param array $criteria
645 * @param boolean $invoice
646 *
647 * @return int
648 * @throws QueryExecutionException
649 */
650 public function getFilteredIdsCount($criteria, $invoice = false)
651 {
652 $params = [];
653 $appointmentParams1 = [];
654 $appointmentParams2 = [];
655 $eventParams = [];
656 $whereAppointment1 = [];
657 $whereAppointment2 = [];
658 $whereEvent = [];
659
660 if ($invoice) {
661 $whereAppointment1[] = 'p.parentId IS NULL';
662 $whereAppointment2[] = 'p.parentId IS NULL';
663 $whereEvent[] = 'p.parentId IS NULL';
664 }
665
666 $basedOnDate = 'created';
667
668 if (!empty($criteria['ids'])) {
669 $queryIds1 = [];
670 $queryIds2 = [];
671 $queryIds3 = [];
672
673 foreach ($criteria['ids'] as $index => $value) {
674 $param1 = ':id0' . $index;
675 $param2 = ':id1' . $index;
676 $param3 = ':id2' . $index;
677 $queryIds1[] = $param1;
678 $queryIds2[] = $param2;
679 $queryIds3[] = $param3;
680 $appointmentParams1[$param1] = $value;
681 $appointmentParams2[$param2] = $value;
682 $eventParams[$param3] = $value;
683 }
684
685 $whereAppointment1[] = 'p.id IN (' . implode(', ', $queryIds1) . ')';
686 $whereAppointment2[] = 'p.id IN (' . implode(', ', $queryIds2) . ')';
687 $whereEvent[] = 'p.id IN (' . implode(', ', $queryIds3) . ')';
688 }
689
690 if (!empty($criteria['dates'])) {
691 $whereAppointment1[] = "(p.{$basedOnDate} BETWEEN :paymentAppointmentFrom1 AND :paymentAppointmentTo1)";
692 $whereAppointment2[] = "(p.{$basedOnDate} BETWEEN :paymentAppointmentFrom2 AND :paymentAppointmentTo2)";
693 $appointmentParams1[':paymentAppointmentFrom1'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][0]);
694 $appointmentParams2[':paymentAppointmentFrom2'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][0]);
695 $appointmentParams1[':paymentAppointmentTo1'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][1]);
696 $appointmentParams2[':paymentAppointmentTo2'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][1]);
697
698 $whereEvent[] = "(p.{$basedOnDate} BETWEEN :paymentEventFrom AND :paymentEventTo)";
699 $eventParams[':paymentEventFrom'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][0]);
700 $eventParams[':paymentEventTo'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][1]);
701 }
702
703 if (!empty($criteria['customerId'])) {
704 $criteria['customers'][] = $criteria['customerId'];
705 }
706
707 if (!empty($criteria['customers'])) {
708 $queryCustomers1 = [];
709 $queryCustomers2 = [];
710 $queryCustomers3 = [];
711
712 foreach ((array)$criteria['customers'] as $index => $value) {
713 $param1 = ':customer0' . $index;
714 $param2 = ':customer1' . $index;
715 $param3 = ':customer2' . $index;
716 $queryCustomers1[] = $param1;
717 $queryCustomers2[] = $param2;
718 $queryCustomers3[] = $param3;
719 $appointmentParams1[$param1] = $value;
720 $appointmentParams2[$param2] = $value;
721 $eventParams[$param3] = $value;
722 }
723
724 $whereAppointment1[] = 'cb.customerId IN (' . implode(', ', $queryCustomers1) . ')';
725 $whereAppointment2[] = 'pc.customerId IN (' . implode(', ', $queryCustomers2) . ')';
726 $whereEvent[] = 'cb.customerId IN (' . implode(', ', $queryCustomers3) . ')';
727 }
728
729 $eventsProvidersJoin = '';
730
731 if (!empty($criteria['providerId'])) {
732 $criteria['providers'][] = $criteria['providerId'];
733 }
734
735 if (!empty($criteria['providers'])) {
736 $queryProviders1 = [];
737 $queryProviders2 = [];
738 $queryProviders3 = [];
739
740 foreach ((array)$criteria['providers'] as $index => $value) {
741 $param1 = ':provider0' . $index;
742 $param2 = ':provider1' . $index;
743 $param3 = ':provider2' . $index;
744 $queryProviders1[] = $param1;
745 $queryProviders2[] = $param2;
746 $queryProviders3[] = $param3;
747 $appointmentParams1[$param1] = $value;
748 $appointmentParams2[$param2] = $value;
749 $eventParams[$param3] = $value;
750 }
751
752 $whereAppointment1[] = 'a.providerId IN (' . implode(', ', $queryProviders1) . ')';
753 $whereAppointment2[] = 'a.providerId IN (' . implode(', ', $queryProviders2) . ')';
754 $whereEvent[] = 'epu.userId IN (' . implode(', ', $queryProviders3) . ')';
755
756 $eventsProvidersJoin = "
757 INNER JOIN {$this->eventsPeriodsTable} ep ON ep.id = cbe.eventPeriodId
758 INNER JOIN {$this->eventsProvidersTable} epu ON epu.eventId = ep.eventId
759 ";
760 }
761
762 if (!empty($criteria['services'])) {
763 $queryServices1 = [];
764 $queryServices2 = [];
765
766 foreach ((array)$criteria['services'] as $index => $value) {
767 $param1 = ':service0' . $index;
768 $param2 = ':service1' . $index;
769 $queryServices1[] = $param1;
770 $queryServices2[] = $param2;
771 $appointmentParams1[$param1] = $value;
772 $appointmentParams2[$param2] = $value;
773 }
774
775 $whereAppointment1[] = 'a.serviceId IN (' . implode(', ', $queryServices1) . ')';
776 $whereAppointment2[] = 'a.serviceId IN (' . implode(', ', $queryServices2) . ')';
777 }
778
779 $appointments2ProvidersServicesJoin = '';
780
781 if (!empty($criteria['providers']) || !empty($criteria['services'])) {
782 $appointments2ProvidersServicesJoin = "
783 INNER JOIN {$this->packagesCustomersServiceTable} pcs ON pc.id = pcs.packageCustomerId
784 INNER JOIN {$this->bookingsTable} cb ON cb.packageCustomerServiceId = pcs.id
785 INNER JOIN {$this->appointmentsTable} a ON a.id = cb.appointmentId
786 ";
787 }
788
789 if (!empty($criteria['status'])) {
790 $criteria['statuses'][] = $criteria['status'];
791 }
792
793 if (!empty($criteria['statuses'])) {
794 $queryStatuses1 = [];
795 $queryStatuses2 = [];
796 $queryStatuses3 = [];
797
798 foreach ($criteria['statuses'] as $index => $value) {
799 $param1 = ':status0' . $index;
800 $param2 = ':status1' . $index;
801 $param3 = ':status2' . $index;
802 $queryStatuses1[] = $param1;
803 $queryStatuses2[] = $param2;
804 $queryStatuses3[] = $param3;
805 $appointmentParams1[$param1] = $value;
806 $appointmentParams2[$param2] = $value;
807 $eventParams[$param3] = $value;
808 }
809
810 $whereAppointment1[] = 'p.status IN (' . implode(', ', $queryStatuses1) . ')';
811 $whereAppointment2[] = 'p.status IN (' . implode(', ', $queryStatuses2) . ')';
812 $whereEvent[] = 'p.status IN (' . implode(', ', $queryStatuses3) . ')';
813 }
814
815 if (!empty($criteria['packages'])) {
816 $queryPackages = [];
817
818 foreach ((array)$criteria['packages'] as $index => $value) {
819 $param = ':package' . $index;
820 $queryPackages[] = $param;
821 $appointmentParams2[$param] = $value;
822 }
823
824 $whereAppointment2[] = "p.packageCustomerId IN (SELECT pc.id
825 FROM {$this->packagesCustomersTable} pc
826 WHERE pc.packageId IN (" . implode(', ', $queryPackages) . '))';
827 }
828
829 if (!empty($criteria['events'])) {
830 $queryEvents = [];
831
832 foreach ((array)$criteria['events'] as $index => $value) {
833 $param = ':event' . $index;
834 $queryEvents[] = $param;
835 $eventParams[$param] = $value;
836 }
837
838 $whereEvent[] = "p.customerBookingId IN (SELECT cbe.customerBookingId
839 FROM {$this->eventsTable} e
840 INNER JOIN {$this->eventsPeriodsTable} ep ON ep.eventId = e.id
841 INNER JOIN {$this->customerBookingsToEventsPeriodsTable} cbe ON cbe.eventPeriodId = ep.id
842 WHERE e.id IN (" . implode(', ', $queryEvents) . '))';
843 }
844
845 $whereAppointment1 = $whereAppointment1 ? ' AND ' . implode(' AND ', $whereAppointment1) : '';
846 $whereAppointment2 = $whereAppointment2 ? ' AND ' . implode(' AND ', $whereAppointment2) : '';
847 $whereEvent = $whereEvent ? ' AND ' . implode(' AND ', $whereEvent) : '';
848
849 $groupByAppointment1Clause = empty($criteria['separateRows']) ? "GROUP BY p.customerBookingId" : "";
850 $groupByAppointment2Clause = empty($criteria['separateRows']) ? "GROUP BY p.packageCustomerId" : "";
851 $groupByEventClause = empty($criteria['separateRows']) ? "GROUP BY p.customerBookingId" : "";
852
853 // Build list-style subqueries mirroring getFilteredIds (no ORDER BY / LIMIT here)
854 $listAppointment1 = "SELECT
855 p.id AS id,
856 p.dateTime AS dateTime,
857 p.created AS created,
858 p.status AS status,
859 p.invoiceNumber AS invoiceNumber,
860 'appointment' AS type
861 FROM {$this->table} p
862 INNER JOIN {$this->bookingsTable} cb ON cb.id = p.customerBookingId
863 INNER JOIN {$this->appointmentsTable} a ON a.id = cb.appointmentId
864 WHERE 1=1 {$whereAppointment1} {$groupByAppointment1Clause}";
865
866 $listAppointment2 = "SELECT
867 p.id AS id,
868 p.dateTime AS dateTime,
869 p.created AS created,
870 p.status AS status,
871 p.invoiceNumber AS invoiceNumber,
872 'package' AS type
873 FROM {$this->table} p
874 INNER JOIN {$this->packagesCustomersTable} pc ON p.packageCustomerId = pc.id
875 {$appointments2ProvidersServicesJoin}
876 WHERE 1=1 {$whereAppointment2} {$groupByAppointment2Clause}";
877
878 $listEvent = "SELECT
879 p.id AS id,
880 p.dateTime AS dateTime,
881 p.created AS created,
882 p.status AS status,
883 p.invoiceNumber AS invoiceNumber,
884 'event' AS type
885 FROM {$this->table} p
886 INNER JOIN {$this->bookingsTable} cb ON cb.id = p.customerBookingId
887 INNER JOIN {$this->customerBookingsToEventsPeriodsTable} cbe ON cbe.customerBookingId = cb.id
888 {$eventsProvidersJoin}
889 WHERE 1=1 {$whereEvent} {$groupByEventClause}";
890
891 if (isset($criteria['events'], $criteria['services'])) {
892 return 0;
893 }
894
895 // Assemble a single union of the list-style subqueries matching the list endpoint
896 if (isset($criteria['services'])) {
897 $listPaymentQuery = "({$listAppointment1}) UNION ALL ({$listAppointment2})";
898 $params = array_merge($params, $appointmentParams1, $appointmentParams2);
899 } elseif (isset($criteria['events'])) {
900 $listPaymentQuery = "({$listEvent})";
901 $params = array_merge($params, $eventParams);
902 } elseif (isset($criteria['packages'])) {
903 $listPaymentQuery = "({$listAppointment2})";
904 $params = array_merge($params, $appointmentParams2);
905 } else {
906 $listPaymentQuery = "({$listAppointment1}) UNION ALL ({$listAppointment2}) UNION ALL ({$listEvent})";
907 $params = array_merge($params, $appointmentParams1, $appointmentParams2, $eventParams);
908 }
909
910 $bookingTypeCondition = '';
911 if (!empty($criteria['bookingTypes'])) {
912 $bookingTypeCondition = 'WHERE type IN ("' . implode('", "', $criteria['bookingTypes']) . '")';
913 }
914
915 // Invoice page: count distinct invoices across the union to mirror list grouping
916 if ($invoice) {
917 try {
918 $statement = $this->connection->prepare(
919 "SELECT COUNT(DISTINCT IFNULL(invoiceNumber, id)) AS cnt FROM ({$listPaymentQuery}) payments {$bookingTypeCondition}"
920 );
921 $statement->execute($params);
922 $row = $statement->fetch();
923 return (int)($row['cnt'] ?? 0);
924 } catch (\Exception $e) {
925 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
926 }
927 }
928
929 // Non-invoice: simply count rows of the grouped list union (matches separateRows logic)
930 try {
931 $statement = $this->connection->prepare(
932 "SELECT COUNT(*) AS cnt FROM ({$listPaymentQuery}) payments {$bookingTypeCondition}"
933 );
934 $statement->execute($params);
935 $row = $statement->fetch();
936 return (int)($row['cnt'] ?? 0);
937 } catch (\Exception $e) {
938 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
939 }
940 }
941
942 /**
943 * Returns a collection of customers that have birthday on today's date and where notification is not sent
944 *
945 * @return Collection
946 * @throws InvalidArgumentException
947 * @throws QueryExecutionException
948 * @throws \Exception
949 */
950 public function getUncompletedActionsForPayments()
951 {
952 $params = [];
953
954 $currentDateTime = "STR_TO_DATE('" . DateTimeService::getNowDateTimeInUtc() . "', '%Y-%m-%d %H:%i:%s')";
955
956 $pastDateTime =
957 "STR_TO_DATE('" .
958 DateTimeService::getNowDateTimeObjectInUtc()->modify('-1 day')->format('Y-m-d H:i:s') .
959 "', '%Y-%m-%d %H:%i:%s')";
960
961 try {
962 $statement = $this->connection->prepare(
963 "SELECT * FROM {$this->table}
964 WHERE
965 actionsCompleted = 0 AND
966 {$currentDateTime} > DATE_ADD(created, INTERVAL 300 SECOND) AND
967 {$pastDateTime} < created AND
968 entity IS NOT NULL"
969 );
970
971 $statement->execute($params);
972
973 $rows = $statement->fetchAll();
974 } catch (\Exception $e) {
975 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
976 }
977
978 $items = [];
979
980 foreach ($rows as $row) {
981 $items[] = call_user_func([static::FACTORY, 'create'], $row);
982 }
983
984 return new Collection($items);
985 }
986
987 /**
988 * @param array $data
989 * @param boolean $invoice
990 *
991 * @return array
992 * @throws QueryExecutionException
993 */
994 public function getSecondaryPaymentIds($data, $invoice)
995 {
996 $params = [];
997
998 $where = [];
999
1000 $parentIdParam1 = null;
1001 $parentIdParam2 = null;
1002 $paymentIdParam2 = null;
1003
1004 foreach ($data as $index => $item) {
1005 $paymentIdParam1 = ':paymentId1' . $index;
1006 $params[$paymentIdParam1] = $item['paymentId'];
1007
1008 if ($invoice) {
1009 if (!empty($item['parentId'])) {
1010 $parentIdParam1 = ':parentId1' . $index;
1011 $params[$parentIdParam1] = $item['parentId'];
1012 $parentIdParam2 = ':parentId2' . $index;
1013 $params[$parentIdParam2] = $item['parentId'];
1014 }
1015 $paymentIdParam2 = ':paymentId2' . $index;
1016 $params[$paymentIdParam2] = $item['paymentId'];
1017 }
1018
1019 $relationParam = ':' . $item['columnName'] . $index;
1020
1021 $params[$relationParam] = $item['columnId'];
1022
1023 // change in the future to simply retrieve by invoiceNumber when on invoice page since all the related payments will have the same invoiceNumber
1024 // cannot be done immediately since invoiceNumber is NULL for existing payments
1025 if ($invoice) {
1026 $where[] =
1027 "((id <> $paymentIdParam1 AND " .
1028 $item['columnName'] . " = $relationParam) OR parentId = $paymentIdParam2" .
1029 (!empty($item['parentId']) ? " OR id = $parentIdParam1 OR parentId = $parentIdParam2)" : ")");
1030 } else {
1031 $where[] = "(id <> $paymentIdParam1 AND " . $item['columnName'] . " = $relationParam)";
1032 }
1033 }
1034
1035 $where = $where ? 'WHERE ' . implode(' OR ', $where) : '';
1036
1037 try {
1038 $statement = $this->connection->prepare(
1039 "SELECT
1040 p.id AS id,
1041 p.entity AS entity
1042 FROM {$this->table} p
1043 {$where}"
1044 );
1045
1046 $statement->execute($params);
1047
1048 $rows = $statement->fetchAll();
1049 } catch (\Exception $e) {
1050 throw new QueryExecutionException('Unable to find by id in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
1051 }
1052
1053 $result = [];
1054
1055 foreach ($rows as $row) {
1056 $result[(int)$row['id']] = $row['entity'];
1057 }
1058
1059 return $result;
1060 }
1061
1062 /**
1063 * @param int $paymentId
1064 * @param string $transactionId
1065 *
1066 * @throws QueryExecutionException
1067 */
1068 public function updateTransactionId($paymentId, $transactionId)
1069 {
1070 $params = [
1071 ':transactionId' => $transactionId,
1072 ':paymentId1' => $paymentId,
1073 ':paymentId2' => $paymentId
1074 ];
1075
1076 try {
1077 $statement = $this->connection->prepare(
1078 "UPDATE {$this->table} SET `transactionId` = :transactionId WHERE id = :paymentId1 OR parentId = :paymentId2"
1079 );
1080
1081 $statement->execute($params);
1082 } catch (\Exception $e) {
1083 throw new QueryExecutionException('Unable to update data in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
1084 }
1085
1086 return true;
1087 }
1088
1089
1090
1091 /**
1092 * @param array $data
1093 *
1094 * @return bool
1095 * @throws QueryExecutionException
1096 */
1097 public function setInvoiceNumber($data)
1098 {
1099 $params = [
1100 ':id1' => $data['id'],
1101 ':id2' => $data['id'],
1102 ":{$data['columnName']}" => $data['columnValue']
1103 ];
1104
1105 $where = "WHERE id = :id1 OR parentId = :id2 OR {$data['columnName']} = :{$data['columnName']}";
1106
1107 if (!empty($data['parentId'])) {
1108 $params[':parentId1'] = $params[':parentId2'] = $data['parentId'];
1109 $where = ' OR id = :parentId1 OR parentId = :parentId2';
1110 }
1111
1112 try {
1113 $statement = $this->connection->prepare(
1114 "UPDATE {$this->table}
1115 SET `invoiceNumber` = (SELECT COALESCE(MAX(invoiceNumber), 0) + 1 FROM (SELECT * FROM {$this->table}) AS p)
1116 {$where}"
1117 );
1118
1119 $statement->execute($params);
1120 } catch (\Exception $e) {
1121 throw new QueryExecutionException('Unable to save invoice number in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
1122 }
1123
1124 return true;
1125 }
1126
1127 /**
1128 * @param array $rows
1129 *
1130 * @return array
1131 */
1132 private function getEntitiesPaymentsResult($rows)
1133 {
1134 $result = [];
1135
1136 foreach ($rows as &$row) {
1137 $customerInfo = $row['info'] ? json_decode($row['info'], true) : null;
1138
1139 if (empty($result[(int)$row['id']])) {
1140 $result[(int)$row['id']] = [
1141 'id' => (int)$row['id'],
1142 'dateTime' => DateTimeService::getCustomDateTimeFromUtc($row['dateTime']),
1143 'created' => DateTimeService::getCustomDateTimeFromUtc($row['created']),
1144 'bookingStart' => $row['bookingStart'] ?
1145 DateTimeService::getCustomDateTimeFromUtc($row['bookingStart']) : null,
1146 'status' => $row['status'],
1147 'parentId' => $row['parentId'],
1148 'wcOrderId' => $row['wcOrderId'],
1149 'wcOrderItemId' => $row['wcOrderItemId'],
1150 'gateway' => $row['gateway'],
1151 'gatewayTitle' => $row['gatewayTitle'],
1152 'transactionId' => $row['transactionId'],
1153 'type' => $row['type'],
1154 'name' => $row['bookableName'],
1155 'customerBookingId' => (int)$row['customerBookingId'] ?: null,
1156 'packageCustomerId' => (int)$row['packageCustomerId'] ?: null,
1157 'amount' => (float)$row['amount'],
1158 'invoiceNumber' => $row['invoiceNumber'],
1159 'providers' => (int)$row['providerId'] ? [
1160 [
1161 'id' => (int)$row['providerId'],
1162 'fullName' => $row['providerFirstName'] . ' ' . $row['providerLastName'],
1163 'email' => $row['providerEmail'],
1164 'firstName' => $row['providerFirstName'],
1165 'lastName' => $row['providerLastName'],
1166 'picture' => $row['providerPictureThumbPath'],
1167 ]
1168 ] : [],
1169 'location' => (int)$row['locationId'] || $row['location_address'] ?
1170 [
1171 'id' => (int)$row['locationId'],
1172 'location_name' => $row['location_name'],
1173 'location_address' => $row['location_address'],
1174 ]
1175 : null,
1176 'customerId' => (int)$row['customerId'],
1177 'serviceId' => (int)$row['serviceId'] ?: null,
1178 'appointmentId' => (int)$row['appointmentId'] ?: null,
1179 'packageId' => (int)$row['packageId'] ?: null,
1180 'bookedPrice' => (float)$row['bookedPrice'] ?: 0,
1181 'bookedTax' => $row['bookedTax'] ?: null,
1182 'bookingId' => !empty($row['bookingId']) ? (int)$row['bookingId'] : null,
1183 'bookableName' => $row['bookableName'],
1184 'customerFirstName' => $customerInfo ? $customerInfo['firstName'] : $row['customerFirstName'],
1185 'customerLastName' => $customerInfo ? $customerInfo['lastName'] : $row['customerLastName'],
1186 'info' => $row['info'],
1187 'customerEmail' => $row['customerEmail'],
1188 'customerStatus' => $row['customerStatus'],
1189 'coupon' => !empty($row['coupon_id']) ? [
1190 'id' => (int)$row['coupon_id'],
1191 'discount' => (float)$row['coupon_discount'],
1192 'deduction' => (float)$row['coupon_deduction'],
1193 'code' => $row['coupon_code']
1194 ] : null,
1195 'persons' => (int)$row['persons'],
1196 'aggregatedPrice' => (bool)$row['aggregatedPrice'],
1197 'extras' => [],
1198 ];
1199 }
1200
1201 if ($result[(int)$row['id']] && $row['bookingExtra_id']) {
1202 $result[(int)$row['id']]['extras'][] = [
1203 'id' => (int)$row['bookingExtra_id'],
1204 'extraId' => (int)$row['bookingExtra_extraId'],
1205 'quantity' => (int)$row['bookingExtra_quantity'],
1206 'price' => (float)$row['bookingExtra_price'],
1207 'aggregatedPrice' => (bool)$row['bookingExtra_aggregatedPrice'],
1208 'tax' => $row['bookingExtra_tax'] ?: null
1209 ];
1210 }
1211 }
1212
1213 return $result;
1214 }
1215
1216 /**
1217 * @param array $ids
1218 *
1219 * @return array
1220 * @throws QueryExecutionException
1221 * @throws InvalidArgumentException
1222 */
1223 public function getAppointmentsPaymentsByIds($ids)
1224 {
1225 $params = [];
1226
1227 $where = [];
1228
1229 if (!empty($ids)) {
1230 foreach ($ids as $index => $value) {
1231 $param = ':sId' . $index;
1232
1233 $params[$param] = $value;
1234 }
1235
1236 $where[] = 'p.id IN (' . implode(', ', array_keys($params)) . ')';
1237 }
1238
1239 $where = $where ? ' AND ' . implode(' AND ', $where) : '';
1240
1241 $customerBookingsExtrasTable = CustomerBookingsToExtrasTable::getTableName();
1242
1243 $couponsTable = CouponsTable::getTableName();
1244
1245 $locationsTable = LocationsTable::getTableName();
1246
1247 try {
1248 $statement = $this->connection->prepare(
1249 "SELECT
1250 p.id AS id,
1251 p.customerBookingId AS customerBookingId,
1252 NULL AS packageCustomerId,
1253 p.amount AS amount,
1254 p.invoiceNumber AS invoiceNumber,
1255 p.dateTime AS dateTime,
1256 p.created AS created,
1257 p.status AS status,
1258 p.wcOrderId AS wcOrderId,
1259 p.wcOrderItemId AS wcOrderItemId,
1260 p.gateway AS gateway,
1261 p.gatewayTitle AS gatewayTitle,
1262 p.transactionId AS transactionId,
1263 p.parentId AS parentId,
1264 p.entity AS type,
1265
1266 NULL AS packageId,
1267 cb.id AS bookingId,
1268 cb.price AS bookedPrice,
1269 cb.tax AS bookedTax,
1270 a.providerId AS providerId,
1271 cb.customerId AS customerId,
1272 cb.persons AS persons,
1273 cb.aggregatedPrice AS aggregatedPrice,
1274 cb.info AS info,
1275
1276 cbe.id AS bookingExtra_id,
1277 cbe.extraId AS bookingExtra_extraId,
1278 cbe.quantity AS bookingExtra_quantity,
1279 cbe.price AS bookingExtra_price,
1280 cbe.aggregatedPrice AS bookingExtra_aggregatedPrice,
1281 cbe.tax AS bookingExtra_tax,
1282
1283 c.id AS coupon_id,
1284 c.discount AS coupon_discount,
1285 c.deduction AS coupon_deduction,
1286 c.code AS coupon_code,
1287
1288 a.serviceId AS serviceId,
1289 a.id AS appointmentId,
1290 a.bookingStart AS bookingStart,
1291 s.name AS bookableName,
1292 cu.firstName AS customerFirstName,
1293 cu.lastName AS customerLastName,
1294 cu.email AS customerEmail,
1295 cu.status AS customerStatus,
1296 pu.firstName AS providerFirstName,
1297 pu.lastName AS providerLastName,
1298 pu.email AS providerEmail,
1299 pu.pictureThumbPath AS providerPictureThumbPath,
1300 l.id AS locationId,
1301 l.name AS location_name,
1302 l.address AS location_address
1303 FROM {$this->table} p
1304 INNER JOIN {$this->bookingsTable} cb ON cb.id = p.customerBookingId
1305 LEFT JOIN {$customerBookingsExtrasTable} cbe ON cbe.customerBookingId = cb.id
1306 LEFT JOIN {$couponsTable} c ON c.id = cb.couponId
1307 INNER JOIN {$this->appointmentsTable} a ON a.id = cb.appointmentId
1308 INNER JOIN {$this->servicesTable} s ON s.id = a.serviceId
1309 INNER JOIN {$this->usersTable} cu ON cu.id = cb.customerId
1310 INNER JOIN {$this->usersTable} pu ON pu.id = a.providerId
1311 LEFT JOIN {$locationsTable} l ON l.id = a.locationId
1312 WHERE 1=1 {$where}"
1313 );
1314
1315 $statement->execute($params);
1316
1317 $rows = $statement->fetchAll();
1318 } catch (\Exception $e) {
1319 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
1320 }
1321
1322 return $this->getEntitiesPaymentsResult($rows);
1323 }
1324
1325 /**
1326 * @param array $ids
1327 *
1328 * @return array
1329 * @throws QueryExecutionException
1330 * @throws InvalidArgumentException
1331 */
1332 public function getEventsPaymentsByIds($ids)
1333 {
1334 $params = [];
1335
1336 $where = [];
1337
1338 if (!empty($ids)) {
1339 foreach ($ids as $index => $value) {
1340 $param = ':eId' . $index;
1341
1342 $params[$param] = $value;
1343 }
1344
1345 $where[] = 'p.id IN (' . implode(', ', array_keys($params)) . ')';
1346 }
1347
1348 $where = $where ? ' AND ' . implode(' AND ', $where) : '';
1349
1350 $couponsTable = CouponsTable::getTableName();
1351
1352 $locationsTable = LocationsTable::getTableName();
1353
1354 try {
1355 $statement = $this->connection->prepare(
1356 "SELECT
1357 p.id AS id,
1358 p.customerBookingId AS customerBookingId,
1359 NULL AS packageCustomerId,
1360 p.amount AS amount,
1361 p.invoiceNumber AS invoiceNumber,
1362 p.dateTime AS dateTime,
1363 p.created AS created,
1364 p.status AS status,
1365 p.wcOrderId AS wcOrderId,
1366 p.wcOrderItemId AS wcOrderItemId,
1367 p.gateway AS gateway,
1368 p.gatewayTitle AS gatewayTitle,
1369 p.transactionId AS transactionId,
1370 p.parentId AS parentId,
1371 p.entity AS type,
1372
1373 NULL AS packageId,
1374 cb.id AS bookingId,
1375 cb.price AS bookedPrice,
1376 cb.tax AS bookedTax,
1377 NULL AS providerId,
1378 cb.customerId AS customerId,
1379 cb.persons AS persons,
1380 cb.aggregatedPrice AS aggregatedPrice,
1381 cb.info AS info,
1382
1383 NULL AS bookingExtra_id,
1384 NULL AS bookingExtra_extraId,
1385 NULL AS bookingExtra_quantity,
1386 NULL AS bookingExtra_price,
1387 NULL AS bookingExtra_aggregatedPrice,
1388 NULL AS bookingExtra_tax,
1389
1390 c.id AS coupon_id,
1391 c.discount AS coupon_discount,
1392 c.deduction AS coupon_deduction,
1393 c.code AS coupon_code,
1394
1395 NULL AS serviceId,
1396 NULL AS appointmentId,
1397 NULL AS bookingStart,
1398 NULL AS bookableName,
1399 cu.firstName AS customerFirstName,
1400 cu.lastName AS customerLastName,
1401 cu.email AS customerEmail,
1402 cu.status AS customerStatus,
1403 NULL AS providerFirstName,
1404 NULL AS providerLastName,
1405 NULL AS providerEmail,
1406 l.id AS locationId,
1407 l.name AS location_name,
1408 (CASE WHEN e.customlocation IS NOT NULL THEN e.customlocation ELSE l.address END) AS location_address
1409 FROM {$this->table} p
1410 INNER JOIN {$this->bookingsTable} cb ON cb.id = p.customerBookingId
1411 LEFT JOIN {$couponsTable} c ON c.id = cb.couponId
1412 INNER JOIN {$this->usersTable} cu ON cu.id = cb.customerId
1413 INNER JOIN {$this->customerBookingsToEventsPeriodsTable} cbe ON cbe.customerBookingId = cb.id
1414 INNER JOIN {$this->eventsPeriodsTable} ep ON ep.id = cbe.eventPeriodId
1415 INNER JOIN {$this->eventsTable} e ON e.id = ep.eventId
1416 LEFT JOIN {$this->eventsProvidersTable} epu ON epu.eventId = ep.eventId
1417 LEFT JOIN {$locationsTable} l ON l.id = e.locationId
1418 WHERE 1=1 {$where}"
1419 );
1420
1421 $statement->execute($params);
1422
1423 $rows = $statement->fetchAll();
1424 } catch (\Exception $e) {
1425 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
1426 }
1427
1428 return $this->getEntitiesPaymentsResult($rows);
1429 }
1430
1431 /**
1432 * @param array $ids
1433 *
1434 * @return array
1435 * @throws QueryExecutionException
1436 * @throws InvalidArgumentException
1437 */
1438 public function getPackagesPaymentsByIds($ids)
1439 {
1440 $params = [];
1441
1442 $where = [];
1443
1444 if (!empty($ids)) {
1445 foreach ($ids as $index => $value) {
1446 $param = ':pId' . $index;
1447
1448 $params[$param] = $value;
1449 }
1450
1451 $where[] = 'p.id IN (' . implode(', ', array_keys($params)) . ')';
1452 }
1453
1454 $where = $where ? ' AND ' . implode(' AND ', $where) : '';
1455
1456 $couponsTable = CouponsTable::getTableName();
1457
1458 try {
1459 $statement = $this->connection->prepare(
1460 "SELECT
1461 p.id AS id,
1462 NULL AS customerBookingId,
1463 p.packageCustomerId AS packageCustomerId,
1464 p.amount AS amount,
1465 p.invoiceNumber AS invoiceNumber,
1466 p.dateTime AS dateTime,
1467 p.created AS created,
1468 p.status AS status,
1469 p.wcOrderId AS wcOrderId,
1470 p.wcOrderItemId AS wcOrderItemId,
1471 p.gateway AS gateway,
1472 p.gatewayTitle AS gatewayTitle,
1473 p.transactionId AS transactionId,
1474 p.parentId AS parentId,
1475 p.entity AS type,
1476
1477 pc.packageId AS packageId,
1478 pc.id AS bookingId,
1479 pc.price AS bookedPrice,
1480 pc.tax AS bookedTax,
1481 NULL AS providerId,
1482 pc.customerId AS customerId,
1483 NULL AS persons,
1484 NULL AS aggregatedPrice,
1485 cb.info AS info,
1486
1487 NULL AS bookingExtra_id,
1488 NULL AS bookingExtra_extraId,
1489 NULL AS bookingExtra_quantity,
1490 NULL AS bookingExtra_price,
1491 NULL AS bookingExtra_aggregatedPrice,
1492 NULL AS bookingExtra_tax,
1493
1494 c.id AS coupon_id,
1495 c.discount AS coupon_discount,
1496 c.deduction AS coupon_deduction,
1497 c.code AS coupon_code,
1498
1499 NULL AS serviceId,
1500 NULL AS appointmentId,
1501 NULL AS bookingStart,
1502 pa.name AS bookableName,
1503 cu.firstName AS customerFirstName,
1504 cu.lastName AS customerLastName,
1505 cu.email AS customerEmail,
1506 cu.status AS customerStatus,
1507 '' AS providerFirstName,
1508 '' AS providerLastName,
1509 '' AS providerEmail,
1510 '' AS locationId,
1511 '' AS location_name,
1512 '' AS location_address
1513 FROM {$this->table} p
1514 INNER JOIN {$this->packagesCustomersTable} pc ON p.packageCustomerId = pc.id
1515 INNER JOIN {$this->usersTable} cu ON cu.id = pc.customerId
1516 LEFT JOIN {$couponsTable} c ON c.id = pc.couponId
1517 INNER JOIN {$this->packagesTable} pa ON pa.id = pc.packageId
1518 INNER JOIN {$this->packagesCustomersServiceTable} pcs ON pc.id = pcs.packageCustomerId
1519 LEFT JOIN {$this->bookingsTable} cb ON cb.packageCustomerServiceId = pcs.id
1520 LEFT JOIN {$this->appointmentsTable} a ON a.id = cb.appointmentId
1521 WHERE 1=1 {$where} ORDER BY p.id ASC"
1522 );
1523
1524 $statement->execute($params);
1525
1526 $rows = $statement->fetchAll();
1527 } catch (\Exception $e) {
1528 throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
1529 }
1530
1531 return $this->getEntitiesPaymentsResult($rows);
1532 }
1533 }
1534