[Fix] transaksi

This commit is contained in:
Baghaztra 2025-09-12 11:10:13 +07:00
parent 03d01a1b78
commit eaa3318506
6 changed files with 253 additions and 312 deletions

View File

@ -5,6 +5,7 @@ namespace App\Http\Controllers;
use App\Models\Transaksi; use App\Models\Transaksi;
use App\Models\ItemTransaksi; use App\Models\ItemTransaksi;
use App\Models\Item; use App\Models\Item;
use App\Models\Sales;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@ -20,17 +21,7 @@ class TransaksiController extends Controller
} }
$transaksi = $query->get(); $transaksi = $query->get();
// Mapping agar sesuai dengan kebutuhan frontend return response()->json($transaksi); // Ubah $mapped menjadi $transaksi jika ingin mengirim data asli
$mapped = $transaksi->map(function ($trx) {
return [
'id' => $trx->id,
'tanggal' => $trx->created_at->format('d/m/Y'),
'kode' => 'TRX-' . str_pad($trx->id, 6, '0', STR_PAD_LEFT),
'pendapatan'=> $trx->total_harga,
];
});
return response()->json($mapped);
} }
@ -42,63 +33,76 @@ class TransaksiController extends Controller
} }
// Membuat transaksi baru // Membuat transaksi baru
public function store(Request $request) public function store(Request $request)
{ {
// Ambil user yang login via Sanctum $kasir = $request->user();
$kasir = $request->user(); // user authenticated if (!$kasir) {
if (!$kasir) { return response()->json(['error' => 'Unauthorized'], 401);
return response()->json(['error' => 'Unauthorized'], 401);
}
// Validasi request (id_kasir dihapus karena otomatis dari token)
$request->validate([
'id_sales' => 'nullable|exists:sales,id',
'nama_sales' => 'required|string',
'no_hp' => 'required|string',
'alamat' => 'required|string',
'ongkos_bikin' => 'nullable|numeric|min:0',
'total_harga' => 'required|numeric',
'items' => 'required|array',
'items.*.id_item' => 'required|exists:items,id',
'items.*.harga_deal' => 'required|numeric',
]);
DB::beginTransaction();
try {
$transaksi = Transaksi::create([
'id_kasir' => $kasir->id, // ambil dari token
'id_sales' => $request->id_sales,
'nama_sales' => $request->nama_sales,
'no_hp' => $request->no_hp,
'alamat' => $request->alamat,
'ongkos_bikin' => $request->ongkos_bikin ?? 0,
'total_harga' => $request->total_harga,
]);
foreach ($request->items as $it) {
ItemTransaksi::create([
'id_transaksi' => $transaksi->id,
'id_item' => $it['id_item'],
'harga_deal' => $it['harga_deal'],
]);
Item::where('id', $it['id_item'])->update(['is_sold' => true]);
} }
DB::commit(); $request->validate([
return response()->json( 'id_sales' => 'required|exists:sales,id',
$transaksi->load(['itemTransaksi.item.produk.foto', 'kasir', 'sales']), 'nama_pembeli' => 'required|string',
201 'no_hp' => 'required|string',
); 'alamat' => 'required|string',
'ongkos_bikin' => 'nullable|numeric|min:0',
'total_harga' => 'required|numeric',
'items' => 'required|array',
'items.*.kode_item' => 'required|exists:items,id',
'items.*.harga_deal' => 'required|numeric',
]);
} catch (\Exception $e) { DB::beginTransaction();
DB::rollBack(); try {
return response()->json([
'error' => $e->getMessage(), $sales = Sales::find($request->id_sales);
'trace' => $e->getTrace()
], 500); $transaksi = Transaksi::create([
} 'kode_transaksi' => 'belum pak',
} 'id_kasir' => $kasir->id,
'id_sales' => $request->id_sales,
'nama_sales' => $sales->nama ?? 'N/A',
'nama_pembeli' => $request->nama_pembeli,
'no_hp' => $request->no_hp,
'alamat' => $request->alamat,
'ongkos_bikin' => $request->ongkos_bikin ?? 0,
'total_harga' => $request->total_harga,
]);
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::find($it['kode_item']);
ItemTransaksi::create([
'id_transaksi' => $transaksi->id,
'id_item' => $item->id,
'harga_deal' => $it['harga_deal'],
'posisi_asal' => $item->nampan ? 'Nampan ' . $item->nampan->nama : 'Brankas',
]);
$item->update([
'is_sold' => true,
'id_nampan' => null,
]);
}
DB::commit();
return response()->json(
$transaksi->load(['itemTransaksi.item.produk.foto', 'kasir', 'sales']),
201
);
} catch (\Exception $e) {
DB::rollBack();
return response()->json([
'error' => $e->getMessage(),
'trace' => $e->getTrace()
], 500);
}
}
// Update transaksi // Update transaksi
@ -107,7 +111,12 @@ class TransaksiController extends Controller
$transaksi = Transaksi::findOrFail($id); $transaksi = Transaksi::findOrFail($id);
$transaksi->update($request->only([ $transaksi->update($request->only([
'id_sales', 'nama_sales', 'no_hp', 'alamat', 'ongkos_bikin', 'total_harga' 'id_sales',
'nama_sales',
'no_hp',
'alamat',
'ongkos_bikin',
'total_harga'
])); ]));
return response()->json($transaksi); return response()->json($transaksi);

