first commit

This commit is contained in:
ExtraNetwork
2026-05-12 17:04:54 +03:00
commit e5c4b6aa13
1425 changed files with 284735 additions and 0 deletions

View File

@@ -0,0 +1,541 @@
<?php
namespace App\Http\Controllers\MetaSearch\Yandex\v1;
use App\Core\Service\ChannelManagerPropertyMappingService;
use App\Core\Service\CurrencyService;
use App\Core\Service\PropertyChannelCouponService;
use App\Exceptions\ApiErrorException;
use App\Http\Controllers\Controller;
use App\Models\PropertyChannel;
use App\Models\PropertyContact;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Exception;
class YandexController extends Controller
{
private $username;
private $password;
private $authorization;
private $channelManagerId;
private $channelManagerLogId;
private $mealCodeMapping;
private $paymentTypeMapping;
private $countryCodeCampaign;
public function __construct(
Request $request,
CurrencyService $currencyService,
ChannelManagerPropertyMappingService $channelManagerPropertyMappingService,
PropertyChannelCouponService $propertyChannelCouponService
)
{
$this->username = 'yandex';
$this->password = 'P8MUQtNP6TkKMz3E';
$this->channelManagerId = 13;//Yandex
$this->request = $request;
$this->currencyService = $currencyService;
$this->channelManagerPropertyMappingService = $channelManagerPropertyMappingService;
$this->propertyChannelCouponService = $propertyChannelCouponService;
$payload = $this->request->getContent();
parse_str(urldecode($payload), $payloadDecode);
$this->param = $payloadDecode;
$this->authorization = $request->header('authorization');
$this->tax = 10;
$this->mealCodeMapping = [
10 => 'AI',
11 => 'BB',
13 => 'RO',
14 => 'FB',
15 => 'HB',
];
$this->paymentTypeMapping = [
'CRD' => 'prepaid',
'HTL' => 'postpaid'
];
}
public function checkAuthentication($authorization)
{
$response = ['status' => false, 'message' => ''];
$basicAuth = 'Basic ' . base64_encode($this->username . ':' . $this->password);
if ($authorization != $basicAuth) {
$response['message'] = 'Your username or password is incorrect.';
} else {
$response['status'] = true;
}
return $response;
}
public function responseError($errorMessage)
{
$response = [
'status' => false,
'message' => $errorMessage,
];
//channelManagerLogService
if (!is_null($this->channelManagerLogId)) {
$updateDataLog = [
'response' => json_encode($response),
'status' => 0
];
if (!is_null($this->channelManagerRequestTime)) {
$updateDataLog['response_time'] = microtime(true) - $this->channelManagerRequestTime;
}
$channelManagerLog = $this->channelManagerLogService->update($this->channelManagerLogId, $updateDataLog);
}
//channelManagerLogService
return response()->json($response);
}
public function requestParamConverter($requestParam = [])
{
$searchRequestJson = [];
$searchRequestJson['date']['checkIn'] = Carbon::parse($requestParam['Checkin'])->toDateString();
$searchRequestJson['date']['checkOut'] = Carbon::parse($requestParam['Checkin'])->addDays($requestParam['Nights'])->toDateString();
$rooms = [];
$rooms[0]['adults'] = (integer)$requestParam['Context']['OccupancyDetails']['NumAdults'];
$rooms[0]['children'] = (integer)($requestParam['Context']['Occupancy'] - $requestParam['Context']['OccupancyDetails']['NumAdults']);
$rooms[0]['age'] = [];
if (isset($requestParam['Context']['OccupancyDetails']['Children']['Child'])) {
$requestParam['Context']['OccupancyDetails']['Children']['Child'] = singleElementXMLArray($requestParam['Context']['OccupancyDetails']['Children']['Child']);
} else {
$requestParam['Context']['OccupancyDetails']['Children']['Child'] = [];
}
foreach ($requestParam['Context']['OccupancyDetails']['Children']['Child'] as $child) {
$rooms[0]['age'][] = $child['@attributes']['age'];
}
$searchRequestJson['rooms'] = $rooms;
if (isset($requestParam['PropertyList']['Property'])) {
$requestParam['PropertyList']['Property'] = singleElementXMLArray($requestParam['PropertyList']['Property']);
} else {
$requestParam['PropertyList']['Property'] = [];
}
$searchRequestJson['property'] = $requestParam['PropertyList']['Property'];
return $searchRequestJson;
}
public function roomOccupancy($requestParam)
{
$roomOccupancy = [];
foreach ($requestParam as $room) {
$adults = str_repeat('A', $room['adults']);
$children = [];
if ($room['children'] > 0 && !empty($room['age'])) {
foreach ($room['age'] as $child) {
$children[] = 'C' . $child;
}
}
$roomOccupancy[] = $adults . implode('', $children);
}
return $roomOccupancy;
}
public function deepLinkGenerator($token, $requestParam = [])
{
$deepLink = 'https://be.extranetwork.com/' . $token . '/' . fillOnUndefined($requestParam, 'locale', 'en') . '/search/';
$deepLink .= Carbon::parse($requestParam['date']['checkIn'])->format('Ymd') . '/';
$deepLink .= Carbon::parse($requestParam['date']['checkOut'])->format('Ymd') . '/';
$roomOccupancy = $this->roomOccupancy($requestParam['rooms']);
$deepLink .= implode(',', $roomOccupancy);;
$deepLink .= '?utm_source=yandex';
return $deepLink;
}
public function couponCodeCheck($propertyId, $checkIn, $checkOut)
{
//$propertyChannelCoupon
$propertyChannelCouponsCriteria = [
'criteria' => [
['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
['field' => 'channel_id', 'condition' => '=', 'value' => 1],
['field' => 'start_date', 'condition' => '<=', 'value' => Carbon::now()->toDateString()],
['field' => 'end_date', 'condition' => '>=', 'value' => Carbon::now()->toDateString()],
['field' => 'status', 'condition' => '=', 'value' => 1],
],
'orderBy' => [
['field' => 'id', 'value' => 'DESC']
],
];
$propertyChannelCoupons = $this->propertyChannelCouponService->select($propertyChannelCouponsCriteria);
if ($propertyChannelCoupons['status'] == 'success') {
$propertyChannelCoupons = $propertyChannelCoupons['data'];
foreach ($propertyChannelCoupons as $propertyChannelCouponKey => $propertyChannelCouponData) {
//Reservation Date Check
if (!is_null($propertyChannelCouponData['reservation_start_date']) && !is_null($propertyChannelCouponData['reservation_end_date'])) {
$reservationDateCheck = Carbon::parse($propertyChannelCouponData['reservation_start_date'])->lessThanOrEqualTo(Carbon::parse($checkIn))
&& Carbon::parse($propertyChannelCouponData['reservation_end_date'])->greaterThanOrEqualTo(Carbon::parse($checkOut));
if (!$reservationDateCheck) {
unset($propertyChannelCoupons[$propertyChannelCouponKey]);
}
}
}
} else {
$propertyChannelCoupons = [];
}
$propertyChannelCoupon = !empty($propertyChannelCoupons) ? reset($propertyChannelCoupons) : null;
return $propertyChannelCoupon;
}
public function hotel(Request $request)
{
$response = ['status' => true, 'message' => ''];
$listings = new \SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><listings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.gstatic.com/localfeed/local_feed.xsd"></listings>');
$listings->addChild('language', 'tr');
try {
$channelManagerPropertyMappingCriteria['criteria'] = [
['field' => 'channel_manager_id', 'condition' => '=', 'value' => $this->channelManagerId],
['field' => 'channel_manager_property_id', 'condition' => '=', 'value' => null],
['field' => 'status', 'condition' => '=', 'value' => 1],
];
$channelManagerPropertyMappingCriteria['with'] = [
'property.propertyType', 'property.propertyContact', 'property.propertyWeb', 'property.country'
];
$channelManagerPropertyMapping = $this->channelManagerPropertyMappingService->select($channelManagerPropertyMappingCriteria);
if ($channelManagerPropertyMapping['status'] == 'success' && !empty($channelManagerPropertyMapping['data'])) {
foreach ($channelManagerPropertyMapping['data'] as $propertyMapping) {
if ($propertyMapping['status'] != 1) {
continue;
}
$metaAddress = json_decode($propertyMapping['property']['property_contact']['meta'], 1);
$listing = $listings->addChild('listing');
$listing->addChild('id', $propertyMapping['property']['id']);
$listing->addChild('name', htmlspecialchars($propertyMapping['property']['name'], ENT_XML1, 'UTF-8'));
$address = $listing->addChild('address');
$address->addAttribute('format', 'simple');
$component = $address->addChild('component', htmlspecialchars(fillOnUndefined($metaAddress, 'street'), ENT_XML1, 'UTF-8'));
$component->addAttribute('name', 'addr1');
//$component = $address->addChild('component');
//$component->addAttribute('name', 'addr2');
$component = $address->addChild('component', fillOnUndefined($metaAddress, 'city'));
$component->addAttribute('name', 'city');
//$component = $address->addChild('component', $propertyMapping['property']['country']['name']);
//$component->addAttribute('name','region');
$component = $address->addChild('component', fillOnUndefined($metaAddress, 'zip_code'));
$component->addAttribute('name', 'postal_code');
$listing->addChild('country', $propertyMapping['property']['country']['country_code']);
$listing->addChild('latitude', $propertyMapping['property']['property_contact']['latitude']);
$listing->addChild('longitude', $propertyMapping['property']['property_contact']['longitude']);
$listing->addChild('category', 'hotel');
}
}
} 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();
}
header('Content-Type: application/xml; charset=UTF-8');
echo $listings->asXML();
exit;
}
public function availability(Request $request)
{
$response = ['status' => true, 'message' => ''];
$checkAuthentication = $this->checkAuthentication($this->authorization);
if (!$checkAuthentication['status']) {
return $this->responseError($checkAuthentication['message']);
}
$searchController = App::make("App\Http\Controllers\BookingEngine\V1\SearchController");
$requestTime = microtime(true);
$param = $this->request->getContent();
$paramXML = simplexml_load_string($param);
$requestParam = json_decode(json_encode($paramXML), 1);
$hotelIdList = collect($requestParam['PropertyList']['Property'])->values();
$hotelIdList = $hotelIdList ? $hotelIdList->toArray() : [];
$transaction = new \SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><Transaction></Transaction>');
try {
//Hotels Check
$channelManagerPropertyList = [];
$channelManagerPropertyMappingCriteria['criteria'] = [
['field' => 'channel_manager_id', 'condition' => '=', 'value' => $this->channelManagerId],
['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'])) {
$channelManagerPropertyList = pickItemFromArray('property_id', $channelManagerPropertyMapping['data']);
}
$availableHotelIds = array_intersect($hotelIdList, $channelManagerPropertyList);
if (empty($availableHotelIds)) {
throw new ApiErrorException('Hotel not found');
}
//Hotels Check
$searchRequestJson = $this->requestParamConverter($requestParam);
$searchRequestJson['isMobile'] = null;
$searchRequestJson['noneCacheSearch'] = true;
$searchRequestJson['ipAddress'] = $request->getClientIp();
$searchRequestJson['justPriceValues'] = true;
$searchRequestJson['locale'] = fillOnUndefined($requestParam, 'Locale') ?? 'tr';
$roomOccupancy = $this->roomOccupancy($searchRequestJson['rooms']);
$roomOccupancy = implode(',', $roomOccupancy);
$requestCurrency = fillOnUndefined($requestParam, 'Currency') ?? 'TRY';
$cacheKeyParam = $requestCurrency . ':' . $searchRequestJson['date']['checkIn'] . ':' . $searchRequestJson['date']['checkOut'] . ':' . implode(',', $searchRequestJson['property']) . ':' . $roomOccupancy;
$cacheKey = 'YND:' . md5($cacheKeyParam);
//Cache::forget($cacheKey);
if (Cache::has($cacheKey)) {
$search = Cache::get($cacheKey);
} else {
$requestCreate = Request::create(null, null, [], [], [], [], json_encode($searchRequestJson));
$requestCreate->headers->set('channelId', '1');
//$requestCreate->headers->set('bookingEnginePropertyId', null);
$requestCreate->headers->set('channelToken', 'ece3ef02-42e7-92b7-f379-08226ed7a0f3');//TODO: from DB
$requestCreate->headers->set('bookingEngineToken', null);
$search = $searchController->search($requestCreate);
Cache::put($cacheKey, $search, 60 * 60);//1 Day 24 * 60 * 60
}
$search = json_decode(json_encode($search), 1);
if ($search['original']['status'] != 200) {
throw new ApiErrorException('Hotel not found');
}
$properties = $search['original']['data']['properties'];
if (empty($properties)) {
throw new ApiErrorException('Hotel not found');
}
$hotelCounter = 0;
$numberOfStay = Carbon::parse($searchRequestJson['date']['checkIn'])->diffInDays(Carbon::parse($searchRequestJson['date']['checkOut']));
foreach ($properties as $propertyId => $property) {
$propertyName = $property['name'];
if (!isset($property['currency'])) {
continue;
}
$currencyExchangeRate = 1;
if ($requestCurrency != $property['currency']) {
$currencyExchangeRate = $this->currencyService->lastExchangeRate($property['currency'], $requestCurrency);
if ($currencyExchangeRate['status'] == 'success') {
$currencyExchangeRate = $currencyExchangeRate['data'];
}
}
$token = $property['booking_engine_token'];
$deepLinkGenerator = $this->deepLinkGenerator($token, $searchRequestJson);
$property = reset($property['availabilities']);
$propertyRooms = $property['rooms'];
//Standard Room Room Only FreeCancellation - Pay at Hotel
$requestedRoomPriceGroup = [];
foreach ($propertyRooms as $propertyRoomId => $propertyRoom) {
foreach ($propertyRoom['rates'] as $propertyRoomRateId => $propertyRoomRate) {
foreach ($propertyRoomRate['requestedRoomPrice'] as $occupancyCode => $requestedRoomPrices) {
foreach ($requestedRoomPrices['prices'] as $requestedRoomPriceKey => $requestedRoomPrice) {
$roomRateKeyName = $occupancyCode . ' ' . $requestedRoomPrice['room']['name'] . ' ' . $requestedRoomPrice['rate']['boardName'] . ' ' . $requestedRoomPrice['name'];
$roomRateKeycode = $requestedRoomPrice['rate']['accommodationCode'] . '|' . (isset($requestedRoomPrice['cancellationPolicy']['id']) ? $requestedRoomPrice['cancellationPolicy']['id'] : 0) . '|' . $requestedRoomPrice['bookingPaymentType']['code'];
//$requestedRoomPriceGroup[$roomRateKeycode][$occupancyCode][] = $roomRateKeyName . '-' . $requestedRoomPrice['rateKeyCode'];
$requestedRoomPrice['dailyAverageDiscount'] = $requestedRoomPrices['dailyAverageDiscount'];
$requestedRoomPriceGroup[] = $requestedRoomPrice;
}
}
}
}
if (!empty($requestedRoomPriceGroup)) {
$requestedRoomPriceGroup = collect($requestedRoomPriceGroup)->sortBy('total')->toArray();
}
$requestedRoomPrice = reset($requestedRoomPriceGroup);
$propertyCouponCodeCheck = $this->couponCodeCheck($propertyId, $searchRequestJson['date']['checkIn'], $searchRequestJson['date']['checkOut']);
if ($propertyCouponCodeCheck) {
$requestedRoomPrice['totalWithoutPopup'] = $requestedRoomPrice['total'];
$couponPercentageValue = (100 - $propertyCouponCodeCheck['value']) / 100;
$requestedRoomPrice['total'] = moneyDoubleFormatDecimal($requestedRoomPrice['total'] * $couponPercentageValue);
}
$transactionResult = $transaction->addChild('Result');
$transactionResult->addChild('Property', $propertyId);
$transactionResult->addChild('Checkin', $searchRequestJson['date']['checkIn']);
$transactionResult->addChild('Nights', $numberOfStay);
$taxValue = $requestedRoomPrice['total'] * ($this->tax / 100);
$baseTotalValue = $requestedRoomPrice['total'] - $taxValue;
$netTotalValue = ($taxValue + $baseTotalValue);
$baseRate = $transactionResult->addChild('Baserate', moneyDoubleFormatDecimal($baseTotalValue * $currencyExchangeRate));
$baseRate->addAttribute('currency', $requestCurrency);
$tax = $transactionResult->addChild('Tax', moneyDoubleFormatDecimal($taxValue * $currencyExchangeRate));
$tax->addAttribute('currency', $requestCurrency);
$otherFees = $transactionResult->addChild('OtherFees', 0);
$otherFees->addAttribute('currency', $requestCurrency);
$transactionResult->addChild('Custom1', htmlspecialchars($propertyName, ENT_XML1, 'UTF-8'));
$allowablePointsOfSale = $transactionResult->addChild('AllowablePointsOfSale');
$pointOfSale = $allowablePointsOfSale->addChild('PointOfSale');
$pointOfSale->addAttribute('id', 'default');
$pointOfSale->addChild('URL', htmlspecialchars($deepLinkGenerator, ENT_XML1, 'UTF-8'));
}
} 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();
}
header('Content-Type: application/xml; charset=UTF-8');
echo $transaction->asXML();
exit;
}
}