feat: enhance credit note functionality and improve task order handling
This commit is contained in:
parent
91c7db7c7b
commit
dc225ac31b
3 changed files with 125 additions and 36 deletions
|
|
@ -23,7 +23,9 @@ const emit = defineEmits<{
|
|||
|
||||
const props = defineProps<{
|
||||
taskListGroup?: {
|
||||
product: RequestWork['productService']['product'];
|
||||
product:
|
||||
| RequestWork['productService']['product']
|
||||
| RequestWork['productService'];
|
||||
list: (RequestWork & {
|
||||
_template?: {
|
||||
id: string;
|
||||
|
|
@ -135,6 +137,7 @@ async function getList() {
|
|||
}
|
||||
|
||||
function getStep(requestWork: RequestWork) {
|
||||
if (!requestWork.stepStatus) return 0;
|
||||
const target = requestWork.stepStatus.find(
|
||||
(v) =>
|
||||
v.workStatus === RequestWorkStatus.Ready ||
|
||||
|
|
@ -166,7 +169,7 @@ function submit() {
|
|||
requestWorkStep?: Task;
|
||||
}[] = [];
|
||||
selectedEmployee.value.forEach((v, i) => {
|
||||
if (v.stepStatus.length === 0) {
|
||||
if (!v.stepStatus || v.stepStatus.length === 0) {
|
||||
selected.push({
|
||||
step: 0,
|
||||
requestWorkId: v.id || '',
|
||||
|
|
@ -224,7 +227,7 @@ function close() {
|
|||
|
||||
function onDialogOpen() {
|
||||
// assign selected to group
|
||||
!props.creditNote && assignTempGroup();
|
||||
assignTempGroup();
|
||||
|
||||
// match group to check
|
||||
selectedEmployee.value = [];
|
||||
|
|
@ -232,7 +235,7 @@ function onDialogOpen() {
|
|||
const matchingItems = tempGroupEdit.value
|
||||
.flatMap((g) => g.list)
|
||||
.filter((l) => {
|
||||
if (l.stepStatus.length === 0) {
|
||||
if (!l.stepStatus || l.stepStatus.length === 0) {
|
||||
return taskList.value.some(
|
||||
(t) => t.requestWorkStep?.requestWork.id === l.id,
|
||||
);
|
||||
|
|
@ -248,8 +251,12 @@ function onDialogOpen() {
|
|||
function assignTempGroup() {
|
||||
if (!props.taskListGroup) return;
|
||||
props.taskListGroup.forEach((newGroup) => {
|
||||
const productId = props.creditNote
|
||||
? (newGroup.product as RequestWork['productService']).productId
|
||||
: (newGroup.product as RequestWork['productService']['product']).id;
|
||||
|
||||
const existingGroup = tempGroupEdit.value.find(
|
||||
(g) => g.product.id === newGroup.product.id,
|
||||
(g) => g.product.id === productId,
|
||||
);
|
||||
|
||||
if (existingGroup) {
|
||||
|
|
@ -260,7 +267,9 @@ function assignTempGroup() {
|
|||
});
|
||||
} else {
|
||||
tempGroupEdit.value.push({
|
||||
...newGroup,
|
||||
product: props.creditNote
|
||||
? (newGroup.product as RequestWork['productService']).product
|
||||
: (newGroup.product as RequestWork['productService']['product']),
|
||||
list: [...newGroup.list], // Ensure a new reference
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,13 @@ import SelectReadyRequestWork from '../09_task-order/SelectReadyRequestWork.vue'
|
|||
import RefundInformation from './RefundInformation.vue';
|
||||
import QuotationFormReceipt from '../05_quotation/QuotationFormReceipt.vue';
|
||||
import DialogViewFile from 'src/components/dialog/DialogViewFile.vue';
|
||||
import { MainButton, SaveButton } from 'src/components/button';
|
||||
import {
|
||||
MainButton,
|
||||
SaveButton,
|
||||
CancelButton,
|
||||
EditButton,
|
||||
UndoButton,
|
||||
} from 'src/components/button';
|
||||
import { RequestWork } from 'src/stores/request-list/types';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useOptionStore from 'src/stores/options';
|
||||
|
|
@ -76,15 +82,16 @@ const statusTabForm = ref<
|
|||
}[]
|
||||
>([]);
|
||||
|
||||
const readonly = computed(
|
||||
() =>
|
||||
creditNoteData.value?.creditNoteStatus === CreditNoteStatus.Pending ||
|
||||
creditNoteData.value?.creditNoteStatus === CreditNoteStatus.Success,
|
||||
);
|
||||
// const readonly = computed(
|
||||
// () =>
|
||||
// creditNoteData.value?.creditNoteStatus === CreditNoteStatus.Pending ||
|
||||
// creditNoteData.value?.creditNoteStatus === CreditNoteStatus.Success,
|
||||
// );
|
||||
|
||||
const pageState = reactive({
|
||||
productDialog: false,
|
||||
fileDialog: false,
|
||||
mode: 'view' as 'view' | 'edit' | 'info',
|
||||
});
|
||||
|
||||
const defaultRemark = '#[quotation-labor]<br/><br/>#[quotation-payment]';
|
||||
|
|
@ -161,9 +168,11 @@ async function initStatus() {
|
|||
{
|
||||
title: 'Pending',
|
||||
status: creditNoteData.value?.id
|
||||
? creditNoteData.value.creditNoteStatus === CreditNoteStatus.Success
|
||||
? 'done'
|
||||
: 'doing'
|
||||
? creditNoteData.value.creditNoteStatus === CreditNoteStatus.Waiting
|
||||
? 'waiting'
|
||||
: creditNoteData.value.creditNoteStatus === CreditNoteStatus.Success
|
||||
? 'done'
|
||||
: 'doing'
|
||||
: 'waiting',
|
||||
active: () => view.value === CreditNoteStatus.Pending,
|
||||
handler: async () => {
|
||||
|
|
@ -253,8 +262,9 @@ function assignFormData() {
|
|||
requestWorkStep: {
|
||||
requestWork: {
|
||||
...v,
|
||||
stepStatus: v.stepStatus || [],
|
||||
request: { ...v.request, quotation: current.quotation },
|
||||
},
|
||||
} as RequestWork,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
|
@ -285,12 +295,24 @@ async function getQuotation() {
|
|||
|
||||
async function submit() {
|
||||
const payload = formData.value;
|
||||
|
||||
payload.requestWorkId = formTaskList.value.map((v) => v.requestWorkId);
|
||||
payload.quotationId =
|
||||
typeof route.query['quotationId'] === 'string'
|
||||
? route.query['quotationId']
|
||||
: '';
|
||||
const res = await creditNote.createCreditNote(payload);
|
||||
(pageState.mode === 'edit'
|
||||
? creditNoteData.value?.quotationId
|
||||
: typeof route.query['quotationId'] === 'string'
|
||||
? route.query['quotationId']
|
||||
: '') || '';
|
||||
|
||||
const res =
|
||||
pageState.mode === 'edit'
|
||||
? await creditNote.updateCreditNote(
|
||||
creditNoteData.value?.id || '',
|
||||
payload,
|
||||
)
|
||||
: creditNoteData.value
|
||||
? await creditNote.acceptCreditNote(creditNoteData.value.id)
|
||||
: await creditNote.createCreditNote(payload);
|
||||
|
||||
if (res) {
|
||||
await router.push(`/credit-note/${res.id}`);
|
||||
|
|
@ -302,6 +324,7 @@ async function submit() {
|
|||
}
|
||||
|
||||
initStatus();
|
||||
pageState.mode = 'info';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -526,13 +549,31 @@ function storeDataLocal() {
|
|||
window.open(url, '_blank');
|
||||
}
|
||||
|
||||
function closeTab() {
|
||||
dialogWarningClose(t, {
|
||||
message: t('dialog.message.close'),
|
||||
action: () => {
|
||||
window.close();
|
||||
},
|
||||
cancel: () => {},
|
||||
});
|
||||
}
|
||||
|
||||
function undo() {
|
||||
assignFormData();
|
||||
pageState.mode = 'info';
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
initTheme();
|
||||
initLang();
|
||||
await useConfigStore().getConfig();
|
||||
await getCreditNote();
|
||||
await getQuotation();
|
||||
creditNoteData.value && (await getFileList(creditNoteData.value.id, true));
|
||||
if (creditNoteData.value) {
|
||||
pageState.mode = 'info';
|
||||
await getFileList(creditNoteData.value.id, true);
|
||||
}
|
||||
initStatus();
|
||||
});
|
||||
</script>
|
||||
|
|
@ -587,7 +628,7 @@ onMounted(async () => {
|
|||
:key="i.title"
|
||||
:label="
|
||||
$t(
|
||||
`creditNote${i.title === 'title' ? '' : '.stats'}.${i.title}`,
|
||||
`creditNote${i.title === 'title' ? '' : '.status'}.${i.title}`,
|
||||
)
|
||||
"
|
||||
:status-active="i.active?.()"
|
||||
|
|
@ -616,7 +657,7 @@ onMounted(async () => {
|
|||
>
|
||||
<CreditNoteExpansion
|
||||
v-if="view === null"
|
||||
:readonly="readonly"
|
||||
:readonly="pageState.mode === 'info'"
|
||||
v-model:reason="formData.reason"
|
||||
v-model:detail="formData.detail"
|
||||
/>
|
||||
|
|
@ -625,7 +666,7 @@ onMounted(async () => {
|
|||
<ProductExpansion
|
||||
v-if="view === null"
|
||||
creditNote
|
||||
:readonly="readonly"
|
||||
:readonly="pageState.mode === 'info'"
|
||||
:agentPrice="quotationData?.agentPrice"
|
||||
:task-list="taskListGroup"
|
||||
@add-product="openProductDialog"
|
||||
|
|
@ -633,7 +674,7 @@ onMounted(async () => {
|
|||
|
||||
<PaymentExpansion
|
||||
v-if="view === null"
|
||||
:readonly="readonly"
|
||||
:readonly="pageState.mode === 'info'"
|
||||
:total-price="summaryPrice.finalPrice"
|
||||
v-model:payback-type="formData.paybackType"
|
||||
v-model:payback-bank="formData.paybackBank"
|
||||
|
|
@ -746,7 +787,7 @@ onMounted(async () => {
|
|||
v-model:remark="formData.remark"
|
||||
:default-remark="defaultRemark"
|
||||
:items="[]"
|
||||
:readonly
|
||||
:readonly="pageState.mode === 'info'"
|
||||
>
|
||||
<template #hint>
|
||||
{{ $t('general.hintRemark') }}
|
||||
|
|
@ -793,7 +834,7 @@ onMounted(async () => {
|
|||
|
||||
<!-- SEC: footer -->
|
||||
<footer class="surface-1 q-pa-md full-width">
|
||||
<nav class="row justify-end">
|
||||
<nav class="row justify-end" style="gap: var(--size-2)">
|
||||
<!-- TODO: view example -->
|
||||
<MainButton
|
||||
class="q-mr-auto"
|
||||
|
|
@ -804,16 +845,48 @@ onMounted(async () => {
|
|||
>
|
||||
{{ $t('general.view', { msg: $t('general.example') }) }}
|
||||
</MainButton>
|
||||
<!-- @click="submit" -->
|
||||
|
||||
<UndoButton v-if="pageState.mode === 'edit'" outlined @click="undo()" />
|
||||
<CancelButton
|
||||
v-if="
|
||||
pageState.mode === 'info' &&
|
||||
creditNoteData?.creditNoteStatus === CreditNoteStatus.Waiting
|
||||
"
|
||||
@click="closeTab()"
|
||||
:label="$t('dialog.action.close')"
|
||||
outlined
|
||||
/>
|
||||
<SaveButton
|
||||
v-if="!readonly"
|
||||
:disabled="taskListGroup.length === 0"
|
||||
v-if="
|
||||
!creditNoteData ||
|
||||
creditNoteData?.creditNoteStatus === CreditNoteStatus.Waiting
|
||||
"
|
||||
:disabled="taskListGroup.length === 0 || pageState.mode === 'edit'"
|
||||
type="submit"
|
||||
@click.stop="(e) => refForm?.submit(e)"
|
||||
:label="$t('creditNote.label.submit')"
|
||||
:label="
|
||||
$t(
|
||||
`creditNote.label.${creditNoteData?.creditNoteStatus ? 'submit' : 'request'}`,
|
||||
)
|
||||
"
|
||||
icon="mdi-account-multiple-check-outline"
|
||||
solid
|
||||
></SaveButton>
|
||||
/>
|
||||
<SaveButton
|
||||
v-if="pageState.mode === 'edit'"
|
||||
:disabled="taskListGroup.length === 0"
|
||||
@click="(e) => refForm?.submit(e)"
|
||||
solid
|
||||
/>
|
||||
<EditButton
|
||||
v-if="
|
||||
pageState.mode === 'info' &&
|
||||
creditNoteData?.creditNoteStatus === CreditNoteStatus.Waiting
|
||||
"
|
||||
class="no-print"
|
||||
@click="pageState.mode = 'edit'"
|
||||
solid
|
||||
/>
|
||||
</nav>
|
||||
</footer>
|
||||
</div>
|
||||
|
|
@ -822,6 +895,7 @@ onMounted(async () => {
|
|||
<SelectReadyRequestWork
|
||||
v-if="quotationData"
|
||||
creditNote
|
||||
:task-list-group="taskListGroup"
|
||||
:fetch-params="{ cancelOnly: true, quotationId: quotationData.id }"
|
||||
v-model:open="pageState.productDialog"
|
||||
v-model:task-list="formTaskList"
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ const { stats, pageMax, page, data, pageSize } = storeToRefs(creditNote);
|
|||
// NOTE: Variable
|
||||
const pageState = reactive({
|
||||
quotationId: '',
|
||||
currentTab: CreditNoteStatus.Pending,
|
||||
currentTab: CreditNoteStatus.Waiting,
|
||||
hideStat: false,
|
||||
statusFilter: 'None',
|
||||
inputSearch: '',
|
||||
|
|
@ -180,16 +180,22 @@ watch(
|
|||
<StatCardComponent
|
||||
labelI18n
|
||||
:branch="[
|
||||
{
|
||||
icon: 'icon-park-outline:loading-one',
|
||||
count: stats[CreditNoteStatus.Pending] || 0,
|
||||
label: `creditNote.status.${CreditNoteStatus.Waiting}`,
|
||||
color: 'light-yellow',
|
||||
},
|
||||
{
|
||||
icon: 'material-symbols-light:receipt-long',
|
||||
count: stats[CreditNoteStatus.Pending] || 0,
|
||||
label: `creditNote.stats.${CreditNoteStatus.Pending}`,
|
||||
label: `creditNote.status.${CreditNoteStatus.Pending}`,
|
||||
color: 'orange',
|
||||
},
|
||||
{
|
||||
icon: 'mdi-check-decagram-outline',
|
||||
count: stats[CreditNoteStatus.Success] || 0,
|
||||
label: `creditNote.stats.${CreditNoteStatus.Success}`,
|
||||
label: `creditNote.status.${CreditNoteStatus.Success}`,
|
||||
color: 'blue',
|
||||
},
|
||||
]"
|
||||
|
|
@ -345,7 +351,7 @@ watch(
|
|||
<TableCreditNote
|
||||
:grid="pageState.gridView"
|
||||
:visible-columns="pageState.fieldSelected"
|
||||
:hide-delete="pageState.currentTab === CreditNoteStatus.Success"
|
||||
:hide-delete="pageState.currentTab !== CreditNoteStatus.Waiting"
|
||||
@view="(v) => navigateTo({ statusDialog: 'info', creditId: v.id })"
|
||||
@delete="(v) => triggerDelete(v.id)"
|
||||
>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue