widgetName = JText::translate('VBO_W_FINANCE_TITLE'); $this->widgetDescr = JText::translate('VBO_W_FINANCE_DESCR'); $this->widgetId = basename(__FILE__, '.php'); // define widget and icon and style name $this->widgetIcon = ''; $this->widgetStyleName = 'red'; } /** * Preload the necessary CSS/JS assets. * * @return void */ public function preload() { // load assets for datepicker $this->vbo_app->loadDatePicker(); // load assets for contextual menu $this->vbo_app->loadContextMenuAssets(); // check for daily welcome message with stats $this->setupWelcomeStats(); // lang vars for JS JText::script('VBO_COMPARE_WITH_LAST_Y'); JText::script('VBO_COMPARE_WITH_PREV_Q'); JText::script('VBO_COMPARE_WITH_PREV_M'); JText::script('VBO_COMPARE_WITH_PREV_W'); JText::script('VBO_COMPARE_WITH_PREV_D'); JText::script('VBNOTRACKINGS'); JText::script('VBO_ERR_LOAD_RESULTS'); JText::script('VBNOROOMSFOUND'); JText::script('VBO_SEARCHING'); JText::script('VBROOMFILTER'); } /** * Custom method for this widget only to load the financial statistics. * The method is called by the admin controller through an AJAX request. * The visibility should be public, it should not exit the process, and * any content sent to output will be returned to the AJAX response. * In this case we return an array because this method requires "return":1. * * It's the actual rendering of the widget which also allows navigation. */ public function loadFinancialStats() { $app = JFactory::getApplication(); $wrapper = $app->input->getString('wrapper', ''); $fromdate = $app->input->getString('fromdate', ''); $todate = $app->input->getString('todate', ''); $step = $app->input->getString('step', 'quarter'); $date_dir = $app->input->getInt('date_dir', 0); $room_ids = array_filter((array) $app->input->getInt('room_ids', [])); if (empty($fromdate)) { // default to current quarter (3 full months) $now_info = getdate(); $end_info = getdate(mktime(0, 0, 0, ($now_info['mon'] + 2), 1, $now_info['year'])); $to_ts = mktime(23, 59, 59, $end_info['mon'], date('t', $end_info[0]), $end_info['year']); $fromdate = date('Y-m-d', mktime(0, 0, 0, $now_info['mon'], 1, $now_info['year'])); $todate = date('Y-m-d', $to_ts); } // convert dates to timestamps to support custom date formats $from_ts = VikBooking::getDateTimestamp($fromdate); $to_ts = VikBooking::getDateTimestamp($todate, 23, 59, 59); // check dates navigation and step $step_name = ''; if ($date_dir > 0 || $date_dir < 0) { // calculate forward or backward dates for navigation list($from_ts, $to_ts, $step_name) = $this->calcDatesNavigation($from_ts, $to_ts, $step, $date_dir); } // convert final dates to Y-m-d $fromdate = date('Y-m-d', $from_ts); $todate = date('Y-m-d', $to_ts); // stats calculation type $calc_type = !strcasecmp($step, 'booking_dates') ? 'booking_dates' : 'stay_dates'; // access the finance helper object $finance = VBOTaxonomyFinance::getInstance(); // currency symbol $currencysymb = VikBooking::getCurrencySymb(); // get the financial stats for the requested dates try { $stats = $finance->getStats($fromdate, $todate, $room_ids, $calc_type); } catch (Exception $e) { // make the AJAX request fail nicely VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage()); } // language string identifier for step-comparison $js_step_comp_str = 'VBO_COMPARE_WITH_PREV_Q'; if ($step == 'month') { $js_step_comp_str = 'VBO_COMPARE_WITH_PREV_M'; } elseif ($step == 'week') { $js_step_comp_str = 'VBO_COMPARE_WITH_PREV_W'; } elseif (!strcasecmp($step, 'booking_dates')) { $js_step_comp_str = 'VBO_COMPARE_WITH_PREV_D'; } // start output buffering ob_start(); if ($room_ids) { // get the details of the rooms filtered $rooms_filtered = VikBooking::getAvailabilityInstance()->loadRooms($room_ids); if ($rooms_filtered) { ?>
numberFormatShort($stats['gross_revenue']); ?>
numberFormatShort($stats['taxes']); ?>
numberFormatShort($stats['cmms']); ?>
numberFormatShort($stats['revenue']); ?>
numberFormatShort($stats['ibe_revenue']); ?>
numberFormatShort($stats['ota_revenue']); ?>
0) { ?>
%
numberFormatShort($stats['cmm_savings']); ?>
numberFormatShort($stats['cancellations_amt']); ?>
numberFormatShort($country_rank['revenue']); ?>
%
numberFormatShort($pos_revenue['revenue']); ?>
%
parseReadableDateInterval($from_ts, $to_ts, $this->df, $step); // return an associative array of values return [ 'html' => $html_content, 'fromdate' => $fromdate, 'f_fromdate' => $format_from_date, 'todate' => $todate, 'f_todate' => $format_to_date, 'step' => $step, 'step_name' => $step_name, 'stats' => $stats, ]; } /** * Custom method for this widget only to load the comparison values. * The method is called by the admin controller through an AJAX request. * The visibility should be public, it should not exit the process, and * any content sent to output will be returned to the AJAX response. * In this case we return an array because this method requires "return":1. * * Returns the necessary HTML to display comparison values with past dates. */ public function loadComparisonStats() { $app = JFactory::getApplication(); $wrapper = $app->input->getString('wrapper', ''); $fromdate = $app->input->getString('fromdate', ''); $todate = $app->input->getString('todate', ''); $step = $app->input->getString('step', 'quarter'); $prev_stats = $app->input->get('stats', [], 'array'); $date_dir = -1; if (empty($fromdate) || empty($todate) || empty($prev_stats)) { // make the AJAX request fail nicely VBOHttpDocument::getInstance()->close(500, 'Missing data to calculate comparison values'); } // convert dates to timestamps to support custom date formats $from_ts = VikBooking::getDateTimestamp($fromdate); $to_ts = VikBooking::getDateTimestamp($todate, 23, 59, 59); // stats calculation type $calc_type = 'stay_dates'; if (!strcasecmp($step, 'booking_dates')) { $calc_type = 'booking_dates'; } // calculate backward dates for comparison list($from_ts, $to_ts, $step_name) = $this->calcDatesNavigation($from_ts, $to_ts, $step, $date_dir); // convert final dates to Y-m-d $fromdate = date('Y-m-d', $from_ts); $todate = date('Y-m-d', $to_ts); // access the finance helper object $finance = VBOTaxonomyFinance::getInstance(); // currency symbol $currencysymb = VikBooking::getCurrencySymb(); // get the financial stats for the requested dates and use them for comparison try { $compare_stats = $finance->getStats($fromdate, $todate, [], $calc_type); } catch (Exception $e) { // make the AJAX request fail nicely VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage()); } // define the "compare vs" string switch ($step) { case 'year': $compare_vs_str = JText::translate('VBO_VS_LAST_Y'); break; case 'quarter': $compare_vs_str = JText::translate('VBO_VS_PREV_Q'); break; case 'month': $compare_vs_str = JText::translate('VBO_VS_PREV_M'); break; case 'week': $compare_vs_str = JText::translate('VBO_VS_PREV_W'); break; case 'booking_dates': $compare_vs_str = JText::translate('VBO_VS_PREV_D'); break; default: $compare_vs_str = ''; break; } // build comparison values $comparison = []; // stats that require percent values for comparison $pcent_stats = [ 'gross_revenue' => [], 'taxes' => [], 'cmms' => [ 'reverse' => 1, ], 'revenue' => [], 'ibe_revenue' => [], 'ota_revenue' => [], 'ota_avg_cmms' => [ 'reverse' => 1, 'no_pcent' => 1, 'fixednum' => 1, ], 'cmm_savings' => [], 'tot_bookings' => [ 'fixednum' => 1, ], 'nights_booked' => [ 'fixednum' => 1, ], 'avg_los' => [ 'fixednum' => 1, ], 'abw' => [ 'fixednum' => 1, ], 'rooms_booked' => [ 'fixednum' => 1, ], 'cancellations_amt' => [ 'reverse' => 1, ], ]; foreach ($pcent_stats as $stat_name => $stat_opt) { if (!isset($compare_stats[$stat_name])) { continue; } // make sure the previous value is set $prev_stats[$stat_name] = !isset($prev_stats[$stat_name]) ? 0 : $prev_stats[$stat_name]; // difference $diff = isset($stat_opt['reverse']) ? ($compare_stats[$stat_name] - $prev_stats[$stat_name]) : ($prev_stats[$stat_name] - $compare_stats[$stat_name]); // calculate values $comparison[$stat_name] = [ 'amount' => $compare_stats[$stat_name], 'amount_f' => VikBooking::numberFormat($compare_stats[$stat_name]), 'amount_s' => $finance->numberFormatShort($compare_stats[$stat_name]), 'diff' => $diff, 'diff_f' => VikBooking::numberFormat($diff), 'diff_s' => $finance->numberFormatShort($diff), 'pcent' => isset($stat_opt['no_pcent']) ? null : $finance->calcAbsPercent($prev_stats[$stat_name], $compare_stats[$stat_name]), 'reverse' => $stat_opt['reverse'] ?? false, ]; // inject property for fixed number with no currency if (isset($stat_opt['fixednum']) && $stat_opt['fixednum']) { $comparison[$stat_name]['fixednum'] = $stat_opt['fixednum']; } } // return an associative array of values return [ 'no_data' => ($compare_stats['tot_bookings'] < 1 ? 1 : 0), 'compare' => $comparison, 'vs_str' => $compare_vs_str, 'currency' => $currencysymb, 'stats' => $compare_stats, ]; } /** * Custom method for this widget only to retrieve the daily * welcome statistics about the bookings of the day before. * * @return array the associative list of statistics. */ public function getWelcomeStats() { // get yesterday's date $yesterday = date('Y-m-d', strtotime('yesterday')); // access the finance helper object $finance = VBOTaxonomyFinance::getInstance(); // get the financial stats for the requested dates try { $stats = $finance->getStats($yesterday, $yesterday, $rooms = [], $type = 'booking_dates'); } catch (Exception $e) { // make the AJAX request fail nicely VBOHttpDocument::getInstance()->close($e->getCode(), $e->getMessage()); } return $stats; } /** * Main method to invoke the widget. Contents will be loaded * through AJAX requests, not via PHP when the page loads. * * @param VBOMultitaskData $data * * @return void */ public function render(VBOMultitaskData $data = null) { // increase widget's instance counter static::$instance_counter++; // check whether the widget is being rendered via AJAX when adding it through the customizer $is_ajax = $this->isAjaxRendering(); // generate a unique ID for the sticky notes wrapper instance $wrapper_instance = !$is_ajax ? static::$instance_counter : rand(); $wrapper_id = 'vbo-widget-finance-' . $wrapper_instance; // check permissions $vbo_auth_pricing = JFactory::getUser()->authorise('core.vbo.pricing', 'com_vikbooking'); $vbo_auth_bookings = JFactory::getUser()->authorise('core.vbo.bookings', 'com_vikbooking'); if (!$vbo_auth_pricing || !$vbo_auth_bookings) { // base permissions are not met return; } // we make use of the rates flow and occupancy ranking report helper classes $report = VikBooking::getReportInstance('rates_flow'); if (!$report) { // display nothing return; } // get minimum and maximum nights updated for dates filters list($mindate, $maxdate) = $this->getMinDatesFinance(); $mindate = empty($mindate) ? time() : $mindate; $maxdate = empty($maxdate) ? $mindate : $maxdate; // dates navigation preference $cookie = JFactory::getApplication()->input->cookie; $cookie_step = $cookie->get('vbo_widget_finance_step', 'quarter', 'string'); // determine default period name and dates $df = $report->getDateFormat(); $dtpicker_df = $report->getDateFormat('jui'); $now_info = getdate(); if ($cookie_step == 'week') { // next week $from_ts = mktime(0, 0, 0, $now_info['mon'], $now_info['mday'], $now_info['year']); $to_ts = mktime(0, 0, 0, $now_info['mon'], ($now_info['mday'] + 7), $now_info['year']); $fromdate = date($df, $from_ts); $todate = date($df, $to_ts); $period_name = JText::translate('VBOWEEK'); } elseif ($cookie_step == 'month') { // current full month $from_ts = mktime(0, 0, 0, $now_info['mon'], 1, $now_info['year']); $fromdate = date($df, $from_ts); $to_ts = mktime(23, 59, 59, $now_info['mon'], date('t', $now_info[0]), $now_info['year']); $todate = date($df, $to_ts); $period_name = JText::translate('VBPVIEWRESTRICTIONSTWO'); } else { // default to next 3 (total) months from today's month $from_ts = mktime(0, 0, 0, $now_info['mon'], 1, $now_info['year']); $fromdate = date($df, $from_ts); $end_info = getdate(mktime(0, 0, 0, ($now_info['mon'] + 2), 1, $now_info['year'])); $to_ts = mktime(23, 59, 59, $end_info['mon'], date('t', $end_info[0]), $end_info['year']); $todate = date($df, $to_ts); $period_name = JText::translate('VBO_QUARTER'); } // check multitask data $rooms_filtered = []; if ($data) { $inj_fromdate = $data->get('fromdate', $this->options()->get('fromdate', '')); $inj_todate = $data->get('todate', $this->options()->get('todate', '')); $inj_type = $data->get('type', $this->options()->get('type', '')); // check if some room IDs were filtered $rooms_filtered = (array) $data->get('room_ids', $this->options()->get('room_ids', [])); if (preg_match("/^\d{4}-\d{2}-\d{2}$/", $inj_fromdate) && preg_match("/^\d{4}-\d{2}-\d{2}$/", $inj_todate)) { // valid dates injected in Y-m-d format $fromdate = $inj_fromdate; $todate = $inj_todate; $to_info = getdate(strtotime($todate)); $from_ts = strtotime($fromdate); $to_ts = mktime(23, 59, 59, $to_info['mon'], $to_info['mday'], $to_info['year']); if (!empty($inj_type)) { $cookie_step = $inj_type; if (!strcasecmp($inj_type, 'booking_dates')) { $period_name = JText::translate('VBOSTATSMODETS'); } } } } // take care of the readable dates interval list($format_from_date, $format_to_date) = $this->parseReadableDateInterval($from_ts, $to_ts, $df, $cookie_step); $interval_name = $format_from_date . ' - ' . $format_to_date; if ($format_from_date == $format_to_date) { $interval_name = $format_from_date; } ?>

widgetIcon; ?> widgetName; ?>

setQuery($q); $data = $dbo->loadAssoc(); if ($data) { if (!empty($data['mindate']) && !empty($data['maxdate'])) { $mindate = $data['mindate']; $maxdate = $data['maxdate']; } } return [$mindate, $maxdate]; } /** * Calculates the new dates interval for navigation according to step. * Internal method for this widget only. * * @param int $from_ts current from date timestamp. * @param int $to_ts current end date timestamp. * @param string $step the navigation step to take (week, month, quarter or booking_dates). * @param int $date_dir less than 0 backward nav, more than 0 forward. * * @return array the new from and end date timestamps, plus the step name. */ protected function calcDatesNavigation($from_ts, $to_ts, $step, $date_dir) { if (empty($from_ts) || (!($date_dir > 0) && !($date_dir < 0))) { return [$from_ts, $to_ts, '']; } // start/end date information $from_info = getdate($from_ts); $to_info = getdate($to_ts); // next or prev day (booking_dates) if (!strcasecmp($step, 'booking_dates')) { if ($date_dir > 0) { // forward dates navigation $from_ts = mktime(0, 0, 0, $to_info['mon'], ($to_info['mday'] + 1), $to_info['year']); $to_ts = mktime(23, 59, 59, $to_info['mon'], ($to_info['mday'] + 1), $to_info['year']); } elseif ($date_dir < 0) { // backward dates navigation $from_ts = mktime(0, 0, 0, $from_info['mon'], ($from_info['mday'] - 1), $from_info['year']); $to_ts = mktime(23, 59, 59, $from_info['mon'], ($from_info['mday'] - 1), $from_info['year']); } return [$from_ts, $to_ts, JText::translate('VBPCHOOSEBUSYORDATE')]; } // next or prev week if ($step == 'week') { if ($date_dir > 0) { // forward dates navigation $from_ts = $to_ts; $to_ts = strtotime("+1 week", $to_ts); } elseif ($date_dir < 0) { // backward dates navigation $to_ts = $from_ts; $from_ts = strtotime("-1 week", $from_ts); } return [$from_ts, $to_ts, JText::translate('VBOWEEK')]; } // next or prev month if ($step == 'month') { if ($date_dir > 0) { // forward dates navigation $from_ts = mktime(0, 0, 0, ($from_info['mon'] + 1), 1, $from_info['year']); $to_ts = mktime(0, 0, 0, ($from_info['mon'] + 1), date('t', $from_ts), $from_info['year']); } elseif ($date_dir < 0) { // backward dates navigation $from_ts = mktime(0, 0, 0, ($from_info['mon'] - 1), 1, $from_info['year']); $to_ts = mktime(0, 0, 0, ($from_info['mon'] - 1), date('t', $from_ts), $from_info['year']); } return [$from_ts, $to_ts, JText::translate('VBPVIEWRESTRICTIONSTWO')]; } // next or prev year (keep the same exact dates) if ($step == 'year') { if ($date_dir > 0) { // forward dates navigation $from_ts = mktime(0, 0, 0, $from_info['mon'], $from_info['mday'], ($from_info['year'] + 1)); $to_ts = mktime(0, 0, 0, $to_info['mon'], $to_info['mday'], ($to_info['year'] + 1)); } elseif ($date_dir < 0) { // backward dates navigation $from_ts = mktime(0, 0, 0, $from_info['mon'], $from_info['mday'], ($from_info['year'] - 1)); $to_ts = mktime(0, 0, 0, $to_info['mon'], $to_info['mday'], ($to_info['year'] - 1)); } return [$from_ts, $to_ts, JText::translate('VBCONFIGSEARCHPMAXDATEYEARS')]; } // next or prev quarter by default if ($date_dir > 0) { // forward dates navigation $from_ts = mktime(0, 0, 0, ($from_info['mon'] + 3), 1, $from_info['year']); $end_ts = mktime(0, 0, 0, ($from_info['mon'] + 5), 1, $from_info['year']); $to_ts = mktime(0, 0, 0, ($from_info['mon'] + 5), date('t', $end_ts), $from_info['year']); } elseif ($date_dir < 0) { // backward dates navigation $from_ts = mktime(0, 0, 0, ($from_info['mon'] - 3), 1, $from_info['year']); $end_ts = mktime(0, 0, 0, ($from_info['mon'] - 1), 1, $from_info['year']); $to_ts = mktime(0, 0, 0, ($from_info['mon'] - 1), date('t', $end_ts), $from_info['year']); } return [$from_ts, $to_ts, JText::translate('VBO_QUARTER')]; } /** * Parse an interval of date timestamps into a readable interval of dates according to step. * Internal method for this widget only. * * @param int $from_ts current from date timestamp. * @param int $to_ts current end date timestamp. * @param string $vbo_df the date format in VBO. * @param string $step the navigation step to take (week, month or quarter). * * @return array the formatted from and to date interval strings. */ protected function parseReadableDateInterval($from_ts, $to_ts, $vbo_df, $step) { $from_info = getdate($from_ts); $to_info = getdate($to_ts); $format_from_date = date($vbo_df, $from_ts); $format_to_date = date($vbo_df, $to_ts); if ($step == 'week') { // include day of week $format_from_date = VikBooking::sayWeekDay($from_info['wday']) . ', ' . $format_from_date; $format_to_date = VikBooking::sayWeekDay($to_info['wday']) . ', ' . $format_to_date; } elseif ($step == 'month') { // check if it's a full month to say its name if ($from_info['mon'] == $to_info['mon'] && $from_info['year'] == $to_info['year']) { if ($from_info['mday'] == 1 && $to_info['mday'] == date('t', $to_ts)) { $format_from_date = VikBooking::sayMonth($from_info['mon']) . ' ' . $from_info['year']; $format_to_date = VikBooking::sayMonth($to_info['mon']) . ' ' . $to_info['year']; } } } elseif ($step == 'quarter') { // check if it's a full quarter if ($from_info['mday'] == 1 && $to_info['mday'] == date('t', $to_ts)) { $format_from_date = VikBooking::sayMonth($from_info['mon']) . ' ' . $from_info['year']; $format_to_date = VikBooking::sayMonth($to_info['mon']) . ' ' . $to_info['year']; } } return [$format_from_date, $format_to_date]; } /** * Sets up the necessary script to load the welcome message for the user. * On WordPress this method may run outside Vik Booking, and so Javascript, * may not be able to access language definitions from the DOM. * * @return bool true if welcome was set up for the user, or false. */ protected function setupWelcomeStats() { // avoid welcome stats on certain pages if (VBOPlatformDetection::isWordPress()) { global $pagenow; $skip_pages = ['update.php', 'plugins.php', 'plugin-install.php']; if (isset($pagenow) && in_array($pagenow, $skip_pages)) { return false; } } $admin_user = JFactory::getUser(); $admin_user_name = $admin_user->name; if (!$admin_user_name || !$admin_user->authorise('core.vbo.bookings', 'com_vikbooking')) { // user not authorized return false; } // get yesterday's date $yesterday_info = getdate(strtotime('yesterday')); $yesterday_read = implode(' ', [VikBooking::sayWeekDay($yesterday_info['wday'], true), $yesterday_info['mday'], VikBooking::sayMonth($yesterday_info['mon'], true)]); $yesterday_read = htmlspecialchars($yesterday_read); $yesterday = date('Y-m-d', $yesterday_info[0]); // the payload for getting the welcome stats for yesterday $payload = [ 'fromdate' => $yesterday, 'todate' => $yesterday, 'type' => 'booking_dates', ]; // check if we are inside Vik Booking $in_vbo = (int)(JFactory::getApplication()->input->get('option', '') === 'com_vikbooking'); $vbo_uri = VBOPlatformDetection::isWordPress() ? 'admin.php?page=vikbooking' : 'index.php?option=com_vikbooking'; if (!$in_vbo && VBOPlatformDetection::isWordPress()) { // append query string value to render the admin widget $q_cmds = [ 'load_widget' => $this->widgetId, 'multitask_data' => $payload, ]; $vbo_uri .= '&' . http_build_query($q_cmds); } // build data (the JS code may not be able to access script language definitions if running outside Vik Booking) $aj_endpoint = $this->getExecWidgetAjaxUri(); $widget_id = $this->getIdentifier(); $website_logo = $this->getIconUrl(); $website_logo = $website_logo ? $website_logo : ''; $greetings = VikBooking::strTrimLiteral(htmlspecialchars(JText::sprintf('VBO_WELCOME_ADMIN_USER', $admin_user_name))); $greetings_ms = VikBooking::strTrimLiteral(htmlspecialchars(JText::translate('VBO_BOOKINGS_YESTERDAY'))); $modal_title = VikBooking::strTrimLiteral(htmlspecialchars(JText::translate('VBOYESTERDAY') . ', ' . $yesterday_read)); $payload_json = json_encode($payload); $sugg_notifs_btn = ''; JFactory::getDocument()->addScriptDeclaration( << { try { var obj_res = typeof response === 'string' ? JSON.parse(response) : response; if (!obj_res.hasOwnProperty(call_method)) { throw new Error('Unexpected JSON response'); } VBOCore.storageSetItem('vbo_finance_last_dt', '$yesterday'); if (!obj_res[call_method].hasOwnProperty('tot_bookings') || !obj_res[call_method]['tot_bookings']) { return; } let vbo_notif_click_handler = 'VBOCore.handleGoto'; if ($in_vbo) { vbo_notif_click_handler = () => { try { let yesterday_modal = VBOCore.displayModal({ suffix: 'finance-welcome', extra_class: 'vbo-modal-rounded vbo-modal-tall vbo-modal-nofooter', title: '$modal_title' + (VBOCore.notificationsEnabled() === false ? '$sugg_notifs_btn' : '') + '', dismiss_event: 'vbo-dismiss-modal-finance-welcome', loading_event: 'vbo-loading-modal-finance-welcome', }); VBOCore.suggestNotifications('.vbo-suggest-notifications-btn'); VBOCore.emitEvent('vbo-loading-modal-finance-welcome'); VBOCore.renderAdminWidget('$this->widgetId', $payload_json).then((content) => { VBOCore.emitEvent('vbo-loading-modal-finance-welcome'); yesterday_modal.append(content); }).catch((error) => { VBOCore.emitEvent('vbo-dismiss-modal-finance-welcome'); alert(error); }); } catch(e) { document.location.href = '$vbo_uri'; } }; } setTimeout(() => { VBOCore.dispatchNotification({ title: '$greetings', message: ('$greetings_ms').replace('%d', obj_res[call_method]['tot_bookings']), icon: '$website_logo', onclick: vbo_notif_click_handler, gotourl: '$vbo_uri', }); }, 500); } catch(e) { console.error(e); } }, (error) => { console.error(error.responseText); } ); }); })(jQuery); JS ); return true; } /** * Returns the URL to the default site logo. * * @return string|null */ protected function getIconUrl() { $config = VBOFactory::getConfig(); // back-end custom logo $use_logo = $config->get('backlogo'); if (empty($use_logo) || !strcasecmp($use_logo, 'vikbooking.png')) { // fallback to company (site) logo $use_logo = $config->get('sitelogo'); } if (!empty($use_logo) && strcasecmp($use_logo, 'vikbooking.png')) { // uploaded logo found $use_logo = VBO_ADMIN_URI . 'resources/' . $use_logo; } else { $use_logo = null; } return $use_logo; } }