feat: add separate price vat calc
This commit is contained in:
parent
ef81a93690
commit
310464f834
7 changed files with 344 additions and 280 deletions
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue';
|
||||
import { formatNumberDecimal, commaInput } from 'stores/utils';
|
||||
import { QTableProps } from 'quasar';
|
||||
import { QTableProps, QTableSlots } from 'quasar';
|
||||
import { calculatePrice } from 'src/utils/arithmetic';
|
||||
|
||||
const serviceCharge = defineModel<number>('serviceCharge');
|
||||
|
|
@ -9,24 +9,48 @@ const agentPrice = defineModel<number>('agentPrice');
|
|||
const price = defineModel<number>('price');
|
||||
const vatIncluded = defineModel<boolean>('vatIncluded');
|
||||
const calcVat = defineModel<boolean>('calcVat');
|
||||
const agentPriceVatIncluded = defineModel<boolean>('agentPriceVatIncluded');
|
||||
const agentPriceCalcVat = defineModel<boolean>('agentPriceCalcVat');
|
||||
const serviceChargeVatIncluded = defineModel<boolean>(
|
||||
'serviceChargeVatIncluded',
|
||||
);
|
||||
const serviceChargeCalcVat = defineModel<boolean>('serviceChargeCalcVat');
|
||||
|
||||
const price4Show = ref<string>(commaInput(price.value?.toString() || '0'));
|
||||
const agentPrice4Show = ref<string>(
|
||||
const formattedPrice = ref<string>(commaInput(price.value?.toString() || '0'));
|
||||
const formattedAgentPrice = ref<string>(
|
||||
commaInput(agentPrice.value?.toString() || '0'),
|
||||
);
|
||||
const serviceCharge4Show = ref<string>(
|
||||
const formattedServiceCharge = ref<string>(
|
||||
commaInput(serviceCharge.value?.toString() || '0'),
|
||||
);
|
||||
|
||||
const column = [
|
||||
type RowData = {
|
||||
pricePerUnit: number;
|
||||
calcVat: boolean;
|
||||
vatIncluded: boolean;
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: 'label',
|
||||
align: 'center',
|
||||
align: 'left',
|
||||
label: 'productService.product.priceInformation',
|
||||
field: 'label',
|
||||
},
|
||||
{
|
||||
name: 'pricePerUnit',
|
||||
name: '#calcVat',
|
||||
align: 'center',
|
||||
label: 'general.calculateVat',
|
||||
field: '#calcVat',
|
||||
},
|
||||
{
|
||||
name: '#vatIncluded',
|
||||
align: 'center',
|
||||
label: 'productService.product.vatIncluded',
|
||||
field: '#vatIncluded',
|
||||
},
|
||||
{
|
||||
name: '#pricePerUnit',
|
||||
align: 'center',
|
||||
label: 'quotation.pricePerUnit',
|
||||
field: 'pricePerUnit',
|
||||
|
|
@ -35,54 +59,77 @@ const column = [
|
|||
name: 'beforeVat',
|
||||
align: 'right',
|
||||
label: 'quotation.priceBeforeVat',
|
||||
field: 'beforeVat',
|
||||
field: (data: RowData) =>
|
||||
formatNumberDecimal(
|
||||
calculatePrice({
|
||||
output: 'beforeVat',
|
||||
vatIncluded: data.vatIncluded,
|
||||
price: data.pricePerUnit || 0,
|
||||
}),
|
||||
2,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'vat',
|
||||
align: 'right',
|
||||
label: 'general.vat',
|
||||
field: 'vat',
|
||||
field: (data: RowData) =>
|
||||
formatNumberDecimal(
|
||||
calculatePrice({
|
||||
output: 'vat',
|
||||
calcVat: data.calcVat,
|
||||
price: Number(
|
||||
formatNumberDecimal(
|
||||
calculatePrice({
|
||||
output: 'beforeVat',
|
||||
vatIncluded: data.vatIncluded,
|
||||
price: data.pricePerUnit,
|
||||
}),
|
||||
2,
|
||||
).replaceAll(',', ''),
|
||||
),
|
||||
}),
|
||||
2,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'total',
|
||||
align: 'right',
|
||||
label: 'quotation.sumPrice',
|
||||
field: 'total',
|
||||
field: (data: RowData) =>
|
||||
formatNumberDecimal(
|
||||
calculatePrice({
|
||||
output: 'total',
|
||||
vat: 0.07,
|
||||
price: data.pricePerUnit,
|
||||
}) +
|
||||
(!data.vatIncluded
|
||||
? calculatePrice({
|
||||
output: 'vat',
|
||||
calcVat: data.calcVat,
|
||||
price: data.pricePerUnit,
|
||||
})
|
||||
: 0),
|
||||
2,
|
||||
),
|
||||
},
|
||||
] as const satisfies QTableProps['columns'];
|
||||
] as QTableProps['columns'];
|
||||
|
||||
const row = [
|
||||
{
|
||||
label: 'productService.product.salePrice',
|
||||
beforeVat: 0,
|
||||
vat: 0,
|
||||
total: 0,
|
||||
},
|
||||
{
|
||||
label: 'productService.product.agentPrice',
|
||||
beforeVat: 0,
|
||||
vat: 0,
|
||||
total: 0,
|
||||
},
|
||||
{
|
||||
label: 'productService.product.processingPrice',
|
||||
beforeVat: 0,
|
||||
vat: 0,
|
||||
total: 0,
|
||||
},
|
||||
] as const satisfies QTableProps['rows'];
|
||||
|
||||
watch(calcVat, () => {
|
||||
if (calcVat.value === false) vatIncluded.value = false;
|
||||
watch([calcVat, agentPriceCalcVat, serviceChargeCalcVat], () => {
|
||||
if (calcVat.value === false) {
|
||||
vatIncluded.value = false;
|
||||
}
|
||||
if (agentPriceCalcVat.value === false) {
|
||||
agentPriceVatIncluded.value = false;
|
||||
}
|
||||
if (serviceChargeCalcVat.value === false) {
|
||||
serviceChargeVatIncluded.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
dense?: boolean;
|
||||
outlined?: boolean;
|
||||
readonly?: boolean;
|
||||
separator?: boolean;
|
||||
isType?: boolean;
|
||||
priceDisplay?: {
|
||||
price: boolean;
|
||||
agentPrice: boolean;
|
||||
|
|
@ -115,255 +162,237 @@ withDefaults(
|
|||
{{ $t('productService.product.priceInformation') }}
|
||||
</span>
|
||||
</div>
|
||||
<section class="q-pr-md">
|
||||
<input
|
||||
id="input-calc-vat"
|
||||
type="checkbox"
|
||||
v-model="calcVat"
|
||||
:disabled="readonly"
|
||||
/>
|
||||
<label
|
||||
class="q-pl-sm"
|
||||
for="input-calc-vat"
|
||||
:style="{ opacity: readonly ? '.5' : undefined }"
|
||||
>
|
||||
{{ $t('general.calculateVat') }}
|
||||
</label>
|
||||
</section>
|
||||
<div
|
||||
class="surface-3 q-px-sm q-py-xs row text-caption app-text-muted"
|
||||
style="border-radius: var(--radius-3)"
|
||||
v-if="calcVat"
|
||||
>
|
||||
<span
|
||||
id="btn-include-vat"
|
||||
for="btn-include-vat"
|
||||
class="q-px-sm q-mr-lg rounded cursor-pointer"
|
||||
:class="{
|
||||
dark: $q.dark.isActive,
|
||||
'active-addr': vatIncluded,
|
||||
'cursor-not-allowed': readonly,
|
||||
}"
|
||||
@click="readonly ? '' : (vatIncluded = true)"
|
||||
>
|
||||
{{ $t('productService.product.vatIncluded') }}
|
||||
</span>
|
||||
<span
|
||||
id="btn-no-include-vat"
|
||||
for="btn-no-include-vat"
|
||||
class="q-px-sm rounded cursor-pointer"
|
||||
:class="{
|
||||
dark: $q.dark.isActive,
|
||||
'active-addr': !vatIncluded,
|
||||
'cursor-not-allowed': readonly,
|
||||
}"
|
||||
@click="readonly ? '' : (vatIncluded = false)"
|
||||
>
|
||||
{{ $t('productService.product.vatExcluded') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 full-width">
|
||||
<q-table
|
||||
:columns="column"
|
||||
:rows="row"
|
||||
:rows-per-page-options="[0]"
|
||||
:rows="[
|
||||
{
|
||||
label: $t('productService.product.salePrice'),
|
||||
pricePerUnit: price,
|
||||
calcVat,
|
||||
vatIncluded,
|
||||
},
|
||||
{
|
||||
label: $t('productService.product.agentPrice'),
|
||||
calcVat: agentPriceCalcVat,
|
||||
vatIncluded: agentPriceVatIncluded,
|
||||
pricePerUnit: agentPrice,
|
||||
},
|
||||
{
|
||||
label: $t('productService.product.processingPrice'),
|
||||
calcVat: serviceChargeCalcVat,
|
||||
vatIncluded: serviceChargeVatIncluded,
|
||||
pricePerUnit: serviceCharge,
|
||||
},
|
||||
]"
|
||||
:columns
|
||||
hide-bottom
|
||||
bordered
|
||||
flat
|
||||
hide-pagination
|
||||
selection="multiple"
|
||||
class="full-width"
|
||||
:no-data-label="$t('general.noDataTable')"
|
||||
>
|
||||
<template v-slot:header="props">
|
||||
<q-tr
|
||||
style="background-color: hsla(var(--info-bg) / 0.07)"
|
||||
:props="props"
|
||||
>
|
||||
<q-th v-for="col in props.cols" :key="col.name" :props="props">
|
||||
{{ col.label && $t(col.label) }}
|
||||
<q-th v-for="col in columns" :key="col.name" :props="props">
|
||||
<template v-if="!!col.label">
|
||||
{{ $t(col.label) }}
|
||||
</template>
|
||||
</q-th>
|
||||
</q-tr>
|
||||
</template>
|
||||
|
||||
<template v-slot:body="props">
|
||||
<q-tr>
|
||||
<q-td>{{ $t(props.row.label) }}</q-td>
|
||||
<q-td class="text-right" style="width: 15%">
|
||||
<q-input
|
||||
v-if="priceDisplay?.price && props.rowIndex === 0"
|
||||
id="input-price"
|
||||
for="input-price"
|
||||
:dense="dense"
|
||||
outlined
|
||||
:readonly="readonly"
|
||||
:borderless="readonly"
|
||||
hide-bottom-space
|
||||
input-class="text-right"
|
||||
:model-value="price4Show"
|
||||
@blur="
|
||||
() => {
|
||||
price = Number(price4Show.replace(/,/g, ''));
|
||||
if (price % 1 === 0) {
|
||||
const [, dec] = price4Show.split('.');
|
||||
if (!dec) {
|
||||
price4Show += '.00';
|
||||
<template
|
||||
v-slot:body="props: {
|
||||
row: RowData;
|
||||
} & Omit<Parameters<QTableSlots['body']>[0], 'row'>"
|
||||
>
|
||||
<q-tr :class="{ dark: $q.dark.isActive }" class="text-center">
|
||||
<q-td v-for="(col, i) in columns" :align="col.align" :key="i">
|
||||
<!-- NOTE: custom column will starts with # -->
|
||||
<template v-if="!col.name.startsWith('#')">
|
||||
<span
|
||||
v-if="col.name === 'total'"
|
||||
class="text-weight-bold"
|
||||
:class="{
|
||||
['tags-color-orange']: props.rowIndex === 0,
|
||||
['tags-color-purple']: props.rowIndex === 1,
|
||||
['tags-color-pink']: props.rowIndex === 2,
|
||||
['dark']: $q.dark.isActive,
|
||||
}"
|
||||
>
|
||||
{{
|
||||
typeof col.field === 'string'
|
||||
? props.row[col.field as keyof RowData]
|
||||
: col.field(props.row)
|
||||
}}
|
||||
</span>
|
||||
<template v-else>
|
||||
{{
|
||||
typeof col.field === 'string'
|
||||
? props.row[col.field as keyof RowData]
|
||||
: col.field(props.row)
|
||||
}}
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="col.name === '#calcVat'">
|
||||
<q-checkbox
|
||||
v-if="priceDisplay?.price && props.rowIndex === 0"
|
||||
v-model="calcVat"
|
||||
size="xs"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-if="priceDisplay?.agentPrice && props.rowIndex === 1"
|
||||
v-model="agentPriceCalcVat"
|
||||
size="xs"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-if="priceDisplay?.serviceCharge && props.rowIndex === 2"
|
||||
v-model="serviceChargeCalcVat"
|
||||
size="xs"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="col.name === '#vatIncluded'">
|
||||
<q-select
|
||||
:options="[
|
||||
{ label: $t('general.included'), value: true },
|
||||
{ label: $t('general.notIncluded'), value: false },
|
||||
]"
|
||||
v-if="priceDisplay?.price && props.rowIndex === 0"
|
||||
map-options
|
||||
emit-value
|
||||
flat
|
||||
outlined
|
||||
dense
|
||||
v-model="vatIncluded"
|
||||
></q-select>
|
||||
<q-select
|
||||
:options="[
|
||||
{ label: $t('general.included'), value: true },
|
||||
{ label: $t('general.notIncluded'), value: false },
|
||||
]"
|
||||
v-if="priceDisplay?.agentPrice && props.rowIndex === 1"
|
||||
map-options
|
||||
emit-value
|
||||
flat
|
||||
outlined
|
||||
dense
|
||||
v-model="agentPriceVatIncluded"
|
||||
></q-select>
|
||||
<q-select
|
||||
:options="[
|
||||
{ label: $t('general.included'), value: true },
|
||||
{ label: $t('general.notIncluded'), value: false },
|
||||
]"
|
||||
v-if="priceDisplay?.serviceCharge && props.rowIndex === 2"
|
||||
map-options
|
||||
emit-value
|
||||
flat
|
||||
outlined
|
||||
dense
|
||||
v-model="serviceChargeVatIncluded"
|
||||
></q-select>
|
||||
</template>
|
||||
<template v-if="col.name === '#pricePerUnit'">
|
||||
<q-input
|
||||
v-if="priceDisplay?.price && props.rowIndex === 0"
|
||||
id="input-price"
|
||||
for="input-price"
|
||||
dense
|
||||
outlined
|
||||
hide-bottom-space
|
||||
input-class="text-right"
|
||||
:readonly
|
||||
:borderless="readonly"
|
||||
:model-value="formattedPrice"
|
||||
@blur="
|
||||
() => {
|
||||
price = Number(formattedPrice.replace(/,/g, ''));
|
||||
if (price % 1 === 0 && !formattedPrice.split('.').at(1)) {
|
||||
formattedPrice += '.00';
|
||||
}
|
||||
}
|
||||
}
|
||||
"
|
||||
@update:model-value="
|
||||
(v) => {
|
||||
price4Show = commaInput(v?.toString() || '0', 'string');
|
||||
}
|
||||
"
|
||||
/>
|
||||
<q-input
|
||||
v-if="priceDisplay?.agentPrice && props.rowIndex === 1"
|
||||
id="input-agent-price"
|
||||
for="input-agent-price"
|
||||
:dense="dense"
|
||||
outlined
|
||||
:readonly="readonly"
|
||||
:borderless="readonly"
|
||||
hide-bottom-space
|
||||
input-class="text-right"
|
||||
:model-value="agentPrice4Show"
|
||||
@blur="
|
||||
() => {
|
||||
agentPrice = Number(agentPrice4Show.replace(/,/g, ''));
|
||||
if (agentPrice % 1 === 0) {
|
||||
const [, dec] = agentPrice4Show.split('.');
|
||||
if (!dec) {
|
||||
agentPrice4Show += '.00';
|
||||
"
|
||||
@update:model-value="
|
||||
(v) => {
|
||||
formattedPrice = commaInput(
|
||||
v?.toString() || '0',
|
||||
'string',
|
||||
);
|
||||
}
|
||||
"
|
||||
/>
|
||||
<q-input
|
||||
v-if="priceDisplay?.agentPrice && props.rowIndex === 1"
|
||||
id="input-agent-price"
|
||||
for="input-agent-price"
|
||||
dense
|
||||
outlined
|
||||
hide-bottom-space
|
||||
input-class="text-right"
|
||||
:readonly
|
||||
:borderless="readonly"
|
||||
:model-value="formattedAgentPrice"
|
||||
@blur="
|
||||
() => {
|
||||
agentPrice = Number(formattedPrice.replace(/,/g, ''));
|
||||
if (
|
||||
agentPrice % 1 === 0 &&
|
||||
!formattedAgentPrice.split('.').at(1)
|
||||
) {
|
||||
formattedAgentPrice += '.00';
|
||||
}
|
||||
}
|
||||
}
|
||||
"
|
||||
@update:model-value="
|
||||
(v) => {
|
||||
agentPrice4Show = commaInput(
|
||||
v?.toString() || '0',
|
||||
'string',
|
||||
);
|
||||
}
|
||||
"
|
||||
/>
|
||||
<q-input
|
||||
v-if="priceDisplay?.serviceCharge && props.rowIndex === 2"
|
||||
id="input-service-charge"
|
||||
for="input-service-charge"
|
||||
:dense="dense"
|
||||
outlined
|
||||
:readonly="readonly"
|
||||
:borderless="readonly"
|
||||
input-class="text-right"
|
||||
hide-bottom-space
|
||||
:model-value="serviceCharge4Show"
|
||||
@blur="
|
||||
() => {
|
||||
serviceCharge = Number(
|
||||
serviceCharge4Show.replace(/,/g, ''),
|
||||
);
|
||||
if (serviceCharge % 1 === 0) {
|
||||
const [, dec] = serviceCharge4Show.split('.');
|
||||
if (!dec) {
|
||||
serviceCharge4Show += '.00';
|
||||
"
|
||||
@update:model-value="
|
||||
(v) => {
|
||||
formattedAgentPrice = commaInput(
|
||||
v?.toString() || '0',
|
||||
'string',
|
||||
);
|
||||
}
|
||||
"
|
||||
/>
|
||||
<q-input
|
||||
v-if="priceDisplay?.serviceCharge && props.rowIndex === 2"
|
||||
id="input-service-charge"
|
||||
for="input-service-charge"
|
||||
dense
|
||||
outlined
|
||||
input-class="text-right"
|
||||
hide-bottom-space
|
||||
:readonly
|
||||
:borderless="readonly"
|
||||
:model-value="formattedServiceCharge"
|
||||
@blur="
|
||||
() => {
|
||||
serviceCharge = Number(
|
||||
formattedServiceCharge.replace(/,/g, ''),
|
||||
);
|
||||
if (
|
||||
serviceCharge % 1 === 0 &&
|
||||
!formattedServiceCharge.split('.').at(1)
|
||||
) {
|
||||
formattedServiceCharge += '.00';
|
||||
}
|
||||
}
|
||||
}
|
||||
"
|
||||
@update:model-value="
|
||||
(v) => {
|
||||
serviceCharge4Show = commaInput(
|
||||
v?.toString() || '0',
|
||||
'string',
|
||||
);
|
||||
}
|
||||
"
|
||||
/>
|
||||
</q-td>
|
||||
<q-td class="text-right" style="width: 15%">
|
||||
{{
|
||||
formatNumberDecimal(
|
||||
calculatePrice({
|
||||
output: 'beforeVat',
|
||||
vatIncluded: vatIncluded,
|
||||
price:
|
||||
(props.rowIndex === 0
|
||||
? price
|
||||
: props.rowIndex === 1
|
||||
? agentPrice
|
||||
: serviceCharge) || 0,
|
||||
}),
|
||||
2,
|
||||
)
|
||||
}}
|
||||
</q-td>
|
||||
<q-td class="text-right" style="width: 15%">
|
||||
{{
|
||||
formatNumberDecimal(
|
||||
calculatePrice({
|
||||
output: 'vat',
|
||||
calcVat: calcVat,
|
||||
price: Number(
|
||||
formatNumberDecimal(
|
||||
calculatePrice({
|
||||
output: 'beforeVat',
|
||||
vatIncluded: vatIncluded,
|
||||
price:
|
||||
(props.rowIndex === 0
|
||||
? price
|
||||
: props.rowIndex === 1
|
||||
? agentPrice
|
||||
: serviceCharge) || 0,
|
||||
}),
|
||||
2,
|
||||
).replaceAll(',', ''),
|
||||
),
|
||||
}),
|
||||
2,
|
||||
)
|
||||
}}
|
||||
</q-td>
|
||||
<q-td class="text-right" style="width: 15%">
|
||||
<span
|
||||
class="text-weight-bold"
|
||||
:class="{
|
||||
'tags-color-orange': props.rowIndex === 0,
|
||||
'tags-color-purple': props.rowIndex === 1,
|
||||
'tags-color-pink': props.rowIndex === 2,
|
||||
dark: $q.dark.isActive,
|
||||
}"
|
||||
>
|
||||
{{
|
||||
formatNumberDecimal(
|
||||
calculatePrice({
|
||||
output: 'total',
|
||||
vat: 0.03,
|
||||
price:
|
||||
(props.rowIndex === 0
|
||||
? price
|
||||
: props.rowIndex === 1
|
||||
? agentPrice
|
||||
: serviceCharge) || 0,
|
||||
}) +
|
||||
(!vatIncluded
|
||||
? calculatePrice({
|
||||
output: 'vat',
|
||||
calcVat: calcVat,
|
||||
price:
|
||||
(props.rowIndex === 0
|
||||
? price
|
||||
: props.rowIndex === 1
|
||||
? agentPrice
|
||||
: serviceCharge) || 0,
|
||||
})
|
||||
: 0),
|
||||
2,
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
"
|
||||
@update:model-value="
|
||||
(v) => {
|
||||
formattedServiceCharge = commaInput(
|
||||
v?.toString() || '0',
|
||||
'string',
|
||||
);
|
||||
}
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</q-td>
|
||||
</q-tr>
|
||||
</template>
|
||||
|
|
@ -373,16 +402,6 @@ withDefaults(
|
|||
</template>
|
||||
|
||||
<style scoped>
|
||||
.active-addr {
|
||||
color: hsl(var(--info-bg));
|
||||
background-color: hsla(var(--info-bg) / 0.1);
|
||||
border-radius: var(--radius-3);
|
||||
|
||||
&.dark {
|
||||
background-color: var(--surface-1);
|
||||
}
|
||||
}
|
||||
|
||||
.tags-color-orange {
|
||||
color: var(--orange-5);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ function calcPrice(c: (typeof rows.value)[number]) {
|
|||
const finalPriceNoVat = finalPriceWithVat / (1 + (config.value?.vat || 0.07));
|
||||
|
||||
const price = finalPriceNoVat * c.amount - c.discount;
|
||||
const vat = c.product.calcVat
|
||||
const vat = c.product[props.agentPrice ? 'agentPriceCalcVat' : 'calcVat']
|
||||
? (finalPriceNoVat * c.amount - c.discount) * (config.value?.vat || 0.07)
|
||||
: 0;
|
||||
return precisionRound(price + vat);
|
||||
|
|
@ -387,7 +387,9 @@ watch(
|
|||
{{
|
||||
formatNumberDecimal(
|
||||
props.row.pricePerUnit +
|
||||
(props.row.product.calcVat
|
||||
(props.row.product[
|
||||
agentPrice ? 'agentPriceCalcVat' : 'calcVat'
|
||||
]
|
||||
? props.row.pricePerUnit * (config?.vat || 0.07)
|
||||
: 0),
|
||||
2,
|
||||
|
|
|
|||
|
|
@ -1014,6 +1014,10 @@ const currentNoAction = ref(false);
|
|||
const prevProduct = ref<ProductCreate>({
|
||||
expenseType: '',
|
||||
vatIncluded: true,
|
||||
agentPriceVatIncluded: true,
|
||||
agentPriceCalcVat: true,
|
||||
serviceChargeVatIncluded: true,
|
||||
serviceChargeCalcVat: true,
|
||||
productGroupId: '',
|
||||
remark: '',
|
||||
serviceCharge: 0,
|
||||
|
|
@ -1050,6 +1054,10 @@ async function assignFormDataProduct(data: Product) {
|
|||
status: data.status,
|
||||
expenseType: data.expenseType,
|
||||
vatIncluded: data.vatIncluded,
|
||||
serviceChargeCalcVat: data.serviceChargeCalcVat,
|
||||
serviceChargeVatIncluded: data.serviceChargeVatIncluded,
|
||||
agentPriceCalcVat: data.agentPriceCalcVat,
|
||||
agentPriceVatIncluded: data.agentPriceVatIncluded,
|
||||
selectedImage: data.selectedImage,
|
||||
document: data.document,
|
||||
shared: data.shared,
|
||||
|
|
@ -1086,6 +1094,10 @@ function clearFormProduct() {
|
|||
expenseType: '',
|
||||
calcVat: true,
|
||||
vatIncluded: true,
|
||||
agentPriceCalcVat: true,
|
||||
agentPriceVatIncluded: true,
|
||||
serviceChargeCalcVat: true,
|
||||
serviceChargeVatIncluded: true,
|
||||
shared: false,
|
||||
};
|
||||
imageProduct.value = undefined;
|
||||
|
|
@ -3900,7 +3912,12 @@ watch(
|
|||
v-model:service-charge="formProduct.serviceCharge"
|
||||
v-model:vat-included="formProduct.vatIncluded"
|
||||
v-model:calc-vat="formProduct.calcVat"
|
||||
dense
|
||||
v-model:agent-price-vat-included="formProduct.agentPriceVatIncluded"
|
||||
v-model:agent-price-calc-vat="formProduct.agentPriceCalcVat"
|
||||
v-model:service-charge-vat-included="
|
||||
formProduct.serviceChargeVatIncluded
|
||||
"
|
||||
v-model:service-charge-calc-vat="formProduct.serviceChargeCalcVat"
|
||||
/>
|
||||
<FormDocument
|
||||
v-if="productTab === 3"
|
||||
|
|
@ -4109,7 +4126,12 @@ watch(
|
|||
v-model:service-charge="formProduct.serviceCharge"
|
||||
v-model:vat-included="formProduct.vatIncluded"
|
||||
v-model:calc-vat="formProduct.calcVat"
|
||||
dense
|
||||
v-model:agent-price-vat-included="formProduct.agentPriceVatIncluded"
|
||||
v-model:agent-price-calc-vat="formProduct.agentPriceCalcVat"
|
||||
v-model:service-charge-vat-included="
|
||||
formProduct.serviceChargeVatIncluded
|
||||
"
|
||||
v-model:service-charge-calc-vat="formProduct.serviceChargeCalcVat"
|
||||
:priceDisplay="priceDisplay"
|
||||
/>
|
||||
<FormDocument
|
||||
|
|
|
|||
|
|
@ -251,10 +251,13 @@ function getPrice(
|
|||
const vat =
|
||||
(finalPriceNoVat * c.amount - c.discount) * (config.value?.vat || 0.07);
|
||||
|
||||
const calcVat =
|
||||
c.product[agentPrice.value ? 'agentPriceCalcVat' : 'calcVat'];
|
||||
|
||||
a.totalPrice = precisionRound(a.totalPrice + price);
|
||||
a.totalDiscount = precisionRound(a.totalDiscount + Number(c.discount));
|
||||
a.vat = c.product.calcVat ? precisionRound(a.vat + vat) : a.vat;
|
||||
a.vatExcluded = c.product.calcVat
|
||||
a.vat = calcVat ? precisionRound(a.vat + vat) : a.vat;
|
||||
a.vatExcluded = calcVat
|
||||
? a.vatExcluded
|
||||
: precisionRound(a.vatExcluded + price);
|
||||
a.finalPrice = precisionRound(
|
||||
|
|
|
|||
|
|
@ -260,7 +260,11 @@ function mapNode() {
|
|||
const price = prop.agentPrice
|
||||
? p.product.agentPrice
|
||||
: p.product.price;
|
||||
const pricePerUnit = p.product.vatIncluded
|
||||
const pricePerUnit = (
|
||||
prop.agentPrice
|
||||
? p.product.agentPriceVatIncluded
|
||||
: p.product.vatIncluded
|
||||
)
|
||||
? precisionRound(price / (1 + (config.value?.vat || 0.07)))
|
||||
: price;
|
||||
productCount.value++;
|
||||
|
|
@ -334,7 +338,9 @@ function mapNode() {
|
|||
};
|
||||
} else {
|
||||
const price = prop.agentPrice ? v.raw.agentPrice : v.raw.price;
|
||||
const pricePerUnit = v.raw.vatIncluded
|
||||
const pricePerUnit = (
|
||||
prop.agentPrice ? v.raw.agentPriceVatIncluded : v.raw.vatIncluded
|
||||
)
|
||||
? precisionRound(price / (1 + (config.value?.vat || 0.07)))
|
||||
: price;
|
||||
productCount.value++;
|
||||
|
|
|
|||
|
|
@ -160,6 +160,10 @@ export interface Product {
|
|||
calcVat: boolean;
|
||||
expenseType: string;
|
||||
vatIncluded: boolean;
|
||||
agentPriceVatIncluded: boolean;
|
||||
agentPriceCalcVat: boolean;
|
||||
serviceChargeVatIncluded: boolean;
|
||||
serviceChargeCalcVat: boolean;
|
||||
remark: string;
|
||||
updatedAt: string;
|
||||
updatedBy: UpdatedBy;
|
||||
|
|
@ -189,8 +193,12 @@ export interface ProductCreate {
|
|||
productGroupId: string;
|
||||
remark: string;
|
||||
serviceCharge: number;
|
||||
serviceChargeCalcVat: boolean;
|
||||
serviceChargeVatIncluded: boolean;
|
||||
calcVat?: boolean;
|
||||
agentPrice: number;
|
||||
agentPriceCalcVat: boolean;
|
||||
agentPriceVatIncluded: boolean;
|
||||
price: number;
|
||||
process: number;
|
||||
detail: string;
|
||||
|
|
|
|||
|
|
@ -143,6 +143,10 @@ export type ProductRelation = {
|
|||
serviceCharge: number;
|
||||
vatIncluded: boolean;
|
||||
calcVat: boolean;
|
||||
agentPriceVatIncluded: boolean;
|
||||
agentPriceCalcVat: boolean;
|
||||
serviceChargeVatIncluded: boolean;
|
||||
serviceChargeCalcVat: boolean;
|
||||
expenseType: string;
|
||||
status: Status;
|
||||
statusOrder: number;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue