[ 'page_title' => 'Διαχείριση Προϊόντων - Hockey CMS', 'header_title' => 'Διαχείριση Προϊόντων', 'attr_cat_title' => 'Χαρακτηριστικά Κατηγορίας', 'attr_placeholder' => 'π.χ. συμπληρώστε τιμή...', 'edit_prod_title' => 'Επεξεργασία Προϊόντος #', 'add_prod_title' => 'Προσθήκη Νέου Προϊόντος', 'prod_title' => 'Τίτλος Προϊόντος *', 'category' => 'Κατηγορία *', 'select_cat' => '-- Επίλεξε --', 'sku' => 'Κωδικός / Αύξων Αριθμός (SKU)', 'price' => 'Τιμή (€) *', 'stock' => 'Απόθεμα', 'status' => 'Κατάσταση', 'status_avail' => 'Διαθέσιμο (Available)', 'status_sold' => 'Πουλήθηκε (Sold)', 'status_hidden' => 'Απόκρυψη', 'seller_assign' => 'Ιδιοκτήτης / Πωλητής *', 'tags' => 'Ετικέτες Αναζήτησης (Tags)', 'tags_placeholder' => 'Πληκτρολογήστε λέξη και πατήστε Enter...', 'tags_hint' => 'Πατήστε Enter ή Κόμμα (,) για να δημιουργήσετε tag.', 'desc' => 'Περιγραφή', 'photo' => 'Κεντρική Φωτογραφία', 'photo_hint_edit' => '(Αφήστε το κενό αν δεν θέλετε να την αλλάξετε)', 'photo_hint_add' => '(Αυτόματο resize)', 'btn_update' => 'Ενημέρωση', 'btn_add' => 'Προσθήκη', 'btn_cancel' => 'Ακύρωση', 'list_title' => 'Λίστα Προϊόντων', 'th_id_sku' => 'ID / SKU', 'th_photo' => 'Φωτογραφία', 'th_title' => 'Τίτλος / Tags', 'th_cat' => 'Κατηγορία', 'th_price' => 'Τιμή', 'th_stock' => 'Απόθεμα', 'th_status' => 'Κατάσταση', 'th_actions' => 'Ενέργειες', 'no_img' => 'No IMG', 'pcs' => 'τεμ.', 'btn_view' => 'Προβολή', 'btn_del' => 'Διαγραφή', 'confirm_del' => 'Είστε σίγουρος ότι θέλετε να διαγράψετε αυτό το προϊόν;', 'modal_id' => 'Κωδικός (ID):', 'modal_sku' => 'SKU:', 'modal_cat' => 'Κατηγορία:', 'modal_price' => 'Τιμή:', 'modal_stock' => 'Απόθεμα:', 'modal_status' => 'Κατάσταση:', 'modal_seller' => 'Πωλητής:', 'modal_tags' => 'Tags:', 'modal_desc' => 'Περιγραφή Αγγελίας:', 'modal_no_attrs' => 'Δεν υπάρχουν επιπλέον χαρακτηριστικά', 'msg_add_ok' => 'Το προϊόν προστέθηκε επιτυχώς!', 'msg_edit_ok' => 'Το προϊόν ενημερώθηκε επιτυχώς!', 'msg_err_req' => 'Παρακαλώ συμπληρώστε τα υποχρεωτικά πεδία.', 'msg_err_del_orders' => 'Δεν μπορείτε να διαγράψετε αυτό το προϊόν διότι υπάρχει στο ιστορικό παραγγελιών. Αν δεν θέλετε να φαίνεται, αλλάξτε την κατάστασή του σε "Απόκρυψη".', 'msg_del_ok' => 'Το προϊόν διαγράφηκε επιτυχώς!' ], 'en' => [ 'page_title' => 'Products Management - Hockey CMS', 'header_title' => 'Products Management', 'attr_cat_title' => 'Category Attributes', 'attr_placeholder' => 'e.g. fill in value...', 'edit_prod_title' => 'Edit Product #', 'add_prod_title' => 'Add New Product', 'prod_title' => 'Product Title *', 'category' => 'Category *', 'select_cat' => '-- Select --', 'sku' => 'Code / Sequential (SKU)', 'price' => 'Price (€) *', 'stock' => 'Stock', 'status' => 'Status', 'status_avail' => 'Available', 'status_sold' => 'Sold', 'status_hidden' => 'Hidden', 'seller_assign' => 'Owner / Seller *', 'tags' => 'Search Tags', 'tags_placeholder' => 'Type a word and press Enter...', 'tags_hint' => 'Press Enter or Comma (,) to create a tag.', 'desc' => 'Description', 'photo' => 'Main Photo', 'photo_hint_edit' => '(Leave empty to keep current)', 'photo_hint_add' => '(Auto resize)', 'btn_update' => 'Update', 'btn_add' => 'Add', 'btn_cancel' => 'Cancel', 'list_title' => 'Products List', 'th_id_sku' => 'ID / SKU', 'th_photo' => 'Photo', 'th_title' => 'Title / Tags', 'th_cat' => 'Category', 'th_price' => 'Price', 'th_stock' => 'Stock', 'th_status' => 'Status', 'th_actions' => 'Actions', 'no_img' => 'No IMG', 'pcs' => 'pcs.', 'btn_view' => 'View', 'btn_del' => 'Delete', 'confirm_del' => 'Are you sure you want to delete this product?', 'modal_id' => 'ID:', 'modal_sku' => 'SKU:', 'modal_cat' => 'Category:', 'modal_price' => 'Price:', 'modal_stock' => 'Stock:', 'modal_status' => 'Status:', 'modal_seller' => 'Seller:', 'modal_tags' => 'Tags:', 'modal_desc' => 'Listing Description:', 'modal_no_attrs' => 'No additional attributes', 'msg_add_ok' => 'Product added successfully!', 'msg_edit_ok' => 'Product updated successfully!', 'msg_err_req' => 'Please fill in the required fields.', 'msg_err_del_orders' => 'Cannot delete product because it exists in order history. If you want to hide it, change status to "Hidden".', 'msg_del_ok' => 'Product deleted successfully!' ] ]; $t = $translations[$current_lang]; // --- 1. AJAX API: Φέρνει δυναμικά τα πεδία όταν αλλάζει η Κατηγορία --- if (isset($_GET['ajax_get_attributes']) && isset($_GET['category_id'])) { $cat_id = (int)$_GET['category_id']; $product_id = isset($_GET['product_id']) ? (int)$_GET['product_id'] : 0; $stmt = $pdo->prepare("SELECT attribute_group_id FROM categories WHERE id = ?"); $stmt->execute([$cat_id]); $cat = $stmt->fetch(); if ($cat && $cat['attribute_group_id']) { $attrStmt = $pdo->prepare("SELECT id, name, unit FROM attributes WHERE group_id = ? ORDER BY name"); $attrStmt->execute([$cat['attribute_group_id']]); $attributes = $attrStmt->fetchAll(); $existing_values = []; if ($product_id > 0) { $valStmt = $pdo->prepare("SELECT attribute_id, value FROM product_attribute_values WHERE product_id = ?"); $valStmt->execute([$product_id]); while ($vRow = $valStmt->fetch(PDO::FETCH_ASSOC)) { $existing_values[$vRow['attribute_id']] = $vRow['value']; } } if ($attributes) { echo "

