Skip to content

Commit 09578c9

Browse files
authored
[Maintenance][Checkout] Less rigid checkout address validation (#163)
2 parents c28eb8a + 8517650 commit 09578c9

File tree

3 files changed

+179
-3
lines changed

3 files changed

+179
-3
lines changed

config/services/validator.xml

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
<?xml version="1.0" encoding="UTF-8" ?>
22

3-
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
3+
<container
4+
xmlns="http://symfony.com/schema/dic/services"
5+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"
7+
>
8+
<parameters>
9+
<parameter key="sylius_adyen.checkout.addressing.countries_requiring_province" type="collection">
10+
<parameter>CA</parameter>
11+
<parameter>US</parameter>
12+
</parameter>
13+
</parameters>
14+
515
<services>
616
<defaults public="true"/>
717

@@ -20,7 +30,10 @@
2030
id="sylius_adyen.validator.province_address_constraint_decorator"
2131
decorates="sylius.validator.valid_province_address"
2232
>
23-
<argument type="service" id=".inner"/>
33+
<argument type="service" id=".inner" />
34+
<argument>%sylius_adyen.checkout.addressing.countries_requiring_province%</argument>
35+
<argument type="service" id="sylius.context.channel" />
36+
<argument type="service" id="sylius_adyen.repository.query.adyen_payment_method"/>
2437
</service>
2538

2639
</services>

src/Validator/Constraint/ProvinceAddressConstraintValidatorDecorator.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313

1414
namespace Sylius\AdyenPlugin\Validator\Constraint;
1515

16+
use Sylius\AdyenPlugin\Repository\Query\AdyenPaymentMethodQueryInterface;
1617
use Sylius\Bundle\AddressingBundle\Validator\Constraints\ProvinceAddressConstraint;
1718
use Sylius\Bundle\AddressingBundle\Validator\Constraints\ProvinceAddressConstraintValidator;
19+
use Sylius\Component\Channel\Context\ChannelContextInterface;
1820
use Sylius\Component\Core\Model\AddressInterface;
1921
use Symfony\Component\Validator\Constraint;
2022
use Symfony\Component\Validator\ConstraintValidator;
@@ -30,6 +32,8 @@ public function __construct(
3032
private readonly ProvinceAddressConstraintValidator $decorated,
3133
/** @var array|string[] */
3234
private readonly array $provinceRequiredCountriesList = self::PROVINCE_REQUIRED_COUNTRIES_DEFAULT_LIST,
35+
private readonly ?ChannelContextInterface $channelContext = null,
36+
private readonly ?AdyenPaymentMethodQueryInterface $adyenPaymentMethodQuery = null,
3337
) {
3438
}
3539

@@ -42,6 +46,10 @@ public function validate($value, Constraint $constraint): void
4246
$this->decorated->initialize($this->context);
4347
$this->decorated->validate($value, $constraint);
4448

49+
if (!$this->isAnyAdyenMethodAvailable()) {
50+
return;
51+
}
52+
4553
Assert::isInstanceOf($value, AddressInterface::class);
4654
Assert::isInstanceOf($constraint, ProvinceAddressConstraint::class);
4755

@@ -72,4 +80,21 @@ private function hasViolation(Constraint $constraint): bool
7280

7381
return false;
7482
}
83+
84+
private function isAnyAdyenMethodAvailable(): bool
85+
{
86+
if (null === $this->channelContext || null === $this->adyenPaymentMethodQuery) {
87+
return true;
88+
}
89+
90+
$channel = $this->channelContext->getChannel();
91+
$paymentMethods = $this->adyenPaymentMethodQuery->findAllAdyenByChannel($channel);
92+
foreach ($paymentMethods as $key => $paymentMethod) {
93+
if (!$paymentMethod->isEnabled()) {
94+
unset($paymentMethods[$key]);
95+
}
96+
}
97+
98+
return 0 !== count($paymentMethods);
99+
}
75100
}

tests/Unit/Validator/ProvinceAddressConstraintValidatorDecoratorTest.php

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@
1414
namespace Tests\Sylius\AdyenPlugin\Unit\Validator;
1515

