Skip to Content
Menu
This question has been flagged
3 Replies
395 Views

Hello and thanks in advance.

I am trying to create custom model to update the qty on purchase order lines. I have the following code but it is not working:

class PurchaseOrderLines(models.Model):
    """Inherited the model for add field for barcode."""
    _inherit = "purchase.order.line"

    barcode_scan = fields.Char(string='Product Barcode',
                               related='product_id.barcode', readonly=False,
                               help="Here you can provide the barcode for "
                                    "the product")

    @api.onchange('barcode_scan')
    def _onchange_barcode_scan(self):
        """Onchange function for searching product using their barcode Including the Multi-Barcodes"""
        if self.barcode_scan:
            multi_barcode_id = self.env['product.template.barcode'].search([('name', '=', self.barcode_scan)])
            package_barcode = self.env['product.packaging'].search([('barcode', '=', self.barcode_scan)])
            product_idd = self.env['product.product'].search([('barcode', '=', self.barcode_scan)])
            if multi_barcode_id:
                self.product_id = multi_barcode_id.product_id
            elif package_barcode:
                self.product_id = package_barcode.product_id
self.product_quantity = package_barcode.qty
            else:
                self.product_id = product_idd


The line to update Qty is:

                self.product_quantity = package_barcode.qty

the purchase line qty is always one and does not update. How can override the default odoo code in the purchase line to update the qty I need.


Avatar
Discard
Author

I have also tried using that variable and still no change. the default qty 1 is always there regardless of the qty set in the package barcode

Author

Odoo AI suggested the following code but still no luck. odoo default actions kicks in and set the qty back to 1.


from odoo import models, fields, api

class PurchaseOrderLine(models.Model):
    _inherit = "purchase.order.line"

    barcode_scan = fields.Char(
        string='Product Barcode',
        readonly=False,
        help="Here you can provide the barcode for the product."
    )

    packaging_id = fields.Many2one(
        'product.packaging',
        string='Product Packaging',
        domain="[('product_id', '=', product_id)]" # Filter packagings based on the selected product
    )

    @api.onchange('barcode_scan')
    def _onchange_barcode_scan(self):
        """Onchange function for barcode input that finds product and updates quantity."""
        if self.barcode_scan:
            multi_barcode = self.env['product.template.barcode'].search([('name', '=', self.barcode_scan)], limit=1)
            packaging = self.env['product.packaging'].search([('barcode', '=', self.barcode_scan)], limit=1)
            product = self.env['product.product'].search([('barcode', '=', self.barcode_scan)], limit=1)

            if multi_barcode:
                self.product_id = multi_barcode.product_id
                self.packaging_id = False  # Clear packaging if a product barcode is scanned
            elif packaging:
                self.product_id = packaging.product_id
                self.packaging_id = packaging  # Set the packaging_id
            elif product:
                self.product_id = product
                self.packaging_id = False

            # Clear the barcode_scan field after processing
            self.barcode_scan = False

    @api.onchange('packaging_id')
    def _onchange_packaging_id(self):
        """Update product_qty based on the selected packaging."""
        if self.packaging_id:
            self.product_qty = self.packaging_id.qty
        else:
            # Handle when no packaging is selected
            if self.product_id:
                 # You might want to reset to the product's default purchase quantity
                 # (If you have a field for that on product.product)
                 self.product_qty = 1 # Example: Set a default quantity of 1
            else:
                 self.product_qty = 0 # Or a default value like 1 if no product is selected

Author Best Answer

After struggling to get the right code I finally found it. The following works perfectly all the time.

I hope this helps someone.

from odoo import models, fields, api

class PurchaseOrderLine(models.Model):
    _inherit = "purchase.order.line"

    barcode_scan = fields.Char(
                   string='Product Barcode',
                   readonly=False,
                   help="Scan the product barcode to automatically set the product and quantity."
                   )
    packaging_id = fields.Many2one(
        'product.packaging',
        string='Product Packaging',
        domain="[('product_id', '=', product_id)]" # Filter packagings based on the selected product
    )
    @api.onchange('barcode_scan')
    def _onchange_barcode_scan(self):
        if not self.barcode_scan:
            return
        barcode = self.barcode_scan.strip()
        packaging = self.env['product.packaging'].search([('barcode', '=', barcode)], limit=1)
        multi_barcode = self.env['product.template.barcode'].search([('name', '=', barcode)], limit=1)
        product = self.env['product.product'].search([('barcode', '=', barcode)], limit=1)
        if packaging:
            self.product_id = packaging.product_id
            self.packaging_id = packaging # Set the packaging_id field here
            self.product_qty = packaging.qty # Set quantity directly here as a fallback
        elif multi_barcode:
            self.product_id = multi_barcode.product_id
            self.packaging_id = False
        elif product:
            self.product_id = product
            self.packaging_id = False
        else:
            self.product_id = False
            self.packaging_id = False

    @api.onchange('product_id')
    def onchange_product_id_override(self): # Use a distinct name for your overriding method
        # Call the default Odoo onchange logic first
        super(PurchaseOrderLine, self).onchange_product_id()  # Use the correct parent method name here

        # After the default logic, update the quantity based on packaging
        if self.packaging_id:
            self.product_qty = self.packaging_id.qty

    @api.onchange('packaging_id')
    def _onchange_packaging_id(self):
        """Update product_qty based on the selected packaging."""
        if self.packaging_id:
            self.product_qty = self.packaging_id.qty
        else:
            # Optional: handle when no packaging is selected
            if self.product_id:
                 # You might want to reset to the product's default purchase quantity
                 self.product_qty = 1 # Example: Set a default quantity of 1
            else:
                 self.product_qty = 0 # Or a default value

