mirror of
https://github.com/crater-invoice/crater.git
synced 2025-10-28 12:11:08 -04:00
Compare commits
8 Commits
fix-logout
...
tax-calcul
| Author | SHA1 | Date | |
|---|---|---|---|
| 9608ab6207 | |||
| c14eb1b414 | |||
| 6d0edb4b5a | |||
| 0dc8941975 | |||
| f11437ce63 | |||
| dbd75bbe68 | |||
| 4fc67c74e4 | |||
| 27660c6bce |
@ -45,15 +45,21 @@ class EstimatesRequest extends FormRequest
|
|||||||
'nullable'
|
'nullable'
|
||||||
],
|
],
|
||||||
'discount' => [
|
'discount' => [
|
||||||
|
'numeric',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'discount_val' => [
|
'discount_val' => [
|
||||||
|
'integer',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'sub_total' => [
|
'sub_total' => [
|
||||||
|
'integer',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'total' => [
|
'total' => [
|
||||||
|
'integer',
|
||||||
|
'numeric',
|
||||||
|
'max:99999999',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'tax' => [
|
'tax' => [
|
||||||
@ -77,9 +83,11 @@ class EstimatesRequest extends FormRequest
|
|||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'items.*.quantity' => [
|
'items.*.quantity' => [
|
||||||
|
'integer',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'items.*.price' => [
|
'items.*.price' => [
|
||||||
|
'integer',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@ -45,15 +45,21 @@ class InvoicesRequest extends FormRequest
|
|||||||
'nullable'
|
'nullable'
|
||||||
],
|
],
|
||||||
'discount' => [
|
'discount' => [
|
||||||
|
'numeric',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'discount_val' => [
|
'discount_val' => [
|
||||||
|
'integer',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'sub_total' => [
|
'sub_total' => [
|
||||||
|
'integer',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'total' => [
|
'total' => [
|
||||||
|
'integer',
|
||||||
|
'numeric',
|
||||||
|
'max:99999999',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'tax' => [
|
'tax' => [
|
||||||
@ -77,9 +83,11 @@ class InvoicesRequest extends FormRequest
|
|||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'items.*.quantity' => [
|
'items.*.quantity' => [
|
||||||
|
'integer',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'items.*.price' => [
|
'items.*.price' => [
|
||||||
|
'integer',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@ -43,15 +43,21 @@ class RecurringInvoiceRequest extends FormRequest
|
|||||||
'nullable'
|
'nullable'
|
||||||
],
|
],
|
||||||
'discount' => [
|
'discount' => [
|
||||||
|
'numeric',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'discount_val' => [
|
'discount_val' => [
|
||||||
|
'integer',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'sub_total' => [
|
'sub_total' => [
|
||||||
|
'integer',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'total' => [
|
'total' => [
|
||||||
|
'integer',
|
||||||
|
'numeric',
|
||||||
|
'max:99999999',
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'tax' => [
|
'tax' => [
|
||||||
|
|||||||
@ -271,23 +271,19 @@ const price = computed({
|
|||||||
} else {
|
} else {
|
||||||
updateItemAttribute('price', newValue)
|
updateItemAttribute('price', newValue)
|
||||||
}
|
}
|
||||||
|
setDiscount()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const subtotal = computed(() => props.itemData.price * props.itemData.quantity)
|
const subtotal = computed(() => Math.round(props.itemData.price * props.itemData.quantity))
|
||||||
|
|
||||||
const discount = computed({
|
const discount = computed({
|
||||||
get: () => {
|
get: () => {
|
||||||
return props.itemData.discount
|
return props.itemData.discount
|
||||||
},
|
},
|
||||||
set: (newValue) => {
|
set: (newValue) => {
|
||||||
if (props.itemData.discount_type === 'percentage') {
|
|
||||||
updateItemAttribute('discount_val', (subtotal.value * newValue) / 100)
|
|
||||||
} else {
|
|
||||||
updateItemAttribute('discount_val', Math.round(newValue * 100))
|
|
||||||
}
|
|
||||||
|
|
||||||
updateItemAttribute('discount', newValue)
|
updateItemAttribute('discount', newValue)
|
||||||
|
setDiscount()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -313,7 +309,7 @@ const showRemoveButton = computed(() => {
|
|||||||
const totalSimpleTax = computed(() => {
|
const totalSimpleTax = computed(() => {
|
||||||
return Math.round(
|
return Math.round(
|
||||||
sumBy(props.itemData.taxes, function (tax) {
|
sumBy(props.itemData.taxes, function (tax) {
|
||||||
if (!tax.compound_tax) {
|
if (tax.amount) {
|
||||||
return tax.amount
|
return tax.amount
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
@ -321,18 +317,7 @@ const totalSimpleTax = computed(() => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const totalCompoundTax = computed(() => {
|
const totalTax = computed(() => totalSimpleTax.value)
|
||||||
return Math.round(
|
|
||||||
sumBy(props.itemData.taxes, function (tax) {
|
|
||||||
if (tax.compound_tax) {
|
|
||||||
return tax.amount
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const totalTax = computed(() => totalSimpleTax.value + totalCompoundTax.value)
|
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
name: {
|
name: {
|
||||||
@ -416,6 +401,16 @@ function updateTax(data) {
|
|||||||
syncItemToStore()
|
syncItemToStore()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setDiscount() {
|
||||||
|
const newValue = props.store[props.storeProp].items[props.index].discount
|
||||||
|
|
||||||
|
if (props.itemData.discount_type === 'percentage'){
|
||||||
|
updateItemAttribute('discount_val', Math.round((subtotal.value * newValue) / 100))
|
||||||
|
}else{
|
||||||
|
updateItemAttribute('discount_val', Math.round(newValue * 100))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function searchVal(val) {
|
function searchVal(val) {
|
||||||
updateItemAttribute('name', val)
|
updateItemAttribute('name', val)
|
||||||
}
|
}
|
||||||
@ -485,10 +480,12 @@ function syncItemToStore() {
|
|||||||
total: total.value,
|
total: total.value,
|
||||||
sub_total: subtotal.value,
|
sub_total: subtotal.value,
|
||||||
totalSimpleTax: totalSimpleTax.value,
|
totalSimpleTax: totalSimpleTax.value,
|
||||||
totalCompoundTax: totalCompoundTax.value,
|
|
||||||
totalTax: totalTax.value,
|
totalTax: totalTax.value,
|
||||||
tax: totalTax.value,
|
tax: totalTax.value,
|
||||||
taxes: [...itemTaxes],
|
taxes: [...itemTaxes],
|
||||||
|
tax_type_ids: itemTaxes.flatMap(_t =>
|
||||||
|
_t.tax_type_id ? _t.tax_type_id : [],
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
props.store.updateItem(data)
|
props.store.updateItem(data)
|
||||||
|
|||||||
@ -146,14 +146,14 @@ const filteredTypes = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const taxAmount = computed(() => {
|
const taxAmount = computed(() => {
|
||||||
if (localTax.compound_tax && props.discountedTotal) {
|
|
||||||
return ((props.discountedTotal + props.totalTax) * localTax.percent) / 100
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.discountedTotal && localTax.percent) {
|
if (props.discountedTotal && localTax.percent) {
|
||||||
|
const taxPerItemEnabled = props.store[props.storeProp].tax_per_item === 'YES'
|
||||||
|
const discountPerItemEnabled = props.store[props.storeProp].discount_per_item === 'YES'
|
||||||
|
if (taxPerItemEnabled && !discountPerItemEnabled){
|
||||||
|
return getTaxAmount()
|
||||||
|
}
|
||||||
return (props.discountedTotal * localTax.percent) / 100
|
return (props.discountedTotal * localTax.percent) / 100
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -171,6 +171,13 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => taxAmount.value,
|
||||||
|
() => {
|
||||||
|
updateRowTax()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
// Set SelectedTax
|
// Set SelectedTax
|
||||||
if (props.taxData.tax_type_id > 0) {
|
if (props.taxData.tax_type_id > 0) {
|
||||||
selectedTax.value = taxTypeStore.taxTypes.find(
|
selectedTax.value = taxTypeStore.taxTypes.find(
|
||||||
@ -183,7 +190,6 @@ updateRowTax()
|
|||||||
function onSelectTax(val) {
|
function onSelectTax(val) {
|
||||||
localTax.percent = val.percent
|
localTax.percent = val.percent
|
||||||
localTax.tax_type_id = val.id
|
localTax.tax_type_id = val.id
|
||||||
localTax.compound_tax = val.compound_tax
|
|
||||||
localTax.name = val.name
|
localTax.name = val.name
|
||||||
|
|
||||||
updateRowTax()
|
updateRowTax()
|
||||||
@ -220,6 +226,27 @@ function openTaxModal() {
|
|||||||
function removeTax(index) {
|
function removeTax(index) {
|
||||||
props.store.$patch((state) => {
|
props.store.$patch((state) => {
|
||||||
state[props.storeProp].items[props.itemIndex].taxes.splice(index, 1)
|
state[props.storeProp].items[props.itemIndex].taxes.splice(index, 1)
|
||||||
|
state[props.storeProp].items[props.itemIndex].tax = 0
|
||||||
|
state[props.storeProp].items[props.itemIndex].totalTax = 0
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTaxAmount() {
|
||||||
|
let total = 0
|
||||||
|
let discount = 0
|
||||||
|
const itemTotal = props.discountedTotal
|
||||||
|
const modelDiscount = props.store[props.storeProp].discount ? props.store[props.storeProp].discount : 0
|
||||||
|
const type = props.store[props.storeProp].discount_type
|
||||||
|
if (modelDiscount > 0) {
|
||||||
|
props.store[props.storeProp].items.forEach((_i) => {
|
||||||
|
total += _i.total
|
||||||
|
})
|
||||||
|
const proportion = (itemTotal / total).toFixed(2)
|
||||||
|
discount = type === 'fixed' ? modelDiscount * 100 : (total * modelDiscount) / 100
|
||||||
|
const itemDiscount = Math.round(discount * proportion)
|
||||||
|
const discounted = itemTotal - itemDiscount
|
||||||
|
return Math.round((discounted * localTax.percent) / 100)
|
||||||
|
}
|
||||||
|
return Math.round((props.discountedTotal * localTax.percent) / 100)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -191,7 +191,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, inject, ref } from 'vue'
|
import { computed, inject, ref, watch } from 'vue'
|
||||||
import Guid from 'guid'
|
import Guid from 'guid'
|
||||||
import Tax from './CreateTotalTaxes.vue'
|
import Tax from './CreateTotalTaxes.vue'
|
||||||
import TaxStub from '@/scripts/admin/stub/abilities'
|
import TaxStub from '@/scripts/admin/stub/abilities'
|
||||||
@ -227,19 +227,20 @@ const utils = inject('$utils')
|
|||||||
|
|
||||||
const companyStore = useCompanyStore()
|
const companyStore = useCompanyStore()
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.store[props.storeProp].items,
|
||||||
|
(val) => {
|
||||||
|
setDiscount()
|
||||||
|
}, { deep: true },
|
||||||
|
)
|
||||||
|
|
||||||
const totalDiscount = computed({
|
const totalDiscount = computed({
|
||||||
get: () => {
|
get: () => {
|
||||||
return props.store[props.storeProp].discount
|
return props.store[props.storeProp].discount
|
||||||
},
|
},
|
||||||
set: (newValue) => {
|
set: (newValue) => {
|
||||||
if (props.store[props.storeProp].discount_type === 'percentage') {
|
|
||||||
props.store[props.storeProp].discount_val = Math.round(
|
|
||||||
(props.store.getSubTotal * newValue) / 100
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
props.store[props.storeProp].discount_val = Math.round(newValue * 100)
|
|
||||||
}
|
|
||||||
props.store[props.storeProp].discount = newValue
|
props.store[props.storeProp].discount = newValue
|
||||||
|
setDiscount()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -265,7 +266,7 @@ const itemWiseTaxes = computed(() => {
|
|||||||
} else if (tax.tax_type_id) {
|
} else if (tax.tax_type_id) {
|
||||||
taxes.push({
|
taxes.push({
|
||||||
tax_type_id: tax.tax_type_id,
|
tax_type_id: tax.tax_type_id,
|
||||||
amount: tax.amount,
|
amount: Math.round(tax.amount),
|
||||||
percent: tax.percent,
|
percent: tax.percent,
|
||||||
name: tax.name,
|
name: tax.name,
|
||||||
})
|
})
|
||||||
@ -284,6 +285,19 @@ const defaultCurrency = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function setDiscount() {
|
||||||
|
const newValue = props.store[props.storeProp].discount
|
||||||
|
|
||||||
|
if (props.store[props.storeProp].discount_type === 'percentage') {
|
||||||
|
props.store[props.storeProp].discount_val
|
||||||
|
= Math.round((props.store.getSubTotal * newValue) / 100)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
props.store[props.storeProp].discount_val = Math.round(newValue * 100)
|
||||||
|
}
|
||||||
|
|
||||||
function selectFixed() {
|
function selectFixed() {
|
||||||
if (props.store[props.storeProp].discount_type === 'fixed') {
|
if (props.store[props.storeProp].discount_type === 'fixed') {
|
||||||
return
|
return
|
||||||
@ -295,24 +309,21 @@ function selectFixed() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectPercentage() {
|
function selectPercentage() {
|
||||||
if (props.store[props.storeProp].discount_type === 'percentage') {
|
if (props.store[props.storeProp].discount_type === 'percentage'){
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
props.store[props.storeProp].discount_val =
|
|
||||||
(props.store.getSubTotal * props.store[props.storeProp].discount) / 100
|
const val = Math.round(props.store[props.storeProp].discount * 100) / 100
|
||||||
|
|
||||||
|
props.store[props.storeProp].discount_val
|
||||||
|
= Math.round((props.store.getSubTotal * val) / 100)
|
||||||
|
|
||||||
props.store[props.storeProp].discount_type = 'percentage'
|
props.store[props.storeProp].discount_type = 'percentage'
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSelectTax(selectedTax) {
|
function onSelectTax(selectedTax) {
|
||||||
let amount = 0
|
let amount = 0
|
||||||
|
if (props.store.getSubtotalWithDiscount && selectedTax.percent) {
|
||||||
if (selectedTax.compound_tax && props.store.getSubtotalWithDiscount) {
|
|
||||||
amount = Math.round(
|
|
||||||
((props.store.getSubtotalWithDiscount + props.store.getTotalSimpleTax) *
|
|
||||||
selectedTax.percent) /
|
|
||||||
100
|
|
||||||
)
|
|
||||||
} else if (props.store.getSubtotalWithDiscount && selectedTax.percent) {
|
|
||||||
amount = Math.round(
|
amount = Math.round(
|
||||||
(props.store.getSubtotalWithDiscount * selectedTax.percent) / 100
|
(props.store.getSubtotalWithDiscount * selectedTax.percent) / 100
|
||||||
)
|
)
|
||||||
@ -323,7 +334,6 @@ function onSelectTax(selectedTax) {
|
|||||||
id: Guid.raw(),
|
id: Guid.raw(),
|
||||||
name: selectedTax.name,
|
name: selectedTax.name,
|
||||||
percent: selectedTax.percent,
|
percent: selectedTax.percent,
|
||||||
compound_tax: selectedTax.compound_tax,
|
|
||||||
tax_type_id: selectedTax.id,
|
tax_type_id: selectedTax.id,
|
||||||
amount,
|
amount,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -77,17 +77,6 @@
|
|||||||
@input="v$.currentTaxType.description.$touch()"
|
@input="v$.currentTaxType.description.$touch()"
|
||||||
/>
|
/>
|
||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
|
|
||||||
<BaseInputGroup
|
|
||||||
:label="$t('tax_types.compound_tax')"
|
|
||||||
variant="horizontal"
|
|
||||||
class="flex flex-row-reverse"
|
|
||||||
>
|
|
||||||
<BaseSwitch
|
|
||||||
v-model="taxTypeStore.currentTaxType.compound_tax"
|
|
||||||
class="flex items-center"
|
|
||||||
/>
|
|
||||||
</BaseInputGroup>
|
|
||||||
</BaseInputGrid>
|
</BaseInputGrid>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -209,14 +198,7 @@ async function submitTaxTypeData() {
|
|||||||
|
|
||||||
function SelectTax(taxData) {
|
function SelectTax(taxData) {
|
||||||
let amount = 0
|
let amount = 0
|
||||||
if (taxData.compound_tax && estimateStore.getSubtotalWithDiscount) {
|
if (estimateStore.getSubtotalWithDiscount && taxData.percent) {
|
||||||
amount = Math.round(
|
|
||||||
((estimateStore.getSubtotalWithDiscount +
|
|
||||||
estimateStore.getTotalSimpleTax) *
|
|
||||||
taxData.percent) /
|
|
||||||
100
|
|
||||||
)
|
|
||||||
} else if (estimateStore.getSubtotalWithDiscount && taxData.percent) {
|
|
||||||
amount = Math.round(
|
amount = Math.round(
|
||||||
(estimateStore.getSubtotalWithDiscount * taxData.percent) / 100
|
(estimateStore.getSubtotalWithDiscount * taxData.percent) / 100
|
||||||
)
|
)
|
||||||
@ -226,7 +208,6 @@ function SelectTax(taxData) {
|
|||||||
id: Guid.raw(),
|
id: Guid.raw(),
|
||||||
name: taxData.name,
|
name: taxData.name,
|
||||||
percent: taxData.percent,
|
percent: taxData.percent,
|
||||||
compound_tax: taxData.compound_tax,
|
|
||||||
tax_type_id: taxData.id,
|
tax_type_id: taxData.id,
|
||||||
amount,
|
amount,
|
||||||
}
|
}
|
||||||
@ -242,7 +223,6 @@ function selectItemTax(taxData) {
|
|||||||
id: Guid.raw(),
|
id: Guid.raw(),
|
||||||
name: taxData.name,
|
name: taxData.name,
|
||||||
percent: taxData.percent,
|
percent: taxData.percent,
|
||||||
compound_tax: taxData.compound_tax,
|
|
||||||
tax_type_id: taxData.id,
|
tax_type_id: taxData.id,
|
||||||
}
|
}
|
||||||
modalStore.refreshData(data)
|
modalStore.refreshData(data)
|
||||||
|
|||||||
@ -143,7 +143,8 @@ export const useEstimateStore = (useWindow = false) => {
|
|||||||
axios
|
axios
|
||||||
.get(`/api/v1/estimates/${id}`)
|
.get(`/api/v1/estimates/${id}`)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
Object.assign(this.newEstimate, response.data.data)
|
this.setEstimateData(response.data.data)
|
||||||
|
this.setCustomerAddresses(this.newEstimate.customer)
|
||||||
resolve(response)
|
resolve(response)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@ -154,6 +155,41 @@ export const useEstimateStore = (useWindow = false) => {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setEstimateData(estimate) {
|
||||||
|
Object.assign(this.newEstimate, estimate)
|
||||||
|
if (this.newEstimate.tax_per_item === 'YES') {
|
||||||
|
this.newEstimate.items.forEach((_i) => {
|
||||||
|
if (_i.taxes && !_i.taxes.length){
|
||||||
|
_i.taxes.push({ ...taxStub, id: Guid.raw() })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (this.newEstimate.discount_per_item === 'YES') {
|
||||||
|
this.newEstimate.items.forEach((_i, index) => {
|
||||||
|
if (_i.discount_type === 'fixed'){
|
||||||
|
this.newEstimate.items[index].discount = _i.discount / 100
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (this.newEstimate.discount_type === 'fixed'){
|
||||||
|
this.newEstimate.discount = this.newEstimate.discount / 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setCustomerAddresses(customer) {
|
||||||
|
const customer_business = customer.customer_business
|
||||||
|
|
||||||
|
if (customer_business?.billing_address){
|
||||||
|
this.newEstimate.customer.billing_address = customer_business.billing_address
|
||||||
|
}
|
||||||
|
|
||||||
|
if (customer_business?.shipping_address){
|
||||||
|
this.newEstimate.customer.shipping_address = customer_business.shipping_address
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
addSalesTaxUs() {
|
addSalesTaxUs() {
|
||||||
const taxTypeStore = useTaxTypeStore()
|
const taxTypeStore = useTaxTypeStore()
|
||||||
let salesTax = { ...taxStub }
|
let salesTax = { ...taxStub }
|
||||||
|
|||||||
@ -133,8 +133,8 @@ export const useInvoiceStore = (useWindow = false) => {
|
|||||||
axios
|
axios
|
||||||
.get(`/api/v1/invoices/${id}`)
|
.get(`/api/v1/invoices/${id}`)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
Object.assign(this.newInvoice, response.data.data)
|
this.setInvoiceData(response.data.data)
|
||||||
this.newInvoice.customer = response.data.data.customer
|
this.setCustomerAddresses(this.newInvoice.customer)
|
||||||
resolve(response)
|
resolve(response)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@ -144,6 +144,38 @@ export const useInvoiceStore = (useWindow = false) => {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setInvoiceData(invoice) {
|
||||||
|
Object.assign(this.newInvoice, invoice)
|
||||||
|
|
||||||
|
if (this.newInvoice.tax_per_item === 'YES') {
|
||||||
|
this.newInvoice.items.forEach((_i) => {
|
||||||
|
if (_i.taxes && !_i.taxes.length)
|
||||||
|
_i.taxes.push({ ...taxStub, id: Guid.raw() })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.newInvoice.discount_per_item === 'YES') {
|
||||||
|
this.newInvoice.items.forEach((_i, index) => {
|
||||||
|
if (_i.discount_type === 'fixed')
|
||||||
|
this.newInvoice.items[index].discount = _i.discount / 100
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (this.newInvoice.discount_type === 'fixed')
|
||||||
|
this.newInvoice.discount = this.newInvoice.discount / 100
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setCustomerAddresses(customer) {
|
||||||
|
const customer_business = customer.customer_business
|
||||||
|
|
||||||
|
if (customer_business?.billing_address)
|
||||||
|
this.newInvoice.customer.billing_address = customer_business.billing_address
|
||||||
|
|
||||||
|
if (customer_business?.shipping_address)
|
||||||
|
this.newInvoice.customer.shipping_address = customer_business.shipping_address
|
||||||
|
},
|
||||||
|
|
||||||
addSalesTaxUs() {
|
addSalesTaxUs() {
|
||||||
const taxTypeStore = useTaxTypeStore()
|
const taxTypeStore = useTaxTypeStore()
|
||||||
let salesTax = { ...taxStub }
|
let salesTax = { ...taxStub }
|
||||||
|
|||||||
@ -35,7 +35,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="grid col-span-12 mt-6 text-center xl:mt-0 sm:grid-cols-4 xl:text-right xl:col-span-3 xl:grid-cols-1 xxl:col-span-2"
|
class="
|
||||||
|
grid
|
||||||
|
col-span-12
|
||||||
|
mt-6
|
||||||
|
text-center
|
||||||
|
xl:mt-0
|
||||||
|
sm:grid-cols-4
|
||||||
|
xl:text-right xl:col-span-3 xl:grid-cols-1
|
||||||
|
xxl:col-span-2
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<div class="px-6 py-2">
|
<div class="px-6 py-2">
|
||||||
<span class="text-xs leading-5 lg:text-sm">
|
<span class="text-xs leading-5 lg:text-sm">
|
||||||
@ -168,12 +177,10 @@ const getChartInvoices = computed(() => {
|
|||||||
return []
|
return []
|
||||||
})
|
})
|
||||||
|
|
||||||
const customerId = computed(() => route.params.id)
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => customerId.value,
|
route,
|
||||||
(id) => {
|
() => {
|
||||||
if (id && route.name === 'customers.view') {
|
if (route.params.id) {
|
||||||
loadCustomer()
|
loadCustomer()
|
||||||
}
|
}
|
||||||
selectedYear.value = 'This year'
|
selectedYear.value = 'This year'
|
||||||
|
|||||||
@ -37,10 +37,32 @@
|
|||||||
|
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div
|
<div
|
||||||
class="fixed top-0 left-0 hidden h-full pt-16 pb-[6.4rem] ml-56 bg-white xl:ml-64 w-88 xl:block"
|
class="
|
||||||
|
fixed
|
||||||
|
top-0
|
||||||
|
left-0
|
||||||
|
hidden
|
||||||
|
h-full
|
||||||
|
pt-16
|
||||||
|
pb-[6.4rem]
|
||||||
|
ml-56
|
||||||
|
bg-white
|
||||||
|
xl:ml-64
|
||||||
|
w-88
|
||||||
|
xl:block
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-between px-4 pt-8 pb-2 border border-gray-200 border-solid height-full"
|
class="
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
justify-between
|
||||||
|
px-4
|
||||||
|
pt-8
|
||||||
|
pb-2
|
||||||
|
border border-gray-200 border-solid
|
||||||
|
height-full
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<BaseInput
|
<BaseInput
|
||||||
@ -70,7 +92,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="px-4 py-1 pb-2 mb-1 mb-2 text-sm border-b border-gray-200 border-solid"
|
class="
|
||||||
|
px-4
|
||||||
|
py-1
|
||||||
|
pb-2
|
||||||
|
mb-1 mb-2
|
||||||
|
text-sm
|
||||||
|
border-b border-gray-200 border-solid
|
||||||
|
"
|
||||||
>
|
>
|
||||||
{{ $t('general.sort_by') }}
|
{{ $t('general.sort_by') }}
|
||||||
</div>
|
</div>
|
||||||
@ -127,7 +156,12 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
ref="estimateListSection"
|
ref="estimateListSection"
|
||||||
class="h-full overflow-y-scroll border-l border-gray-200 border-solid base-scroll"
|
class="
|
||||||
|
h-full
|
||||||
|
overflow-y-scroll
|
||||||
|
border-l border-gray-200 border-solid
|
||||||
|
base-scroll
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<div v-for="(estimate, index) in estimateList" :key="index">
|
<div v-for="(estimate, index) in estimateList" :key="index">
|
||||||
<router-link
|
<router-link
|
||||||
@ -147,11 +181,29 @@
|
|||||||
<BaseText
|
<BaseText
|
||||||
:text="estimate.customer.name"
|
:text="estimate.customer.name"
|
||||||
:length="30"
|
:length="30"
|
||||||
class="pr-2 mb-2 text-sm not-italic font-normal leading-5 text-black capitalize truncate"
|
class="
|
||||||
|
pr-2
|
||||||
|
mb-2
|
||||||
|
text-sm
|
||||||
|
not-italic
|
||||||
|
font-normal
|
||||||
|
leading-5
|
||||||
|
text-black
|
||||||
|
capitalize
|
||||||
|
truncate
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="mt-1 mb-2 text-xs not-italic font-medium leading-5 text-gray-600"
|
class="
|
||||||
|
mt-1
|
||||||
|
mb-2
|
||||||
|
text-xs
|
||||||
|
not-italic
|
||||||
|
font-medium
|
||||||
|
leading-5
|
||||||
|
text-gray-600
|
||||||
|
"
|
||||||
>
|
>
|
||||||
{{ estimate.estimate_number }}
|
{{ estimate.estimate_number }}
|
||||||
</div>
|
</div>
|
||||||
@ -168,11 +220,26 @@
|
|||||||
<BaseFormatMoney
|
<BaseFormatMoney
|
||||||
:amount="estimate.total"
|
:amount="estimate.total"
|
||||||
:currency="estimate.customer.currency"
|
:currency="estimate.customer.currency"
|
||||||
class="block mb-2 text-xl not-italic font-semibold leading-8 text-right text-gray-900"
|
class="
|
||||||
|
block
|
||||||
|
mb-2
|
||||||
|
text-xl
|
||||||
|
not-italic
|
||||||
|
font-semibold
|
||||||
|
leading-8
|
||||||
|
text-right text-gray-900
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="text-sm not-italic font-normal leading-5 text-right text-gray-600 est-date"
|
class="
|
||||||
|
text-sm
|
||||||
|
not-italic
|
||||||
|
font-normal
|
||||||
|
leading-5
|
||||||
|
text-right text-gray-600
|
||||||
|
est-date
|
||||||
|
"
|
||||||
>
|
>
|
||||||
{{ estimate.formatted_estimate_date }}
|
{{ estimate.formatted_estimate_date }}
|
||||||
</div>
|
</div>
|
||||||
@ -197,7 +264,13 @@
|
|||||||
>
|
>
|
||||||
<iframe
|
<iframe
|
||||||
:src="`${shareableLink}`"
|
:src="`${shareableLink}`"
|
||||||
class="flex-1 border border-gray-400 border-solid rounded-md bg-white frame-style"
|
class="
|
||||||
|
flex-1
|
||||||
|
border border-gray-400 border-solid
|
||||||
|
rounded-md
|
||||||
|
bg-white
|
||||||
|
frame-style
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</BasePage>
|
</BasePage>
|
||||||
@ -272,14 +345,11 @@ const getCurrentEstimateId = computed(() => {
|
|||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
|
|
||||||
const estimateId = computed(() => route.params.id)
|
watch(route, (to, from) => {
|
||||||
|
if (to.name === 'estimates.view') {
|
||||||
watch(
|
loadEstimate()
|
||||||
() => estimateId.value,
|
|
||||||
(id) => {
|
|
||||||
if (id && route.name === 'estimates.view') loadEstimate()
|
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
|
|
||||||
loadEstimates()
|
loadEstimates()
|
||||||
loadEstimate()
|
loadEstimate()
|
||||||
|
|||||||
@ -138,6 +138,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref, watch, onMounted } from 'vue'
|
import { computed, ref, watch, onMounted } from 'vue'
|
||||||
|
import { cloneDeep } from 'lodash'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import {
|
import {
|
||||||
@ -257,11 +258,30 @@ async function submitForm() {
|
|||||||
|
|
||||||
isSaving.value = true
|
isSaving.value = true
|
||||||
|
|
||||||
let data = {
|
let data = cloneDeep({
|
||||||
...estimateStore.newEstimate,
|
...estimateStore.newEstimate,
|
||||||
sub_total: estimateStore.getSubTotal,
|
sub_total: estimateStore.getSubTotal,
|
||||||
total: estimateStore.getTotal,
|
total: estimateStore.getTotal,
|
||||||
tax: estimateStore.getTotalTax,
|
tax: estimateStore.getTotalTax,
|
||||||
|
})
|
||||||
|
if (data.discount_per_item === 'YES') {
|
||||||
|
data.items.forEach((item, index) => {
|
||||||
|
if (item.discount_type === 'fixed'){
|
||||||
|
data.items[index].discount = Math.round(item.discount * 100)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (data.discount_type === 'fixed'){
|
||||||
|
data.discount = Math.round(data.discount * 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!estimateStore.newEstimate.tax_per_item === 'YES'
|
||||||
|
&& data.taxes.length
|
||||||
|
){
|
||||||
|
data.tax_type_ids = data.taxes.map(_t => _t.tax_type_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
const action = isEdit.value
|
const action = isEdit.value
|
||||||
|
|||||||
@ -65,14 +65,11 @@ const getCurrentInvoiceId = computed(() => {
|
|||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
|
|
||||||
const invoiceId = computed(() => route.params.id)
|
watch(route, (to, from) => {
|
||||||
|
if (to.name === 'invoices.view') {
|
||||||
watch(
|
loadInvoice()
|
||||||
() => invoiceId.value,
|
|
||||||
(id) => {
|
|
||||||
if (id && route.name === 'invoices.view') loadInvoice()
|
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
|
|
||||||
async function onMarkAsSent() {
|
async function onMarkAsSent() {
|
||||||
dialogStore
|
dialogStore
|
||||||
@ -289,10 +286,32 @@ onSearched = debounce(onSearched, 500)
|
|||||||
|
|
||||||
<!-- sidebar -->
|
<!-- sidebar -->
|
||||||
<div
|
<div
|
||||||
class="fixed top-0 left-0 hidden h-full pt-16 pb-[6.4rem] ml-56 bg-white xl:ml-64 w-88 xl:block"
|
class="
|
||||||
|
fixed
|
||||||
|
top-0
|
||||||
|
left-0
|
||||||
|
hidden
|
||||||
|
h-full
|
||||||
|
pt-16
|
||||||
|
pb-[6.4rem]
|
||||||
|
ml-56
|
||||||
|
bg-white
|
||||||
|
xl:ml-64
|
||||||
|
w-88
|
||||||
|
xl:block
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-between px-4 pt-8 pb-2 border border-gray-200 border-solid height-full"
|
class="
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
justify-between
|
||||||
|
px-4
|
||||||
|
pt-8
|
||||||
|
pb-2
|
||||||
|
border border-gray-200 border-solid
|
||||||
|
height-full
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<BaseInput
|
<BaseInput
|
||||||
@ -316,7 +335,14 @@ onSearched = debounce(onSearched, 500)
|
|||||||
</BaseButton>
|
</BaseButton>
|
||||||
</template>
|
</template>
|
||||||
<div
|
<div
|
||||||
class="px-2 py-1 pb-2 mb-1 mb-2 text-sm border-b border-gray-200 border-solid"
|
class="
|
||||||
|
px-2
|
||||||
|
py-1
|
||||||
|
pb-2
|
||||||
|
mb-1 mb-2
|
||||||
|
text-sm
|
||||||
|
border-b border-gray-200 border-solid
|
||||||
|
"
|
||||||
>
|
>
|
||||||
{{ $t('general.sort_by') }}
|
{{ $t('general.sort_by') }}
|
||||||
</div>
|
</div>
|
||||||
@ -373,7 +399,12 @@ onSearched = debounce(onSearched, 500)
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
ref="invoiceListSection"
|
ref="invoiceListSection"
|
||||||
class="h-full overflow-y-scroll border-l border-gray-200 border-solid base-scroll"
|
class="
|
||||||
|
h-full
|
||||||
|
overflow-y-scroll
|
||||||
|
border-l border-gray-200 border-solid
|
||||||
|
base-scroll
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<div v-for="(invoice, index) in invoiceList" :key="index">
|
<div v-for="(invoice, index) in invoiceList" :key="index">
|
||||||
<router-link
|
<router-link
|
||||||
@ -393,11 +424,29 @@ onSearched = debounce(onSearched, 500)
|
|||||||
<BaseText
|
<BaseText
|
||||||
:text="invoice.customer.name"
|
:text="invoice.customer.name"
|
||||||
:length="30"
|
:length="30"
|
||||||
class="pr-2 mb-2 text-sm not-italic font-normal leading-5 text-black capitalize truncate"
|
class="
|
||||||
|
pr-2
|
||||||
|
mb-2
|
||||||
|
text-sm
|
||||||
|
not-italic
|
||||||
|
font-normal
|
||||||
|
leading-5
|
||||||
|
text-black
|
||||||
|
capitalize
|
||||||
|
truncate
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="mt-1 mb-2 text-xs not-italic font-medium leading-5 text-gray-600"
|
class="
|
||||||
|
mt-1
|
||||||
|
mb-2
|
||||||
|
text-xs
|
||||||
|
not-italic
|
||||||
|
font-medium
|
||||||
|
leading-5
|
||||||
|
text-gray-600
|
||||||
|
"
|
||||||
>
|
>
|
||||||
{{ invoice.invoice_number }}
|
{{ invoice.invoice_number }}
|
||||||
</div>
|
</div>
|
||||||
@ -411,12 +460,27 @@ onSearched = debounce(onSearched, 500)
|
|||||||
|
|
||||||
<div class="flex-1 whitespace-nowrap right">
|
<div class="flex-1 whitespace-nowrap right">
|
||||||
<BaseFormatMoney
|
<BaseFormatMoney
|
||||||
class="mb-2 text-xl not-italic font-semibold leading-8 text-right text-gray-900 block"
|
class="
|
||||||
|
mb-2
|
||||||
|
text-xl
|
||||||
|
not-italic
|
||||||
|
font-semibold
|
||||||
|
leading-8
|
||||||
|
text-right text-gray-900
|
||||||
|
block
|
||||||
|
"
|
||||||
:amount="invoice.total"
|
:amount="invoice.total"
|
||||||
:currency="invoice.customer.currency"
|
:currency="invoice.customer.currency"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="text-sm not-italic font-normal leading-5 text-right text-gray-600 est-date"
|
class="
|
||||||
|
text-sm
|
||||||
|
not-italic
|
||||||
|
font-normal
|
||||||
|
leading-5
|
||||||
|
text-right text-gray-600
|
||||||
|
est-date
|
||||||
|
"
|
||||||
>
|
>
|
||||||
{{ invoice.formatted_invoice_date }}
|
{{ invoice.formatted_invoice_date }}
|
||||||
</div>
|
</div>
|
||||||
@ -441,7 +505,13 @@ onSearched = debounce(onSearched, 500)
|
|||||||
>
|
>
|
||||||
<iframe
|
<iframe
|
||||||
:src="`${shareableLink}`"
|
:src="`${shareableLink}`"
|
||||||
class="flex-1 border border-gray-400 border-solid bg-white rounded-md frame-style"
|
class="
|
||||||
|
flex-1
|
||||||
|
border border-gray-400 border-solid
|
||||||
|
bg-white
|
||||||
|
rounded-md
|
||||||
|
frame-style
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</BasePage>
|
</BasePage>
|
||||||
|
|||||||
@ -147,6 +147,7 @@ import {
|
|||||||
decimal,
|
decimal,
|
||||||
} from '@vuelidate/validators'
|
} from '@vuelidate/validators'
|
||||||
import useVuelidate from '@vuelidate/core'
|
import useVuelidate from '@vuelidate/core'
|
||||||
|
import { cloneDeep } from 'lodash'
|
||||||
|
|
||||||
import { useInvoiceStore } from '@/scripts/admin/stores/invoice'
|
import { useInvoiceStore } from '@/scripts/admin/stores/invoice'
|
||||||
import { useModuleStore } from '@/scripts/admin/stores/module'
|
import { useModuleStore } from '@/scripts/admin/stores/module'
|
||||||
@ -258,11 +259,29 @@ async function submitForm() {
|
|||||||
|
|
||||||
isSaving.value = true
|
isSaving.value = true
|
||||||
|
|
||||||
let data = {
|
let data = cloneDeep({
|
||||||
...invoiceStore.newInvoice,
|
...invoiceStore.newInvoice,
|
||||||
sub_total: invoiceStore.getSubTotal,
|
sub_total: invoiceStore.getSubTotal,
|
||||||
total: invoiceStore.getTotal,
|
total: invoiceStore.getTotal,
|
||||||
tax: invoiceStore.getTotalTax,
|
tax: invoiceStore.getTotalTax,
|
||||||
|
})
|
||||||
|
if (data.discount_per_item === 'YES') {
|
||||||
|
data.items.forEach((item, index) => {
|
||||||
|
if (item.discount_type === 'fixed'){
|
||||||
|
data.items[index].discount = item.discount * 100
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (data.discount_type === 'fixed'){
|
||||||
|
data.discount = data.discount * 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!invoiceStore.newInvoice.tax_per_item === 'YES'
|
||||||
|
&& data.taxes.length
|
||||||
|
){
|
||||||
|
data.tax_type_ids = data.taxes.map(_t => _t.tax_type_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -22,10 +22,31 @@
|
|||||||
|
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div
|
<div
|
||||||
class="fixed top-0 left-0 hidden h-full pt-16 pb-[6rem] ml-56 bg-white xl:ml-64 w-88 xl:block"
|
class="
|
||||||
|
fixed
|
||||||
|
top-0
|
||||||
|
left-0
|
||||||
|
hidden
|
||||||
|
h-full
|
||||||
|
pt-16
|
||||||
|
pb-[6rem]
|
||||||
|
ml-56
|
||||||
|
bg-white
|
||||||
|
xl:ml-64
|
||||||
|
w-88
|
||||||
|
xl:block
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-between px-4 pt-8 pb-6 border border-gray-200 border-solid"
|
class="
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
justify-between
|
||||||
|
px-4
|
||||||
|
pt-8
|
||||||
|
pb-6
|
||||||
|
border border-gray-200 border-solid
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<BaseInput
|
<BaseInput
|
||||||
v-model="searchData.searchText"
|
v-model="searchData.searchText"
|
||||||
@ -49,7 +70,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="px-4 py-1 pb-2 mb-2 text-sm border-b border-gray-200 border-solid"
|
class="
|
||||||
|
px-4
|
||||||
|
py-1
|
||||||
|
pb-2
|
||||||
|
mb-2
|
||||||
|
text-sm
|
||||||
|
border-b border-gray-200 border-solid
|
||||||
|
"
|
||||||
>
|
>
|
||||||
{{ $t('general.sort_by') }}
|
{{ $t('general.sort_by') }}
|
||||||
</div>
|
</div>
|
||||||
@ -131,17 +159,43 @@
|
|||||||
<BaseText
|
<BaseText
|
||||||
:text="payment?.customer?.name"
|
:text="payment?.customer?.name"
|
||||||
:length="30"
|
:length="30"
|
||||||
class="pr-2 mb-2 text-sm not-italic font-normal leading-5 text-black capitalize truncate"
|
class="
|
||||||
|
pr-2
|
||||||
|
mb-2
|
||||||
|
text-sm
|
||||||
|
not-italic
|
||||||
|
font-normal
|
||||||
|
leading-5
|
||||||
|
text-black
|
||||||
|
capitalize
|
||||||
|
truncate
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="mb-1 text-xs not-italic font-medium leading-5 text-gray-500 capitalize"
|
class="
|
||||||
|
mb-1
|
||||||
|
text-xs
|
||||||
|
not-italic
|
||||||
|
font-medium
|
||||||
|
leading-5
|
||||||
|
text-gray-500
|
||||||
|
capitalize
|
||||||
|
"
|
||||||
>
|
>
|
||||||
{{ payment?.payment_number }}
|
{{ payment?.payment_number }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="mb-1 text-xs not-italic font-medium leading-5 text-gray-500 capitalize"
|
class="
|
||||||
|
mb-1
|
||||||
|
text-xs
|
||||||
|
not-italic
|
||||||
|
font-medium
|
||||||
|
leading-5
|
||||||
|
text-gray-500
|
||||||
|
capitalize
|
||||||
|
"
|
||||||
>
|
>
|
||||||
{{ payment?.invoice_number }}
|
{{ payment?.invoice_number }}
|
||||||
</div>
|
</div>
|
||||||
@ -149,7 +203,15 @@
|
|||||||
|
|
||||||
<div class="flex-1 whitespace-nowrap right">
|
<div class="flex-1 whitespace-nowrap right">
|
||||||
<BaseFormatMoney
|
<BaseFormatMoney
|
||||||
class="block mb-2 text-xl not-italic font-semibold leading-8 text-right text-gray-900"
|
class="
|
||||||
|
block
|
||||||
|
mb-2
|
||||||
|
text-xl
|
||||||
|
not-italic
|
||||||
|
font-semibold
|
||||||
|
leading-8
|
||||||
|
text-right text-gray-900
|
||||||
|
"
|
||||||
:amount="payment?.amount"
|
:amount="payment?.amount"
|
||||||
:currency="payment.customer?.currency"
|
:currency="payment.customer?.currency"
|
||||||
/>
|
/>
|
||||||
@ -251,14 +313,9 @@ const paymentDate = computed(() => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const paymentId = computed(() => route.params.id)
|
watch(route, () => {
|
||||||
|
loadPayment()
|
||||||
watch(
|
})
|
||||||
() => paymentId.value,
|
|
||||||
(id) => {
|
|
||||||
if (id && route.name === 'payments.view') loadPayment()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
loadPayments()
|
loadPayments()
|
||||||
loadPayment()
|
loadPayment()
|
||||||
|
|||||||
@ -78,12 +78,10 @@ let isLoading = computed(() => {
|
|||||||
return recurringInvoiceStore.isFetchingViewData
|
return recurringInvoiceStore.isFetchingViewData
|
||||||
})
|
})
|
||||||
|
|
||||||
const invoiceId = computed(() => route.params.id)
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => invoiceId.value,
|
route,
|
||||||
(id) => {
|
() => {
|
||||||
if (id && route.name === 'recurring-invoices.view') {
|
if (route.params.id && route.name === 'recurring-invoices.view') {
|
||||||
loadRecurringInvoice()
|
loadRecurringInvoice()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -20,21 +20,6 @@
|
|||||||
:data="fetchData"
|
:data="fetchData"
|
||||||
:columns="taxTypeColumns"
|
:columns="taxTypeColumns"
|
||||||
>
|
>
|
||||||
<template #cell-compound_tax="{ row }">
|
|
||||||
<BaseBadge
|
|
||||||
:bg-color="
|
|
||||||
utils.getBadgeStatusColor(row.data.compound_tax ? 'YES' : 'NO')
|
|
||||||
.bgColor
|
|
||||||
"
|
|
||||||
:color="
|
|
||||||
utils.getBadgeStatusColor(row.data.compound_tax ? 'YES' : 'NO')
|
|
||||||
.color
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{ row.data.compound_tax ? 'Yes' : 'No'.replace('_', ' ') }}
|
|
||||||
</BaseBadge>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #cell-percent="{ row }"> {{ row.data.percent }} % </template>
|
<template #cell-percent="{ row }"> {{ row.data.percent }} % </template>
|
||||||
|
|
||||||
<template v-if="hasAtleastOneAbility()" #cell-actions="{ row }">
|
<template v-if="hasAtleastOneAbility()" #cell-actions="{ row }">
|
||||||
@ -91,11 +76,6 @@ const taxTypeColumns = computed(() => {
|
|||||||
thClass: 'extra',
|
thClass: 'extra',
|
||||||
tdClass: 'font-medium text-gray-900',
|
tdClass: 'font-medium text-gray-900',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: 'compound_tax',
|
|
||||||
label: t('settings.tax_types.compound_tax'),
|
|
||||||
tdClass: 'font-medium text-gray-900',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: 'percent',
|
key: 'percent',
|
||||||
label: t('settings.tax_types.percent'),
|
label: t('settings.tax_types.percent'),
|
||||||
|
|||||||
@ -309,6 +309,8 @@ function changeSorting(column) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!usesLocalData.value) {
|
if (!usesLocalData.value) {
|
||||||
|
if (pagination.value)
|
||||||
|
pagination.value.currentPage = 1
|
||||||
mapDataToRows()
|
mapDataToRows()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -326,7 +328,10 @@ async function pageChange(page) {
|
|||||||
await mapDataToRows()
|
await mapDataToRows()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refresh() {
|
async function refresh(isPreservePage = false) {
|
||||||
|
if (pagination.value && !isPreservePage)
|
||||||
|
pagination.value.currentPage = 1
|
||||||
|
|
||||||
await mapDataToRows()
|
await mapDataToRows()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user