request = $request; $this->bookingService = $bookingService; $this->bookingRoomService = $bookingRoomService; $this->bookingRoomPaxService = $bookingRoomPaxService; $this->bookingContactService = $bookingContactService; $this->bookingPaymentService = $bookingPaymentService; $this->propertyRoomAvailabilityService = $propertyRoomAvailabilityService; $this->propertyChannelMappingService = $propertyChannelMappingService; $this->propertyPaymentService = $propertyPaymentService; $this->channelManagerBookingService = $channelManagerBookingService; $this->channelManagerPropertyMappingService = $channelManagerPropertyMappingService; $this->channelId = $this->request->channelId; $this->channelToken = $this->request->channelToken; $this->bookingEngineToken = $this->request->bookingEngineToken; $this->bookingEnginePropertyId = $this->request->bookingEnginePropertyId; $this->newBookingMailService = $newBookingMailService; $this->notificationService = $notificationService; $this->propertyAddonService = $propertyAddonService; $this->bookingAddonService = $bookingAddonService; $this->propertyChannelCouponService = $propertyChannelCouponService; $this->propertyBookingEngineSearchService = $propertyBookingEngineSearchService; $this->channelService = $channelService; $this->propertyBookingEngineService = $propertyBookingEngineService; $this->currencyService = $currencyService; $this->mailer = $mailer; } public function checkRoomAndCacheData($roomInfo, $searchCacheData) { $checkRoomAndCache = true; $roomPricesCollect = collect($searchCacheData['roomPrices']); foreach ($roomInfo as $roomKey => $room) { $cachedSearchPriceKeys = $roomPricesCollect->where('occupancyCode', $room['occupancyCode'])->keys()->toArray(); if (!in_array($room['rateKey'], $cachedSearchPriceKeys)) { $checkRoomAndCache = false; continue; } } return $checkRoomAndCache; } public function getPropertyRoomAndRoomRateAvailability($param = []) { $response = ['status' => false, 'message' => '']; try { $requestParam = [ 'criteria' => [ ['field' => 'property_id', 'condition' => '=', 'value' => $param['property_id']], ['field' => 'availability', 'condition' => '>', 'value' => 0], ['field' => 'date', 'condition' => '>=', 'value' => $param['checkIn']], ['field' => 'date', 'condition' => '<', 'value' => $param['checkOut']], ['field' => 'status', 'condition' => '=', 'value' => 1], ], 'with' => ['roomDetail.propertyRoomConnected'], 'orderBy' => [ ['field' => 'availability_type_id', 'value' => 'ASC'], ['field' => 'property_room_id', 'value' => 'ASC'], ['field' => 'room_rate_mapping_id', 'value' => 'ASC'], ['field' => 'date', 'value' => 'ASC'] ], ]; $getPropertyRoomAndRoomRateAvailability = $this->propertyRoomAvailabilityService->select($requestParam); if ($getPropertyRoomAndRoomRateAvailability['status'] != 'success' || empty($getPropertyRoomAndRoomRateAvailability['data'])) { throw new ApiErrorException(lang('PropertyRoomAndRoomRateAvailability not found')); } $response = [ 'status' => true, 'data' => $getPropertyRoomAndRoomRateAvailability['data'] ]; } catch (ApiErrorException $e) { $response['message'] = implode(', ', $e->getMessageArr()); } catch (Exception $e) { $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage(); Log::error($message); $response['message'] = $e->getMessage(); } return $response; } public function getChannelPropertyDetail($channelId, $propertyId) { $response = ['status' => false, 'message' => '']; try { $requestParam = [ 'criteria' => [ ['field' => 'channel_id', 'condition' => '=', 'value' => $channelId], ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId], ['field' => 'status', 'condition' => '=', 'value' => 1], ], 'with' => [ 'property', 'channelAvailabilityType', 'channelBookingType', 'channelRoomPricingType', 'channelBookingPaymentType.paymentType', 'channel' ], 'firstRow' => true, ]; $getChannelProperty = $this->propertyChannelMappingService->select($requestParam); $response = [ 'status' => true, 'data' => $getChannelProperty['data'], ]; } catch (ApiErrorException $e) { $response['message'] = implode(', ', $e->getMessageArr()); } catch (Exception $e) { $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage(); Log::error($message); $response['message'] = $e->getMessage(); } return $response; } public function booking(Request $request) { $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500]; try { if (is_null($this->request->getContent())) { throw new ApiErrorException(lang('Parameter Error.')); } $params = json_decode($this->request->getContent(), 1); $roomInfo = $params['roomInfo']; $contactInfo = $params['contactInfo']; $searchKey = $params['searchKey']; $couponCode = fillOnUndefined($params, 'couponCode'); $propertyId = $this->bookingEnginePropertyId; $extraParam = $params['extraParam'] ?? null; if (empty($propertyId)) { $propertyId = $params['propertyId']; } //SearchKey Check Data $searchCacheData = $this->getCacheDataWithSearchKey($searchKey); if (empty($searchCacheData)) { throw new ApiErrorException(lang('Cache data was expired.')); } $requestParams = $searchCacheData['requestParams']; //$checkRoomAndCacheData Check Data $checkRoomAndCacheData = $this->checkRoomAndCacheData($roomInfo, $searchCacheData); if (!$checkRoomAndCacheData) { throw new ApiErrorException(lang('Room rate keys are not matched.')); } $getChannelPropertyDetail = $this->getChannelPropertyDetail($this->channelId, $propertyId); if (!$getChannelPropertyDetail['status']) { throw new ApiErrorException(lang('Property and Channel are not matched.')); } $getChannelPropertyDetail = $getChannelPropertyDetail['data']; $currencyCode = null; $currencyCodes = []; $paymentCodes = []; $propertyIds = []; $totalRoomsPrice = 0; $roomAvailabilityKeyGroup = []; $searchCacheRoomPrices = $searchCacheData['roomPrices']; foreach ($roomInfo as $roomOccupancy => $room) { $rateKeyCodeDecoded = $this->rateKeyCodeDecode($searchCacheRoomPrices[$room['rateKey']]['rateKeyCode']); if ($rateKeyCodeDecoded['availabilityTypeId'] == 1) { if (!isset($roomAvailabilityKeyGroup[$rateKeyCodeDecoded['availabilityTypeId']][$rateKeyCodeDecoded['roomId']]['count'])) { $roomAvailabilityKeyGroup[$rateKeyCodeDecoded['availabilityTypeId']][$rateKeyCodeDecoded['roomId']]['count'] = 0; } $roomAvailabilityKeyGroup[$rateKeyCodeDecoded['availabilityTypeId']][$rateKeyCodeDecoded['roomId']]['count']++; $roomAvailabilityKeyGroup[$rateKeyCodeDecoded['availabilityTypeId']][$rateKeyCodeDecoded['roomId']]['detail'] = $rateKeyCodeDecoded; } else { if (!isset($roomAvailabilityKeyGroup[$rateKeyCodeDecoded['availabilityTypeId']][$rateKeyCodeDecoded['roomId']][$rateKeyCodeDecoded['rateMappingId']]['count'])) { $roomAvailabilityKeyGroup[$rateKeyCodeDecoded['availabilityTypeId']][$rateKeyCodeDecoded['roomId']][$rateKeyCodeDecoded['rateMappingId']]['count'] = 0; } $roomAvailabilityKeyGroup[$rateKeyCodeDecoded['availabilityTypeId']][$rateKeyCodeDecoded['roomId']][$rateKeyCodeDecoded['rateMappingId']]['count']++; $roomAvailabilityKeyGroup[$rateKeyCodeDecoded['availabilityTypeId']][$rateKeyCodeDecoded['roomId']][$rateKeyCodeDecoded['rateMappingId']]['detail'] = $rateKeyCodeDecoded; } $totalRoomsPrice += $searchCacheData['roomPrices'][$room['rateKey']]['total']; $currencyCodes[] = $searchCacheData['roomPrices'][$room['rateKey']]['currency']; $paymentCodes[] = $searchCacheData['roomPrices'][$room['rateKey']]['bookingPaymentType']['code']; $propertyIds[] = $rateKeyCodeDecoded['propertyId']; } $currencyCodes = array_unique($currencyCodes); if (count($currencyCodes) != 1) { throw new ApiErrorException(lang('Currency Code not matched')); } $currencyCode = reset($currencyCodes); $paymentCodes = array_unique($paymentCodes); if (count($paymentCodes) != 1) { throw new ApiErrorException(lang('Payment Code not matched')); } $paymentCode = reset($paymentCodes); if ($paymentCode != $params['paymentInfo']['paymentCode']) { throw new ApiErrorException(lang('Payment Code and Payment Code Param not matched')); } $propertyIds = array_unique($propertyIds); if (count($propertyIds) != 1) { throw new ApiErrorException(lang('Property ID not matched')); } if (reset($propertyIds) != $propertyId) { throw new ApiErrorException(lang('Property ID not matched')); } //dd($roomInfo); $roomInfoCollect = collect($roomInfo)->groupBy('occupancyCode')->toArray(); $roomsByOccupancies = $this->getRoomsByOccupancies($requestParams['rooms']); foreach ($roomsByOccupancies as $roomOccupancyKey => $roomsByOccupancy) { if (!isset($roomInfoCollect[$roomOccupancyKey])) { throw new ApiErrorException(lang('Room Occupancy Key not matched')); } if ($roomsByOccupancy['roomCount'] != count($roomInfoCollect[$roomOccupancyKey])) { throw new ApiErrorException(lang('Room Occupancy Count and Request Room Occupancy Count not matched')); } } $propertyRoomAndRoomRateAvailabilityParam = [ 'property_id' => $propertyId, 'checkIn' => $searchCacheData['requestParams']['date']['checkIn'], 'checkOut' => $searchCacheData['requestParams']['date']['checkOut'], ]; $getPropertyRoomAndRoomRateAvailability = $this->getPropertyRoomAndRoomRateAvailability($propertyRoomAndRoomRateAvailabilityParam); if ($getPropertyRoomAndRoomRateAvailability['status'] != 'success' || empty($getPropertyRoomAndRoomRateAvailability['data'])) { throw new ApiErrorException(lang('Room or rooms not available.')); } $propertyRoomAndRoomRateAvailability = collect($getPropertyRoomAndRoomRateAvailability['data']); $dateByDay = $this->getDateByDay($searchCacheData['requestParams']['date']); $bookingAddon = []; $totalAddonPrice = 0; if (isset($params['addonInfo'])) { $propertyChannelAddonCriteria = [ 'criteria' => [ ['field' => 'property_id', 'condition' => '=', 'value' => $getChannelPropertyDetail['property_id']], ['field' => 'channel_id', 'condition' => '=', 'value' => $getChannelPropertyDetail['channel_id']], ['field' => 'status', 'condition' => '=', 'value' => 1], ], 'with' => ['propertyAddon.fact'] ]; $columns = ['id', 'property_id', 'channel_id', 'property_addon_id', 'amount', 'type', 'min_stay']; $selectPropertyChannelAddon = $this->propertyAddonService->selectPropertyChannelAddon($propertyChannelAddonCriteria, $columns); $propertyChannelAddon = []; if ($selectPropertyChannelAddon['status'] == 'success') { $propertyChannelAddon = $selectPropertyChannelAddon['data']; } if (empty($propertyChannelAddon)) { throw new ApiErrorException(lang('No additional defined products found.')); } $propertyChannelAddonCollect = collect($propertyChannelAddon); $propertyChannelAddonIds = $propertyChannelAddonCollect->pluck('id'); $propertyChannelAddonIds = $propertyChannelAddonIds ? $propertyChannelAddonIds->toArray() : []; $nightOfStay = Carbon::parse($searchCacheData['requestParams']['date']['checkIn'])->diff(Carbon::parse($searchCacheData['requestParams']['date']['checkOut']))->days; $addonInfo = collect($params['addonInfo']); $addonInfoIds = $addonInfo->pluck('id'); $addonInfoIds = $addonInfoIds ? $addonInfoIds->toArray() : []; if (count(array_intersect($addonInfoIds, $propertyChannelAddonIds)) != count($addonInfoIds)) { throw new ApiErrorException(lang('Additional product values submitted do not match.')); } foreach ($params['addonInfo'] as $addonInfo) { $selectedAddon = $propertyChannelAddonCollect->where('id', $addonInfo['id'])->first(); $addonInfoAttribute = null; /*if (isset($addonInfo['attribute'])) { foreach ($addonInfo['attribute'] as $addonAttribute) { if (count(array_intersect_key($addonAttribute, $selectedAddon['property_addon']['attributeArray'])) != count($addonAttribute)) { throw new ApiErrorException(lang('Additional product attribute values submitted do not match.')); } } $addonInfoAttribute = $addonInfo['attribute']; }*/ if (!is_null($selectedAddon['min_stay']) && $selectedAddon['min_stay'] <= $nightOfStay) { $selectedAddon['amount'] = 0; } $bookingAddon[$selectedAddon['id']] = [ 'property_addon_id' => $selectedAddon['property_addon_id'], 'property_channel_addon_id' => $selectedAddon['id'], 'count' => $addonInfo['count'], 'amount' => $selectedAddon['amount'], 'total' => moneyDoubleFormatDecimal($addonInfo['count'] * $selectedAddon['amount']), 'currency_code' => $currencyCode, 'attribute' => $addonInfoAttribute ]; $totalAddonPrice += $bookingAddon[$selectedAddon['id']]['total']; } } $couponCodeData = []; if (!is_null($couponCode)) { $propertyChannelCouponCriteria = [ 'criteria' => [ ['field' => 'property_id', 'condition' => '=', 'value' => $getChannelPropertyDetail['property_id']], ['field' => 'channel_id', 'condition' => '=', 'value' => $getChannelPropertyDetail['channel_id']], ['field' => 'code', 'condition' => '=', 'value' => $couponCode], ['field' => 'start_date', 'condition' => '<=', 'value' => Carbon::now()->toDateString()], ['field' => 'end_date', 'condition' => '>=', 'value' => Carbon::now()->toDateString()], ['field' => 'status', 'condition' => '=', 'value' => 1], ], 'firstRow' => true ]; $propertyChannelCoupon = $this->propertyChannelCouponService->select($propertyChannelCouponCriteria); if ($propertyChannelCoupon['status'] == 'success') { $couponCodeData = $propertyChannelCoupon['data']; } //Reservation Date Check $reservationDateCheck = true; if (!is_null($couponCodeData['reservation_start_date']) && !is_null($couponCodeData['reservation_end_date'])) { if (isset($searchCacheData['requestParams']['date']['checkIn']) && isset($searchCacheData['requestParams']['date']['checkOut'])) { $reservationDateCheck = Carbon::parse($couponCodeData['reservation_start_date'])->lessThanOrEqualTo(Carbon::parse($searchCacheData['requestParams']['date']['checkIn'])) && Carbon::parse($couponCodeData['reservation_end_date'])->greaterThanOrEqualTo(Carbon::parse($searchCacheData['requestParams']['date']['checkOut'])); } } if(!$reservationDateCheck) { $couponCodeData = []; } } if (!isset($params['bookingCode'])) { //TODO: VALIDATORs //1. Roominfo içindeki her bir occupancyCode ile paxes alar validatorden geçecek //2. paxes için valdiatorden geçecek, eğer çocuk ise dt zorunlu, type, name, surname, citizen zorunlu //3. contactInfo içi komple zorunlu validatorden geçecek //4. searchKey, propertyId, contactInfo, roomInfo, paymentInfo zorunlu //5. gelen ödeme tipi ile rate lerde ödmee tipleri kontrol edilecek ///BOOKING START DB::beginTransaction(); $bookingCode = getCodeGenerate('BKG'); $bookingStatus = in_array($params['paymentInfo']['paymentCode'], ['HTL', 'CHN']) ? 1 : 2; //1. Booking //2. PreBooking $totalRoomsPriceBeforeDiscount = $totalRoomsPrice; $bookingDiscountAmount = 0; if (!empty($couponCodeData)) { if ($couponCodeData['type'] == 'PER') { $bookingDiscountAmount = ($totalRoomsPriceBeforeDiscount * $couponCodeData['value'] / 100); } elseif ($couponCodeData['type'] == 'FIX') { $bookingDiscountAmount = $couponCodeData['value']; } $totalRoomsPrice = $totalRoomsPrice - $bookingDiscountAmount; } $bookingTotalAmount = $totalRoomsPrice + $totalAddonPrice; //Wholesaler MARKUP $channelPropertyMarkup = []; if (in_array($getChannelPropertyDetail['channel']['channel_category_id'], [7])) { if (!is_null($getChannelPropertyDetail['markup']) && !empty($getChannelPropertyDetail['channel']['default_currency'])) { $lastExchangeRate = 1; if ($getChannelPropertyDetail['currency_code'] != $getChannelPropertyDetail['channel']['default_currency']) { $lastExchangeRate = $this->currencyService->lastExchangeRate($getChannelPropertyDetail['currency_code'], $getChannelPropertyDetail['channel']['default_currency']); if ($lastExchangeRate['status'] == 'success') { $lastExchangeRate = $lastExchangeRate['data']; } } $connectedChannelAction = !is_null($getChannelPropertyDetail['connected_channel_action']) ? json_decode($getChannelPropertyDetail['connected_channel_action'], 1) : null; $channelPropertyMarkup = [ 'channel_discount' => !empty($connectedChannelAction) && isset($connectedChannelAction['value']) ? $connectedChannelAction['value'] : null, 'channel_markup' => $getChannelPropertyDetail['markup'], 'channel_currency_code' => $getChannelPropertyDetail['channel']['default_currency'], 'channel_currency_exchange' => $lastExchangeRate, ]; } } //Wholesaler MARKUP $bannedCharacters = ['<','>', ';', '(', ')', '=', ':', 'shell_exec']; $bannedCheckParameter = ['name', 'surname', 'phone_number', 'email', 'note']; $bookingCreateParam = [ 'property_id' => $propertyId, 'channel_id' => $this->channelId, 'booking_code' => $bookingCode, 'search_key' => $params['searchKey'], 'checkin_date' => $searchCacheData['requestParams']['date']['checkIn'], 'checkout_date' => $searchCacheData['requestParams']['date']['checkOut'], 'rooms' => json_encode($searchCacheData['requestParams']['rooms']), 'payment_type_code' => $params['paymentInfo']['paymentCode'], 'room_amount' => $totalRoomsPriceBeforeDiscount, 'addon_amount' => $totalAddonPrice, 'discount_amount' => $bookingDiscountAmount, 'total' => $bookingTotalAmount, 'currency_code' => $currencyCode, 'channel_token' => $this->channelToken, 'booking_engine_token' => $this->bookingEngineToken, 'status' => $bookingStatus, 'channel_discount' => fillOnUndefined($channelPropertyMarkup, 'channel_discount'), 'channel_markup' => fillOnUndefined($channelPropertyMarkup, 'channel_markup'), 'channel_currency_code' => fillOnUndefined($channelPropertyMarkup, 'channel_currency_code'), 'channel_currency_exchange' => fillOnUndefined($channelPropertyMarkup, 'channel_currency_exchange'), 'extra_param' => !empty($extraParam) ? json_encode($extraParam) : null, 'coupon_code' => fillOnUndefined($couponCodeData,'code') //Burada sor sat için bişey gelebilir ]; $bookingCreate = $this->bookingService->create($bookingCreateParam); //$bookingCreate['status'] = 'success'; //$bookingCreate['data']['id'] = 16; if ($bookingCreate['status'] != 'success') { throw new ApiErrorException(lang('Booking could not be made')); } //INSERT CONTACT DATA $bookingContactCreateParam = [ 'booking_id' => $bookingCreate['data']['id'], 'name' => $params['contactInfo']['name'], 'surname' => $params['contactInfo']['surName'], 'phone_code' => $params['contactInfo']['phoneCode'], 'phone_number' => $params['contactInfo']['phoneNumber'], 'email' => $params['contactInfo']['email'], 'note' => fillOnUndefined($params['contactInfo'], 'note'), 'language_code' => fillOnUndefined($params['contactInfo'], 'language_code', 'en'), 'invoice_request' => fillOnUndefined($params['contactInfo'], 'invoice_request') ? 1 : null, 'status' => 1 ]; foreach ($bannedCheckParameter as $checkParameter) { if (isset($bookingContactCreateParam[$checkParameter])) { foreach ($bannedCharacters as $bannedCharacter) { if (str_contains($bookingContactCreateParam[$checkParameter], $bannedCharacter)) { throw new ApiErrorException(lang('Booking could not be made! - Contact')); } } } } $bookingContactCreate = $this->bookingContactService->create($bookingContactCreateParam); //$bookingContactCreate['status'] = 'success'; if ($bookingContactCreate['status'] != 'success') { throw new ApiErrorException(lang('Booking Contact could not be made')); } //INSERT ADDON DATA foreach ($bookingAddon as $propertyAddonId => $propertyAddon) { $bookingAddonCreateParam = [ 'booking_id' => $bookingCreate['data']['id'], 'property_channel_addon_id' => $propertyAddon['property_channel_addon_id'], 'count' => $propertyAddon['count'], 'amount' => $propertyAddon['amount'], 'total' => $propertyAddon['total'], 'currency_code' => $propertyAddon['currency_code'], 'attribute' => !empty($propertyAddon['attribute']) ? json_encode($propertyAddon['attribute']) : null, ]; $bookingAddonCreate = $this->bookingAddonService->create($bookingAddonCreateParam); //$bookingRoomCreate['status'] = 'success'; //$bookingRoomCreate['data']['id'] = 1; if ($bookingAddonCreate['status'] != 'success') { throw new ApiErrorException(lang('Booking Addon could not be made')); } } //INSERT ROOM DATA foreach ($roomInfo as $roomOrder => $room) { $rateKeyCodeDecoded = $this->rateKeyCodeDecode($searchCacheRoomPrices[$room['rateKey']]['rateKeyCode']); $roomPrice = $searchCacheRoomPrices[$room['rateKey']]['total']; $roomPriceBeforeDiscount = $searchCacheRoomPrices[$room['rateKey']]['total']; $roomDiscountAmount = 0; if (!empty($couponCodeData)) { if ($couponCodeData['type'] == 'PER') { $roomDiscountAmount = ($roomPriceBeforeDiscount * $couponCodeData['value'] / 100); } elseif ($couponCodeData['type'] == 'FIX') { $roomDiscountAmount = $couponCodeData['value']; } $roomPrice = $roomPriceBeforeDiscount - $roomDiscountAmount; } $bookingRoomCreateParam = [ 'booking_id' => $bookingCreate['data']['id'], 'room_order_number' => ($roomOrder + 1), 'occupancy_code' => $room['occupancyCode'], 'checkin_date' => $searchCacheData['requestParams']['date']['checkIn'], 'checkout_date' => $searchCacheData['requestParams']['date']['checkOut'], 'rate_key' => $room['rateKey'], 'rate_key_code' => $searchCacheRoomPrices[$room['rateKey']]['rateKeyCode'], 'availability_id' => $rateKeyCodeDecoded['availabilityTypeId'], 'availability_code' => $searchCacheRoomPrices[$room['rateKey']]['availability']['code'], 'room_id' => $rateKeyCodeDecoded['roomId'], 'room_name' => $searchCacheRoomPrices[$room['rateKey']]['room']['name'], 'room_rate_mapping_id' => $rateKeyCodeDecoded['rateMappingId'], 'room_rate_name' => $searchCacheRoomPrices[$room['rateKey']]['rate']['name'], 'cancellation_policy' => json_encode($searchCacheRoomPrices[$room['rateKey']]['cancellationPolicy']), 'payment_type_code' => $searchCacheRoomPrices[$room['rateKey']]['bookingPaymentType']['code'], 'daily_amount' => json_encode($searchCacheRoomPrices[$room['rateKey']]['policyPriceDaily']), 'rate_detail' => json_encode($searchCacheRoomPrices[$room['rateKey']]), 'amount' => $roomPriceBeforeDiscount, 'discount_amount' => $roomDiscountAmount, 'total' => $roomPrice, 'currency_code' => $searchCacheRoomPrices[$room['rateKey']]['currency'], 'status' => 1 ]; $bookingRoomCreate = $this->bookingRoomService->create($bookingRoomCreateParam); //$bookingRoomCreate['status'] = 'success'; //$bookingRoomCreate['data']['id'] = 1; if ($bookingRoomCreate['status'] != 'success') { throw new ApiErrorException(lang('Booking Room could not be made')); } foreach ($room['paxes'] as $roomPax) { $bookingRoomPaxParam = [ 'booking_id' => $bookingCreate['data']['id'], 'booking_room_id' => $bookingRoomCreate['data']['id'], 'type' => fillOnUndefined($roomPax, 'type'), 'name' => fillOnUndefined($roomPax, 'name'), 'surname' => fillOnUndefined($roomPax, 'surName'), 'gender' => fillOnUndefined($roomPax, 'gender'), 'citizen' => fillOnUndefined($roomPax, 'citizen'), 'birth_date' => fillOnUndefined($roomPax, 'birthDate'), ]; foreach ($bannedCheckParameter as $checkParameter) { if (isset($bookingRoomPaxParam[$checkParameter])) { foreach ($bannedCharacters as $bannedCharacter) { if (str_contains($bookingRoomPaxParam[$checkParameter], $bannedCharacter)) { throw new ApiErrorException(lang('Booking could not be made! - Pax')); } } } } $bookingRoomPaxCreate = $this->bookingRoomPaxService->create($bookingRoomPaxParam); //$bookingRoomCreate['status'] = 'success'; //$bookingRoomCreate['data']['id'] = 1; if ($bookingRoomPaxCreate['status'] != 'success') { throw new ApiErrorException(lang('Booking Room Pax could not be made')); } } } } else { $bookingDetailParam = [ 'criteria' => [ ['field' => 'booking_code', 'condition' => '=', 'value' => $params['bookingCode']] ], 'with' => ['bookingPayment', 'bookingRoom', 'bookingAddon'], 'firstRow' => true ]; $bookingCreate = $this->bookingService->select($bookingDetailParam); if ($bookingCreate['status'] != 'success' || empty($bookingCreate['data'])) { throw new ApiErrorException(lang('Booking not found')); } $bookingDetail = $bookingCreate['data']; //DELETE OLD ADDON DATA if (!empty(pickItemFromArray('id', $bookingDetail['booking_addon']))) { $this->bookingAddonService->delete(pickItemFromArray('id', $bookingDetail['booking_addon'])); } //INSERT ADDON DATA foreach ($bookingAddon as $propertyAddonId => $propertyAddon) { $bookingAddonCreateParam = [ 'booking_id' => $bookingDetail['id'], 'property_channel_addon_id' => $propertyAddon['property_channel_addon_id'], 'count' => $propertyAddon['count'], 'amount' => $propertyAddon['amount'], 'total' => $propertyAddon['total'], 'currency_code' => $propertyAddon['currency_code'], 'attribute' => !empty($propertyAddon['attribute']) ? json_encode($propertyAddon['attribute']) : null, ]; $bookingAddonCreate = $this->bookingAddonService->create($bookingAddonCreateParam); if ($bookingAddonCreate['status'] != 'success') { throw new ApiErrorException(lang('Booking Addon could not be made')); } } $bookingCode = $bookingCreate['data']['booking_code']; $bookingStatus = in_array($params['paymentInfo']['paymentCode'], ['HTL', 'CHN']) ? 1 : 2; $totalRoomsPriceBeforeDiscount = $totalRoomsPrice; $bookingDiscountAmount = 0; if (!empty($couponCodeData)) { if ($couponCodeData['type'] == 'PER') { $bookingDiscountAmount = ($totalRoomsPriceBeforeDiscount * $couponCodeData['value'] / 100); } elseif ($couponCodeData['type'] == 'FIX') { $bookingDiscountAmount = $couponCodeData['value']; } $totalRoomsPrice = $totalRoomsPrice - $bookingDiscountAmount; } $bookingTotalAmount = $totalRoomsPrice + $totalAddonPrice; $bookingDetailUpdate = [ 'room_amount' => $totalRoomsPriceBeforeDiscount, 'addon_amount' => $totalAddonPrice, 'total' => $bookingTotalAmount, ]; $this->bookingService->update($bookingDetail['id'], $bookingDetailUpdate); } //Eğer kredi kartı ise $initializePayment = []; if (!in_array($params['paymentInfo']['paymentCode'], ['HTL', 'CHN'])) { $isDirectPayment = true; //TODO: validator $params['paymentInfo']['creditCard']['cardExpireMonth'] = strlen($params['paymentInfo']['creditCard']['cardExpireMonth']) == 2 ? $params['paymentInfo']['creditCard']['cardExpireMonth'] : str_pad($params['paymentInfo']['creditCard']['cardExpireMonth'], 2, 0, STR_PAD_LEFT); $initializePaymentParam = [ 'propertyId' => $propertyId, 'orderId' => $bookingCode, 'installment' => isset($params['paymentInfo']['creditCard']['installment']) ? $params['paymentInfo']['creditCard']['installment'] : 1, 'amount' => (double)$bookingTotalAmount, 'currency' => $currencyCode, 'type' => 'BKG', 'responseUrl' => $params['paymentInfo']['responseUrl'], 'creditCard' => [ 'name' => $params['paymentInfo']['creditCard']['cardHolder'], 'number' => $params['paymentInfo']['creditCard']['cardNumber'], 'month' => $params['paymentInfo']['creditCard']['cardExpireMonth'], 'year' => $params['paymentInfo']['creditCard']['cardExpireYear'], 'cvv' => $params['paymentInfo']['creditCard']['cardCvv'], ] ]; $initializePayment = $this->propertyPaymentService->initializePayment($initializePaymentParam); if (!$initializePayment['status']) { Log::error($initializePayment); throw new ApiErrorException(lang('Initialize Payment could not be made')); } if (isset($initializePayment['data']['redirectUrl'])) { $isDirectPayment = false; } } //Eğer direk ödeme ile para çekilip işlem yapılmış ise if (isset($isDirectPayment) && $isDirectPayment) { $bookingStatus = 1; $this->bookingService->update($bookingCreate['data']['id'], ['status' => 1]); } $bookingPaymentCreateParam = [ 'booking_id' => $bookingCreate['data']['id'], 'payment_code' => isset($initializePayment['data']['paymentCode']) ? $initializePayment['data']['paymentCode'] : null, 'payment_type_code' => $params['paymentInfo']['paymentCode'], 'total' => in_array($params['paymentInfo']['paymentCode'], ['HTL', 'CHN']) || ($bookingStatus == 1 && $isDirectPayment) ? $bookingTotalAmount : null, 'currency_code' => in_array($params['paymentInfo']['paymentCode'], ['HTL', 'CHN']) || ($bookingStatus == 1 && $isDirectPayment) ? $currencyCode : null, 'status' => (isset($isDirectPayment) && $isDirectPayment) ? 1 : 2 ]; $bookingPaymentCreate = $this->bookingPaymentService->create($bookingPaymentCreateParam); //$bookingContactCreate['status'] = 'success'; if ($bookingPaymentCreate['status'] != 'success') { throw new ApiErrorException(lang('Booking Payment could not be made')); } //Buradan eksiltme transaction ları başlatılacak ki ok ise düşsün $roomAvailabilityStatus = true; foreach ($roomAvailabilityKeyGroup as $roomAvailabilityKey => $roomAvailability) { if ($roomAvailabilityKey == 1) { foreach ($roomAvailability as $roomKey => $room) { foreach ($dateByDay as $day) { $roomAndRoomRateAvailability = $propertyRoomAndRoomRateAvailability ->where('date', $day) ->where('property_room_id', $room['detail']['roomId']) ->where('availability_type_id', $room['detail']['availabilityTypeId']) ->where('availability', '>=', $room['count']) ->where('status', 1) ->first(); if (is_null($roomAndRoomRateAvailability)) { $roomAvailabilityStatus = false; break 3; } //Kontenjan Azaltma //Otelde öde ise düşürülecek kontenjan if (in_array($params['paymentInfo']['paymentCode'], ['HTL', 'CHN']) || $isDirectPayment) { $roomNewAvailability = $roomAndRoomRateAvailability['availability'] - $room['count']; $this->propertyRoomAvailabilityService->update($roomAndRoomRateAvailability['id'], ['availability' => $roomNewAvailability]); //Connected Room Case if ($roomAndRoomRateAvailability['room_detail']['is_connected_room'] && $roomAndRoomRateAvailability['room_detail']['is_connected_room_availability']) { foreach ($roomAndRoomRateAvailability['room_detail']['property_room_connected'] as $connectedRoom) { $roomAndRoomRateAvailabilityConnected = $propertyRoomAndRoomRateAvailability ->where('date', $day) ->where('property_room_id', $connectedRoom['connected_room_id']) ->where('availability_type_id', $room['detail']['availabilityTypeId']) ->where('availability', '>=', $room['count']) ->where('status', 1) ->first(); if (is_null($roomAndRoomRateAvailabilityConnected)) { continue; } $roomNewAvailabilityConnected = $roomAndRoomRateAvailabilityConnected['availability'] - $room['count']; $this->propertyRoomAvailabilityService->update($roomAndRoomRateAvailabilityConnected['id'], ['availability' => $roomNewAvailabilityConnected]); } } //Connected Room Case } } } //Connected Room Case $roomAvailabilityUpdateForConnectedRoomParams = [ 'property_id' => $propertyId, 'channel_id' => $this->channelId, 'availability_type_id' => [$roomAvailabilityKey], 'startDate' => reset($dateByDay), 'endDate' => last($dateByDay), 'user_id' => fillOnUndefined($params, "user_id", 0) ]; $this->propertyRoomAvailabilityService->roomAvailabilityUpdateForConnectedRooms($roomAvailabilityUpdateForConnectedRoomParams); //Connected Room Case } else { foreach ($roomAvailability as $roomKey => $roomRateMapping) { foreach ($roomRateMapping as $roomRateMappingKey => $roomRate) { foreach ($dateByDay as $day) { $roomAndRoomRateAvailability = $propertyRoomAndRoomRateAvailability ->where('date', $day) ->where('property_room_id', $roomRate['detail']['roomId']) ->where('availability_type_id', $roomRate['detail']['availabilityTypeId']) ->where('room_rate_mapping_id', $roomRate['detail']['rateMappingId']) ->where('channel_id', $roomRate['detail']['channelId']) ->where('availability', '>=', $roomRate['count']) ->where('status', 1) ->first(); if (is_null($roomAndRoomRateAvailability)) { $roomAvailabilityStatus = false; break 4; } //Kontenjan Azaltma //Otelde öde ise düşürülecek kontenjan if (in_array($params['paymentInfo']['paymentCode'], ['HTL', 'CHN']) || $isDirectPayment) { //TODO: Garantili kontenjan ve limitlide havuzdan da azaltılmalı $roomNewAvailability = $roomAndRoomRateAvailability['availability'] - $roomRate['count']; $this->propertyRoomAvailabilityService->update($roomAndRoomRateAvailability['id'], ['availability' => $roomNewAvailability]); } } } } } } if (!$roomAvailabilityStatus) { throw new ApiErrorException(lang('One or more of the requested rooms are not available')); } //BOOKING FINISHED $responseData = [ 'bookingCode' => $bookingCode, 'total' => $bookingTotalAmount, 'currency' => $currencyCode, 'bookingStatus' => $bookingStatus, 'bookingStatusText' => $bookingStatus == 1 ? 'Booking' : 'PreBooking', ]; //TODO: Eğer Booking yapılmış ise if (in_array($params['paymentInfo']['paymentCode'], ['HTL', 'CHN']) || ($bookingStatus == 1 && isset($isDirectPayment) && $isDirectPayment)) { $mailParams = ['booking_id' => $bookingCreate['data']['id']]; $this->newBookingMailService->process($mailParams); //PUSH NOTIFICATION $newBookingNotificationParam = ['booking_id' => $bookingCreate['data']['id']]; $this->notificationService->sendNewBookingNotification($newBookingNotificationParam); //PUSH NOTIFICATION //PUSH CHANNEL MANAGER QUEUE //if ($bookingCreate['data']['channel_id'] == 1) { $channelManagerPropertyMappingCriteria = [ 'criteria' => [ ['field' => 'property_id', 'condition' => '=', 'value' => $bookingCreate['data']['property_id']], //['field' => 'channel_manager_property_id', 'condition' => '=', 'value' => null], ['field' => 'status', 'condition' => '=', 'value' => 1], ] ]; $channelManagerPropertyMapping = $this->channelManagerPropertyMappingService->select($channelManagerPropertyMappingCriteria); if ($channelManagerPropertyMapping['status'] == 'success' && !empty($channelManagerPropertyMapping['data'])) { foreach ($channelManagerPropertyMapping['data'] as $channelPropertyData) { //Trivago if ($channelPropertyData['channel_manager_id'] == 11 && !isset($params['extraParam']['trv_reference'])) { continue; } //Hyperguest if ($channelPropertyData['channel_manager_id'] != 10 && !is_null($channelPropertyData['channel_manager_property_id'])) { continue; } if(in_array($channelPropertyData['channel_manager_id'],[13])) { continue; } $channelManagerBookingCreateParam = [ 'property_id' => $bookingCreate['data']['property_id'], 'booking_id' => $bookingCreate['data']['id'], 'channel_manager_id' => $channelPropertyData['channel_manager_id'], 'type' => 'Booking', ]; $channelManagerBookingCreate = $this->channelManagerBookingService->create($channelManagerBookingCreateParam); } } //} //PUSH CHANNEL MANAGER QUEUE } //Eğer kredi kartı ise ve ödeme başlamış ise if (!empty($initializePayment)) { $responseData['paymentCode'] = $initializePayment['data']['paymentCode']; if (isset($initializePayment['data']['redirectUrl'])) { $responseData['redirectUrl'] = $initializePayment['data']['redirectUrl']; } } //Pay at Hotel - Info Store if (in_array($params['paymentInfo']['paymentCode'], ['HTL', 'CHN']) && isset($params['paymentInfo']['creditCard']) && !empty($params['paymentInfo']['creditCard']['cardNumber'])) { $creditCard = $params['paymentInfo']['creditCard']; $cardNumber = $creditCard['cardNumber']; $cardLengthSize = ceil(strlen($cardNumber) / 4); $cardNumberParse = []; for ($i = 0; $i < $cardLengthSize; $i++) { $cardNumberParse['cc'][] = Crypt::encrypt(mb_substr($cardNumber, $i * 4, 4)); } $cardNumberParse['cm'] = Crypt::encrypt($creditCard['cardExpireMonth']); $cardNumberParse['cy'] = Crypt::encrypt(mb_substr($creditCard['cardExpireYear'], -2, 2)); $cardNumberParse['cv'] = Crypt::encrypt($creditCard['cardCvv']); $cardNumberParse['ch'] = Crypt::encrypt($creditCard['cardHolder']); foreach ($cardNumberParse as $type => $value) { $bookingPaymentDataCreateParam = []; if ($type == 'cc') { foreach ($value as $cardValue) { $bookingPaymentDataCreateParam = [ 'booking_id' => $bookingCreate['data']['id'], 'type' => $type, 'data' => $cardValue, ]; $this->bookingPaymentService->createPaymentData($bookingPaymentDataCreateParam); } } else { $bookingPaymentDataCreateParam = [ 'booking_id' => $bookingCreate['data']['id'], 'type' => $type, 'data' => $value, ]; $this->bookingPaymentService->createPaymentData($bookingPaymentDataCreateParam); } } } //Pay at Hotel - Info Store //Booking Engine Search Update $bookingEngineSearchParam = [ 'criteria' => [ ['field' => 'search_key', 'condition' => '=', 'value' => $params['searchKey']], ['field' => 'status', 'condition' => '=', 'value' => 1], ], 'firstRow' => true ]; $bookingEngineSearch = $this->propertyBookingEngineSearchService->select($bookingEngineSearchParam); if ($bookingEngineSearch['status'] == 'success' && !empty($bookingEngineSearch['data'])) { $bookingEngineSearchUpdateParam = [ 'booking_code' => $bookingCode, 'amount' => $bookingTotalAmount, 'status' => 2, ]; if (in_array($params['paymentInfo']['paymentCode'], ['HTL', 'CHN']) || ($bookingStatus == 1 && isset($isDirectPayment) && $isDirectPayment)) { $bookingEngineSearchUpdateParam['status'] = 3; } $bookingEngineSearchUpdate = $this->propertyBookingEngineSearchService->update($bookingEngineSearch['data']['id'], $bookingEngineSearchUpdateParam); } $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $responseData]; } catch (ApiErrorException $e) { $response['message'] = implode(', ', $e->getMessageArr()); $response['statusCode'] = 400; } catch (Exception $e) { $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage(); Log::error($message); $response['message'] = $e->getMessage(); $response['statusCode'] = 500; } if ($response['status']) { DB::commit(); } else { DB::rollBack(); } return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']); } public function bookingConfirm(Request $request) { $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500]; try { if (is_null($this->request->getContent())) { throw new ApiErrorException(lang('Parameter Error.')); } $params = json_decode($this->request->getContent(), 1); $bookingCode = $params['bookingCode']; $paymentCode = $params['paymentCode']; $bookingDetailParam = [ 'criteria' => [ ['field' => 'booking_code', 'condition' => '=', 'value' => $bookingCode] ], 'with' => ['property', 'bookingPayment', 'bookingRoom'], 'firstRow' => true ]; $bookingDetail = $this->bookingService->select($bookingDetailParam); if ($bookingDetail['status'] != 'success' || empty($bookingDetail['data'])) { throw new ApiErrorException(lang('Booking not found')); } $bookingDetail = $bookingDetail['data']; $paymentDetailParam = [ 'criteria' => [ ['field' => 'code', 'condition' => '=', 'value' => $paymentCode] ], 'firstRow' => true ]; $paymentDetail = $this->propertyPaymentService->selectPaymentTransaction($paymentDetailParam); if ($paymentDetail['status'] != 'success' || empty($paymentDetail['data'])) { throw new ApiErrorException(lang('Payment not found')); } $paymentDetail = $paymentDetail['data']; if ($paymentDetail['status'] != 1) { throw new ApiErrorException('Payment not confirmed'); } if ($bookingDetail['status'] == 1) { throw new ApiErrorException('Previously approved transaction'); } DB::beginTransaction(); //Booking Confirm $this->bookingService->update($bookingDetail['id'], ['status' => 1]); //Availability Change if ($bookingDetail['status'] == 2) { $propertyRoomAndRoomRateAvailabilityParam = [ 'property_id' => $bookingDetail['property_id'], 'checkIn' => $bookingDetail['checkin_date'], 'checkOut' => $bookingDetail['checkout_date'], ]; $getPropertyRoomAndRoomRateAvailability = $this->getPropertyRoomAndRoomRateAvailability($propertyRoomAndRoomRateAvailabilityParam); if ($getPropertyRoomAndRoomRateAvailability['status'] != 'success' || empty($getPropertyRoomAndRoomRateAvailability['data'])) { throw new ApiErrorException(lang('Room or rooms not available.')); } $propertyRoomAndRoomRateAvailability = collect($getPropertyRoomAndRoomRateAvailability['data']); $roomAvailabilityStatus = true; foreach ($bookingDetail['booking_room'] as $room) { $dateByDay = $this->getDateByDay(['checkIn' => $room['checkin_date'], 'checkOut' => $room['checkout_date']]); foreach ($dateByDay as $day) { $roomRateDetail = json_decode($room['rate_detail'], 1); $rateKeyCodeDecoded = $this->rateKeyCodeDecode($roomRateDetail['rateKeyCode']); if ($rateKeyCodeDecoded['availabilityTypeId'] == 1) { $roomAndRoomRateAvailability = $propertyRoomAndRoomRateAvailability ->where('date', $day) ->where('property_room_id', $rateKeyCodeDecoded['roomId']) ->where('availability_type_id', $rateKeyCodeDecoded['availabilityTypeId']) ->where('availability', '>=', 1) ->where('status', 1) ->first(); if (is_null($roomAndRoomRateAvailability)) { $roomAvailabilityStatus = false; break 2; } //Kontenjan Azaltma $roomNewAvailability = $roomAndRoomRateAvailability['availability'] - 1; $this->propertyRoomAvailabilityService->update($roomAndRoomRateAvailability['id'], ['availability' => $roomNewAvailability]); //Connected Room Case if ($roomAndRoomRateAvailability['room_detail']['is_connected_room'] && $roomAndRoomRateAvailability['room_detail']['is_connected_room_availability']) { foreach ($roomAndRoomRateAvailability['room_detail']['property_room_connected'] as $connectedRoom) { $roomAndRoomRateAvailabilityConnected = $propertyRoomAndRoomRateAvailability ->where('date', $day) ->where('property_room_id', $connectedRoom['connected_room_id']) ->where('availability_type_id', $rateKeyCodeDecoded['availabilityTypeId']) ->where('availability', '>=', 1) ->where('status', 1) ->first(); if (is_null($roomAndRoomRateAvailabilityConnected)) { continue; } $roomNewAvailabilityConnected = $roomAndRoomRateAvailabilityConnected['availability'] - 1; $this->propertyRoomAvailabilityService->update($roomAndRoomRateAvailabilityConnected['id'], ['availability' => $roomNewAvailabilityConnected]); } } //Connected Room Case } else { $roomAndRoomRateAvailability = $propertyRoomAndRoomRateAvailability ->where('date', $day) ->where('property_room_id', $rateKeyCodeDecoded['roomId']) ->where('availability_type_id', $rateKeyCodeDecoded['availabilityTypeId']) ->where('room_rate_mapping_id', $rateKeyCodeDecoded['rateMappingId']) ->where('channel_id', $rateKeyCodeDecoded['channelId']) ->where('availability', '>=', 1) ->where('status', 1) ->first(); if (is_null($roomAndRoomRateAvailability)) { $roomAvailabilityStatus = false; break 2; } //TODO: Garantili kontenjan ve limitlide havuzdan da azaltılmalı //Kontenjan Azaltma $roomNewAvailability = $roomAndRoomRateAvailability['availability'] - 1; $this->propertyRoomAvailabilityService->update($roomAndRoomRateAvailability['id'], ['availability' => $roomNewAvailability]); } } } //Connected Room Case $roomAvailabilityUpdateForConnectedRoomParams = [ 'property_id' => $bookingDetail['property_id'], 'channel_id' => $bookingDetail['channel_id'], 'availability_type_id' => [1], 'startDate' => reset($dateByDay), 'endDate' => last($dateByDay), 'user_id' => fillOnUndefined($params, "user_id", 0) ]; $this->propertyRoomAvailabilityService->roomAvailabilityUpdateForConnectedRooms($roomAvailabilityUpdateForConnectedRoomParams); //Connected Room Case if (!$roomAvailabilityStatus) { throw new ApiErrorException(lang('One or more of the requested rooms are not available')); } } //Booking Payment Update $bookingPaymentUpdateParam = [ 'status' => 1, 'total' => $paymentDetail['amount'], 'currency_code' => $paymentDetail['currency'], ]; $this->bookingPaymentService->update($bookingDetail['booking_payment']['id'], $bookingPaymentUpdateParam); $mailParams = ['booking_id' => $bookingDetail['id']]; $this->newBookingMailService->process($mailParams); //PUSH NOTIFICATION $newBookingNotificationParam = ['booking_id' => $bookingDetail['id']]; $this->notificationService->sendNewBookingNotification($newBookingNotificationParam); //PUSH NOTIFICATION //PUSH CHANNEL MANAGER QUEUE //if ($bookingDetail['channel_id'] == 1) { $channelManagerPropertyMappingCriteria = [ 'criteria' => [ ['field' => 'property_id', 'condition' => '=', 'value' => $bookingDetail['property_id']], //['field' => 'channel_manager_property_id', 'condition' => '=', 'value' => null], ['field' => 'status', 'condition' => '=', 'value' => 1], ] ]; $channelManagerPropertyMapping = $this->channelManagerPropertyMappingService->select($channelManagerPropertyMappingCriteria); if ($channelManagerPropertyMapping['status'] == 'success' && !empty($channelManagerPropertyMapping['data'])) { foreach ($channelManagerPropertyMapping['data'] as $channelPropertyData) { //Trivago if ($channelPropertyData['channel_manager_id'] == 11 && !isset($params['extraParam']['trv_reference'])) { continue; } //Hyperguest if ($channelPropertyData['channel_manager_id'] != 10 && !is_null($channelPropertyData['channel_manager_property_id'])) { continue; } //Yandex if(in_array($channelPropertyData['channel_manager_id'],[13])) { continue; } $channelManagerBookingCreateParam = [ 'property_id' => $bookingDetail['property_id'], 'booking_id' => $bookingDetail['id'], 'channel_manager_id' => $channelPropertyData['channel_manager_id'], 'type' => 'Booking', ]; $channelManagerBookingCreate = $this->channelManagerBookingService->create($channelManagerBookingCreateParam); } } //} //PUSH CHANNEL MANAGER QUEUE //Booking Engine Search Update //if ($bookingDetail['channel_id'] == 1) { $bookingEngineSearchParam = [ 'criteria' => [ ['field' => 'search_key', 'condition' => '=', 'value' => $bookingDetail['search_key']], ['field' => 'status', 'condition' => '=', 'value' => 2], ], 'firstRow' => true ]; $bookingEngineSearch = $this->propertyBookingEngineSearchService->select($bookingEngineSearchParam); if ($bookingEngineSearch['status'] == 'success' && !empty($bookingEngineSearch['data'])) { $bookingEngineSearchUpdateParam = [ 'booking_code' => $bookingDetail['booking_code'], 'amount' => $bookingDetail['total'], 'currency_code' => $bookingDetail['currency_code'], 'status' => 3, ]; $bookingEngineSearchUpdate = $this->propertyBookingEngineSearchService->update($bookingEngineSearch['data']['id'], $bookingEngineSearchUpdateParam); } //} $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => []]; } catch (ApiErrorException $e) { $response['message'] = implode(', ', $e->getMessageArr()); $response['statusCode'] = 400; } catch (Exception $e) { $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage(); Log::error($message); $response['message'] = $e->getMessage(); $response['statusCode'] = 500; } if ($response['status']) { DB::commit(); } else { DB::rollBack(); } return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']); } public function bookingDetail(Request $request, $bookingCode) { $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500]; try { $bookingDetailParam = [ 'criteria' => [ ['field' => 'booking_code', 'condition' => '=', 'value' => $bookingCode], //['field' => 'channel_id', 'condition' => '=', 'value' => $this->channelId],//TODO: Kontrol gerekli! ], 'with' => [ 'bookingPayment.paymentTypeCode', 'bookingRoom.roomPax.paxCountry', 'bookingRoom.roomRateMapping.propertyRoomRate', 'bookingRoom.roomRateMapping.propertyRoom', 'bookingContact', 'bookingProperty.propertyContact', 'bookingProperty.propertyBrand', 'bookingProperty.propertyAdditionalInfos.propertyAdditionalInfoKey', 'bookingAddon.propertyChannelAddon.propertyAddon.fact', 'bookingChannel','propertyChannelMapping.channelBookingPaymentType', 'bookingRoom.roomRateMapping.propertyRoom.propertyRoomBedGroup.propertyRoomBedType', 'bookingRoom.roomRateMapping.propertyRoom.smokingPreference.propertyFact', 'bookingRoom.propertyRoomBed', 'bookingRoom.smokingFact','propertyBookingEngineSearch' ], 'firstRow' => true ]; $bookingDetail = $this->bookingService->select($bookingDetailParam); if ($bookingDetail['status'] != 'success' || empty($bookingDetail['data'])) { throw new ApiErrorException(lang('Booking not found')); } $bookingDetail['data']['booking_property']['checkin_time'] = '14:00'; $bookingDetail['data']['booking_property']['checkout_time'] = '12:00'; if (!empty($bookingDetail['data']['booking_property']['property_additional_infos'])) { $propertyAdditionalInfos = collect($bookingDetail['data']['booking_property']['property_additional_infos']); $checkinTimeData = $propertyAdditionalInfos->where('property_additional_info_key.additional_info_key', 'checkin_time')->first(); $bookingDetail['data']['booking_property']['checkin_time'] = isset($checkinTimeData['value']) ? $checkinTimeData['value'] : '14:00'; $checkoutTimeData = $propertyAdditionalInfos->where('property_additional_info_key.additional_info_key', 'checkout_time')->first(); $bookingDetail['data']['booking_property']['checkout_time'] = isset($checkinTimeData['value']) ? $checkoutTimeData['value'] : '12:00'; } unset($bookingDetail['data']['booking_property']['property_additional_infos']); //BOOKING ADDON $bookingAddons = $bookingDetail['data']['booking_addon']; unset($bookingDetail['data']['booking_addon']); $bookingAddonList = []; foreach ($bookingAddons as $bookingAddon) { $bookingAddonAttributeList = []; $isHasAttribute = false; $attributeArray = []; if (!empty($bookingAddon['property_channel_addon']['property_addon']['attributeArray'])) { $isHasAttribute = true; $attributeArray = $bookingAddon['property_channel_addon']['property_addon']['attributeArray']; $bookingAddonAttributes = json_decode($bookingAddon['attribute'], 1); if (!is_null($bookingAddonAttributes)) { foreach ($bookingAddonAttributes as $key => $bookingAddonAttribute) { foreach ($bookingAddonAttribute as $bookingAddonAttributeKey => $bookingAddonAttributeValue) { if (isset($bookingAddon['property_channel_addon']['property_addon']['attributeArray'][$bookingAddonAttributeKey])) { $bookingAddonAttributeList[$key][$bookingAddonAttributeKey] = [ 'name' => $bookingAddon['property_channel_addon']['property_addon']['attributeArray'][$bookingAddonAttributeKey]['name'], 'language_key' => $bookingAddon['property_channel_addon']['property_addon']['attributeArray'][$bookingAddonAttributeKey]['language_key'], 'value' => $bookingAddonAttributeValue, ]; } } } } } $bookingAddonList[] = [ 'id' => $bookingAddon['id'], 'booking_id' => $bookingAddon['booking_id'], 'property_channel_addon_id' => $bookingAddon['property_channel_addon_id'], 'count' => $bookingAddon['count'], 'amount' => $bookingAddon['amount'], 'total' => $bookingAddon['total'], 'currency_code' => $bookingAddon['currency_code'], 'name' => $bookingAddon['property_channel_addon']['property_addon']['fact']['name'], 'title' => $bookingAddon['property_channel_addon']['title'], 'language_key' => $bookingAddon['property_channel_addon']['property_addon']['fact']['language_key'], 'icon' => $bookingAddon['property_channel_addon']['property_addon']['fact']['icon'], 'isHasAttribute' => $isHasAttribute, 'attributeArray' => $attributeArray, 'attribute' => $bookingAddonAttributeList ]; } $bookingDetail['data']['booking_addon'] = $bookingAddonList; //BOOKING ADDON //DAILY AMOUNT BY ROOM $hasNonRefundableRoom = false; foreach ($bookingDetail['data']['booking_room'] as $roomKey => $roomDetail) { if (!empty($roomDetail['room_rate_mapping']['property_room'])) { $bookingDetail['data']['booking_room'][$roomKey]['room_name'] = $roomDetail['room_rate_mapping']['property_room']['name']; } if (!empty($roomDetail['room_rate_mapping']['property_room_rate'])) { $bookingDetail['data']['booking_room'][$roomKey]['room_rate_name'] = $roomDetail['room_rate_mapping']['property_room_rate']['name']; } $diffInDays = Carbon::parse($roomDetail['checkin_date'])->diffInDays(Carbon::parse($roomDetail['checkout_date'])); $baseRateDaily = moneyDoubleFormatDecimal($roomDetail['total'] / $diffInDays); $roomDailyAmount = []; if (!empty($roomDetail['daily_amount'])) { $roomDetailDailyAmount = json_decode($roomDetail['daily_amount'], 1); if (!empty($roomDetailDailyAmount) && isset($roomDetailDailyAmount)) { foreach ($roomDetailDailyAmount as $roomRateAmount) { $roomDailyAmount[] = [ 'date' => $roomRateAmount['date'], 'amount' => $roomRateAmount['amount'], 'currency_code' => $roomRateAmount['currency_code'], ]; } } } if (empty($roomDailyAmount)) { $roomRateDetail = json_decode($roomDetail['rate_detail'], 1); if (!empty($roomRateDetail) && isset($roomRateDetail['days'])) { foreach ($roomRateDetail['days'] as $roomRateDay => $roomRateAmount) { $roomDailyAmount[] = [ 'date' => Carbon::parse($roomRateDay)->toDateString(), 'amount' => $roomRateAmount, 'currency_code' => $roomDetail['currency_code'], ]; } } } if (empty($roomDailyAmount)) { $currentDate = $roomDetail['checkin_date']; for ($i = 0; $i < $diffInDays; $i++) { $roomDailyAmount[] = [ 'date' => $currentDate, 'amount' => $baseRateDaily, 'currency_code' => $roomDetail['currency_code'], ]; $currentDate = Carbon::parse($currentDate)->addDay()->toDateString(); } } $bookingDetail['data']['booking_room'][$roomKey]['daily_amount'] = $roomDailyAmount; $extraParam = null; if (!empty($roomDetail['extra_param'])) { $extraParamDecode = json_decode($roomDetail['extra_param'], 1); foreach ($extraParamDecode as $extraParamKey => $extraParamValue) { $extraParamTitle = explode('_', $extraParamKey); foreach ($extraParamTitle as $extraParamTitleKey => $extraParamTitleValue) { $extraParamTitle[$extraParamTitleKey] = ucwords($extraParamTitleValue); } $extraParamTitle = implode(' ', $extraParamTitle); $extraParam[$extraParamKey] = [ 'title' => $extraParamTitle, 'value' => $extraParamValue, ]; } } $bookingDetail['data']['booking_room'][$roomKey]['extra_param'] = $extraParam; $bookingDetail['data']['booking_room'][$roomKey]['occupancyFormatted'] = occupancyCodeFormatted($roomDetail['occupancy_code']); $cancellationPolicy = !empty($roomDetail['cancellation_policy']) ? json_decode($roomDetail['cancellation_policy'], 1) : null; if (is_array($cancellationPolicy) && isset($cancellationPolicy['isNonRefundable']) && $cancellationPolicy['isNonRefundable']) { $hasNonRefundableRoom = true; } //property_room_bed_group //unset($bookingDetail['data']['booking_room'][$roomKey]['room_rate_mapping']['property_room']['property_room_bed_group']); $propertyRoomBedGroup = collect($roomDetail['room_rate_mapping']['property_room']['property_room_bed_group'])->groupBy('bed_group'); $propertyRoomBedGroup = $propertyRoomBedGroup ? $propertyRoomBedGroup->toArray() : null; $bookingDetail['data']['booking_room'][$roomKey]['room_rate_mapping']['property_room']['property_room_bed_group'] = $propertyRoomBedGroup; $bookingDetail['data']['booking_room'][$roomKey]['property_room_bed_group'] = null; if(isset($propertyRoomBedGroup[$bookingDetail['data']['booking_room'][$roomKey]['property_room_bed_group_id']])) { $bookingDetail['data']['booking_room'][$roomKey]['property_room_bed_group'] = $propertyRoomBedGroup[$bookingDetail['data']['booking_room'][$roomKey]['property_room_bed_group_id']]; } } //DAILY AMOUNT BY ROOM $bookingChannel = $bookingDetail['data']['booking_channel']; unset($bookingDetail['data']['booking_channel']); $bookingDetail['data']['booking_channel'] = [ 'name' => $bookingChannel['name'], 'logo' => $bookingChannel['logoUrl'], 'channel_category_id' => $bookingChannel['channel_category_id'], ]; $bookingContactExtraParam = null; if (!empty($bookingDetail['data']['booking_contact']['extra_param'])) { $bookingContactExtraParam = json_decode($bookingDetail['data']['booking_contact']['extra_param'], 1); } $bookingDetail['data']['booking_contact']['extra_param'] = $bookingContactExtraParam; $bookingDetail = $bookingDetail['data']; $bookingDetail['isOnlineCancellation'] = false; if ($bookingDetail['status'] == 1 && in_array($bookingDetail['booking_channel']['channel_category_id'], [2]) && !$hasNonRefundableRoom) { $bookingDetail['isOnlineCancellation'] = false; } if ($bookingDetail['status'] == 1 && in_array($bookingDetail['booking_channel']['channel_category_id'], [3]) && in_array($bookingDetail['booking_property']['country'], ['GE'])) { $bookingDetail['isOnlineCancellation'] = false; } $payAtHotelCreditCardCheck = collect($bookingDetail['property_channel_mapping']['channel_booking_payment_type'])->where('is_get_payment_data',1)->where('payment_type_id',2)->isNotEmpty(); $bookingDetail['credit_card_required'] = $payAtHotelCreditCardCheck; unset($bookingDetail['property_channel_mapping']); //Wholesaler MARKUP CALCULATE $getChannelPropertyDetail = $this->getChannelPropertyDetail($this->channelId, $bookingDetail['property_id']); if (!$getChannelPropertyDetail['status']) { throw new ApiErrorException(lang('Property and Channel are not matched.')); } $getChannelPropertyDetail = $getChannelPropertyDetail['status'] ? $getChannelPropertyDetail['data'] : null; if ($getChannelPropertyDetail && in_array($getChannelPropertyDetail['channel']['channel_category_id'], [7])) { $channelCurrencyCode = fillOnUndefined($bookingDetail, 'channel_currency_code', $bookingDetail['currency_code']); $channelCurrencyExchange = fillOnUndefined($bookingDetail, 'channel_currency_exchange', 1); $channelMarkup = 1; if (!is_null($bookingDetail['channel_markup'])) { $channelMarkup = (($bookingDetail['channel_markup'] + 100) / 100); } foreach ($bookingDetail['booking_room'] as $roomKey => $room) { foreach ($room['daily_amount'] as $dailKey => $dailyAmount) { $bookingDetail['booking_room'][$roomKey]['daily_amount'][$dailKey]['currency_code'] = $channelCurrencyCode; $bookingDetail['booking_room'][$roomKey]['daily_amount'][$dailKey]['amount'] = moneyDoubleFormatDecimal($dailyAmount['amount'] * $channelMarkup * $channelCurrencyExchange); } $bookingDetail['booking_room'][$roomKey]['amount'] = moneyDoubleFormatDecimal(collect($bookingDetail['booking_room'][$roomKey]['daily_amount'])->sum('amount')); $bookingDetail['booking_room'][$roomKey]['discount_amount'] = moneyDoubleFormatDecimal($room['discount_amount'] * $channelMarkup * $channelCurrencyExchange); $bookingDetail['booking_room'][$roomKey]['total'] = moneyDoubleFormatDecimal(collect($bookingDetail['booking_room'][$roomKey]['daily_amount'])->sum('amount')); $bookingDetail['booking_room'][$roomKey]['currency_code'] = $channelCurrencyCode; unset($bookingDetail['booking_room'][$roomKey]['rate_detail']); } $bookingDetail['currency_code'] = $channelCurrencyCode; $bookingDetail['room_amount'] = moneyDoubleFormatDecimal(collect($bookingDetail['booking_room'])->sum('amount')); $bookingDetail['addon_amount'] = moneyDoubleFormatDecimal($bookingDetail['addon_amount'] * $channelMarkup * $channelCurrencyExchange); $bookingDetail['discount_amount'] = moneyDoubleFormatDecimal(collect($bookingDetail['booking_room'])->sum('discount_amount')); $bookingDetail['total'] = moneyDoubleFormatDecimal(collect($bookingDetail['booking_room'])->sum('amount')); $bookingDetail['booking_payment']['currency_code'] = $channelCurrencyCode; $bookingDetail['booking_payment']['total'] = moneyDoubleFormatDecimal(collect($bookingDetail['booking_room'])->sum('total')); } //Wholesaler MARKUP CALCULATE unset($bookingDetail['channel_markup']); unset($bookingDetail['channel_currency_code']); unset($bookingDetail['channel_currency_exchange']); $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $bookingDetail]; } catch (ApiErrorException $e) { $response['message'] = implode(', ', $e->getMessageArr()); $response['statusCode'] = 400; } catch (Exception $e) { $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage(); Log::error($message); $response['message'] = $e->getMessage(); $response['statusCode'] = 500; } return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']); } public function bookingUpdate(Request $request, $bookingCode) { DB::beginTransaction(); $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500]; try { if (is_null($this->request->getContent())) { throw new ApiErrorException(lang('Parameter Error.')); } $params = json_decode($this->request->getContent(), 1); $bookingDetailParam = [ 'criteria' => [ ['field' => 'booking_code', 'condition' => '=', 'value' => $bookingCode], ], 'with' => [ 'bookingRoom.roomRateMapping.propertyRoom', 'bookingRoom.roomRateMapping.propertyRoom.propertyRoomBedGroup.propertyRoomBedType', 'bookingRoom.roomRateMapping.propertyRoom.smokingPreference.propertyFact', 'bookingRoom.propertyRoomBed','bookingRoom.smokingFact' ], 'firstRow' => true ]; $bookingDetail = $this->bookingService->select($bookingDetailParam); if ($bookingDetail['status'] != 'success' || empty($bookingDetail['data'])) { throw new ApiErrorException(lang('Booking not found')); } $bookingDetail = $bookingDetail['data']; if(fillOnUndefined($params,'propertyId') != fillOnUndefined($bookingDetail,'property_id')) { throw new ApiErrorException('PropertyI ID is not matching.'); } $bookingRoomUpdateParam = ['smoking_fact_id','property_room_bed_id','property_room_bed_group_id']; if(isset($params['booking_room']) && isset($params['booking_room']['id'])) { $bookingRoomIds = collect($bookingDetail['booking_room'])->pluck('id'); $bookingRoomIds = $bookingRoomIds ? $bookingRoomIds->toArray() : null; if(empty($bookingRoomIds)) { throw new ApiErrorException('Booking Room ID not found.'); } if(!in_array($params['booking_room']['id'],$bookingRoomIds )) { throw new ApiErrorException('Booking Room ID not matching.'); } $bookingRoomDetail = collect($bookingDetail['booking_room'])->where('id',$params['booking_room']['id'])->first(); foreach ($bookingRoomUpdateParam as $updateColumn) { //smoking_fact_id if($updateColumn == 'smoking_fact_id' && isset($params['booking_room']['smoking_fact_id'])) { $smokingPreferenceIds = collect($bookingRoomDetail['room_rate_mapping']['property_room']['smoking_preference'])->pluck('fact_id')->toArray(); if(!in_array($params['booking_room']['smoking_fact_id'],$smokingPreferenceIds)) { throw new ApiErrorException('smoking_fact_id: ID params not matching.'); } $this->bookingRoomService->update($params['booking_room']['id'], ['smoking_fact_id' => $params['booking_room']['smoking_fact_id']]); } //property_room_bed_id if($updateColumn == 'property_room_bed_id' && isset($params['booking_room']['property_room_bed_id'])) { $propertyRoomBedGroupIds = collect($bookingRoomDetail['room_rate_mapping']['property_room']['property_room_bed_group'])->pluck('id')->toArray(); if(!in_array($params['booking_room']['property_room_bed_id'],$propertyRoomBedGroupIds)) { throw new ApiErrorException('property_room_bed_id: ID params not matching.'); } $this->bookingRoomService->update($params['booking_room']['id'], ['property_room_bed_id' => $params['booking_room']['property_room_bed_id']]); } //property_room_bed_group_id if($updateColumn == 'property_room_bed_group_id' && isset($params['booking_room']['property_room_bed_group_id'])) { $propertyRoomBedGroupIds = collect($bookingRoomDetail['room_rate_mapping']['property_room']['property_room_bed_group'])->pluck('bed_group')->toArray(); if(!in_array($params['booking_room']['property_room_bed_group_id'],$propertyRoomBedGroupIds)) { throw new ApiErrorException('property_room_bed_group_id: ID params not matching.'); } $this->bookingRoomService->update($params['booking_room']['id'], ['property_room_bed_group_id' => $params['booking_room']['property_room_bed_group_id']]); } } } else { throw new ApiErrorException('Property Room ID not found.'); } $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => null]; } catch (ApiErrorException $e) { $response['message'] = implode(', ', $e->getMessageArr()); $response['statusCode'] = 400; } catch (Exception $e) { $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage(); Log::error($message); $response['message'] = $e->getMessage(); $response['statusCode'] = 500; } if ($response['status']) { DB::commit(); } else { DB::rollBack(); } return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']); } public function bookingPaymentInstallment(Request $request) { $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500]; try { $paymentData = []; $paymentData['isExchangeAmount'] = false; if (is_null($this->request->getContent())) { throw new ApiErrorException(lang('Parameter Error.')); } $params = json_decode($this->request->getContent(), 1); $propertyId = $this->bookingEnginePropertyId; $cardBinNumber = $params['cardBinNumber']; $amount = $params['amount']; $currency = $params['currency']; $paymentData['amount'] = $amount; $paymentData['currency'] = $currency; $paymentData['installment'] = []; $paymentType = $this->propertyPaymentService->getPaymentTypeMapping($propertyId, $currency, $cardBinNumber); if (is_null($paymentType['propertyPaymentMappingId'])) { throw new ApiErrorException(lang('Payment Type not found')); } if ($params['currency'] != $paymentType['propertyPaymentMappingCurrency']) { $exchangeRate = $this->propertyPaymentService->getExchangeRates(); if (isset($exchangeRate[$params['currency'] . $paymentType['propertyPaymentMappingCurrency']])) { $exchangeRateValue = $exchangeRate[$params['currency'] . $paymentType['propertyPaymentMappingCurrency']]; } else { throw new ApiErrorException(lang('Currency exchange value not found.')); } $paymentData['isExchangeAmount'] = true; $paymentData['amount'] = moneyDoubleFormatDecimal($amount * $exchangeRateValue); $paymentData['currency'] = $paymentType['propertyPaymentMappingCurrency']; $paymentData['base_amount'] = $amount; $paymentData['base_currency'] = $currency; $paymentData['exchangeRate'] = $exchangeRateValue; } if (!empty($paymentType['propertyPaymentMappingInstallment'])) { $amountBeforeInstallment = $amount; if ($paymentData['isExchangeAmount']) { $amountBeforeInstallment = $paymentData['amount']; } foreach ($paymentType['propertyPaymentMappingInstallment'] as $installmentData) { $paymentData['installment'][$installmentData['installment']] = [ 'installment' => $installmentData['installment'], 'commission' => $installmentData['commission'], 'amount' => moneyDoubleFormatDecimal($amountBeforeInstallment + ($amountBeforeInstallment * $installmentData['commission'] / 100)) ]; } } $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $paymentData]; } catch (ApiErrorException $e) { $response['message'] = implode(', ', $e->getMessageArr()); $response['statusCode'] = 400; } catch (Exception $e) { $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage(); Log::error($message); $response['message'] = $e->getMessage(); $response['statusCode'] = 500; } if ($response['status']) { DB::commit(); } else { DB::rollBack(); } return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']); } public function couponCodeCheck(Request $request) { $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500]; try { if (is_null($this->request->getContent())) { throw new ApiErrorException(lang('Parameter Error.')); } $params = json_decode($this->request->getContent(), 1); $couponData = []; $channelId = $this->channelId; $propertyId = $this->bookingEnginePropertyId; $getChannelPropertyDetail = $this->getChannelPropertyDetail($this->channelId, $propertyId); if (!$getChannelPropertyDetail['status']) { throw new ApiErrorException(lang('Property and Channel are not matched.')); } $getChannelPropertyDetail = $getChannelPropertyDetail['data']; $propertyChannelCouponCriteria = [ 'criteria' => [ ['field' => 'property_id', 'condition' => '=', 'value' => $getChannelPropertyDetail['property_id']], ['field' => 'channel_id', 'condition' => '=', 'value' => $getChannelPropertyDetail['channel_id']], ['field' => 'code', 'condition' => '=', 'value' => $params['code']], ['field' => 'start_date', 'condition' => '<=', 'value' => Carbon::now()->toDateString()], ['field' => 'end_date', 'condition' => '>=', 'value' => Carbon::now()->toDateString()], ['field' => 'status', 'condition' => '=', 'value' => 1], ], 'firstRow' => true ]; $propertyChannelCoupon = $this->propertyChannelCouponService->select($propertyChannelCouponCriteria); if ($propertyChannelCoupon['status'] == 'success') { $propertyChannelCoupon = $propertyChannelCoupon['data']; } if (empty($propertyChannelCoupon)) { throw new ApiErrorException(lang('Code that has expired or is not available.')); } $codeChecked = fillOnUndefined($propertyChannelCoupon,'checked', 0); $codeChecked++; $this->propertyChannelCouponService->update($propertyChannelCoupon['id'], ['checked' => $codeChecked]); //Reservation Date Check if (!is_null($propertyChannelCoupon['reservation_start_date']) && !is_null($propertyChannelCoupon['reservation_end_date'])) { if (isset($params['checkIn']) && isset($params['checkOut'])) { $reservationDateCheck = Carbon::parse($propertyChannelCoupon['reservation_start_date'])->lessThanOrEqualTo(Carbon::parse($params['checkIn'])) && Carbon::parse($propertyChannelCoupon['reservation_end_date'])->greaterThanOrEqualTo(Carbon::parse($params['checkOut'])); if (!$reservationDateCheck) { throw new ApiErrorException(lang('The code is not within the reservation period entered.')); } } } $couponData = [ 'code' => $propertyChannelCoupon['code'], 'type' => $propertyChannelCoupon['type'], 'value' => $propertyChannelCoupon['value'], ]; $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $couponData]; } catch (ApiErrorException $e) { $response['message'] = implode(', ', $e->getMessageArr()); $response['statusCode'] = 400; } catch (Exception $e) { $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage(); Log::error($message); $response['message'] = $e->getMessage(); $response['statusCode'] = 500; } return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']); } public function couponCodeNotify(Request $request) { $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500]; try { if (is_null($this->request->getContent())) { throw new ApiErrorException(lang('Parameter Error.')); } $params = json_decode($this->request->getContent(), 1); $channelId = $this->channelId; $propertyId = $this->bookingEnginePropertyId; $getChannelPropertyDetail = $this->getChannelPropertyDetail($this->channelId, $propertyId); if (!$getChannelPropertyDetail['status']) { throw new ApiErrorException(lang('Property and Channel are not matched.')); } $getChannelPropertyDetail = $getChannelPropertyDetail['data']; $propertyChannelCouponCriteria = [ 'criteria' => [ ['field' => 'property_id', 'condition' => '=', 'value' => $getChannelPropertyDetail['property_id']], ['field' => 'channel_id', 'condition' => '=', 'value' => $getChannelPropertyDetail['channel_id']], //['field' => 'code', 'condition' => '=', 'value' => $params['code']], ['field' => 'start_date', 'condition' => '<=', 'value' => Carbon::now()->toDateString()], ['field' => 'end_date', 'condition' => '>=', 'value' => Carbon::now()->toDateString()], ['field' => 'status', 'condition' => '=', 'value' => 1], ['field' => 'is_notify', 'condition' => '=', 'value' => 1], ], "orderBy" => [ ["field" => "id", "value" => "DESC"] ], 'firstRow' => true ]; //dd($propertyChannelCouponCriteria); $propertyChannelCoupon = $this->propertyChannelCouponService->select($propertyChannelCouponCriteria); if ($propertyChannelCoupon['status'] == 'success') { $propertyChannelCoupon = $propertyChannelCoupon['data']; } if (empty($propertyChannelCoupon)) { throw new ApiErrorException(lang('No active code to notify was found')); } //Reservation Date Check if (!is_null($propertyChannelCoupon['reservation_start_date']) && !is_null($propertyChannelCoupon['reservation_end_date'])) { if (isset($params['checkIn']) && isset($params['checkOut'])) { $reservationDateCheck = Carbon::parse($propertyChannelCoupon['reservation_start_date'])->lessThanOrEqualTo(Carbon::parse($params['checkIn'])) && Carbon::parse($propertyChannelCoupon['reservation_end_date'])->greaterThanOrEqualTo(Carbon::parse($params['checkOut'])); if (!$reservationDateCheck) { throw new ApiErrorException(lang('The code is not within the reservation period entered.')); } } } $couponData = [ 'code' => $propertyChannelCoupon['code'], 'type' => $propertyChannelCoupon['type'], 'value' => $propertyChannelCoupon['value'], ]; $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $couponData]; } catch (ApiErrorException $e) { $response['message'] = implode(', ', $e->getMessageArr()); $response['statusCode'] = 400; } catch (Exception $e) { $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage(); Log::error($message); $response['message'] = $e->getMessage(); $response['statusCode'] = 500; } return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']); } public function bookingAddonAttribute(Request $request) { $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500]; try { if (is_null($this->request->getContent())) { throw new ApiErrorException(lang('Parameter Error.')); } $params = json_decode($this->request->getContent(), 1); $channelId = $this->channelId; $propertyId = $this->bookingEnginePropertyId; $bookingCode = $params['bookingCode']; $bookingAddonId = $params['bookingAddonId']; //TODO: Validator, $getChannelPropertyDetail = $this->getChannelPropertyDetail($channelId, $propertyId); if (!$getChannelPropertyDetail['status']) { throw new ApiErrorException(lang('Property and Channel are not matched.')); } $bookingDetailParam = [ 'criteria' => [ ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId], ['field' => 'channel_id', 'condition' => '=', 'value' => $channelId], ['field' => 'booking_code', 'condition' => '=', 'value' => $bookingCode] ], 'with' => ['bookingAddon.propertyChannelAddon.propertyAddon.fact'], 'firstRow' => true ]; $bookingDetail = $this->bookingService->select($bookingDetailParam); if ($bookingDetail['status'] != 'success' || empty($bookingDetail['data'])) { throw new ApiErrorException('Booking not found'); } $bookingDetail = $bookingDetail['data']; if (empty($bookingDetail['booking_addon'])) { throw new ApiErrorException('Booking Addon not found'); } $bookingAddonCollect = collect($bookingDetail['booking_addon']); $selectedAddon = $bookingAddonCollect->where('id', $bookingAddonId)->first(); if (empty($selectedAddon)) { throw new ApiErrorException('Booking Selected Addon not found'); } $attributeArray = $selectedAddon['property_channel_addon']['property_addon']['attributeArray']; $addonInfoAttribute = null; if (isset($params['attribute'])) { foreach ($params['attribute'] as $addonAttribute) { if (count(array_intersect_key($addonAttribute, $attributeArray)) != count($addonAttribute)) { throw new ApiErrorException('Additional product attribute values submitted do not match.'); } } $addonInfoAttribute = $params['attribute']; } if ($selectedAddon['count'] != count($addonInfoAttribute)) { throw new ApiErrorException('The number of additional items purchased and the number of additional information entered do not match'); } $updateParam['attribute'] = null; if (!is_null($addonInfoAttribute)) { $updateParam['attribute'] = json_encode($addonInfoAttribute); } $this->bookingAddonService->update($bookingAddonId, $updateParam); $bookingPropertyAddonUpdateMail = [ 'propertyId' => $bookingDetail['property_id'], 'bookingCode' => $bookingDetail['booking_code'], 'addonLanguageKey' => $selectedAddon['property_channel_addon']['property_addon']['fact']['language_key'] ]; $this->mailer->onQueue('bookingPropertyAddonUpdateMail', new BookingPropertyAddonUpdateMail($bookingPropertyAddonUpdateMail)); $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => []]; } catch (ApiErrorException $e) { $response['message'] = implode(', ', $e->getMessageArr()); $response['statusCode'] = 400; } catch (Exception $e) { $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage(); Log::error($message); $response['message'] = $e->getMessage(); $response['statusCode'] = 500; } return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']); } public function bookingCancellation(Request $request) { $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500]; try { $confirmCodeGenerate = null; $propertyBookingController = \Illuminate\Support\Facades\App::make("App\Http\Controllers\V1\PropertyBookingController"); if (is_null($this->request->getContent())) { throw new ApiErrorException(lang('Parameter Error.')); } $params = json_decode($this->request->getContent(), 1); $channelId = $this->channelId; $propertyId = $this->bookingEnginePropertyId; $bookingCode = $params['bookingCode']; $confirmCode = fillOnUndefined($params, 'confirmCode'); $getChannelPropertyDetail = $this->getChannelPropertyDetail($channelId, $propertyId); if (!$getChannelPropertyDetail['status']) { throw new ApiErrorException(lang('Property and Channel are not matched.')); } $getChannelPropertyDetail = $getChannelPropertyDetail['data']; $bookingDetailParam = [ 'criteria' => [ ['field' => 'channel_id', 'condition' => '=', 'value' => $channelId], ['field' => 'booking_code', 'condition' => '=', 'value' => $bookingCode] ], 'with' => ['bookingChannel.propertyChannelCategory', 'bookingProperty', 'bookingRoom'], 'firstRow' => true ]; $bookingDetail = $this->bookingService->select($bookingDetailParam); if ($bookingDetail['status'] != 'success' || ($bookingDetail['status'] == 'success' && empty($bookingDetail['data']))) { throw new ApiErrorException('Property and Booking Code are not matched.'); } $bookingDetail = $bookingDetail['data']; if ($bookingDetail['status'] != 1) { throw new ApiErrorException('Reservation status not available.'); } //Only GE Hotels if ($bookingDetail['status'] == 1 && in_array($bookingDetail['booking_channel']['channel_category_id'], [3]) && in_array($bookingDetail['booking_property']['country'], ['GE'])) { //Check Cancellation Policy $isBookingRefundable = false; foreach ($bookingDetail['booking_room'] as $bookingRoom) { $cancellationPolicy = json_decode($bookingRoom['cancellation_policy'], 1); if (!empty($cancellationPolicy)) { if ($cancellationPolicy['isNonRefundable']) { break; } if ($cancellationPolicy['isFreeCancellation']) { if (isset($cancellationPolicy['beforeArrivalDay'])) { if (Carbon::now()->startOfDay()->lessThan(Carbon::parse($bookingRoom['checkin_date'])->subDays($cancellationPolicy['beforeArrivalDay'])->toDateString())) { $isBookingRefundable = true; } } else { $isBookingRefundable = true; } } } } if ($isBookingRefundable) { //Cancellation Process $updateBookingParam = [ 'locale' => $request->getLocale(), 'property_id' => $bookingDetail['property_id'], 'booking_id' => $bookingDetail['id'], 'total' => $bookingDetail['total'], 'currency_code' => $bookingDetail['currency_code'], 'status' => 0 ]; $request['requestParams'] = $updateBookingParam; $updateBooking = $propertyBookingController->updateBooking($request); $updateBooking = $updateBooking->getData(); if ($updateBooking->status != 200) { throw new ApiErrorException($updateBooking->message); } $mailParams = ['booking_id' => $bookingDetail['id']]; $this->mailer->onQueue('cancelBookingMail', new CancelBookingMail($mailParams)); $response = [ 'status' => 1, 'statusCode' => 200, 'data' => [ 'isCancellationRequest' => true ], 'message' => __('api-cancellation_confirm-message', [], $request->getLocale()) ]; } else { $mailParams = [ 'bookingCode' => $bookingCode ]; $this->mailer->send(new BookingCancellationRequestMail($mailParams)); $response = [ 'status' => 1, 'statusCode' => 200, 'data' => [ 'isCancellationRequest' => true ], 'message' => __('api-cancellation_request-message', [], $request->getLocale()) ]; } return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']); } //Just Offline Booking Engines if (!in_array($bookingDetail['booking_channel']['channel_category_id'], [2, 7])) { throw new ApiErrorException('Online reservation cancellation is not active for this channel.'); } //TODO: Checkin tarihi geçmemiş olmalı kontrol eklenecek $cacheKey = md5('BookingCancellation-' . $bookingDetail['booking_code']); if (!empty($confirmCode) || in_array($bookingDetail['booking_channel']['channel_category_id'], [7])) { if (!in_array($bookingDetail['booking_channel']['channel_category_id'], [7])) { if (!Cache::has($cacheKey)) { throw new ApiErrorException('Verification code not found, please try again.'); } if ($confirmCode != Cache::get($cacheKey)) { throw new ApiErrorException('The entered code could not be verified, please enter the updated code sent to your e-mail address.'); } } //Cancellation Process $updateBookingParam = [ 'locale' => $request->getLocale(), 'property_id' => $bookingDetail['property_id'], 'booking_id' => $bookingDetail['id'], 'total' => $bookingDetail['total'], 'currency_code' => $bookingDetail['currency_code'], 'status' => 0 ]; $request['requestParams'] = $updateBookingParam; $updateBooking = $propertyBookingController->updateBooking($request); $updateBooking = $updateBooking->getData(); if ($updateBooking->status != 200) { throw new ApiErrorException($updateBooking->message); } $mailParams = ['booking_id' => $bookingDetail['id']]; $this->mailer->onQueue('cancelBookingMail', new CancelBookingMail($mailParams)); Cache::forget($cacheKey); $response = [ 'status' => 1, 'statusCode' => 200, 'data' => null, 'message' => null ]; } else { $confirmCodeGenerate = rand(1000, 9999); Cache::put($cacheKey, $confirmCodeGenerate, 60 * 5);//600 10 dk //$confirmCode $mailParams = [ 'bookingCode' => $bookingCode, 'confirmCode' => $confirmCodeGenerate ]; $this->mailer->send(new BookingCancellationConfirmCodeMail($mailParams)); $response = [ 'status' => 1, 'statusCode' => 200, 'data' => null, 'message' => 'Please enter the cancellation verification code sent to your e-mail address.' ]; } } catch (ApiErrorException $e) { $response['message'] = implode(', ', $e->getMessageArr()); $response['statusCode'] = 400; } catch (Exception $e) { $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage(); Log::error($message); $response['message'] = $e->getMessage(); $response['statusCode'] = 500; } return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']); } public function bookingInvoice(Request $request) { $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500]; try { if (is_null($this->request->getContent())) { throw new ApiErrorException(lang('Parameter Error.')); } $params = json_decode($this->request->getContent(), 1); $channelId = $this->channelId; $propertyId = $this->bookingEnginePropertyId; $bookingCode = $params['bookingCode']; $getChannelPropertyDetail = $this->getChannelPropertyDetail($channelId, $propertyId); if (!$getChannelPropertyDetail['status']) { throw new ApiErrorException(lang('Property and Channel are not matched.')); } $getChannelPropertyDetail = $getChannelPropertyDetail['data']; $bookingDetailParam = [ 'criteria' => [ ['field' => 'channel_id', 'condition' => '=', 'value' => $channelId], ['field' => 'booking_code', 'condition' => '=', 'value' => $bookingCode] ], 'with' => ['bookingChannel.propertyChannelCategory', 'bookingProperty', 'bookingRoom', 'bookingContact'], 'firstRow' => true ]; $bookingDetail = $this->bookingService->select($bookingDetailParam); if ($bookingDetail['status'] != 'success' || ($bookingDetail['status'] == 'success' && empty($bookingDetail['data']))) { throw new ApiErrorException('Property and Booking Code are not matched.'); } $bookingDetail = $bookingDetail['data']; if ($bookingDetail['status'] != 1) { throw new ApiErrorException('Reservation status not available.'); } if ($bookingDetail['booking_contact']['invoice_request'] != 1) { throw new ApiErrorException('Reservation invoice status not available.'); } $invoiceParam = [ 'name_surname' => fillOnUndefined($params, 'name_surname'), 'citizen_number' => fillOnUndefined($params, 'citizen_number'), 'company' => fillOnUndefined($params, 'company'), 'tax_number' => fillOnUndefined($params, 'tax_number'), 'address' => fillOnUndefined($params, 'address'), ]; $bookingInvoiceUpdate = $this->bookingContactService->update($bookingDetail['booking_contact']['id'], ['invoice' => json_encode($invoiceParam)]); if ($bookingInvoiceUpdate['status'] != 'success') { throw new ApiErrorException('Invoice update operation could not be performed.'); } $bookingPropertyAddonUpdateMail = [ 'bookingCode' => $bookingDetail['booking_code'] ]; $this->mailer->onQueue('bookingInvoiceUpdateMail', new BookingInvoiceUpdateMail($bookingPropertyAddonUpdateMail)); $response = [ 'status' => 1, 'statusCode' => 200, 'data' => null, 'message' => null ]; } catch (ApiErrorException $e) { $response['message'] = implode(', ', $e->getMessageArr()); $response['statusCode'] = 400; } catch (Exception $e) { $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage(); Log::error($message); $response['message'] = $e->getMessage(); $response['statusCode'] = 500; } return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']); } public function propertyList(Request $request) { $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500]; try { $ipAddress = $request->ip(); $channelToken = $request->header('channelToken'); if (!$channelToken) { return apiResponse(0, 'Token not provided.', null, 401); } $ipRestriction = [ //City Travel '1500c5d5-b55e-4fa0-966b-698f4f168f48' => [ '127.0.0.1', '185.137.215.118', '176.236.59.130', '176.236.59.131', '176.236.59.132', '176.236.59.133', '176.236.59.134', '176.236.59.135', '176.236.59.136', '176.236.59.137', '176.236.59.138', '176.236.59.139', '54.72.215.85', '54.77.48.206', '34.252.23.103', '52.19.162.59', '54.72.80.155', '52.210.166.9', '54.72.220.60', '52.17.235.55', '176.236.59.130', '54.72.215.85', '54.77.48.206', '52.213.250.14', '34.252.23.103' ] ]; if (isset($ipRestriction[$channelToken]) && !in_array($ipAddress, $ipRestriction[$channelToken])) { return apiResponse(0, 'Cannot be accessed via this IP address: ' . $ipAddress, null, 401); } $channelRequest = [ 'criteria' => [ ['field' => 'token', 'condition' => '=', 'value' => $channelToken], ['field' => 'status', 'condition' => '=', 'value' => 1], ], 'firstRow' => 1 ]; $channelCheck = $this->channelService->select($channelRequest); if ($channelCheck['status'] != 'success' || empty($channelCheck['data'])) { return apiResponse(0, 'Channel Token not found.', null, 401); } $channelCheck = $channelCheck['data']; $propertyBookingEngineParam = [ 'criteria' => [ ['field' => 'channel_id', 'condition' => '=', 'value' => $channelCheck['id']], ['field' => 'status', 'condition' => '=', 'value' => 1], ], 'with' => ['channel', 'property.propertyBookingEngineToken', 'property.propertyType', 'property.propertyContact', 'property.propertyDestination'], "orderBy" => [ ["field" => "id", "value" => "DESC"] ] ]; $propertyBookingEngine = $this->propertyBookingEngineService->select($propertyBookingEngineParam); $propertyBookingEngine = $propertyBookingEngine['status'] == 'success' ? $propertyBookingEngine['data'] : []; $propertyList = []; foreach ($propertyBookingEngine as $bookingEngine) { $propertyList[] = [ 'id' => $bookingEngine['property']['id'], 'name' => $bookingEngine['property']['name'], 'type' => $bookingEngine['property']['property_type']['name'], 'country' => $bookingEngine['property']['country'], 'destination' => $bookingEngine['property']['property_destination']['name'], 'destination_id' => $bookingEngine['property']['destination_id'], 'token' => $bookingEngine['token'], 'mapping' => !empty($bookingEngine['property']['mapping']) ? json_decode($bookingEngine['property']['mapping'], 1) : null, 'contact' => [ 'address' => $bookingEngine['property']['property_contact']['address'], 'phone' => $bookingEngine['property']['property_contact']['view_full_phone'], 'email' => $bookingEngine['property']['property_contact']['email'], 'latitude' => $bookingEngine['property']['property_contact']['latitude'], 'longitude' => $bookingEngine['property']['property_contact']['longitude'], ], ]; } $response = [ 'status' => 1, 'statusCode' => 200, 'data' => $propertyList, 'message' => null ]; } catch (ApiErrorException $e) { $response['message'] = implode(', ', $e->getMessageArr()); $response['statusCode'] = 400; } catch (Exception $e) { $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage(); Log::error($message); $response['message'] = $e->getMessage(); $response['statusCode'] = 500; } return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']); } }