diff --git a/hesabixCore/src/Controller/PersonsController.php b/hesabixCore/src/Controller/PersonsController.php index c105c8a..347a4f0 100644 --- a/hesabixCore/src/Controller/PersonsController.php +++ b/hesabixCore/src/Controller/PersonsController.php @@ -1117,25 +1117,51 @@ class PersonsController extends AbstractController } #[Route('/api/approval/approve/receive/{code}', name: 'app_approval_approve_receive', methods: ['POST'])] - public function approveReceiveDoc(string $code, Request $request, Access $access, EntityManagerInterface $entityManager): JsonResponse + public function approveReceiveDoc($code, Request $request, Access $access, EntityManagerInterface $entityManager): JsonResponse { $acc = $access->hasRole('getpay'); if (!$acc) throw $this->createAccessDeniedException(); - $doc = $entityManager->getRepository(HesabdariDoc::class)->findOneBy([ - 'bid' => $acc['bid']->getId(), - 'code' => $code, - 'money' => $acc['money']->getId(), - 'type' => 'person_receive' - ]); + // Debug: بررسی مقادیر + $bidId = $acc['bid']->getId(); + $moneyId = $acc['money']->getId(); + $yearId = $acc['year']->getId(); + + // جستجوی سند با QueryBuilder برای debug بیشتر (بدون سال) + $queryBuilder = $entityManager->createQueryBuilder(); + $doc = $queryBuilder + ->select('d') + ->from(HesabdariDoc::class, 'd') + ->where('d.bid = :bid') + ->andWhere('d.code = :code') + ->andWhere('d.type = :type') + ->setParameter('bid', $acc['bid']) + ->setParameter('code', $code) + ->setParameter('type', 'person_receive') + ->getQuery() + ->getOneOrNullResult(); + if (!$doc) { - throw $this->createNotFoundException( - 'سند دریافت یافت نشد' - . 'code ' . $code - . ' money ' . $acc['money']->getId() - . ' year ' . $acc['year']->getId() - . ' bid ' . $acc['bid']->getId() - ); + // جستجوی تمام اسناد با همین code برای debug + $allDocsWithCode = $entityManager->createQueryBuilder() + ->select('d') + ->from(HesabdariDoc::class, 'd') + ->where('d.code = :code') + ->setParameter('code', $code) + ->getQuery() + ->getResult(); + + $debugInfo = 'سند دریافت یافت نشد - Debug Info: '; + $debugInfo .= 'code=' . $code . ', bid=' . $bidId . ', money=' . $moneyId . ', year=' . $yearId; + $debugInfo .= ', total docs with this code=' . count($allDocsWithCode); + + foreach ($allDocsWithCode as $debugDoc) { + $debugInfo .= ', found doc: bid=' . $debugDoc->getBid()->getId() . + ' money=' . $debugDoc->getMoney()->getId() . + ' type=' . $debugDoc->getType(); + } + + throw $this->createNotFoundException($debugInfo); } $doc->setIsPreview(false); @@ -1148,15 +1174,14 @@ class PersonsController extends AbstractController } #[Route('/api/approval/unapprove/receive/{code}', name: 'app_approval_unapprove_receive', methods: ['POST'])] - public function unapproveReceiveDoc(string $code, Request $request, Access $access, EntityManagerInterface $entityManager): JsonResponse + public function unapproveReceiveDoc($code, Request $request, Access $access, EntityManagerInterface $entityManager): JsonResponse { $acc = $access->hasRole('getpay'); if (!$acc) throw $this->createAccessDeniedException(); $doc = $entityManager->getRepository(HesabdariDoc::class)->findOneBy([ - 'bid' => $acc['bid']->getId(), + 'bid' => $acc['bid'], 'code' => $code, - 'money' => $acc['money']->getId(), 'type' => 'person_receive' ]); if (!$doc) throw $this->createNotFoundException('سند دریافت یافت نشد'); @@ -1183,14 +1208,42 @@ class PersonsController extends AbstractController return $this->json(['success' => false, 'message' => 'هیچ سندی انتخاب نشده است']); } - $docs = $entityManager->getRepository(HesabdariDoc::class)->findBy([ - 'bid' => $acc['bid']->getId(), - 'code' => $docIds, - 'money' => $acc['money']->getId(), - 'type' => 'person_receive' - ]); + // جستجوی اسناد با QueryBuilder برای debug بهتر + $queryBuilder = $entityManager->createQueryBuilder(); + $docs = $queryBuilder + ->select('d') + ->from(HesabdariDoc::class, 'd') + ->where('d.bid = :bid') + ->andWhere('d.code IN (:codes)') + ->andWhere('d.type = :type') + ->setParameter('bid', $acc['bid']) + ->setParameter('codes', $docIds) + ->setParameter('type', 'person_receive') + ->getQuery() + ->getResult(); + if (empty($docs)) { - return $this->json(['success' => false, 'message' => 'سند دریافت یافت نشد']); + // Debug: جستجوی تمام اسناد با این codes + $allDocsWithCodes = $entityManager->createQueryBuilder() + ->select('d') + ->from(HesabdariDoc::class, 'd') + ->where('d.code IN (:codes)') + ->setParameter('codes', $docIds) + ->getQuery() + ->getResult(); + + $debugInfo = 'هیچ سند دریافت یافت نشد - Debug Info: '; + $debugInfo .= 'requested codes=' . implode(',', $docIds); + $debugInfo .= ', bid=' . $acc['bid']->getId(); + $debugInfo .= ', total docs with these codes=' . count($allDocsWithCodes); + + foreach ($allDocsWithCodes as $debugDoc) { + $debugInfo .= ', found doc: code=' . $debugDoc->getCode() . + ' bid=' . $debugDoc->getBid()->getId() . + ' type=' . $debugDoc->getType(); + } + + return $this->json(['success' => false, 'message' => $debugInfo]); } foreach ($docs as $doc) { $doc->setIsPreview(false); @@ -2430,6 +2483,7 @@ class PersonsController extends AbstractController $itemsPerPage = (int) ($params['itemsPerPage'] ?? 10); $search = $params['search'] ?? ''; $dateFilter = $params['dateFilter'] ?? 'all'; + $approvalFilter = $params['approvalFilter'] ?? 'all'; // پردازش پارامترهای سورت $sortBy = 'id'; @@ -2454,16 +2508,30 @@ class PersonsController extends AbstractController $queryBuilder = $entityManager->getRepository(HesabdariDoc::class) ->createQueryBuilder('d') ->select('DISTINCT d.id, d.date, d.code, d.des, d.amount') + ->addSelect('d.isPreview, d.isApproved') + ->addSelect('approver.fullName as approvedByName, approver.id as approvedById, approver.email as approvedByEmail') + ->leftJoin('d.approvedBy', 'approver') ->where('d.bid = :bid') ->andWhere('d.type = :type') ->andWhere('d.year = :year') ->andWhere('d.money = :money') - ->andWhere('d.isApproved = :isApproved') ->setParameter('bid', $acc['bid']) ->setParameter('type', 'person_send') ->setParameter('year', $acc['year']) - ->setParameter('money', $acc['money']) - ->setParameter('isApproved', true); + ->setParameter('money', $acc['money']); + + // فیلتر تایید + if ($approvalFilter === 'approved') { + $queryBuilder->andWhere('d.isApproved = true'); + } elseif ($approvalFilter === 'pending') { + $queryBuilder->andWhere('d.isPreview = true AND d.isApproved = false'); + } else { + // اگر تایید دو مرحله‌ای فعال نیست، فقط اسناد تایید شده را نمایش بده + $business = $entityManager->getRepository(Business::class)->find($acc['bid']); + if (!$business || !$business->isRequireTwoStepApproval()) { + $queryBuilder->andWhere('d.isApproved = true'); + } + } // جست‌وجو if (!empty($search)) { @@ -2514,12 +2582,23 @@ class PersonsController extends AbstractController ->andWhere('d.type = :type') ->andWhere('d.year = :year') ->andWhere('d.money = :money') - ->andWhere('d.isApproved = :isApproved') ->setParameter('bid', $acc['bid']) ->setParameter('type', 'person_send') ->setParameter('year', $acc['year']) - ->setParameter('money', $acc['money']) - ->setParameter('isApproved', true); + ->setParameter('money', $acc['money']); + + // فیلتر تایید برای کوئری تعداد کل + if ($approvalFilter === 'approved') { + $totalQueryBuilder->andWhere('d.isApproved = true'); + } elseif ($approvalFilter === 'pending') { + $totalQueryBuilder->andWhere('d.isPreview = true AND d.isApproved = false'); + } else { + // اگر تایید دو مرحله‌ای فعال نیست، فقط اسناد تایید شده را نمایش بده + $business = $entityManager->getRepository(Business::class)->find($acc['bid']); + if (!$business || !$business->isRequireTwoStepApproval()) { + $totalQueryBuilder->andWhere('d.isApproved = true'); + } + } // اعمال فیلترهای جست‌وجو و تاریخ برای کوئری تعداد if (!empty($search)) { @@ -2685,6 +2764,13 @@ class PersonsController extends AbstractController 'amount' => $doc['amount'], 'persons' => $persons[$doc['id']] ?? [], 'accounts' => $accounts[$doc['id']] ?? [], + 'isPreview' => $doc['isPreview'], + 'isApproved' => $doc['isApproved'], + 'approvedBy' => $doc['approvedByName'] ? [ + 'fullName' => $doc['approvedByName'], + 'id' => $doc['approvedById'], + 'email' => $doc['approvedByEmail'] + ] : null, ]; } @@ -2694,4 +2780,150 @@ class PersonsController extends AbstractController ]); } + #[Route('/api/approval/approve/send/{code}', name: 'app_approval_approve_send', methods: ['POST'])] + public function approveSendDoc($code, Request $request, Access $access, EntityManagerInterface $entityManager): JsonResponse + { + $acc = $access->hasRole('getpay'); + if (!$acc) throw $this->createAccessDeniedException(); + + // Debug: بررسی مقادیر + $bidId = $acc['bid']->getId(); + $moneyId = $acc['money']->getId(); + $yearId = $acc['year']->getId(); + + // جستجوی سند با QueryBuilder برای debug بیشتر (بدون سال) + $queryBuilder = $entityManager->createQueryBuilder(); + $doc = $queryBuilder + ->select('d') + ->from(HesabdariDoc::class, 'd') + ->where('d.bid = :bid') + ->andWhere('d.code = :code') + ->andWhere('d.type = :type') + ->setParameter('bid', $acc['bid']) + ->setParameter('code', $code) + ->setParameter('type', 'person_send') + ->getQuery() + ->getOneOrNullResult(); + + if (!$doc) { + // جستجوی تمام اسناد با همین code برای debug + $allDocsWithCode = $entityManager->createQueryBuilder() + ->select('d') + ->from(HesabdariDoc::class, 'd') + ->where('d.code = :code') + ->setParameter('code', $code) + ->getQuery() + ->getResult(); + + $debugInfo = 'سند پرداخت یافت نشد - Debug Info: '; + $debugInfo .= 'code=' . $code . ', bid=' . $bidId . ', money=' . $moneyId . ', year=' . $yearId; + $debugInfo .= ', total docs with this code=' . count($allDocsWithCode); + + foreach ($allDocsWithCode as $debugDoc) { + $debugInfo .= ', found doc: bid=' . $debugDoc->getBid()->getId() . + ' money=' . $debugDoc->getMoney()->getId() . + ' type=' . $debugDoc->getType(); + } + + throw $this->createNotFoundException($debugInfo); + } + + $doc->setIsPreview(false); + $doc->setIsApproved(true); + $doc->setApprovedBy($this->getUser()); + $entityManager->persist($doc); + $entityManager->flush(); + + return $this->json(['success' => true, 'message' => 'سند پرداخت تایید شد']); + } + + #[Route('/api/approval/unapprove/send/{code}', name: 'app_approval_unapprove_send', methods: ['POST'])] + public function unapproveSendDoc($code, Request $request, Access $access, EntityManagerInterface $entityManager): JsonResponse + { + $acc = $access->hasRole('getpay'); + if (!$acc) throw $this->createAccessDeniedException(); + + $doc = $entityManager->getRepository(HesabdariDoc::class)->findOneBy([ + 'bid' => $acc['bid'], + 'code' => $code, + 'type' => 'person_send' + ]); + if (!$doc) throw $this->createNotFoundException('سند پرداخت یافت نشد'); + + $doc->setIsPreview(true); + $doc->setIsApproved(false); + $doc->setApprovedBy(null); + $entityManager->persist($doc); + $entityManager->flush(); + + return $this->json(['success' => true, 'message' => 'تایید سند پرداخت لغو شد']); + } + + #[Route('/api/approval/approve/group/send', name: 'app_approval_approve_group_send', methods: ['POST'])] + public function approveGroupSendDocs(Request $request, Access $access, EntityManagerInterface $entityManager): JsonResponse + { + $acc = $access->hasRole('getpay'); + if (!$acc) throw $this->createAccessDeniedException(); + + $params = json_decode($request->getContent(), true) ?? []; + $docIds = $params['docIds'] ?? []; + + if (empty($docIds)) { + return $this->json(['success' => false, 'message' => 'هیچ سندی انتخاب نشده است']); + } + + // جستجوی اسناد با QueryBuilder برای debug بهتر + $queryBuilder = $entityManager->createQueryBuilder(); + $docs = $queryBuilder + ->select('d') + ->from(HesabdariDoc::class, 'd') + ->where('d.bid = :bid') + ->andWhere('d.code IN (:codes)') + ->andWhere('d.type = :type') + ->setParameter('bid', $acc['bid']) + ->setParameter('codes', $docIds) + ->setParameter('type', 'person_send') + ->getQuery() + ->getResult(); + + if (empty($docs)) { + + // Debug: جستجوی تمام اسناد برای بررسی مشکل + $debugQuery = $entityManager->createQueryBuilder() + ->select('d.code, d.type, d.bid') + ->from(HesabdariDoc::class, 'd') + ->where('d.code IN (:codes)') + ->setParameter('codes', $docIds) + ->getQuery() + ->getArrayResult(); + + $debugInfo = 'اسناد پرداخت یافت نشد - Debug Info: '; + $debugInfo .= 'requested codes=' . implode(',', $docIds) . ', bid=' . $acc['bid']->getId(); + $debugInfo .= ', found docs=' . count($debugQuery); + + foreach ($debugQuery as $debugDoc) { + $debugInfo .= ', code=' . $debugDoc['code'] . ' type=' . $debugDoc['type'] . ' bid=' . $debugDoc['bid']; + } + + return $this->json(['success' => false, 'message' => $debugInfo]); + } + + $successCount = 0; + foreach ($docs as $doc) { + if ($doc->isPreview() && !$doc->isApproved()) { + $doc->setIsPreview(false); + $doc->setIsApproved(true); + $doc->setApprovedBy($this->getUser()); + $entityManager->persist($doc); + $successCount++; + } + } + + if ($successCount > 0) { + $entityManager->flush(); + } + + return $this->json(['success' => true, 'message' => "$successCount سند پرداخت تایید شد"]); + } + } diff --git a/webUI/src/views/acc/persons/receive/list.vue b/webUI/src/views/acc/persons/receive/list.vue index 31e4455..e062afe 100755 --- a/webUI/src/views/acc/persons/receive/list.vue +++ b/webUI/src/views/acc/persons/receive/list.vue @@ -14,12 +14,6 @@ - - - + + +
@@ -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 @@ + + + + +
+ + اسناد تایید شده + اسناد در انتظار تایید + +
سند حسابداری + + + + + +