Skip to content

[FIX] base_vat: compute vies_valid on create() without a write() - #286201

Closed
kukor-odoo wants to merge 1 commit into
odoo:18.0from
odoo-dev:18.0-bas_vat-vies-guest-checkout-fix-kukor
Closed

[FIX] base_vat: compute vies_valid on create() without a write()#286201
kukor-odoo wants to merge 1 commit into
odoo:18.0from
odoo-dev:18.0-bas_vat-vies-guest-checkout-fix-kukor

Conversation

@kukor-odoo

Copy link
Copy Markdown
Contributor

Description

Steps to Reproduce

  1. Install Belgium Localization, then go to Settings → Accounting/Invoicing.
  2. Enable Verify VAT Numbers (vat_check_vies).
  3. Go to Accounting → Configuration → Fiscal Positions and confirm or create an Intra-Community fiscal position with:
    • Detect Automatically (auto_apply): enabled
    • VAT Required (vat_required): enabled
    • Country Group: EU, no specific country configured
  4. Open an incognito/private browser window and make sure the session is unauthenticated.
  5. Go to the website's /shop page and add any product to the cart.
  6. Proceed to checkout until reaching the Address step (/shop/address).
  7. Enter a delivery address in an EU country different from the company's country (e.g. company in Belgium, delivery address in the Netherlands).
  8. In the VAT Number field, enter a real, valid, VIES-registered VAT number corresponding to the delivery country (e.g. a valid NL VAT number for a Netherlands address).
  9. Click Save Address / Continue and proceed to the Payment step (/shop/payment).
  10. Check the tax applied to the delivery line and the resulting order total.

Issue

The delivery product and the overall order are taxed at the standard/domestic VAT rate instead of the expected 0% intra-community rate — even though the customer provided a valid, VIES-registered EU VAT number matching the delivery country.

Root Cause

In base_vat, res.partner.create() unconditionally removes vies_valid from the ORM's pending computation queue via env.remove_to_compute(), relying on a subsequent write() to trigger the actual VIES check. This holds for the standard backend flow, where creation is followed by a write() — but the website guest checkout flow differs:

  • website_sale creates the guest partner through _create_new_address().
  • The partner is created via a single create() call, with no follow-up write().
  • _compute_vies_valid() is therefore never triggered.
  • vies_valid remains permanently unset (NULL), despite a VAT number being provided.

Downstream, account.fiscal.position._get_vat_required_valid() reads this unset value as falsy, so the Intra-Community fiscal position's vat_required condition fails and is rejected in favor of another applicable position (e.g. EU B2C or Domestic).

Solution

After partner creation, explicitly trigger _compute_vies_valid() when the partner has a VAT number and the operation is not part of a file import (import_file context) — performing the VIES check immediately instead of relying on a write() that guest checkout never issues.

Result

Guest customers providing a valid EU VAT number now get vies_valid computed immediately at creation. Fiscal position detection correctly identifies the Intra-Community position, and the expected 0% VAT treatment is applied to the delivery and order.

OPW: 6522992

@robodoo

robodoo commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Pull request status dashboard

Steps to Reproduce:

1. Install Belgium L10n and go to Settings > Accounting/Invoicing and enable
   Verify VAT Numbers (vat_check_vies).
2. Go to Accounting > Configuration > Fiscal Positions and confirm
   (or create) an Intra-Community fiscal position with:
   - Detect Automatically (auto_apply) = enabled
   - VAT Required (vat_required) = enabled
   - Country Group = EU (no specific country set)
3. Open an incognito/private browser window (must be a guest,
   unauthenticated session - do not log in).
4. Go to the website's /shop page and add any product to the cart.
5. Proceed to checkout until you reach the Address step
   (/shop/address).
6. Enter a delivery address in an EU country different from the
   company's own country (e.g. company based in Belgium, delivery
   address in Netherlands).
7. In the VAT Number field, enter a real, valid, VIES-registered
   EU VAT number matching that same country (e.g. an NL... VAT
   number for a Netherlands address).
8. Click Save Address / Continue and proceed through to the
   payment step (/shop/payment).
9. Check the tax shown on the delivery line and order total.

Issue:

The delivery product and order total are taxed at the standard/
domestic rate instead of the expected 0% intra-community rate,
even though a genuinely valid EU VAT number was provided.

