Add printer installer endpoint (data + floor-map positions)

Shopfloor 2.0 PCs can't run unsigned .bat printer maps, so the signed printer
installer EXE pulls printer data + floor-map positions from the API and renders
the picker itself. Adds the endpoint the EXE consumes.

GET /api/printers/install-list - flat, unpaginated list of NETWORK printers
(USB-only excluded), each with: printerid, name, machinenumber, windowsname,
sharename, hostname, ipaddress, vendorname, modelnumber, installpath, iscsf,
locationname, mapx, mapy. Replaces the classic apiprinters.asp contract and
adds the map position (mapx/mapy) the EXE needs.

Tests: network printer appears with map position + installer fields; USB-only
printer excluded. 188 tests pass, naming green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-06-26 21:51:59 -04:00
parent 10ed83e14c
commit 85f98e87cb
2 changed files with 95 additions and 0 deletions

View File

@@ -188,6 +188,53 @@ def list_printers():
return paginated_response(data, page, per_page, total)
@printers_asset_bp.route('/install-list', methods=['GET'])
@jwt_required(optional=True)
def printer_install_list():
"""Flat, unpaginated list of network printers for the printer installer.
Shopfloor 2.0 PCs cannot run unsigned .bat maps, so the signed installer EXE
pulls printer data + floor-map positions from here and renders the picker.
Replaces the classic apiprinters.asp contract, adding mapx/mapy. Network
printers only (USB-only printers are excluded).
"""
rows = []
query = db.session.query(Printer).join(Asset).filter(Asset.isactive == True)
for printer in query.all():
asset = printer.asset
if not asset:
continue
primary = Communication.query.filter_by(
assetid=asset.assetid, isprimary=True).first() \
or Communication.query.filter_by(assetid=asset.assetid).first()
ipaddress = primary.ipaddress if primary else None
# Network printers only: must have a hostname or a non-USB IP.
is_network = bool(printer.hostname) or (ipaddress and ipaddress != 'USB')
if not is_network:
continue
data = printer.to_dict()
rows.append({
'printerid': printer.printerid,
'name': asset.name or asset.assetnumber,
'machinenumber': asset.assetnumber,
'windowsname': printer.windowsname,
'sharename': printer.sharename,
'hostname': printer.hostname,
'ipaddress': ipaddress,
'vendorname': data.get('vendorname'),
'modelnumber': data.get('modelname'),
'installpath': printer.installpath,
'iscsf': printer.iscsf,
'locationname': asset.location.locationname if asset.location else None,
'mapx': asset.mapx,
'mapy': asset.mapy,
})
return success_response(rows)
@printers_asset_bp.route('/<int:printer_id>', methods=['GET'])
@jwt_required(optional=True)
def get_printer(printer_id: int):