PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 1.2.20
Booking for Appointments and Events Calendar – Amelia v1.2.20
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 / Bookable / BookableApplicationService.php
ameliabooking / src / Application / Services / Bookable Last commit date
AbstractPackageApplicationService.php 2 years ago BasicPackageApplicationService.php 2 years ago BookableApplicationService.php 1 year ago
BookableApplicationService.php
1218 lines
1 <?php
2
3 namespace AmeliaBooking\Application\Services\Bookable;
4
5 use AmeliaBooking\Application\Services\Booking\AppointmentApplicationService;
6 use AmeliaBooking\Application\Services\Booking\BookingApplicationService;
7 use AmeliaBooking\Application\Services\Gallery\GalleryApplicationService;
8 use AmeliaBooking\Application\Services\Payment\PaymentApplicationService;
9 use AmeliaBooking\Domain\Collection\Collection;
10 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
11 use AmeliaBooking\Domain\Entity\Bookable\Service\Category;
12 use AmeliaBooking\Domain\Entity\Bookable\Service\Extra;
13 use AmeliaBooking\Domain\Entity\Bookable\Service\Package;
14 use AmeliaBooking\Domain\Entity\Bookable\Service\PackageCustomer;
15 use AmeliaBooking\Domain\Entity\Bookable\Service\PackageCustomerService;
16 use AmeliaBooking\Domain\Entity\Bookable\Service\PackageService;
17 use AmeliaBooking\Domain\Entity\Bookable\Service\Service;
18 use AmeliaBooking\Domain\Entity\Booking\Appointment\Appointment;
19 use AmeliaBooking\Domain\Entity\Booking\Appointment\CustomerBooking;
20 use AmeliaBooking\Domain\Entity\Entities;
21 use AmeliaBooking\Domain\Entity\Location\Location;
22 use AmeliaBooking\Domain\Entity\Payment\Payment;
23 use AmeliaBooking\Domain\Entity\Schedule\Period;
24 use AmeliaBooking\Domain\Entity\Schedule\PeriodService;
25 use AmeliaBooking\Domain\Entity\Schedule\SpecialDay;
26 use AmeliaBooking\Domain\Entity\Schedule\SpecialDayPeriod;
27 use AmeliaBooking\Domain\Entity\Schedule\SpecialDayPeriodService;
28 use AmeliaBooking\Domain\Entity\Schedule\WeekDay;
29 use AmeliaBooking\Domain\Entity\User\Provider;
30 use AmeliaBooking\Domain\Factory\Bookable\Service\PackageServiceFactory;
31 use AmeliaBooking\Domain\Factory\Location\LocationFactory;
32 use AmeliaBooking\Domain\Factory\User\UserFactory;
33 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
34 use AmeliaBooking\Domain\Services\User\ProviderService;
35 use AmeliaBooking\Domain\ValueObjects\BooleanValueObject;
36 use AmeliaBooking\Domain\ValueObjects\Duration;
37 use AmeliaBooking\Domain\ValueObjects\Json;
38 use AmeliaBooking\Domain\ValueObjects\Number\Float\Price;
39 use AmeliaBooking\Domain\ValueObjects\Number\Integer\Id;
40 use AmeliaBooking\Domain\ValueObjects\Number\Integer\PositiveInteger;
41 use AmeliaBooking\Domain\ValueObjects\Number\Integer\WholeNumber;
42 use AmeliaBooking\Infrastructure\Common\Container;
43 use AmeliaBooking\Infrastructure\Common\Exceptions\NotFoundException;
44 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
45 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\CategoryRepository;
46 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\ExtraRepository;
47 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\PackageCustomerRepository;
48 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\PackageCustomerServiceRepository;
49 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\PackageRepository;
50 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\PackageServiceLocationRepository;
51 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\PackageServiceProviderRepository;
52 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\PackageServiceRepository;
53 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\ProviderServiceRepository;
54 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\ResourceEntitiesRepository;
55 use AmeliaBooking\Infrastructure\Repository\Bookable\Service\ServiceRepository;
56 use AmeliaBooking\Infrastructure\Repository\Booking\Appointment\AppointmentRepository;
57 use AmeliaBooking\Infrastructure\Repository\Booking\Appointment\CustomerBookingExtraRepository;
58 use AmeliaBooking\Infrastructure\Repository\Booking\Appointment\CustomerBookingRepository;
59 use AmeliaBooking\Infrastructure\Repository\Coupon\CouponServiceRepository;
60 use AmeliaBooking\Infrastructure\Repository\Coupon\CouponPackageRepository;
61 use AmeliaBooking\Infrastructure\Repository\CustomField\CustomFieldServiceRepository;
62 use AmeliaBooking\Infrastructure\Repository\Notification\NotificationsToEntitiesRepository;
63 use AmeliaBooking\Infrastructure\Repository\Payment\PaymentRepository;
64 use AmeliaBooking\Infrastructure\Repository\Schedule\PeriodServiceRepository;
65 use AmeliaBooking\Infrastructure\Repository\Schedule\SpecialDayPeriodServiceRepository;
66 use AmeliaBooking\Infrastructure\Repository\Tax\TaxEntityRepository;
67 use AmeliaBooking\Infrastructure\Repository\User\ProviderRepository;
68 use Interop\Container\Exception\ContainerException;
69 use Slim\Exception\ContainerValueNotFoundException;
70
71 /**
72 * Class BookableApplicationService
73 *
74 * @package AmeliaBooking\Application\Services\Booking
75 */
76 class BookableApplicationService
77 {
78
79 private $container;
80
81 /**
82 * BookableApplicationService constructor.
83 *
84 * @param Container $container
85 */
86 public function __construct(Container $container)
87 {
88 $this->container = $container;
89 }
90
91 /**
92 * @param int $serviceId
93 * @param int $providerId
94 *
95 * @return Service
96 *
97 * @throws ContainerValueNotFoundException
98 * @throws QueryExecutionException
99 * @throws InvalidArgumentException
100 * @throws NotFoundException
101 */
102 public function getAppointmentService($serviceId, $providerId)
103 {
104 /** @var ServiceRepository $serviceRepository */
105 $serviceRepository = $this->container->get('domain.bookable.service.repository');
106
107 /** @var Collection $providerServices */
108 $providerServices = $serviceRepository->getProviderServicesWithExtras($serviceId, $providerId);
109
110 return $providerServices->keyExists($serviceId) ?
111 $providerServices->getItem($serviceId) : $serviceRepository->getByIdWithExtras($serviceId);
112 }
113
114 /**
115 * @param Collection $categories
116 * @param Collection $services
117 *
118 * @throws InvalidArgumentException
119 */
120 public function addServicesToCategories($categories, $services)
121 {
122 /** @var Category $category */
123 foreach ($categories->getItems() as $category) {
124 $category->setServiceList(new Collection());
125 }
126
127 /** @var Service $service */
128 foreach ($services->getItems() as $service) {
129 $categoryId = $service->getCategoryId()->getValue();
130
131 $categories
132 ->getItem($categoryId)
133 ->getServiceList()
134 ->addItem($service, $service->getId()->getValue());
135 }
136 }
137
138 /**
139 * @param Service $service
140 * @param Collection $providers
141 *
142 * @throws ContainerValueNotFoundException
143 * @throws QueryExecutionException
144 */
145 public function manageProvidersForServiceAdd($service, $providers)
146 {
147 /** @var ProviderServiceRepository $providerServiceRepo */
148 $providerServiceRepo = $this->container->get('domain.bookable.service.providerService.repository');
149
150 /** @var Provider $provider */
151 foreach ($providers->getItems() as $provider) {
152 $providerServiceRepo->add($service, $provider->getId()->getValue());
153 }
154 }
155
156 /**
157 * @param Package $package
158 *
159 * @throws ContainerValueNotFoundException
160 * @throws QueryExecutionException
161 */
162 public function manageServicesForPackageAdd($package)
163 {
164 /** @var PackageServiceRepository $packageServiceRepository */
165 $packageServiceRepository = $this->container->get('domain.bookable.package.packageService.repository');
166 /** @var PackageServiceLocationRepository $packageServiceLocationRepository */
167 $packageServiceLocationRepository =
168 $this->container->get('domain.bookable.package.packageServiceLocation.repository');
169 /** @var PackageServiceProviderRepository $packageServiceProviderRepository */
170 $packageServiceProviderRepository =
171 $this->container->get('domain.bookable.package.packageServiceProvider.repository');
172
173 /** @var PackageService $bookable */
174 foreach ($package->getBookable()->getItems() as $bookable) {
175 $bookableId = $packageServiceRepository->add($bookable, $package->getId()->getValue());
176
177 $bookable->setId(new Id($bookableId));
178
179 /** @var Location $location */
180 foreach ($bookable->getLocations()->getItems() as $location) {
181 $packageServiceLocationRepository->add($location, $bookable->getId()->getValue());
182 }
183
184 /** @var Provider $provider */
185 foreach ($bookable->getProviders()->getItems() as $provider) {
186 $packageServiceProviderRepository->add($provider, $bookable->getId()->getValue());
187 }
188 }
189 }
190
191 /**
192 * @param Package $package
193 * @param array $bookableServices
194 *
195 * @throws ContainerValueNotFoundException
196 * @throws QueryExecutionException
197 * @throws InvalidArgumentException
198 */
199 public function manageServicesForPackageUpdate($package, $bookableServices)
200 {
201 /** @var PackageRepository $packageRepository */
202 $packageRepository = $this->container->get('domain.bookable.package.repository');
203 /** @var PackageServiceRepository $packageServiceRepository */
204 $packageServiceRepository = $this->container->get('domain.bookable.package.packageService.repository');
205 /** @var PackageServiceLocationRepository $packageServiceLocationRepository */
206 $packageServiceLocationRepository =
207 $this->container->get('domain.bookable.package.packageServiceLocation.repository');
208 /** @var PackageServiceProviderRepository $packageServiceProviderRepository */
209 $packageServiceProviderRepository =
210 $this->container->get('domain.bookable.package.packageServiceProvider.repository');
211 /** @var ServiceRepository $serviceRepository */
212 $serviceRepository = $this->container->get('domain.bookable.service.repository');
213
214 /** @var Collection $services */
215 $services = $serviceRepository->getByCriteria(['services' => array_keys($bookableServices)]);
216
217 /** @var Package $oldPackage */
218 $oldPackage = $packageRepository->getById($package->getId()->getValue());
219
220 $oldPackageServicesIds = [];
221
222 /** @var PackageService $oldPackageService */
223 foreach ($oldPackage->getBookable()->getItems() as $oldPackageService) {
224 $serviceId = $oldPackageService->getService()->getId()->getValue();
225
226 $oldPackageServicesIds[$serviceId] = [
227 'providersIds' => [],
228 'locationsIds' => [],
229 ];
230
231 /** @var Location $location */
232 foreach ($oldPackageService->getLocations()->getItems() as $location) {
233 $oldPackageServicesIds[$serviceId]['locationsIds'][] = $location->getId()->getValue();
234 }
235
236 /** @var Provider $provider */
237 foreach ($oldPackageService->getProviders()->getItems() as $provider) {
238 $oldPackageServicesIds[$serviceId]['providersIds'][] = $provider->getId()->getValue();
239 }
240 }
241
242 foreach ($bookableServices as $serviceId => $data) {
243 if (!in_array($serviceId, array_keys($oldPackageServicesIds), false)) {
244 $packageService = PackageServiceFactory::create(
245 [
246 'service' => $services->getItem($serviceId)->toArray(),
247 'quantity' => $data['quantity'],
248 'minimumScheduled' => $data['minimumScheduled'],
249 'maximumScheduled' => $data['maximumScheduled'],
250 'allowProviderSelection' => $data['allowProviderSelection'],
251 'providers' => $data['providers'],
252 'locations' => $data['locations'],
253 'position' => $data['position'],
254 ]
255 );
256
257 $packageServiceId = $packageServiceRepository->add($packageService, $package->getId()->getValue());
258
259 $packageService->setId(new Id($packageServiceId));
260
261 /** @var Location $location */
262 foreach ($packageService->getLocations()->getItems() as $location) {
263 $packageServiceLocationRepository->add($location, $packageService->getId()->getValue());
264 }
265
266 /** @var Provider $provider */
267 foreach ($packageService->getProviders()->getItems() as $provider) {
268 $packageServiceProviderRepository->add($provider, $packageService->getId()->getValue());
269 }
270 }
271 }
272
273 /** @var PackageService $oldPackageService */
274 foreach ($oldPackage->getBookable()->getItems() as $oldPackageService) {
275 $serviceId = $oldPackageService->getService()->getId()->getValue();
276
277 if (in_array($serviceId, array_keys($bookableServices), false)) {
278 $oldPackageService->setQuantity(new PositiveInteger($bookableServices[$serviceId]['quantity']));
279
280 $oldPackageService->setMinimumScheduled(
281 new WholeNumber($bookableServices[$serviceId]['minimumScheduled'])
282 );
283
284 $oldPackageService->setMaximumScheduled(
285 new WholeNumber($bookableServices[$serviceId]['maximumScheduled'])
286 );
287
288 $oldPackageService->setAllowProviderSelection(
289 new BooleanValueObject($bookableServices[$serviceId]['allowProviderSelection'])
290 );
291
292 $oldPackageService->setPosition(
293 new PositiveInteger($bookableServices[$serviceId]['position'])
294 );
295
296 $packageServiceRepository->update($oldPackageService->getId()->getValue(), $oldPackageService);
297
298 foreach ($bookableServices[$serviceId]['locations'] as $data) {
299 if (!in_array($data['id'], $oldPackageServicesIds[$serviceId]['locationsIds'], false)) {
300 $packageServiceLocationRepository->add(
301 LocationFactory::create($data),
302 $oldPackageService->getId()->getValue()
303 );
304 }
305 }
306
307 $packageServiceLocationRepository->deleteAllNotInLocationsServicesArrayForPackage(
308 array_column($bookableServices[$serviceId]['locations'], 'id'),
309 $oldPackageService->getId()->getValue()
310 );
311
312 foreach ($bookableServices[$serviceId]['providers'] as $data) {
313 if (!in_array($data['id'], $oldPackageServicesIds[$serviceId]['providersIds'], false)) {
314 $packageServiceProviderRepository->add(
315 UserFactory::create($data),
316 $oldPackageService->getId()->getValue()
317 );
318 }
319 }
320
321 $packageServiceProviderRepository->deleteAllNotInProvidersServicesArrayForPackage(
322 array_column($bookableServices[$serviceId]['providers'], 'id'),
323 $oldPackageService->getId()->getValue()
324 );
325 } else {
326 $packageServiceLocationRepository->deleteAllNotInLocationsServicesArrayForPackage(
327 $oldPackageServicesIds[$serviceId]['locationsIds'],
328 $oldPackageService->getId()->getValue()
329 );
330
331 $packageServiceProviderRepository->deleteAllNotInProvidersServicesArrayForPackage(
332 $oldPackageServicesIds[$serviceId]['providersIds'],
333 $oldPackageService->getId()->getValue()
334 );
335 }
336 }
337
338 $packageServiceRepository->deleteAllNotInServicesArrayForPackage(
339 array_keys($bookableServices),
340 $package->getId()->getValue()
341 );
342 }
343
344 /**
345 * @param Service $service
346 * @param array $serviceProvidersIds
347 * @param bool $updateCustomPricing
348 *
349 * @throws ContainerValueNotFoundException
350 * @throws QueryExecutionException
351 * @throws InvalidArgumentException
352 */
353 public function manageProvidersForServiceUpdate($service, $serviceProvidersIds, $updateCustomPricing)
354 {
355 /** @var ProviderRepository $providerRepo */
356 $providerRepo = $this->container->get('domain.users.providers.repository');
357 /** @var ProviderServiceRepository $providerServiceRepo */
358 $providerServiceRepo = $this->container->get('domain.bookable.service.providerService.repository');
359 /** @var PeriodServiceRepository $periodServiceRepo */
360 $periodServiceRepo = $this->container->get('domain.schedule.period.service.repository');
361 /** @var SpecialDayPeriodServiceRepository $specialDayPeriodServiceRepo */
362 $specialDayPeriodServiceRepo = $this->container->get('domain.schedule.specialDay.period.service.repository');
363
364 /** @var ServiceRepository $serviceRepository */
365 $serviceRepository = $this->container->get('domain.bookable.service.repository');
366 /** @var ProviderService $providerDomainService */
367 $providerDomainService = $this->container->get('domain.user.provider.service');
368
369 /** @var Collection $services */
370 $services = $serviceRepository->getAllArrayIndexedById();
371
372 /** @var Collection $providers */
373 $providers = $providerRepo->getWithSchedule([]);
374
375 /** @var Collection $serviceProviders */
376 $serviceProviders = new Collection();
377
378 /** @var Provider $provider */
379 foreach ($providers->getItems() as $provider) {
380 /** @var Service $providerService */
381 foreach ($provider->getServiceList()->getItems() as $providerService) {
382 if ($providerService->getId()->getValue() === $service->getId()->getValue()) {
383 $providerDomainService->setProviderServices($provider, $services, true);
384
385 $serviceProviders->addItem($provider, $provider->getId()->getValue());
386
387 break;
388 }
389 }
390 }
391
392 $serviceId = $service->getId()->getValue();
393
394 /** @var Provider $provider */
395 foreach ($serviceProviders->getItems() as $provider) {
396 $isServiceProvider = in_array($provider->getId()->getValue(), $serviceProvidersIds, false);
397
398 if (!$isServiceProvider) {
399 /** @var WeekDay $weekDay */
400 foreach ($provider->getWeekDayList()->getItems() as $weekDay) {
401 /** @var Period $period */
402 foreach ($weekDay->getPeriodList()->getItems() as $period) {
403 /** @var PeriodService $periodService */
404 foreach ($period->getPeriodServiceList()->getItems() as $periodService) {
405 if ($periodService->getServiceId()->getValue() === $serviceId) {
406 $periodServiceRepo->delete($periodService->getId()->getValue());
407 }
408 }
409 }
410 }
411
412 /** @var SpecialDay $specialDay */
413 foreach ($provider->getSpecialDayList()->getItems() as $specialDay) {
414 /** @var SpecialDayPeriod $period */
415 foreach ($specialDay->getPeriodList()->getItems() as $period) {
416 /** @var SpecialDayPeriodService $periodService */
417 foreach ($period->getPeriodServiceList()->getItems() as $periodService) {
418 if ($periodService->getServiceId()->getValue() === $serviceId) {
419 $specialDayPeriodServiceRepo->delete($periodService->getId()->getValue());
420 }
421 }
422 }
423 }
424 }
425
426 if ($updateCustomPricing && $isServiceProvider) {
427 if ($provider->getServiceList()->keyExists($serviceId)) {
428 /** @var Service $providerService */
429 $providerService = $provider->getServiceList()->getItem($serviceId);
430
431 $updateProviderService = false;
432
433 if ((!$providerService->getCustomPricing() && $service->getCustomPricing()) ||
434 ($providerService->getCustomPricing() && !$service->getCustomPricing())
435 ) {
436 $updateProviderService = true;
437
438 $providerService->setCustomPricing($service->getCustomPricing());
439 } elseif ($service->getCustomPricing() && $providerService->getCustomPricing()) {
440 $serviceCustomPricing = json_decode($service->getCustomPricing()->getValue(), true);
441
442 $providerCustomPricing = json_decode($providerService->getCustomPricing()->getValue(), true);
443
444 foreach ($serviceCustomPricing['durations'] as $duration => $durationData) {
445 if (array_key_exists($duration, $providerCustomPricing['durations'])) {
446 $serviceCustomPricing['durations'][$duration] =
447 $providerCustomPricing['durations'][$duration];
448 } else {
449 $updateProviderService = true;
450 }
451 }
452
453 if ($serviceCustomPricing['enabled'] !== $providerCustomPricing['enabled']) {
454 $updateProviderService = true;
455 }
456
457 $providerService->setCustomPricing(new Json(json_encode($serviceCustomPricing)));
458
459 if (!$updateProviderService) {
460 foreach ($providerCustomPricing['durations'] as $duration => $durationData) {
461 if (!array_key_exists($duration, $serviceCustomPricing['durations'])) {
462 $updateProviderService = true;
463 }
464 }
465 }
466 }
467
468 if ($updateProviderService) {
469 $providerServiceRepo->updateServiceForProvider(
470 $providerService,
471 $providerService->getId()->getValue(),
472 $provider->getId()->getValue()
473 );
474 }
475 }
476 }
477 }
478
479 $providerServiceRepo->deleteAllNotInProvidersArrayForService($serviceProvidersIds, $serviceId);
480
481 foreach ($serviceProvidersIds as $providerId) {
482 if (!in_array($providerId, $serviceProviders->keys(), false)) {
483 $providerServiceRepo->add($service, (int)$providerId);
484 }
485 }
486
487 $providerServiceRepo->deleteDuplicated(
488 $service->getId()->getValue(),
489 Entities::SERVICE
490 );
491 }
492
493 /**
494 * @param Service $service
495 *
496 * @throws ContainerValueNotFoundException
497 * @throws QueryExecutionException
498 * @throws InvalidArgumentException
499 */
500 public function managePackagesForServiceUpdate($service)
501 {
502 /** @var PackageRepository $packageRepository */
503 $packageRepository = $this->container->get('domain.bookable.package.repository');
504
505 /** @var Collection $packages */
506 $packages = $packageRepository->getByCriteria([]);
507
508 /** @var Package $package */
509 foreach ($packages->getItems() as $package) {
510 $hasService = false;
511
512 /** @var PackageService $bookable */
513 foreach ($package->getBookable()->getItems() as $bookable) {
514 if ($bookable->getService()->getId()->getValue() === $service->getId()->getValue()) {
515 $hasService = true;
516
517 break;
518 }
519 }
520
521 if ($hasService && $package->getCalculatedPrice()->getValue()) {
522 $price = 0;
523
524 /** @var PackageService $bookable */
525 foreach ($package->getBookable()->getItems() as $bookable) {
526 $price += $bookable->getService()->getPrice()->getValue() * $bookable->getQuantity()->getValue();
527 }
528
529 $package->setPrice(new Price($price));
530
531 $packageRepository->update($package->getId()->getValue(), $package);
532 }
533 }
534 }
535
536 /**
537 * Accept two collection: services and providers
538 * For each service function will add providers that are working on this service
539 *
540 * @param Service $service
541 * @param Collection $providers
542 *
543 * @return Collection
544 *
545 * @throws InvalidArgumentException
546 */
547 public function getServiceProviders($service, $providers)
548 {
549 $serviceProviders = new Collection();
550
551 /** @var Provider $provider */
552 foreach ($providers->getItems() as $provider) {
553 /** @var Service $providerService */
554 foreach ($provider->getServiceList()->getItems() as $providerService) {
555 if ($providerService->getId()->getValue() === $service->getId()->getValue()) {
556 $serviceProviders->addItem($provider, $provider->getId()->getValue());
557 }
558 }
559 }
560
561 return $serviceProviders;
562 }
563
564 /**
565 * Add 0 as duration for service time before or time after if it is null
566 *
567 * @param Service $service
568 *
569 * @throws InvalidArgumentException
570 */
571 public function checkServiceTimes($service)
572 {
573 if (!$service->getTimeBefore()) {
574 $service->setTimeBefore(new Duration(0));
575 }
576
577 if (!$service->getTimeAfter()) {
578 $service->setTimeAfter(new Duration(0));
579 }
580 }
581
582 /**
583 * Return collection of extras that are passed in $extraIds array for provided service
584 *
585 * @param array $extraIds
586 * @param Service $service
587 *
588 * @return Collection
589 * @throws InvalidArgumentException
590 */
591 public function filterServiceExtras($extraIds, $service)
592 {
593 $extras = new Collection();
594
595 foreach ((array)$service->getExtras()->keys() as $extraKey) {
596 /** @var Extra $extra */
597 $extra = $service->getExtras()->getItem($extraKey);
598
599 if (in_array($extra->getId()->getValue(), $extraIds, false)) {
600 if (!$extra->getDuration()) {
601 $extra->setDuration(new Duration(0));
602 }
603
604 $extras->addItem($extra, $extraKey);
605 }
606 }
607
608 return $extras;
609 }
610
611 /**
612 *
613 * @param array $servicesIds
614 *
615 * @return array
616 *
617 * @throws ContainerValueNotFoundException
618 * @throws QueryExecutionException
619 * @throws InvalidArgumentException
620 */
621 public function getAppointmentsCountForServices($servicesIds)
622 {
623 /** @var AppointmentRepository $appointmentRepository */
624 $appointmentRepository = $this->container->get('domain.booking.appointment.repository');
625
626 /** @var PackageCustomerServiceRepository $packageCustomerServiceRepository */
627 $packageCustomerServiceRepository = $this->container->get('domain.bookable.packageCustomerService.repository');
628
629 $futureAppointmentsCount = $appointmentRepository->getPeriodAppointmentsCount(
630 [
631 'services' => $servicesIds,
632 'dates' => [
633 0 => DateTimeService::getNowDateTime()
634 ]
635 ]
636 );
637
638 $pastAppointmentsCount = $appointmentRepository->getPeriodAppointmentsCount(
639 [
640 'services' => $servicesIds,
641 'dates' => [
642 1 => DateTimeService::getNowDateTime()
643 ]
644 ]
645 );
646
647 if ($futureAppointmentsCount) {
648 return [
649 'futureAppointments' => $futureAppointmentsCount,
650 'pastAppointments' => $pastAppointmentsCount,
651 ];
652 }
653
654 /** @var Collection $appointments */
655 $appointments = $appointmentRepository->getFiltered(['services' => $servicesIds]);
656
657 /** @var Collection $packageCustomerServices */
658 $packageCustomerServices = $packageCustomerServiceRepository->getByCriteria(['services' => $servicesIds]);
659
660 /** @var AbstractPackageApplicationService $packageApplicationService */
661 $packageApplicationService = $this->container->get('application.bookable.package');
662
663 return [
664 'futureAppointments' => $futureAppointmentsCount,
665 'pastAppointments' => $pastAppointmentsCount,
666 'packageAppointments' => $packageApplicationService->getPackageUnusedBookingsCount(
667 $packageCustomerServices,
668 $appointments
669 ),
670 ];
671 }
672
673 /**
674 *
675 * @param array $packagesIds
676 *
677 * @return array
678 *
679 * @throws ContainerValueNotFoundException
680 * @throws QueryExecutionException
681 * @throws InvalidArgumentException
682 */
683 public function getAppointmentsCountForPackages($packagesIds)
684 {
685 /** @var AppointmentRepository $appointmentRepository */
686 $appointmentRepository = $this->container->get('domain.booking.appointment.repository');
687
688 /** @var PackageCustomerServiceRepository $packageCustomerServiceRepository */
689 $packageCustomerServiceRepository = $this->container->get('domain.bookable.packageCustomerService.repository');
690
691 /** @var Collection $packageCustomerServices */
692 $packageCustomerServices = $packageCustomerServiceRepository->getByCriteria(['packages' => $packagesIds]);
693
694 /** @var Collection $appointments */
695 $appointments = $packageCustomerServices->keys() ? $appointmentRepository->getFiltered(
696 ['packageCustomerServices' => $packageCustomerServices->keys()]
697 ) : new Collection();
698
699 $now = DateTimeService::getNowDateTimeObject();
700
701 $futureAppointments = 0;
702
703 $pastAppointments = 0;
704
705 /** @var Appointment $appointment */
706 foreach ($appointments->getItems() as $appointment) {
707 if ($appointment->getBookingStart()->getValue() >= $now) {
708 $futureAppointments++;
709 } else {
710 $pastAppointments++;
711 }
712 }
713
714 /** @var AbstractPackageApplicationService $packageApplicationService */
715 $packageApplicationService = $this->container->get('application.bookable.package');
716
717 return [
718 'futureAppointments' => $futureAppointments,
719 'pastAppointments' => $pastAppointments,
720 'packageAppointments' => $packageApplicationService->getPackageUnusedBookingsCount(
721 $packageCustomerServices,
722 $appointments
723 ),
724 ];
725 }
726
727 /**
728 *
729 * @param Category $category
730 *
731 * @return boolean
732 *
733 * @throws ContainerValueNotFoundException
734 * @throws QueryExecutionException
735 * @throws ContainerException
736 * @throws InvalidArgumentException
737 */
738 public function deleteCategory($category)
739 {
740 /** @var CategoryRepository $categoryRepository */
741 $categoryRepository = $this->container->get('domain.bookable.category.repository');
742
743 /** @var Service $service */
744 foreach ($category->getServiceList()->getItems() as $service) {
745 if (!$this->deleteService($service)) {
746 return false;
747 }
748 }
749
750 return $categoryRepository->delete($category->getId()->getValue());
751 }
752
753 /**
754 *
755 * @param Service $service
756 *
757 * @return boolean
758 *
759 * @throws ContainerValueNotFoundException
760 * @throws QueryExecutionException
761 * @throws ContainerException
762 * @throws InvalidArgumentException
763 */
764 public function deleteService($service)
765 {
766 /** @var GalleryApplicationService $galleryService */
767 $galleryService = $this->container->get('application.gallery.service');
768
769 /** @var AppointmentRepository $appointmentRepository */
770 $appointmentRepository = $this->container->get('domain.booking.appointment.repository');
771
772 /** @var ServiceRepository $serviceRepository */
773 $serviceRepository = $this->container->get('domain.bookable.service.repository');
774
775 /** @var TaxEntityRepository $taxEntityRepository */
776 $taxEntityRepository = $this->container->get('domain.tax.entity.repository');
777
778 /** @var CouponServiceRepository $couponServiceRepository */
779 $couponServiceRepository = $this->container->get('domain.coupon.service.repository');
780
781 /** @var ProviderServiceRepository $providerServiceRepository */
782 $providerServiceRepository = $this->container->get('domain.bookable.service.providerService.repository');
783
784 /** @var PeriodServiceRepository $periodServiceRepository */
785 $periodServiceRepository = $this->container->get('domain.schedule.period.service.repository');
786
787 /** @var SpecialDayPeriodServiceRepository $specialDayPeriodServiceRepository */
788 $specialDayPeriodServiceRepository =
789 $this->container->get('domain.schedule.specialDay.period.service.repository');
790
791 /** @var CustomFieldServiceRepository $customFieldServiceRepository */
792 $customFieldServiceRepository = $this->container->get('domain.customFieldService.repository');
793
794 /** @var AppointmentApplicationService $appointmentApplicationService */
795 $appointmentApplicationService = $this->container->get('application.booking.appointment.service');
796
797 /** @var NotificationsToEntitiesRepository $notificationEntitiesRepo */
798 $notificationEntitiesRepo = $this->container->get('domain.notificationEntities.repository');
799
800 /** @var PackageServiceRepository $packageServiceRepository */
801 $packageServiceRepository = $this->container->get('domain.bookable.package.packageService.repository');
802
803 /** @var ResourceEntitiesRepository $resourceEntitiesRepository */
804 $resourceEntitiesRepository = $this->container->get('domain.bookable.resourceEntities.repository');
805
806 /** @var PackageCustomerServiceRepository $packageCustomerServiceRepository */
807 $packageCustomerServiceRepository =
808 $this->container->get('domain.bookable.packageCustomerService.repository');
809
810 /** @var PackageServiceProviderRepository $packageServiceProviderRepository */
811 $packageServiceProviderRepository =
812 $this->container->get('domain.bookable.package.packageServiceProvider.repository');
813
814 /** @var PackageServiceLocationRepository $packageServiceLocationRepository */
815 $packageServiceLocationRepository =
816 $this->container->get('domain.bookable.package.packageServiceLocation.repository');
817
818 /** @var PackageRepository $packageRepository */
819 $packageRepository = $this->container->get('domain.bookable.package.repository');
820
821 /** @var Collection $packages */
822 $packages = $packageRepository->getByCriteria(['services' => [$service->getId()->getValue()]]);
823
824 /** @var Collection $appointments */
825 $appointments = $appointmentRepository->getFiltered(
826 [
827 'services' => [$service->getId()->getValue()]
828 ]
829 );
830
831 /** @var Appointment $appointment */
832 foreach ($appointments->getItems() as $appointment) {
833 if (!$appointmentApplicationService->delete($appointment)) {
834 return false;
835 }
836 }
837
838 if (!$notificationEntitiesRepo->removeIfOnly($service->getId()->getValue())) {
839 return false;
840 }
841
842 /** @var Extra $extra */
843 foreach ($service->getExtras()->getItems() as $extra) {
844 if (!$this->deleteExtra($extra)) {
845 return false;
846 }
847 }
848
849 /** @var Package $package */
850 foreach ($packages->getItems() as $package) {
851 /** @var PackageService $packageService */
852 foreach ($package->getBookable()->getItems() as $packageService) {
853 if ($packageService->getService()->getId()->getValue() === $service->getId()->getValue()) {
854 if (!$packageServiceProviderRepository->deleteByEntityId(
855 $packageService->getId()->getValue(),
856 'packageServiceId'
857 ) ||
858 !$packageServiceLocationRepository->deleteByEntityId(
859 $packageService->getId()->getValue(),
860 'packageServiceId'
861 )
862 ) {
863 return false;
864 }
865 }
866 }
867 }
868
869 return
870 $galleryService->manageGalleryForEntityDelete($service->getGallery()) &&
871 $customFieldServiceRepository->deleteByEntityId($service->getId()->getValue(), 'serviceId') &&
872 $specialDayPeriodServiceRepository->deleteByEntityId($service->getId()->getValue(), 'serviceId') &&
873 $periodServiceRepository->deleteByEntityId($service->getId()->getValue(), 'serviceId') &&
874 $providerServiceRepository->deleteByEntityId($service->getId()->getValue(), 'serviceId') &&
875 $taxEntityRepository->deleteByEntityIdAndEntityType($service->getId()->getValue(), 'service') &&
876 $couponServiceRepository->deleteByEntityId($service->getId()->getValue(), 'serviceId') &&
877 $serviceRepository->deleteViewStats($service->getId()->getValue()) &&
878 $packageServiceRepository->deleteByEntityId($service->getId()->getValue(), 'serviceId') &&
879 $packageCustomerServiceRepository->deleteByEntityId($service->getId()->getValue(), 'serviceId') &&
880 $resourceEntitiesRepository->deleteByEntityIdAndEntityType($service->getId()->getValue(), 'service') &&
881 $serviceRepository->delete($service->getId()->getValue());
882 }
883
884 /**
885 *
886 * @param Package $package
887 *
888 * @return boolean
889 *
890 * @throws ContainerValueNotFoundException
891 * @throws QueryExecutionException
892 * @throws ContainerException
893 * @throws InvalidArgumentException
894 */
895 public function deletePackage($package)
896 {
897 /** @var GalleryApplicationService $galleryService */
898 $galleryService = $this->container->get('application.gallery.service');
899
900 /** @var CustomerBookingRepository $customerBookingRepository */
901 $customerBookingRepository = $this->container->get('domain.booking.customerBooking.repository');
902
903 /** @var PaymentRepository $paymentRepository */
904 $paymentRepository = $this->container->get('domain.payment.repository');
905
906 /** @var PackageRepository $packageRepository */
907 $packageRepository = $this->container->get('domain.bookable.package.repository');
908
909 /** @var PackageServiceRepository $packageServiceRepository */
910 $packageServiceRepository = $this->container->get('domain.bookable.package.packageService.repository');
911
912 /** @var PackageServiceLocationRepository $packageServiceLocationRepository */
913 $packageServiceLocationRepository =
914 $this->container->get('domain.bookable.package.packageServiceLocation.repository');
915
916 /** @var PackageServiceProviderRepository $packageServiceProviderRepository */
917 $packageServiceProviderRepository =
918 $this->container->get('domain.bookable.package.packageServiceProvider.repository');
919
920 /** @var PackageCustomerRepository $packageCustomerRepository */
921 $packageCustomerRepository = $this->container->get('domain.bookable.packageCustomer.repository');
922
923 /** @var PackageCustomerServiceRepository $packageCustomerServiceRepository */
924 $packageCustomerServiceRepository = $this->container->get('domain.bookable.packageCustomerService.repository');
925
926 /** @var PaymentApplicationService $paymentAS */
927 $paymentAS = $this->container->get('application.payment.service');
928
929 /** @var TaxEntityRepository $taxEntityRepository */
930 $taxEntityRepository = $this->container->get('domain.tax.entity.repository');
931
932 /** @var CouponPackageRepository $couponPackageRepository */
933 $couponPackageRepository = $this->container->get('domain.coupon.package.repository');
934
935 /** @var Collection $packageCustomerServices */
936 $packageCustomerServices = $packageCustomerServiceRepository->getByCriteria(
937 ['packages' => [$package->getId()->getValue()]]
938 );
939
940 /** @var PackageCustomerService $packageCustomerService */
941 foreach ($packageCustomerServices->getItems() as $packageCustomerService) {
942 if (!$customerBookingRepository->updateByEntityId(
943 $packageCustomerService->getId()->getValue(),
944 null,
945 'packageCustomerServiceId'
946 )) {
947 return false;
948 }
949 }
950
951 /** @var Collection $packageCustomers */
952 $packageCustomers = $packageCustomerRepository->getByEntityId($package->getId()->getValue(), 'packageId');
953
954 /** @var PackageCustomer $packageCustomer */
955 foreach ($packageCustomers->getItems() as $packageCustomer) {
956 /** @var Collection $payments */
957 $payments = $paymentRepository->getByEntityId(
958 $packageCustomer->getId()->getValue(),
959 'packageCustomerId'
960 );
961
962 /** @var Payment $payment */
963 foreach ($payments->getItems() as $payment) {
964 if (!$paymentAS->delete($payment)) {
965 return false;
966 }
967 }
968
969 if (!$packageCustomerServiceRepository->deleteByEntityId(
970 $packageCustomer->getId()->getValue(),
971 'packageCustomerId'
972 ) ||
973 !$packageCustomerRepository->delete($packageCustomer->getId()->getValue())
974 ) {
975 return false;
976 }
977 }
978
979 /** @var PackageService $packageService */
980 foreach ($package->getBookable()->getItems() as $packageService) {
981 $packageServiceId = $packageService->getId()->getValue();
982
983 if (!$packageServiceLocationRepository->deleteByEntityId($packageServiceId, 'packageServiceId') ||
984 !$packageServiceProviderRepository->deleteByEntityId($packageServiceId, 'packageServiceId')
985 ) {
986 return false;
987 }
988 }
989
990 return
991 $galleryService->manageGalleryForEntityDelete($package->getGallery()) &&
992 $packageServiceRepository->deleteByEntityId($package->getId()->getValue(), 'packageId') &&
993 $taxEntityRepository->deleteByEntityIdAndEntityType($package->getId()->getValue(), 'package') &&
994 $couponPackageRepository->deleteByEntityId($package->getId()->getValue(), 'packageId') &&
995 $packageRepository->delete($package->getId()->getValue());
996 }
997
998 /**
999 *
1000 * @param PackageCustomer $packageCustomer
1001 *
1002 * @return array|bool
1003 *
1004 * @throws ContainerException
1005 * @throws InvalidArgumentException
1006 * @throws NotFoundException
1007 * @throws QueryExecutionException
1008 */
1009 public function deletePackageCustomer($packageCustomer)
1010 {
1011 /** @var AppointmentApplicationService $appointmentApplicationService */
1012 $appointmentApplicationService = $this->container->get('application.booking.appointment.service');
1013
1014 /** @var BookingApplicationService $bookingApplicationService */
1015 $bookingApplicationService = $this->container->get('application.booking.booking.service');
1016
1017 /** @var PaymentRepository $paymentRepository */
1018 $paymentRepository = $this->container->get('domain.payment.repository');
1019
1020 /** @var PackageCustomerRepository $packageCustomerRepository */
1021 $packageCustomerRepository = $this->container->get('domain.bookable.packageCustomer.repository');
1022
1023 /** @var PackageCustomerServiceRepository $packageCustomerServiceRepository */
1024 $packageCustomerServiceRepository = $this->container->get('domain.bookable.packageCustomerService.repository');
1025
1026 /** @var AppointmentRepository $appointmentRepository */
1027 $appointmentRepository = $this->container->get('domain.booking.appointment.repository');
1028
1029 /** @var PaymentApplicationService $paymentApplicationService */
1030 $paymentApplicationService = $this->container->get('application.payment.service');
1031
1032
1033 $resultData = [
1034 'updatedAppointments' => [],
1035 'deletedAppointments' => [],
1036 ];
1037
1038 /** @var Collection $packageCustomerServices */
1039 $packageCustomerServices = $packageCustomerServiceRepository->getByCriteria(
1040 ['packagesCustomers' => [$packageCustomer->getId()->getValue()]]
1041 );
1042
1043 /** @var Collection $packageAppointments */
1044 $packageAppointments = $packageCustomerServices->length() ? $appointmentRepository->getFiltered(
1045 [
1046 'packageCustomerServices' => $packageCustomerServices->keys()
1047 ]
1048 ) : new Collection();
1049
1050 if ($packageAppointments->length()) {
1051 /** @var Collection $appointments */
1052 $appointments = $appointmentRepository->getFiltered(['ids' => $packageAppointments->keys()]);
1053
1054 /** @var Appointment $appointment */
1055 foreach ($appointments->getItems() as $appointment) {
1056 $serviceId = $appointment->getServiceId()->getValue();
1057
1058 /** @var CustomerBooking $customerBooking */
1059 foreach ($appointment->getBookings()->getItems() as $customerBooking) {
1060 if ($customerBooking->getPackageCustomerService() &&
1061 $packageCustomerServices->keyExists(
1062 $customerBooking->getPackageCustomerService()->getId()->getValue()
1063 )
1064 ) {
1065 /** @var PackageCustomerService $packageCustomerService */
1066 $packageCustomerService = $packageCustomerServices->getItem(
1067 $customerBooking->getPackageCustomerService()->getId()->getValue()
1068 );
1069
1070 $packageId = $packageCustomerService->getPackageCustomer()->getPackageId()->getValue();
1071
1072 $id = $packageCustomerService->getId()->getValue();
1073
1074 $customerId = $customerBooking->getCustomerId()->getValue();
1075
1076 if (!empty($packageData[$customerId][$serviceId][$packageId][$id])) {
1077 if ($packageData[$customerId][$serviceId][$packageId][$id]['available'] > 0) {
1078 $packageData[$customerId][$serviceId][$packageId][$id]['available']--;
1079 } else {
1080 foreach ($packageData[$customerId][$serviceId][$packageId] as $pcsId => $value) {
1081 if ($value['available'] > 0) {
1082 $packageData[$customerId][$serviceId][$packageId][$pcsId]['available']--;
1083
1084 $customerBooking->getPackageCustomerService()->setId(new Id($pcsId));
1085
1086 break;
1087 }
1088 }
1089 }
1090 }
1091 }
1092 }
1093 }
1094
1095 /** @var Appointment $appointment */
1096 foreach ($appointments->getItems() as $appointment) {
1097 if ($appointment->getBookings()->length() === 1) {
1098 if (!$appointmentApplicationService->delete($appointment)) {
1099 return false;
1100 }
1101
1102 $resultData['deletedAppointments'][] =
1103 $appointmentApplicationService->removeBookingFromNonGroupAppointment(
1104 $appointment,
1105 $appointment->getBookings()->getItem($appointment->getBookings()->keys()[0])
1106 );
1107 } else {
1108 $removedBooking = null;
1109
1110 /** @var CustomerBooking $customerBooking */
1111 foreach ($appointment->getBookings()->getItems() as $customerBooking) {
1112 if ($customerBooking->getPackageCustomerService() &&
1113 in_array(
1114 $customerBooking->getPackageCustomerService()->getId()->getValue(),
1115 $packageCustomerServices->keys()
1116 )
1117 ) {
1118 if (!$bookingApplicationService->delete($customerBooking)) {
1119 return false;
1120 }
1121
1122 $removedBooking = $customerBooking;
1123 }
1124 }
1125
1126 if ($removedBooking) {
1127 $result = $appointmentApplicationService->removeBookingFromGroupAppointment(
1128 $appointment,
1129 $removedBooking
1130 );
1131
1132 foreach ($result['bookingsWithChangedStatus'] as &$booking) {
1133 if ($booking['id'] === $removedBooking->getId()->getValue()) {
1134 $booking['skipNotification'] = true;
1135 }
1136 }
1137
1138 $resultData['updatedAppointments'][] = $result;
1139 }
1140 }
1141 }
1142 }
1143
1144 /** @var Collection $payments */
1145 $payments = $paymentRepository->getByEntityId(
1146 $packageCustomer->getId()->getValue(),
1147 'packageCustomerId'
1148 );
1149
1150 /** @var Payment $payment */
1151 foreach ($payments->getItems() as $payment) {
1152 if (!$paymentApplicationService->delete($payment)) {
1153 return false;
1154 }
1155 }
1156
1157 if (!$packageCustomerServiceRepository->deleteByEntityId(
1158 $packageCustomer->getId()->getValue(),
1159 'packageCustomerId'
1160 ) ||
1161 !$packageCustomerRepository->delete($packageCustomer->getId()->getValue())
1162 ) {
1163 return false;
1164 }
1165
1166 return $resultData;
1167 }
1168
1169 /**
1170 *
1171 * @param Extra $extra
1172 *
1173 * @return boolean
1174 *
1175 * @throws ContainerValueNotFoundException
1176 * @throws QueryExecutionException
1177 */
1178 public function deleteExtra($extra)
1179 {
1180 /** @var ExtraRepository $extraRepository */
1181 $extraRepository = $this->container->get('domain.bookable.extra.repository');
1182
1183 /** @var CustomerBookingExtraRepository $customerBookingExtraRepository */
1184 $customerBookingExtraRepository = $this->container->get('domain.booking.customerBookingExtra.repository');
1185
1186 return
1187 $customerBookingExtraRepository->deleteByEntityId($extra->getId()->getValue(), 'extraId') &&
1188 $extraRepository->delete($extra->getId()->getValue());
1189 }
1190
1191 /**
1192 *
1193 * @param Service $service
1194 * @param int $duration
1195 *
1196 * @return boolean
1197 *
1198 * @throws ContainerValueNotFoundException
1199 * @throws InvalidArgumentException
1200 */
1201 public function modifyServicePriceByDuration($service, $duration)
1202 {
1203 if ($duration) {
1204 $customPricing = $service->getCustomPricing()
1205 ? json_decode($service->getCustomPricing()->getValue(), true) : null;
1206
1207 if ($customPricing &&
1208 $customPricing['enabled'] &&
1209 array_key_exists($duration, $customPricing['durations'])
1210 ) {
1211 $service->setPrice(
1212 new Price($customPricing['durations'][$duration]['price'])
1213 );
1214 }
1215 }
1216 }
1217 }
1218