diff --git a/addons/barcodes/static/src/barcode_service.js b/addons/barcodes/static/src/barcode_service.js index f449c01a53e..0c1a2fb6e2b 100644 --- a/addons/barcodes/static/src/barcode_service.js +++ b/addons/barcodes/static/src/barcode_service.js @@ -28,6 +28,10 @@ export const barcodeService = { // this is done here to make it easily mockable in mobile tests isMobileChrome: isMobileOS() && isBrowserChrome(), + cleanBarcode: function(barcode) { + return barcode.replace(/Alt|Shift|Control/g, ''); + }, + start() { const bus = new EventBus(); let timeout = null; @@ -47,7 +51,8 @@ export const barcodeService = { * check if we have a barcode, and trigger appropriate events */ function checkBarcode() { - const str = barcodeInput ? barcodeInput.value : bufferedBarcode; + let str = barcodeInput ? barcodeInput.value : bufferedBarcode; + str = barcodeService.cleanBarcode(str); if (str.length >= 3) { handleBarcode(str, currentTarget); } @@ -66,9 +71,11 @@ export const barcodeService = { return; } // Ignore 'Shift', 'Escape', 'Backspace', 'Insert', 'Delete', 'Home', 'End', Arrow*, F*, Page*, ... - // ctrl, meta and alt are often used for UX purpose (like shortcuts) - // Note: shiftKey is not ignored because it can be used by some barcode scanner for digits. - const isSpecialKey = ev.key.length > 1 || ev.ctrlKey || ev.metaKey || ev.altKey; + // meta is often used for UX purpose (like shortcuts) + // Notes: + // - shiftKey is not ignored because it can be used by some barcode scanner for digits. + // - altKey/ctrlKey are not ignored because it can be used in some barcodes (e.g. GS1 separator) + const isSpecialKey = !['Control', 'Alt'].includes(ev.key) && (ev.key.length > 1 || ev.metaKey); const isEndCharacter = ev.key.match(/(Enter|Tab)/); // Don't catch non-printable keys except 'enter' and 'tab' diff --git a/addons/barcodes_gs1_nomenclature/__manifest__.py b/addons/barcodes_gs1_nomenclature/__manifest__.py index 288b0111dca..671103a611a 100644 --- a/addons/barcodes_gs1_nomenclature/__manifest__.py +++ b/addons/barcodes_gs1_nomenclature/__manifest__.py @@ -14,6 +14,7 @@ 'assets': { 'web.assets_backend': [ 'barcodes_gs1_nomenclature/static/src/js/barcode_parser.js', + 'barcodes_gs1_nomenclature/static/src/js/barcode_service.js', ], 'web.qunit_suite_tests': [ 'barcodes_gs1_nomenclature/static/src/js/tests/**/*', diff --git a/addons/barcodes_gs1_nomenclature/models/__init__.py b/addons/barcodes_gs1_nomenclature/models/__init__.py index 01218f2351b..d979a2928fc 100644 --- a/addons/barcodes_gs1_nomenclature/models/__init__.py +++ b/addons/barcodes_gs1_nomenclature/models/__init__.py @@ -1,2 +1,3 @@ from . import barcode_nomenclature from . import barcode_rule +from . import ir_http diff --git a/addons/barcodes_gs1_nomenclature/models/barcode_nomenclature.py b/addons/barcodes_gs1_nomenclature/models/barcode_nomenclature.py index b9a3df7d7ef..3ed7cec3ba1 100644 --- a/addons/barcodes_gs1_nomenclature/models/barcode_nomenclature.py +++ b/addons/barcodes_gs1_nomenclature/models/barcode_nomenclature.py @@ -16,8 +16,8 @@ class BarcodeNomenclature(models.Model): string="Is GS1 Nomenclature", help="This Nomenclature use the GS1 specification, only GS1-128 encoding rules is accepted is this kind of nomenclature.") gs1_separator_fnc1 = fields.Char( - string="FNC1 Separator", trim=False, - help="Alternative regex delimiter for the FNC1 (by default, if not set, it is ASCII 29 char). The separator must not match the begin/end of any related rules pattern.") + string="FNC1 Separator", trim=False, default=r'(Alt029|#|\x1D)', + help="Alternative regex delimiter for the FNC1. The separator must not match the begin/end of any related rules pattern.") @api.constrains('gs1_separator_fnc1') def _check_pattern(self): diff --git a/addons/barcodes_gs1_nomenclature/models/ir_http.py b/addons/barcodes_gs1_nomenclature/models/ir_http.py new file mode 100644 index 00000000000..58b95bfefdc --- /dev/null +++ b/addons/barcodes_gs1_nomenclature/models/ir_http.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models + + +class IrHttp(models.AbstractModel): + _inherit = 'ir.http' + + def session_info(self): + res = super().session_info() + nomenclature = self.env.company.nomenclature_id + if not nomenclature.is_gs1_nomenclature: + return res + res['gs1_group_separator_encodings'] = nomenclature.gs1_separator_fnc1 + return res diff --git a/addons/barcodes_gs1_nomenclature/static/src/js/barcode_parser.js b/addons/barcodes_gs1_nomenclature/static/src/js/barcode_parser.js index 1de5b782326..f17e14e5881 100644 --- a/addons/barcodes_gs1_nomenclature/static/src/js/barcode_parser.js +++ b/addons/barcodes_gs1_nomenclature/static/src/js/barcode_parser.js @@ -88,9 +88,6 @@ BarcodeParser.include({ const results = []; const rules = this.nomenclature.rules.filter(rule => rule.encoding === 'gs1-128'); let separatorReg = FNC1_CHAR + "?"; - if (this.nomenclature.gs1_separator_fnc1 && this.nomenclature.gs1_separator_fnc1.trim()){ - separatorReg = `(?:${this.nomenclature.gs1_separator_fnc1})?`; - } while (barcode.length > 0) { const barcodeLength = barcode.length; @@ -151,5 +148,8 @@ BarcodeParser.include({ }, }); -return BarcodeParser; +return { + BarcodeParser, + FNC1_CHAR, +}; }); diff --git a/addons/barcodes_gs1_nomenclature/static/src/js/barcode_service.js b/addons/barcodes_gs1_nomenclature/static/src/js/barcode_service.js new file mode 100644 index 00000000000..d37a4adb811 --- /dev/null +++ b/addons/barcodes_gs1_nomenclature/static/src/js/barcode_service.js @@ -0,0 +1,18 @@ +/** @odoo-module **/ + +import { session } from "@web/session"; +import { patch } from "@web/core/utils/patch"; +import { barcodeService } from '@barcodes/barcode_service'; + +import { FNC1_CHAR } from "barcodes_gs1_nomenclature/static/src/js/barcode_parser.js"; + + +patch(barcodeService, 'barcodes_gs1_nomenclature', { + // Use the regex given by the session, else use an impossible one + gs1SeparatorRegex: new RegExp(session.gs1_group_separator_encodings || '.^', 'g'), + + cleanBarcode: function(barcode) { + barcode = barcode.replace(barcodeService.gs1SeparatorRegex, FNC1_CHAR); + return this._super(barcode); + }, +}); diff --git a/addons/barcodes_gs1_nomenclature/static/src/js/tests/barcode_parser_tests.js b/addons/barcodes_gs1_nomenclature/static/src/js/tests/barcode_parser_tests.js index 5da8f68be94..c5cca71ff7b 100644 --- a/addons/barcodes_gs1_nomenclature/static/src/js/tests/barcode_parser_tests.js +++ b/addons/barcodes_gs1_nomenclature/static/src/js/tests/barcode_parser_tests.js @@ -248,35 +248,6 @@ QUnit.module('Barcode GS1 Parser', { }); - QUnit.test('Test Alternative GS1 Separator (fnc1)', async function (assert) { - assert.expect(6); - let barcodeNomenclature = new BarcodeParser({'nomenclature_id': 2}); - await barcodeNomenclature.loaded; - - barcodeNomenclature.nomenclature = this.data['barcode.nomenclature'].records[0]; - barcodeNomenclature.nomenclature.gs1_separator_fnc1 = "#"; - barcodeNomenclature.nomenclature.rules = this.data['barcode.rule'].records; - - // (21)12345(15)090101(16)100101 - let code128 = "2112345\x1D1509010116100101"; - let res; - try { - res = barcodeNomenclature.gs1_decompose_extanded(code128); - } catch (error) { - assert.ok( - error instanceof Error, - "Default separator shouldn't work" - ); - } - - code128 = "2112345#1509010116100101"; - res = barcodeNomenclature.gs1_decompose_extanded(code128); - assert.equal(res.length, 3); - assert.equal(res[0].ai, "21"); - assert.equal(res[0].value, "12345"); - assert.equal(res[1].ai, "15"); - assert.equal(res[2].ai, "16"); - }); }); }); });