Exemple #1
0
def transfer_node_to_modifiers(node,
                               modifiers,
                               context=None,
                               in_tree_view=False):
    if node.get('attrs'):
        modifiers.update(safe_eval(node.get('attrs')))

    if node.get('states'):
        if 'invisible' in modifiers and isinstance(modifiers['invisible'],
                                                   list):
            # TODO combine with AND or OR, use implicit AND for now.
            modifiers['invisible'].append(
                ('state', 'not in', node.get('states').split(',')))
        else:
            modifiers['invisible'] = [('state', 'not in',
                                       node.get('states').split(','))]

    for a in ('invisible', 'readonly', 'required'):
        if node.get(a):
            v = bool(safe_eval(node.get(a), {'context': context or {}}))
            if in_tree_view and a == 'invisible':
                # Invisible in a tree view has a specific meaning, make it a
                # new key in the modifiers attribute.
                modifiers['column_invisible'] = v
            elif v or (a not in modifiers
                       or not isinstance(modifiers[a], list)):
                # Don't set the attribute to False if a dynamic value was
                # provided (i.e. a domain from attrs or states).
                modifiers[a] = v
Exemple #2
0
 def compute_all(self,
                 price_unit,
                 currency=None,
                 quantity=1.0,
                 product=None,
                 partner=None):
     taxes = self.filtered(lambda r: r.amount_type != 'code')
     company = self.env.user.company_id
     for tax in self.filtered(lambda r: r.amount_type == 'code'):
         localdict = {
             'price_unit': price_unit,
             'quantity': quantity,
             'product': product,
             'partner': partner,
             'company': company
         }
         safe_eval(tax.python_applicable,
                   localdict,
                   mode="exec",
                   nocopy=True)
         if localdict.get('result', False):
             taxes += tax
     return super(AccountTaxPython,
                  taxes).compute_all(price_unit, currency, quantity,
                                     product, partner)
Exemple #3
0
 def run_action_code_multi(self, action, eval_context=None):
     safe_eval(action.sudo().code.strip(),
               eval_context,
               mode="exec",
               nocopy=True)  # nocopy allows to return 'action'
     if 'action' in eval_context:
         return eval_context['action']
Exemple #4
0
    def _satisfy_condition(self, localdict):
        """
        @param contract_id: id of hr.contract to be tested
        @return: returns True if the given rule match the condition for the given contract. Return False otherwise.
        """
        self.ensure_one()

        if self.condition_select == 'none':
            return True
        elif self.condition_select == 'range':
            try:
                result = safe_eval(self.condition_range, localdict)
                return self.condition_range_min <= result and result <= self.condition_range_max or False
            except:
                raise UserError(
                    _('Wrong range condition defined for salary rule %s (%s).')
                    % (self.name, self.code))
        else:  # python code
            try:
                safe_eval(self.condition_python,
                          localdict,
                          mode='exec',
                          nocopy=True)
                return 'result' in localdict and localdict['result'] or False
            except:
                raise UserError(
                    _('Wrong python condition defined for salary rule %s (%s).'
                      ) % (self.name, self.code))
Exemple #5
0
    def execute_code(self, code_exec):
        def reconciled_inv():
            """
            returns the list of invoices that are set as reconciled = True
            """
            return self.env['account.invoice'].search([('reconciled', '=',
                                                        True)]).ids

        def order_columns(item, cols=None):
            """
            This function is used to display a dictionary as a string, with its columns in the order chosen.

            :param item: dict
            :param cols: list of field names
            :returns: a list of tuples (fieldname: value) in a similar way that would dict.items() do except that the
                returned values are following the order given by cols
            :rtype: [(key, value)]
            """
            if cols is None:
                cols = list(item)
            return [(col, item.get(col)) for col in cols if col in item]

        localdict = {
            'cr': self.env.cr,
            'uid': self.env.uid,
            'reconciled_inv':
            reconciled_inv,  # specific function used in different tests
            'result': None,  # used to store the result of the test
            'column_order':
            None,  # used to choose the display order of columns (in case you are returning a list of dict)
            '_': _,
        }
        safe_eval(code_exec, localdict, mode="exec", nocopy=True)
        result = localdict['result']
        column_order = localdict.get('column_order', None)

        if not isinstance(result, (tuple, list, set)):
            result = [result]
        if not result:
            result = [_('The test was passed successfully')]
        else:

            def _format(item):
                if isinstance(item, dict):
                    return ', '.join([
                        "%s: %s" % (tup[0], tup[1])
                        for tup in order_columns(item, column_order)
                    ])
                else:
                    return item

            result = [_format(rec) for rec in result]

        return result
