Skip to content

Commit fe2ba59

Browse files
committed
fix vat number selection from address book
1 parent a9648d0 commit fe2ba59

13 files changed

Lines changed: 227 additions & 0 deletions

File tree

config/services/form.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,8 @@ services:
1111
class: Gewebe\SyliusVATPlugin\Form\Extension\ShopBillingDataTypeExtension
1212
tags:
1313
- { name: form.type_extension, extended_type: Sylius\Bundle\CoreBundle\Form\Type\ShopBillingDataType }
14+
15+
gewebe_sylius_vat_plugin.form.modifier.vat_number_address_form_values:
16+
class: Gewebe\SyliusVATPlugin\Form\Modifier\VatNumberAddressFormValuesModifier
17+
tags:
18+
- { name: sylius_shop.modifier.address_form_values }

features/checkout/seeing_tax_total_dependent_on_country_and_vat.feature

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ Feature: Seeing tax total dependent on country and vat
5353
And I have 2 products "PHP T-Shirt" in the cart
5454
And I am at the checkout addressing step
5555

56+
@ui @javascript
57+
Scenario: Choosing an address with VAT number from the address book
58+
Given I have an address "Ankh Morpork", "Rue Neuve", "1000", "Brussels", "Belgium" in my address book
59+
And the "Rue Neuve" street VAT number is "BE0123456789"
60+
And I go to the checkout addressing step
61+
When I choose "Rue Neuve" street for billing address
62+
Then the billing VAT number should be "BE0123456789"
63+
5664
@ui
5765
Scenario: Seeing included tax of 21% within business country
5866
When I specify the billing address as "Gent", "Merelstraat", "9000", "Belgium" for "Ankh Morpork"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Gewebe\SyliusVATPlugin\DependencyInjection\Compiler;
6+
7+
use Gewebe\SyliusVATPlugin\Twig\Component\Checkout\Address\FormComponent;
8+
use Sylius\Bundle\ShopBundle\Modifier\AddressFormValuesModifierInterface;
9+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
10+
use Symfony\Component\DependencyInjection\ContainerBuilder;
11+
12+
final class ConfigureCheckoutAddressFormComponentPass implements CompilerPassInterface
13+
{
14+
private const FORM_COMPONENT_SERVICE_ID = 'sylius_shop.twig.component.checkout.address.form';
15+
16+
public function process(ContainerBuilder $container): void
17+
{
18+
if (
19+
interface_exists(AddressFormValuesModifierInterface::class) ||
20+
!$container->hasDefinition(self::FORM_COMPONENT_SERVICE_ID)
21+
) {
22+
return;
23+
}
24+
25+
$container->getDefinition(self::FORM_COMPONENT_SERVICE_ID)->setClass(FormComponent::class);
26+
}
27+
}

src/DependencyInjection/GewebeSyliusVATExtension.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Sylius\Bundle\CoreBundle\DependencyInjection\PrependDoctrineMigrationsTrait;
88
use Sylius\Bundle\ResourceBundle\DependencyInjection\Extension\AbstractResourceExtension;
9+
use Sylius\Bundle\ShopBundle\Modifier\AddressFormValuesModifierInterface;
910
use Symfony\Component\Config\FileLocator;
1011
use Symfony\Component\DependencyInjection\ContainerBuilder;
1112
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
@@ -20,6 +21,11 @@ public function load(array $configs, ContainerBuilder $container): void
2021
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../../config'));
2122
$loader->load('services.yaml');
2223

