bug fix in lists

This commit is contained in:
Hesabix 2025-03-18 12:16:01 +00:00
parent 9df5a5864b
commit 5470b82951
4 changed files with 496 additions and 201 deletions

View file

@ -172,27 +172,104 @@ class AdminController extends AbstractController
return $this->json($extractor->operationSuccess($resp));
}
#[Route('/api/admin/users/search', name: 'admin_users_list_search')]
public function admin_users_list_search(Extractor $extractor, Jdate $jdate, #[CurrentUser] ?User $user, UserPasswordHasherInterface $userPasswordHasher, EntityManagerInterface $entityManager, Request $request): Response
{
$params = [];
if ($content = $request->getContent()) {
$params = json_decode($content, true);
#[Route('/api/admin/users/search', name: 'admin_users_list_search', methods: ['POST'])]
public function admin_users_list_search(
Extractor $extractor,
Jdate $jdate,
#[CurrentUser] ?User $user,
EntityManagerInterface $entityManager,
Request $request
): Response {
$params = json_decode($request->getContent(), true) ?? [];
// پارامترهای صفحه‌بندی و مرتب‌سازی
$pagination = $params['pagination'] ?? ['page' => 1, 'limit' => 10];
$sort = $params['sort'] ?? ['sortBy' => 'id', 'sortDesc' => true];
$filters = $params['filters'] ?? [];
$page = max(1, $pagination['page'] ?? 1);
$limit = max(1, min(100, $pagination['limit'] ?? 10));
$offset = ($page - 1) * $limit;
// ساخت کوئری پایه
$queryBuilder = $entityManager->createQueryBuilder()
->select('u')
->from(User::class, 'u');
// اعمال فیلترها و جستجو
if (!empty($filters['search'])) {
$searchTerm = $filters['search'];
$queryBuilder->andWhere(
$queryBuilder->expr()->orX(
'u.email LIKE :search',
'u.fullName LIKE :search',
'u.mobile LIKE :search',
'u.dateRegister LIKE :search',
'u.invateCode LIKE :search'
)
)
->setParameter('search', "%$searchTerm%");
}
$items = $entityManager->getRepository(User::class)->findByPage($params['options']['page'], $params['options']['rowsPerPage'], $params['search']);
// اعمال فیلترهای وضعیت
if (isset($filters['status'])) {
$queryBuilder->andWhere('u.active = :status')
->setParameter('status', $filters['status']);
}
// اعمال مرتب‌سازی
$sortField = $sort['sortBy'] ?? 'id';
$sortDirection = ($sort['sortDesc'] ?? true) ? 'DESC' : 'ASC';
// اطمینان از اینکه فیلد مرتب‌سازی معتبر است
$allowedSortFields = ['id', 'email', 'fullName', 'mobile', 'dateRegister', 'active'];
if (in_array($sortField, $allowedSortFields)) {
$queryBuilder->orderBy("u.$sortField", $sortDirection);
} else {
$queryBuilder->orderBy('u.id', 'DESC');
}
// محاسبه تعداد کل نتایج
$totalItemsQuery = clone $queryBuilder;
$totalItems = $totalItemsQuery->select('COUNT(u.id)')
->getQuery()
->getSingleScalarResult();
// اعمال صفحه‌بندی
$queryBuilder->setFirstResult($offset)
->setMaxResults($limit);
// دریافت نتایج
$items = $queryBuilder->getQuery()->getResult();
// تبدیل نتایج به فرمت مورد نظر
$resp = [];
foreach ($items as $item) {
$temp = [];
$temp['id'] = $item->getId();
$temp['email'] = $item->getEmail();
$temp['mobile'] = $item->getMobile();
$temp['fullname'] = $item->getFullName();
$temp['status'] = $item->isActive();
$temp['dateRegister'] = $jdate->jdate('Y/n/d', $item->getDateRegister());
$temp['bidCount'] = count($entityManager->getRepository(Business::class)->findBy(['owner' => $item]));
$temp = [
'id' => $item->getId(),
'email' => $item->getEmail(),
'mobile' => $item->getMobile(),
'fullname' => $item->getFullName(),
'status' => $item->isActive(),
'dateRegister' => $jdate->jdate('Y/n/d', $item->getDateRegister()),
'bidCount' => count($entityManager->getRepository(Business::class)->findBy(['owner' => $item])),
'roles' => $item->getRoles(),
'inviteCode' => $item->getInvateCode()
];
$resp[] = $temp;
}
return $this->json($extractor->operationSuccess($resp));
return $this->json([
'status' => 'success',
'message' => 'عملیات با موفقیت انجام شد',
'data' => [
'items' => $resp,
'total' => (int) $totalItems,
'page' => $page,
'limit' => $limit,
'totalPages' => ceil($totalItems / $limit)
]
]);
}
#[Route('/api/admin/settings/sms/info', name: 'admin_settings_sms_info')]

View file

@ -160,4 +160,155 @@ class CostController extends AbstractController
'series' => $series,
]);
}
#[Route('/api/cost/list/search', name: 'app_cost_list_search', methods: ['POST'])]
public function searchCostList(
Request $request,
Access $access,
EntityManagerInterface $entityManager,
Jdate $jdate
): JsonResponse {
$acc = $access->hasRole('cost');
if (!$acc) {
throw $this->createAccessDeniedException();
}
$params = json_decode($request->getContent(), true) ?? [];
// پارامترهای ورودی
$filters = $params['filters'] ?? [];
$pagination = $params['pagination'] ?? ['page' => 1, 'limit' => 10];
$sort = $params['sort'] ?? ['sortBy' => 'id', 'sortDesc' => true];
$type = $params['type'] ?? 'cost';
// تنظیم پارامترهای صفحه‌بندی
$page = max(1, $pagination['page'] ?? 1);
$limit = max(1, min(100, $pagination['limit'] ?? 10));
// ساخت کوئری پایه
$queryBuilder = $entityManager->createQueryBuilder()
->select('DISTINCT d.id, d.dateSubmit, d.date, d.type, d.code, d.des, d.amount')
->addSelect('u.fullName as submitter')
->from('App\Entity\HesabdariDoc', 'd')
->leftJoin('d.submitter', 'u')
->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', $type)
->setParameter('money', $acc['money']);
// اعمال فیلترها
if (!empty($filters)) {
if (isset($filters['search'])) {
$queryBuilder->leftJoin('d.hesabdariRows', 'r')
->leftJoin('r.person', 'p')
->leftJoin('r.ref', 't')
->andWhere(
$queryBuilder->expr()->orX(
'd.code LIKE :search',
'd.des LIKE :search',
'd.date LIKE :search',
'd.amount LIKE :search',
'p.nikename LIKE :search',
't.name LIKE :search'
)
)
->setParameter('search', "%{$filters['search']}%");
}
if (isset($filters['dateFrom'])) {
$queryBuilder->andWhere('d.date >= :dateFrom')
->setParameter('dateFrom', $filters['dateFrom']);
}
if (isset($filters['dateTo'])) {
$queryBuilder->andWhere('d.date <= :dateTo')
->setParameter('dateTo', $filters['dateTo']);
}
if (isset($filters['amount'])) {
$queryBuilder->andWhere('d.amount = :amount')
->setParameter('amount', $filters['amount']);
}
}
// اعمال مرتب‌سازی
$sortField = $sort['sortBy'] ?? 'id';
$sortDirection = ($sort['sortDesc'] ?? true) ? 'DESC' : 'ASC';
$queryBuilder->orderBy("d.$sortField", $sortDirection);
// محاسبه تعداد کل نتایج
$totalItemsQuery = clone $queryBuilder;
$totalItems = $totalItemsQuery->select('COUNT(DISTINCT d.id)')
->getQuery()
->getSingleScalarResult();
// اعمال صفحه‌بندی
$queryBuilder->setFirstResult(($page - 1) * $limit)
->setMaxResults($limit);
$docs = $queryBuilder->getQuery()->getArrayResult();
$dataTemp = [];
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']
];
// دریافت اطلاعات مرکز هزینه و مبلغ
$costDetails = $entityManager->createQueryBuilder()
->select('t.name as center_name, r.bd as amount')
->from('App\Entity\HesabdariRow', 'r')
->join('r.ref', 't')
->where('r.doc = :docId')
->andWhere('r.bd != 0')
->setParameter('docId', $doc['id'])
->getQuery()
->getResult();
$item['costCenters'] = array_map(function($detail) {
return [
'name' => $detail['center_name'],
'amount' => (int) $detail['amount']
];
}, $costDetails);
// دریافت اطلاعات شخص مرتبط
$personInfo = $entityManager->createQueryBuilder()
->select('p.id, p.nikename, p.code')
->from('App\Entity\HesabdariRow', 'r')
->join('r.person', 'p')
->where('r.doc = :docId')
->andWhere('r.person IS NOT NULL')
->setParameter('docId', $doc['id'])
->setMaxResults(1)
->getQuery()
->getOneOrNullResult();
$item['person'] = $personInfo ? [
'id' => $personInfo['id'],
'nikename' => $personInfo['nikename'],
'code' => $personInfo['code']
] : null;
$dataTemp[] = $item;
}
return $this->json([
'items' => $dataTemp,
'total' => (int) $totalItems,
'page' => $page,
'limit' => $limit
]);
}
}

