Exemplo n.º 1
0
class SMSTemplatePreview(models.TransientModel):
    _inherit = "sms.template"
    _name = "sms.template.preview"
    _description = "SMS Template Preview"

    @api.model
    def _selection_target_model(self):
        models = self.env['ir.model'].search([])
        return [(model.model, model.name) for model in models]

    @api.model
    def _selection_languages(self):
        return self.env['res.lang'].get_installed()

    @api.model
    def default_get(self, fields):
        result = super(SMSTemplatePreview, self).default_get(fields)
        sms_template = self._context.get(
            'default_sms_template_id') and self.env['sms.template'].browse(
                self._context['default_sms_template_id']) or False
        if sms_template and not result.get('res_id'):
            result['res_id'] = self.env[sms_template.model].search([], limit=1)
        return result

    sms_template_id = fields.Many2one(
        'sms.template')  # NOTE This should probably be required

    lang = fields.Selection(_selection_languages,
                            string='Template Preview Language')
    model_id = fields.Many2one('ir.model', related="sms_template_id.model_id")
    res_id = fields.Integer(string='Record ID')
    resource_ref = fields.Reference(string='Record reference',
                                    selection='_selection_target_model',
                                    compute='_compute_resource_ref',
                                    inverse='_inverse_resource_ref')

    @api.depends('model_id', 'res_id')
    def _compute_resource_ref(self):
        for preview in self:
            if preview.model_id:
                preview.resource_ref = '%s,%s' % (preview.model_id.model,
                                                  preview.res_id or 0)
            else:
                preview.resource_ref = False

    def _inverse_resource_ref(self):
        for preview in self:
            if preview.resource_ref:
                preview.res_id = preview.resource_ref.id

    @api.onchange('lang', 'resource_ref')
    def on_change_resource_ref(self):
        # Update res_id and body depending of the resource_ref
        if self.resource_ref:
            self.res_id = self.resource_ref.id
        if self.sms_template_id:
            template = self.sms_template_id.with_context(lang=self.lang)
            self.body = template._render_template(template.body,
                                                  template.model, self.res_id
                                                  or 0)
Exemplo n.º 2
0
class ThemeView(models.Model):
    _name = 'theme.ir.ui.view'
    _description = 'Theme UI View'

    def compute_arch_fs(self):
        path_info = get_resource_from_path(self._context['install_filename'])
        if path_info:
            return '/'.join(path_info[0:2])

    name = fields.Char(required=True)
    key = fields.Char()
    type = fields.Char()
    priority = fields.Integer(default=16, required=True)
    mode = fields.Selection([('primary', "Base view"),
                             ('extension', "Extension View")])
    active = fields.Boolean(default=True)
    arch = fields.Text(translate=xml_translate)
    arch_fs = fields.Char(default=compute_arch_fs)
    inherit_id = fields.Reference(
        selection=[('ir.ui.view',
                    'ir.ui.view'), ('theme.ir.ui.view', 'theme.ir.ui.view')])
    copy_ids = fields.One2many('ir.ui.view',
                               'theme_template_id',
                               'Views using a copy of me',
                               copy=False,
                               readonly=True)

    # TODO master add missing field: customize_show

    @api.multi
    def _convert_to_base_model(self, website, **kwargs):
        self.ensure_one()
        inherit = self.inherit_id
        if self.inherit_id and self.inherit_id._name == 'theme.ir.ui.view':
            inherit = self.inherit_id.with_context(
                active_test=False).copy_ids.filtered(
                    lambda x: x.website_id == website)
            if not inherit:
                # inherit_id not yet created, add to the queue
                return False

        new_view = {
            'type': self.type or 'qweb',
            'name': self.name,
            'arch': self.arch,
            'key': self.key,
            'inherit_id': inherit and inherit.id,
            'arch_fs': self.arch_fs,
            'priority': self.priority,
            'active': self.active,
            'theme_template_id': self.id,
            'website_id': website.id,
        }

        if self.mode:  # if not provided, it will be computed automatically (if inherit_id or not)
            new_view['mode'] = self.mode

        return new_view
