尽管只发送了一个ID,为什么我会收到错误“预期单身人士”?

时间:2017-06-24 20:34:08

标签: python odoo-8 odoo recordset

我在模型stock.move中添加了一些字段,然后导入CSV文件以创建一些记录。我查看了所有行,然后逐个创建记录,如您所见:

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)

我在方法_get_lot_id中根据需要创建了批次。如果已经创建了批次,则返回id。这很好用

这很简单并且运行很多次,但有时我会得到以下错误,尽管我在字段restrict_lot_id中只填充了一个id,如字典中所示。它看起来像是附加了前一个循环的批次ID。怎么可能?我的数据库坏了吗?

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)')

我还验证了id正好位于create模块中原始stock函数内部。 这对我没有任何意义。发生了什么事?

我刚刚检查过,如果我总是创造它,它运作良好。因此,我在此处显示的方法_get_lot_id存在一些问题

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

3 个答案:

答案 0 :(得分:5)

我认为问题在于您的代码之一,请确保在对代码进行注释时重新启动服务器。 但是让我解释为什么这个错误可能发生在odoo中,方法中的self是一个记录集,意味着它可以包含一个或多个记录。当你使用装饰 @ api.multi,depends或约束这里self可以包含多个记录,以避免这种错误,确保你循环自我。

     for rec in self:
               # your code here

如果您在执行self.some_field时没有循环,当记录集只有一条记录时这可以正常工作但是当你有更多记录时,这会让你想要获得some_field的值的记录令人困惑你得到这个错误。

但是当你在这里使用decorator @ api.one时,你告诉odoo在自己中传递一条记录,所以单身错误永远不会与api.one一起使用api.one不建议使用api.one

检查原始插件中的代码,他们在计算字段中使用几乎循环。

当我在学习odoo时,这个错误让我发疯。阅读decorator one和multi以了解差异

答案 1 :(得分:1)

可能某个自定义(或不​​是)模块覆盖了create方法,该模块修改了传递给create函数的val。

找出正在发生的事情的方法是转到create模型的stock.production.lot方法的定义(addons / stock / stock.py)并提出异常或{{1查看被调用的方法。之后,您可以看到改变价值的那个。

如果不是这样,您必须为我们分享更多代码才能看到正在发生的事情以及如何创建import traceback;traceback.print_stack()字典

答案 2 :(得分:1)

最后我发现了错误。 @Cherif Odoo说,错误发生在计算字段中。我有这个方法

@api.multi
@api.depends('incoming_moves', 'incoming_moves.box_quantity')
def _compute_in_box_vqty(self):
    for lot in self:
        lot.in_box_vqty = sum(
            move.box_quantity for move in self.incoming_moves)

我必须将self替换为lot,如此

@api.multi
@api.depends('incoming_moves', 'incoming_moves.box_quantity')
def _compute_in_box_vqty(self):
    for lot in self:
        lot.in_box_vqty = sum(
            move.box_quantity for move in lot.incoming_moves)

我之前没有找到错误,因为堆栈跟踪不是很有用。我在评论方法,字段,约束后创建了......