hapusproduk.php PHP
<?php
declare(strict_types=1);
session_start();
require_once 'koneksi.php';

function h(string $s): string { return htmlspecialchars($s, ENT_QUOTES, 'UTF-8'); }

$kode_produk = trim((string)($_POST['kode_produk'] ?? $_GET['kode_produk'] ?? ''));
$confirm     = isset($_POST['confirm']) ? (int)$_POST['confirm'] : 0;

if ($kode_produk === '') {
    header('Location: beranda?error=kode_produk_kosong');
    exit;
}

/* 1) Cek apakah ada relasi di tabel anak (bahan_terpakai) */
$jumlahRelasi = 0;
if ($stmt = $kon->prepare("SELECT COUNT(*) FROM bahan_terpakai WHERE kode_produk = ?")) {
    $stmt->bind_param('s', $kode_produk);
    $stmt->execute();
    $stmt->bind_result($jumlahRelasi);
    $stmt->fetch();
    $stmt->close();
} else {
    header('Location: beranda?error=gagal_cek_relasi');
    exit;
}

/* 2) Jika tidak ada relasi & belum konfirmasi → langsung hapus produk */
if ($jumlahRelasi == 0 && $confirm === 0) {
    if ($stmt = $kon->prepare("DELETE FROM produk WHERE kode_produk = ?")) {
        $stmt->bind_param('s', $kode_produk);
        if ($stmt->execute()) {
            $stmt->close();
            header('Location: beranda?deleted=1');
            exit;
        } else {
            $err = $stmt->error;
            $stmt->close();
            header('Location: beranda?error=' . rawurlencode($err));
            exit;
        }
    } else {
        header('Location: beranda?error=gagal_prepare_delete_produk');
        exit;
    }
}

/* 3) Jika ada relasi & belum konfirmasi → tampilkan UI konfirmasi */
if ($jumlahRelasi > 0 && $confirm === 0) {
    ?>
<!doctype html>
<html lang="id">
<head>
  <meta charset="utf-8">
  <title>Konfirmasi Hapus Produk</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-gray-50 flex items-center justify-center p-6">
  <div class="w-full max-w-lg">
    <div class="bg-white rounded-2xl shadow-xl overflow-hidden">
      <div class="p-6 border-b">
        <h1 class="text-xl font-semibold text-gray-800">Yakin hapus produk yang pernah terjual?</h1>
        <p class="mt-1 text-sm text-gray-500">
          Kode Produk:
          <span class="font-mono bg-gray-100 px-2 py-0.5 rounded"><?php echo h($kode_produk); ?></span>
        </p>
      </div>
      <div class="p-6 space-y-4">
        <div class="flex gap-3">
          <div class="shrink-0 p-2 rounded-full bg-amber-100">
            <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-amber-600" viewBox="0 0 24 24" fill="none" stroke="currentColor">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
            </svg>
          </div>
          <div>
            <p class="text-gray-700">
              Produk ini memiliki relasi dengan <span class="font-semibold">barang terpakai/terjual</span>.
              Jika anda menghapusnya maka <span class="font-semibold">data terjual akan hilang</span>
              <br><span class="font-semibold">Yakin hapus?</span>
            </p>
            <p class="mt-2 text-sm text-gray-500">Relasi terdeteksi: <?php echo (int)$jumlahRelasi; ?> baris di <code>Bahan baku Terpakai / produk terjual</code>.</p>
          </div>
        </div>

        <form method="post" class="flex justify-end gap-3">
          <input type="hidden" name="kode_produk" value="<?php echo h($kode_produk); ?>">
          <input type="hidden" name="confirm" value="1">
          <a href="beranda" class="px-4 py-2.5 rounded-xl border border-gray-200 text-gray-700 hover:bg-gray-50">Batal</a>
          <button type="submit" class="px-4 py-2.5 rounded-xl bg-rose-600 text-white hover:bg-rose-700 shadow">YA HAPUS!</button>
        </form>
      </div>
      <div class="px-6 py-4 bg-gray-50 border-t text-xs text-gray-500">
        Aksi ini akan menghapus data terkait lalu menghapus produk.
      </div>
    </div>
  </div>
</body>
</html>
    <?php
    exit;
}

/* 4) Sudah konfirmasi → hapus aman (pakai transaksi) */
$kon->begin_transaction();
try {
    // Jika FK belum CASCADE, pastikan baris anak dihapus manual.
    if ($jumlahRelasi > 0) {
        if (!$stmt = $kon->prepare("DELETE FROM bahan_terpakai WHERE kode_produk = ?")) {
            throw new Exception('Gagal prepare hapus anak: ' . $kon->error);
        }
        $stmt->bind_param('s', $kode_produk);
        if (!$stmt->execute()) {
            $err = $stmt->error;
            $stmt->close();
            throw new Exception('Gagal eksekusi hapus anak: ' . $err);
        }
        $stmt->close();
    }

    // Hapus induk (jika FK sudah CASCADE, baris anak sudah otomatis hilang).
    if (!$stmt = $kon->prepare("DELETE FROM produk WHERE kode_produk = ?")) {
        throw new Exception('Gagal prepare hapus produk: ' . $kon->error);
    }
    $stmt->bind_param('s', $kode_produk);
    if (!$stmt->execute()) {
        $err = $stmt->error;
        $stmt->close();
        throw new Exception('Gagal eksekusi hapus produk: ' . $err);
    }
    $stmt->close();

    $kon->commit();
    header('Location: beranda?deleted=1');
    exit;

} catch (Throwable $e) {
    $kon->rollback();
    header('Location: beranda?error=' . rawurlencode($e->getMessage()));
    exit;
}