Exemplo n.º 3
0
class MixedModel(models.Model):
    _name = 'test_new_api.mixed'
    _description = 'Test New API Mixed'

    number = fields.Float(digits=(10, 2), default=3.14)
    number2 = fields.Float(digits='New API Precision')
    date = fields.Date()
    moment = fields.Datetime()
    now = fields.Datetime(compute='_compute_now')
    lang = fields.Selection(string='Language', selection='_get_lang')
    reference = fields.Reference(string='Related Document',
                                 selection='_reference_models')
    comment1 = fields.Html(sanitize=False)
    comment2 = fields.Html(sanitize_attributes=True, strip_classes=False)
    comment3 = fields.Html(sanitize_attributes=True, strip_classes=True)
    comment4 = fields.Html(sanitize_attributes=True, strip_style=True)

    currency_id = fields.Many2one(
        'res.currency', default=lambda self: self.env.ref('base.EUR'))
    amount = fields.Monetary()

    def _compute_now(self):
        # this is a non-stored computed field without dependencies
        for message in self:
            message.now = fields.Datetime.now()

    @api.model
    def _get_lang(self):
        return self.env['res.lang'].get_installed()

    @api.model
    def _reference_models(self):
        models = self.env['ir.model'].sudo().search([('state', '!=', 'manual')
                                                     ])
        return [(model.model, model.name) for model in models
                if not model.model.startswith('ir.')]
