Requirements
- Collect tax numbers on billing profiles, with the ability to store and reuse them via the address book, same as the address.
- If the same profile type is used for both billing and shipping information, make sure that the tax number is only shown for billing
- The ability to select which countries the tax number should be collected for (and hide the field for others)
- The ability to limit tax number collection to the EU (to avoid having to select ~28 countries manually).
- Validation rules for all EU countries
- The ability to "verify" a tax number, by contacting a remote web service (VIES).
- The ability to store and display the verification timestamp and result (name/address returned by the service. Or an error/failure).
- The ability to block checkout if verification failed (service indicated that the number is invalid)
- The ability to continue checkout if the verification service is temporarily unavailable (and re-attempt verification later)
- The ability to integrate validation/verification for non-EU countries (with Norway and Switzerland being the obvious priorities). This requires making the logic pluggable.
Original issue
From EuropeanUnionVat:
// @todo Replace with $customer_profile->get('tax_number')->value
// once tax numbers are implemented.
$customer_tax_number = '';
We want to create our own field type (easier to extend with settings & validators VS using a regular string field), create an instance on profile ("customer" bundle), but have it hidden by default. Then people can edit the form mode and enable it, thus enabling tax numbers.
We want the tax number field to be on the customer profile so that it can be reused, and so that it can depend on the address (we can have a "Show only for these countries" setting, which is a common use case, and validators can compare the selected country with the one from the tax number in the VAT case).
| Comment | File | Size | Author |
|---|---|---|---|
| #29 | ic-vat-checkout.png | 35.56 KB | bojanz |
| #29 | tax-number-order-admin.png | 37.88 KB | bojanz |
| #29 | 2874149-tax-number-29.patch | 86.42 KB | bojanz |
| #27 | 2874149-tax-number-27.patch | 91.86 KB | bojanz |
| #26 | 2874149-tax-number-25.patch | 86.63 KB | bojanz |
Comments
Comment #2
xsdx commentedI created a patch for new field type commerce_tax_number, also provided validation on widget for EU vies and you have settings only for these countries as well. Field is locked on customer profile and disabled on view mode. Also there is post_update for attaching field and install yml file for creation on install. Please check it if I missed something and let me know if you want any changes done. Tnx
Comment #3
xsdx commentedComment #4
xsdx commentedAdding new patch improved patch, moving validations to validator from widget and adding support for country code from address field and from tax number from tax number field.
Comment #5
xsdx commentedMoved VIES validation settings on field storage settings for validator
Comment #6
dalra commentedThe VAT Number module does a similar thing.
Maybe the new tax_number field should implement some of its features, like checking if the VAT country matches the shipping country.
Comment #7
xsdx commented@daira
VAT number validator (for tax number) currently checks for locked address field (and its country code) if it matches tax number country if VAT applicable so this is already implemented in this patch
Comment #8
aleixI am trying to understand the mess with all the European union VAT... What I found (maybe issues, correct me if not) related with this tax_number fieldtype is:
- The VIES validator is disabled by default and since the field settings are blocked validator cannot be turned on.
- When using the field the checkout process fails, with this error:
InvalidArgumentException: Missing required property "display_label". en Drupal\commerce_tax\TaxZone->__construct() (linea 57 de /var/www/web.scaffolding/web/modules/contrib/commerce/modules/tax/src/TaxZone.php).
FIX: I don't know if it's ok, but adding the display_label to "ic" makes it work.
- Then it complains again when trying to obtain the selected "ic" zone:
PHP Fatal error: Call to a member function getDisplayLabel() on null in /var/www/web.scaffolding/web/modules/contrib/commerce/modules/tax/src/Plugin/Commerce/TaxType/LocalTaxTypeBase.php on line 165
FIX: Adding "ic" zone with getIcZone to the Array returned by buildZones fix it.
Comment #9
archnode commentedThank you for this patch! I fixed a few minor issues with updating and generally turned the validation in the locked field settings on. Altering the settings of locked fields seems to be the topic of #806102: Locked fields can change the widget but not settings - I guess it would be better to either activate it by default or move the validation setting to the form settings.
Comment #11
archnode commentedI further updated the patch and integrated the remarks from #9. As the EU-Vat exemption basically is it's own zone we have to specially handle it to allow negative adjustments to correctly get applied. With this patch it should be applied correctly.
Comment #12
archnode commentedCorrected botched indenting in patch. There are still a few failed tests which are related to the initialization of the tax_number field.
Comment #13
archnode commentedI refactored this quite a bit and moved the validation logic and configuration to the tax types. This seems more logical and should be more extendable than the current eu-only approach.
I created a pull request on github: https://github.com/drupalcommerce/commerce/pull/839
Patch based on pull request attached.
Comment #14
archnode commentedThis patch removes much of the functionality added in #13. Further functionality based on this is (re-)added in #2930722: Tax number validation and validation for tax number in the EU and #2927833: Provide EU event tax handling and VAT exemption.
Comment #15
xsdx commentedFixing commerce tax post update issue and providing updated patch
Comment #16
jeff veit commentedPatch #15 still applies! But unfortunately gives an error on update.php
Possibly this is the same error that patch 15 was meant to fix.
Comment #17
jeff veit commentedFurther to #16, the issue is that the the two lines with Yaml::parse functions should read \Symphony\Components\Yaml\Yaml::parse.
Secondly, the patch does not integrate cleanly into a site with Commerce Tax already installed. It looks like there's no entity update for the customer profile. The error on admin/people/profiles is "The website encountered an unexpected error. Please try again later.Drupal\Core\Database\DatabaseExceptionWrapper: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'mydb.profile__tax_number' doesn't exist.
If you have Commerce Tax disabled, then apply the patch, then turn it on, there's no error. You still have to alter the profile form to show the new Tax number field.
Comment #18
jeff veit commented/admin/config/people/profiles/manage/customer/display gives an error when you try to add Tax number to be a displayed field.
Enough testing for now. I'll be using VAT Number module for now. And I think there will need to be a smooth upgrade from that eventually.
Comment #19
jsacksick commentedThe attached patch just adds a new field type (the patch doesn't contain validation yet, and no field is attached to the customer profile type, but just posting the patch I started.
Comment #20
jsacksick commentedThe attached patch is still far from being ready but pushing my progress here so someone else can take that work over.
Bojan and I discussed this on Slack yesterday and agreed to implement the tax number validation via tagged services.
I started by defining 3 value objects (copied the AccessResult approach for the value objects that should be returned by the validate method on the tagged tax number validation services, but we can do the same with only one.
We need to start by implementing a tax number validator for the EU VAT number, I thought we could avoid passing the country code to the validators since EU VAT numbers always start by the country code, but in fact we can't since we wouldn't be able to determine if the number entered is for a european country or not (If it doesn't start by the country code, we can't just assume it's not a EU VAT number).
Remaining work to do:
Comment #21
jsacksick commentedForgot the patch.
Comment #22
bojanz commentedWorking on this.
Comment #23
bojanz commentedThe requirements here grew quite a bit. Updating issue summary to clarify what we're trying to accomplish.
A first patch should be up tomorrow covering most of the requirements. I will move any remaining requirements to follow-up issues for expediency.
EDIT:
Spun off and committed #3083053: Introduce tax number type plugins and #3083030: The Intra-Community EU VAT zone/rate is broken to decrease the size of the upcoming patch.
Comment #24
bojanz commentedSome initial code, without the ability to re-verify.
Needs widget tests.
Needs an expanded formatter.
Comment #26
bojanz commented#24 proves that once this is committed, commerce_tax will no longer be uninstallable, due to a core bug (#2871486: field.storage YAML and FieldType plugin cannot coexist in same module because of FieldUninstallValidator constraint). This is the same bug we've been hitting in recurring and shipping. I tried to move the tax_number field to commerce_order, but it didn't do the trick. We'll have to fix the core issue. In the meantime, removed commerce_tax from the uninstall test.
Anyway, here's the next iteration. Note that the field schema has changed.
The field item tests have been greatly expanded.
The widget is now fully functional and covered by tests.
Special care has been given to avoiding unnecessary verifications (if the value hasn't changed, or if we're still within the same request), to avoid repeating slow API calls.
TODO:
- Add the verification details to the formatter.
- Add a re-verify link to the formatter.
- Finish TaxNumberController and cover it with tests (to confirm re-verification works).
- Formatter tests
A shipping patch is also needed: #3084489: Update TaxSubscriber for Commerce 2.15.
Comment #27
bojanz commentedWell, not much feedback here :)
Here's a reroll on top of:
#3086907: Add an "admin" view mode for profiles
#3086915: Add VIES verification to the EU tax number type
Other changes:
- The formatter now shows an icon for the verification state
- Basic formatter tests (for the value and verification state data)
- Automatically exposes the tax_number field on the appropriate view modes.
Comment #29
bojanz commentedHere is the final patch for this issue.
I have removed the re-verification controller and will continue that in a followup.
Same for the verification result rendering in the formatter.
Can't continue rerolling a 90kb patch.
Attaching a screenshot of the tax number on the order admin page.
Also attaching a screenshot of the IC VAT at checkout. I think we'll need to come up with a shorter label. Also followup material.
Comment #31
bojanz commentedCommitted.
See you in followups:
#3087069: Show the verification result in the TaxNumberDefaultFormatter
#3087070: Allow tax numbers to be re-verified
Don't forget that you need Shipping -dev for #3084489: Update TaxSubscriber for Commerce 2.15.