View file

@ -377,6 +377,7 @@ class SellController extends AbstractController
$perPage = max(1, min(100, $params['perPage'] ?? 10));
$types = $params['types'] ?? [];
$dateFilter = $params['dateFilter'] ?? 'all';
$sortBy = $params['sortBy'] ?? [];
$queryBuilder = $entityManager->createQueryBuilder()
->select('DISTINCT d.id, d.dateSubmit, d.date, d.type, d.code, d.des, d.amount')
@ -385,6 +386,7 @@ class SellController extends AbstractController
->from(HesabdariDoc::class, 'd')
->leftJoin('d.submitter', 'u')
->leftJoin('d.InvoiceLabel', 'l')
->leftJoin('d.hesabdariRows', 'r')
->where('d.bid = :bid')
->andWhere('d.year = :year')
->andWhere('d.type = :type')
@ -392,9 +394,9 @@ class SellController extends AbstractController
->setParameter('bid', $acc['bid'])
->setParameter('year', $acc['year'])
->setParameter('type', 'sell')
->setParameter('money', $acc['money'])
->orderBy('d.id', 'DESC');
->setParameter('money', $acc['money']);
// اعمال فیلترهای تاریخ
$today = $jdate->jdate('Y/m/d', time());
if ($dateFilter === 'today') {
$queryBuilder->andWhere('d.date = :today')
@ -412,8 +414,7 @@ class SellController extends AbstractController
}
if ($searchTerm) {
$queryBuilder->leftJoin('d.hesabdariRows', 'r')
->leftJoin('r.person', 'p')
$queryBuilder->leftJoin('r.person', 'p')
->andWhere(
$queryBuilder->expr()->orX(
'd.code LIKE :search',
@ -432,6 +433,40 @@ class SellController extends AbstractController
->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',
'status' => 'd.status',
'submitter' => 'u.fullName',
'label' => 'l.label', // از InvoiceLabel
];
// اعمال مرتب‌سازی توی دیتابیس
if (!empty($sortBy)) {
foreach ($sortBy as $sort) {
$key = $sort['key'] ?? 'id';
$direction = isset($sort['order']) && strtoupper($sort['order']) === 'DESC' ? 'DESC' : 'ASC';
if ($key === 'profit' || $key === 'receivedAmount') {
continue; // این‌ها توی PHP مرتب می‌شن
} elseif (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()
@ -473,32 +508,57 @@ class SellController extends AbstractController
'code' => $mainRow->getPerson()->getCode()
] : null;
$relatedDocs = $entityManager->createQueryBuilder()
->select('SUM(rd.amount)')
->from(HesabdariDoc::class, 'rd')
->join('rd.relatedDocs', 'r')
->where('r.id = :docId')
->setParameter('docId', $doc['id'])
->getQuery()
->getSingleScalarResult();
$item['relatedDocsCount'] = $relatedDocs ? count($relatedDocs) : 0;
$item['relatedDocsPays'] = $relatedDocs ?: 0;
// استفاده از SQL خام برای محاسبه پرداختی‌ها
$sql = "
SELECT SUM(rd.amount) as total_pays, COUNT(rd.id) as count_docs
FROM hesabdari_doc rd
JOIN hesabdari_doc_hesabdari_doc rel ON rel.hesabdari_doc_target = rd.id
WHERE rel.hesabdari_doc_source = :sourceDocId
AND rd.bid_id = :bidId
";
$stmt = $entityManager->getConnection()->prepare($sql);
$stmt->bindValue('sourceDocId', $doc['id']);
$stmt->bindValue('bidId', $acc['bid']->getId());
$result = $stmt->executeQuery()->fetchAssociative();
$relatedDocsPays = $result['total_pays'] ?? 0;
$relatedDocsCount = $result['count_docs'] ?? 0;
$item['relatedDocsCount'] = (int) $relatedDocsCount;
$item['relatedDocsPays'] = $relatedDocsPays;
$item['profit'] = $this->calculateProfit($doc['id'], $acc, $entityManager);
$item['discountAll'] = 0;
$item['transferCost'] = 0;
$rows = $entityManager->getRepository(HesabdariRow::class)->findBy(['doc' => $doc]);
foreach ($rows as $row) {
if ($row->getRef()->getCode() == '104')
if ($row->getRef()->getCode() == '104') {
$item['discountAll'] = $row->getBd();
elseif ($row->getRef()->getCode() == '61')
} elseif ($row->getRef()->getCode() == '61') {
$item['transferCost'] = $row->getBs();
}
}
$dataTemp[] = $item;
}
// مرتب‌سازی توی PHP برای profit و receivedAmount
if (!empty($sortBy)) {
foreach ($sortBy as $sort) {
$key = $sort['key'] ?? 'id';
$direction = isset($sort['order']) && strtoupper($sort['order']) === 'DESC' ? SORT_DESC : SORT_ASC;
if ($key === 'profit') {
usort($dataTemp, function ($a, $b) use ($direction) {
return $direction === SORT_ASC ? $a['profit'] - $b['profit'] : $b['profit'] - $a['profit'];
});
} elseif ($key === 'receivedAmount') {
usort($dataTemp, function ($a, $b) use ($direction) {
return $direction === SORT_ASC ? $a['relatedDocsPays'] - $b['relatedDocsPays'] : $b['relatedDocsPays'] - $a['relatedDocsPays'];
});
}
}
}
return $this->json([
'items' => $dataTemp,
'total' => (int) $totalItems,
@ -507,6 +567,7 @@ class SellController extends AbstractController
]);
}
// متد calculateProfit بدون تغییر
private function calculateProfit(int $docId, array $acc, EntityManagerInterface $entityManager): int
{
$profit = 0;

View file

@ -79,6 +79,11 @@ class HesabdariDoc
private ?WalletTransaction $walletTransaction = null;
#[ORM\ManyToMany(targetEntity: self::class)]
#[ORM\JoinTable(
name: 'hesabdari_doc_hesabdari_doc',
joinColumns: [new ORM\JoinColumn(name: 'hesabdari_doc_source', referencedColumnName: 'id')],
inverseJoinColumns: [new ORM\JoinColumn(name: 'hesabdari_doc_target', referencedColumnName: 'id')]
)]
#[Ignore]
private Collection $relatedDocs;
@ -394,6 +399,7 @@ class HesabdariDoc
return $this;
}
public function getStatus(): ?string
{
return $this->status;