class CrmClaim(models.Model):
    _name = "crm.claim"
    _description = "Claim"
    _order = "priority,date desc"
    _inherit = ['mail.thread', 'mail.activity.mixin']

    @api.model
    def _get_default_stage_id(self):
        """ Gives default stage_id """
        team_id = self.env['crm.team']._get_default_team_id()
        return self.stage_find(team_id.id, [('sequence', '=', '1')])

    @api.model
    def _get_default_team(self):
        return self.env['crm.team']._get_default_team_id()

    @api.model
    def _selection_model(self):
        return [(x, _(self.env[x]._description)) for x in APPLICABLE_MODELS
                if x in self.env]

    name = fields.Char(
        string='Claim Subject',
        required=True,
    )
    active = fields.Boolean(default=True, )
    description = fields.Text()
    resolution = fields.Text()
    create_date = fields.Datetime(
        string='Creation Date',
        readonly=True,
    )
    write_date = fields.Datetime(
        string='Update Date',
        readonly=True,
    )
    date_deadline = fields.Date(string='Deadline', )
    date_closed = fields.Datetime(
        string='Closed',
        readonly=True,
    )
    date = fields.Datetime(
        string='Claim Date',
        index=True,
        default=fields.Datetime.now,
    )
    model_ref_id = fields.Reference(
        selection='_selection_model',
        string='Reference',
        oldname='ref',
    )
    categ_id = fields.Many2one(
        comodel_name='crm.claim.category',
        string='Category',
    )
    priority = fields.Selection(
        selection=[
            ('0', 'Low'),
            ('1', 'Normal'),
            ('2', 'High'),
        ],
        default='1',
    )
    type_action = fields.Selection(
        selection=[
            ('correction', 'Corrective Action'),
            ('prevention', 'Preventive Action'),
        ],
        string='Action Type',
    )
    user_id = fields.Many2one(
        comodel_name='res.users',
        string='Responsible',
        track_visibility='always',
        default=lambda self: self.env.user,
    )
    user_fault = fields.Char(string='Trouble Responsible', )
    team_id = fields.Many2one(
        comodel_name='crm.team',
        string='Sales Team',
        index=True,
        default=_get_default_team,
        help="Responsible sales team. Define Responsible user and Email "
        "account for mail gateway.",
    )
    company_id = fields.Many2one(
        comodel_name='res.company',
        string='Company',
        default=lambda self: self.env.user.company_id,
    )
    partner_id = fields.Many2one(
        comodel_name='res.partner',
        string='Partner',
    )
    email_cc = fields.Text(
        string='Watchers Emails',
        help="These email addresses will be added to the CC field of all "
        "inbound and outbound emails for this record before being sent. "
        "Separate multiple email addresses with a comma",
    )
    email_from = fields.Char(
        string='Email',
        help="Destination email for email gateway.",
    )
    partner_phone = fields.Char(string='Phone', )
    stage_id = fields.Many2one(
        comodel_name='crm.claim.stage',
        string='Stage',
        track_visibility='onchange',
        default=_get_default_stage_id,
        domain="['|', ('team_ids', '=', team_id), ('case_default', '=', True)]"
    )
    cause = fields.Text(string='Root Cause', )

    def stage_find(self, team_id, domain=None, order='sequence'):
        """ Override of the base.stage method
            Parameter of the stage search taken from the lead:
            - team_id: if set, stages must belong to this team or
              be a default case
        """
        if domain is None:  # pragma: no cover
            domain = []
        # collect all team_ids
        team_ids = []
        if team_id:
            team_ids.append(team_id)
        team_ids.extend(self.mapped('team_id').ids)
        search_domain = []
        if team_ids:
            search_domain += ['|'] * len(team_ids)
            for team_id in team_ids:
                search_domain.append(('team_ids', '=', team_id))
        search_domain.append(('case_default', '=', True))
        # AND with the domain in parameter
        search_domain += list(domain)
        # perform search, return the first found
        return self.env['crm.claim.stage'].search(search_domain,
                                                  order=order,
                                                  limit=1).id

    @api.onchange('partner_id')
    def onchange_partner_id(self):
        """This function returns value of partner address based on partner
           :param email: ignored
        """
        if self.partner_id:
            self.email_from = self.partner_id.email
            self.partner_phone = self.partner_id.phone

    @api.onchange('categ_id')
    def onchange_categ_id(self):
        if self.stage_id:
            self.team_id = self.categ_id.team_id

    @api.model
    def create(self, values):
        ctx = self.env.context.copy()
        if values.get('team_id') and not ctx.get('default_team_id'):
            ctx['default_team_id'] = values.get('team_id')
        return super(CrmClaim, self.with_context(context=ctx)).create(values)

    @api.multi
    def copy(self, default=None):
        default = dict(
            default or {},
            stage_id=self._get_default_stage_id(),
            name=_('%s (copy)') % self.name,
        )
        return super(CrmClaim, self).copy(default)

    # -------------------------------------------------------
    # Mail gateway
    # -------------------------------------------------------
    @api.model
    def message_new(self, msg, custom_values=None):
        """ Overrides mail_thread message_new that is called by the mailgateway
            through message_process.
            This override updates the document according to the email.
        """
        if custom_values is None:
            custom_values = {}
        desc = html2plaintext(msg.get('body')) if msg.get('body') else ''
        defaults = {
            'name': msg.get('subject') or _("No Subject"),
            'description': desc,
            'email_from': msg.get('from'),
            'email_cc': msg.get('cc'),
            'partner_id': msg.get('author_id', False),
        }
        if msg.get('priority'):
            defaults['priority'] = msg.get('priority')
        defaults.update(custom_values)
        return super(CrmClaim, self).message_new(msg, custom_values=defaults)
