|
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 : /var/www/laciasmara.com/public_html/shop/application/controllers/admin/ |
Upload File : |
<?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('stocks_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,
CASE
WHEN (s.stock - COALESCE(s.stock_sample, 0) - COALESCE(s.stock_keep, 0) - COALESCE(s.stock_reject, 0)) < 0
THEN 0
ELSE (s.stock - COALESCE(s.stock_sample, 0) - COALESCE(s.stock_keep, 0) - COALESCE(s.stock_reject, 0))
END 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;
}
// Validasi stock_type yang diizinkan
$allowed_stock_types = ['stock', 'stock_keep', 'stock_reject', 'stock_sample'];
if (!in_array($stock_type, $allowed_stock_types)) {
echo json_encode(["success" => false, "message" => "Tipe stok tidak valid"]);
return;
}
// Validasi action yang diizinkan
if (!in_array($action, ['add', 'subtract'])) {
echo json_encode(["success" => false, "message" => "Aksi tidak valid"]);
return;
}
try {
$this->db->trans_start(); // Mulai transaksi database
// Get current stock information dan SKU
$current_stock_data = $this->stocks_m->get_stock_with_sku($product_detail_id, $warehouse_id);
if (!$current_stock_data) {
echo json_encode(["success" => false, "message" => "Data stok tidak ditemukan"]);
return;
}
$stock_id = $current_stock_data['stock_id'];
$id_product = $current_stock_data['id_product'];
$sku = $current_stock_data['sku'];
$old_value = intval($current_stock_data[$stock_type]);
// Hitung nilai baru
$new_value = ($action === 'add') ? $old_value + $amount : $old_value - $amount;
// Cek jika stok akan menjadi negatif
if ($new_value < 0) {
$stock_type_label = $this->get_stock_type_label($stock_type);
echo json_encode(["success" => false, "message" => "{$stock_type_label} tidak cukup"]);
return;
}
// Update stok menggunakan method dari model
$update_success = $this->stocks_m->update_stock_by_type($stock_id, $stock_type, $new_value);
if (!$update_success) {
$this->db->trans_rollback();
echo json_encode(["success" => false, "message" => "Gagal mengupdate stok"]);
return;
}
// Generate remark menggunakan method dari model
$remark_details = [
'user' => $user_name,
'reason' => $note,
'type' => ($action === 'add') ? '+' : '-',
'change' => $amount,
'total' => $new_value,
'old_value' => $old_value,
'stock_type' => $stock_type
];
$remark = $this->stocks_m->generate_remark('MANUAL_ADJUSTMENT', $sku, $remark_details);
// Log stock movement menggunakan method dari model
$movement_type = ($action === 'add') ? '+' : '-';
$movement_success = $this->stocks_m->log_stock_movement_by_type(
$stock_id,
$movement_type,
$amount,
$new_value,
$remark,
$stock_type,
$user_name
);
if (!$movement_success) {
$this->db->trans_rollback();
echo json_encode(["success" => false, "message" => "Gagal mencatat pergerakan stok"]);
return;
}
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) {
echo json_encode(["success" => false, "message" => "Transaksi database gagal"]);
return;
}
// Return response sukses
echo json_encode([
"success" => true,
"message" => "Stok berhasil diperbarui",
"csrf_token" => $this->security->get_csrf_hash(),
"data" => [
"sku" => $sku,
"old_value" => $old_value,
"new_value" => $new_value,
"difference" => $amount,
"action" => $action,
"stock_type" => $stock_type,
"stock_type_label" => $this->get_stock_type_label($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()]);
}
}
/**
* Helper method untuk mendapatkan label stock type
*/
private function get_stock_type_label($stock_type)
{
$labels = [
'stock' => 'Stok',
'stock_keep' => 'Stok keep',
'stock_reject' => 'Stok reject',
'stock_sample' => 'Stok sample'
];
return isset($labels[$stock_type]) ? $labels[$stock_type] : 'Stok';
}
/**
* 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 {
// LOG: Cek stok sebelum update
log_message('debug', '=== PRODUCT UPDATE START - Product ID: ' . $id_products . ' ===');
$stock_before = $this->db->get_where('stock', ['id_product' => $id_products])->result_array();
log_message('debug', 'Stock before update: ' . json_encode($stock_before));
// 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'])) {
log_message('debug', 'Variant update section started');
$selected_variant_data = json_decode($data['selected_variant_data'], true);
log_message('debug', 'Selected variant data: ' . json_encode($selected_variant_data));
$variant_ids = array_column($selected_variant_data, 'variant_id');
log_message('debug', 'Variant IDs: ' . json_encode($variant_ids));
// Dapatkan data variasi yang ada
$existing_variants = $this->db->get_where('product_combination', [
'product_id' => $id_products
])->result_array();
log_message('debug', 'Existing variants: ' . json_encode($existing_variants));
$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)) {
log_message('debug', 'Variants to remove: ' . json_encode($variants_to_remove));
foreach ($variants_to_remove as $variant_id) {
$product_details_id = $existing_variant_details[$variant_id];
// LOG: Stok yang akan dihapus
$stock_to_delete = $this->db->get_where('stock', [
'id_product' => $id_products,
'id_product_detail' => $product_details_id
])->result_array();
log_message('debug', 'Deleting stock for product_details_id ' . $product_details_id . ': ' . json_encode($stock_to_delete));
// Hapus stok untuk variasi yang dihapus - TAMBAHKAN WHERE CLAUSE WAREHOUSE_ID
$this->db->where('id_product', $id_products);
$this->db->where('id_product_detail', $product_details_id);
$this->db->where('warehouse_id', 1); // PERBAIKAN: Tambahkan filter warehouse_id
$deleted_rows = $this->db->delete('stock');
log_message('debug', 'Deleted stock rows: ' . $this->db->affected_rows() . ' for warehouse_id 1');
// 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'];
log_message('debug', 'Processing variant index ' . $index . ', variant_id: ' . $variant_id);
if (isset($existing_variant_details[$variant_id])) {
// Update variasi yang sudah ada
$product_details_id = $existing_variant_details[$variant_id];
log_message('debug', 'Updating existing variant - product_details_id: ' . $product_details_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])) {
log_message('debug', 'Stock update requested for variant index ' . $index . ': ' . $data['variant_stock'][$index]);
// PERBAIKAN: Tambahkan WHERE clause untuk warehouse_id
$stock_exists = $this->db->get_where('stock', [
'id_product' => $id_products,
'id_product_detail' => $product_details_id,
'warehouse_id' => 1 // PERBAIKAN: Tambahkan filter warehouse_id
])->row();
log_message('debug', 'Stock exists check (warehouse_id = 1): ' . ($stock_exists ? 'YES - Stock ID: ' . $stock_exists->id : 'NO'));
$stock_data = [
'stock' => (int)$data['variant_stock'][$index]
];
if ($stock_exists) {
log_message('debug', 'Updating stock for warehouse_id 1, product_details_id: ' . $product_details_id);
// PERBAIKAN: Tambahkan WHERE clause untuk warehouse_id
$this->db->where('id_product', $id_products);
$this->db->where('id_product_detail', $product_details_id);
$this->db->where('warehouse_id', 1); // PERBAIKAN: Tambahkan filter warehouse_id
$this->db->update('stock', $stock_data);
log_message('debug', 'Updated stock rows: ' . $this->db->affected_rows() . ' for warehouse_id 1');
log_message('debug', 'Last query: ' . $this->db->last_query());
} else {
log_message('debug', 'Inserting new stock for warehouse_id 1, product_details_id: ' . $product_details_id);
$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);
log_message('debug', 'Inserted stock with ID: ' . $this->db->insert_id());
log_message('debug', 'Last query: ' . $this->db->last_query());
}
}
} else {
// Tambahkan variasi baru
log_message('debug', 'Adding new variant - variant_id: ' . $variant_id);
$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();
log_message('debug', 'New product_details created with ID: ' . $product_details_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])) {
log_message('debug', 'Inserting stock for new variant, stock: ' . $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);
log_message('debug', 'Inserted new stock with ID: ' . $this->db->insert_id());
log_message('debug', 'Last query: ' . $this->db->last_query());
}
}
}
}
// LOG: Cek stok setelah update
$stock_after = $this->db->get_where('stock', ['id_product' => $id_products])->result_array();
log_message('debug', 'Stock after update: ' . json_encode($stock_after));
log_message('debug', '=== PRODUCT UPDATE END ===');
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();
log_message('error', 'Product update failed: ' . $e->getMessage());
log_message('error', 'Stack trace: ' . $e->getTraceAsString());
$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');
}
}