Compare commits

..

No commits in common. "develop" and "version-0.11.42" have entirely different histories.

60 changed files with 394 additions and 1022 deletions

View file

@ -293,11 +293,15 @@ watch(
:readonly="readonly"
:label="$t('form.birthDate')"
:disabled-dates="disabledAfterToday"
:rules="[
(val: string) =>
!!val ||
$t('form.error.selectField', { field: $t('form.birthDate') }),
]"
:rules="
employee
? []
: [
(val: string) =>
!!val ||
$t('form.error.selectField', { field: $t('form.birthDate') }),
]
"
/>
<q-input

View file

@ -1,10 +1,9 @@
<script setup lang="ts">
import { CustomerBranch } from 'src/stores/customer';
import SelectCustomer from '../shared/select/SelectCustomer.vue';
import SelectBranch from '../shared/select/SelectBranch.vue';
import { CustomerBranch } from 'src/stores/customer';
import { ref } from 'vue';
const branchId = defineModel<string>('branchId');
const customerBranchId = defineModel<string>('customerBranchId');
const agentPrice = defineModel<boolean>('agentPrice');
@ -74,7 +73,6 @@ defineEmits<{
required
:readonly
/>
<SelectCustomer
id="about-select-customer-branch-id"
for="about-select-customer-branch-id"

View file

@ -1,6 +1,6 @@
<script lang="ts" setup>
import { QTableProps } from 'quasar';
import { dateFormat, dateFormatJS } from 'src/utils/datetime';
import { dateFormat } from 'src/utils/datetime';
import { formatNumberDecimal } from 'stores/utils';
@ -86,11 +86,11 @@ defineEmits<{
</q-td>
<q-td v-if="visibleColumns.includes('createdAt')">
{{ dateFormatJS({ date: props.row.createdAt }) }}
{{ dateFormat(props.row.createdAt) }}
</q-td>
<q-td v-if="visibleColumns.includes('dueDate')">
{{ dateFormatJS({ date: props.row.dueDate }) }}
{{ dateFormat(props.row.dueDate) }}
</q-td>
<q-td v-if="visibleColumns.includes('contactName')">

View file

@ -27,38 +27,26 @@ withDefaults(
class="app-text-muted q-pr-sm"
:width="iconSize || '2rem'"
/>
<span :id="`dd-wrapper-${label}`" class="row col">
<span
:id="`dd-label-${label}`"
class="col-12 app-text-muted-2"
style="font-size: 10px"
>
<span class="row col">
<span class="col-12 app-text-muted-2" style="font-size: 10px">
{{ label }}
</span>
<span :id="`dd-value-wrapper-${label}`" class="col-12 ellipsis">
<span class="col-12 ellipsis">
<slot name="value">
<span
:class="{ 'link cursor-pointer': clickable }"
v-if="typeof value === 'string'"
@click="clickable ? $emit('labelClick', value, null) : undefined"
:id="`link-${value}`"
:for="`link-${value}`"
>
{{ value }}
<q-tooltip v-if="tooltip" :delay="500">{{ value }}</q-tooltip>
</span>
<span
:id="`dd-value-${label}`"
v-else
:class="{ 'link cursor-pointer': clickable }"
>
<span v-else :class="{ 'link cursor-pointer': clickable }">
<span
v-for="(item, index) in value"
:key="index"
@click="$emit('labelClick', item, index)"
class="link cursor-pointer"
:id="`link-${item}`"
:for="`link-${item}`"
>
{{ item }}
<span v-if="index < value.length - 1">,&nbsp;</span>

View file

@ -96,9 +96,7 @@ defineEmits<{
expandedTree[expandedTree.length - 1] === node.id,
}"
>
{{
$i18n.locale === 'eng' ? node.nameEN || node.name : node.name
}}
{{ node.name }}
</span>
<span class="app-text-muted text-caption ellipsis">
{{ node.code }}

View file

@ -5,7 +5,6 @@ defineEmits<{
(e: 'click', v: MouseEvent): void;
}>();
defineProps<{
id?: string;
icon?: string;
color: string;
iconOnly?: boolean;
@ -19,7 +18,6 @@ defineProps<{
<template>
<button
:id="id"
@click="(e) => $emit('click', e)"
class="main-btn"
:class="{

View file

@ -10,7 +10,6 @@ defineProps<{
outlined?: boolean;
disabled?: boolean;
dark?: boolean;
color?: string;
label?: string;
icon?: string;
@ -24,7 +23,7 @@ defineProps<{
@click="(e) => $emit('click', e)"
v-bind="{ ...$props, ...$attrs }"
:icon="icon || 'mdi-content-save-outline'"
:color="color || '207 96% 32%'"
color="207 96% 32%"
:title="iconOnly ? $t('general.save') : undefined"
>
{{ label || $t('general.save') }}

View file

@ -13,7 +13,6 @@ let defaultFilter: (
const props = withDefaults(
defineProps<{
prefix?: string;
id?: string;
label?: string;
option: T[];
@ -72,7 +71,6 @@ watch(
</script>
<template>
<q-select
:id="id"
:placeholder="placeholder"
outlined
:clearable

View file

@ -75,9 +75,9 @@ function setDefaultValue() {
</script>
<template>
<SelectInput
for="select-hq-id"
v-model="value"
incremental
id="select-hq-id"
:label
:placeholder
:readonly

View file

@ -26,7 +26,6 @@ defineEmits<{
type ExclusiveProps = {
selectFirstValue?: boolean;
prefix?: string;
};
const props = defineProps<SelectProps<typeof getList> & ExclusiveProps>();
@ -72,7 +71,6 @@ function setDefaultValue() {
<SelectInput
v-model="value"
incremental
:id="`${prefix || 'nome'}-select-user`"
:label
:placeholder
:readonly

View file

@ -145,7 +145,6 @@ function selectedIndex(item: Employee) {
<template v-if="col.name === '#check'">
<q-checkbox
id="select-worker-all"
for="select-worker-all"
v-model="props.selected"
@update:model-value="(v) => handleUpdate()"
size="sm"
@ -201,7 +200,6 @@ function selectedIndex(item: Employee) {
v-model="props.selected"
size="sm"
:id="`select-worker-${props.row.firstName}`"
:for="`select-worker-${props.row.firstName}`"
/>
</template>
</q-td>

View file

@ -161,7 +161,6 @@ export default {
documentStatus: 'Document Status',
advanceSearch: 'Advance Search',
totalPeople: '{meg} people',
price: 'Price {price} Baht',
},
menu: {
@ -1234,9 +1233,6 @@ 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',
},
},

View file

@ -161,7 +161,6 @@ export default {
documentStatus: 'สถานะเอกสาร',
advanceSearch: 'ค้นหาขั้นสูง',
totalPeople: '{meg} คน',
price: 'ราคา {price} บาท',
},
menu: {
@ -1220,8 +1219,6 @@ export default {
'มีงานหนึ่งงานหรือมากกว่าที่ไม่อยู่ในสถานะรอดำเนินการ',
reqNotMet: 'ไม่ตรงกัน',
systemError: 'ระบบเกิดข้อผิดพลาด',
taskOrderInvalid: 'โปรดเลือก สินค้าเเละสาขา',
flowAccountProductIdNotFound: 'ไม่พบสินค้าใน flow account',
},
},

View file

@ -2,7 +2,7 @@
import { ref, onMounted, computed, reactive } from 'vue';
import { storeToRefs } from 'pinia';
import { useQuasar } from 'quasar';
import { getUserId, getUsername, getName, logout, getRole } from 'src/services/keycloak';
import { getUserId, getUsername, 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, locale } = useI18n({ useScope: 'global' });
const { t } = useI18n({ useScope: 'global' });
const userStore = useUserStore();
const canvasModal = ref(false);
@ -52,14 +52,8 @@ const unread = computed<number>(
);
const userImage = ref<string>();
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;
@ -167,14 +161,9 @@ onMounted(async () => {
if (user === 'admin') return;
if (uid) {
const res = await userStore.fetchById(uid);
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();
if (res && res.gender) {
userGender.value = res.gender;
userImage.value = `${baseUrl}/user/${uid}/profile-image/${res.selectedImage}`;
}
}
});
@ -495,7 +484,6 @@ onMounted(async () => {
<!-- User -->
<ProfileMenu
id="btn-profile-menu"
:user-name="displayName"
@logout="doLogout"
@edit-personal-info="console.log('edit')"
@signature="

View file

@ -12,7 +12,6 @@ const filterRole = ref<string[]>();
defineProps<{
userImage?: string;
gender?: string;
userName?: string;
}>();
const inputFile = document.createElement('input');
@ -148,9 +147,9 @@ onMounted(async () => {
class="text-weight-bold ellipsis"
style="max-width: 9vw"
>
{{ userName || getName() }}
{{ getName() }}
<q-tooltip>
{{ userName || getName() }}
{{ getName() }}
</q-tooltip>
</span>
<span
@ -235,12 +234,12 @@ onMounted(async () => {
style="margin-top: 58px"
>
<span v-if="isLoggedIn()">
{{ userName || getName() }}
{{ getName() }}
</span>
<span v-else>{{ 'Guest' }}</span>
<q-tooltip>
<span v-if="isLoggedIn()">
{{ userName || getName() }}
{{ getName() }}
</span>
<span v-else>{{ 'Guest' }}</span>
</q-tooltip>

View file

@ -541,8 +541,7 @@ onMounted(async () => {
<div class="col">
<div class="col">
{{
props.row.customerType === 'CORP' &&
locale === 'tha'
props.row.customerType === 'CORP'
? props.row.branch[0]?.registerName || '-'
: optionStore.mapOption(
props.row.branch[0].namePrefix,
@ -552,24 +551,10 @@ onMounted(async () => {
' ' +
props.row.branch[0]?.lastName || '-'
}}
{{
props.row.customerType === 'CORP' &&
locale === 'eng'
? props.row.branch[0]?.registerNameEN || '-'
: optionStore.mapOption(
props.row.branch[0].namePrefix,
) +
' ' +
props.row.branch[0]?.firstNameEN +
' ' +
props.row.branch[0]?.lastNameEN || '-'
}}
</div>
<div class="col app-text-muted">
{{
props.row.customerType === 'CORP' &&
locale === 'tha'
props.row.customerType === 'CORP'
? props.row.branch[0]?.registerNameEN || '-'
: capitalizeFirstLetter(
props.row.branch[0].namePrefix,
@ -579,19 +564,6 @@ onMounted(async () => {
' ' +
props.row.branch[0]?.lastNameEN || '-'
}}
{{
props.row.customerType === 'CORP' &&
locale === 'eng'
? props.row.branch[0]?.registerName || '-'
: capitalizeFirstLetter(
props.row.branch[0].namePrefix,
) +
' ' +
props.row.branch[0]?.firstName +
' ' +
props.row.branch[0]?.lastName || '-'
}}
</div>
</div>
</div>

View file

@ -102,8 +102,6 @@ const {
deleteWork,
importProduct,
productExport,
} = productServiceStore;
const { workNameItems } = storeToRefs(productServiceStore);
@ -1171,7 +1169,6 @@ function clearFormService() {
profileSubmit.value = false;
imageProduct.value = undefined;
profileFileImg.value = null;
serviceTab.value = 1;
}
function sameFormService() {
@ -1899,25 +1896,6 @@ 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) => {
@ -2251,6 +2229,7 @@ watch(
</AdvanceSearch>
</template>
</q-input>
<div class="row col-md-6" style="white-space: nowrap">
<q-select
v-show="$q.screen.gt.sm"
@ -2801,13 +2780,6 @@ watch(
}
"
/>
<SaveButton
icon-only
:icon="'material-symbols:download'"
color="var(--info-bg)"
@click.stop="triggerExport()"
/>
</div>
<div class="row col-md-6" style="white-space: nowrap">
@ -4385,7 +4357,6 @@ watch(
<!-- add service -->
<DialogForm
v-if="dialogService"
hide-footer
no-address
no-app-box
@ -4751,7 +4722,6 @@ watch(
<!-- edit service edit package-->
<!-- :edit="!(formDataProductService.status === 'INACTIVE')" -->
<DialogForm
v-if="dialogServiceEdit"
hide-footer
no-address
height="95vh"

View file

@ -1,5 +1,5 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, reactive, ref, watch, computed } from 'vue';
import { onMounted, reactive, ref, watch, computed } from 'vue';
import { storeToRefs } from 'pinia';
import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n';
@ -275,10 +275,6 @@ const customerNameInfo = computed(() => {
return name || '-';
});
function handleWindowFocus() {
fetchQuotationList();
}
onMounted(async () => {
pageState.gridView = $q.screen.lt.md ? true : false;
navigatorStore.current.title = 'quotation.title';
@ -316,12 +312,6 @@ onMounted(async () => {
}
flowStore.rotate();
window.addEventListener('focus', handleWindowFocus);
});
onUnmounted(() => {
window.removeEventListener('focus', handleWindowFocus);
});
async function fetchQuotationList(mobileFetch?: boolean) {
@ -777,13 +767,8 @@ async function filterBySellerId() {
:worker-count="item.row._count.worker"
:worker-max="item.row.workerMax || item.row._count.worker"
:customer-name="
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 || ''}`
item.row.customerBranch.registerName ||
`${item.row.customerBranch.firstName || '-'} ${item.row.customerBranch.lastName || ''}`
"
:reporter="
$i18n.locale === 'eng'

View file

@ -1,9 +1,16 @@
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue';
import { QFile, QMenu } from 'quasar';
import { baseUrl, dialog } from 'stores/utils';
import { storeToRefs } from 'pinia';
import { useConfigStore } from 'stores/config';
import { formatNumberDecimal } from 'stores/utils';
import { SaveButton, EditButton, UndoButton } from 'components/button';
import SelectInput from 'src/components/shared/SelectInput.vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
import { reactive, ref } from 'vue';
import { useQuotationPayment } from 'src/stores/quotations';
import {
PaymentPayload,
@ -12,25 +19,16 @@ import {
QuotationPaymentData,
} from 'src/stores/quotations/types';
import { dateFormatJS } from 'src/utils/datetime';
import { DebitNote } from 'src/stores/debit-note';
import { baseUrl, dialog, formatNumberDecimal } from 'stores/utils';
import { useConfigStore } from 'stores/config';
import useBranchStore from 'src/stores/branch';
import useOptionStore from 'src/stores/options';
import { QFile, QMenu } from 'quasar';
import UploadFileCard from 'src/components/upload-file/UploadFileCard.vue';
import SelectInput from 'src/components/shared/SelectInput.vue';
import { SaveButton, EditButton, UndoButton } from 'components/button';
import { onMounted } from 'vue';
import { DebitNote } from 'src/stores/debit-note';
const { t } = useI18n();
const { fetchListBankByBranch } = useBranchStore();
const { mapOption } = useOptionStore();
const configStore = useConfigStore();
const quotationPayment = useQuotationPayment();
const { data: config } = storeToRefs(configStore);
const prop = defineProps<{
branchId: string;
data?: Quotation | QuotationFull | DebitNote;
readonly?: boolean;
isDebitNote?: boolean;
@ -41,7 +39,6 @@ const firstCodePayment = defineModel<string>('firstCodePayment');
const refQFile = ref<InstanceType<typeof QFile>[]>([]);
const refQMenu = ref<InstanceType<typeof QMenu>[]>([]);
const paymentData = ref<QuotationPaymentData[]>([]);
const accountOpt = ref<{ label: string; value: string }[]>([]);
const formPaymentMethod = ref<
{
id: string;
@ -183,7 +180,7 @@ async function selectStatus(
payment.paymentStatus = status;
const payload = {
paymentStatus: payment.paymentStatus,
date: new Date(),
date: new Date(payment.date),
amount: payment.amount,
};
const res = await quotationPayment.updateQuotationPayment(
@ -218,7 +215,6 @@ async function triggerSubmit(id: string) {
formPaymentMethod.value[index].isEdit = false;
setTimeout(async () => {
await fetchData();
await getSlipList(paymentData.value[index], index);
}, 300);
}
@ -251,25 +247,8 @@ async function fetchData() {
}
}
async function fetchBankOption() {
const bankOption = await fetchListBankByBranch(prop.branchId);
accountOpt.value = bankOption
.map((b) => {
const name =
`${b.accountName} ${mapOption(b.bankName)} ${mapOption(b.accountType)} ${b.accountNumber}`.trim();
if (!name) return;
return {
label: name,
value: name,
};
})
.filter((i) => !!i);
}
onMounted(async () => {
await fetchData();
await fetchBankOption();
});
</script>
<template>
@ -661,115 +640,95 @@ onMounted(async () => {
</template>
<!-- การรบชำระ -->
<template v-if="payment.paymentStatus === 'PaymentSuccess'">
<section
class="q-px-md q-py-xs text-weight-medium row items-center"
style="background-color: hsla(var(--info-bg) / 0.1)"
>
{{ $t('quotation.receiptDialog.paymentMethod') }}
</section>
<q-form
class="column full-height"
@submit.prevent
@submit="triggerSubmit(payment.id)"
>
<div
class="surface-2 q-px-md q-py-sm row q-col-gutter-sm items-center"
>
<SelectInput
id="input-payment-channel"
for="input-payment-channel"
:readonly="
readonly ||
(!formPaymentMethod[i].isEdit && !!payment.channel)
"
v-model="formPaymentMethod[i].channel"
class="col-md-2 col-6"
:rules="[
(val: string) => !!val || $t('form.error.required'),
]"
:option="[
{
label: $t('creditNote.label.Cash'),
value: 'Cash',
},
{
label: $t('creditNote.label.BankTransfer'),
value: 'BankTransfer',
},
]"
:label="$t('quotation.receiptDialog.paymentMethod')"
@update:model-value="
() => {
if (formPaymentMethod[i].channel === 'Cash') {
formPaymentMethod[i].reference = null;
formPaymentMethod[i].account = null;
}
}
"
/>
<q-input
v-if="formPaymentMethod[i].channel === 'BankTransfer'"
dense
outlined
class="col-md-3 col-6"
v-model="formPaymentMethod[i].reference"
:readonly="
readonly ||
(!formPaymentMethod[i].isEdit && !!payment.channel)
"
:label="$t('quotation.refNo')"
:rules="[
(val: string) => !!val || $t('form.error.required'),
]"
hide-bottom-space
/>
<SelectInput
v-if="formPaymentMethod[i].channel === 'BankTransfer'"
id="select-payment-account"
for="select-payment-account"
:readonly="
readonly ||
(!formPaymentMethod[i].isEdit && !!payment.channel)
"
v-model="formPaymentMethod[i].account"
class="col"
:option="accountOpt"
:label="$t('quotation.bankAccount')"
:rules="[
(val: string) => !!val || $t('form.error.required'),
]"
/>
<div class="q-ml-auto">
<UndoButton
v-if="formPaymentMethod[i].isEdit"
icon-only
@click="
() => {
formPaymentMethod[i].isEdit = false;
formPaymentMethod[i].channel = payment.channel;
formPaymentMethod[i].reference = payment.reference;
formPaymentMethod[i].account = payment.account;
}
"
/>
<SaveButton
v-if="!payment.channel || formPaymentMethod[i].isEdit"
icon-only
type="submit"
/>
<EditButton
v-if="
payment.channel && formPaymentMethod[i].isEdit === false
"
icon-only
@click="formPaymentMethod[i].isEdit = true"
/>
</div>
</div>
</q-form>
</template>
<section
class="q-px-md q-py-xs text-weight-medium row items-center"
style="background-color: hsla(var(--info-bg) / 0.1)"
>
{{ $t('quotation.receiptDialog.paymentMethod') }}
</section>
<div
class="surface-2 q-px-md q-py-sm row q-col-gutter-sm items-center"
>
<SelectInput
id="input-payment-channel"
for="input-payment-channel"
:readonly="
readonly ||
(!formPaymentMethod[i].isEdit && !!payment.channel)
"
v-model="formPaymentMethod[i].channel"
class="col-md-2 col-6"
:option="[
{
label: $t('creditNote.label.Cash'),
value: 'Cash',
},
{
label: $t('creditNote.label.BankTransfer'),
value: 'BankTransfer',
},
]"
:label="$t('quotation.receiptDialog.paymentMethod')"
@update:model-value="
() => {
if (formPaymentMethod[i].channel === 'Cash') {
formPaymentMethod[i].reference = null;
formPaymentMethod[i].account = null;
}
}
"
/>
<q-input
v-if="formPaymentMethod[i].channel === 'BankTransfer'"
dense
outlined
class="col-md-3 col-6"
v-model="formPaymentMethod[i].reference"
:readonly="
readonly ||
(!formPaymentMethod[i].isEdit && !!payment.channel)
"
:label="$t('quotation.refNo')"
/>
<q-input
v-if="formPaymentMethod[i].channel === 'BankTransfer'"
dense
outlined
class="col"
v-model="formPaymentMethod[i].account"
:readonly="
readonly ||
(!formPaymentMethod[i].isEdit && !!payment.channel)
"
:label="$t('quotation.bankAccount')"
/>
<div class="q-ml-auto">
<UndoButton
v-if="formPaymentMethod[i].isEdit"
icon-only
@click="
() => {
formPaymentMethod[i].isEdit = false;
formPaymentMethod[i].channel = payment.channel;
formPaymentMethod[i].reference = payment.reference;
formPaymentMethod[i].account = payment.account;
}
"
/>
<SaveButton
v-if="!payment.channel || formPaymentMethod[i].isEdit"
icon-only
@click="triggerSubmit(payment.id)"
/>
<EditButton
v-if="
payment.channel && formPaymentMethod[i].isEdit === false
"
icon-only
@click="formPaymentMethod[i].isEdit = true"
/>
</div>
</div>
<!-- ปโหลดใบเสร -->
<section

View file

@ -96,8 +96,6 @@ type ProductGroupId = string;
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
const customerBranchOption = ref<CustomerBranch>();
const employeeStore = useEmployeeStore();
const route = useRoute();
const useReceiptStore = useReceipt();
@ -115,6 +113,8 @@ const $q = useQuasar();
const openQuotation = ref<boolean>(false);
const formMetadata = ref();
const customerBranchOption = ref<CustomerBranch>();
const rowsRequestList = ref<RequestData[]>([]);
const {
@ -161,7 +161,49 @@ const selectedWorker = ref<
}[];
})[]
>([]);
const selectedWorkerItem = ref([]);
const selectedWorkerItem = computed(() => {
return [
...selectedWorker.value.map((e) => ({
foreignRefNo: e.employeePassport
? e.employeePassport[0]?.number || '-'
: '-',
employeeName:
locale.value === Lang.English
? `${e.firstNameEN} ${e.lastNameEN}`
: e.firstName
? `${e.firstName} ${e.lastName}`
: `${e.firstNameEN} ${e.lastNameEN}`,
birthDate: dateFormatJS({ date: e.dateOfBirth }),
gender: e.gender,
age: calculateAge(e.dateOfBirth),
nationality: optionStore.mapOption(e.nationality),
documentExpireDate:
e.employeePassport !== undefined &&
e.employeePassport[0]?.expireDate !== undefined
? dateFormatJS({ date: e.employeePassport[0]?.expireDate })
: '-',
imgUrl: e.selectedImage
? `${API_BASE_URL}/employee/${e.id}/image/${e.selectedImage}`
: '',
status: e.status,
})),
...newWorkerList.value.map((v: any) => ({
foreignRefNo: v.passportNo,
employeeName:
locale.value === Lang.English
? `${v.firstNameEN} ${v.lastNameEN}`
: `${v.firstName} ${v.lastName}`,
birthDate: dateFormatJS({ date: v.dateOfBirth }),
gender: v.gender,
age: calculateAge(v.dateOfBirth),
nationality: optionStore.mapOption(v.nationality),
documentExpireDate: '-',
imgUrl: '',
status: 'CREATED',
})),
];
});
const firstCodePayment = ref('');
const selectedProductGroup = ref('');
const selectedInstallmentNo = ref<number[]>([]);
@ -196,7 +238,7 @@ function getPrice(
) {
if (filterHook) list = list.filter(filterHook);
const value = list.reduce(
return list.reduce(
(a, c) => {
if (
selectedInstallmentNo.value.length > 0 &&
@ -236,8 +278,6 @@ function getPrice(
finalPrice: 0,
},
);
return value;
}
const summaryPrice = computed(() => getPrice(productServiceList.value));
@ -516,7 +556,7 @@ async function convertDataToFormSubmit() {
),
);
selectedWorkerItem.value.forEach((v, i) => {
selectedWorker.value.forEach((v, i) => {
if (v.attachment !== undefined) {
v.attachment.forEach((value) => {
fileItemNewWorker.value.push({
@ -533,7 +573,7 @@ async function convertDataToFormSubmit() {
quotationFormData.value.worker = JSON.parse(
JSON.stringify([
...selectedWorkerItem.value.map((v) => {
...selectedWorker.value.map((v) => {
{
return v.id;
}
@ -766,40 +806,7 @@ function toggleDeleteProduct(index: number) {
}
async function assignWorkerToSelectedWorker() {
selectedWorkerItem.value = quotationFormData.value.worker.map((e) => {
return {
id: e.id,
foreignRefNo: e.employeePassport
? e.employeePassport[0]?.number || '-'
: '-',
employeeName:
locale.value === Lang.English
? `${e.firstNameEN} ${e.lastNameEN}`
: `${e.firstName || e.firstNameEN} ${e.lastName || e.lastNameEN}`,
birthDate: dateFormatJS({ date: e.dateOfBirth }),
gender: e.gender,
age: calculateAge(e.dateOfBirth),
nationality: optionStore.mapOption(e.nationality),
documentExpireDate:
e.employeePassport !== undefined &&
e.employeePassport[0]?.expireDate !== undefined
? dateFormatJS({ date: e.employeePassport[0]?.expireDate })
: '-',
imgUrl: e.selectedImage
? `${API_BASE_URL}/employee/${e.id}/image/${e.selectedImage}`
: '',
employeePassport: e.employeePassport,
status: e.status,
workerNew: false,
lastNameEN: e.lastNameEN,
lastName: e.lastName,
middleNameEN: e.middleNameEN,
middleName: e.middleName,
firstNameEN: e.firstNameEN,
firstName: e.firstName,
namePrefix: e.namePrefix,
};
});
selectedWorker.value = quotationFormData.value.worker;
}
function convertToTable(nodes: Node[]) {
@ -858,21 +865,21 @@ function convertToTable(nodes: Node[]) {
function convertEmployeeToTable(selected: Employee[]) {
productServiceList.value.forEach((v) => {
if (selectedWorkerItem.value.length === 0 && v.amount === 1) v.amount -= 1;
if (selectedWorker.value.length === 0 && v.amount === 1) v.amount -= 1;
v.amount = Math.max(
v.amount + selected.length - selectedWorkerItem.value.length,
v.amount + selected.length - selectedWorker.value.length,
1,
);
const oldWorkerId: string[] = [];
const newWorkerIndex: number[] = [];
selectedWorkerItem.value.forEach((item, i) => {
selectedWorker.value.forEach((item, i) => {
if (v.workerIndex.includes(i)) oldWorkerId.push(item.id);
});
selected.forEach((item, i) => {
if (selectedWorkerItem.value.find((n) => item.id === n.id)) return;
if (selectedWorker.value.find((n) => item.id === n.id)) return;
newWorkerIndex.push(i);
});
@ -885,7 +892,7 @@ function convertEmployeeToTable(selected: Employee[]) {
pageState.employeeModal = false;
quotationFormData.value.workerMax = Math.max(
quotationFormData.value.workerMax || 1,
selectedWorkerItem.value.length,
selectedWorker.value.length,
);
}
@ -958,71 +965,6 @@ function viewProductFile(data: ProductRelation) {
pageState.imageDialogUrl = base64 ? base64[1] : '';
}
function combineWorker(newWorker: any, oldWorker: any) {
selectedWorkerItem.value = [
...oldWorker.map((e) => ({
id: e.id,
foreignRefNo: e.employeePassport
? e.employeePassport[0]?.number || '-'
: '-',
employeeName:
locale.value === Lang.English
? `${e.firstNameEN} ${e.lastNameEN}`
: `${e.firstName || e.firstNameEN} ${e.lastName || e.lastNameEN}`,
birthDate: dateFormatJS({ date: e.dateOfBirth }),
gender: e.gender,
age: calculateAge(e.dateOfBirth),
nationality: optionStore.mapOption(e.nationality),
documentExpireDate:
e.employeePassport !== undefined &&
e.employeePassport[0]?.expireDate !== undefined
? dateFormatJS({ date: e.employeePassport[0]?.expireDate })
: '-',
imgUrl: e.selectedImage
? `${API_BASE_URL}/employee/${e.id}/image/${e.selectedImage}`
: '',
employeePassport: e.employeePassport,
status: e.status,
workerNew: false,
lastNameEN: e.lastNameEN,
lastName: e.lastName,
middleNameEN: e.middleNameEN,
middleName: e.middleName,
firstNameEN: e.firstNameEN,
firstName: e.firstName,
namePrefix: e.namePrefix,
})),
...newWorker.map((v: any) => ({
id: v.id,
foreignRefNo: v.passportNo || '-',
employeeName:
locale.value === Lang.English
? `${v.firstNameEN} ${v.lastNameEN}`
: `${v.firstName || v.firstNameEN} ${v.lastName || v.lastNameEN}`,
birthDate: dateFormatJS({ date: v.dateOfBirth }),
gender: v.gender,
age: calculateAge(v.dateOfBirth),
nationality: optionStore.mapOption(v.nationality),
documentExpireDate: '-',
imgUrl: '',
status: 'CREATED',
lastNameEN: v.lastNameEN,
lastName: v.lastName,
middleNameEN: v.middleNameEN,
middleName: v.middleName,
firstNameEN: v.firstNameEN,
firstName: v.firstName,
namePrefix: v.namePrefix,
dateOfBirth: v.dateOfBirth,
workerNew: true,
})),
];
}
const sessionData = ref<Record<string, any>>();
onMounted(async () => {
@ -1094,7 +1036,7 @@ watch(
() => quotationFormData.value.customerBranchId,
async (v) => {
if (!v) return;
selectedWorkerItem.value = [];
selectedWorker.value = [];
},
);
@ -1110,15 +1052,6 @@ watch(
const productServiceNodes = ref<ProductTree>([]);
watch(customerBranchOption, () => {
if (!customerBranchOption.value) return;
quotationFormData.value.contactName =
customerBranchOption.value.contactName || '';
quotationFormData.value.contactTel =
customerBranchOption.value.contactTel || '';
});
watch(
() => productServiceList.value,
() => {
@ -1154,19 +1087,7 @@ watch(customerBranchOption, () => {
// }
function storeDataLocal() {
const tempProductService = productService.value.map((v) => {
return {
...v,
vat: v.product[agentPrice ? 'agentPriceCalcVat' : 'calcVat']
? precisionRound(
((v.pricePerUnit * (1 + (config?.value.vat || 0.07)) * v.amount -
v.discount) /
(1 + (config?.value.vat || 0.07))) *
0.07,
)
: 0,
};
});
quotationFormData.value.productServiceList = productService.value;
localStorage.setItem(
'quotation-preview',
@ -1175,7 +1096,7 @@ function storeDataLocal() {
codeInvoice: code.value,
codePayment: firstCodePayment.value,
...quotationFormData.value,
productServiceList: tempProductService,
productServiceList: productService.value,
},
meta: {
source: {
@ -1195,7 +1116,7 @@ function storeDataLocal() {
workName: quotationFormData.value.workName,
dueDate: quotationFormData.value.dueDate,
},
selectedWorker: selectedWorkerItem.value,
selectedWorker: selectedWorker.value,
createdBy: quotationFormState.value.createdBy('tha'),
agentPrice: agentPrice.value,
},
@ -1280,10 +1201,10 @@ async function getWorkerFromCriteria(
if (!ret) return false; // error, do not close dialog
const deduplicate = ret.result.filter(
(a) => !selectedWorkerItem.value.find((b) => a.id === b.id),
(a) => !selectedWorker.value.find((b) => a.id === b.id),
);
convertEmployeeToTable([...deduplicate, ...selectedWorkerItem.value]);
convertEmployeeToTable([...deduplicate, ...selectedWorker.value]);
return true;
}
@ -1673,15 +1594,15 @@ function covertToNode() {
(v) =>
(quotationFormData.workerMax = Math.max(
v,
selectedWorkerItem.length,
selectedWorker.length,
))
"
:employee-amount="
quotationFormData.workerMax || selectedWorkerItem.length
quotationFormData.workerMax || selectedWorker.length
"
:readonly="readonly"
:rows="selectedWorkerItem"
@delete="(i) => deleteItem(selectedWorkerItem, i)"
@delete="(i) => deleteItem(selectedWorker, i)"
/>
</div>
</q-expansion-item>
@ -1925,7 +1846,7 @@ function covertToNode() {
installments: quotationFormData.paySplit,
},
'quotation-labor': {
name: selectedWorkerItem.map(
name: selectedWorker.map(
(v, i) =>
`${i + 1}. ` +
`${v.employeePassport.length !== 0 ? v.employeePassport[0].number + '_' : ''}${v.namePrefix}.${v.firstNameEN ? `${v.firstNameEN} ${v.lastNameEN}` : `${v.firstName} ${v.lastName}`} `.toUpperCase(),
@ -2018,7 +1939,6 @@ function covertToNode() {
view !== View.Receipt &&
view !== View.Complete
"
:branch-id="quotationFull.registeredBranchId"
:readonly="
isRoleInclude(['sale', 'head_of_sale']) ||
!canAccess('quotation', 'edit')
@ -2469,12 +2389,13 @@ function covertToNode() {
<!-- add employee quotation -->
<QuotationFormWorkerSelect
:preselect-worker="selectedWorkerItem"
:preselect-worker="selectedWorker"
:customerBranchId="quotationFormData.customerBranchId"
v-model:open="pageState.employeeModal"
v-model:new-worker-list="newWorkerList"
@success="
(v) => {
combineWorker(v.newWorker, v.worker);
selectedWorker = v.worker;
}
"
/>
@ -2517,7 +2438,7 @@ function covertToNode() {
<!-- add Worker -->
<QuotationFormWorkerAddDialog
v-if="quotationFormState.source"
:disabled-worker-id="selectedWorkerItem.map((v) => v.id)"
:disabled-worker-id="selectedWorker.map((v) => v.id)"
:product-service-list="quotationFormState.source.productServiceList"
:quotation-id="quotationFormState.source.id"
:customer-branch-id="quotationFormState.source.customerBranchId"

View file

@ -234,7 +234,6 @@ watch(
<section class="row q-col-gutter-sm col-12 items-center">
<SelectInput
class="col-md-6 col-12"
id="select-pay-type"
:label="$t('quotation.payType')"
:option="
taskOrder
@ -242,6 +241,7 @@ watch(
: payTypeOption
"
:readonly="readonly || debitNote"
id="pay-type"
:model-value="payType"
@update:model-value="
(v) => {
@ -275,7 +275,6 @@ watch(
</div>
<q-input
v-model="paySplitCount"
id="input-pay-split-count"
:readonly="readonly || payType === 'Split'"
class="col-3"
type="number"
@ -312,7 +311,6 @@ watch(
<q-input
:readonly="readonly"
:label="$t('general.name')"
:id="`input-period-name-${i}`"
v-if="payType === 'SplitCustom'"
v-model="period.name"
class="col q-mx-sm"
@ -322,7 +320,6 @@ watch(
<q-input
:readonly="readonly || payType === 'Split'"
class="col q-mx-sm"
:id="`input-period-amount-${i}`"
:label="$t('quotation.amount')"
:model-value="
amount4Show[i] || commaInput(period.amount.toString())
@ -380,7 +377,6 @@ watch(
<DatePicker
v-if="payType === 'BillFull'"
id="datepicker-bill-date"
:readonly
class="col-12"
:label="$t('quotation.callDueDate')"
@ -488,11 +484,7 @@ watch(
<div class="q-pa-sm row surface-2 items-center text-weight-bold">
{{ $t('quotation.totalPriceBaht') }}
<span
class="q-ml-auto"
style="color: var(--brand-1)"
id="value-final-price"
>
<span class="q-ml-auto" style="color: var(--brand-1)">
{{
payType === 'SplitCustom' && view === View.Invoice
? formatNumberDecimal(Math.max(installmentAmount || 0, 0), 2) || 0

View file

@ -341,13 +341,12 @@ watch(() => state.search, getWorkerList);
>
<div
style="display: inline-block; margin-inline: auto"
v-if="workerList.length === 0 && state.search"
v-if="workerList.length === 0"
>
<NoData :not-found="!!state.search" />
</div>
<TableWorker
v-else
v-model:selected="workerSelected"
:rows="workerList"
:disabledWorkerId

View file

@ -113,7 +113,7 @@ const props = withDefaults(
defineProps<{
customerBranchId?: string;
disabledWorkerId?: string[];
preselectWorker?: (Employee & { workerNew: boolean })[];
preselectWorker?: Employee[];
}>(),
{},
);
@ -133,7 +133,7 @@ const optionStore = useOptionStore();
const employeeStore = useEmployeeStore();
const open = defineModel<boolean>('open', { default: false });
const newWorkerList = ref<
const newWorkerList = defineModel<
(EmployeeWorker & {
attachment?: {
name?: string;
@ -143,7 +143,7 @@ const newWorkerList = ref<
_meta?: Record<string, any>;
}[];
})[]
>([]);
>('newWorkerList', { default: [] });
const workerSelected = ref<Employee[]>([]);
const workerList = ref<Employee[]>([]);
const importWorkerCriteria = ref<{
@ -208,13 +208,7 @@ function getEmployeeImageUrl(item: Employee) {
function init() {
if (props.preselectWorker) {
workerSelected.value = JSON.parse(
JSON.stringify(props.preselectWorker.filter((v) => !v.workerNew)),
);
newWorkerList.value = JSON.parse(
JSON.stringify(props.preselectWorker.filter((v) => v.workerNew)),
);
workerSelected.value = JSON.parse(JSON.stringify(props.preselectWorker));
}
getWorkerList();
}
@ -614,14 +608,11 @@ watch(
solid
id="btn-success"
@click="
() => {
$emit('success', {
worker: workerSelected,
newWorker: newWorkerList,
});
open = false;
}
(emits('success', {
worker: workerSelected,
newWorker: newWorkerList,
}),
(open = false))
"
>
{{ $t('general.select', { msg: $t('quotation.employeeList') }) }}
@ -643,11 +634,9 @@ watch(
if (employeeFormState.currentTab === 'personalInfo') {
const currentEmployeeId =
await employeeFormStore.submitPersonal(onCreateImageList);
newWorkerList.push(
quotationForm.injectNewEmployee({
data: { ...currentFromDataEmployee, id: currentEmployeeId },
}),
);
quotationForm.injectNewEmployee({
data: { ...currentFromDataEmployee, id: currentEmployeeId },
});
employeeFormState.isEmployeeEdit = false;
employeeFormState.dialogType = 'info';
}

View file

@ -69,7 +69,6 @@ export const useQuotationForm = defineStore('form-quotation', () => {
file?: File;
_meta?: Record<string, any>;
}[];
workerNew: boolean;
})[]
>([]);
@ -221,7 +220,7 @@ export const useQuotationForm = defineStore('form-quotation', () => {
},
callback?: () => void,
) {
const temp = {
newWorkerList.value.push({
//passportNo: obj.data.passportNo,
//documentExpireDate: obj.data.documentExpireDate,
id: obj.data.id,
@ -236,12 +235,9 @@ export const useQuotationForm = defineStore('form-quotation', () => {
gender: obj.data.gender,
dateOfBirth: obj.data.dateOfBirth,
attachment: obj.data.attachment,
workerNew: true,
};
});
callback?.();
return temp;
}
function dialogDelete(callback: () => void) {

View file

@ -61,7 +61,6 @@ const props = withDefaults(
readonly?: boolean;
listDocument: string[];
currentId: { customer: string; employee: string };
prefix?: string;
}>(),
{
listDocument: () => [],
@ -245,14 +244,14 @@ function changeCustomerTab(opts: { tab: 'customer' | 'employee' }) {
<nav class="q-ml-auto row" v-if="!readonly">
<CancelButton
v-if="state.isEdit"
:id="`btn-docs-${props.prefix || 'nome'}-info-basic-undo`"
id="btn-info-basic-undo"
icon-only
type="button"
@click.stop="triggerCancel"
/>
<EditButton
v-if="!state.isEdit"
:id="`btn-docs-${props.prefix || 'nome'}-info-basic-edit`"
id="btn-info-basic-edit"
icon-only
@click.stop="triggerEdit"
type="button"

View file

@ -11,7 +11,6 @@ import { useRequestList } from 'src/stores/request-list';
const props = defineProps<{
readonly?: boolean;
step: Step;
prefix?: string;
}>();
const requestListStore = useRequestList();
@ -101,21 +100,21 @@ function assignToForm() {
<nav class="q-ml-auto row" v-if="!readonly">
<UndoButton
v-if="state.isEdit"
:id="`btn-duty-${props.prefix || 'nome'}-info-basic-undo`"
id="btn-info-basic-undo"
icon-only
type="button"
@click.stop="triggerUndo"
/>
<SaveButton
v-if="state.isEdit"
:id="`btn-duty-${props.prefix || 'nome'}-info-basic-save`"
id="btn-info-basic-save"
icon-only
type="submit"
@click.stop="triggerSubmit"
/>
<EditButton
v-if="!state.isEdit"
:id="`btn-duty-${props.prefix || 'nome'}-info-basic-edit`"
id="btn-info-basic-edit"
icon-only
@click.stop="triggerEdit"
type="button"

View file

@ -12,7 +12,6 @@ const props = defineProps<{
readonly?: boolean;
step: Step;
requestWorkId: string;
prefix?: string;
}>();
const requestListStore = useRequestList();
@ -91,21 +90,21 @@ function assignToForm() {
<nav class="q-ml-auto row" v-if="!readonly">
<UndoButton
v-if="state.isEdit"
:id="`btn-form-${props.prefix || 'nome'}-info-basic-undo`"
id="btn-info-basic-undo"
icon-only
type="button"
@click.stop="triggerUndo"
/>
<SaveButton
v-if="state.isEdit"
:id="`btn-form-${props.prefix || 'nome'}-info-basic-save`"
id="btn-info-basic-save"
icon-only
type="submit"
@click.stop="triggerSubmit"
/>
<EditButton
v-if="!state.isEdit"
:id="`btn-form-${props.prefix || 'nome'}-info-basic-edit`"
id="btn-info-basic-edit"
icon-only
@click.stop="triggerEdit"
type="button"

View file

@ -12,7 +12,6 @@ const responsibleUserId = defineModel<string>('responsibleUserId', {
defineProps<{
readonly?: boolean;
districtId?: string;
prefix?: string;
}>();
watch(responsibleUserLocal, (lhs, rhs) => {
@ -28,8 +27,6 @@ watch(responsibleUserLocal, (lhs, rhs) => {
:label="$t('requestList.localEmployee')"
:disable="readonly"
class="col"
:id="`${prefix || 'nome'}-radio-local-employee`"
:for="`${prefix || 'nome'}-radio-local-employee`"
/>
<q-radio
v-model="responsibleUserLocal"
@ -37,8 +34,6 @@ watch(responsibleUserLocal, (lhs, rhs) => {
:label="$t('requestList.nonLocalEmployee')"
:disable="readonly"
class="col"
:id="`${prefix || 'nome'}-radio-non-local-employee`"
:for="`${prefix || 'nome'}-radio-non-local-employee`"
/>
<div class="col" />
<div class="offset-md-7"></div>
@ -57,8 +52,6 @@ watch(responsibleUserLocal, (lhs, rhs) => {
}"
:readonly
:label="$t('general.select', { msg: $t('personnel.MESSENGER') })"
:id="`${prefix || 'nome'}-select-user`"
:for="`${prefix || 'nome'}-select-user`"
/>
</div>
</div>

View file

@ -95,7 +95,6 @@ function triggerCancel(id: string) {
const res = await requestListStore.cancelRequest(id);
if (res) {
fetchList();
fetchStats();
}
},
});

View file

@ -14,7 +14,6 @@ const props = defineProps<{
step: Step;
responsibleAreaDistrictId?: string;
defaultMessenger?: string;
prefix?: string;
}>();
const emit = defineEmits<{
@ -117,21 +116,21 @@ function assignToForm() {
<nav class="q-ml-auto row" v-if="!readonly">
<UndoButton
v-if="state.isEdit"
:id="`btn-messenger-${props.prefix || 'nome'}-info-basic-undo`"
id="btn-info-basic-undo"
icon-only
type="button"
@click.stop="triggerUndo"
/>
<SaveButton
v-if="state.isEdit"
:id="`btn-messenger-${props.prefix || 'nome'}-info-basic-save`"
id="btn-info-basic-save"
icon-only
type="submit"
@click.stop="(e) => refForm?.submit(e)"
/>
<EditButton
v-if="!state.isEdit"
:id="`btn-messenger-${props.prefix || 'nome'}-info-basic-edit`"
id="btn-info-basic-edit"
icon-only
@click.stop="triggerEdit"
type="button"
@ -158,7 +157,6 @@ function assignToForm() {
v-model:responsible-user-local="formData.responsibleUserLocal"
v-model:responsible-user-id="formData.responsibleUserId"
:district-id="responsibleAreaDistrictId"
:prefix
/>
</q-form>
</section>

View file

@ -83,8 +83,6 @@ function changeableStatus(currentStatus?: RequestWorkStatus) {
</script>
<template>
<q-expansion-item
:id="`expansion-${product?.name || name}`"
:for="`expansion-${product?.name || name}`"
dense
:class="{ 'status-unpaid': !paySuccess }"
class="overflow-hidden"
@ -148,8 +146,6 @@ function changeableStatus(currentStatus?: RequestWorkStatus) {
<div class="q-ml-auto q-gutter-y-xs">
<div class="justify-end flex">
<q-btn-dropdown
:id="`btn-dropdown-${product?.name || name}`"
:for="`btn-dropdown-${product?.name || name}`"
:disable="
readonly || changeableStatus(status?.workStatus).length === 0
"
@ -201,8 +197,6 @@ function changeableStatus(currentStatus?: RequestWorkStatus) {
<q-list dense>
<q-item
v-for="(value, index) in changeableStatus(status?.workStatus)"
:id="`btn-dropdown-${product?.name || name}-${value}`"
:for="`btn-dropdown-${product?.name || name}-${value}`"
:key="index"
clickable
v-close-popup
@ -277,15 +271,15 @@ function changeableStatus(currentStatus?: RequestWorkStatus) {
}
:deep(
i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-item__toggle-icon--rotated
) {
i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-item__toggle-icon--rotated
) {
color: var(--brand-1);
}
:deep(
.q-item.q-item-type.row.no-wrap.q-item--dense.q-item--clickable.q-link.cursor-pointer.q-focusable.q-hoverable.surface-1
.q-focus-helper
) {
.q-item.q-item-type.row.no-wrap.q-item--dense.q-item--clickable.q-link.cursor-pointer.q-focusable.q-hoverable.surface-1
.q-focus-helper
) {
visibility: hidden;
}

View file

@ -28,7 +28,6 @@ const props = withDefaults(
readonly?: boolean;
propertiesToShow: (PropString | PropNumber | PropDate | PropOptions)[];
requestListData: RequestData;
prefix?: string;
}>(),
{
id: '',
@ -129,7 +128,7 @@ defineEmits<{
<nav class="q-ml-auto row" v-if="!readonly">
<UndoButton
v-if="state.isEdit"
:id="`btn-properties-${props.prefix || 'nome'}-info-basic-undo`"
id="btn-info-basic-undo"
icon-only
type="button"
@click.stop="triggerUndo"
@ -137,14 +136,13 @@ defineEmits<{
<SaveButton
v-if="state.isEdit"
id="btn-info-basic-save"
:id="`btn-properties-${props.prefix || 'nome'}-info-basic-save`"
icon-only
type="submit"
@click.stop="triggerSubmit"
/>
<EditButton
v-if="!state.isEdit"
:id="`btn-properties-${props.prefix || 'nome'}-info-basic-edit`"
id="btn-info-basic-edit"
icon-only
@click.stop="triggerEdit"
type="button"

View file

@ -881,7 +881,6 @@ function toEmployee(employee: RequestData['employee']) {
:readonly="value._readonly"
ref="refDocumentExpansion"
:attributes="value.attributes"
:prefix="value.productService.product.name"
@change-status="
(opt) => {
triggerChangeStatusFile({
@ -929,7 +928,6 @@ function toEmployee(employee: RequestData['employee']) {
<MessengerExpansion
v-if="value._messengerExpansion"
:readonly="value._readonly"
:prefix="value.productService.product.name"
:default-messenger="
value.stepStatus[pageState.currentStep - 1]
? undefined
@ -955,7 +953,6 @@ function toEmployee(employee: RequestData['employee']) {
<DutyExpansion
v-if="value._dutyExpansion"
:readonly="value._readonly"
:prefix="value.productService.product.name"
:step="{
step: pageState.currentStep,
requestWorkId: value.id || '',
@ -969,7 +966,6 @@ function toEmployee(employee: RequestData['employee']) {
v-if="value._formExpansion"
:request-work-id="value.id"
:readonly="value._readonly"
:prefix="value.productService.product.name"
:step="{
step: pageState.currentStep,
requestWorkId: value.id || '',
@ -983,7 +979,6 @@ function toEmployee(employee: RequestData['employee']) {
:request-list-data="data"
:id="value.id"
:readonly="value._readonly"
:prefix="value.productService.product.name"
:properties-to-show="
value.productService.work?.attributes.workflowStep[
pageState.currentStep - 1

View file

@ -190,8 +190,6 @@ function handleCheckAll() {
>
<q-th v-if="checkable">
<q-checkbox
:for="`list-checkbox-all`"
:id="`list-checkbox-all`"
v-if="selected.length > 0"
:model-value="
selected.length ===
@ -231,8 +229,6 @@ function handleCheckAll() {
>
<q-td v-if="checkable">
<q-checkbox
:for="`list-checkbox-${props.rowIndex + 1}`"
:id="`list-checkbox-${props.rowIndex + 1}`"
:disable="
selected.length > 0 &&
!listSameArea.includes(

View file

@ -1,6 +1,6 @@
<script lang="ts" setup>
// NOTE: Library
import { computed, onMounted, onUnmounted, reactive, watch, ref } from 'vue';
import { computed, onMounted, reactive, watch, ref } from 'vue';
import { storeToRefs } from 'pinia';
import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n';
@ -86,7 +86,6 @@ async function fetchTaskOrderList(opts?: { page?: number; pageSize?: number }) {
});
}
if (res) {
taskOrderStore.getTaskOrderStats();
data.value = res.result;
pageState.total = res.total;
pageMax.value = Math.ceil(res.total / pageSize.value);
@ -147,10 +146,6 @@ async function deleteTaskOrder(id: string) {
});
}
function handleWindowFocus() {
fetchTaskOrderList();
}
onMounted(async () => {
pageState.gridView = $q.screen.lt.md ? true : false;
navigatorStore.current.title = 'taskOrder.title';
@ -161,12 +156,6 @@ onMounted(async () => {
if (route.query['tab'] && typeof route.query['tab'] === 'string') {
pageState.currentTab = route.query['tab'];
}
window.addEventListener('focus', handleWindowFocus);
});
onUnmounted(() => {
window.removeEventListener('focus', handleWindowFocus);
});
watch(
@ -229,11 +218,7 @@ watch(
color: hsl(var(--info-bg));
"
>
{{
pageState.isMessenger
? pageState.total
: stats[pageState.currentTab as TaskOrderStatus]
}}
{{ Object.values(stats).reduce((s, v) => s + v, 0) }}
</q-badge>
<q-btn
class="q-ml-sm"

View file

@ -295,7 +295,6 @@ function assignTempGroup() {
class="bordered-b"
>
<q-expansion-item
:id="`expansion-product-${product.code}`"
dense
class="overflow-hidden"
switch-toggle-side
@ -349,7 +348,6 @@ function assignTempGroup() {
</FormGroupHead>
<div class="q-pa-md full-width">
<TableEmployee
:id="`table-employee-${product.code}`"
checkbox-on
check-all
select-ready
@ -373,15 +371,9 @@ function assignTempGroup() {
</section>
<template #footer>
<CancelButton
id="btn-dialog-cancel"
class="q-ml-auto"
outlined
@click="close"
/>
<CancelButton class="q-ml-auto" outlined @click="close" />
<SaveButton
:label="$t('general.select')"
id="btn-dialog-select"
class="q-ml-sm"
icon="mdi-check"
solid

View file

@ -225,7 +225,6 @@ function disableCheckAll() {
<template>
<q-table
flat
id="table-employee"
bordered
row-key="id"
v-bind="props"
@ -274,7 +273,6 @@ function disableCheckAll() {
>
<q-th v-if="checkboxOn" class="relative-position">
<q-checkbox
id="checkbox-check-all"
v-if="checkAll"
:disable="disableCheckAll()"
:model-value="
@ -307,7 +305,6 @@ function disableCheckAll() {
class="absolute-right row items-center"
>
<q-btn
id="btn-change-all-status"
flat
dense
rounded
@ -342,7 +339,6 @@ function disableCheckAll() {
{{ $t(`taskOrder.status.Complete`) }}
</q-item>
<q-item
id="menu-item-redo"
clickable
v-close-popup
class="items-center"
@ -362,7 +358,6 @@ function disableCheckAll() {
{{ $t(`taskOrder.status.Redo`) }}
</q-item>
<q-item
id="menu-item-restart"
clickable
v-close-popup
class="items-center"
@ -384,7 +379,6 @@ function disableCheckAll() {
</q-list>
<q-list v-if="!validate" dense>
<q-item
id="menu-item-success"
clickable
v-close-popup
class="items-center"
@ -404,7 +398,6 @@ function disableCheckAll() {
{{ $t(`taskOrder.status.Success`) }}
</q-item>
<q-item
id="menu-item-failed"
clickable
v-close-popup
class="items-center"
@ -487,7 +480,6 @@ function disableCheckAll() {
<q-td>
<span
class="cursor-pointer link"
:id="`link-request-list-${props.row.request.code}`"
@click="goToRequestList(props.row.request.id)"
>
{{ props.row.request.code }}
@ -497,7 +489,6 @@ function disableCheckAll() {
<q-td>
<span
class="cursor-pointer link"
:id="`link-quotation-${props.row.request.quotation?.code}`"
@click="goToQuotation(props.row.request.quotation)"
>
{{ props.row.request.quotation?.code }}
@ -505,11 +496,7 @@ function disableCheckAll() {
</q-td>
<q-td v-if="stepOn" class="text-left">
<div
v-if="props.row._template"
class="column text-left"
:id="`template-step-${props.row.request.code}`"
>
<div v-if="props.row._template" class="column text-left">
<span>{{ props.row._template.templateName }}</span>
<span class="app-text-muted text-caption">
{{ $t('flow.stepNo', { msg: props.row._template.step }) }}
@ -535,10 +522,7 @@ function disableCheckAll() {
</template>
</q-img>
</q-avatar>
<div
class="column text-left q-ml-sm"
:id="`employee-name-${props.row.request.employee?.code}`"
>
<div class="column text-left q-ml-sm">
<div>
{{ getEmployeeName(props.row, { locale: $i18n.locale }) }}
</div>
@ -548,7 +532,6 @@ function disableCheckAll() {
</div>
</div>
<Icon
:id="`icon-gender-${props.row.request.employee?.code}`"
class="q-ml-md"
:class="`app-text-${props.row.request.employee?.gender}`"
:icon="`material-symbols:${props.row.request.employee?.gender}`"
@ -556,18 +539,13 @@ function disableCheckAll() {
/>
</div>
</q-td>
<q-td :id="`employee-age-${props.row.request.employee?.code}`">
{{ calculateAge(props.row.request.employee?.dateOfBirth) }}
</q-td>
<q-td :id="`employee-nationality-${props.row.request.employee?.code}`">
<q-td>{{ calculateAge(props.row.request.employee?.dateOfBirth) }}</q-td>
<q-td>
{{
useOptionStore().mapOption(props.row.request.employee?.nationality)
}}
</q-td>
<q-td
:id="`quotation-due-date-${props.row.request.quotation?.code}`"
v-if="!statusOn"
>
<q-td>
{{
dateFormatJS({
date: props.row.request.quotation?.dueDate,
@ -577,16 +555,13 @@ function disableCheckAll() {
})
}}
</q-td>
<q-td
:id="`expiration-date-${props.row.request.quotation?.code}`"
v-if="!statusOn"
>
<q-td>
<ExpirationDate
:expiration-date="new Date(props.row.request.quotation?.dueDate)"
/>
</q-td>
<q-td v-if="!statusOn">
<q-td>
<BadgeComponent
v-if="props.row.request.quotation?.urgent"
icon="mdi-fire"

View file

@ -114,7 +114,6 @@ const emit = defineEmits<{
</script>
<template>
<q-table
id="table-task-order"
v-bind="props"
:columns="column"
bordered
@ -134,11 +133,7 @@ const emit = defineEmits<{
:props="props"
>
<q-th v-if="selection !== 'none'">
<q-checkbox
id="checkbox-select-all-task"
v-model="props.selected"
size="sm"
/>
<q-checkbox v-model="props.selected" size="sm" />
</q-th>
<q-th v-for="col in props.cols" :key="col.name" :props="props">
{{ col.label && $t(col.label) }}
@ -154,21 +149,13 @@ const emit = defineEmits<{
>
<q-tr class="text-center" :class="{ urgent: props.row.urgent }">
<q-td v-if="selection !== 'none'">
<q-checkbox
:id="`checkbox-task-${props.row.code}`"
v-model="props.selected"
size="sm"
/>
<q-checkbox v-model="props.selected" size="sm" />
</q-td>
<q-td v-if="visibleColumns.includes('order')">
{{ props.rowIndex + 1 }}
</q-td>
<q-td
v-if="visibleColumns.includes('taskName')"
class="text-left"
:id="`task-name-${props.row.code}`"
>
<div :id="`task-name-div-${props.row.code}`">
<q-td v-if="visibleColumns.includes('taskName')" class="text-left">
<div>
{{ props.row.taskName || '-' }}
<q-tooltip :delay="300">
{{ props.row.taskName || '-' }}
@ -183,51 +170,31 @@ const emit = defineEmits<{
}}
</div>
</q-td>
<q-td
v-if="visibleColumns.includes('issueBranch')"
:id="`task-issue-branch-${props.row.code}`"
>
<q-td v-if="visibleColumns.includes('issueBranch')">
{{
$i18n.locale === 'eng'
? props.row.registeredBranch.nameEN || '-'
: props.row.registeredBranch.name || '-'
}}
</q-td>
<q-td
v-if="visibleColumns.includes('institution')"
:id="`task-institution-${props.row.code}`"
>
<q-td v-if="visibleColumns.includes('institution')">
{{
$i18n.locale === 'eng'
? props.row.institution.nameEN || '-'
: props.row.institution.name || '-'
}}
</q-td>
<q-td
v-if="visibleColumns.includes('createdAt')"
:id="`task-created-at-${props.row.code}`"
>
<q-td v-if="visibleColumns.includes('createdAt')">
{{ dateFormatJS({ date: props.row.createdAt }) || '-' }}
{{ dateFormatJS({ date: props.row.createdAt, timeOnly: true }) }}
</q-td>
<q-td
v-if="visibleColumns.includes('createdBy')"
class="text-left"
:id="`task-created-by-${props.row.code}`"
>
<q-td v-if="visibleColumns.includes('createdBy')" class="text-left">
{{ getCreatedByName(props.row, $i18n) }}
</q-td>
<q-td
v-if="visibleColumns.includes('contactTel')"
:id="`task-contact-tel-${props.row.code}`"
>
<q-td v-if="visibleColumns.includes('contactTel')">
{{ props.row.contactTel || '-' }}
</q-td>
<q-td
v-if="visibleColumns.includes('contactName')"
class="text-left"
:id="`task-contact-name-${props.row.code}`"
>
<q-td v-if="visibleColumns.includes('contactName')" class="text-left">
{{ props.row.contactName || '-' }}
</q-td>
<q-td v-if="visibleColumns.includes('taskStatus')">
@ -235,12 +202,11 @@ const emit = defineEmits<{
hide-icon
:hsla-color="taskOrderStatus(props.row.taskOrderStatus, 'color')"
:title="$t(taskOrderStatus(props.row.taskOrderStatus, 'status'))"
:id="`badge-task-status-${props.row.code}`"
/>
</q-td>
<q-td v-if="selection === 'none'">
<q-btn
:id="`btn-view-task-${props.row.code}`"
:id="`btn-eye-${props.row.taskName}`"
icon="mdi-eye-outline"
size="sm"
dense
@ -255,7 +221,7 @@ const emit = defineEmits<{
canAccess('taskOrder', 'edit')
"
:hide-delete="!canAccess('taskOrder', 'create')"
:idName="`btn-kebab-${props.row.code}`"
:idName="`btn-kebab-${props.row.taskName}`"
status="'ACTIVE'"
hide-toggle
@view="$emit('view', props.row)"
@ -267,7 +233,6 @@ const emit = defineEmits<{
<q-btn
dense
flat
:id="`btn-sub-row-${props.row.code}`"
class="rounded"
@click.stop="
() => {

View file

@ -60,25 +60,16 @@ function inactiveCheck() {
</script>
<template>
<div
:id="`readonly-status-${status}`"
:for="`readonly-status-${status}`"
v-if="readonly"
class="row rounded bordered surface-2 items-center justify-center q-pa-xs no-wrap"
:style="`color: hsl(var(--${currStatus?.color}-bg))`"
>
<q-icon
:id="`readonly-status-icon-${status}`"
:name="currStatus?.icon"
class="q-pr-xs"
size="xs"
/>
<span :id="`readonly-status-label-${status}`">{{ $t(`taskOrder.status.${status}`) }}</span>
<q-icon :name="currStatus?.icon" class="q-pr-xs" size="xs" />
{{ $t(`taskOrder.status.${status}`) }}
</div>
<div v-else class="row items-center justify-center no-wrap">
<q-btn-dropdown
:id="`btn-dropdown-status-${status}`"
:for="`btn-dropdown-status-${status}`"
dense
unelevated
:label="
@ -119,8 +110,6 @@ function inactiveCheck() {
>
<q-list v-if="!noAction" dense>
<q-item
:for="`menu-item-status-${v.value}`"
:id="`menu-item-status-${v.value}`"
v-for="(v, index) in type === 'order'
? {
Success: taskStatusOrderToggle.filter(
@ -158,8 +147,6 @@ function inactiveCheck() {
</q-btn-dropdown>
<q-btn
:id="`btn-failed-remark-${status}`"
:for="`btn-failed-remark-${status}`"
v-if="currStatus?.value === TaskStatus.Failed"
flat
dense
@ -199,9 +186,9 @@ function inactiveCheck() {
}
:deep(
.hide-icon
i.q-icon.mdi.mdi-chevron-down.q-btn-dropdown__arrow.q-btn-dropdown__arrow-container
) {
.hide-icon
i.q-icon.mdi.mdi-chevron-down.q-btn-dropdown__arrow.q-btn-dropdown__arrow-container
) {
display: none;
}
</style>

View file

@ -25,7 +25,6 @@ const fileData = defineModel<
</script>
<template>
<q-expansion-item
id="expansion-additional-file"
dense
class="overflow-hidden bordered full-width"
switch-toggle-side
@ -42,7 +41,6 @@ const fileData = defineModel<
<main class="q-px-md q-py-sm surface-1">
<UploadFileSection
id="upload-additional-file"
multiple
:layout="$q.screen.gt.sm ? 'column' : 'row'"
:readonly

View file

@ -22,7 +22,6 @@ const contactTel = defineModel<string>('contactTel');
</script>
<template>
<q-expansion-item
id="expansion-document"
default-opened
dense
class="overflow-hidden bordered full-width"
@ -39,16 +38,13 @@ const contactTel = defineModel<string>('contactTel');
<main class="q-px-md q-py-sm surface-1 row q-col-gutter-sm">
<SelectBranch
id="select-issue-branch"
:readonly
required
class="col-md-4 col-12"
:label="`${$t('taskOrder.issueBranch')}${$i18n.locale === 'tha' ? $t('taskOrder.title') : ''}`"
v-model:value="registeredBranchId"
auto-select-on-single
/>
<SelectInstitution
id="select-agencies"
:readonly
required
class="col-md-4 col-12"
@ -59,7 +55,6 @@ const contactTel = defineModel<string>('contactTel');
auto-select-on-single
/>
<DatePicker
id="datepicker-issue-date"
:label="$t('taskOrder.issueDate')"
class="col-md-2 col-6"
:model-value="issueDate || new Date(Date.now())"
@ -67,7 +62,6 @@ const contactTel = defineModel<string>('contactTel');
:disabled="!readonly"
/>
<q-input
id="input-task-code"
:label="$t('taskOrder.code')"
outlined
dense
@ -78,7 +72,6 @@ const contactTel = defineModel<string>('contactTel');
/>
<q-input
id="input-task-name"
:readonly
:label="$t('general.name', { msg: $t('taskOrder.title') })"
outlined
@ -87,7 +80,6 @@ const contactTel = defineModel<string>('contactTel');
v-model="taskName"
/>
<q-input
id="input-contact-name"
:readonly
:label="$t('taskOrder.contactName')"
outlined
@ -96,7 +88,6 @@ const contactTel = defineModel<string>('contactTel');
v-model="contactName"
/>
<q-input
id="input-contact-tel"
:readonly
:label="$t('general.telephone')"
outlined
@ -105,7 +96,6 @@ const contactTel = defineModel<string>('contactTel');
v-model="contactTel"
/>
<q-input
id="input-made-by"
:readonly
:label="$t('taskOrder.madeBy')"
outlined

View file

@ -32,7 +32,6 @@ const summaryPrice = defineModel<{
</script>
<template>
<q-expansion-item
id="expansion-payment"
dense
class="overflow-hidden bordered full-width"
switch-toggle-side
@ -48,7 +47,6 @@ const summaryPrice = defineModel<{
<main class="q-px-md q-py-sm surface-1">
<QuotationFormInfo
id="form-info-payment"
task-order
:task-order-complete="complete"
v-model:pay-type="payType"

View file

@ -111,7 +111,6 @@ function taskOrderStatus(value: TaskStatus) {
</script>
<template>
<q-expansion-item
id="expansion-product-list"
dense
class="overflow-hidden bordered full-width"
switch-toggle-side
@ -124,11 +123,9 @@ function taskOrderStatus(value: TaskStatus) {
<span
class="row items-center justify-between full-width"
style="min-height: 31.01px"
id="header-product-list"
>
{{ $t('general.information', { msg: $t('taskOrder.productList') }) }}
<AddButton
id="btn-add-product"
icon-only
@click.stop="$emit('addProduct')"
v-if="!readonly"
@ -138,7 +135,6 @@ function taskOrderStatus(value: TaskStatus) {
<main class="q-px-md q-py-sm surface-1">
<q-table
id="table-product-list"
:columns="
creditNote
? productColumn.filter(
@ -184,7 +180,7 @@ function taskOrderStatus(value: TaskStatus) {
} & Omit<Parameters<QTableSlots['body']>[0], 'row'>"
>
<q-tr class="text-center">
<q-td :id="`product-order-${props.rowIndex}`">
<q-td>
{{ props.rowIndex + 1 }}
</q-td>
<q-td>
@ -210,17 +206,16 @@ function taskOrderStatus(value: TaskStatus) {
</q-td>
<q-td class="text-left" v-if="!creditNote">
<BadgeComponent
:id="`badge-status-${props.row.product.code}`"
hide-icon
:hsla-color="taskOrderStatus(props.row.product.taskStatus)"
:title="`${$t(`taskOrder.status.${props.row.product.taskStatus}`)} ${!!props.row.product.totalNotStatusComplete ? $t('general.totalPeople', { meg: props.row.product.totalNotStatusComplete }) : ''}`"
/>
</q-td>
<q-td :id="`product-amount-${props.row.product.code}`">
<q-td>
{{ props.row.list.length }}
</q-td>
<q-td :id="`product-price-per-unit-${props.row.product.code}`" class="text-right">
<q-td class="text-right">
{{
formatNumberDecimal(
calcPricePerUnit(props.row.product) +
@ -235,7 +230,6 @@ function taskOrderStatus(value: TaskStatus) {
<!-- TODO: display price detail -->
<q-td align="center" v-if="!creditNote">
<q-input
:id="`input-discount-${props.row.product.code}`"
:readonly
:bg-color="readonly ? 'transparent' : ''"
dense
@ -273,11 +267,7 @@ function taskOrderStatus(value: TaskStatus) {
/>
</q-td>
<!-- before vat -->
<q-td
:id="`product-price-before-vat-${props.row.product.code}`"
class="text-right"
v-if="!creditNote"
>
<q-td class="text-right" v-if="!creditNote">
{{
formatNumberDecimal(
props.row.product.serviceChargeCalcVat
@ -294,11 +284,7 @@ function taskOrderStatus(value: TaskStatus) {
}}
</q-td>
<!-- vat -->
<q-td
:id="`product-vat-${props.row.product.code}`"
class="text-right"
v-if="!creditNote"
>
<q-td class="text-right" v-if="!creditNote">
{{
formatNumberDecimal(
props.row.product.serviceChargeCalcVat
@ -315,7 +301,7 @@ function taskOrderStatus(value: TaskStatus) {
}}
</q-td>
<!-- total -->
<q-td :id="`product-total-price-${props.row.product.code}`" class="text-right">
<q-td class="text-right">
{{
formatNumberDecimal(
calcPrice(props.row.product, props.row.list.length),
@ -325,7 +311,6 @@ function taskOrderStatus(value: TaskStatus) {
</q-td>
<q-td>
<q-btn
:id="`btn-toggle-employee-${props.row.product.code}`"
dense
flat
class="rounded"
@ -349,7 +334,6 @@ function taskOrderStatus(value: TaskStatus) {
<q-tr v-show="currentBtnOpen[props.rowIndex]" :props="props">
<q-td colspan="100%" style="padding: 16px">
<TableEmployee
:id="`table-employee-in-product-${props.row.product.code}`"
:step-on="!creditNote"
:status-on="creditNote"
:rows="props.row.list"
@ -367,9 +351,7 @@ function taskOrderStatus(value: TaskStatus) {
})
}}
</span>
<div class="surface-3 q-px-sm rounded" id="total-product-count">
{{ taskList.length }}
</div>
<div class="surface-3 q-px-sm rounded">{{ taskList.length }}</div>
</div>
</main>
</q-expansion-item>

View file

@ -33,7 +33,6 @@ const getToolbarConfig = computed(() => {
</script>
<template>
<q-expansion-item
id="expansion-remark"
dense
class="overflow-hidden bordered full-width"
switch-toggle-side
@ -49,7 +48,6 @@ const getToolbarConfig = computed(() => {
<main class="surface-1 q-pa-md full-width">
<q-editor
id="editor-remark"
dense
:readonly="readonly || !remarkWrite"
:model-value="
@ -92,7 +90,6 @@ const getToolbarConfig = computed(() => {
<template v-if="!readonly" v-slot:toggle>
<div class="text-caption row no-wrap q-px-sm">
<MainButton
id="btn-remark-view"
:solid="!remarkWrite"
icon="mdi-eye-outline"
color="0 0% 40%"
@ -105,7 +102,6 @@ const getToolbarConfig = computed(() => {
{{ $t('general.view', { msg: $t('general.example') }) }}
</MainButton>
<MainButton
id="btn-remark-edit"
:solid="remarkWrite"
icon="mdi-pencil-outline"
color="0 0% 40%"

View file

@ -47,17 +47,11 @@ defineProps<{
<div class="row q-col-gutter-sm q-px-md q-py-sm">
<DataDisplay
class="col-md col-6"
id="dd-recipient"
:label="$t('taskOrder.recipientOrSender')"
>
<template #value>
<q-avatar size="md" class="q-mr-xs">
<q-img
:id="`img-avatar-${contactName}`"
class="text-center"
:ratio="1"
:src="contactUrl"
>
<q-img class="text-center" :ratio="1" :src="contactUrl">
<template #error>
<div
class="no-padding full-width full-height flex items-center justify-center"
@ -65,7 +59,6 @@ defineProps<{
>
<q-img
v-if="gender"
:id="`img-gender-${contactName}`"
:src="
gender === 'male'
? '/no-img-man.png'
@ -74,7 +67,6 @@ defineProps<{
/>
<q-icon
v-else
:id="`icon-avatar-${contactName}`"
size="sm"
name="mdi-account-outline"
style="color: white"
@ -89,21 +81,18 @@ defineProps<{
<DataDisplay
class="col-md col-6"
id="dd-telephone"
:label="$t('general.telephone')"
:value="contactTel || '-'"
/>
<DataDisplay
class="col-md col-6"
id="dd-email"
:label="$t('form.email')"
:value="email || '-'"
/>
<DataDisplay
class="col-md col-6"
id="dd-work-start-date"
:label="$t('taskOrder.workStartDate')"
>
<template #value>
@ -117,7 +106,6 @@ defineProps<{
<DataDisplay
class="col-md col-6"
id="dd-work-submission-date"
:label="$t('taskOrder.workSubmissionDate')"
>
<template #value>
@ -129,14 +117,9 @@ defineProps<{
</template>
</DataDisplay>
<DataDisplay
id="dd-status"
class="col-md col-6"
:label="$t('general.status')"
>
<DataDisplay class="col-md col-6" :label="$t('general.status')">
<template #value>
<BadgeComponent
:id="`badge-status-${contactName}`"
v-if="status"
hide-icon
:title="

View file

@ -814,7 +814,7 @@ watch(
>
<section class="banner" :class="{ dark: $q.dark.isActive }"></section>
<div style="flex: 1" class="row items-center">
<RouterLink to="/task-order" id="link-task-order">
<RouterLink to="/task-order">
<q-img src="/icons/favicon-512x512.png" width="3rem" />
</RouterLink>
<span class="column text-h6 text-bold q-ml-md">
@ -863,7 +863,6 @@ watch(
<!-- TODO: replace step and status -->
<StateButton
v-for="i in statusTabForm"
:id="`btn-status-${i.title}`"
:key="i.title"
:label="$t(`taskOrder.${i.title}`)"
:status-active="i.active?.()"
@ -917,7 +916,6 @@ watch(
"
>
<DocumentExpansion
id="expansion-document"
:readonly="!['create', 'edit'].includes(state.mode || '')"
v-model:registered-branch-id="currentFormData.registeredBranchId"
v-model:institution-id="currentFormData.institutionId"
@ -937,7 +935,6 @@ watch(
/>
</q-form>
<ProductExpansion
id="expansion-product"
ref="refProductExpansion"
v-if="
view === TaskOrderStatus.Pending ||
@ -950,7 +947,6 @@ watch(
/>
<PaymentExpansion
id="expansion-payment"
v-model:summary-price="summaryPrice"
:complete="view === TaskOrderStatus.Complete"
v-if="
@ -960,7 +956,6 @@ watch(
/>
<AdditionalFileExpansion
id="expansion-additional-file"
:readonly="!['create', 'edit'].includes(state.mode || '')"
v-if="
view === TaskOrderStatus.Pending ||
@ -1019,7 +1014,6 @@ watch(
/>
<!-- TODO: blind remark, urgent -->
<RemarkExpansion
id="expansion-remark"
v-if="
view === TaskOrderStatus.Pending ||
view === TaskOrderStatus.Complete
@ -1044,7 +1038,6 @@ watch(
"
>
<InfoMessengerExpansion
:id="`expansion-messenger-${messengerIndex}`"
v-for="(v, messengerIndex) in messengerListGroup"
:key="messengerIndex"
:gender="getMessengerName(v.responsibleUser, { gender: true })"
@ -1080,7 +1073,6 @@ watch(
class="bordered-b"
>
<q-expansion-item
:id="`expansion-product-${productIndex}`"
dense
class="overflow-hidden"
switch-toggle-side
@ -1254,7 +1246,6 @@ watch(
<nav class="row justify-end">
<MainButton
class="q-mr-auto"
id="btn-view-example"
v-if="currentFormData.id"
outlined
icon="mdi-play-box-outline"
@ -1269,16 +1260,10 @@ watch(
{{ $t('general.view', { msg: $t('general.example') }) }}
</MainButton>
<div class="row" style="gap: var(--size-2)">
<UndoButton
id="btn-undo"
outlined
@click="undo()"
v-if="state.mode === 'edit'"
/>
<UndoButton outlined @click="undo()" v-if="state.mode === 'edit'" />
<CancelButton
v-if="state.mode !== 'edit'"
:label="$t('dialog.action.close')"
id="btn-close"
outlined
@click="closeTab()"
/>
@ -1290,14 +1275,12 @@ watch(
"
>
<SaveButton
id="btn-save"
v-if="state.mode && ['create', 'edit'].includes(state.mode)"
@click="() => formDocument.submit()"
solid
/>
<EditButton
v-else
id="btn-edit"
class="no-print"
@click="state.mode = 'edit'"
solid
@ -1305,7 +1288,6 @@ watch(
</template>
<SaveButton
v-if="
canAccess('taskOrder', 'edit') &&
state.mode !== 'create' &&
view === TaskOrderStatus.Validate &&
fullTaskOrder?.taskOrderStatus !== TaskOrderStatus.Pending &&
@ -1344,7 +1326,6 @@ watch(
"
:label="$t('taskOrder.confirmEndWork')"
icon="mdi-check"
id="btn-confirm-end-work"
solid
></SaveButton>
</div>
@ -1354,7 +1335,6 @@ watch(
<!-- SEC: Dialog -->
<SelectReadyRequestWork
id="dialog-select-request-work"
:task-list-group="taskListGroup"
:fetch-params="{ readyToTask: true }"
v-model:open="pageState.productDialog"

View file

@ -98,7 +98,6 @@ function tooltip(id: string) {
<main class="q-py-sm q-px-md scroll">
<q-select
:readonly
id="select-fail-task"
dense
outlined
multiple
@ -132,7 +131,6 @@ function tooltip(id: string) {
>
<template #selected-item="scope">
<q-chip
:id="`chip-fail-task-${taskStatusList[scope.index].code}`"
dense
:removable="!readonly"
@remove="scope.removeAtIndex(scope.index)"
@ -172,7 +170,6 @@ function tooltip(id: string) {
<template #option="scope">
<q-item
:id="`option-fail-task-${scope.opt.request.code}`"
clickable
v-bind="scope.itemProps"
class="row items-start col-12 no-padding"
@ -233,7 +230,6 @@ function tooltip(id: string) {
<SelectInput
:readonly
id="select-fail-type"
:option="[
{
label: $t('taskOrder.documentSubmitFailed'),
@ -264,7 +260,6 @@ function tooltip(id: string) {
<div v-if="failedType === 'other'" class="q-mt-sm rounded">
<q-editor
id="editor-fail-comment"
dense
flat
v-model="failedComment"
@ -284,18 +279,8 @@ function tooltip(id: string) {
</main>
<template #footer v-if="!readonly">
<CancelButton
id="btn-fail-remark-cancel"
class="q-ml-auto"
outlined
@click="$emit('close')"
/>
<SaveButton
id="btn-fail-remark-save"
class="q-ml-sm"
solid
@click="submit"
/>
<CancelButton class="q-ml-auto" outlined @click="$emit('close')" />
<SaveButton class="q-ml-sm" solid @click="submit" />
</template>
</DialogFormContainer>
</template>

View file

@ -394,14 +394,8 @@ watch(
{
label: $t('general.customer'),
value:
item.row.quotation.customerBranch.customer
.customerType === 'CORP'
? $i18n.locale === 'tha'
? item.row.quotation.customerBranch.registerName
: item.row.quotation.customerBranch.registerNameEN
: $i18n.locale === 'tha'
? `${item.row.quotation.customerBranch?.firstName || '-'} ${item.row.quotation.customerBranch?.lastName || ''}`
: `${item.row.quotation.customerBranch?.firstNameEN || '-'} ${item.row.quotation.customerBranch?.lastNameEN || ''}`,
item.row.quotation.customerBranch.registerName ||
`${item.row.quotation.customerBranch?.firstName || '-'} ${item.row.quotation.customerBranch?.lastName || ''}`,
},
{
label: $t('taskOrder.issueDate'),

View file

@ -83,16 +83,11 @@ defineEmits<{
<!-- NOTE: custom column will starts with # -->
<template v-if="!col.name.startsWith('#')">
<span>
<template v-if="typeof col.field === 'function'">
{{
typeof col.field(props.row) === 'object'
? col.field(props.row)[$i18n.locale]
: col.field(props.row)
}}
</template>
<template v-else>
{{ props.row[col.field as keyof Invoice] }}
</template>
{{
typeof col.field === 'string'
? props.row[col.field as keyof Invoice]
: col.field(props.row)
}}
</span>
</template>
<template v-if="col.name === '#order'">

View file

@ -29,16 +29,7 @@ export const columns = [
name: 'customer',
align: 'center',
label: 'general.customer',
field: (v: Invoice) =>
v.quotation.customerBranch.customer.customerType === 'CORP'
? {
tha: v.quotation.customerBranch.registerName,
eng: v.quotation.customerBranch.registerNameEN,
}
: {
tha: `${v.quotation.customerBranch.firstName || ''} ${v.quotation.customerBranch.lastName || ''}`,
eng: `${v.quotation.customerBranch.firstNameEN || ''} ${v.quotation.customerBranch.lastNameEN || ''}`,
},
field: (v: Invoice) => v.quotation.customerBranch.registerName,
},
{

View file

@ -134,11 +134,6 @@ onMounted(async () => {
creditNote.getCreditNoteStats().then((res) => res && (stats.value = res));
getList();
window.addEventListener('focus', () => {
creditNote.getCreditNoteStats().then((res) => res && (stats.value = res));
getList();
});
});
watch(
@ -411,12 +406,10 @@ watch(
value:
item.row.quotation.customerBranch.customer
.customerType === 'CORP'
? $i18n.locale === 'tha'
? item.row.quotation.customerBranch.registerName
: item.row.quotation.customerBranch.registerNameEN
? item.row.quotation.customerBranch.registerName
: $i18n.locale === 'tha'
? `${item.row.quotation.customerBranch.firstName || ''} ${item.row.quotation.customerBranch.lastName || ''}`
: `${item.row.quotation.customerBranch.firstNameEN || ''} ${item.row.quotation.customerBranch.lastNameEN || ''}`,
? `${item.row.quotation.customerBranch.firstName} ${item.row.quotation.customerBranch.lastName}`
: `${item.row.quotation.customerBranch.firstNameEN} ${item.row.quotation.customerBranch.lastNameEN}`,
},
{
label: $t('requestList.quotationCode'),

View file

@ -8,7 +8,7 @@ import { columns } from './constants';
import KebabAction from 'src/components/shared/KebabAction.vue';
const creditNote = useCreditNote();
const { data, page, pageSize } = storeToRefs(creditNote);
const { data, page } = storeToRefs(creditNote);
const prop = defineProps<{
grid: boolean;
@ -26,14 +26,7 @@ const visible = computed(() =>
<template>
<q-table
:rows-per-page-options="[0]"
:rows="
data.map((item, i) => ({
...item,
_index: i,
_page: page,
_pageSize: pageSize,
}))
"
:rows="data.map((item, i) => ({ ...item, _index: i, _page: page }))"
:columns="visible"
:grid
hide-bottom
@ -59,7 +52,7 @@ const visible = computed(() =>
<template
v-slot:body="props: {
row: CreditNote & { _index: number; _page: number; _pageSize: number };
row: CreditNote & { _index: number; _page: number };
} & Omit<Parameters<QTableSlots['body']>[0], 'row'>"
>
<q-tr :class="{ dark: $q.dark.isActive }" class="text-center">

View file

@ -32,9 +32,8 @@ export const columns = [
name: 'order',
align: 'center',
label: 'general.order',
field: (
data: CreditNote & { _index: number; _page: number; _pageSize: number },
) => (data._page - 1) * data._pageSize + (data._index + 1),
field: (data: CreditNote & { _index: number; _page: number }) =>
data._page * (data._index + 1),
},
{
name: 'code',

View file

@ -209,7 +209,47 @@ const selectedWorker = ref<
}[];
})[]
>([]);
const selectedWorkerItem = ref([]);
const selectedWorkerItem = computed(() => {
return [
...selectedWorker.value.map((e) => ({
foreignRefNo: e.employeePassport
? e.employeePassport[0]?.number || '-'
: '-',
employeeName:
locale.value === Lang.English
? `${e.firstNameEN} ${e.lastNameEN}`
: `${e.firstName || e.firstNameEN} ${e.lastName || e.lastNameEN}`,
birthDate: dateFormatJS({ date: e.dateOfBirth }),
gender: e.gender,
age: calculateAge(e.dateOfBirth),
nationality: optionStore.mapOption(e.nationality),
documentExpireDate:
e.employeePassport !== undefined &&
e.employeePassport[0]?.expireDate !== undefined
? dateFormatJS({ date: e.employeePassport[0]?.expireDate })
: '-',
imgUrl: e.selectedImage
? `${API_BASE_URL}/employee/${e.id}/image/${e.selectedImage}`
: '',
status: e.status,
})),
...newWorkerList.value.map((v: any) => ({
foreignRefNo: v.passportNo || '-',
employeeName:
locale.value === Lang.English
? `${v.firstNameEN} ${v.lastNameEN}`
: `${v.firstName || v.firstNameEN} ${v.lastName || v.lastNameEN}`,
birthDate: dateFormatJS({ date: v.dateOfBirth }),
gender: v.gender,
age: calculateAge(v.dateOfBirth),
nationality: optionStore.mapOption(v.nationality),
documentExpireDate: '-',
imgUrl: '',
status: 'CREATED',
})),
];
});
const selectedInstallmentNo = ref<number[]>([]);
const installmentAmount = ref<number>(0);
@ -334,39 +374,7 @@ function assignProductServiceList() {
function assignSelectedWorker() {
if (debitNoteData.value)
selectedWorkerItem.value = debitNoteData.value.worker.map((e) => {
return {
id: e.employee.id,
foreignRefNo: e.employee.employeePassport
? e.employee.employeePassport[0]?.number || '-'
: '-',
employeeName:
locale.value === Lang.English
? `${e.employee.firstNameEN} ${e.employee.lastNameEN}`
: `${e.employee.firstName || e.employee.firstNameEN} ${e.employee.lastName || e.employee.lastNameEN}`,
birthDate: dateFormatJS({ date: e.employee.dateOfBirth }),
gender: e.employee.gender,
age: calculateAge(e.employee.dateOfBirth),
nationality: optionStore.mapOption(e.employee.nationality),
documentExpireDate:
e.employee.employeePassport !== undefined &&
e.employee.employeePassport[0]?.expireDate !== undefined
? dateFormatJS({ date: e.employee.employeePassport[0]?.expireDate })
: '-',
imgUrl: e.employee.selectedImage
? `${API_BASE_URL}/employee/${e.id}/image/${e.employee.selectedImage}`
: '',
status: e.employee.status,
workerNew: false,
lastNameEN: e.employee.lastNameEN,
lastName: e.employee.lastName,
middleNameEN: e.employee.middleNameEN,
middleName: e.employee.middleName,
firstNameEN: e.employee.firstNameEN,
firstName: e.employee.firstName,
namePrefix: e.employee.namePrefix,
};
});
selectedWorker.value = debitNoteData.value.worker.map((v) => v.employee);
}
async function assignFormData(id: string) {
@ -378,7 +386,7 @@ async function assignFormData(id: string) {
selectedProductGroup.value =
data.productServiceList[0]?.product.productGroup?.id || '';
(previousValue = {
((previousValue = {
id: data.id || undefined,
debitNoteQuotationId: data.debitNoteQuotationId || undefined,
productServiceList: structuredClone(
@ -404,7 +412,7 @@ async function assignFormData(id: string) {
quotationId: data.debitNoteQuotationId,
remark: data.remark || undefined,
}),
(currentFormData.value = structuredClone(previousValue));
(currentFormData.value = structuredClone(previousValue)));
assignProductServiceList();
assignSelectedWorker();
@ -532,6 +540,8 @@ function getPrice(
) {
if (filterHook) list = list.filter(filterHook);
console.log(list);
return list.reduce(
(a, c) => {
if (
@ -805,11 +815,15 @@ async function submit() {
worker: JSON.parse(
JSON.stringify([
...selectedWorkerItem.value.map((v) => {
...selectedWorker.value.map((v) => {
{
return v.id;
}
}),
...newWorkerList.value.map((v) => {
const { attachment, ...payload } = v;
return pageState.mode === 'edit' ? payload.id : payload;
}),
]),
),
dueDate: currentFormData.value.dueDate,
@ -888,7 +902,7 @@ function storeDataLocal() {
dueDate: currentFormData.value.dueDate,
},
productServicelist: productService.value,
selectedWorker: selectedWorkerItem.value,
selectedWorker: selectedWorker.value,
createdBy: getName(),
},
}),
@ -913,69 +927,6 @@ function closeAble() {
return window.opener !== null;
}
function combineWorker(newWorker: any, oldWorker: any) {
selectedWorkerItem.value = [
...oldWorker.map((e) => ({
id: e.id,
foreignRefNo: e.employeePassport
? e.employeePassport[0]?.number || '-'
: '-',
employeeName:
locale.value === Lang.English
? `${e.firstNameEN} ${e.lastNameEN}`
: `${e.firstName || e.firstNameEN} ${e.lastName || e.lastNameEN}`,
birthDate: dateFormatJS({ date: e.dateOfBirth }),
gender: e.gender,
age: calculateAge(e.dateOfBirth),
nationality: optionStore.mapOption(e.nationality),
documentExpireDate:
e.employeePassport !== undefined &&
e.employeePassport[0]?.expireDate !== undefined
? dateFormatJS({ date: e.employeePassport[0]?.expireDate })
: '-',
imgUrl: e.selectedImage
? `${API_BASE_URL}/employee/${e.id}/image/${e.selectedImage}`
: '',
status: e.status,
workerNew: false,
lastNameEN: e.lastNameEN,
lastName: e.lastName,
middleNameEN: e.middleNameEN,
middleName: e.middleName,
firstNameEN: e.firstNameEN,
firstName: e.firstName,
namePrefix: e.namePrefix,
})),
...newWorker.map((v: any) => ({
id: v.id,
foreignRefNo: v.passportNo || '-',
employeeName:
locale.value === Lang.English
? `${v.firstNameEN} ${v.lastNameEN}`
: `${v.firstName || v.firstNameEN} ${v.lastName || v.lastNameEN}`,
birthDate: dateFormatJS({ date: v.dateOfBirth }),
gender: v.gender,
age: calculateAge(v.dateOfBirth),
nationality: optionStore.mapOption(v.nationality),
documentExpireDate: '-',
imgUrl: '',
status: 'CREATED',
lastNameEN: v.lastNameEN,
lastName: v.lastName,
middleNameEN: v.middleNameEN,
middleName: v.middleName,
firstNameEN: v.firstNameEN,
firstName: v.firstName,
namePrefix: v.namePrefix,
dateOfBirth: v.dateOfBirth,
workerNew: true,
})),
];
}
watch(
() => pageState.mode,
() => toggleMode(pageState.mode),
@ -1139,7 +1090,6 @@ async function submitAccepted() {
<PaymentForm
v-if="view === QuotationStatus.PaymentPending"
is-debit-note
:branch-id="quotationData?.registeredBranchId"
:readonly="isRoleInclude(['sale', 'head_of_sale'])"
:data="debitNoteData"
@fetch-status="
@ -1161,7 +1111,7 @@ async function submitAccepted() {
"
:row-worker="selectedWorkerItem"
@add-worker="() => (pageState.employeeModal = true)"
@delete="(i) => deleteItem(selectedWorkerItem, i)"
@delete="(i) => deleteItem(selectedWorker, i)"
/>
<!-- #TODO add openProductDialog at @add-product-->
@ -1381,7 +1331,7 @@ async function submitAccepted() {
<SaveButton
v-if="pageState.mode !== 'info'"
:disabled="
selectedWorkerItem.length === 0 || productService.length === 0
selectedWorkerItem.length === 0 && productService.length === 0
"
@click="submit"
solid
@ -1426,12 +1376,13 @@ async function submitAccepted() {
<!-- add employee quotation -->
<QuotationFormWorkerSelect
:preselect-worker="selectedWorkerItem"
:preselect-worker="selectedWorker"
:customerBranchId="quotationData?.customerBranchId"
v-model:open="pageState.employeeModal"
v-model:new-worker-list="newWorkerList"
@success="
(v) => {
combineWorker(v.newWorker, v.worker);
selectedWorker = v.worker;
}
"
/>

View file

@ -143,15 +143,6 @@ onMounted(async () => {
});
getList();
window.addEventListener('focus', () => {
debitNote.getDebitNoteStats().then((res) => {
if (res) {
stats.value = res;
}
});
getList();
});
});
watch(
@ -434,12 +425,10 @@ watch(
label: $t('quotation.customer'),
value:
item.row.customerBranch.customer.customerType === 'CORP'
? $i18n.locale === 'tha'
? item.row.customerBranch.registerName
: item.row.customerBranch.registerNameEN
? item.row.customerBranch.registerName
: $i18n.locale === 'tha'
? `${item.row.customerBranch.firstName || ''} ${item.row.customerBranch.lastName || ''}`
: `${item.row.customerBranch.firstNameEN || ''} ${item.row.customerBranch.lastNameEN || ''}`,
? `${item.row.customerBranch.firstName} ${item.row.customerBranch.lastName}`
: `${item.row.customerBranch.firstNameEN} ${item.row.customerBranch.lastNameEN}`,
},
{
label: $t('requestList.quotationCode'),

View file

@ -343,16 +343,9 @@ watch(
{
label: $t('general.customer'),
value:
item.row.invoice.quotation.customerBranch.customer
.customerType === 'CORP'
? $i18n.locale === 'tha'
? item.row.invoice.quotation.customerBranch
.registerName
: item.row.invoice.quotation.customerBranch
.registerNameEN
: $i18n.locale === 'tha'
? `${item.row.invoice.quotation.customerBranch?.firstName || '-'} ${item.row.invoice.quotation.customerBranch?.lastName || ''}`
: `${item.row.invoice.quotation.customerBranch?.firstNameEN || '-'} ${item.row.invoice.quotation.customerBranch?.lastNameEN || ''}`,
item.row.invoice.quotation.customerBranch
.registerName ||
`${item.row.invoice.quotation.customerBranch?.firstName || '-'} ${item.row.invoice.quotation.customerBranch?.lastName || ''}`,
},
{
label: $t('taskOrder.issueDate'),

View file

@ -45,7 +45,7 @@ const fieldSelected = ref<('no' | 'name' | 'nameEN')[]>([
const fieldSelectedOption = ref<{ label: string; value: string }[]>([
{
label: 'general.order',
value: 'no',
value: 'orderNumber',
},
{
@ -312,6 +312,25 @@ watch(
</q-input>
<div class="row col-md-5 justify-end" style="white-space: nowrap">
<q-select
v-if="$q.screen.gt.sm"
v-model="statusFilter"
outlined
dense
option-value="value"
option-label="label"
class="col"
:class="{ 'offset-md-5': pageState.gridView }"
map-options
emit-value
:for="'field-select-status'"
:hide-dropdown-icon="$q.screen.lt.sm"
:options="[
{ label: $t('general.all'), value: 'all' },
{ label: $t('general.active'), value: 'statusACTIVE' },
{ label: $t('general.inactive'), value: 'statusINACTIVE' },
]"
/>
<q-select
v-if="!pageState.gridView"
id="select-field"
@ -576,18 +595,10 @@ watch(
></q-badge>
</q-avatar>
<span class="text-weight-bold column q-pl-md">
{{
$i18n.locale === 'tha'
? props.row.name
: props.row.nameEN
}}
{{ props.row.name }}
<span class="text-caption app-text-muted-2">
{{
$i18n.locale === 'tha'
? props.row.nameEN
: props.row.name
}}
{{ props.row.nameEN }}
</span>
</span>
<nav

View file

@ -447,17 +447,6 @@ const useBranchStore = defineStore('api-branch', () => {
return false;
}
async function fetchListBankByBranch(branchId: string) {
const res = await api.get(`/branch/${branchId}/bank`, {
headers: { 'X-Rtid': flowStore.rtid },
});
if (!res) return false;
if (res.status === 200) return res.data;
return false;
}
return {
data,
map,
@ -486,8 +475,6 @@ const useBranchStore = defineStore('api-branch', () => {
fetchByIdAttachment,
putAttachment,
deleteByIdAttachment,
fetchListBankByBranch,
};
});

View file

@ -2,7 +2,6 @@ import { defineStore } from 'pinia';
import { api } from 'src/boot/axios';
import { Pagination } from 'stores/types';
import { getToken } from 'src/services/keycloak';
import {
ProductGroup,
@ -20,7 +19,6 @@ import {
import { ref } from 'vue';
const useProductServiceStore = defineStore('api-product-service', () => {
const baseUrl = import.meta.env.VITE_API_BASE_URL;
const splitPay = ref<number>(0);
const workNameItems = ref<
{
@ -530,53 +528,6 @@ const useProductServiceStore = defineStore('api-product-service', () => {
if (!res) return false;
}
async function productExport(params: {
status?: 'CREATED' | 'ACTIVE' | 'INACTIVE';
shared?: boolean;
productGroupId?: string;
query?: string;
page?: number;
pageSize?: number;
orderField?: string;
orderBy?: string;
activeOnly?: boolean;
startDate?: Date;
endDate?: Date;
}) {
let url = baseUrl + '/' + 'product-export';
const queryParams = new URLSearchParams(
Object.keys(params).reduce((acc: Record<string, string>, key) => {
const value = params[key as keyof typeof params];
if (value !== undefined && value !== null && value !== '') {
const stringValue =
typeof value === 'boolean' || typeof value === 'number'
? String(value)
: value instanceof Date
? value.toISOString()
: String(value);
acc[key] = stringValue;
}
return acc;
}, {}),
);
url += '?' + queryParams.toString();
const res = await fetch(url, {
headers: { ['Authorization']: 'Bearer ' + (await getToken()) },
});
const text = await res.json();
const blob = new Blob([text], { type: 'text/csv' });
if (res.ok && blob) {
const a = document.createElement('a');
a.download = 'customer-report' + '.csv';
a.href = window.URL.createObjectURL(blob);
a.click();
a.remove();
}
}
return {
workNameItems,
splitPay,
@ -617,8 +568,6 @@ const useProductServiceStore = defineStore('api-product-service', () => {
deleteImageByName,
importProduct,
productExport,
};
});

View file

@ -23,23 +23,22 @@ const templates = {
installments?: {
no: number;
amount: number;
name?: string;
}[];
}) => {
if (context?.paymentType === 'Full') {
return [
`**** ${i18n.global.t('general.additional')}`,
`- ${i18n.global.t('quotation.paymentCondition')} ${i18n.global.t('quotation.type.Full')}`,
`&nbsp; ${i18n.global.t('general.amount')} ${formatNumberDecimal(context?.amount || 0, 2)}`,
'**** เงื่อนไขเพิ่มเติม',
'- เงื่อนไขการชำระเงิน แบบเต็มจำนวน',
`&nbsp; จำนวน ${formatNumberDecimal(context?.amount || 0, 2)}`,
].join('<br/>');
} else {
return [
`**** ${i18n.global.t('general.additional')}`,
`- ${i18n.global.t('quotation.paymentCondition')} ${i18n.global.t('quotation.type.Split')}${context?.paymentType === 'SplitCustom' ? ` (${i18n.global.t('general.specify')}) ` : ' '}${context?.installments?.length} ${i18n.global.t('quotation.receiptDialog.installments')}`,
...(context?.installments?.map((v) => {
const installmentName = v.name ? ` (${v.name})` : '';
return `&nbsp; ${i18n.global.t('quotation.periodNo')} ${v.no}${installmentName} ${i18n.global.t('general.amount')} ${formatNumberDecimal(v.amount, 2)}`;
}) || []),
'**** เงื่อนไขเพิ่มเติม',
`- เงื่อนไขการชำระเงิน แบบแบ่งจ่าย${context?.paymentType === 'SplitCustom' ? ' กำหนดเอง ' : ' '}${context?.installments?.length} งวด`,
...(context?.installments?.map(
(v) =>
`&nbsp; งวดที่ ${v.no} จำนวน ${formatNumberDecimal(v.amount, 2)}`,
) || []),
].join('<br />');
}
},
@ -74,14 +73,14 @@ const templates = {
const employee = v.request.employee;
const branch = v.request.quotation.customerBranch;
return (
` ${i + 1}. ` +
` ${v.request.code}_${branch.customer.customerType === 'PERS' ? `${branch.namePrefix}. ${branch.firstNameEN} ${branch.lastNameEN} `.toUpperCase() : i18n.global.locale.value == 'tha' ? branch.registerName : branch.registerNameEN}_` +
`${i + 1}. ` +
` ${v.request.code}_${branch.customer.customerType === 'PERS' ? `${branch.namePrefix}. ${branch.firstNameEN} ${branch.lastNameEN} `.toUpperCase() : branch.registerName}_` +
`${employee.namePrefix}. ${employee.firstNameEN} ${employee.lastNameEN} `.toUpperCase() +
`${!!v.failedType && v.failedType !== 'other' ? `${i18n.global.t(`taskOrder.${v.failedType}`)}` : !!v.failedComment ? v.failedComment : ''}`
);
});
return [
`- ${item.product.name} ${i18n.global.t('price', { price: price })} `,
`- ${item.product.name} ราคา ${price} บาท`,
'',
...list,
'',