478 lines
22 KiB
Vue
478 lines
22 KiB
Vue
<template>
|
|
<div style="width: 100%;">
|
|
<v-toolbar color="primary" dark>
|
|
<v-toolbar-title class="white--text">PURCHASE INVOICE</v-toolbar-title>
|
|
<v-spacer></v-spacer>
|
|
<!-- <v-btn icon @click="newFaktur()">
|
|
<v-icon large>add_box</v-icon>
|
|
</v-btn> -->
|
|
</v-toolbar>
|
|
|
|
<v-card class="pa-2">
|
|
<v-layout row wrap>
|
|
<v-flex xs2 pr-2>
|
|
<v-menu
|
|
v-model="filterDateForm" transition="scale-transition"
|
|
full-width offset-y lazy :nudge-right="40"
|
|
max-width="290px" min-width="290px"
|
|
:close-on-content-click="false"
|
|
>
|
|
<template v-slot:activator="{on}">
|
|
<v-text-field
|
|
label="Tanggal Awal" readonly v-on="on"
|
|
outline hide-details :value="DateFormated"
|
|
></v-text-field>
|
|
</template>
|
|
<v-date-picker
|
|
no-title v-model="filter.date" @input="filterDateForm = false"
|
|
></v-date-picker>
|
|
</v-menu>
|
|
</v-flex>
|
|
<v-flex xs2 pr-2>
|
|
<v-menu
|
|
v-model="filterEndDateForm" transition="scale-transition"
|
|
full-width offset-y lazy :nudge-right="40"
|
|
max-width="290px" min-width="290px"
|
|
:close-on-content-click="false"
|
|
>
|
|
<template v-slot:activator="{on}">
|
|
<v-text-field
|
|
label="Tanggal Akhir" readonly v-on="on"
|
|
outline hide-details :value="EndDateFormated"
|
|
></v-text-field>
|
|
</template>
|
|
<v-date-picker
|
|
no-title v-model="filter.enddate" @input="filterEndDateForm = false"
|
|
></v-date-picker>
|
|
</v-menu>
|
|
</v-flex>
|
|
<v-flex xs3 pr-2>
|
|
<v-autocomplete
|
|
v-model="filter.supplier" label="Supplier" hide-details item-value="SupplierID"
|
|
:items="list_supplier.records" outline item-text="SupplierName" clearable
|
|
></v-autocomplete>
|
|
</v-flex>
|
|
<v-flex xs2 pr-2>
|
|
<v-autocomplete
|
|
v-model="filter.status" label="Status" hide-details
|
|
:items="statusFaktur" outline
|
|
></v-autocomplete>
|
|
</v-flex>
|
|
<v-flex xs3>
|
|
<v-layout row justify-space-between>
|
|
<v-flex xs10 pr-2>
|
|
<v-text-field
|
|
v-model="filter.nomor" hide-details outline
|
|
label="Nomor Faktur / Delivery / Supplier Invoice"
|
|
></v-text-field>
|
|
</v-flex>
|
|
<v-flex xs2>
|
|
<v-btn
|
|
dark color="primary" @click="searchFaktur()"
|
|
style="height: 40px; min-width: 40px;"
|
|
>
|
|
<v-icon>search</v-icon>
|
|
</v-btn>
|
|
</v-flex>
|
|
</v-layout>
|
|
</v-flex>
|
|
</v-layout>
|
|
</v-card>
|
|
|
|
<v-card class="pa-2 mt-2">
|
|
<v-data-table
|
|
:headers="headers" :items="list_faktur.records"
|
|
hide-actions class="elevation-1 mb-2"
|
|
>
|
|
<template v-slot:items="props">
|
|
<tr>
|
|
<td class="text-xs-center pa-2">{{ props.index + 1}}</td>
|
|
<td class="text-xs-center pa-2">{{ props.item.SupplierInvoiceNumber }}</td>
|
|
<td class="text-xs-center pa-2">{{ deFormatedDate(props.item.SupplierInvoiceDate) }}</td>
|
|
<td class="text-xs-center pa-2">{{ deFormatedDate(props.item.SupplierInvoiceDueDate) }}</td>
|
|
<td class="text-xs-center pa-2">{{ props.item.SupplierName }}</td>
|
|
<td class="text-xs-center pa-2">{{ props.item.WarehouseName }}</td>
|
|
<td class="text-xs-center pa-2 text-truncate">{{ props.item.SupplierInvoiceNote }}</td>
|
|
<td class="text-xs-center pa-2">Rp. {{ toRupiah(props.item.SupplierInvoiceGrandTotal) }}</td>
|
|
<td class="text-xs-center pa-2">{{ props.item.SupplierInvoiceStatus }}</td>
|
|
<td class="text-xs-center pa-2">
|
|
<v-layout align-center justify-center row fill-height>
|
|
<v-tooltip bottom class="pr-1">
|
|
<template v-slot:activator="{ on }">
|
|
<v-btn
|
|
color="info" dark small v-on="on"
|
|
style="min-width: 40px; margin: 0;"
|
|
@click="viewAttachment(props.item)"
|
|
>
|
|
<v-icon small>attachment</v-icon>
|
|
</v-btn>
|
|
</template>
|
|
<span>Bukti Penerimaan</span>
|
|
</v-tooltip>
|
|
<div v-show="props.item.SupplierInvoiceStatus == 'Draft'">
|
|
<v-tooltip bottom pr-2>
|
|
<template v-slot:activator="{on}">
|
|
<v-btn
|
|
color="warning" dark small v-on="on"
|
|
style="min-width: 40px; margin: 0;"
|
|
@click="editFaktur(props.item)"
|
|
>
|
|
<v-icon small>edit</v-icon>
|
|
</v-btn>
|
|
</template>
|
|
<span>Edit Draft</span>
|
|
</v-tooltip>
|
|
<v-tooltip bottom pr-2>
|
|
<template v-slot:activator="{on}">
|
|
<v-btn
|
|
color="success" dark small v-on="on"
|
|
style="min-width: 40px; margin: 0;"
|
|
@click="fakturVerify(props.item)"
|
|
>
|
|
<v-icon small>send</v-icon>
|
|
</v-btn>
|
|
</template>
|
|
<span>Verifikasi Draft</span>
|
|
</v-tooltip>
|
|
</div>
|
|
<div v-show="props.item.SupplierInvoiceStatus == 'Verified'">
|
|
<v-tooltip bottom pr-2>
|
|
<template v-slot:activator="{on}">
|
|
<v-btn
|
|
color="success" dark small v-on="on"
|
|
style="min-width: 40px; margin: 0;"
|
|
@click="fakturApprove(props.item)"
|
|
>
|
|
<v-icon small>done_all</v-icon>
|
|
</v-btn>
|
|
</template>
|
|
<span>Approve Faktur</span>
|
|
</v-tooltip>
|
|
<v-tooltip bottom pr-2>
|
|
<template v-slot:activator="{on}">
|
|
<v-btn
|
|
color="error" dark small v-on="on"
|
|
style="min-width: 40px; margin: 0;"
|
|
@click="fakturReject(props.item)"
|
|
>
|
|
<v-icon small>block</v-icon>
|
|
</v-btn>
|
|
</template>
|
|
<span>Tolak Faktur</span>
|
|
</v-tooltip>
|
|
</div>
|
|
<div v-show="props.item.SupplierInvoiceStatus == 'Approved'">
|
|
<v-tooltip bottom>
|
|
<template v-slot:activator="{on}">
|
|
<v-btn
|
|
style="min-width: 40px; margin: 0;"
|
|
color="blue" small v-on="on" dark
|
|
@click="viewFaktur(props.item)"
|
|
>
|
|
<v-icon small>visibility</v-icon>
|
|
</v-btn>
|
|
</template>
|
|
<span>Detail Faktur</span>
|
|
</v-tooltip>
|
|
</div>
|
|
</v-layout>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
</v-data-table>
|
|
<v-divider></v-divider>
|
|
<div class="pa-2 mt-2 text-xs-center">
|
|
<v-pagination v-model="page_list" :length="list_length" :total-visible="10"></v-pagination>
|
|
</div>
|
|
</v-card>
|
|
|
|
<dialog-form></dialog-form>
|
|
<dialog-item></dialog-item>
|
|
<dialog-view></dialog-view>
|
|
<dialog-attachment></dialog-attachment>
|
|
|
|
<v-snackbar
|
|
v-model="snack.isOpen" :timeout="3000" :multi-line="false"
|
|
:vertical="false" :top="true" :color="snack.color"
|
|
>
|
|
{{ snack.message }}
|
|
<v-btn class="pl-2" flat @click="closeSnackbar()">Tutup</v-btn>
|
|
</v-snackbar>
|
|
|
|
<v-dialog v-model="confirmDialog" persistent max-width="50%">
|
|
<v-card>
|
|
<v-card-title class="headline grey lighten-2" primary-title>
|
|
KONFIRMASI HAPUS FAKTUR
|
|
</v-card-title>
|
|
<v-card-text class="pt-0 pb-0 mt-4">
|
|
<h4>Apakah anda yakin ingin menghapus faktur no: {{ this.fakturdelete.SupplierInvoiceNumber }}</h4>
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-spacer></v-spacer>
|
|
<v-btn color="error" flat @click="confirmDialog = false">
|
|
Batal
|
|
</v-btn>
|
|
<v-btn color="primary" dark @click="deleteFaktur()">
|
|
Hapus
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.text-truncate {
|
|
max-width: 150px;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
module.exports = {
|
|
components: {
|
|
"dialog-form": httpVueLoader("./dialogform.vue"),
|
|
"dialog-item": httpVueLoader("./dialogItem.vue"),
|
|
"dialog-view": httpVueLoader("./viewFaktur.vue"),
|
|
"dialog-attachment": httpVueLoader("./dialog-attachment.vue"),
|
|
},
|
|
mounted() {
|
|
this.$store.dispatch("data/getListSupplier")
|
|
this.$store.dispatch("data/getListFaktur")
|
|
},
|
|
data() {
|
|
return {
|
|
filterDateForm: false,
|
|
filterEndDateForm: false,
|
|
confirmDialog: false,
|
|
fakturdelete: {},
|
|
statusFaktur: ['All', 'Draft', 'Verified', 'Approved', 'Rejected', 'Scheduled', 'Paid', 'Partially Paid', 'Canceled'],
|
|
headers: [
|
|
{
|
|
text: 'NO', align: 'center', sortable: false, value: 'no',
|
|
width: '5%', class: 'blue lighten-3 white--text'
|
|
},
|
|
{
|
|
text: 'NOMOR FAKTUR', align: 'center', sortable: false, value: 'nomor',
|
|
width: '10%', class: 'blue lighten-3 white--text'
|
|
},
|
|
{
|
|
text: 'TANGGAL', align: 'center', sortable: false, value: 'tanggal',
|
|
width: '10%', class: 'blue lighten-3 white--text'
|
|
},
|
|
{
|
|
text: 'JATUH TEMPO', align: 'center', sortable: false, value: 'jatuhtempo',
|
|
width: '10%', class: 'blue lighten-3 white--text'
|
|
},
|
|
{
|
|
text: 'SUPPLIER', align: 'center', sortable: false, value: 'supplier',
|
|
width: '15%', class: 'blue lighten-3 white--text'
|
|
},
|
|
{
|
|
text: 'GUDANG PENERIMA', align: 'center', sortable: false, value: 'warehouse',
|
|
width: '10%', class: 'blue lighten-3 white--text'
|
|
},
|
|
{
|
|
text: 'CATATAN', align: 'center', sortable: false, value: 'supplier',
|
|
width: '15%', class: 'blue lighten-3 white--text'
|
|
},
|
|
{
|
|
text: 'TOTAL', align: 'center', sortable: false, value: 'status',
|
|
width: '10%', class: 'blue lighten-3 white--text'
|
|
},
|
|
{
|
|
text: 'STATUS', align: 'center', sortable: false, value: 'status',
|
|
width: '5%', class: 'blue lighten-3 white--text'
|
|
},
|
|
{
|
|
text: 'AKSI', align: 'center', sortable: false, value: 'aksi',
|
|
width: '15%', class: 'blue lighten-3 white--text'
|
|
},
|
|
]
|
|
}
|
|
},
|
|
computed: {
|
|
dialogCreate: {
|
|
get() {
|
|
return this.$store.state.form.opendialog;
|
|
},
|
|
set(val) {
|
|
this.$store.commit("form/update_opendialog", val);
|
|
}
|
|
},
|
|
snack: {
|
|
get() {
|
|
return this.$store.state.data.snack;
|
|
},
|
|
set(val) {
|
|
this.$store.commit("data/update_snack", val)
|
|
}
|
|
},
|
|
page_list: {
|
|
get() {
|
|
return this.$store.state.data.page_list
|
|
},
|
|
set(val) {
|
|
this.$store.commit("data/update_page_list", val)
|
|
this.$store.dispatch("data/getListFaktur")
|
|
}
|
|
},
|
|
list_length() {
|
|
let total = this.list_faktur.total
|
|
if (total == undefined || total == 0) return 1
|
|
return Math.ceil(total/10)
|
|
},
|
|
list_faktur() {
|
|
return this.$store.state.data.list_faktur
|
|
},
|
|
filter: {
|
|
get() {
|
|
return this.$store.state.data.filter
|
|
},
|
|
set(val) {
|
|
this.$store.commit("data/update_filter", val)
|
|
}
|
|
},
|
|
list_supplier() {
|
|
return this.$store.state.data.list_supplier;
|
|
},
|
|
DateFormated() {
|
|
return this.formatDate(this.filter.date)
|
|
},
|
|
EndDateFormated() {
|
|
return this.formatDate(this.filter.enddate)
|
|
},
|
|
is_create: {
|
|
get() {
|
|
return this.$store.state.form.is_create
|
|
},
|
|
set(val) {
|
|
this.$store.commit("form/update_is_create", val)
|
|
}
|
|
},
|
|
viewFakturDialog: {
|
|
get() {
|
|
return this.$store.state.data.viewfaktur
|
|
},
|
|
set(val) {
|
|
this.$store.commit("data/update_viewfaktur", val)
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
newFaktur() {
|
|
this.is_create = true;
|
|
this.dialogCreate = true;
|
|
this.$store.dispatch("data/getListSupplier");
|
|
this.$store.dispatch("data/getListStaff");
|
|
this.$store.dispatch("form/resetForm");
|
|
},
|
|
viewAttachment(item) {
|
|
let param = {
|
|
roID: item.ReceiveOrderPoID,
|
|
category: item.PurchaseOrderItemCategoryID
|
|
}
|
|
|
|
this.$store.dispatch('data/getListAttachment', param)
|
|
this.$store.commit('data/update_dialog_attachment', true)
|
|
},
|
|
editFaktur(item) {
|
|
this.is_create = false
|
|
this.dialogCreate = true;
|
|
this.$store.dispatch("data/getListSupplier");
|
|
this.$store.dispatch("data/getDetailFaktur", {SInvoiceID: item.SupplierInvoiceID});
|
|
},
|
|
viewFaktur(item) {
|
|
this.viewFakturDialog = true;
|
|
this.$store.dispatch("data/getListSupplier");
|
|
this.$store.dispatch("data/getDetailFaktur", {SInvoiceID: item.SupplierInvoiceID});
|
|
},
|
|
konfirmDelete(item) {
|
|
this.confirmDialog = true
|
|
this.fakturdelete = item
|
|
},
|
|
toRupiah(data) {
|
|
// Input validation
|
|
if (!data) return '0,00'
|
|
|
|
// Ensure we're working with a number
|
|
if (typeof data !== 'number') {
|
|
data = parseFloat(data)
|
|
}
|
|
|
|
// Handle invalid numbers
|
|
if (isNaN(data)) return '0,00'
|
|
|
|
// Convert to string with exactly 2 decimal places without rounding
|
|
// This preserves the exact value for display
|
|
const parts = data.toString().split('.')
|
|
const wholePart = parts[0]
|
|
let decimalPart = parts.length > 1 ? parts[1] : '00'
|
|
|
|
// Ensure we have exactly 2 decimal digits for display
|
|
if (decimalPart.length > 2) {
|
|
decimalPart = decimalPart.substring(0, 2)
|
|
} else if (decimalPart.length < 2) {
|
|
decimalPart = decimalPart.padEnd(2, '0')
|
|
}
|
|
|
|
// Format the whole number part with dots as thousand separators
|
|
const formatted = wholePart.replace(/\B(?=(\d{3})+(?!\d))/g, ".")
|
|
|
|
// Return the formatted number
|
|
return `${formatted},${decimalPart}`
|
|
},
|
|
deleteFaktur() {
|
|
this.$store.dispatch("form/deleteFaktur", {SInvoiceID: this.fakturdelete.SupplierInvoiceID})
|
|
this.fakturdelete = {}
|
|
this.confirmDialog = false
|
|
},
|
|
closeSnackbar() {
|
|
let snacc = { isOpen: false, message: "", color: "error" }
|
|
this.snack = snacc
|
|
},
|
|
formatDate(date) {
|
|
if (!date) return null
|
|
const [year, month, day] = date.split("-")
|
|
return `${day}-${month}-${year}`;
|
|
},
|
|
deFormatedDate(date) {
|
|
if (!date) return null;
|
|
|
|
const [day, month, year] = date.split("-");
|
|
return `${year}-${month.padStart(2, "0")}-${day.padStart(2, "0")}`;
|
|
},
|
|
searchFaktur() {
|
|
this.$store.dispatch("data/getListFaktur")
|
|
},
|
|
fakturApprove(item) {
|
|
if (item.SupplierInvoiceID != '') {
|
|
this.$store.dispatch("form/approveFaktur", {fakturID: item.SupplierInvoiceID});
|
|
}
|
|
},
|
|
fakturReject(item) {
|
|
if (item.SupplierInvoiceID != '') {
|
|
this.$store.dispatch("form/rejectFaktur", {fakturID: item.SupplierInvoiceID});
|
|
}
|
|
},
|
|
fakturVerify(item) {
|
|
// console.log(item)
|
|
// Validation before verify
|
|
if (item.SupplierInvoiceSupplierInvoiceNumber == '' || item.SupplierInvoiceSupplierInvoiceNumber == null) {
|
|
this.snack = { isOpen: true, message: "Nomor invoice supplier tidak boleh kosong", color: "error" }
|
|
return
|
|
}
|
|
|
|
if (item.SupplierInvoiceID != '') {
|
|
this.$store.dispatch("form/verifyFaktur", {fakturID: item.SupplierInvoiceID});
|
|
}
|
|
}
|
|
},
|
|
watch: {
|
|
|
|
}
|
|
}
|
|
</script>
|