From 98b1db6dccbf46e29b3b7ca20aee43909786b3e4 Mon Sep 17 00:00:00 2001 From: hapt-odoo Date: Tue, 8 Jul 2025 18:40:10 +0530 Subject: [PATCH 1/2] [ADD] barcode_scan: Added barcode scanning in SO/PO Added barcode scanning functionality in product_catalog In Sale Order and Purchase Order. After scanning the barcode of any product, if the product is available in The catalog, then the quantity will be updated by 1 unit, and if the product is not available, then the notification of warning will be shown to the user --- barcode_scan/__manifest__.py | 15 +++++ .../static/src/js/kanban_controller.js | 56 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 barcode_scan/__manifest__.py create mode 100644 barcode_scan/static/src/js/kanban_controller.js diff --git a/barcode_scan/__manifest__.py b/barcode_scan/__manifest__.py new file mode 100644 index 00000000000..2927d075492 --- /dev/null +++ b/barcode_scan/__manifest__.py @@ -0,0 +1,15 @@ +{ + 'name': "Barcode Scanning In SO/PO", + 'category': '', + 'version': '0.1', + 'depends': ['product', 'barcodes', 'sale', 'web', 'stock_barcode', 'purchase'], + 'sequence': 1, + 'application': True, + 'installable': True, + "assets": { + 'web.assets_backend': [ + 'barcode_scan/static/src/**/*', + ], + }, + 'license': 'AGPL-3' +} diff --git a/barcode_scan/static/src/js/kanban_controller.js b/barcode_scan/static/src/js/kanban_controller.js new file mode 100644 index 00000000000..0fb0e8fe792 --- /dev/null +++ b/barcode_scan/static/src/js/kanban_controller.js @@ -0,0 +1,56 @@ +import { patch } from "@web/core/utils/patch"; +import { rpc } from "@web/core/network/rpc"; +import { useService, useBus } from "@web/core/utils/hooks"; +import { ProductCatalogKanbanController } from "@product/product_catalog/kanban_controller"; + +patch(ProductCatalogKanbanController.prototype, { + setup(){ + super.setup(); + this.orm = useService("orm"); + this.barcodeService = useService("barcode"); + useBus(this.barcodeService.bus, "barcode_scanned", (ev) => this.onBarcodeScannedHandler(ev.detail.barcode)); + this.resModel = this.props.context.product_catalog_order_model; + this.notification = useService("notification"); + }, + + async onBarcodeScannedHandler(barcode) { + const [product] = await this.orm.searchRead( + "product.product", + [["barcode", "=", barcode]], + ["id"], + { limit: 1 } + ); + if (!product) { + this.notification.add(("No product found with barcode: ") + barcode, { type: "danger" }); + return; + } + + let productQuantity; + if (this.resModel == "sale.order") { + productQuantity = "product_uom_qty"; + } else if (this.resModel == "purchase.order") { + productQuantity = "product_qty"; + } else { + console.error("Model not found"); + return; + } + + const orderLines = await this.orm.searchRead( + this.props.context.active_model, + [["order_id", "=", this.props.context.order_id], + ["product_id", "=", product.id]], + ["id", productQuantity, "product_id"] + ); + + const existingQty = orderLines[0]?.[productQuantity] || 0; + const finallyQuantity = existingQty + 1; + await rpc("/product/catalog/update_order_line_info", { + order_id: this.props.context.order_id, + product_id: product.id, + quantity: finallyQuantity, + res_model: this.resModel, + }); + + this.model.load(); + } +}); From 54a47568c8dd5ef0f2b41723cefc40f4f4c523e5 Mon Sep 17 00:00:00 2001 From: hapt-odoo Date: Wed, 9 Jul 2025 18:38:59 +0530 Subject: [PATCH 2/2] [IMP] barcode_scan: On barcode scan ,product is added to catalog On barcode scanning of any product, the product is added to the first page on a catalog based on the quantity added to a sale or purchase order. --- barcode_scan/__manifest__.py | 5 ++- .../kanban_controller.js | 15 ++++---- .../src/product_catalog/kanban_model.js | 36 +++++++++++++++++++ .../static/src/product_catalog/kanban_view.js | 11 ++++++ 4 files changed, 56 insertions(+), 11 deletions(-) rename barcode_scan/static/src/{js => product_catalog}/kanban_controller.js (84%) create mode 100644 barcode_scan/static/src/product_catalog/kanban_model.js create mode 100644 barcode_scan/static/src/product_catalog/kanban_view.js diff --git a/barcode_scan/__manifest__.py b/barcode_scan/__manifest__.py index 2927d075492..6298ee5a307 100644 --- a/barcode_scan/__manifest__.py +++ b/barcode_scan/__manifest__.py @@ -1,9 +1,8 @@ { 'name': "Barcode Scanning In SO/PO", - 'category': '', 'version': '0.1', - 'depends': ['product', 'barcodes', 'sale', 'web', 'stock_barcode', 'purchase'], - 'sequence': 1, + 'summary': 'Adds barcode scanning capabilities to product catalog', + 'depends': ['sale_management', 'stock_barcode', 'purchase'], 'application': True, 'installable': True, "assets": { diff --git a/barcode_scan/static/src/js/kanban_controller.js b/barcode_scan/static/src/product_catalog/kanban_controller.js similarity index 84% rename from barcode_scan/static/src/js/kanban_controller.js rename to barcode_scan/static/src/product_catalog/kanban_controller.js index 0fb0e8fe792..33a222e5f5e 100644 --- a/barcode_scan/static/src/js/kanban_controller.js +++ b/barcode_scan/static/src/product_catalog/kanban_controller.js @@ -25,14 +25,13 @@ patch(ProductCatalogKanbanController.prototype, { return; } - let productQuantity; - if (this.resModel == "sale.order") { - productQuantity = "product_uom_qty"; - } else if (this.resModel == "purchase.order") { - productQuantity = "product_qty"; - } else { - console.error("Model not found"); - return; + const quantityFieldMap = { + "sale.order": "product_uom_qty", + "purchase.order": "product_qty", + }; + const productQuantity = quantityFieldMap[this.resModel]; + if (!productQuantity) { + this.notification.add("Unsupported model: " + this.resModel, { type: "danger" }); } const orderLines = await this.orm.searchRead( diff --git a/barcode_scan/static/src/product_catalog/kanban_model.js b/barcode_scan/static/src/product_catalog/kanban_model.js new file mode 100644 index 00000000000..407034787a9 --- /dev/null +++ b/barcode_scan/static/src/product_catalog/kanban_model.js @@ -0,0 +1,36 @@ +import { ProductCatalogKanbanModel } from "@product/product_catalog/kanban_model"; +import { getFieldsSpec } from "@web/model/relational_model/utils"; +import { rpc } from "@web/core/network/rpc"; + +export class CustomProductCatalogKanbanModel extends ProductCatalogKanbanModel { + async _loadUngroupedList(config) { + const ProductIds = await this.orm.search(config.resModel, config.domain); + if (!ProductIds.length) { + return { records: [], length: 0 }; + } + + let orderLinesInfo = {}; + if (config.context.order_id && config.context.product_catalog_order_model) { + orderLinesInfo = await rpc("/product/catalog/order_lines_info", { + order_id: config.context.order_id, + product_ids: ProductIds, + res_model: config.context.product_catalog_order_model, + }); + ProductIds.sort((a, b) => (orderLinesInfo[b].quantity || 0) - (orderLinesInfo[a].quantity || 0)); + } + + const catalogPage = ProductIds.slice(config.offset, config.offset + config.limit); + + const kwargs = { + specification: getFieldsSpec(config.activeFields, config.fields, config.context), + }; + + const result = await this.orm.webSearchRead(config.resModel, [["id", "in", catalogPage]], kwargs); + + result.records.sort((a, b) => (orderLinesInfo[b.id].quantity || 0) - (orderLinesInfo[a.id].quantity || 0)); + return { + length: ProductIds.length, + records: result.records, + }; + } +} diff --git a/barcode_scan/static/src/product_catalog/kanban_view.js b/barcode_scan/static/src/product_catalog/kanban_view.js new file mode 100644 index 00000000000..274a7801a0b --- /dev/null +++ b/barcode_scan/static/src/product_catalog/kanban_view.js @@ -0,0 +1,11 @@ +import { registry } from "@web/core/registry"; +import { productCatalogKanbanView } from "@product/product_catalog/kanban_view"; +import { CustomProductCatalogKanbanModel } from "./kanban_model"; + +export const customProductCatalogKanbanView = { + ...productCatalogKanbanView, + Model: CustomProductCatalogKanbanModel, +}; + +registry.category("views").remove("product_kanban_catalog"); +registry.category("views").add("product_kanban_catalog", customProductCatalogKanbanView);