Skip to content

Commit b6526a6

Browse files
committed
Can filter users by when/whether they credited their account #12092
1 parent 8014f5f commit b6526a6

10 files changed

Lines changed: 221 additions & 0 deletions

File tree

client/app/shared/natural-search/natural-search-facets.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,13 @@ export function users(): NaturalSearchFacets {
448448
items: inject(NaturalEnumService).get('BillingType'),
449449
},
450450
} satisfies DropdownFacet<TypeSelectConfiguration>,
451+
{
452+
display: 'Date de crédit',
453+
field: 'hasCreditOnDate',
454+
component: TypeDateComponent,
455+
configuration: {nullable: true},
456+
transform: prefixOperatorWithField,
457+
} satisfies DropdownFacet<TypeDateConfiguration>,
451458
{
452459
display: 'Solde',
453460
field: 'accountBalance',
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Application\Api\Input\Operator\HasCreditOnDate;
6+
7+
use Cake\Chronos\ChronosDate;
8+
use Doctrine\ORM\Mapping\ClassMetadata;
9+
use Doctrine\ORM\QueryBuilder;
10+
use Ecodev\Felix\ORM\Query\NativeIn;
11+
use GraphQL\Doctrine\Definition\Operator\AbstractOperator;
12+
use GraphQL\Doctrine\Factory\UniqueNameFactory;
13+
use GraphQL\Type\Definition\LeafType;
14+
15+
abstract class AbstractOperatorType extends AbstractOperator
16+
{
17+
abstract protected function getDqlOperator(): string;
18+
19+
protected function getConfiguration(LeafType $leafType): array
20+
{
21+
return [
22+
'description' => 'Filter the users by the date they credited their account',
23+
'fields' => [
24+
[
25+
'name' => 'value',
26+
'type' => self::nonNull(_types()->get(ChronosDate::class)),
27+
],
28+
],
29+
];
30+
}
31+
32+
public function getDqlCondition(UniqueNameFactory $uniqueNameFactory, ClassMetadata $metadata, QueryBuilder $queryBuilder, string $alias, string $field, ?array $args): string
33+
{
34+
if (!$args) {
35+
return '';
36+
}
37+
38+
/** @var ChronosDate $date */
39+
$date = $args['value'];
40+
$date = _em()->getConnection()->quote($date->toDateString());
41+
42+
$dqlOperator = $this->getDqlOperator();
43+
44+
return NativeIn::dql(
45+
$alias . '.id',
46+
<<<SQL
47+
SELECT account.owner_id FROM transaction_line
48+
INNER JOIN account ON transaction_line.credit_id = account.id
49+
WHERE
50+
account.owner_id IS NOT NULL
51+
AND DATE(transaction_date) $dqlOperator $date
52+
SQL
53+
);
54+
}
55+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Application\Api\Input\Operator\HasCreditOnDate;
6+
7+
final class HasCreditOnDateEqualOperatorType extends AbstractOperatorType
8+
{
9+
protected function getDqlOperator(): string
10+
{
11+
return '=';
12+
}
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Application\Api\Input\Operator\HasCreditOnDate;
6+
7+
final class HasCreditOnDateGreaterOperatorType extends AbstractOperatorType
8+
{
9+
protected function getDqlOperator(): string
10+
{
11+
return '>';
12+
}
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Application\Api\Input\Operator\HasCreditOnDate;
6+
7+
final class HasCreditOnDateGreaterOrEqualOperatorType extends AbstractOperatorType
8+
{
9+
protected function getDqlOperator(): string
10+
{
11+
return '>=';
12+
}
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Application\Api\Input\Operator\HasCreditOnDate;
6+
7+
final class HasCreditOnDateLessOperatorType extends AbstractOperatorType
8+
{
9+
protected function getDqlOperator(): string
10+
{
11+
return '<';
12+
}
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Application\Api\Input\Operator\HasCreditOnDate;
6+
7+
final class HasCreditOnDateLessOrEqualOperatorType extends AbstractOperatorType
8+
{
9+
protected function getDqlOperator(): string
10+
{
11+
return '<=';
12+
}
13+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Application\Api\Input\Operator\HasCreditOnDate;
6+
7+
use Doctrine\ORM\Mapping\ClassMetadata;
8+
use Doctrine\ORM\QueryBuilder;
9+
use Ecodev\Felix\ORM\Query\NativeIn;
10+
use GraphQL\Doctrine\Definition\Operator\AbstractOperator;
11+
use GraphQL\Doctrine\Factory\UniqueNameFactory;
12+
use GraphQL\Type\Definition\LeafType;
13+
14+
final class HasCreditOnDateNullOperatorType extends AbstractOperator
15+
{
16+
protected function getConfiguration(LeafType $leafType): array
17+
{
18+
return [
19+
'description' => 'Filter the users whether they ever credited their account',
20+
'fields' => [
21+
[
22+
'name' => 'not',
23+
'type' => self::boolean(),
24+
'defaultValue' => false,
25+
],
26+
],
27+
];
28+
}
29+
30+
public function getDqlCondition(UniqueNameFactory $uniqueNameFactory, ClassMetadata $metadata, QueryBuilder $queryBuilder, string $alias, string $field, ?array $args): string
31+
{
32+
if (!$args) {
33+
return '';
34+
}
35+
36+
return NativeIn::dql(
37+
$alias . '.id',
38+
<<<SQL
39+
SELECT account.owner_id FROM transaction_line
40+
INNER JOIN account ON transaction_line.credit_id = account.id
41+
WHERE
42+
account.owner_id IS NOT NULL
43+
SQL,
44+
!$args['not'],
45+
);
46+
}
47+
}

server/Application/Model/User.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
use Application\Api\Input\Operator\HasBookingStatusOperatorType;
2626
use Application\Api\Input\Operator\HasBookingWithBookableOperatorType;
2727
use Application\Api\Input\Operator\HasBookingWithTaggedBookableOperatorType;
28+
use Application\Api\Input\Operator\HasCreditOnDate\HasCreditOnDateEqualOperatorType;
29+
use Application\Api\Input\Operator\HasCreditOnDate\HasCreditOnDateGreaterOperatorType;
30+
use Application\Api\Input\Operator\HasCreditOnDate\HasCreditOnDateGreaterOrEqualOperatorType;
31+
use Application\Api\Input\Operator\HasCreditOnDate\HasCreditOnDateLessOperatorType;
32+
use Application\Api\Input\Operator\HasCreditOnDate\HasCreditOnDateLessOrEqualOperatorType;
33+
use Application\Api\Input\Operator\HasCreditOnDate\HasCreditOnDateNullOperatorType;
2834
use Application\Api\Input\Sorting\Age;
2935
use Application\Api\Input\Sorting\Balance;
3036
use Application\Enum\BillingType;
@@ -78,6 +84,12 @@
7884
#[API\Filter(field: 'bookingDate', operator: BookingDateGreaterOrEqualOperatorType::class, type: 'Date')]
7985
#[API\Filter(field: 'bookingDate', operator: BookingDateLessOperatorType::class, type: 'Date')]
8086
#[API\Filter(field: 'bookingDate', operator: BookingDateLessOrEqualOperatorType::class, type: 'Date')]
87+
#[API\Filter(field: 'hasCreditOnDate', operator: HasCreditOnDateEqualOperatorType::class, type: 'Money')]
88+
#[API\Filter(field: 'hasCreditOnDate', operator: HasCreditOnDateGreaterOperatorType::class, type: 'Money')]
89+
#[API\Filter(field: 'hasCreditOnDate', operator: HasCreditOnDateGreaterOrEqualOperatorType::class, type: 'Money')]
90+
#[API\Filter(field: 'hasCreditOnDate', operator: HasCreditOnDateLessOperatorType::class, type: 'Money')]
91+
#[API\Filter(field: 'hasCreditOnDate', operator: HasCreditOnDateLessOrEqualOperatorType::class, type: 'Money')]
92+
#[API\Filter(field: 'hasCreditOnDate', operator: HasCreditOnDateNullOperatorType::class, type: 'Money')]
8193
#[ORM\Entity(UserRepository::class)]
8294
#[ORM\HasLifecycleCallbacks]
8395
#[ORM\AssociationOverrides([new ORM\AssociationOverride(name: 'owner', inversedBy: 'users')])]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ApplicationTest\Api\Input\Operator\HasCreditOnDate;
6+
7+
use Application\Model\User;
8+
use ApplicationTest\Traits\TestWithTransactionAndUser;
9+
use Ecodev\Felix\Testing\Api\Input\Operator\OperatorType;
10+
11+
class HasCreditOnDateNullOperatorTypeTest extends OperatorType
12+
{
13+
use TestWithTransactionAndUser;
14+
15+
/**
16+
* @dataProvider providerGetDqlCondition
17+
*/
18+
public function testGetDqlCondition(int $expected, bool $not): void
19+
{
20+
$this->setCurrentUser('administrator');
21+
22+
$values = [
23+
'not' => $not,
24+
];
25+
26+
$actual = $this->getFilteredResult(User::class, 'hasCreditOnDate', 'hasCreditOnDateNull', $values);
27+
self::assertCount($expected, $actual);
28+
}
29+
30+
public static function providerGetDqlCondition(): iterable
31+
{
32+
yield [15, false];
33+
yield [1, true];
34+
}
35+
}

0 commit comments

Comments
 (0)