diff --git a/hesabixCore/migrations/Version20250819234842.php b/hesabixCore/migrations/Version20250819234842.php new file mode 100644 index 0000000..1457fd9 --- /dev/null +++ b/hesabixCore/migrations/Version20250819234842.php @@ -0,0 +1,35 @@ +addSql(<<<'SQL' + ALTER TABLE hesabdari_doc CHANGE is_preview is_preview TINYINT(1) DEFAULT 0, CHANGE is_approved is_approved TINYINT(1) DEFAULT 1 + SQL); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql(<<<'SQL' + ALTER TABLE hesabdari_doc CHANGE is_preview is_preview TINYINT(1) DEFAULT NULL, CHANGE is_approved is_approved TINYINT(1) DEFAULT NULL + SQL); + } +} diff --git a/hesabixCore/src/Controller/ApprovalController.php b/hesabixCore/src/Controller/ApprovalController.php index 0cf8839..f3814d8 100644 --- a/hesabixCore/src/Controller/ApprovalController.php +++ b/hesabixCore/src/Controller/ApprovalController.php @@ -250,7 +250,7 @@ class ApprovalController extends AbstractController foreach ($docIds as $docId) { $document = $entityManager->getRepository(HesabdariDoc::class)->findOneByIncludePreview([ - 'id' => $docId, + 'code' => $docId, 'bid' => $business ]); @@ -378,6 +378,274 @@ class ApprovalController extends AbstractController } } + #[Route('/api/approval/approve/buy/{docId}', name: 'api_approval_approve_buy', methods: ['POST'])] + public function approveBuyInvoice( + $docId, + #[CurrentUser] ?User $user, + Access $access, + LogService $logService, + EntityManagerInterface $entityManager + ): Response { + try { + $acc = $access->hasRole('buy'); + if (!$acc) { + throw $this->createAccessDeniedException(); + } + + $business = $acc['bid']; + $businessSettings = $entityManager->getRepository(Business::class)->find($business->getId()); + + if (!$businessSettings->isRequireTwoStepApproval()) { + return $this->json(['success' => false, 'message' => 'تأیید دو مرحله‌ای فعال نیست']); + } + + $document = $entityManager->getRepository(HesabdariDoc::class)->findOneByIncludePreview([ + 'code' => $docId, + 'bid' => $business + ]); + + if (!$document) { + return $this->json(['success' => false, 'message' => 'فاکتور خرید یافت نشد']); + } + + $canApprove = $this->canUserApproveBuyInvoice($user, $businessSettings); + if (!$canApprove) { + return $this->json(['success' => false, 'message' => 'شما مجوز تأیید این فاکتور را ندارید']); + } + + $document->setIsPreview(false); + $document->setIsApproved(true); + $document->setApprovedBy($user); + + $entityManager->persist($document); + $entityManager->flush(); + + $logService->insert( + 'تأیید فاکتور خرید', + "فاکتور خرید {$document->getCode()} توسط {$user->getFullName()} تأیید شد", + $user, + $business + ); + + return $this->json([ + 'success' => true, + 'message' => 'فاکتور خرید با موفقیت تأیید شد' + ]); + + } catch (\Exception $e) { + return $this->json([ + 'success' => false, + 'message' => 'خطا در تأیید فاکتور خرید: ' . $e->getMessage() + ], 500); + } + } + + #[Route('/api/approval/approve/group/buy', name: 'api_approval_approve_group_buy', methods: ['POST'])] + public function approveBuyInvoiceGroup( + Request $request, + #[CurrentUser] ?User $user, + Access $access, + LogService $logService, + EntityManagerInterface $entityManager + ): Response { + try { + $acc = $access->hasRole('buy'); + if (!$acc) { + throw $this->createAccessDeniedException(); + } + + $business = $acc['bid']; + $businessSettings = $entityManager->getRepository(Business::class)->find($business->getId()); + + if (!$businessSettings->isRequireTwoStepApproval()) { + return $this->json(['success' => false, 'message' => 'تأیید دو مرحله‌ای فعال نیست']); + } + + $canApprove = $this->canUserApproveBuyInvoice($user, $businessSettings); + if (!$canApprove) { + return $this->json(['success' => false, 'message' => 'شما مجوز تأیید این فاکتورها را ندارید']); + } + + $data = json_decode($request->getContent(), true); + $docIds = $data['docIds'] ?? []; + + foreach ($docIds as $docId) { + $document = $entityManager->getRepository(HesabdariDoc::class)->findOneByIncludePreview([ + 'code' => $docId, + 'bid' => $business + ]); + + if (!$document) { + return $this->json(['success' => false, 'message' => 'فاکتور خرید یافت نشد']); + } + + if ($document->isApproved()) { + return $this->json(['success' => false, 'message' => 'فاکتور خرید تایید شده است']); + } + + $document->setIsPreview(false); + $document->setIsApproved(true); + $document->setApprovedBy($user); + + $entityManager->persist($document); + } + + $entityManager->flush(); + + $logService->insert( + 'تأیید فاکتورهای خرید', + "فاکتورهای خرید " . implode(', ', $docIds) . " توسط {$user->getFullName()} تأیید شدند", + $user, + $business + ); + + return $this->json([ + 'success' => true, + 'message' => 'فاکتورهای خرید با موفقیت تأیید شدند' + ]); + + } catch (\Exception $e) { + return $this->json([ + 'success' => false, + 'message' => 'خطا در تأیید فاکتورهای خرید: ' . $e->getMessage() + ], 500); + } + } + + #[Route('/api/approval/unapprove/buy/{docId}', name: 'api_approval_unapprove_buy', methods: ['POST'])] + public function unapproveBuyInvoice( + $docId, + #[CurrentUser] ?User $user, + Access $access, + LogService $logService, + EntityManagerInterface $entityManager + ): Response { + try { + $acc = $access->hasRole('buy'); + if (!$acc) { + throw $this->createAccessDeniedException(); + } + + $business = $acc['bid']; + $businessSettings = $entityManager->getRepository(Business::class)->find($business->getId()); + + if (!$businessSettings->isRequireTwoStepApproval()) { + return $this->json(['success' => false, 'message' => 'تأیید دو مرحله‌ای فعال نیست']); + } + + $document = $entityManager->getRepository(HesabdariDoc::class)->findOneByIncludePreview([ + 'code' => $docId, + 'bid' => $business + ]); + + if (!$document) { + return $this->json(['success' => false, 'message' => 'فاکتور خرید یافت نشد']); + } + + $canApprove = $this->canUserApproveBuyInvoice($user, $businessSettings); + if (!$canApprove) { + return $this->json(['success' => false, 'message' => 'شما مجوز تأیید این فاکتور را ندارید']); + } + + $document->setIsPreview(true); + $document->setIsApproved(false); + $document->setApprovedBy(null); + + $entityManager->persist($document); + $entityManager->flush(); + + $logService->insert( + 'لغو تأیید فاکتور خرید', + "فاکتور خرید {$document->getCode()} توسط {$user->getFullName()} لغو تأیید شد", + $user, + $business + ); + + return $this->json([ + 'success' => true, + 'message' => 'فاکتور خرید با موفقیت لغو تأیید شد' + ]); + + } catch (\Exception $e) { + return $this->json([ + 'success' => false, + 'message' => 'خطا در لغو تأیید فاکتور خرید: ' . $e->getMessage() + ], 500); + } + } + + #[Route('/api/approval/unapprove/group/buy', name: 'api_approval_unapprove_group_buy', methods: ['POST'])] + public function unapproveBuyInvoiceGroup( + Request $request, + #[CurrentUser] ?User $user, + Access $access, + LogService $logService, + EntityManagerInterface $entityManager + ): Response { + try { + $acc = $access->hasRole('buy'); + if (!$acc) { + throw $this->createAccessDeniedException(); + } + + $business = $acc['bid']; + $businessSettings = $entityManager->getRepository(Business::class)->find($business->getId()); + + if (!$businessSettings->isRequireTwoStepApproval()) { + return $this->json(['success' => false, 'message' => 'تأیید دو مرحله‌ای فعال نیست']); + } + + $canApprove = $this->canUserApproveBuyInvoice($user, $businessSettings); + if (!$canApprove) { + return $this->json(['success' => false, 'message' => 'شما مجوز تأیید این فاکتورها را ندارید']); + } + + $data = json_decode($request->getContent(), true); + $docIds = $data['docIds'] ?? []; + + foreach ($docIds as $docId) { + $document = $entityManager->getRepository(HesabdariDoc::class)->findOneByIncludePreview([ + 'code' => $docId, + 'bid' => $business + ]); + + if (!$document) { + return $this->json(['success' => false, 'message' => 'فاکتور خرید یافت نشد']); + } + + if (!$document->isApproved()) { + return $this->json(['success' => false, 'message' => 'فاکتور خرید تایید نشده است']); + } + + $document->setIsPreview(true); + $document->setIsApproved(false); + $document->setApprovedBy(null); + + $entityManager->persist($document); + } + + $entityManager->flush(); + + $logService->insert( + 'لغو تأیید فاکتورهای خرید', + "فاکتورهای خرید " . implode(', ', $docIds) . " توسط {$user->getFullName()} لغو تأیید شدند", + $user, + $business + ); + + return $this->json([ + 'success' => true, + 'message' => 'فاکتورهای خرید با موفقیت لغو تأیید شدند' + ]); + + } catch (\Exception $e) { + return $this->json([ + 'success' => false, + 'message' => 'خطا در لغو تأیید فاکتورهای خرید: ' . $e->getMessage() + ], 500); + } + } + private function canUserApproveDocument(User $user, Business $business, HesabdariDoc $document): bool { if ($user->getEmail() === $business->getOwner()->getEmail()) { @@ -432,4 +700,13 @@ class ApprovalController extends AbstractController return $business->getApproverSellInvoice() === $user->getEmail(); } + + private function canUserApproveBuyInvoice(User $user, Business $business): bool + { + if ($user->getEmail() === $business->getOwner()->getEmail()) { + return true; + } + + return $business->getApproverBuyInvoice() === $user->getEmail(); + } } diff --git a/hesabixCore/src/Controller/BuyController.php b/hesabixCore/src/Controller/BuyController.php index c678f0e..6348269 100644 --- a/hesabixCore/src/Controller/BuyController.php +++ b/hesabixCore/src/Controller/BuyController.php @@ -252,6 +252,9 @@ class BuyController extends AbstractController return $this->json($extractor->notFound()); } foreach ($params['items'] as $item) { + if (!$item || !isset($item['code'])) { + continue; + } $doc = $entityManager->getRepository(HesabdariDoc::class)->findOneBy([ 'bid' => $acc['bid'], 'year' => $acc['year'], @@ -286,77 +289,177 @@ class BuyController extends AbstractController return $this->json($extractor->operationSuccess()); } - #[Route('/api/buy/docs/search', name: 'app_buy_docs_search')] + #[Route('/api/buy/docs/search', name: 'app_buy_docs_search', methods: ['POST'])] public function app_buy_docs_search(Provider $provider, Request $request, Access $access, Log $log, EntityManagerInterface $entityManager): JsonResponse { $acc = $access->hasRole('buy'); if (!$acc) throw $this->createAccessDeniedException(); - $params = []; - if ($content = $request->getContent()) { - $params = json_decode($content, true); + $params = json_decode($request->getContent(), true) ?? []; + $searchTerm = $params['search'] ?? ''; + $page = max(1, $params['page'] ?? 1); + $perPage = max(1, min(100, $params['perPage'] ?? 10)); + $types = $params['types'] ?? []; + $sortBy = $params['sortBy'] ?? []; + + $queryBuilder = $entityManager->createQueryBuilder() + ->select('DISTINCT d.id, d.dateSubmit, d.date, d.type, d.code, d.des, d.amount') + ->addSelect('d.isPreview, d.isApproved') + ->addSelect('u.fullName as submitter') + ->addSelect('approver.fullName as approvedByName, approver.id as approvedById, approver.email as approvedByEmail') + ->addSelect('l.code as labelCode, l.label as labelLabel') + ->from(HesabdariDoc::class, 'd') + ->leftJoin('d.submitter', 'u') + ->leftJoin('d.approvedBy', 'approver') + ->leftJoin('d.InvoiceLabel', 'l') + ->leftJoin('d.hesabdariRows', 'r') + ->where('d.bid = :bid') + ->andWhere('d.year = :year') + ->andWhere('d.type = :type') + ->andWhere('d.money = :money') + ->setParameter('bid', $acc['bid']) + ->setParameter('year', $acc['year']) + ->setParameter('type', 'buy') + ->setParameter('money', $acc['money']); + + if ($searchTerm) { + $queryBuilder->leftJoin('r.person', 'p') + ->andWhere( + $queryBuilder->expr()->orX( + 'd.code LIKE :search', + 'd.des LIKE :search', + 'd.date LIKE :search', + 'd.amount LIKE :search', + 'p.nikename LIKE :search', + 'p.mobile LIKE :search' + ) + ) + ->setParameter('search', "%$searchTerm%"); } - $data = $entityManager->getRepository(HesabdariDoc::class)->findBy([ - 'bid' => $acc['bid'], - 'year' => $acc['year'], - 'type' => 'buy', - 'money' => $acc['money'] - ], [ - 'id' => 'DESC' - ]); + + if (!empty($types)) { + $queryBuilder->andWhere('l.code IN (:types)') + ->setParameter('types', $types); + } + + // فیلدهای معتبر برای مرتب‌سازی توی دیتابیس + $validDbFields = [ + 'id' => 'd.id', + 'dateSubmit' => 'd.dateSubmit', + 'date' => 'd.date', + 'type' => 'd.type', + 'code' => 'd.code', + 'des' => 'd.des', + 'amount' => 'd.amount', + 'mdate' => 'd.mdate', + 'plugin' => 'd.plugin', + 'refData' => 'd.refData', + 'shortlink' => 'd.shortlink', + 'isPreview' => 'd.isPreview', + 'isApproved' => 'd.isApproved', + 'approvedBy' => 'd.approvedBy', + 'submitter' => 'u.fullName', + 'label' => 'l.label', + ]; + + // اعمال مرتب‌سازی توی دیتابیس + if (!empty($sortBy)) { + foreach ($sortBy as $sort) { + $key = $sort['key'] ?? 'id'; + $direction = isset($sort['order']) && strtoupper($sort['order']) === 'DESC' ? 'DESC' : 'ASC'; + if (isset($validDbFields[$key])) { + $queryBuilder->addOrderBy($validDbFields[$key], $direction); + } + } + } else { + $queryBuilder->orderBy('d.id', 'DESC'); + } + + $totalItemsQuery = clone $queryBuilder; + $totalItems = $totalItemsQuery->select('COUNT(DISTINCT d.id)') + ->getQuery() + ->getSingleScalarResult(); + + $queryBuilder->setFirstResult(($page - 1) * $perPage) + ->setMaxResults($perPage); + + $docs = $queryBuilder->getQuery()->getArrayResult(); $dataTemp = []; - foreach ($data as $item) { - $temp = [ - 'id' => $item->getId(), - 'dateSubmit' => $item->getDateSubmit(), - 'date' => $item->getDate(), - 'type' => $item->getType(), - 'code' => $item->getCode(), - 'des' => $item->getDes(), - 'amount' => $item->getAmount(), - 'submitter' => $item->getSubmitter()->getFullName(), + foreach ($docs as $doc) { + $item = [ + 'id' => $doc['id'], + 'dateSubmit' => $doc['dateSubmit'], + 'date' => $doc['date'], + 'type' => $doc['type'], + 'code' => $doc['code'], + 'des' => $doc['des'], + 'amount' => $doc['amount'], + 'submitter' => $doc['submitter'], + 'label' => $doc['labelCode'] ? [ + 'code' => $doc['labelCode'], + 'label' => $doc['labelLabel'] + ] : null, + 'isPreview' => $doc['isPreview'], + 'isApproved' => $doc['isApproved'], + 'approvedBy' => $doc['approvedByName'] ? [ + 'fullName' => $doc['approvedByName'], + 'id' => $doc['approvedById'], + 'email' => $doc['approvedByEmail'] + ] : null, ]; - $mainRow = $entityManager->getRepository(HesabdariRow::class)->getNotEqual($item, 'person'); - $temp['person'] = ''; - if ($mainRow) - $temp['person'] = Explore::ExplorePerson($mainRow->getPerson()); - $temp['label'] = null; - if ($item->getInvoiceLabel()) { - $temp['label'] = [ - 'code' => $item->getInvoiceLabel()->getCode(), - 'label' => $item->getInvoiceLabel()->getLabel() - ]; - } + $mainRow = $entityManager->getRepository(HesabdariRow::class) + ->createQueryBuilder('r') + ->where('r.doc = :docId') + ->andWhere('r.person IS NOT NULL') + ->setParameter('docId', $doc['id']) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + $item['person'] = $mainRow && $mainRow->getPerson() ? Explore::ExplorePerson($mainRow->getPerson()) : null; - $temp['relatedDocsCount'] = count($item->getRelatedDocs()); - $pays = 0; - foreach ($item->getRelatedDocs() as $relatedDoc) { - $pays += $relatedDoc->getAmount(); - } - $temp['relatedDocsPays'] = $pays; + // محاسبه پرداختی‌ها + $relatedDocs = $entityManager->getRepository(HesabdariDoc::class) + ->createQueryBuilder('rd') + ->select('SUM(rd.amount) as total_pays, COUNT(rd.id) as count_docs') + ->innerJoin('rd.relatedDocs', 'rel') + ->where('rel.id = :sourceDocId') + ->andWhere('rd.bid = :bidId') + ->setParameter('sourceDocId', $doc['id']) + ->setParameter('bidId', $acc['bid']->getId()) + ->getQuery() + ->getSingleResult(); - $temp['commodities'] = []; - foreach ($item->getHesabdariRows() as $item) { - if ($item->getRef()->getCode() == '51') { - $temp['discountAll'] = $item->getBs(); - } elseif ($item->getRef()->getCode() == '90') { - $temp['transferCost'] = $item->getBd(); - } - if ($item->getCommodity()) { - $temp['commodities'][] = Explore::ExploreCommodity($item->getCommodity(), $item->getCommdityCount()); + $item['relatedDocsCount'] = (int) $relatedDocs['count_docs']; + $item['relatedDocsPays'] = $relatedDocs['total_pays'] ?? 0; + + // محاسبه کالاها و تخفیف/هزینه حمل + $item['commodities'] = []; + $item['discountAll'] = 0; + $item['transferCost'] = 0; + + $rows = $entityManager->getRepository(HesabdariRow::class)->findBy(['doc' => $doc['id']]); + foreach ($rows as $row) { + if ($row->getRef()->getCode() == '51') { + $item['discountAll'] = $row->getBs(); + } elseif ($row->getRef()->getCode() == '90') { + $item['transferCost'] = $row->getBd(); + } elseif ($row->getCommodity()) { + $item['commodities'][] = Explore::ExploreCommodity($row->getCommodity(), $row->getCommdityCount()); } } - if (!array_key_exists('discountAll', $temp)) - $temp['discountAll'] = 0; - if (!array_key_exists('transferCost', $temp)) - $temp['transferCost'] = 0; - $dataTemp[] = $temp; + $dataTemp[] = $item; } - return $this->json($dataTemp); + + return $this->json([ + 'items' => $dataTemp, + 'total' => (int) $totalItems, + 'page' => $page, + 'perPage' => $perPage, + ]); } #[Route('/api/buy/posprinter/invoice', name: 'app_buy_posprinter_invoice')] @@ -425,6 +528,8 @@ class BuyController extends AbstractController return $this->json(['id' => $pdfPid]); } + + #[Route('/api/buy/print/invoice', name: 'app_buy_print_invoice')] public function app_buy_print_invoice(Printers $printers, Provider $provider, Request $request, Access $access, Log $log, EntityManagerInterface $entityManager, TemplateRenderer $renderer): JsonResponse { @@ -586,4 +691,43 @@ class BuyController extends AbstractController } return $this->json(['id' => $pdfPid]); } + + #[Route('/api/buy/approve/{code}', name: 'app_buy_approve', methods: ['POST'])] + public function approveBuyDoc(string $code, Request $request, Access $access, EntityManagerInterface $entityManager): JsonResponse + { + $acc = $access->hasRole('buy'); + if (!$acc) throw $this->createAccessDeniedException(); + $doc = $entityManager->getRepository(HesabdariDoc::class)->findOneBy([ + 'bid' => $acc['bid'], + 'code' => $code, + 'money' => $acc['money'] + ]); + if (!$doc) throw $this->createNotFoundException('فاکتور یافت نشد'); + $doc->setIsPreview(false); + $doc->setIsApproved(true); + $doc->setApprovedBy($this->getUser()); + $entityManager->persist($doc); + $entityManager->flush(); + return $this->json(['result' => 0]); + } + + #[Route('/api/buy/payment/approve/{code}', name: 'app_buy_payment_approve', methods: ['POST'])] + public function approveBuyPayment(string $code, Request $request, Access $access, EntityManagerInterface $entityManager): JsonResponse + { + $acc = $access->hasRole('buy'); + if (!$acc) throw $this->createAccessDeniedException(); + $paymentDoc = $entityManager->getRepository(HesabdariDoc::class)->findOneBy([ + 'bid' => $acc['bid'], + 'code' => $code, + 'money' => $acc['money'], + 'type' => 'buy_pay' + ]); + if (!$paymentDoc) throw $this->createNotFoundException('سند پرداخت یافت نشد'); + $paymentDoc->setIsPreview(false); + $paymentDoc->setIsApproved(true); + $paymentDoc->setApprovedBy($this->getUser()); + $entityManager->persist($paymentDoc); + $entityManager->flush(); + return $this->json(['result' => 0]); + } } diff --git a/hesabixCore/src/Entity/HesabdariDoc.php b/hesabixCore/src/Entity/HesabdariDoc.php index b3b86ff..a15dd47 100644 --- a/hesabixCore/src/Entity/HesabdariDoc.php +++ b/hesabixCore/src/Entity/HesabdariDoc.php @@ -728,11 +728,11 @@ class HesabdariDoc } // Approval fields - #[ORM\Column(nullable: true)] - private ?bool $isPreview = null; + #[ORM\Column(nullable: true, options: ['default' => false])] + private ?bool $isPreview = false; - #[ORM\Column(nullable: true)] - private ?bool $isApproved = null; + #[ORM\Column(nullable: true, options: ['default' => true])] + private ?bool $isApproved = true; #[ORM\ManyToOne] #[ORM\JoinColumn(nullable: true)] diff --git a/hesabixCore/src/Repository/HesabdariDocRepository.php b/hesabixCore/src/Repository/HesabdariDocRepository.php index f944a2c..b993e18 100644 --- a/hesabixCore/src/Repository/HesabdariDocRepository.php +++ b/hesabixCore/src/Repository/HesabdariDocRepository.php @@ -109,7 +109,11 @@ class HesabdariDocRepository extends ServiceEntityRepository $qb = $this->createQueryBuilder('h'); foreach ($criteria as $field => $value) { - $qb->andWhere("h.$field = :$field")->setParameter($field, $value); + if ($field === 'bid' && is_object($value)) { + $qb->andWhere("h.$field = :$field")->setParameter($field, $value->getId()); + } else { + $qb->andWhere("h.$field = :$field")->setParameter($field, $value); + } } $qb->andWhere('(h.isApproved = 1 OR (h.isApproved = 0 AND h.isPreview = 0))'); @@ -129,7 +133,11 @@ class HesabdariDocRepository extends ServiceEntityRepository $qb = $this->createQueryBuilder('h'); foreach ($criteria as $field => $value) { - $qb->andWhere("h.$field = :$field")->setParameter($field, $value); + if ($field === 'bid' && is_object($value)) { + $qb->andWhere("h.$field = :$field")->setParameter($field, $value->getId()); + } else { + $qb->andWhere("h.$field = :$field")->setParameter($field, $value); + } } if ($orderBy) { @@ -146,7 +154,11 @@ class HesabdariDocRepository extends ServiceEntityRepository $qb = $this->createQueryBuilder('h'); foreach ($criteria as $field => $value) { - $qb->andWhere("h.$field = :$field")->setParameter($field, $value); + if ($field === 'bid' && is_object($value)) { + $qb->andWhere("h.$field = :$field")->setParameter($field, $value->getId()); + } else { + $qb->andWhere("h.$field = :$field")->setParameter($field, $value); + } } $qb->andWhere('(h.isApproved = 1 OR (h.isApproved = 0 AND h.isPreview = 0))'); @@ -175,4 +187,34 @@ class HesabdariDocRepository extends ServiceEntityRepository ->getQuery() ->getResult(); } + + //include preview + public function findByIncludePreview(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + { + $qb = $this->createQueryBuilder('h'); + + foreach ($criteria as $field => $value) { + if ($field === 'bid' && is_object($value)) { + $qb->andWhere("h.$field = :$field")->setParameter($field, $value->getId()); + } else { + $qb->andWhere("h.$field = :$field")->setParameter($field, $value); + } + } + + if ($orderBy) { + foreach ($orderBy as $field => $direction) { + $qb->addOrderBy("h.$field", $direction); + } + } + + if ($limit) { + $qb->setMaxResults($limit); + } + + if ($offset) { + $qb->setFirstResult($offset); + } + + return $qb->getQuery()->getResult(); + } } \ No newline at end of file diff --git a/webUI/src/views/acc/buy/list.vue b/webUI/src/views/acc/buy/list.vue index 1bc1200..be2cf87 100755 --- a/webUI/src/views/acc/buy/list.vue +++ b/webUI/src/views/acc/buy/list.vue @@ -28,6 +28,17 @@ + عملیات گروهی تایید + + + + + + تغییر برچسب‌ها