diff --git a/addons/pos_self_order/__manifest__.py b/addons/pos_self_order/__manifest__.py index ba54c2c17cc..fe1ad6ed32c 100644 --- a/addons/pos_self_order/__manifest__.py +++ b/addons/pos_self_order/__manifest__.py @@ -55,6 +55,7 @@ 'bus/static/src/bus_parameters_service.js', 'bus/static/src/multi_tab_service.js', 'bus/static/src/workers/*', + 'barcodes/static/src/barcode_service.js', 'web/static/lib/bootstrap/js/dist/dom/data.js', 'web/static/lib/bootstrap/js/dist/dom/event-handler.js', 'web/static/lib/bootstrap/js/dist/dom/manipulator.js', diff --git a/addons/pos_self_order/models/product_product.py b/addons/pos_self_order/models/product_product.py index 73d1d33ca1a..3f227392a8c 100644 --- a/addons/pos_self_order/models/product_product.py +++ b/addons/pos_self_order/models/product_product.py @@ -196,6 +196,7 @@ class ProductProduct(models.Model): "is_pos_groupable": self.uom_id.is_pos_groupable, "write_date": self.write_date.timestamp(), "self_order_available": self.self_order_available, + "barcode": self.barcode, } def _get_self_order_data(self, pos_config: PosConfig) -> List[Dict]: diff --git a/addons/pos_self_order/static/src/app/models/product.js b/addons/pos_self_order/static/src/app/models/product.js index b0da4f3ed88..7269ea59f57 100644 --- a/addons/pos_self_order/static/src/app/models/product.js +++ b/addons/pos_self_order/static/src/app/models/product.js @@ -35,6 +35,7 @@ export class Product extends Reactive { this.is_pos_groupable = product.is_pos_groupable; this.write_date = product.write_date; this.self_order_available = product.self_order_available; + this.barcode = product.barcode; // data this.showPriceTaxIncluded = showPriceTaxIncluded; diff --git a/addons/pos_self_order/static/src/app/pages/combo_page/combo_page.js b/addons/pos_self_order/static/src/app/pages/combo_page/combo_page.js index 319a3b84e7c..75068f752b4 100644 --- a/addons/pos_self_order/static/src/app/pages/combo_page/combo_page.js +++ b/addons/pos_self_order/static/src/app/pages/combo_page/combo_page.js @@ -27,7 +27,7 @@ export class ComboPage extends Component { }); if (!this.props.product) { - this.router.navigate("productList"); + this.router.navigate("product_list"); return; } diff --git a/addons/pos_self_order/static/src/app/pages/product_page/product_page.js b/addons/pos_self_order/static/src/app/pages/product_page/product_page.js index a815e226058..76ee80e65e7 100644 --- a/addons/pos_self_order/static/src/app/pages/product_page/product_page.js +++ b/addons/pos_self_order/static/src/app/pages/product_page/product_page.js @@ -3,10 +3,7 @@ import { Component, onWillUnmount, useState, useSubEnv } from "@odoo/owl"; import { useSelfOrder } from "@pos_self_order/app/self_order_service"; import { AttributeSelection } from "@pos_self_order/app/components/attribute_selection/attribute_selection"; -import { Line } from "@pos_self_order/app/models/line"; import { useService } from "@web/core/utils/hooks"; -import { attributeFlatter } from "@pos_self_order/app/utils"; -import { constructFullProductName } from "@point_of_sale/utils"; export class ProductPage extends Component { static template = "pos_self_order.ProductPage"; @@ -19,7 +16,7 @@ export class ProductPage extends Component { useSubEnv({ selectedValues: {}, customValues: {}, editable: this.editableProductLine }); if (!this.props.product) { - this.router.navigate("productList"); + this.router.navigate("product_list"); return; } @@ -80,75 +77,19 @@ export class ProductPage extends Component { return increase ? this.state.qty++ : this.state.qty--; } - orderlineCanBeMerged() { - if (this.props.product.pos_combo_ids.length) { - return false; - } - const editedLine = this.selfOrder.editedLine; - - if (editedLine) { - return editedLine; - } - - const line = this.selfOrder.currentOrder.lines.find( - (l) => - JSON.stringify(l.attribute_value_ids.sort()) === - JSON.stringify(attributeFlatter(this.env.selectedValues).sort()) && - l.customer_note === this.state.customer_note && - l.product_id === this.product.id - ); - - return line || false; - } - - async addToCart() { - const lines = this.selfOrder.currentOrder.lines; - const lineToMerge = this.orderlineCanBeMerged(); - - if (lineToMerge) { - lineToMerge.attribute_value_ids = attributeFlatter(this.env.selectedValues); - lineToMerge.customer_note = this.state.customer_note; - lineToMerge.full_product_name = this.product.name; - - if (this.selfOrder.editedLine) { - lineToMerge.qty = this.state.qty; - } else { - lineToMerge.qty += this.state.qty; - } - } else { - const mainLine = new Line({ - id: lineToMerge ? lineToMerge.id : null, - uuid: lineToMerge ? lineToMerge.uuid : null, - qty: this.state.qty, - product_id: this.product.id, - customer_note: this.state.customer_note, - custom_attribute_value_ids: Object.values(this.env.customValues), - attribute_value_ids: attributeFlatter(this.env.selectedValues), - }); - - mainLine.full_product_name = constructFullProductName( - mainLine, - this.selfOrder.attributeValueById, - this.product.name - ); - - lines.push(mainLine); - } - - // If a command line does not have a quantity greater than 0, we consider it deleted - await this.selfOrder.getPricesFromServer(); - this.selfOrder.currentOrder.lines = lines.filter((o) => o.qty > 0); - - if (this.selfOrder.currentOrder.lines.length === 0) { - this.router.navigate("productList"); - } else { - this.router.back(); - } - } - get showQtyButtons() { return this.props.product.self_order_available; } + addToCart() { + this.selfOrder.addToCart( + this.props.product, + this.state.qty, + this.state.customer_note, + this.env.selectedValues, + this.env.customValues + ); + this.router.back(); + } isEveryValueSelected() { return Object.values(this.state.selectedValues).find((value) => !value) == false; diff --git a/addons/pos_self_order/static/src/app/self_order_service.js b/addons/pos_self_order/static/src/app/self_order_service.js index 2853b22f613..7c15934e653 100644 --- a/addons/pos_self_order/static/src/app/self_order_service.js +++ b/addons/pos_self_order/static/src/app/self_order_service.js @@ -7,7 +7,7 @@ import { Product } from "@pos_self_order/app/models/product"; import { Combo } from "@pos_self_order/app/models/combo"; import { session } from "@web/session"; import { getColor } from "@web/core/colors/colors"; -import { categorySorter, attributeFormatter } from "@pos_self_order/app/utils"; +import { categorySorter, attributeFormatter, attributeFlatter } from "@pos_self_order/app/utils"; import { Order } from "@pos_self_order/app/models/order"; import { batched } from "@web/core/utils/timing"; import { useState, markup } from "@odoo/owl"; @@ -16,7 +16,8 @@ import { registry } from "@web/core/registry"; import { cookie } from "@web/core/browser/cookie"; import { formatDateTime } from "@web/core/l10n/dates"; import { printerService } from "@point_of_sale/app/printer/printer_service"; -import { qrCodeSrc } from "@point_of_sale/utils"; +import { constructFullProductName, qrCodeSrc } from "@point_of_sale/utils"; +import { Line } from "./models/line"; export class SelfOrder extends Reactive { constructor(...args) { @@ -24,13 +25,14 @@ export class SelfOrder extends Reactive { this.ready = this.setup(...args).then(() => this); } - async setup(env, { rpc, notification, router, printer }) { + async setup(env, { rpc, notification, router, printer, barcode }) { // services this.notification = notification; this.router = router; this.env = env; this.rpc = rpc; this.printer = printer; + this.barcode = barcode; // data Object.assign(this, { @@ -60,6 +62,75 @@ export class SelfOrder extends Reactive { } else { await this.initMobileData(); } + barcode.bus.addEventListener("barcode_scanned", (ev) => { + if (!this.ordering) { + this.notification.add(_t("We're currently closed"), { + type: "danger", + }); + return; + } + const product = Object.values(this.productByIds).filter( + (p) => p.barcode === ev.detail.barcode + )?.[0]; + if (!product) { + this.notification.add(_t("Product not found"), { + type: "danger", + }); + return; + } + if (!product.self_order_available) { + this.notification.add(_t("Product is not available"), { + type: "danger", + }); + return; + } + if (product.attributes.length) { + this.router.navigate("product", { id: product.id }); + return; + } + this.addToCart(product, 1, "", {}, {}); + this.router.navigate("cart"); + }); + } + + async addToCart(product, qty, customer_note, selectedValues, customValues) { + const lineToMerge = + !product.pos_combo_ids.length && + (this.editedLine || + this.currentOrder.lines.find( + (l) => + JSON.stringify(l.attribute_value_ids.sort()) === + JSON.stringify(attributeFlatter(selectedValues).sort()) && + l.customer_note === customer_note && + l.product_id === product.id + )); + if (lineToMerge) { + lineToMerge.attribute_value_ids = attributeFlatter(selectedValues); + lineToMerge.customer_note = customer_note; + lineToMerge.full_product_name = product.name; + if (this.editedLine) { + lineToMerge.qty = qty; + } else { + lineToMerge.qty += qty; + } + } else { + const mainLine = new Line({ + qty, + product_id: product.id, + customer_note, + custom_attribute_value_ids: Object.values(customValues), + attribute_value_ids: attributeFlatter(selectedValues), + }); + mainLine.full_product_name = constructFullProductName( + mainLine, + this.attributeValueById, + product.name + ); + this.currentOrder.lines.push(mainLine); + } + await this.getPricesFromServer(); + // If a command line does not have a quantity greater than 0, we consider it deleted + this.currentOrder.lines = this.currentOrder.lines.filter((o) => o.qty > 0); } async confirmOrder() { @@ -587,9 +658,9 @@ export class SelfOrder extends Reactive { } export const selfOrderService = { - dependencies: ["rpc", "notification", "router", "printer"], - async start(env, { rpc, notification, router, printer }) { - return new SelfOrder(env, { rpc, notification, router, printer }).ready; + dependencies: ["rpc", "notification", "router", "printer", "barcode"], + async start(env, { rpc, notification, router, printer, barcode }) { + return new SelfOrder(env, { rpc, notification, router, printer, barcode }).ready; }, };