https://t.me/RX1948
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/admin/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : //proc/self/root/var/www/laciasmara.com/public_html/shop/application/controllers/admin/Products.php
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');



class Products extends Admin_Controller

{

	function __construct()

	{



		parent::__construct();

		$this->load->model('product_m');

		$this->load->model('category_m');

		$this->load->model('configuration_m');

		$this->load->model('brand_m');

		$this->load->model('warehouse_m');

		$this->load->model('product_attributes_m');

		$this->load->helper('form');

	}



	function index()

	{

		$data['userdata'] = $this->session->userdata();

		$data['categories'] = $this->category_m->all_categories();

		$data['brands'] = $this->brand_m->get_all_brands();

		$data['title'] = 'Pengaturan Produk | Laciasmara';

		$data['total_products'] = $this->product_m->count_products();

		$data['active_products'] = $this->product_m->count_products(1);

		$data['inactive_products'] = $this->product_m->count_products(0);



		$this->load->view('admin_new/layouts/header', $data);

		$this->load->view('admin_new/products/manage_product');

		$this->load->view('admin_new/layouts/footer');

	}



	// Pages

	// Manage Product

	function manage()

	{

		$data['userdata'] = $this->session->userdata();

		$data['categories'] = $this->category_m->all_categories();

		$data['brands'] = $this->brand_m->get_all_brands();

		$data['title'] = 'Pengaturan Produk | Laciasmara';

		$data['total_products'] = $this->product_m->count_products();

		$data['active_products'] = $this->product_m->count_products(1);

		$data['inactive_products'] = $this->product_m->count_products(0);



		$this->load->view('admin_new/layouts/header', $data);

		$this->load->view('admin_new/products/manage_product');

		$this->load->view('admin_new/layouts/footer');

	}

	// Add Product Page

	function add_product()

	{

		$data['userdata'] = $this->session->userdata();

		$data['title'] = 'Tambah Produk | Laciasmara';

		$data['brands'] = $this->brand_m->get_all_brands();

		$data['categories'] = $this->category_m->all_categories();

		$data['products'] = $this->product_m->all_products();

		$data['productAttributes'] = $this->product_m->get_all_attributes();

		$data['shippingMethods'] = $this->product_m->get_all_shipping_methods();



		$this->load->view('admin_new/layouts/header', $data);

		$this->load->view('admin_new/products/add_product');

		$this->load->view('admin_new/layouts/footer');

	}



	// Edit Product Page

	public function edit_product($id_product = NULL)

	{

		if (!$id_product) {

			redirect('admin/products/manage-product');

		}

		$data['userdata'] = $this->session->userdata();

		$data['title'] = 'Ubah Produk | Laciasmara';



		$data['brands'] = $this->brand_m->get_all_brands();

		$data['categories'] = $this->category_m->all_categories();

		$data['products'] = $this->product_m->all_products();

		$data['productAttributes'] = $this->product_m->get_all_attributes();

		$data['shippingMethods'] = $this->product_m->get_all_shipping_methods();



		// Fetch data produk yang mau di ubah

		$data['product'] = $this->product_m->fetch_product_by_id($id_product);



		// Selected Category

		$product_categories = $this->product_m->fetch_product_categories($id_product);

		// Convert ke array, biar lebih gampang dipake

		$data['product_categories'] = array_map(function ($cat) {

			return $cat->id_category;

		}, $product_categories);





		// Selected Shipping Method

		$shipping_method = $this->product_m->fetch_product_shipping_methods($id_product);

		$data['shipping_methods'] = array_map(function ($ship) {

			return $ship->shipment_method_id;

		}, $shipping_method);



		// Product Reccomendation

		if ($data['product']->product_suggest) {

			$data['product_suggestions'] = explode(',', $data['product']->product_suggest);

		} else {

			$data['product_suggestions'] = [];

		}



		// Variant

		$data['product_variants'] = $this->product_m->fetch_product_variants($id_product);



		if (!$data['product']) {

			redirect('admin/products/manage-product');

		}



		$this->load->view('admin_new/layouts/header', $data);

		$this->load->view('admin_new/products/edit_product');

		$this->load->view('admin_new/layouts/footer');

	}



	public function product_image($id_product = NULL)

	{

		if (!$id_product) {

			redirect('admin/products/manage-product');

		}



		$product = $this->db->get_where('products', ['id_products' => $id_product])->row_array();

		$product_name = $product ? $product['title'] : '';



		$data['userdata'] = $this->session->userdata();

		$data['title'] = 'Gambar Produk | Laciasmara';

		$product_details = $this->product_m->fetch_product_details_by_id($id_product);

		$data['product_details'] = $product_details;

		$data['id_product'] = $id_product;

		$data['product_name'] = $product_name;



		$product_details_ids = array_column($product_details, 'id');

		$product_images = $this->product_m->fetch_product_images_by_id_details($product_details_ids);



		$data['product_images'] = $product_images;



		$this->load->view('admin_new/layouts/header', $data);

		$this->load->view('admin_new/products/image_product');

		$this->load->view('admin_new/layouts/footer');

	}



	public function store_image($id_product)

	{

		$config['upload_path'] = './uploads/product/';

		$config['allowed_types'] = 'jpg|jpeg|png|gif|webp';

		$config['max_size'] = 1024; // 1MB

		$config['encrypt_name'] = TRUE;



		if (!is_dir($config['upload_path'])) {

			mkdir($config['upload_path'], 0777, TRUE);

		}



		$product = $this->db->get_where('products', ['id_products' => $id_product])->row_array();

		$product_name = $product ? $product['title'] : '';



		$this->load->library('upload', $config);

		$this->db->trans_begin();



		try {

			$product_images = $_FILES['product_images'] ?? [];

			$deleted_images = $this->input->post('delete_images');

			$existing_images = $this->input->post('existing_images'); // Ambil existing images dari form



			// **Step 1: Update Priority dari Existing Images**

			if (!empty($existing_images)) {

				foreach ($existing_images as $product_details_id => $images) {

					foreach ($images as $index => $image_id) {

						$this->db->where('id', $image_id);

						$this->db->update('product_images', [

							'title' => $product_name,      // Tambahkan title

							'title_en' => $product_name,   // Tambahkan title_en

							'alt' => $product_name,

							'priority' => $index + 1, // Update priority sesuai index yang dikirim

							'updated_at' => date('Y-m-d H:i:s')

						]);

					}

				}

			}



			// **Step 2: Hapus Gambar Jika Ada Data delete_images[]**

			if (!empty($deleted_images)) {

				foreach ($deleted_images as $image_id) {

					$image = $this->db->get_where('product_images', ['id' => $image_id])->row_array();



					if ($image) {

						$image_path = './uploads/product/' . $image['image'];

						if (file_exists($image_path)) {

							unlink($image_path);

						}



						$this->db->where('id', $image_id);

						$this->db->delete('product_images');

					}

				}

			}



			// **Step 3: Proses Upload Gambar Baru**

			foreach ($product_images['name'] as $product_details_id => $images) {

				foreach ($images as $index => $file_name) {

					if (!empty($file_name)) {

						$_FILES['image']['name'] = $file_name;

						$_FILES['image']['type'] = $product_images['type'][$product_details_id][$index];

						$_FILES['image']['tmp_name'] = $product_images['tmp_name'][$product_details_id][$index];

						$_FILES['image']['error'] = $product_images['error'][$product_details_id][$index];

						$_FILES['image']['size'] = $product_images['size'][$product_details_id][$index];



						if ($this->upload->do_upload('image')) {

							$upload_data = $this->upload->data();

							$image_name = $upload_data['file_name'];



							$this->db->insert('product_images', [

								'product_id' => $id_product,

								'product_details_id' => $product_details_id,

								'image' => $image_name,

								'title' => $product_name,      // Tambahkan title

								'title_en' => $product_name,   // Tambahkan title_en

								'alt' => $product_name,

								'priority' => $index + 1, // Priority sesuai index

								'status' => 1,

								'created_at' => date('Y-m-d H:i:s'),

								'updated_at' => date('Y-m-d H:i:s')

							]);

						} else {

							throw new Exception($this->upload->display_errors('', ''));

						}

					}

				}

			}



			if ($this->db->trans_status() === FALSE) {

				throw new Exception('Database error.');

			}



			$this->db->trans_commit();

			$this->session->set_flashdata('message', 'Gambar produk berhasil diperbarui.');

			$this->session->set_flashdata('message_type', 'success');

		} catch (Exception $e) {

			$this->db->trans_rollback();

			$this->session->set_flashdata('message', 'Gagal memperbarui gambar produk: ' . $e->getMessage());

			$this->session->set_flashdata('message_type', 'error');

		}



		redirect('admin/products/product-image/' . $id_product);

	}



