feat: invoice (#174)
* feat: add 10 invoice * feat: invoicelayout * feat: invoicetable * refactor: uew new table * fix: columns missing * feat: invoicebadgestatus * feat: formatdate #156 * refactor: watch pagesize and page #159 * refector: filter status #160 * feat: invoice stats * fix: typo * chore: cleanup * refactor: add columns action * refactor: add btn view invoice * refactor: add query tab * refactor: change set code invoice to function * chore: change case * refactor: add i18n netvalue * refactor: add record colors of status invoice * feat: add view card invoice * chore: cleanpu * refactor: handle i18n pay condition * refactor: handle value by storage or by api * refactor: add btnn preview * refactor: function view doc example * refactor: bind function view doc example --------- Co-authored-by: Thanaphon Frappet <thanaphon@frappet.com> Co-authored-by: nwpptrs <jay02499@gmail.com> Co-authored-by: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Co-authored-by: oat_dev <nattapon@frappet.com>
This commit is contained in:
parent
7d1f32a5cb
commit
c5d3897d76
12 changed files with 801 additions and 86 deletions
|
|
@ -356,18 +356,8 @@ async function fetchStatus() {
|
|||
code.value = '';
|
||||
selectedInstallmentNo.value = [];
|
||||
selectedInstallment.value = [];
|
||||
view.value =
|
||||
quotationFormData.value.payCondition === 'Full' ||
|
||||
quotationFormData.value.payCondition === 'BillFull'
|
||||
? View.Invoice
|
||||
: View.InvoicePre;
|
||||
|
||||
if (
|
||||
quotationFormData.value.payCondition === 'Full' ||
|
||||
quotationFormData.value.payCondition === 'BillFull'
|
||||
) {
|
||||
getInvoiceCodeFullPay();
|
||||
}
|
||||
getInvoice();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -1011,35 +1001,7 @@ onMounted(async () => {
|
|||
pageState.isLoaded = true;
|
||||
|
||||
if (route.query['tab'] === 'invoice') {
|
||||
if (route.query['id']) {
|
||||
const queryInvoiceId = route.query['id'] as string;
|
||||
const queryInvoiceAmount = Number(route.query['amount']) || 0;
|
||||
|
||||
await getInvoiceCode(queryInvoiceId);
|
||||
|
||||
selectedInstallmentNo.value =
|
||||
quotationFormState.value.source?.paySplit
|
||||
.filter((v) => v.invoiceId === queryInvoiceId)
|
||||
.map((v) => v.no) || [];
|
||||
|
||||
installmentAmount.value = queryInvoiceAmount;
|
||||
view.value = View.Invoice;
|
||||
return;
|
||||
}
|
||||
selectedInstallmentNo.value = [];
|
||||
selectedInstallment.value = [];
|
||||
view.value =
|
||||
quotationFormData.value.payCondition === 'Full' ||
|
||||
quotationFormData.value.payCondition === 'BillFull'
|
||||
? View.Invoice
|
||||
: View.InvoicePre;
|
||||
|
||||
if (
|
||||
quotationFormData.value.payCondition === 'Full' ||
|
||||
quotationFormData.value.payCondition === 'BillFull'
|
||||
) {
|
||||
getInvoiceCodeFullPay();
|
||||
}
|
||||
getInvoice();
|
||||
}
|
||||
if (route.query['tab'] === 'receipt') {
|
||||
await fetchReceipt();
|
||||
|
|
@ -1241,6 +1203,23 @@ async function exampleReceipt(id: string) {
|
|||
}
|
||||
}
|
||||
|
||||
function getInvoice() {
|
||||
view.value =
|
||||
quotationFormData.value.payCondition === 'Full' ||
|
||||
quotationFormData.value.payCondition === 'BillFull'
|
||||
? View.Invoice
|
||||
: View.InvoicePre;
|
||||
|
||||
if (
|
||||
quotationFormData.value.payCondition === 'Full' ||
|
||||
quotationFormData.value.payCondition === 'BillFull'
|
||||
) {
|
||||
getInvoiceCodeFullPay();
|
||||
} else {
|
||||
code.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
[
|
||||
() => quotationFormState.value.statusFilterRequest,
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@ import { precisionRound } from 'src/utils/arithmetic';
|
|||
import ThaiBahtText from 'thai-baht-text';
|
||||
|
||||
// NOTE: Import stores
|
||||
import useOptionStore from 'stores/options';
|
||||
import { formatNumberDecimal } from 'stores/utils';
|
||||
import { useQuotationForm } from 'pages/05_quotation/form';
|
||||
import { useConfigStore } from 'stores/config';
|
||||
import useBranchStore from 'stores/branch';
|
||||
import { baseUrl } from 'stores/utils';
|
||||
|
|
@ -19,8 +17,8 @@ import { CustomerBranch } from 'stores/customer/types';
|
|||
import { BankBook, Branch } from 'stores/branch/types';
|
||||
import {
|
||||
QuotationPayload,
|
||||
CustomerBranchRelation,
|
||||
Details,
|
||||
QuotationFull,
|
||||
} from 'src/stores/quotations/types';
|
||||
|
||||
// NOTE: Import Components
|
||||
|
|
@ -70,9 +68,7 @@ const attachmentList = ref<
|
|||
isPDF?: boolean;
|
||||
}[]
|
||||
>([]);
|
||||
const data = ref<
|
||||
QuotationPayload & { customerBranch: CustomerBranchRelation; id: string }
|
||||
>();
|
||||
const data = ref<QuotationFull & { remark?: string }>();
|
||||
|
||||
const summaryPrice = ref<SummaryPrice>({
|
||||
totalPrice: 0,
|
||||
|
|
@ -82,6 +78,12 @@ const summaryPrice = ref<SummaryPrice>({
|
|||
finalPrice: 0,
|
||||
});
|
||||
|
||||
async function fetchQuotationById(id: string) {
|
||||
const res = await quotationStore.getQuotation(id);
|
||||
|
||||
if (res) data.value = res;
|
||||
}
|
||||
|
||||
async function getAttachment(quotationId: string) {
|
||||
const attachment = await quotationStore.listAttachment({
|
||||
parentId: quotationId,
|
||||
|
|
@ -178,10 +180,13 @@ onMounted(async () => {
|
|||
data.value = 'data' in parsed ? parsed.data : undefined;
|
||||
|
||||
if (data.value) {
|
||||
await getAttachment(data.value.id);
|
||||
if (!!data.value.id) {
|
||||
await getAttachment(data.value.id);
|
||||
await fetchQuotationById(data.value.id);
|
||||
}
|
||||
|
||||
const resCustomerBranch = await customerStore.getBranchById(
|
||||
data.value.customerBranchId,
|
||||
data.value?.customerBranchId,
|
||||
);
|
||||
|
||||
if (resCustomerBranch) {
|
||||
|
|
@ -189,19 +194,27 @@ onMounted(async () => {
|
|||
}
|
||||
|
||||
details.value = {
|
||||
code: parsed.meta.source.code,
|
||||
createdAt: parsed.meta.source.createdAt,
|
||||
createdBy: `${parsed.meta.createdBy} ${!parsed.meta.source.createdBy ? '' : parsed.meta.source.createdBy.telephoneNo}`,
|
||||
payCondition: parsed.meta.source.payCondition,
|
||||
contactName: parsed.meta.source.contactName,
|
||||
contactTel: parsed.meta.source.contactTel,
|
||||
workName: parsed.meta.source.workName,
|
||||
dueDate: parsed.meta.source.dueDate,
|
||||
worker: parsed.meta.selectedWorker,
|
||||
code: parsed?.meta?.source?.code ?? data.value?.code,
|
||||
createdAt:
|
||||
parsed?.meta?.source?.createdAt ??
|
||||
new Date(data.value?.createdAt || ''),
|
||||
createdBy:
|
||||
`${parsed?.meta?.source?.createdBy?.firstName ?? ''} ${parsed?.meta?.source?.createdBy?.telephoneNo ?? ''}`.trim() ||
|
||||
`${data.value?.createdBy?.firstName ?? ''} ${data.value?.createdBy?.telephoneNo ?? ''}`.trim(),
|
||||
payCondition:
|
||||
parsed?.meta?.source?.payCondition ?? data.value?.payCondition,
|
||||
contactName: parsed?.meta?.source?.contactName ?? data.value?.contactName,
|
||||
contactTel: parsed?.meta?.source?.contactTel ?? data.value?.contactTel,
|
||||
workName: parsed?.meta?.source?.workName ?? data.value?.workName,
|
||||
dueDate:
|
||||
parsed?.meta?.source?.dueDate ?? new Date(data.value?.dueDate || ''),
|
||||
worker:
|
||||
parsed?.meta?.selectedWorker ??
|
||||
data.value?.worker.map((v) => v.employee),
|
||||
};
|
||||
|
||||
const resBranch = await branchStore.fetchById(
|
||||
data.value?.registeredBranchId,
|
||||
data.value?.registeredBranchId ?? data.value?.registeredBranchId,
|
||||
);
|
||||
|
||||
if (resBranch) {
|
||||
|
|
@ -214,26 +227,31 @@ onMounted(async () => {
|
|||
}
|
||||
|
||||
productList.value =
|
||||
data.value?.productServiceList.map((v) => ({
|
||||
id: v.product.id,
|
||||
code: v.product.code,
|
||||
detail: v.product.name,
|
||||
amount: v.amount || 0,
|
||||
priceUnit: v.pricePerUnit || 0,
|
||||
discount: v.discount || 0,
|
||||
vat: v.vat || 0,
|
||||
value: precisionRound(
|
||||
(v.pricePerUnit || 0) * v.amount -
|
||||
(v.discount || 0) +
|
||||
(v.product.calcVat
|
||||
? ((v.pricePerUnit || 0) * v.amount - (v.discount || 0)) *
|
||||
(config.value?.vat || 0.07)
|
||||
: 0),
|
||||
),
|
||||
})) || [];
|
||||
(data?.value?.productServiceList ?? data.value?.productServiceList).map(
|
||||
(v) => ({
|
||||
id: v.product.id,
|
||||
code: v.product.code,
|
||||
detail: v.product.name,
|
||||
amount: v.amount || 0,
|
||||
priceUnit: v.pricePerUnit || 0,
|
||||
discount: v.discount || 0,
|
||||
vat: v.vat || 0,
|
||||
value: precisionRound(
|
||||
(v.pricePerUnit || 0) * v.amount -
|
||||
(v.discount || 0) +
|
||||
(v.product.calcVat
|
||||
? ((v.pricePerUnit || 0) * v.amount - (v.discount || 0)) *
|
||||
(config.value?.vat || 0.07)
|
||||
: 0),
|
||||
),
|
||||
}),
|
||||
) || [];
|
||||
}
|
||||
|
||||
summaryPrice.value = (data.value?.productServiceList || []).reduce(
|
||||
summaryPrice.value = (
|
||||
(data?.value?.productServiceList ?? data.value?.productServiceList) ||
|
||||
[]
|
||||
).reduce(
|
||||
(a, c) => {
|
||||
const price = precisionRound((c.pricePerUnit || 0) * c.amount);
|
||||
const vat = precisionRound(
|
||||
|
|
|
|||
|
|
@ -121,14 +121,7 @@ function titleMode(mode: View): string {
|
|||
<div>
|
||||
<div>เงื่อนไขการชำระ</div>
|
||||
<div>
|
||||
{{
|
||||
{
|
||||
Full: $t('quotation.type.fullAmountCash'),
|
||||
Split: $t('quotation.type.installmentsCash'),
|
||||
BillFull: $t('quotation.type.fullAmountBill'),
|
||||
BillSplit: $t('quotation.type.installmentsBill'),
|
||||
}[details.payCondition]
|
||||
}}
|
||||
{{ $t(`quotation.type.${details.payCondition}`) }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue