@@ -698,39 +698,43 @@ const canShowUnapproveButton = (item) => {
const approveReceive = async (code) => {
try {
- loading.value = true;
const response = await axios.post(`/api/approval/approve/receive/${code}`);
- await loadData();
-
if (response.data.success) {
+ // پاک کردن انتخابها و بهروزرسانی فوری جدول
+ selectedItems.value = selectedItems.value.filter(item => item.code !== code);
+ selectAll.value = false;
+ updateSelectedSum();
+ console.log('Before loadData in approveReceive');
+ await loadData();
+ console.log('After loadData in approveReceive');
Swal.fire({ text: 'سند دریافت تایید شد', icon: 'success', confirmButtonText: 'قبول' });
} else {
Swal.fire({ text: response.data.message, icon: 'error', confirmButtonText: 'قبول' });
}
} catch (error) {
Swal.fire({ text: 'خطا در تایید سند: ' + (error.response?.data?.message || error.message), icon: 'error', confirmButtonText: 'قبول' });
- } finally {
- loading.value = false;
}
};
const unapproveReceive = async (code) => {
try {
- loading.value = true;
const response = await axios.post(`/api/approval/unapprove/receive/${code}`);
- await loadData();
-
if (response.data.success) {
+ // پاک کردن انتخابها و بهروزرسانی فوری جدول
+ selectedItems.value = selectedItems.value.filter(item => item.code !== code);
+ selectAll.value = false;
+ updateSelectedSum();
+ console.log('Before loadData in unapproveReceive');
+ await loadData();
+ console.log('After loadData in unapproveReceive');
Swal.fire({ text: 'تایید سند لغو شد', icon: 'success', confirmButtonText: 'قبول' });
} else {
Swal.fire({ text: response.data.message, icon: 'error', confirmButtonText: 'قبول' });
}
} catch (error) {
Swal.fire({ text: 'خطا در لغو تایید سند: ' + (error.response?.data?.message || error.message), icon: 'error', confirmButtonText: 'قبول' });
- } finally {
- loading.value = false;
}
};
@@ -758,14 +762,22 @@ const approveSelectedReceives = async () => {
bulkLoading.value = true;
try {
- await axios.post(`/api/approval/approve/group/receive`, {
+ const response = await axios.post(`/api/approval/approve/group/receive`, {
'docIds': selectedItems.value.map(item => item.code)
});
- Swal.fire({ text: 'اسناد تایید شدند.', icon: 'success', confirmButtonText: 'قبول' });
- selectedItems.value = [];
- await loadData();
+
+ if (response.data.success) {
+ Swal.fire({ text: 'اسناد تایید شدند.', icon: 'success', confirmButtonText: 'قبول' });
+ selectedItems.value = [];
+ selectAll.value = false;
+ updateSelectedSum();
+ // بهروزرسانی فوری جدول
+ await loadData();
+ } else {
+ Swal.fire({ text: response.data.message || 'خطا در تایید اسناد', icon: 'error', confirmButtonText: 'قبول' });
+ }
} catch (e) {
- Swal.fire({ text: 'خطا در تایید اسناد', icon: 'error', confirmButtonText: 'قبول' });
+ Swal.fire({ text: 'خطا در تایید اسناد: ' + (e.response?.data?.message || e.message), icon: 'error', confirmButtonText: 'قبول' });
} finally {
bulkLoading.value = false;
}
diff --git a/webUI/src/views/acc/persons/send/list.vue b/webUI/src/views/acc/persons/send/list.vue
index e0d4d45..4f188b1 100755
--- a/webUI/src/views/acc/persons/send/list.vue
+++ b/webUI/src/views/acc/persons/send/list.vue
@@ -61,7 +61,20 @@
+
+
+
+
+
+
+
+
+ اسناد تایید شده
+ اسناد در انتظار تایید
+
+
سند حسابداری
+
+
+ mdi-check-decagram
+
+
+
+
+ mdi-cancel
+
+
@@ -198,6 +223,14 @@
{{ $filters.formatNumber(item.amount) }}
+
+
+ {{ getApprovalStatusText(item) }}
+
+
+
+ {{ item.approvedBy?.fullName || '-' }}
+
@@ -278,6 +311,10 @@ const sumTotal = ref(0);
const sumSelected = ref(0);
const sortBy = ref('id');
const sortDesc = ref(true);
+const currentTab = ref('approved');
+const business = ref({ requireTwoStepApproval: false, approvers: { sendToPersons: null } });
+const currentUser = ref({ email: '', owner: false });
+const bulkLoading = ref(false);
const allHeaders = reactive([
{ title: '', key: 'select', sortable: false, visible: true, customizable: false },
@@ -288,13 +325,20 @@ const allHeaders = reactive([
{ title: 'تاریخ', key: 'date', sortable: true, visible: true },
{ title: 'شرح', key: 'des', sortable: true, visible: true },
{ title: 'مبلغ', key: 'amount', sortable: true, visible: true },
+ { title: 'وضعیت تایید', key: 'approvalStatus', sortable: true, visible: true },
+ { title: 'تاییدکننده', key: 'approvedBy', sortable: true, visible: true },
]);
const customizableHeaders = computed(() =>
allHeaders.filter(h => h.customizable !== false && h.key !== 'operation')
);
const visibleHeaders = computed(() =>
- allHeaders.filter(h => h.customizable === false || h.visible)
+ allHeaders.filter(h => {
+ if ((h.key === 'approvalStatus' || h.key === 'approvedBy') && !business.value.requireTwoStepApproval) {
+ return false;
+ }
+ return h.customizable === false || h.visible;
+ })
);
const dateFilterOptions = [
@@ -338,6 +382,7 @@ const loadData = async (options = null) => {
itemsPerPage: options?.itemsPerPage || itemsPerPage.value,
search: searchValue.value,
dateFilter: dateFilter.value,
+ approvalFilter: business.value.requireTwoStepApproval ? currentTab.value : 'all',
sortBy: [{
key: sortBy.value,
order: sortDesc.value ? 'desc' : 'asc'
@@ -587,8 +632,153 @@ watch([page, itemsPerPage], () => {
loadData();
}, { deep: true });
+watch(currentTab, () => {
+ loadData();
+});
+
+// Methods for approval functionality
+const checkApprover = () => {
+ return business.value.requireTwoStepApproval && (business.value.approvers.sendToPersons == currentUser.value.email || currentUser.value.owner === true);
+};
+
+const getApprovalStatusText = (item) => {
+ if (!business.value?.requireTwoStepApproval) return 'تایید دو مرحلهای غیرفعال';
+
+ if (item.isPreview) return 'در انتظار تایید';
+ if (item.isApproved) return 'تایید شده';
+ return 'تایید شده';
+};
+
+const getApprovalStatusColor = (item) => {
+ if (!business.value?.requireTwoStepApproval) return 'default';
+
+ if (item.isPreview) return 'warning';
+ if (item.isApproved) return 'success';
+ return 'success';
+};
+
+const canShowApprovalButton = (item) => {
+ if (!checkApprover()) return false;
+ if (item?.isApproved) return false;
+ return true;
+};
+
+const canShowUnapproveButton = (item) => {
+ return !canShowApprovalButton(item) && checkApprover();
+};
+
+const approveSend = async (code) => {
+ try {
+ const response = await axios.post(`/api/approval/approve/send/${code}`);
+
+ if (response.data.success) {
+ // پاک کردن انتخابها و بهروزرسانی فوری جدول
+ selectedItems.value = selectedItems.value.filter(item => item.code !== code);
+ selectAll.value = false;
+ updateSelectedSum();
+ console.log('Before loadData in approveSend');
+ await loadData();
+ console.log('After loadData in approveSend');
+ Swal.fire({ text: 'سند پرداخت تایید شد', icon: 'success', confirmButtonText: 'قبول' });
+ } else {
+ Swal.fire({ text: response.data.message, icon: 'error', confirmButtonText: 'قبول' });
+ }
+ } catch (error) {
+ Swal.fire({ text: 'خطا در تایید سند: ' + (error.response?.data?.message || error.message), icon: 'error', confirmButtonText: 'قبول' });
+ }
+};
+
+const unapproveSend = async (code) => {
+ try {
+ const response = await axios.post(`/api/approval/unapprove/send/${code}`);
+
+ if (response.data.success) {
+ // پاک کردن انتخابها و بهروزرسانی فوری جدول
+ selectedItems.value = selectedItems.value.filter(item => item.code !== code);
+ selectAll.value = false;
+ updateSelectedSum();
+ console.log('Before loadData in unapproveSend');
+ await loadData();
+ console.log('After loadData in unapproveSend');
+ Swal.fire({ text: 'تایید سند لغو شد', icon: 'success', confirmButtonText: 'قبول' });
+ } else {
+ Swal.fire({ text: response.data.message, icon: 'error', confirmButtonText: 'قبول' });
+ }
+ } catch (error) {
+ Swal.fire({ text: 'خطا در لغو تایید سند: ' + (error.response?.data?.message || error.message), icon: 'error', confirmButtonText: 'قبول' });
+ }
+};
+
+const approveSelectedSends = async () => {
+ if (selectedItems.value.length === 0) {
+ Swal.fire({ text: 'هیچ موردی انتخاب نشده است.', icon: 'warning', confirmButtonText: 'قبول' });
+ return;
+ }
+
+ const selectedSends = items.value.filter(send => selectedItems.value.some(sel => sel.code === send.code));
+ if (selectedSends.some(send => !(!send.isApproved && send.isPreview))) {
+ Swal.fire({ text: 'برخی اسناد انتخابی تایید شده هستند.', icon: 'warning', confirmButtonText: 'قبول' });
+ return;
+ }
+
+ Swal.fire({
+ title: 'تایید اسناد انتخابی',
+ text: 'اسناد انتخابشده تایید خواهند شد.',
+ icon: 'question',
+ showCancelButton: true,
+ confirmButtonText: 'بله',
+ cancelButtonText: 'خیر'
+ }).then(async (r) => {
+ if (!r.isConfirmed) return;
+ bulkLoading.value = true;
+
+ try {
+ const response = await axios.post(`/api/approval/approve/group/send`, {
+ 'docIds': selectedItems.value.map(item => item.code)
+ });
+
+ if (response.data.success) {
+ Swal.fire({ text: 'اسناد تایید شدند.', icon: 'success', confirmButtonText: 'قبول' });
+ selectedItems.value = [];
+ selectAll.value = false;
+ updateSelectedSum();
+ // بهروزرسانی فوری جدول
+ await loadData();
+ } else {
+ Swal.fire({ text: response.data.message || 'خطا در تایید اسناد', icon: 'error', confirmButtonText: 'قبول' });
+ }
+ } catch (e) {
+ Swal.fire({ text: 'خطا در تایید اسناد: ' + (e.response?.data?.message || e.message), icon: 'error', confirmButtonText: 'قبول' });
+ } finally {
+ bulkLoading.value = false;
+ }
+ });
+};
+
+const loadBusinessInfo = async () => {
+ try {
+ const response = await axios.get('/api/business/get/info/' + localStorage.getItem('activeBid'));
+ business.value = response.data || { requireTwoStepApproval: false, approvers: { sendToPersons: null } };
+ } catch (error) {
+ console.error('Error loading business info:', error);
+ business.value = { requireTwoStepApproval: false, approvers: { sendToPersons: null } };
+ }
+};
+
+const loadCurrentUser = async () => {
+ try {
+ const response = await axios.post('/api/business/get/user/permissions');
+ currentUser.value = response.data || { email: '', owner: false };
+ } catch (error) {
+ console.error('Error loading current user:', error);
+ currentUser.value = { email: '', owner: false };
+ }
+};
+
onMounted(() => {
loadColumnSettings();
+ loadBusinessInfo();
+ loadCurrentUser();
loadData();
});