Skip to content

Commit f1233f3

Browse files
committed
Replace VatNumber validator with new one (#21)
1 parent 762ca2e commit f1233f3

19 files changed

Lines changed: 365 additions & 95 deletions

README.md

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,6 @@
1111

1212
## Installation
1313

14-
0. This plugin requires the [MyOnlineStore/ViesBundle](https://github.com/MyOnlineStore/ViesBundle) but this is not actually compatible with Symfony 7, there is an open PR: https://github.com/MyOnlineStore/ViesBundle/pull/18
15-
16-
Thus, you have to run the following command to require a fork of the bundle which is compatible with Symfony 7:
17-
18-
```bash
19-
composer config repositories.sandwich/vies-bundle git https://github.com/mmenozzi/ViesBundle.git
20-
```
21-
22-
and you have to run this command too to allow "dev" versions of the bundle (we need the "dev-patch-1" version):
23-
24-
```bash
25-
composer config minimum-stability dev
26-
```
27-
2814
1. Require the plugin:
2915

3016
```bash
@@ -44,19 +30,19 @@
4430
- { resource: "@WebgriffeSyliusItalianInvoiceableOrderPlugin/config/config.yaml" }
4531
```
4632
47-
3. By default, the parameter `app.taxation.eu_zone_code` is set to "EU", as it must be the code of a zone representing the EU. This is used to determine if an order is invoiced to a company within the EU or not. Please change this parameter according to your Sylius's zone configuration if needed:
33+
4. By default, the parameter `app.taxation.eu_zone_code` is set to "EU", as it must be the code of a zone representing the EU. This is used to determine if an order is invoiced to a company within the EU or not. Please change this parameter according to your Sylius's zone configuration if needed:
4834

4935
```yaml
5036
# config/services.yaml
5137
parameters:
5238
app.taxation.eu_zone_code: 'EU' # Change it if needed
5339
```
5440

55-
4. Your `Address` entity must implement the `Webgriffe\SyliusItalianInvoiceableOrderPlugin\Model\ItalianInvoiceableAddressInterface` and the `Symfony\Component\Validator\GroupSequenceProviderInterface`. You can use the `Webgriffe\SyliusItalianInvoiceableOrderPlugin\Model\ItalianInvoiceableAddressTrait` as implementation for both interfaces.
41+
5. Your `Address` entity must implement the `Webgriffe\SyliusItalianInvoiceableOrderPlugin\Model\ItalianInvoiceableAddressInterface` and the `Symfony\Component\Validator\GroupSequenceProviderInterface`. You can use the `Webgriffe\SyliusItalianInvoiceableOrderPlugin\Model\ItalianInvoiceableAddressTrait` as implementation for both interfaces.
5642

57-
5. Your `Order` entity must implement the `Webgriffe\SyliusItalianInvoiceableOrderPlugin\Model\ItalianInvoiceableOrderInterface`. You can use the `Webgriffe\SyliusItalianInvoiceableOrderPlugin\Model\ItalianInvoiceableOrderTrait` as default implementation for the interface.
43+
6. Your `Order` entity must implement the `Webgriffe\SyliusItalianInvoiceableOrderPlugin\Model\ItalianInvoiceableOrderInterface`. You can use the `Webgriffe\SyliusItalianInvoiceableOrderPlugin\Model\ItalianInvoiceableOrderTrait` as default implementation for the interface.
5844

59-
6. You need to import the `Address` and `Order` validator configuration into your project by copying the configuration files provided by this plugin:
45+
7. You need to import the `Address` and `Order` validator configuration into your project by copying the configuration files provided by this plugin:
6046

6147
```bash
6248
mkdir -p config/validator/
@@ -77,12 +63,21 @@
7763
```bash
7864
sed -i '' 's/Tests\\Webgriffe\\SyliusItalianInvoiceableOrderPlugin/App/g' config/validator/Address.xml config/validator/Order.xml
7965
```
66+
67+
If you already have some validator file for these entities you have to merge the configuration manually.
68+
69+
*NB* Please, note that currently these validation rules are applied in strict mode. This means that if the VIES
70+
service is not available for some reason, the validation of the VAT number will fail. This could occur frequently on
71+
specific countries like Germany or France due
72+
to this problem: https://viesapi.eu/vies-problems-with-verifying-companies-from-germany-de/.
73+
If you want to avoid this strict behavior you can change the `strict` option of the
74+
`Webgriffe\SyliusItalianInvoiceableOrderPlugin\Validator\Constraints\EuropeanVatNumber` constraint to `false` in the
75+
validation configuration file. This way, if the VIES service is not available, the VAT number will be considered
76+
valid and the checkout will not be blocked.
8077

81-
If you alread have some validator file for these entities you have to merge the configuration manually.
82-
83-
7. Configure Sylius to use the `Italian tax calculation` tax calculation strategy.
78+
8. Configure Sylius to use the `Italian tax calculation` tax calculation strategy.
8479

85-
8. To properly enable group sequence validation of your Address entity you must set the `Default` validation group instead of the `sylius` validation group:
80+
9. To properly enable group sequence validation of your Address entity you must set the `Default` validation group instead of the `sylius` validation group:
8681

8782
```yaml
8883
# config/parameters.yaml
@@ -93,28 +88,27 @@
9388

9489
For more information see [here](https://symfony.com/doc/current/validation/sequence_provider.html).
9590

96-
9. Run migration
91+
10. Run migration
9792

9893
```bash
99-
bin/console cache:clear
10094
bin/console doctrine:migrations:migrate
10195
```
10296

103-
10. Add invoiceable fields to the address show template for admin. To do so you have to override this template:
97+
11. Add invoiceable fields to the address show template for admin. To do so you have to override this template:
10498

10599
```bash
106100
vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/templates/shared/helper/address.html.twig
107101
```
108-
102+
109103
by copying directly our implementation provided in the plugin:
110104

111105
```bash
112106
mkdir -p templates/bundles/SyliusAdminBundle/shared/helper/
113107
cp vendor/webgriffe/sylius-italian-invoiceable-order-plugin/tests/TestApplication/templates/bundles/SyliusAdminBundle/shared/helper/address.html.twig templates/bundles/SyliusAdminBundle/shared/helper/address.html.twig
114108
```
115-
109+
116110
or by copying the original template and adding the invoiceable fields by yourself. In this case your template should look like the following:
117-
111+
118112
```twig
119113
{% macro address(address) %}
120114
<address>

UPGRADE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44

55
- The service `app.taxation.italian_tax_calculation_strategy` has been renamed to `webgriffe_sylius_italian_invoiceable_order.strategy.taxation.tax_calculation.italian_tax_calculation_strategy`.
66
- The class `Webgriffe\SyliusItalianInvoiceableOrderPlugin\Model\ItalianTaxCalculationStrategy` has been moved to `Webgriffe\SyliusItalianInvoiceableOrderPlugin\Taxation\ItalianTaxCalculationStrategy`.
7-
-
7+
- The package `sandwich/vies-bundle` has been removed.
8+
- The constraint `Symfony\Component\Validator\Constraints\Sandwich\ViesBundle\Validator\Constraint\VatNumber` has been replaced with `Webgriffe\SyliusItalianInvoiceableOrderPlugin\Validator\Constraints\EuropeanVatNumber`. Please update your validation rules accordingly with search and replace.
9+
Please, note also that now is available a new strict option that allows you to block the checkout step if the VIES service is not available. You can enable it by setting the `strict` option to `true` in your validation rules.

composer.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
"require": {
1212
"php": "^8.2",
1313
"dragonbe/vies": "^2.3.2",
14-
"sandwich/vies-bundle": "dev-patch-1",
1514
"sylius/sylius": "^2.2",
1615
"webmozart/assert": "^1.9"
1716
},

config/services/validator.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,18 @@
44

55
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
66

7-
use Webgriffe\SyliusElasticsearchPlugin\Validator\RequestValidator;
7+
use Webgriffe\SyliusItalianInvoiceableOrderPlugin\Validator\Constraints\EuropeanVatNumberValidator;
88

99
return static function (ContainerConfigurator $containerConfigurator) {
1010
$services = $containerConfigurator->services();
1111

12-
$services->set('webgriffe.sylius_elasticsearch_plugin.validator.request', RequestValidator::class);
12+
$services->set('webgriffe_sylius_italian_invoiceable_order.validator.european_vat_number', EuropeanVatNumberValidator::class)
13+
->args([
14+
service('webgriffe_sylius_italian_invoiceable_order.vies'),
15+
service('logger'),
16+
])
17+
->tag('validator.constraint_validator', [
18+
'alias' => 'webgriffe_sylius_italian_invoiceable_order.european_vat_number_validator',
19+
])
20+
;
1321
};

config/services/vies.php

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 Symfony\Component\DependencyInjection\Loader\Configurator;
6+
7+
use DragonBe\Vies\Vies;
8+
9+
return static function (ContainerConfigurator $containerConfigurator) {
10+
$services = $containerConfigurator->services();
11+
12+
$services->set('webgriffe_sylius_italian_invoiceable_order.vies', Vies::class);
13+
};

psalm.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
<errorLevel type="suppress">
1818
<file name="src/Comparator/ItalianInvoiceableAddressComparatorDecorator.php" />
1919
<file name="src/Form/Extension/ItalianInvoiceableAddressTypeExtension.php" />
20-
<file name="src/Model/ItalianTaxCalculationStrategy.php" />
20+
<file name="src/Taxation/ItalianTaxCalculationStrategy.php" />
2121
<file name="src/Modifier/AddressFormValuesModifier.php" />
22+
<file name="src/Validator/Constraints/EuropeanVatNumberValidator.php" />
2223
</errorLevel>
2324
</UnusedClass>
2425
</issueHandlers>
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 Webgriffe\SyliusItalianInvoiceableOrderPlugin\Validator\Constraints;
6+
7+
use Symfony\Component\Validator\Constraint;
8+
9+
/**
10+
* @psalm-suppress PropertyNotSetInConstructor
11+
*/
12+
final class EuropeanVatNumber extends Constraint
13+
{
14+
public bool $strict = false;
15+
16+
public string $format = 'NL';
17+
18+
public string $message = 'webgriffe_sylius_italian_invoiceable_order.address.european_vat_number.valid';
19+
20+
public function isStrict(): bool
21+
{
22+
return $this->strict;
23+
}
24+
25+
public function getFormat(): string
26+
{
27+
return $this->format;
28+
}
29+
30+
#[\Override]
31+
public function validatedBy(): string
32+
{
33+
return 'webgriffe_sylius_italian_invoiceable_order.european_vat_number_validator';
34+
}
35+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Webgriffe\SyliusItalianInvoiceableOrderPlugin\Validator\Constraints;
6+
7+
use DragonBe\Vies\Vies;
8+
use DragonBe\Vies\ViesException;
9+
use DragonBe\Vies\ViesServiceException;
10+
use Psr\Log\LoggerInterface;
11+
use Symfony\Component\Validator\Constraint;
12+
use Symfony\Component\Validator\ConstraintValidator;
13+
14+
/**
15+
* @psalm-suppress PropertyNotSetInConstructor
16+
*/
17+
final class EuropeanVatNumberValidator extends ConstraintValidator
18+
{
19+
public function __construct(
20+
private readonly Vies $viesApi,
21+
private readonly LoggerInterface $logger,
22+
) {
23+
}
24+
25+
#[\Override]
26+
public function validate(mixed $value, Constraint $constraint): void
27+
{
28+
if (!is_string($value) || $value === '') {
29+
return;
30+
}
31+
if (!$constraint instanceof EuropeanVatNumber) {
32+
return;
33+
}
34+
35+
if (!$this->viesApi->getHeartBeat()->isAlive()) {
36+
if ($constraint->isStrict()) {
37+
$this->context->addViolation('webgriffe_sylius_italian_invoiceable_order.address.european_vat_number.vies_not_alive');
38+
}
39+
40+
return;
41+
}
42+
43+
$format = $constraint->getFormat();
44+
45+
try {
46+
$isValidEuropeanVatNumber = $this->viesApi->validateVat(
47+
$format,
48+
str_replace($format, '', $value),
49+
)->isValid();
50+
} catch (ViesServiceException|ViesException $exception) {
51+
$this->logger->warning($exception->getMessage());
52+
if ($constraint->isStrict()) {
53+
$this->context->addViolation('webgriffe_sylius_italian_invoiceable_order.address.european_vat_number.vies_not_alive');
54+
}
55+
56+
return;
57+
}
58+
if ($isValidEuropeanVatNumber) {
59+
return;
60+
}
61+
62+
$this->context->addViolation($constraint->message, ['%format%' => $format]);
63+
}
64+
}

0 commit comments

Comments
 (0)