Exemple #6
0
    def format(self, percent, value, grouping=False, monetary=False):
        """ Format() will return the language-specific output for float values"""
        self.ensure_one()
        if percent[0] != '%':
            raise ValueError(
                _("format() must be given exactly one %char format specifier"))

        formatted = percent % value

        # floats and decimal ints need special action!
        if grouping:
            lang_grouping, thousands_sep, decimal_point = self._data_get(
                monetary)
            eval_lang_grouping = safe_eval(lang_grouping)

            if percent[-1] in 'eEfFgG':
                parts = formatted.split('.')
                parts[0] = intersperse(parts[0], eval_lang_grouping,
                                       thousands_sep)[0]

                formatted = decimal_point.join(parts)

            elif percent[-1] in 'diu':
                formatted = intersperse(formatted, eval_lang_grouping,
                                        thousands_sep)[0]

        return formatted
Exemple #7
0
 def test_01_safe_eval(self):
     """ Try a few common expressions to verify they work with safe_eval """
     expected = (1, {"a": 9 * 2}, (True, False, None))
     actual = safe_eval('(1, {"a": 9 * 2}, (True, False, None))')
     self.assertEqual(
         actual, expected,
         "Simple python expressions are not working with safe_eval")
Exemple #8
0
    def postprocess_pdf_report(self, record, buffer):
        '''Hook to handle post processing during the pdf report generation.
        The basic behavior consists to create a new attachment containing the pdf
        base64 encoded.

        :param record_id: The record that will own the attachment.
        :param pdf_content: The optional name content of the file to avoid reading both times.
        :return: The newly generated attachment if no AccessError, else None.
        '''
        attachment_name = safe_eval(self.attachment, {'object': record, 'time': time})
        if not attachment_name:
            return None
        attachment_vals = {
            'name': attachment_name,
            'datas': base64.encodestring(buffer.getvalue()),
            'datas_fname': attachment_name,
            'res_model': self.model,
            'res_id': record.id,
        }
        attachment = None
        try:
            attachment = self.env['ir.attachment'].create(attachment_vals)
        except AccessError:
            _logger.info("Cannot save PDF report %r as attachment", attachment_vals['name'])
        else:
            _logger.info('The PDF document %s is now saved in the database', attachment_vals['name'])
        return attachment
Exemple #9
0
    def _get_price_from_picking(self, total, weight, volume, quantity):
        price = 0.0
        criteria_found = False
        price_dict = {
            'price': total,
            'volume': volume,
            'weight': weight,
            'wv': volume * weight,
            'quantity': quantity
        }
        for line in self.price_rule_ids:
            test = safe_eval(
                line.variable + line.operator + str(line.max_value),
                price_dict)
            if test:
                price = line.list_base_price + line.list_price * price_dict[
                    line.variable_factor]
                criteria_found = True
                break
        if not criteria_found:
            raise UserError(
                _("No price rule matching this order; delivery cost cannot be computed."
                  ))

        return price
Exemple #10
0
    def action_launch(self, context=None):
        """ Launch Action of Wizard"""
        self.ensure_one()

        self.write({'state': 'done'})

        # Load action
        action = self.env[self.action_id.type].browse(self.action_id.id)

        result = action.read()[0]
        if action._name != 'ir.actions.act_window':
            return result
        result.setdefault('context', '{}')

        # Open a specific record when res_id is provided in the context
        ctx = safe_eval(result['context'], {'user': self.env.user})
        if ctx.get('res_id'):
            result['res_id'] = ctx.pop('res_id')

        # disable log for automatic wizards
        ctx['disable_log'] = True

        result['context'] = ctx

        return result
