container = $container; } /** @noinspection MoreThanThreeArgumentsInspection */ /** * @param CommandResult $result * @param array $appointmentData * @param bool $inspectTimeSlot * @param bool $inspectCoupon * @param bool $save * * @return array|null * @throws \Slim\Exception\ContainerValueNotFoundException * @throws InvalidArgumentException * @throws QueryExecutionException * @throws \Exception * @throws \Interop\Container\Exception\ContainerException */ public function process($result, $appointmentData, $inspectTimeSlot, $inspectCoupon, $save) { /** @var CouponApplicationService $couponAS */ $couponAS = $this->container->get('application.coupon.service'); /** @var SettingsService $settingsService */ $settingsService = $this->container->get('domain.settings.service'); if (isset($appointmentData['payment']) && isset($appointmentData['payment']['gateway']) === PaymentType::ON_SITE && !$settingsService->getSetting('payments', 'onSite')) { $result->setResult(CommandResult::RESULT_ERROR); $result->setData(['paymentError' => true]); return null; } /** @var Coupon $coupon */ $coupon = null; // Inspect if coupon is existing and valid if sent from the front-end. if ($appointmentData['couponCode']) { $coupon = $couponAS->processCoupon( $appointmentData['couponCode'], $appointmentData['serviceId'], $inspectCoupon, $result ); if ($result->getResult() === CommandResult::RESULT_ERROR) { return null; } if ($coupon) { $appointmentData['bookings'][0]['coupon'] = $coupon->toArray(); } } $appointmentData['bookings'][0]['info'] = json_encode([ 'firstName' => $appointmentData['bookings'][0]['customer']['firstName'], 'lastName' => $appointmentData['bookings'][0]['customer']['lastName'], 'phone' => $appointmentData['bookings'][0]['customer']['phone'], ]); /** @var AbstractUser $user */ $user = null; $newUserId = null; // Create a new user if doesn't exists. For adding appointment from the front-end. if (!$appointmentData['bookings'][0]['customerId'] && !$appointmentData['bookings'][0]['customer']['id']) { /** @var CustomerApplicationService $customerAS */ $customerAS = $this->container->get('application.user.customer.service'); /** @var UserRepository $userRepository */ $userRepository = $this->container->get('domain.users.repository'); $user = $customerAS->getNewOrExistingCustomer($appointmentData['bookings'][0]['customer'], $result); if ($result->getResult() === CommandResult::RESULT_ERROR) { return null; } if ($save && !$user->getId()) { if (!($newUserId = $userRepository->add($user))) { $result->setResult(CommandResult::RESULT_ERROR); $result->setData(['emailError' => true]); return null; } $user->setId(new Id($newUserId)); } if ($user->getId()) { $appointmentData['bookings'][0]['customerId'] = $user->getId()->getValue(); } } try { $bookingData = $this->book($appointmentData, $inspectTimeSlot, $save); } catch (CustomerBookedException $e) { $result->setResult(CommandResult::RESULT_ERROR); $result->setMessage(FrontendStrings::getCommonStrings()['customer_already_booked']); $result->setData([ 'customerAlreadyBooked' => true ]); return null; } catch (BookingUnavailableException $e) { $result->setResult(CommandResult::RESULT_ERROR); $result->setMessage(FrontendStrings::getCommonStrings()['time_slot_unavailable']); $result->setData([ 'timeSlotUnavailable' => true ]); return null; } /** @var CustomerBooking $booking */ $booking = $bookingData['booking']; if ($save) { try { $createNewUser = $settingsService->getSetting('roles', 'automaticallyCreateCustomer'); if ($newUserId && $user && $createNewUser && $user->getEmail() ) { /** @var UserApplicationService $userAS */ $userAS = $this->container->get('application.user.service'); if ($user->getExternalId() && $user->getExternalId()->getValue()) { $userAS->setWpUserIdForExistingUser($user->getId()->getValue(), $user); } else { $userAS->setWpUserIdForNewUser($user->getId()->getValue(), $user); } } if ($createNewUser && $user && $user->getExternalId()) { $booking->getCustomer()->setExternalId(new Id($user->getExternalId()->getValue())); } } catch (\Exception $e) { } } return $bookingData; } /** * @param CustomerBooking $booking * @param AbstractBookable $bookable * * @return float * * @throws InvalidArgumentException */ public function getPaymentAmount($booking, $bookable) { $price = (float)$bookable->getPrice()->getValue() * $booking->getPersons()->getValue(); foreach ((array)$booking->getExtras()->keys() as $extraKey) { /** @var CustomerBookingExtra $customerBookingExtra */ $customerBookingExtra = $booking->getExtras()->getItem($extraKey); $extraId = $customerBookingExtra->getExtraId()->getValue(); /** @var Extra $extra */ $extra = $bookable->getExtras()->getItem($extraId); $price += (float)$extra->getPrice()->getValue() * $booking->getPersons()->getValue() * $customerBookingExtra->getQuantity()->getValue(); } if ($booking->getCoupon()) { $price -= $price / 100 * ($booking->getCoupon()->getDiscount()->getValue() ?: 0) + ($booking->getCoupon()->getDeduction()->getValue() ?: 0); } return $price; } /** @noinspection MoreThanThreeArgumentsInspection */ /** * @param int $bookingId * @param array $paymentData * @param float $amount * @param \DateTime $dateTime * * @return boolean * @throws \Slim\Exception\ContainerValueNotFoundException * @throws InvalidArgumentException * @throws QueryExecutionException * @throws \Interop\Container\Exception\ContainerException */ function addPayment($bookingId, $paymentData, $amount, $dateTime) { /** @var PaymentRepository $paymentRepository */ $paymentRepository = $this->container->get('domain.payment.repository'); $paymentStatus = PaymentStatus::PENDING; switch ($paymentData['gateway']) { case (PaymentType::WC): $paymentStatus = $paymentData['status']; break; case (PaymentType::PAY_PAL): $paymentStatus = PaymentStatus::PAID; break; case (PaymentType::STRIPE): $paymentStatus = PaymentStatus::PAID; break; } $paymentAmount = $paymentData['gateway'] === PaymentType::ON_SITE ? 0 : $amount; $payment = PaymentFactory::create([ 'customerBookingId' => $bookingId, 'amount' => $paymentAmount, 'status' => $paymentStatus, 'gateway' => $paymentData['gateway'], 'dateTime' => ($paymentData['gateway'] === PaymentType::ON_SITE) ? $dateTime->format('Y-m-d H:i:s') : DateTimeService::getNowDateTimeObject()->format('Y-m-d H:i:s'), 'gatewayTitle' => isset($paymentData['gatewayTitle']) ? $paymentData['gatewayTitle'] : '' ]); if (!$payment instanceof Payment) { throw new InvalidArgumentException('Unknown type'); } return $paymentRepository->add($payment); } /** * @param CustomerBooking $booking * @param string $token * * @return boolean * * @throws \Slim\Exception\ContainerValueNotFoundException * @throws \Interop\Container\Exception\ContainerException * @throws AccessDeniedException */ function inspectToken($booking, $token) { $loggedInUser = $this->container->get('logged.in.user'); if (($token !== null && $token !== $booking->getToken()->getValue()) || ( $token === null && $loggedInUser && $loggedInUser->getId() !== null && $loggedInUser->getId()->getValue() !== $booking->getCustomerId()->getValue() ) ) { throw new AccessDeniedException('You are not allowed to update booking status'); } return true; } /** * @param \DateTime $bookingStart * * @return boolean * * @throws \Slim\Exception\ContainerValueNotFoundException * @throws \Interop\Container\Exception\ContainerException * @throws BookingCancellationException */ function inspectMinimumCancellationTime($bookingStart) { /** @var SettingsService $settingsService */ $settingsService = $this->container->get('domain.settings.service'); $minimumCancelTime = $settingsService->getCategorySettings('general')['minimumTimeRequirementPriorToCanceling']; if (DateTimeService::getNowDateTimeObject() >= DateTimeService::getCustomDateTimeObject( $bookingStart->format('Y-m-d H:i:s'))->modify("-{$minimumCancelTime} second") ) { throw new BookingCancellationException('You are not allowed to update booking status'); } return true; } }