Draw a dual-bay secondary where it actually is, and make two counts add up

Three map and aggregation defects. The first is a behaviour change you asked
for; the other two are the 2026-09-03 run's findings.

A dualpath secondary bay was excluded from /api/assets/map unconditionally
while the collapse setting is on, so positioning it was a silent no-op: the
form took the pin, stored mapx/mapy, and the map never drew it. One marker per
pair is right when the pair sits in one place, and that stays the default - but
a dual-bay machine whose second bay is physically elsewhere is exactly what
positioning it separately means. Now: a secondary with its own position draws
its own marker; one without is represented by the primary's, which carries the
combined '2007 / 2008' label. Nothing extra is needed for the fallback, because
the feed already requires mapx/mapy - an unpositioned bay never reaches the
loop.

The combined label is now suppressed when the partner draws its own marker.
Labelling two separate pins '2007 / 2008' would say one machine is in two
places, which is worse than either bay being unlabelled.

Verified against a live instance: unpositioned secondary gives one marker
labelled with both bays; positioned gives two markers each with its own name;
clearing the position puts it back to one. That third case matters - a
one-way door would be its own bug.

machines/dashboard/summary applied the dualpath exclusion to total and bytype
but not to bystatus, so the status bars summed to more than the headline above
them, by exactly the number of secondary bays. A breakdown that does not add up
to its own total is an afternoon of reconciling.

The measuring-tool calibrationstatus filter ran AFTER pagination. It is a
derived value so it cannot be a SQL filter, but applying it to the current
page meant asking for 'overdue' with one overdue tool in sixteen returned an
empty page 1, a total of 16, eight pages, and the row itself on page 3. When
that filter is in play the matching set is now built and filtered before
paging - the same tradeoff the old comment named, spent on correct answers
instead of a cheaper query.

Seven tests. The pagination one verified against the committed version, which
fails it.

Scope: product
This commit is contained in:
cproudlock
2026-09-03 15:07:49 -04:00
parent 1d2bbb3630
commit b1e5dd734d
5 changed files with 197 additions and 23 deletions

View File

@@ -1012,17 +1012,26 @@ def get_assets_map():
Asset.mapy.isnot(None)
)
# Dualpath single-machine collapse: hide the secondary bay marker so a
# dual-bay pair shows one marker; the primary carries the partner label.
# Gated on the site setting (default on).
# Dualpath single-machine collapse on the map: a secondary bay draws its
# OWN marker when somebody has positioned it, and is represented by the
# primary's marker when nobody has.
#
# It used to be excluded unconditionally, which made setting a position on
# a secondary bay a silent no-op: the form accepted the pin, stored it, and
# the map never drew it. One marker per pair is right when the pair sits in
# one place, which is the common case and still the default - but a
# dual-bay machine whose second bay is physically somewhere else is exactly
# what positioning it separately means.
#
# No extra filtering is needed for the fallback half: the query above
# already requires mapx/mapy, so an unpositioned secondary never reaches
# here and the primary's marker stands for both, carrying the combined
# label.
from shopdb.core.services.dualpath import (
resolve_dualpath_pairs, dualpath_single_machine_enabled)
dualpath_collapse = None
if dualpath_single_machine_enabled():
dualpath_collapse = resolve_dualpath_pairs()
if dualpath_collapse.secondaryassetids:
query = query.filter(
Asset.assetid.notin_(dualpath_collapse.secondaryassetids))
selected_assettype = request.args.get('assettype')
@@ -1102,6 +1111,10 @@ def get_assets_map():
assets = query.all()
# Every asset that ends up with a marker. Used to decide whether a dual-bay
# partner draws its own pin or is represented by this one.
positioned_assetids = {asset.assetid for asset in assets}
# Batch-load primary IPs in a single query instead of N+1 per asset.
# Prefer isprimary=True IP, fall back to any IP (comtypeid=1).
asset_ids = [a.assetid for a in assets]
@@ -1153,10 +1166,17 @@ def get_assets_map():
if type_data:
item['typedata'] = type_data
# combined-label partner for a collapsed dual-bay pair (label only)
# Combined label for a dual-bay pair, and ONLY when this marker really
# stands for both bays. A partner that draws its own marker gets its
# own name: labelling two separate pins '2007 / 2008' would say the
# same machine is in two places.
if dualpath_collapse:
partner = dualpath_collapse.partnerbyasset.get(asset.assetid)
item['dualpathpartner'] = partner['assetnumber'] if partner else None
partner_has_marker = bool(
partner and partner['assetid'] in positioned_assetids)
item['dualpathpartner'] = (
partner['assetnumber'] if partner and not partner_has_marker
else None)
data.append(item)