feat(payments): automatically notify admin and show existing invoice details when selecting student
This commit is contained in:
@@ -119,15 +119,28 @@
|
||||
<!-- Duplicate Payment Warning -->
|
||||
<div
|
||||
v-if="duplicateWarning && duplicateWarning.hasDuplicate"
|
||||
class="p-3 border-round flex align-items-start gap-2 duplicate-warning-box"
|
||||
class="p-3 border-round flex flex-column gap-2 duplicate-warning-box"
|
||||
>
|
||||
<i class="pi pi-exclamation-triangle text-xl text-yellow-400 mt-1 flex-shrink-0"></i>
|
||||
<div class="flex flex-column gap-1">
|
||||
<span class="font-bold text-yellow-300 text-sm">هشدار: برای این دانشجو قبلاً در این کلاس صورتحساب ثبت شده است.</span>
|
||||
<span class="text-xs text-yellow-200" v-if="duplicateWarning.payments && duplicateWarning.payments.length">
|
||||
صورتحساب قبلی با کد {{ duplicateWarning.payments.map(p => p.uniqueCode || p._id).join('، ') }} موجود است.
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-exclamation-triangle text-xl text-yellow-500 flex-shrink-0"></i>
|
||||
<span class="font-bold text-sm text-yellow-800 dark:text-yellow-200">
|
||||
توجه: برای این دانشجو قبلاً در این کلاس صورتحساب ثبت شده است.
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-column gap-2 mt-1 text-xs" v-if="duplicateWarning.payments && duplicateWarning.payments.length">
|
||||
<div
|
||||
v-for="p in duplicateWarning.payments"
|
||||
:key="p._id"
|
||||
class="duplicate-item p-2 border-round flex flex-wrap align-items-center justify-content-between gap-2"
|
||||
>
|
||||
<div class="flex align-items-center gap-2 flex-wrap">
|
||||
<span>کد صورتحساب: <strong>{{ p.uniqueCode || p._id }}</strong></span>
|
||||
<span v-if="p.amount">مبلغ: <strong>{{ toPersianDigits((p.amount || 0).toLocaleString()) }} تومان</strong></span>
|
||||
<span v-if="p.createdAt" class="text-color-secondary">تاریخ: {{ formatJalali(p.createdAt) }}</span>
|
||||
</div>
|
||||
<StatusTag v-if="p.status" :value="p.status" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-column gap-2">
|
||||
@@ -316,7 +329,7 @@ import DatePicker from 'vue3-persian-datetime-picker';
|
||||
|
||||
const { toPersianDigits, formatJalali, toGregorianIso, getTodayJalali } = usePersianDate();
|
||||
|
||||
const { showSuccess, showError } = useToast();
|
||||
const { showSuccess, showError, showWarn } = useToast();
|
||||
|
||||
const {
|
||||
items,
|
||||
@@ -334,6 +347,7 @@ const usersList = ref([]);
|
||||
const classesList = ref([]);
|
||||
const isCreating = ref(false);
|
||||
const duplicateWarning = ref(null);
|
||||
let lastDuplicateAlertKey = '';
|
||||
|
||||
const createForm = reactive({
|
||||
user: null,
|
||||
@@ -418,24 +432,43 @@ const checkDuplicateInvoice = async (userIdVal = null) => {
|
||||
const targetUserId = extractId(userIdVal) || extractId(createForm.user);
|
||||
if (!targetUserId || !createForm.classes || !createForm.classes.length) {
|
||||
duplicateWarning.value = null;
|
||||
lastDuplicateAlertKey = '';
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const classIds = Array.isArray(createForm.classes)
|
||||
? createForm.classes.map(extractId).filter(Boolean).join(',')
|
||||
? createForm.classes.map(extractId).filter(Boolean).sort().join(',')
|
||||
: (extractId(createForm.classes) || '');
|
||||
if (!classIds) {
|
||||
duplicateWarning.value = null;
|
||||
lastDuplicateAlertKey = '';
|
||||
return;
|
||||
}
|
||||
|
||||
const checkKey = `${targetUserId}_${classIds}`;
|
||||
const res = await paymentApi.checkDuplicate({
|
||||
userId: targetUserId,
|
||||
classes: classIds
|
||||
});
|
||||
duplicateWarning.value = res.data?.data || res.data || res;
|
||||
const result = res.data?.data || res.data || res;
|
||||
duplicateWarning.value = result;
|
||||
|
||||
if (result && result.hasDuplicate) {
|
||||
if (lastDuplicateAlertKey !== checkKey) {
|
||||
lastDuplicateAlertKey = checkKey;
|
||||
const studentObj = usersList.value.find((u) => String(u._id || u.id) === String(targetUserId));
|
||||
const studentName = studentObj?.name || studentObj?.fullName || 'این دانشجو';
|
||||
const codes = (result.payments || []).map((p) => p.uniqueCode || p._id).filter(Boolean).join('، ');
|
||||
const codeSuffix = codes ? ` (کد: ${codes})` : '';
|
||||
showWarn(`برای ${studentName} قبلاً در این کلاس صورتحساب ثبت شده است${codeSuffix}.`, 'اطلاعیه صورتحساب قبلی');
|
||||
}
|
||||
} else {
|
||||
lastDuplicateAlertKey = '';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('checkDuplicateInvoice error:', err);
|
||||
duplicateWarning.value = null;
|
||||
lastDuplicateAlertKey = '';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -446,6 +479,7 @@ watch(
|
||||
await checkDuplicateInvoice(newUser);
|
||||
} else {
|
||||
duplicateWarning.value = null;
|
||||
lastDuplicateAlertKey = '';
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
@@ -507,6 +541,7 @@ const resetCreateForm = () => {
|
||||
createForm.dueDate = getTodayJalali();
|
||||
hasDiscount.value = false;
|
||||
duplicateWarning.value = null;
|
||||
lastDuplicateAlertKey = '';
|
||||
createNotify.sms = true;
|
||||
createNotify.email = true;
|
||||
createNotify.bot = true;
|
||||
@@ -691,8 +726,12 @@ onMounted(() => {
|
||||
|
||||
<style scoped>
|
||||
.duplicate-warning-box {
|
||||
background: rgba(234, 179, 8, 0.15) !important;
|
||||
border: 1px solid rgba(234, 179, 8, 0.6) !important;
|
||||
color: #fef08a !important;
|
||||
background: rgba(245, 158, 11, 0.12) !important;
|
||||
border: 1px solid rgba(245, 158, 11, 0.45) !important;
|
||||
}
|
||||
|
||||
.duplicate-item {
|
||||
background: rgba(245, 158, 11, 0.08);
|
||||
border: 1px dashed rgba(245, 158, 11, 0.35);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user