Commit Graph

889 Commits

Author SHA1 Message Date
gsinghpal
13fd0712d9 docs(fusion_plating): add Promote Customer Spec design + implementation plan
- Spec: retire fp.coating.config + fp.treatment, promote fusion.plating.customer.spec
- Two-picker SO line UX (Specification + Recipe), aerospace-correct audit posture
- Plan: 5 phases (foundation, SO line, pricing/quality/job/cert, reports/tablet/portal, removal)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 00:23:22 -04:00
gsinghpal
1414ef2c1c fix(fusion_clock): NFC kiosk header — center logo at top, stack clock+date below 2026-05-14 08:42:26 -04:00
gsinghpal
42e8fe3d21 fix(fusion_clock): NFC kiosk — subtle logo glass, centered clock, AM/PM 2026-05-14 08:38:25 -04:00
gsinghpal
bad73fcea8 fix(fusion_clock): NFC kiosk visual polish — bigger chip, uncut waves, logo glass pill, no clock collision 2026-05-14 08:29:33 -04:00
gsinghpal
94249ba67d feat(fusion_clock): premium glass NFC kiosk + scope CSS to kiosk page
Visual rewrite of the NFC kiosk page:
- Animated mesh gradient background (drifts on a 28s loop)
- Glass-panel state cards with backdrop-filter blur
- Animated SVG NFC icon (concentric waves emanate from a chip)
- Company logo pulled from res.company.logo, displayed in header
- Dominant-hue extraction from logo sets --nfc-h CSS var; entire
  palette interpolates from that one HSL hue
- Success burst (green glow + scale), error shake, smooth state fades
- Reduced-motion fallback respects prefers-reduced-motion
- Glass numpad + employee picker in Enroll Mode