Exemple #11
0
    def action_your_pipeline(self):
        action = self.env.ref('crm.crm_lead_opportunities_tree_view').read()[0]
        user_team_id = self.env.user.sale_team_id.id
        if not user_team_id:
            user_team_id = self.search([], limit=1).id
            action[
                'help'] = """<p class='oe_view_nocontent_create'>Click here to add new opportunities</p><p>
    Looks like you are not a member of a sales channel. You should add yourself
    as a member of one of the sales channel.
</p>"""
            if user_team_id:
                action[
                    'help'] += "<p>As you don't belong to any sales channel, izi opens the first one by default.</p>"

        action_context = safe_eval(action['context'], {'uid': self.env.uid})
        if user_team_id:
            action_context['default_team_id'] = user_team_id

        tree_view_id = self.env.ref('crm.crm_case_tree_view_oppor').id
        form_view_id = self.env.ref('crm.crm_case_form_view_oppor').id
        kanb_view_id = self.env.ref('crm.crm_case_kanban_view_leads').id
        action['views'] = [[kanb_view_id, 'kanban'], [tree_view_id, 'tree'],
                           [form_view_id, 'form'], [False, 'graph'],
                           [False, 'calendar'], [False, 'pivot']]
        action['context'] = action_context
        return action
Exemple #12
0
 def action_view_all_rating(self):
     """ return the action to see all the rating of the project, and activate default filters """
     action = self.env['ir.actions.act_window'].for_xml_id('rating_project', 'rating_rating_action_view_project_rating')
     action['name'] = _('Ratings of %s') % (self.name,)
     action_context = safe_eval(action['context']) if action['context'] else {}
     action_context.update(self._context)
     action_context['search_default_rating_tasks'] = 1
     return dict(action, context=action_context)
Exemple #13
0
 def _filter_post(self, records):
     """ Filter the records that satisfy the postcondition of action ``self``. """
     if self.filter_domain and records:
         domain = [('id', 'in', records.ids)] + safe_eval(
             self.filter_domain, self._get_eval_context())
         return records.search(domain)
     else:
         return records
Exemple #14
0
 def get_alias_values(self):
     has_group_use_lead = self.env.user.has_group('crm.group_use_lead')
     values = super(Team, self).get_alias_values()
     values['alias_defaults'] = defaults = safe_eval(self.alias_defaults
                                                     or "{}")
     defaults[
         'type'] = 'lead' if has_group_use_lead and self.use_leads else 'opportunity'
     defaults['team_id'] = self.id
     return values
Exemple #15
0
 def generate(self, uid, dom=None, args=None):
     Model = request.env[self.model].sudo(uid)
     domain = safe_eval(self.domain, (args or {}).copy())
     if dom:
         domain += dom
     for record in Model.search_read(domain=domain,
                                     fields=['write_date',
                                             Model._rec_name]):
         if record.get(Model._rec_name, False):
             yield {'loc': (record['id'], record[Model._rec_name])}
Exemple #16
0
 def get_google_drive_config(self, res_model, res_id):
     '''
     Function called by the js, when no google doc are yet associated with a record, with the aim to create one. It
     will first seek for a google.docs.config associated with the model `res_model` to find out what's the template
     of google doc to copy (this is usefull if you want to start with a non-empty document, a type or a name
     different than the default values). If no config is associated with the `res_model`, then a blank text document
     with a default name is created.
       :param res_model: the object for which the google doc is created
       :param ids: the list of ids of the objects for which the google doc is created. This list is supposed to have
         a length of 1 element only (batch processing is not supported in the code, though nothing really prevent it)
       :return: the config id and config name
     '''
     # TO DO in master: fix my signature and my model
     if isinstance(res_model, pycompat.string_types):
         res_model = self.env['ir.model'].search([('model', '=', res_model)
                                                  ]).id
     if not res_id:
         raise UserError(
             _("Creating google drive may only be done by one at a time."))
     # check if a model is configured with a template
     configs = self.search([('model_id', '=', res_model)])
     config_values = []
     for config in configs.sudo():
         if config.filter_id:
             if config.filter_id.user_id and config.filter_id.user_id.id != self.env.user.id:
                 #Private
                 continue
             domain = [('id', 'in', [res_id])] + safe_eval(
                 config.filter_id.domain)
             additionnal_context = safe_eval(config.filter_id.context)
             google_doc_configs = self.env[
                 config.filter_id.model_id].with_context(
                     **additionnal_context).search(domain)
             if google_doc_configs:
                 config_values.append({
                     'id': config.id,
                     'name': config.name
                 })
         else:
             config_values.append({'id': config.id, 'name': config.name})
     return config_values
