/** * @param $cubilisRateIdDates * @param $roomTypeId * @param $dates * @param $bookingDomain * @param $fromCubilisRatesData * @param $productId * @param $channelResId * @param $partnerId * @param $isApartel * @param $building * @param $apartmentListUsed * @param $guestCount * @return array */ public function getNightlyData($cubilisRateIdDates, $roomTypeId, $dates, $bookingDomain, $fromCubilisRatesData, $productId, $channelResId, $partnerId, $isApartel, $building, $apartmentListUsed, $guestCount) { /** * @var \DDD\Dao\Apartment\General $apartmentDao * @var \DDD\Dao\Apartel\Inventory $apartelInventoryDao * @var \DDD\Dao\Apartel\General $apartelDao * @var \DDD\Service\Reservation\RateSelector $rateSelector * @var \DDD\Service\Reservation\RateSelector $rateSelector * @var \DDD\Service\Reservation\PartnerSpecific $partnerSpecificService * @var \DDD\Dao\Partners\Partners $partnerDao * @var \DDD\Service\Apartel\Type $apartelTypeService * @var \DDD\Service\Partners $partnerService */ $rateSelector = $this->getServiceLocator()->get('service_reservation_rate_selector'); $partnerSpecificService = $this->getServiceLocator()->get('service_reservation_partner_specific'); $apartmentInventoryDao = new Inventory($this->getServiceLocator(), '\\ArrayObject'); $apartelTypeService = $this->getServiceLocator()->get('service_apartel_type'); $partnerDao = $this->getServiceLocator()->get('dao_partners_partners'); $partnerService = $this->getServiceLocator()->get('service_partners'); $result = ['ratesData' => [], 'overbooking' => false, 'apartel' => false]; // night count $nightCount = Helper::getDaysFromTwoDate($dates['date_from'], $dates['date_to']); // Apartel reservation if ($isApartel) { $apartelInventoryDao = $this->getServiceLocator()->get('dao_apartel_inventory'); $apartelDao = $this->getServiceLocator()->get('dao_apartel_general'); $apartelId = $productId; $rates = $apartelInventoryDao->getRateByCubilisRateIdDates($cubilisRateIdDates, $roomTypeId); // if empty get parent and create task if (!count($rates) || count($rates) != $nightCount) { $rates = $apartelInventoryDao->getRateByParentRateIdDates($dates, $roomTypeId); $result['rateMissingTask'] = true; } $rates = iterator_to_array($rates); $firstApartment = $apartelDao->getApartelCurrency($apartelId); $ginosiCurrency = $firstApartment['code']; // modification if ($bookingDomain) { $apartmentId = $bookingDomain->getApartmentIdAssigned(); } else { // new reservation // get best apartment for apartel reservation $getApartmentForType = $apartelTypeService->getBestApartmentForType($roomTypeId, $dates, $guestCount, $apartmentListUsed, $building); if ($getApartmentForType['status'] == 'not-available') { $result['overbooking'] = true; } $apartmentId = $getApartmentForType['apartment_id']; } } else { $rates = $apartmentInventoryDao->getRateByCubilisRateIdDates($cubilisRateIdDates, $roomTypeId); // if empty get parent and create task if (!count($rates) || count($rates) != $nightCount) { $rates = $apartmentInventoryDao->getRateByParentRateIdDates($dates, $roomTypeId); $result['rateMissingTask'] = true; } $apartmentId = $productId; $apartelId = 0; $apartmentDao = $this->getServiceLocator()->get('dao_apartment_general'); $apartmentData = $apartmentDao->getCurrency($apartmentId); $ginosiCurrency = $apartmentData['code']; } $ratesData = []; $currencyNotMatch = $ratePriceNotMatch = $rateNameNot = false; // Modification: check has availability this apartment after change date if ($bookingDomain && ($dates['date_from'] < $bookingDomain->getDateFrom() || $dates['date_to'] > $bookingDomain->getDateTo())) { $oldNightlyData = Helper::getDateListInRange($bookingDomain->getDateFrom(), date('Y-m-d', strtotime('-1 day', strtotime($bookingDomain->getDateTo())))); $newDateRange = Helper::getDateListInRange($dates['date_from'], date('Y-m-d', strtotime('-1 day', strtotime($dates['date_to'])))); $diffDates = array_diff($newDateRange, $oldNightlyData); $apartmentAvailability = $apartmentInventoryDao->checkApartmentAvailabilityApartmentDateList($apartmentId, $diffDates); if (!$apartmentAvailability) { $result['overbooking'] = true; } } // init strategy to get Partner Id if one was not registered in our system $partner = ['id' => $partnerService::PARTNER_UNKNOWN, 'commission' => $partnerService::PARTNER_UNKNOWN_COMMISSION]; if ($partnerId) { $changedPartnerId = $partnerSpecificService->changePartnerForSomeCases($partnerId, $apartmentId); $partnerId = $changedPartnerId ? $changedPartnerId : $partnerId; $isOurPartnerId = $changedPartnerId ? true : false; $partnerData = $partnerService->getPartnerDataForReservation($partnerId, $apartmentId, $isOurPartnerId); $partner = ['id' => $partnerData->getGid(), 'commission' => $partnerData->getCommission()]; } // check apply fuzzy logic for this partner $applyFuzzyLogic = $partnerDao->checkFuzzyLogic($partner['id']); foreach ($rates as $rate) { $ourPrice = $rate['price']; // if modification check rate exist and active if not use fuzzy logic if ($bookingDomain && ($bookingDomain->getDateFrom() > $rate['date'] || $bookingDomain->getDateTo() <= $rate['date']) && (!$rate['rate_id'] || !$rate['active'])) { $rate = $rateSelector->getSelectorRate($bookingDomain->getId(), $rate['date'], false, $isApartel); } // check availability in Reservation if (!$bookingDomain && !$result['overbooking'] && $rate['availability'] == 0) { $result['overbooking'] = true; } // check rate price mismatch if ($applyFuzzyLogic && isset($fromCubilisRatesData[$rate['date']]['price']) && $ourPrice != $fromCubilisRatesData[$rate['date']]['price']) { // fuzzy logic for base price $priceFuzzyLogic = $partnerSpecificService->getBasePriceByFuzzyLogic($fromCubilisRatesData[$rate['date']]['price'], $partner, $apartmentId, $rate['capacity'], $nightCount); $price = $priceFuzzyLogic ? $priceFuzzyLogic : $ourPrice; } else { $price = $ourPrice; } $cubilisRateId = isset($fromCubilisRatesData[$rate['date']]['channel_rate_id']) ? $fromCubilisRatesData[$rate['date']]['channel_rate_id'] : 0; // check Rate Name if (isset($fromCubilisRatesData[$rate['date']]['rate_name']) && $fromCubilisRatesData[$rate['date']]['rate_name']) { $rateName = $fromCubilisRatesData[$rate['date']]['rate_name']; } else { $rateName = $rate['rate_name']; // send critical email if not send rate name if (!$rateNameNot) { $this->gr2err('Cubilis Not Sending Rate Name', ['cron' => 'ChannelManager', 'apartment_id' => $apartmentId, 'apartel_id' => $apartelId, 'channel_rate_id' => $cubilisRateId, 'channel_res_id' => $channelResId, 'date' => $rate['date']]); $rateNameNot = true; } } $ratesData[$rate['date']] = ['apartment_id' => $apartmentId, 'room_id' => $rate['room_type_id'], 'rate_name' => $rateName, 'price' => $price, 'date' => $rate['date'], 'capacity' => $rate['capacity'], 'rate_id' => $rate['rate_id'], 'availability' => $rate['availability']]; // send critical email if has currency mismatch if (!$currencyNotMatch && (!isset($fromCubilisRatesData[$rate['date']]['currency']) || strtolower($ginosiCurrency) != strtolower($fromCubilisRatesData[$rate['date']]['currency']))) { $this->gr2err('Cubilis apartment currency mismatch with our apartment currency', ['cron' => 'ChannelManager', 'apartment_id' => $apartmentId, 'apartel_id' => $apartelId, 'channel_res_id' => $channelResId]); $currencyNotMatch = true; } } // extra check if rate not matched if (count($rates) != $nightCount) { $result['overbooking'] = true; } // apartel data if ($isApartel) { $result['apartel']['apartment_id'] = $apartmentId; $result['apartel']['apartel_id'] = $apartelId; } $result['ratesData'] = $ratesData; return $result; }
/** * @param int $apartment_id * @param float $sale * @param date $startDate * @param date $endDate * @var ginosiColl ginosiCollectTransactionsSummaryInApartmentCurrency * @var partnerColl partnerCollectTransactionsSummaryInApartmentCurrency * @return Array */ private function _getSaleArray($apartment_id, $sale, $startDate, $endDate, $passYear = false) { $sale['all_bookings'] = $sale['all_cancelations'] = $sale['all_cancelations'] = $sale['highest_sold_price'] = $sale['long_stay'] = $sale['stay_period']['long'] = 0; $sale['stay_period'] = []; $notUsedStatus = [ForBookingStatus::BOOKING_STATUS_CANCELLED_INVALID, ForBookingStatus::BOOKING_STATUS_CANCELLED_EXCEPTION, ForBookingStatus::BOOKING_STATUS_CANCELLED_TEST_BOOKING, ForBookingStatus::BOOKING_STATUS_CANCELLED_MOVED]; /** * @var $bankTransactionService \DDD\Service\Booking\BankTransaction * @var \DDD\Dao\Booking\ReservationNightly $reservationNightlyDao */ $bookingDao = new Booking($this->getServiceLocator(), 'DDD\\Domain\\Apartment\\Statistics\\ForBasicDataBooking'); $userManagerDao = $this->getServiceLocator()->get('dao_user_user_manager'); $reservationNightlyDao = $this->getServiceLocator()->get('dao_booking_reservation_nightly'); $inventoryDao = new Inventory($this->getServiceLocator(), '\\ArrayObject'); $bankTransactionService = $this->getServiceLocator()->get('service_booking_bank_transaction'); $expenseDao = new ExpenseStatistics($this->getServiceLocator()); $bookings = $bookingDao->getBookingsForYear($apartment_id, $startDate, $endDate, $notUsedStatus); $monthlyConst = $expenseDao->getMonthlyCost($apartment_id, $startDate, $endDate); // calculate with nightly data $fistDate = $startDate; $i = 0; while ($i <= 12) { $nextDate = date('Y-m-01', strtotime('+1 month', strtotime($fistDate))); $monthDays = cal_days_in_month(CAL_GREGORIAN, date('m', strtotime($fistDate)), date('Y', strtotime($fistDate))); // reservation day count $monthlyData = $reservationNightlyDao->getBookedMonthlyData($apartment_id, $fistDate, $nextDate); $bookedDayCount = $monthlyData['count']; $monthlySum = $monthlyData['sum']; // closed days $totalClosed = $inventoryDao->getClosedAv($apartment_id, $fistDate, $nextDate); $selectedMonth = date("M_Y", strtotime($fistDate)); $sale['close_out'][$selectedMonth] = $totalClosed - $bookedDayCount; $sale['unsold_days'][$selectedMonth] = $monthDays - $bookedDayCount; $sale['monthly_av_price'][$selectedMonth] = number_format($bookedDayCount ? $monthlySum / $bookedDayCount : 0, 2, '.', ''); // get highest and lowest sold prices if ($passYear) { // get highest price if ($sale['highest_sold_price'] < $monthlyData['max']) { $sale['highest_sold_price'] = $monthlyData['max']; } // get lowest price if (!array_key_exists('lowest_sold_price', $sale) && $monthlyData['min']) { $sale['lowest_sold_price'] = $monthlyData['min']; } elseif (isset($sale['lowest_sold_price']) && $sale['lowest_sold_price'] > $monthlyData['min'] && $monthlyData['min']) { $sale['lowest_sold_price'] = $monthlyData['min']; } } $fistDate = $nextDate; $i++; } // Monthly Booking And Cancelations And Margin foreach ($bookings as $book) { $month = date("M_Y", strtotime($book->getDate_to())); /* @var $ginosiColl $ginosiCollectTransactionsSummaryDomain \DDD\Domain\Booking\TransactionSummary */ $ginosiColl = $bankTransactionService->getTransactionsSummary($book->getId(), BankTransaction::TRANSACTION_MONEY_DIRECTION_GINOSI_COLLECT, [BankTransaction::BANK_TRANSACTION_TYPE_PAY]); $ginosiCollCurrency = $ginosiColl->getSummaryInApartmentCurrency(); /* @var $partnerCollectTransactionsSummaryDomain \DDD\Domain\Booking\TransactionSummary */ $partnerColl = $bankTransactionService->getTransactionsSummary($book->getId(), BankTransaction::TRANSACTION_MONEY_DIRECTION_PARTNER_COLLECT, [BankTransaction::BANK_TRANSACTION_TYPE_PAY]); $partnerCollCurrency = $partnerColl->getSummaryInApartmentCurrency(); $transactionsSummary = $ginosiCollCurrency + $partnerCollCurrency; if (ForBookingStatus::BOOKING_STATUS_BOOKED == $book->getStatus()) { $sale['all_bookings'] += 1; $sale['monthly_bookings'][$month] += 1; $ginosiksRes = $userManagerDao->getGinosiksReservation($book->getGuestEmail()); if ($ginosiksRes) { $sale['free_sold'][$month] += 1; } $date_diff = Helper::getDaysFromTwoDate($book->getDate_to(), $book->getDate_from()); if ($sale['long_stay'] < $date_diff) { $sale['long_stay'] = $date_diff; } } elseif (ForBookingStatus::BOOKING_STATUS_CANCELLED_BY_CUSTOMER == $book->getStatus()) { $sale['all_cancelations'] += 1; $month = date("M_Y", strtotime($book->getDate_to())); $sale['monthly_cancalations'][$month] += 1; } $sale = $this->_setMonthlyCost($book, $month, $sale, $transactionsSummary); } //Calculate final monthly cost foreach ($monthlyConst as $month => $cost) { if (isset($sale['monthly_cost'][$month])) { $sale['monthly_cost'][$month] += $cost; $sale['monthly_cost_total'] += $cost; $sale['profit'][$month] = $sale['monthly_revenue'][$month] - $sale['monthly_cost'][$month]; } } // Cancellation score $total_reservations = ($sale['all_cancelations'] + $sale['all_bookings']) * 100; if (0 != $total_reservations) { $sale['cancelation_score'] = $sale['all_cancelations'] / ($sale['all_cancelations'] + $sale['all_bookings']) * 100; $sale['cancelation_score'] = number_format($sale['cancelation_score'], 1); } else { $sale['cancelation_score'] = 0; } // Monthly Occupancy $bookingReservationData = $bookingDao->getReservationForAccOnDate($apartment_id, $startDate, $endDate); $reservationDates = []; foreach ($bookingReservationData as $reservation) { $reservationDates = array_merge($reservationDates, Helper::getDateListInRange($reservation->getDate_from(), date('Y-m-d', strtotime('-1 day', strtotime($reservation->getDate_to()))))); } //Get Extremes $inventoryDao = new Inventory($this->getServiceLocator(), 'DDD\\Domain\\Apartment\\Statistics\\ForBasicDataInventory'); $extremums = $inventoryDao->getExtremums($apartment_id, $startDate, $endDate); $sale['max_avilability'] = $extremums->getMax_availability(); $sale['max_price'] = $extremums->getMax_price(); $sale['min_price'] = $extremums->getMin_price(); //Get Review $apartmentReview = $this->getServiceLocator()->get('service_apartment_review'); $apartmentGeneralDao = $this->getServiceLocator()->get('dao_apartment_general'); $reviewScore = $apartmentGeneralDao->getReviewScore($apartment_id)['score']; $sale['review'] = $reviewScore; return $sale; //Set All Times Statistics }