diff --git a/fusion_plating/fusion_plating_jobs/__manifest__.py b/fusion_plating/fusion_plating_jobs/__manifest__.py index 1af0f261..0134b2e0 100644 --- a/fusion_plating/fusion_plating_jobs/__manifest__.py +++ b/fusion_plating/fusion_plating_jobs/__manifest__.py @@ -3,7 +3,7 @@ # License OPL-1 (Odoo Proprietary License v1.0) { 'name': 'Fusion Plating — Native Jobs', - 'version': '19.0.10.28.0', + 'version': '19.0.10.29.0', 'category': 'Manufacturing/Plating', 'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.', 'author': 'Nexa Systems Inc.', diff --git a/fusion_plating/fusion_plating_jobs/static/src/js/fp_record_inputs_dialog.js b/fusion_plating/fusion_plating_jobs/static/src/js/fp_record_inputs_dialog.js index f016d1cb..ea9efc4c 100644 --- a/fusion_plating/fusion_plating_jobs/static/src/js/fp_record_inputs_dialog.js +++ b/fusion_plating/fusion_plating_jobs/static/src/js/fp_record_inputs_dialog.js @@ -236,6 +236,52 @@ export class FpRecordInputsDialog extends Component { return "any"; } + // Stepper helpers — give the operator a tap-to-increment / -decrement + // pair next to each numeric input so they don't have to open the + // keyboard for small adjustments. Field is one of: value_number, + // value_min, value_max. Increment uses stepFor() so taps move in the + // same decimal magnitude the recipe spec was written in. Clamps at 0 + // (typical qty/time/temp on a plating shop floor doesn't go negative; + // if a recipe needs negatives, the operator can still type the value + // by tapping the input). + _stepDelta(row) { + const s = this.stepFor(row); + if (s === "any") return 1; + const n = parseFloat(s); + return isNaN(n) || n <= 0 ? 1 : n; + } + + _stepRound(n, delta) { + // Avoid floating-point fuzz (0.1+0.2=0.30000004). Round to the + // delta's decimal precision. + const decimals = (String(delta).split(".")[1] || "").length; + if (!decimals) return Math.round(n); + const factor = Math.pow(10, decimals); + return Math.round(n * factor) / factor; + } + + onIncrement(row, field) { + const cur = parseFloat(row[field]) || 0; + const delta = this._stepDelta(row); + row[field] = this._stepRound(cur + delta, delta); + } + + onDecrement(row, field) { + const cur = parseFloat(row[field]) || 0; + const delta = this._stepDelta(row); + row[field] = Math.max(0, this._stepRound(cur - delta, delta)); + } + + inputModeFor(row) { + // Tablet keyboard hint — show numeric keypad instead of full + // keyboard when the operator does tap the input. 'decimal' is + // safer than 'numeric' because it includes the decimal point + // (needed for pH, thickness, temperature). + const t = row.input_type || ""; + if (t === "time_seconds" || t === "time_hms") return "numeric"; + return "decimal"; + } + _fpCountDecimals(n) { if (n === null || n === undefined || n === "" || n === 0) return 0; const s = String(n); diff --git a/fusion_plating/fusion_plating_jobs/static/src/scss/fp_record_inputs_dialog.scss b/fusion_plating/fusion_plating_jobs/static/src/scss/fp_record_inputs_dialog.scss index 4a94e82e..b2444b1c 100644 --- a/fusion_plating/fusion_plating_jobs/static/src/scss/fp_record_inputs_dialog.scss +++ b/fusion_plating/fusion_plating_jobs/static/src/scss/fp_record_inputs_dialog.scss @@ -801,3 +801,49 @@ $rid-warn : var(--fp-rid-warn, #{$_fp-rid-warn-hex}); color: $rid-required; } } + +// Numeric stepper (tap-to-increment / tap-to-decrement around the input). +// Operator can still tap the input to open the keypad (inputmode="decimal" +// gives them the number keypad on iPad). +.o_fp_ri_stepper { + display: flex; + align-items: stretch; + gap: 0; + max-width: 16rem; +} + +.o_fp_ri_stepper_btn { + flex: 0 0 auto; + width: 3.2rem; + border: 1px solid #cdd0d4; + background: #f5f6f8; + color: #1d1d1f; + font-size: 1.3rem; + cursor: pointer; + transition: background 80ms; + display: flex; + align-items: center; + justify-content: center; + + &:hover, &:active { background: #e5e7eb; } + + &.o_fp_ri_stepper_minus { + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; + border-right: 0; + } + &.o_fp_ri_stepper_plus { + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; + border-left: 0; + } +} + +.o_fp_ri_stepper_input { + flex: 1 1 auto; + border-radius: 0; + text-align: center; + font-size: 1.2rem; + font-weight: 600; + min-width: 4rem; +} diff --git a/fusion_plating/fusion_plating_jobs/static/src/xml/fp_record_inputs_dialog.xml b/fusion_plating/fusion_plating_jobs/static/src/xml/fp_record_inputs_dialog.xml index d021546f..2c106bdb 100644 --- a/fusion_plating/fusion_plating_jobs/static/src/xml/fp_record_inputs_dialog.xml +++ b/fusion_plating/fusion_plating_jobs/static/src/xml/fp_record_inputs_dialog.xml @@ -120,11 +120,26 @@