Exemple #17
0
 def _compute_rule(self, localdict):
     """
     :param localdict: dictionary containing the environement in which to compute the rule
     :return: returns a tuple build as the base/amount computed, the quantity and the rate
     :rtype: (float, float, float)
     """
     self.ensure_one()
     if self.amount_select == 'fix':
         try:
             return self.amount_fix, float(
                 safe_eval(self.quantity, localdict)), 100.0
         except:
             raise UserError(
                 _('Wrong quantity defined for salary rule %s (%s).') %
                 (self.name, self.code))
     elif self.amount_select == 'percentage':
         try:
             return (float(safe_eval(self.amount_percentage_base,
                                     localdict)),
                     float(safe_eval(self.quantity,
                                     localdict)), self.amount_percentage)
         except:
             raise UserError(
                 _('Wrong percentage base or quantity defined for salary rule %s (%s).'
                   ) % (self.name, self.code))
     else:
         try:
             safe_eval(self.amount_python_compute,
                       localdict,
                       mode='exec',
                       nocopy=True)
             return float(
                 localdict['result']
             ), 'result_qty' in localdict and localdict[
                 'result_qty'] or 1.0, 'result_rate' in localdict and localdict[
                     'result_rate'] or 100.0
         except:
             raise UserError(
                 _('Wrong python code defined for salary rule %s (%s).') %
                 (self.name, self.code))
Exemple #18
0
 def _compute_amount(self,
                     base_amount,
                     price_unit,
                     quantity=1.0,
                     product=None,
                     partner=None):
     self.ensure_one()
     if self.amount_type == 'code':
         company = self.env.user.company_id
         localdict = {
             'base_amount': base_amount,
             'price_unit': price_unit,
             'quantity': quantity,
             'product': product,
             'partner': partner,
             'company': company
         }
         safe_eval(self.python_compute, localdict, mode="exec", nocopy=True)
         return localdict['result']
     return super(AccountTaxPython,
                  self)._compute_amount(base_amount, price_unit, quantity,
                                        product, partner)
Exemple #19
0
 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
Exemple #20
0
    def retrieve_attachment(self, record):
        '''Retrieve an attachment for a specific record.

        :param record: The record owning of the attachment.
        :param attachment_name: The optional name of the attachment.
        :return: A recordset of length <=1 or None
        '''
        attachment_name = safe_eval(self.attachment, {'object': record, 'time': time})
        if not attachment_name:
            return None
        return self.env['ir.attachment'].search([
                ('datas_fname', '=', attachment_name),
                ('res_model', '=', self.model),
                ('res_id', '=', record.id)
        ], limit=1)
Exemple #21
0
 def message_get_email_values(self, notif_mail=None):
     res = super(Task, self).message_get_email_values(notif_mail=notif_mail)
     headers = {}
     if res.get('headers'):
         try:
             headers.update(safe_eval(res['headers']))
         except Exception:
             pass
     if self.project_id:
         current_objects = [h for h in headers.get('X-izi-Objects', '').split(',') if h]
         current_objects.insert(0, 'project.project-%s, ' % self.project_id.id)
         headers['X-izi-Objects'] = ','.join(current_objects)
     if self.tag_ids:
         headers['X-izi-Tags'] = ','.join(self.tag_ids.mapped('name'))
     res['headers'] = repr(headers)
     return res
