记一次M2O字段创建报错调试

起因

image.png

一个简单的form页面,根据入库单据的选择,带出对应的明细行,而在明细行中入库单行即为一个M2O字段关联了入库明细行,就在这个保存这个表单时报了下面的错误提示

Traceback (most recent call last):
  File "D:\odoo\gooderp_\openobject\odoo\http.py", line 640, in _handle_exception
    return super(JsonRequest, self)._handle_exception(exception)
  File "D:\odoo\gooderp_\openobject\odoo\http.py", line 677, in dispatch
    result = self._call_function(**self.params)
  File "D:\odoo\gooderp_\openobject\odoo\http.py", line 333, in _call_function
    return checked_call(self.db, *args, **kwargs)
  File "D:\odoo\gooderp_\openobject\odoo\service\model.py", line 101, in wrapper
    return f(dbname, *args, **kwargs)
  File "D:\odoo\gooderp_\openobject\odoo\http.py", line 326, in checked_call
    result = self.endpoint(*a, **kw)
  File "D:\odoo\gooderp_\openobject\odoo\http.py", line 935, in __call__
    return self.method(*args, **kw)
  File "D:\odoo\gooderp_\openobject\odoo\http.py", line 506, in response_wrap
    response = f(*args, **kw)
  File "D:\odoo\gooderp_\openobject\odoo\addons\web\controllers\main.py", line 885, in call_kw
    return self._call_kw(model, method, args, kwargs)
  File "D:\odoo\gooderp_\openobject\odoo\addons\web\controllers\main.py", line 877, in _call_kw
    return call_kw(request.env[model], method, args, kwargs)
  File "D:\odoo\gooderp_\openobject\odoo\api.py", line 687, in call_kw
    return call_kw_model(method, model, args, kwargs)
  File "D:\odoo\gooderp_\openobject\odoo\api.py", line 672, in call_kw_model
    result = method(recs, *args, **kwargs)
  File "D:\odoo\gooderp_\myaddons_gooderp\hui_change_cost\models\change_cost.py", line 180, in create
    return super(ChangeCost, self).create(vals)
  File "D:\odoo\gooderp_\gooderp\good_process\models\mail_thread.py", line 191, in create
    thread_row = super(MailThread, self).create(vals)
  File "D:\odoo\gooderp_\openobject\odoo\addons\mail\models\mail_thread.py", line 228, in create
    thread = super(MailThread, self).create(values)
  File "D:\odoo\gooderp_\gooderp\core\models\core.py", line 38, in create
    record_id = create_original(self, vals)
  File "D:\odoo\gooderp_\openobject\odoo\models.py", line 3826, in create
    record = self.browse(self._create(old_vals))
  File "D:\odoo\gooderp_\openobject\odoo\models.py", line 3975, in _create
    field.write(self.with_context(rel_context), vals[name])
  File "D:\odoo\gooderp_\openobject\odoo\fields.py", line 2215, in write
    comodel.create(act[2])
  File "D:\odoo\gooderp_\gooderp\core\models\core.py", line 38, in create
    record_id = create_original(self, vals)
  File "D:\odoo\gooderp_\openobject\odoo\models.py", line 3826, in create
    record = self.browse(self._create(old_vals))
  File "D:\odoo\gooderp_\openobject\odoo\models.py", line 3921, in _create
    cr.execute(query, tuple(u[2] for u in updates if len(u) > 2))
  File "D:\odoo\gooderp_\openobject\odoo\sql_db.py", line 154, in wrapper
    return f(self, *args, **kwargs)
  File "D:\odoo\gooderp_\openobject\odoo\sql_db.py", line 231, in execute
    res = self._obj.execute(query, params)
ProgrammingError: ARRAY types integer and boolean cannot be matched
LINE 1: ...0', NULL, 35, '0.0000', 1, '0', NULL, ARRAY[7295, false], NU...

翻译过来的意思就是数据库中整型字段不能填入一个数组格式,正常一个M2O存入数据库中应该是一个id值为什么会变成一个数组呢?

追踪过程

前端页面保存一个新的记录肯定是调用模型的create方法,重写create打印创建字典

image.png

确实这个in_move_line字段的值变成了一个数组,但是仔细看uom_id也是个M2O字段,但它确实正常id值,所以继续从前端传值查追查看什么时候这里变成了数组

image.png

从前端create的请求参数中发现,这个in_move_line还是一个数组,继续往调用堆栈中查找什么时候变成了数组,
data_model.js 中rpc调用的后端create方法,-->data.js中的create方法,-->orm_view.js中的_process_save方法
image.png

最终找到create的值是在_process_save方法中的get_value中获取各个字段的值,最终在form_relational_widgets.js中找到O2M的get_value方法,在该方法中有对M20取值的方法:

                // format many2one values
                for (var k in values) {
                    if ((values[k] instanceof Array) && values[k].length === 2 && typeof values[k][0] === "number" && typeof values[k][1] === "string") {
                        values[k] = values[k][0];
                    }
                }

注意这里的判断: 如果字段是一个数组且数组长度为2,数组第一个元素是数字类型,第二个元素是字符串类型,那么就会将这个数字的第一个元素,也就是M20字段的id值取出来,而我的问题恰恰就出在数组中的第二个元素是false,并不是字符串,到此我以为就是因为in_move_line中没有name字段的原因导致的为false,但经过其他模型M20的实验发现并不是,在前端中关系字段的默认格式应该是[id,model_name,id],第二个元素不可能是false,既然和原生的不一样,那么大胆猜测一下就应该是in_move_line的name_get方法被重写了吧,果然被我找到了重写方法(gooderp原生代码)

@api.multi
def name_get(self):
  res = []
  for line in self:
    if self.env.context.get('match'):
      res.append((line.id, '%s-%s->%s(%s, %s%s)' %
        (line.move_id.name, line.warehouse_id.name, line.warehouse_dest_id.name,
          line.goods_id.name, str(line.goods_qty), line.uom_id.name)))
    else:
      res.append((line.id, line.lot))
  return res

一般返回都是(line.id, line.lot),如果明细行没有批号就会导致false值

总结

  • 导致这个报错的原因一方面感觉odoo10前端中对这个判断不太恰当,第二个元素非要是字符串才可以,但是name_get这个方法也是经常重写用于替换M20展示名的,第二个方面就是gooderp中没有考虑到明细行中没批号的情况导致了false。

  • 这个问题估计也比较难复现,而且odoo的前端改动太大,在13中压根就没有form_relational_widgets.js文件,如果遇到类似问题的小伙伴,可以按这个思路去排查一下吧,解决方法就仁者见仁智者见智,比如一开始百思不得其解时我就暴力的重写create方法将list改回了id值.

  • 最后感谢一下Ruter大佬提供排查的思路

你可能感兴趣的:(记一次M2O字段创建报错调试)