Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Compliance] Current Address Resource does not allow European VAT Tax calculation or eInvoicing compliance #6110

Open
fthobe opened this issue Feb 10, 2025 · 8 comments

Comments

@fthobe
Copy link
Contributor

fthobe commented Feb 10, 2025

Concerns: #3852 #3234 solidus_braintree #226 #6112

Realted to: Solidus Address Name Extension

Overview (TL;DR)

The current default address scheme of Solidus does not possess sufficient information to

  1. Calculate VAT reliably for transactions within the European Union;
  2. Calcualte VAT reliably for domestic transactions in European Union countries;
  3. Generate (mandatory) electronic invoices (eInvoice) across all jurisdictions.

While it can be assumed that all companies have some kind of bookkeeping software to issue the invoice, currently the data required to calculate taxes and issue a correct invoice are not present.

To suffice to all standards (NAFTA / European Union) the address model should be extended to following scheme. Hereby it should be noted that while the American tax calculations, require less customer data. It is also worth mentioning that both models are not incompatible for vat calculation. In the US more burden is shifted on state and state level requiring more formulas but less validation (, while the European Model requires more data from the customer to apply correct taxes. Both models can coexist.

  1. * First_Name (Required in several European Countries to generate eInvoices reliably)
  2. * Last_Name (Required in several European Countries to generate eInvoices reliably)
  3. * Company_Name (Required in several European Countries to generate eInvoices reliably)
  4. * Remove Name (redundant at that point)
  5. Street 1
  6. Street 2
  7. City
  8. Zip Code
  9. Country
  10. State
  11. Phone
  12. * Email (Required in several European Countries to generate eInvoices)
  13. * VAT-ID (Required in all countries to generate eInvoices and in all B2B cross border transactions to calculate taxes)

Values with * need to be either added or modified.

Incremental Breakdown of Reasons

VAT_ID, First_Name, Last_Name and Company_Name are required to generate eInvoices accross all jurisdictions

The European Union is, on different levels varying country by country, right now rolling out mandatory electronic invoices for B2B transactions.
The electronic invoice hereby consists of a signed xml file according to different national validation schemes.

Hereby several combinations of first name, last name and company name are used, depending on the country of fiscal residence of the seller.

  1. First Name and Last Name as separated values such as in Spain
  2. Concatenated (Germany and France for example which by the way developed the standard together, but also Belgium) as you linked already.
  3. Company Name interchangeably used with First Name Last Name concatenated.
  4. Company Name not interchangeably used with First Name Last Name concatenated but as fully separate field.
  5. Interchangeably either 1 or 2 works (Italy for example with the extended format, but not with the simplified) for individuals, but company names are an entirely different field so you actually need to identify if your address is a company or private individual (which you can do through a company name field for example).

While a concatenation can always be achieved, a joint name field makes it in many cases impossible to render reliably the data needed to emit an invoice.

The VAT-ID is required to correctly apply VAT domestic or cross border transactions inside the European Union

Why we need VAT-ID

VAT in European Union cross border transactions between businesses varies according to multiple factors:

  • Actually to determine if VAT needs to be charged on cross border transactions a seller must consult this platform to identify if the VAT ID requires shipments with or without VAT.
    Otherwise you risk having to backpay VAT (if the national fiscal authority doesn't reject your invoice straight away depending on the country of fiscal residence of the seller) if you didn't charge it. The registration of VAT IDs to participate in VAT exemption became practically universal within Europe;
  • there are various countries which also allow reverse charge vat exemptions internally. The EU allows this reverse charge on goods or services sensitive to fraud, including allowances to emit greenhouse gases, mobile phones, integrated devices, cereals and raw metals. This includes almost all electronics.
Image

In all cases the eligibility of the applicable tax rate needs to be confirmed through VAT-ID and country of shipping and / or billing. Therefor if we do want to render Solidus compliant with the European market both these fields need to be present.

Why can't the VAT-ID be stored on the customer resource?

There are multiple cases in which a customer might need more than one VAT-ID and cases in which the seller needs more than one VAT-ID.

  • Dropshipping between businesses
  • B2B Customers that have unincorporated branch offices
  • In UK any division can have a different VAT number

The reasons are plenty and vary from country to country.

Solidus Version:
All versions

@fthobe fthobe changed the title [Compliance] Current Address Resource does not allow compliance with European VAT Tax calculation or eInvoicing regulations [Compliance] Current Address Resource does not allow European VAT Tax calculation or eInvoicing compliance Feb 10, 2025
@mamhoff
Copy link
Contributor

mamhoff commented Feb 10, 2025

Company

A company string is already present on the address resource.

First name and last name

first_name and last_name can be generated by separating the string using the Spree::Address::Name model. The mandatory fields can thus be filled. The only legislation that requires the name to be separated that I could find is the Spanish legislation, which ... requires three name fields: First name, Last name, and Second last name. Their documentation already fills this field with bogus data, namely one "John Spanish Spanish". At the end of the day, first name and last name field will always be concatenated to a full name. For Italy, just use the extended syntax.

Furthermore, EU legislation requires all formats to be interoperable. I'm pretty sure that interoperability requirement will already require anyone using the standards with concatenated first name and last name to split names, leading many invoices in Spains Facturae format to have bad data in their first name and last name fields. They'll be used to it.

We've already moved forward with concatenating first name and last name, and the stores I work with really like the simplicity and reduced friction in the (already complicated) address forms. I am not willing to move them back to a separate first name / last name situation, especially because that would mean a data migration that's quite prone to errors, and that will take days of work to get right. If separated first name and last name become a reality, this MUST be behind a configuration flag for store owners to decide.

Email

The Spree::Order has an email field that can, and should, be used as a source for the email in invoices.

VAT ID

This is the most complex of all the requirements. I think it should be its own resource, and should not be tied to all addresses at the schema level. They have separate validation needs, as you indicate above. In the US, tax exemption works by state, so users need more than one tax exemption as well (there, however, the exemption is a piece of paper that needs to scanned, not an ID, and it's - as you write - far less systematic). Hoping for a better suggestion here.

@fthobe
Copy link
Contributor Author

fthobe commented Feb 10, 2025

Interoperability in this case means that all standards are validatable against XML not that all schemas are the same.
I ask you kindly here to take my word for it and not force me to make a comparison table of the name schemes, kindly and again. I already have incrementally broken down the differences on 5 ways names are stored.

first_name and last_name can be generated by separating the string using the Spree::Address::Name model. The mandatory fields can thus be filled. The only legislation that requires the name to be separated that I could find is the Spanish legislation, which ... requires three name fields: First name, Last name, and Second last name.

We've already moved forward with concatenating first name and last name, and the stores I work with really like the simplicity and reduced friction in the (already complicated) address forms. I am not willing to move them back to a separate first name / last name situation, especially because that would mean a data migration that's quite prone to errors, and that will take days of work to get right. If separated first name and last name become a reality, this MUST be behind a configuration flag for store owners to decide.

I agree on a configuration flag as I agree with backwards compatibility.

This is the most complex of all the requirements. I think it should be its own resource, and should not be tied to all addresses at the schema level. They have separate validation needs, as you indicate above. In the US, tax exemption works by state, so users need more than one tax exemption as well (there, however, the exemption is a piece of paper that needs to scanned, not an ID, and it's - as you write - far less systematic).

Yes, we agree on that. It would be valuable inside to understand where this makes us end up:

  1. some b2b centric stores in Europe hard validate VAT-IDs (check if you are eligible), which depending on validation can take up to 4-5 seconds;
  2. most of them validate after the order (you put a vat id, trust is given till proven otherwise) and validate in accounting, not on the shop.

Another problem is that the validation state is not permanent and can change over time, VAT IDs can lapse creating serious backcharges for the merchant.

A reasonable middle ground would be (in my oppinion but open to any suggestion):

  • acquire the string as naked text field and throw it into the address
  • implement tax calculation for it
  • maybe throw a warning on that kind of calculations in backend and frontend
  • document that real validation is currently not covered and we do a technically best effort to assume the correct outcome on reverse charge based on no validation

This leaves everybody the chance to either

  • assume the risk of eventual backpayments;
  • validate manually;
  • validate with an automatic solution.

It is worth noting that the various (national) systems have various response times. The France vat ID validation frequently reaches 3000ms and i do not think it's the job of solidus to cover for it, but an extension could be made for that as they get hammered with literally millions of requests per day.

I am not aiming to eliminate risk for backtaxing here, but to errogate the instruments to solve it individually. In my oppinion tax validation should have a state on it's own but I see how that's not possible.

Image

@fthobe
Copy link
Contributor Author

fthobe commented Feb 19, 2025

We had some thoughts about it internally and took a look at the PRs Thomas once made and we would like to make the changes as upstream compatible as any possible.

Ideally the choice can be made upon installation as it's a relatively boolean step (Am I in Europe and do I want this).

Walking through the old PRs we saw that First_Name and Last_name are not entirely exstinct from solidus. So we came up with a couple of questions:

  • do we want to resurrect zombies like first_name and last_name or make new name fields (fname lname) or is it indifferent to you?
  • do we want to collect an additional optional email for billing (some countries have an optional field for that on eInvoices)?
  • is the idea of having a reverse_charge_status than can be toggled internally or externally (eg API) something we can all get behind?

I kindly ask you also to be as specific as any possible. We will try to make a PR as close to what you expect as possible but we need help here to define the scope precisely.

@kennyadsl
Copy link
Member

The only thing that is concerning to me here is the will to throw the vat id (and other billing fields) into the addresses. If I need to add a different address (maybe my company has multiple locations), do I need to enter the vat id multiple times? This just feels wrong, so I'd like to map the information in a way that makes more sense and are not redundant.

On the other hand, we need to store the info on the order to have a historical record of the vat id used at checkout (in case someone changes the vat id after placing the order), and the address is incredibly tempting for solving this.

I think we'll need the extra email field (we have the PEC here in Italy, which can be used instead of the vat id as an identifier if I recall correctly).

What about having a concept similar to the address book, but called billing info, which is tied to the user. The final address will be the address + billing info, but those entities can be combined in different ways. For example a user might have multiple addresses and just one billing info, which they use in the checkout if/when needed.

@fthobe
Copy link
Contributor Author

fthobe commented Feb 19, 2025

hey I mostly agree, the vat ID in the address seams a compromise to me,
having it on the customer is legally impractical for the above reasons I quote below:

Why can't the VAT-ID be stored on the customer resource?
There are multiple cases in which a customer might need more than one VAT-ID and cases in which the seller needs more than one VAT-ID and I believe having it as an own resource for the only purpose of recalling it on the billing address is overkill.

Dropshipping between businesses
B2B Customers that have unincorporated branch offices
In UK any division can have a different VAT number
The reasons are plenty and vary from country to country.

The thing is, the billing address covers really all cases, while admittedly asking some customers to maybe add the same vat id to multiple addresses, but this seems like a super small price to pay for a streamlined solution.

@elia
Copy link
Member

elia commented Feb 20, 2025

My 2 cents on the topic of first/last name.

Back in 2023 we did extensive customer interviews and the two topics that came up over and over were the admin UI (that's how solidus_admin was started), and the unified name field. They were all asking why the change was introduced and were never satisfied by the answer, because on a practical level virtually all the 3rd party tools expected two fields. For those who had to incur in the migration they mostly did it reluctantly to reap the benefits of staying up to date, but never got any value out of it, on the contrary.

So I would really love to see that change rolled back to the point where the default is reversed and maybe a configuration is kept around as a legitimate citizen for those who endured the migration. Besides, lowering the barrier of entry is the best thing we can do to lift up a small business.

As further proof of how frequently this issue was raised this repo exists: https://github.com/nebulab/solidus_address_name.

@fthobe
Copy link
Contributor Author

fthobe commented Feb 20, 2025

@jarednorman you have some more american insight and I know names are often structured differently there, do you have an oppinion on this one?

@fthobe
Copy link
Contributor Author

fthobe commented Feb 20, 2025

TL;DR

First Name and Last Name needs to be taken in consideration as separate values in many countries to comply with fiscal requirements and regulations, it's easier to unmerge than merging this fields as we can simply write First_Name and Last_Name in together in name for the forseeable future to not break anything. Let's do it 🔥

Proposal

Intro

After having had brief initial discussion with @kennyadsl @tvdeyen I'd like to formally request a public discussion about this. I would like to underline that I don't request this easily, I am well aware of the process that has been made in 3 PRs to migrate away from separated fields for first_name and Last_name. The decision was made, when eInvoicing was not as prevalent as it became over the past 4 years in Europe. The fact that many countries (while sharing a standard) do not necessarily use the same schema and moved at different speeds (Italy very early on einvoicing, Germany very late) posed an additional barrier in researching this topic properly during the conception of single name fields in Solidus.

Some more legal information about fiscal requirements can be read at the top of this thread or here.

The issue of a merged field nevertheless seems to be a problem for some time given that extensions for this purpose have been build and are updated frequently:

As further proof of how frequently this issue was raised this repo exists: https://github.com/nebulab/solidus_address_name.

The question is now, how do we softly weasel out of this situation.

Some things to know about billing addresses for companies and consumers

  • some systems need separated names, others a joined First Name Last Name
  • a company can have multiple VAT-ID inside a company but also broken down per branch office (domestic and abroad), legislation here varies significantly by country (UK very liberal, Germany very 1 VAT ID);
  • while a VAT ID on the customer does not tackle all cases, VAT ID per billing address does by allowing more granular per order settings;
  • while the proposed idea of @kennyadsl and @mamhoff has some usability merits, it doesn't change that to fully validate reverse charge in all scenarios we need all customer information present before payment, but other than removing a step of entering a VAT ID on the rare cases that it changes for a customer, we do not win any benefits by fragmenting the billing address by splitting VAT-IDs in a separate resource. A billing address is either as a whole valid for reverse charge or not.

Considerations

Various address schemes are used around the world. These consist primary of 3 large families:

  1. First and Last Name in conjunction inside one column mostly used with card payments and some einvoicing schemes in Europe
  2. First and Last Name separated into two columns used by various einvoicing systems in Europe
  3. First, Initial and Last Name by many legacy authentication systems, hereby the initial is usually optional

While the merger of two separated names into one united output is as we all know relatively painless, the separation of two stored values is challenging, several issues come to mind:

  • Spaces can not be reliably used as they provide inconsistent results as multiple names (eg. John Harold Doe) or multiple surnames (eg. Van du Deier ;) or the combination of either of them will yield outcome variability;
  • Naming Pattern heuristics do not reliably resolve the problem either as in many countries common first names can also be common last names (such as Romero in Spain or Ulrich in Germany).

The problem hereby is that while it can be decided to support or non support certain private standards in the name scheme (for example address schemes of shipping companies), in many countries you are or will be in the close future required to issue xml invoices on every order that will require a split field for first name and last name.

Solution

While the change seems to be dramatic given also the many PRs it took to remove first name and last name, there's a large benefit it split fields: we can always join them.

The process could be to not even deprecate Name and just fill it up with a joined First_name Last_name value.
The advantage would be allowing us to:

  • reach immediately compliance on being able to generate an address that can be validated for eInvoices (in all member states in all cases)
  • continue to write name as joined value
  • keep all current addresses healthy
  • not force any hard migrations

In addition the initial extension of the address form would not be technically to challenging.

In addition a joined field allows to ease many additional functions such as:

  • build Shipping Addresses for labels (frequently asking for joint fields)
  • credit card information

It should be possible to do this without killing anybody.

The final address scheme should like this:

  • First_Name (Required in several European Countries to generate eInvoices reliably)
  • Last_Name (Required in several European Countries to generate eInvoices reliably)
  • Company_Name (Required in several European Countries to generate eInvoices reliably)
  • Name (can be hidden by setting)
    Street 1
    Street 2
    City
    Zip Code
    Country
    State
    Phone
  • Email (Required in several European Countries to generate eInvoices)
  • VAT-ID (Required in all countries to generate eInvoices and in all B2B cross border transactions to calculate taxes)

@fthobe fthobe mentioned this issue Mar 23, 2025
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants