Dodałem kilka pól do modelu stock.move i importuję plik CSV w celu utworzenia niektórych rekordów. Przechodzę przez wszystkie rzędy i tworzę rekordy na jeden, jak widać tutaj:

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)

Tworzę dużo w razie potrzeby w metodzie _get_lot_id. Jeśli partia jest już utworzona, zwracam identyfikator. To działa dobrze

Jest bardzo prosty i działa dobrze wiele razy, ale czasami dostaję następujący błąd pomimo tego, że wypełniam pole restrict_lot_id z tylko jednym identyfikatorem, jak widać w słowniku. Wygląda na to, że jest to dołączanie identyfikatora partii poprzedniej pętli. Jak to możliwe? Czy moja baza danych jest uszkodzona?

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

Weryfikowałem również, że identyfikator jest dobrze przyjeżdża wewnątrz funkcji oryginału {x0}} w module stock. Nie ma dla mnie sensu. Co się dzieje?

Właśnie sprawdziłem, że jeśli zawsze tworzę dużo, to działa dobrze. Więc coś musi być nie tak z metodą _get_lot_id, którą tutaj pokazuję

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
4
ChesuCR 24 czerwiec 2017, 23:34

3 odpowiedzi

Najlepsza odpowiedź

Myślę, że problem jest w jednym z twoich kodu.

Pozwól mi wyjaśnić, dlaczego ten błąd może się zdarzyć w Odaoo self w metodzie jest recordSet, oznacza, że może zawierać jeden lub więcej rekordów. Kiedy używasz dekoratora @api.multi, depends lub constraints tutaj self może zawierać więcej niż jeden rekord, aby uniknąć tego rodzaju błędów upewnij się, że loop przez {{x7} }.

     for rec in self:
               # your code here
               # always access to rec fields not self here

Jeśli nie pętli, kiedy to zrobisz self.some_field Działa dobrze, gdy recordset ma tylko jeden rekord, ale kiedy masz więcej, jest to mylące, co chcesz uzyskać wartość some_field Od i tutaj otrzymujesz ten błąd.

Ale kiedy używasz dekoratora @api.one tutaj wywołuje metodę dla każdego rekordu, Błąd Singleton nigdy nie stanie się z api.one, ponieważ ja zawsze zawiera jeden Recurrd.

6
Charif DZ 15 sierpień 2019, 22:02

W końcu znalazłem błąd. Błąd był w polu obliczonym, jak powiedział @cherif Odo. Miałem tę metodę

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

I musiałem zastąpić self z lot w ten sposób

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

Nie znalazłem błędu wcześniej, ponieważ ślad stosu nie był bardzo przydatny. Znalazłem go po komentarzu metodach, polach, ograniczeń, tworzy ...

1
ChesuCR 27 czerwiec 2017, 10:59

Prawdopodobnie metoda create została nadpisana przez niektóre niestandardowe (lub nie) moduł, który modyfikuje Vals przekazywane do funkcji Utwórz.

Sposób, aby dowiedzieć się, co się dzieje, byłoby przejść do definicji create Metoda stock.production.lot Model (Dodatki / Stock / Stock.py) i podnoszą wyjątek lub import traceback;traceback.print_stack() Zobacz metody, które są nazywane. Po tym możesz zobaczyć ten, który zmienia twoje wartości.

Jeśli tak nie jest, musisz udostępnić więcej kodu, aby zobaczyć, co się dzieje i jak tworzysz słownik move

1
George Daramouskas 24 czerwiec 2017, 21:33