You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

181 lines
6.0 KiB

/** @odoo-module */
import { browser } from "@web/core/browser/browser";
import { Dialog } from "@web/core/dialog/dialog";
import { _t } from "@web/core/l10n/translation";
import { useChildRef, useService } from "@web/core/utils/hooks";
import { Component, useRef, onWillUnmount } from "@odoo/owl";
var beep = new Audio('/barcode_capturing_sale_purchase/static/src/audio/beep_scan.mp3');
//BarcodeDialog is a component that captures barcode input through the device's camera,
// processes the scanned barcode, and interacts with the Odoo backend to perform
// actions based on the scanned data.
export class BarcodeDialog extends Component {
async setup() {
super.setup();
this.env.dialogData.dismiss = () => this._cancel();
this.orm = useService('orm');
this.notificationService = useService("notification");
this.modalRef = useChildRef();
this.videoPreviewRef = useRef("videoPreview");
this.isMounted = true;
// Cleanup function to stop video stream when component unmounts
onWillUnmount(() => {
this.isMounted = false;
this._stopVideoStream();
});
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
this.stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false });
} else {
// Handle case where camera access is not available
this.notificationService.add(_t("Camera access is not available"), {
title: _t("Error"),
type: "danger",
});
this.props.close();
return;
}
this.videoPreviewRef.el.srcObject = this.stream;
this.videoPreviewRef.el.play();
Quagga.init({
inputStream: {
name: "Live",
type: "LiveStream",
target: this.videoPreviewRef.el,
constraints: {
width: 640,
height: 480,
facingMode: "environment" // Use the rear camera
}
},
decoder: {
readers: [
"code_128_reader",
"ean_reader",
"ean_8_reader",
"upc_reader",
"upc_e_reader"
]
}
}, (err) => {
if (err) {
return;
}
Quagga.start();
});
Quagga.onDetected((result) => {
if (!this.isMounted) return;
var barcode = result.codeResult.code;
Quagga.offDetected();
Quagga.stop();
this.scan_product(barcode);
});
}
// Handles the cancellation of the dialog.
async _cancel() {
return this.execButton(this.props.cancel);
}
// Handles the confirmation of the dialog.
async _dialogConfirm() {
return this.execButton(this.props.confirm);
}
// Processes the scanned product by barcode.
async scan_product(barcode) {
if (!this.isMounted) return;
var last_code = barcode;
var last_result = [];
last_result.push(last_code);
last_result = [];
beep.play();
Quagga.stop();
var order_id = this.props.order_id;
var method = this.props.model === "sale.order" ? "sale.order" : "purchase.order";
try {
const data = await this.orm.call(method, "barcode_search", [last_code, order_id]);
if (!this.isMounted) return;
if (data === true) {
this.notificationService.add(_t("Product with the scanned Barcode Not Found in the system"), {
title: _t("Product Not Found!"),
type: "danger",
});
} else {
location.reload(); // Ensure the page reloads after adding a product
}
} catch (error) {
if (this.isMounted) {
console.error("Error scanning product: ", error);
}
}
this._stopVideoStream();
this.props.close();
}
// Stops the video stream if it is active.
_stopVideoStream() {
if (this.videoPreviewRef.el && this.videoPreviewRef.el.srcObject) {
const tracks = this.videoPreviewRef.el.srcObject.getTracks();
tracks.forEach((track) => track.stop());
}
}
// sets button disabled
setButtonsDisabled(disabled) {
this.isProcess = disabled;
if (!this.modalRef.el) {
return;
}
for (const button of [...this.modalRef.el.querySelectorAll(".modal-footer button")]) {
button.disabled = disabled;
}
}
async execButton(callback) {
if (this.isProcess) {
return;
}
this.setButtonsDisabled(true);
if (callback) {
let shouldClose;
try {
shouldClose = await callback();
} catch (e) {
this.props.close();
throw e;
}
if (shouldClose === false) {
this.setButtonsDisabled(false);
return;
}
}
this.props.close();
}
}
BarcodeDialog.template = "BarcodeDialog";
BarcodeDialog.components = { Dialog };
BarcodeDialog.props = {
close: Function,
order_id: Number,
model: String,
title: {
validate: (m) => {
return (
typeof m === "string" || (typeof m === "object" && typeof m.toString === "function")
);
},
optional: true,
},
body: String,
confirm: { type: Function, optional: true },
confirmLabel: { type: String, optional: true },
confirmClass: { type: String, optional: true },
cancel: { type: Function, optional: true },
cancelLabel: { type: String, optional: true },
};
BarcodeDialog.defaultProps = {
confirmLabel: _t("Ok"),
cancelLabel: _t("Cancel"),
confirmClass: "btn-primary",
title: _t("Confirmation"),
};