Exemple #22
0
    def _check(self, automatic=False, use_new_cursor=False):
        """ This Function is called by scheduler. """
        if '__action_done' not in self._context:
            self = self.with_context(__action_done={})

        # retrieve all the action rules to run based on a timed condition
        eval_context = self._get_eval_context()
        for action in self.with_context(active_test=True).search([
            ('trigger', '=', 'on_time')
        ]):
            last_run = fields.Datetime.from_string(
                action.last_run) or datetime.datetime.utcfromtimestamp(0)

            # retrieve all the records that satisfy the action's condition
            domain = []
            context = dict(self._context)
            if action.filter_domain:
                domain = safe_eval(action.filter_domain, eval_context)
            records = self.env[action.model_name].with_context(context).search(
                domain)

            # determine when action should occur for the records
            if action.trg_date_id.name == 'date_action_last' and 'create_date' in records._fields:
                get_record_dt = lambda record: record[action.trg_date_id.name
                                                      ] or record.create_date
            else:
                get_record_dt = lambda record: record[action.trg_date_id.name]

            # process action on the records that should be executed
            now = datetime.datetime.now()
            for record in records:
                record_dt = get_record_dt(record)
                if not record_dt:
                    continue
                action_dt = self._check_delay(action, record, record_dt)
                if last_run <= action_dt < now:
                    try:
                        action._process(record)
                    except Exception:
                        _logger.error(traceback.format_exc())

            action.write(
                {'last_run': now.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})

            if automatic:
                # auto-commit for batch processing
                self._cr.commit()
Exemple #23
0
 def action_view_project_ids(self):
     self.ensure_one()
     if len(self.project_ids) == 1:
         if self.env.user.has_group("hr_timesheet.group_hr_timesheet_user"):
             action = self.project_ids.action_view_timesheet_plan()
         else:
             action = self.env.ref("project.act_project_project_2_project_task_all").read()[0]
             action['context'] = safe_eval(action.get('context', '{}'), {'active_id': self.project_ids.id, 'active_ids': self.project_ids.ids})
     else:
         view_form_id = self.env.ref('project.edit_project').id
         view_kanban_id = self.env.ref('project.view_project_kanban').id
         action = {
             'type': 'ir.actions.act_window',
             'domain': [('id', 'in', self.project_ids.ids)],
             'views': [(view_kanban_id, 'kanban'), (view_form_id, 'form')],
             'view_mode': 'kanban,form',
             'name': _('Projects'),
             'res_model': 'project.project',
         }
     return action
Exemple #24
0
    def _check_domain_validity(self):
        # take admin as should always be present
        for definition in self:
            if definition.computation_mode not in ('count', 'sum'):
                continue

            Obj = self.env[definition.model_id.model]
            try:
                domain = safe_eval(definition.domain,
                                   {'user': self.env.user.sudo(self.env.user)})
                # dummy search to make sure the domain is valid
                Obj.search_count(domain)
            except (ValueError, SyntaxError) as e:
                msg = e
                if isinstance(e, SyntaxError):
                    msg = (e.msg + '\n' + e.text)
                raise exceptions.UserError(
                    _("The domain for the definition %s seems incorrect, please check it.\n\n%s"
                      ) % (definition.name, msg))
        return True
Exemple #25
0
 def message_get_email_values(self, notif_mail=None):
     self.ensure_one()
     res = super(MailGroup,
                 self).message_get_email_values(notif_mail=notif_mail)
     base_url = self.env['ir.config_parameter'].sudo().get_param(
         'web.base.url')
     headers = {}
     if res.get('headers'):
         try:
             headers = safe_eval(res['headers'])
         except Exception:
             pass
     headers.update({
         'List-Archive':
         '<%s/groups/%s>' % (base_url, slug(self)),
         'List-Subscribe':
         '<%s/groups>' % (base_url),
         'List-Unsubscribe':
         '<%s/groups?unsubscribe>' % (base_url, ),
     })
     res['headers'] = repr(headers)
     return res