	// Manage Variant

	function manage_variant()

	{

		$data['userdata'] = $this->session->userdata();

		$data['title'] = 'Pengaturan Varian | Laciasmara';

		$attributes = $this->product_m->get_all_attributes();



		foreach ($attributes as &$attribute) {

			$values = $this->product_m->get_attribute_values($attribute->id);

			$attribute->value_count = count($values); // Simpan jumlah opsi

			$attribute->product_count = $this->product_m->count_products_by_attribute($attribute->id);

		}



		$data['product_attributes'] = $attributes;



		$this->load->view('admin_new/layouts/header', $data);

		$this->load->view('admin_new/variants/variant_product');

		$this->load->view('admin_new/layouts/footer');

	}



	// Add Variant Page

	function add_variant()

	{

		$data['userdata'] = $this->session->userdata();

		$data['title'] = 'Tambah Varian | Laciasmara';



		$this->load->view('admin_new/layouts/header', $data);

		$this->load->view('admin_new/variants/add_variant');

		$this->load->view('admin_new/layouts/footer');

	}



	// Edit Variant

	public function edit_variant($id_variant = NULL)

	{

		if (!$id_variant) {

			redirect('admin/products/variant-product');

		}

		$data['userdata'] = $this->session->userdata();

		$data['title'] = 'Ubah Produk | Laciasmara';

		// Fetch data produk yang mau di ubah

		$data['product_attribute'] = $this->product_m->fetch_variant_by_id($id_variant);

		if (!$data['product_attribute']) {

			$this->session->set_flashdata('message', 'Atribut tidak ditemukan.');

			$this->session->set_flashdata('message_type', 'error');

			redirect('admin/products/variant-product');

		}



		$this->load->view('admin_new/layouts/header', $data);

		$this->load->view('admin_new/variants/edit_variant');

		$this->load->view('admin_new/layouts/footer');

	}



	public function manage_variant_options($id_attribute = NULL)

	{

		if (!$id_attribute) {

			redirect('admin/products/variant-product');

		}

		$data['userdata'] = $this->session->userdata();

		$data['title'] = 'Ubah Opsi Atribut | Laciasmara';



		$data['attribute_values'] = $this->product_m->get_attribute_values($id_attribute);

		$data['product_attribute'] = $this->product_m->fetch_variant_by_id($id_attribute);



		// if (!$data['attribute_values']) {

		// 	$this->session->set_flashdata('message', 'Opsi Atribut tidak ditemukan.');

		// 	$this->session->set_flashdata('message_type', 'error');

		// 	redirect('admin/products/variant-product');

		// }



		$this->load->view('admin_new/layouts/header', $data);

		$this->load->view('admin_new/variants/edit_variant_values');

		$this->load->view('admin_new/layouts/footer');

	}



	// Stock

	function stock()

	{

		$data['userdata'] = $this->session->userdata();

		$data['categories'] = $this->category_m->all_categories();

		$data['brands'] = $this->brand_m->get_all_brands();

		$data['warehouses'] = $this->warehouse_m->fetch_all_warehouses();

		$data['title'] = 'Stok Produk | Laciasmara';

		$data['total_products'] = $this->product_m->count_products();

		$data['active_products'] = $this->product_m->count_products(1);

		$data['inactive_products'] = $this->product_m->count_products(0);



		$this->load->view('admin_new/layouts/header', $data);

		$this->load->view('admin_new/products/stock_product');

		$this->load->view('admin_new/layouts/footer');

	}



	function transfer_stock()

	{

		$data['userdata'] = $this->session->userdata();

		$data['warehouses'] = $this->warehouse_m->fetch_all_warehouses();

		$data['products'] = [];

		$data['shippingMethods'] = $this->product_m->get_all_shipping_methods();





		$data['title'] = 'Transfer Stok | Laciasmara';



		$this->load->view('admin_new/layouts/header', $data);

		$this->load->view('admin_new/products/transfer_stock');

		$this->load->view('admin_new/layouts/footer');

	}

	function list_transfer_stock()

	{

		$data['userdata'] = $this->session->userdata();

		$data['warehouses'] = $this->warehouse_m->fetch_all_warehouses();

		$data['products'] = [];

		$data['shippingMethods'] = $this->product_m->get_all_shipping_methods();





		$data['title'] = 'Daftar Transfer Stok | Laciasmara';



		$this->load->view('admin_new/layouts/header', $data);

		$this->load->view('admin_new/products/list_transfer_stock');

		$this->load->view('admin_new/layouts/footer');

	}



	function get_warehouse_products()

	{

		$warehouse_id = $this->input->post('warehouse_id');



		if (!$warehouse_id) {

			echo json_encode(['error' => 'Warehouse ID is required']);

			return;

		}



		$products = $this->product_m->get_products_by_warehouse($warehouse_id);

		echo json_encode($products);

	}



	// Data

	// Fetch Product Data

	public function get_products()

