Compare commits
No commits in common. "98a809672556aa14ed3ea0fd82397624b3a771fb" and "f2b1ba34a7a0695cf72c611342bed93819f9322a" have entirely different histories.
98a8096725
...
f2b1ba34a7
@ -37,9 +37,17 @@ class DatabaseSeeder extends Seeder
|
|||||||
'updated_at' => now(),
|
'updated_at' => now(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Create sales record
|
||||||
|
Sales::create([
|
||||||
|
'nama' => 'Kasir',
|
||||||
|
'no_hp' => '-',
|
||||||
|
'alamat' => '-',
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now(),
|
||||||
|
]);
|
||||||
|
|
||||||
// Call other seeders
|
// Call other seeders
|
||||||
$this->call(DataSeeder::class);
|
$this->call(DataSeeder::class);
|
||||||
$this->call(DummySeeder::class);
|
$this->call(DummySeeder::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -18,7 +18,7 @@
|
|||||||
<p class="flex items-center gap-2">
|
<p class="flex items-center gap-2">
|
||||||
<i class="fab fa-whatsapp text-green-500 text-xl"></i> 08158851178
|
<i class="fab fa-whatsapp text-green-500 text-xl"></i> 08158851178
|
||||||
</p>
|
</p>
|
||||||
<p class="text-sm">TRSXXXXXXXXXXXX</p>
|
<p class=" text-sm">{{ generateTransactionCode() }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="absolute inset-x-0 top-[-48px] flex flex-col items-center">
|
<div class="absolute inset-x-0 top-[-48px] flex flex-col items-center">
|
||||||
@ -108,7 +108,7 @@
|
|||||||
|
|
||||||
<div class="w-[20%] p-2 flex flex-col items-center justify-center">
|
<div class="w-[20%] p-2 flex flex-col items-center justify-center">
|
||||||
<p><strong>Hormat Kami</strong></p>
|
<p><strong>Hormat Kami</strong></p>
|
||||||
<inputSelect v-model="selectedSales" :options="salesOptions" placeholder="Pilih Sales"
|
<inputSelect v-model="selectedSales" :options="salesOptions"
|
||||||
class="mt-16 text-sm rounded bg-B cursor-pointer !w-[160px] text-center [option]:text-left" />
|
class="mt-16 text-sm rounded bg-B cursor-pointer !w-[160px] text-center [option]:text-left" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -189,9 +189,18 @@ import inputSelect from '@/components/InputSelect.vue'
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
isOpen: Boolean,
|
isOpen: {
|
||||||
pesanan: Array,
|
type: Boolean,
|
||||||
total: Number
|
default: false,
|
||||||
|
},
|
||||||
|
pesanan: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
total: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['close', 'confirm', 'transaksi-saved'])
|
const emit = defineEmits(['close', 'confirm', 'transaksi-saved'])
|
||||||
@ -209,31 +218,52 @@ const showToast = ref(false)
|
|||||||
const toastType = ref('error')
|
const toastType = ref('error')
|
||||||
const toastMessage = ref('')
|
const toastMessage = ref('')
|
||||||
|
|
||||||
// 🧾 kode transaksi tetap
|
|
||||||
const transactionCode = ref('')
|
|
||||||
|
|
||||||
const toastClasses = computed(() => {
|
const toastClasses = computed(() => {
|
||||||
const base = 'text-white'
|
const baseClasses = 'text-white'
|
||||||
const type = {
|
const typeClasses = {
|
||||||
error: 'bg-red-500',
|
error: 'bg-red-500',
|
||||||
success: 'bg-green-500',
|
success: 'bg-green-500',
|
||||||
info: 'bg-blue-500'
|
info: 'bg-blue-500'
|
||||||
}
|
}
|
||||||
return `${base} ${type[toastType.value]}`
|
return `${baseClasses} ${typeClasses[toastType.value]}`
|
||||||
})
|
})
|
||||||
|
|
||||||
const grandTotal = computed(() => props.total + (ongkosBikin.value || 0))
|
const grandTotal = computed(() => {
|
||||||
|
return props.total + (ongkosBikin.value || 0)
|
||||||
|
})
|
||||||
|
|
||||||
const getRowStyle = () => props.pesanan.length === 1 ? { height: '126px' } : { height: '63px' }
|
const getRowStyle = () => {
|
||||||
const getImageClass = () => props.pesanan.length === 1 ? 'w-25 h-25' : 'w-12 h-12'
|
if (props.pesanan.length === 1) {
|
||||||
const getTextClass = () => props.pesanan.length === 1 ? 'text-lg font-medium' : 'text-sm'
|
return { height: '126px' }
|
||||||
|
}
|
||||||
|
return { height: '63px' }
|
||||||
|
}
|
||||||
|
|
||||||
|
const getImageClass = () => {
|
||||||
|
if (props.pesanan.length === 1) {
|
||||||
|
return 'w-25 h-25'
|
||||||
|
}
|
||||||
|
return 'w-12 h-12'
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTextClass = () => {
|
||||||
|
if (props.pesanan.length === 1) {
|
||||||
|
return 'text-lg font-medium'
|
||||||
|
}
|
||||||
|
return 'text-sm'
|
||||||
|
}
|
||||||
|
|
||||||
const getCurrentDate = () => {
|
const getCurrentDate = () => {
|
||||||
const days = ['Minggu','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu']
|
const days = ['Minggu', 'Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu']
|
||||||
|
const months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12']
|
||||||
|
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
|
const dayName = days[now.getDay()]
|
||||||
const day = String(now.getDate()).padStart(2, '0')
|
const day = String(now.getDate()).padStart(2, '0')
|
||||||
const month = String(now.getMonth() + 1).padStart(2, '0')
|
const month = months[now.getMonth()]
|
||||||
return `${days[now.getDay()]}, ${day}-${month}-${now.getFullYear()}`
|
const year = now.getFullYear()
|
||||||
|
|
||||||
|
return `${dayName}, ${day}-${month}-${year}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const generateTransactionCode = () => {
|
const generateTransactionCode = () => {
|
||||||
@ -246,33 +276,55 @@ const showSimpleToast = (type, message, duration = 3000) => {
|
|||||||
toastType.value = type
|
toastType.value = type
|
||||||
toastMessage.value = message
|
toastMessage.value = message
|
||||||
showToast.value = true
|
showToast.value = true
|
||||||
setTimeout(() => (showToast.value = false), duration)
|
|
||||||
|
setTimeout(() => {
|
||||||
|
showToast.value = false
|
||||||
|
}, duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchSales = async () => {
|
const fetchSales = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get('/api/sales', {
|
const response = await axios.get('/api/sales', {
|
||||||
headers: { Authorization: `Bearer ${localStorage.getItem("token")}` }
|
headers: {
|
||||||
|
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
salesOptions.value = res.data.map(s => ({ value: s.id, label: s.nama }))
|
|
||||||
if (salesOptions.value.length > 0) selectedSales.value = salesOptions.value[0].value
|
salesOptions.value = response.data.map(sales => ({
|
||||||
} catch (e) {
|
value: sales.id,
|
||||||
console.error('Error fetching sales:', e)
|
label: sales.nama
|
||||||
|
}))
|
||||||
|
|
||||||
|
if (salesOptions.value.length > 0) {
|
||||||
|
selectedSales.value = salesOptions.value[0].value
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching sales:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🟢 Generate kode hanya saat menyimpan transaksi
|
|
||||||
const handleSimpan = () => {
|
const handleSimpan = () => {
|
||||||
if (!namaPembeli.value.trim()) return showSimpleToast('error', 'Nama pembeli harus diisi!')
|
if (!namaPembeli.value.trim()) {
|
||||||
if (!nomorTelepon.value.trim()) return showSimpleToast('error', 'Nomor telepon harus diisi!')
|
showSimpleToast('error', 'Nama pembeli harus diisi!')
|
||||||
if (!alamat.value.trim()) return showSimpleToast('error', 'Alamat harus diisi!')
|
return
|
||||||
if (!selectedSales.value) return showSimpleToast('error', 'Sales harus dipilih!')
|
}
|
||||||
|
|
||||||
// Kode transaksi dibuat hanya saat simpan
|
if (!nomorTelepon.value.trim()) {
|
||||||
transactionCode.value = generateTransactionCode()
|
showSimpleToast('error', 'Nomor telepon harus diisi!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!alamat.value.trim()) {
|
||||||
|
showSimpleToast('error', 'Alamat harus diisi!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selectedSales.value) {
|
||||||
|
showSimpleToast('error', 'Sales harus dipilih!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
simpanTransaksi({
|
simpanTransaksi({
|
||||||
kode_transaksi: transactionCode.value,
|
|
||||||
id_sales: selectedSales.value,
|
id_sales: selectedSales.value,
|
||||||
nama_pembeli: namaPembeli.value,
|
nama_pembeli: namaPembeli.value,
|
||||||
no_hp: nomorTelepon.value,
|
no_hp: nomorTelepon.value,
|
||||||
@ -285,37 +337,48 @@ const handleSimpan = () => {
|
|||||||
|
|
||||||
const simpanTransaksi = async (dataTransaksi) => {
|
const simpanTransaksi = async (dataTransaksi) => {
|
||||||
if (isSaving.value) return
|
if (isSaving.value) return
|
||||||
|
|
||||||
isSaving.value = true
|
isSaving.value = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await axios.post('/api/transaksi', dataTransaksi, {
|
const response = await axios.post('/api/transaksi', dataTransaksi, {
|
||||||
headers: { Authorization: `Bearer ${localStorage.getItem("token")}` },
|
headers: {
|
||||||
})
|
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
showSimpleToast('success', 'Transaksi berhasil disimpan!', 2000)
|
showSimpleToast('success', 'Transaksi berhasil disimpan!', 2000)
|
||||||
|
|
||||||
|
// Emit event dengan data transaksi yang sudah disimpan
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
emit('transaksi-saved', res.data)
|
emit('transaksi-saved', response.data);
|
||||||
emit('close')
|
emit('close');
|
||||||
}, 2200)
|
}, 2200);
|
||||||
} catch (err) {
|
|
||||||
const msg = err.response?.data?.message || err.message || 'Terjadi kesalahan saat menyimpan transaksi'
|
} catch (error) {
|
||||||
showSimpleToast('error', `Error: ${msg}`, 4000)
|
console.error('Error saving transaksi:', error);
|
||||||
|
const errorMessage = error.response?.data?.message || error.message || 'Terjadi kesalahan saat menyimpan transaksi';
|
||||||
|
showSimpleToast('error', `Error: ${errorMessage}`, 4000);
|
||||||
} finally {
|
} finally {
|
||||||
isSaving.value = false
|
isSaving.value = false
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.isOpen) fetchSales()
|
if (props.isOpen) {
|
||||||
|
fetchSales()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function formatInput(e) {
|
function formatInput(e) {
|
||||||
let val = e.target.value.replace(/\D/g, "")
|
let value = e.target.value.replace(/\D/g, "");
|
||||||
ongkosBikin.value = val ? parseInt(val, 10) : null
|
ongkosBikin.value = value ? parseInt(value, 10) : null;
|
||||||
ongkosBikinFormatted.value = val ? new Intl.NumberFormat("id-ID").format(val) : ""
|
ongkosBikinFormatted.value = value
|
||||||
|
? new Intl.NumberFormat("id-ID").format(value)
|
||||||
|
: "";
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@import url('https://fonts.googleapis.com/css2?family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap');
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user