diff --git a/app/Http/Controllers/ItemController.php b/app/Http/Controllers/ItemController.php index 7b51944..843c177 100644 --- a/app/Http/Controllers/ItemController.php +++ b/app/Http/Controllers/ItemController.php @@ -42,9 +42,20 @@ class ItemController extends Controller /** * Display the specified resource. */ - public function show(int $id) + public function show(string $kode_item) { - $item = Item::with('produk.foto','nampan')->findOrFail($id); + $query = Item::with(['produk.foto', 'nampan']); + + if (is_numeric($kode_item)) { + $item = $query->where('id', (int)$kode_item)->first(); + } else { + $item = $query->where('kode_item', $kode_item)->first(); + } + + if (!$item) { + return response()->json(['message' => 'Item tidak ditemukan'], 404); + } + return response()->json($item); } diff --git a/app/Http/Controllers/NampanController.php b/app/Http/Controllers/NampanController.php index 91f7ffd..8e98de8 100644 --- a/app/Http/Controllers/NampanController.php +++ b/app/Http/Controllers/NampanController.php @@ -27,14 +27,13 @@ class NampanController extends Controller 'nama' => 'required|string|max:10|unique:nampans,nama', ], [ - 'nama.required' => 'Nama nampan harus diisi.', + 'nama.max' => 'Nama nampan maksimal 10 karakter.', 'nama.unique' => 'Nampan dengan nama yang sama sudah ada.', - 'nama.max' => 'Nama nampan maksimal 10 karakter.' + 'nama.required' => 'Nama nampan harus diisi.' ]); Nampan::create($validated); - return response()->json([ 'message' => 'Nampan berhasil dibuat' ],201); @@ -59,7 +58,9 @@ class NampanController extends Controller 'nama' => 'required|string|max:10|unique:nampans,nama,'.$id, ], [ - 'nama' => 'Nama nampan harus diisi.' + 'nama.max' => 'Nama nampan maksimal 10 karakter.', + 'nama.unique' => 'Nampan dengan nama yang sama sudah ada.', + 'nama.required' => 'Nama nampan harus diisi.' ]); $nampan = Nampan::findOrFail($id); diff --git a/app/Http/Controllers/TransaksiController.php b/app/Http/Controllers/TransaksiController.php index 931504d..2e9cbd6 100644 --- a/app/Http/Controllers/TransaksiController.php +++ b/app/Http/Controllers/TransaksiController.php @@ -39,7 +39,7 @@ class TransaksiController extends Controller if ($search) { $query->where(function ($q) use ($search) { $q->where('kode_transaksi', 'like', '%' . $search . '%') - ->orWhere('nama_pembeli', 'like', '%' . $search . '%'); + ->orWhere('nama_pembeli', 'like', '%' . $search . '%'); }); } @@ -51,7 +51,7 @@ class TransaksiController extends Controller $transaksi->total_items = $transaksi->itemTransaksi->count(); $transaksi->tanggal = $transaksi->created_at->format('d/m/Y H:i'); $transaksi->pendapatan = $transaksi->total_harga ?? 0; - + return $transaksi; }); @@ -72,8 +72,8 @@ class TransaksiController extends Controller public function show($id) { $transaksi = Transaksi::with([ - 'kasir', - 'sales', + 'kasir', + 'sales', 'itemTransaksi.produk', 'itemTransaksi' => function ($query) { $query->orderBy('created_at', 'asc'); @@ -125,13 +125,20 @@ class TransaksiController extends Controller ]); foreach ($request->items as $it) { - // TODO: ubah saat transaksi pake kode_item - // $item = Item::where('kode_item', $it['kode_item'])->first(); - // if (!$item) { - // throw new \Exception("Item dengan kode_item {$it['kode_item']} tidak ditemukan."); - // } - $item = Item::where('id',$it['kode_item'])->with('produk')->first(); + $query = Item::with(['produk.foto', 'nampan']); + if (is_numeric($it['kode_item'])) { + $item = $query->where('id', (int)$it['kode_item'])->first(); + } else { + $item = $query->where('kode_item', $it['kode_item'])->first(); + } + + if (!$item) { + return response()->json(['message' => 'Item tidak ditemukan'], 404); + } + if (!$item) { + throw new \Exception("Item dengan kode_item {$it['kode_item']} tidak ditemukan."); + } ItemTransaksi::create([ 'id_transaksi' => $transaksi->id, 'id_produk' => $item->produk->id, diff --git a/database/migrations/2025_08_25_071441_create_nampans_table.php b/database/migrations/2025_08_25_071441_create_nampans_table.php index 812d225..754bd0b 100644 --- a/database/migrations/2025_08_25_071441_create_nampans_table.php +++ b/database/migrations/2025_08_25_071441_create_nampans_table.php @@ -13,7 +13,7 @@ return new class extends Migration { Schema::create('nampans', function (Blueprint $table) { $table->id(); - $table->string('nama', 100)->unique(); + $table->string('nama', 10)->unique(); $table->timestamps(); }); } diff --git a/database/seeders/DataSeeder.php b/database/seeders/DataSeeder.php new file mode 100644 index 0000000..0085195 --- /dev/null +++ b/database/seeders/DataSeeder.php @@ -0,0 +1,62 @@ +create([ + 'nama' => 'A' . ($i + 1) + ]); + } + } + + // Kategori + $kategoriList = ['Cincin', 'Gelang Rantai', 'Gelang Bulat', 'Kalung', 'Liontin', 'Anting', 'Giwang']; + foreach ($kategoriList as $kategori) { + Kategori::factory()->create([ + 'nama' => $kategori + ]); + } + + // Produk + $produk1 = Produk::factory()->create([ + 'nama'=>'Gelang serut daun shimmer mp (mas putih)', + 'id_kategori'=>Kategori::find(2), + 'berat'=>1.4, + 'kadar'=>8, + 'harga_per_gram'=>900000, + 'harga_jual'=>1260000, + ]); + $produk1->foto()->create([ + 'id_produk'=>$produk1->id, + 'url'=>'https://i.imgur.com/eGYHzvw.jpeg' + ]); + + $produk2 = Produk::factory()->create([ + 'nama'=>'Gelang rantai 5 buah clover merah', + 'id_kategori'=>Kategori::find(2), + 'berat'=>3.6, + 'kadar'=>8, + 'harga_per_gram'=>850000, + 'harga_jual'=>3060000, + ]); + $produk2->foto()->create([ + 'id_produk'=>$produk2->id, + 'url'=>'https://i.imgur.com/UjQzYoE.jpeg' + ]); + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 8d7258c..6f8fdfe 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -20,109 +20,23 @@ class DatabaseSeeder extends Seeder public function run(): void { User::factory()->create([ - 'nama' => 'andre', + 'nama' => 'admin', 'role' => 'owner', 'password' => bcrypt('123123'), ]); User::factory()->create([ - 'nama' => 'luis', + 'nama' => 'kasir', 'role' => 'kasir', 'password' => bcrypt('123123'), ]); - User::factory(2)->create(); - Sales::factory(5)->create(); - - for ($i=0; $i < 30; $i++) { - if ($i != 12) { - Nampan::factory()->create([ - 'nama' => 'A' . ($i + 1) - ]); - } - } - - $kategoriList = ['Cincin', 'Gelang Rantai', 'Gelang Bulat', 'Kalung', 'Liontin', 'Anting', 'Giwang']; - foreach ($kategoriList as $kategori) { - Kategori::factory()->create([ - 'nama' => $kategori - ]); - } - - // Produk::factory(10)->create()->each(function ($produk) { - // // setiap produk punya 1-3 foto - // $jumlah_foto = rand(1, 3); - // $fotoData = []; - // for ($i = 0; $i < $jumlah_foto; $i++) { - // $fotoData[] = [ - // // 'url' => 'https://random-image-pepebigotes.vercel.app/api/random-image' - // 'url' => 'https://static.promediateknologi.id/crop/0x0:0x0/0x0/webp/photo/p2/255/2024/12/10/Screenshot_2024-12-10-11-50-18-88_1c337646f29875672b5a61192b9010f9-1-1282380831.jpg' - // ]; - // } - // $produk->foto()->createMany($fotoData); - - // $jumlah_item = rand(1, 20); - // Item::factory($jumlah_item)->create([ - // 'id_produk' => $produk->id, - // ]); - // }); - - $produk1 = Produk::factory()->create([ - 'nama'=>'Gelang serut daun shimmer mp (mas putih)', - 'id_kategori'=>Kategori::find(2), - 'berat'=>1.4, - 'kadar'=>8, - 'harga_per_gram'=>900000, - 'harga_jual'=>1260000, - ]); - $produk1->foto()->create([ - 'id_produk'=>$produk1->id, - 'url'=>'https://i.imgur.com/eGYHzvw.jpeg' - ]); - - $produk2 = Produk::factory()->create([ - 'nama'=>'Gelang rantai 5 buah clover merah', - 'id_kategori'=>Kategori::find(2), - 'berat'=>3.6, - 'kadar'=>8, - 'harga_per_gram'=>850000, - 'harga_jual'=>3060000, - ]); - $produk2->foto()->create([ - 'id_produk'=>$produk2->id, - 'url'=>'https://i.imgur.com/UjQzYoE.jpeg' + Sales::factory()->create([ + 'nama' => 'Umum', + 'no_hp' => '-', + 'alamat' => '-', ]); - Item::factory(500)->create(); - - // 75% peluang item masuk nampan, sisanya di brankas - $nampans = Nampan::all()->pluck('id')->toArray(); - $jumlahNampan = count($nampans); - $counter = 0; - - foreach (Item::all() as $item) { - if (rand(1, 100) <= 75) { - $item->update([ - 'id_nampan' => $nampans[$counter % $jumlahNampan], - ]); - $counter++; - } - } - - Transaksi::factory(250)->create()->each(function ($transaksi) { - $jumlah_item = rand(1, 2); - $items = Item::with('produk')->inRandomOrder()->limit($jumlah_item)->get(); - if ($items->isEmpty()) return; - $total_harga = $transaksi->total_harga; - foreach ($items as $item) { - $transaksi->itemTransaksi()->create([ - 'id_produk' => $item->produk->id, - 'harga_deal' => $item->produk->harga_jual, - 'posisi_asal' => $item->id_nampan ? $item->nampan->nama : 'Brankas', - ]); - $item->delete(); - $total_harga += $item->produk->harga_jual; - } - $transaksi->update(['total_harga' => $total_harga]); - }); + $this->call(DataSeeder::class); + $this->call(DummySeeder::class); } } diff --git a/database/seeders/DummySeeder.php b/database/seeders/DummySeeder.php new file mode 100644 index 0000000..d2c099a --- /dev/null +++ b/database/seeders/DummySeeder.php @@ -0,0 +1,56 @@ +create(); + Sales::factory(5)->create(); + + Item::factory(500)->create(); + + // 75% peluang item masuk nampan, sisanya di brankas + $nampans = Nampan::all()->pluck('id')->toArray(); + $jumlahNampan = count($nampans); + $counter = 0; + + foreach (Item::all() as $item) { + if (rand(1, 100) <= 75) { + $item->update([ + 'id_nampan' => $nampans[$counter % $jumlahNampan], + ]); + $counter++; + } + } + + Transaksi::factory(250)->create()->each(function ($transaksi) { + $jumlah_item = rand(1, 2); + $items = Item::with('produk')->inRandomOrder()->limit($jumlah_item)->get(); + if ($items->isEmpty()) return; + $total_harga = $transaksi->total_harga; + foreach ($items as $item) { + $transaksi->itemTransaksi()->create([ + 'id_produk' => $item->produk->id, + 'harga_deal' => $item->produk->harga_jual, + 'posisi_asal' => $item->id_nampan ? $item->nampan->nama : 'Brankas', + ]); + $item->delete(); + $total_harga += $item->produk->harga_jual; + } + $transaksi->update(['total_harga' => $total_harga]); + }); + } +} diff --git a/resources/js/components/BrankasList.vue b/resources/js/components/BrankasList.vue index 904ea91..881f29e 100644 --- a/resources/js/components/BrankasList.vue +++ b/resources/js/components/BrankasList.vue @@ -66,10 +66,10 @@
- +
- QR Code + Barcode
@@ -201,11 +201,11 @@ const confirmModalMessage = ref(""); const confirmText = ref("Ya, Konfirmasi"); const cancelText = ref("Batal"); -// QR Code generator -const qrCodeUrl = computed(() => { +// Barcode generator (Code128) +const barcodeUrl = computed(() => { if (selectedItem.value) { const data = selectedItem.value.kode_item; - return `https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${encodeURIComponent(data)}`; + return `https://barcode.tec-it.com/barcode.ashx?data=${encodeURIComponent(data)}&code=Code128&dpi=96`; } return ""; }); @@ -333,15 +333,15 @@ const handleConfirmAction = async () => { // Fungsi utilitas const printQR = () => { - if (qrCodeUrl.value) { + if (barcodeUrl.value) { const printWindow = window.open('', '_blank'); printWindow.document.write(` - Print QR Code - ${selectedItem.value.kode_item} + Print Barcode - ${selectedItem.value.kode_item} -
- QR Code + Barcode
${selectedItem.value.kode_item} diff --git a/resources/js/components/CreateItemModal.vue b/resources/js/components/CreateItemModal.vue index 88101f7..63551ff 100644 --- a/resources/js/components/CreateItemModal.vue +++ b/resources/js/components/CreateItemModal.vue @@ -102,14 +102,16 @@ const createdItem = ref(null); // QR Code generator - berdasarkan logika dari brankas list const qrCodeUrl = computed(() => { if (createdItem.value && props.product) { - const itemId = createdItem.value.id || createdItem.value.kode_item; - const productName = props.product.nama.replace(/\s/g, ""); - const data = `ITM-${itemId}-${productName}`; - return `https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${encodeURIComponent(data)}`; + const itemId = createdItem.value.kode_item || createdItem.value.id; + const data = `${itemId}`; + + // Barcode Code128 + return `https://barcode.tec-it.com/barcode.ashx?data=${encodeURIComponent(data)}&code=Code128&dpi=96`; } return ""; }); + // Methods const loadNampanList = async () => { try { @@ -204,7 +206,7 @@ const printItem = () => {
- QR Code + Barcode
${itemCode}
${props.product.nama}
diff --git a/resources/js/components/KasirForm.vue b/resources/js/components/KasirForm.vue index 6b11af4..81a8e26 100644 --- a/resources/js/components/KasirForm.vue +++ b/resources/js/components/KasirForm.vue @@ -31,9 +31,9 @@
- { const value = event.target.value; // Hapus semua karakter selain angka const cleanValue = value.replace(/\D/g, ""); - + if (cleanValue) { // Format dengan pemisah ribuan const formatted = formatNumber(cleanValue); @@ -284,7 +284,7 @@ const konfirmasiPenjualan = () => { }, 5000); return; } - + console.log(pesanan.value) // Tampilkan struk overlay showStruk.value = true; }; diff --git a/resources/js/components/ModalConfirm.vue b/resources/js/components/ModalConfirm.vue new file mode 100644 index 0000000..4e4a267 --- /dev/null +++ b/resources/js/components/ModalConfirm.vue @@ -0,0 +1,20 @@ + + + diff --git a/resources/js/components/StrukOverlay.vue b/resources/js/components/StrukOverlay.vue index 06bd95f..2cd21b7 100644 --- a/resources/js/components/StrukOverlay.vue +++ b/resources/js/components/StrukOverlay.vue @@ -355,7 +355,7 @@ const handleSimpan = () => { } const simpanTransaksi = async (dataTransaksi) => { - // console.log('Data transaksi yang akan disimpan:', dataTransaksi); +// console.log('Data transaksi yang akan disimpan:', dataTransaksi); try { const response = await axios.post('/api/transaksi', dataTransaksi, { diff --git a/resources/js/components/TrayList.vue b/resources/js/components/TrayList.vue index 6da99da..e728ec3 100644 --- a/resources/js/components/TrayList.vue +++ b/resources/js/components/TrayList.vue @@ -88,7 +88,7 @@
- QR Code + Barcode
@@ -167,25 +167,25 @@ const selectedItem = ref(null); const selectedTrayId = ref(""); const showDeleteConfirm = ref(false); -// QR Code generator -const qrCodeUrl = computed(() => { +// Barcode generator (Code128) +const barcodeUrl = computed(() => { if (selectedItem.value) { const data = selectedItem.value.kode_item; - return `https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${encodeURIComponent(data)}`; + return `https://barcode.tec-it.com/barcode.ashx?data=${encodeURIComponent(data)}&code=Code128&dpi=96`; } return ""; }); const printQR = () => { - if (qrCodeUrl.value) { + if (barcodeUrl.value) { const printWindow = window.open('', '_blank'); printWindow.document.write(` - Print QR Code - ${selectedItem.value.kode_item} + Print Barcode - ${selectedItem.value.kode_item} -
- QR Code +
+ Barcode
${selectedItem.value.kode_item}
@@ -226,7 +226,7 @@ const printQR = () => { printWindow.document.close(); - const img = printWindow.document.getElementById("qr-img"); + const img = printWindow.document.getElementById("barcode-img"); img.onload = () => { printWindow.focus(); printWindow.print(); diff --git a/resources/js/pages/Kasir.vue b/resources/js/pages/Kasir.vue index 5a41651..fb733c3 100644 --- a/resources/js/pages/Kasir.vue +++ b/resources/js/pages/Kasir.vue @@ -33,16 +33,26 @@
+ + +