|  | 
from odoo import api, fields, models
from odoo.exceptions import UserError
class Warehouse(models.Model):
    _name = 'warehouse'
    _description = '仓库'
    # 用户只能创建stock类型的仓库
    WAREHOUSE_TYPE = [
        ('stock', '库存'),
        ('supplier', '供应商'),
        ('customer', '客户'),
        ('inventory', '盘点'),
        ('production', '生产'),
        ('others', '其他'),
    ]
    display_name = fields.Char(compute='_compute_display_name', store=True)
    name = fields.Char('名称', required=True)
    code = fields.Char('编号')
    type = fields.Selection(WAREHOUSE_TYPE, '类型', default='stock')
    active = fields.Boolean('启用', default=True)
    user_ids = fields.Many2many('res.users', string='库管')
    address = fields.Char('地址')
    phone = fields.Char('电话')
    contact = fields.Char('联系人')
    company_id = fields.Many2one(
        'res.company',
        string='公司',
        change_default=True,
        default=lambda self: self.env.company)
    _sql_constraints = [
        ('name_uniq', 'unique(name)', '仓库不能重名')
    ]
    @api.model
    def name_search(self, name='', args=None, operator='ilike', limit=100):
        ''' 让warehouse支持使用code来搜索'''
        args = args or []
        # 将name当成code搜
        if name and not [_type for _type in args if _type[0] == 'code']:
            warehouses = self.search(
                [('type', '=', 'stock'), ('code', 'ilike', name)])
            if warehouses:
                return warehouses.name_get()
        # 下拉列表只显示stock类型的仓库
        if not [_type for _type in args if _type[0] == 'type']:
            args = [['type', '=', 'stock']] + args
        return super(Warehouse, self).name_search(
            name=name, args=args,
            operator=operator, limit=limit)
    def name_get(self):
        '''将仓库显示为 [编号]名字 的形式'''
        res = []
        for Warehouse in self:
            res.append((Warehouse.id, '[%s]%s' %
                        (Warehouse.code, Warehouse.name)))
        return res
    @api.depends('code', 'name')
    def _compute_display_name(self):
        '''将仓库显示为 [编号]名字 的形式,  注意原来的 name_get 被name_search使用, 不能删除'''
        for record in self:
            record.display_name= record.code and (record.code + '_' + record.name) or record.name
    def get_warehouse_by_type(self, _type, need_user_ids=True):
        '''返回指定类型的第一个仓库'''
        if not _type or _type not in [
                _type[0] for _type in self.WAREHOUSE_TYPE]:
            raise UserError('仓库类型" % s"不在预先定义的type之中,请联系管理员' % _type)
        domain = [('type', '=', _type)]
        # 仓库管理员带出有权限的仓库作为默认值
        if _type == 'stock' and self.env.user.has_group('warehouse.group_warehouse') and need_user_ids:
            # 由于权限组在仓库模块,这里core模块测试用例测不到
            domain += ['|', ('user_ids', '=', False),
                       ('user_ids', 'in', self._uid)]
        warehouses = self.search(domain, limit=1, order='id asc')
        if not warehouses:
            raise UserError('不存在类型为%s的仓库,请检查基础数据是否全部导入' % _type)
        return warehouses[0]
    def write(self, vals):
        # 如果仓库里存有商品,则禁止此仓库存档并提示错误
        if 'active' in vals and not vals['active']:
            name_list = []
            for line in self:
                name_list.append(line.name)
            stock = self.env['report.stock.balance'].search([('warehouse', 'in', name_list), ('goods_qty', '!=', 0)])
            name_list = []
            for li in stock:
                name_list.append(li.warehouse)
            raise UserError('仓库名称为%s的仓库库存不为0' % str(set(name_list)))
        return super().write(vals)
 |