Exemplo n.º 5
0
class IrServerObjectLines(models.Model):
    _name = 'ir.server.object.lines'
    _description = 'Server Action value mapping'
    _sequence = 'ir_actions_id_seq'

    server_id = fields.Many2one('ir.actions.server',
                                string='Related Server Action',
                                ondelete='cascade')
    col1 = fields.Many2one('ir.model.fields', string='Field', required=True)
    value = fields.Text(
        required=True,
        help="Expression containing a value specification. \n"
        "When Formula type is selected, this field may be a Python expression "
        " that can use the same values as for the code field on the server action.\n"
        "If Value type is selected, the value will be used directly without evaluation."
    )
    type = fields.Selection([('value', 'Value'), ('reference', 'Reference'),
                             ('equation', 'Python expression')],
                            'Evaluation Type',
                            default='value',
                            required=True,
                            change_default=True)
    resource_ref = fields.Reference(string='Record',
                                    selection='_selection_target_model',
                                    compute='_compute_resource_ref',
                                    inverse='_set_resource_ref')

    @api.model
    def _selection_target_model(self):
        models = self.env['ir.model'].search([])
        return [(model.model, model.name) for model in models]

    @api.depends('col1.relation', 'value', 'type')
    def _compute_resource_ref(self):
        for line in self:
            if line.type in ['reference', 'value'
                             ] and line.col1 and line.col1.relation:
                value = line.value or ''
                try:
                    value = int(value)
                    if not self.env[line.col1.relation].browse(value).exists():
                        record = self.env[line.col1.relation]._search([],
                                                                      limit=1)
                        value = record[0] if record else 0
                except ValueError:
                    record = self.env[line.col1.relation]._search([], limit=1)
                    value = record[0] if record else 0
                line.resource_ref = '%s,%s' % (line.col1.relation, value)
            else:
                line.resource_ref = False

    @api.onchange('resource_ref')
    def _set_resource_ref(self):
        for line in self.filtered(lambda line: line.type == 'reference'):
            if line.resource_ref:
                line.value = str(line.resource_ref.id)

    @api.multi
    def eval_value(self, eval_context=None):
        result = dict.fromkeys(self.ids, False)
        for line in self:
            expr = line.value
            if line.type == 'equation':
                expr = safe_eval(line.value, eval_context)
            elif line.col1.ttype in ['many2one', 'integer']:
                try:
                    expr = int(line.value)
                except Exception:
                    pass
            result[line.id] = expr
        return result