Exemple #26
0
 def message_get_email_values(self, notif_mail=None):
     self.ensure_one()
     res = super(Channel, self).message_get_email_values(notif_mail=notif_mail)
     headers = {}
     if res.get('headers'):
         try:
             headers.update(safe_eval(res['headers']))
         except Exception:
             pass
     headers['Precedence'] = 'list'
     # avoid out-of-office replies from MS Exchange
     # http://blogs.technet.com/b/exchange/archive/2006/10/06/3395024.aspx
     headers['X-Auto-Response-Suppress'] = 'OOF'
     if self.alias_domain and self.alias_name:
         headers['List-Id'] = '<%s.%s>' % (self.alias_name, self.alias_domain)
         headers['List-Post'] = '<mailto:%s@%s>' % (self.alias_name, self.alias_domain)
         # Avoid users thinking it was a personal message
         # X-Forge-To: will replace To: after SMTP envelope is determined by ir.mail.server
         list_to = '"%s" <%s@%s>' % (self.name, self.alias_name, self.alias_domain)
         headers['X-Forge-To'] = list_to
     res['headers'] = repr(headers)
     return res
Exemple #27
0
    def get_action(self):
        """Get the ir.action related to update the goal

        In case of a manual goal, should return a wizard to update the value
        :return: action description in a dictionary
        """
        if self.definition_id.action_id:
            # open a the action linked to the goal
            action = self.definition_id.action_id.read()[0]

            if self.definition_id.res_id_field:
                current_user = self.env.user.sudo(self.env.user)
                action['res_id'] = safe_eval(self.definition_id.res_id_field,
                                             {'user': current_user})

                # if one element to display, should see it in form mode if possible
                action['views'] = [(view_id, mode)
                                   for (view_id, mode) in action['views']
                                   if mode == 'form'] or action['views']
            return action

        if self.computation_mode == 'manually':
            # open a wizard window to update the value manually
            action = {
                'name': _("Update %s") % self.definition_id.name,
                'id': self.id,
                'type': 'ir.actions.act_window',
                'views': [[False, 'form']],
                'target': 'new',
                'context': {
                    'default_goal_id': self.id,
                    'default_current': self.current
                },
                'res_model': 'gamification.goal.wizard'
            }
            return action

        return False
Exemple #28
0
    def _compute_domain(self, model_name, mode="read"):
        if mode not in self._MODES:
            raise ValueError('Invalid mode: %r' % (mode, ))

        if self._uid == SUPERUSER_ID:
            return None

        query = """ SELECT r.id FROM ir_rule r JOIN ir_model m ON (r.model_id=m.id)
                    WHERE m.model=%s AND r.active AND r.perm_{mode}
                    AND (r.id IN (SELECT rule_group_id FROM rule_group_rel rg
                                  JOIN res_groups_users_rel gu ON (rg.group_id=gu.gid)
                                  WHERE gu.uid=%s)
                         OR r.global)
                """.format(mode=mode)
        self._cr.execute(query, (model_name, self._uid))
        rule_ids = [row[0] for row in self._cr.fetchall()]
        if not rule_ids:
            return []

        # browse user and rules as SUPERUSER_ID to avoid access errors!
        eval_context = self._eval_context()
        user_groups = self.env.user.groups_id
        global_domains = []  # list of domains
        group_domains = []  # list of domains
        for rule in self.browse(rule_ids).sudo():
            # evaluate the domain for the current user
            dom = safe_eval(rule.domain_force,
                            eval_context) if rule.domain_force else []
            dom = expression.normalize_domain(dom)
            if not rule.groups:
                global_domains.append(dom)
            elif rule.groups & user_groups:
                group_domains.append(dom)

        # combine global domains and group domains
        return expression.AND(global_domains + [expression.OR(group_domains)])
