hero($label); ?> kpi_cards($abprf_info, $kpi); ?>
today_deliveries(); ?> today_collections(); ?> orders_summary(); ?>
display_name) ? $user->display_name : __('Admin', 'abp-rentalforge'); ?>

prefix . 'abprf_orders'; $groups = array(); $statuses = array_filter(array_map('sanitize_text_field', explode(',', (string)ABPRF_Function::booking_status()))); if (!empty($statuses) && current($statuses) !== 'all') { $placeholders = implode(',', array_fill(0, count($statuses), '%s')); $sql = "SELECT id, item_id, order_id, post_id, start_time, end_time, order_status, book_status, billing_name, property_info, price_info FROM %i WHERE order_status IN ($placeholders) AND book_status <> 5 AND ( DATE(start_time) = %s OR book_status IN (0,1) ) ORDER BY start_time ASC"; $params = array_merge(array($table), $statuses, array($today)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared $result = $wpdb->get_results($wpdb->prepare($sql, $params), ARRAY_A); $result = is_array($result) ? $result : array(); foreach ($result as $booking) { $pid = (int)($booking['post_id'] ?? 0); if ($pid > 0) { $groups[$pid][] = $booking; } } } $rows = array(); foreach (array_keys($groups) as $pid) { $rows[] = self::booking_meta($pid, $today); } ?>

delivery_post_rows($rows, $today, $groups); ?>

• •
•
0 && function_exists('wc_price') ? wp_strip_all_tags(wc_price($rent)) : ($rent > 0 ? number_format_i18n($rent, 2) : __('FREE', 'abp-rentalforge')))); ?> 0 && function_exists('wc_price') ? wp_strip_all_tags(wc_price($deposit)) : ($deposit > 0 ? number_format_i18n($deposit, 2) : __('FREE', 'abp-rentalforge')))); ?>
delivery_order_row($delivery_booking); } ?>
#
• —
0) { ?> 0 && $book_status < 2) { ?>
prefix . 'abprf_orders'; $statuses = array_filter(array_map('sanitize_text_field', explode(',', (string)ABPRF_Function::booking_status()))); if (!empty($statuses) && current($statuses) !== 'all') { $placeholders = implode(',', array_fill(0, count($statuses), '%s')); $sql = "SELECT id, item_id, order_id, post_id, start_time, end_time, order_status, book_status, billing_name, property_info, price_info FROM %i WHERE order_status IN ($placeholders) AND ( ( DATE(end_time) <= %s AND book_status NOT IN (3,5) ) OR book_status = 2 ) ORDER BY end_time ASC"; $params = array_merge(array($table), $statuses, array($today)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared $due = $wpdb->get_results($wpdb->prepare($sql, $params), ARRAY_A); $due = is_array($due) ? $due : array(); } ?>

collection_order_rows($due); ?>

$booking) { $property_infos = json_decode($booking['property_info'] ?? '', true) ?: array(); if (is_array($property_infos)) { foreach ($property_infos as $property_info) { $items += (int)($property_info['qty'] ?? 0); } } $is_overdue = ($booking['end_time'] ?? '') !== '' && strtotime($booking['end_time']) < strtotime($now); $bookings[$key]['_is_overdue'] = $is_overdue; if ($is_overdue) { $overdue_count++; } } $count = count($bookings); /* translators: %d: number of orders. */ $meta_orders = sprintf(_n('%d order', '%d orders', $count, 'abp-rentalforge'), $count); /* translators: %d: number of items. */ $meta_items = sprintf(_n('%d item', '%d items', $items, 'abp-rentalforge'), $items); /* translators: %d: number of overdue orders. */ $meta_overdue = $overdue_count > 0 ? sprintf(_n('%d overdue', '%d overdue', $overdue_count, 'abp-rentalforge'), $overdue_count) : ''; ?>
• •
#
• —
0) { ?> 0) { ?> 0 && $book_status < 3) { ?>
'on_off']), 'warning'), array('fas fa-calendar-days', __('Global Dates', 'abp-rentalforge'), __('Manage global dates', 'abp-rentalforge'), ABPRF_Function::build_url('configuration', ['configuration' => 'dates']), 'theme'), ); if (ABPRF_Function::on_off('additional_info')) { $actions[] = array('fas fa-list-check', __('Additional Services', 'abp-rentalforge'), __('Manage additional services', 'abp-rentalforge'), ABPRF_Function::build_url('configuration', ['configuration' => 'additional']), 'success'); } if (ABPRF_Function::on_off('client_info')) { $actions[] = array('fas fa-user', __('Client Form', 'abp-rentalforge'), __('Manage client form fields', 'abp-rentalforge'), ABPRF_Function::build_url('configuration', ['configuration' => 'client_form']), 'purple'); } if (ABPRF_Function::on_off('location')) { $actions[] = array('fas fa-map-marker-alt', __('Locations', 'abp-rentalforge'), __('Manage rental locations', 'abp-rentalforge'), ABPRF_Function::build_url('configuration', ['configuration' => 'location']), 'navy'); } if (ABPRF_Function::on_off('category')) { $actions[] = array('fas fa-folder', __('Categories', 'abp-rentalforge'), __('Manage rental categories', 'abp-rentalforge'), ABPRF_Function::build_url('configuration', ['configuration' => 'category']), 'theme'); } if (ABPRF_Function::on_off('brand')) { $actions[] = array('fas fa-tag', __('Brands', 'abp-rentalforge'), __('Manage rental brands', 'abp-rentalforge'), ABPRF_Function::build_url('configuration', ['configuration' => 'brand']), 'purple'); } if (defined('ABPRF_DIR_PRO')) { if (ABPRF_Function::on_off('partial_payment')) { $actions[] = array('fas fa-hand-holding-dollar', __('Deposit Settings', 'abp-rentalforge'), __('Configure deposit system', 'abp-rentalforge'), ABPRF_Function::build_url('configuration', ['configuration' => 'discount']), 'success'); } } ?>

