// Resolves the physical label size (mm) for a CUPS queue. // // Order of truth: // 1. App printer registry (iDempiere `CUST_Printer`, columns LabelWidthMm / // LabelHeightMm, maintained at Settings → Printers) — matched by CupsName. // 2. The CUPS queue's own default PageSize (see cupsMedia.ts). // 3. null → caller keeps its legacy page format. // // The registry columns may not exist yet: the read is done WITHOUT `$select` // (a missing column would 400) and any error degrades to an empty map. import fetchHelper from './fetchHelper' import getTokenHelper from './getTokenHelper' import { getQueueMediaMm, type MediaMm } from './cupsMedia' export interface ResolvedMedia extends MediaMm { source: 'registry' | 'cups' /** Label product identification (CUST_Printer.LabelType), registry only. */ labelType?: string } export interface RegistryLabelInfo extends MediaMm { labelType: string } const CACHE_TTL = 5 * 60 * 1000 const registryCache = new Map; ts: number }>() const num = (v: any): number => { const n = Number(v) return Number.isFinite(n) && n > 0 ? n : 0 } /** Registry label sizes keyed by CUPS queue name for the current org (+ org 0). */ export const getRegistryLabelSizes = async (event: any): Promise> => { const organizationId = getCookie(event, 'logship_organization_id') || '0' const hit = registryCache.get(organizationId) if (hit && Date.now() - hit.ts < CACHE_TTL) return hit.value const map = new Map() try { const token = await getTokenHelper(event) const filter = `(AD_Org_ID eq ${organizationId} or AD_Org_ID eq 0) and IsActive eq true` const res: any = await fetchHelper(event, `models/cust_printer?$filter=${encodeURIComponent(filter)}`, 'GET', token, null) const records: any[] = Array.isArray(res?.records) ? res.records : [] for (const r of records) { const cups = String(r?.CupsName ?? r?.cupsName ?? r?.cupsname ?? '').trim() if (!cups) continue const w = num(r?.LabelWidthMm ?? r?.labelWidthMm ?? r?.labelwidthmm) const h = num(r?.LabelHeightMm ?? r?.labelHeightMm ?? r?.labelheightmm) if (!w || !h) continue const labelType = String(r?.LabelType ?? r?.labelType ?? r?.labeltype ?? '').trim() const orgId = Number(r?.AD_Org_ID?.id ?? r?.AD_Org_ID ?? 0) // Org-specific row wins over the shared (org 0) row for the same queue. const existing = map.get(cups) as any if (existing && existing._orgId !== 0 && orgId === 0) continue map.set(cups, Object.assign({ w, h, labelType }, { _orgId: orgId }) as any) } } catch (err: any) { console.warn(`[labelMedia] registry read failed: ${err?.message || err}`) } registryCache.set(organizationId, { value: map, ts: Date.now() }) return map } export const clearRegistryLabelCache = () => { registryCache.clear() } /** Registry size → CUPS default → null. */ export const resolveLabelMedia = async (event: any, queue: string): Promise => { const q = String(queue || '').trim() if (!q) return null const registry = await getRegistryLabelSizes(event) const reg = registry.get(q) if (reg) return { w: reg.w, h: reg.h, source: 'registry', labelType: reg.labelType || undefined } const cups = await getQueueMediaMm(q) if (cups) return { w: cups.w, h: cups.h, source: 'cups' } return null }