CRITICAL FIX: scoped all kiosk styles under :has(#nfc_kiosk_root) so
they no longer leak into other frontend pages. Previous version applied
html/body overflow:hidden + display:none on header/footer globally,
breaking website scrolling and chrome on every frontend page.
2026-05-14 08:22:47 -04:00
gsinghpal
2abd859a29 feat(fusion_clock): NFC kiosk Wake Lock to keep screen on while active 2026-05-14 08:09:27 -04:00
gsinghpal
98cb42d2e5 feat(fusion_clock): NFC kiosk on-screen debug overlay + clearer settings label 2026-05-14 08:03:47 -04:00
gsinghpal
878d05685c fix(fusion_clock): split min(80vw,700px) into width+max-width to avoid Sass unit error 2026-05-14 07:23:49 -04:00
gsinghpal
bd2c037a97 Update 2026-05-13-nfc-clock-kiosk-plan.md 2026-05-14 07:07:45 -04:00
gsinghpal
44636e47fb chore(fusion_clock): bump version to 19.0.3.0.0 for NFC kiosk feature 2026-05-14 01:32:07 -04:00
gsinghpal
06c49ecec6 feat(fusion_clock): NFC kiosk mock-tap debug shortcut
Add Ctrl+Shift+T keyboard shortcut (guarded by debugEnabled / nfc_kiosk_debug
setting) that prompts for a UID and fires _onEnrollTap or handleTap depending
on currentState (ENROLL vs IDLE). Persists last-used UID in localStorage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 01:30:35 -04:00
gsinghpal
37deaedf0d feat(fusion_clock): NFC kiosk Enroll Mode UI
Replaces the Task 18 stub renderEnroll with the full four-phase
implementation (password numpad → employee picker → tap-to-enroll →
result), adds _onEnrollTap wired to the NFC reading event, and exposes
it via window.__nfcKiosk.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 01:28:36 -04:00
gsinghpal
30f7f18472 feat(fusion_clock): camera capture on NFC kiosk
Replace camera stub with real getUserMedia + canvas capture. Setup button
now starts NFC reader and camera together; camera failure is non-fatal when
photo is not required.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 01:25:12 -04:00
gsinghpal
66e9749853 feat(fusion_clock): Web NFC integration on kiosk page
Adds NDEFReader scan loop, onNfcReading tap dispatcher, handleTap
state machine, postJson helper, capturePhoto stub (Task 17), and
setup wizard activation with error display.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 01:22:55 -04:00
gsinghpal
c9be68a575 feat(fusion_clock): NFC kiosk JS scaffold + state machine + clock display
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 01:20:31 -04:00
gsinghpal
19d692afe7 feat(fusion_clock): NFC kiosk QWeb template with static chrome + setup wizard
Replace placeholder template with full version: static chrome (company,
clock, date, location, settings button), one-time setup wizard state,
hidden video/canvas for camera, and data-* attrs for JS feature flags.
Update test assertion from h1 text to nfc_kiosk_root id to match new markup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 01:18:04 -04:00
gsinghpal
0351dcd497 feat(fusion_clock): NFC kiosk SCSS (always-dark, high-contrast)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 01:14:14 -04:00
gsinghpal
03fd3d7c1c feat(fusion_clock): NFC kiosk employee search endpoint
Add /fusion_clock/kiosk/nfc/employee_search that delegates to the
existing kiosk_search method, avoiding logic duplication. Adds
TestEmployeeSearch HttpCase (33 tests total, all passing).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 01:11:28 -04:00
gsinghpal
f4c9ed3d24 feat(fusion_clock): NFC tap photo capture + photo-required gate
- Add _strip_data_url_prefix() helper to clean data-URL prefix from base64 photo payloads
- Gate nfc_tap on fusion_clock.nfc_photo_required ICP param (default True): rejects with error='photo_required' when photo absent
- Write x_fclk_check_in_photo / x_fclk_check_out_photo on clock-in/out attendance records
- Add TestTapPhotoHandling (3 tests): photo saved, required-rejects-missing, optional-succeeds-without

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 01:09:27 -04:00
gsinghpal
ef885c66dc feat(fusion_clock): NFC tap endpoint debounce + 6 error-case tests
Adds module-level 5s debounce (_is_debounced) with thread-safe dict +
GC. Inserts debounce guard in nfc_tap immediately after uid validation.
Adds TestTapEndpointErrors (6 tests): unknown_card, clock_disabled,
no_location_configured, kiosk_disabled, invalid_uid, debounce.
Adds setUp() to both tap test classes to clear _recent_taps between
tests, preventing cross-test debounce bleed. 29/29 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 01:06:30 -04:00
gsinghpal
148aa5cba8 feat(fusion_clock): NFC tap endpoint (happy path)
Add /fusion_clock/kiosk/nfc/tap JSON-RPC endpoint that toggles attendance
via _attendance_action_change, writing x_fclk_clock_source='nfc_kiosk' and
location on clock-in, applying break deduction/penalty checks on clock-out.
Add 2 HttpCase tests (clock-in + clock-out with 6s debounce sleep).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 01:02:49 -04:00
gsinghpal
661c8ae227 feat(fusion_clock): NFC card enrollment endpoint
Adds /fusion_clock/kiosk/nfc/enroll (jsonrpc, auth=user) that validates
the enroll password, normalises the card UID, checks for duplicate
assignments, writes x_fclk_nfc_card_uid, and creates a card_enrollment
activity log entry. 4 new tests; 21 total passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 00:58:25 -04:00
gsinghpal
a24a1ddf1a feat(fusion_clock): NFC card UID normalization helper
Add _normalize_uid static method to FusionClockNfcKiosk that strips
whitespace, uppercases, removes separators, validates hex-only content,
and reformats to canonical colon-separated pairs; returns None for
empty/invalid input. Covered by 7 new TransactionCase unit tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 00:56:02 -04:00
gsinghpal
f05cacec22 feat(fusion_clock): NFC kiosk page render route
Controller scaffold with GET /fusion_clock/kiosk/nfc, placeholder QWeb
template, and HttpCase tests (10 pass, 0 failures). Fixed Odoo 19
res.users create API: groups_id -> group_ids.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 00:53:03 -04:00
gsinghpal
9239ee2822 feat(fusion_clock): add NFC Clock Kiosk settings block
Extends res.config.settings with 5 NFC kiosk fields (enable toggle,
photo required, enroll password, debug mode, kiosk location via
related company field) and adds the corresponding settings view block
with conditional sub-fields hidden until the kiosk is enabled.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 00:45:41 -04:00
gsinghpal
4733885211 feat(fusion_clock): add NFC kiosk ir.config_parameter defaults
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 00:43:07 -04:00
gsinghpal
8e708bf2c4 fix(fusion_clock): NFC kiosk location domain + test isolation
Add domain filter on x_fclk_nfc_kiosk_location_id so the dropdown
only shows locations belonging to the current company in multi-company
setups. Replace shared-company mutation in test with a fresh company
to prevent cross-test state leakage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 00:40:28 -04:00
gsinghpal
caf240daec feat(fusion_clock): add NFC kiosk location to res.company
Adds x_fclk_nfc_kiosk_location_id (Many2one → fusion.clock.location) to
res.company so each company can designate which NFC kiosk location it uses.
Two tests cover field assignment and default-false behaviour.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 00:36:56 -04:00
gsinghpal
4bed8ab2c5 fix(fusion_clock): reorder NFC kiosk source before System per plan
Move ('nfc_kiosk', 'NFC Kiosk') to sit between kiosk and system in the
source Selection field, matching the spec's semantic grouping of
interactive sources before the automated system source.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 00:34:36 -04:00
gsinghpal
50c209b8d3 feat(fusion_clock): NFC kiosk attendance fields + activity-log selections
- Add 'nfc_kiosk' to x_fclk_clock_source selection on hr.attendance
- Add x_fclk_check_in_photo and x_fclk_check_out_photo Binary fields (attachment=True)
- Add 'card_enrollment' and 'unknown_card_tap' to activity log log_type selection
- Add 'nfc_kiosk' to activity log source selection
- Add TestNfcAttendanceFields test class (3 tests); all 6 fusion_clock tests pass

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 00:24:35 -04:00
gsinghpal
65a1c4b17e fix(fusion_clock): remove unused ValidationError import in NFC tests 2026-05-14 00:19:20 -04:00
gsinghpal
91d3a3f9d1 docs(fusion_clock): use actual docker env names (odoo-modsdev-app/modsdev) in NFC plan 2026-05-14 00:14:51 -04:00
gsinghpal
70f855d91b feat(fusion_clock): add x_fclk_nfc_card_uid to hr.employee
Adds the NFC card UID field (Char, unique, manager-only) that the kiosk
will use to identify employees by card tap. Includes the tests package
with three post-install tests covering write, uniqueness, and nullable
multi-row behaviour.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 00:13:26 -04:00
gsinghpal
85eddba546 docs(fusion_clock): NFC clock kiosk implementation plan
20-task TDD plan for the NFC clock kiosk feature spec'd in
2026-05-13-nfc-clock-kiosk-design.md. Bite-sized steps with full code
in each, ordered: data model -> config -> backend endpoints ->
SCSS+template -> JS state machine -> NFC + camera -> Enroll Mode ->
debug shortcut -> version bump.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 00:05:23 -04:00
gsinghpal
48d3e48e61 docs(fusion_clock): NFC clock kiosk design
Design for tap-to-clock NFC kiosk in fusion_clock. Pilot scope: 1
station per company, Samsung Galaxy Tab Active 5 Pro running Web NFC
in Chrome kiosk mode. Reuses Ubiquiti-issued cards. Silent photo
verification via front camera. Backend reuses FusionClockAPI helpers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 23:50:00 -04:00
gsinghpal
f07e1bcce1 fix(chatter): wrap HTML message_post bodies in Markup() — 4 sites
Four message_post calls were passing strings with HTML tags as
plain `body=_(...)` instead of `body=Markup(_(...))`. Odoo escapes
non-Markup strings, so the chatter rendered "<b>QA Review failed</b>"
as literal text instead of bolding it.

Original bug surfaced via the Contract Review (QA-005) flow:
  body: "&lt;b&gt;QA Review failed&lt;/b&gt; by Garry Singh. Awaiting
  client information.&lt;br/&gt;&lt;b&gt;Reason:&lt;/b&gt;&lt;br/&gt;
  &lt;div data-oe-version=\"2.0\"&gt;Need to get updated
  drawing...&lt;/div&gt;"

Audit scan turned up three more identical patterns:

  fusion_plating/models/fp_parent_numbered_mixin.py:118
     "Issued <strong>%s</strong> to ..."
  fusion_plating_jobs/models/sale_order.py:282
     "Confirmed quote <strong>%s</strong> as <strong>%s</strong>."
  fusion_plating_quality/models/fp_contract_review.py:430
     "<b>QA Review failed</b> by ... <b>Reason:</b><br/>%(reason)s"
  fusion_plating_quality/models/fp_contract_review.py:524
     "<b>QA Review completed</b> by ... <b>Special Instructions
      captured:</b><br/>%(notes)s"

Fixes:
- Wrapped each body=_(...) with Markup(_(...)) using the
  Markup(template) % values pattern (auto-escapes the substituted
  values; user-supplied free text stays safe).
- For Html-field substitutions (qa_failure_reason,
  special_instructions), explicitly wrapped the value in Markup()
  so already-formatted HTML editor content (with data-oe-version="2.0"
  wrapper divs) flows through without being re-escaped.
- Added `from markupsafe import Markup` to the two files that
  didn't already import it (mixin + contract_review).

Drift cleanup: pulled the 180-line newer fp_contract_review.py
from entech to the local repo (added action_qa_review_failed,
action_open_client_email_wizard, action_view_client_emails,
action_complete_after_info, awaiting_info state, qa_failure_reason
+ special_instructions Html fields, etc. that had been edited on
entech without being committed).

Tested by re-posting via odoo shell on review 10: body now stores
"<b>QA Review failed</b>..." with literal HTML tags instead of
the double-escaped "&lt;b&gt;..." entities. Old chatter records
with the bad escape stay as-is in the audit trail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 08:41:39 -04:00
gsinghpal
e7c6960de9 feat(sticker): restore customer-name secrecy cover (ABC-MANU)
Body Customer row now prints a 3-and-4 short code instead of the
full company name. Operators see "ABC-MANU" on the floor; visiting
customers / unauthorised passers-by can't immediately tell whose
parts are on which rack.

Rule (per user's reference design):
  - First 3 chars of first word + "-" + first 4 chars of second word
  - Single-word names → just first 3 chars
  - All uppercase
  - Strips non-alphanumeric per word so "St. John's Mfg." doesn't
    leak punctuation into the slice

Logic lives in the shared inner template, so all 4 variants pick
it up automatically:
  sale.order     External + Internal Sticker
  fp.job         External + Internal Job Sticker

Verified on fp.job 2635: Customer row now reads "ABC-MANU" (was
"ABC Manufactoring").

Doesn't use the orphaned x_fc_short_code field on res.partner
(that field has no column or compute — broken Studio remnant).
A future spec can replace this inline computation with a proper
stored+inverse field if customers want per-partner overrides.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 08:24:07 -04:00
gsinghpal
ad64b0b4c9 changes 2026-05-13 08:17:35 -04:00
gsinghpal
cd763fa1d7 chore(sticker): rename External action labels for the variant split
Print menu now shows External + Internal as paired entries:

  sale.order:  External Sticker      / Internal Sticker
  fp.job:      External Job Sticker  / Internal Job Sticker

XML IDs unchanged (action_report_fp_so_sticker /
action_report_fp_job_sticker) so existing bookmarks and
binding_model_id records keep working. print_report_name strings
also updated so the downloaded filename matches the new label.

DB verification:
  fp.job      | External Job Sticker
  fp.job      | Internal Job Sticker
  sale.order  | External Sticker
  sale.order  | Internal Sticker

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 08:07:50 -04:00
gsinghpal
f40f44aafd feat(sticker): add Internal Job Sticker variant on fp.job Print menu
Mirror of the SO Internal variant for fp.job. Same body fields,
same per-box loop; Notes column reads x_fc_internal_description
from the first linked SO line (job.sale_order_line_ids[:1]).
Operator on the shop floor sees ops-internal notes without those
ever appearing on the customer-facing External sticker.

Verified on fp.job 2635 with seeded internal_description: Notes
column reads "INTERNAL JOB: handle with care, no rework on this
batch" — confirms the Job Internal variant's override path mirrors
the SO Internal variant's.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 08:06:12 -04:00
gsinghpal
63bf271725 feat(sticker): add Internal Sticker variant on sale.order Print menu
Same 3-cell + body layout as External; Notes column reads
x_fc_internal_description (Sub 2 internal-description field on the
SO line) instead of line.name. Shop floor gets ops-facing notes
without leaking them to the customer-facing variant.

New action record action_report_fp_so_sticker_internal — binds to
sale.order, appears in the Print menu next to the existing External
sticker. New template report_fp_so_sticker_internal that pre-sets
_notes_content before t-calling the shared inner.

Verified on SO-30019 with a seeded internal_description: Notes
column reads "INTERNAL: rework if any dings on flange. Buff per
WI-104." — confirms the override path is wired through the
defaults-block initialiser, the inner's fallback chain, and the
new outer template.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 08:04:29 -04:00
gsinghpal
974b8a5152 feat(sticker): wire _qty_total in SO + Job External outers
Activates the per-box loop landed in the prior commit. SO External
reads line.product_uom_qty; Job External reads job.qty. Inner
template now renders one sticker per physical box, marking each
with "X / N" in the Qty row.

Verified on fp.job 2635 (qty temporarily set to 3): 3-page PDF
with Qty rows "1 / 3", "2 / 3", "3 / 3" — each page identical
otherwise (same WO#, same QR, same body fields).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 08:02:32 -04:00
gsinghpal
0a32ed2da7 feat(sticker): per-box render loop + Notes override hook
Inner sticker template gains two parameters that outer templates
pre-set:

  _qty_total — total qty for the line/job. Inner wraps the body
    in t-foreach="range(int(_qty_total or 1))" so a qty=5 line
    produces 5 consecutive single-box stickers. Qty row in the
    body switches from "5" to "1 / 5", "2 / 5", ... "5 / 5".
    When _qty_total is missing/0/1, the Qty row keeps showing
    the plain integer (regression-free).

  _notes_content — Notes column source. Existing inner code
    hard-read _line.name; new code accepts an outer override
    and falls back to _line.name. External outers don't set it
    (unchanged behaviour); the new Internal outers (Task 4+5)
    pre-set it to x_fc_internal_description.

Defaults template initialises both new vars to False so the
inner's "outer-supplied OR fallback" pattern doesn't NameError
when called from existing outers that haven't been updated yet.

Verified regression-free: fp.job 2635 (qty=1) renders identically
to its pre-Task baseline — Qty row shows plain "1", Notes from
line.name as before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 08:00:22 -04:00
gsinghpal
e4681a58c6 fix(jobs): split fp.jobs by thickness + serial on SO confirm
The _fp_auto_create_job grouping key was (recipe, part, coating).
Lines that shared all three but differed in thickness (or serial)
silently collapsed into one fp.job — the second line's thickness/SN
was lost, and any downstream cert printed the first line's values
across both batches. Silent mis-attestation = compliance hole.

Extended the key tuple to (recipe, part, coating, thickness, serial).
Single-line SOs and same-(thickness, SN) multi-line SOs collapse
identically to before. Only lines that previously merged when they
shouldn't have now split into their own fp.jobs.

TDD via test_so_confirm_splits_by_thickness:
  - seeds the part with default_process_id so both lines hit the
    `if recipe:` branch (where the bug lived — the no_recipe branch
    already split correctly per line)
  - confirms 2 jobs after action_confirm with each carrying its
    own thickness via the linked SO line

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 07:57:56 -04:00
gsinghpal
135cbd3a5c docs: implementation plan — sticker multi-part / per-box / Internal+External
7 tasks, bite-sized steps with exact code + commands. TDD on the
backend grouping change (new test_so_confirm_splits_by_thickness);
deploy-and-render-PDF on the QWeb template changes. Each task
self-contained, pushes to entech LXC 111 via the standard pct
exec + cat-pipe path, bumps the module version, and commits.

Task 7 is verification-only — creates a multi-line test SO with
two different thicknesses, renders External + Internal stickers
on both the SO and each spawned fp.job, confirms the box loop
and the Notes variant pattern both work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 07:47:40 -04:00
gsinghpal
3182ca3c39 docs: design spec — sticker multi-part / per-box / Internal+External
Three problems on the box-sticker stack rolled into one spec:

1. Backend: _create_fp_jobs grouping key collapses lines with
   different thicknesses or SNs into one job. Silent compliance
   hole. Fix: add thickness_id + serial_id to the key tuple.
2. No per-box stickers: a line with qty=5 prints 1 page showing
   "Qty: 5". Want 5 pages with "1 / 5", "2 / 5", ... "5 / 5".
3. No Internal variant: sticker always reads line.name (customer
   facing). Want a parallel variant that reads
   x_fc_internal_description (Sub 2 internal description field).

Renaming: existing actions keep their XML IDs (bookmarks /
binding_model_id records survive). Labels become:
  sale.order:  External Sticker      + Internal Sticker      (new)
  fp.job:      External Job Sticker  + Internal Job Sticker  (new)

All three changes share the same inner template, same files —
ship together. No data migration required; existing fp.jobs are
protected by the idempotency guard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 07:41:53 -04:00
gsinghpal
677e460438 fix(sticker): wire SN # + Thickness to the correct Sub 5 fields
The values were structurally blank because the variable
resolution was reading the wrong field names:

  Was:  _line.x_fc_serial_number    (doesn't exist)
        _line.x_fc_thickness        (doesn't exist)
  Now:  _line.x_fc_serial_id.name           (M2O fp.serial)
        _line.x_fc_thickness_id.display_name (M2O fp.coating.thickness)

Sub 5 shipped these as Many2one registries (fp.serial,
fp.coating.thickness) — the sticker was guessing at flat
Char-field equivalents that were never created.

Verified on SO-30019: SN # now prints "65767", Thickness now
prints "0.3-0.5 mils" (the en-dash in display_name mojibakes
to "â€"" through wkhtmltopdf's font path on entech, so we
replace en-dash + em-dash with ASCII hyphen-minus before
render — ASCII-only is what label printers want anyway).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 07:25:42 -04:00
gsinghpal
c7b794f604 fix(sticker): drop SO-line sequence suffix + bump Notes type
SO sticker (report_fp_so_sticker):
  Was: "SO-30019 / 10"  (the "/ 10" was line.sequence — Odoo's
       default increment-by-10 — meaningless to the operator)
  Now: "SO-30019"
Multi-line SOs are disambiguated by the body fields (Part #,
Customer, etc.) which already differ per sticker, so the
suffix wasn't earning its keep.

Notes column size bumps:
- Label 44pt -> 48pt
- Content 30pt -> 36pt (+20%) — easier to read from across
  the line. Line-height tightened 1.15 -> 1.1 to keep the
  multi-paragraph wrap inside the body band.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 07:21:09 -04:00
gsinghpal
64c61dcca8 feat(sticker): much bigger text + QR +30%
wkhtmltopdf renders CSS font-size at a smaller physical scale
than the em-square math predicts (a "30pt" cell text was only
~4mm tall visually). Pushing all type up significantly so it
actually reads at scan/print distance:

Text bumps:
- Body field text 30pt -> 50pt (+67%, label + value)
- WO# 56pt -> 72pt (+29%)
- Notes label 30pt -> 44pt
- Notes content 22pt -> 30pt (+36%)
- Muted rev tag 22pt -> 30pt
- Body cell padding 0 10px -> 0 8px (a touch more horizontal
  room for long values now that the font is bigger)

QR + 30% as asked:
- Wrapper 280 -> 365px (+30.4%). Image 368 -> 480px, offset
  -44 -> -58px (recomputed for the new quiet-zone crop).

Header re-balanced for the bigger content:
- Height 25% -> 32% (fits the +30% QR + bigger WO# + bigger
  logo at 135px)
- Body band: 75% -> 68% (rows now ~9.6mm tall; line-height
  1.0 keeps the 50pt body text snug inside)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 23:48:40 -04:00
gsinghpal
649b75d4a1 feat(sticker): bigger field labels + values + notes text
Trimmed the header from 30% to 25% of page height to free up
vertical room for the body band's 7 rows. Each row is now
~10.45mm tall (was 9.88mm), so the field font fits comfortably
at the bigger size.

Size bumps:
- Body field text 26pt -> 30pt (label + value, +15%)
- Muted rev tag 18pt -> 22pt
- Notes label 26pt -> 30pt
- Notes content 19pt -> 22pt (+16%, wraps cleanly to 2 lines
  when the customer description runs long)

Header re-fit (smaller cells, same content):
- Header height 30% -> 25%
- WO# font 62pt -> 56pt
- Logo max-height 135 -> 105px
- QR wrapper 340 -> 280px (image 447 -> 368px, offset -53 ->
  -44px to keep the quiet-zone crop math right)
- High-def 600x600 QR source unchanged — still prints crisp
  at the smaller wrapper size

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 23:41:17 -04:00