Root Cause:

base_vat's res.partner.create() unconditionally removes vies_valid
from the ORM's pending-computation queue (env.remove_to_compute),
assuming a subsequent write() call will trigger the actual VIES
check. That assumption holds for backend form saves (which perform
create() then write()), but website_sale's guest checkout flow
(_create_new_address) only performs a single create() call with no
follow-up write(). As a result, vies_valid remains permanently
unset (NULL) for guest-created partners with a VAT number.
Downstream, account.fiscal.position._get_vat_required_valid() reads
this blank value as falsy, so the Intra-Community fiscal position's
vat_required condition fails and the position is rejected in favor
of a lower-priority one (e.g. EU B2C or Domestic).

Solution:

After partner creation, if the partner has a VAT number and the
creation is not part of a file import (import_file context),
explicitly trigger _compute_vies_valid() to perform the VIES check
immediately, rather than relying on a write() that guest checkout
never issues.

Result:

Guest checkout customers providing a valid, verifiable EU VAT
number now correctly get vies_valid computed at creation time,
allowing the Intra-Community fiscal position to match as intended
and 0% VAT to apply.

opw-6522992
@kukor-odoo
kukor-odoo force-pushed the 18.0-bas_vat-vies-guest-checkout-fix-kukor branch from 71bc9d6 to 04d8fc8 Compare September 2, 2026 13:01
@kukor-odoo
kukor-odoo marked this pull request as ready for review September 4, 2026 05:33
@C3POdoo
C3POdoo requested review from a team and FlorianGilbert and removed request for a team September 4, 2026 05:35

@FlorianGilbert FlorianGilbert left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

robodoo pushed a commit that referenced this pull request Sep 4, 2026
Steps to Reproduce:

1. Install Belgium L10n and go to Settings > Accounting/Invoicing and enable
   Verify VAT Numbers (vat_check_vies).
2. Go to Accounting > Configuration > Fiscal Positions and confirm
   (or create) an Intra-Community fiscal position with:
   - Detect Automatically (auto_apply) = enabled
   - VAT Required (vat_required) = enabled
   - Country Group = EU (no specific country set)
3. Open an incognito/private browser window (must be a guest,
   unauthenticated session - do not log in).
4. Go to the website's /shop page and add any product to the cart.
5. Proceed to checkout until you reach the Address step
   (/shop/address).
6. Enter a delivery address in an EU country different from the
   company's own country (e.g. company based in Belgium, delivery
   address in Netherlands).
7. In the VAT Number field, enter a real, valid, VIES-registered
   EU VAT number matching that same country (e.g. an NL... VAT
   number for a Netherlands address).
8. Click Save Address / Continue and proceed through to the
   payment step (/shop/payment).
9. Check the tax shown on the delivery line and order total.

Issue:

The delivery product and order total are taxed at the standard/
domestic rate instead of the expected 0% intra-community rate,
even though a genuinely valid EU VAT number was provided.

Root Cause:

base_vat's res.partner.create() unconditionally removes vies_valid
from the ORM's pending-computation queue (env.remove_to_compute),
assuming a subsequent write() call will trigger the actual VIES
check. That assumption holds for backend form saves (which perform
create() then write()), but website_sale's guest checkout flow
(_create_new_address) only performs a single create() call with no
follow-up write(). As a result, vies_valid remains permanently
unset (NULL) for guest-created partners with a VAT number.
Downstream, account.fiscal.position._get_vat_required_valid() reads
this blank value as falsy, so the Intra-Community fiscal position's
vat_required condition fails and the position is rejected in favor
of a lower-priority one (e.g. EU B2C or Domestic).

Solution:

After partner creation, if the partner has a VAT number and the
creation is not part of a file import (import_file context),
explicitly trigger _compute_vies_valid() to perform the VIES check
immediately, rather than relying on a write() that guest checkout
never issues.

Result:

Guest checkout customers providing a valid, verifiable EU VAT
number now correctly get vies_valid computed at creation time,
allowing the Intra-Community fiscal position to match as intended
and 0% VAT to apply.

opw-6522992

closes #286201

Signed-off-by: Florian Gilbert (flg) <flg@odoo.com>
@robodoo robodoo closed this Sep 4, 2026
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

Successfully merging this pull request may close these issues.

3 participants