{$t['attr_cat_title']}

"; echo "
"; foreach ($attributes as $attr) { $val = isset($existing_values[$attr['id']]) ? htmlspecialchars($existing_values[$attr['id']]) : ''; echo "
"; echo ""; echo ""; echo "
"; } echo "
"; } } exit; } // --- 2. AJAX API: Δημιουργία προτεινόμενου SKU (Πρόθεμα 3 Γράμματα + Αύξων) --- if (isset($_GET['ajax_generate_sku']) && isset($_GET['category_id'])) { $cat_id = (int)$_GET['category_id']; $stmt = $pdo->prepare("SELECT name_en FROM categories WHERE id = ?"); $stmt->execute([$cat_id]); $name_en = $stmt->fetchColumn(); if ($name_en) { // Κρατάμε μόνο τα γράμματα από τα Αγγλικά $clean_name = preg_replace('/[^a-zA-Z]/', '', $name_en); $prefix = strtoupper(substr($clean_name, 0, 3)); if (empty($prefix)) { $prefix = 'CAT'; } // Βρίσκουμε το μεγαλύτερο νούμερο με αυτό το πρόθεμα $stmtSku = $pdo->prepare("SELECT sku FROM products WHERE sku LIKE ?"); $stmtSku->execute([$prefix . '-%']); $skus = $stmtSku->fetchAll(PDO::FETCH_COLUMN); $max = 0; foreach ($skus as $s) { $parts = explode('-', $s); if (count($parts) > 1) { $num = (int)end($parts); if ($num > $max) { $max = $num; } } } // Γεννάμε το νέο νούμερο με μηδενικά μπροστά (π.χ. 001, 002) $next_num = str_pad($max + 1, 3, '0', STR_PAD_LEFT); echo $prefix . '-' . $next_num; } exit; } header('Content-Type: text/html; charset=utf-8'); $message = ''; function resizeAndSaveImage($source_file, $target_file, $max_resolution = 800) { $info = getimagesize($source_file); if (!$info) return false; $mime = $info['mime']; switch ($mime) { case 'image/jpeg': $image = imagecreatefromjpeg($source_file); break; case 'image/png': $image = imagecreatefrompng($source_file); break; case 'image/gif': $image = imagecreatefromgif($source_file); break; default: return false; } $original_width = imagesx($image); $original_height = imagesy($image); $ratio = $max_resolution / max($original_width, $original_height); $new_width = $original_width > $max_resolution ? round($original_width * $ratio) : $original_width; $new_height = $original_height > $max_resolution ? round($original_height * $ratio) : $original_height; $new_image = imagecreatetruecolor($new_width, $new_height); if ($mime == 'image/png') { imagealphablending($new_image, false); imagesavealpha($new_image, true); } imagecopyresampled($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $original_width, $original_height); imagejpeg($new_image, $target_file, 85); imagedestroy($image); imagedestroy($new_image); return true; } if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { $action = $_POST['action']; $title = trim($_POST['title']); $sku = trim($_POST['sku']); $category_id = (int)$_POST['category_id']; $price = (float)$_POST['price']; $quantity = (int)$_POST['quantity']; $status = $_POST['status'] ?? 'available'; $description = trim($_POST['description']); $search_tags = trim($_POST['search_tags']); $seller_id = isset($_POST['seller_id']) ? (int)$_POST['seller_id'] : $_SESSION['user_id']; if (!empty($title) && !empty($category_id) && !empty($price)) { try { $pdo->beginTransaction(); $stmtGrp = $pdo->prepare("SELECT attribute_group_id FROM categories WHERE id = ?"); $stmtGrp->execute([$category_id]); $group_id = $stmtGrp->fetchColumn(); if ($action == 'add_product') { $stmt = $pdo->prepare("INSERT INTO products (seller_id, category_id, attribute_group_id, title, sku, description, search_tags, price, quantity, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmt->execute([$seller_id, $category_id, $group_id, $title, $sku, $description, $search_tags, $price, $quantity, $status]); $product_id = $pdo->lastInsertId(); $message_text = $t['msg_add_ok']; } elseif ($action == 'edit_product') { $product_id = (int)$_POST['product_id']; $stmt = $pdo->prepare("UPDATE products SET seller_id = ?, category_id = ?, attribute_group_id = ?, title = ?, sku = ?, description = ?, search_tags = ?, price = ?, quantity = ?, status = ? WHERE id = ?"); $stmt->execute([$seller_id, $category_id, $group_id, $title, $sku, $description, $search_tags, $price, $quantity, $status, $product_id]); $delAttr = $pdo->prepare("DELETE FROM product_attribute_values WHERE product_id = ?"); $delAttr->execute([$product_id]); $message_text = $t['msg_edit_ok']; } if (isset($_POST['attributes']) && is_array($_POST['attributes'])) { $insAttr = $pdo->prepare("INSERT INTO product_attribute_values (product_id, attribute_id, value) VALUES (?, ?, ?)"); foreach ($_POST['attributes'] as $attr_id => $val) { $val = trim($val); if ($val !== '') { $insAttr->execute([$product_id, $attr_id, $val]); } } } if (isset($_FILES['image']) && $_FILES['image']['error'] == 0) { $upload_dir = '../uploads/equipment/'; if (!is_dir($upload_dir)) { mkdir($upload_dir, 0755, true); } $filename = 'prod_' . $product_id . '_' . time() . '.jpg'; $target_path = $upload_dir . $filename; if (resizeAndSaveImage($_FILES['image']['tmp_name'], $target_path)) { $checkImg = $pdo->prepare("SELECT id FROM product_images WHERE product_id = ? AND is_primary = 1"); $checkImg->execute([$product_id]); if ($checkImg->fetch()) { $updImg = $pdo->prepare("UPDATE product_images SET image_path = ? WHERE product_id = ? AND is_primary = 1"); $updImg->execute(['uploads/equipment/' . $filename, $product_id]); } else { $insImg = $pdo->prepare("INSERT INTO product_images (product_id, image_path, is_primary) VALUES (?, ?, 1)"); $insImg->execute([$product_id, 'uploads/equipment/' . $filename]); } } } $pdo->commit(); $message = "
{$message_text}
"; } catch (Exception $e) { $pdo->rollBack(); $message = "
Σφάλμα: " . $e->getMessage() . "
"; } } else { $message = "
{$t['msg_err_req']}
"; } } if (isset($_GET['delete'])) { $del_id = (int)$_GET['delete']; $checkOrders = $pdo->prepare("SELECT COUNT(*) FROM order_items WHERE product_id = ?"); $checkOrders->execute([$del_id]); if ($checkOrders->fetchColumn() > 0) { $message = "
{$t['msg_err_del_orders']}
"; } else { try { $pdo->beginTransaction(); $imgStmt = $pdo->prepare("SELECT image_path FROM product_images WHERE product_id = ?"); $imgStmt->execute([$del_id]); $images = $imgStmt->fetchAll(); foreach ($images as $img) { $imgPath = '../' . $img['image_path']; if (file_exists($imgPath) && is_file($imgPath)) { @unlink($imgPath); } } $pdo->prepare("DELETE FROM product_attribute_values WHERE product_id = ?")->execute([$del_id]); $pdo->prepare("DELETE FROM product_images WHERE product_id = ?")->execute([$del_id]); $pdo->prepare("DELETE FROM products WHERE id = ?")->execute([$del_id]); $pdo->commit(); $message = "
{$t['msg_del_ok']}
"; } catch (Exception $e) { $pdo->rollBack(); $message = "
Σφάλμα: " . $e->getMessage() . "
"; } } } $edit_product = null; if (isset($_GET['edit'])) { $edit_id = (int)$_GET['edit']; $editStmt = $pdo->prepare("SELECT * FROM products WHERE id = ?"); $editStmt->execute([$edit_id]); $edit_product = $editStmt->fetch(PDO::FETCH_ASSOC); } // Φόρτωση Κατηγοριών $cat_col = ($current_lang === 'en') ? 'name_en' : 'name_el'; $categories = $pdo->query("SELECT id, IFNULL(NULLIF(name_en, ''), name_el) as name FROM categories ORDER BY sort_order ASC, name_el ASC")->fetchAll(); if ($current_lang === 'el') { $categories = $pdo->query("SELECT id, name_el as name FROM categories ORDER BY sort_order ASC, name_el ASC")->fetchAll(); } // Φόρτωση όλων των χρηστών & Έξυπνη Εύρεση Ονόματος/Επιθέτου $all_users = $pdo->query("SELECT * FROM users ORDER BY username ASC")->fetchAll(PDO::FETCH_ASSOC); $user_map = []; foreach ($all_users as $u) { $fName = $u['first_name'] ?? $u['name'] ?? $u['firstname'] ?? ''; $lName = $u['last_name'] ?? $u['surname'] ?? $u['lastname'] ?? ''; $fullName = trim($fName . ' ' . $lName); $user_map[$u['id']] = $fullName ? $fullName . ' (' . $u['username'] . ')' : $u['username']; } // Λίστα προϊόντων $products = $pdo->query("SELECT p.id, p.sku, p.title, p.description, p.search_tags, p.price, p.quantity, p.status, p.category_id, p.seller_id, p.created_at, IFNULL(NULLIF(c.name_en, ''), c.name_el) as cat_name_en, c.name_el as cat_name_el, u.username, pi.image_path FROM products p LEFT JOIN categories c ON p.category_id = c.id LEFT JOIN users u ON p.seller_id = u.id LEFT JOIN product_images pi ON (p.id = pi.product_id AND pi.is_primary = 1) ORDER BY p.id DESC")->fetchAll(PDO::FETCH_ASSOC); $all_attrs = $pdo->query("SELECT pav.product_id, a.name, a.name_en, a.unit, pav.value FROM product_attribute_values pav JOIN attributes a ON pav.attribute_id = a.id")->fetchAll(PDO::FETCH_ASSOC); $attrs_by_product = []; foreach($all_attrs as $attr) { $attr['display_name'] = ($current_lang === 'en' && !empty($attr['name_en'])) ? $attr['name_en'] : $attr['name']; $attrs_by_product[$attr['product_id']][] = $attr; } foreach ($products as &$prod) { $prod['cat_name'] = ($current_lang === 'en' && !empty($prod['cat_name_en'])) ? $prod['cat_name_en'] : $prod['cat_name_el']; $prod['attributes'] = isset($attrs_by_product[$prod['id']]) ? $attrs_by_product[$prod['id']] : []; $prod['seller_display'] = isset($user_map[$prod['seller_id']]) ? $user_map[$prod['seller_id']] : $prod['username']; } unset($prod); ?> <?php echo $t['page_title']; ?>

#
'.htmlspecialchars(trim($tg)).''; } ?>
€