Work-order codes no longer overlap (#42), Materials before Heat map (#44), 60 min idle for Admin and Clerical (#45)
- Traveler: each work-order line shrinks, then clips, to fit its own box; 18 pt gap between boxes - Work orders tab: card text wraps inside the card, smaller work order, wider cards - Packet tabs: Materials before Heat map - Sessions: SESSION_DESK_MINUTES (60) for Admin and Clerical lock and sign-out; /me answers lock_minutes and the browser's idle lock follows it Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -17,16 +17,30 @@ from pypdf import PdfReader, PdfWriter
|
||||
from reportlab.graphics import renderPDF
|
||||
from reportlab.graphics.barcode.qr import QrCodeWidget
|
||||
from reportlab.graphics.shapes import Drawing
|
||||
from reportlab.pdfbase.pdfmetrics import stringWidth
|
||||
|
||||
from . import parts, stamps
|
||||
from .databook import heats_for
|
||||
from .doc import Doc
|
||||
from .doc import Doc, font_of
|
||||
from .style import CW, GREY, LINE, Built, L, PdfError, R, WhoRef, clean, fmt_d, fmt_dt, fmt_num, site_tz, utc_now
|
||||
|
||||
BLANK = "________"
|
||||
BLANK_LONG = "________________"
|
||||
QR_BOX_H = 96.0
|
||||
QR_SIZE = 84.0
|
||||
QR_GAP = 18.0 # between work-order boxes: a quiet zone so the kiosk scanner reads one code at a time
|
||||
|
||||
|
||||
def fit_line(s: Any, width: float, size: float, *, bold: bool = False) -> tuple[str, float]:
|
||||
"""One line that fits `width` (issue #42): shrink down to 70% of `size`, then cut with "..."."""
|
||||
text, font, z = clean(s), font_of(bold), size
|
||||
while z - 0.5 >= size * 0.7 and stringWidth(text, font, z) > width:
|
||||
z -= 0.5
|
||||
if stringWidth(text, font, z) > width:
|
||||
while len(text) > 1 and stringWidth(text + "...", font, z) > width:
|
||||
text = text[:-1]
|
||||
text += "..."
|
||||
return text, z
|
||||
|
||||
|
||||
def qr_text(wo: Mapping[str, Any]) -> str:
|
||||
@@ -150,32 +164,38 @@ def _draw(conn: Any, settings: Any, p: Mapping[str, Any]) -> Doc:
|
||||
y += 16
|
||||
y = d.section_label("Work orders - scan at the labor kiosk to clock on in Visual", y)
|
||||
wos = p.get("work_orders") or []
|
||||
bw = (CW - 12) / 2
|
||||
bw = (CW - QR_GAP) / 2
|
||||
for i, w in enumerate(wos):
|
||||
col = i % 2
|
||||
if col == 0:
|
||||
y = d.ensure_space(y, QR_BOX_H + 8)
|
||||
x = L + col * (bw + 12)
|
||||
y = d.ensure_space(y, QR_BOX_H + QR_GAP)
|
||||
x = L + col * (bw + QR_GAP)
|
||||
d.rect(x, y, bw, QR_BOX_H, stroke=LINE, width=0.8)
|
||||
draw_qr(d, qr_text(w), x + 6, y + 6, QR_SIZE)
|
||||
tx0 = x + QR_BOX_H + 2
|
||||
d.tx(w.get("wo_base") or "", tx0, y + 20, size=12, bold=True)
|
||||
d.tx(
|
||||
f"Lot {w.get('lot') or ''} Seq {'' if w.get('seq') is None else w.get('seq')} {w.get('op') or ''}",
|
||||
tx0,
|
||||
y + 36,
|
||||
size=8.5,
|
||||
)
|
||||
d.tx(f"Target {fmt_num(w.get('target_hrs'))} h Qty {fmt_num(w.get('qty'))}", tx0, y + 50, size=8.5)
|
||||
d.tx(
|
||||
f"Drawing {w.get('dwg') or p.get('drawing') or ''} Rev {w.get('rev') or p.get('rev') or ''}",
|
||||
tx0,
|
||||
y + 64,
|
||||
size=7.5,
|
||||
color=GREY,
|
||||
)
|
||||
tx0, tw = x + QR_BOX_H + 2, bw - QR_BOX_H - 8 # text stays inside its own box
|
||||
lines: list[tuple[str, float, float, bool, Any]] = [
|
||||
(w.get("wo_base") or "", 20, 12, True, None),
|
||||
(
|
||||
f"Lot {w.get('lot') or ''} Seq {'' if w.get('seq') is None else w.get('seq')} {w.get('op') or ''}",
|
||||
36,
|
||||
8.5,
|
||||
False,
|
||||
None,
|
||||
),
|
||||
(f"Target {fmt_num(w.get('target_hrs'))} h Qty {fmt_num(w.get('qty'))}", 50, 8.5, False, None),
|
||||
(
|
||||
f"Drawing {w.get('dwg') or p.get('drawing') or ''} Rev {w.get('rev') or p.get('rev') or ''}",
|
||||
64,
|
||||
7.5,
|
||||
False,
|
||||
GREY,
|
||||
),
|
||||
]
|
||||
for s, dy, size, bold, color in lines:
|
||||
text, z = fit_line(s, tw, size, bold=bold)
|
||||
d.tx(text, tx0, y + dy, size=z, bold=bold, **({"color": color} if color else {}))
|
||||
if col == 1 or i == len(wos) - 1:
|
||||
y += QR_BOX_H + 8
|
||||
y += QR_BOX_H + QR_GAP
|
||||
if not wos:
|
||||
y = d.note_box("No work orders were read from this packet.", y, True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user