![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/ts.corals.io/frontend/components/Clients/ |
<template> <crud-index ref="invoicesTable" :columns="columns" :deleteHref="deleteHref" :editHref="editHref" :bulk-action-options="bulkActionOptions" :resourceURL="invoicesResource" :options="options" :labels="labels" :form="form" form-size="lg"> <template v-slot:code="{object}"> <nuxt-link :to="`/invoices/${object.row.id}`"> {{ object.row.code }} </nuxt-link> </template> <template v-slot:status="{object}"> <span v-html="object.row.status"></span> </template> <template v-slot:total="{object}"> <table class="table totals-table table-borderless"> <tr v-if="parseFloat(object.row.total) !== parseFloat(object.row.subtotal)"> <td>Subtotal</td> <td class="text-right">{{ object.row.subtotal }}</td> </tr> <tr v-if="parseFloat(object.row.tax_total)"> <td>Taxes</td> <td class="text-right">{{ object.row.tax_total }}</td> </tr> <tr v-if="parseFloat(object.row.discount_total)"> <td>Discount</td> <td class="text-right">{{ object.row.discount_total }}</td> </tr> <tr> <td><b>Total</b></td> <td class="text-right"><b>{{ object.row.total }}</b></td> </tr> </table> </template> <template v-slot:notes="{object}"> <fa v-if="object.row.notes" icon="sticky-note" v-b-popover.click.blur="object.row.notes" class="text-primary cursor-pointer"/> <span v-else>{{ object.row.notes }}</span> </template> <template v-slot:default="{form}"> <div> <div class="row sm-gutters"> <div class="col-md-6"> <corals-radio :form="form" field="status" label="Status" :list="form.getFormData('status_options')" required/> </div> <div class="col-md-6"> <corals-select :form="form" label="Project" field="project_id" :options="form.getFormData('client_projects_options')"/> </div> </div> <div class="row sm-gutters"> <div class="col-md-6"> <corals-datepicker :form="form" field="invoice_date" label="Invoice Date"/> </div> <div class="col-md-6"> <corals-datepicker :form="form" field="due_date" label="Due Date"/> </div> </div> <corals-textarea :form="form" field="notes" placeholder="Place invoice notes here..."/> </div> <hr/> <div id="invoice-items"> <div :key="'item_'+index" class="p-1 position-relative" v-for="(item,index) in form.items" :style="(index % 2 !== 0) ? {'background-color': 'rgba(0, 0, 0, 0.05)'} :''"> <div class="row sm-gutters"> <div class="col-md-8"> <div class="row sm-gutters"> <div class="col-md-7"> <corals-input :form="form" size="sm" type="text" :field="`items.${index}.title`" v-model="item.title" label="Title" required/> </div> <div class="col-md-5"> <label class="required-field">Type</label> <b-form-select size="sm" v-model="item.type" :options="form.getFormData('type_options')" text-field="label" value-field="id" required ></b-form-select> </div> </div> <div class="row sm-gutters"> <div class="col-md-4"> <corals-input :form="form" size="sm" type="number" :field="`items.${index}.quantity`" v-model="item.quantity" label="Quantity" step="0.01" required/> </div> <div class="col-md-4"> <corals-input :form="form" size="sm" type="number" :field="`items.${index}.rate`" v-model="item.rate" label="Rate" step="0.01" required/> </div> <div class="col-md-4"> <label class="d-block">Amount</label> <div class=""> <b-form-input size="sm" :value="Math.round(item.quantity * item.rate * 100) / 100" readonly></b-form-input> </div> </div> </div> </div> <div class="col-md-4"> <corals-textarea :form="form" size="sm" :field="`items.${index}.notes`" v-model="item.notes" label="Notes" rows="4" placeholder="Item Notes..."/> </div> </div> <a href="#" @click.prevent="removeItem(index)" class="text-danger clear-item-btn"> <fa icon="times"/> </a> </div> <button @click.prevent="addItem" class="btn btn-sm btn-success mt-1"> <fa icon="plus"/> Add Item </button> </div> </template> </crud-index> </template> <script> import CrudIndex from "@/components/layout/CRUDIndex"; export default { name: "ClientsInvoicesIndex", components: {CrudIndex}, provide() { return { handleBulkAction: this.handleBulkAction, } }, props: { client: { required: true } }, data() { return { form: this.$form({ notes: '', status: 'pending', project_id: '', invoice_date: new Date(), due_date: new Date(), items: [ this.getItemObject() ], }, { fetchFormDataURL: `timesheet/invoices/get-form-data?client_id=${this.client.id}`, model: 'invoice', loadFormDataCallBack: () => { this.options.listColumns.status = this.getOptions(this.form.formData.status_options); } }), labels: { title: 'Invoices', singularTitle: 'Invoice', }, options: { hideCreate: this.$notAdmin(), listColumns: { status: [], }, customColumns: ['code', 'status', 'total', 'notes'], filterable: ['code', 'status', 'notes', 'invoice_date'], headings: { 'total': 'Summary', 'total_hours': 'Hours', 'project_name': 'Project' } }, } }, methods: { getOptions(list) { let allOption = {id: '', text: 'All'}; let options = []; options.push(allOption); list.map(row => { let label = row.label.split(","); options.push({id: row.id ?? row.value, text: label[0]}); }); return options; }, handleBulkAction(action, selectedIds) { this.$bvModal.msgBoxConfirm('Are you sure?', { size: 'md', buttonSize: 'sm', okVariant: 'danger', footerClass: 'p-2', hideHeaderClose: false, centered: true }) .then(value => { if (value === true) { this.$axios.post('timesheet/invoices/bulk-action', { 'selection': selectedIds, 'action': action }).then(response => { let level = response.data.data.level; let message = response.data.data.message; if (level === 'success') { this.$toast.success(message); } else { this.$toast.error(message); } this.$eventBus.$emit('setSelectedIds', []); this.$refs.invoicesTable.refresh(); }).catch(err => { this.$toast.error(err.response.data.message); }); } }) .catch(err => { }) }, getItemObject() { return { 'title': '', 'type': 'item', 'rate': '', 'quantity': 1, 'notes': '' } }, addItem() { this.form.items.push(this.getItemObject()); }, removeItem(itemIndex) { let result = []; this.form.items.forEach((arr, index) => { if (index != itemIndex) { result.push(arr); } }); this.form.items = result; } }, computed: { deleteHref() { return `timesheet/invoices`; }, editHref() { return `timesheet/invoices` }, columns() { let columns = []; if (this.$isAdmin() && this.bulkActionOptions.length) { columns.push('checkbox'); } columns.push('code', 'project_name', 'total', 'total_hours', 'invoice_date', 'notes', 'status', 'actions'); if (this.$notAdmin()) { columns.pop(); } return columns; }, invoicesResource() { return `/timesheet/invoices/by-client/${this.client.id}`; }, bulkActionOptions() { if (this.$notAdmin()) { return []; } return ['delete', 'pending', 'paid', 'void']; }, }, } </script> <style scoped> .totals-table { margin-bottom: 0; } .totals-table tr, .totals-table td { background-color: unset !important; padding: 2px; } .clear-item-btn { position: absolute; top: 0; right: 5px; } #invoice-items .form-group { margin-bottom: 0.5rem; } #invoice-items >>> label { margin-bottom: 0.25rem; } </style>