PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.1.3
Booking for Appointments and Events Calendar – Amelia v2.1.3
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 / Infrastructure / Repository / Bookable / Service / PackageCustomerRepository.php
ameliabooking / src / Infrastructure / Repository / Bookable / Service Last commit date
CategoryRepository.php 5 months ago ExtraRepository.php 5 months ago PackageCustomerRepository.php 5 months ago PackageCustomerServiceRepository.php 5 months ago PackageRepository.php 5 months ago PackageServiceLocationRepository.php 5 months ago PackageServiceProviderRepository.php 5 months ago PackageServiceRepository.php 5 months ago ProviderServiceRepository.php 5 months ago ResourceEntitiesRepository.php 5 months ago ResourceRepository.php 5 months ago ServiceRepository.php 5 months ago
PackageCustomerRepository.php
617 lines
1 <?php
2
3 namespace AmeliaBooking\Infrastructure\Repository\Bookable\Service;
4
5 use AmeliaBooking\Domain\Collection\Collection;
6 use AmeliaBooking\Domain\Entity\Bookable\Service\Package;
7 use AmeliaBooking\Domain\Entity\Bookable\Service\PackageCustomer;
8 use AmeliaBooking\Domain\Factory\Bookable\Service\PackageCustomerFactory;
9 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
10 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
11 use AmeliaBooking\Infrastructure\Repository\AbstractRepository;
12 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Bookable\PackagesCustomersServicesTable;
13 use AmeliaBooking\Infrastructure\Connection;
14 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
15 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Bookable\PackagesServicesTable;
16 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Bookable\PackagesTable;
17 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Bookable\ServicesTable;
18 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\AppointmentsTable;
19 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\CustomerBookingsTable;
20 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Coupon\CouponsTable;
21 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Payment\PaymentsTable;
22 use AmeliaBooking\Infrastructure\WP\InstallActions\DB\User\UsersTable;
23
24 class PackageCustomerRepository extends AbstractRepository
25 {
26 public const FACTORY = PackageCustomerFactory::class;
27
28 /** @var string */
29 protected $packagesCustomersServicesTable;
30
31 /**
32 * @param Connection $connection
33 * @param string $table
34 *
35 * @throws InvalidArgumentException
36 */
37 public function __construct(
38 Connection $connection,
39 $table
40 ) {
41 parent::__construct($connection, $table);
42
43 $this->packagesCustomersServicesTable = PackagesCustomersServicesTable::getTableName();
44 }
45
46 /**
47 * @param PackageCustomer $entity
48 *
49 * @return int
50 * @throws QueryExecutionException
51 */
52 public function add($entity)
53 {
54 $data = $entity->toArray();
55
56 $params = [
57 ':packageId' => $data['packageId'],
58 ':customerId' => $data['customerId'],
59 ':price' => $data['price'],
60 ':tax' => !empty($data['tax']) ? json_encode($data['tax']) : null,
61 ':start' => $data['start'],
62 ':end' => $data['end'],
63 ':purchased' => $data['purchased'],
64 ':bookingsCount' => $data['bookingsCount'],
65 ':couponId' => $data['couponId'],
66 ':token' => $data['token'] ?: null,
67 ];
68
69 try {
70 $statement = $this->connection->prepare(
71 "INSERT INTO {$this->table}
72 (`packageId`, `customerId`, `price`, `tax`, `start`, `end`, `purchased`, `status`, `bookingsCount`, `couponId`, `token`)
73 VALUES
74 (:packageId, :customerId, :price, :tax, :start, :end, :purchased, 'approved', :bookingsCount, :couponId, :token)"
75 );
76
77 $statement->execute($params);
78 } catch (\Exception $e) {
79 throw new QueryExecutionException('Unable to add data in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
80 }
81
82 return $this->connection->lastInsertId();
83 }
84
85
86 /**
87 * @param int $id
88 * @param PackageCustomer $entity
89 *
90 * @return boolean
91 * @throws QueryExecutionException
92 */
93 public function update($id, $entity)
94 {
95 $data = $entity->toArray();
96
97 $params = [
98 ':status' => $data['status'],
99 ':end' => $data['end'],
100 ':id' => $id,
101 ];
102
103
104 try {
105 $statement = $this->connection->prepare(
106 "UPDATE {$this->table}
107 SET
108 `status` = :status,
109 `end` = :end
110 WHERE
111 id = :id"
112 );
113
114 $statement->execute($params);
115
116 return true;
117 } catch (\Exception $e) {
118 throw new QueryExecutionException('Unable to save data in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
119 }
120 }
121
122
123 /**
124 * @param Package $package
125 * @param int $customerId
126 * @param array $limitPerCustomer
127 * @param boolean $packageSpecific
128 * @return int
129 * @throws QueryExecutionException
130 */
131 public function getUserPackageCount($package, $customerId, $limitPerCustomer, $packageSpecific)
132 {
133 $params = [
134 ':customerId' => $customerId
135 ];
136
137 $startDate = DateTimeService::getNowDateTimeObject()->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i');
138
139 $intervalString = "interval " . $limitPerCustomer['period'] . " " . $limitPerCustomer['timeFrame'];
140
141 $where = "(STR_TO_DATE('" . $startDate . "', '%Y-%m-%d %H:%i:%s') BETWEEN " .
142 "(pc.purchased - " . $intervalString . " + interval 1 second) AND " .
143 "(pc.purchased + " . $intervalString . " - interval 1 second))"; //+ interval 2 day
144
145 if ($packageSpecific) {
146 $where .= " AND pc.packageId = :packageId";
147 $params[':packageId'] = $package->getId()->getValue();
148 }
149
150 try {
151 $statement = $this->connection->prepare(
152 "SELECT COUNT(DISTINCT pc.id) AS count
153 FROM {$this->table} pc
154 WHERE pc.customerId = :customerId AND {$where} AND pc.status = 'approved'
155 "
156 );
157
158 $statement->execute($params);
159
160 $rows = $statement->fetch()['count'];
161 } catch (\Exception $e) {
162 throw new QueryExecutionException('Unable to find by id in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
163 }
164
165 return $rows;
166 }
167
168 /**
169 * @param array $criteria
170 *
171 * @return array
172 * @throws QueryExecutionException
173 * @throws InvalidArgumentException
174 */
175 public function getFilteredIds($criteria = [], $itemsPerPage = null)
176 {
177 $bookingsTable = CustomerBookingsTable::getTableName();
178 $appointmentsTable = AppointmentsTable::getTableName();
179 $usersTable = UsersTable::getTableName();
180 $packagesTable = PackagesTable::getTableName();
181
182 $params = [];
183 $where = [];
184 $joins = '';
185 $having = '';
186
187 if (!empty($criteria['dates'])) {
188 $where[] = "(pc.purchased BETWEEN :purchasedFrom AND :purchasedTo)";
189
190 $params[':purchasedFrom'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][0]);
191
192 $params[':purchasedTo'] = DateTimeService::getCustomDateTimeInUtc($criteria['dates'][1]);
193 }
194
195 if (!empty($criteria['packages'])) {
196 $queryServices = [];
197
198 foreach ($criteria['packages'] as $index => $value) {
199 $param = ':package' . $index;
200
201 $queryServices[] = $param;
202
203 $params[$param] = $value;
204 }
205
206 $where[] = 'pc.packageId IN (' . implode(', ', $queryServices) . ')';
207 }
208
209
210 if (!empty($criteria['customers'])) {
211 $queryCustomers = [];
212
213 foreach ($criteria['customers'] as $index => $value) {
214 $param = ':customer' . $index;
215
216 $queryCustomers[] = $param;
217
218 $params[$param] = $value;
219 }
220
221 $where[] = 'pc.customerId IN (' . implode(', ', $queryCustomers) . ')';
222 }
223
224
225 if (!empty($criteria['search'])) {
226 $terms = preg_split('/\s+/', trim($criteria['search']));
227 $termIndex = 0;
228
229 foreach ($terms as $term) {
230 $param = ":search{$termIndex}";
231 $params[$param] = "%{$term}%";
232
233 $where[] = "(
234 p.name LIKE {$param}
235 OR u.firstName LIKE {$param}
236 OR u.lastName LIKE {$param}
237 OR pc.id LIKE {$param}
238 )";
239
240 $termIndex++;
241 }
242
243 $joins .= "
244 INNER JOIN {$usersTable} u ON u.id = pc.customerId
245 INNER JOIN {$packagesTable} p ON p.id = pc.packageId
246 ";
247 }
248
249
250 if (!empty($criteria['status'])) {
251 $whereOr = [];
252 foreach ($criteria['status'] as $status) {
253 switch ($status) {
254 case 'expired':
255 $whereOr[] = "(pc.end IS NOT NULL AND pc.end < NOW())";
256 break;
257 case 'approved':
258 case 'active':
259 $whereOr[] = "((pc.end > NOW() OR pc.end IS NULL) AND pc.status = 'approved')";
260 break;
261 case 'canceled':
262 $whereOr[] = "(pc.status = 'canceled')";
263 break;
264 default:
265 break;
266 }
267 }
268 $where[] = '(' . implode(' OR ', $whereOr) . ')';
269 }
270
271 if (!empty($criteria['providers']) || !empty($criteria['services']) || !empty($criteria['availability']) || !empty($criteria['locations'])) {
272 $whereProviders = '';
273 if (!empty($criteria['providers'])) {
274 $queryProviders = [];
275
276 foreach ($criteria['providers'] as $index => $value) {
277 $param = ':provider' . $index;
278
279 $queryProviders[] = $param;
280
281 $params[$param] = $value;
282 }
283
284 $whereProviders = 'a.providerId IN (' . implode(', ', $queryProviders) . ')';
285 }
286
287 $whereServices = '';
288 $queryServices = [];
289 if (!empty($criteria['services'])) {
290 foreach ($criteria['services'] as $index => $value) {
291 $param = ':service' . $index;
292
293 $queryServices[] = $param;
294
295 $params[$param] = $value;
296 }
297
298 $whereServices = 'a.serviceId IN (' . implode(', ', $queryServices) . ')';
299 }
300
301 $whereLocations = '';
302 if (!empty($criteria['locations'])) {
303 $queryLocations = [];
304
305 foreach ($criteria['locations'] as $index => $value) {
306 $param = ':location' . $index;
307
308 $queryLocations[] = $param;
309
310 $params[$param] = $value;
311 }
312
313 $whereLocations = 'a.locationId IN (' . implode(', ', $queryLocations) . ')';
314 }
315
316 if (!empty($criteria['availability']) && count($criteria['availability']) === 1) {
317 if ($criteria['availability'][0] === 'full') {
318 $having = "HAVING COUNT(a.id)>0 AND
319 (
320 COUNT(a.id) = (
321 SELECT SUM(pcs2.bookingsCount) FROM {$this->packagesCustomersServicesTable} pcs2 WHERE pcs2.packageCustomerId = pc.id
322 )
323 OR COUNT(a.id) = pc.bookingsCount
324 )";
325 } elseif ($criteria['availability'][0] === 'available') {
326 $having = "HAVING
327 (pc.bookingsCount = 0 AND COUNT(a.id) < (
328 SELECT SUM(pcs2.bookingsCount) FROM {$this->packagesCustomersServicesTable} pcs2 WHERE pcs2.packageCustomerId=pc.id
329 )
330 )
331 OR (pc.bookingsCount > 0 AND COUNT(a.id) < pc.bookingsCount)";
332 }
333
334 if (!empty($whereServices)) {
335 $where[] = "EXISTS (
336 SELECT a2.id
337 FROM {$appointmentsTable} a2
338 INNER JOIN {$bookingsTable} cb2 ON a2.id = cb2.appointmentId
339 INNER join {$this->packagesCustomersServicesTable} pcs2 on pcs2.id = cb2.packageCustomerServiceId and pcs2.packageCustomerId = pc.id
340
341 WHERE a2.serviceId IN (" . implode(', ', $queryServices) . "))";
342 }
343 if (!empty($whereProviders)) {
344 $where[] = "EXISTS (
345 SELECT a2.id
346 FROM {$appointmentsTable} a2
347 INNER JOIN {$bookingsTable} cb2 ON a2.id = cb2.appointmentId
348 INNER join {$this->packagesCustomersServicesTable} pcs2 on pcs2.id = cb2.packageCustomerServiceId and pcs2.packageCustomerId = pc.id
349
350 WHERE a2.providerId IN (" . implode(', ', $queryProviders) . "))";
351 }
352 if (!empty($whereLocations)) {
353 $where[] = "EXISTS (
354 SELECT a2.id
355 FROM {$appointmentsTable} a2
356 INNER JOIN {$bookingsTable} cb2 ON a2.id = cb2.appointmentId
357 INNER join {$this->packagesCustomersServicesTable} pcs2 on pcs2.id = cb2.packageCustomerServiceId and pcs2.packageCustomerId = pc.id
358
359 WHERE a2.locationId IN (" . implode(', ', $queryLocations) . "))";
360 }
361 } else {
362 if (!empty($whereServices)) {
363 $where[] = $whereServices;
364 }
365 if (!empty($whereProviders)) {
366 $where[] = $whereProviders;
367 }
368 if (!empty($whereLocations)) {
369 $where[] = $whereLocations;
370 }
371 }
372
373 $joins .= "
374 INNER JOIN {$this->packagesCustomersServicesTable} pcs ON pc.id = pcs.packageCustomerId
375 LEFT JOIN {$bookingsTable} cb ON pcs.id = cb.packageCustomerServiceId
376 LEFT JOIN {$appointmentsTable} a ON a.id = cb.appointmentId
377 ";
378 }
379
380
381 if (isset($criteria['couponId'])) {
382 $where[] = 'pc.couponId = :couponId';
383 $params[':couponId'] = (int)$criteria['couponId'];
384 }
385
386 $limit = $this->getLimit(
387 !empty($criteria['page']) ? (int)$criteria['page'] : 0,
388 !empty($itemsPerPage) ? (int)$itemsPerPage : 0
389 );
390
391 $orderBy = 'ORDER BY pc.purchased';
392 if (!empty($criteria['sort'])) {
393 $column = $criteria['sort'][0] === '-' ? substr($criteria['sort'], 1) : $criteria['sort'];
394 $orderColumn = '';
395 if ($column === 'customer') {
396 $joins .= "
397 INNER JOIN {$usersTable} cu ON cu.id = pc.customerId
398 ";
399 $orderColumn = 'CONCAT(cu.firstName, " ", cu.lastName)';
400 } elseif ($column === 'date') {
401 $orderColumn = 'pc.purchased';
402 } elseif ($column === 'id') {
403 $orderColumn = 'pc.id';
404 } elseif ($column === 'package') {
405 $joins .= "
406 INNER JOIN {$packagesTable} pa ON pa.id = pc.packageId
407 ";
408 $orderColumn = 'pa.name';
409 }
410 $orderDir = $orderColumn ? ($criteria['sort'][0] === '-' ? 'DESC' : 'ASC') : '';
411 $orderBy = $orderColumn ? "ORDER BY {$orderColumn} {$orderDir}" : 'ORDER BY pc.purchased';
412 }
413
414 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
415
416 try {
417 $statement = $this->connection->prepare(
418 "SELECT
419 pc.id AS id,
420 pc.bookingsCount AS bookingsCount
421 FROM {$this->table} pc
422 {$joins}
423 {$where}
424 GROUP BY pc.id
425 {$having}
426 {$orderBy}
427 {$limit}"
428 );
429
430 $statement->execute($params);
431
432 $rows = $statement->fetchAll();
433 } catch (\Exception $e) {
434 throw new QueryExecutionException('Unable to find by id in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
435 }
436
437 return array_column($rows, 'id');
438 }
439
440 /**
441 * @param array $ids
442 * @param array $options
443 * @param string $sort
444 *
445 * @return Collection
446 * @throws InvalidArgumentException
447 * @throws QueryExecutionException
448 */
449 public function getFiltered($ids, $options = [], $sort = null)
450 {
451 $bookingsTable = CustomerBookingsTable::getTableName();
452
453 $appointmentsTable = AppointmentsTable::getTableName();
454
455 $usersTable = UsersTable::getTableName();
456 $packagesTable = PackagesTable::getTableName();
457 $packageServicesTable = PackagesServicesTable::getTableName();
458 $servicesTable = ServicesTable::getTableName();
459 $paymentsTable = PaymentsTable::getTableName();
460 $couponsTable = CouponsTable::getTableName();
461
462 $params = [];
463
464 $where = [];
465
466 $fields = "";
467
468 $joins = "
469 INNER JOIN {$this->packagesCustomersServicesTable} pcs ON pc.id = pcs.packageCustomerId
470 LEFT JOIN {$bookingsTable} cb ON pcs.id = cb.packageCustomerServiceId
471 LEFT JOIN {$appointmentsTable} a ON a.id = cb.appointmentId
472 LEFT JOIN {$usersTable} cu ON cu.id = pc.customerId
473 LEFT JOIN {$packagesTable} pa ON pa.id = pc.packageId
474 LEFT JOIN {$paymentsTable} p ON p.packageCustomerId = pc.id
475 LEFT JOIN {$couponsTable} c ON c.id = pc.couponId
476 ";
477
478 if (!empty($options['fetchPackageServices'])) {
479 $joins .= "
480 LEFT JOIN {$packageServicesTable} pas ON pas.packageId = pa.id
481 LEFT JOIN {$servicesTable} s ON s.id = pas.serviceId
482 ";
483
484 $fields .= "
485 pas.id AS package_service_id,
486 pas.serviceId AS package_service_serviceId,
487
488 s.id AS service_id,
489 s.name AS service_name,
490 ";
491 }
492
493 if (!empty($options['fetchAppointmentProviders'])) {
494 $joins .= "
495 LEFT JOIN {$usersTable} pu ON pu.id = a.providerId
496 ";
497
498 $fields .= "
499 pu.id AS provider_id,
500 pu.firstName AS provider_firstName,
501 pu.lastName AS provider_lastName,
502 pu.email AS provider_email,
503 pu.badgeId AS provider_badgeId,
504 pu.pictureFullPath AS provider_pictureFullPath,
505 pu.pictureThumbPath AS provider_pictureThumbPath,
506 ";
507 }
508
509 if (!empty($ids)) {
510 $queryIds = [];
511
512 foreach ($ids as $index => $value) {
513 $param = ':id' . $index;
514
515 $queryIds[] = $param;
516
517 $params[$param] = $value;
518 }
519
520 $where[] = 'pc.id IN (' . implode(', ', $queryIds) . ')';
521 }
522
523 $orderBy = 'ORDER BY pc.purchased';
524 if ($sort) {
525 $column = $sort[0] === '-' ? substr($sort, 1) : $sort;
526 $orderColumn = '';
527 if ($column === 'customer') {
528 $orderColumn = 'CONCAT(cu.firstName, " ", cu.lastName)';
529 } elseif ($column === 'date') {
530 $orderColumn = 'pc.purchased';
531 } elseif ($column === 'id') {
532 $orderColumn = 'pc.id';
533 } elseif ($column === 'package') {
534 $orderColumn = 'pa.name';
535 }
536 $orderDir = $orderColumn ? ($sort[0] === '-' ? 'DESC' : 'ASC') : '';
537 $orderBy = $orderColumn ? "ORDER BY {$orderColumn} {$orderDir}" : 'ORDER BY pc.purchased';
538 }
539
540 $where = $where ? 'WHERE ' . implode(' AND ', $where) : '';
541
542 $fields .= "
543 pc.id AS package_customer_id,
544 pc.packageId AS package_customer_packageId,
545 pc.purchased AS package_customer_purchased,
546 pc.end AS package_customer_end,
547 pc.status AS package_customer_status,
548 pc.customerId AS package_customer_customerId,
549 pc.bookingsCount AS package_customer_bookingsCount,
550 pc.price AS package_customer_price,
551 pc.tax AS package_customer_tax,
552 pc.couponId AS package_customer_couponId,
553 pc.token AS package_customer_token,
554
555 pcs.id AS package_customer_service_id,
556 pcs.bookingsCount AS package_customer_service_bookingsCount,
557
558 cb.id AS booking_id,
559
560 a.id AS appointment_id,
561 a.providerId AS appointment_providerId,
562 a.serviceId AS appointment_serviceId,
563 a.notifyParticipants AS appointment_notifyParticipants,
564 a.bookingStart AS appointment_bookingStart,
565 a.bookingEnd AS appointment_bookingEnd,
566 a.status AS appointment_status,
567
568 cu.id AS customer_id,
569 cu.firstname AS customer_firstName,
570 cu.lastname AS customer_lastName,
571 cu.email AS customer_email,
572 cu.note AS customer_note,
573
574 pa.id AS package_id,
575 pa.name AS package_name,
576 pa.pictureThumbPath AS package_pictureThumbPath,
577 pa.pictureFullPath AS package_pictureFullPath,
578 pa.color AS package_color,
579 pa.calculatedPrice AS package_calculatedPrice,
580 pa.discount AS package_discount,
581
582 p.id AS payment_id,
583 p.status AS payment_status,
584 p.amount AS payment_amount,
585 p.dateTime AS payment_dateTime,
586 p.gateway AS payment_gateway,
587 p.wcOrderId AS payment_wcOrderId,
588 p.wcOrderItemId AS payment_wcOrderItemId,
589 p.created AS payment_created,
590
591 c.id AS coupon_id,
592 c.discount AS coupon_discount,
593 c.deduction AS coupon_deduction,
594 c.status AS coupon_status
595 ";
596
597 try {
598 $statement = $this->connection->prepare(
599 "SELECT {$fields}
600 FROM {$this->table} pc
601 {$joins}
602 {$where}
603 {$orderBy}
604 "
605 );
606
607 $statement->execute($params);
608
609 $rows = $statement->fetchAll();
610 } catch (\Exception $e) {
611 throw new QueryExecutionException('Unable to find by id in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e);
612 }
613
614 return call_user_func([static::FACTORY, 'createCollection'], $rows);
615 }
616 }
617