Avatar
Discard
Best Answer

Hi,


You're on the right track, but the issue is that you're trying to set self.product_quantity, which doesn't exist on purchase.order.line. The correct field name for quantity in purchase.order.line is 'product_qty'.


Update your code as follows.


self.product_qty = package_barcode.qty


Hope it helps

Avatar
Discard
Best Answer

Hii,

Set product_qty after product selection and after Odoo's default logic finishes.

Use @api.onchange on barcode_scan and delay setting product_qty

Override the quantity after product assignment and onchange logic like this:

from odoo import models, fields, api class PurchaseOrderLine(models.Model): _inherit = "purchase.order.line" barcode_scan = fields.Char( string='Product Barcode', related='product_id.barcode', readonly=False, help="Here you can provide the barcode for the product." ) @api.onchange('barcode_scan') def _onchange_barcode_scan(self): """Onchange function for barcode input that finds product and updates quantity.""" if self.barcode_scan: # Search in multi-barcodes multi_barcode = self.env['product.template.barcode'].search([('name', '=', self.barcode_scan)], limit=1) # Search in packaging packaging = self.env['product.packaging'].search([('barcode', '=', self.barcode_scan)], limit=1) # Search in default barcode product = self.env['product.product'].search([('barcode', '=', self.barcode_scan)], limit=1) if multi_barcode: self.product_id = multi_barcode.product_id elif packaging: self.product_id = packaging.product_id # Delay setting product_qty so that _onchange_product_id doesn't override it self._update_quantity_after_onchange(packaging.qty) elif product: self.product_id = product def _update_quantity_after_onchange(self, qty): """Helper to delay setting quantity after default onchange logic.""" if qty > 0: self.product_qty = qty

This approach ensures that product_qty is set after the default product onchange logic.
i hope this code is use full

Avatar
Discard
Author

I have tried the entire block of code but it did not work. qty is always 1 regardless is how many is set on the packaging qty.

from odoo import models, fields, api

class PurchaseOrderLine(models.Model):
_inherit = "purchase.order.line"

barcode_scan = fields.Char(
string='Product Barcode',
readonly=False,
help="Scan the product barcode to automatically set the product and quantity."
)

@api.onchange('barcode_scan')
def _onchange_barcode_scan(self):
if not self.barcode_scan:
return

barcode = self.barcode_scan.strip()

# Try match in product.packaging first
packaging = self.env['product.packaging'].search([('barcode', '=', barcode)], limit=1)
multi_barcode = self.env['product.template.barcode'].search([('name', '=', barcode)], limit=1)
product = self.env['product.product'].search([('barcode', '=', barcode)], limit=1)

# Store quantity to be set *after* product_id onchange
self._barcode_matched_qty = 0 # Custom transient field, not stored

if packaging:
self.product_id = packaging.product_id
self._barcode_matched_qty = packaging.qty
elif multi_barcode:
self.product_id = multi_barcode.product_id
elif product:
self.product_id = product
else:
self.product_id = False

@api.onchange('product_id')
def _onchange_product_id_override(self):
super()._onchange_product_id()

# Apply delayed qty update if barcode matched a packaging
if hasattr(self, '_barcode_matched_qty') and self._barcode_matched_qty:
self.product_qty = self._barcode_matched_qty
del self._barcode_matched_qty # Clean up
please try this
i hope it is usefull

Author

Thank you for your help really, but Odoo is complaining

File "/opt/odoo18/custom/addons/barcode_scanning_sale_purchase/models/purchase_order_line.py", line 60, in _onchange_product_id_override
super()._onchange_product_id()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'super' object has no attribute '_onchange_product_id'

Hii,
from odoo import models, fields, api

class PurchaseOrderLine(models.Model):
_inherit = "purchase.order.line"

barcode_scan = fields.Char(
string='Product Barcode',
readonly=False,
help="Scan the product barcode to automatically set the product and quantity."
)

@api.onchange('barcode_scan')
def _onchange_barcode_scan(self):
if not self.barcode_scan:
return

barcode = self.barcode_scan.strip()

# Try to match barcode in different places
packaging = self.env['product.packaging'].search([('barcode', '=', barcode)], limit=1)
multi_barcode = self.env['product.template.barcode'].search([('name', '=', barcode)], limit=1)
product = self.env['product.product'].search([('barcode', '=', barcode)], limit=1)

# Store quantity to be set *after* product_id onchange
self._barcode_matched_qty = 0 # Temporary field, not stored

if packaging:
self.product_id = packaging.product_id
self._barcode_matched_qty = packaging.qty
elif multi_barcode:
self.product_id = multi_barcode.product_id
elif product:
self.product_id = product
else:
self.product_id = False

@api.onchange('product_id')
def _onchange_product_id_override(self):
super(PurchaseOrderLine, self)._onchange_product_id()

# Apply delayed quantity update if barcode matched a packaging
if hasattr(self, '_barcode_matched_qty') and self._barcode_matched_qty:
self.product_qty = self._barcode_matched_qty
del self._barcode_matched_qty # Clean up after use

try this
i hope it is finally work

Related Posts Replies Views Activity
2
May 25
2002
3
Dec 24
5962
1
Jul 24
2841
1
Jun 24
2007
2
Jun 24
2774