1616
use PHPUnit\Framework\Attributes\DataProvider;
17+
use Sylius\AdyenPlugin\Repository\Query\AdyenPaymentMethodQueryInterface;
1718
use Sylius\AdyenPlugin\Validator\Constraint\ProvinceAddressConstraintValidatorDecorator;
1819
use Sylius\Bundle\AddressingBundle\Validator\Constraints\ProvinceAddressConstraint;
1920
use Sylius\Bundle\AddressingBundle\Validator\Constraints\ProvinceAddressConstraintValidator;
21+
use Sylius\Component\Channel\Context\ChannelContextInterface;
22+
use Sylius\Component\Channel\Model\ChannelInterface;
23+
use Sylius\Component\Core\Model\PaymentMethodInterface;
2024
use Symfony\Component\Validator\ConstraintValidatorInterface;
2125
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
2226
use Tests\Sylius\AdyenPlugin\Unit\AddressMother;
@@ -80,4 +84,138 @@ public function testRelatedCountryAndEmptyProvinceWithAlreadyViolatedConstraint(
8084
$this->validator->validate($address, $constraint);
8185
$this->assertCount($expectedCount, $this->context->getViolations());
8286
}
87+
88+
public function testRelatedCountryAndEmptyProvinceWithProvidedDependenciesWhenNoAdyenMethodIsEnabled(): void
89+
{
90+
$constraint = new ProvinceAddressConstraint();
91+
$address = AddressMother::createAddressWithSpecifiedCountryAndEmptyProvince('US');
92+
93+
$channel = $this->createMock(ChannelInterface::class);
94+
$channelContext = $this->createMock(ChannelContextInterface::class);
95+
$channelContext->method('getChannel')->willReturn($channel);
96+
97+
$adyenPaymentMethodQuery = $this->createMock(AdyenPaymentMethodQueryInterface::class);
98+
$adyenPaymentMethodQuery
99+
->method('findAllAdyenByChannel')
100+
->with($channel)
101+
->willReturn([])
102+
;
103+
104+
$validator = $this->createValidatorWithDependencies($channelContext, $adyenPaymentMethodQuery);
105+
$validator->validate($address, $constraint);
106+
107+
$this->assertNoViolation();
108+
}
109+
110+
public function testRelatedCountryAndEmptyProvinceWithProvidedDependenciesWhenAdyenMethodIsEnabled(): void
111+
{
112+
$constraint = new ProvinceAddressConstraint();
113+
$address = AddressMother::createAddressWithSpecifiedCountryAndEmptyProvince('US');
114+
115+
$channel = $this->createMock(ChannelInterface::class);
116+
$channelContext = $this->createMock(ChannelContextInterface::class);
117+
$channelContext->method('getChannel')->willReturn($channel);
118+
119+
$enabledPaymentMethod = $this->createMock(PaymentMethodInterface::class);
120+
$enabledPaymentMethod->method('isEnabled')->willReturn(true);
121+
122+
$adyenPaymentMethodQuery = $this->createMock(AdyenPaymentMethodQueryInterface::class);
123+
$adyenPaymentMethodQuery
124+
->method('findAllAdyenByChannel')
125+
->with($channel)
126+
->willReturn([$enabledPaymentMethod])
127+
;
128+
129+
$validator = $this->createValidatorWithDependencies($channelContext, $adyenPaymentMethodQuery);
130+
$validator->validate($address, $constraint);
131+
132+
$this->buildViolation($constraint->message)
133+
->assertRaised()
134+
;
135+
}
136+
137+
public function testRelatedCountryAndEmptyProvinceWithProvidedDependenciesWhenAllMethodsDisabled(): void
138+
{
139+
$constraint = new ProvinceAddressConstraint();
140+
$address = AddressMother::createAddressWithSpecifiedCountryAndEmptyProvince('US');
141+
142+
$channel = $this->createMock(ChannelInterface::class);
143+
$channelContext = $this->createMock(ChannelContextInterface::class);
144+
$channelContext->method('getChannel')->willReturn($channel);
145+
146+
$disabledPaymentMethod = $this->createMock(PaymentMethodInterface::class);
147+
$disabledPaymentMethod->method('isEnabled')->willReturn(false);
148+
149+
$adyenPaymentMethodQuery = $this->createMock(AdyenPaymentMethodQueryInterface::class);
150+
$adyenPaymentMethodQuery
151+
->method('findAllAdyenByChannel')
152+
->with($channel)
153+
->willReturn([$disabledPaymentMethod])
154+
;
155+
156+
$validator = $this->createValidatorWithDependencies($channelContext, $adyenPaymentMethodQuery);
157+
$validator->validate($address, $constraint);
158+
159+
$this->assertNoViolation();
160+
}
161+
162+
public function testRelatedCountryWithProvinceWhenAdyenMethodIsEnabled(): void
163+
{
164+
$constraint = new ProvinceAddressConstraint();
165+
$address = AddressMother::createAddressWithSpecifiedCountryAndEmptyProvince('US');
166+
$address->setProvinceCode('US-TX');
167+
168+
$channel = $this->createMock(ChannelInterface::class);
169+
$channelContext = $this->createMock(ChannelContextInterface::class);
170+
$channelContext->method('getChannel')->willReturn($channel);
171+
172+
$enabledPaymentMethod = $this->createMock(PaymentMethodInterface::class);
173+
$enabledPaymentMethod->method('isEnabled')->willReturn(true);
174+
175+
$adyenPaymentMethodQuery = $this->createMock(AdyenPaymentMethodQueryInterface::class);
176+
$adyenPaymentMethodQuery
177+
->method('findAllAdyenByChannel')
178+
->with($channel)
179+
->willReturn([$enabledPaymentMethod])
180+
;
181+
182+
$validator = $this->createValidatorWithDependencies($channelContext, $adyenPaymentMethodQuery);
183+
$validator->validate($address, $constraint);
184+
185+
$this->assertNoViolation();
186+
}
187+
188+
public function testCustomRequiredCountryListAddsViolation(): void
189+
{
190+
$constraint = new ProvinceAddressConstraint();
191+
$address = AddressMother::createAddressWithSpecifiedCountryAndEmptyProvince('PL');
192+
193+
$validator = $this->createValidatorWithDependencies(
194+
null,
195+
null,
196+
['PL'],
197+
);
198+
$validator->validate($address, $constraint);
199+
200+
$this->buildViolation($constraint->message)
201+
->assertRaised()
202+
;
203+
}
204+
205+
private function createValidatorWithDependencies(
206+
?ChannelContextInterface $channelContext,
207+
?AdyenPaymentMethodQueryInterface $adyenPaymentMethodQuery,
208+
?array $countryList = null,
209+
): ProvinceAddressConstraintValidatorDecorator {
210+
$this->validator = new ProvinceAddressConstraintValidatorDecorator(
211+
$this->decorated,
212+
$countryList ?? ProvinceAddressConstraintValidatorDecorator::PROVINCE_REQUIRED_COUNTRIES_DEFAULT_LIST,
213+
$channelContext,
214+
$adyenPaymentMethodQuery,
215+
);
216+
217+
$this->validator->initialize($this->context);
218+
219+
return $this->validator;
220+
}
83221
}

0 commit comments

Comments
 (0)