Edit invoice

This commit is contained in:
Peter Papp
2021-05-05 17:07:36 +02:00
parent bdfd92872e
commit 599b238ab4
22 changed files with 976 additions and 162 deletions
@@ -14,7 +14,7 @@
<tr>
<td>
<span class="cell-item">
{{ row.data.attributes.invoiceNumber }}
{{ row.data.attributes.invoice_number }}
</span>
</td>
<td>
@@ -32,7 +32,7 @@
<a @click="downloadItem(row)">
<DownloadCloudIcon size="15" class="icon" />
</a>
<router-link :to="{name: 'ClientDetail'}">
<router-link :to="{name: 'EditInvoice', params: {id: row.data.id}}">
<edit2-icon size="15" class="icon" />
</router-link>
</div>
@@ -277,7 +277,7 @@
</div>
</div>
<div :class="{'is-offset': isDiscount && invoice.discount_rate > 0}">
<div v-if="isVatPayer" :class="{'is-offset': isDiscount && invoice.discount_rate > 0}">
<div v-for="(tax, i) in taxBased" :key="i" class="row small">
<div class="cell">
<span>{{ $t('in_editor.summary.vat_base') }} {{ tax.rate }}%</span>
@@ -288,7 +288,7 @@
</div>
</div>
<div :class="{'is-offset': taxSummary.length > 1}">
<div v-if="isVatPayer" :class="{'is-offset': taxSummary.length > 1}">
<div v-for="(tax, i) in taxSummary" :key="i" class="row small">
<div class="cell">
<span>{{ $t('in_editor.summary.vat') }} {{ tax.rate }}%</span>
@@ -474,7 +474,7 @@
let total_without_tax = (item.price * item.amount)
// Count tax
if (item.tax_rate) {
if (this.isVatPayer && item.tax_rate) {
total_without_tax += total_without_tax * (item.tax_rate / 100)
}
@@ -535,8 +535,8 @@
price: undefined,
}
],
discount_type: undefined,
discount_rate: undefined,
discount_type: 'percent',
discount_rate: 10,
client: '',
client_avatar: '',
client_name: '',
@@ -552,16 +552,6 @@
send_invoice: true,
store_client: true,
},
invoiceTypeList: [
{
label: 'Regular Invoice',
value: 'regular-invoice',
},
{
label: 'Advance Invoice',
value: 'advance-invoice',
},
],
discountTypeList: [
{
label: this.$t('in_editor.discount_type_percent'),
@@ -583,15 +573,6 @@
this.invoice.client_city = response.data.city
this.invoice.client_postal_code = response.data.addr_zip
this.fullDetails = response.data.name + ' ' + response.data.addr_full
//this.$refs.createUser.reset()
})
.catch(error => {
/*if (error.response.status == 404) {
this.$refs.createUser.setErrors({
'ICO': 'Nič sa nenašlo :('
});
}*/
})
}, 300),
formatCurrency(value) {
@@ -690,7 +671,6 @@
})
this.$nextTick(() => this.$refs.duplicatorItemTitle.slice(-1).pop().focus())
},
removeRow(item) {
if (this.invoice.items.length > 1)
@@ -0,0 +1,700 @@
<template>
<div id="single-page">
<MobileHeader :title="pageTitle" />
<PageHeader :title="pageTitle" />
<div id="page-content">
<div class="content-page" v-if="! isLoadingPage">
<ValidationObserver @submit.prevent="updateInvoice" ref="updateInvoice" v-slot="{ invalid }" tag="form" class="form block-form">
<PageTab>
<!--Properties-->
<PageTabGroup>
<FormLabel icon="tool">{{ $t('in_editor.properties') }}</FormLabel>
<div class="block-wrapper">
<label>{{ $t('in_number') }}:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="invoice_number" rules="required" v-slot="{ errors }">
<input v-model.number="invoice.invoice_number" :placeholder="$t('in_editor.plac.invoice_number')" type="number" :class="{'is-error': errors[0]}" class="focus-border-theme" />
<small v-if="latestInvoiceNumber" class="input-help">
{{ $t('in_number_desc', {number: latestInvoiceNumber}) }}
</small>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>{{ $t('in_variable') }}:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="variable_number" rules="required" v-slot="{ errors }">
<input v-model.number="invoice.variable_number" :placeholder="$t('in_editor.plac.variable_number')" type="number" :class="{'is-error': errors[0]}" class="focus-border-theme" />
<small v-if="latestInvoiceNumber" class="input-help">
{{ $t('in_variable_desc') }}
</small>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>{{ $t('in_delivery_at') }}:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="delivery_at" rules="required" v-slot="{ errors }">
<input v-model="invoice.delivery_at" type="date" :class="{'is-error': errors[0]}" class="focus-border-theme" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</PageTabGroup>
<!--Client-->
<PageTabGroup>
<FormLabel icon="user">{{ $t('in_editor.client') }}</FormLabel>
<div class="block-wrapper">
<label>{{ $t('in_editor.client') }}:</label>
<div class="input-wrapper">
<input v-model.number="invoice.client['name']" type="text" disabled />
</div>
</div>
</PageTabGroup>
<!--Items-->
<PageTabGroup>
<FormLabel icon="edit">{{ $t('in_editor.items') }}</FormLabel>
<div class="duplicator">
<div class="plan-item duplicator-item" v-for="(item, index) in invoice.items" :key="index++">
<x-icon @click="removeRow(item)" v-if="index !== 1" size="22" class="delete-item hover-text-theme" />
<div class="block-wrapper">
<label>{{ $t('in_editor.description') }}:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="description" rules="required" v-slot="{ errors }">
<input v-model="item.description" ref="duplicatorItemTitle" :placeholder="$t('in_editor.plac.item_desc')" type="text" :class="{'is-error': errors[0]}" class="focus-border-theme" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="wrapper-inline">
<div class="block-wrapper">
<label>{{ $t('in_editor.amount') }}:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="amount" rules="required" v-slot="{ errors }">
<input v-model.number="item.amount" :placeholder="$t('in_editor.plac.item_amount')" type="number" :class="{'is-error': errors[0]}" class="focus-border-theme" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div v-if="isVatPayer" class="block-wrapper">
<label>{{ $t('in_editor.tax_rate') }}:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="tax_rate" rules="required" v-slot="{ errors }">
<input v-model.number="item.tax_rate" :placeholder="$t('in_editor.plac.item_tax_rate')" type="number" step="1" min="1" max="100" :class="{'is-error': errors[0]}" class="focus-border-theme" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>{{ $t('in_editor.price') }}:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="price" rules="required" v-slot="{ errors }">
<input v-model.number="item.price" :placeholder="$t('in_editor.plac.item_price')" type="text" pattern="[0-9]{1,4}(\.[0-9]{2})?" step="0.01" :class="{'is-error': errors[0]}" class="focus-border-theme" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
</div>
<ButtonBase @click.native="addRow" class="duplicator-add-button" button-style="theme">
{{ $t('in_editor.add_item') }}
</ButtonBase>
</div>
</PageTabGroup>
<!--Discount-->
<PageTabGroup>
<FormLabel icon="credit-card">
{{ $t('in_editor.discount') }}
</FormLabel>
<div class="block-wrapper">
<div class="input-wrapper">
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label">{{ $t('in_editor.apply_discount') }}:</label>
<small class="input-help">{{ $t('in_editor.discount_help') }}</small>
</div>
<SwitchInput v-model="isDiscount" class="switch" :state="isDiscount" />
</div>
</div>
</div>
<div v-if="isDiscount" class="block-wrapper">
<label>{{ $t('in_editor.discount_type') }}:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="discount_type" rules="required" v-slot="{ errors }">
<SelectInput v-model="invoice.discount_type" :default="invoice.discount_type" :options="discountTypeList" :placeholder="$t('in_editor.plac.discount_type')" :isError="errors[0]" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div v-if="isDiscount" class="block-wrapper">
<label>{{ $t('in_editor.discount_rate') }}:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="discount_rate" rules="required" v-slot="{ errors }">
<input v-model.number="invoice.discount_rate" :placeholder="$t('in_editor.plac.discount_rate')" max="100" min="0" type="number" :class="{'is-error': errors[0]}" class="focus-border-theme" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</PageTabGroup>
<!--Others-->
<PageTabGroup>
<FormLabel icon="settings">{{ $t('in_editor.others') }}</FormLabel>
<div v-if="invoice.client_email" class="block-wrapper">
<div class="input-wrapper">
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label">{{ $t('in_editor.store_client') }}:</label>
<small class="input-help">{{ $t('in_editor.store_client_notes') }}</small>
</div>
<SwitchInput v-model="invoice.send_invoice" class="switch" :state="invoice.send_invoice" />
</div>
</div>
</div>
<div class="block-wrapper">
<div class="input-wrapper">
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label">{{ $t('in_editor.send') }}:</label>
<small class="input-help">{{ $t('in_editor.send_notes') }}</small>
</div>
<SwitchInput v-model="invoice.send_invoice" class="switch" :state="invoice.send_invoice" />
</div>
</div>
</div>
</PageTabGroup>
</PageTab>
</ValidationObserver>
<div class="summary">
<FormLabel icon="credit-card">
{{ $t('in_editor.summary') }}
</FormLabel>
<div class="summary-list" :class="{'is-error': isError}">
<div v-if="isDiscount && invoice.discount_rate > 0" class="row small">
<div class="cell">
<span>{{ $t('in_editor.discount') }}</span>
</div>
<div class="cell">
<span>-{{ invoice.discount_type === 'percent' ? formatNumber(invoice.discount_rate) + '%' : formatCurrency(invoice.discount_rate) }}</span>
</div>
</div>
<div v-if="isVatPayer" :class="{'is-offset': isDiscount && invoice.discount_rate > 0}">
<div v-for="(tax, i) in taxBased" :key="i" class="row small">
<div class="cell">
<span>{{ $t('in_editor.summary.vat_base') }} {{ tax.rate }}%</span>
</div>
<div class="cell">
<span>{{ formatCurrency(tax.total) }}</span>
</div>
</div>
</div>
<div v-if="isVatPayer" :class="{'is-offset': taxSummary.length > 1}">
<div v-for="(tax, i) in taxSummary" :key="i" class="row small">
<div class="cell">
<span>{{ $t('in_editor.summary.vat') }} {{ tax.rate }}%</span>
</div>
<div class="cell">
<span>{{ formatCurrency(tax.total) }}</span>
</div>
</div>
</div>
<div class="row" :class="{'row-summary': total > 0}">
<div class="cell">
<b>{{ $t('in_editor.summary.total') }}</b>
</div>
<div class="cell">
<b>{{ formatCurrency(total) }}</b>
</div>
</div>
<ButtonBase :disabled="isLoading" @click.native="deleteInvoice" button-style="danger" class="next-submit">
Delete Invoice
</ButtonBase>
<ButtonBase :disabled="isLoading" :loading="isLoading" @click.native="updateInvoice" button-style="theme-solid" class="next-submit" style="margin-top: 10px">
{{ $t('in_editor.submit') }}
</ButtonBase>
<p class="error-message" v-if="isError">
{{ errorMessage }}
</p>
</div>
</div>
</div>
<div id="loader" v-if="isLoadingPage">
<Spinner />
</div>
</div>
</div>
</template>
<script>
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
import PageTabGroup from '@/components/Others/Layout/PageTabGroup'
import SwitchInput from '@/components/Others/Forms/SwitchInput'
import SelectInput from '@/components/Others/Forms/SelectInput'
import ImageInput from '@/components/Others/Forms/ImageInput'
import FormLabel from '@/components/Others/Forms/FormLabel'
import MobileHeader from '@/components/Mobile/MobileHeader'
import ButtonBase from '@/components/FilesView/ButtonBase'
import PageTab from '@/components/Others/Layout/PageTab'
import PageHeader from '@/components/Others/PageHeader'
import InfoBox from '@/components/Others/Forms/InfoBox'
import Spinner from '@/components/FilesView/Spinner'
import {required} from 'vee-validate/dist/rules'
import {XIcon} from 'vue-feather-icons'
import {mapGetters} from 'vuex'
import {events} from "@/bus"
import axios from "axios"
import {debounce} from "lodash"
export default {
name: 'CreateInvoice',
components: {
ValidationProvider,
ValidationObserver,
PageTabGroup,
MobileHeader,
SelectInput,
SwitchInput,
ImageInput,
PageHeader,
ButtonBase,
FormLabel,
required,
Spinner,
InfoBox,
PageTab,
XIcon,
},
computed: {
...mapGetters([
'countries',
'config',
]),
pageTitle() {
return {
'regular-invoice': this.$t('in_editor.page.edit_regular_invoice'),
'advance-invoice': this.$t('in_editor.page.edit_advance_invoice'),
}[this.invoice.invoice_type]
},
taxBased() {
let bag = [];
this.invoice.items.forEach(item => {
if (item.price && item.amount && item.tax_rate) {
if (!bag.find(bagItem => bagItem.rate === item.tax_rate)) {
bag.push({
rate: item.tax_rate,
total: (item.price * item.amount),
})
} else {
bag.find(bagItem => {
// Count total tax rate for percentage
if (bagItem.rate === item.tax_rate) {
bagItem.total += (item.price * item.amount)
}
})
}
}
})
// Count discount
if (this.isDiscount) {
bag.forEach(bagItem => {
if (this.invoice.discount_type === 'percent') {
bagItem.total -= bagItem.total * (this.invoice.discount_rate / 100)
}
if (this.invoice.discount_type === 'value') {
let percentage_of_discount = this.invoice.discount_rate / (this.total + this.invoice.discount_rate)
bagItem.total -= bagItem.total * percentage_of_discount
}
})
}
return bag
},
taxSummary() {
let bag = [];
this.invoice.items.forEach(item => {
if (item.price && item.amount && item.tax_rate) {
if (!bag.find(bagItem => bagItem.rate === item.tax_rate)) {
bag.push({
rate: item.tax_rate,
total: (item.price * item.amount) * (item.tax_rate / 100),
})
} else {
bag.map(bagItem => {
// Count total tax rate for percentage
if (bagItem.rate === item.tax_rate) {
bagItem.total += (item.price * item.amount) * (item.tax_rate / 100)
}
})
}
}
})
// Count discount
if (this.isDiscount) {
bag.forEach(bagItem => {
if (this.invoice.discount_type === 'percent') {
bagItem.total -= bagItem.total * (this.invoice.discount_rate / 100)
}
if (this.invoice.discount_type === 'value') {
let percentage_of_discount = this.invoice.discount_rate / (this.total + this.invoice.discount_rate)
bagItem.total -= bagItem.total * percentage_of_discount
}
})
}
return bag
},
total() {
let total = 0;
this.invoice.items.forEach(item => {
if (item.price && item.amount) {
let total_without_tax = (item.price * item.amount)
// Count tax
if (this.isVatPayer && item.tax_rate) {
total_without_tax += total_without_tax * (item.tax_rate / 100)
}
total += total_without_tax
}
})
// Count discount
if (this.isDiscount) {
if (this.invoice.discount_type === 'percent') {
total -= total * (this.invoice.discount_rate / 100)
}
if (this.invoice.discount_type === 'value') {
total -= this.invoice.discount_rate
}
}
return total
}
},
watch: {
isDiscount(val) {
if (!val) {
this.invoice.discount_rate = null
this.invoice.discount_type = null
}
},
'invoice.invoice_number': function (val) {
this.invoice.variable_number = val
},
},
data() {
return {
fullDetails: undefined,
isLoadingPage: true,
isLoading: false,
isError: false,
isDiscount: false,
isVatPayer: false,
clients: [],
latestInvoiceNumber: undefined,
invoice: {
invoice_type: '',
invoice_number: '',
variable_number: '',
delivery_at: '',
items: [
{
id: Math.floor(Math.random() * 10000000),
description: '',
amount: 1,
tax_rate: 21,
price: undefined,
}
],
discount_type: undefined,
discount_rate: undefined,
client: '',
send_invoice: false,
},
discountTypeList: [
{
label: this.$t('in_editor.discount_type_percent'),
value: 'percent',
},
{
label: this.$t('in_editor.discount_type_amount'),
value: 'value',
},
],
}
},
methods: {
formatCurrency(value) {
return new Intl
.NumberFormat('cs-CS', {
style: 'currency',
currency: 'CZK'
})
.format(value)
},
formatNumber(value) {
return (Math.round(value * 100) / 100)
.toFixed(2);
},
deleteInvoice() {
events.$emit('confirm:open', {
title: `Are you sure you want to delete this invoice?`,
message: 'Your invoice will be permanently deleted.',
buttonColor: 'danger-solid',
action: {
id: this.$route.params.id,
operation: 'delete-invoice'
}
})
},
async updateInvoice() {
const isValid = await this.$refs.updateInvoice.validate();
if (!isValid) {
this.isError = true
this.errorMessage = this.$t('in_editor.error')
return
}
// Start loading
this.isLoading = true
// Create form
let formData = new FormData()
// Append data to form
Object.keys(this.invoice).forEach(key => {
if (key === 'items') {
formData.append(key, JSON.stringify(this.invoice[key]))
} else {
if (this.invoice[key])
formData.append(key, this.invoice[key])
}
})
// Send request to get user token
axios
.post(`/api/oasis/invoices/${this.$route.params.id}`, formData)
.then(() => {
events.$emit('toaster', {
type: 'success',
message: 'The invoice was successfully edited.',
})
})
.catch(error => {
this.isError = true
if (error.response.status === 422) {
Object.keys(error.response.data.errors).forEach(key => {
let obj = {};
obj[key] = error.response.data.errors[key]
this.$refs.updateInvoice.setErrors(obj);
})
} else {
events.$emit('alert:open', {
title: this.$t('popup_error.title'),
message: this.$t('popup_error.message'),
})
}
})
.finally(() => {
this.isLoading = false
})
},
addRow() {
let lastTaxRate = this.invoice.items.slice(-1).pop()
this.invoice.items.push({
id: Math.floor(Math.random() * 10000000),
description: '',
amount: 1,
tax_rate: lastTaxRate?.tax_rate || 21,
price: 1,
})
this.$nextTick(() => this.$refs.duplicatorItemTitle.slice(-1).pop().focus())
},
removeRow(item) {
if (this.invoice.items.length > 1)
this.invoice.items = this.invoice.items.filter(obj => obj.id !== item.id)
}
},
mounted() {
axios.get('/api/oasis/invoices/editor')
.then(response => {
this.isVatPayer = response.data.isVatPayer
})
axios.get(`/api/oasis/invoices/${this.$route.params.id}`)
.then(response => {
this.invoice.invoice_number = response.data.data.attributes.invoice_number
this.invoice.variable_number = response.data.data.attributes.variable_number
this.invoice.invoice_type = response.data.data.attributes.invoice_type
this.invoice.delivery_at = response.data.data.attributes.delivery_at
this.invoice.items = response.data.data.attributes.items
this.invoice.discount_type = response.data.data.attributes.discount_type
this.invoice.discount_rate = response.data.data.attributes.discount_rate
this.invoice.client = response.data.data.attributes.client
if (this.invoice.discount_type && this.invoice.discount_rate) {
this.isDiscount = true
}
})
.finally(() => {
this.isLoadingPage = false
})
}
}
</script>
<style lang="scss" scoped>
@import '@assets/vuefilemanager/_variables';
@import '@assets/vuefilemanager/_mixins';
@import '@assets/vuefilemanager/_forms';
#page-content {
max-width: 1100px;
}
.content-page {
display: grid;
grid-template-columns: 2fr 1fr;
margin-bottom: 30px;
gap: 50px;
.form {
max-width: 100%;
}
}
.summary-list {
box-shadow: 0 7px 20px 5px hsla(220, 36%, 16%, 0.06);
border-radius: 8px;
min-width: 300px;
position: sticky;
padding: 25px;
top: 85px;
&.is-error {
border: 2px solid $danger;
box-shadow: 0 7px 20px 5px rgba($danger, 0.06);
}
.error-message {
font-weight: 600;
}
.next-submit {
width: 100%;
margin-top: 20px;
}
.disclaimer {
@include font-size(12);
line-height: 1.6;
display: block;
margin-top: 12px;
}
.is-offset {
border-top: 1px solid $light_mode_border;
display: block;
padding-top: 10px;
}
.row {
display: flex;
justify-content: space-between;
padding: 15px 0;
&.small {
padding: 0 0 10px;
}
&:first-child {
padding-top: 0;
}
&.row-summary {
border-top: 1px solid $light_mode_border;
padding-bottom: 0;
b {
font-weight: 800;
}
}
}
.cell {
b {
display: block;
@include font-size(18);
}
small {
color: $text-muted;
@include font-size(12);
}
span {
@include font-size(14);
font-weight: 600;
}
}
}
.duplicator {
.wrapper-inline {
margin-bottom: 0 !important;
}
}
@media only screen and (max-width: 970px) {
.content-page {
grid-template-columns: 1fr;
margin-bottom: 30px;
gap: 0;
}
}
</style>
@@ -4,7 +4,7 @@
<!--Invoice-->
<div v-show="isInvoice" class="menu-options" id="menu-list">
<OptionGroup class="menu-option-group">
<Option @click.native="" title="Edit Invoice" icon="rename" />
<Option @click.native="editItem" title="Edit Invoice" icon="rename" />
<Option @click.native="" title="Send Invoice" icon="send" />
<Option @click.native="goToCompany" title="Go to Company" icon="user" />
<Option @click.native="deleteItem" :title="$t('context_menu.delete')" icon="trash" />
@@ -95,9 +95,12 @@ export default {
// Show panel if is not open
this.$store.dispatch('fileInfoToggle', true)
},
editItem() {
this.$router.push({name: 'EditInvoice', params: {id: this.item.id}})
},
deleteItem() {
events.$emit('confirm:open', {
title: `Are you sure you want to delete invoice number ${this.item.invoiceNumber}?`,
title: `Are you sure you want to delete invoice number ${this.item.invoice_number}?`,
message: 'Your invoice will be permanently deleted.',
buttonColor: 'danger-solid',
action: {
@@ -36,7 +36,7 @@
<!--Invoice Controls-->
<ToolbarGroup v-if="! $isMobile()">
<ToolbarButton @click.native="shareInvoice" :class="{'is-inactive': canActiveInView }" source="send" :action="$t('actions.share')" />
<ToolbarButton @click.native="shareInvoice" :class="{'is-inactive': canActiveInView }" source="rename" :action="$t('actions.share')" />
<ToolbarButton @click.native="editInvoice" :class="{'is-inactive': canActiveInView }" source="rename" :action="$t('actions.share')" />
<ToolbarButton @click.native="deleteInvoice" :class="{'is-inactive': canActiveInView }" source="trash" :action="$t('actions.delete')" />
</ToolbarGroup>
@@ -131,7 +131,7 @@
if (this.clipboard.length > 0) {
events.$emit('confirm:open', {
title: `Are you sure you want to delete invoice number ${this.clipboard[0].invoiceNumber}?`,
title: `Are you sure you want to delete invoice number ${this.clipboard[0].invoice_number}?`,
message: 'Your invoice will be permanently deleted.',
buttonColor: 'danger-solid',
action: {
@@ -144,6 +144,9 @@
shareInvoice() {
alert('Send Invoice')
},
editInvoice() {
this.$router.push({name: 'EditInvoice', params: {id: this.clipboard[0].id}})
},
},
}
</script>
@@ -60,8 +60,8 @@
<div v-if="isSingleFile && !isEmpty" class="info-headline">
<TitlePreview
icon="file-text"
:title="singleFile.clientName"
:subtitle="'Invoice - ' + singleFile.invoiceNumber"
:title="singleFile.client_name"
:subtitle="'Invoice - ' + singleFile.invoice_number"
/>
</div>
@@ -70,7 +70,7 @@
<ListInfoItem
title="Invoice Number"
:content="singleFile.invoiceNumber"
:content="singleFile.invoice_number"
/>
<ListInfoItem
@@ -80,7 +80,7 @@
<ListInfoItem
title="Client"
:content="singleFile.clientName"
:content="singleFile.client_name"
/>
<!--Created At-->
@@ -15,12 +15,12 @@
<div class="item-name">
<b :ref="item.id" class="name">
{{ item.clientName }} - {{ item.total }}
{{ item.client_name }} - {{ item.total }}
</b>
<div class="item-info">
<span class="item-size">
{{ item.created_at }}, n. {{ item.invoiceNumber }}
{{ item.created_at }}, n. {{ item.invoice_number }}
</span>
</div>
</div>
@@ -5,7 +5,7 @@
class="headline"
icon="file-text"
:title="clipboard[0].name"
:subtitle="'Invoice - ' + clipboard[0].invoiceNumber"
:subtitle="'Invoice - ' + clipboard[0].invoice_number"
/>
<!--Trash location-->
@@ -64,7 +64,7 @@ export default {
},
deleteInvoice() {
events.$emit('confirm:open', {
title: `Are you sure you want to delete invoice number ${this.clipboard[0].invoiceNumber}?`,
title: `Are you sure you want to delete invoice number ${this.clipboard[0].invoice_number}?`,
message: 'Your invoice will be permanently deleted.',
buttonColor: 'danger-solid',
action: {
+9
View File
@@ -121,6 +121,15 @@ const routesOasis = [
requiresAuth: true,
},
},
{
name: 'EditInvoice',
path: '/invoice/edit-invoice/:id',
component: () =>
import(/* webpackChunkName: "chunks/oasis/invoices/edit-invoice" */ './Oasis/Invoices/Invoices/EditInvoice'),
meta: {
requiresAuth: true,
},
},
{
name: 'Client',
path: '/invoice/client/:id',
+1 -1
View File
@@ -8,7 +8,7 @@
<template slot-scope="{ row }">
<tr>
<td>
<a :href="'/invoice/' + row.data.attributes.customer + '/' + row.data.id" target="_blank" class="cell-item">
<a :href="'/stripe-invoice/' + row.data.attributes.customer + '/' + row.data.id" target="_blank" class="cell-item">
{{ row.data.attributes.order }}
</a>
</td>