起因
一个简单的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打印创建字典
确实这个in_move_line
字段的值变成了一个数组,但是仔细看uom_id
也是个M2O字段,但它确实正常id值,所以继续从前端传值查追查看什么时候这里变成了数组
从前端create的请求参数中发现,这个
in_move_line
还是一个数组,继续往调用堆栈中查找什么时候变成了数组,
data_model.js 中rpc调用的后端create方法,-->data.js中的create方法,-->orm_view.js中的_process_save方法
最终找到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大佬提供排查的思路