current_time('Y-m-d'))); ?>

order_table($last); ?>
today_orders_pane($today); ?>
order_table($items, $step); ?> $step) { ?>

$booking) { $order_id = (int)($booking['order_id'] ?? 0); $post_id = (int)($booking['post_id'] ?? 0); $start_time = $booking['start_time'] ?? ''; $end_time = $booking['end_time'] ?? ''; $status = $booking['order_status'] ?? ''; $book_status = (int)($booking['book_status'] ?? 0); $name = $booking['billing_name'] ?? ''; $property_infos = json_decode($booking['property_info'] ?? '', true) ?: array(); $property_text = array(); $qty = 0; if (is_array($property_infos)) { foreach ($property_infos as $property_info) { $p_qty = (int)($property_info['qty'] ?? 1); $p_name = $property_info['name'] ?? ''; $qty += $p_qty; if ($p_name !== '') { $property_text[] = $p_name . ' x ' . $p_qty; } } } $price_info = json_decode($booking['price_info'] ?? '', true) ?: array(); $row_total = (float)($price_info['item_total'] ?? 0); $total += $row_total; $row_class = ($limit > 0 && $index >= $limit) ? 'dash_row_hidden' : ''; ?>
#
•
0) { ?> 0 && $book_status < 2) { ?> 0 && $book_status === 2) { ?>
__('Invalid security token or Insufficient permissions.', 'abp-rentalforge'), 'type' => 'warn'], 403); } $post_id = isset($_POST['post_id']) ? (int)$_POST['post_id'] : 0; $start_time = isset($_POST['start_time']) ? sanitize_text_field(wp_unslash($_POST['start_time'])) : ''; if ($post_id <= 0 || empty($start_time)) { wp_send_json_error(['msg' => __('Invalid booking.', 'abp-rentalforge'), 'type' => 'warn'], 400); } $meta = self::booking_meta($post_id, $start_time); ob_start(); ?>