Exemple #29
0
    def _send(self, auto_commit=False, raise_exception=False, smtp_session=None):
        IrMailServer = self.env['ir.mail_server']
        for mail_id in self.ids:
            try:
                mail = self.browse(mail_id)
                if mail.state != 'outgoing':
                    if mail.state != 'exception' and mail.auto_delete:
                        mail.sudo().unlink()
                    continue
                # TDE note: remove me when model_id field is present on mail.message - done here to avoid doing it multiple times in the sub method
                if mail.model:
                    model = self.env['ir.model']._get(mail.model)[0]
                else:
                    model = None
                if model:
                    mail = mail.with_context(model_name=model.name)

                # load attachment binary data with a separate read(), as prefetching all
                # `datas` (binary field) could bloat the browse cache, triggerring
                # soft/hard mem limits with temporary data.
                attachments = [(a['datas_fname'], base64.b64decode(a['datas']), a['mimetype'])
                               for a in mail.attachment_ids.sudo().read(['datas_fname', 'datas', 'mimetype'])]

                # specific behavior to customize the send email for notified partners
                email_list = []
                if mail.email_to:
                    email_list.append(mail.send_get_email_dict())
                for partner in mail.recipient_ids:
                    email_list.append(mail.send_get_email_dict(partner=partner))

                # headers
                headers = {}
                ICP = self.env['ir.config_parameter'].sudo()
                bounce_alias = ICP.get_param("mail.bounce.alias")
                catchall_domain = ICP.get_param("mail.catchall.domain")
                if bounce_alias and catchall_domain:
                    if mail.model and mail.res_id:
                        headers['Return-Path'] = '%s+%d-%s-%d@%s' % (bounce_alias, mail.id, mail.model, mail.res_id, catchall_domain)
                    else:
                        headers['Return-Path'] = '%s+%d@%s' % (bounce_alias, mail.id, catchall_domain)
                if mail.headers:
                    try:
                        headers.update(safe_eval(mail.headers))
                    except Exception:
                        pass

                # Writing on the mail object may fail (e.g. lock on user) which
                # would trigger a rollback *after* actually sending the email.
                # To avoid sending twice the same email, provoke the failure earlier
                mail.write({
                    'state': 'exception',
                    'failure_reason': _('Error without exception. Probably due do sending an email without computed recipients.'),
                })
                mail_sent = False

                # build an RFC2822 email.message.Message object and send it without queuing
                res = None
                for email in email_list:
                    msg = IrMailServer.build_email(
                        email_from=mail.email_from,
                        email_to=email.get('email_to'),
                        subject=mail.subject,
                        body=email.get('body'),
                        body_alternative=email.get('body_alternative'),
                        email_cc=tools.email_split(mail.email_cc),
                        reply_to=mail.reply_to,
                        attachments=attachments,
                        message_id=mail.message_id,
                        references=mail.references,
                        object_id=mail.res_id and ('%s-%s' % (mail.res_id, mail.model)),
                        subtype='html',
                        subtype_alternative='plain',
                        headers=headers)
                    try:
                        res = IrMailServer.send_email(
                            msg, mail_server_id=mail.mail_server_id.id, smtp_session=smtp_session)
                    except AssertionError as error:
                        if str(error) == IrMailServer.NO_VALID_RECIPIENT:
                            # No valid recipient found for this particular
                            # mail item -> ignore error to avoid blocking
                            # delivery to next recipients, if any. If this is
                            # the only recipient, the mail will show as failed.
                            _logger.info("Ignoring invalid recipients for mail.mail %s: %s",
                                         mail.message_id, email.get('email_to'))
                        else:
                            raise
                if res:
                    mail.write({'state': 'sent', 'message_id': res, 'failure_reason': False})
                    mail_sent = True

                # /!\ can't use mail.state here, as mail.refresh() will cause an error
                # see revid:[email protected] in 6.1
                if mail_sent:
                    _logger.info('Mail with ID %r and Message-Id %r successfully sent', mail.id, mail.message_id)
                mail._postprocess_sent_message(mail_sent=mail_sent)
            except MemoryError:
                # prevent catching transient MemoryErrors, bubble up to notify user or abort cron job
                # instead of marking the mail as failed
                _logger.exception(
                    'MemoryError while processing mail with ID %r and Msg-Id %r. Consider raising the --limit-memory-hard startup option',
                    mail.id, mail.message_id)
                raise
            except psycopg2.Error:
                # If an error with the database occurs, chances are that the cursor is unusable.
                # This will lead to an `psycopg2.InternalError` being raised when trying to write
                # `state`, shadowing the original exception and forbid a retry on concurrent
                # update. Let's bubble it.
                raise
            except Exception as e:
                failure_reason = tools.ustr(e)
                _logger.exception('failed sending mail (id: %s) due to %s', mail.id, failure_reason)
                mail.write({'state': 'exception', 'failure_reason': failure_reason})
                mail._postprocess_sent_message(mail_sent=False)
                if raise_exception:
                    if isinstance(e, AssertionError):
                        # get the args of the original error, wrap into a value and throw a MailDeliveryException
                        # that is an except_orm, with name and value as arguments
                        value = '. '.join(e.args)
                        raise MailDeliveryException(_("Mail Delivery Failed"), value)
                    raise

            if auto_commit is True:
                self._cr.commit()
        return True
