An education entry names its institution as a company, one that is in education #685
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#685
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?
The maintainer's list says, under Your career: “Learning institution are Companies (with valid NACE code).” Today the institution of an education entry is free text, on purpose (#131), and a company has no NACE code of its own. This issue links the entry to a company the way #683 does for an experience, and says what “valid NACE code” can mean given what Postulo stores.
What exists today
Education.institutionis a requiredCharField(200)(src/postulo/resume/models.py:104). It is not translatable on purpose, for the reason #131 gave about Universidade de Lisboa (src/postulo/resume/translatable.py:16-27; pinned bytests/test_career_languages.py:72-79,:305-312). The wiki repeats it (Your-career-record.md, “Some things are not translated, on purpose”). It is read by the form (resume/forms.py:98-124), the CV themes (templates/documents/themes/base_cv.html:137,base_portfolio.html:142), the preview, the text and the Word file (documents/rendering.py:310,:379), search (core/search.py:476-481), the candidate file, where an entry is its institution, qualification and dates (resume/candidate.py:198-217), and the Europass import (resume/importing.py:240-250).core/importer.py:530-575,:597), the archive and the candidate file share one block and one fingerprint (core/export.py:355-366,tests/test_candidate_file.py:354-387), a company merge and delete know nothing of the career (jobs/merging.py:230-250,jobs/views.py:574-610), and every list of companies would gain the school.Industryhas one:Industry.codeis the division, set from the name bysave()when the name is a division's name in the reader's language or English, and a company has industries through a many-to-many (jobs/models.py:42-81,:288-290;jobs/industries.py:165-176). The vendored file holds the 22 sections and 87 divisions of NACE Rev. 2.1 in 24 languages and no groups or classes (jobs/data/nace-2.1.json,data/LICENCE.md: “Groups (three digits) and classes (four) were not taken”). #671 adds the registry of which divisions qualify a company for a role."85": {"section": "Q"}), and Eurostat's NACE Rev. 2.1, 2025 edition (KS-GQ-24-007-EN-N) heads it “SECTION Q -- EDUCATION”; Rev. 2 had education in section P, which is where an older note or table may say it still is. The division's classes there: 85.10 pre-primary, 85.20 primary, 85.31 general secondary, 85.32 vocational secondary, 85.33 post-secondary non-tertiary, 85.40 tertiary education (“public and private universities”, the granting of degrees “at short-cycle, bachelor's or equivalent level, master's or equivalent level, and doctoral level”), 85.51 sports and recreation, 85.52 cultural, 85.53 driving schools, 85.59 other education n.e.c. (examination review courses, language and computer training), 85.61 intermediation for courses and tutors and 85.69 educational support n.e.c. Non-formal courses and training are group 85.5 by the classification's own definition. Every one of these codes and titles was read in Eurostat's publication.jobs/industries.pystill describes Rev. 2. Its docstring speaks of “21 sections” and “615 classes”; Rev. 2.1 has 22 sections, 87 divisions, 287 groups and 651 classes. Not part of this issue's fix, but it is wrong in the file the issue touches.CompanyKindhas only employer and employment service (jobs/models.py:209-221); nothing counts employers today except the industry tally of applications, where a school with no applications never appears (applications/reports.py:522-529).Checked against
mainatf09b6010b.Proposal
Three commits, after #683 (the link, the marker, the files) and #671 (the registry); each leaves
maingreen.Education.company, a nullable foreign key tojobs.Company,SET_NULL, withinstitutionkept as the required text every theme and file reads. The form's institution box offers the person's companies as #683's does, in the order e1's registry gives for the role “place of learning”: the companies whose industries include division 85 first, then every other company below them (a typed box hides nothing). On save the text is matched to the owner's company by name, case-insensitively, or a company is added, marked as from the career. A company added from an education entry is given the industry named by division 85 in the person's language, visibly (the form says “Added to your companies as Education”), and the person can remove it; an existing company is never given an industry by this form.company(name or blank), read as #683 reads it: by name, after the companies exist; offered as a link on the candidate review page only on an exact match; a file never creates a company; the Europass import links by exact name and adds none. A migration links an entry where exactly one company of the same owner has the institution's name, and adds none. The company's page lists the education entries that name it with the experiences, the merge moves them, and the delete dialog counts them.Decisions
Prior art
No new dependency. NACE Rev. 2.1 is Eurostat's, published by the Publications Office and already vendored under CC BY 4.0 (
jobs/data/LICENCE.md); the rule that a classification is taken and not invented is #140's and #266's, and the maintainer's list states it again. Source for every code above: Eurostat, NACE Rev. 2.1 — Statistical classification of economic activities in the European Union, 2025 edition (doi:10.2785/155339), read in full for division 85 and checked, class by class, against the Publications Office copy a previous attempt had harvested (1,020 of the 1,025 divisions, groups and classes carry the same title; the five that differ are in divisions 11, 20, 22, 47 and 77, by a word, an apostrophe or a line break).Builds on
Issues #131 (career entries per language, reversed in part), #140 and #266 (a classification is taken, not written), #202 (company kinds), #683, #671.
Needed by
#695 (the provider of a course), #673 (a name in a language, from Wikidata).
Done when
tests/test_career_companies.py(new in #683) gains the education cases: saving links or adds a company marked as from the career, gives a newly added company the division-85 industry and no existing one, never uses another owner's company; the migration links exact matches only.tests/test_nace.py, which is about the classification file and industries): the “place of learning” role is division 85 and nothing else, an unknown division is refused, and every code named in the registry exists in the vendored file; a company with the industry “Education” (and its French and Portuguese names) qualifies, one without does not.tests/test_help_text.pyfollows the field.tests/test_merging.pymoves education entries;tests/test_jobs_isolation.pyandtests/security/test_isolation_sweep.pyshow another account's company is neither offered nor linked;tests/test_career_languages.pystill passes unchanged.tests/test_export.pyand the archive round trip carrycompanyon an education entry at the new format;tests/test_candidate_file.pyholds the newSHAPESline (the education block changes with #684 and this issue, and each commit bumps the format it changes) and a hostilecompanyintests/security/test_candidate_file.py;tests/test_importers.pyandtests/test_europass_candidate.pyfor the links.core/gdpr.py). Standing checklist otherwise: archive format one more than whatever it is when the commit lands (29 atf09b6010b), candidate format likewise (4), strings in the working catalogues (en-GB, fr-FR, pt-PT as drafts) and Weblate (#349);Your-career-record.mdandjobs/industries.py's docstring (22 sections, 651 classes) changed in the same commits.From the list of improvements of 2026-10-02.
Landed on main with a green Forgejo CI run. Its entry in the CHANGELOG's Unreleased section ends in (#685).