Repository navigation
feat: scan printed labels back into InvenTree, and print its short code on them - #10
Merged
Merged
Conversation
…de on them Every label this driver prints carries a QR with the agent's short link, e.g. https://sngn.top/i/SI1. Phones open it fine, but InvenTree's own scanner only knows its native short format (INV-SI1) and answers "No match found". Linking barcodes one item at a time is not a fix. Add LabelfabShortlink, a BarcodeMixin plugin shipped in the same package. It strips the configured base, rebuilds INV-SI1 and passes it to the builtin InvenTreeBarcode plugin, so model codes, permissions and the response shape stay InvenTree's. Matching ignores scheme and case, so labels printed earlier as SNGN.TOP/I/PA39 resolve too. An empty base keeps the plugin inert. Label text now leads with the short barcode and IPN ("INV-SI1 · A1533") and puts the name underneath, so a label whose QR will not scan can still be typed in. The prefix comes from the instance's SHORT_BARCODE_PREFIX. Part labels use name instead of full_name, which already embeds the IPN. Stock items drop the location and only show a quantity for bulk stock, formatted without Decimal's trailing zeros (was 1.00000).
impuls42
added a commit
to sengine-cloud/labelfab
that referenced
this pull request
Sep 25, 2026
A title of `INV-SI1` on the stock item preset at 12mm prints as `INV-SI`. The `1` is past the right edge. `_wrap` has `if not current or font.getlength(trial) <= width`, so the first word of each paragraph goes in without being measured. Multi-word titles get checked from the second word on, which is why this hasn't shown up before. A single word never is, so `_fit`'s binary search only has height to satisfy and climbs to `max_pt`. `_fit(120, 60)` on `INV-SI1` returned one line at 45px, which is exactly 16pt, in a 120px box. Measuring the first word fixes that and exposes a second problem. `_wrap` splits an over-long word at the pixel boundary, so in a box tall enough for two lines, `INV-S` / `I1` at a big size passes the fit and beats a smaller size that keeps the word whole. For codes that's worse than small text, since a split code reads as two codes. `_fit` now runs the search with word splitting off first, and only falls back to splitting when nothing fits otherwise. `measure()` also stops reporting a natural width narrower than the longest word. The existing tests couldn't catch any of this. `test_very_long_text_is_truncated_not_overflowed` only asserts the image size, which is fixed by construction. `test_text_stays_inside_the_canvas` only checks the top row for ink. The new tests look at line widths and at the right edge. Mutation check, same four tests: - code on main: all 4 fail - first-word fix only, without the whole-words-first search: `test_a_word_is_kept_whole_when_a_smaller_size_fits` fails - this PR: all pass, full suite 275 passed Found while laying out labels for sengine-cloud/inventree-label-dispatch#10, which puts `INV-SI1`-style codes in the title. A part without an IPN gets a title that is just `INV-PA12`, a single word.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
InvenTree's scanner answers "No match found" for every label this driver prints. The QR holds the agent's short link (
https://sngn.top/i/SI1), which a phone opens fine, but InvenTree only resolves its own short format (INV-SI1). Linking barcodes item by item worked for one label and does not scale, so this fixes it on the InvenTree side instead.Scanning
LabelfabShortlinkis aBarcodeMixinplugin registered next to the machine driver. It strips the configured base, rebuildsINV-SI1and hands that to the builtinInvenTreeBarcodeplugin'sscan(). So there's no model table here to drift: codes, permissions and the response shape all come from InvenTree. It needs one setting, Short link base, set to the agent'srender.qr_base_url. Empty means inert.Scheme and case are ignored when matching. That matters because two labels are already out in the world as
SNGN.TOP/I/PA39(bare, uppercase) from before the agent switched tohttps://sngn.top/i/, and both forms should resolve.The parsing sits in
shortlink.pywith no InvenTree imports, same split asdispatch/extractorsvsdriver, so it's unit-tested.barcode.pyis the thin shim.Label text
The title now leads with the short barcode and IPN, with the name underneath:
INV-SI1can be typed into InvenTree's scanner as is, so a label still works when its QR doesn't. The prefix is read from the instance'sSHORT_BARCODE_PREFIXonce per batch. Parts usenamerather thanfull_name, sincefull_nameis already "IPN | name" and printed the IPN twice. Stock items drop the location (it goes stale the moment something moves) and only print a quantity for bulk stock, without Decimal's trailing zeros.Checked
python:3.9-slim), since CI only runs 3.12 and the package claims 3.9.str.removeprefixis the newest thing used and landed in 3.9.startswithguard inparse()disabled,test_rejects[SI1]fails, so the guard is actually covered.INV-SI1andINV-PA39resolve through the builtin today,inv-si1andSI1don't. That's why the plugin uppercases and adds the prefix before delegating.After deploy: activate LabelfabShortlink and set its base to
https://sngn.top/i/.