Exemple #30
0
    def get_diagram_info(self, id, model, node, connector, src_node, des_node,
                         label, **kw):

        visible_node_fields = kw.get('visible_node_fields', [])
        invisible_node_fields = kw.get('invisible_node_fields', [])
        node_fields_string = kw.get('node_fields_string', [])
        connector_fields = kw.get('connector_fields', [])
        connector_fields_string = kw.get('connector_fields_string', [])

        bgcolors = {}
        shapes = {}
        bgcolor = kw.get('bgcolor', '')
        shape = kw.get('shape', '')

        if bgcolor:
            for color_spec in bgcolor.split(';'):
                if color_spec:
                    colour, color_state = color_spec.split(':')
                    bgcolors[colour] = color_state

        if shape:
            for shape_spec in shape.split(';'):
                if shape_spec:
                    shape_colour, shape_color_state = shape_spec.split(':')
                    shapes[shape_colour] = shape_color_state

        ir_view = http.request.env['ir.ui.view']
        graphs = ir_view.graph_get(int(id), model, node, connector, src_node,
                                   des_node, label, (140, 180))
        nodes = graphs['nodes']
        transitions = graphs['transitions']
        isolate_nodes = {}
        for blnk_node in graphs['blank_nodes']:
            isolate_nodes[blnk_node['id']] = blnk_node
        y = [t['y'] for t in nodes.values() if t['x'] == 20 if t['y']]
        y_max = (y and max(y)) or 120

        connectors = {}
        list_tr = []

        for tr in transitions:
            list_tr.append(tr)
            connectors.setdefault(
                tr, {
                    'id': int(tr),
                    's_id': transitions[tr][0],
                    'd_id': transitions[tr][1]
                })

        connector_model = http.request.env[connector]
        data_connectors = connector_model.search([('id', 'in', list_tr)
                                                  ]).read(connector_fields)

        for tr in data_connectors:
            transition_id = str(tr['id'])
            _sourceid, label = graphs['label'][transition_id]
            t = connectors[transition_id]
            t.update(source=tr[src_node][1],
                     destination=tr[des_node][1],
                     options={},
                     signal=label)

            for i, fld in enumerate(connector_fields):
                t['options'][connector_fields_string[i]] = tr[fld]

        fields = http.request.env['ir.model.fields']
        field = fields.search([('model', '=', model), ('relation', '=', node)])
        node_act = http.request.env[node]
        search_acts = node_act.search([(field.relation_field, '=', id)])
        data_acts = search_acts.read(invisible_node_fields +
                                     visible_node_fields)

        for act in data_acts:
            n = nodes.get(str(act['id']))
            if not n:
                n = isolate_nodes.get(act['id'], {})
                y_max += 140
                n.update(x=20, y=y_max)
                nodes[act['id']] = n

            n.update(id=act['id'], color='white', options={})
            for color, expr in bgcolors.items():
                if safe_eval(expr, act):
                    n['color'] = color

            for shape, expr in shapes.items():
                if safe_eval(expr, act):
                    n['shape'] = shape

            for i, fld in enumerate(visible_node_fields):
                n['options'][node_fields_string[i]] = act[fld]

        _id, name = http.request.env[model].browse([id]).name_get()[0]
        return dict(nodes=nodes,
                    conn=connectors,
                    display_name=name,
                    parent_field=graphs['node_parent_field'])