diff --git a/addons/point_of_sale/controllers/main.py b/addons/point_of_sale/controllers/main.py
index 5e753b831a7..1ffee22f674 100644
--- a/addons/point_of_sale/controllers/main.py
+++ b/addons/point_of_sale/controllers/main.py
@@ -55,6 +55,7 @@ class PosController(PortalAccount):
session_info = request.env['ir.http'].session_info()
session_info['user_context']['allowed_company_ids'] = company.ids
session_info['user_companies'] = {'current_company': company.id, 'allowed_companies': {company.id: session_info['user_companies']['allowed_companies'][company.id]}}
+ session_info['nomenclature_id'] = pos_session.company_id.nomenclature_id.id
context = {
'session_info': session_info,
'login_number': pos_session.login(),
diff --git a/addons/point_of_sale/static/src/app/barcode_reader_hook.js b/addons/point_of_sale/static/src/app/barcode_reader_hook.js
new file mode 100644
index 00000000000..ebab8d653c7
--- /dev/null
+++ b/addons/point_of_sale/static/src/app/barcode_reader_hook.js
@@ -0,0 +1,18 @@
+/** @odoo-module */
+
+import { useService } from "@web/core/utils/hooks";
+import { useComponent, useEffect } from "@odoo/owl";
+
+export function useBarcodeReader(callbackMap, exclusive = false) {
+ const current = useComponent();
+ const barcodeReader = useService("barcode_reader");
+ if (barcodeReader) {
+ for (const [key, callback] of Object.entries(callbackMap)) {
+ callbackMap[key] = callback.bind(current);
+ }
+ useEffect(
+ () => barcodeReader.register(callbackMap, exclusive),
+ () => []
+ );
+ }
+}
diff --git a/addons/point_of_sale/static/src/app/barcode_reader_service.js b/addons/point_of_sale/static/src/app/barcode_reader_service.js
new file mode 100644
index 00000000000..599922f80b9
--- /dev/null
+++ b/addons/point_of_sale/static/src/app/barcode_reader_service.js
@@ -0,0 +1,142 @@
+/** @odoo-module */
+
+import { registry } from "@web/core/registry";
+import { Mutex } from "@web/core/utils/concurrency";
+import { session } from "@web/session";
+import { ErrorPopup } from "@point_of_sale/js/Popups/ErrorPopup";
+import { ErrorBarcodePopup } from "@point_of_sale/js/Popups/ErrorBarcodePopup";
+import BarcodeParser from "barcodes.BarcodeParser";
+
+export class BarcodeReader {
+ constructor({ parser, popup }) {
+ this.parser = parser;
+ this.popup = popup;
+ this.setup();
+ }
+
+ setup() {
+ this.mutex = new Mutex();
+ this.cbMaps = new Set();
+ // FIXME POSREF: When LoginScreen becomes a normal screen, we can remove this exclusive callback handling.
+ this.exclusiveCbMap = null;
+ this.remoteScanning = false;
+ this.remoteActive = 0;
+ }
+
+ register(cbMap, exclusive) {
+ if (exclusive) {
+ this.exclusiveCbMap = cbMap;
+ } else {
+ this.cbMaps.add(cbMap);
+ }
+ return () => {
+ if (exclusive) {
+ this.exclusiveCbMap = null;
+ } else {
+ this.cbMaps.delete(cbMap);
+ }
+ };
+ }
+
+ scan(code) {
+ return this.mutex.exec(() => this._scan(code));
+ }
+
+ async _scan(code) {
+ if (!code) {
+ return;
+ }
+
+ const cbMaps = this.exclusiveCbMap ? [this.exclusiveCbMap] : [...this.cbMaps];
+
+ let parsedResult = this.parser.parse_barcode(code);
+ if (!Array.isArray(parsedResult)) {
+ parsedResult = [parsedResult];
+ }
+
+ for (const parseBarcode of parsedResult) {
+ const cbs = cbMaps.map((cbMap) => cbMap[parseBarcode.type]).filter(Boolean);
+ if (cbs.length === 0) {
+ this.popup.add(ErrorBarcodePopup, { code: this.codeRepr(parseBarcode) });
+ }
+ for (const cb of cbs) {
+ await cb(parseBarcode);
+ }
+ }
+ }
+
+ codeRepr(parsedBarcode) {
+ if (parsedBarcode.code.length > 32) {
+ return parsedBarcode.code.substring(0, 29) + "...";
+ } else {
+ return parsedBarcode.code;
+ }
+ }
+
+ // the barcode scanner will listen on the hw_proxy/scanner interface for
+ // scan events until disconnectFromProxy is called
+ connectToProxy(hwProxy) {
+ this.remoteScanning = true;
+ if (this.remoteActive >= 1) {
+ return;
+ }
+ this.remoteActive = 1;
+ this.waitForBarcode(hwProxy);
+ }
+
+ async waitForBarcode(hwProxy) {
+ try {
+ const barcode = await hwProxy.connection.rpc(
+ "/hw_proxy/scanner",
+ {},
+ { shadow: true, timeout: 7500 }
+ );
+ if (!this.remoteScanning) {
+ this.remoteActive = 0;
+ return;
+ }
+ this.scan(barcode);
+ } catch {
+ if (!this.remoteScanning) {
+ this.remoteActive = 0;
+ return;
+ }
+ }
+ this.waitForBarcode();
+ }
+
+ // the barcode scanner will stop listening on the hw_proxy/scanner remote interface
+ disconnectFromProxy() {
+ this.remoteScanning = false;
+ }
+}
+
+export const barcodeReader = {
+ dependencies: ["barcode", "popup"],
+ async start(env, { barcode, popup }) {
+ let barcodeReader = null;
+
+ if (session.nomenclature_id) {
+ const parser = new BarcodeParser({ nomenclature_id: [session.nomenclature_id] });
+ await parser.is_loaded();
+ barcodeReader = new BarcodeReader({ parser, popup });
+ }
+
+ barcode.bus.addEventListener("barcode_scanned", (ev) => {
+ if (barcodeReader) {
+ barcodeReader.scan(ev.detail.barcode);
+ } else {
+ popup.add(ErrorPopup, {
+ title: env._t("Unable to parse barcode"),
+ body: env._t(
+ "No barcode nomenclature has been configured. This can be changed in the configuration settings."
+ ),
+ });
+ }
+ });
+
+ return barcodeReader;
+ },
+};
+
+registry.category("services").add("barcode_reader", barcodeReader);
diff --git a/addons/point_of_sale/static/src/app/debug/debug_widget.js b/addons/point_of_sale/static/src/app/debug/debug_widget.js
index c2b3a0bfa32..ce6a092243b 100644
--- a/addons/point_of_sale/static/src/app/debug/debug_widget.js
+++ b/addons/point_of_sale/static/src/app/debug/debug_widget.js
@@ -17,6 +17,7 @@ export class DebugWidget extends Component {
super.setup();
this.debug = useService("debug");
this.popup = useService("popup");
+ this.barcodeReader = useService("barcode_reader");
const numberBuffer = useService("number_buffer");
useBus(numberBuffer, "buffer-update", this._onBufferUpdate);
this.state = useState({
@@ -87,14 +88,18 @@ export class DebugWidget extends Component {
this.env.proxy.debug_reset_weight();
}
async barcodeScan() {
- await this.env.barcode_reader.scan(this.state.barcodeInput);
+ if (!this.barcodeReader) {
+ return;
+ }
+ await this.barcodeReader.scan(this.state.barcodeInput);
}
async barcodeScanEAN() {
- const ean = this.env.barcode_reader.barcode_parser.sanitize_ean(
- this.state.barcodeInput || "0"
- );
+ if (!this.barcodeReader) {
+ return;
+ }
+ const ean = this.barcodeReader.parser.sanitize_ean(this.state.barcodeInput || "0");
this.state.barcodeInput = ean;
- await this.env.barcode_reader.scan(ean);
+ await this.barcodeReader.scan(ean);
}
async deleteOrders() {
const { confirmed } = await this.popup.add(ConfirmPopup, {
diff --git a/addons/point_of_sale/static/src/app/debug/debug_widget.xml b/addons/point_of_sale/static/src/app/debug/debug_widget.xml
index 8962ce39e34..b029d5398d2 100644
--- a/addons/point_of_sale/static/src/app/debug/debug_widget.xml
+++ b/addons/point_of_sale/static/src/app/debug/debug_widget.xml
@@ -22,7 +22,7 @@
Barcode Scanner
-
-
+
- Scan
- Scan EAN-13
diff --git a/addons/point_of_sale/static/src/app/pos_store.js b/addons/point_of_sale/static/src/app/pos_store.js
index 39e12339311..d92d9fbb7bb 100644
--- a/addons/point_of_sale/static/src/app/pos_store.js
+++ b/addons/point_of_sale/static/src/app/pos_store.js
@@ -21,12 +21,13 @@ export class PosStore extends Reactive {
legacyEnv = legacyEnv;
globalState = new PosGlobalState({ env: markRaw(legacyEnv) });
- static serviceDependencies = ["popup", "orm", "number_buffer"];
- constructor({ popup, orm, number_buffer }) {
+ static serviceDependencies = ["popup", "orm", "number_buffer", "barcode_reader"];
+ constructor({ popup, orm, number_buffer, barcode_reader }) {
super();
this.orm = orm;
this.popup = popup;
this.numberBuffer = number_buffer;
+ this.barcodeReader = barcode_reader;
this.setup();
}
// use setup instead of constructor because setup can be patched.
@@ -46,9 +47,9 @@ export class PosStore extends Reactive {
this.showScreen(screenName);
}
- connect_to_proxy() {
+ connectToProxy() {
return new Promise((resolve, reject) => {
- this.globalState.env.barcode_reader.disconnect_from_proxy();
+ this.barcodeReader?.disconnectFromProxy();
this.globalState.loadingSkipButtonIsShown = true;
this.globalState.env.proxy
.autoconnect({
@@ -58,7 +59,7 @@ export class PosStore extends Reactive {
.then(
() => {
if (this.globalState.config.iface_scan_via_proxy) {
- this.globalState.env.barcode_reader.connect_to_proxy();
+ this.barcodeReader?.connectToProxy(this.globalState.env.proxy);
}
resolve();
},
diff --git a/addons/point_of_sale/static/src/js/Chrome.js b/addons/point_of_sale/static/src/js/Chrome.js
index 813912ebf3a..5efed15d78d 100644
--- a/addons/point_of_sale/static/src/js/Chrome.js
+++ b/addons/point_of_sale/static/src/js/Chrome.js
@@ -2,7 +2,6 @@
import { loadCSS } from "@web/core/assets";
import { useService } from "@web/core/utils/hooks";
-import BarcodeParser from "barcodes.BarcodeParser";
import { batched } from "@point_of_sale/js/utils";
import { debounce } from "@web/core/utils/timing";
import { Transition } from "@web/core/transition";
@@ -139,9 +138,8 @@ export class Chrome extends Component {
try {
await this.env.pos.load_server_data();
- await this.setupBarcodeParser();
if (this.env.pos.config.use_proxy) {
- await this.pos.connect_to_proxy();
+ await this.pos.connectToProxy();
}
// Load the saved `env.pos.toRefundLines` from localStorage when
// the PosGlobalState is ready.
@@ -219,23 +217,6 @@ export class Chrome extends Component {
}
}
- setupBarcodeParser() {
- if (!this.env.pos.company.nomenclature_id) {
- const errorMessage = this.env._t(
- "The barcode nomenclature setting is not configured. " +
- "Make sure to configure it on your Point of Sale configuration settings"
- );
- throw new Error(this.env._t("Missing barcode nomenclature"), {
- cause: { message: errorMessage },
- });
- }
- const barcode_parser = new BarcodeParser({
- nomenclature_id: this.env.pos.company.nomenclature_id,
- });
- this.env.barcode_reader.set_barcode_parser(barcode_parser);
- return barcode_parser.is_loaded();
- }
-
/**
* Save `env.pos.toRefundLines` in localStorage on beforeunload - closing the
* browser, reloading or going to other page.
diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductScreen.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductScreen.js
index 283b9ddf05f..2ef853577b6 100644
--- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductScreen.js
+++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductScreen.js
@@ -3,12 +3,11 @@
import { ControlButtonsMixin } from "@point_of_sale/js/ControlButtonsMixin";
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
-import { useBarcodeReader } from "@point_of_sale/js/custom_hooks";
+import { useBarcodeReader } from "@point_of_sale/app/barcode_reader_hook";
import { parse } from "web.field_utils";
import { NumberPopup } from "@point_of_sale/js/Popups/NumberPopup";
import { ErrorPopup } from "@point_of_sale/js/Popups/ErrorPopup";
-import { ErrorBarcodePopup } from "@point_of_sale/js/Popups/ErrorBarcodePopup";
import { ControlButtonPopup } from "@point_of_sale/js/Popups/ControlButtonPopup";
import { ConnectionLostError } from "@web/core/network/rpc_service";
@@ -49,7 +48,6 @@ export class ProductScreen extends ControlButtonsMixin(Component) {
price: this._barcodeProductAction,
client: this._barcodePartnerAction,
discount: this._barcodeDiscountAction,
- error: this._barcodeErrorAction,
});
this.state = useState({
mobile_pane: this.props.mobile_pane || "right",
@@ -186,19 +184,6 @@ export class ProductScreen extends ControlButtonsMixin(Component) {
last_orderline.set_discount(code.value);
}
}
- // IMPROVEMENT: The following two methods should be in PosScreenComponent?
- // Why? Because once we start declaring barcode actions in different
- // screens, these methods will also be declared over and over.
- _barcodeErrorAction(code) {
- this.popup.add(ErrorBarcodePopup, { code: this._codeRepr(code) });
- }
- _codeRepr(code) {
- if (code.code.length > 32) {
- return code.code.substring(0, 29) + "...";
- } else {
- return code.code;
- }
- }
async _displayAllControlPopup() {
await this.popup.add(ControlButtonPopup, {
controlButtons: this.controlButtons,
diff --git a/addons/point_of_sale/static/src/js/barcode_reader.js b/addons/point_of_sale/static/src/js/barcode_reader.js
deleted file mode 100644
index 46d6f4fa231..00000000000
--- a/addons/point_of_sale/static/src/js/barcode_reader.js
+++ /dev/null
@@ -1,165 +0,0 @@
-/** @odoo-module */
-
-import concurrency from "web.concurrency";
-import core from "web.core";
-var Mutex = concurrency.Mutex;
-
-// this module interfaces with the barcode reader. It assumes the barcode reader
-// is set-up to act like a keyboard. Use connect() and disconnect() to activate
-// and deactivate the barcode reader. Use set_action_callbacks to tell it
-// what to do when it reads a barcode.
-export const BarcodeReader = core.Class.extend({
- actions: ["product", "cashier", "client"],
-
- init: function (attributes) {
- this.mutex = new Mutex();
- this.action_callbacks = {};
- this.exclusive_callbacks = {};
- this.proxy = attributes.proxy;
- this.env = attributes.env;
- this.remote_scanning = false;
- this.remote_active = 0;
-
- this.barcode_parser = attributes.barcode_parser;
-
- this.action_callback_stack = [];
-
- core.bus.on("barcode_scanned", this, function (barcode) {
- // use mutex to make sure scans are done one after the other
- this.mutex.exec(async () => {
- await this.scan(barcode);
- });
- });
- },
-
- set_barcode_parser: function (barcode_parser) {
- this.barcode_parser = barcode_parser;
- },
-
- // when a barcode is scanned and parsed, the callback corresponding
- // to its type is called with the parsed_barcode as a parameter.
- // (parsed_barcode is the result of parse_barcode(barcode))
- //
- // callbacks is a Map of 'actions' : callback(parsed_barcode)
- // that sets the callback for each action. if a callback for the
- // specified action already exists, it is replaced.
- //
- // possible actions include :
- // 'product' | 'cashier' | 'client' | 'discount'
- set_action_callback: function (name, callback) {
- if (this.action_callbacks[name]) {
- this.action_callbacks[name].add(callback);
- } else {
- this.action_callbacks[name] = new Set([callback]);
- }
- },
-
- remove_action_callback: function (name, callback) {
- if (!callback) {
- delete this.action_callbacks[name];
- return;
- }
- const callbacks = this.action_callbacks[name];
- if (callbacks) {
- callbacks.delete(callback);
- if (callbacks.size === 0) {
- delete this.action_callbacks[name];
- }
- }
- },
-
- /**
- * Allow setting of exclusive callbacks. If there are exclusive callbacks,
- * these callbacks are called neglecting the regular callbacks. This is
- * useful for rendered Components that wants to take exclusive access
- * to the barcode reader.
- *
- * @param {String} name
- * @param {Function} callback function that takes parsed barcode
- */
- set_exclusive_callback: function (name, callback) {
- if (this.exclusive_callbacks[name]) {
- this.exclusive_callbacks[name].add(callback);
- } else {
- this.exclusive_callbacks[name] = new Set([callback]);
- }
- },
-
- remove_exclusive_callback: function (name, callback) {
- if (!callback) {
- delete this.exclusive_callbacks[name];
- return;
- }
- const callbacks = this.exclusive_callbacks[name];
- if (callbacks) {
- callbacks.delete(callback);
- if (callbacks.size === 0) {
- delete this.exclusive_callbacks[name];
- }
- }
- },
-
- scan: async function (code) {
- if (!code) {
- return;
- }
-
- const callbacks = Object.keys(this.exclusive_callbacks).length
- ? this.exclusive_callbacks
- : this.action_callbacks;
- let parsed_results = this.barcode_parser.parse_barcode(code);
- if (!Array.isArray(parsed_results)) {
- parsed_results = [parsed_results];
- }
- for (const parsed_result of parsed_results) {
- if (callbacks[parsed_result.type]) {
- for (const cb of callbacks[parsed_result.type]) {
- await cb(parsed_result);
- }
- } else if (callbacks.error) {
- [...callbacks.error].map((cb) => cb(parsed_result));
- } else {
- console.warn("Ignored Barcode Scan:", parsed_result);
- }
- }
- },
-
- // the barcode scanner will listen on the hw_proxy/scanner interface for
- // scan events until disconnect_from_proxy is called
- connect_to_proxy: function () {
- var self = this;
- this.remote_scanning = true;
- if (this.remote_active >= 1) {
- return;
- }
- this.remote_active = 1;
-
- function waitforbarcode() {
- return self.proxy.connection
- .rpc("/hw_proxy/scanner", {}, { shadow: true, timeout: 7500 })
- .then(
- function (barcode) {
- if (!self.remote_scanning) {
- self.remote_active = 0;
- return;
- }
- self.scan(barcode);
- waitforbarcode();
- },
- function () {
- if (!self.remote_scanning) {
- self.remote_active = 0;
- return;
- }
- waitforbarcode();
- }
- );
- }
- waitforbarcode();
- },
-
- // the barcode scanner will stop listening on the hw_proxy/scanner remote interface
- disconnect_from_proxy: function () {
- this.remote_scanning = false;
- },
-});
diff --git a/addons/point_of_sale/static/src/js/custom_hooks.js b/addons/point_of_sale/static/src/js/custom_hooks.js
index 4db00c0b8f1..23c91f118e4 100644
--- a/addons/point_of_sale/static/src/js/custom_hooks.js
+++ b/addons/point_of_sale/static/src/js/custom_hooks.js
@@ -3,7 +3,7 @@ import { OfflineErrorPopup } from "./Popups/OfflineErrorPopup";
import { ConfirmPopup } from "./Popups/ConfirmPopup";
import { ErrorTracebackPopup } from "./Popups/ErrorTracebackPopup";
import { ErrorPopup } from "./Popups/ErrorPopup";
-import { useEnv, onMounted, onPatched, onWillUnmount, useComponent } from "@odoo/owl";
+import { useEnv, onMounted, onPatched, useComponent } from "@odoo/owl";
/**
* Introduce error handlers in the component.
@@ -90,33 +90,3 @@ export function useAutoFocusToLast() {
onMounted(autofocus);
onPatched(autofocus);
}
-
-export function useBarcodeReader(callbackMap, exclusive = false) {
- const current = useComponent();
- const barcodeReader = current.env.barcode_reader;
- for (const [key, callback] of Object.entries(callbackMap)) {
- callbackMap[key] = callback.bind(current);
- }
- onMounted(() => {
- if (barcodeReader) {
- for (const key in callbackMap) {
- if (exclusive) {
- barcodeReader.set_exclusive_callback(key, callbackMap[key]);
- } else {
- barcodeReader.set_action_callback(key, callbackMap[key]);
- }
- }
- }
- });
- onWillUnmount(() => {
- if (barcodeReader) {
- for (const key in callbackMap) {
- if (exclusive) {
- barcodeReader.remove_exclusive_callback(key, callbackMap[key]);
- } else {
- barcodeReader.remove_action_callback(key, callbackMap[key]);
- }
- }
- }
- });
-}
diff --git a/addons/point_of_sale/static/src/js/pos_env.js b/addons/point_of_sale/static/src/js/pos_env.js
index bb9e1eb8323..765ecc6b3ab 100644
--- a/addons/point_of_sale/static/src/js/pos_env.js
+++ b/addons/point_of_sale/static/src/js/pos_env.js
@@ -6,7 +6,6 @@
import env from "web.env";
import concurrency from "web.concurrency";
import { JobQueue, ProxyDevice } from "@point_of_sale/js/devices";
-import { BarcodeReader } from "@point_of_sale/js/barcode_reader";
// Create new env object base on web.env.
// Mutating this new object won't affect the original object.
@@ -14,5 +13,4 @@ export const pos_env = Object.create(env);
pos_env.proxy_queue = new JobQueue(); // used to prevent parallels communications to the proxy
pos_env.proxy = new ProxyDevice({ env: pos_env }); // used to communicate to the hardware devices via a local proxy
-pos_env.barcode_reader = new BarcodeReader({ env: pos_env, proxy: pos_env.proxy });
pos_env.posMutex = new concurrency.Mutex();
diff --git a/addons/pos_hr/static/src/js/SelectCashierMixin.js b/addons/pos_hr/static/src/js/SelectCashierMixin.js
index 3a540196d1b..41d2e41175d 100644
--- a/addons/pos_hr/static/src/js/SelectCashierMixin.js
+++ b/addons/pos_hr/static/src/js/SelectCashierMixin.js
@@ -8,7 +8,7 @@ import { SelectionPopup } from "@point_of_sale/js/Popups/SelectionPopup";
import { ErrorPopup } from "@point_of_sale/js/Popups/ErrorPopup";
import { useService } from "@web/core/utils/hooks";
import { useEnv } from "@odoo/owl";
-import { useBarcodeReader } from "@point_of_sale/js/custom_hooks";
+import { useBarcodeReader } from "@point_of_sale/app/barcode_reader_hook";
export function useCashierSelector(
{ onCashierChanged, exclusive } = { onCashierChanged: () => {}, exclusive: false }
diff --git a/addons/pos_loyalty/static/src/js/ProductScreen.js b/addons/pos_loyalty/static/src/js/ProductScreen.js
index 74d2a8a4370..6d2cf493ee6 100644
--- a/addons/pos_loyalty/static/src/js/ProductScreen.js
+++ b/addons/pos_loyalty/static/src/js/ProductScreen.js
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { ProductScreen } from "@point_of_sale/js/Screens/ProductScreen/ProductScreen";
-import { useBarcodeReader } from "@point_of_sale/js/custom_hooks";
+import { useBarcodeReader } from "@point_of_sale/app/barcode_reader_hook";
import { patch } from "@web/core/utils/patch";
import { ConfirmPopup } from "@point_of_sale/js/Popups/ConfirmPopup";
import { useService } from "@web/core/utils/hooks";
diff --git a/addons/pos_mercury/static/src/js/PaymentScreen.js b/addons/pos_mercury/static/src/js/PaymentScreen.js
index 4b3d69c8ed1..2a88d82c7a3 100644
--- a/addons/pos_mercury/static/src/js/PaymentScreen.js
+++ b/addons/pos_mercury/static/src/js/PaymentScreen.js
@@ -3,7 +3,7 @@
import { _t } from "web.core";
import { patch } from "@web/core/utils/patch";
import { PaymentScreen } from "@point_of_sale/js/Screens/PaymentScreen/PaymentScreen";
-import { useBarcodeReader } from "@point_of_sale/js/custom_hooks";
+import { useBarcodeReader } from "@point_of_sale/app/barcode_reader_hook";
import { ErrorPopup } from "@point_of_sale/js/Popups/ErrorPopup";
import { PaymentTransactionPopup } from "./PaymentTransactionPopup";
import { SelectionPopup } from "@point_of_sale/js/Popups/SelectionPopup";
diff --git a/addons/pos_mercury/static/src/js/ProductScreen.js b/addons/pos_mercury/static/src/js/ProductScreen.js
index 83eaa238173..97afa2b9d74 100644
--- a/addons/pos_mercury/static/src/js/ProductScreen.js
+++ b/addons/pos_mercury/static/src/js/ProductScreen.js
@@ -1,7 +1,7 @@
/** @odoo-module */
import { ProductScreen } from "@point_of_sale/js/Screens/ProductScreen/ProductScreen";
-import { useBarcodeReader } from "@point_of_sale/js/custom_hooks";
+import { useBarcodeReader } from "@point_of_sale/app/barcode_reader_hook";
import { patch } from "@web/core/utils/patch";
import { ErrorPopup } from "@point_of_sale/js/Popups/ErrorPopup";