{"record":{"id":"4cfa966ee81d8b7c","repo":"odoo/odoo","slug":"to-explicitly-indicate-no-valid-vat-use-ins","errorCode":null,"errorMessage":"To explicitly indicate no (valid) VAT, use '/' instead. ","messagePattern":"To explicitly indicate no \\(valid\\) VAT, use '/' instead\\. ","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"addons/base_vat/models/res_partner.py","lineNumber":117,"sourceCode":"    )\n    # Field representing whether vies_valid is relevant for selecting a fiscal position on this partner\n    perform_vies_validation = fields.Boolean(compute='_compute_perform_vies_validation')\n    # We put on inverse because a compute with a dependency to itself is not well managed in the ORM (it should be triggered first)\n    country_id = fields.Many2one(inverse=\"_inverse_vat\", store=True)\n    vat = fields.Char(inverse=\"_inverse_vat\", store=True)\n\n    @api.model\n    def _run_vat_checks(self, country, vat, partner_name='', validation='error'):\n        \"\"\" OVERRIDE \"\"\"\n        if not country or not vat:\n            return vat, False\n        if len(vat) == 1:\n            if vat == '/' or not validation:\n                return vat, False\n            if validation == 'setnull':\n                return '', False\n            if validation == 'error':\n                raise ValidationError(_(\"To explicitly indicate no (valid) VAT, use '/' instead. \"))\n        vat_prefix, vat_number = self._split_vat(vat)\n\n        if vat_prefix == 'EU' and country not in self.env.ref('base.europe').country_ids:\n            # Foreign companies that trade with non-enterprises in the EU\n            # may have a VATIN starting with \"EU\" instead of a country code.\n            return vat, False\n\n        do_eu_check = False\n        prefixed_country = ''\n        eu_prefix_country_group = self.env['res.country.group'].search([('code', '=', 'EU_PREFIX')], limit=1)\n        country_code = EU_EXTRA_VAT_CODES_INV.get(vat_prefix, vat_prefix)\n        if country_code in eu_prefix_country_group.country_ids.mapped('code'):\n            if 'EU_PREFIX' in country.country_group_codes and vat_prefix:\n                vat = vat_number\n                prefixed_country = vat_prefix\n            else:\n                do_eu_check = True\n","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/odoo/odoo/blob/1e661df964b1b264c9cef3ab28430d4785be3fda/addons/base_vat/models/res_partner.py#L99-L135","documentation":"Raised by base_vat's _run_vat_checks() when the partner's vat value is exactly one character long and is neither '/' nor handled by a softer validation mode. Odoo uses '/' as the explicit sentinel meaning 'this partner has no VAT number', so any other single-character VAT is treated as invalid input rather than being checked.","triggerScenarios":"Setting res_partner.vat to a single non-'/' character (e.g. '0', 'x', '-') while the partner has a country with VAT validation active and validation='error' (the default on create/write of vat).","commonSituations":"Data imports or CSV syncs that map an empty/placeholder VAT column to a stray character; users typing '-' or '.' to mean 'none'; connectors pushing partial values.","solutions":["Use '/' as the vat value to explicitly record that the partner has no (valid) VAT number.","Leave the vat field empty (falsy) instead of writing a placeholder character — empty values skip validation entirely.","For bulk imports where the source data is dirty, pre-clean single-character VATs to '' or '/' before writing to res.partner."],"exampleFix":"# before\npartner.write({'vat': '-'})  # ValidationError\n\n# after\npartner.write({'vat': '/'})  # explicit 'no VAT' sentinel","handlingStrategy":"validation","validationCode":"def normalize_vat(vat):\n    if vat and len(vat) == 1 and vat != '/':\n        return ''  # or '/' to explicitly mark 'no VAT'\n    return vat\n\npartner.write({'vat': normalize_vat(raw_vat)})","typeGuard":null,"tryCatchPattern":"from odoo.exceptions import ValidationError\ntry:\n    partner.write({'vat': raw})\nexcept ValidationError:\n    partner.write({'vat': '/'})  # explicit no-VAT sentinel","preventionTips":["Use '/' or empty string for partners without a VAT number; never placeholder characters.","Pre-clean VAT columns in import scripts: strip whitespace, map single-char junk to '' or '/'.","Add unit tests asserting single-character VATs are normalized before reaching base_vat."],"tags":["odoo","vat","validation","res-partner","data-import"],"backgroundTag":null,"analyzedSha":"1e661df964b1b264c9cef3ab28430d4785be3fda","analyzedAt":"2026-08-15T05:22:16.142Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}