CRUD adalah 4 operasi dasar dalam pengelolaan data:
Tambah data baru
INSERT INTO
Tampilkan data
SELECT FROM
Ubah data
UPDATE SET
Hapus data
DELETE FROM
produk/index.php (READ) → tambah.php (CREATE) → edit.php (UPDATE) → hapus.php (DELETE)
<?php
// ============================================
// FILE: produk/index.php
// Menampilkan daftar semua produk (READ)
// ============================================
$pageTitle = 'Daftar Produk';
require_once '../config/database.php';
require_once '../includes/functions.php';
require_once '../includes/header.php';
// ============================================
// QUERY: Ambil semua produk + nama kategori
// JOIN dengan tabel kategori
// ============================================
$sql = "SELECT p.*, k.nama_kategori
FROM produk p
LEFT JOIN kategori k ON p.id_kategori = k.id
ORDER BY p.created_at DESC";
$stmt = $pdo->query($sql);
$produkList = $stmt->fetchAll(); // Ambil semua baris sekaligus
// fetchAll() → array of arrays, bisa diloop
// Cek apakah ada pesan sukses dari halaman sebelumnya
$pesan = $_GET['pesan'] ?? '';
?>
<!-- Header Halaman -->
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h4 class="fw-bold mb-1">📦 Daftar Produk</h4>
<p class="text-muted mb-0">Total: <strong><?= count($produkList) ?></strong> produk</p>
</div>
<a href="tambah.php" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>Tambah Produk
</a>
</div>
<!-- Alert Sukses/Error -->
<?php if ($pesan === 'tambah'): ?>
<div class="alert alert-success alert-dismissible fade show">
✅ Produk berhasil ditambahkan!
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php elseif ($pesan === 'edit'): ?>
<div class="alert alert-info alert-dismissible fade show">
✏️ Produk berhasil diperbarui!
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php elseif ($pesan === 'hapus'): ?>
<div class="alert alert-warning alert-dismissible fade show">
🗑️ Produk berhasil dihapus!
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<!-- Tabel Produk -->
<div class="card border-0 shadow-sm">
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-dark">
<tr>
<th>No</th>
<th>Kode</th>
<th>Nama Produk</th>
<th>Kategori</th>
<th>Harga Jual</th>
<th class="text-center">Stok</th>
<th class="text-center">Aksi</th>
</tr>
</thead>
<tbody>
<?php if (empty($produkList)): ?>
<!-- Tampilkan jika tidak ada data -->
<tr>
<td colspan="7" class="text-center py-5 text-muted">
<i class="fas fa-box-open fa-3x mb-3 d-block opacity-25"></i>
Belum ada produk.
<a href="tambah.php">Tambah sekarang?</a>
</td>
</tr>
<?php else: ?>
<?php foreach ($produkList as $i => $produk): ?>
<tr>
<td><?= $i + 1 ?></td>
<td>
<code><?= htmlspecialchars($produk['kode_produk']) ?></code>
</td>
<td>
<strong><?= htmlspecialchars($produk['nama_produk']) ?></strong>
</td>
<td>
<span class="badge bg-secondary">
<?= htmlspecialchars($produk['nama_kategori'] ?? 'Tanpa Kategori') ?>
</span>
</td>
<td><?= formatRupiah($produk['harga_jual']) ?></td>
<td class="text-center">
<!-- Tampilkan badge merah jika stok menipis -->
<span class="badge <?= $produk['stok'] < 10 ? 'bg-danger' : 'bg-success' ?>">
<?= $produk['stok'] ?>
</span>
</td>
<td class="text-center">
<!-- Tombol Edit -->
<a href="edit.php?id=<?= $produk['id'] ?>"
class="btn btn-sm btn-warning me-1"
title="Edit">
<i class="fas fa-edit"></i>
</a>
<!-- Tombol Hapus -->
<a href="hapus.php?id=<?= $produk['id'] ?>"
class="btn btn-sm btn-danger"
title="Hapus"
onclick="return confirm('Yakin hapus produk <?= htmlspecialchars($produk['nama_produk']) ?>?')">
<i class="fas fa-trash"></i>
</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<?php require_once '../includes/footer.php'; ?>
<?php
// ============================================
// FILE: produk/tambah.php
// Form tambah produk baru (CREATE)
// ============================================
$pageTitle = 'Tambah Produk';
require_once '../config/database.php';
require_once '../includes/functions.php';
require_once '../includes/header.php';
// Ambil data kategori untuk dropdown
$kategoriList = $pdo->query("SELECT * FROM kategori ORDER BY nama_kategori")->fetchAll();
// Inisialisasi variabel untuk form (isi ulang saat error)
$form = [
'kode_produk' => '',
'nama_produk' => '',
'harga_beli' => '',
'harga_jual' => '',
'stok' => '',
'id_kategori' => '',
];
$errors = [];
// ============================================
// PROSES SIMPAN (saat form di-submit)
// ============================================
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 1. Ambil & bersihkan semua input
$form = [
'kode_produk' => trim($_POST['kode_produk'] ?? ''),
'nama_produk' => trim($_POST['nama_produk'] ?? ''),
'harga_beli' => $_POST['harga_beli'] ?? 0,
'harga_jual' => $_POST['harga_jual'] ?? 0,
'stok' => $_POST['stok'] ?? 0,
'id_kategori' => $_POST['id_kategori'] ?? null,
];
// 2. Validasi input
if (empty($form['kode_produk'])) $errors[] = 'Kode produk harus diisi!';
if (empty($form['nama_produk'])) $errors[] = 'Nama produk harus diisi!';
if ($form['harga_jual'] <= 0) $errors[] = 'Harga jual harus lebih dari 0!';
if ($form['stok'] < 0) $errors[] = 'Stok tidak boleh negatif!';
// 3. Cek apakah kode produk sudah ada
if (empty($errors)) {
$cek = $pdo->prepare("SELECT id FROM produk WHERE kode_produk = ?");
$cek->execute([$form['kode_produk']]);
if ($cek->fetch()) {
$errors[] = 'Kode produk sudah digunakan, gunakan kode lain!';
}
}
// 4. Jika tidak ada error, simpan ke database
if (empty($errors)) {
$sql = "INSERT INTO produk
(kode_produk, nama_produk, harga_beli, harga_jual, stok, id_kategori)
VALUES
(:kode, :nama, :hbeli, :hjual, :stok, :kategori)";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':kode' => $form['kode_produk'],
':nama' => $form['nama_produk'],
':hbeli' => $form['harga_beli'],
':hjual' => $form['harga_jual'],
':stok' => $form['stok'],
':kategori' => $form['id_kategori'] ?: null,
]);
// Redirect dengan pesan sukses
header('Location: index.php?pesan=tambah');
exit();
}
}
?>
<div class="row justify-content-center">
<div class="col-lg-8">
<!-- Header -->
<div class="d-flex align-items-center gap-3 mb-4">
<a href="index.php" class="btn btn-outline-secondary btn-sm">
<i class="fas fa-arrow-left"></i>
</a>
<h4 class="fw-bold mb-0">➕ Tambah Produk Baru</h4>
</div>
<!-- Tampilkan error jika ada -->
<?php if (!empty($errors)): ?>
<div class="alert alert-danger">
<strong>❌ Terjadi kesalahan:</strong>
<ul class="mb-0 mt-2">
<?php foreach ($errors as $err): ?>
<li><?= htmlspecialchars($err) ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<!-- Form Tambah -->
<div class="card border-0 shadow-sm">
<div class="card-body p-4">
<form method="POST" action="">
<div class="row g-3">
<!-- Kode Produk -->
<div class="col-md-4">
<label class="form-label fw-semibold">
Kode Produk <span class="text-danger">*</span>
</label>
<input type="text" name="kode_produk" class="form-control"
value="<?= htmlspecialchars($form['kode_produk']) ?>"
placeholder="cth: PRD011" required>
<div class="form-text">Kode unik untuk setiap produk</div>
</div>
<!-- Nama Produk -->
<div class="col-md-8">
<label class="form-label fw-semibold">
Nama Produk <span class="text-danger">*</span>
</label>
<input type="text" name="nama_produk" class="form-control"
value="<?= htmlspecialchars($form['nama_produk']) ?>"
placeholder="cth: Indomie Goreng" required>
</div>
<!-- Kategori -->
<div class="col-md-4">
<label class="form-label fw-semibold">Kategori</label>
<select name="id_kategori" class="form-select">
<option value="">-- Pilih Kategori --</option>
<?php foreach ($kategoriList as $kat): ?>
<option value="<?= $kat['id'] ?>"
<?= ($form['id_kategori'] == $kat['id']) ? 'selected' : '' ?>>
<?= htmlspecialchars($kat['nama_kategori']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<!-- Stok -->
<div class="col-md-4">
<label class="form-label fw-semibold">Stok Awal</label>
<input type="number" name="stok" class="form-control"
value="<?= $form['stok'] ?>" min="0" placeholder="0">
</div>
<!-- Harga Beli -->
<div class="col-md-6">
<label class="form-label fw-semibold">Harga Beli (Modal)</label>
<div class="input-group">
<span class="input-group-text">Rp</span>
<input type="number" name="harga_beli" class="form-control"
value="<?= $form['harga_beli'] ?>" min="0" placeholder="0">
</div>
</div>
<!-- Harga Jual -->
<div class="col-md-6">
<label class="form-label fw-semibold">
Harga Jual <span class="text-danger">*</span>
</label>
<div class="input-group">
<span class="input-group-text">Rp</span>
<input type="number" name="harga_jual" class="form-control"
value="<?= $form['harga_jual'] ?>" min="1" placeholder="0" required>
</div>
</div>
</div>
<!-- Tombol -->
<div class="d-flex gap-2 mt-4">
<button type="submit" class="btn btn-primary px-4">
<i class="fas fa-save me-2"></i>Simpan Produk
</button>
<a href="index.php" class="btn btn-outline-secondary">
Batal
</a>
</div>
</form>
</div>
</div>
</div>
</div>
<?php require_once '../includes/footer.php'; ?>
<?php
// ============================================
// FILE: produk/edit.php
// Form edit produk (UPDATE)
// ============================================
$pageTitle = 'Edit Produk';
require_once '../config/database.php';
require_once '../includes/functions.php';
require_once '../includes/header.php';
// Ambil ID dari URL: edit.php?id=5
$id = (int)($_GET['id'] ?? 0);
// Cari produk berdasarkan ID
$stmt = $pdo->prepare("SELECT * FROM produk WHERE id = ?");
$stmt->execute([$id]);
$produk = $stmt->fetch();
// Jika produk tidak ditemukan, kembali ke daftar
if (!$produk) {
header('Location: index.php');
exit();
}
// Ambil kategori untuk dropdown
$kategoriList = $pdo->query("SELECT * FROM kategori ORDER BY nama_kategori")->fetchAll();
$errors = [];
$form = $produk; // Isi form dengan data saat ini
// ============================================
// PROSES UPDATE (saat form di-submit)
// ============================================
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$form = [
'kode_produk' => trim($_POST['kode_produk'] ?? ''),
'nama_produk' => trim($_POST['nama_produk'] ?? ''),
'harga_beli' => $_POST['harga_beli'] ?? 0,
'harga_jual' => $_POST['harga_jual'] ?? 0,
'stok' => $_POST['stok'] ?? 0,
'id_kategori' => $_POST['id_kategori'] ?: null,
];
// Validasi
if (empty($form['kode_produk'])) $errors[] = 'Kode produk harus diisi!';
if (empty($form['nama_produk'])) $errors[] = 'Nama produk harus diisi!';
if ($form['harga_jual'] <= 0) $errors[] = 'Harga jual harus lebih dari 0!';
// Cek kode duplikat (tapi izinkan kode yang sama milik produk ini)
if (empty($errors)) {
$cek = $pdo->prepare(
"SELECT id FROM produk WHERE kode_produk = ? AND id != ?"
);
$cek->execute([$form['kode_produk'], $id]);
if ($cek->fetch()) {
$errors[] = 'Kode produk sudah digunakan produk lain!';
}
}
// Simpan perubahan
if (empty($errors)) {
$sql = "UPDATE produk SET
kode_produk = :kode,
nama_produk = :nama,
harga_beli = :hbeli,
harga_jual = :hjual,
stok = :stok,
id_kategori = :kategori
WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':kode' => $form['kode_produk'],
':nama' => $form['nama_produk'],
':hbeli' => $form['harga_beli'],
':hjual' => $form['harga_jual'],
':stok' => $form['stok'],
':kategori' => $form['id_kategori'],
':id' => $id,
]);
header('Location: index.php?pesan=edit');
exit();
}
}
?>
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="d-flex align-items-center gap-3 mb-4">
<a href="index.php" class="btn btn-outline-secondary btn-sm">
<i class="fas fa-arrow-left"></i>
</a>
<h4 class="fw-bold mb-0">✏️ Edit Produk</h4>
</div>
<?php if (!empty($errors)): ?>
<div class="alert alert-danger">
<ul class="mb-0">
<?php foreach ($errors as $err): ?>
<li><?= htmlspecialchars($err) ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<div class="card border-0 shadow-sm">
<div class="card-body p-4">
<form method="POST" action="">
<div class="row g-3">
<div class="col-md-4">
<label class="form-label fw-semibold">Kode Produk *</label>
<input type="text" name="kode_produk" class="form-control"
value="<?= htmlspecialchars($form['kode_produk']) ?>" required>
</div>
<div class="col-md-8">
<label class="form-label fw-semibold">Nama Produk *</label>
<input type="text" name="nama_produk" class="form-control"
value="<?= htmlspecialchars($form['nama_produk']) ?>" required>
</div>
<div class="col-md-4">
<label class="form-label fw-semibold">Kategori</label>
<select name="id_kategori" class="form-select">
<option value="">-- Pilih --</option>
<?php foreach ($kategoriList as $kat): ?>
<option value="<?= $kat['id'] ?>"
<?= ($form['id_kategori'] == $kat['id']) ? 'selected' : '' ?>>
<?= htmlspecialchars($kat['nama_kategori']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-4">
<label class="form-label fw-semibold">Stok</label>
<input type="number" name="stok" class="form-control"
value="<?= $form['stok'] ?>" min="0">
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Harga Beli</label>
<div class="input-group">
<span class="input-group-text">Rp</span>
<input type="number" name="harga_beli" class="form-control"
value="<?= $form['harga_beli'] ?>" min="0">
</div>
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Harga Jual *</label>
<div class="input-group">
<span class="input-group-text">Rp</span>
<input type="number" name="harga_jual" class="form-control"
value="<?= $form['harga_jual'] ?>" min="1" required>
</div>
</div>
</div>
<div class="d-flex gap-2 mt-4">
<button type="submit" class="btn btn-warning px-4">
<i class="fas fa-save me-2"></i>Simpan Perubahan
</button>
<a href="index.php" class="btn btn-outline-secondary">Batal</a>
</div>
</form>
</div>
</div>
</div>
</div>
<?php require_once '../includes/footer.php'; ?>
<?php
// ============================================
// FILE: produk/hapus.php
// Proses hapus produk (DELETE)
// File ini TIDAK punya tampilan UI
// Hanya proses dan redirect
// ============================================
session_start();
require_once '../config/database.php';
// Ambil ID dari URL: hapus.php?id=5
$id = (int)($_GET['id'] ?? 0);
// Validasi: ID harus valid
if ($id <= 0) {
header('Location: index.php');
exit();
}
// Cek apakah produk ada
$cek = $pdo->prepare("SELECT id, nama_produk FROM produk WHERE id = ?");
$cek->execute([$id]);
$produk = $cek->fetch();
if ($produk) {
// Hapus produk
$stmt = $pdo->prepare("DELETE FROM produk WHERE id = ?");
$stmt->execute([$id]);
// Redirect dengan pesan sukses
header('Location: index.php?pesan=hapus');
} else {
// Produk tidak ditemukan
header('Location: index.php');
}
exit();
?>
confirm() di tombol)deleted_at daripada benar-benar hapus)<!-- Footer dipanggil di akhir setiap halaman -->
</div><!-- End container-fluid -->
<footer class="bg-white border-top mt-5 py-3 text-center">
<small class="text-muted">
Sistem POS © <?= date('Y') ?> — Logged in as
<strong><?= htmlspecialchars($_SESSION['user_nama'] ?? '') ?></strong>
</small>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>