Exemplo n.º 6
0
class IrUiMenu(models.Model):
    _name = 'ir.ui.menu'
    _description = 'Menu'
    _order = "sequence,id"
    _parent_store = True

    def __init__(self, *args, **kwargs):
        super(IrUiMenu, self).__init__(*args, **kwargs)
        self.pool['ir.model.access'].register_cache_clearing_method(
            self._name, 'clear_caches')

    name = fields.Char(string='Menu', required=True, translate=True)
    active = fields.Boolean(default=True)
    sequence = fields.Integer(default=10)
    child_id = fields.One2many('ir.ui.menu', 'parent_id', string='Child IDs')
    parent_id = fields.Many2one('ir.ui.menu',
                                string='Parent Menu',
                                index=True,
                                ondelete="restrict")
    parent_path = fields.Char(index=True)
    groups_id = fields.Many2many('res.groups', 'ir_ui_menu_group_rel',
                                 'menu_id', 'gid', string='Groups',
                                 help="If you have groups, the visibility of this menu will be based on these groups. "\
                                      "If this field is empty, Eagle will compute visibility based on the related object's read access.")
    complete_name = fields.Char(compute='_compute_complete_name',
                                string='Full Path')
    web_icon = fields.Char(string='Web Icon File')
    action = fields.Reference(selection=[(
        'ir.actions.report', 'ir.actions.report'
    ), ('ir.actions.act_window',
        'ir.actions.act_window'), (
            'ir.actions.act_url',
            'ir.actions.act_url'), (
                'ir.actions.server',
                'ir.actions.server'), ('ir.actions.client',
                                       'ir.actions.client')])

    web_icon_data = fields.Binary(string='Web Icon Image', attachment=True)

    @api.depends('name', 'parent_id.complete_name')
    def _compute_complete_name(self):
        for menu in self:
            menu.complete_name = menu._get_full_name()

    def _get_full_name(self, level=6):
        """ Return the full name of ``self`` (up to a certain level). """
        if level <= 0:
            return '...'
        if self.parent_id:
            return self.parent_id._get_full_name(
                level - 1) + MENU_ITEM_SEPARATOR + (self.name or "")
        else:
            return self.name

    def read_image(self, path):
        if not path:
            return False
        path_info = path.split(',')
        icon_path = get_module_resource(path_info[0], path_info[1])
        icon_image = False
        if icon_path:
            with tools.file_open(icon_path, 'rb') as icon_file:
                icon_image = base64.encodestring(icon_file.read())
        return icon_image

    @api.constrains('parent_id')
    def _check_parent_id(self):
        if not self._check_recursion():
            raise ValidationError(
                _('Error! You cannot create recursive menus.'))

    @api.model
    @tools.ormcache('frozenset(self.env.user.groups_id.ids)', 'debug')
    def _visible_menu_ids(self, debug=False):
        """ Return the ids of the menu items visible to the user. """
        # retrieve all menus, and determine which ones are visible
        context = {'ir.ui.menu.full_list': True}
        menus = self.with_context(context).search([])

        groups = self.env.user.groups_id
        if not debug:
            groups = groups - self.env.ref('base.group_no_one')
        # first discard all menus with groups the user does not have
        menus = menus.filtered(
            lambda menu: not menu.groups_id or menu.groups_id & groups)

        # take apart menus that have an action
        action_menus = menus.filtered(lambda m: m.action and m.action.exists())
        folder_menus = menus - action_menus
        visible = self.browse()

        # process action menus, check whether their action is allowed
        access = self.env['ir.model.access']
        MODEL_GETTER = {
            'ir.actions.act_window': lambda action: action.res_model,
            'ir.actions.report': lambda action: action.model,
            'ir.actions.server': lambda action: action.model_id.model,
        }
        for menu in action_menus:
            get_model = MODEL_GETTER.get(menu.action._name)
            if not get_model or not get_model(menu.action) or \
                    access.check(get_model(menu.action), 'read', False):
                # make menu visible, and its folder ancestors, too
                visible += menu
                menu = menu.parent_id
                while menu and menu in folder_menus and menu not in visible:
                    visible += menu
                    menu = menu.parent_id

        return set(visible.ids)

    @api.multi
    @api.returns('self')
    def _filter_visible_menus(self):
        """ Filter `self` to only keep the menu items that should be visible in
            the menu hierarchy of the current user.
            Uses a cache for speeding up the computation.
        """
        visible_ids = self._visible_menu_ids(
            request.debug if request else False)
        return self.filtered(lambda menu: menu.id in visible_ids)

    @api.model
    def _search(self,
                args,
                offset=0,
                limit=None,
                order=None,
                count=False,
                access_rights_uid=None):
        menu_ids = super(IrUiMenu,
                         self)._search(args,
                                       offset=0,
                                       limit=None,
                                       order=order,
                                       count=False,
                                       access_rights_uid=access_rights_uid)
        menus = self.browse(menu_ids)
        if menus:
            # menu filtering is done only on main menu tree, not other menu lists
            if not self._context.get('ir.ui.menu.full_list'):
                menus = menus._filter_visible_menus()
            if offset:
                menus = menus[offset:]
            if limit:
                menus = menus[:limit]
        return len(menus) if count else menus.ids

    @api.multi
    def name_get(self):
        return [(menu.id, menu._get_full_name()) for menu in self]

    @api.model_create_multi
    def create(self, vals_list):
        self.clear_caches()
        for values in vals_list:
            if 'web_icon' in values:
                values['web_icon_data'] = self._compute_web_icon_data(
                    values.get('web_icon'))
        return super(IrUiMenu, self).create(vals_list)

    @api.multi
    def write(self, values):
        self.clear_caches()
        if 'web_icon' in values:
            values['web_icon_data'] = self._compute_web_icon_data(
                values.get('web_icon'))
        return super(IrUiMenu, self).write(values)

    def _compute_web_icon_data(self, web_icon):
        """ Returns the image associated to `web_icon`.
            `web_icon` can either be:
              - an image icon [module, path]
              - a built icon [icon_class, icon_color, background_color]
            and it only has to call `read_image` if it's an image.
        """
        if web_icon and len(web_icon.split(',')) == 2:
            return self.read_image(web_icon)

    @api.multi
    def unlink(self):
        # Detach children and promote them to top-level, because it would be unwise to
        # cascade-delete submenus blindly. We also can't use ondelete=set null because
        # that is not supported when _parent_store is used (would silently corrupt it).
        # TODO: ideally we should move them under a generic "Orphans" menu somewhere?
        extra = {'ir.ui.menu.full_list': True}
        direct_children = self.with_context(**extra).search([('parent_id',
                                                              'in', self.ids)])
        direct_children.write({'parent_id': False})

        self.clear_caches()
        return super(IrUiMenu, self).unlink()

    @api.multi
    def copy(self, default=None):
        record = super(IrUiMenu, self).copy(default=default)
        match = NUMBER_PARENS.search(record.name)
        if match:
            next_num = int(match.group(1)) + 1
            record.name = NUMBER_PARENS.sub('(%d)' % next_num, record.name)
        else:
            record.name = record.name + '(1)'
        return record

    @api.model
    @api.returns('self')
    def get_user_roots(self):
        """ Return all root menu ids visible for the user.

        :return: the root menu ids
        :rtype: list(int)
        """
        return self.search([('parent_id', '=', False)])

    @api.model
    @tools.ormcache_context('self._uid', keys=('lang', ))
    def load_menus_root(self):
        fields = ['name', 'sequence', 'parent_id', 'action', 'web_icon_data']
        menu_roots = self.get_user_roots()
        menu_roots_data = menu_roots.read(fields) if menu_roots else []

        menu_root = {
            'id': False,
            'name': 'root',
            'parent_id': [-1, ''],
            'children': menu_roots_data,
            'all_menu_ids': menu_roots.ids,
        }

        menu_roots._set_menuitems_xmlids(menu_root)

        return menu_root

    @api.model
    @tools.ormcache_context('self._uid', 'debug', keys=('lang', ))
    def load_menus(self, debug):
        """ Loads all menu items (all applications and their sub-menus).

        :return: the menu root
        :rtype: dict('children': menu_nodes)
        """
        fields = [
            'name', 'sequence', 'parent_id', 'action', 'web_icon',
            'web_icon_data'
        ]
        menu_roots = self.get_user_roots()
        menu_roots_data = menu_roots.read(fields) if menu_roots else []
        menu_root = {
            'id': False,
            'name': 'root',
            'parent_id': [-1, ''],
            'children': menu_roots_data,
            'all_menu_ids': menu_roots.ids,
        }

        if not menu_roots_data:
            return menu_root

        # menus are loaded fully unlike a regular tree view, cause there are a
        # limited number of items (752 when all 6.1 addons are installed)
        menus = self.search([('id', 'child_of', menu_roots.ids)])
        menu_items = menus.read(fields)

        # add roots at the end of the sequence, so that they will overwrite
        # equivalent menu items from full menu read when put into id:item
        # mapping, resulting in children being correctly set on the roots.
        menu_items.extend(menu_roots_data)
        menu_root['all_menu_ids'] = menus.ids  # includes menu_roots!

        # make a tree using parent_id
        menu_items_map = {
            menu_item["id"]: menu_item
            for menu_item in menu_items
        }
        for menu_item in menu_items:
            parent = menu_item['parent_id'] and menu_item['parent_id'][0]
            if parent in menu_items_map:
                menu_items_map[parent].setdefault('children',
                                                  []).append(menu_item)

        # sort by sequence a tree using parent_id
        for menu_item in menu_items:
            menu_item.setdefault('children',
                                 []).sort(key=operator.itemgetter('sequence'))

        (menu_roots + menus)._set_menuitems_xmlids(menu_root)

        return menu_root

    def _set_menuitems_xmlids(self, menu_root):
        menuitems = self.env['ir.model.data'].sudo().search([
            ('res_id', 'in', self.ids), ('model', '=', 'ir.ui.menu')
        ])

        xmlids = {menu.res_id: menu.complete_name for menu in menuitems}

        def _set_xmlids(tree, xmlids):
            tree['xmlid'] = xmlids.get(tree['id'], '')
            if 'children' in tree:
                for child in tree['children']:
                    _set_xmlids(child, xmlids)

        _set_xmlids(menu_root, xmlids)