—
0) { ?>
()
today_bookings($post_id, $start_time); ?>
$html, 'msg' => esc_html__('Booking details loaded.', 'abp-rentalforge'), 'type' => 'success']); } //=============================// public function update_book_status(): void { if (!check_ajax_referer('abprf_admin_ajax_nonce', 'nonce', false) || !current_user_can('manage_options')) { wp_send_json_error(['msg' => __('Invalid security token or Insufficient permissions.', 'abp-rentalforge'), 'type' => 'warn'], 403); } $item_id = isset($_POST['item_id']) ? (int)$_POST['item_id'] : 0; $book_status = isset($_POST['book_status']) ? (int)$_POST['book_status'] : 0; if ($item_id <= 0 || !in_array($book_status, array(2, 3), true)) { wp_send_json_error(['msg' => __('Invalid request.', 'abp-rentalforge'), 'type' => 'warn'], 400); } global $wpdb; $table = $wpdb->prefix . 'abprf_orders'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $row = $wpdb->get_row($wpdb->prepare("SELECT book_status, price_info, others FROM %i WHERE item_id = %d", $table, $item_id), ARRAY_A); if (null === $row) { wp_send_json_error(['msg' => __('Booking not found.', 'abp-rentalforge'), 'type' => 'warn'], 404); } if ((int)($row['book_status'] ?? 0) === 5) { wp_send_json_error(['msg' => __('This booking is canceled.', 'abp-rentalforge'), 'type' => 'warn'], 400); } $now = current_time('Y-m-d H:i:s'); $update_data = array('book_status' => $book_status, 'updated_at' => $now); $update_formats = array('%d', '%s'); $others = json_decode($row['others'] ?? '', true); $others = is_array($others) ? $others : array(); if (2 === $book_status) { $others['delivery_time'] = $now; $update_data['others'] = wp_json_encode($others); $update_formats[] = '%s'; } elseif (3 === $book_status) { $others['received_time'] = $now; $update_data['others'] = wp_json_encode($others); $update_formats[] = '%s'; $price_info = json_decode($row['price_info'] ?? '', true); if (is_array($price_info) && !empty($price_info['deposit'])) { $deposit = (float)$price_info['deposit']; $price_info['deposit'] = 0; if (isset($price_info['item_total'])) { $price_info['item_total'] = (float)$price_info['item_total'] - $deposit; } $update_data['price_info'] = wp_json_encode($price_info); $update_formats[] = '%s'; } } // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $updated = $wpdb->update($table, $update_data, array('item_id' => $item_id), $update_formats, array('%d')); if (false === $updated) { wp_send_json_error(['msg' => __('Could not update status.', 'abp-rentalforge'), 'type' => 'warn']); } $text = ABPRF_Layout::book_status_text($book_status); /* translators: %s: new rent status label. */ wp_send_json_success(['msg' => sprintf(__('Status updated to %s.', 'abp-rentalforge'), $text), 'type' => 'success', 'book_status' => $book_status, 'book_status_text' => $text]); } //=============================// private function today_bookings($post_id, $start_time): void { $filters = array( 'post_id' => $post_id, 'start_time' => $start_time, 'cache' => false, ); $bookings = ABPRF_Query::get_booking_query($filters); if (empty($bookings)) { echo '

' . esc_html__('No bookings for this period yet.', 'abp-rentalforge') . '

'; return; } ?>
: 0 && function_exists('wc_price') ? wp_kses_post(wc_price($rent)) : esc_html__('FREE', 'abp-rentalforge'); ?> : 0 && function_exists('wc_price') ? wp_kses_post(wc_price($ex_price)) : esc_html__('FREE', 'abp-rentalforge'); ?> 0) { ?> : : 0 && function_exists('wc_price') ? wp_kses_post(wc_price($item_total)) : esc_html__('FREE', 'abp-rentalforge'); ?>
0 && $book_status < 2) { ?>
ABPRF_Function::get_cpt(), 'meta_key' => 'dummy', 'meta_value' => 'on', 'posts_per_page' => -1, 'post_status' => 'any', 'fields' => 'ids', ])); ?>

