[REF] point_of_sale,pos_*: convert barcode_reader to service
**Notable feature changes**
- PoS app continues to load even if no nomenclature_id is configured.
- When scanning, an error popup is shown to the user mentioning about
the misconfiguration.
- We introduce a default error handler that shows the ErrorBarcodePopup
when there are no registered barcode handlers via the
`useBarcodeReader` hook.
closes odoo/odoo#115906
Related: odoo/enterprise#38444
Signed-off-by: Samuel Degueldre <sad@odoo.com>
This commit is contained in:
@@ -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(),
|
||||
|
||||
@@ -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),
|
||||
() => []
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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, {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<p class="category">Barcode Scanner</p>
|
||||
<ul>
|
||||
<li>
|
||||
<input t-model="state.barcodeInput" type="text" class="ean"></input>
|
||||
<input t-model="state.barcodeInput" type="text" class="ean" t-att-disabled="!barcodeReader" t-attf-placeholder="{{ !barcodeReader ? 'No nomenclature' : '' }}"/>
|
||||
</li>
|
||||
<li class="button barcode" t-on-click="barcodeScan">Scan</li>
|
||||
<li class="button custom_ean" t-on-click="barcodeScanEAN">Scan EAN-13</li>
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
});
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user