diff --git a/public/images/customer-CORP-avartar-female.png b/public/images/customer-CORP-avartar-female.png index 446ef866..4cbb894f 100644 Binary files a/public/images/customer-CORP-avartar-female.png and b/public/images/customer-CORP-avartar-female.png differ diff --git a/public/images/customer-CORP-avartar-male.png b/public/images/customer-CORP-avartar-male.png index 6ad95d7d..ae177f60 100644 Binary files a/public/images/customer-CORP-avartar-male.png and b/public/images/customer-CORP-avartar-male.png differ diff --git a/public/images/customer-PERS-avartar-female.png b/public/images/customer-PERS-avartar-female.png index ca0a2bf1..c3ba574e 100644 Binary files a/public/images/customer-PERS-avartar-female.png and b/public/images/customer-PERS-avartar-female.png differ diff --git a/public/images/customer-PERS-avartar-male.png b/public/images/customer-PERS-avartar-male.png index e9fd15fe..ce0ab20c 100644 Binary files a/public/images/customer-PERS-avartar-male.png and b/public/images/customer-PERS-avartar-male.png differ diff --git a/public/images/employee-avatar-female.png b/public/images/employee-avatar-female.png index 66ace3a0..ce9370f1 100644 Binary files a/public/images/employee-avatar-female.png and b/public/images/employee-avatar-female.png differ diff --git a/public/images/employee-avatar-male.png b/public/images/employee-avatar-male.png index a8daa8ff..aaf5fb1f 100644 Binary files a/public/images/employee-avatar-male.png and b/public/images/employee-avatar-male.png differ diff --git a/public/no-img-female.png b/public/no-img-female.png index 4e177dca..95f959ff 100644 Binary files a/public/no-img-female.png and b/public/no-img-female.png differ diff --git a/public/no-img-man.png b/public/no-img-man.png index 861f356a..f0ccba15 100644 Binary files a/public/no-img-man.png and b/public/no-img-man.png differ diff --git a/src/components/02_personnel-management/FormPerson.vue b/src/components/02_personnel-management/FormPerson.vue index 1aee5b95..cb0463af 100644 --- a/src/components/02_personnel-management/FormPerson.vue +++ b/src/components/02_personnel-management/FormPerson.vue @@ -293,15 +293,11 @@ watch( :readonly="readonly" :label="$t('form.birthDate')" :disabled-dates="disabledAfterToday" - :rules=" - employee - ? [] - : [ - (val: string) => - !!val || - $t('form.error.selectField', { field: $t('form.birthDate') }), - ] - " + :rules="[ + (val: string) => + !!val || + $t('form.error.selectField', { field: $t('form.birthDate') }), + ]" /> +import { storeToRefs } from 'pinia'; +import { useRoute } from 'vue-router'; +import { useI18n } from 'vue-i18n'; + +import FormPerson from '../02_personnel-management/FormPerson.vue'; +import { ProfileBanner, DialogForm, SideMenu } from 'src/components'; +import { + AddButton, + EditButton, + DeleteButton, + SaveButton, + UndoButton, +} from 'components/button'; +import AddressForm from '../form/AddressForm.vue'; +import NoticeJobEmployment from '../upload-file/NoticeJobEmployment.vue'; +import UploadFileGroup from '../upload-file/UploadFileGroup.vue'; +import BasicInformation from './employee/BasicInformation.vue'; +import FormEmployeeHealthCheck from './FormEmployeeHealthCheck.vue'; +import FormEmployeeOther from './FormEmployeeOther.vue'; +import FormEmployeePassport from './FormEmployeePassport.vue'; +import FormEmployeeVisa from './FormEmployeeVisa.vue'; +import FormEmployeeWorkHistory from './FormEmployeeWorkHistory.vue'; +import ExpirationDate from 'components/03_customer-management/ExpirationDate.vue'; +import ImageUploadDialog from '../ImageUploadDialog.vue'; + +import { + uploadFileListEmployee, + columnsAttachment, +} from 'src/pages/03_customer-management/constant'; +import { + baseUrl, + setPrefixName, + waitAll, + notify, + dialogCheckData, +} from 'src/stores/utils'; +import { + useCustomerForm, + useEmployeeForm, +} from 'src/pages/03_customer-management/form'; +import useFlowStore from 'src/stores/flow'; +import useEmployeeStore from 'src/stores/employee'; +import useOcrStore from 'stores/ocr'; +import { dateFormat } from 'src/utils/datetime'; +import { runOcr, parseResultMRZ } from 'src/utils/ocr'; +import useOptionStore from 'src/stores/options'; + +const route = useRoute(); +const ocrStore = useOcrStore(); +const flowStore = useFlowStore(); +const { t, locale } = useI18n(); +const optionStore = useOptionStore(); +const employeeFormStore = useEmployeeForm(); +const employeeStore = useEmployeeStore(); +const customerFormStore = useCustomerForm(); +const { state: customerFormState, currentFormData: customerFormData } = + storeToRefs(customerFormStore); +const { employeeFormUndo, employeeConfirmUnsave, deleteEmployeeById } = + employeeFormStore; +const { + state: employeeFormState, + currentFromDataEmployee, + onCreateImageList, + statusEmployeeCreate, + refreshImageState, +} = storeToRefs(employeeFormStore); + +const props = defineProps<{ + currentTab: string; + fetchListEmployee: (opt?: { + fetchStats?: boolean; + page?: number; + pageSize?: number; + customerId?: string; + mobileFetch?: boolean; + }) => Promise; + fetchImageList: ( + id: string, + selectedName: string, + type: 'customer' | 'employee', + ) => Promise; +}>(); + +const mrz = defineModel>>('mrz'); + + diff --git a/src/components/03_customer-management/DrawerEmployee.vue b/src/components/03_customer-management/DrawerEmployee.vue new file mode 100644 index 00000000..1c1d39bf --- /dev/null +++ b/src/components/03_customer-management/DrawerEmployee.vue @@ -0,0 +1,1772 @@ + + + diff --git a/src/components/03_customer-management/FormEmployeePassport.vue b/src/components/03_customer-management/FormEmployeePassport.vue index 040c9676..06373538 100644 --- a/src/components/03_customer-management/FormEmployeePassport.vue +++ b/src/components/03_customer-management/FormEmployeePassport.vue @@ -20,8 +20,8 @@ const issuePlace = defineModel('issuePlace'); const issueCountry = defineModel('issueCountry'); const issueDate = defineModel('issueDate'); const type = defineModel('type'); -const expireDate = defineModel('expireDate'); -const birthDate = defineModel('birthDate'); +const expireDate = defineModel('expireDate'); +const birthDate = defineModel('birthDate'); const workerStatus = defineModel('workerStatus'); const nationality = defineModel('nationality'); const gender = defineModel('gender'); diff --git a/src/components/03_customer-management/FormEmployeeVisa.vue b/src/components/03_customer-management/FormEmployeeVisa.vue index a5f0f292..7c9085c4 100644 --- a/src/components/03_customer-management/FormEmployeeVisa.vue +++ b/src/components/03_customer-management/FormEmployeeVisa.vue @@ -28,12 +28,12 @@ const arrivalAt = defineModel('arrivalAt'); const arrivalTMNo = defineModel('arrivalTmNo'); const arrivalTM = defineModel('arrivalTm'); const mrz = defineModel('mrz'); -const entryCount = defineModel('entryCount'); +const entryCount = defineModel('entryCount'); const issuePlace = defineModel('issuePlace'); const issueCountry = defineModel('issueCountry'); const issueDate = defineModel('visaIssueDate'); const type = defineModel('type'); -const expireDate = defineModel('expireDate'); +const expireDate = defineModel('expireDate'); const remark = defineModel('remark'); const workerType = defineModel('workerType'); const number = defineModel('number'); diff --git a/src/components/03_customer-management/TableEmpoloyee.vue b/src/components/03_customer-management/TableEmpoloyee.vue index d93c6085..000c701a 100644 --- a/src/components/03_customer-management/TableEmpoloyee.vue +++ b/src/components/03_customer-management/TableEmpoloyee.vue @@ -141,8 +141,9 @@ defineEmits<{ ('branchId'); const customerBranchId = defineModel('customerBranchId'); const agentPrice = defineModel('agentPrice'); const special = defineModel('special'); +const customerBranchOption = defineModel( + 'customerBranchOption', +); + defineProps<{ outlined?: boolean; readonly?: boolean; @@ -67,10 +74,12 @@ defineEmits<{ required :readonly /> + {{ formatNumberDecimal( - props.row.pricePerUnit * props.row.amount - - props.row.discount, + props.row.product[ + agentPrice ? 'agentPriceCalcVat' : 'calcVat' + ] + ? precisionRound( + (props.row.pricePerUnit * + (1 + (config?.vat || 0.07)) * + props.row.amount - + props.row.discount) / + (1 + (config?.vat || 0.07)), + ) + : precisionRound( + props.row.pricePerUnit * props.row.amount - + props.row.discount, + ), 2, ) }} @@ -448,9 +459,12 @@ watch( agentPrice ? 'agentPriceCalcVat' : 'calcVat' ] ? precisionRound( - (props.row.pricePerUnit * props.row.amount - - props.row.discount) * - (config?.vat || 0.07), + ((props.row.pricePerUnit * + (1 + (config?.vat || 0.07)) * + props.row.amount - + props.row.discount) / + (1 + (config?.vat || 0.07))) * + 0.07, ) : 0, 2, diff --git a/src/components/05_quotation/TableQuotation.vue b/src/components/05_quotation/TableQuotation.vue index 414eedf9..76c9e38c 100644 --- a/src/components/05_quotation/TableQuotation.vue +++ b/src/components/05_quotation/TableQuotation.vue @@ -1,6 +1,6 @@ diff --git a/src/components/upload-file/UploadFileCard.vue b/src/components/upload-file/UploadFileCard.vue index 2e269d8b..b299c51d 100644 --- a/src/components/upload-file/UploadFileCard.vue +++ b/src/components/upload-file/UploadFileCard.vue @@ -54,10 +54,11 @@ onMounted(() => { @click="$emit('click')" > -
- +
+
{{ name }} - +
+ {{ uploading.loaded @@ -79,7 +80,7 @@ onMounted(() => { /> {{ idle ? `Pending` : progress !== 1 ? `Uploading...` : 'Completed' }} -
+ void | Promise<{ + ) => Promise<{ status: boolean; group: string; meta: { name: string; value: string }[]; diff --git a/src/css/quasar.variables.scss b/src/css/quasar.variables.scss index 7bd226ac..eb2b877b 100644 --- a/src/css/quasar.variables.scss +++ b/src/css/quasar.variables.scss @@ -198,3 +198,10 @@ i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-i .q-focus-helper { visibility: hidden; } + +.clear-btn { + opacity: 0.6; + &:hover { + opacity: 1; + } +} diff --git a/src/i18n/eng.ts b/src/i18n/eng.ts index 5546d0b8..3379ba60 100644 --- a/src/i18n/eng.ts +++ b/src/i18n/eng.ts @@ -161,6 +161,7 @@ export default { documentStatus: 'Document Status', advanceSearch: 'Advance Search', totalPeople: '{meg} people', + price: 'Price {price} Baht', }, menu: { @@ -507,6 +508,7 @@ export default { miss: 'MISS.', }, + taxpayyerNo: 'Taxpayer Identification Number', citizenId: 'Citizen ID', religion: 'Religion', issueDate: 'Issue Date', @@ -777,6 +779,8 @@ export default { seller: 'Seller', paymentChannels: 'Payment Channels', channelsThat: 'Channels That', + refNo: 'Reference Number', + bankAccount: 'Bank Account', bankAccountNumber: 'Bank Account Number', bankAccountName: 'Bank Account Name', inTheNameOf: 'In The Name Of', @@ -1230,6 +1234,9 @@ export default { taskListNotPending: 'One or more task is not pending.', reqNotMet: 'Not Match', systemError: 'A system error occurred.', + taskOrderInvalid: 'Please select the product and the organization.', + + flowAccountProductIdNotFound: 'Product not found in flow account', }, }, diff --git a/src/i18n/tha.ts b/src/i18n/tha.ts index 64411146..921e25fd 100644 --- a/src/i18n/tha.ts +++ b/src/i18n/tha.ts @@ -161,6 +161,7 @@ export default { documentStatus: 'สถานะเอกสาร', advanceSearch: 'ค้นหาขั้นสูง', totalPeople: '{meg} คน', + price: 'ราคา {price} บาท', }, menu: { @@ -508,6 +509,7 @@ export default { religion: 'ศาสนา', issueDate: 'วันที่ออกหนังสือ', passportExpiryDate: 'วันหiมดอายุหนังสือเดินทาง', + taxpayyerNo: 'เลขที่ประจำตัวผู้เสียภาษี', ownerName: 'ชื่อนายจ้าง', firstName: 'ชื่อ ', @@ -775,6 +777,8 @@ export default { seller: 'ผู้ขาย', paymentChannels: 'ช่องทางชำระเงิน', channelsThat: 'ช่องทางที่', + refNo: 'เลขที่อ้างอิง', + bankAccount: 'บัญชีธนาคาร', bankAccountNumber: 'เลขบัญชีธนาคาร', bankAccountName: 'ชื่อบัญชี', inTheNameOf: 'ในนาม', @@ -1216,6 +1220,8 @@ export default { 'มีงานหนึ่งงานหรือมากกว่าที่ไม่อยู่ในสถานะรอดำเนินการ', reqNotMet: 'ไม่ตรงกัน', systemError: 'ระบบเกิดข้อผิดพลาด', + taskOrderInvalid: 'โปรดเลือก สินค้าเเละสาขา', + flowAccountProductIdNotFound: 'ไม่พบสินค้าใน flow account', }, }, diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index c09effed..29e106bc 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -2,7 +2,7 @@ import { ref, onMounted, computed, reactive } from 'vue'; import { storeToRefs } from 'pinia'; import { useQuasar } from 'quasar'; -import { getUserId, getUsername, logout, getRole } from 'src/services/keycloak'; +import { getUserId, getUsername, getName, logout, getRole } from 'src/services/keycloak'; import { Icon } from '@iconify/vue'; import { useI18n } from 'vue-i18n'; import moment from 'moment'; @@ -39,7 +39,7 @@ const configStore = useConfigStore(); const { data: notificationData } = storeToRefs(notificationStore); const { visible } = storeToRefs(loaderStore); -const { t } = useI18n({ useScope: 'global' }); +const { t, locale } = useI18n({ useScope: 'global' }); const userStore = useUserStore(); const canvasModal = ref(false); @@ -52,8 +52,14 @@ const unread = computed( ); const userImage = ref(); const userGender = ref(''); +const userName = ref({ th: '', en: '' }); const canvasRef = ref(); +const displayName = computed(() => { + if (!userName.value.th && !userName.value.en) return getName() || 'Guest'; + return locale.value === 'eng' ? userName.value.en : userName.value.th; +}); + const language: { value: Lang; label: string; @@ -161,9 +167,14 @@ onMounted(async () => { if (user === 'admin') return; if (uid) { const res = await userStore.fetchById(uid); - if (res && res.gender) { - userGender.value = res.gender; - userImage.value = `${baseUrl}/user/${uid}/profile-image/${res.selectedImage}`; + if (res) { + if (res.gender) { + userGender.value = res.gender; + userImage.value = `${baseUrl}/user/${uid}/profile-image/${res.selectedImage}`; + } + // เก็บชื่อทั้งสองภาษา + userName.value.th = `${res.firstName || ''} ${res.lastName || ''}`.trim(); + userName.value.en = `${res.firstNameEN || ''} ${res.lastNameEN || ''}`.trim(); } } }); @@ -484,6 +495,7 @@ onMounted(async () => { - {{ getName() }} + {{ userName || getName() }} - {{ getName() }} + {{ userName || getName() }} { style="margin-top: 58px" > - {{ getName() }} + {{ userName || getName() }} {{ 'Guest' }} - {{ getName() }} + {{ userName || getName() }} {{ 'Guest' }} diff --git a/src/pages/03_customer-management/BranchPage.vue b/src/pages/03_customer-management/BranchPage.vue index 3c2e07bb..dd8c4737 100644 --- a/src/pages/03_customer-management/BranchPage.vue +++ b/src/pages/03_customer-management/BranchPage.vue @@ -18,6 +18,8 @@ import { CustomerBranch, CustomerType } from 'stores/customer/types'; import { columnsEmployee } from './constant'; import { useCustomerBranchForm, useEmployeeForm } from './form'; +import DialogEmployee from 'src/components/03_customer-management/DialogEmployee.vue'; +import DrawerEmployee from 'src/components/03_customer-management/DrawerEmployee.vue'; import EmployerFormAuthorized from './components/employer/EmployerFormAuthorized.vue'; import FloatingActionButton from 'components/FloatingActionButton.vue'; import SideMenu from 'components/SideMenu.vue'; @@ -89,6 +91,11 @@ const prop = withDefaults( currentCitizenId?: string; gender: string; selectedImage: string; + fetchImageList: ( + id: string, + selectedName: string, + type: 'customer' | 'employee', + ) => Promise; }>(), { color: 'green', @@ -96,7 +103,6 @@ const prop = withDefaults( ); const currentBranchEmployee = ref(''); const listEmployee = ref([]); - const customerId = defineModel('customerId', { required: true }); defineEmits<{ @@ -106,16 +112,6 @@ defineEmits<{ (e: 'dialog'): void; }>(); -onMounted(async () => { - customerBranchFormState.value.currentCustomerId = route.params - .customerId as string; - await fetchList(); - - branch.value?.forEach((v) => { - currentBtnOpen.value.push(false); - }); -}); - const columns = [ { name: 'branchName', @@ -257,10 +253,6 @@ async function fetchEmployee(opts: { branchId: string; pageSize?: number }) { } } -onMounted(async () => { - await fetchList(); -}); - watch([customerId, inputSearch, currentStatus, pageSizeBranch], async () => { await fetchList(); }); @@ -280,6 +272,16 @@ watch( } }, ); + +onMounted(async () => { + customerBranchFormState.value.currentCustomerId = route.params + .customerId as string; + await fetchList(); + + branch.value?.forEach((v) => { + currentBtnOpen.value.push(false); + }); +}); + + + + diff --git a/src/pages/03_customer-management/TabEmployee.vue b/src/pages/03_customer-management/TabEmployee.vue new file mode 100644 index 00000000..81348622 --- /dev/null +++ b/src/pages/03_customer-management/TabEmployee.vue @@ -0,0 +1,514 @@ + + + + diff --git a/src/pages/03_customer-management/components/employer/EmployerFormAbout.vue b/src/pages/03_customer-management/components/employer/EmployerFormAbout.vue index 0d19e8e9..7353db3c 100644 --- a/src/pages/03_customer-management/components/employer/EmployerFormAbout.vue +++ b/src/pages/03_customer-management/components/employer/EmployerFormAbout.vue @@ -336,6 +336,7 @@ watch( (v) => (typeof v === 'string' ? (prefixName = v) : '') " @clear="prefixName = ''" + :rules="[(val: string) => !!val || $t('form.error.required')]" > diff --git a/src/pages/03_customer-management/components/employer/EmployerFormContact.vue b/src/pages/03_customer-management/components/employer/EmployerFormContact.vue index 4a58439c..7f56742c 100644 --- a/src/pages/03_customer-management/components/employer/EmployerFormContact.vue +++ b/src/pages/03_customer-management/components/employer/EmployerFormContact.vue @@ -9,8 +9,6 @@ const contactName = defineModel('contactName'); const email = defineModel('email'); const contactTel = defineModel('contactTel'); const officeTel = defineModel('officeTel'); -const agent = defineModel('agent'); - const agentUserId = defineModel('agentUserId'); @@ -109,7 +107,6 @@ const agentUserId = defineModel('agentUserId'); />
- { const customerStore = useCustomerStore(); + const onCreateImageList = ref<{ + selectedImage: string; + list: { url: string; imgFile: File | null; name: string }[]; + }>({ selectedImage: '', list: [] }); const { t } = useI18n(); const flowStore = useFlowStore(); @@ -30,6 +34,8 @@ export const useCustomerForm = defineStore('form-customer', () => { const registerAbleBranchOption = ref<{ id: string; name: string }[]>(); + const currentBranchRootId = ref(''); + const tabFieldRequired = ref<{ [key: string]: (keyof CustomerBranchCreate)[]; }>({ @@ -82,6 +88,7 @@ export const useCustomerForm = defineStore('form-customer', () => { formDataOcr: Record; isImageEdit: boolean; currentCustomerId?: string; + imageList: { list: string[]; selectedImage: string }; }>({ dialogType: 'info', dialogOpen: false, @@ -98,6 +105,7 @@ export const useCustomerForm = defineStore('form-customer', () => { treeFile: [], formDataOcr: {}, isImageEdit: false, + imageList: { list: [], selectedImage: '' }, }); watch( @@ -160,6 +168,7 @@ export const useCustomerForm = defineStore('form-customer', () => { state.value.editCustomerCode = data.code; state.value.customerImageUrl = `${baseUrl}/customer/${id}/image/${data.selectedImage}`; state.value.defaultCustomerImageUrl = `${baseUrl}/customer/${id}/image/${data.selectedImage}`; + currentBranchRootId.value = data.branch[0].id || ''; resetFormData.registeredBranchId = data.registeredBranchId; resetFormData.status = data.status; @@ -255,7 +264,6 @@ export const useCustomerForm = defineStore('form-customer', () => { async function addCurrentCustomerBranch() { if (currentFormData.value.customerBranch?.some((v) => !v.id)) return; currentFormData.value.customerBranch?.push({ - id: '', customerId: '', branchCode: currentFormData.value.customerBranch.length !== 0 @@ -495,11 +503,14 @@ export const useCustomerForm = defineStore('form-customer', () => { } return { + onCreateImageList, tabFieldRequired, registerAbleBranchOption, state, resetFormData, currentFormData, + currentBranchRootId, + isFormDataDifferent, resetForm, assignFormData, @@ -779,6 +790,7 @@ export const useEmployeeForm = defineStore('form-employee', () => { } | undefined; ocr: boolean; + imageList: { list: string[]; selectedImage: string }; }>({ currentBranchId: '', isImageEdit: false, @@ -803,6 +815,7 @@ export const useEmployeeForm = defineStore('form-employee', () => { infoEmployeePersonCard: [], formDataEmployeeOwner: undefined, ocr: false, + imageList: { list: [], selectedImage: '' }, }); const defaultFormData: EmployeeCreate & { image?: File } = { @@ -955,6 +968,7 @@ export const useEmployeeForm = defineStore('form-employee', () => { state.value.currentIndexVisa = -1; state.value.currentIndexCheckup = -1; state.value.currentIndexWorkHistory = -1; + state.value.imageList = { list: [], selectedImage: '' }; // state.value.currentTab = 'personalInfo'; if (clean) { state.value.formDataEmployeeOwner = undefined; @@ -1384,12 +1398,10 @@ export const useEmployeeForm = defineStore('form-employee', () => { statusSave: true, })), ), - employeeOtherInfo: structuredClone( - { - ...payload.employeeOtherInfo, - statusSave: !!payload.employeeOtherInfo?.id ? true : false, - } || {}, - ), + employeeOtherInfo: structuredClone({ + ...(payload.employeeOtherInfo ?? {}), + statusSave: true, + }), employeeWork: structuredClone( payload.employeeWork?.length === 0 ? state.value.dialogModal @@ -1663,6 +1675,7 @@ export const useEmployeeForm = defineStore('form-employee', () => { state, currentFromDataEmployee, resetEmployeeData, + addPassport, addVisa, addCheckup, diff --git a/src/pages/04_product-service/MainPage.vue b/src/pages/04_product-service/MainPage.vue index 442401f1..17cd4040 100644 --- a/src/pages/04_product-service/MainPage.vue +++ b/src/pages/04_product-service/MainPage.vue @@ -102,6 +102,8 @@ const { deleteWork, importProduct, + + productExport, } = productServiceStore; const { workNameItems } = storeToRefs(productServiceStore); @@ -1169,6 +1171,7 @@ function clearFormService() { profileSubmit.value = false; imageProduct.value = undefined; profileFileImg.value = null; + serviceTab.value = 1; } function sameFormService() { @@ -1896,6 +1899,25 @@ async function submitWorkName( else await editWork(workId, data); } +async function triggerExport() { + productExport({ + pageSize: 100_000, + productGroupId: currentIdGroup.value, + query: !!inputSearchProductAndService.value + ? inputSearchProductAndService.value + : undefined, + status: + currentStatus.value === 'INACTIVE' + ? 'INACTIVE' + : currentStatus.value === 'ACTIVE' + ? 'ACTIVE' + : undefined, + + startDate: searchDate.value[0] ? new Date(searchDate.value[0]) : undefined, + endDate: searchDate.value[1] ? new Date(searchDate.value[1]) : undefined, + }); +} + watch( () => formService.value.attributes.workflowId, async (a, b) => { @@ -2229,7 +2251,6 @@ watch( -
+ +
@@ -4357,6 +4385,7 @@ watch( -import { onMounted, reactive, ref, watch, computed } from 'vue'; +import { onMounted, onUnmounted, reactive, ref, watch, computed } from 'vue'; import { storeToRefs } from 'pinia'; import { useQuasar } from 'quasar'; import { useI18n } from 'vue-i18n'; @@ -60,7 +60,6 @@ const flowStore = useFlowStore(); const userBranch = useMyBranch(); const navigatorStore = useNavigator(); const customerStore = useCustomerStore(); - const { fetchListOfOptionBranch, customerFormUndo, @@ -76,6 +75,7 @@ const { const { state: customerFormState, currentFormData: customerFormData, + currentBranchRootId, registerAbleBranchOption, tabFieldRequired, } = storeToRefs(customerFormStore); @@ -89,6 +89,8 @@ const fieldSelectedOption = computed(() => { value: v.name, })); }); + +const keyAddDialog = ref(0); const special = ref(false); const branchId = ref(''); const agentPrice = ref(false); @@ -273,6 +275,10 @@ const customerNameInfo = computed(() => { return name || '-'; }); +function handleWindowFocus() { + fetchQuotationList(); +} + onMounted(async () => { pageState.gridView = $q.screen.lt.md ? true : false; navigatorStore.current.title = 'quotation.title'; @@ -310,6 +316,12 @@ onMounted(async () => { } flowStore.rotate(); + + window.addEventListener('focus', handleWindowFocus); +}); + +onUnmounted(() => { + window.removeEventListener('focus', handleWindowFocus); }); async function fetchQuotationList(mobileFetch?: boolean) { @@ -765,8 +777,13 @@ async function filterBySellerId() { :worker-count="item.row._count.worker" :worker-max="item.row.workerMax || item.row._count.worker" :customer-name=" - item.row.customerBranch.registerName || - `${item.row.customerBranch.firstName || '-'} ${item.row.customerBranch.lastName || ''}` + item.row.customerBranch.customer.customerType === 'CORP' + ? $i18n.locale === 'tha' + ? item.row.customerBranch.registerName + : item.row.customerBranch.registerNameEN + : $i18n.locale === 'tha' + ? `${item.row.customerBranch.firstName || '-'} ${item.row.customerBranch.lastName || ''}` + : `${item.row.customerBranch.firstNameEN || '-'} ${item.row.customerBranch.lastNameEN || ''}` " :reporter=" $i18n.locale === 'eng' @@ -865,6 +882,7 @@ async function filterBySellerId() {
@@ -999,6 +1018,7 @@ async function filterBySellerId() { () => { customerFormState.dialogModal = false; onCreateImageList = { selectedImage: '', list: [] }; + keyAddDialog++; } " > @@ -1190,7 +1210,7 @@ async function filterBySellerId() { customerFormData.customerBranch[0].legalPersonNo " v-model:business-type=" - customerFormData.customerBranch[0].businessType + customerFormData.customerBranch[0].businessTypeId " v-model:job-position=" customerFormData.customerBranch[0].jobPosition @@ -1271,7 +1291,6 @@ async function filterBySellerId() { res = await customerStore.createBranch({ ...customerFormData.customerBranch[idx], customerId: customerFormState.editCustomerId || '', - id: undefined, }); } if (res) { diff --git a/src/pages/05_quotation/PaymentForm.vue b/src/pages/05_quotation/PaymentForm.vue index 64f57560..cf3d7c63 100644 --- a/src/pages/05_quotation/PaymentForm.vue +++ b/src/pages/05_quotation/PaymentForm.vue @@ -1,15 +1,9 @@ diff --git a/src/pages/09_task-order/document_view/MainPage.vue b/src/pages/09_task-order/document_view/MainPage.vue index b631dbb1..fc936db4 100644 --- a/src/pages/09_task-order/document_view/MainPage.vue +++ b/src/pages/09_task-order/document_view/MainPage.vue @@ -202,40 +202,44 @@ onMounted(async () => { }) .reduce( (a, c) => { - const priceNoVat = c.product.serviceChargeVatIncluded - ? c.pricePerUnit / (1 + (config.value?.vat || 0.07)) - : c.pricePerUnit; - const adjustedPriceWithVat = precisionRound( - priceNoVat * (1 + (config.value?.vat || 0.07)), - ); - const adjustedPriceNoVat = - adjustedPriceWithVat / (1 + (config.value?.vat || 0.07)); - const priceDiscountNoVat = adjustedPriceNoVat * c.amount - c.discount; + const vatFactor = c.product.serviceChargeCalcVat + ? (config.value?.vat ?? 0.07) + : 0; - const rawVatTotal = priceDiscountNoVat * (config.value?.vat || 0.07); - const rawVat = rawVatTotal / c.amount; + const pricePerUnit = + precisionRound(c.product.serviceCharge * (1 + vatFactor)) / + (1 + vatFactor); + + const amount = c.amount; + const discount = c.discount || 0; + + const price = + (pricePerUnit * amount * (1 + vatFactor) - discount) / + (1 + vatFactor); + + const vat = price * vatFactor; product.value.push({ id: c.product.id, code: c.product.code, detail: c.product.name, - priceUnit: precisionRound(priceNoVat), + priceUnit: precisionRound(pricePerUnit), amount: c.amount, discount: c.discount, - vat: c.product.serviceChargeCalcVat ? precisionRound(rawVat) : 0, + vat: c.product.serviceChargeCalcVat ? precisionRound(vat) : 0, value: precisionRound( - priceNoVat * c.amount + - (c.product.serviceChargeCalcVat ? rawVatTotal : 0), + pricePerUnit * c.amount + + (c.product.serviceChargeCalcVat ? vat : 0), ), }); - a.totalPrice = a.totalPrice + priceDiscountNoVat; - a.totalDiscount = a.totalDiscount + Number(c.discount); - a.vat = c.product.calcVat ? a.vat + rawVatTotal : a.vat; - a.vatExcluded = c.product.calcVat + a.totalPrice = precisionRound(a.totalPrice + price + discount); + a.totalDiscount = precisionRound(a.totalDiscount + discount); + a.vat = precisionRound(a.vat + vat); + a.vatExcluded = c.product.serviceChargeCalcVat ? a.vatExcluded - : precisionRound(a.vatExcluded + priceDiscountNoVat); - a.finalPrice = a.totalPrice - a.totalDiscount + a.vat; + : precisionRound(a.vatExcluded + price); + a.finalPrice = precisionRound(a.totalPrice - a.totalDiscount + a.vat); return a; }, { @@ -311,7 +315,7 @@ function closeAble() { border-bottom: 2px solid var(--main); " > - {{ $t('taskOrder.goodReceipt') }} + {{ $t('preview.productList') }} @@ -335,7 +339,9 @@ function closeAble() { {{ formatNumberDecimal(v.priceUnit, 2) }}
- {{ formatNumberDecimal(v.discount, 2) }} + {{ formatNumberDecimal(v.vat, 2) }} @@ -346,7 +352,6 @@ function closeAble() {
- {{ formatNumberDecimal( - summaryPrice.totalPrice - summaryPrice.totalDiscount, + summaryPrice.totalPrice - + summaryPrice.totalDiscount - + summaryPrice.vatExcluded, 2, ) }} diff --git a/src/pages/09_task-order/document_view/ViewHeader.vue b/src/pages/09_task-order/document_view/ViewHeader.vue index 0d1a89c3..9097cc89 100644 --- a/src/pages/09_task-order/document_view/ViewHeader.vue +++ b/src/pages/09_task-order/document_view/ViewHeader.vue @@ -64,8 +64,8 @@ defineProps<{ }) }} - เลขประจำตัวผู้เสียภาษี {{ branch.taxNo }} - เบอร์โทร {{ branch.telephoneNo }} + {{ $t('branch.form.taxNo') }} {{ branch.taxNo }} + {{ $t('taskOrder.telephone') }} {{ branch.telephoneNo }}{{ branch.webUrl }}
diff --git a/src/pages/09_task-order/expansion/AdditionalFileExpansion.vue b/src/pages/09_task-order/expansion/AdditionalFileExpansion.vue index b14ee28a..2d3ebdea 100644 --- a/src/pages/09_task-order/expansion/AdditionalFileExpansion.vue +++ b/src/pages/09_task-order/expansion/AdditionalFileExpansion.vue @@ -25,6 +25,7 @@ const fileData = defineModel<