JFIF    $         d d  7    * Z qn )ZP 0   !1 A "#a$2Qr   D8 a Ri [f  \m I ykI w0 c u F c Rı?lO7 к _f˓ [C $殷WF< _W ԣ s Kc ëI zyQy /_LK ℂ ;C",p F A : /] =H  ~ , l s / 9  ć: [=/#f ; ) x { ٛE Q )~     = 𘙲r*2~  a _V = '  ku m F  D } KYYC )( { * g& f `툪 r y ` = ^ c J. I ]( * `wq  1dđ #̩ ͑ 0  ; H ] u 搂 @:~ ו K L  N s h } O I R* 8 :2 ! lD JV o (  3 = M ( z Ȱ+i *N A  r6K n S l ) ! J J Ӂ* %  ݉?|D } d5: eP0 R; {$X' x F @ .ÊB {,WJ uQ ɲRI ;9 Q E琯 6 2fT .DU J ;*c  P A\IL Nj! J ۱+ O\ ͔ ] ޒ S߼ J ȧ c%A N ol  ՎprU L Zԛe r E2= X D Xg VQeӓ k y P7 U* o m Q I s ,K `) 6\G3t?pgjr m ۛجw luGt f  h 9uyP 0D;Uڽ"OXl i f $ ) &|ML 0 Z rm1 [ H XP l P R0  'G=i 2N +0 e 2 ]] 9 VT P  O׮ 7 h(F * 癈 ' = Q VZD F,d ߬ ~ T X G[ `le 69C R(!S2! P  < 0 x <     !1AQ "Raq 02Br #S CTb  ? Ζ "]mH5WR 7 k.ۛ ! } Q~ + yԏ z |@ T20 S~ K e k *zF f^2X *( @ 8 r ? C I uI|֓>^Ex LgNU Y+{.R Ѫ τV׸ YT D I 6 2 '8Y2  7'\T P.6 d &˦ @V q i  |8 -O Ε  ] ʔ U=   T L 8= ;6c |  !qfF3 a ů& ~$ l} 'NW U s$U k^S V : U# 6w +  +s &r+n ڐ   { @ 29 gL u " T Ù  M=6  (^ "7 r}=6Yݾ lC u hquymp Ǧ G jhs ǜNl ɻ} o 7 #S6 a w 4 !  OS  r D  5 7 % | ?x> L |  / nD 6?/8 w # [ ) L 7 +6〼T A T g   !  %5  Mm Z /c  -{1_Je "| ^$ 'O  & ޱմ < H vNqϡQ$ < 6 &Nݛ ֨tǻN (9 n ru~'όN sMG& ,uH Kw *Ī 5@  u6  BԒ  i YN * f 0 _ GhKW u  lT <nj- 0{  M L~ | /a v\ E = ?1 \ɟuq Ђ Y O a K ޡP q  $ H8o Q˼EV ~ k 0 h' L  Pp M -M"  m^ !6l nմ 쮝C U T . ! :vMǨb h ډ Vc r @񄞅~p   #   !1QAa q  ? AL0L  x LU 4 d ; x   " 16ad0 7.\ߋ 0  = P l v/ " c A Ay A|2pO8"d MV #1] = \ " ˡ ] k v I9 d ۓ & q ) ǐq E ꞅ v "P )q X  &Q  З non]я u ג./ ; gZ$ M QР 2M ]h ni 0  P $ێ 3CɏGjώy : m c # S_ l@ '_ \m|C 2`K _  1 cIvGc $? PCQ S+D ? K aײ k Fr b 8 ύ NEدg ĝ U 3  6 #Ik+ v  {ƒ v i ( ވ  ? a e)  X xy/*@Q Ǽ Ծ ) $ IWO l c G;  !i  k{ gOŀ L ('x  T rb $ w) R $ & N1E td U3Uȉ1p M"N* (DNy d96.(jQ)  X 5 c QɎMy W ?  Q *!R > 6=7)Xj 5`J ] e  8%t ! + ' ! 1Q 5   !1 AQaq ё #2 "0BRb ? G t^ ## .l lQ T $  v , ,m   㵜5u bV  =sY+ @d { N ! dn O < .- B;  _w J t 6;Q  Jd. Q c%p{ 1 ,sND dF H I0 Гo X ш  e黅X ۢ F :)[ F G X ƹ / w _c MeD   ,ʡc c .  W D  tA $ j@ : ) - # u c1< @ۗ9F ) KJ- hpP] _ x [ q B lb p ʖ w q " LFGd ƶ * s +ډ_Zc " ? % t[I P  6 J ]# =ɺ V v v CGs Gh1 > )6 |e y ? L ӣ m,4 G W Ui ` ] uJVo VDG< SB 6ϏQ @ TiU l y O U 0 kfV ~ ~}S Z @ *WU Ui ## ; s /[ = ! 7}" W N ] ' (L !  ~ y5 g9T̅J kbM' +s :S +B) v @ M  j e C f j E 0  Y\Qn z G 1 д~ W o{T 9?`  Rm yhsy3 !HAD ] m  c1 ~ 2 L  S u7x T ;j$ `} 4-> L#  vzŏ I L S  ֭  T { r  jGK C ; b  pU= - ` Bs K. S F w4  M q] Z dH S 0 ) tLg Tiny File Manager | CustomerRepository.php
<?php namespace AmeliaBooking\Infrastructure\Repository\User; use AmeliaBooking\Domain\Collection\Collection; use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException; use AmeliaBooking\Domain\Entity\User\AbstractUser; use AmeliaBooking\Domain\Repository\User\CustomerRepositoryInterface; use AmeliaBooking\Domain\Services\DateTime\DateTimeService; use AmeliaBooking\Domain\ValueObjects\String\BookingStatus; use AmeliaBooking\Domain\ValueObjects\String\Status; use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException; use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Bookable\PackagesCustomersTable; use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\AppointmentsTable; use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\CustomerBookingsTable; use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\CustomerBookingsToEventsPeriodsTable; use AmeliaBooking\Infrastructure\WP\InstallActions\DB\Booking\EventsPeriodsTable; use AmeliaBooking\Infrastructure\WP\InstallActions\DB\User\WPUsersTable; /** * Class UserRepository * * @package AmeliaBooking\Infrastructure\Repository */ class CustomerRepository extends UserRepository implements CustomerRepositoryInterface { /** * @param $criteria * @param int $itemsPerPage * * @return array * @throws QueryExecutionException * @throws \Exception */ public function getFiltered($criteria, $itemsPerPage = null) { try { $wpUserTable = WPUsersTable::getTableName(); $bookingsTable = CustomerBookingsTable::getTableName(); $appointmentsTable = AppointmentsTable::getTableName(); $eventsPeriodsTable = EventsPeriodsTable::getTableName(); $bookingsEventsPeriodsTable = CustomerBookingsToEventsPeriodsTable::getTableName(); $packagesCustomersTable = PackagesCustomersTable::getTableName(); $params = [ ':type_customer' => AbstractUser::USER_ROLE_CUSTOMER, ':type_admin' => AbstractUser::USER_ROLE_ADMIN, ]; $joinWithBookings = empty($criteria['ignoredBookings']); $where = [ 'u.type IN (:type_customer, :type_admin)', ]; $order = ''; if (!empty($criteria['sort'])) { $column = $criteria['sort'][0] === '-' ? substr($criteria['sort'], 1) : $criteria['sort']; $orderColumns = [ 'customer' => 'CONCAT(u.firstName, \' \', u.lastName)', 'total-bookings' => 'totalBookings', ]; $orderColumn = $orderColumns[$column] ?? 'lastBooking'; $orderDirection = $criteria['sort'][0] === '-' ? 'DESC' : 'ASC'; $order = "ORDER BY {$orderColumn} {$orderDirection}"; $joinWithBookings = $column !== 'customer' || $joinWithBookings; } if (!empty($criteria['search'])) { $terms = preg_split('/\s+/', trim($criteria['search'])); $termIndex = 0; foreach ($terms as $term) { $param = ":search{$termIndex}"; $params[$param] = "%{$term}%"; $where[] = "( u.firstName LIKE {$param} OR u.lastName LIKE {$param} OR u.email LIKE {$param} OR u.phone LIKE {$param} OR u.note LIKE {$param} OR wpu.display_name LIKE {$param} OR u.id LIKE {$param} )"; $termIndex++; } } if (!empty($criteria['customers'])) { $customersCriteria = []; foreach ((array)$criteria['customers'] as $key => $customerId) { $params[":customerId$key"] = $customerId; $customersCriteria[] = ":customerId$key"; } $where[] = 'u.id IN (' . implode(', ', $customersCriteria) . ')'; } $statsFields = ' NULL as lastBooking, NULL as lastAppointment, NULL as lastEvent, 0 as totalBookings, 0 as countPendingAppointments, 0 as countAppointmentBookings, 0 as countEventBookings, '; $statsJoins = ''; $having = ''; if ($joinWithBookings) { $params[':bookingPendingStatus'] = BookingStatus::PENDING; $statsFields = " COALESCE(GREATEST(MAX(app.bookingStart), MAX(ep.periodStart)), MAX(app.bookingStart), MAX(ep.periodStart), MAX(pc.purchased)) as lastBooking, MAX(app.bookingStart) as lastAppointment, MAX(ep.periodStart) as lastEvent, MAX(pc.purchased) as lastPackage, COUNT(DISTINCT cb.id) as totalBookings, SUM(case when cb.status = :bookingPendingStatus then 1 else 0 end) as countPendingAppointments, COUNT(DISTINCT CASE WHEN cb.appointmentId IS NOT NULL THEN cb.id ELSE NULL END) as countAppointmentBookings, COUNT(DISTINCT CASE WHEN cb.appointmentId IS NULL THEN cb.id ELSE NULL END) as countEventBookings, COUNT(pc.customerId) as countPackagePurchases, "; $statsJoins = " LEFT JOIN {$bookingsTable} cb ON u.id = cb.customerId LEFT JOIN {$appointmentsTable} app ON app.id = cb.appointmentId LEFT JOIN {$bookingsEventsPeriodsTable} bep ON bep.customerBookingId = cb.id LEFT JOIN {$eventsPeriodsTable} ep ON ep.id = bep.eventPeriodId LEFT JOIN {$packagesCustomersTable} pc ON pc.customerId = u.id "; if (!empty($criteria['noShow'])) { $having = "HAVING ("; foreach ($criteria['noShow'] as $index => $noShowId) { $param = ':noShow' . $index; $params[$param] = $noShowId; $having .= ($index === 0 ? "" : " OR ") . "(COUNT(DISTINCT CASE WHEN cb.status = 'no-show' THEN cb.id ELSE NULL END) " . ($noShowId === "3" ? '>=' : '=') . " " . $param . ")"; } $having .= ")"; } } $where = $where ? 'WHERE ' . implode(' AND ', $where) : ''; $limit = $this->getLimit( !empty($criteria['page']) ? (int)$criteria['page'] : 0, (int)$itemsPerPage ); $statement = $this->connection->prepare( "SELECT u.id as id, u.status as status, u.firstName as firstName, u.lastName as lastName, u.email as email, u.phone as phone, u.countryPhoneIso AS countryPhoneIso, u.gender as gender, u.externalId as externalId, u.translations as translations, IF(u.birthday IS NOT NULL, u.birthday , '') as birthday, u.note as note, u.customFields as customFields, {$statsFields} IF(wpu.display_name IS NOT NULL, wpu.display_name , '') as wpName FROM {$this->table} as u LEFT JOIN {$wpUserTable} wpu ON u.externalId = wpu.id {$statsJoins} {$where} GROUP BY u.id {$having} {$order} {$limit}" ); $statement->execute($params); $rows = $statement->fetchAll(); } catch (\Exception $e) { throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e); } $items = []; foreach ($rows as $row) { $row['id'] = (int)$row['id']; $row['externalId'] = $row['externalId'] === null ? $row['externalId'] : (int)$row['externalId']; $row['lastBooking'] = !empty($row['lastBooking']) ? DateTimeService::getCustomDateTimeFromUtc($row['lastBooking']) : $row['lastBooking']; $row['lastAppointment'] = !empty($row['lastAppointment']) ? DateTimeService::getCustomDateTimeFromUtc($row['lastAppointment']) : $row['lastAppointment']; $row['lastEvent'] = !empty($row['lastEvent']) ? DateTimeService::getCustomDateTimeFromUtc($row['lastEvent']) : $row['lastEvent']; $row['lastPackage'] = !empty($row['lastPackage']) ? DateTimeService::getCustomDateTimeFromUtc($row['lastPackage']) : null; $row['totalBookings'] = (int)$row['totalBookings']; $row['totalAppointments'] = (int)$row['countAppointmentBookings']; $row['totalEvents'] = (int)$row['countEventBookings']; $row['totalPackages'] = !empty($row['countPackagePurchases']) ? (int)$row['countPackagePurchases'] : 0; // Fix for customFields being encoded multiple times if ($row['customFields'] && !is_array(json_decode($row['customFields'], true))) { $row['customFields'] = null; } $items[$row['id']] = $row; } return $items; } /** * @param $criteria * * @return mixed * @throws QueryExecutionException */ public function getCount($criteria) { $wpUserTable = WPUsersTable::getTableName(); $params = [ ':type_customer' => AbstractUser::USER_ROLE_CUSTOMER, ':type_admin' => AbstractUser::USER_ROLE_ADMIN, ]; $where = [ 'u.type IN (:type_customer, :type_admin)', ]; if (!empty($criteria['search'])) { $terms = preg_split('/\s+/', trim($criteria['search'])); $termIndex = 0; foreach ($terms as $term) { $param = ":search{$termIndex}"; $params[$param] = "%{$term}%"; $where[] = "( u.firstName LIKE {$param} OR u.lastName LIKE {$param} OR u.email LIKE {$param} OR u.phone LIKE {$param} OR u.note LIKE {$param} OR wpu.display_name LIKE {$param} OR u.id LIKE {$param} )"; $termIndex++; } } if (!empty($criteria['customers'])) { $customersCriteria = []; foreach ((array)$criteria['customers'] as $key => $customerId) { $params[":customerId$key"] = $customerId; $customersCriteria[] = ":customerId$key"; } $where[] = 'u.id IN (' . implode(', ', $customersCriteria) . ')'; } if (!empty($criteria['noShow'])) { $bookingsTable = CustomerBookingsTable::getTableName(); $noShowWhere = "exists (SELECT COUNT(*) as c FROM {$bookingsTable} cb WHERE cb.status='no-show' AND cb.customerId=u.id HAVING "; foreach ($criteria['noShow'] as $index => $noShowId) { $param = ':noShow' . $index; $params[$param] = $noShowId; $noShowWhere .= ($index === 0 ? "" : " OR ") . "c " . ($noShowId === "3" ? '>=' : '=') . $param; } $noShowWhere .= ")"; $where[] = $noShowWhere; } $where = $where ? 'WHERE ' . implode(' AND ', $where) : ''; try { $statement = $this->connection->prepare( "SELECT COUNT(*) as count FROM {$this->table} as u LEFT JOIN {$wpUserTable} wpu ON u.externalId = wpu.id $where " ); $statement->execute($params); $rows = $statement->fetch()['count']; } catch (\Exception $e) { throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e); } return $rows; } /** * @param string $phone * * @return array * @throws QueryExecutionException * @throws \Exception */ public function getByPhoneNumber($phone) { try { $params[':phone'] = '+' . $phone; $statement = $this->connection->prepare( "SELECT u.id as id, u.status as status, u.firstName as firstName, u.lastName as lastName, u.email as email, u.phone as phone, u.countryPhoneIso AS countryPhoneIso, u.gender as gender, u.externalId as externalId, IF(u.birthday IS NOT NULL, u.birthday , '') as birthday, u.note as note FROM {$this->table} as u WHERE u.type = 'customer' AND phone = :phone" ); $statement->execute($params); $rows = $statement->fetchAll(); } catch (\Exception $e) { throw new QueryExecutionException('Unable to get data from ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e); } return $rows; } /** * @param array $criteria * * @return Collection * @throws QueryExecutionException * @throws InvalidArgumentException * @throws InvalidArgumentException */ public function getByCriteria($criteria = []) { $params = []; $where = []; $fields = ' u.id AS id, u.type AS type, u.firstName AS firstName, u.lastName AS lastName, u.email AS email, u.note AS note, u.phone AS phone, u.countryPhoneIso AS countryPhoneIso, u.gender AS gender, u.birthday AS birthday, u.status AS status '; if (!empty($criteria['ids'])) { $queryIds = []; foreach ($criteria['ids'] as $index => $value) { $param = ':id' . $index; $queryIds[] = $param; $params[$param] = $value; } $where[] = 'u.id IN (' . implode(', ', $queryIds) . ')'; } $where = $where ? 'WHERE ' . implode(' AND ', $where) : ''; try { $statement = $this->connection->prepare( "SELECT {$fields} FROM {$this->table} u {$where}" ); $statement->execute($params); $rows = $statement->fetchAll(); } catch (\Exception $e) { throw new QueryExecutionException('Unable to find event by id in ' . __CLASS__ . '. ' . $e->getMessage(), $e->getCode(), $e); } $items = new Collection(); foreach ($rows as $row) { $row['type'] = 'customer'; $items->addItem(call_user_func([static::FACTORY, 'create'], $row), $row['id']); } return $items; } }