Several addresses, several pins: count a company at every place it has an address #703

Closed
opened 2026-10-03 01:59:12 +00:00 by tiagoagueda · 1 comment
Owner

From the list: “Multiple addresses = multiple pins on a map.” The map draws one dot per place, from one location per company. Once an address can be placed (#702), an employer with offices in three cities has to be at three places, and the page's counts have to say what they now count. The engine and precision are #700's.

What exists today

  • One place per company, grouped by its text. CompanyMapView reads each company's location text and its one coordinate, groups companies by the text, counts how many are at each place and draws one proportional dot per place, with the list beside it as the page (src/postulo/jobs/views.py:147-199, src/postulo/templates/jobs/company_map.html). A place's coordinate is the first one found for that text (views.py:182-184).
  • Two spellings are two places. The key is the text as typed, so “Lisboa” and “Lisbon” give two dots on one spot; nothing merges places by where they resolve to.
  • A holder can already have several addresses, one marked primary (PostalAddress, src/postulo/core/models.py:486-570, constraint one_primary_address_per_holder), for a profile and a contact; a company will once #329 lands. Nothing draws more than one.
  • The page says what a count is: “n company / n companies” at a place (company_map.html). With several addresses that sentence would be wrong.

Checked against main at f09b6010b.

Proposal

  1. Group places by where they resolve to, not by their text: the resolved city or postcode centroid, falling back to the text for a place that does not resolve. Two spellings of one town become one dot.
  2. A company is counted once at every place it has a pinned address, and the list under a place names the company and, in text, which address it is (its kind: head office, branch, as the person labelled it). The count at a place is the number of distinct companies there.
  3. Say what the totals mean: the page notes that a company with offices in several places appears at each, so the counts add up to more than the number of companies. The empty and the “not on the map” sentences cover an address that could not be placed.
  4. Contacts' and the person's addresses follow #702's defaults: nothing is drawn for them unless pinned on request, and then each pinned address is its own entry.
  5. Keep the page a list first: every pinned address is in the text before it is drawn, in the same order, with scripts off.

Decisions

  • A company's location text and its addresses. Once a company has pinned addresses, the text's own dot is either kept as an extra place, replaced by the addresses, or used only when there is none. Recommended: used only when there is no pinned address, so a company is not drawn twice at one town; the text stays on the record.
  • The primary address. Show it first and in the list marked, or treat all alike. Recommended: mark it in the list and treat all alike on the drawing; the question the map answers is where the search is spread.
  • How many pins. No limit today on addresses per holder. Recommended: leave it, and draw at most one dot per place however many addresses it has, which also bounds the drawing.

Builds on

Issues #92 (several addresses), #108 (the map's list-first rule), #329 (companies get addresses). #700 decides the engine and what may be drawn; #702 places an address.

Done when

  • tests/test_company_map.py: a company with two pinned addresses in two towns appears at both with a count of one each; two spellings of one town are one place; a company with no pinned address still uses its text; the totals sentence is present only when it is true; a second owner's addresses never appear.
  • The page still passes axe in both themes (tests/e2e/test_accessibility.py:471 visits it, and tests/test_page_coverage.py holds every URL to that list) and works with scripts off.
  • No new stored data beyond #702's, so no archive bump here. New strings are in the working catalogues (en-GB, fr-FR, pt-PT as drafts) and Weblate (#349); the wiki's Configuration page, which describes the map (Configuration.md:114-115), is updated.

From the list of improvements of 2026-10-02.

From the list: “Multiple addresses = multiple pins on a map.” The map draws one dot per place, from one location per company. Once an address can be placed (#702), an employer with offices in three cities has to be at three places, and the page's counts have to say what they now count. The engine and precision are #700's. ## What exists today - **One place per company, grouped by its text.** `CompanyMapView` reads each company's `location` text and its one coordinate, groups companies by the text, counts how many are at each place and draws one proportional dot per place, with the list beside it as the page (`src/postulo/jobs/views.py:147-199`, `src/postulo/templates/jobs/company_map.html`). A place's coordinate is the first one found for that text (`views.py:182-184`). - **Two spellings are two places.** The key is the text as typed, so “Lisboa” and “Lisbon” give two dots on one spot; nothing merges places by where they resolve to. - **A holder can already have several addresses**, one marked primary (`PostalAddress`, `src/postulo/core/models.py:486-570`, constraint `one_primary_address_per_holder`), for a profile and a contact; a company will once #329 lands. Nothing draws more than one. - **The page says what a count is**: “n company / n companies” at a place (`company_map.html`). With several addresses that sentence would be wrong. Checked against `main` at `f09b6010b`. ## Proposal 1. **Group places by where they resolve to, not by their text**: the resolved city or postcode centroid, falling back to the text for a place that does not resolve. Two spellings of one town become one dot. 2. **A company is counted once at every place it has a pinned address**, and the list under a place names the company and, in text, which address it is (its kind: head office, branch, as the person labelled it). The count at a place is the number of distinct companies there. 3. **Say what the totals mean**: the page notes that a company with offices in several places appears at each, so the counts add up to more than the number of companies. The empty and the “not on the map” sentences cover an address that could not be placed. 4. **Contacts' and the person's addresses follow #702's defaults**: nothing is drawn for them unless pinned on request, and then each pinned address is its own entry. 5. **Keep the page a list first**: every pinned address is in the text before it is drawn, in the same order, with scripts off. ## Decisions - **A company's `location` text and its addresses.** Once a company has pinned addresses, the text's own dot is either kept as an extra place, replaced by the addresses, or used only when there is none. **Recommended: used only when there is no pinned address**, so a company is not drawn twice at one town; the text stays on the record. - **The primary address.** Show it first and in the list marked, or treat all alike. **Recommended: mark it in the list and treat all alike on the drawing**; the question the map answers is where the search is spread. - **How many pins.** No limit today on addresses per holder. **Recommended: leave it, and draw at most one dot per place however many addresses it has**, which also bounds the drawing. ## Builds on Issues #92 (several addresses), #108 (the map's list-first rule), #329 (companies get addresses). #700 decides the engine and what may be drawn; #702 places an address. ## Done when - `tests/test_company_map.py`: a company with two pinned addresses in two towns appears at both with a count of one each; two spellings of one town are one place; a company with no pinned address still uses its text; the totals sentence is present only when it is true; a second owner's addresses never appear. - The page still passes axe in both themes (`tests/e2e/test_accessibility.py:471` visits it, and `tests/test_page_coverage.py` holds every URL to that list) and works with scripts off. - No new stored data beyond #702's, so no archive bump here. New strings are in the working catalogues (en-GB, fr-FR, pt-PT as drafts) and Weblate (#349); the wiki's *Configuration* page, which describes the map (`Configuration.md:114-115`), is updated. From the list of improvements of 2026-10-02.
tiagoagueda added this to the 1.0.0 milestone 2026-10-03 01:59:12 +00:00
Author
Owner

From the maintainer's improvements list of 2026-10-07: every company is a pin on the map. Today one dot per place, sized by how many companies are there (jobs/views.py:153-226); this issue already moves grouping from the location text to the resolved coordinate. The request reads as one marker per company — at a zoom where companies at one place are distinguishable, a cluster otherwise (Leaflet's own clustering is a plugin; #700 vendors Leaflet only). Recommended: one marker per company inside each place's cluster, the cluster count as today. The full-window map and the location button are filed as their own issues. Checked against main at 8c3d03570.

From the maintainer's improvements list of 2026-10-07: **every company is a pin on the map**. Today one dot per place, sized by how many companies are there (`jobs/views.py:153-226`); this issue already moves grouping from the location text to the resolved coordinate. The request reads as one marker per company — at a zoom where companies at one place are distinguishable, a cluster otherwise (Leaflet's own clustering is a plugin; #700 vendors Leaflet only). Recommended: one marker per company inside each place's cluster, the cluster count as today. The full-window map and the location button are filed as their own issues. Checked against `main` at `8c3d03570`.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#703
No description provided.