模块二 多公司多仓库库存显示

本模块的创作来源于客户的实际需求,原生odoo想要同时查看多公司下的库存需要切换公司,不能在某个公司下同时一览多个公司的库存。为了解决这个问题,笔者因此开发了本模块(基于13.0)。

设计思路

如果按照客户原始的需求,我们需要在产品模型中给每个公司创建一个专属的字段来统计该公司下面的库存,这个思路的问题在于,公司是动态的,我们没新增一个公司就要改动一次代码,可维护性并不高。

因此我想的是,能否根据当前登录用户所拥有权限的公司动态地显示每个公司下的库存。该思路的难点在于,要解决动态公司添加(删除的可能性比较小)的问题。

另外一个问题,就是新增字段的显示问题,我们要根据每个公司显示相应的库存,那么对应的字段势必就要根据每个公司的名称定制,因此属于一个动态label的问题。

开发过程

下面我们来一个一个解决这些问题,首先是在产品信息中针对每个公司新增一个库存字段的问题。很显然,我们不能使用新增一个公司改一次代码的低效方式,我们知道,odoo中有几个字段是具备魔法属性的,即每个模型都能自动新增,例如,create_uid, write_uid。那么,我们能不能自定义魔法字段呢?答案显然是肯定的,我们可以利用基础模型中的_add_magic_fields方法在模块安装/升级的过程中自动给每个公司新增一个库存字段。

@api.model
def _add_magic_fields(self):
    """Add company stock fields."""
    company_ids = self.env['res.company'].search([])
    for company_id in company_ids:
        name = f"{PRE}{company_id.id}"
        field = fields.Float(string=f"{company_id.short_name or company_id.name}{company_id.stock_string or APD}", compute="_compute_multi_company_quanity")
        self._add_field(name, field)
    return super()._add_magic_fields()

依照设计,我们自动给产品模型新增的字段要跟每个公司对应,因此我们给新增的字段制定了一个套命名标注:

available_qty_company_x

其中x是公司的ID,即假如我们有2家公司,那么新增的字段会被命名为

  • available_qty_company_1
  • available_qty_company_2

解决了字段新增的问题,那么接下来我们来解决新增字段的命名问题。假设我们这里的两家公司名称分别为苹果和微软,那么我们希望看到的字段命名方式为: 苹果库存,微软库存。考虑到公司名称会变,因此这个label必须是动态的,而不能像其他字段一样硬编码在代码里。那么我们怎么来实现动态lable这个需求呢?

以往我们解决动态label的思路是在视图中创建两个相同的字段,根据不同的条件显示不同的label。很显然,这种方式并不适用于本场景。那么我们想到了,既然label要动态显示,那么我就动态修改视图的返回值,可能写到这里有的同学已经猜到答案了,是的,我们的解决这个拦路虎的武器就是fields_view_get方法,关于fields_view_get方法的内容请参考第二部分ORM一章。

@api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
    """add magic fields to tree view."""
    res = super().fields_view_get(view_id=view_id,
                                    view_type=view_type, toolbar=toolbar, submenu=submenu)
    if view_type == 'tree':
        doc = etree.XML(res['arch'])
        node = doc.xpath("//field[@name='qty_available']")[0]
        index = doc.index(node) +1
        for company_id in self.env.user.company_ids:
            key = f"{PRE}{company_id.id}"
            if key not in self._get_available_fields():
                continue
            field = etree.Element("field",{
                'name': key
            })
            node.getparent().insert(index, field)
        res['arch'] = etree.tostring(doc)
    return res

fields_view_get方法里主要处理的就是使用xpath将当前登录用户可访问的公司的库存字段添加到视图中。

关于_add_magic_fields方法更多的内容,请参考第五部分模型一章。

避坑指南

原本以为思路很清晰,编码应该不会太麻烦,然而实际过程却是,纸上得来终觉浅,绝知此事要躬行。这里简单总结一下碰到的问题:

多公司的库存统计

原本的思路是使用with_context,切换一下公司主体,就能得到即时库存。然而事实是,在新创建的数据库中完美可行,发布到客户测试环境失败,目前怀疑是不知道是哪个第三方模块的重载代码不规范使with_context的force_company失效。后来的解决方案是,根据当前公司寻找所属根库位,直接查找相库位的库存。

总结: force_company并非100%可靠。

公司名字太长,导致字段名字太长

通常我们的公司名字全称都挺长,这样就导致我们最后生成的列表视图字段名称很长,不是很美观,因此,我们在模块中给每个公司新增了一个简称字段,这样在显示库存的时候就可以使用简称。

但是使用动态名称的后果就是,每次在新增公司以后,都要将我们的模块重新升级一边才可以正常显示。

事例

我们在测试环境中安装了本模块,可以看下面的示例:

技术支持

因为是客户定制模块,因此只实现了13.0版本,如有同学需要可以付费购买此模块或基于此定制特定版本。

results matching ""

    No results matching ""