From b292e0038001001d96cff575e6356aaa2b758ba5 Mon Sep 17 00:00:00 2001 From: Methapon Metanipat Date: Thu, 10 Oct 2024 09:24:02 +0700 Subject: [PATCH] feat: price summary --- src/components/05_quotation/ProductItem.vue | 11 ++-- src/pages/05_quotation/ProductServiceForm.vue | 9 --- src/pages/05_quotation/QuotationForm.vue | 57 ++++++++++++++----- src/pages/05_quotation/QuotationFormInfo.vue | 40 +++++++++++-- 4 files changed, 85 insertions(+), 32 deletions(-) diff --git a/src/components/05_quotation/ProductItem.vue b/src/components/05_quotation/ProductItem.vue index 7b96a2b4..6bc728fe 100644 --- a/src/components/05_quotation/ProductItem.vue +++ b/src/components/05_quotation/ProductItem.vue @@ -48,6 +48,8 @@ const groupList = ref< }[] >([]); +const finalDiscount = defineModel('finalDiscount', { default: 0 }); + const summaryPrice = defineModel<{ totalPrice: number; totalDiscount: number; @@ -66,14 +68,13 @@ const summaryPrice = defineModel<{ const currentBtnOpen = ref<{ title: string; opened: boolean[] }[]>([ { title: '', opened: [] }, ]); -const finalDiscount = ref(0); const finalDiscount4Show = ref(finalDiscount.value.toString()); function calcPrice(c: (typeof rows.value)[number]) { return precisionRound( c.pricePerUnit * c.amount - c.discount + - c.pricePerUnit * (config.value?.vat || 0.07) * c.amount, + (c.pricePerUnit * c.amount - c.discount) * (config.value?.vat || 0.07), ); } @@ -88,7 +89,9 @@ const summary = computed(() => a.totalPrice = precisionRound(a.totalPrice + price); a.totalDiscount = precisionRound(a.totalDiscount + Number(c.discount)); a.vat = precisionRound(a.vat + vat); - a.finalPrice = precisionRound(a.finalPrice + price + vat); + a.finalPrice = precisionRound( + a.totalPrice - a.totalDiscount + a.vat - Number(finalDiscount.value), + ); return a; }, @@ -96,7 +99,7 @@ const summary = computed(() => totalPrice: 0, totalDiscount: 0, vat: 0, - finalPrice: -(+finalDiscount.value || 0), + finalPrice: 0, }, ), ); diff --git a/src/pages/05_quotation/ProductServiceForm.vue b/src/pages/05_quotation/ProductServiceForm.vue index f9cec0ac..f5bc6ade 100644 --- a/src/pages/05_quotation/ProductServiceForm.vue +++ b/src/pages/05_quotation/ProductServiceForm.vue @@ -200,7 +200,6 @@ function mapNode() { opened: v.work.length > 0, checked: true, icon: 'mdi-server-outline', - attributes: v.attributes, bg: 'hsla(var(--orange-5-hsl)/0.1)', fg: 'var(--orange-5)', children: (function () { @@ -240,13 +239,11 @@ function mapNode() { const withNameObjects = v.work .filter((w: Work) => w.name) .flatMap((w: Work) => ({ - type: 'work', id: w.id, title: w.name, subtitle: ' ', opened: w.productOnWork.length > 0, checked: true, - attributes: w.attributes, children: w.productOnWork.map((p) => { const price = prop.agentPrice ? p.product.agentPrice @@ -259,8 +256,6 @@ function mapNode() { title: p.product.name, subtitle: p.product.code || ' ', checked: true, - detail: p.product.detail, - remark: p.product.remark, value: { vat: 0, pricePerUnit, @@ -270,7 +265,6 @@ function mapNode() { work: w, product: p.product, }, - type: 'product', }; }), })); @@ -286,8 +280,6 @@ function mapNode() { id: v.id, title: v.name, subtitle: v.code, - detail: v.detail, - remark: v.remark, value: { vat: 0, pricePerUnit, @@ -296,7 +288,6 @@ function mapNode() { product: v.raw, }, checked: true, - type: 'product', icon: 'mdi-shopping-outline', bg: 'hsla(var(--teal-10-hsl)/0.1)', fg: 'var(--teal-10)', diff --git a/src/pages/05_quotation/QuotationForm.vue b/src/pages/05_quotation/QuotationForm.vue index 0f7f06b8..2f72ee7d 100644 --- a/src/pages/05_quotation/QuotationForm.vue +++ b/src/pages/05_quotation/QuotationForm.vue @@ -2,7 +2,15 @@ import { useI18n } from 'vue-i18n'; import { storeToRefs } from 'pinia'; import { useQuasar } from 'quasar'; -import { nextTick, onBeforeMount, onMounted, reactive, ref, watch } from 'vue'; +import { + computed, + nextTick, + onBeforeMount, + onMounted, + reactive, + ref, + watch, +} from 'vue'; import { dialog } from 'stores/utils'; // NOTE: Import stores @@ -53,6 +61,8 @@ import { columnsAttachment, } from 'src/pages/03_customer-management/constant'; import { group } from 'node:console'; +import { precisionRound } from 'src/utils/arithmetic'; +import { useConfigStore } from 'src/stores/config'; defineProps<{ readonly?: boolean; @@ -71,6 +81,7 @@ type Node = { type ProductGroupId = string; type Id = string; +const configStore = useConfigStore(); const productServiceStore = useProductServiceStore(); const employeeFormStore = useEmployeeForm(); const customerStore = useCustomerStore(); @@ -89,6 +100,8 @@ const { quotationFull, } = storeToRefs(quotationForm); +const { data: config } = storeToRefs(configStore); + const refSelectZoneEmployee = ref>(); const mrz = ref>>(); const selectedBranchIssuer = ref(''); @@ -115,17 +128,33 @@ const workerList = ref([]); const selectedProductGroup = ref(''); const agentPrice = ref(false); -const summaryPrice = ref<{ - totalPrice: number; - totalDiscount: number; - vat: number; - finalPrice: number; -}>({ - totalPrice: 0, - totalDiscount: 0, - vat: 0, - finalPrice: 0, -}); +const finalDiscount = ref(0); +const summaryPrice = computed(() => + productServiceList.value.reduce( + (a, c) => { + console.log(finalDiscount.value); + const price = precisionRound(c.pricePerUnit * c.amount); + const vat = precisionRound( + (c.pricePerUnit * c.amount - c.discount) * (config.value?.vat || 0.07), + ); + + a.totalPrice = precisionRound(a.totalPrice + price); + a.totalDiscount = precisionRound(a.totalDiscount + Number(c.discount)); + a.vat = precisionRound(a.vat + vat); + a.finalPrice = precisionRound( + a.totalPrice - a.totalDiscount + a.vat - Number(finalDiscount.value), + ); + + return a; + }, + { + totalPrice: 0, + totalDiscount: 0, + vat: 0, + finalPrice: 0, + }, + ), +); const quotationNo = ref(''); const payBank = ref(''); @@ -409,6 +438,7 @@ function changeMode(mode: string) { } onMounted(async () => { + await configStore.getConfig(); // get language const getCurLang = localStorage.getItem('currentLanguage'); if (getCurLang === 'English') { @@ -748,6 +778,7 @@ watch( v-model:pay-split-count="quotationFormData.paySplitCount" v-model:pay-split="quotationFormData.paySplit" :readonly + v-model:final-discount="finalDiscount" v-model:summary-price="summaryPrice" /> @@ -1082,7 +1113,7 @@ watch( mrz = await runOcr(file, parseResultMRZ); if (mrz !== null) { - const mapMrz = Object.entries(mrz.result).map( + const mapMrz = Object.entries(mrz.result || {}).map( ([key, value]) => ({ name: key, value: value, diff --git a/src/pages/05_quotation/QuotationFormInfo.vue b/src/pages/05_quotation/QuotationFormInfo.vue index bddc4ebf..9bef79ec 100644 --- a/src/pages/05_quotation/QuotationFormInfo.vue +++ b/src/pages/05_quotation/QuotationFormInfo.vue @@ -71,7 +71,7 @@ const summaryPrice = defineModel<{ const optionStore = useOptionStore(); -const finalDiscount = ref(0); +const finalDiscount = defineModel('finalDiscount', { default: 0 }); const payTypeOpion = ref([ { value: 'Full', @@ -429,7 +429,9 @@ watch( {{ formatNumberDecimal( - summaryPrice.finalPrice + Number(finalDiscount), + summaryPrice.finalPrice + + summaryPrice.totalDiscount + + Number(finalDiscount), 2, ) || 0 }} @@ -444,15 +446,41 @@ watch(
{{ $t('general.totalAfterDiscount') }} - {{ data?.totalAfterDiscount || 0 }} ฿ + + {{ + formatNumberDecimal( + summaryPrice.finalPrice + Number(finalDiscount), + 2, + ) + }} + ฿ +
{{ $t('general.totalVatExcluded') }} - {{ data?.totalVatExcluded || 0 }} ฿ + + {{ + formatNumberDecimal( + summaryPrice.finalPrice + + Number(finalDiscount) - + Number(summaryPrice.vat), + 2, + ) || 0 + }} + ฿ +
{{ $t('general.totalVatIncluded') }} - {{ data?.totalVatIncluded || 0 }} ฿ + + {{ + formatNumberDecimal( + summaryPrice.finalPrice + Number(finalDiscount), + 2, + ) || 0 + }} + ฿ +
{{ @@ -460,7 +488,7 @@ watch( msg: `${config && Math.round(config.vat * 100)}%`, }) }} - {{ data?.totalVatIncluded || 0 }} ฿ + {{ summaryPrice.vat || 0 }} ฿
{{ $t('general.discountAfterVat') }}