chore: install prettier
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
<template>
|
||||
<div class="px-3">
|
||||
<div v-if="loadingData" class="has-text-centered py-5">
|
||||
<div
|
||||
v-if="loadingData"
|
||||
class="has-text-centered py-5"
|
||||
>
|
||||
<SvgIcon v-bind="{ name: 'loading.svg', type: 'primary', size: 18 }" />
|
||||
<p class="mt-2">
|
||||
{{ isVietnamese ? "Đang tải thông tin công nợ..." : "Loading payment schedule information..." }}
|
||||
@@ -17,11 +20,17 @@
|
||||
</div>
|
||||
<div class="column is-3">
|
||||
<strong>{{ isVietnamese ? "Trạng thái:" : "Status:" }}</strong>
|
||||
<p :class="{
|
||||
'has-text-success': paymentScheduleData.status__name === 'Đã xác nhận' || paymentScheduleData.status__name === 'Paid',
|
||||
'has-text-warning': paymentScheduleData.status__name === 'Chưa xác nhận' || paymentScheduleData.status__name === 'Pending',
|
||||
'has-text-danger': paymentScheduleData.status__name === 'Quá hạn' || paymentScheduleData.status__name === 'Overdue'
|
||||
}">
|
||||
<p
|
||||
:class="{
|
||||
'has-text-success':
|
||||
paymentScheduleData.status__name === 'Đã xác nhận' || paymentScheduleData.status__name === 'Paid',
|
||||
'has-text-warning':
|
||||
paymentScheduleData.status__name === 'Chưa xác nhận' ||
|
||||
paymentScheduleData.status__name === 'Pending',
|
||||
'has-text-danger':
|
||||
paymentScheduleData.status__name === 'Quá hạn' || paymentScheduleData.status__name === 'Overdue',
|
||||
}"
|
||||
>
|
||||
{{ paymentScheduleData.status__name || "-" }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -35,24 +44,37 @@
|
||||
</div>
|
||||
<div class="column is-3">
|
||||
<strong>{{ isVietnamese ? "Tiền gốc theo kỳ thanh toán:" : "Amount:" }}</strong>
|
||||
<p class="has-text-weight-bold has-text-primary">{{ $numtoString(paymentScheduleData.amount) }}</p>
|
||||
<p class="has-text-weight-bold has-text-primary">
|
||||
{{ $numtoString(paymentScheduleData.amount) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="column is-3">
|
||||
<strong>{{ isVietnamese ? "Số tiền gốc đã thanh toán:" : "Paid Amount:" }}</strong>
|
||||
<p class="has-text-weight-bold has-text-primary">{{ $numtoString(paymentScheduleData.paid_amount) }}</p>
|
||||
<p class="has-text-weight-bold has-text-primary">
|
||||
{{ $numtoString(paymentScheduleData.paid_amount) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="column is-3">
|
||||
<strong>{{ isVietnamese ? "Số tiền gốc còn lại:" : "Remaining Principal:" }}</strong>
|
||||
<p class="has-text-weight-bold"
|
||||
:class="paymentScheduleData.amount_remain > 0 ? 'has-text-danger' : 'has-text-success'">
|
||||
<p
|
||||
class="has-text-weight-bold"
|
||||
:class="paymentScheduleData.amount_remain > 0 ? 'has-text-danger' : 'has-text-success'"
|
||||
>
|
||||
{{ $numtoString(paymentScheduleData.amount_remain) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="column is-3">
|
||||
<strong>{{ isVietnamese ? "Ngày đến hạn:" : "Due Date:" }}</strong>
|
||||
<p :class="{ 'has-text-danger': isOverdue(paymentScheduleData.to_date && paymentScheduleData.ovd_days > 0) }">
|
||||
<p
|
||||
:class="{
|
||||
'has-text-danger': isOverdue(paymentScheduleData.to_date && paymentScheduleData.ovd_days > 0),
|
||||
}"
|
||||
>
|
||||
{{ formatDate(paymentScheduleData.to_date) }}
|
||||
<span v-if="isOverdue(paymentScheduleData.to_date && paymentScheduleData.ovd_days > 0 )" class="has-text-weight-bold">
|
||||
<span
|
||||
v-if="isOverdue(paymentScheduleData.to_date && paymentScheduleData.ovd_days > 0)"
|
||||
class="has-text-weight-bold"
|
||||
>
|
||||
(Quá hạn {{ paymentScheduleData.ovd_days }} ngày)
|
||||
</span>
|
||||
</p>
|
||||
@@ -83,30 +105,39 @@
|
||||
</div>
|
||||
<div class="column is-3">
|
||||
<strong>{{ isVietnamese ? "Tổng tiền phải thanh toán:" : "Total Remaining:" }}</strong>
|
||||
<p class="has-text-weight-bold has-text-primary">{{ $numtoString(paymentScheduleData.remain_amount) }}</p>
|
||||
<p class="has-text-weight-bold has-text-primary">
|
||||
{{ $numtoString(paymentScheduleData.remain_amount) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="column is-3">
|
||||
<strong>{{ isVietnamese ? "Ghi chú:" : "Note:" }}</strong>
|
||||
<p class="is-size-6">{{ paymentScheduleData.detail?.note || "-" }}</p>
|
||||
<p class="is-size-6">
|
||||
{{ paymentScheduleData.detail?.note || "-" }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Timeline lịch sử -->
|
||||
|
||||
|
||||
<div v-if="processedEntries.length > 0" class="is-flex is-flex-direction-column is-gap-5" >
|
||||
|
||||
<div v-for="(item, index) in processedEntries" :key="index" class="is-flex is-align-items-start is-gap-4">
|
||||
<div style="min-width: 3rem;">
|
||||
<div
|
||||
v-if="processedEntries.length > 0"
|
||||
class="is-flex is-flex-direction-column is-gap-5"
|
||||
>
|
||||
<div
|
||||
v-for="(item, index) in processedEntries"
|
||||
:key="index"
|
||||
class="is-flex is-align-items-start is-gap-4"
|
||||
>
|
||||
<div style="min-width: 3rem">
|
||||
<p class="is-size-5 has-text-weight-bold has-text-primary">
|
||||
{{ formatDate(item.entry.date) }}
|
||||
</p>
|
||||
<p v-if="item.entry.code" class="is-size-6 has-text-grey">
|
||||
<p
|
||||
v-if="item.entry.code"
|
||||
class="is-size-6 has-text-grey"
|
||||
>
|
||||
{{ item.entry.code }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -114,48 +145,71 @@
|
||||
<div class="is-flex-grow-1">
|
||||
<p class="is-size-5 has-text-weight-bold has-text-dark mb-2">
|
||||
{{ getEntryTypeLabel(item.entry.type) }}
|
||||
<span v-if="item.entry.code" class="tag is-link is-light ml-2">
|
||||
<span
|
||||
v-if="item.entry.code"
|
||||
class="tag is-link is-light ml-2"
|
||||
>
|
||||
{{ item.entry.code }}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<div class="box is-shadowless p-4" style="border-left: 5px solid #204853;">
|
||||
<div
|
||||
class="box is-shadowless p-4"
|
||||
style="border-left: 5px solid #204853"
|
||||
>
|
||||
<div class="columns is-mobile is-multiline is-gap-3">
|
||||
<div class="column is-6-mobile">
|
||||
<span class="has-text-grey-light">Gốc trả:</span><br />
|
||||
<span v-if="item.entry.principal > 0" class="has-text-success has-text-weight-semibold is-size-5">
|
||||
<span
|
||||
v-if="item.entry.principal > 0"
|
||||
class="has-text-success has-text-weight-semibold is-size-5"
|
||||
>
|
||||
{{ $numtoString(item.entry.principal) }}
|
||||
</span>
|
||||
<span v-else class="has-text-grey-light">-</span>
|
||||
<span
|
||||
v-else
|
||||
class="has-text-grey-light"
|
||||
>-</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="column is-6-mobile">
|
||||
<span class="has-text-grey-light">Lãi trả:</span><br />
|
||||
<span v-if="item.entry.penalty > 0" class="has-text-danger has-text-weight-semibold is-size-5">
|
||||
<span
|
||||
v-if="item.entry.penalty > 0"
|
||||
class="has-text-danger has-text-weight-semibold is-size-5"
|
||||
>
|
||||
{{ $numtoString(item.entry.penalty) }}
|
||||
</span>
|
||||
<span v-else class="has-text-grey-light">-</span>
|
||||
<span
|
||||
v-else
|
||||
class="has-text-grey-light"
|
||||
>-</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="column is-6-mobile">
|
||||
<span class="has-text-grey-light">Gốc còn lại :</span><br />
|
||||
<strong :class="item.principalRemain > 0 ? 'has-text-danger' : 'has-text-success'"
|
||||
class="is-size-5">
|
||||
<strong
|
||||
:class="item.principalRemain > 0 ? 'has-text-danger' : 'has-text-success'"
|
||||
class="is-size-5"
|
||||
>
|
||||
{{ $numtoString(item.principalRemain) }}
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Chi tiết lãi phát sinh -->
|
||||
<div class="">
|
||||
<!-- Diễn giải chi tiết cách tính lãi kỳ này -->
|
||||
<p v-if="item.penaltyThisPeriod > 0" class="is-size-6 has-text-grey">
|
||||
Dư nợ gốc còn lại: {{ $numtoString(item.principalBefore) }} ×
|
||||
{{ item.penaltyDetail.days }} ngày (từ {{ item.penaltyDetail.from }} đến {{ item.penaltyDetail.to
|
||||
}}) × {{item.rate}}%/ngày = {{ $numtoString(item.penaltyThisPeriod) }}
|
||||
<p
|
||||
v-if="item.penaltyThisPeriod > 0"
|
||||
class="is-size-6 has-text-grey"
|
||||
>
|
||||
Dư nợ gốc còn lại:
|
||||
{{ $numtoString(item.principalBefore) }} × {{ item.penaltyDetail.days }} ngày (từ
|
||||
{{ item.penaltyDetail.from }} đến {{ item.penaltyDetail.to }}) × {{ item.rate }}%/ngày =
|
||||
{{ $numtoString(item.penaltyThisPeriod) }}
|
||||
</p>
|
||||
|
||||
<p class="is-size-6 mt-3">
|
||||
@@ -171,18 +225,30 @@
|
||||
</div>
|
||||
|
||||
<!-- Tiền lãi hiện tại (nếu chưa hết nợ) -->
|
||||
<div v-if="hasUnpaidDebt && latestPenaltyToThisEntry != paymentScheduleData.penalty_amount && processedEntries.length > 0 && latestPenaltyToThisEntry >0" class="mt-5 box has-background-warning-light">
|
||||
|
||||
<div
|
||||
v-if="
|
||||
hasUnpaidDebt &&
|
||||
latestPenaltyToThisEntry != paymentScheduleData.penalty_amount &&
|
||||
processedEntries.length > 0 &&
|
||||
latestPenaltyToThisEntry > 0
|
||||
"
|
||||
class="mt-5 box has-background-warning-light"
|
||||
>
|
||||
<p class="is-size-5">
|
||||
<strong>Lãi đến ngày thanh toán gần nhất ({{ latestEntryDate }}) :</strong> {{ $numtoString(latestPenaltyToThisEntry) }}
|
||||
<strong>Lãi đến ngày thanh toán gần nhất ({{ latestEntryDate }}) :</strong>
|
||||
{{ $numtoString(latestPenaltyToThisEntry) }}
|
||||
</p>
|
||||
<p v-if="latestAdditionalPenalty > 0" class="is-size-5 mt-2">
|
||||
<strong>Lãi phát sinh từ ngày {{ latestEntryDate }} đến nay:</strong> {{
|
||||
$numtoString(latestAdditionalPenalty) }}
|
||||
<p
|
||||
v-if="latestAdditionalPenalty > 0"
|
||||
class="is-size-5 mt-2"
|
||||
>
|
||||
<strong>Lãi phát sinh từ ngày {{ latestEntryDate }} đến nay:</strong>
|
||||
{{ $numtoString(latestAdditionalPenalty) }}
|
||||
</p>
|
||||
<p class="is-size-5 has-text-weight-bold mt-3">
|
||||
Tổng lãi hiện tại : {{
|
||||
$numtoString(latestPenaltyToThisEntry) }} + {{ $numtoString(latestAdditionalPenalty) }} = {{ $numtoString(paymentScheduleData.penalty_amount) }}
|
||||
Tổng lãi hiện tại : {{ $numtoString(latestPenaltyToThisEntry) }} +
|
||||
{{ $numtoString(latestAdditionalPenalty) }} =
|
||||
{{ $numtoString(paymentScheduleData.penalty_amount) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -192,44 +258,68 @@
|
||||
<div class="columns is-mobile is-multiline">
|
||||
<div class="column is-3-tablet is-6-mobile">
|
||||
<p class="heading">Gốc đã trả</p>
|
||||
<p class="title is-5 has-text-success">{{ $numtoString(paymentScheduleData.paid_amount) }}</p>
|
||||
<p class="title is-5 has-text-success">
|
||||
{{ $numtoString(paymentScheduleData.paid_amount) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="column is-3-tablet is-6-mobile">
|
||||
<p class="heading">Gốc còn lại</p>
|
||||
<p class="title is-5"
|
||||
:class="paymentScheduleData.amount_remain > 0 ? 'has-text-danger' : 'has-text-success'">
|
||||
<p
|
||||
class="title is-5"
|
||||
:class="paymentScheduleData.amount_remain > 0 ? 'has-text-danger' : 'has-text-success'"
|
||||
>
|
||||
{{ $numtoString(paymentScheduleData.amount_remain) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="column is-3-tablet is-6-mobile">
|
||||
<p class="heading">Lãi đã trả</p>
|
||||
<p class="title is-5 has-text-success">{{ $numtoString(paymentScheduleData.penalty_paid) }}</p>
|
||||
<p class="title is-5 has-text-success">
|
||||
{{ $numtoString(paymentScheduleData.penalty_paid) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="column is-3-tablet is-6-mobile">
|
||||
<p class="heading">Lãi còn lại</p>
|
||||
<p class="title is-5"
|
||||
:class="paymentScheduleData.penalty_remain > 0 ? 'has-text-danger' : 'has-text-success'">
|
||||
<p
|
||||
class="title is-5"
|
||||
:class="paymentScheduleData.penalty_remain > 0 ? 'has-text-danger' : 'has-text-success'"
|
||||
>
|
||||
{{ $numtoString(paymentScheduleData.penalty_remain) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="column is-3-tablet is-6-mobile">
|
||||
<p class="heading">Tổng tiền phải thanh toán</p>
|
||||
<p class="title is-5 has-text-primary">{{ $numtoString(paymentScheduleData.remain_amount) }}</p>
|
||||
<p class="title is-5 has-text-primary">
|
||||
{{ $numtoString(paymentScheduleData.remain_amount) }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isConfirmAllowed && $getEditRights()" class="field is-grouped is-grouped-left ">
|
||||
<div
|
||||
v-if="isConfirmAllowed && $getEditRights()"
|
||||
class="field is-grouped is-grouped-left"
|
||||
>
|
||||
<p class="control">
|
||||
<button class="button is-info mx-3 has-text-white" @click="handleViewEmail">
|
||||
<button
|
||||
class="button is-info mx-3 has-text-white"
|
||||
@click="handleViewEmail"
|
||||
>
|
||||
<span>Gửi thông báo</span>
|
||||
</button>
|
||||
<button v-if="paymentScheduleData.batch_date == null" class="button is-danger has-text-white"
|
||||
:class="{ 'is-loading': isLoading }" @click="getPenalty" :disabled="isLoading">
|
||||
<button
|
||||
v-if="paymentScheduleData.batch_date == null"
|
||||
class="button is-danger has-text-white"
|
||||
:class="{ 'is-loading': isLoading }"
|
||||
@click="getPenalty"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
<span>Tính lãi</span>
|
||||
</button>
|
||||
</p>
|
||||
<Modal @close="showModalViewEmail = undefined" v-bind="showModalViewEmail" v-if="showModalViewEmail"></Modal>
|
||||
<Modal
|
||||
@close="showModalViewEmail = undefined"
|
||||
v-bind="showModalViewEmail"
|
||||
v-if="showModalViewEmail"
|
||||
></Modal>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -293,7 +383,7 @@ const processedEntries = computed(() => {
|
||||
if (!paymentScheduleData.value?.entry) return [];
|
||||
|
||||
const relevantEntries = paymentScheduleData.value.entry.filter(
|
||||
(e) => e.type === "PAYMENT" && e.penalty_added_to_entry !== undefined
|
||||
(e) => e.type === "PAYMENT" && e.penalty_added_to_entry !== undefined,
|
||||
);
|
||||
|
||||
relevantEntries.sort((a, b) => new Date(a.date) - new Date(b.date));
|
||||
@@ -337,7 +427,7 @@ const processedEntries = computed(() => {
|
||||
penaltyAccumulated: totalPenaltyAccumulated,
|
||||
penaltyThisPeriod,
|
||||
penaltyRemain,
|
||||
rate:Number(entry.DAILY_PENALTY_RATE || 0)*100,
|
||||
rate: Number(entry.DAILY_PENALTY_RATE || 0) * 100,
|
||||
totalDebt: Number(entry.amount_remain_after_allocation || 0) + penaltyThisPeriod,
|
||||
penaltyDetail: {
|
||||
from: lastEventDate.format("DD/MM/YYYY"),
|
||||
@@ -354,17 +444,14 @@ const processedEntries = computed(() => {
|
||||
const latestEntry = computed(() => {
|
||||
if (!paymentScheduleData.value?.entry?.length) return null;
|
||||
const paymentEntries = paymentScheduleData.value.entry.filter(
|
||||
e => e.type === "PAYMENT" && e.penalty_to_this_entry !== undefined
|
||||
(e) => e.type === "PAYMENT" && e.penalty_to_this_entry !== undefined,
|
||||
);
|
||||
if (paymentEntries.length === 0) return null;
|
||||
return paymentEntries[paymentEntries.length - 1];
|
||||
});
|
||||
|
||||
const hasUnpaidDebt = computed(() => {
|
||||
return (
|
||||
paymentScheduleData.value?.amount_remain > 0 ||
|
||||
paymentScheduleData.value?.penalty_remain > 0
|
||||
);
|
||||
return paymentScheduleData.value?.amount_remain > 0 || paymentScheduleData.value?.penalty_remain > 0;
|
||||
});
|
||||
|
||||
const latestPenaltyToThisEntry = computed(() => {
|
||||
@@ -407,7 +494,7 @@ const fetchPaymentScheduleData = async () => {
|
||||
$snackbar(
|
||||
isVietnamese.value ? "Không thể tải thông tin công nợ." : "Failed to load payment schedule information.",
|
||||
"Lỗi",
|
||||
"Error"
|
||||
"Error",
|
||||
);
|
||||
} finally {
|
||||
loadingData.value = false;
|
||||
@@ -439,7 +526,7 @@ const handleUpdateInvoice = async () => {
|
||||
$snackbar(
|
||||
isVietnamese.value ? "Vui lòng nhập đầy đủ link và mã xác thực" : "Please enter both link and reference code",
|
||||
"Cảnh báo",
|
||||
"Warning"
|
||||
"Warning",
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -454,22 +541,18 @@ const handleUpdateInvoice = async () => {
|
||||
ref_code: invoiceData.value.ref_code,
|
||||
},
|
||||
undefined,
|
||||
false
|
||||
false,
|
||||
);
|
||||
if (response === "error" || !response) throw new Error("Update failed");
|
||||
$snackbar(
|
||||
isVietnamese.value ? "Cập nhật hóa đơn thành công!" : "Invoice updated successfully!",
|
||||
"Thành công",
|
||||
"Success"
|
||||
"Success",
|
||||
);
|
||||
await fetchPaymentScheduleData();
|
||||
} catch (error) {
|
||||
console.error("Error updating invoice:", error);
|
||||
$snackbar(
|
||||
isVietnamese.value ? "Có lỗi xảy ra khi cập nhật hóa đơn" : "Error updating invoice",
|
||||
"Lỗi",
|
||||
"Error"
|
||||
);
|
||||
$snackbar(isVietnamese.value ? "Có lỗi xảy ra khi cập nhật hóa đơn" : "Error updating invoice", "Lỗi", "Error");
|
||||
} finally {
|
||||
isUpdatingInvoice.value = false;
|
||||
}
|
||||
@@ -497,7 +580,7 @@ async function handleViewEmail() {
|
||||
"emailtemplate",
|
||||
{ name: "Mail Thông báo đến hạn thanh toán" },
|
||||
undefined,
|
||||
false
|
||||
false,
|
||||
);
|
||||
showModalViewEmail.value = {
|
||||
component: "marketing/email/viewEmail/ViewEmail",
|
||||
@@ -507,7 +590,7 @@ async function handleViewEmail() {
|
||||
idEmailTemplate: emailTemplate[0]?.id || null,
|
||||
scheduleItemId: props.scheduleItemId,
|
||||
},
|
||||
onConfirm: () => { },
|
||||
onConfirm: () => {},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -522,4 +605,4 @@ const handleConfirmDelete = () => {
|
||||
onMounted(() => {
|
||||
fetchPaymentScheduleData();
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user