init
commit
50f38a9e9a
@ -0,0 +1,126 @@
|
||||
<?php
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
checkAuth();
|
||||
|
||||
$message = '';
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$product_name = trim($_POST['product_name']);
|
||||
$quantity = (int)$_POST['quantity'];
|
||||
$purchase_place = trim($_POST['purchase_place']);
|
||||
$price = (float)str_replace(',', '.', $_POST['price_per_unit']);
|
||||
$delivery_date = $_POST['delivery_date'];
|
||||
$notes = trim($_POST['notes']);
|
||||
$recipient = trim($_POST['recipient']);
|
||||
$delivery_address = trim($_POST['delivery_address']);
|
||||
$company = trim($_POST['company'] ?? ''); // NOWE POLE
|
||||
|
||||
if (!empty($product_name) && $quantity > 0) {
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
$sql = "INSERT INTO " . DB_PREFIX . "orders
|
||||
(product_name, quantity, purchase_place, price_per_unit, delivery_date, notes, recipient, delivery_address, company, status)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'nowe')";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$product_name, $quantity, $purchase_place, $price, $delivery_date, $notes, $recipient, $delivery_address, $company]);
|
||||
|
||||
$order_id = $pdo->lastInsertId();
|
||||
|
||||
$hist_sql = "INSERT INTO " . DB_PREFIX . "order_history (order_id, user_id, action) VALUES (?, ?, ?)";
|
||||
$hist_stmt = $pdo->prepare($hist_sql);
|
||||
$hist_stmt->execute([$order_id, $_SESSION['user_id'], 'Utworzono nowe zamówienie.']);
|
||||
|
||||
$pdo->commit();
|
||||
|
||||
$message = "<div class='alert alert-success'>Zamówienie dodane pomyślnie!</div>";
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
$message = "<div class='alert alert-danger'>Błąd: " . $e->getMessage() . "</div>";
|
||||
}
|
||||
} else {
|
||||
$message = "<div class='alert alert-warning'>Wypełnij nazwę produktu i ilość.</div>";
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Dodaj zamówienie - <?php echo APP_NAME; ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<div class="container py-5">
|
||||
<div class="card shadow mx-auto" style="max-width: 600px;">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-plus-circle"></i> Nowe zamówienie</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php echo $message; ?>
|
||||
<form method="POST">
|
||||
|
||||
<div class="mb-3 p-2 bg-success bg-opacity-10 border border-success rounded">
|
||||
<label class="form-label small fw-bold text-success"><i class="bi bi-building"></i> Firma kupująca</label>
|
||||
<select name="company" class="form-select border-success">
|
||||
<option value="">Wybierz firmę...</option>
|
||||
<option value="Przedsiębiorstwo">Przedsiębiorstwo</option>
|
||||
<option value="Spółka">Spółka</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label small fw-bold">Nazwa produktu *</label>
|
||||
<input type="text" name="product_name" class="form-control" required>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label small fw-bold">Ilość *</label>
|
||||
<input type="number" name="quantity" class="form-control" value="1" min="1" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label small fw-bold">Cena za sztukę</label>
|
||||
<div class="input-group">
|
||||
<input type="text" name="price_per_unit" class="form-control" placeholder="0.00">
|
||||
<span class="input-group-text">zł</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small fw-bold">Sklep / Miejsce zakupu</label>
|
||||
<input type="text" name="purchase_place" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="row bg-light p-3 border rounded mb-3">
|
||||
<div class="col-md-6 mb-3 mb-md-0">
|
||||
<label class="form-label small fw-bold text-primary">Odbiorca / Projekt</label>
|
||||
<input type="text" name="recipient" class="form-control form-control-sm">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold text-primary">Adres dostawy</label>
|
||||
<textarea name="delivery_address" class="form-control form-control-sm" rows="1"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label small fw-bold">Szacowana data dostawy</label>
|
||||
<input type="date" name="delivery_date" class="form-control">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small fw-bold">Notatki</label>
|
||||
<textarea name="notes" class="form-control" rows="2"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="index.php" class="btn btn-secondary">Powrót do listy</a>
|
||||
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg"></i> Zapisz zamówienie</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,359 @@
|
||||
<?php
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
|
||||
checkAuth();
|
||||
checkAdmin(); // Tylko admin tu wejdzie
|
||||
|
||||
$message = '';
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 0. INICJALIZACJA DOMYŚLNYCH USTAWIEŃ FIRM (jeśli nie istnieją)
|
||||
// ---------------------------------------------------------
|
||||
$default_settings = [
|
||||
'company_1_name' => 'Moje Przedsiębiorstwo IT',
|
||||
'company_1_details' => 'ul. Główna 1, 00-000 Warszawa | NIP: 0987654321',
|
||||
'company_2_name' => 'Spółka Celowa Sp. z o.o.',
|
||||
'company_2_details' => 'ul. Przykładowa 10, 00-000 Warszawa | NIP: 1234567890 | KRS: 0000123456'
|
||||
];
|
||||
|
||||
foreach ($default_settings as $key => $val) {
|
||||
// INSERT IGNORE dodaje wpis tylko wtedy, gdy taki klucz jeszcze nie istnieje w tabeli
|
||||
$stmt = $pdo->prepare("INSERT IGNORE INTO " . DB_PREFIX . "settings (setting_key, setting_value) VALUES (?, ?)");
|
||||
$stmt->execute([$key, $val]);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 1. WGRYWANIE LOGO
|
||||
// ---------------------------------------------------------
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_FILES['logo'])) {
|
||||
if ($_FILES['logo']['error'] === 0) {
|
||||
$upload_dir = 'uploads/';
|
||||
if (!is_dir($upload_dir)) mkdir($upload_dir, 0777, true);
|
||||
|
||||
$file_ext = strtolower(pathinfo($_FILES['logo']['name'], PATHINFO_EXTENSION));
|
||||
if(in_array($file_ext, ['jpg', 'jpeg', 'png', 'gif', 'svg'])) {
|
||||
$new_name = 'logo_' . time() . '.' . $file_ext;
|
||||
$dest_path = $upload_dir . $new_name;
|
||||
|
||||
if (move_uploaded_file($_FILES['logo']['tmp_name'], $dest_path)) {
|
||||
$stmt = $pdo->prepare("REPLACE INTO " . DB_PREFIX . "settings (setting_key, setting_value) VALUES ('logo_path', ?)");
|
||||
$stmt->execute([$dest_path]);
|
||||
$message = "<div class='alert alert-success'>Pomyślnie zaktualizowano logo!</div>";
|
||||
} else {
|
||||
$message = "<div class='alert alert-danger'>Błąd: Nie udało się zapisać pliku. Sprawdź uprawnienia folderu 'uploads'.</div>";
|
||||
}
|
||||
} else {
|
||||
$message = "<div class='alert alert-warning'>Błąd: Dozwolone są tylko pliki graficzne (JPG, PNG, GIF, SVG).</div>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 1B. ZAPISYWANIE DANYCH FIRM
|
||||
// ---------------------------------------------------------
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'update_company_settings') {
|
||||
$settings_to_update = ['company_1_name', 'company_1_details', 'company_2_name', 'company_2_details'];
|
||||
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
$update_stmt = $pdo->prepare("UPDATE " . DB_PREFIX . "settings SET setting_value = ? WHERE setting_key = ?");
|
||||
|
||||
foreach ($settings_to_update as $key) {
|
||||
if (isset($_POST[$key])) {
|
||||
$update_stmt->execute([trim($_POST[$key]), $key]);
|
||||
}
|
||||
}
|
||||
$pdo->commit();
|
||||
$message = "<div class='alert alert-success'>Ustawienia firmowe zostały zapisane!</div>";
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
$message = "<div class='alert alert-danger'>Błąd zapisu: " . $e->getMessage() . "</div>";
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 2. DODAWANIE UŻYTKOWNIKA
|
||||
// ---------------------------------------------------------
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['add_user'])) {
|
||||
$new_user = trim($_POST['new_username']);
|
||||
$new_pass = $_POST['new_password'];
|
||||
$new_role = $_POST['new_role'];
|
||||
|
||||
if (!empty($new_user) && !empty($new_pass)) {
|
||||
try {
|
||||
$hashed_pass = password_hash($new_pass, PASSWORD_BCRYPT);
|
||||
$stmt = $pdo->prepare("INSERT INTO " . DB_PREFIX . "users (username, password, role) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$new_user, $hashed_pass, $new_role]);
|
||||
$message = "<div class='alert alert-success'>Dodano nowego użytkownika: <strong>$new_user</strong></div>";
|
||||
} catch (PDOException $e) {
|
||||
$message = "<div class='alert alert-danger'>Błąd: Użytkownik o takiej nazwie prawdopodobnie już istnieje.</div>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 3. RESET HASŁA UŻYTKOWNIKA
|
||||
// ---------------------------------------------------------
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['reset_password'])) {
|
||||
$user_id = (int)$_POST['user_id'];
|
||||
$new_pass = $_POST['new_password'];
|
||||
|
||||
if (!empty($new_pass)) {
|
||||
$hashed_pass = password_hash($new_pass, PASSWORD_BCRYPT);
|
||||
$stmt = $pdo->prepare("UPDATE " . DB_PREFIX . "users SET password = ? WHERE id = ?");
|
||||
$stmt->execute([$hashed_pass, $user_id]);
|
||||
$message = "<div class='alert alert-info'>Zmieniono hasło dla wybranego użytkownika.</div>";
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 4. USUWANIE UŻYTKOWNIKA
|
||||
// ---------------------------------------------------------
|
||||
if (isset($_GET['delete'])) {
|
||||
$id_to_delete = (int)$_GET['delete'];
|
||||
if ($id_to_delete != $_SESSION['user_id']) {
|
||||
$stmt = $pdo->prepare("DELETE FROM " . DB_PREFIX . "users WHERE id = ?");
|
||||
$stmt->execute([$id_to_delete]);
|
||||
$message = "<div class='alert alert-success'>Użytkownik został pomyślnie usunięty.</div>";
|
||||
} else {
|
||||
$message = "<div class='alert alert-warning'>Odmowa: Nie możesz usunąć własnego konta administratora!</div>";
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// POBIERANIE DANYCH DO WIDOKU
|
||||
// ---------------------------------------------------------
|
||||
$users = $pdo->query("SELECT id, username, role FROM " . DB_PREFIX . "users")->fetchAll();
|
||||
|
||||
$settings = [];
|
||||
try {
|
||||
$settings = $pdo->query("SELECT setting_key, setting_value FROM " . DB_PREFIX . "settings")->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
} catch(PDOException $e) {
|
||||
// Zabezpieczenie na wypadek awarii tabeli settings
|
||||
}
|
||||
|
||||
$current_logo = $settings['logo_path'] ?? '';
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="pl" data-bs-theme="light" id="mainHtml">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Panel Administratora - <?php echo defined('APP_NAME') ? APP_NAME : 'System'; ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
|
||||
<style>
|
||||
.logo-img { max-height: 40px; width: auto; }
|
||||
.transition-colors { transition: background-color 0.3s ease, color 0.3s ease; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-body-tertiary transition-colors">
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-4 shadow-sm">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="index.php">
|
||||
<?php if($current_logo && file_exists($current_logo)): ?>
|
||||
<img src="<?php echo $current_logo; ?>" alt="Logo" class="logo-img me-2">
|
||||
<?php else: ?>
|
||||
<span class="me-2">💻</span>
|
||||
<?php endif; ?>
|
||||
<strong><?php echo defined('APP_NAME') ? APP_NAME : 'System IT'; ?></strong>
|
||||
</a>
|
||||
|
||||
<div class="navbar-nav ms-auto align-items-center">
|
||||
<button class="btn btn-sm btn-outline-secondary me-3" onclick="toggleDarkMode()">
|
||||
<i class="bi bi-moon-stars" id="themeIcon"></i>
|
||||
</button>
|
||||
<span class="nav-link text-light me-3 small">Admin: <strong><?php echo $_SESSION['username']; ?></strong></span>
|
||||
<a class="btn btn-outline-light btn-sm me-2" href="index.php"><i class="bi bi-arrow-left"></i> Powrót do zamówień</a>
|
||||
<a class="btn btn-outline-danger btn-sm" href="logout.php">Wyloguj</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container pb-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Panel Zarządzania Systemem</h2>
|
||||
</div>
|
||||
|
||||
<?php echo $message; ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-5 mb-4">
|
||||
|
||||
<div class="card shadow-sm mb-4 border-0">
|
||||
<div class="card-header bg-secondary text-white">
|
||||
<i class="bi bi-image"></i> Ustawienia Wizualne
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<div class="text-center mb-3">
|
||||
<?php if($current_logo && file_exists($current_logo)): ?>
|
||||
<img src="<?php echo $current_logo; ?>" class="img-thumbnail" style="max-height: 80px;">
|
||||
<?php else: ?>
|
||||
<div class="text-muted small">Brak wgranego logo</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small">Zmień logotyp (PNG/JPG)</label>
|
||||
<input type="file" name="logo" class="form-control form-control-sm" accept="image/*" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-dark w-100 btn-sm">Wgraj plik na serwer</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-header bg-info text-dark fw-bold">
|
||||
<i class="bi bi-buildings"></i> Dane firm (Stopki wydruków)
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST">
|
||||
<input type="hidden" name="action" value="update_company_settings">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label small fw-bold text-primary">1. Przedsiębiorstwo (Nazwa)</label>
|
||||
<input type="text" name="company_1_name" class="form-control form-control-sm border-primary" value="<?php echo htmlspecialchars($settings['company_1_name'] ?? ''); ?>" required>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label small fw-bold text-primary">Przedsiębiorstwo (Adres/NIP)</label>
|
||||
<input type="text" name="company_1_details" class="form-control form-control-sm" value="<?php echo htmlspecialchars($settings['company_1_details'] ?? ''); ?>">
|
||||
</div>
|
||||
|
||||
<div class="mb-3 border-top pt-3">
|
||||
<label class="form-label small fw-bold text-success">2. Spółka (Nazwa)</label>
|
||||
<input type="text" name="company_2_name" class="form-control form-control-sm border-success" value="<?php echo htmlspecialchars($settings['company_2_name'] ?? ''); ?>" required>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label small fw-bold text-success">Spółka (Adres/NIP/KRS)</label>
|
||||
<input type="text" name="company_2_details" class="form-control form-control-sm" value="<?php echo htmlspecialchars($settings['company_2_details'] ?? ''); ?>">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-info w-100 btn-sm fw-bold text-dark"><i class="bi bi-save"></i> Zapisz stopki firm</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<i class="bi bi-person-plus"></i> Dodaj pracownika
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST">
|
||||
<div class="mb-3">
|
||||
<label class="form-label small">Login użytkownika</label>
|
||||
<input type="text" name="new_username" class="form-control" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small">Hasło początkowe</label>
|
||||
<input type="password" name="new_password" class="form-control" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small">Rola w systemie</label>
|
||||
<select name="new_role" class="form-select">
|
||||
<option value="user">Zwykły pracownik</option>
|
||||
<option value="admin">Administrator</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" name="add_user" class="btn btn-primary w-100"><i class="bi bi-check2-circle"></i> Utwórz konto</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-7">
|
||||
<div class="card shadow-sm text-nowrap border-0">
|
||||
<div class="card-header bg-dark text-white">
|
||||
<i class="bi bi-people"></i> Zarejestrowani pracownicy
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0 align-middle">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th class="px-3">ID</th>
|
||||
<th>Login</th>
|
||||
<th>Uprawnienia</th>
|
||||
<th class="text-end px-4">Zarządzaj</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($users as $u): ?>
|
||||
<tr>
|
||||
<td class="px-3 text-muted"><?php echo $u['id']; ?></td>
|
||||
<td><strong><?php echo htmlspecialchars($u['username']); ?></strong></td>
|
||||
<td>
|
||||
<span class="badge <?php echo $u['role'] == 'admin' ? 'bg-danger' : 'bg-primary'; ?>">
|
||||
<?php echo $u['role'] == 'admin' ? 'Administrator' : 'Użytkownik'; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end px-3">
|
||||
<button class="btn btn-sm btn-outline-info me-1" data-bs-toggle="modal" data-bs-target="#resetModal<?php echo $u['id']; ?>">
|
||||
<i class="bi bi-shield-lock"></i> Reset hasła
|
||||
</button>
|
||||
|
||||
<?php if ($u['id'] != $_SESSION['user_id']): ?>
|
||||
<a href="?delete=<?php echo $u['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Czy na pewno chcesz bezpowrotnie usunąć to konto?')">
|
||||
<i class="bi bi-trash"></i> Usuń
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<button class="btn btn-sm btn-outline-secondary disabled"><i class="bi bi-person-check"></i> To ty</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="modal fade" id="resetModal<?php echo $u['id']; ?>" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm modal-dialog-centered">
|
||||
<div class="modal-content text-start">
|
||||
<form method="POST">
|
||||
<div class="modal-header bg-light">
|
||||
<h6 class="modal-title"><i class="bi bi-key"></i> Nowe hasło: <?php echo $u['username']; ?></h6>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" name="user_id" value="<?php echo $u['id']; ?>">
|
||||
<label class="form-label small">Wpisz nowe hasło:</label>
|
||||
<input type="password" name="new_password" class="form-control" required minlength="4">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Anuluj</button>
|
||||
<button type="submit" name="reset_password" class="btn btn-info btn-sm text-white">Zapisz hasło</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleDarkMode() {
|
||||
const html = document.getElementById('mainHtml');
|
||||
const icon = document.getElementById('themeIcon');
|
||||
const currentTheme = html.getAttribute('data-bs-theme');
|
||||
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
|
||||
|
||||
html.setAttribute('data-bs-theme', newTheme);
|
||||
icon.classList.toggle('bi-moon-stars', newTheme === 'light');
|
||||
icon.classList.toggle('bi-sun', newTheme === 'dark');
|
||||
localStorage.setItem('theme', newTheme);
|
||||
}
|
||||
|
||||
if(localStorage.getItem('theme') === 'dark') {
|
||||
document.getElementById('mainHtml').setAttribute('data-bs-theme', 'dark');
|
||||
document.getElementById('themeIcon').classList.replace('bi-moon-stars', 'bi-sun');
|
||||
}
|
||||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
checkAuth();
|
||||
|
||||
header('Content-Type: application/json');
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (!$data || empty($data['action']) || empty($data['id'])) {
|
||||
die(json_encode(['success' => false, 'error' => 'Brak danych']));
|
||||
}
|
||||
|
||||
$id = (int)$data['id'];
|
||||
$action = $data['action'];
|
||||
|
||||
try {
|
||||
if ($action === 'archive') {
|
||||
$stmt = $pdo->prepare("UPDATE " . DB_PREFIX . "orders SET is_archived = 1 WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
|
||||
$hist = $pdo->prepare("INSERT INTO " . DB_PREFIX . "order_history (order_id, user_id, action) VALUES (?, ?, ?)");
|
||||
$hist->execute([$id, $_SESSION['user_id'], 'Przeniesiono zamówienie do archiwum.']);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
|
||||
} elseif ($action === 'duplicate') {
|
||||
// Pobierz oryginał
|
||||
$stmt = $pdo->prepare("SELECT * FROM " . DB_PREFIX . "orders WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$orig = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$orig) {
|
||||
die(json_encode(['success' => false, 'error' => 'Nie znaleziono zamówienia']));
|
||||
}
|
||||
|
||||
// Zapisz kopię (zawsze jako nowe, nie zarchiwizowane)
|
||||
$insert = $pdo->prepare("INSERT INTO " . DB_PREFIX . "orders
|
||||
(product_name, part_number, quantity, purchase_place, price_per_unit, delivery_date, notes, recipient, delivery_address, company, status, is_archived)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'nowe', 0)");
|
||||
|
||||
$insert->execute([
|
||||
$orig['product_name'] . ' (Kopia)',
|
||||
$orig['part_number'],
|
||||
$orig['quantity'],
|
||||
$orig['purchase_place'],
|
||||
$orig['price_per_unit'],
|
||||
$orig['delivery_date'],
|
||||
$orig['notes'],
|
||||
$orig['recipient'],
|
||||
$orig['delivery_address'],
|
||||
$orig['company']
|
||||
]);
|
||||
|
||||
$new_id = $pdo->lastInsertId();
|
||||
|
||||
$hist = $pdo->prepare("INSERT INTO " . DB_PREFIX . "order_history (order_id, user_id, action) VALUES (?, ?, ?)");
|
||||
$hist->execute([$new_id, $_SESSION['user_id'], "Sklonowano na podstawie archiwalnego/starego zamówienia #$id."]);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
} else {
|
||||
echo json_encode(['success' => false, 'error' => 'Nieznana akcja']);
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
?>
|
||||
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
checkAuth();
|
||||
|
||||
header('Content-Type: application/json');
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (!$data || empty(trim($data['product_name']))) {
|
||||
die(json_encode(['success' => false, 'error' => 'Nazwa produktu jest wymagana!']));
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO " . DB_PREFIX . "orders (product_name, quantity, purchase_place, price_per_unit, status) VALUES (?, ?, ?, ?, 'nowe')");
|
||||
|
||||
$price = (float)str_replace(',', '.', $data['price_per_unit'] ?? 0);
|
||||
$qty = (int)($data['quantity'] ?? 1);
|
||||
|
||||
$stmt->execute([
|
||||
trim($data['product_name']),
|
||||
$qty,
|
||||
trim($data['purchase_place'] ?? ''),
|
||||
$price
|
||||
]);
|
||||
|
||||
$new_id = $pdo->lastInsertId();
|
||||
|
||||
$hist = $pdo->prepare("INSERT INTO " . DB_PREFIX . "order_history (order_id, user_id, action) VALUES (?, ?, ?)");
|
||||
$hist->execute([$new_id, $_SESSION['user_id'], "Utworzono zamówienie (szybkie dodawanie na liście)."]);
|
||||
|
||||
$pdo->commit();
|
||||
echo json_encode(['success' => true]);
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
?>
|
||||
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
checkAuth();
|
||||
|
||||
header('Content-Type: application/json');
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (!$data || !isset($data['id'], $data['field'], $data['value'])) {
|
||||
die(json_encode(['success' => false, 'error' => 'Brak danych']));
|
||||
}
|
||||
|
||||
$id = (int)$data['id'];
|
||||
$field = $data['field'];
|
||||
$value = trim($data['value']);
|
||||
|
||||
// TUTAJ JEST MAGIA: dodano 'company' na końcu listy
|
||||
$allowed_fields = ['product_name', 'quantity', 'purchase_place', 'price_per_unit', 'delivery_date', 'status', 'recipient', 'delivery_address', 'notes', 'company'];
|
||||
|
||||
if (!in_array($field, $allowed_fields)) {
|
||||
die(json_encode(['success' => false, 'error' => 'Niedozwolona kolumna']));
|
||||
}
|
||||
|
||||
$field_labels = [
|
||||
'product_name' => 'Produkt',
|
||||
'quantity' => 'Ilość',
|
||||
'purchase_place' => 'Miejsce zakupu',
|
||||
'price_per_unit' => 'Cena za sztukę',
|
||||
'delivery_date' => 'Data dostawy',
|
||||
'status' => 'Status',
|
||||
'recipient' => 'Odbiorca',
|
||||
'delivery_address' => 'Adres dostawy',
|
||||
'notes' => 'Notatki',
|
||||
'company' => 'Firma kupująca'
|
||||
];
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT $field FROM " . DB_PREFIX . "orders WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$old_val = $stmt->fetchColumn();
|
||||
|
||||
if ((string)$old_val !== (string)$value) {
|
||||
if ($field === 'price_per_unit') {
|
||||
$value = (float)str_replace(',', '.', $value);
|
||||
}
|
||||
|
||||
$update = $pdo->prepare("UPDATE " . DB_PREFIX . "orders SET $field = ? WHERE id = ?");
|
||||
$update->execute([$value, $id]);
|
||||
|
||||
$label = $field_labels[$field] ?? $field;
|
||||
$old_display = $old_val ?: '(brak)';
|
||||
$new_display = $value ?: '(brak)';
|
||||
$hist_msg = "Szybka edycja: $label zmieniono z [$old_display] ➔ [$new_display]";
|
||||
|
||||
$hist = $pdo->prepare("INSERT INTO " . DB_PREFIX . "order_history (order_id, user_id, action) VALUES (?, ?, ?)");
|
||||
$hist->execute([$id, $_SESSION['user_id'], $hist_msg]);
|
||||
}
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
} catch (PDOException $e) {
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
?>
|
||||
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
checkAuth();
|
||||
|
||||
$message = '';
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$old_pass = $_POST['old_password'];
|
||||
$new_pass = $_POST['new_password'];
|
||||
$confirm_pass = $_POST['confirm_password'];
|
||||
|
||||
if ($new_pass !== $confirm_pass) {
|
||||
$message = '<div class="alert alert-danger">Nowe hasła nie są identyczne!</div>';
|
||||
} else {
|
||||
// Pobierz aktualne hasło z bazy
|
||||
$stmt = $pdo->prepare("SELECT password FROM " . DB_PREFIX . "users WHERE id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if (password_verify($old_pass, $user['password'])) {
|
||||
// Hasło poprawne - aktualizujemy
|
||||
$new_hash = password_hash($new_pass, PASSWORD_BCRYPT);
|
||||
$update = $pdo->prepare("UPDATE " . DB_PREFIX . "users SET password = ? WHERE id = ?");
|
||||
$update->execute([$new_hash, $_SESSION['user_id']]);
|
||||
$message = '<div class="alert alert-success">Hasło zostało zmienione pomyślnie!</div>';
|
||||
} else {
|
||||
$message = '<div class="alert alert-danger">Obecne hasło jest nieprawidłowe.</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Zmiana hasła - <?php echo APP_NAME; ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<div class="container py-5">
|
||||
<div class="card shadow mx-auto" style="max-width: 450px;">
|
||||
<div class="card-header bg-dark text-white">
|
||||
<h5 class="mb-0">Zmiana hasła</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php echo $message; ?>
|
||||
<form method="POST">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Obecne hasło</label>
|
||||
<input type="password" name="old_password" class="form-control" required>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Nowe hasło</label>
|
||||
<input type="password" name="new_password" class="form-control" required minlength="5">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Powtórz nowe hasło</label>
|
||||
<input type="password" name="confirm_password" class="form-control" required>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="index.php" class="btn btn-secondary">Powrót</a>
|
||||
<button type="submit" class="btn btn-primary">Zmień hasło</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,322 @@
|
||||
<?php
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
checkAuth();
|
||||
|
||||
$message = '';
|
||||
$id = $_GET['id'] ?? 0;
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM " . DB_PREFIX . "orders WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
if (!$order) {
|
||||
die("Zamówienie nie istnieje.");
|
||||
}
|
||||
|
||||
// 1. OBSŁUGA ZMIANY STATUSU ARCHIWUM
|
||||
if (isset($_POST['archive_action'])) {
|
||||
$new_archive_status = $order['is_archived'] ? 0 : 1;
|
||||
|
||||
$update_arch = $pdo->prepare("UPDATE " . DB_PREFIX . "orders SET is_archived = ? WHERE id = ?");
|
||||
$update_arch->execute([$new_archive_status, $id]);
|
||||
|
||||
$action_msg = $new_archive_status ? "Przeniesiono do archiwum." : "Przywrócono z archiwum do aktualnych.";
|
||||
$hist_arch = $pdo->prepare("INSERT INTO " . DB_PREFIX . "order_history (order_id, user_id, action) VALUES (?, ?, ?)");
|
||||
$hist_arch->execute([$id, $_SESSION['user_id'], $action_msg]);
|
||||
|
||||
// Wracamy na listę, uwzględniając czy lądujemy w archiwum czy nie
|
||||
$redirect_url = $new_archive_status ? "index.php?archive=1" : "index.php";
|
||||
header("Location: $redirect_url");
|
||||
exit();
|
||||
}
|
||||
|
||||
// 2. OBSŁUGA DODAWANIA KOMENTARZA
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['add_comment'])) {
|
||||
$comment_text = trim($_POST['comment_text'] ?? '');
|
||||
|
||||
if (!empty($comment_text)) {
|
||||
try {
|
||||
$ins_comm = $pdo->prepare("INSERT INTO " . DB_PREFIX . "order_comments (order_id, user_id, comment_text) VALUES (?, ?, ?)");
|
||||
$ins_comm->execute([$id, $_SESSION['user_id'], $comment_text]);
|
||||
|
||||
// Przeładowanie strony (PRG - Post/Redirect/Get), aby uniknąć ponownego wysłania przy odświeżaniu F5
|
||||
header("Location: edit_order.php?id=" . $id);
|
||||
exit();
|
||||
} catch (PDOException $e) {
|
||||
$message = "<div class='alert alert-danger'>Błąd zapisu komentarza: " . $e->getMessage() . "</div>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. OBSŁUGA STANDARDOWEJ EDYCJI
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && !isset($_POST['archive_action']) && !isset($_POST['add_comment'])) {
|
||||
$product_name = trim($_POST['product_name'] ?? '');
|
||||
$part_number = trim($_POST['part_number'] ?? '');
|
||||
$quantity = (int)$_POST['quantity'];
|
||||
$purchase_place = trim($_POST['purchase_place'] ?? '');
|
||||
$status = $_POST['status'];
|
||||
$price = (float)str_replace(',', '.', $_POST['price_per_unit'] ?? '0');
|
||||
$delivery_date = $_POST['delivery_date'] ?? null;
|
||||
$notes = trim($_POST['notes'] ?? '');
|
||||
$recipient = trim($_POST['recipient'] ?? '');
|
||||
$delivery_address = trim($_POST['delivery_address'] ?? '');
|
||||
$company = trim($_POST['company'] ?? '');
|
||||
|
||||
$changes = [];
|
||||
if (($order['company'] ?? '') !== $company) $changes[] = "Firma: [{$order['company']}] ➔ [$company]";
|
||||
if (($order['product_name'] ?? '') !== $product_name) $changes[] = "Produkt: [{$order['product_name']}] ➔ [$product_name]";
|
||||
if (($order['part_number'] ?? '') !== $part_number) $changes[] = "PN: [{$order['part_number']}] ➔ [$part_number]";
|
||||
if ((int)$order['quantity'] !== $quantity) $changes[] = "Ilość: [{$order['quantity']}] ➔ [$quantity]";
|
||||
if (($order['purchase_place'] ?? '') !== $purchase_place) $changes[] = "Sklep: [{$order['purchase_place']}] ➔ [$purchase_place]";
|
||||
if (($order['status'] ?? '') !== $status) $changes[] = "Status: [{$order['status']}] ➔ [$status]";
|
||||
if ((float)$order['price_per_unit'] !== $price) $changes[] = "Cena: [{$order['price_per_unit']}] ➔ [$price]";
|
||||
if (($order['delivery_date'] ?? '') !== $delivery_date) $changes[] = "Dostawa: [{$order['delivery_date']}] ➔ [$delivery_date]";
|
||||
if (($order['recipient'] ?? '') !== $recipient) $changes[] = "Odbiorca: [{$order['recipient']}] ➔ [$recipient]";
|
||||
if (($order['delivery_address'] ?? '') !== $delivery_address) $changes[] = "Adres: [{$order['delivery_address']}] ➔ [$delivery_address]";
|
||||
if (($order['notes'] ?? '') !== $notes) $changes[] = "Zaktualizowano notatki";
|
||||
|
||||
if (!empty($changes)) {
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
$update = $pdo->prepare("UPDATE " . DB_PREFIX . "orders SET
|
||||
product_name=?, part_number=?, quantity=?, purchase_place=?, status=?, price_per_unit=?, delivery_date=?, notes=?, recipient=?, delivery_address=?, company=?
|
||||
WHERE id=?");
|
||||
$update->execute([$product_name, $part_number, $quantity, $purchase_place, $status, $price, $delivery_date, $notes, $recipient, $delivery_address, $company, $id]);
|
||||
|
||||
$action_text = "Zmieniono: " . implode(', ', $changes);
|
||||
$hist = $pdo->prepare("INSERT INTO " . DB_PREFIX . "order_history (order_id, user_id, action) VALUES (?, ?, ?)");
|
||||
$hist->execute([$id, $_SESSION['user_id'], $action_text]);
|
||||
|
||||
$pdo->commit();
|
||||
$message = "<div class='alert alert-success'>Zmiany zostały zapisane!</div>";
|
||||
|
||||
$stmt->execute([$id]);
|
||||
$order = $stmt->fetch();
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
$message = "<div class='alert alert-danger'>Błąd bazy: " . $e->getMessage() . "</div>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// POBIERANIE HISTORII
|
||||
$hist_sql = "SELECT h.action, h.created_at, u.username
|
||||
FROM " . DB_PREFIX . "order_history h
|
||||
LEFT JOIN " . DB_PREFIX . "users u ON h.user_id = u.id
|
||||
WHERE h.order_id = ?
|
||||
ORDER BY h.created_at DESC";
|
||||
$hist_stmt = $pdo->prepare($hist_sql);
|
||||
$hist_stmt->execute([$id]);
|
||||
$history = $hist_stmt->fetchAll();
|
||||
|
||||
// POBIERANIE KOMENTARZY
|
||||
$comm_sql = "SELECT c.comment_text, c.created_at, u.username
|
||||
FROM " . DB_PREFIX . "order_comments c
|
||||
LEFT JOIN " . DB_PREFIX . "users u ON c.user_id = u.id
|
||||
WHERE c.order_id = ?
|
||||
ORDER BY c.created_at DESC";
|
||||
$comm_stmt = $pdo->prepare($comm_sql);
|
||||
$comm_stmt->execute([$id]);
|
||||
$comments = $comm_stmt->fetchAll();
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Karta Zamówienia - <?php echo APP_NAME; ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
|
||||
<nav class="navbar navbar-expand navbar-dark bg-dark mb-4 shadow-sm position-relative">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center m-0" href="index.php">
|
||||
<?php
|
||||
$logo_path = $pdo->query("SELECT setting_value FROM " . DB_PREFIX . "settings WHERE setting_key = 'logo_path'")->fetchColumn();
|
||||
if($logo_path && file_exists($logo_path)): ?>
|
||||
<img src="<?php echo $logo_path; ?>" alt="Logo" style="max-height: 40px; width: auto;">
|
||||
<?php else: ?>
|
||||
<span class="fs-4">💻</span>
|
||||
<?php endif; ?>
|
||||
</a>
|
||||
<div class="position-absolute top-50 start-50 translate-middle text-white fw-bold d-none d-md-block" style="font-size: 1.15rem; letter-spacing: 0.5px;">
|
||||
<?php echo APP_NAME; ?>
|
||||
</div>
|
||||
<div class="d-flex ms-auto align-items-center gap-2">
|
||||
<span class="text-light small d-none d-lg-inline me-2">Witaj, <strong><?php echo $_SESSION['username']; ?></strong></span>
|
||||
<a class="btn btn-outline-danger btn-sm" href="logout.php">Wyloguj</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container pb-5">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-7 mb-4">
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header bg-dark text-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-box-seam"></i> Edycja zamówienia #<?php echo $id; ?>
|
||||
<?php if ($order['is_archived']): ?>
|
||||
<span class="badge bg-secondary ms-2"><i class="bi bi-archive"></i> Archiwum</span>
|
||||
<?php endif; ?>
|
||||
</h5>
|
||||
<a href="index.php<?php echo $order['is_archived'] ? '?archive=1' : ''; ?>" class="btn btn-sm btn-outline-light"><i class="bi bi-arrow-left"></i> Powrót</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php echo $message; ?>
|
||||
<form method="POST">
|
||||
|
||||
<div class="mb-3 p-2 bg-success bg-opacity-10 border border-success rounded">
|
||||
<label class="form-label small fw-bold text-success"><i class="bi bi-building"></i> Firma kupująca</label>
|
||||
<select name="company" class="form-select border-success">
|
||||
<option value="" <?php if(empty($order['company'])) echo 'selected'; ?>>Wybierz firmę...</option>
|
||||
<option value="Przedsiębiorstwo" <?php if(($order['company']??'')=='Przedsiębiorstwo') echo 'selected'; ?>>Przedsiębiorstwo</option>
|
||||
<option value="Spółka" <?php if(($order['company']??'')=='Spółka') echo 'selected'; ?>>Spółka</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-8">
|
||||
<label class="form-label small fw-bold">Nazwa produktu</label>
|
||||
<input type="text" name="product_name" class="form-control" value="<?php echo htmlspecialchars($order['product_name'] ?? ''); ?>" required>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold">PN (Part Number)</label>
|
||||
<input type="text" name="part_number" class="form-control" placeholder="np. 90NB0W..." value="<?php echo htmlspecialchars($order['part_number'] ?? ''); ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small fw-bold">Ilość</label>
|
||||
<input type="number" name="quantity" class="form-control" value="<?php echo $order['quantity']; ?>" required min="1">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold">Cena za szt.</label>
|
||||
<div class="input-group">
|
||||
<input type="text" name="price_per_unit" class="form-control" value="<?php echo $order['price_per_unit']; ?>">
|
||||
<span class="input-group-text">zł</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<label class="form-label small fw-bold">Miejsce zakupu</label>
|
||||
<input type="text" name="purchase_place" class="form-control" value="<?php echo htmlspecialchars($order['purchase_place'] ?? ''); ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold">Szacowana data dostawy</label>
|
||||
<input type="date" name="delivery_date" class="form-control" value="<?php echo $order['delivery_date'] ?? ''; ?>">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold text-danger">Bieżący Status</label>
|
||||
<select name="status" class="form-select border-danger">
|
||||
<option value="nowe" <?php if($order['status']=='nowe') echo 'selected'; ?>>Nowe</option>
|
||||
<option value="w trakcie realizacji" <?php if($order['status']=='w trakcie realizacji') echo 'selected'; ?>>W trakcie</option>
|
||||
<option value="zrealizowane" <?php if($order['status']=='zrealizowane') echo 'selected'; ?>>Zrealizowane</option>
|
||||
<option value="anulowane" <?php if($order['status']=='anulowane') echo 'selected'; ?>>Anulowane</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-3 bg-light border rounded mb-3">
|
||||
<div class="row">
|
||||
<div class="col-md-5 mb-2 mb-md-0">
|
||||
<label class="form-label small fw-bold text-primary">Odbiorca / Projekt</label>
|
||||
<input type="text" name="recipient" class="form-control form-control-sm" value="<?php echo htmlspecialchars($order['recipient'] ?? ''); ?>">
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<label class="form-label small fw-bold text-primary">Adres dostawy</label>
|
||||
<textarea name="delivery_address" class="form-control form-control-sm" rows="1"><?php echo htmlspecialchars($order['delivery_address'] ?? ''); ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="form-label small fw-bold">Notatki wewnętrzne</label>
|
||||
<textarea name="notes" class="form-control" rows="3"><?php echo htmlspecialchars($order['notes'] ?? ''); ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
<button type="submit" name="archive_action" value="1" class="btn btn-outline-secondary" formnovalidate>
|
||||
<i class="bi bi-archive"></i> <?php echo $order['is_archived'] ? 'Przywróć z archiwum' : 'Zarchiwizuj zamówienie'; ?>
|
||||
</button>
|
||||
<button type="submit" class="btn btn-success px-4"><i class="bi bi-save"></i> Zapisz modyfikacje</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5">
|
||||
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<i class="bi bi-chat-text"></i> Komentarze i ustalenia
|
||||
</div>
|
||||
<div class="card-body bg-light">
|
||||
<form method="POST" class="mb-3">
|
||||
<div class="input-group shadow-sm">
|
||||
<textarea name="comment_text" class="form-control" rows="2" placeholder="Wpisz nowy komentarz..." required></textarea>
|
||||
<button type="submit" name="add_comment" class="btn btn-primary px-3"><i class="bi bi-send"></i></button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="comments-list" style="max-height: 350px; overflow-y: auto;">
|
||||
<?php if (empty($comments)): ?>
|
||||
<div class="text-muted small text-center p-3 border rounded bg-white">Brak komentarzy. Bądź pierwszy!</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($comments as $c): ?>
|
||||
<div class="card mb-2 border-0 shadow-sm">
|
||||
<div class="card-body p-2 px-3">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1 border-bottom pb-1">
|
||||
<strong class="small text-primary"><i class="bi bi-person-circle"></i> <?php echo htmlspecialchars($c['username']); ?></strong>
|
||||
<span class="text-muted" style="font-size: 0.70rem;"><?php echo date('d.m.Y H:i', strtotime($c['created_at'])); ?></span>
|
||||
</div>
|
||||
<div class="small mt-1 text-dark" style="line-height: 1.4;">
|
||||
<?php echo nl2br(htmlspecialchars($c['comment_text'])); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-header bg-info text-dark">
|
||||
<i class="bi bi-clock-history"></i> Historia zmian
|
||||
</div>
|
||||
<div class="card-body p-0" style="max-height: 300px; overflow-y: auto;">
|
||||
<ul class="list-group list-group-flush">
|
||||
<?php if (empty($history)): ?>
|
||||
<li class="list-group-item text-muted small">Brak zapisanej historii modyfikacji.</li>
|
||||
<?php else: ?>
|
||||
<?php foreach ($history as $h): ?>
|
||||
<li class="list-group-item p-3">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<strong class="small text-primary"><i class="bi bi-person"></i> <?php echo htmlspecialchars($h['username'] ?? 'System'); ?></strong>
|
||||
<span class="text-muted" style="font-size: 0.75rem;"><?php echo date('d.m.Y H:i', strtotime($h['created_at'])); ?></span>
|
||||
</div>
|
||||
<div class="small text-secondary">
|
||||
<?php echo htmlspecialchars($h['action']); ?>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
checkAuth();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['order_ids'])) {
|
||||
$ids = $_POST['order_ids'];
|
||||
|
||||
// Tworzenie znaków zapytania do zapytania SQL (np. ?, ?, ?)
|
||||
$placeholders = str_repeat('?,', count($ids) - 1) . '?';
|
||||
|
||||
// Pobieranie zaznaczonych rekordów
|
||||
$sql = "SELECT * FROM " . DB_PREFIX . "orders WHERE id IN ($placeholders) ORDER BY id DESC";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($ids);
|
||||
$orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Ustawienia nagłówków dla przeglądarki, by wymusić pobieranie pliku
|
||||
header('Content-Type: text/csv; charset=utf-8');
|
||||
header('Content-Disposition: attachment; filename=zamowienia_' . date('Ymd_Hi') . '.csv');
|
||||
|
||||
// Wymuszenie BOM (dzięki temu Excel od razu poprawnie przeczyta polskie znaki w UTF-8)
|
||||
echo "\xEF\xBB\xBF";
|
||||
|
||||
$output = fopen('php://output', 'w');
|
||||
|
||||
// Zapisanie nagłówków kolumn (zwróć uwagę na średniki, które lubi polski Excel)
|
||||
fputcsv($output, ['ID', 'Produkt', 'Part Number', 'Ilosc', 'Miejsce zakupu', 'Cena szt.', 'Data dostawy', 'Odbiorca', 'Adres dostawy', 'Status', 'Notatki'], ';');
|
||||
|
||||
// Zapisywanie danych
|
||||
foreach ($orders as $o) {
|
||||
fputcsv($output, [
|
||||
$o['id'],
|
||||
$o['product_name'],
|
||||
$o['part_number'],
|
||||
$o['quantity'],
|
||||
$o['purchase_place'],
|
||||
number_format($o['price_per_unit'], 2, ',', ''), // Cena z przecinkiem dla Excela
|
||||
$o['delivery_date'],
|
||||
$o['recipient'],
|
||||
$o['delivery_address'],
|
||||
$o['status'],
|
||||
$o['notes']
|
||||
], ';');
|
||||
}
|
||||
|
||||
fclose($output);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Jeśli ktoś wszedł tu bezpośrednio lub nic nie zaznaczył, wracamy do indexu
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
?>
|
||||
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
|
||||
checkAuth();
|
||||
|
||||
$message = '';
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_FILES['csv_file'])) {
|
||||
$file = $_FILES['csv_file']['tmp_name'];
|
||||
|
||||
if (($handle = fopen($file, "r")) !== FALSE) {
|
||||
// Pomijamy pierwszy wiersz (nagłówki)
|
||||
fgetcsv($handle, 1000, ";");
|
||||
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
$sql = "INSERT INTO " . DB_PREFIX . "orders
|
||||
(product_name, quantity, purchase_place, price_per_unit, delivery_date, notes, status)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
|
||||
$count = 0;
|
||||
while (($row = fgetcsv($handle, 1000, ";")) !== FALSE) {
|
||||
// $row[0] to LP - pomijamy zgodnie z wymaganiem
|
||||
|
||||
// Obsługa polskich znaków (jeśli plik jest w Windows-1250)
|
||||
foreach($row as $key => $value) {
|
||||
$row[$key] = mb_convert_encoding($value, "UTF-8", "auto");
|
||||
}
|
||||
|
||||
if (empty($row[1])) continue; // Pomiń jeśli brak nazwy produktu
|
||||
|
||||
$stmt->execute([
|
||||
$row[1], // Produkt
|
||||
(int)$row[2], // Ilość
|
||||
$row[3], // Miejsce zakupu
|
||||
(float)str_replace(',', '.', $row[4]), // Cena (zamiana przecinka na kropkę)
|
||||
$row[5], // Data dostawy
|
||||
$row[6], // Notatki
|
||||
$row[7] ?? 'nowe' // Status
|
||||
]);
|
||||
$count++;
|
||||
}
|
||||
$pdo->commit();
|
||||
$message = "<div class='alert alert-success'>Zaimportowano $count zamówień z pliku CSV!</div>";
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
$message = "<div class='alert alert-danger'>Błąd: " . $e->getMessage() . "</div>";
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Import CSV - <?php echo APP_NAME; ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<div class="container py-5">
|
||||
<div class="card shadow mx-auto" style="max-width: 600px;">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h4 class="mb-0">Import z pliku CSV</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php echo $message; ?>
|
||||
|
||||
<div class="alert alert-warning small">
|
||||
<strong>Ważne:</strong> W Excelu wybierz <em>Zapisz jako</em> -> <strong>CSV (rozdzielany średnikami)</strong>.
|
||||
</div>
|
||||
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Wybierz plik .csv</label>
|
||||
<input type="file" name="csv_file" class="form-control" accept=".csv" required>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="index.php" class="btn btn-secondary">Powrót</a>
|
||||
<button type="submit" class="btn btn-success">Importuj dane</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
require 'vendor/autoload.php'; // Ładowanie biblioteki PhpSpreadsheet
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
|
||||
checkAuth();
|
||||
|
||||
$message = '';
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_FILES['excel_file'])) {
|
||||
$file = $_FILES['excel_file']['tmp_name'];
|
||||
|
||||
try {
|
||||
$spreadsheet = IOFactory::load($file);
|
||||
$worksheet = $spreadsheet->getActiveSheet();
|
||||
$rows = $worksheet->toArray();
|
||||
|
||||
// Pomijamy nagłówek (pierwszy wiersz w Excelu)
|
||||
unset($rows[0]);
|
||||
|
||||
$pdo->beginTransaction();
|
||||
$sql = "INSERT INTO " . DB_PREFIX . "orders
|
||||
(product_name, quantity, purchase_place, price_per_unit, delivery_date, notes, status)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
|
||||
$count = 0;
|
||||
foreach ($rows as $row) {
|
||||
// Zgodnie z wymaganiem: pomijamy 1. kolumnę ($row[0])
|
||||
// Mapowanie kolumn Excela:
|
||||
// $row[1] -> Produkt, $row[2] -> Ilość, $row[3] -> Miejsce,
|
||||
// $row[4] -> Cena, $row[5] -> Data, $row[6] -> Notatki, $row[7] -> Status
|
||||
|
||||
if (empty($row[1])) continue; // Pomiń puste wiersze
|
||||
|
||||
$stmt->execute([
|
||||
$row[1], // Produkt
|
||||
(int)$row[2], // Ilość
|
||||
$row[3], // Miejsce zakupu
|
||||
(float)$row[4], // Cena
|
||||
$row[5], // Data dostawy (format YYYY-MM-DD)
|
||||
$row[6], // Notatki
|
||||
$row[7] ?? 'nowe' // Status
|
||||
]);
|
||||
$count++;
|
||||
}
|
||||
$pdo->commit();
|
||||
$message = "<div class='alert alert-success'>Pomyślnie zaimportowano $count zamówień!</div>";
|
||||
|
||||
} catch (Exception $e) {
|
||||
if ($pdo->inTransaction()) $pdo->rollBack();
|
||||
$message = "<div class='alert alert-danger'>Błąd importu: " . $e->getMessage() . "</div>";
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Import Zamówień - <?php echo APP_NAME; ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<div class="container py-5">
|
||||
<div class="card shadow mx-auto" style="max-width: 600px;">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h4 class="mb-0">Import z pliku Excel (.xlsx)</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php echo $message; ?>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<strong>Instrukcja:</strong><br>
|
||||
1. System pomija pierwszą kolumnę (LP).<br>
|
||||
2. Kolejne kolumny to: Produkt, Ilość, Miejsce, Cena, Data (RRRR-MM-DD), Notatki, Status.
|
||||
</div>
|
||||
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Wybierz plik Excel</label>
|
||||
<input type="file" name="excel_file" class="form-control" accept=".xlsx, .xls" required>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="index.php" class="btn btn-secondary">Powrót</a>
|
||||
<button type="submit" class="btn btn-success">Rozpocznij import</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
// Funkcja sprawdzająca czy użytkownik jest zalogowany
|
||||
function checkAuth() {
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header("Location: login.php");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// Funkcja sprawdzająca czy użytkownik jest adminem
|
||||
function checkAdmin() {
|
||||
if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
|
||||
die("Błąd: Brak uprawnień administratora.");
|
||||
}
|
||||
}
|
||||
?>
|
||||
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
// Dane do połączenia z bazą
|
||||
define('DB_HOST', '');
|
||||
define('DB_NAME', '');
|
||||
define('DB_USER', ''); // Zmień na swojego użytkownika bazy
|
||||
define('DB_PASS', ''); // Zmień na swoje hasło
|
||||
define('DB_PREFIX', '');
|
||||
|
||||
// Ustawienia aplikacji
|
||||
define('APP_NAME', ' Zeszyt 2.0');
|
||||
?>
|
||||
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
require_once 'config.php';
|
||||
|
||||
try {
|
||||
$dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4";
|
||||
$options = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
|
||||
$pdo = new PDO($dsn, DB_USER, DB_PASS, $options);
|
||||
} catch (\PDOException $e) {
|
||||
throw new \PDOException($e->getMessage(), (int)$e->getCode());
|
||||
}
|
||||
?>
|
||||
@ -0,0 +1,620 @@
|
||||
<?php
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
checkAuth();
|
||||
|
||||
$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 25;
|
||||
$page = isset($_GET['p']) ? (int)$_GET['p'] : 1;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
// CZY JESTEŚMY W ARCHIWUM?
|
||||
$is_archived = isset($_GET['archive']) && $_GET['archive'] == '1' ? 1 : 0;
|
||||
|
||||
$status_filter = $_GET['status'] ?? '';
|
||||
$date_from = $_GET['date_from'] ?? '';
|
||||
$date_to = $_GET['date_to'] ?? '';
|
||||
$search_query = trim($_GET['q'] ?? '');
|
||||
|
||||
$sort_col = $_GET['sort'] ?? 'id';
|
||||
$sort_dir = strtolower($_GET['dir'] ?? 'desc');
|
||||
|
||||
$allowed_sort_cols = ['id' => 'id', 'product_name' => 'product_name', 'quantity' => 'quantity', 'purchase_place' => 'purchase_place', 'price_per_unit' => 'price_per_unit', 'delivery_date' => 'delivery_date', 'status' => 'status'];
|
||||
if (!array_key_exists($sort_col, $allowed_sort_cols)) $sort_col = 'id';
|
||||
if ($sort_dir !== 'asc' && $sort_dir !== 'desc') $sort_dir = 'desc';
|
||||
|
||||
function getSortLink($col_key, $label, $current_sort, $current_dir) {
|
||||
global $status_filter, $date_from, $date_to, $search_query, $limit, $is_archived;
|
||||
$new_dir = ($current_sort === $col_key && $current_dir === 'asc') ? 'desc' : 'asc';
|
||||
$icon = ($current_sort === $col_key) ? ($current_dir === 'asc' ? '<i class="bi bi-sort-up"></i>' : '<i class="bi bi-sort-down"></i>') : '<i class="bi bi-arrow-down-up opacity-50" style="font-size: 0.8em;"></i>';
|
||||
$text_class = ($current_sort === $col_key) ? 'text-warning' : 'text-white';
|
||||
|
||||
// Dodano parametr 'archive' do linków sortowania
|
||||
$params = ['archive' => $is_archived, 'status' => $status_filter, 'date_from' => $date_from, 'date_to' => $date_to, 'q' => $search_query, 'limit' => $limit, 'sort' => $col_key, 'dir' => $new_dir];
|
||||
$url = '?' . http_build_query($params);
|
||||
return "<a href=\"$url\" class=\"$text_class text-decoration-none d-flex align-items-center gap-1\">$label $icon</a>";
|
||||
}
|
||||
|
||||
// BAZOWY WARUNEK ARCHIWUM
|
||||
$where = ["is_archived = ?"];
|
||||
$params = [$is_archived];
|
||||
|
||||
if ($status_filter) { $where[] = "status = ?"; $params[] = $status_filter; }
|
||||
if ($date_from) { $where[] = "delivery_date >= ?"; $params[] = $date_from; }
|
||||
if ($date_to) { $where[] = "delivery_date <= ?"; $params[] = $date_to; }
|
||||
if ($search_query !== '') {
|
||||
$where[] = "(product_name LIKE ? OR part_number LIKE ? OR purchase_place LIKE ? OR recipient LIKE ? OR delivery_address LIKE ? OR notes LIKE ? OR company LIKE ?)";
|
||||
$like_term = "%" . $search_query . "%";
|
||||
for ($i = 0; $i < 7; $i++) { $params[] = $like_term; }
|
||||
}
|
||||
$where_sql = implode(" AND ", $where);
|
||||
|
||||
$count_stmt = $pdo->prepare("SELECT COUNT(*) FROM " . DB_PREFIX . "orders WHERE $where_sql");
|
||||
$count_stmt->execute($params);
|
||||
$total_rows = $count_stmt->fetchColumn();
|
||||
$total_pages = ceil($total_rows / $limit);
|
||||
|
||||
$sql = "SELECT * FROM " . DB_PREFIX . "orders WHERE $where_sql ORDER BY $sort_col $sort_dir LIMIT $limit OFFSET $offset";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$orders = $stmt->fetchAll();
|
||||
|
||||
$logo_path = $pdo->query("SELECT setting_value FROM " . DB_PREFIX . "settings WHERE setting_key = 'logo_path'")->fetchColumn() ?: 'assets/default_logo.png';
|
||||
|
||||
function getStatusClass($status) {
|
||||
return match($status) {
|
||||
'nowe' => 'bg-info text-dark',
|
||||
'w trakcie realizacji' => 'bg-warning text-dark',
|
||||
'zrealizowane' => 'bg-success',
|
||||
'anulowane' => 'bg-danger',
|
||||
default => 'bg-secondary',
|
||||
};
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="pl" data-bs-theme="light" id="mainHtml">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title><?php echo $is_archived ? 'Archiwum' : 'Zamówienia IT'; ?> - <?php echo APP_NAME; ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
|
||||
<style>
|
||||
.logo-img { max-height: 40px; width: auto; }
|
||||
.table-container { background: var(--bs-body-bg); border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
|
||||
.transition-colors { transition: background-color 0.3s ease, color 0.3s ease; }
|
||||
th a:hover { opacity: 0.8; }
|
||||
|
||||
.editable { cursor: pointer; border-bottom: 1px dashed #ccc; padding-bottom: 1px; transition: 0.2s; min-width: 40px; display: inline-block; }
|
||||
.editable:hover { background-color: rgba(0, 123, 255, 0.1); }
|
||||
.inline-input { border: 1px solid #0d6efd; border-radius: 4px; padding: 2px 5px; font-size: inherit; width: 100%; box-sizing: border-box; }
|
||||
|
||||
.sub-row td { border-top: none; padding-top: 0; padding-bottom: 12px; }
|
||||
.sub-row-content { display: flex; gap: 20px; font-size: 0.85em; background: rgba(0,0,0,0.02); padding: 8px 12px; border-radius: 6px; flex-wrap: wrap; }
|
||||
[data-bs-theme="dark"] .sub-row-content { background: rgba(255,255,255,0.05); }
|
||||
|
||||
.inline-add-row td { background-color: rgba(25, 135, 84, 0.1) !important; padding: 8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-body-tertiary transition-colors">
|
||||
|
||||
<nav class="navbar navbar-expand navbar-dark bg-dark mb-4 shadow-sm position-relative">
|
||||
<div class="container">
|
||||
|
||||
<a class="navbar-brand d-flex align-items-center m-0" href="index.php">
|
||||
<?php if(file_exists($logo_path)): ?>
|
||||
<img src="<?php echo $logo_path; ?>" alt="Logo" class="logo-img">
|
||||
<?php else: ?>
|
||||
<span class="fs-4">💻</span>
|
||||
<?php endif; ?>
|
||||
</a>
|
||||
|
||||
<div class="position-absolute top-50 start-50 translate-middle text-white fw-bold d-none d-md-block" style="font-size: 1.15rem; letter-spacing: 0.5px;">
|
||||
<?php echo APP_NAME; ?>
|
||||
</div>
|
||||
|
||||
<div class="d-flex ms-auto align-items-center gap-2">
|
||||
<button class="btn btn-sm btn-outline-secondary" onclick="toggleDarkMode()"><i class="bi bi-moon-stars" id="themeIcon"></i></button>
|
||||
<span class="text-light small d-none d-lg-inline me-2">Witaj, <strong><?php echo $_SESSION['username']; ?></strong></span>
|
||||
<a class="btn btn-outline-light btn-sm" href="change_password.php"><i class="bi bi-key"></i> Hasło</a>
|
||||
<?php if ($_SESSION['role'] === 'admin'): ?>
|
||||
<a class="btn btn-outline-warning btn-sm" href="admin.php"><i class="bi bi-gear"></i> Admin</a>
|
||||
<?php endif; ?>
|
||||
<a class="btn btn-outline-danger btn-sm" href="logout.php">Wyloguj</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
<div class="d-flex flex-wrap justify-content-between align-items-center mb-4 gap-3">
|
||||
<h2 class="mb-0 d-flex align-items-center gap-2">
|
||||
<?php if ($is_archived): ?>
|
||||
<i class="bi bi-archive text-secondary"></i> Archiwum zamówień
|
||||
<?php else: ?>
|
||||
<i class="bi bi-list-task text-primary"></i> Lista zamówień
|
||||
<?php endif; ?>
|
||||
</h2>
|
||||
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<?php if ($is_archived): ?>
|
||||
<a href="index.php" class="btn btn-outline-primary fw-bold"><i class="bi bi-calendar2-check"></i> Widok Aktualnych</a>
|
||||
<?php else: ?>
|
||||
<a href="?archive=1" class="btn btn-outline-secondary fw-bold"><i class="bi bi-archive"></i> Widok Archiwum</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<button type="submit" form="bulkForm" formaction="export_csv.php" class="btn btn-success"><i class="bi bi-filetype-csv"></i> Eksportuj</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#printModal"><i class="bi bi-list-ul"></i> Drukuj listę</button>
|
||||
<button type="button" class="btn btn-warning text-dark fw-bold" data-bs-toggle="modal" data-bs-target="#deliveryModal"><i class="bi bi-truck"></i> Drukuj dostawę</button>
|
||||
<a href="import_csv.php" class="btn btn-success"><i class="bi bi-file-earmark-spreadsheet"></i> Import</a>
|
||||
<a href="add_order.php" class="btn btn-primary"><i class="bi bi-plus-circle"></i> Pełny formularz</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3 border-0 shadow-sm <?php echo $is_archived ? 'bg-secondary bg-opacity-10' : ''; ?>">
|
||||
<div class="card-body p-3">
|
||||
<form method="GET" class="row g-2 align-items-end">
|
||||
<input type="hidden" name="archive" value="<?php echo $is_archived; ?>">
|
||||
<input type="hidden" name="sort" value="<?php echo htmlspecialchars($sort_col); ?>">
|
||||
<input type="hidden" name="dir" value="<?php echo htmlspecialchars($sort_dir); ?>">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small fw-bold"><i class="bi bi-search"></i> Szukaj tekstu</label>
|
||||
<input type="text" name="q" class="form-control form-control-sm" value="<?php echo htmlspecialchars($search_query); ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label small fw-bold">Status</label>
|
||||
<select name="status" class="form-select form-select-sm">
|
||||
<option value="">Wszystkie</option>
|
||||
<option value="nowe" <?php if($status_filter=='nowe') echo 'selected'; ?>>Nowe</option>
|
||||
<option value="w trakcie realizacji" <?php if($status_filter=='w trakcie realizacji') echo 'selected'; ?>>W trakcie</option>
|
||||
<option value="zrealizowane" <?php if($status_filter=='zrealizowane') echo 'selected'; ?>>Zrealizowane</option>
|
||||
<option value="anulowane" <?php if($status_filter=='anulowane') echo 'selected'; ?>>Anulowane</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label small fw-bold">Data od</label>
|
||||
<input type="date" name="date_from" class="form-control form-control-sm" value="<?php echo $date_from; ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label small fw-bold">Data do</label>
|
||||
<input type="date" name="date_to" class="form-control form-control-sm" value="<?php echo $date_to; ?>">
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
<label class="form-label small fw-bold">Wyników</label>
|
||||
<select name="limit" class="form-select form-select-sm">
|
||||
<option value="25" <?php if($limit==25) echo 'selected'; ?>>25</option>
|
||||
<option value="50" <?php if($limit==50) echo 'selected'; ?>>50</option>
|
||||
<option value="100" <?php if($limit==100) echo 'selected'; ?>>100</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-1"><button type="submit" class="btn btn-sm btn-dark w-100"><i class="bi bi-funnel"></i></button></div>
|
||||
<div class="col-md-1"><a href="index.php<?php echo $is_archived ? '?archive=1' : ''; ?>" class="btn btn-sm btn-outline-secondary w-100">Reset</a></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="POST" id="bulkForm">
|
||||
<div class="table-container p-0 overflow-hidden mb-3">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0 align-middle">
|
||||
<thead class="table-dark user-select-none">
|
||||
<tr>
|
||||
<th class="px-3" style="width: 40px;"><input class="form-check-input" type="checkbox" id="selectAll"></th>
|
||||
<th style="width: 60px;"><?php echo getSortLink('id', 'ID', $sort_col, $sort_dir); ?></th>
|
||||
<th><?php echo getSortLink('product_name', 'Produkt', $sort_col, $sort_dir); ?></th>
|
||||
<th style="width: 60px;"><?php echo getSortLink('quantity', 'Szt.', $sort_col, $sort_dir); ?></th>
|
||||
<th><?php echo getSortLink('purchase_place', 'Miejsce', $sort_col, $sort_dir); ?></th>
|
||||
<th style="width: 100px;"><?php echo getSortLink('price_per_unit', 'Cena', $sort_col, $sort_dir); ?></th>
|
||||
<th style="width: 120px;"><?php echo getSortLink('delivery_date', 'Dostawa', $sort_col, $sort_dir); ?></th>
|
||||
<th style="width: 120px;"><?php echo getSortLink('status', 'Status', $sort_col, $sort_dir); ?></th>
|
||||
<th class="text-center" style="width: 130px;">Akcje</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="ordersTableBody">
|
||||
<?php if (empty($orders)): ?>
|
||||
<tr><td colspan="9" class="text-center py-4 text-muted">Brak wyników w tej sekcji.</td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($orders as $order): ?>
|
||||
<tr class="main-row" data-id="<?php echo $order['id']; ?>">
|
||||
<td class="px-3"><input class="form-check-input row-checkbox" type="checkbox" name="order_ids[]" value="<?php echo $order['id']; ?>"></td>
|
||||
<td class="text-muted">#<?php echo $order['id']; ?></td>
|
||||
<td>
|
||||
<strong class="editable" data-field="product_name" data-val="<?php echo htmlspecialchars($order['product_name']); ?>"><?php echo htmlspecialchars($order['product_name']); ?></strong>
|
||||
<?php if (!empty($order['part_number'])): ?>
|
||||
<br><span class="text-muted" style="font-size: 0.75em;">PN: <?php echo htmlspecialchars($order['part_number']); ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><span class="editable" data-field="quantity" data-val="<?php echo $order['quantity']; ?>"><?php echo $order['quantity']; ?></span></td>
|
||||
<td>
|
||||
<span class="editable" data-field="purchase_place" data-val="<?php echo htmlspecialchars($order['purchase_place'] ?? ''); ?>">
|
||||
<?php echo !empty($order['purchase_place']) ? htmlspecialchars($order['purchase_place']) : '<i class="text-muted small opacity-50">kliknij...</i>'; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><span class="editable" data-field="price_per_unit" data-val="<?php echo number_format($order['price_per_unit'], 2, '.', ''); ?>"><?php echo number_format($order['price_per_unit'], 2, '.', ''); ?></span> zł</td>
|
||||
<td>
|
||||
<span class="editable" data-field="delivery_date" data-val="<?php echo $order['delivery_date'] ?? ''; ?>">
|
||||
<?php echo !empty($order['delivery_date']) ? $order['delivery_date'] : '<i class="text-muted small opacity-50">dodaj datę</i>'; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><span class="badge <?php echo getStatusClass($order['status']); ?> editable" data-field="status" data-val="<?php echo $order['status']; ?>"><?php echo $order['status']; ?></span></td>
|
||||
<td class="text-center">
|
||||
<a href="edit_order.php?id=<?php echo $order['id']; ?>" class="btn btn-sm btn-outline-primary mb-1" title="Edycja"><i class="bi bi-pencil"></i></a>
|
||||
|
||||
<button type="button" class="btn btn-sm btn-outline-success mb-1" onclick="performAction(<?php echo $order['id']; ?>, 'duplicate')" title="Klonuj/Duplikuj"><i class="bi bi-copy"></i></button>
|
||||
|
||||
<?php if (!$is_archived): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary mb-1" onclick="performAction(<?php echo $order['id']; ?>, 'archive')" title="Zarchiwizuj"><i class="bi bi-archive"></i></button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="sub-row" data-id="<?php echo $order['id']; ?>">
|
||||
<td></td>
|
||||
<td colspan="8">
|
||||
<div class="sub-row-content">
|
||||
<div class="view-col view-company" style="display: none;">
|
||||
<span class="text-muted"><i class="bi bi-building"></i> Firma:</span>
|
||||
<strong class="editable text-success" data-field="company" data-val="<?php echo htmlspecialchars($order['company'] ?? ''); ?>">
|
||||
<?php echo !empty($order['company']) ? htmlspecialchars($order['company']) : '<i class="text-muted small opacity-50">wybierz firmę</i>'; ?>
|
||||
</strong>
|
||||
</div>
|
||||
<div class="view-col view-recipient" style="display: none;">
|
||||
<span class="text-muted">Odbiorca:</span>
|
||||
<strong class="editable text-primary" data-field="recipient" data-val="<?php echo htmlspecialchars($order['recipient'] ?? ''); ?>">
|
||||
<?php echo !empty($order['recipient']) ? htmlspecialchars($order['recipient']) : '<i class="text-muted small opacity-50">kliknij aby dodać</i>'; ?>
|
||||
</strong>
|
||||
</div>
|
||||
<div class="view-col view-address" style="display: none;">
|
||||
<span class="text-muted">Adres:</span>
|
||||
<span class="editable" data-field="delivery_address" data-val="<?php echo htmlspecialchars($order['delivery_address'] ?? ''); ?>">
|
||||
<?php echo !empty($order['delivery_address']) ? htmlspecialchars($order['delivery_address']) : '<i class="text-muted small opacity-50">kliknij aby dodać</i>'; ?>
|
||||
</span>
|
||||
</div>
|
||||
<div class="view-col view-notes" style="display: none;">
|
||||
<span class="text-muted"><i class="bi bi-sticky"></i> Notatki:</span>
|
||||
<em class="editable" data-field="notes" data-val="<?php echo htmlspecialchars($order['notes'] ?? ''); ?>">
|
||||
<?php echo !empty($order['notes']) ? htmlspecialchars($order['notes']) : '<i class="text-muted small opacity-50">kliknij aby dodać</i>'; ?>
|
||||
</em>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="printModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-light">
|
||||
<h6 class="modal-title"><i class="bi bi-printer"></i> Ustawienia wydruku</h6>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="small text-muted mb-3">Wybierz kolumny na papierze:</p>
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" name="print_cols[]" value="id" checked> <label class="form-check-label small">ID</label></div>
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" name="print_cols[]" value="product" checked> <label class="form-check-label small">Produkt (oraz PN)</label></div>
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" name="print_cols[]" value="quantity" checked> <label class="form-check-label small">Ilość</label></div>
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" name="print_cols[]" value="place" checked> <label class="form-check-label small">Miejsce</label></div>
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" name="print_cols[]" value="price" checked> <label class="form-check-label small">Cena</label></div>
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" name="print_cols[]" value="recipient" checked> <label class="form-check-label small">Odbiorca</label></div>
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" name="print_cols[]" value="address"> <label class="form-check-label small text-primary">Adres</label></div>
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" name="print_cols[]" value="status" checked> <label class="form-check-label small">Status</label></div>
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" name="print_cols[]" value="notes"> <label class="form-check-label small text-primary">Notatki</label></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" formaction="print.php" formtarget="_blank" class="btn btn-sm btn-primary w-100" onclick="setTimeout(()=>$('#printModal').modal('hide'), 500);">Generuj wydruk</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="deliveryModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-warning text-dark">
|
||||
<h6 class="modal-title fw-bold"><i class="bi bi-truck"></i> Generuj Dokument Dostawy</h6>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold">Typ dokumentu:</label>
|
||||
<select name="doc_type" class="form-select form-select-sm">
|
||||
<option value="Protokół odbioru">Protokół odbioru</option>
|
||||
<option value="List przewozowy">List przewozowy</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold text-success">Wystawca dokumentu:</label>
|
||||
<select name="company_footer" class="form-select form-select-sm border-success">
|
||||
<option value="Przedsiębiorstwo">Przedsiębiorstwo</option>
|
||||
<option value="Spółka">Spółka</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small fw-bold">Wspólny adres dostawy:</label>
|
||||
<textarea name="global_delivery_address" class="form-control" rows="2" placeholder="Wpisz nazwę działu..."></textarea>
|
||||
</div>
|
||||
<div class="row mb-3 bg-light p-2 border rounded mx-0">
|
||||
<div class="col-6">
|
||||
<label class="form-label small fw-bold text-muted">Wydał (Imię/Nazwisko):</label>
|
||||
<input type="text" name="issued_by" class="form-control form-control-sm" value="<?php echo htmlspecialchars($_SESSION['username']); ?>">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small fw-bold text-muted">Odebrał (Opcjonalnie):</label>
|
||||
<input type="text" name="received_by" class="form-control form-control-sm" placeholder="Kto odbierze?">
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<p class="small text-muted mb-2">Kolumny na wydruku:</p>
|
||||
<div class="d-flex flex-wrap gap-3">
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" name="delivery_cols[]" value="id" checked> <label class="form-check-label small">ID</label></div>
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" name="delivery_cols[]" value="product" checked> <label class="form-check-label small">Produkt</label></div>
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" name="delivery_cols[]" value="quantity" checked> <label class="form-check-label small">Ilość</label></div>
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" name="delivery_cols[]" value="notes" checked> <label class="form-check-label small">Notatki</label></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" formaction="print_delivery.php" formtarget="_blank" class="btn btn-warning text-dark fw-bold w-100" onclick="setTimeout(()=>$('#deliveryModal').modal('hide'), 500);">Utwórz Dokument</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-5 flex-wrap gap-3">
|
||||
<button class="btn btn-info text-dark shadow-sm fw-bold" data-bs-toggle="modal" data-bs-target="#viewModal">
|
||||
<i class="bi bi-layout-three-columns"></i> Widok kolumn
|
||||
</button>
|
||||
|
||||
<?php if ($total_pages > 1): ?>
|
||||
<ul class="pagination pagination-sm mb-0">
|
||||
<?php for($i=1; $i<=$total_pages; $i++): ?>
|
||||
<li class="page-item <?php echo ($page == $i) ? 'active' : ''; ?>">
|
||||
<a class="page-link" href="?p=<?php echo $i; ?>&archive=<?php echo $is_archived; ?>&limit=<?php echo $limit; ?>&status=<?php echo urlencode($status_filter); ?>&date_from=<?php echo urlencode($date_from); ?>&date_to=<?php echo urlencode($date_to); ?>&q=<?php echo urlencode($search_query); ?>&sort=<?php echo urlencode($sort_col); ?>&dir=<?php echo urlencode($sort_dir); ?>"><?php echo $i; ?></a>
|
||||
</li>
|
||||
<?php endfor; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
|
||||
<button type="button" class="btn btn-primary shadow-sm" id="btn-inline-add">
|
||||
<i class="bi bi-plus-circle"></i> Dodaj wiersz
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="viewModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-light">
|
||||
<h6 class="modal-title"><i class="bi bi-eye"></i> Pokaż pod zamówieniem:</h6>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-check form-switch mb-2">
|
||||
<input class="form-check-input view-toggle" type="checkbox" id="toggle-company" value="company">
|
||||
<label class="form-check-label fw-bold text-success" for="toggle-company">Firma kupująca</label>
|
||||
</div>
|
||||
<div class="form-check form-switch mb-2">
|
||||
<input class="form-check-input view-toggle" type="checkbox" id="toggle-recipient" value="recipient">
|
||||
<label class="form-check-label" for="toggle-recipient">Odbiorca / Projekt</label>
|
||||
</div>
|
||||
<div class="form-check form-switch mb-2">
|
||||
<input class="form-check-input view-toggle" type="checkbox" id="toggle-address" value="address">
|
||||
<label class="form-check-label" for="toggle-address">Adres dostawy</label>
|
||||
</div>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input view-toggle" type="checkbox" id="toggle-notes" value="notes">
|
||||
<label class="form-check-label" for="toggle-notes">Notatki wewnętrzne</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-sm btn-info text-dark w-100 fw-bold" data-bs-dismiss="modal">Zapisz i zamknij</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function performAction(orderId, actionType) {
|
||||
let confirmMsg = actionType === 'archive'
|
||||
? "Czy na pewno chcesz przenieść to zamówienie do archiwum?"
|
||||
: "Zduplikować to zamówienie?";
|
||||
|
||||
if (!confirm(confirmMsg)) return;
|
||||
|
||||
try {
|
||||
let response = await fetch('ajax_action.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id: orderId, action: actionType })
|
||||
});
|
||||
let resData = await response.json();
|
||||
|
||||
if(resData.success) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert("Błąd: " + resData.error);
|
||||
}
|
||||
} catch(err) {
|
||||
alert("Błąd połączenia z serwerem.");
|
||||
}
|
||||
}
|
||||
|
||||
// 1. ZARZĄDZANIE WIDOKIEM
|
||||
function applyViewSettings() {
|
||||
let savedView = JSON.parse(localStorage.getItem('orderViewSettings')) || ['notes', 'company'];
|
||||
document.querySelectorAll('.view-col').forEach(el => el.style.display = 'none');
|
||||
document.querySelectorAll('.sub-row').forEach(row => row.style.display = 'none');
|
||||
document.querySelectorAll('.view-toggle').forEach(checkbox => {
|
||||
checkbox.checked = savedView.includes(checkbox.value);
|
||||
if (checkbox.checked) {
|
||||
document.querySelectorAll('.view-' + checkbox.value).forEach(el => el.style.display = 'block');
|
||||
document.querySelectorAll('.sub-row').forEach(row => row.style.display = 'table-row');
|
||||
}
|
||||
});
|
||||
}
|
||||
document.querySelectorAll('.view-toggle').forEach(checkbox => {
|
||||
checkbox.addEventListener('change', function() {
|
||||
let active = [];
|
||||
document.querySelectorAll('.view-toggle:checked').forEach(cb => active.push(cb.value));
|
||||
localStorage.setItem('orderViewSettings', JSON.stringify(active));
|
||||
applyViewSettings();
|
||||
});
|
||||
});
|
||||
applyViewSettings();
|
||||
|
||||
// 2. EDYCJA W LOCIE
|
||||
document.querySelectorAll('.editable').forEach(cell => {
|
||||
cell.addEventListener('dblclick', function() {
|
||||
if (this.querySelector('input') || this.querySelector('select')) return;
|
||||
|
||||
let currentText = this.getAttribute('data-val') || '';
|
||||
let fieldName = this.getAttribute('data-field');
|
||||
let orderId = this.closest('tr').getAttribute('data-id');
|
||||
let originalHTML = this.innerHTML;
|
||||
|
||||
let inputHTML = '';
|
||||
if (fieldName === 'status') {
|
||||
inputHTML = `
|
||||
<select class="inline-input">
|
||||
<option value="nowe" ${currentText=='nowe'?'selected':''}>Nowe</option>
|
||||
<option value="w trakcie realizacji" ${currentText=='w trakcie realizacji'?'selected':''}>W trakcie</option>
|
||||
<option value="zrealizowane" ${currentText=='zrealizowane'?'selected':''}>Zrealizowane</option>
|
||||
<option value="anulowane" ${currentText=='anulowane'?'selected':''}>Anulowane</option>
|
||||
</select>`;
|
||||
} else if (fieldName === 'company') {
|
||||
inputHTML = `
|
||||
<select class="inline-input border-success">
|
||||
<option value="" ${currentText==''?'selected':''}>Wybierz...</option>
|
||||
<option value="Przedsiębiorstwo" ${currentText=='Przedsiębiorstwo'?'selected':''}>Przedsiębiorstwo</option>
|
||||
<option value="Spółka" ${currentText=='Spółka'?'selected':''}>Spółka</option>
|
||||
</select>`;
|
||||
} else if (fieldName === 'delivery_date') {
|
||||
inputHTML = `<input type="date" class="inline-input" value="${currentText}">`;
|
||||
} else if (fieldName === 'quantity' || fieldName === 'price_per_unit') {
|
||||
inputHTML = `<input type="number" step="0.01" class="inline-input" style="width: 70px;" value="${currentText}">`;
|
||||
} else {
|
||||
inputHTML = `<input type="text" class="inline-input" value="${currentText}">`;
|
||||
}
|
||||
|
||||
this.innerHTML = inputHTML;
|
||||
let inputElement = this.querySelector('.inline-input');
|
||||
inputElement.focus();
|
||||
|
||||
let saveEdits = async () => {
|
||||
let newValue = inputElement.value.trim();
|
||||
if(newValue === currentText) {
|
||||
this.innerHTML = originalHTML;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
let response = await fetch('ajax_edit.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id: orderId, field: fieldName, value: newValue })
|
||||
});
|
||||
let resData = await response.json();
|
||||
if(resData.success) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert("Błąd zapisu: " + resData.error);
|
||||
this.innerHTML = originalHTML;
|
||||
}
|
||||
} catch (err) {
|
||||
alert("Wystąpił błąd komunikacji z serwerem.");
|
||||
this.innerHTML = originalHTML;
|
||||
}
|
||||
};
|
||||
|
||||
inputElement.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Enter') saveEdits();
|
||||
if (e.key === 'Escape') cell.innerHTML = originalHTML;
|
||||
});
|
||||
inputElement.addEventListener('blur', saveEdits);
|
||||
});
|
||||
});
|
||||
|
||||
// 3. SZYBKIE DODAWANIE WIERSZA (Tym razem widoczne zawsze!)
|
||||
const btnInlineAdd = document.getElementById('btn-inline-add');
|
||||
if(btnInlineAdd) {
|
||||
btnInlineAdd.addEventListener('click', function() {
|
||||
if(document.getElementById('inline-add-row')) return;
|
||||
|
||||
const tbody = document.getElementById('ordersTableBody');
|
||||
const tr = document.createElement('tr');
|
||||
tr.id = 'inline-add-row';
|
||||
tr.className = 'inline-add-row';
|
||||
tr.innerHTML = `
|
||||
<td></td>
|
||||
<td class="text-muted"><span class="badge bg-info text-dark">Nowe</span></td>
|
||||
<td><input type="text" class="form-control form-control-sm border-primary" id="add-prod" placeholder="Nazwa produktu..."></td>
|
||||
<td><input type="number" class="form-control form-control-sm border-primary" id="add-qty" value="1" style="width: 60px;"></td>
|
||||
<td><input type="text" class="form-control form-control-sm border-primary" id="add-place" placeholder="Sklep..."></td>
|
||||
<td><input type="text" class="form-control form-control-sm border-primary" id="add-price" placeholder="0.00" style="width: 80px;"></td>
|
||||
<td class="text-muted small">Brak</td>
|
||||
<td><span class="badge bg-secondary">nowe</span></td>
|
||||
<td class="text-center">
|
||||
<button type="button" class="btn btn-sm btn-success mb-1" onclick="saveInlineRow()" title="Zapisz"><i class="bi bi-check-lg"></i></button>
|
||||
<button type="button" class="btn btn-sm btn-danger mb-1" onclick="this.closest('tr').remove()" title="Anuluj"><i class="bi bi-x-lg"></i></button>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(tr);
|
||||
tr.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
document.getElementById('add-prod').focus();
|
||||
});
|
||||
}
|
||||
|
||||
async function saveInlineRow() {
|
||||
const prod = document.getElementById('add-prod').value;
|
||||
const qty = document.getElementById('add-qty').value;
|
||||
const place = document.getElementById('add-place').value;
|
||||
const price = document.getElementById('add-price').value;
|
||||
|
||||
if(!prod) { alert("Nazwa produktu jest obowiązkowa!"); document.getElementById('add-prod').focus(); return; }
|
||||
|
||||
try {
|
||||
let response = await fetch('ajax_add_row.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ product_name: prod, quantity: qty, purchase_place: place, price_per_unit: price })
|
||||
});
|
||||
let resData = await response.json();
|
||||
|
||||
if(resData.success) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert("Błąd zapisu: " + resData.error);
|
||||
}
|
||||
} catch(err) {
|
||||
alert("Błąd połączenia z serwerem.");
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('selectAll').addEventListener('change', function() {
|
||||
let checkboxes = document.querySelectorAll('.row-checkbox');
|
||||
for (let checkbox of checkboxes) { checkbox.checked = this.checked; }
|
||||
});
|
||||
|
||||
function toggleDarkMode() {
|
||||
const html = document.getElementById('mainHtml');
|
||||
const icon = document.getElementById('themeIcon');
|
||||
const newTheme = html.getAttribute('data-bs-theme') === 'light' ? 'dark' : 'light';
|
||||
html.setAttribute('data-bs-theme', newTheme);
|
||||
icon.classList.toggle('bi-moon-stars', newTheme === 'light');
|
||||
icon.classList.toggle('bi-sun', newTheme === 'dark');
|
||||
localStorage.setItem('theme', newTheme);
|
||||
}
|
||||
if(localStorage.getItem('theme') === 'dark') {
|
||||
document.getElementById('mainHtml').setAttribute('data-bs-theme', 'dark');
|
||||
document.getElementById('themeIcon').classList.replace('bi-moon-stars', 'bi-sun');
|
||||
}
|
||||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
// 1. Włączenie raportowania błędów (na czas testów)
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
// 2. Start sesji - musi być na samym początku, przed jakimkolwiek znakiem!
|
||||
session_start();
|
||||
|
||||
// 3. Połączenie z bazą danych
|
||||
require_once 'includes/db.php';
|
||||
|
||||
$error = '';
|
||||
$logo_path = '';
|
||||
|
||||
// Pobranie ścieżki do logo z bazy danych
|
||||
try {
|
||||
$stmt = $pdo->query("SELECT setting_value FROM " . DB_PREFIX . "settings WHERE setting_key = 'logo_path'");
|
||||
if ($stmt) {
|
||||
$logo_path = $stmt->fetchColumn();
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
// Ignorujemy błąd, jeśli tabela jeszcze nie istnieje itp.
|
||||
}
|
||||
|
||||
// 4. Obsługa logowania
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$username = trim($_POST['username']);
|
||||
$password = $_POST['password'];
|
||||
|
||||
if (!empty($username) && !empty($password)) {
|
||||
try {
|
||||
// Pobieranie użytkownika z bazy (uwzględniając prefix)
|
||||
$stmt = $pdo->prepare("SELECT * FROM " . DB_PREFIX . "users WHERE username = ?");
|
||||
$stmt->execute([$username]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user) {
|
||||
// Weryfikacja hasła
|
||||
if (password_verify($password, $user['password'])) {
|
||||
// Logowanie udane - zapis do sesji
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['role'] = $user['role'];
|
||||
|
||||
// Przekierowanie do index.php
|
||||
header("Location: index.php");
|
||||
exit();
|
||||
} else {
|
||||
$error = "Błędne hasło. Upewnij się, że hasło jest poprawne).";
|
||||
}
|
||||
} else {
|
||||
$error = "Użytkownik '$username' nie istnieje w bazie.";
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error = "Błąd bazy danych: " . $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
$error = "Proszę wypełnić oba pola.";
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Logowanie - <?php echo defined('APP_NAME') ? APP_NAME : 'System Zamówień'; ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body { background-color: #f4f7f6; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
|
||||
.login-card { width: 100%; max-width: 400px; padding: 2rem; border-radius: 15px; background: white; box-shadow: 0 10px 25px rgba(0,0,0,0.1); }
|
||||
.btn-primary { background-color: #007bff; border: none; }
|
||||
.login-logo { max-height: 80px; max-width: 100%; margin-bottom: 15px; object-fit: contain; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="login-card">
|
||||
<div class="text-center mb-4">
|
||||
<?php if ($logo_path && file_exists($logo_path)): ?>
|
||||
<img src="<?php echo htmlspecialchars($logo_path); ?>" alt="Logo" class="login-logo">
|
||||
<?php else: ?>
|
||||
<h3>💻 Logowanie</h3>
|
||||
<?php endif; ?>
|
||||
<p class="text-muted small">Wpisz dane, aby zarządzać zamówieniami</p>
|
||||
</div>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger p-2 small"><?php echo $error; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" action="login.php">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label small">Użytkownik</label>
|
||||
<input type="text" name="username" id="username" class="form-control" required autofocus>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label small">Hasło</label>
|
||||
<input type="password" name="password" id="password" class="form-control" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100">Zaloguj się</button>
|
||||
</form>
|
||||
|
||||
<div class="mt-4 text-center border-top pt-3">
|
||||
<p class="text-muted" style="font-size: 0.8rem;">
|
||||
Aplikacja: <strong>goral.edu.pl/zeszyt</strong><br>
|
||||
Serwer: <strong>OVH PHP 8.x</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
// 1. Rozpoczęcie sesji, aby mieć do niej dostęp
|
||||
session_start();
|
||||
|
||||
// 2. Usunięcie wszystkich zmiennych sesyjnych (user_id, role, username)
|
||||
session_unset();
|
||||
|
||||
// 3. Całkowite zniszczenie sesji na serwerze
|
||||
session_destroy();
|
||||
|
||||
// 4. Przekierowanie użytkownika do strony logowania
|
||||
header("Location: login.php");
|
||||
exit();
|
||||
?>
|
||||
@ -0,0 +1,112 @@
|
||||
<?php
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
checkAuth();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['order_ids'])) {
|
||||
$ids = $_POST['order_ids'];
|
||||
$placeholders = str_repeat('?,', count($ids) - 1) . '?';
|
||||
$cols = $_POST['print_cols'] ?? ['id', 'product', 'quantity', 'place', 'price', 'status'];
|
||||
|
||||
$hasCol = function($colName) use ($cols) { return in_array($colName, $cols); };
|
||||
|
||||
$sql = "SELECT * FROM " . DB_PREFIX . "orders WHERE id IN ($placeholders) ORDER BY id DESC";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($ids);
|
||||
$orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Obliczamy ile głównych kolumn wydrukować, żeby ustawić odpowiedni colspan dla sub-wiersza
|
||||
$mainColsCount = 0;
|
||||
$main_available = ['id', 'product', 'quantity', 'place', 'price', 'status'];
|
||||
foreach($main_available as $mc) { if($hasCol($mc)) $mainColsCount++; }
|
||||
if($mainColsCount == 0) $mainColsCount = 1;
|
||||
|
||||
} else {
|
||||
die("Błąd: Nie wybrano żadnych zamówień do druku.");
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Wydruk listy - <?php echo date('Y-m-d'); ?></title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; font-size: 11px; margin: 20px; color: #000; }
|
||||
h2 { text-align: center; margin-bottom: 20px; font-size: 18px; text-transform: uppercase; }
|
||||
table { width: 100%; border-collapse: collapse; margin-bottom: 30px; }
|
||||
th, td { border: 1px solid #777; padding: 6px; text-align: left; vertical-align: top; }
|
||||
th { background-color: #f0f0f0; font-weight: bold; }
|
||||
.footer { font-size: 10px; color: #555; text-align: right; border-top: 1px solid #ccc; padding-top: 5px; }
|
||||
|
||||
/* Magia sub-wiersza na papierze */
|
||||
.sub-row td { border-top: none; padding: 4px 8px 12px 8px; background-color: #fcfcfc; font-size: 10px; color: #333; }
|
||||
.sub-item { margin-right: 20px; display: inline-block; }
|
||||
.sub-item strong { color: #000; }
|
||||
|
||||
@media print {
|
||||
.no-print { display: none; }
|
||||
body { margin: 0; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body onload="window.print()">
|
||||
|
||||
<div class="no-print" style="margin-bottom: 20px; text-align: center; background: #e9ecef; padding: 10px; border-radius: 5px;">
|
||||
<button onclick="window.print()" style="padding: 8px 16px; cursor: pointer; font-weight: bold;">🖨️ Drukuj listę</button>
|
||||
<button onclick="window.close()" style="padding: 8px 16px; cursor: pointer;">❌ Zamknij</button>
|
||||
</div>
|
||||
|
||||
<h2>Zestawienie zamówień IT</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<?php if($hasCol('id')): ?> <th style="width: 40px;">ID</th> <?php endif; ?>
|
||||
<?php if($hasCol('product')): ?> <th>Produkt (PN)</th> <?php endif; ?>
|
||||
<?php if($hasCol('quantity')): ?> <th style="width: 30px; text-align: center;">Szt.</th> <?php endif; ?>
|
||||
<?php if($hasCol('place')): ?> <th>Sklep</th> <?php endif; ?>
|
||||
<?php if($hasCol('price')): ?> <th style="width: 70px;">Cena jedn.</th> <?php endif; ?>
|
||||
<?php if($hasCol('status')): ?> <th style="width: 90px;">Status</th> <?php endif; ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($orders as $o): ?>
|
||||
<tr>
|
||||
<?php if($hasCol('id')): ?> <td>#<?php echo $o['id']; ?></td> <?php endif; ?>
|
||||
<?php if($hasCol('product')): ?>
|
||||
<td>
|
||||
<strong><?php echo htmlspecialchars($o['product_name']); ?></strong>
|
||||
<?php if(!empty($o['part_number'])): ?><br><span style="font-size: 9px; color: #555;">PN: <?php echo htmlspecialchars($o['part_number']); ?></span><?php endif; ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<?php if($hasCol('quantity')): ?> <td style="text-align: center;"><strong><?php echo $o['quantity']; ?></strong></td> <?php endif; ?>
|
||||
<?php if($hasCol('place')): ?> <td><?php echo htmlspecialchars($o['purchase_place']); ?></td> <?php endif; ?>
|
||||
<?php if($hasCol('price')): ?> <td><?php echo number_format($o['price_per_unit'], 2, ',', ' '); ?> zł</td> <?php endif; ?>
|
||||
<?php if($hasCol('status')): ?> <td><?php echo $o['status']; ?></td> <?php endif; ?>
|
||||
</tr>
|
||||
|
||||
<?php if($hasCol('recipient') || $hasCol('address') || $hasCol('notes')): ?>
|
||||
<tr class="sub-row">
|
||||
<td colspan="<?php echo $mainColsCount; ?>">
|
||||
<?php if($hasCol('recipient') && !empty($o['recipient'])): ?>
|
||||
<div class="sub-item"><strong>Odbiorca:</strong> <?php echo htmlspecialchars($o['recipient']); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($hasCol('address') && !empty($o['delivery_address'])): ?>
|
||||
<div class="sub-item"><strong>Adres:</strong> <?php echo htmlspecialchars($o['delivery_address']); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($hasCol('notes') && !empty($o['notes'])): ?>
|
||||
<div class="sub-item"><strong>Notatki:</strong> <em><?php echo htmlspecialchars($o['notes']); ?></em></div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="footer">Wygenerowano: <?php echo date('d.m.Y H:i'); ?> | System IT</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,150 @@
|
||||
<?php
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
checkAuth();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['order_ids'])) {
|
||||
$ids = $_POST['order_ids'];
|
||||
$placeholders = str_repeat('?,', count($ids) - 1) . '?';
|
||||
|
||||
$doc_type = $_POST['doc_type'] ?? 'List przewozowy';
|
||||
$company_footer = $_POST['company_footer'] ?? 'Przedsiębiorstwo';
|
||||
|
||||
$delivery_address = trim($_POST['global_delivery_address'] ?? '');
|
||||
$issued_by = trim($_POST['issued_by'] ?? '');
|
||||
$received_by = trim($_POST['received_by'] ?? '');
|
||||
|
||||
$cols = $_POST['delivery_cols'] ?? ['id', 'product', 'quantity', 'notes'];
|
||||
$hasCol = function($colName) use ($cols) { return in_array($colName, $cols); };
|
||||
|
||||
$sql = "SELECT * FROM " . DB_PREFIX . "orders WHERE id IN ($placeholders) ORDER BY id DESC";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($ids);
|
||||
$orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$logo_db = $pdo->query("SELECT setting_value FROM " . DB_PREFIX . "settings WHERE setting_key = 'logo_path'")->fetchColumn();
|
||||
$logo_src = (file_exists('uploads/logo.png')) ? 'uploads/logo.png' : ($logo_db ?: '');
|
||||
|
||||
// --- KONFIGURACJA STOPEK (pobierana z bazy) ---
|
||||
$settings_stmt = $pdo->query("SELECT setting_key, setting_value FROM " . DB_PREFIX . "settings WHERE setting_key IN ('company_1_name', 'company_1_details', 'company_2_name', 'company_2_details')");
|
||||
$settings = $settings_stmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
|
||||
if ($company_footer === 'Spółka') {
|
||||
$footer_company_name = $settings['company_2_name'] ?? "Spółka Celowa Sp. z o.o.";
|
||||
$footer_company_details = $settings['company_2_details'] ?? "-";
|
||||
} else {
|
||||
$footer_company_name = $settings['company_1_name'] ?? "Moje Przedsiębiorstwo IT";
|
||||
$footer_company_details = $settings['company_1_details'] ?? "-";
|
||||
}
|
||||
|
||||
} else {
|
||||
die("Błąd: Nie wybrano zamówień.");
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title><?php echo htmlspecialchars($doc_type); ?> - <?php echo date('Y-m-d'); ?></title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; font-size: 12px; margin: 30px; color: #000; position: relative; min-height: 90vh; }
|
||||
|
||||
.header-box { display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: 30px; border-bottom: 2px solid #000; padding-bottom: 20px; }
|
||||
.logo-container { max-width: 50%; }
|
||||
.logo-container img { max-height: 65px; margin-bottom: 10px; }
|
||||
.title { font-size: 24px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; }
|
||||
|
||||
.address-box { border: 2px solid #000; padding: 15px; width: 45%; min-height: 80px; font-size: 14px; background-color: #fdfdfd; }
|
||||
.address-title { font-weight: bold; margin-bottom: 5px; font-size: 11px; color: #555; text-transform: uppercase; }
|
||||
|
||||
table { width: 100%; border-collapse: collapse; margin-bottom: 50px; }
|
||||
th, td { border: 1px solid #000; padding: 10px; text-align: left; }
|
||||
th { background-color: #eee; font-weight: bold; text-transform: uppercase; font-size: 11px; }
|
||||
|
||||
.signatures { display: flex; justify-content: space-between; margin-top: 60px; padding: 0 30px; }
|
||||
.sig-block { text-align: center; width: 250px; }
|
||||
.sig-line { border-top: 1px solid #000; padding-top: 5px; font-size: 11px; margin-bottom: 5px; }
|
||||
.sig-name { font-size: 14px; font-weight: bold; min-height: 18px; }
|
||||
|
||||
.footer { position: absolute; bottom: 0; left: 0; right: 0; text-align: center; border-top: 1px solid #ddd; padding-top: 10px; }
|
||||
.footer-company { font-weight: bold; font-size: 14px; margin-bottom: 2px; }
|
||||
.footer-details { font-size: 10px; color: #555; margin-bottom: 5px; }
|
||||
.footer-meta { font-size: 9px; color: #999; }
|
||||
|
||||
@media print {
|
||||
.no-print { display: none; }
|
||||
body { margin: 0; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body onload="window.print()">
|
||||
|
||||
<div class="no-print" style="margin-bottom: 20px; background: #fff3cd; padding: 10px; border-radius: 5px; text-align: center;">
|
||||
<button onclick="window.print()" style="padding: 8px 16px; font-weight: bold;">🖨️ Drukuj Dokument</button>
|
||||
<button onclick="window.close()" style="padding: 8px 16px;">❌ Zamknij</button>
|
||||
</div>
|
||||
|
||||
<div class="header-box">
|
||||
<div class="logo-container">
|
||||
<?php if(!empty($logo_src)): ?>
|
||||
<img src="<?php echo htmlspecialchars($logo_src); ?>" alt="Logo">
|
||||
<?php endif; ?>
|
||||
<div class="title"><?php echo htmlspecialchars($doc_type); ?></div>
|
||||
</div>
|
||||
|
||||
<div class="address-box">
|
||||
<div class="address-title">Miejsce dostawy / Odbiorca:</div>
|
||||
<?php echo nl2br(htmlspecialchars($delivery_address)); ?>
|
||||
<?php if(empty($delivery_address)) echo "<span style='color:#ccc;'>(Brak podanego adresu na dokumencie)</span>"; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 30px;">LP</th>
|
||||
<?php if($hasCol('id')): ?> <th style="width: 50px;">ID</th> <?php endif; ?>
|
||||
<?php if($hasCol('product')): ?> <th>Wydawany Towar (Produkt / PN)</th> <?php endif; ?>
|
||||
<?php if($hasCol('quantity')): ?> <th style="width: 50px; text-align: center;">Ilość</th> <?php endif; ?>
|
||||
<?php if($hasCol('notes')): ?> <th>Notatki</th> <?php endif; ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php $lp = 1; foreach ($orders as $o): ?>
|
||||
<tr>
|
||||
<td style="text-align: center;"><?php echo $lp++; ?></td>
|
||||
<?php if($hasCol('id')): ?> <td>#<?php echo $o['id']; ?></td> <?php endif; ?>
|
||||
<?php if($hasCol('product')): ?>
|
||||
<td>
|
||||
<strong><?php echo htmlspecialchars($o['product_name'] ?? ''); ?></strong>
|
||||
<?php if(!empty($o['part_number'])): ?><br><span style="font-size: 10px; color: #555;">PN: <?php echo htmlspecialchars($o['part_number'] ?? ''); ?></span><?php endif; ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<?php if($hasCol('quantity')): ?> <td style="text-align: center; font-size: 14px;"><strong><?php echo $o['quantity']; ?></strong></td> <?php endif; ?>
|
||||
<?php if($hasCol('notes')): ?>
|
||||
<td><?php echo htmlspecialchars($o['notes'] ?? ''); ?></td>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="signatures">
|
||||
<div class="sig-block">
|
||||
<div class="sig-line">Wydający (Podpis i data)</div>
|
||||
<div class="sig-name"><?php echo htmlspecialchars($issued_by); ?></div>
|
||||
</div>
|
||||
<div class="sig-block">
|
||||
<div class="sig-line">Odbierający (Czytelny podpis i data)</div>
|
||||
<div class="sig-name"><?php echo htmlspecialchars($received_by); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<div class="footer-company"><?php echo htmlspecialchars($footer_company_name); ?></div>
|
||||
<div class="footer-details"><?php echo htmlspecialchars($footer_company_details); ?></div>
|
||||
<div class="footer-meta">Data wydruku: <?php echo date('d.m.Y H:i'); ?> | System: <?php echo defined('APP_NAME') ? APP_NAME : 'System IT'; ?> | Generujący: <?php echo htmlspecialchars($_SESSION['username']); ?></div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
Loading…
Reference in New Issue