Skip to content

Commit 2cfa334

Browse files
authored
Add customer account order and complaint filtering (#4641)
2 parents 7e54696 + e52ac27 commit 2cfa334

18 files changed

Lines changed: 574 additions & 70 deletions

src/Model/Complaint/ComplaintApiFacade.php

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use Shopsys\FrameworkBundle\Model\Complaint\ComplaintItemFactory;
1515
use Shopsys\FrameworkBundle\Model\Complaint\ComplaintNumberSequenceRepository;
1616
use Shopsys\FrameworkBundle\Model\Complaint\Mail\ComplaintMailFacade;
17+
use Shopsys\FrameworkBundle\Model\Complaint\Status\ComplaintStatus;
18+
use Shopsys\FrameworkBundle\Model\Complaint\Status\ComplaintStatusFacade;
1719
use Shopsys\FrameworkBundle\Model\Customer\Customer;
1820
use Shopsys\FrameworkBundle\Model\Customer\User\CurrentCustomerUser;
1921
use Shopsys\FrameworkBundle\Model\Customer\User\CustomerUser;
@@ -43,6 +45,7 @@ public function __construct(
4345
protected readonly ComplaintMailFacade $complaintMailFacade,
4446
protected readonly ComplaintRepository $complaintRepository,
4547
protected readonly WithdrawalRequestFacade $withdrawalRequestFacade,
48+
protected readonly ComplaintStatusFacade $complaintStatusFacade,
4649
) {
4750
}
4851

@@ -143,9 +146,14 @@ public function getCustomerUserComplaintsLimitedList(
143146
CustomerUser $customerUser,
144147
int $limit,
145148
int $offset,
146-
?string $search = null,
149+
ComplaintFilter $filter,
147150
): array {
148-
return $this->complaintRepository->getCustomerUserComplaintsLimitedList($customerUser, $limit, $offset, $search);
151+
return $this->complaintRepository->getCustomerUserComplaintsLimitedList(
152+
$customerUser,
153+
$limit,
154+
$offset,
155+
$filter,
156+
);
149157
}
150158

151159
/**
@@ -155,23 +163,78 @@ public function getCustomerComplaintsLimitedList(
155163
Customer $customer,
156164
int $limit,
157165
int $offset,
158-
?string $search = null,
166+
ComplaintFilter $filter,
159167
): array {
160-
return $this->complaintRepository->getCustomerComplaintsLimitedList($customer, $limit, $offset, $search);
168+
return $this->complaintRepository->getCustomerComplaintsLimitedList($customer, $limit, $offset, $filter);
161169
}
162170

163171
public function getCustomerUserComplaintsLimitedListCount(
164172
CustomerUser $customerUser,
165-
?string $search = null,
173+
ComplaintFilter $filter,
166174
): int {
167-
return $this->complaintRepository->getCustomerUserComplaintsListCount($customerUser, $search);
175+
return $this->complaintRepository->getCustomerUserComplaintsListCount($customerUser, $filter);
168176
}
169177

170178
public function getCustomerComplaintsLimitedListCount(
171179
Customer $customer,
172-
?string $search = null,
180+
ComplaintFilter $filter,
173181
): int {
174-
return $this->complaintRepository->getCustomerComplaintsListCount($customer, $search);
182+
return $this->complaintRepository->getCustomerComplaintsListCount($customer, $filter);
183+
}
184+
185+
/**
186+
* @return array<int, array{status: array{code: string, type: string, name: string}, count: int}>
187+
*/
188+
public function getCustomerUserComplaintStatusCounts(
189+
CustomerUser $customerUser,
190+
ComplaintFilter $filter,
191+
string $locale,
192+
): array {
193+
return $this->getComplaintStatusesWithCounts(
194+
$this->complaintRepository->getCustomerUserComplaintStatusCounts($customerUser, $filter),
195+
$locale,
196+
);
197+
}
198+
199+
/**
200+
* @return array<int, array{status: array{code: string, type: string, name: string}, count: int}>
201+
*/
202+
public function getCustomerComplaintStatusCounts(
203+
Customer $customer,
204+
ComplaintFilter $filter,
205+
string $locale,
206+
): array {
207+
return $this->getComplaintStatusesWithCounts(
208+
$this->complaintRepository->getCustomerComplaintStatusCounts($customer, $filter),
209+
$locale,
210+
);
211+
}
212+
213+
/**
214+
* @param array<int, int> $countsByStatusId
215+
* @return array<int, array{status: array{code: string, type: string, name: string}, count: int}>
216+
*/
217+
protected function getComplaintStatusesWithCounts(array $countsByStatusId, string $locale): array
218+
{
219+
return array_map(
220+
fn (ComplaintStatus $complaintStatus): array => [
221+
'status' => $this->createComplaintStatusData($complaintStatus, $locale),
222+
'count' => $countsByStatusId[$complaintStatus->getId()] ?? 0,
223+
],
224+
$this->complaintStatusFacade->getAll(),
225+
);
226+
}
227+
228+
/**
229+
* @return array{code: string, type: string, name: string}
230+
*/
231+
protected function createComplaintStatusData(ComplaintStatus $complaintStatus, string $locale): array
232+
{
233+
return [
234+
'code' => $complaintStatus->getCode(),
235+
'type' => $complaintStatus->getStatusType(),
236+
'name' => $complaintStatus->getName($locale),
237+
];
175238
}
176239

177240
public function findByComplaintNumberAndCustomerUser(
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shopsys\FrontendApiBundle\Model\Complaint;
6+
7+
use DateTimeImmutable;
8+
9+
class ComplaintFilter
10+
{
11+
/**
12+
* @param \Shopsys\FrameworkBundle\Model\Complaint\Status\ComplaintStatus[]|null $statuses
13+
*/
14+
public function __construct(
15+
protected ?DateTimeImmutable $createdAfter = null,
16+
protected ?DateTimeImmutable $createdBefore = null,
17+
protected ?array $statuses = null,
18+
protected ?string $search = null,
19+
) {
20+
}
21+
22+
public function getCreatedAfter(): ?DateTimeImmutable
23+
{
24+
return $this->createdAfter;
25+
}
26+
27+
public function getCreatedBefore(): ?DateTimeImmutable
28+
{
29+
return $this->createdBefore;
30+
}
31+
32+
/**
33+
* @return \Shopsys\FrameworkBundle\Model\Complaint\Status\ComplaintStatus[]|null
34+
*/
35+
public function getStatuses(): ?array
36+
{
37+
return $this->statuses;
38+
}
39+
40+
public function getSearch(): ?string
41+
{
42+
return $this->search;
43+
}
44+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shopsys\FrontendApiBundle\Model\Complaint;
6+
7+
use Overblog\GraphQLBundle\Definition\Argument;
8+
use Shopsys\FrameworkBundle\Model\Complaint\Status\ComplaintStatusFacade;
9+
10+
class ComplaintFilterFactory
11+
{
12+
public function __construct(
13+
protected readonly ComplaintStatusFacade $complaintStatusFacade,
14+
) {
15+
}
16+
17+
public function createFromArgument(Argument $argument): ComplaintFilter
18+
{
19+
if (!isset($argument['filter'])) {
20+
return new ComplaintFilter();
21+
}
22+
23+
$filter = $argument['filter'];
24+
$statusCodes = $filter['statusCodes'] ?? [];
25+
$statuses = $this->complaintStatusFacade->getAllByCodes($statusCodes);
26+
27+
$search = isset($filter['search']) ? trim($filter['search']) : null;
28+
29+
return new ComplaintFilter(
30+
$filter['createdAfter'] ?? null,
31+
$filter['createdBefore'] ?? null,
32+
$statuses !== [] ? $statuses : null,
33+
$search !== '' ? $search : null,
34+
);
35+
}
36+
}

src/Model/Complaint/ComplaintRepository.php

Lines changed: 99 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,17 @@ public function getCustomerUserComplaintsLimitedList(
2626
CustomerUser $customerUser,
2727
int $limit,
2828
int $offset,
29-
?string $search = null,
29+
ComplaintFilter $filter,
3030
): array {
3131
$queryBuilder = $this->createCustomerUserComplaintsQueryBuilder($customerUser)
3232
->orderBy('c.createdAt', 'DESC')
3333
->addOrderBy('c.id', 'DESC')
3434
->setMaxResults($limit)
3535
->setFirstResult($offset);
3636

37+
$this->applyFilterToQueryBuilder($queryBuilder, $filter);
3738

38-
return $this->applySearchToQueryBuilder($queryBuilder, $search)
39-
->getQuery()
40-
->getResult();
39+
return $queryBuilder->getQuery()->getResult();
4140
}
4241

4342
/**
@@ -47,41 +46,75 @@ public function getCustomerComplaintsLimitedList(
4746
Customer $customer,
4847
int $limit,
4948
int $offset,
50-
?string $search = null,
49+
ComplaintFilter $filter,
5150
): array {
5251
$queryBuilder = $this->createCustomerComplaintsQueryBuilder($customer)
5352
->orderBy('c.createdAt', 'DESC')
5453
->addOrderBy('c.id', 'DESC')
5554
->setMaxResults($limit)
5655
->setFirstResult($offset);
5756

58-
return $this->applySearchToQueryBuilder($queryBuilder, $search)
59-
->getQuery()
60-
->getResult();
57+
$this->applyFilterToQueryBuilder($queryBuilder, $filter);
58+
59+
return $queryBuilder->getQuery()->getResult();
6160
}
6261

6362
public function getCustomerUserComplaintsListCount(
6463
CustomerUser $customerUser,
65-
?string $search = null,
64+
ComplaintFilter $filter,
6665
): int {
6766
$queryBuilder = $this->createCustomerUserComplaintsQueryBuilder($customerUser)
68-
->select('COUNT(c)');
67+
->select('COUNT(DISTINCT c.id)');
6968

70-
return $this->applySearchToQueryBuilder($queryBuilder, $search)
71-
->getQuery()
72-
->getSingleScalarResult();
69+
$this->applyFilterToQueryBuilder($queryBuilder, $filter);
70+
71+
return $queryBuilder->getQuery()->getSingleScalarResult();
7372
}
7473

7574
public function getCustomerComplaintsListCount(
7675
Customer $customer,
77-
?string $search = null,
76+
ComplaintFilter $filter,
7877
): int {
7978
$queryBuilder = $this->createCustomerComplaintsQueryBuilder($customer)
80-
->select('COUNT(c)');
79+
->select('COUNT(DISTINCT c.id)');
8180

82-
return $this->applySearchToQueryBuilder($queryBuilder, $search)
83-
->getQuery()
84-
->getSingleScalarResult();
81+
$this->applyFilterToQueryBuilder($queryBuilder, $filter);
82+
83+
return $queryBuilder->getQuery()->getSingleScalarResult();
84+
}
85+
86+
/**
87+
* @return array<int, int>
88+
*/
89+
public function getCustomerUserComplaintStatusCounts(
90+
CustomerUser $customerUser,
91+
ComplaintFilter $filter,
92+
): array {
93+
$queryBuilder = $this->createCustomerUserComplaintsQueryBuilder($customerUser)
94+
->join('c.status', 'cs')
95+
->select('cs.id AS statusId, COUNT(DISTINCT c.id) AS complaintsCount')
96+
->groupBy('cs.id');
97+
98+
$this->applyFilterToQueryBuilder($queryBuilder, $filter);
99+
100+
return $this->extractComplaintStatusCountsByStatusId($queryBuilder->getQuery()->getArrayResult());
101+
}
102+
103+
/**
104+
* @return array<int, int>
105+
*/
106+
public function getCustomerComplaintStatusCounts(
107+
Customer $customer,
108+
ComplaintFilter $filter,
109+
): array {
110+
$queryBuilder = $this->createCustomerComplaintsQueryBuilder($customer)
111+
->join('c.status', 'cs')
112+
->select('cs.id AS statusId, COUNT(DISTINCT c.id) AS complaintsCount')
113+
->groupBy('cs.id');
114+
115+
$this->applyFilterToQueryBuilder($queryBuilder, $filter);
116+
117+
return $this->extractComplaintStatusCountsByStatusId($queryBuilder->getQuery()->getArrayResult());
85118
}
86119

87120
protected function createCustomerUserComplaintsQueryBuilder(
@@ -129,22 +162,56 @@ protected function createQueryBuilder(): QueryBuilder
129162
->select('c');
130163
}
131164

132-
protected function applySearchToQueryBuilder(QueryBuilder $queryBuilder, ?string $search = null): QueryBuilder
165+
protected function applyFilterToQueryBuilder(QueryBuilder $queryBuilder, ComplaintFilter $filter): void
133166
{
134-
if ($search === null) {
135-
return $queryBuilder;
167+
if ($filter->getCreatedAfter() !== null) {
168+
$queryBuilder->andWhere('c.createdAt >= :createdAfter')
169+
->setParameter('createdAfter', $filter->getCreatedAfter());
170+
}
171+
172+
if ($filter->getCreatedBefore() !== null) {
173+
$queryBuilder->andWhere('c.createdAt <= :createdBefore')
174+
->setParameter('createdBefore', $filter->getCreatedBefore());
175+
}
176+
177+
if ($filter->getSearch() !== null) {
178+
$search = $this->databaseSearchingHelper->getFullTextLikeSearchString($filter->getSearch());
179+
180+
$queryBuilder
181+
->distinct()
182+
->leftJoin('c.items', 'ci')
183+
->leftJoin('ci.orderItem', 'oi')
184+
->andWhere(
185+
$queryBuilder->expr()->orX(
186+
'NORMALIZED(c.number) LIKE NORMALIZED(:search)',
187+
'NORMALIZED(oi.name) LIKE NORMALIZED(:search)',
188+
'NORMALIZED(oi.catnum) LIKE NORMALIZED(:search)',
189+
),
190+
)
191+
->setParameter('search', $search);
192+
}
193+
194+
if ($filter->getStatuses() === null || count($filter->getStatuses()) <= 0) {
195+
return;
196+
}
197+
198+
$queryBuilder->andWhere('c.status IN (:statuses)')
199+
->setParameter('statuses', $filter->getStatuses());
200+
}
201+
202+
/**
203+
* @param array<int, array{statusId: int|string, complaintsCount: int|string}> $complaintStatusCounts
204+
* @return array<int, int>
205+
*/
206+
protected function extractComplaintStatusCountsByStatusId(array $complaintStatusCounts): array
207+
{
208+
$complaintStatusCountsByStatusId = [];
209+
210+
foreach ($complaintStatusCounts as $complaintStatusCount) {
211+
$complaintStatusCountsByStatusId[(int)$complaintStatusCount['statusId']] =
212+
(int)$complaintStatusCount['complaintsCount'];
136213
}
137214

138-
return $queryBuilder
139-
->leftJoin('c.items', 'ci')
140-
->leftJoin('ci.orderItem', 'oi')
141-
->andWhere(
142-
$queryBuilder->expr()->orX(
143-
'NORMALIZED(c.number) LIKE NORMALIZED(:search)',
144-
'NORMALIZED(oi.name) LIKE NORMALIZED(:search)',
145-
'NORMALIZED(oi.catnum) LIKE NORMALIZED(:search)',
146-
),
147-
)
148-
->setParameter('search', $this->databaseSearchingHelper->getFullTextLikeSearchString($search));
215+
return $complaintStatusCountsByStatusId;
149216
}
150217
}

0 commit comments

Comments
 (0)