@ -0,0 +1,50 @@ |
|||||
|
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg |
||||
|
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html |
||||
|
:alt: License: AGPL-3 |
||||
|
|
||||
|
Scan Product Barcode for Sale & Purchase |
||||
|
======================================== |
||||
|
This module captures barcode of products through system camera and add product |
||||
|
to order line. |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
* No additional configurations are required |
||||
|
|
||||
|
Company |
||||
|
======= |
||||
|
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
||||
|
|
||||
|
License |
||||
|
======= |
||||
|
GNU LESSER GENERAL PUBLIC LICENSE, Version 3 (AGPLv3) |
||||
|
(https://www.gnu.org/licenses/agpl-3.0-standalone.html) |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
* Developers: (V18) Manasa T P, |
||||
|
(V17) Subina , |
||||
|
(V16) RAHUL C K, |
||||
|
Contact: odoo@cybrosys.com |
||||
|
|
||||
|
Contacts |
||||
|
======== |
||||
|
* Mail Contact : odoo@cybrosys.com |
||||
|
* Website : https://cybrosys.com |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
||||
|
|
||||
|
Maintainer |
||||
|
========== |
||||
|
.. image:: https://cybrosys.com/images/logo.png |
||||
|
:target: https://cybrosys.com |
||||
|
|
||||
|
This module is maintained by Cybrosys Technologies. |
||||
|
|
||||
|
For support and more information, please visit https://www.cybrosys.com. |
||||
|
|
||||
|
Further information |
||||
|
=================== |
||||
|
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################ |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Manasa T P (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################ |
||||
|
from . import models |
@ -0,0 +1,58 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################ |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Manasa T P (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################ |
||||
|
{ |
||||
|
'name': "Scan Product Barcode for Sale & Purchase", |
||||
|
'version': '18.0.1.0.0', |
||||
|
'category': 'Extra Tools', |
||||
|
'summary': """Scan Barcode from Camera in sale and purchase orders.""", |
||||
|
'description': """Products can be added to sale or purchase orders by |
||||
|
scanning barcode of products through system camera. Products will be |
||||
|
automatically added to order line once the barcode is identified.""", |
||||
|
'author': "Cybrosys Techno Solutions", |
||||
|
'company': "Cybrosys Techno Solutions", |
||||
|
'maintainer': "Cybrosys Techno Solutions", |
||||
|
'website': "https://www.cybrosys.com", |
||||
|
'depends': ['sale_management', 'purchase'], |
||||
|
'data': [ |
||||
|
'views/sale_order_views.xml', |
||||
|
'views/purchase_order_views.xml' |
||||
|
], |
||||
|
'assets': { |
||||
|
'web.assets_backend': [ |
||||
|
'https://cdn.jsdelivr.net/npm/quagga@0.12.1/dist/quagga.min.js', |
||||
|
'barcode_capturing_sale_purchase/static/src/js/registry_barcode_sale.js', |
||||
|
'barcode_capturing_sale_purchase/static/src/js/registry_barcode_purchase.js', |
||||
|
'barcode_capturing_sale_purchase/static/src/js/sale_barcode.js', |
||||
|
'barcode_capturing_sale_purchase/static/src/js/purchase_barcode.js', |
||||
|
'barcode_capturing_sale_purchase/static/src/js/barcode_dialog.js', |
||||
|
'barcode_capturing_sale_purchase/static/src/css/styles.css', |
||||
|
'barcode_capturing_sale_purchase/static/src/xml/purchase_web_form_templates.xml', |
||||
|
'barcode_capturing_sale_purchase/static/src/xml/sale_web_form_templates.xml', |
||||
|
'barcode_capturing_sale_purchase/static/src/xml/barcode_dialog_templates.xml', |
||||
|
], |
||||
|
}, |
||||
|
'images': ['static/description/banner.jpg'], |
||||
|
'license': 'AGPL-3', |
||||
|
'installable': True, |
||||
|
'auto_install': False, |
||||
|
'application': False, |
||||
|
} |
@ -0,0 +1,7 @@ |
|||||
|
## Module <barcode_capturing_sale_purchase> |
||||
|
|
||||
|
#### 09.04.2025 |
||||
|
#### Version 18.0.1.0.0 |
||||
|
#### ADD |
||||
|
|
||||
|
- Initial commit for Scan Product Barcode for Sale & Purchase |
@ -0,0 +1,23 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################ |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Manasa T P (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################ |
||||
|
from . import purchase_order |
||||
|
from . import sale_order |
@ -0,0 +1,57 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################ |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Manasa T P (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################ |
||||
|
from odoo import api, models |
||||
|
|
||||
|
|
||||
|
class PurchaseOrder(models.Model): |
||||
|
"""Module is inherited and function is created to create a purchase |
||||
|
order line with the scanned barcode of product""" |
||||
|
_inherit = 'purchase.order' |
||||
|
|
||||
|
@api.model |
||||
|
def barcode_search(self, last_code, order_id): |
||||
|
"""Purchase Order line is created and product is added by checking |
||||
|
the barcode. args contains the barcode of product and purchase order |
||||
|
id""" |
||||
|
product = self.env['product.product'].search([('barcode', '=', |
||||
|
last_code)]) |
||||
|
if not product: |
||||
|
return True |
||||
|
else: |
||||
|
purchase_order = self.browse(order_id) |
||||
|
if purchase_order.order_line: |
||||
|
for rec in purchase_order.order_line: |
||||
|
if rec.product_id == product: |
||||
|
rec.product_qty += 1 |
||||
|
return { |
||||
|
'type': 'ir.actions.client', |
||||
|
'tag': 'reload', |
||||
|
} |
||||
|
purchase_order.order_line.create({ |
||||
|
'order_id': purchase_order.id, |
||||
|
'product_id': product.id, |
||||
|
'product_uom_qty': 1 |
||||
|
}) |
||||
|
return { |
||||
|
'type': 'ir.actions.client', |
||||
|
'tag': 'reload', |
||||
|
} |
@ -0,0 +1,49 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################ |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Manasa T P (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################ |
||||
|
from odoo import api, models |
||||
|
|
||||
|
|
||||
|
class SaleOrder(models.Model): |
||||
|
"""Module is inherited and function is created to create a sale |
||||
|
order line with the scanned barcode of product""" |
||||
|
_inherit = 'sale.order' |
||||
|
|
||||
|
@api.model |
||||
|
def barcode_search(self, last_code, order_id): |
||||
|
"""Sale Order line is created and product is added by checking |
||||
|
the barcode. args contains the barcode of product and sale order id.""" |
||||
|
product = self.env['product.product'].search([('barcode', '=', |
||||
|
last_code)]) |
||||
|
if not product: |
||||
|
return True |
||||
|
else: |
||||
|
sale_order = self.browse(order_id) |
||||
|
if sale_order.order_line: |
||||
|
for rec in sale_order.order_line: |
||||
|
if rec.product_id == product: |
||||
|
rec.product_uom_qty += 1 |
||||
|
return |
||||
|
sale_order.order_line.create({ |
||||
|
'order_id': sale_order.id, |
||||
|
'product_id': product.id, |
||||
|
'product_uom_qty': 1 |
||||
|
}) |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 628 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 210 KiB |
After Width: | Height: | Size: 209 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 495 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 624 B |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 214 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 929 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 542 B |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 156 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 600 B |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 462 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 926 B |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 800 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 189 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 875 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 912 KiB |
After Width: | Height: | Size: 767 KiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 138 KiB |
After Width: | Height: | Size: 760 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 697 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 331 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 880 KiB |
After Width: | Height: | Size: 144 KiB |
After Width: | Height: | Size: 8.5 KiB |
@ -0,0 +1,3 @@ |
|||||
|
.btn-close{ |
||||
|
display:none; |
||||
|
} |
@ -0,0 +1,181 @@ |
|||||
|
/** @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"), |
||||
|
}; |
@ -0,0 +1,64 @@ |
|||||
|
/** @odoo-module **/ |
||||
|
import { FormController } from "@web/views/form/form_controller"; |
||||
|
import { Dialog } from "@web/core/dialog/dialog"; |
||||
|
import { BarcodeDialog } from "./barcode_dialog.js"; |
||||
|
import { useChildRef, useService } from "@web/core/utils/hooks"; |
||||
|
import { Component, onWillUnmount, EventBus } from "@odoo/owl"; |
||||
|
import { _t } from "@web/core/l10n/translation"; |
||||
|
|
||||
|
var beep = new Audio('/barcode_capturing_sale_purchase/static/src/audio/beep_scan.mp3'); |
||||
|
// Extends FormController for rendering the purchase order form with barcode scanning functionality.
|
||||
|
export class ComPurchaseOrderRender extends FormController { |
||||
|
setup() { |
||||
|
this.bus = new EventBus(); |
||||
|
this.modalRef = useChildRef(); |
||||
|
this.isProcess = false; |
||||
|
this.dialog = useService("dialog"); |
||||
|
this.notificationService = useService("notification"); |
||||
|
onWillUnmount(() => { |
||||
|
if (this.stream) { |
||||
|
this.stream.getTracks().forEach((track) => track.stop()); |
||||
|
this.stream = null; |
||||
|
} |
||||
|
}); |
||||
|
super.setup(); |
||||
|
} |
||||
|
// Opens a dialog for barcode scanning.
|
||||
|
async PurchaseBarcodeDialog() { |
||||
|
var self = this; |
||||
|
var load_params = self.model.config; |
||||
|
var model = this.props.resModel |
||||
|
if(load_params.resId){ |
||||
|
var order_id = load_params.resId; |
||||
|
} |
||||
|
else{ |
||||
|
if(load_params.resIds[0]){ |
||||
|
var order_id = load_params.resIds[0]; |
||||
|
} |
||||
|
else{ |
||||
|
this.notificationService.add(_t("Create or Save Purchase Order to start barcode scan"), { |
||||
|
title: _t("Create/save Order"), |
||||
|
type: "danger", |
||||
|
}); |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
// Opens a Dialog box for scanning barcode
|
||||
|
const constraints = { |
||||
|
video: { facingMode: this.props.facingMode }, |
||||
|
audio: false, |
||||
|
}; |
||||
|
try { |
||||
|
this.dialog.add(BarcodeDialog, { |
||||
|
title: _t("Barcode Scanner"), |
||||
|
body: _t("An administrator needs to configure Google Synchronization before you can use it!"), |
||||
|
close: true, |
||||
|
order_id: order_id, |
||||
|
model: model, |
||||
|
}); |
||||
|
} catch (err) { |
||||
|
window.alert('Failed to detect webcam.Please ensure that your browser has the required permissions to access your webcam.') |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
ComPurchaseOrderRender.template = "barcode_capturing_sale_purchase.purchase_scanner"; |
@ -0,0 +1,11 @@ |
|||||
|
/** @odoo-module **/ |
||||
|
import { formView } from '@web/views/form/form_view'; |
||||
|
import { FormController } from '@web/views/form/form_controller'; |
||||
|
import { registry } from "@web/core/registry"; |
||||
|
import { ComPurchaseOrderRender } from '@barcode_capturing_sale_purchase/js/purchase_barcode'; |
||||
|
//JsClassBarcodePurchase constant is added to views registry
|
||||
|
export const JsClassBarcodePurchase = { |
||||
|
...formView, |
||||
|
Controller: ComPurchaseOrderRender, |
||||
|
}; |
||||
|
registry.category("views").add("purchase_order_barcode", JsClassBarcodePurchase); |