Skip to content

[ADD] sales_purchase_barcode: added barcode scanning in product catalog #901

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: 18.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions sales_purchase_barcode/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "SO/PO Barcode Scanning",
"version": "1.0",
"category": "Sales",
"summary": "Adds products to SO from catalog via barcode scanning.",
"author": "Kalpan Desai",
"depends": ["sale_management", "web", "product", "purchase", "barcodes"],
"license": "LGPL-3",
"assets": {
"web.assets_backend": [
"sales_purchase_barcode/static/src/**/*"
]
},
"installable": True,
"application": True,
}
92 changes: 92 additions & 0 deletions sales_purchase_barcode/static/src/barcodescanner_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { patch } from "@web/core/utils/patch";
import { ProductCatalogKanbanController } from "@product/product_catalog/kanban_controller";
import { rpc } from "@web/core/network/rpc";
import { useService, useBus } from "@web/core/utils/hooks";

patch(ProductCatalogKanbanController.prototype, {
/**
* @override
*/
setup() {
super.setup();
this.orm = useService("orm");
this.notification = useService("notification");
this.barcodeService = useService('barcode');
useBus(this.barcodeService.bus, 'barcode_scanned', (ev) => this._processBarcode(ev.detail.barcode));
},

/**
* Processes the scanned barcode to find the corresponding product and update the order.
*
* @param {string} scannedBarcode The barcode string to process.
*/
async _processBarcode(scannedBarcode) {
// An order must be selected to add products.
if (!this.orderId) {
this.notification.add("Please select an order first.", { type: "warning" });
return;
}

try {
// Search for a product with the scanned barcode.
const products = await this.orm.searchRead(
"product.product",
[["barcode", "=", scannedBarcode]],
["id", "name"]
);

if (!products.length) {
this.notification.add("No product found for this barcode.", { type: "warning" });
return;
}

const product = products[0];

let orderLineModel, quantityField;
// Determine the correct model and field names based on the order type.
if (this.orderResModel === "sale.order") {
orderLineModel = "sale.order.line";
quantityField = "product_uom_qty";
} else if (this.orderResModel === "purchase.order") {
orderLineModel = "purchase.order.line";
quantityField = "product_qty";
} else {
// Log an error if the order model is not supported.
console.error("Unsupported order model for barcode scanning:", this.orderResModel);
this.notification.add("Barcode scanning is not supported for this document type.", { type: "danger" });
return;
}

// Check if there is an existing order line for this product.
const existingOrderLines = await this.orm.searchRead(
orderLineModel,
[["order_id", "=", this.orderId], ["product_id", "=", product.id]],
["id", quantityField]
);

// If a line exists, increment its quantity; otherwise, set quantity to 1.
const updatedQuantity = existingOrderLines.length ? existingOrderLines[0][quantityField] + 1 : 1;

// Call the backend to create or update the order line.
await rpc("/product/catalog/update_order_line_info", {
res_model: this.orderResModel,
order_id: this.orderId,
product_id: product.id,
quantity: updatedQuantity,
});

// Notify the user of the successful addition.
this.notification.add(
`Added ${product.name} (Qty: ${updatedQuantity})`,
{ type: "success" }
);

// Reload the view to show the updated order line information.
this.model.load();

} catch (error) {
console.error("Error processing barcode scan:", error);
this.notification.add("An error occurred while processing the barcode.", { type: "danger" });
}
},
});
61 changes: 61 additions & 0 deletions sales_purchase_barcode/static/src/kanban_model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/** @odoo-module **/

import { rpc } from "@web/core/network/rpc";
import { ProductCatalogKanbanModel } from "@product/product_catalog/kanban_model";
import { getFieldsSpec } from "@web/model/relational_model/utils";

export class BarcodeProductCatalogKanbanModel extends ProductCatalogKanbanModel {

async _loadUngroupedList(config) {
const allProducts = await this.orm.search(config.resModel, config.domain);

if (!allProducts.length) {
return { records: [], length: 0 };
}

let orderLines = {};
const scanned = [], unscanned = [];

if (config.context.order_id && config.context.product_catalog_order_model) {
orderLines = await rpc("/product/catalog/order_lines_info", {
order_id: config.context.order_id,
product_ids: allProducts,
res_model: config.context.product_catalog_order_model,
});

for (const id of allProducts) {
const qty = (orderLines[id]?.quantity) || 0;
if (qty > 0) scanned.push(id);
else unscanned.push(id);
}


scanned.sort((a, b) =>
(orderLines[b]?.quantity || 0) - (orderLines[a]?.quantity || 0)
);
} else {
unscanned.push(...allProducts);
}

const sortedProductIds = [...scanned, ...unscanned];
const paginatedProductIds = sortedProductIds.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", paginatedProductIds]], kwargs);

result.records.sort((a, b) => {
const qtyA = orderLines[a.id]?.quantity || 0;
const qtyB = orderLines[b.id]?.quantity || 0;
return qtyB - qtyA || a.id - b.id;
});

return {
length: allProducts.length,
records: result.records,
};
}

}
11 changes: 11 additions & 0 deletions sales_purchase_barcode/static/src/kanban_view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { registry } from "@web/core/registry";
import { productCatalogKanbanView } from "@product/product_catalog/kanban_view";
import { BarcodeProductCatalogKanbanModel } from "./kanban_model";

export const BarcodeProductCatalogKanbanView = {
...productCatalogKanbanView,
Model: BarcodeProductCatalogKanbanModel,
};

registry.category("views").remove("product_kanban_catalog");
registry.category("views").add("product_kanban_catalog", BarcodeProductCatalogKanbanView);