= 2 && defined('WC_VERSION')) { ?>
= 2) { $wc_name = get_option('woocommerce_email_from_name'); $wc_email = get_option('woocommerce_email_from_address'); if (!empty($wc_name)) { ?>
checklist_item(__('WooCommerce Plugin', 'abp-rentalforge'), defined('ABPRF_WC') && ABPRF_WC >= 2, defined('ABPRF_WC') && ABPRF_WC == 1 ? 'wc_active' : 'wc_install_active'); ?> checklist_item(__('Booking Page', 'abp-rentalforge'), (bool)ABPRF_Function::get_page_by_slug('rf_booking'), 'rf_booking'); ?> checklist_item( /* translators: %s: plugin label. */ sprintf(esc_html__('%s List Page', 'abp-rentalforge'), esc_html($label)), (bool)ABPRF_Function::get_page_by_slug('rf_post'), 'rf_post' ); ?> checklist_item(__('Property List Page', 'abp-rentalforge'), (bool)ABPRF_Function::get_page_by_slug('rf_property'), 'rf_property'); ?> checklist_item(__('Gallery Page', 'abp-rentalforge'), (bool)ABPRF_Function::get_page_by_slug('rf_gallery'), 'rf_gallery'); ?> checklist_item(__('First Post Added', 'abp-rentalforge'), $total > 0, 'add_new'); ?>
0) { ?> 0) { ?>

0 ? (int)round(($row[2] / $sum) * 100) : 0; if ($row[2] > 0 && $width < 1) { $width = 1; } ?>
prefix . 'abprf_orders'; $data = array('revenue' => 0, 'rented' => 0, 'today' => 0); $statuses = array_filter(array_map('sanitize_text_field', explode(',', (string)ABPRF_Function::booking_status()))); if (!empty($statuses) && current($statuses) !== 'all') { $placeholders = implode(',', array_fill(0, count($statuses), '%s')); $sql = "SELECT price_info, property_info FROM %i WHERE order_status IN ($placeholders)"; $params = array_merge(array($table_name), $statuses); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- $placeholders is a generated %s list passed via $wpdb->prepare(). $rows = $wpdb->get_results($wpdb->prepare($sql, $params), ARRAY_A); if (!empty($rows)) { foreach ($rows as $row) { $price_info = json_decode($row['price_info'] ?? '', true) ?: array(); $data['revenue'] += (float)($price_info['item_total'] ?? 0); $property_info = json_decode($row['property_info'] ?? '', true) ?: array(); if (is_array($property_info)) { foreach ($property_info as $p) { $data['rented'] += (int)($p['qty'] ?? 0); } } } } } // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $data['today'] = (int)$wpdb->get_var( $wpdb->prepare('SELECT COUNT(*) FROM %i WHERE DATE(created_at) = %s', $table_name, current_time('Y-m-d')) ); wp_cache_set($cache_key, $data, 'abprf_dashboard'); return $data; } //=============================// public static function booking_meta($post_id, $start_time): array { $post_id = (int)$post_id; $total = 0; $reserve = 0; $properties = ABPRF_Query::get_property(array('post_id' => $post_id, 'status' => 'publish')); if (is_array($properties)) { foreach ($properties as $property) { $stock = self::property_stock($property); $total += $stock['qty']; $reserve += $stock['reserve']; } } $filters = array('post_id' => $post_id, 'start_time' => $start_time, 'cache' => false); $booking_lists = ABPRF_Query::get_booking_query($filters); $sold_qty = 0; $day_rent = 0; $day_deposit = 0; if (!empty($booking_lists)) { foreach ($booking_lists as $booking) { $p_infos = json_decode($booking['property_info'] ?? '', true) ?: array(); foreach ($p_infos as $pi) { $sold_qty += (int)($pi['qty'] ?? 0); } $price_info = json_decode($booking['price_info'] ?? '', true) ?: array(); $day_rent += (float)($price_info['rent'] ?? 0); $day_deposit += (float)($price_info['deposit'] ?? 0); } } $order_count = is_array($booking_lists) ? count($booking_lists) : 0; $available = $total - $sold_qty - $reserve; if ($available < 0) { $available = 0; } return array( 'post_id' => $post_id, 'start_time' => $start_time, 'end_time' => $start_time, 'title' => get_the_title($post_id), 'sold' => (int)$sold_qty, 'available' => $available, 'total' => $total, 'reserve' => $reserve, 'day_rent' => $day_rent, 'day_deposit' => $day_deposit, 'order_count' => (int)$order_count, ); } //=============================// private static function property_stock($property): array { $stock = array('qty' => 0, 'reserve' => 0); if (!is_array($property)) { return $stock; } $pqi = json_decode($property['price_qty_info'] ?? '', true); if (!is_array($pqi)) { return $stock; } $rule = $property['rent_rule'] ?? ''; $candidates = array(); if ($rule !== '' && isset($pqi[$rule]) && is_array($pqi[$rule])) { $candidates[] = $pqi[$rule]; } foreach ($pqi as $sub) { if (is_array($sub) && isset($sub[$rule]) && is_array($sub[$rule])) { $candidates[] = $sub[$rule]; } } if (empty($candidates)) { foreach ($pqi as $sub) { if (is_array($sub) && isset($sub['qty'])) { $candidates[] = $sub; break; } } } if (!empty($candidates)) { $info = $candidates[0]; $stock['qty'] = (int)($info['qty'] ?? 0); $stock['reserve'] = (int)($info['reserve'] ?? 0); } return $stock; } //=============================// public function wc_config(): void { if (!check_ajax_referer('abprf_admin_ajax_nonce', 'nonce', false) || !current_user_can('manage_options')) { wp_send_json_error(['msg' => __('Invalid security token or Insufficient permissions.', 'abp-rentalforge'), 'type' => 'warn'], 403); } $post_val = fn($key, $default = '') => isset($_POST[$key]) ? sanitize_text_field(wp_unslash($_POST[$key])) : $default; $page_type = $post_val('type'); if ($page_type == 'wc_install_active') { include_once(ABSPATH . 'wp-admin/includes/plugin-install.php'); include_once(ABSPATH . 'wp-admin/includes/file.php'); include_once(ABSPATH . 'wp-admin/includes/misc.php'); include_once(ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'); $plugin = 'woocommerce'; $api = plugins_api('plugin_information', array( 'slug' => $plugin, 'fields' => array( 'short_description' => false, 'sections' => false, 'requires' => false, 'rating' => false, 'ratings' => false, 'downloaded' => false, 'last_updated' => false, 'added' => false, 'tags' => false, 'compatibility' => false, 'homepage' => false, 'donate_link' => false, ), )); if (is_wp_error($api)) { wp_send_json_error(['html' => '', 'msg' => $api->get_error_message()]); } $title = 'title'; $url = 'url'; $nonce = 'nonce'; $woocommerce_plugin = new Plugin_Upgrader(new Plugin_Installer_Skin(compact('title', 'url', 'nonce', 'plugin', 'api'))); $installed = $woocommerce_plugin->install($api->download_link); if (is_wp_error($installed)) { wp_send_json_error(['msg' => $installed->get_error_message(), 'type' => 'warn']); } $activated = activate_plugin('woocommerce/woocommerce.php'); if (is_wp_error($activated)) { wp_send_json_error(['msg' => $activated->get_error_message(), 'type' => 'warn']); } wp_send_json_success(['msg' => esc_html__('WooCommerce installed and activated successfully!', 'abp-rentalforge'), 'type' => 'success'], 200); } if ($page_type == 'wc_active') { if (defined('ABPRF_WC') && ABPRF_WC == 1) { $activated = activate_plugin('woocommerce/woocommerce.php'); if (is_wp_error($activated)) { wp_send_json_error(['msg' => $activated->get_error_message(), 'type' => 'warn']); } wp_send_json_success(['msg' => esc_html__('WooCommerce activated successfully!', 'abp-rentalforge'), 'type' => 'success'], 200); } } wp_send_json_error(['msg' => esc_html__('WooCommerce is either not installed or already active.', 'abp-rentalforge'), 'type' => 'warn'], 403); } //=============================// public function create_page(): void { if (!check_ajax_referer('abprf_admin_ajax_nonce', 'nonce', false)) { wp_send_json_error(['info_type' => 'warn', 'msg' => __('Invalid security token.', 'abp-rentalforge')], 403); } if (!current_user_can('manage_options')) { wp_send_json_error(['info_type' => 'warn', 'msg' => __('Insufficient permissions.', 'abp-rentalforge')], 403); } $post_val = fn($key, $default = '') => isset($_POST[$key]) ? sanitize_text_field(wp_unslash($_POST[$key])) : $default; $page_type = $post_val('type'); if (!empty($page_type)) { if (!ABPRF_Function::get_page_by_slug($page_type)) { $label = ABPRF_Function::label(); $short_code = ''; if ($page_type == 'rf_booking') { $label = __('Booking', 'abp-rentalforge'); $short_code = '[abprf-booking]'; } if ($page_type == 'rf_post') { $short_code = '[abprf-post]'; } if ($page_type == 'rf_property') { $label = __('Property', 'abp-rentalforge'); $short_code = '[abprf-property]'; } if ($page_type == 'rf_gallery') { $label = __('Gallery', 'abp-rentalforge'); $short_code = '[abprf-gallery]'; } $page = array( 'post_type' => 'page', 'post_name' => $page_type, 'post_title' => $label, 'post_content' => $short_code, 'post_status' => 'publish', ); $post_id = wp_insert_post($page); if (is_wp_error($post_id) || 0 === $post_id) { wp_send_json_error(['info_type' => 'warn', 'msg' => esc_html__('Failed to create page.', 'abp-rentalforge')]); } flush_rewrite_rules(); /* translators: %s: Custom rental item type label (e.g., Vehicle, Equipment, Property) */ $translated_format = esc_html__('%s Page Created successfully.....', 'abp-rentalforge'); $msg = sprintf($translated_format, $label); wp_send_json_success(['info_type' => 'success', 'msg' => $msg]); } wp_send_json_error(['info_type' => 'warn', 'msg' => esc_html__('Page already exists.', 'abp-rentalforge')]); } else { wp_send_json_error(['info_type' => 'warn', 'msg' => esc_html__('Something Wrong...!', 'abp-rentalforge')]); } } } new ABPRF_Dashboard(); }