Thursday, 27 August 2026

Membangun aplikasi Kasir (Point of Sale) sederhana

Berikut adalah modul pembelajaran lengkap untuk membangun aplikasi Kasir (Point of Sale) sederhana berbasis JavaScript/Web, lengkap dengan persiapan, struktur kode, dan alur logika di balik layarnya.

Modul 1: Persiapan & Struktur Project

1. Tools yang Dibutuhkan

  • Editor Kode: Visual Studio Code.

  • Browser: Google Chrome / Firefox.

2. Struktur Folder & File Buat folder baru bernama aplikasi-kasir dan siapkan 3 file utama:

  • index.html (Tampilan antarmuka)

  • style.css (Desain/tata letak)

  • app.js (Logika & pemrosesan data)

Modul 2: Desain Antarmuka (index.html & style.css)

Buat struktur HTML dengan dua area utama: Daftar Produk (kiri) dan Keranjang/Struk (kanan).

index.html

<!DOCTYPE html>

<html lang="id">

<head>

  <meta charset="UTF-8">

  <title>Aplikasi Kasir Sederhana</title>

  <link rel="stylesheet" href="style.css">

</head>

<body>

  <div class="container">

    <!-- Bagian Produk -->

    <div class="produk-section">

      <h2>Daftar Produk</h2>

      <div id="daftar-produk" class="grid-produk"></div>

    </div>


    <!-- Bagian Keranjang & Pembayaran -->

    <div class="kasir-section">

      <h2>Keranjang Belanja</h2>

      <ul id="daftar-keranjang"></ul>

      <hr>

      <p><strong>Total: Rp <span id="total-harga">0</span></strong></p>


      <div class="pembayaran">

        <label>Bayar: Rp</label>

        <input type="number" id="input-bayar" placeholder="Masukkan nominal">

        <button onclick="prosesBayar()">Proses Transaksi</button>

      </div>

      <p id="pesan-kembalian"></p>

    </div>

  </div>


  <script src="app.js"></script>

</body>

</html>


style.css

