webgriffe/sylius-italian-invoiceable-order-plugin

Sylius 插件,允许意大利商家收集其订单的发票数据。


README

意大利发票订单插件

Sylius 插件,允许意大利商家收集订单的发票数据,如税号、增值税号、SDI码等,并允许商家仅对那些可以(并且必须)预缴税款的客户征税。

Build Status

安装

  1. 需要插件

    composer require webgriffe/sylius-italian-invoiceable-order-plugin
  2. 将包添加到 config/bundles.php 文件

        Sandwich\ViesBundle\SandwichViesBundle::class => ['all' => true],
        Webgriffe\SyliusItalianInvoiceableOrderPlugin\WebgriffeSyliusItalianInvoiceableOrderPlugin::class => ['all' => true],
  3. 定义参数 app.taxation.eu_zone_code 的值,这必须是代表欧盟的区域的代码。这用于确定订单是否向欧盟内的公司开具发票。

  4. 您的 Address 实体必须实现 Webgriffe\SyliusItalianInvoiceableOrderPlugin\Model\ItalianInvoiceableAddressInterfaceSymfony\Component\Validator\GroupSequenceProviderInterface。您可以使用 Webgriffe\SyliusItalianInvoiceableOrderPlugin\Model\ItalianInvoiceableAddressTrait 作为两个接口的实现。

  5. 您的 Order 实体必须实现 Webgriffe\SyliusItalianInvoiceableOrderPlugin\Model\ItalianInvoiceableOrderInterface。您可以使用 Webgriffe\SyliusItalianInvoiceableOrderPlugin\Model\ItalianInvoiceableOrderTrait 作为接口的默认实现。

  6. 您需要通过复制此插件提供的配置文件或将配置合并到现有的 AddressOrder 验证器配置中,将 AddressOrder 验证器配置导入到项目中。

    mkdir -p config/validator/
    cp vendor/webgriffe/sylius-italian-invoiceable-order-plugin/tests/Application/config/validator/Address.xml config/validator/
    cp vendor/webgriffe/sylius-italian-invoiceable-order-plugin/tests/Application/config/validator/Order.xml config/validator/

    或通过合并配置到现有的 AddressOrder 验证器配置。

  7. 配置 Sylius 使用 意大利税计算 税计算策略。

  8. 为了正确启用地址实体的分组验证,您必须设置 Default 验证组而不是 sylius 验证组。

    # config/services.yaml
    parameters:
        # ...
        sylius.form.type.address.validation_groups: ['Default']

    更多信息请参阅 这里

  9. 运行 Doctrine 迁移的差异并运行它

    bin/console doctrine:migrations:diff
    bin/console doctrine:migrations:migrate
  10. 将可开票地址字段添加到您的商店地址表单模板。为此,您需要覆盖模板

    cp vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Resources/views/Common/Form/_address.html.twig templates/bundles/SyliusShopBundle/Common/Form/_address.html.twig

    然后在 templates/bundles/SyliusShopBundle/Common/Form/_address.html.twig 中,您必须添加以下内容

    {# templates/bundles/SyliusShopBundle/Common/Form/_address.html.twig #}
    {% if type != 'shipping-' %}
     {{ form_row(form.billingRecipientType, sylius_test_form_attribute(type ~ 'billing-recipient-type')) }}
        {{ form_row(form.taxCode, sylius_test_form_attribute(type ~ 'tax-code')) }}
        {{ form_row(form.vatNumber, sylius_test_form_attribute(type ~ 'vat-number')) }}
        {{ form_row(form.sdiCode, sylius_test_form_attribute(type ~ 'sdi-code')) }}
        {{ form_row(form.pecAddress, sylius_test_form_attribute(type ~ 'pec-address')) }}    
    {% endif %}

    您可以将字段按照您想要的顺序放置,但我们建议用 {% if type != 'shipping-' %} 检查包围它们。这样,您就不会在结账页面的收货地址部分显示这些字段,因为这些字段在那里不相关。

  11. 将可开票地址字段添加到您的管理员地址表单模板。为此,您需要覆盖模板

cp vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/Resources/views/Common/Form/_address.html.twig templates/bundles/SyliusAdminBundle/Common/Form/_address.html.twig

然后在 templates/bundles/SyliusAdminBundle/Common/Form/_address.html.twig 中,您必须添加可开票字段。您应该只在这些字段绑定到订单的账单地址时添加这些字段。为此,您的模板应如下所示

{# templates/bundles/SyliusAdminBundle/Common/Form/_address.html.twig #}
{% set shouldShowInvoiceableFields = form.parent.vars.data.billingAddress.id is defined and form.vars.data.id is defined and form.parent.vars.data.billingAddress.id == form.vars.data.id %}

{% if shouldShowInvoiceableFields %}
    {{ form_row(form.billingRecipientType) }}
{% endif %}

<div class="two fields">
    {{ form_row(form.firstName) }}
    {{ form_row(form.lastName) }}
</div>

{% if shouldShowInvoiceableFields %}
    {{ form_row(form.taxCode) }}
    {{ form_row(form.vatNumber) }}
    {{ form_row(form.sdiCode) }}
    {{ form_row(form.pecAddress) }}
{% endif %}

{{ form_row(form.company) }}
{{ form_row(form.street) }}
{{ form_row(form.countryCode) }}
<div class="province-container field" data-url="{{ path('sylius_admin_ajax_render_province_form') }}">
    {% if form.provinceCode is defined %}
        {{ form_row(form.provinceCode, {'attr': {'class': 'ui dropdown'}}) }}
    {% endif %}
</div>
<div class="two fields">
    {{ form_row(form.city) }}
    {{ form_row(form.postcode) }}
</div>
{{ form_row(form.phoneNumber) }}
  1. 将可开票字段添加到管理员和商店的地址显示模板。为此,您需要覆盖这些模板
cp vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Resources/views/Common/_address.html.twig templates/bundles/SyliusShopBundle/Common/_address.html.twig
cp vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/Resources/views/Common/_address.html.twig templates/bundles/SyliusAdminBundle/Common/_address.html.twig

然后,用此插件提供的可开票地址信息模板替换打印公司、名和姓。然后,这些模板应如下所示

{# templates/bundles/SyliusShopBundle/Common/_address.html.twig #}
{% import "@SyliusUi/Macro/flags.html.twig" as flags %}

<address {{ sylius_test_html_attribute('address-context', "%s %s"|format(address.firstName, address.lastName)) }}>
    {% include '@WebgriffeSyliusItalianInvoiceableOrderPlugin/Common/_invoiceableAddressInfo.html.twig' %}
    {% if address.phoneNumber is not null %}
        {{ address.phoneNumber }}<br/>
    {% endif %}
    {{ address.street }}<br/>
    {{ address.city }}, {{ address.postcode }}<br/>
    {% if address|sylius_province_name is not empty %}
        {{ address|sylius_province_name }}<br/>
    {% endif %}
    {{ flags.fromCountryCode(address.countryCode) }}
    {{ address.countryCode|sylius_country_name|upper }}
</address>
{# templates/bundles/SyliusAdminBundle/Common/_address.html.twig #}
{% import "@SyliusUi/Macro/flags.html.twig" as flags %}

<address>
    {% include '@WebgriffeSyliusItalianInvoiceableOrderPlugin/Common/_invoiceableAddressInfo.html.twig' %}
    {{ address.phoneNumber }}<br/>
    {{ address.street }}<br/>
    {{ address.city }}<br/>
    {% if address|sylius_province_name is not empty %}
        {{ address|sylius_province_name }}<br/>
    {% endif %}
    {{ flags.fromCountryCode(address.countryCode) }}
    {{ address.countryCode|sylius_country_name|upper }} {{ address.postcode }}
</address>
  1. 将可开票字段添加到地址簿选择数据属性。为此,您需要覆盖地址簿选择模板
cp vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Resources/views/Checkout/Address/_addressBookSelect.html.twig templates/bundles/SyliusShopBundle/Checkout/Address/_addressBookSelect.html.twig

并包含此插件提供的数据属性模板

{% include '@WebgriffeSyliusItalianInvoiceableOrderPlugin/Checkout/Address/_addressBookSelectInvoiceableDataAttributes.html.twig' %}

您必须在适当的地点添加它,即在地址簿选择标签的其他数据属性之后。因此,整个地址簿模板应如下所示

{# templates/bundles/SyliusShopBundle/Checkout/Address/_addressBookSelect.html.twig #}
{% if app.user is not empty and app.user.customer is not empty and app.user.customer.addresses|length > 0 %}
    <div class="ui fluid floating dropdown labeled search icon button address-book-select" {{ sylius_test_html_attribute('address-book') }}>
        <i class="book icon"></i>
        <span class="text">{{ 'sylius.ui.select_address_from_book'|trans }}</span>
        <div class="menu">
            {% for address in app.user.customer.addresses %}
                <div class="item" {{ sylius_test_html_attribute('address-book-item') }}
                     data-id="{{ address.id }}"
                     data-first-name="{{ address.firstName }}"
                     data-last-name="{{ address.lastName }}"
                     data-company="{{ address.company }}"
                     data-street="{{ address.street }}"
                     data-country-code="{{ address.countryCode }}"
                     data-province-code="{{ address.provinceCode }}"
                     data-province-name="{{ address.provinceName }}"
                     data-city="{{ address.city }}"
                     data-postcode="{{ address.postcode }}"
                     data-phone-number="{{ address.phoneNumber }}"

                     {% include '@WebgriffeSyliusItalianInvoiceableOrderPlugin/Checkout/Address/_addressBookSelectInvoiceableDataAttributes.html.twig' %}
                >
                    <strong>{{ address.firstName }} {{ address.lastName }}</strong>, {{ address.street }}, {{ address.city }} {{ address.postcode }}, {{ address.countryCode|sylius_country_name }}
                </div>
            {% endfor %}
        </div>
    </div>
{% endif %}

特性

一旦安装此插件,商店用户即可输入意大利公司为正确开具订单发票所需的全部发票信息。此外,此插件会检查订单的账单数据,并据此决定顾客是否需要缴税。

此插件将向您的地址表单中添加以下字段

  • 账单接收者类型,允许用户指定账单地址是公司还是个人。此字段将用于每个用作订单账单地址的地址。
  • 税号,在意大利被称为“Codice Fiscale”。它类似于美国的社保号(SSN),但在意大利,公司和个人都有税号。此字段对于意大利的个人和公司来说是必需的,并按照正确的校验算法进行验证。
  • 增值税号,在意大利被称为“Partita IVA”。这是另一个识别号,但仅限公司使用,不仅限于意大利,也适用于欧盟。此字段对于意大利公司和欧盟公司来说是必需的,并按照正确的校验算法进行验证。此字段还要求使用欧盟的VIES服务进行验证,并使用MyOnlineStore/ViesBundle
  • SDI 码,其中SDI代表“Sistema Di Interscambio”。这是一个必须生成的“电子发票”的代码,自2019年1月1日起在意大利是强制性的。此字段对于意大利公司来说是必需的,并按照意大利税务局(在意大利称为“Agenzia delle Entrate”)的正确规则进行验证。
  • PEC 地址,其中PEC代表“Posta Elettronica Certificata”(意大利语中的“认证电子邮件”)。它类似于电子邮件地址,但是一种特殊的电子邮件类型,旨在提供传统邮件的法律等效物。更多信息请参阅这里。此字段对于意大利公司不是必需的,但如果填写,则必须是一个有效的电子邮件地址。

如果账单接收者类型设置为公司,此插件还将要求填写Sylius的“公司”字段。

此插件还通过装饰Sylius的Sylius\Component\Addressing\Comparator\AddressComparatorInterface实现,并比较发票字段。因此,在结账期间提供的不同发票地址信息作为新地址保存在客户地址簿中。

此插件还允许在结账时从地址簿中选择可发票地址,并正确填写包含所有发票信息的地址表单。

贡献

要贡献,您需要

  1. 将此存储库克隆到您的开发环境中

  2. 创建tests/Application/.env.localtests/Application/.env.test.local文件,以根据您特定的开发环境自定义环境变量(例如,DATABASE_URL变量)。

  3. 然后,从插件的根目录运行以下命令

    (cd tests/Application && yarn install)
    (cd tests/Application && yarn build)
    (cd tests/Application && bin/console assets:install public)
    (cd tests/Application && bin/console doctrine:database:create)
    (cd tests/Application && bin/console doctrine:schema:create)
    (cd tests/Application && bin/console sylius:fixtures:load)
    (cd tests/Application && symfony server:start -d) # Requires Symfony CLI (https://symfony.com.cn/download)
  4. 现在,您可以在https://127.0.0.1:8000/找到完整的Sylius测试应用程序,该应用程序运行插件。

运行插件测试

在您的更改之后,您必须确保测试仍然通过。

首先设置您的测试数据库

(cd tests/Application && bin/console -e test doctrine:database:create)
(cd tests/Application && bin/console -e test doctrine:schema:create)

当前的CI套件运行以下测试

  • PHPUnit

    vendor/bin/phpunit
  • PHPSpec

    vendor/bin/phpspec run
  • Behat(非JS场景)

    vendor/bin/behat --strict --tags="~@javascript"
  • Behat(JS场景)

    1. 安装Symfony CLI命令.

    2. 启动无头Chrome

    google-chrome-stable --enable-automation --disable-background-networking --no-default-browser-check --no-first-run --disable-popup-blocking --disable-default-apps --allow-insecure-localhost --disable-translate --disable-extensions --no-sandbox --enable-features=Metal --headless --remote-debugging-port=9222 --window-size=2880,1800 --proxy-server='direct://' --proxy-bypass-list='*' http://127.0.0.1
    1. 安装SSL证书(只需一次)并在127.0.0.1:8080上运行测试应用程序的web服务器
    symfony server:ca:install
    APP_ENV=test symfony server:start --port=8080 --dir=tests/Application/public --daemon
    1. 运行Behat
    vendor/bin/behat --strict --tags="@javascript"
  • 静态分析

    • 诗篇

      vendor/bin/psalm
    • PHPStan

      vendor/bin/phpstan analyse -c phpstan.neon -l max src/  
  • 编码规范

    vendor/bin/ecs check src

许可证

本库遵循MIT许可证。完整的许可证请参阅LICENSE文件。

致谢

Webgriffe®开发。