429 lines
21 KiB
PHP
429 lines
21 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../includes/init.php';
|
|
require_role('admin');
|
|
|
|
$pdo = db();
|
|
|
|
// Handle image deletion
|
|
if (isset($_GET['delete_image']) && isset($_GET['id'])) {
|
|
$image_id_to_delete = $_GET['delete_image'];
|
|
$product_id_for_redirect = $_GET['id'];
|
|
|
|
$img_stmt = $pdo->prepare("SELECT file_path FROM product_images WHERE id = ? AND product_id = ?");
|
|
$img_stmt->execute([$image_id_to_delete, $product_id_for_redirect]);
|
|
$image_to_delete = $img_stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($image_to_delete) {
|
|
$file_path = __DIR__ . '/../uploads/products/' . $image_to_delete['file_path'];
|
|
if (file_exists($file_path)) {
|
|
unlink($file_path);
|
|
}
|
|
|
|
$delete_stmt = $pdo->prepare("DELETE FROM product_images WHERE id = ?");
|
|
$delete_stmt->execute([$image_id_to_delete]);
|
|
}
|
|
|
|
header('Location: edit_product.php?id=' . $product_id_for_redirect);
|
|
exit;
|
|
}
|
|
|
|
// Handle document deletion
|
|
if (isset($_GET['delete_document']) && isset($_GET['id'])) {
|
|
$doc_id_to_delete = $_GET['delete_document'];
|
|
$product_id_for_redirect = $_GET['id'];
|
|
|
|
$doc_stmt = $pdo->prepare("SELECT file_path FROM product_documents WHERE id = ? AND product_id = ?");
|
|
$doc_stmt->execute([$doc_id_to_delete, $product_id_for_redirect]);
|
|
$doc_to_delete = $doc_stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($doc_to_delete) {
|
|
$file_path = __DIR__ . '/../uploads/documents/' . $doc_to_delete['file_path'];
|
|
if (file_exists($file_path)) {
|
|
unlink($file_path);
|
|
}
|
|
|
|
$delete_stmt = $pdo->prepare("DELETE FROM product_documents WHERE id = ?");
|
|
$delete_stmt->execute([$doc_id_to_delete]);
|
|
}
|
|
|
|
header('Location: edit_product.php?id=' . $product_id_for_redirect);
|
|
exit;
|
|
}
|
|
|
|
|
|
$product = [
|
|
'id' => null,
|
|
'name' => '',
|
|
'description' => '',
|
|
'price_net' => '',
|
|
'price_gross' => '',
|
|
'supplier_id' => null,
|
|
'is_active' => 1,
|
|
'product_role' => 'membrana',
|
|
'unit' => 'szt',
|
|
'units_per_pallet' => null
|
|
];
|
|
$errors = [];
|
|
|
|
// Fetch suppliers
|
|
$stmt = $pdo->prepare("SELECT id, email FROM users WHERE role = 'supplier' AND is_active = 1 ORDER BY email");
|
|
$stmt->execute();
|
|
$suppliers = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Fetch all attribute keys
|
|
$keys_stmt = $pdo->query("SELECT * FROM attribute_keys ORDER BY name");
|
|
$attribute_keys = $keys_stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Fetch product's current attributes and images
|
|
$product_attributes = [];
|
|
$product_images = [];
|
|
if (isset($_GET['id'])) {
|
|
$product_id = $_GET['id'];
|
|
$attr_stmt = $pdo->prepare("SELECT attribute_key_id, value FROM product_attributes WHERE product_id = ?");
|
|
$attr_stmt->execute([$product_id]);
|
|
$product_attributes_raw = $attr_stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
foreach ($product_attributes_raw as $attr) {
|
|
$product_attributes[$attr['attribute_key_id']] = $attr['value'];
|
|
}
|
|
|
|
$img_stmt = $pdo->prepare("SELECT * FROM product_images WHERE product_id = ? ORDER BY is_primary DESC, id ASC");
|
|
$img_stmt->execute([$product_id]);
|
|
$product_images = $img_stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Fetch all products for related products selection
|
|
$all_products_stmt = $pdo->query("SELECT id, name FROM products ORDER BY name");
|
|
$all_products = $all_products_stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Fetch current related products
|
|
$related_products_stmt = $pdo->prepare("SELECT related_product_id FROM product_relations WHERE product_id = ?");
|
|
$related_products_stmt->execute([$product_id]);
|
|
$related_product_ids = $related_products_stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
|
|
// Fetch product documents
|
|
$docs_stmt = $pdo->prepare("SELECT * FROM product_documents WHERE product_id = ?");
|
|
$docs_stmt->execute([$product_id]);
|
|
$product_documents = $docs_stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
|
|
}
|
|
|
|
if (isset($_GET['id'])) {
|
|
$stmt = $pdo->prepare("SELECT * FROM products WHERE id = ?");
|
|
$stmt->execute([$_GET['id']]);
|
|
$product = $stmt->fetch();
|
|
if (!$product) {
|
|
die('Nie znaleziono produktu');
|
|
}
|
|
}
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$name = $_POST['name'] ?? '';
|
|
$description = $_POST['description'] ?? '';
|
|
$price_net = !empty($_POST['price_net']) ? (float)$_POST['price_net'] : null;
|
|
$price_gross = !empty($_POST['price_gross']) ? (float)$_POST['price_gross'] : null;
|
|
$unit = $_POST['unit'] ?? 'szt';
|
|
$units_per_pallet = !empty($_POST['units_per_pallet']) ? $_POST['units_per_pallet'] : null;
|
|
$supplier_id = !empty($_POST['supplier_id']) ? $_POST['supplier_id'] : null;
|
|
$attributes = $_POST['attributes'] ?? [];
|
|
$is_active = isset($_POST['is_active']) ? 1 : 0;
|
|
$product_role = $_POST['product_role'] ?? 'membrana';
|
|
$id = $_POST['id'] ?? null;
|
|
|
|
// Auto-calculate prices
|
|
if ($price_net !== null && $price_gross === null) {
|
|
$price_gross = round($price_net * 1.23, 2);
|
|
} elseif ($price_gross !== null && $price_net === null) {
|
|
$price_net = round($price_gross / 1.23, 2);
|
|
}
|
|
|
|
if ($supplier_id) {
|
|
$stmt = $pdo->prepare("SELECT COUNT(*) FROM users WHERE id = ? AND role = 'supplier' AND is_active = 1");
|
|
$stmt->execute([$supplier_id]);
|
|
if ($stmt->fetchColumn() == 0) {
|
|
$errors[] = 'Wybrany dostawca jest nieprawidłowy.';
|
|
}
|
|
}
|
|
|
|
if (empty($errors)) {
|
|
try {
|
|
$pdo->beginTransaction();
|
|
|
|
if ($id) { // Update
|
|
$stmt = $pdo->prepare("UPDATE products SET name=?, description=?, price_net=?, price_gross=?, unit=?, units_per_pallet=?, supplier_id=?, is_active=?, product_role=? WHERE id=?");
|
|
$stmt->execute([$name, $description, $price_net, $price_gross, $unit, $units_per_pallet, $supplier_id, $is_active, $product_role, $id]);
|
|
$product_id = $id;
|
|
} else { // Insert
|
|
$stmt = $pdo->prepare("INSERT INTO products (name, description, price_net, price_gross, unit, units_per_pallet, supplier_id, is_active, product_role) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
$stmt->execute([$name, $description, $price_net, $price_gross, $unit, $units_per_pallet, $supplier_id, $is_active, $product_role]);
|
|
$product_id = $pdo->lastInsertId();
|
|
}
|
|
|
|
// Handle image uploads
|
|
if (isset($_FILES['images']) && !empty($_FILES['images']['name'][0])) {
|
|
$image_errors = [];
|
|
$allowed_types = ['image/jpeg', 'image/png'];
|
|
$upload_dir = __DIR__ . '/../uploads/products/';
|
|
|
|
if (!is_dir($upload_dir)) {
|
|
mkdir($upload_dir, 0777, true);
|
|
}
|
|
|
|
foreach ($_FILES['images']['tmp_name'] as $key => $tmp_name) {
|
|
if ($_FILES['images']['error'][$key] === UPLOAD_ERR_OK) {
|
|
$file_type = mime_content_type($tmp_name);
|
|
if (in_array($file_type, $allowed_types)) {
|
|
$product_upload_dir = $upload_dir . $product_id . '/';
|
|
if (!is_dir($product_upload_dir)) {
|
|
mkdir($product_upload_dir, 0777, true);
|
|
}
|
|
$file_ext = pathinfo($_FILES['images']['name'][$key], PATHINFO_EXTENSION);
|
|
$file_name = uniqid('prod_' . $product_id . '_', true) . '.' . $file_ext;
|
|
$destination = $product_upload_dir . $file_name;
|
|
|
|
// GEMINI DEBUG
|
|
file_put_contents('/tmp/gemini_debug.log', "Destination: {$destination}\nFile Path for DB: {$product_id}/{$file_name}\n", FILE_APPEND);
|
|
|
|
if (move_uploaded_file($tmp_name, $destination)) {
|
|
$img_stmt = $pdo->prepare("INSERT INTO product_images (product_id, file_path) VALUES (?, ?)");
|
|
$img_stmt->execute([$product_id, $product_id . '/' . $file_name]);
|
|
} else {
|
|
$image_errors[] = "Nie udało się przenieść pliku: " . htmlspecialchars($_FILES['images']['name'][$key]);
|
|
}
|
|
} else {
|
|
$image_errors[] = "Niedozwolony typ pliku: " . htmlspecialchars($_FILES['images']['name'][$key]);
|
|
}
|
|
} elseif ($_FILES['images']['error'][$key] !== UPLOAD_ERR_NO_FILE) {
|
|
$image_errors[] = "Błąd podczas przesyłania pliku: " . htmlspecialchars($_FILES['images']['name'][$key]) . ": " . upload_error_message($_FILES['images']['error'][$key]);
|
|
}
|
|
}
|
|
// Store image errors in session to display after redirect if needed, or handle differently
|
|
if(!empty($image_errors)) {
|
|
// For simplicity, we add them to the main errors array.
|
|
$errors = array_merge($errors, $image_errors);
|
|
if ($pdo->inTransaction()) $pdo->rollBack();
|
|
// Stop further execution if image upload fails
|
|
goto end_of_post_handling;
|
|
}
|
|
}
|
|
|
|
// Handle document uploads
|
|
if (isset($_FILES['documents']) && !empty($_FILES['documents']['name'][0])) {
|
|
$doc_errors = [];
|
|
$allowed_doc_types = ['application/pdf'];
|
|
$doc_upload_dir = __DIR__ . '/../uploads/documents/' . $product_id . '/';
|
|
|
|
if (!is_dir($doc_upload_dir)) {
|
|
mkdir($doc_upload_dir, 0777, true);
|
|
}
|
|
|
|
foreach ($_FILES['documents']['tmp_name'] as $key => $tmp_name) {
|
|
if ($_FILES['documents']['error'][$key] === UPLOAD_ERR_OK) {
|
|
$file_type = mime_content_type($tmp_name);
|
|
if (in_array($file_type, $allowed_doc_types)) {
|
|
$original_file_name = basename($_FILES['documents']['name'][$key]);
|
|
$sanitized_file_name = sanitize_filename($original_file_name);
|
|
$destination = $doc_upload_dir . $sanitized_file_name;
|
|
|
|
if (move_uploaded_file($tmp_name, $destination)) {
|
|
$doc_stmt = $pdo->prepare("INSERT INTO product_documents (product_id, file_name, file_path) VALUES (?, ?, ?)");
|
|
$doc_stmt->execute([$product_id, $original_file_name, $product_id . '/' . $sanitized_file_name]);
|
|
} else {
|
|
$doc_errors[] = "Nie udało się przenieść pliku: " . htmlspecialchars($original_file_name);
|
|
}
|
|
} else {
|
|
$doc_errors[] = "Niedozwolony typ pliku: " . htmlspecialchars($original_file_name);
|
|
}
|
|
} elseif ($_FILES['documents']['error'][$key] !== UPLOAD_ERR_NO_FILE) {
|
|
$doc_errors[] = "Błąd podczas przesyłania pliku: " . htmlspecialchars($_FILES['documents']['name'][$key]) . ": " . upload_error_message($_FILES['documents']['error'][$key]);
|
|
}
|
|
}
|
|
if(!empty($doc_errors)) {
|
|
$errors = array_merge($errors, $doc_errors);
|
|
if ($pdo->inTransaction()) $pdo->rollBack();
|
|
goto end_of_post_handling;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
$clear_stmt = $pdo->prepare("DELETE FROM product_attributes WHERE product_id = ?");
|
|
$clear_stmt->execute([$product_id]);
|
|
|
|
$attr_sql = "INSERT INTO product_attributes (product_id, attribute_key_id, value) VALUES (?, ?, ?)";
|
|
$attr_stmt = $pdo->prepare($attr_sql);
|
|
foreach ($attributes as $key_id => $value) {
|
|
if (!empty($value)) {
|
|
$attr_stmt->execute([$product_id, $key_id, $value]);
|
|
}
|
|
}
|
|
|
|
// Handle related products
|
|
$related_products = $_POST['related_products'] ?? [];
|
|
$clear_related_stmt = $pdo->prepare("DELETE FROM product_relations WHERE product_id = ?");
|
|
$clear_related_stmt->execute([$product_id]);
|
|
|
|
if (!empty($related_products)) {
|
|
$rel_sql = "INSERT INTO product_relations (product_id, related_product_id) VALUES (?, ?)";
|
|
$rel_stmt = $pdo->prepare($rel_sql);
|
|
foreach ($related_products as $related_id) {
|
|
$rel_stmt->execute([$product_id, $related_id]);
|
|
}
|
|
}
|
|
|
|
|
|
$pdo->commit();
|
|
header("Location: products.php");
|
|
exit;
|
|
|
|
} catch (Exception $e) {
|
|
if ($pdo->inTransaction()) $pdo->rollBack();
|
|
$errors[] = 'Błąd podczas zapisywania produktu: ' . $e->getMessage();
|
|
}
|
|
}
|
|
end_of_post_handling:
|
|
}
|
|
|
|
$page_title = $product['id'] ? 'Edytuj produkt' : 'Dodaj produkt';
|
|
?>
|
|
<?php require_once __DIR__ . '/../includes/html_head.php'; ?>
|
|
<body>
|
|
<?php include __DIR__ . '/menu.php'; ?>
|
|
<main class="container my-5">
|
|
<h1><?php echo $page_title; ?></h1>
|
|
|
|
<?php if (!empty($errors)): ?>
|
|
<div class="alert alert-danger">
|
|
<?php foreach ($errors as $error): ?><p><?php echo htmlspecialchars($error); ?></p><?php endforeach; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<form action="edit_product.php<?php echo $product['id'] ? '?id='.$product['id'] : '' ?>" method="POST" enctype="multipart/form-data">
|
|
<input type="hidden" name="id" value="<?php echo htmlspecialchars($product['id'] ?? ''); ?>">
|
|
|
|
<div class="card card-body mb-4">
|
|
<div class="mb-3">
|
|
<label for="name" class="form-label">Nazwa produktu</label>
|
|
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($product['name'] ?? ''); ?>" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="description" class="form-label">Opis</label>
|
|
<textarea class="form-control" id="description" name="description" rows="3"><?php echo htmlspecialchars($product['description'] ?? ''); ?></textarea>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="price_net" class="form-label">Cena netto</label>
|
|
<input type="number" step="0.01" class="form-control" id="price_net" name="price_net" value="<?= htmlspecialchars($product['price_net'] ?? '') ?>">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="price_gross" class="form-label">Cena brutto (z VAT 23%)</label>
|
|
<input type="number" step="0.01" class="form-control" id="price_gross" name="price_gross" value="<?= htmlspecialchars($product['price_gross'] ?? '') ?>">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="unit" class="form-label">Jednostka miary</label>
|
|
<select name="unit" id="unit" class="form-select">
|
|
<option value="szt" <?= ($product['unit'] ?? 'szt') === 'szt' ? 'selected' : '' ?>><?= t('szt') ?></option>
|
|
<option value="mb" <?= ($product['unit'] ?? 'szt') === 'mb' ? 'selected' : '' ?>><?= t('mb') ?></option>
|
|
<option value="m2" <?= ($product['unit'] ?? 'szt') === 'm2' ? 'selected' : '' ?>><?= t('m2') ?></option>
|
|
<option value="rolka" <?= ($product['unit'] ?? 'szt') === 'rolka' ? 'selected' : '' ?>><?= t('rolka') ?></option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="units_per_pallet" class="form-label">Ilość sztuk na palecie</label>
|
|
<input type="number" min="1" class="form-control" id="units_per_pallet" name="units_per_pallet" value="<?= htmlspecialchars($product['units_per_pallet'] ?? '') ?>">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="product_role" class="form-label">Typ produktu</label>
|
|
<select name="product_role" id="product_role" class="form-select">
|
|
<option value="membrana" <?php echo ($product['product_role'] ?? 'membrana') === 'membrana' ? 'selected' : ''; ?>>membrana</option>
|
|
<option value="akcesoria" <?php echo ($product['product_role'] ?? 'membrana') === 'akcesoria' ? 'selected' : ''; ?>>akcesoria</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-check mb-3">
|
|
<input class="form-check-input" type="checkbox" id="is_active" name="is_active" value="1" <?php echo !empty($product['is_active']) ? 'checked' : ''; ?>>
|
|
<label class="form-check-label" for="is_active">Aktywny</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card card-body mb-4">
|
|
<h5>Zdjęcia</h5>
|
|
<div class="mb-3">
|
|
<label for="images" class="form-label">Dodaj nowe zdjęcia</label>
|
|
<input type="file" class="form-control" id="images" name="images[]" multiple accept="image/png, image/jpeg">
|
|
</div>
|
|
<?php if (!empty($product_images)):
|
|
echo '<div class="row g-3">';
|
|
foreach($product_images as $image) {
|
|
echo '<div class="col-md-3 text-center">';
|
|
echo '<img src="../uploads/products/' . htmlspecialchars($image['file_path']) . '" class="img-thumbnail mb-2" style="max-height: 150px;">';
|
|
echo '<a href="edit_product.php?id=' . htmlspecialchars($product['id']) . '&delete_image=' . htmlspecialchars($image['id']) . '" class="btn btn-danger btn-sm" onclick="return confirm(\'Czy na pewno chcesz usunąć to zdjęcie?\');">Usuń</a>';
|
|
echo '</div>';
|
|
}
|
|
echo '</div>';
|
|
endif; ?>
|
|
</div>
|
|
|
|
<div class="card card-body mb-4">
|
|
<h5>Atrybuty</h5>
|
|
<div class="mb-3">
|
|
<label for="supplier_id" class="form-label">Dostawca</label>
|
|
<select name="supplier_id" id="supplier_id" class="form-select">
|
|
<option value="">-- Wybierz dostawcę --</option>
|
|
<?php foreach ($suppliers as $supplier): ?>
|
|
<option value="<?php echo htmlspecialchars($supplier['id']); ?>" <?php echo (isset($product['supplier_id']) && $product['supplier_id'] == $supplier['id']) ? 'selected' : ''; ?>>
|
|
<?php echo htmlspecialchars($supplier['email']); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<hr>
|
|
<h5>Specyfikacja techniczna</h5>
|
|
<?php foreach ($attribute_keys as $key): ?>
|
|
<div class="mb-3">
|
|
<label for="attribute_<?php echo htmlspecialchars($key['id']); ?>" class="form-label"><?php echo htmlspecialchars($key['name']); ?></label>
|
|
<input type="text" class="form-control" id="attribute_<?php echo htmlspecialchars($key['id']); ?>" name="attributes[<?php echo htmlspecialchars($key['id']); ?>]" value="<?php echo htmlspecialchars($product_attributes[$key['id']] ?? ''); ?>">
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
|
|
<div class="card card-body mb-4">
|
|
<h5>Produkty powiązane</h5>
|
|
<div class="mb-3">
|
|
<label for="related_products" class="form-label">Wybierz produkty powiązane</label>
|
|
<select multiple class="form-control" id="related_products" name="related_products[]" size="10">
|
|
<?php foreach ($all_products as $p): ?>
|
|
<?php if ($p['id'] != $product['id']): // Exclude self ?>
|
|
<option value="<?php echo htmlspecialchars($p['id']); ?>" <?php echo in_array($p['id'], $related_product_ids) ? 'selected' : ''; ?>>
|
|
<?php echo htmlspecialchars($p['name']); ?>
|
|
</option>
|
|
<?php endif; ?>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card card-body mb-4">
|
|
<h5>Dokumenty produktu (PDF)</h5>
|
|
<div class="mb-3">
|
|
<label for="documents" class="form-label">Dodaj nowe dokumenty</label>
|
|
<input type="file" class="form-control" id="documents" name="documents[]" multiple accept="application/pdf">
|
|
</div>
|
|
<?php if (!empty($product_documents)):
|
|
echo '<ul class="list-group">';
|
|
foreach($product_documents as $doc) {
|
|
echo '<li class="list-group-item d-flex justify-content-between align-items-center">';
|
|
echo htmlspecialchars($doc['file_name']);
|
|
echo '<a href="edit_product.php?id=' . htmlspecialchars($product['id']) . '&delete_document=' . htmlspecialchars($doc['id']) . '" class="btn btn-danger btn-sm" onclick="return confirm(\'Czy na pewno chcesz usunąć ten dokument?\');">Usuń</a>';
|
|
echo '</li>';
|
|
}
|
|
echo '</ul>';
|
|
endif; ?>
|
|
</div>
|
|
|
|
<div class="mt-4">
|
|
<button type="submit" class="btn btn-primary">Zapisz</button>
|
|
<a href="products.php" class="btn btn-secondary">Anuluj</a>
|
|
</div>
|
|
</form>
|
|
</main>
|
|
<?php require_once __DIR__ . '/../includes/footer.php'; ?>
|
|
</body>
|
|
</html>
|