Europass import: a telephone number typed with its trunk zero keeps the zero after the dialling code #644
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#644
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-09-29 in a read-only review of postulo at
95348908d, reading the Candidate reader's contact details and running it on files whose number is written the national way.Checked again on 2026-10-01 against
mainat0a5cad587: still present. The code is now atplugins/europass/candidate.py:410-425(_phone); the CV prints the number atdocuments/rendering.py:174, and the link is built atcore/templatetags/postulo.py:301-307.resume/importing.pyandcore/phones.pyare unchanged.The Candidate reader builds an international number by putting the file's
CountryDialingin front of every digit ofAreaDialingandDialNumber. When the number in the file is in its national form, with the trunk prefix, the result is not a valid international number, and it is stored as the profile's telephone number without a check. The telephone field treats the same typing differently:phones.combineremoves the leading zero before it puts the country's code in front.Where:
plugins/europass/candidate.py:409-424(_phone:digits = re.sub(r"\D", "", local)thenreturn f"+{country}{digits}");resume/importing.py:150-159(applystores the number throughsave_only_number, no form and no validator); comparecore/phones.py:389-392(combine).What happens: run against the snapshot:
CountryDialingAreaDialingDialNumberrecord.person["phone"]4407911 123456+4407911123456+4479111234563306 12 34 56 78+330612345678+33612345678490176 12345678+49017612345678+491761234567844020 7946123456+440207946123456+44207946123456The imported value then becomes the profile's primary number. It is printed on the CV as stored (
documents/rendering.py:200), and wherever a page shows the number as a link it istel:+4407911123456, grouped as+44 079 111 234 56(core/templatetags/postulo.py:320-326). Itsnormalisedform (core/models.py:372) differs from the correct number's, so the instance-wide uniqueness check inapply(resume/importing.py:155,taken_elsewhere) does not see that it is a number somebody already holds.What the editor at europass.europa.eu writes in
DialNumberwhen somebody types the zero has not been confirmed on a real download: both fixtures hold numbers from countries without a trunk prefix (tests/data/europass-candidate.xml:57-58,tests/data/europass-candidate-sample.xml:76-78). The reader accepts any Candidate file, whoever wrote it, so the case is reachable either way.Why it matters: an import fills Your details with a number that cannot be dialled as written, and every CV that prints the telephone number prints it. Nothing on the review page says the number was altered or is doubtful.
Fix: do not copy
combine'slstrip("0")into the plugin. That rule is wrong for the countries whose leading zero is part of the number:CountryDialing39with06 6982 1234is read correctly today as+390669821234, andcombinewould make it+39669821234. Whether a leading zero is a trunk prefix is a fact of each country's numbering plan, which #304 brings in. Once it has, pass the number through that parser where the importer writes it (resume/importing.py:150-159), so every importer gets the same treatment and the plugin keeps importing nothing butpostulo.plugins.api: a national prefix after the dialling code is removed where the plan defines one, the E.164 form is stored, and a number the plan calls impossible is reported inReport.skippedinstead of being stored. Update_phone's docstring, which today argues only the case with no dialling code.Related to #304, which decides what a valid number is and whose tests cover the form field only; this path never passes through the field. Related to #318: add "a number typed with its leading zero" to its checklist, so the real download settles what the editor writes.
Done when
tests/test_europass_candidate.pyreads a Candidate file withCountryDialing44andDialNumber07911 123456, applies it, and finds+447911123456as the profile's number; the same test with39and06 6982 1234finds+390669821234.tests/test_importers.pyapplies a record whosephoneis+4407911123456and finds the corrected number stored, or the number named inreport.skipped.