body { font-family: Arial, sans-serif; margin: 20px; background: #f4f4f9; }

.container { display: flex; gap: 20px; }

.produk-section, .kasir-section { background: white; padding: 20px; border-radius: 8px; flex: 1; }

.grid-produk { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }

.item-produk { border: 1px solid #ddd; padding: 10px; text-align: center; border-radius: 5px; }

.item-produk button { background: #28a745; color: white; border: none; padding: 5px 10px; cursor: pointer; }

button { cursor: pointer; }


Modul 3: Logika Sistem & Pemrograman (app.js)

app.js

// Data Master Produk

const produkList = [

  { id: 1, nama: "Kopi Hitam", harga: 10000 },

  { id: 2, nama: "Roti Bakar", harga: 15000 },

  { id: 3, nama: "Es Teh Manis", harga: 5000 },

  { id: 4, nama: "Nasi Goreng", harga: 20000 }

];


// State Keranjang

let keranjang = [];


// 1. Tampilkan Daftar Produk ke HTML

function tampilkanProduk() {

  const container = document.getElementById('daftar-produk');

  container.innerHTML = '';

  

  produkList.forEach(item => {

    container.innerHTML += `

      <div class="item-produk">

        <h4>${item.nama}</h4>

        <p>Rp ${item.harga.toLocaleString('id-ID')}</p>

        <button onclick="tambahKeKeranjang(${item.id})">+ Tambah</button>

      </div>

    `;

  });

}


// 2. Tambah Produk ke Keranjang

function tambahKeKeranjang(idProduk) {

  const itemInKeranjang = keranjang.find(item => item.id === idProduk);

  

  if (itemInKeranjang) {

    itemInKeranjang.jumlah += 1;

  } else {

    const produkAwal = produkList.find(p => p.id === idProduk);

    keranjang.push({ ...produkAwal, jumlah: 1 });

  }

  updateTampilanKeranjang();

}


// 3. Update Tampilan Keranjang & Total

function updateTampilanKeranjang() {

  const listKeranjang = document.getElementById('daftar-keranjang');

  const totalHargaEl = document.getElementById('total-harga');

  

  listKeranjang.innerHTML = '';

  let total = 0;


  keranjang.forEach(item => {

    const subtotal = item.harga * item.jumlah;

    total += subtotal;

    

    listKeranjang.innerHTML += `

      <li>${item.nama} x ${item.jumlah} = Rp ${subtotal.toLocaleString('id-ID')}</li>

    `;

  });


  totalHargaEl.innerText = total.toLocaleString('id-ID');

}


// 4. Hitung Pembayaran & Kembalian

function prosesBayar() {

  const total = keranjang.reduce((acc, item) => acc + (item.harga * item.jumlah), 0);

  const nominalBayar = Number(document.getElementById('input-bayar').value);

  const pesanEl = document.getElementById('pesan-kembalian');


  if (total === 0) {

    pesanEl.innerText = "Keranjang masih kosong!";

    return;

  }


  if (nominalBayar < total) {

    pesanEl.innerText = "Uang tidak cukup!";

  } else {

    const kembalian = nominalBayar - total;

    pesanEl.innerText = `Transaksi Berhasil! Kembalian: Rp ${kembalian.toLocaleString('id-ID')}`;

    

    // Reset Kasir

    keranjang = [];

    document.getElementById('input-bayar').value = '';

    updateTampilanKeranjang();

  }

}


// Jalankan saat pertama kali dibuka

tampilkanProduk();


Modul 4: Penjelasan Alur Logika Sistem

1. Konsep State (Penyimpanan Sementara Data)

  • Array produkList: Berfungsi sebagai database lokal yang menyimpan master barang (ID, nama, harga).

  • Array keranjang: Berfungsi menampung transaksi aktif. Ketika tombol "+ Tambah" diklik, sistem mengecek apakah barang sudah ada di keranjang. Jika sudah ada, tambahkan nilai jumlah (+1). Jika belum ada, masukkan objek barang baru dengan jumlah = 1.

2. Alur Pengolahan Data (Data Flow)

  • Aksi Tambah: User klik tombol $\rightarrow$ Fungsi tambahKeKeranjang(id) $\rightarrow$ Update Array keranjang $\rightarrow$ Panggil updateTampilanKeranjang().

  • Kalkulasi Total: Fungsi updateTampilanKeranjang() melakukan kalkulasi subtotal per item ($\text{harga} \times \text{jumlah}$) lalu menjumlahkan seluruh item untuk menghasilkan Total.

3. Logika Validasi Pembayaran

  • Ambil input dari input-bayar.

  • Lakukan percabangan logika (Condition Check):

    • Jika $\text{Bayar} < \text{Total}$: Tampilkan peringatan uang kurang.

    • Jika $\text{Bayar} \ge \text{Total}$: Hitung $\text{Kembalian} = \text{Bayar} - \text{Total}$, tampilkan pesan sukses, lalu kosongkan array keranjang untuk transaksi berikutnya.


Berikut adalah pembaruan kode app.js yang menyertakan fitur hapus/kurangi item dari keranjang serta penyimpanan riwayat transaksi otomatis menggunakan localStorage agar data tidak hilang saat halaman di-refresh.

1. Pembaruan Antarmuka (index.html)

Tambahkan area untuk menampilkan riwayat transaksi di bawah bagian keranjang pada index.html:

<!-- Tambahkan div ini di dalam .container atau di bagian bawah html -->

<div class="riwayat-section" style="margin-top: 20px; background: white; padding: 20px; border-radius: 8px;">

  <h2>Riwayat Transaksi</h2>

  <button onclick="hapusRiwayat()" style="background: #dc3545; color: white; border: none; padding: 5px 10px; margin-bottom: 10px;">Hapus Riwayat</button>

  <ul id="daftar-riwayat"></ul>

</div>

2. Kode Logika Baru (app.js)

Gantikan seluruh isi file app.js Anda dengan kode berikut:

// Data Master Produk

const produkList = [

  { id: 1, nama: "Kopi Hitam", harga: 10000 },

  { id: 2, nama: "Roti Bakar", harga: 15000 },

  { id: 3, nama: "Es Teh Manis", harga: 5000 },

  { id: 4, nama: "Nasi Goreng", harga: 20000 }

];


// State Keranjang & Riwayat Transaksi

let keranjang = [];

// Ambil riwayat dari LocalStorage jika ada, jika tidak set array kosong

let riwayatTransaksi = JSON.parse(localStorage.getItem('riwayat_kasir')) || [];


// 1. Tampilkan Daftar Produk

function tampilkanProduk() {

  const container = document.getElementById('daftar-produk');

  container.innerHTML = '';

  

  produkList.forEach(item => {

    container.innerHTML += `

      <div class="item-produk">

        <h4>${item.nama}</h4>

        <p>Rp ${item.harga.toLocaleString('id-ID')}</p>

        <button onclick="tambahKeKeranjang(${item.id})">+ Tambah</button>

      </div>

    `;

  });

}


// 2. Tambah Produk ke Keranjang

function tambahKeKeranjang(idProduk) {

  const itemInKeranjang = keranjang.find(item => item.id === idProduk);

  

  if (itemInKeranjang) {

    itemInKeranjang.jumlah += 1;

  } else {

    const produkAwal = produkList.find(p => p.id === idProduk);

    keranjang.push({ ...produkAwal, jumlah: 1 });

  }

  updateTampilanKeranjang();

}


// 3. Fitur Baru: Hapus / Kurangi Item dari Keranjang

function kurangiDariKeranjang(idProduk) {

  const index = keranjang.findIndex(item => item.id === idProduk);

  

  if (index !== -1) {

    if (keranjang[index].jumlah > 1) {

      keranjang[index].jumlah -= 1; // Kurangi jumlah jika > 1

    } else {

      keranjang.splice(index, 1); // Hapus dari keranjang jika jumlah tinggal 1

    }

  }

  updateTampilanKeranjang();

}


// 4. Update Tampilan Keranjang

function updateTampilanKeranjang() {

  const listKeranjang = document.getElementById('daftar-keranjang');

  const totalHargaEl = document.getElementById('total-harga');

  

  listKeranjang.innerHTML = '';

  let total = 0;


  keranjang.forEach(item => {

    const subtotal = item.harga * item.jumlah;

    total += subtotal;

    

    listKeranjang.innerHTML += `

      <li style="margin-bottom: 5px;">

        ${item.nama} x ${item.jumlah} = Rp ${subtotal.toLocaleString('id-ID')}

        <button onclick="kurangiDariKeranjang(${item.id})" style="background:#dc3545; color:white; border:none; padding:2px 6px; border-radius:3px; margin-left:8px;">- Hapus</button>

      </li>

    `;

  });


  totalHargaEl.innerText = total.toLocaleString('id-ID');

}


// 5. Fitur Baru: Simpan & Tampilkan Riwayat

function simpanDanTampilkanRiwayat(transaksiBaru) {

  // Tambahkan ke array riwayat

  riwayatTransaksi.push(transaksiBaru);

  

  // Simpan array riwayat ke LocalStorage (diubah ke format string JSON)

  localStorage.setItem('riwayat_kasir', JSON.stringify(riwayatTransaksi));

  

  tampilkanRiwayat();

}


function tampilkanRiwayat() {

  const listRiwayat = document.getElementById('daftar-riwayat');

  if (!listRiwayat) return;

  

  listRiwayat.innerHTML = '';


  if (riwayatTransaksi.length === 0) {

    listRiwayat.innerHTML = '<li>Belum ada transaksi.</li>';

    return;

  }


  riwayatTransaksi.forEach((tx, index) => {

    listRiwayat.innerHTML += `

      <li style="margin-bottom: 8px; border-bottom: 1px #eee solid; padding-bottom: 5px;">

        <strong>[${tx.waktu}]</strong> Total: Rp ${tx.total.toLocaleString('id-ID')} | Bayar: Rp ${tx.bayar.toLocaleString('id-ID')} (Kembali: Rp ${tx.kembalian.toLocaleString('id-ID')})

      </li>

    `;

  });

}


function hapusRiwayat() {

  localStorage.removeItem('riwayat_kasir');

  riwayatTransaksi = [];

  tampilkanRiwayat();

}


// 6. Hitung Pembayaran

function prosesBayar() {

  const total = keranjang.reduce((acc, item) => acc + (item.harga * item.jumlah), 0);

  const nominalBayar = Number(document.getElementById('input-bayar').value);

  const pesanEl = document.getElementById('pesan-kembalian');


  if (total === 0) {

    pesanEl.innerText = "Keranjang masih kosong!";

    return;

  }


  if (nominalBayar < total) {

    pesanEl.innerText = "Uang tidak cukup!";

  } else {

    const kembalian = nominalBayar - total;

    pesanEl.innerText = `Transaksi Berhasil! Kembalian: Rp ${kembalian.toLocaleString('id-ID')}`;

    

    // Buat Objek Transaksi

    const transaksi = {

      waktu: new Date().toLocaleString('id-ID'),

      total: total,

      bayar: nominalBayar,

      kembalian: kembalian

    };


    // Simpan ke LocalStorage

    simpanDanTampilkanRiwayat(transaksi);


    // Reset Kasir

    keranjang = [];

    document.getElementById('input-bayar').value = '';

    updateTampilanKeranjang();

  }

}


// Inisialisasi awal saat halaman dimuat

tampilkanProduk();

tampilkanRiwayat();


3. Penjelasan Logika Fitur Baru

  • localStorage (Penyimpanan Browser): localStorage hanya menerima tipe data string. Oleh karena itu, kita gunakan JSON.stringify() saat menyimpannya dan JSON.parse() saat membaca kembali data objek ke bentuk Javascript Array.

  • Logika Pengurangan/Penghapusan Array (splice): Pada kurangiDariKeranjang(), sistem mengecek nilai jumlah. Jika item lebih dari 1, nilainya cukup dikurangi 1. Jika tersisa 1, kita gunakan splice(index, 1) untuk menghapus elemen tersebut secara penuh dari array keranjang.


No comments:

Post a Comment

Terima kasih telah mampir ke Blog yang amburadul ini

Membangun web sekolah berbasis Google Apps Script (GAS) dengan Google Sheets sebagai basis datanya.

  Berikut adalah modul panduan langkah demi langkah untuk membangun web sekolah berbasis Google Apps Script (GAS) dengan Google Sheets seb...