24+
// Sylius 2.1 has no address form value modifier; a compiler pass configures the fallback component instead.
25+
if (!interface_exists(AddressFormValuesModifierInterface::class)) {
26+
$container->removeDefinition('gewebe_sylius_vat_plugin.form.modifier.vat_number_address_form_values');
27+
}
28+
2329
$configuration = $this->getConfiguration([], $container);
2430
if ($configuration === null) {
2531
return;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Gewebe\SyliusVATPlugin\Form\Modifier;
6+
7+
use Gewebe\SyliusVATPlugin\Entity\VatNumberAddressInterface;
8+
use Sylius\Bundle\ShopBundle\Modifier\AddressFormValuesModifierInterface;
9+
use Sylius\Component\Addressing\Model\AddressInterface;
10+
11+
final readonly class VatNumberAddressFormValuesModifier implements AddressFormValuesModifierInterface
12+
{
13+
/**
14+
* @param array<string, mixed> $addressData
15+
*
16+
* @return array<string, mixed>
17+
*/
18+
public function modify(array $addressData, AddressInterface $address): array
19+
{
20+
if ($address instanceof VatNumberAddressInterface) {
21+
$addressData['vatNumber'] = $address->getVatNumber();
22+
}
23+
24+
return $addressData;
25+
}
26+
}

src/GewebeSyliusVATPlugin.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,25 @@
44

55
namespace Gewebe\SyliusVATPlugin;
66

7+
use Gewebe\SyliusVATPlugin\DependencyInjection\Compiler\ConfigureCheckoutAddressFormComponentPass;
78
use Sylius\Bundle\CoreBundle\Application\SyliusPluginTrait;
9+
use Symfony\Component\DependencyInjection\ContainerBuilder;
810
use Symfony\Component\HttpKernel\Bundle\Bundle;
911

1012
final class GewebeSyliusVATPlugin extends Bundle
1113
{
1214
use SyliusPluginTrait;
1315

16+
public function build(ContainerBuilder $container): void
17+
{
18+
parent::build($container);
19+
20+
// Sylius 2.1 does not provide address form value modifiers. The compiler pass replaces the checkout
21+
// address component with a compatibility fallback after all bundle services have been loaded.
22+
// TODO: Remove the compiler pass and the fallback component when support for Sylius 2.1 is dropped.
23+
$container->addCompilerPass(new ConfigureCheckoutAddressFormComponentPass());
24+
}
25+
1426
public function getPath(): string
1527
{
1628
return \dirname(__DIR__);
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 Gewebe\SyliusVATPlugin\Twig\Component\Checkout\Address;
6+
7+
use Gewebe\SyliusVATPlugin\Entity\VatNumberAddressInterface;
8+
use Sylius\Bundle\ShopBundle\Twig\Component\Checkout\Address\AddressBookComponent;
9+
use Sylius\Bundle\ShopBundle\Twig\Component\Checkout\Address\FormComponent as BaseFormComponent;
10+
use Sylius\Component\Core\Model\CustomerInterface;
11+
use Symfony\UX\LiveComponent\Attribute\LiveArg;
12+
use Symfony\UX\LiveComponent\Attribute\LiveListener;
13+
14+
/**
15+
* Sylius 2.1 compatibility fallback; Sylius 2.2+ uses VatNumberAddressFormValuesModifier instead.
16+
*/
17+
final class FormComponent extends BaseFormComponent
18+
{
19+
#[LiveListener(AddressBookComponent::SYLIUS_SHOP_ADDRESS_UPDATED)]
20+
public function addressFieldUpdated(#[LiveArg] mixed $addressId, #[LiveArg] string $field): void
21+
{
22+
$customer = $this->customerContext->getCustomer();
23+
if (!$customer instanceof CustomerInterface || !is_scalar($addressId)) {
24+
return;
25+
}
26+
27+
$address = $this->addressRepository->findOneByCustomer((string) $addressId, $customer);
28+
if (!$address instanceof VatNumberAddressInterface) {
29+
return;
30+
}
31+
32+
parent::addressFieldUpdated($addressId, $field);
33+
$this->formValues[$field]['vatNumber'] = $address->getVatNumber();
34+
}
35+
}

tests/Behat/Context/Setup/AddressContext.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use DateTime;
1010
use Doctrine\Persistence\ObjectManager;
1111
use Gewebe\SyliusVATPlugin\Entity\VatNumberAddressInterface;
12+
use Sylius\Component\Core\Model\AddressInterface;
1213
use Sylius\Component\Core\Model\CustomerInterface;
1314

1415
class AddressContext implements Context
@@ -36,4 +37,15 @@ public function theirDefaultAddressVatNumberIs(
3637

3738
$this->objectManager->flush();
3839
}
40+
41+
#[Given('/^the ("[^"]+" street) VAT number is "([^"]+)"$/')]
42+
public function theAddressVatNumberIs(AddressInterface $address, string $vatNumber): void
43+
{
44+
if (!$address instanceof VatNumberAddressInterface) {
45+
throw new \InvalidArgumentException('The address does not support VAT numbers.');
46+
}
47+
48+
$address->setVatNumber($vatNumber);
49+
$this->objectManager->flush();
50+
}
3951
}

tests/Behat/Context/Ui/Shop/Checkout/AddressVatNumberContext.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ public function iSpecifyTheVatNumberForShippingAddress(string $vatNumber): void
4040
$this->addressPage->specifyShippingAddressVatNumber($vatNumber);
4141
}
4242

43+
#[Then('/^the (shipping|billing) VAT number should be "([^"]+)"$/')]
44+
public function theVatNumberShouldBe(string $type, string $vatNumber): void
45+
{
46+
$actualVatNumber = $type === 'shipping'
47+
? $this->addressPage->getShippingAddressVatNumber()
48+
: $this->addressPage->getBillingAddressVatNumber()
49+
;
50+
51+
Assert::same($actualVatNumber, $vatNumber);
52+
}
53+
4354
#[Then('/^I should be notified that the VAT number in (shipping|billing) is required$/')]
4455
public function iShouldBeNotifiedThatTheVatNumberIsRequired(string $type): void
4556
{

tests/Behat/Page/Shop/Checkout/AddressPage.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Tests\Gewebe\SyliusVATPlugin\Behat\Page\Shop\Checkout;
66

77
use Sylius\Behat\Page\Shop\Checkout\AddressPage as BaseAddressPage;
8+
use Webmozart\Assert\Assert;
89

910
class AddressPage extends BaseAddressPage implements AddressPageInterface
1011
{
@@ -18,6 +19,16 @@ public function specifyBillingAddressVatNumber(string $vatNumber): void
1819
$this->getElement('billing_vat_number')->setValue($vatNumber);
1920
}
2021

22+
public function getBillingAddressVatNumber(): string
23+
{
24+
$this->waitForFormToStopLoading();
25+
26+
$vatNumber = $this->getElement('billing_vat_number')->getValue();
27+
Assert::string($vatNumber);
28+
29+
return $vatNumber;
30+
}
31+
2132
public function specifyShippingAddressCompany(string $company): void
2233
{
2334
$this->getElement('shipping_company')->setValue($company);
@@ -28,6 +39,16 @@ public function specifyShippingAddressVatNumber(string $vatNumber): void
2839
$this->getElement('shipping_vat_number')->setValue($vatNumber);
2940
}
3041

42+
public function getShippingAddressVatNumber(): string
43+
{
44+
$this->waitForFormToStopLoading();
45+
46+
$vatNumber = $this->getElement('shipping_vat_number')->getValue();
47+
Assert::string($vatNumber);
48+
49+
return $vatNumber;
50+
}
51+
3152
protected function getDefinedElements(): array
3253
{
3354
return array_merge(parent::getDefinedElements(), [

0 commit comments

Comments
 (0)