View File

@ -11,7 +11,7 @@ class Transaksi extends Model
use HasFactory; use HasFactory;
protected $fillable = [ protected $fillable = [
'kode_transaksi', // ✅ Tambahin kolom kode transaksi 'kode_transaksi',
'id_kasir', 'id_kasir',
'id_sales', 'id_sales',
'nama_sales', 'nama_sales',
@ -25,23 +25,21 @@ class Transaksi extends Model
protected $hidden = ['updated_at', 'deleted_at']; protected $hidden = ['updated_at', 'deleted_at'];
// ✅ Auto-generate kode_transaksi saat create
protected static function boot() protected static function boot()
{ {
parent::boot(); parent::boot();
// Setelah transaksi berhasil dibuat (sudah punya ID) static::created(function ($transaksi) {
static::created(function ($transaksi) { if (!$transaksi->kode_transaksi || $transaksi->kode_transaksi === 'belum pak') {
if (!$transaksi->kode_transaksi) { $prefix = "TRS";
$prefix = "TRS"; $date = $transaksi->created_at->format('Ymd');
$date = $transaksi->created_at->format('Ymd'); $number = str_pad($transaksi->id, 4, '0', STR_PAD_LEFT);
$number = str_pad($transaksi->id, 4, '0', STR_PAD_LEFT);
$transaksi->kode_transaksi = $prefix . $date . $number; $transaksi->kode_transaksi = $prefix . $date . $number;
$transaksi->save(); $transaksi->save();
} }
}); });
} }
public function kasir() public function kasir()
{ {

View File

@ -1,22 +1,9 @@
<template> <template>
<ConfirmDeleteModal <ConfirmDeleteModal v-if="showDeleteModal" :isOpen="showDeleteModal" title="Konfirmasi"
v-if="showDeleteModal" message="Yakin ingin menghapus item ini?" @confirm="hapusPesanan" @cancel="closeDeleteModal" />
:isOpen="showDeleteModal"
title="Konfirmasi"
message="Yakin ingin menghapus item ini?"
@confirm="hapusPesanan"
@cancel="closeDeleteModal"
/>
<!-- ==== TAMBAHAN: Struk Overlay ==== --> <!-- ==== TAMBAHAN: Struk Overlay ==== -->
<StrukOverlay <StrukOverlay v-if="showStruk" :isOpen="showStruk" :pesanan="pesanan" :total="total" @close="closeStruk"/>
v-if="showStruk"
:isOpen="showStruk"
:pesanan="pesanan"
:total="total"
@close="closeStruk"
@confirm="simpanTransaksi"
/>
<!-- ==== END TAMBAHAN ==== --> <!-- ==== END TAMBAHAN ==== -->
<div class="p-2 sm:p-4"> <div class="p-2 sm:p-4">
@ -27,27 +14,14 @@
<!-- Input Kode Item --> <!-- Input Kode Item -->
<div> <div>
<label class="block text-sm font-medium text-D">Kode Item *</label> <label class="block text-sm font-medium text-D">Kode Item *</label>
<div <div class="flex flex-row justify-between mt-1 w-full rounded-md bg-A shadow-sm sm:text-sm border-B">
class="flex flex-row justify-between mt-1 w-full rounded-md bg-A shadow-sm sm:text-sm border-B" <input type="text" v-model="kodeItem" @keyup.enter="inputItem" placeholder="Scan atau masukkan kode item"
> class="bg-A focus:outline-none focus:border-C focus:ring focus:ring-D focus:ring-opacity-50 p-2 w-full rounded-l-md" />
<input <button v-if="!loadingItem" @click="inputItem" class="px-3 bg-D hover:bg-D/80 text-A rounded-r-md">
type="text"
v-model="kodeItem"
@keyup.enter="inputItem"
placeholder="Scan atau masukkan kode item"
class="bg-A focus:outline-none focus:border-C focus:ring focus:ring-D focus:ring-opacity-50 p-2 w-full rounded-l-md"
/>
<button
v-if="!loadingItem"
@click="inputItem"
class="px-3 bg-D hover:bg-D/80 text-A rounded-r-md"
>
<i class="fas fa-arrow-right"></i> <i class="fas fa-arrow-right"></i>
</button> </button>
<div v-else class="flex items-center justify-center px-3"> <div v-else class="flex items-center justify-center px-3">
<div <div class="rounded-full h-5 w-5 border-b-2 border-A flex items-center justify-center">
class="rounded-full h-5 w-5 border-b-2 border-A flex items-center justify-center"
>
<i class="fas fa-spinner"></i> <i class="fas fa-spinner"></i>
</div> </div>
</div> </div>
@ -57,25 +31,17 @@
<!-- Input Harga Jual --> <!-- Input Harga Jual -->
<div> <div>
<label class="block text-sm font-medium text-D">Harga Jual</label> <label class="block text-sm font-medium text-D">Harga Jual</label>
<InputField <InputField v-model="hargaJual" type="number" placeholder="Masukkan Harga Jual" />
v-model="hargaJual"
type="number"
placeholder="Masukkan Harga Jual"
/>
</div> </div>
<!-- Tombol Aksi --> <!-- Tombol Aksi -->
<div class="flex flex-col sm:flex-row justify-between gap-2"> <div class="flex flex-col sm:flex-row justify-between gap-2">
<button <button @click="tambahItem"
@click="tambahItem" class="w-full sm:w-auto px-4 py-2 rounded-md bg-C text-D font-medium hover:bg-C/80 transition">
class="w-full sm:w-auto px-4 py-2 rounded-md bg-C text-D font-medium hover:bg-C/80 transition"
>
Tambah Item Tambah Item
</button> </button>
<button <button @click="konfirmasiPenjualan"
@click="konfirmasiPenjualan" class="w-full sm:w-auto px-6 py-2 rounded-md bg-D text-A font-semibold hover:bg-D/80 transition">
class="w-full sm:w-auto px-6 py-2 rounded-md bg-D text-A font-semibold hover:bg-D/80 transition"
>
Lanjut Lanjut
</button> </button>
</div> </div>
@ -94,64 +60,50 @@
<!-- Error & Info --> <!-- Error & Info -->
<div class="mb-4"> <div class="mb-4">
<p <p v-if="error" :class="{ 'animate-shake': error }" class="text-sm text-red-600 mt-1">
v-if="error"
:class="{ 'animate-shake': error }"
class="text-sm text-red-600 mt-1"
>
{{ error }} {{ error }}
</p> </p>
<p v-if="info" class="text-sm text-C mt-1">{{ info }}</p> <p v-if="info" class="text-sm text-C mt-1">{{ info }}</p>
</div> </div>
<!-- Table Responsive --> <!-- Table Responsive -->
<div class="overflow-x-auto"> <div class="overflow-x-auto">
<table <table class="w-full border border-B rounded-lg overflow-hidden text-xs sm:text-sm">
class="w-full border border-B rounded-lg overflow-hidden text-xs sm:text-sm" <thead class="bg-A text-D">
> <tr>
<thead class="bg-A text-D"> <th class="border border-B p-2 w-8">No</th>
<tr> <th class="border border-B p-2">Nama Produk</th>
<th class="border border-B p-2 w-8">No</th> <th class="border border-B p-2">Posisi</th>
<th class="border border-B p-2">Nama Produk</th> <th class="border border-B p-2">Harga</th>
<th class="border border-B p-2">Posisi</th> <th class="border border-B p-2 w-10"></th>
<th class="border border-B p-2">Harga</th> </tr>
<th class="border border-B p-2 w-10"></th> </thead>
</tr> <tbody>
</thead> <tr v-if="pesanan.length == 0" class="text-center text-D/70">
<tbody> <td colspan="5" class="h-16 border border-B text-xs sm:text-sm">
<tr v-if="pesanan.length == 0" class="text-center text-D/70"> Belum ada item dipesan
<td colspan="5" class="h-16 border border-B text-xs sm:text-sm"> </td>
Belum ada item dipesan </tr>
</td> <tr v-else v-for="(item, index) in pesanan" :key="index" class="hover:bg-gray-50 text-center">
</tr> <td class="border border-B p-2">{{ index + 1 }}</td>
<tr <td class="border border-B p-2 text-left truncate max-w-[120px] sm:max-w-none">
v-else {{ item.produk.nama }}
v-for="(item, index) in pesanan" </td>
:key="index" <td class="border border-B p-2 truncate max-w-[80px]">
class="hover:bg-gray-50 text-center" {{ item.posisi ? item.posisi : "Brankas" }}
> </td>
<td class="border border-B p-2">{{ index + 1 }}</td> <td class="border border-B p-2 whitespace-nowrap">
<td class="border border-B p-2 text-left truncate max-w-[120px] sm:max-w-none"> Rp{{ item.harga_deal.toLocaleString() }}
{{ item.produk.nama }} </td>
</td> <td class="border border-B p-2 text-center">
<td class="border border-B p-2 truncate max-w-[80px]"> <button @click="openDeleteModal(index)" class="text-red-500 hover:text-red-700">
{{ item.posisi ? item.posisi : "Brankas" }} <i class="fas fa-trash"></i>
</td> </button>
<td class="border border-B p-2 whitespace-nowrap"> </td>
Rp{{ item.harga_deal.toLocaleString() }} </tr>
</td> </tbody>
<td class="border border-B p-2 text-center"> </table>
<button </div>
@click="openDeleteModal(index)"
class="text-red-500 hover:text-red-700"
>
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div> </div>
</template> </template>
@ -162,9 +114,7 @@ import { ref, computed } from "vue";
import InputField from "./InputField.vue"; import InputField from "./InputField.vue";
import axios from "axios"; import axios from "axios";
import ConfirmDeleteModal from "./ConfirmDeleteModal.vue"; import ConfirmDeleteModal from "./ConfirmDeleteModal.vue";
// ==== TAMBAHAN: Import StrukOverlay ====
import StrukOverlay from "./StrukOverlay.vue"; import StrukOverlay from "./StrukOverlay.vue";
// ==== END TAMBAHAN ====
const kodeItem = ref(""); const kodeItem = ref("");
const info = ref(""); const info = ref("");
@ -176,92 +126,86 @@ const pesanan = ref([]);
const showDeleteModal = ref(false) const showDeleteModal = ref(false)
const deleteIndex = ref(null) const deleteIndex = ref(null)
// ==== TAMBAHAN: State untuk struk ====
const showStruk = ref(false); const showStruk = ref(false);
// ==== END TAMBAHAN ====
// ==== TAMBAHAN: Emit untuk parent component ====
const emit = defineEmits(['transaksi-saved']);
// ==== END TAMBAHAN ====
let errorTimeout = null; let errorTimeout = null;
let infoTimeout = null; let infoTimeout = null;
const inputItem = async () => { const inputItem = async () => {
if (!kodeItem.value) return; if (!kodeItem.value) return;
info.value = ""; info.value = "";
error.value = ""; error.value = "";
clearTimeout(infoTimeout); clearTimeout(infoTimeout);
clearTimeout(errorTimeout); clearTimeout(errorTimeout);
loadingItem.value = true; loadingItem.value = true;
try { try {
const response = await axios.get(`/api/item/${kodeItem.value}`, { const response = await axios.get(`/api/item/${kodeItem.value}`, {
headers: { headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`, Authorization: `Bearer ${localStorage.getItem("token")}`,
}, },
}); });
item.value = response.data; item.value = response.data;
hargaJual.value = item.value.produk.harga_jual; hargaJual.value = item.value.produk.harga_jual;
if (item.value.is_sold) { if (item.value.is_sold) {
throw new Error("Item sudah terjual"); throw new Error("Item sudah terjual");
}
if (pesanan.value.some((p) => p.id === item.value.id)) {
throw new Error("Item sedang dipesan");
}
info.value = `Item dipilih: ${item.value.produk.nama} dari ${
item.value.posisi ? item.value.posisi : "Brankas"
}`;
infoTimeout = setTimeout(() => {
info.value = "";
}, 3000);
} catch (err) {
if (err == "") {
error.value = "Error: Item tidak ditemukan";
} else {
error.value = err;
}
info.value = "";
hargaJual.value = null;
item.value = null;
errorTimeout = setTimeout(() => {
error.value = "";
}, 3000);
} finally {
loadingItem.value = false;
} }
if (pesanan.value.some((p) => p.id === item.value.id)) {
throw new Error("Item sedang dipesan");
}
info.value = `Item dipilih: ${item.value.produk.nama} dari ${item.value.posisi ? item.value.posisi : "Brankas"
}`;
infoTimeout = setTimeout(() => {
info.value = "";
}, 3000);
} catch (err) {
if (err == "") {
error.value = "Error: Item tidak ditemukan";
} else {
error.value = err;
}
info.value = "";
hargaJual.value = null;
item.value = null;
errorTimeout = setTimeout(() => {
error.value = "";
}, 3000);
} finally {
loadingItem.value = false;
}
}; };
const tambahItem = () => { const tambahItem = () => {
if (!item.value || !hargaJual.value) { if (!item.value || !hargaJual.value) {
error.value = "Scan atau masukkan kode item untuk dijual."; error.value = "Scan atau masukkan kode item untuk dijual.";
if (kodeItem.value) { if (kodeItem.value) {
error.value = error.value =
"Masukkan harga jual, atau input dari kode item lagi."; "Masukkan harga jual, atau input dari kode item lagi.";
}
clearTimeout(errorTimeout);
errorTimeout = setTimeout(() => {
error.value = "";
}, 3000);
return;
} }
clearTimeout(errorTimeout);
errorTimeout = setTimeout(() => {
error.value = "";
}, 3000);
return;
}
// harga deal // harga deal
item.value.harga_deal = Number(hargaJual.value); item.value.kode_item = kodeItem.value;
item.value.harga_deal = Number(hargaJual.value);
pesanan.value.push(item.value); pesanan.value.push(item.value);
// Reset input fields // Reset input fields
kodeItem.value = ""; kodeItem.value = "";
hargaJual.value = null; hargaJual.value = null;
item.value = null; item.value = null;
info.value = ""; info.value = "";
clearTimeout(infoTimeout); clearTimeout(infoTimeout);
}; };
const openDeleteModal = (index) => { const openDeleteModal = (index) => {
@ -283,71 +227,31 @@ const hapusPesanan = () => {
// ==== MODIFIKASI: konfirmasiPenjualan sekarang menampilkan struk ==== // ==== MODIFIKASI: konfirmasiPenjualan sekarang menampilkan struk ====
const konfirmasiPenjualan = () => { const konfirmasiPenjualan = () => {
if (pesanan.value.length === 0) { if (pesanan.value.length === 0) {
error.value = "Belum ada item yang dipesan."; error.value = "Belum ada item yang dipesan.";
clearTimeout(errorTimeout); clearTimeout(errorTimeout);
errorTimeout = setTimeout(() => { errorTimeout = setTimeout(() => {
error.value = ""; error.value = "";
}, 3000); }, 3000);
return; return;
} }
// Tampilkan struk overlay // Tampilkan struk overlay
showStruk.value = true; showStruk.value = true;
}; };
// ==== END MODIFIKASI ==== // ==== END MODIFIKASI ====
// ==== TAMBAHAN: Fungsi untuk menutup struk ==== // ==== TAMBAHAN: Fungsi untuk menutup struk ====
const closeStruk = () => { const closeStruk = () => {
showStruk.value = false; showStruk.value = false;
};
// ==== END TAMBAHAN ====
// ==== TAMBAHAN: Fungsi untuk menyimpan transaksi ====
const simpanTransaksi = async (dataTransaksi) => {
try {
// Siapkan data untuk API
const transaksiData = {
id_kasir: localStorage.getItem('user_id'), // Asumsi user_id disimpan di localStorage
id_sales: dataTransaksi.selectedSales?.id || null,
nama_sales: dataTransaksi.namaPembeli,
no_hp: dataTransaksi.nomorTelepon,
alamat: dataTransaksi.alamat,
ongkos_bikin: dataTransaksi.ongkosBikin || 0,
total_harga: total.value + (dataTransaksi.ongkosBikin || 0),
items: pesanan.value.map(item => ({
id_item: item.id,
harga_deal: item.harga_deal
}))
};
const response = await axios.post('/api/transaksi', transaksiData, {
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
});
// Reset form setelah berhasil
pesanan.value = [];
showStruk.value = false;
// Emit ke parent untuk refresh data transaksi
emit('transaksi-saved', response.data);
alert('Transaksi berhasil disimpan!');
} catch (error) {
console.error('Error saving transaksi:', error);
alert('Error menyimpan transaksi: ' + (error.response?.data?.message || error.message));
}
}; };
// ==== END TAMBAHAN ==== // ==== END TAMBAHAN ====
const total = computed(() => { const total = computed(() => {
let sum = 0; let sum = 0;
pesanan.value.forEach((item) => { pesanan.value.forEach((item) => {
sum += item.harga_deal; sum += item.harga_deal;
}); });
return sum; return sum;
}); });
</script> </script>

View File

@ -14,7 +14,7 @@
<tr v-for="trx in props.transaksi" :key="trx.id" class="hover:bg-A"> <tr v-for="trx in props.transaksi" :key="trx.id" class="hover:bg-A">
<td class="border border-B p-2">{{ trx.tanggal }}</td> <td class="border border-B p-2">{{ trx.tanggal }}</td>
<td class="border border-B p-2">{{ trx.kode }}</td> <td class="border border-B p-2">{{ trx.kode }}</td>
<td class="border border-B p-2">Rp{{ (trx.pendapatan || 0).toLocaleString() }}</td> <td class="border border-B p-2">Rp{{ (trx.total_harga || 0).toLocaleString() }}</td>
<td class="border border-B p-2 text-center"> <td class="border border-B p-2 text-center">
<button <button
@click="$emit('detail', trx)" @click="$emit('detail', trx)"

View File

@ -260,7 +260,7 @@ const fetchSales = async () => {
}) })
salesOptions.value = response.data.map(sales => ({ salesOptions.value = response.data.map(sales => ({
value: sales, value: sales.id,
label: sales.nama label: sales.nama
})) }))
@ -298,14 +298,41 @@ const handleSimpan = () => {
} }
// Emit data ke parent // Emit data ke parent
emit('confirm', { simpanTransaksi({
namaPembeli: namaPembeli.value, id_sales: selectedSales.value,
nomorTelepon: nomorTelepon.value, nama_pembeli: namaPembeli.value,
no_hp: nomorTelepon.value,
alamat: alamat.value, alamat: alamat.value,
ongkosBikin: ongkosBikin.value || 0, ongkosBikin: ongkosBikin.value || 0,
selectedSales: selectedSales.value total_harga: grandTotal.value,
items: props.pesanan
}) })
} }
// ==== TAMBAHAN: Fungsi untuk menyimpan transaksi ====
const simpanTransaksi = async (dataTransaksi) => {
console.log('Data transaksi yang akan disimpan:', dataTransaksi);
try {
const response = await axios.post('/api/transaksi', dataTransaksi, {
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
});
// Reset form setelah berhasil
props.pesanan.value = [];
props.isOpen = false;
alert('Transaksi berhasil disimpan!');
window.location.reload();
} catch (error) {
console.error('Error saving transaksi:', error);
alert('Error menyimpan transaksi: ' + (error.response?.data?.message || error.message));
}
};
// ==== END TAMBAHAN ====
// ==== END TAMBAHAN ==== // ==== END TAMBAHAN ====
// ==== TAMBAHAN: Fetch sales saat component mounted ==== // ==== TAMBAHAN: Fetch sales saat component mounted ====

View File

@ -95,6 +95,9 @@ const fetchTransaksi = async () => {
}); });
transaksi.value = res.data; transaksi.value = res.data;
console.log("Fetched transaksi:", transaksi.value);
} catch (err) { } catch (err) {
console.error("Gagal fetch transaksi:", err); console.error("Gagal fetch transaksi:", err);
} finally { } finally {