Server : Apache/2.4.18 (Ubuntu) System : Linux canvaswebdesign 3.13.0-71-generic #114-Ubuntu SMP Tue Dec 1 02:34:22 UTC 2015 x86_64 User : oppastar ( 1041) PHP Version : 7.0.33-0ubuntu0.16.04.15 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority, Directory : /proc/self/root/var/www/laciasmara.com/public_html/shop/application/controllers/ |
Upload File : |
<?php defined('BASEPATH') or exit('No direct script access allowed'); class Category extends Public_Controller { public function __construct() { parent::__construct(); $this->load->library('GoogleClient'); $this->load->library('VisitorTracking'); $this->load->model('Top_banner_m'); $this->load->model('Review_m'); $this->load->model('customer_m'); $this->load->model('Footer_m'); $this->load->model('Category_m'); $this->load->model('Statistic_m'); $loginUrl = $this->googleclient->getLoginUrl(); $this->data_footer['googleUrl'] = $loginUrl; if ($this->session->userdata('site_lang') == 'english') { $this->lang->load('mainpage', 'english'); } else { $this->lang->load('mainpage', 'indonesian'); } } public function get($categoryAlias = null, $childAlias = null) { $this->load->helper('product'); $this->visitortracking->trackVisitor(); if ($this->session->userdata('customer')) { $id_customer = (int) $this->session->userdata('customer')['customer_id']; $this->data['customer'] = $this->customer_m->get_customer($id_customer); } if ( $categoryAlias !== strtolower($categoryAlias) || ($childAlias && $childAlias !== strtolower($childAlias)) ) { $newUrl = "category/" . strtolower($categoryAlias); if ($childAlias) { $newUrl .= "/" . strtolower($childAlias); } redirect($newUrl); } // Fetch active banners $activeBanners = $this->Top_banner_m->get_active_banners(); // Fetch website data for header and meta information $websiteData = $this->db->select('website_icon, browser_title, meta_description') ->from('configuration') ->where('id_configuration', 1) ->get() ->row(); $meta_description = ($this->session->userdata('site_lang') == 'english') ? "Explore a world full of pleasure. Discover products to make you more confident and satisfied, only at Laci Asmara!" : "Jelajahi dunia penuh kenikmatan. Temukan produk yang bikin kamu makin pede dan puas, hanya di Laci Asmara!"; // Prepare header data $this->data_header = [ 'website_icon' => $websiteData->website_icon, 'browser_title' => $websiteData->browser_title . ' - Categories', 'meta_description' => $meta_description, 'banners' => $activeBanners, 'logo_path' => 'https://storage.googleapis.com/laciasmara-photos/laciaasmara_assets/laciasmara_landing_page/laciasmara_landing_page_logo.webp', 'footer_categories' => $this->Footer_m->get_all_categories(), 'footer_social_media' => $this->Footer_m->get_social_media(), 'footer_payment_methods' => $this->Footer_m->get_payment_methods(), 'footer_asmaradoor' => $this->Footer_m->get_asmaradoor(), 'footer_bottom' => $this->Footer_m->get_footer_bottom() ]; if ($categoryAlias === 'all') { // Fetch all active categories $categories = $this->db->select('*') ->from('categories') ->where('status', 1) ->order_by('priority', 'ASC') ->get() ->result(); // Update header data with categories $this->data_header['categories'] = $categories; // Load views for all categories page $this->load->view("themes/$this->theme_no/header_new", $this->data_header); $this->load->view('all-categories'); $this->load->view("themes/$this->theme_no/footer_new", $this->data_footer); } else { // Check if the category is a main category (level 1) or a subcategory (level 2) $category = $this->getCategoryByAlias($categoryAlias, $childAlias); if (!$category) { // If the category is not found, display the page not found view $this->load->view("pagenotfound"); } else { $query = $this->get_optimized_product_query($category['id_categories']); $this->db->cache_on(); $products = $this->db->query($query)->result_array(); $this->db->cache_off(); // Format data produk $formatted_products = $this->prepare_category_products($products); $this->data_header = [ 'website_icon' => $websiteData->website_icon, 'browser_title' => $category['meta_title'], 'meta_description' => $category['meta_description'], 'products' => $formatted_products, 'banners' => $activeBanners, 'logo_path' => 'https://storage.googleapis.com/laciasmara-photos/laciaasmara_assets/laciasmara_landing_page/laciasmara_landing_page_logo.webp', 'footer_categories' => $this->Footer_m->get_all_categories(), 'footer_social_media' => $this->Footer_m->get_social_media(), 'footer_payment_methods' => $this->Footer_m->get_payment_methods(), 'footer_asmaradoor' => $this->Footer_m->get_asmaradoor(), 'footer_bottom' => $this->Footer_m->get_footer_bottom() ]; $this->data_footer['popular_categories'] = $this->Category_m->get_footer_popular_categories(); $this->data_footer['trending_searches'] = $this->Statistic_m->get_trending_searches(); // Load product list for the selected category $this->load->view("themes/3/header_new", $this->data_header); $this->load->view("themes/3/product_list", ['category' => $category]); $this->load->view("themes/3/footer_new", $this->data_footer); } } } private function prepare_category_products($products) { $customer = $this->session->userdata('customer'); $is_reseller = false; $reseller_price_map = []; // Get reseller information (existing code) if (!empty($customer['customer_id'])) { $customer_id = $customer['customer_id']; $customer_data = $this->db->where('id_customers', $customer_id)->get('customers')->row_array(); if (!empty($customer_data['reseller_id'])) { $reseller = $this->db->where('id_resellers', $customer_data['reseller_id'])->get('resellers')->row_array(); if ($reseller) { $is_reseller = true; $reseller_prices = $this->db->where('reseller_id', $reseller['id_resellers'])->get('resellers_price')->result_array(); foreach ($reseller_prices as $price) { $reseller_price_map[$price['product_detail_id']] = $price['price']; } } } } $formatted_products = []; foreach ($products as $product) { // Price calculations $is_discounted = $product['discounted_price'] > 0; $default_price = $product['price']; $discounted_price = $product['discounted_price']; $current_price = $is_discounted ? $discounted_price : $default_price; $msrp_price = null; // Handle reseller pricing if ($is_reseller && isset($reseller_price_map[$product['id_detail']])) { $msrp_price = $current_price; $current_price = $reseller_price_map[$product['id_detail']]; } // Get reviews $review_data = $this->Review_m->get_product_reviews($product['id_products']); $average_rating = isset($review_data['average_rating']) ? round($review_data['average_rating'], 1) : 0; $total_reviews = isset($review_data['total_reviews']) ? $review_data['total_reviews'] : 0; // Parse variants $variants = !empty($product['variants']) ? explode('; ', $product['variants']) : []; $badges = $this->parse_badges_data($product['badges_data'] ?? ''); $badges_names = $product['badges_names'] ?? ''; // Stock calculations - all done in SQL now, just ensure non-negative values $current_variant_stock_sell = max(0, intval($product['current_variant_stock_sell'] ?? 0)); $total_stock_sell = max(0, intval($product['total_stock_sell'] ?? 0)); $formatted_products[] = [ 'id' => $product['id_products'], 'title' => $product['title'], 'id_detail' => $product['id_detail'], 'alias' => $product['alias'], 'sku' => $product['sku'], 'current_price' => $current_price, 'original_price' => $is_discounted ? $default_price : null, 'msrp_price' => $msrp_price, 'image' => $product['image'], 'image_secondary' => $product['image_secondary'], 'stock' => $product['total_stock'], 'stock_sell' => $current_variant_stock_sell, 'total_stock_sell' => $total_stock_sell, 'average_rating' => $average_rating, 'total_reviews' => $total_reviews, 'variants' => $variants, 'is_wishlisted' => $this->_check_wishlist_status($product['id_products'], $customer['customer_id'] ?? null), 'created_at' => $product['created_at'], 'brand_priority' => $product['brand_priority'], 'savings_amount' => $product['savings_amount'], 'is_discounted' => $is_discounted, 'discount_percentage' => $product['discount_percentage'], // Stock flags - now calculated in SQL 'is_completely_sold_out' => (bool) $product['is_completely_sold_out'], 'current_variant_out_of_stock' => (bool) $product['current_variant_out_of_stock'], 'has_other_variants_available' => (bool) $product['has_other_variants_available'], // Additional stock information 'total_variants' => (int) $product['total_variants'], 'available_variants' => (int) $product['available_variants'], // Badges 'badges' => $badges, 'badges_names' => $badges_names, // Simple comma-separated names for quick display 'badges_count' => (int) ($product['badges_count'] ?? 0), 'has_badges' => !empty($badges), // New arrivals flag for badges 'new_arrivals' => ($product['new_arrival'] === 'yes'), 'best_seller' => ($product['best_seller'] === 'yes'), 'popular_product' => ($product['popular_product'] === 'yes'), ]; } return $formatted_products; } private function parse_badges_data($badges_data) { $badges = []; if (empty($badges_data)) { return $badges; } $badges_raw = explode('|', $badges_data); foreach ($badges_raw as $badge_raw) { if (empty($badge_raw)) continue; $badge_parts = explode(':', $badge_raw); if (count($badge_parts) >= 9) { $badges[] = [ 'id' => (int) $badge_parts[0], 'name' => $badge_parts[1], 'slug' => $badge_parts[2], 'description' => $badge_parts[3], 'background_color' => !empty($badge_parts[4]) ? $badge_parts[4] : '#FF6B6B', 'text_color' => !empty($badge_parts[5]) ? $badge_parts[5] : '#FFFFFF', 'icon' => $badge_parts[6], 'position' => $badge_parts[7], 'priority' => (int) $badge_parts[8], // Additional computed properties 'css_class' => 'badge-' . $badge_parts[2], 'has_icon' => !empty($badge_parts[6]), 'style' => sprintf( 'background-color: %s; color: %s;', !empty($badge_parts[4]) ? $badge_parts[4] : '#FF6B6B', !empty($badge_parts[5]) ? $badge_parts[5] : '#FFFFFF' ) ]; } } // Already sorted by priority in SQL, but double check usort($badges, function ($a, $b) { return $a['priority'] - $b['priority']; }); return $badges; } private function get_optimized_product_query($id_category) { return " SELECT p.id_products, p.title, p.alias, p.brand_id, p.created_at, p.best_seller, p.new_arrival, p.popular_product, p.priority, COALESCE(primary_variant.id, first_variant.id) AS id_detail, COALESCE(primary_variant.price, first_variant.price) AS price, COALESCE(primary_variant.discounted_price, first_variant.discounted_price) AS discounted_price, COALESCE(primary_variant.sku, first_variant.sku) AS sku, COALESCE( main_image.image, COALESCE(primary_variant_image.image, first_variant_image.image), p.image ) AS image, COALESCE( main_image_secondary.image, COALESCE(primary_variant_image_secondary.image, first_variant_image_secondary.image), p.image1 ) AS image_secondary, stock_summary.total_stock, stock_summary.total_stock_keep, stock_summary.total_stock_sell, stock_summary.available_variants, stock_summary.total_variants, COALESCE( GREATEST(0, COALESCE(primary_variant_stock.stock, 0) - COALESCE(primary_variant_stock.stock_keep, 0)), GREATEST(0, COALESCE(first_variant_stock.stock, 0) - COALESCE(first_variant_stock.stock_keep, 0)), 0 ) AS current_variant_stock_sell, CASE WHEN stock_summary.total_stock_sell <= 0 THEN 1 ELSE 0 END AS is_completely_sold_out, CASE WHEN COALESCE( GREATEST(0, COALESCE(primary_variant_stock.stock, 0) - COALESCE(primary_variant_stock.stock_keep, 0)), GREATEST(0, COALESCE(first_variant_stock.stock, 0) - COALESCE(first_variant_stock.stock_keep, 0)), 0 ) <= 0 THEN 1 ELSE 0 END AS current_variant_out_of_stock, CASE WHEN stock_summary.available_variants > 1 THEN 1 ELSE 0 END AS has_other_variants_available, COALESCE(primary_variant_attrs.variants, first_variant_attrs.variants, 'No variants available') AS variants, COALESCE(total_sales.total_sales, 0) AS total_sales, COALESCE(total_reviews.total_reviews, 0) AS total_reviews, COALESCE(reseller_price.price, 0) AS reseller_price, COALESCE(reseller_price.min_quantity, 0) AS reseller_min_quantity, COALESCE(b.priority, 0) AS brand_priority, -- Badges COALESCE(product_badges_data.badges_names, '') AS badges_names, COALESCE(product_badges_data.badges_data, '') AS badges_data, COALESCE(product_badges_data.badges_count, 0) AS badges_count, CASE WHEN COALESCE(primary_variant.discounted_price, first_variant.discounted_price) > 0 AND COALESCE(primary_variant.discounted_price, first_variant.discounted_price) < COALESCE(primary_variant.price, first_variant.price) THEN (COALESCE(primary_variant.price, first_variant.price) - COALESCE(primary_variant.discounted_price, first_variant.discounted_price)) ELSE 0 END AS savings_amount, CASE WHEN COALESCE(primary_variant.discounted_price, first_variant.discounted_price) > 0 AND COALESCE(primary_variant.discounted_price, first_variant.discounted_price) < COALESCE(primary_variant.price, first_variant.price) THEN ROUND(((COALESCE(primary_variant.price, first_variant.price) - COALESCE(primary_variant.discounted_price, first_variant.discounted_price)) / COALESCE(primary_variant.price, first_variant.price)) * 100, 0) ELSE 0 END AS discount_percentage, CASE WHEN stock_summary.total_stock_sell <= 0 THEN 1 ELSE 0 END AS sort_order FROM products p -- Stock Summary LEFT JOIN ( SELECT pd.product_id, COUNT(DISTINCT pd.id) AS total_variants, SUM(COALESCE(s.stock, 0)) AS total_stock, SUM(COALESCE(s.stock_keep, 0)) AS total_stock_keep, SUM(GREATEST(0, COALESCE(s.stock, 0) - COALESCE(s.stock_keep, 0))) AS total_stock_sell, SUM(CASE WHEN GREATEST(0, COALESCE(s.stock, 0) - COALESCE(s.stock_keep, 0)) > 0 THEN 1 ELSE 0 END) AS available_variants FROM product_details pd LEFT JOIN stock s ON pd.id = s.id_product_detail GROUP BY pd.product_id ) stock_summary ON p.id_products = stock_summary.product_id -- Primary Variant LEFT JOIN ( SELECT pd.* FROM product_details pd INNER JOIN ( SELECT product_id, MIN(id) as min_id FROM product_details GROUP BY product_id ) min_pd ON pd.product_id = min_pd.product_id AND pd.id = min_pd.min_id ) primary_variant ON p.id_products = primary_variant.product_id -- First Variant (with max stock sell) LEFT JOIN ( SELECT pd.* FROM product_details pd LEFT JOIN stock s ON pd.id = s.id_product_detail INNER JOIN ( SELECT pd.product_id, MAX(GREATEST(0, COALESCE(s.stock, 0) - COALESCE(s.stock_keep, 0))) AS max_stock FROM product_details pd LEFT JOIN stock s ON pd.id = s.id_product_detail GROUP BY pd.product_id ) max_stock_pd ON pd.product_id = max_stock_pd.product_id LEFT JOIN stock s2 ON pd.id = s2.id_product_detail WHERE GREATEST(0, COALESCE(s2.stock, 0) - COALESCE(s2.stock_keep, 0)) = max_stock_pd.max_stock ) first_variant ON p.id_products = first_variant.product_id -- Stock LEFT JOIN stock primary_variant_stock ON primary_variant.id = primary_variant_stock.id_product_detail LEFT JOIN stock first_variant_stock ON first_variant.id = first_variant_stock.id_product_detail -- Images LEFT JOIN product_images main_image ON p.id_products = main_image.product_id AND main_image.product_details_id = 0 AND main_image.priority = 1 AND main_image.status = '1' LEFT JOIN product_images main_image_secondary ON p.id_products = main_image_secondary.product_id AND main_image_secondary.product_details_id = 0 AND main_image_secondary.priority = 2 AND main_image_secondary.status = '1' LEFT JOIN product_images primary_variant_image ON primary_variant.id = primary_variant_image.product_details_id AND primary_variant_image.priority = 1 AND primary_variant_image.status = '1' LEFT JOIN product_images primary_variant_image_secondary ON primary_variant.id = primary_variant_image_secondary.product_details_id AND primary_variant_image_secondary.priority = 2 AND primary_variant_image_secondary.status = '1' LEFT JOIN product_images first_variant_image ON first_variant.id = first_variant_image.product_details_id AND first_variant_image.priority = 1 AND first_variant_image.status = '1' LEFT JOIN product_images first_variant_image_secondary ON first_variant.id = first_variant_image_secondary.product_details_id AND first_variant_image_secondary.priority = 2 AND first_variant_image_secondary.status = '1' -- Variant Attributes LEFT JOIN ( SELECT pc.product_details_id, GROUP_CONCAT(DISTINCT CONCAT_WS(': ', pa.product_attribute, pad.attribute_detail) SEPARATOR '; ') AS variants FROM product_combination pc JOIN product_attributes pa ON pc.attribute_id = pa.id JOIN product_attributes_detail pad ON pc.attribute_detail_id = pad.id GROUP BY pc.product_details_id ) primary_variant_attrs ON primary_variant.id = primary_variant_attrs.product_details_id LEFT JOIN ( SELECT pc.product_details_id, GROUP_CONCAT(DISTINCT CONCAT_WS(': ', pa.product_attribute, pad.attribute_detail) SEPARATOR '; ') AS variants FROM product_combination pc JOIN product_attributes pa ON pc.attribute_id = pa.id JOIN product_attributes_detail pad ON pc.attribute_detail_id = pad.id GROUP BY pc.product_details_id ) first_variant_attrs ON first_variant.id = first_variant_attrs.product_details_id -- Badges LEFT JOIN ( SELECT pb.product_id, COUNT(pb.badge_id) AS badges_count, GROUP_CONCAT(b.name ORDER BY pb.priority ASC SEPARATOR ', ') AS badges_names, GROUP_CONCAT( CONCAT( b.id, ':', b.name, ':', b.slug, ':', IFNULL(b.description, ''), ':', IFNULL(b.background_color, '#FF6B6B'), ':', IFNULL(b.text_color, '#FFFFFF'), ':', IFNULL(b.icon, ''), ':', pb.position, ':', pb.priority ) ORDER BY pb.priority ASC SEPARATOR '|' ) AS badges_data FROM product_badges pb INNER JOIN badges b ON pb.badge_id = b.id WHERE pb.is_active = 1 AND b.is_active = 1 AND (pb.start_date IS NULL OR pb.start_date <= NOW()) AND (pb.end_date IS NULL OR pb.end_date >= NOW()) GROUP BY pb.product_id ) product_badges_data ON p.id_products = product_badges_data.product_id -- Additional Joins LEFT JOIN ( SELECT item_id, SUM(quantity) AS total_sales FROM orders_detail WHERE warehouse_id = 1 GROUP BY item_id ) total_sales ON COALESCE(primary_variant.id, first_variant.id) = total_sales.item_id LEFT JOIN ( SELECT product_id, COUNT(id) AS total_reviews FROM product_review GROUP BY product_id ) total_reviews ON p.id_products = total_reviews.product_id LEFT JOIN resellers_price reseller_price ON COALESCE(primary_variant.id, first_variant.id) = reseller_price.product_detail_id LEFT JOIN brands b ON p.brand_id = b.id_brands INNER JOIN category_product cp ON p.id_products = cp.id_product WHERE p.product_status = '1' AND p.deleted_at IS NULL AND cp.id_category = " . (int)$id_category . " GROUP BY p.id_products ORDER BY sort_order ASC, p.best_seller DESC, p.new_arrival DESC, p.popular_product DESC, p.priority DESC, COALESCE(b.priority, 0) DESC, p.created_at DESC "; } /** * Helper method untuk mengecek ketersediaan stok semua variant produk * @param int $product_id * @return array Informasi lengkap tentang stok variant */ private function get_product_stock_info($product_id) { // Ambil semua variant dari produk ini dengan perhitungan stock_sell yang aman $this->db->select(' s.stock, s.stock_keep, CASE WHEN (s.stock IS NULL OR s.stock_keep IS NULL) THEN 0 WHEN (s.stock - s.stock_keep) < 0 THEN 0 ELSE (s.stock - s.stock_keep) END as stock_sell_safe ') ->from('product_details pd') ->join('stock s', 'pd.id = s.id_product_detail', 'left') ->where('pd.product_id', $product_id); $variants_stock = $this->db->get()->result_array(); // Jika tidak ada data stock, anggap sold out if (empty($variants_stock)) { return [ 'is_completely_sold_out' => true, 'has_other_variants_available' => false, 'has_other_variants_sold_out' => false, 'total_variants' => 0, 'available_variants' => 0 ]; } $available_variants = 0; $sold_out_variants = 0; $total_variants = count($variants_stock); // Hitung variant yang tersedia dan yang habis dengan logika yang aman foreach ($variants_stock as $variant) { $stock = intval($variant['stock'] ?? 0); $stock_keep = intval($variant['stock_keep'] ?? 0); // Pastikan stock_sell tidak bisa negatif $stock_sell_safe = max(0, $stock - $stock_keep); if ($stock_sell_safe > 0) { $available_variants++; } else { $sold_out_variants++; } } return [ 'is_completely_sold_out' => ($available_variants == 0), // Semua variant habis 'has_other_variants_available' => ($available_variants > 1), // Ada variant lain yang tersedia (selain yang ditampilkan) 'has_other_variants_sold_out' => ($sold_out_variants > 0), // Ada variant lain yang habis 'total_variants' => $total_variants, 'available_variants' => $available_variants ]; } private function _check_wishlist_status($product_id, $customer_id) { if (!$customer_id) return false; $exists = $this->db->where([ 'customer_id' => $customer_id, 'product_id' => $product_id ])->get('wishlists')->num_rows(); return $exists > 0; } /** * Get category by alias and handle child alias logic */ private function getCategoryByAlias($categoryAlias, $childAlias = null) { if ($childAlias) { // Pertama cari parent category $parentQuery = $this->db->where('alias', $categoryAlias) ->or_where('alias_en', $categoryAlias) ->get('categories'); $parentCategory = $parentQuery->row_array(); if (!$parentCategory) { return null; } // Kemudian cari child yang parent_id nya sesuai $childQuery = $this->db->where('parent', $parentCategory['id_categories']) ->where('(alias = ' . $this->db->escape($childAlias) . ' OR alias_en = ' . $this->db->escape($childAlias) . ')') ->get('categories'); return $childQuery->row_array(); } else { // Tambah pengecekan apakah ini sebenarnya child category $category = $this->db->where('alias', $categoryAlias) ->or_where('alias_en', $categoryAlias) ->get('categories') ->row_array(); if ($category && $category['parent']) { // Ini sebenarnya child category, redirect ke URL yang benar $parentCategory = $this->db->get_where( 'categories', ['id_categories' => $category['parent']] )->row_array(); if ($parentCategory) { redirect("category/{$parentCategory['alias']}/{$category['alias']}"); } } return $category; } } public function index() { $this->visitortracking->trackVisitor(); $categories = $this->db->select('*') ->from('categories') ->where('status', 1) ->order_by('priority', 'ASC') ->get() ->result(); $activeBanners = $this->Top_banner_m->get_active_banners(); // Fetch website data for header and meta information $websiteData = $this->db->select('website_icon, browser_title, meta_description') ->from('configuration') ->where('id_configuration', 1) ->get() ->row(); // Prepare header data $this->data_header = [ 'website_icon' => $websiteData->website_icon, 'browser_title' => $websiteData->browser_title . ' - Categories', 'meta_description' => $websiteData->meta_description, 'banners' => $activeBanners, 'logo_path' => 'https://storage.googleapis.com/laciasmara-photos/laciaasmara_assets/laciasmara_landing_page/laciasmara_landing_page_logo.webp', ]; // Update header data with categories $this->data_header['categories'] = $categories; // Load views for all categories page $this->load->view("themes/$this->theme_no/header_new", $this->data_header); $this->load->view('all-categories'); $this->load->view("themes/$this->theme_no/footer_new", $this->data_footer); } }