	{

		// Ambil parameter GET dengan validasi dasar

		$tab = $this->input->get('tab', true);

		$isEmptyStockOnly = filter_var($this->input->get('isEmptyStockOnly', true), FILTER_VALIDATE_BOOLEAN);

		$isLowStock = filter_var($this->input->get('isLowStock', true), FILTER_VALIDATE_BOOLEAN);

		$isNewProduct = filter_var($this->input->get('isNewProduct', true), FILTER_VALIDATE_BOOLEAN);

		$isDiscounted = filter_var($this->input->get('isDiscounted', true), FILTER_VALIDATE_BOOLEAN);

		$isBestSelling = filter_var($this->input->get('isBestSelling', true), FILTER_VALIDATE_BOOLEAN);

		$brandId = $this->input->get('merk', true);

		$categoryId = $this->input->get('kategori', true);

		$sort = $this->input->get('sort', true);



		$searchTerm = $this->input->get('search', true);



		// Query utama untuk mendapatkan produk

		$this->db->select('

			p.title,

			p.alias,

			p.product_status,

			p.id_products,

			p.created_at,

			p.updated_at,

			pd.id as product_detail_id,

			MIN(pd.price) as min_price,

			MAX(pd.price) as max_price,

			CASE 

				WHEN COUNT(pd.id) > 1 THEN "-"

				ELSE MAX(pd.sku)

			END as sku,

			pi.image as image,

			s.stock as total_stock,

			b.brand as brand_title,

			COALESCE(od_count.total_sold, 0) as total_sold

		');

		$this->db->from('products p');

		$this->db->join('product_details pd', 'pd.product_id = p.id_products', 'left');

		$this->db->join('stock s', 'pd.id = s.id_product_detail AND s.warehouse_id = 1', 'left');

		$this->db->join('brands b', 'p.brand_id = b.id_brands', 'left');

		$this->db->join('product_images pi', 'pi.product_details_id = pd.id AND pi.priority = 1 AND pi.status = 1', 'left');

		$this->db->join('category_product cp', 'cp.id_product = p.id_products', 'left');

		$this->db->join('(

			SELECT od.product_id, COUNT(*) as total_sold 

			FROM orders_detail od

			JOIN orders o ON od.orders_id = o.id_orders

			WHERE o.payment_status = 5

			GROUP BY od.product_id

		) as od_count', 'p.id_products = od_count.product_id', 'left');

		$this->db->where('p.deleted_at', null);

		if ($tab === 'active') {

			$this->db->where('p.product_status', '1');

		} elseif ($tab === 'inactive') {

			$this->db->where('p.product_status', '0');

		}



		// 1. **Filter untuk produk dengan stok kosong**

		if ($isEmptyStockOnly) {

			$this->db->having('total_stock = 0');

		}



		// 2. **Filter untuk produk dengan stok rendah (≤ 5)**

		if ($isLowStock) {

			$this->db->having('total_stock > 0 AND total_stock < 5');

		}



		// 3. **Filter untuk produk baru (dalam 30 hari terakhir)**

		if ($isNewProduct) {

			$this->db->where("p.created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)");

		}



		// 4. **Filter untuk produk dengan diskon (discounted_price > 0)**

		if ($isDiscounted) {

			$this->db->where("p.id_products IN (

				SELECT pd.product_id FROM product_details pd

				WHERE pd.discounted_price > 0

			)");

		}



		// 5. **Filter untuk produk terlaris (paling banyak dibeli di orders_detail)**

		if ($isBestSelling) {

			$this->db->join("(

				SELECT od.product_id 

				FROM orders_detail od

				JOIN orders o ON od.orders_id = o.id_orders

				WHERE o.payment_status = 5

				GROUP BY od.product_id 

				ORDER BY COUNT(*) DESC 

				LIMIT 10

			) AS best_selling", "p.id_products = best_selling.product_id");

		}





		// Brand

		if (!empty($brandId)) {

			$this->db->where('p.brand_id', $brandId);

		}



		// Category

		if (!empty($categoryId)) {

			$this->db->where('cp.id_category', $categoryId);

		}



		if (!empty($searchTerm)) {

			$this->db->group_start();

			$this->db->like('p.title', $searchTerm);

			$this->db->or_like('pd.sku', $searchTerm);

			$this->db->or_like('b.brand', $searchTerm);

			$this->db->or_like('p.id_products', $searchTerm);

			$this->db->or_like('pd.id', $searchTerm);

			$this->db->group_end();

		}



		// Sort

		switch ($sort) {

			case 'baru':

				$this->db->order_by('created_at', 'DESC');

				break;

			case 'baru-diubah':

				$this->db->order_by('updated_at', 'DESC');

				break;

			case 'terlaris':

				$this->db->order_by('total_sold', 'DESC');

				break;



			case 'kurang-diminati':

				$this->db->order_by('total_sold', 'ASC');

				break;



			case 'harga-tertinggi':

				$this->db->order_by('max_price', 'DESC');

				break;



			case 'harga-terendah':

				$this->db->order_by('min_price', 'ASC');

				break;



			case 'nama-az':

				$this->db->order_by('p.title', 'ASC');

				break;



			case 'nama-za':

				$this->db->order_by('p.title', 'DESC');

				break;



			case 'stok-terbanyak':

				$this->db->order_by('total_stock', 'DESC');

				break;



			case 'stok-tersedikit':

				$this->db->order_by('total_stock', 'ASC');

				break;

		}



		$this->db->group_by('p.id_products');



		$query = $this->db->get();

		$all_products = $query->result();



		// Post-processing

		foreach ($all_products as $product) {

			// Process price range

			if (!empty($product->min_price) && !empty($product->max_price)) {

				$product->price = ($product->min_price == $product->max_price) ? $product->min_price : $product->min_price . ' - ' . $product->max_price;

			} else {

				$product->price = 'N/A';

			}

			unset($product->min_price, $product->max_price);



			// Ambil detail produk dengan variannya

			$this->db->select('

				pd.id as product_detail_id,

				pd.sku,

				pd.price,

				COALESCE(s.stock, 0) as stock,

				pd.discounted_price,

				GROUP_CONCAT(

					CONCAT_WS(": ", pa.product_attribute, pad.attribute_detail)

					SEPARATOR ", "

				) as variants,

				pa.product_attribute as attribute,

				pad.attribute_detail as attribute_detail

			');

			$this->db->from('product_details pd');

			$this->db->join('product_combination pc', 'pc.product_details_id = pd.id', 'left');

			$this->db->join('product_attributes pa', 'pc.attribute_id = pa.id', 'left');

			$this->db->join('product_attributes_detail pad', 'pc.attribute_detail_id = pad.id', 'left');

			$this->db->join('stock s', 'pd.id = s.id_product_detail', 'left');

			$this->db->where('pd.product_id', $product->id_products);

			$this->db->group_by('pd.id');

			$this->db->order_by('pd.id', 'ASC');



			$variants_query = $this->db->get();

			$product->variants = $variants_query->result();



			// unset($product->id_products);

		}



		echo json_encode($all_products);

	}



	// Fetch Attribute Options Data

	public function get_attribute_options()

	{

		$attribute_id = $this->input->get('attribute_id');

		if (!$attribute_id) {

			echo json_encode([]);

			return;

		}



		$options = $this->product_m->get_attribute_options($attribute_id);

		echo json_encode($options);

	}



	// Update attribute priority

	public function update_attribute_priority()

	{

		// Ambil data yang dikirim dari FormData

		$order = $this->input->post('order');



		if (!empty($order)) {

			foreach ($order as $item) {

				$this->db->where('id', $item['id'])

					->update('product_attributes', ['priority' => $item['priority']]);

			}



			// Kirim response dengan CSRF token baru

			echo json_encode([

				'message' => 'Priority updated successfully',

				'csrf_token' => $this->security->get_csrf_hash()

			]);

		} else {

			echo json_encode([

				'message' => 'No data received',

				'csrf_token' => $this->security->get_csrf_hash()

			]);

		}

	}



	// Update attribute value

	public function update_attribute_value_priority()

	{

		// Ambil data yang dikirim dari FormData

		$order = $this->input->post('order');



		if (!empty($order)) {

			foreach ($order as $item) {

				$this->db->where('id', $item['id'])

					->update('product_attributes_detail', ['priority' => $item['priority']]);

			}



			// Kirim response dengan CSRF token baru

			echo json_encode([

				'message' => 'Priority updated successfully',

				'csrf_token' => $this->security->get_csrf_hash()

			]);

		} else {

			echo json_encode([

				'message' => 'No data received',

				'csrf_token' => $this->security->get_csrf_hash()

			]);

		}

	}





	// Update Price

	public function updatePrice()

	{

		if (!$this->input->is_ajax_request()) {

			show_error('No direct script access allowed', 403);

			return;

		}

		// Ambil data dari POST

		$product_detail_id = $this->input->post('product_detail_id');

		$price = intval($this->input->post('price'));



		// Update harga produk

		$this->db->where('id', $product_detail_id);

		$update = $this->db->update('product_details', ['price' => $price]);



		echo json_encode(["success" => $update]);

	}



	// Update Stock

	public function updateStock()

	{

		// Cek apakah ini AJAX request

		if (!$this->input->is_ajax_request()) {

			show_error('No direct script access allowed', 403);

			return;

		}



		// Ambil data dari POST

		$product_detail_id = $this->input->post('product_detail_id');

		$stock = intval($this->input->post('stock'));



		// Update stok produk di warehouse_id = 1

		$this->db->where('id_product_detail', $product_detail_id);

		$this->db->where('warehouse_id', 1); // Pastikan hanya mengupdate di warehouse_id = 1

		$update = $this->db->update('stock', ['stock' => $stock]);



		// Cek apakah update berhasil

		if ($update) {

			echo json_encode(["success" => true, "message" => "Stock updated successfully"]);

		} else {

			echo json_encode(["success" => false, "message" => "Failed to update stock"]);

		}

	}





	// Update Stock in stock page

	public function update_stock()

	{

		// Cek apakah ini AJAX request

		if (!$this->input->is_ajax_request()) {

			show_error('No direct script access allowed', 403);

			return;

		}



		// Ambil data dari POST

		$product_detail_id = $this->input->post('product_detail_id');

		$warehouse_id = $this->input->post('warehouse_id');

		$stock_type = $this->input->post('stock_type'); // stock, stock_keep, stock_reject, stock_sample

		$action = $this->input->post('action'); // add or subtract

		$amount = intval($this->input->post('amount'));

		$note = $this->input->post('note');

		$user_name = $this->session->userdata('name');



		// Validasi input

		if (

			empty($product_detail_id) || empty($warehouse_id) || empty($stock_type) ||

			empty($action) || $amount <= 0 || empty($note)

		) {

			echo json_encode(["success" => false, "message" => "Data tidak lengkap"]);

			return;

		}



		// Get current stock information

		$this->db->select('id, id_product, stock, stock_keep, stock_reject, stock_sample');

		$this->db->where('id_product_detail', $product_detail_id);

		$this->db->where('warehouse_id', $warehouse_id);

		$current_stock = $this->db->get('stock')->row();



		if (!$current_stock) {

			echo json_encode(["success" => false, "message" => "Data stok tidak ditemukan"]);

			return;

		}



		// Proses update berdasarkan jenis stok dan aksi

		$old_value = 0;

		$new_value = 0;

		$update_data = [];

		$movement_table = 'stock_movement'; // Tabel default



		try {

			$this->db->trans_start(); // Mulai transaksi database



			switch ($stock_type) {

				case 'stock':

					$old_value = intval($current_stock->stock);

					$new_value = ($action === 'add') ? $old_value + $amount : $old_value - $amount;



					// Cek jika stok akan menjadi negatif

					if ($new_value < 0) {

						echo json_encode(["success" => false, "message" => "Stok tidak cukup"]);

						return;

					}



					$update_data['stock'] = $new_value;

					$movement_table = 'stock_movement';

					break;



				case 'stock_keep':

					$old_value = intval($current_stock->stock_keep);

					$new_value = ($action === 'add') ? $old_value + $amount : $old_value - $amount;



					// Cek jika stok akan menjadi negatif

					if ($new_value < 0) {

						echo json_encode(["success" => false, "message" => "Stok keep tidak cukup"]);

						return;

					}



					$update_data['stock_keep'] = $new_value;

					$movement_table = 'stock_movement_keep';

					break;



				case 'stock_reject':

					$old_value = intval($current_stock->stock_reject);

					$new_value = ($action === 'add') ? $old_value + $amount : $old_value - $amount;



					// Cek jika stok akan menjadi negatif

					if ($new_value < 0) {

						echo json_encode(["success" => false, "message" => "Stok reject tidak cukup"]);

						return;

					}



					$update_data['stock_reject'] = $new_value;

					$movement_table = 'stock_movement_reject';

					break;



				case 'stock_sample':

					$old_value = intval($current_stock->stock_sample);

					$new_value = ($action === 'add') ? $old_value + $amount : $old_value - $amount;



					// Cek jika stok akan menjadi negatif

					if ($new_value < 0) {

						echo json_encode(["success" => false, "message" => "Stok sample tidak cukup"]);

						return;

					}



					$update_data['stock_sample'] = $new_value;

					$movement_table = 'stock_movement_sample';

					break;



				default:

					echo json_encode(["success" => false, "message" => "Tipe stok tidak valid"]);

					return;

			}



			// Update stok di database

			$this->db->where('id_product_detail', $product_detail_id);

			$this->db->where('warehouse_id', $warehouse_id);

			$update = $this->db->update('stock', $update_data);



			if (!$update) {

				$this->db->trans_rollback();

				echo json_encode(["success" => false, "message" => "Gagal mengupdate stok"]);

				return;

			}



			// Catat pergerakan stok ke tabel yang sesuai

			$type = ($action === 'add') ? '+' : '-';

			$stock_movement = [

				'stock_id' => $current_stock->id,

				'type' => $type,

				'stock_change' => $amount,

				'remark' => $note,

				'total' => $new_value,

				'name' => $user_name,

				'stock_type' => $stock_type

			];



			$movement_insert = $this->db->insert($movement_table, $stock_movement);



			if (!$movement_insert) {

				$this->db->trans_rollback();

				echo json_encode(["success" => false, "message" => "Gagal mencatat pergerakan stok"]);

				return;

			}



			$this->db->trans_commit(); // Commit transaksi jika semua berhasil



			// Return response sukses

			echo json_encode([

				"success" => true,

				"message" => "Stok berhasil diperbarui",

				"csrf_token" => $this->security->get_csrf_hash(),

				"data" => [

					"old_value" => $old_value,

					"new_value" => $new_value,

					"difference" => $amount,

					"action" => $action,

					"stock_type" => $stock_type

				]

			]);

		} catch (Exception $e) {

			$this->db->trans_rollback();

			log_message('error', 'Update Stock Error: ' . $e->getMessage());

			echo json_encode(["success" => false, "message" => "Terjadi kesalahan: " . $e->getMessage()]);

		}

	}



	/**

	 * Get stock mutation data based on stock type

	 * 

	 * @return json

	 */

	public function get_mutation_data()

	{

		// Cek apakah ini AJAX request

		if (!$this->input->is_ajax_request()) {

			show_error('No direct script access allowed', 403);

			return;

		}



		// Ambil parameter yang dikirim

		$product_detail_id = $this->input->post('product_detail_id') ?? null;

		$warehouse_id      = $this->input->post('warehouse_id') ?? null;

		$stock_type        = $this->input->post('stock_type') ?? null;





		// Validasi parameter

		if (empty($product_detail_id) || empty($warehouse_id)) {

			echo json_encode([

				'status' => 'error',

				'message' => 'Parameter tidak lengkap'

			]);

			return;

		}



		try {

			// Dapatkan stock_id dari tabel stock

			$this->db->select('id');

			$this->db->where('id_product_detail', $product_detail_id);

			$this->db->where('warehouse_id', $warehouse_id);

			$stock_query = $this->db->get('stock');



			if ($stock_query->num_rows() == 0) {

				echo json_encode([

					'status' => 'error',

					'message' => 'Data stok tidak ditemukan'

				]);

				return;

			}



			$stock_id = $stock_query->row()->id;



			// Tentukan tabel yang akan digunakan berdasarkan jenis stok

			$table_name = '';

			switch ($stock_type) {

				case 'stock':

					$table_name = 'stock_movement';

					break;

				case 'stock_keep':

					$table_name = 'stock_movement_keep';

					break;

				case 'stock_reject':

					$table_name = 'stock_movement_reject';

					break;

				case 'stock_sample':

					$table_name = 'stock_movement_sample';

					break;

				default:

					echo json_encode([

						'status' => 'error',

						'message' => 'Tipe stok tidak valid'

					]);

					return;

			}



			// Query untuk mengambil data mutasi stok

			$this->db->select('

				id,

				stock_id,

				type,

				stock_change as amount,

				total as total_stock,

				remark as notes,

				name as admin_name,

				datetime,

				stock_type

			');

			$this->db->where('stock_id', $stock_id);

			$this->db->order_by('datetime', 'DESC');

			$mutations = $this->db->get($table_name)->result_array();



			// Tambahkan informasi waktu untuk setiap data

			foreach ($mutations as &$mutation) {

				if (isset($mutation['datetime']) && $mutation['datetime'] !== null && $mutation['datetime'] !== '') {

					try {

						$date = new DateTime($mutation['datetime']);

						$mutation['datetime'] = $date->format('Y-m-d H:i:s');

					} catch (Exception $e) {

						$mutation['datetime'] = '-';

					}

				} else {

					// Jika datetime kosong atau null, berikan nilai default

					$mutation['datetime'] = '-';

				}



				// Map tipe mutasi untuk tampilan yang lebih baik

				if (isset($mutation['type'])) {

					if ($mutation['type'] === '+') {

						$mutation['type'] = 'add';

					} else if ($mutation['type'] === '-') {

						$mutation['type'] = 'subtract';

					}

				}

			}



			// Return data dalam format JSON

			echo json_encode([

				'status' => 'success',

				'message' => 'Data berhasil diambil',

				'data' => $mutations,

				'csrf_token' => $this->security->get_csrf_hash()

			]);

		} catch (Exception $e) {

			log_message('error', 'Get Stock Mutation Error: ' . $e->getMessage());

			echo json_encode([

				'status' => 'error',

				'message' => 'Terjadi kesalahan: ' . $e->getMessage()

			]);

		}

	}



	// Update Status

	public function updateStatus()

	{

		if (!$this->input->is_ajax_request()) {

			show_error('No direct script access allowed', 403);

			return;

		}

		// Ambil data dari POST

		$product_id = $this->input->post('product_id');

		$new_status = $this->input->post('new_status');



		// Update harga produk

		$this->db->where('id_products', $product_id);

		$update = $this->db->update('products', ['product_status' => $new_status]);



		echo json_encode(["success" => $update]);

	}



	// Delete Product

	public function delete_product($id)

	{

		if (!$id || !is_numeric($id)) {

			echo json_encode(["success" => false, "message" => "ID produk tidak valid."]);

			return;

		}



		$this->db->where('id_products', $id);

		$this->db->where('deleted_at', null);

		$product = $this->db->get('products')->row();



		if (!$product) {

			echo json_encode(["success" => false, "message" => "Produk tidak ditemukan atau sudah dihapus."]);

			return;

		}



		$this->db->where('id_products', $id);

		$updateSuccess = $this->db->update('products', ['deleted_at' => date('Y-m-d H:i:s')]);



		if ($updateSuccess) {

			echo json_encode(["success" => true, "message" => "Produk berhasil dihapus."]);

		} else {

			echo json_encode(["success" => false, "message" => "Gagal menghapus produk, coba lagi nanti."]);

		}

	}





	// Delete Attribute

	public function delete_attribute($id)

	{



		// Validasi ID atribut

		if (!$id || !is_numeric($id)) {

			echo json_encode(["success" => false, "message" => "ID atribut tidak valid."]);

			return;

		}



		// Memeriksa apakah atribut ada

		$attribute = $this->db->where('id', $id)->get('product_attributes')->row();



		if (!$attribute) {

			echo json_encode(["success" => false, "message" => "Atribut tidak ditemukan."]);

			return;

		}



		// Hapus atribut

		$this->db->where('id', $id);

		$deleteSuccess = $this->db->delete('product_attributes');



		if ($deleteSuccess) {

			echo json_encode([

				"success" => true,

				"message" => "Atribut berhasil dihapus.",

				"csrf_token" => $this->security->get_csrf_hash() // Perbarui CSRF token

			]);

		} else {

			echo json_encode([

				"success" => false,

				"message" => "Gagal menghapus atribut, coba lagi nanti.",

				"csrf_token" => $this->security->get_csrf_hash()

			]);

		}

	}



	// Delete Attribute

	public function delete_attribute_value($id)

	{

		// Validasi ID atribut

		if (!$id || !is_numeric($id)) {

			echo json_encode(["success" => false, "message" => "ID atribut tidak valid."]);

			return;

		}



		// Ambil data yang akan dihapus

		$attribute = $this->db->where('id', $id)->get('product_attributes_detail')->row();



		if (!$attribute) {

			echo json_encode(["success" => false, "message" => "Opsi atribut tidak ditemukan."]);

			return;

		}



		$product_attribute_id = $attribute->product_attribute_id;



		// Hapus atribut

		$this->db->where('id', $id);

		$deleteSuccess = $this->db->delete('product_attributes_detail');



		if ($deleteSuccess) {

			// Ambil semua ID dalam urutan yang benar setelah penghapusan

			$query = $this->db->select('id')

				->where('product_attribute_id', $product_attribute_id)

				->order_by('priority', 'ASC')

				->get('product_attributes_detail');



			$attributes = $query->result();

			$newPriority = 1;



			// Update priority satu per satu

			foreach ($attributes as $attr) {

				$this->db->where('id', $attr->id)

					->update('product_attributes_detail', ['priority' => $newPriority]);

				$newPriority++;

			}



			echo json_encode([

				"success" => true,

				"message" => "Opsi Atribut berhasil dihapus dan priority telah diperbarui.",

				"csrf_token" => $this->security->get_csrf_hash()

			]);

		} else {

			echo json_encode([

				"success" => false,

				"message" => "Gagal menghapus opsi atribut, coba lagi nanti.",

				"csrf_token" => $this->security->get_csrf_hash()

			]);

		}

	}





	// Process Add Product 

	public function store()

	{

		// Ambil data dari POST

		$data = $this->input->post();



		// Format alias dari product name

		$alias = preg_replace('/[^a-zA-Z0-9\s]/', '', $data['productName']); // Remove special characters

		$alias = preg_replace('/\s+/', ' ', $alias); // Replace multiple spaces with a single space

		$alias = str_replace(' ', '-', $alias); // Replace spaces with hyphens

		$alias = strtolower($alias);



		// Check if the 'restock' checkbox is set (checked), otherwise set default value to '0'

		$restock = isset($data['restock']) && $data['restock'] == '1' ? 'yes' : 'no';





		// Siapkan data untuk table products

		$product_data = [

			'title' => $data['productName'],

			'alias' => $alias,

			'brand_id' => (int)$data['brand'],

			'product_status' => isset($data['status']) ? (string)$data['status'] : '0',

			'description' => $data['short_desc_id'],

			'description_en' => $data['short_desc_en'],

			'long_description' => $data['full_desc_id'],

			'long_description_en' => $data['full_desc_en'],

			'meta_description' => $data['seoMetaDescription'],

			'meta_title' => $data['seoTitle'],

			'restock' => $restock,

			'media_file_link' => $data['linkMedia'] ? $data['linkMedia'] : null,

			'product_video_link' => $data['productVideo'] ? $data['productVideo'] : null,

			'product_guide_link' => $data['guideVideo'] ? $data['guideVideo'] : null,

			'product_suggest' => isset($data['productRecommendation']) && is_array($data['productRecommendation'])

				? implode(',', array_map('intval', $data['productRecommendation']))

				: null,

			'created_at' => date('Y-m-d H:i:s')

		];



		// Begin transaction

		$this->db->trans_begin();



		try {

			// Insert product

			$this->db->insert('products', $product_data);

			$product_id = $this->db->insert_id();



			// Insert categories

			$category_data = [];



			if (!empty($data['categories']) && is_array($data['categories'])) {

				foreach ($data['categories'] as $category_id) {

					$category_data[] = [

						'id_product' => $product_id,

						'id_category' => $category_id

					];

				}



				if (!empty($category_data)) {

					$this->db->insert_batch('category_product', $category_data);

				}

			}



			// Insert shipping methods

			$shipping_data = [];



			if (!empty($data['shippingMethod']) && is_array($data['shippingMethod'])) {

				foreach ($data['shippingMethod'] as $shipment_id) {

					$shipping_data[] = [

						'product_id' => $product_id,

						'shipment_method_id' => $shipment_id

					];

				}



				if (!empty($shipping_data)) {

					$this->db->insert_batch('shipment_method_product', $shipping_data);

				}

			}





			// Process variants

			if (isset($data['selected_variant_data']) && isset($data['selected_variant'])) {

				$selected_variant_data = json_decode($data['selected_variant_data'], true);

				$selected_variants = explode(',', $data['selected_variant']);



				foreach ($selected_variant_data as $index => $variant) {

					// Insert product details

					$product_details_data = [

						'product_id' => $product_id,

						'sku' => $variant['sku'],

						'weight' => $variant['berat'],

						'price' => $variant['harga'],

						'length' => $variant['panjang'],

						'width' => $variant['lebar'],

						'height' => $variant['tinggi'],

						'is_indent' => 'no' // default value, adjust if needed

					];



					$this->db->insert('product_details', $product_details_data);

					$product_details_id = $this->db->insert_id();



					// Insert product combination

					$product_combination_data = [

						'product_id' => $product_id,

						'product_details_id' => $product_details_id,

						'attribute_id' => $data['variant_type'],

						'attribute_detail_id' => $variant['variant_id']

					];



					$this->db->insert('product_combination', $product_combination_data);



					// Insert stock data for each variant

					$stock_data = [

						'id_product' => $product_id,

						'id_product_detail' => $product_details_id,

						'warehouse_id' => 1, // assuming warehouse_id is 1

						'stock' => $data['variant_stock'][$index], // getting the stock value from variant_stock array

						'stock_keep' => 0,  // Set default values as needed

						'stock_reject' => 0 // Set default values as needed

					];



					$this->db->insert('stock', $stock_data);

				}

			} else {

				// Handle the case where the selected_variant_data is not a valid JSON string or empty

				echo "Invalid or empty selected_variant_data.";

			}







			// Commit transaction

			if ($this->db->trans_status() === FALSE) {

				throw new Exception('Transaction failed');

			}

			$this->db->trans_commit();



			$this->session->set_flashdata('message', 'Product successfully added');

			$this->session->set_flashdata('message_type', 'success');



			// Redirect to manage-product page

			redirect('admin/products/manage-product');

		} catch (Exception $e) {

			// Rollback transaction if failed

			$this->db->trans_rollback();



			$this->session->set_flashdata('message', 'Failed to add product: ' . $e->getMessage());

			$this->session->set_flashdata('message_type', 'error');



			// Redirect to manage-product page

			redirect('admin/products/add-product');

		}

	}



	// Store Variant

	public function store_variant()

	{

		// Ambil data dari POST

		$data = $this->input->post();



		// Validasi input (Pastikan nama atribut tidak kosong)

		if (empty($data['idAttributeName']) || empty($data['enAttributeName'])) {

			$this->session->set_flashdata('message', 'Nama atribut dalam dua bahasa wajib diisi.');

			$this->session->set_flashdata('message_type', 'error');

			redirect('admin/products/add-variant');

			return;

		}



		// Sanitasi input

		$idAttributeName = htmlspecialchars($data['idAttributeName']);

		$enAttributeName = htmlspecialchars($data['enAttributeName']);



		// Periksa apakah atribut sudah ada dalam database

		$this->db->where('product_attribute', $idAttributeName);

		$this->db->or_where('product_attribute_en', $enAttributeName);

		$query = $this->db->get('product_attributes');



		if ($query->num_rows() > 0) {

			// Jika sudah ada, kirim pesan error

			$this->session->set_flashdata('message', 'Nama atribut sudah digunakan. Coba pakai nama yang lain.');

			$this->session->set_flashdata('message_type', 'error');

			redirect('admin/products/add-variant');

			return;

		}



		// Tentukan apakah atribut ini warna atau tidak

		$is_color = isset($data['isColor']) && $data['isColor'] == '1' ? 'yes' : 'no';



		// Ambil nilai priority terakhir

		$this->db->select_max('priority');

		$query = $this->db->get('product_attributes');

		$row = $query->row();



		// Jika ada hasil, tambahkan +1, jika tidak, mulai dari 1

		$priority = $row ? ($row->priority + 1) : 1;



		// Siapkan data untuk dimasukkan ke tabel `product_attributes`

		$attribute_data = [

			'product_attribute' => $idAttributeName,

			'product_attribute_en' => $enAttributeName,

			'is_color' => $is_color,

			'priority' => $priority

		];



		// Mulai transaksi

		$this->db->trans_begin();



		try {

			// Simpan data ke tabel `product_attributes`

			$this->db->insert('product_attributes', $attribute_data);



			// Commit transaksi

			if ($this->db->trans_status() === FALSE) {

				throw new Exception('Gagal menyimpan atribut.');

			}

			$this->db->trans_commit();



			// Redirect dengan pesan sukses

			$this->session->set_flashdata('message', 'Atribut berhasil ditambahkan.');

			$this->session->set_flashdata('message_type', 'success');

			redirect('admin/products/variant-product');

		} catch (Exception $e) {

			// Rollback transaksi jika terjadi kesalahan

			$this->db->trans_rollback();



			$this->session->set_flashdata('message', 'Gagal menambahkan atribut: ' . $e->getMessage());

			$this->session->set_flashdata('message_type', 'error');

			redirect('admin/products/add-variant');

		}

	}



	// Store Variant Value

	public function store_variant_value()

	{

		$this->output->set_content_type('application/json');



		// Validasi input

		$product_attribute_id = $this->input->post("product_attribute_id");

		$attribute_detail = $this->input->post("attribute_detail");

		$attribute_detail_en = $this->input->post("attribute_detail_en");

		$color_hex = $this->input->post("color_hex");



		if (empty($product_attribute_id) || empty($attribute_detail) || empty($attribute_detail_en)) {

			echo json_encode(["success" => false, "message" => "Data tidak lengkap!"]);

			return;

		}



		// Ambil priority terakhir dari product_attribute_id ini

		$this->db->select_max("priority");

		$this->db->where("product_attribute_id", $product_attribute_id);

		$query = $this->db->get("product_attributes_detail");

		$row = $query->row();

		$priority = ($row && $row->priority !== null) ? $row->priority + 1 : 1;



		// Data yang akan dimasukkan ke database

		$insertData = [

			"product_attribute_id" => $product_attribute_id,

			"attribute_detail" => htmlspecialchars($attribute_detail),

			"attribute_detail_en" => htmlspecialchars($attribute_detail_en),

			"color_hex" => $color_hex ? htmlspecialchars($color_hex) : null,

			"priority" => $priority

		];



		// Simpan ke database

		if ($this->db->insert("product_attributes_detail", $insertData)) {

			echo json_encode(["success" => true, "message" => "Data berhasil disimpan"]);

		} else {

			echo json_encode(["success" => false, "message" => "Gagal menyimpan data"]);

		}

	}



	// Process Update Product

	public function update($id_products)

	{

		// Pastikan produk ada sebelum melakukan update

		$product_exists = $this->db->get_where('products', ['id_products' => $id_products])->row();

		if (!$product_exists) {

			$this->session->set_flashdata('message', 'Product not found.');

			$this->session->set_flashdata('message_type', 'error');

			redirect('admin/products/manage-product');

			return;

		}



		// Ambil data dari POST dan sanitasi

		$data = $this->input->post();



		if (!isset($data['productName'])) {

			$this->session->set_flashdata('message', 'Product name is required.');

			$this->session->set_flashdata('message_type', 'error');

			redirect('admin/products/edit_product/' . $id_products);

			return;

		}



		$alias = strtolower(trim(preg_replace('/[^a-zA-Z0-9]+/', '-', $data['productName']), '-'));



		$restock = isset($data['restock']) && $data['restock'] == '1' ? 'yes' : 'no';



		$product_data = [

			'title' => $data['productName'],

			'alias' => $alias,

			'brand_id' => isset($data['brand']) ? (int)$data['brand'] : null,

			'product_status' => isset($data['status']) ? (string)$data['status'] : '0',

			'description' => $data['short_desc_id'],

			'description_en' => $data['short_desc_en'],

			'long_description' => $data['full_desc_id'],

			'long_description_en' => $data['full_desc_en'],

			'meta_description' => $data['seoMetaDescription'],

			'meta_title' => $data['seoTitle'],

			'restock' => $restock,

			'media_file_link' => !empty($data['linkMedia']) ? $data['linkMedia'] : null,

			'product_video_link' => !empty($data['productVideo']) ? $data['productVideo'] : null,

			'product_guide_link' => !empty($data['guideVideo']) ? $data['guideVideo'] : null,

			'product_suggest' => isset($data['productRecommendation']) && is_array($data['productRecommendation'])

				? implode(',', array_map('intval', $data['productRecommendation']))

				: null,

			'updated_at' => date('Y-m-d H:i:s')

		];



		$this->db->trans_begin();



		try {

			// Update produk

			$this->db->where('id_products', $id_products);

			$this->db->update('products', $product_data);



			// **Update Kategori Produk**

			if (!empty($data['categories']) && is_array($data['categories'])) {

				$this->db->delete('category_product', ['id_product' => $id_products]);



				$category_data = array_map(function ($category_id) use ($id_products) {

					return ['id_product' => $id_products, 'id_category' => $category_id];

				}, $data['categories']);



				$this->db->insert_batch('category_product', $category_data);

			}



			// **Update Metode Pengiriman**

			if (!empty($data['shippingMethod']) && is_array($data['shippingMethod'])) {

				$this->db->delete('shipment_method_product', ['product_id' => $id_products]);



				$shipping_data = array_map(function ($shipment_id) use ($id_products) {

					return ['product_id' => $id_products, 'shipment_method_id' => $shipment_id];

				}, $data['shippingMethod']);



				$this->db->insert_batch('shipment_method_product', $shipping_data);

			}



			// **Update Variasi Produk**

			if (isset($data['selected_variant_data']) && isset($data['selected_variant'])) {

				$selected_variant_data = json_decode($data['selected_variant_data'], true);

				$variant_ids = array_column($selected_variant_data, 'variant_id');



				// Dapatkan data variasi yang ada

				$existing_variants = $this->db->get_where('product_combination', [

					'product_id' => $id_products

				])->result_array();



				$existing_variant_details = [];

				foreach ($existing_variants as $variant) {

					$existing_variant_details[$variant['attribute_detail_id']] = $variant['product_details_id'];

				}



				// Hapus variasi yang tidak ada lagi dalam data baru

				$variants_to_keep = $variant_ids;

				$variants_to_remove = array_diff(array_keys($existing_variant_details), $variants_to_keep);



				if (!empty($variants_to_remove)) {

					foreach ($variants_to_remove as $variant_id) {

						$product_details_id = $existing_variant_details[$variant_id];



						// Hapus stok untuk variasi yang dihapus

						$this->db->delete('stock', [

							'id_product' => $id_products,

							'id_product_detail' => $product_details_id

						]);



						// Hapus kombinasi produk untuk variasi yang dihapus

						$this->db->delete('product_combination', [

							'product_id' => $id_products,

							'attribute_detail_id' => $variant_id

						]);



						// Hapus detail produk untuk variasi yang dihapus

						$this->db->delete('product_details', [

							'id' => $product_details_id

						]);

					}

				}



				// Update atau tambahkan variasi baru

				foreach ($selected_variant_data as $index => $variant) {

					$variant_id = (int)$variant['variant_id'];



					if (isset($existing_variant_details[$variant_id])) {

						// Update variasi yang sudah ada

						$product_details_id = $existing_variant_details[$variant_id];



						$product_details_data = [

							'sku' => htmlspecialchars($variant['sku']),

							'weight' => (float)$variant['berat'],

							'price' => (float)$variant['harga'],

							'length' => (float)$variant['panjang'],

							'width' => (float)$variant['lebar'],

							'height' => (float)$variant['tinggi'],

							'is_indent' => 'no'

						];



						$this->db->where('id', $product_details_id);

						$this->db->update('product_details', $product_details_data);



						// Update stok jika ada

						if (isset($data['variant_stock'][$index])) {

							$stock_exists = $this->db->get_where('stock', [

								'id_product' => $id_products,

								'id_product_detail' => $product_details_id

							])->row();



							$stock_data = [

								'stock' => (int)$data['variant_stock'][$index]

							];



							if ($stock_exists) {

								$this->db->where('id_product', $id_products);

								$this->db->where('id_product_detail', $product_details_id);

								$this->db->update('stock', $stock_data);

							} else {

								$stock_data['id_product'] = $id_products;

								$stock_data['id_product_detail'] = $product_details_id;

								$stock_data['warehouse_id'] = 1;

								$stock_data['stock_keep'] = 0;

								$stock_data['stock_reject'] = 0;

								$this->db->insert('stock', $stock_data);

							}

						}

					} else {

						// Tambahkan variasi baru

						$product_details_data = [

							'product_id' => $id_products,

							'sku' => htmlspecialchars($variant['sku']),

							'weight' => (float)$variant['berat'],

							'price' => (float)$variant['harga'],

							'length' => (float)$variant['panjang'],

							'width' => (float)$variant['lebar'],

							'height' => (float)$variant['tinggi'],

							'is_indent' => 'no'

						];



						$this->db->insert('product_details', $product_details_data);

						$product_details_id = $this->db->insert_id();



						$product_combination_data = [

							'product_id' => $id_products,

							'product_details_id' => $product_details_id,

							'attribute_id' => isset($data['variant_type']) ? (int)$data['variant_type'] : null,

							'attribute_detail_id' => $variant_id

						];



						$this->db->insert('product_combination', $product_combination_data);



						if (isset($data['variant_stock'][$index])) {

							$stock_data = [

								'id_product' => $id_products,

								'id_product_detail' => $product_details_id,

								'warehouse_id' => 1,

								'stock' => (int)$data['variant_stock'][$index],

								'stock_keep' => 0,

								'stock_reject' => 0

							];

							$this->db->insert('stock', $stock_data);

						}

					}

				}

			}



			if ($this->db->trans_status() === FALSE) {

				throw new Exception('Transaction failed.');

			}



			$this->db->trans_commit();

			$this->session->set_flashdata('message', 'Product successfully updated.');

			$this->session->set_flashdata('message_type', 'success');

			redirect('admin/products/manage-product');

		} catch (Exception $e) {

			$this->db->trans_rollback();

			$this->session->set_flashdata('message', 'Failed to update product: ' . $e->getMessage());

			$this->session->set_flashdata('message_type', 'error');

			redirect('admin/products/edit_product/' . $id_products);

		}

	}



	// Update Atribut

	public function update_attribute($id_attribute)

	{

		// Ambil data dari form

		$data = $this->input->post();



		// Periksa apakah 'isColor' di-check, jika ya maka 'yes', jika tidak maka 'no'

		$is_color = isset($data['isColor']) && $data['isColor'] == '1' ? 'yes' : 'no';



		// Siapkan data untuk update atribut

		$attribute_data = [

			'product_attribute' => htmlspecialchars($data['idAttributeName']),

			'product_attribute_en' => htmlspecialchars($data['enAttributeName']),

			'is_color' => $is_color,

		];



		// Mulai transaksi database

		$this->db->trans_begin();



		try {

			// Update atribut berdasarkan ID

			$this->db->where('id', $id_attribute);

			$this->db->update('product_attributes', $attribute_data);



			// Commit transaksi jika berhasil

			if ($this->db->trans_status() === FALSE) {

				throw new Exception('Transaction failed');

			}

			$this->db->trans_commit();



			// Set flash message sukses

			$this->session->set_flashdata('message', 'Atribut berhasil diperbarui');

			$this->session->set_flashdata('message_type', 'success');



			// Redirect ke halaman manajemen atribut

			redirect('admin/products/variant-product');

		} catch (Exception $e) {

			// Rollback transaksi jika gagal

			$this->db->trans_rollback();



			// Set flash message error

			$this->session->set_flashdata('message', 'Gagal memperbarui atribut: ' . $e->getMessage());

			$this->session->set_flashdata('message_type', 'error');



			// Redirect kembali ke halaman edit atribut

			redirect('admin/products/edit-attribute/' . $id_attribute);

		}

	}



	public function update_attribute_values($id)

	{

		// Pastikan request adalah AJAX

		if (!$this->input->is_ajax_request()) {

			show_error('No direct script access allowed', 403);

		}



		// Ambil data dari form input

		$data = $this->input->post();

		$response = ['success' => false, 'message' => 'Gagal memperbarui data.'];



		// Pastikan ID valid

		if (!is_numeric($id) || empty($data)) {

			echo json_encode($response);

			return;

		}



		// Siapkan data yang akan diperbarui

		$update_data = [];



		if (isset($data['attribute_detail'])) {

			$update_data['attribute_detail'] = htmlspecialchars($data['attribute_detail']);

		}



		if (isset($data['attribute_detail_en'])) {

			$update_data['attribute_detail_en'] = htmlspecialchars($data['attribute_detail_en']);

		}



		if (isset($data['color_hex'])) {

			$update_data['color_hex'] = htmlspecialchars($data['color_hex']);

		}



		// Periksa apakah ada data untuk diupdate

		if (empty($update_data)) {

			echo json_encode($response);

			return;

		}



		// Mulai transaksi database

		$this->db->trans_begin();



		try {

			// Update atribut berdasarkan ID

			$this->db->where('id', $id);

			$this->db->update('product_attributes_detail', $update_data);



			// Commit transaksi jika berhasil

			if ($this->db->trans_status() === FALSE) {

				throw new Exception('Gagal memperbarui atribut.');

			}



			$this->db->trans_commit();



			// Update CSRF token untuk keamanan

			$new_csrf = $this->security->get_csrf_hash();



			// Respon sukses

			$response = [

				'success' => true,

				'message' => 'Data berhasil diperbarui.',

				'csrf_hash' => $new_csrf

			];

		} catch (Exception $e) {

			// Rollback transaksi jika terjadi kesalahan

			$this->db->trans_rollback();

			$response['message'] = $e->getMessage();

		}



		// Kirim response dalam format JSON

		echo json_encode($response);

	}



	/**

	 * Metode untuk menghapus produk secara massal

	 * Menerima array ID produk dari frontend via AJAX

	 * 

	 * @return JSON response

	 */

	public function bulk_delete()

	{

		// Cek apakah request adalah AJAX

		if (!$this->input->is_ajax_request()) {

			show_404();

		}



		// Ambil data product_ids dari request

		$product_ids = $this->input->post('product_ids');



		// Validasi input

		if (empty($product_ids) || !is_array($product_ids)) {

			// Kembalikan response error

			$response = array(

				'success' => false,

				'message' => 'Data produk tidak valid',

				'product_ids' => $product_ids

			);

			$this->output->set_content_type('application/json')->set_output(json_encode($response));

			return;

		}



		// Filter array untuk memastikan hanya nilai integer yang valid

		$product_ids = array_filter($product_ids, function ($id) {

			return is_numeric($id) && $id > 0;

		});



		// Periksa apakah masih ada produk yang akan dihapus setelah validasi

		if (empty($product_ids)) {

			$response = array(

				'success' => false,

				'message' => 'Tidak ada produk valid untuk dihapus'

			);

			$this->output->set_content_type('application/json')->set_output(json_encode($response));

			return;

		}



		// Jalankan proses bulk delete melalui model

		$result = $this->product_m->bulk_delete_products($product_ids);



		// Kembalikan response

		$response = array(

			'success' => $result,

			'message' => $result ? 'Produk berhasil dihapus' : 'Gagal menghapus produk'

		);



		$this->output->set_content_type('application/json')->set_output(json_encode($response));

	}



	function delete_special_discount($id)

	{



		//check if id exist. If not exist, show 404.

		$count = $this->product_m->count_exist_special_discount($id);



		if ($count == 0) {

			//page not exist 

			show_404();

		}



		$user_id = $this->session->userdata('admin')['id'];



		// Query untuk mengambil title dari tabel product

		$this->db->select('title');

		$this->db->from('special_discount');

		$this->db->where('id_discount', $id);

		$query_product = $this->db->get();

		$product_data = $query_product->row();



		// Buat string "title/SKU"

		if ($product_data) {

			$activity = 'User menghapus special discount (' . $product_data->title . ')';

		} else {

			// Handle jika data produk atau detail produk tidak ditemukan

			$activity = 'User menghapus special discount (' . $id . ')';

		}



		log_activity($user_id, $activity);



		$this->product_m->delete_special_discount($id);



		$this->session->set_flashdata('success', '<br><p style="background:green; color:white; padding:5px; font-weight:bold;">Discount berhasil dihapus</p>');

		redirect('admin/products/specialdiscount');

	}

}


https://t.me/RX1948 - 2025