I added some fields to the model stock.move
and I importing a CSV file in order to create some records. I go over the all the rows and I create the records one by one as you can see here:
lot_id = self._get_lot_id(
n, row, product_id, picking_type_id,
box_quantity, product_uom_qty
)
move = {
'auto_lot_name': False,
'box_quantity': 2,
'client_order_ref': '581002',
'date': datetime.datetime(2017, 6, 24, 19, 55, 52, 372648),
'invoice_state': '2binvoiced',
'location_dest_id': 9,
'location_id': 12,
'name': 'Product name',
'partner_id': 487,
'partner_shipping_id': 488,
'picking_type_id': 2,
'price_unit': 4.0,
'pricelist_id': 1,
'product_code': u'36033',
'product_id': 3,
'product_uom': 3,
'product_uom_qty': 6.0,
'restrict_lot_id': 12222, # lot_id
'tax_id': [(4, 67)]
}
result = self.env['stock.move'].create(move)
I create the lot if needed in the method _get_lot_id
. If the lot is already created I return the id. This is working well
It is very simple and works well many times, but sometimes I get the following error despite that I am filling the field restrict_lot_id
with only one id as you can see in the dictionary. It looks like it is appending the lot id of the previous loop. How is that possible? Is my database broken?
File "/[ ... ]/import_moves/models/stock_picking_import_wizard.py", line 129, in _generate_moves_from_csv
result = self.env['stock.move'].create(move)
File "/[ ... ]/openerp/api.py", line 266, in wrapper
return new_api(self, *args, **kwargs)
File "/[ ... ]/openerp/api.py", line 508, in new_api
result = method(self._model, cr, uid, *args, **old_kwargs)
File "/[ ... ]/stock/stock.py", line 1993, in create
res = super(stock_move, self).create(cr, uid, vals, context=context)
File "/[ ... ]/openerp/api.py", line 268, in wrapper
return old_api(self, *args, **kwargs)
File "/[ ... ]/openerp/api.py", line 372, in old_api
result = method(recs, *args, **kwargs)
File "/[ ... ]/connector/producer.py", line 48, in create ##> strange because this module is not installed
record_id = create_original(self, vals)
File "/[ ... ]/openerp/api.py", line 266, in wrapper
return new_api(self, *args, **kwargs)
File "/[ ... ]/openerp/models.py", line 4126, in create
record = self.browse(self._create(old_vals))
File "/[ ... ]/openerp/api.py", line 266, in wrapper
return new_api(self, *args, **kwargs)
File "/[ ... ]/openerp/api.py", line 508, in new_api
result = method(self._model, cr, uid, *args, **old_kwargs)
File "/[ ... ]/openerp/models.py", line 4323, in _create
recs._validate_fields(vals)
File "/[ ... ]/openerp/api.py", line 266, in wrapper
return new_api(self, *args, **kwargs)
File "/[ ... ]/openerp/models.py", line 1285, in _validate_fields
raise ValidationError("Error while validating constraint\n\n%s" % tools.ustr(e))
ValidationError: ('ValidateError', u'Error while validating constraint\n\nValueError\nExpected singleton: stock.production.lot(12286, 12287)')
I have also verified that the id is arriving well inside the original create
function in the stock
module.
It does not make any sense to me. What is happening?
I have just checked that if I always create the lot it is working well. So something has to be wrong with the method _get_lot_id
that I show here
def _get_lot_id(self, n, row, product_id,
picking_type_id, box_quantity, product_uom_qty):
lot_id_name = row.get('lot_id_name', False)
if lot_id_name != '':
if picking_type_id == STOCK_PICKING_TYPE_OUT:
lot_ids = self.env['stock.production.lot'].search([
('product_id', '=', product_id.id),
('name', '=', lot_id_name)
])
if len(lot_ids) == 0:
try:
lot_id = self.env['stock.production.lot'].create({
'name': lot_id_name,
'product_id': product_id.id,
})
except Exception:
raise Warning(_('The lot could not be created. '
'\nROW: %s') % n)
return lot_id.ensure_one().id
if len(lot_ids) == 1:
return lot_ids[0].id
else:
raise Warning(_('ERROR\nThere is more than one lot with the same name for that product.'
'\nROW: %s') % n)
elif picking_type_id == STOCK_PICKING_TYPE_IN:
lot_ids = self.env['stock.production.lot'].search([
('product_id', '=', product_id.id),
('name', '=', lot_id_name)
])
if len(lot_ids) == 1:
return lot_ids[0].id
try:
lot_id = self.env['stock.production.lot'].create({
'name': lot_id_name,
'product_id': product_id.id,
})
return lot_id.id
except Exception:
raise Warning(_('The lot could not be created. '
'\nROW: %s') % n)
else:
if picking_type_id == STOCK_PICKING_TYPE_OUT:
raise Warning(_('The lot is required for outgoing moves. '
'\nROW: %s') % n)
elif picking_type_id == STOCK_PICKING_TYPE_IN:
# set "auto_lot_name = True" >> this is set by default, so the lot is automatically created
return False
I think the problem is in one of your code.
Let me explain why this error can happen in Odoo the self
in the method is a recordSet
, means it can contain a one or more record. When you use decorator
@api.multi
, depends
, or constraints
here self
can contain more than one record so to avoid this kind of errors make sure you loop
through self
.
for rec in self:
# your code here
# always access to rec fields not self here
If you don't loop when you do self.some_field
this works fine when the recordset
have only one record but when you have more this is confusing what record you want to get the value of some_field
from and here you get this error.
But when you use decorator @api.one
here will call the method for each record , singleton error never happen with api.one
because self always contains one recorrd.
Probably the create
method has been overridden by some custom (or not) module which modifies the vals passed to the create function.
A way to find out what is happening would be to go to the definition of create
method of stock.production.lot
model (addons/stock/stock.py) and either raise an Exception or import traceback;traceback.print_stack()
to see the methods that are called. After that you can see the one which changes your values.
If that is not the case, you have to share more code for us to see what is going on and how do you create the move
dictionary
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With