vatin: reject a duplicated country code prefix (#420) - #500
Conversation
26a63eb to
0380834
Compare
|
Hi @CedricConday, Thanks for looking into this and sorry for not coming back to this sooner. One problem with this approach is that this code will currently fail the following test (while passing on the master branch): from stdnum import vatin
vatin.validate('MX MXDE 111111 GR2')while the number validates just fine: from stdnum.mx import rfc
rfc.validate('MXDE 111111 GR2')This number is constructed and not a number that has been seen in the wild but still. |
vatin.validate() stripped the leading country code itself and then passed the remainder to the country module, which strips its own optional country code prefix again. For a doubled prefix such as 'BE BE 0308.357.159' both strips fired, leaving a valid national number, so the VATIN validated even though stdnum.eu.vat correctly rejects it. Validate the full number with the country module (which strips its own prefix once), mirroring stdnum.eu.vat, and only fall back to stripping the country code for modules that do not recognise it - guarding that fallback so a doubled prefix is not stripped a second time. Closes arthurdejong#420.
0380834 to
8eb3521
Compare
|
Thanks for the counter-example — that one's decisive, and it showed the check I used was the wrong shape. I was testing the prefix syntactically: if the remainder also started with the country code, reject. That can't distinguish Rebased on master and replaced it with a semantic check. The question isn't whether the remainder starts with the country code — it's whether the country module strips it: >>> get_cc_module('be', 'vat').compact('BE0308357159')
'0308357159' # stripped -> the prefix was duplicated
>>> get_cc_module('mx', 'vat').compact('MXDE111111GR2')
'MXDE111111GR2' # kept -> the "MX" is part of the numberSo the fallback path now only rejects when the module consumed a second country code. Your test passes unchanged, including the >>> vatin.validate('MX MXDE 111111 GR2')
'MXMXDE111111GR2'
>>> vatin.validate('MXDE 111111 GR2') # here MX is only the country code
'MXDE111111GR2'
>>> vatin.validate('BE BE 0308.357.159')
InvalidFormatI kept your Two notes:
Full suite green at 100% coverage (413 passed, 9 skipped). AI-assisted, human-reviewed |
Closes #420
vatin.is_valid()accepts a VAT number with a doubled country code, whilestdnum.eu.vatcorrectly rejects it:Cause
vatin.validate()stripped the leading country code itself (module.validate(number[2:])) and then handed the remainder to the country module, which strips its own optional country-code prefix again. ForBE BE 0308.357.159both strips fired, leaving the valid national number0308357159. Countries whose module doesn't strip a prefix (e.g.BR) weren't affected, which is why it reproduced for BE/NL but not MX.Fix
Validate the full number with the country module (it strips its own prefix exactly once), mirroring
stdnum.eu.vat. Only fall back to stripping the country code for modules that don't recognise it — and guard that fallback so a doubled prefix (even writtenBE BE …with whitespace) is not stripped a second time.Tests
Added doctests in
tests/test_vatin.doctestfor the doubled-prefix case (with and without whitespace). They fail onmasterand pass with the fix. The full test suite stays green (405 passed, 9 network-skipped), including the existing multi-country vatin doctests (FR/DE/BR/EL→GR/CHE/XI/EU).AI disclosure: prepared with AI assistance (Claude Code), human-reviewed and verified before opening.