示例#1
0
class XopgiBoardWidget(models.Model):
    _name = WIDGET_MODEL_NAME
    _description = "Board Widget"

    _order = 'category, name'

    name = fields.Char(translate=True)
    category = fields.Many2one('ir.module.category')
    template_name = fields.Char(required=True)
    xml_template = fields.Text(translate=True)
    python_code = fields.Text()

    @api.multi
    def name_get(self):
        '''Returns a list with id, name of widgets or name's template

        '''
        return [(item.id, item.name or item.template_name) for item in self]

    def get_widgets_dict(self):
        '''Returns a dictionary list that represents the widgets that the user
        has access to.

        '''
        widgets = self.env[WIDGET_REL_MODEL_NAME].get_widgets()
        logger.debug('Widgets to show %r' % [w['name'] for w in widgets])
        today = normalize_datetime(fields.Date.today(self))
        for widget in widgets:
            self._eval_python_code(widget, today)
        return widgets

    def _eval_python_code(self, widget, today):
        '''Evaluate the python code of a widget

        '''
        python_code = widget.get('python_code', '')
        if not python_code:
            return
        name = widget.get('name', '')
        env = self.env
        local_dict = locals()
        local_dict.update(globals().get('__builtins__', {}))
        try:
            logger.debug('Starting evaluation of Python code for widget %s' %
                         name)
            safe_eval(python_code, local_dict, mode='exec', nocopy=True)
            logger.debug('Python code for widget %s evaluated sussefully.' %
                         name)
        except ValueError:
            logger.exception(
                'An error happen trying to execute the Python '
                'code for \'%s\' board widget, python code: %s', name,
                python_code)
        widget.update(local_dict.get('result', {}))
示例#2
0
class AccountInvoice(models.Model):
    _inherit = 'account.invoice'

    advance_credits_debits_widget = fields.Text(
        compute='_get_advance_accounts_info_JSON')
    has_advancements = fields.Boolean(
        compute='_get_advance_accounts_info_JSON', )

    @api.one
    def _get_advance_accounts_info_JSON(self):
        if self.type not in ('out_invoice', 'in_invoice'):
            # TODO: Deal with refunds later.
            self.advance_credits_debits_widget = json.dumps(False)
            self.has_advancements = False
            return
        if self._advancements:
            if self.type == 'out_invoice':
                title = PRECOLLECTION_TITLE
            elif self.type == 'in_invoice':
                title = PREPAYMENT_TITLE
            data = {
                'title': title,
                'content': self._advancements,
                'invoice_id': self.id,
                'partner_id': self.partner_id.id
            }
            self.advance_credits_debits_widget = json.dumps(data)
            self.has_advancements = True
        else:
            self.advance_credits_debits_widget = json.dumps(False)
            self.has_advancements = False
示例#3
0
class ControlVariableTemplate(models.Model):
    '''The template is the key for get a value in a control variable: E.g.

    env['{model}'].browse({instance}).{field} -> One instance field value

    '''
    _name = 'cdr.control.variable.template'

    name = fields.Char(
        translate=True
    )

    reusable = fields.Boolean(
        default=True
    )

    definition = fields.Text(
        help="Python code string. Allow format string arguments in it."
    )

    args_need = fields.Boolean(
        help="Marc if definition need to be formatted."
    )

    eval_mode = fields.Selection(
        [('eval', 'Eval'),
         ('exec', 'Execute')],
        default='eval'
    )

    @api.onchange('reusable')
    def onchange_reusable(self):
        if not self.reusable:
            self.args_need = False

    def compile(self, values):
        '''Compiles the expression with `values`.'''
        source = self.definition
        if self.args_need:
            source = source.format(**values)
        compile(source, '<cdr-variable>', self.eval_mode)  # TODO: safe_compile
        return source

    def eval(self, now, values):
        """Evaluate template definition with given param values.

        :param now: datetime of evaluation cycle start.

        :param values: param values to passe it to str.format() on
                           definition.

        """
        code = self.compile(values)
        return evaluate(code, self.eval_mode, now=now, env=self.env)
示例#4
0
class A(models.Model):
    _name = 'model.a'

    add_char = fields.Char()
    add_text = fields.Text()
    price_int = fields.Integer()
    cost_float = fields.Float()
    min_int = fields.Integer()
    max_int = fields.Integer()
    active = fields.Boolean(default=True)
    parent_id = fields.Many2one('model.a', 'Parent')
    meldb_ids = fields.Many2many(comodel_name='model.b',
                                 column1='meld_column2_id',
                                 column2='meld_column1_id',
                                 string='relation')
示例#5
0
文件: mock.py 项目: tate11/xopgi.mail
class AliasMockerMixin(models.AbstractModel):
    '''A mixin that mocks mail.alias.

    True implementations will always read the data from the 'mail.alias'
    model.  A virtual mail alias is simply made available so that other parts
    of the systems (views, most importantly) are easily made.

    A virtual alias is by all means a 'mail.alias' that gains other attributes
    via the 'alias_defaults' dictionary.

    Proposed usage::

        >>> class project_valias(models.Model):
        ... _auto = False
        ... _name = 'project.valias'
        ... _inherit = ['xopgi.mail.alias.mocker']
        ...
        ... project_id = fields.Many2one('project.project', string='Project')

    Then the 'project_id' attribute of 'project.valias' will be the key
    'project_id' in the 'alias_default' attribute of any 'mail_alias'.

    '''
    _name = 'xopgi.mail.alias.mocker'

    alias_name = fields.Char(
        'Alias',
        required=True,
        help=("The name of the email alias, e.g. 'jobs' if "
              "you want to catch emails "
              "for <*****@*****.**>"))

    alias_domain = fields.Char(
        'Domain',
        required=True,
        default=get_default_alias_domain,
        help=("The domain of the email alias, e.g. "
              "'example.my.openerp.com' if you want to catch emails "
              "for <*****@*****.**>"))

    alias_defaults = fields.Text(
        'Default Values',
        default='{}',
        help=("A Python dictionary that will be evaluated to "
              "provide default values when creating new "
              "records for this alias."))

    alias_force_thread_id = fields.Integer(
        'Record Thread ID',
        help=("Optional ID of a thread (record) to which "
              "all incoming messages will be attached, "
              "even if they did not reply to it. If set, "
              "this will disable the creation of new "
              "records completely."))

    @api.multi
    def read(self, fields=None, load='_classic_read'):
        """Read the ids from mail.alias if any of fields are not present on
        mail.alias model then search it on alias_defaults dict.

        """
        Model = self.env['mail.alias']
        extraneous = []
        for field in fields:
            if field not in Model._fields.keys():
                extraneous.append(field)
        if extraneous:
            fields = list(set(fields) - set(extraneous))
        if extraneous and 'alias_defaults' not in fields:
            default_added = True
            fields.append('alias_defaults')
        else:
            default_added = False
        result = Model.browse(self.ids).read(fields)
        if not extraneous:
            return result
        else:
            for row in result:
                defaults = str2dict(row['alias_defaults'])
                for field in extraneous:
                    row[field] = defaults.pop(field, False)
                # Restore the defaults but it will have only the keys not
                # in 'extraneous' (those upgraded to fields)
                if not default_added:
                    row['alias_defaults'] = repr(defaults)
                else:
                    row.pop('alias_defaults')
        return result

    @api.model
    def _parse_fields(self, alias_id, vals):
        '''The fields not present on mail.alias model are include on
           alias_defaults dictionary.
        '''
        Aliases = self.env['mail.alias']
        extraneous = []
        fields = set(vals.keys())
        for field in vals.keys():
            if field not in Aliases._fields.keys():
                extraneous.append(field)
        if extraneous:
            fields -= set(extraneous)
            defaults = {}
            if 'alias_defaults' in fields:
                defaults = str2dict(vals['alias_defaults'], 'Default Values')
            else:
                if alias_id:
                    record = Aliases.browse(alias_id)
                    row = record.read(['alias_defaults'])
                    defaults = str2dict(row[0]['alias_defaults'],
                                        'Default Values')
            for field in extraneous:
                value = vals.pop(field, False)
                if field in defaults:
                    defaults.update({field: value})
                else:
                    defaults.setdefault(field, value)
            vals['alias_defaults'] = repr(defaults)
        return vals
示例#6
0
class ControlVariable(models.Model):
    '''The `control variables` define basic mostly numeric evaluations of a
    single basic indicator. For instance, you may define 'the total amount of
    liquidity' you have available.

    '''
    _name = 'cdr.control.variable'
    _inherits = {'cdr.identifier': 'identifier_id'}

    identifier_id = fields.Many2one(
        'cdr.identifier',
        required=True,
        ondelete='cascade',
        help='Identifier the control variable: name, value, evaluations'
    )

    description = fields.Char(
        translate=True,
        help='Description of control variable'
    )

    template = fields.Many2one(
        'cdr.control.variable.template',
        required=True,
        ondelete='restrict',
        help='The template is the key for get a value in a control variable'
    )

    args_need = fields.Boolean(
        related='template.args_need'
    )

    args = fields.Text(
        help="Python dictionary with arguments that template expect."
    )

    @fields.Property
    def arguments(self):
        return evaluate(self.args) if self.args else {}

    evidences = fields.Many2many(
        'cdr.evidence',
        'evidence_control_variable_rel',
        'var_id',
        'evidence_id',
        ondelete='restrict',
        help='Are predicates over several control variables'
    )

    active = fields.Boolean(
        default=True
    )

    cycle = fields.Many2one(
        'cdr.evaluation.cycle',
        help='The control variable are evaluate in evaluation cycle'
    )

    @api.onchange('template', 'template', 'args_need')
    def onchange_template(self):
        '''Take values of
        '''
        if self.template and self.args_need:
            args = [
                "\n\t'%s': " % arg
                for _, arg, _, _ in self.template.definition._formatter_parser()
                if arg
            ] if self.args_need else []
            self.args = "{%s\n}" % ",".join(args)
        else:
            self.args = ""

    def get_value(self):
        '''Get name: value dictionary

        '''
        return {v.name: v.result for v in self}

    def _value(self):
        '''If value: Verify that the value of control variable is evaluated as
        python code else return None.

        '''
        import warnings
        warnings.warn('The _value() method of control variables is '
                      'deprecated.  Use the `result` property.', stacklevel=2)
        return self.result

    @api.requires_singleton
    def _evaluate(self, now=None):
        '''Allow to make python expression for 'args' in the template. The
        field 'args' represent a string of type text.

        '''
        logger.debug('Evaluating %r', self.name)
        from xoeuf.tools import normalize_datetime
        result = self.template.eval(
            normalize_datetime(now or fields.Datetime.now()),
            self.arguments
        )
        logger.debug('Evaluated %r', self.name)
        return result

    @api.constrains('template', 'args')
    def _check_definition(self):
        '''Check the control variable definition.

        '''
        for variable in self:
            try:
                variable.template.compile(variable.arguments)
            except Exception as e:
                raise exceptions.ValidationError(
                    _("Wrong definition: %s") % e.message
                )

    def evaluate(self, cycle):
        '''Evaluate the control variables in a evaluation cycle.

        '''
        if isinstance(cycle, int):
            cycle = self.env['cdr.evaluation.cycle'].browse(cycle)
        import psycopg2
        logger.debug('Start evaluation of %r, cycle: %r', self.mapped('name'), cycle)
        from celery.exceptions import SoftTimeLimitExceeded
        for var in self:
            try:
                value = var._evaluate(cycle.create_date)
            except SoftTimeLimitExceeded:
                raise
            except (psycopg2.InterfaceError, psycopg2.InternalError):
                # This means the cursor is unusable, so there's no point in
                # trying to do anything else with it.
                raise
            except Exception:
                logger.exception(
                    'Error evaluating control variable %s.',
                    var.name
                )
            else:
                var.write(dict(
                    result=value,
                    cycle=cycle.id,
                    evaluations=[CREATE_RELATED(result=value,
                                                cycle=cycle.id)]
                ))
        logger.debug('Done computing variable %r', self.mapped('name'))

    @api.model
    @api.returns('self', lambda value: value.id)
    def create(self, vals):
        logger.debug('Creating variable %r', vals)
        res = super(ControlVariable, self).create(vals)
        logger.debug('Created variable %r', res.name)
        # evaluate by first time to get init value.
        self.env['cdr.evaluation.cycle'].create_and_evaluate(variables=res)
        logger.debug('Evaluated variable %r', res.name)
        return res
示例#7
0
class WorkDistributionModel(models.Model):
    _name = WORKDIST_MODELNAME

    model = fields.Many2one(
        'ir.model', required=True,
        help='Model where Work Distribution Strategies will be applied.')
    model_name = fields.Char(related='model.model', readonly=True)
    group_field = fields.Many2one(
        'ir.model.fields', 'Group Field',
        help='many2one field where that it value determine domain of '
             'distribution destination.')
    strategy_by_group = fields.Boolean()
    use_domain_builder = fields.Boolean()
    domain = fields.Text(
        help='Odoo domain to search in destination_field`s model.',
        default=lambda self: _(DOMAIN_DEFAULT))
    build_domain = fields.Char(
        help='Odoo domain to search in destination_field`s model.',
        string='Domain')
    destination_field = fields.Many2one(
        'ir.model.fields', 'Destination Field', required=True,
        help='Field that it value it will determinate by distribution '
             'strategy apply.')
    destination_model = fields.Char(related='destination_field.relation',
                                    readonly=True)
    other_fields = fields.Text(
        'Other fields', help='Python Dictionary with others variables (Keys) '
                             'used on some distribution strategy and '
                             'model\' fields where it value are. \n '
                             'Eg: {"date": "date_from"}', default='{}')
    strategy_ids = fields.Many2many(
        'work.distribution.strategy', 'distribution_model_strategy',
        'model_id', 'strategy_id', 'Strategies', required=True,
        help='Work Distribution Strategies possible to apply on this model '
             'objects.')
    action = fields.Many2one('ir.actions.act_window')
    strategy_field = fields.Many2one('ir.model.fields', 'Setting Field')
    when_apply = fields.Selection(
        [('all', 'Always'), ('no_set', 'When no value set')], default='all')
    effort_domain = fields.Text(help="Odoo domain to use on effort "
                                     "based strategies. \nEg: "
                                     "[('state','not in',('done','cancel')]")
    translations = fields.Many2many('ir.translation')

    @api.onchange('use_domain_builder')
    def onchange_use_domain_builder(self):
        ''' If the domain constructor changes it assigns default values ​​to the
        domain. By default use_domain_builder is 'True'.

        '''
        if self.use_domain_builder:
            self.build_domain = ''
            self.domain = ''
        else:
            self.domain = (self.build_domain or '') + _(DOMAIN_DEFAULT)

    @api.constrains('other_fields')
    def _check_other_fields(self):
        ''' Validates that the field names defined in the 'other_field'
        dictionary are among the names of the fields defined for the selected
        strategy. And that the defined fields are in some existing model.
        '''
        for model in self:
            fields_name = model.strategy_ids.get_fields_name()
            if fields_name:
                other_fields = safe_eval(model.other_fields or '{}')
                if not other_fields or not all(
                        other_fields.get(f, False) for f in fields_name):
                    raise ValidationError(
                        _('Other fields must define all fields used on '
                          'selected strategies.'))
                obj = self.env[model.model.model]
                for field in other_fields.itervalues():
                    if not obj or not obj._fields.get(field, False):
                        raise ValidationError(
                            _('Some Other fields defined not exist on '
                              'destination model'))
        return True

    @api.constrains('strategy_ids')
    def _check_strategy_ids(self):
        '''Validate that when no group field is defined, only one strategy
        can be selected.

        '''
        for model in self:
            if not model.group_field and len(model.strategy_ids) > 1:
                raise ValidationError(
                    _('When no group field is defined only one strategy '
                      'must be selected.'))
        return True

    @api.model
    @api.onchange('strategy_ids')
    def onchange_strategy_ids(self):
        ''' When the selected strategies change, it is validated that the
        field 'Other field' maintains the structure of a dictionary that its
        values ​​are valid.
        '''
        warning = False
        try:
            other_fields = safe_eval(self.other_fields or '{}')
        except (ValueError, SyntaxError, ):
            other_fields = {}
            warning = {
                'title': _('Warning!'),
                'message': _('Other fields must be a python dict.')
            }
        fields_name = self.strategy_ids.get_fields_name()
        other_fields.update({n: n
                             for n in fields_name - set(other_fields)})
        self.other_fields = str(other_fields)
        return {'warning': warning} if warning else None

    @api.model
    @api.onchange('strategy_by_group')
    def onchange_strategy_by_group(self):
        ''' If the field 'Strategy by group' is not selected the field
        'Group field' is assigned a false value and is hidden.

        '''
        if not self.strategy_by_group:
            self.group_field = False

    def applicable(self, values):
        if not self.when_apply or self.when_apply == 'all':
            return True
        else:
            return not values.get(self.destination_field.name, False)

    @api.model
    def unlink_rest(self):
        self.search([('id', 'not in', self.ids)]).unlink()

    @api.model
    @api.returns('self', lambda value: value.id)
    def create(self, values):
        if values.get('group_field', False):
            self.sudo().create_related(values)
        res = super(WorkDistributionModel, self).create(values)
        res.update_translations()
        return res

    def create_related(self, values):
        """ Create action and field associated.

        """
        field_obj = self.env['ir.model.fields']
        destination_field = field_obj.browse(values['destination_field'])
        group_field = field_obj.browse(values['group_field'])
        model_id = values.get('model', False)
        model = self.env['ir.model'].browse(model_id)
        strategy_field = self.create_field(group_field.relation, model,
                                           destination_field)
        action = self.create_actions(
            group_field.relation, model.name,
            destination_field.field_description, strategy_field)
        values.update(dict(strategy_field=strategy_field, action=action))

    def create_field(self, group_model, model, destination_field):
        ''' Create field to save which distribution strategy use on each
        group_field model objects.

        '''
        field_obj = self.env['ir.model.fields']
        model_obj = self.env['ir.model']
        group_model = model_obj.search([('model', '=', group_model)])
        field_base_name = '%s_%s' % (model.model.replace('.', '_'),
                                     destination_field.name)
        field_name = 'x_%s_id' % field_base_name
        field_data = {
            'model': group_model[0].model,
            'model_id': group_model.ids[0],
            'name': field_name,
            'relation': 'work.distribution.strategy',
            'field_description':
                _("Work Distribution Strategy for %s on %s") %
                (destination_field.field_description, model.name),
            'state': 'manual',
            'ttype': 'many2one'
        }
        new_field = field_obj.create(field_data)
        self.create_ir_model_data_reference('ir.model.fields',
                                            new_field.id, field_name)
        return new_field.id

    def create_actions(self, group_model, model_name, destination_field,
                       strategy_field_id):
        ''' Create actions to config with strategy use on each group_field
        model objects.

        '''
        action_obj = self.env['ir.actions.act_window']
        value_obj = self.env['ir.values']
        name = (_("Define Work Distribution Strategy for '%s' on '%s'")
                % (destination_field, model_name))
        rol = self.env.ref('xopgi_work_distributor.group_distributor_manager',
                           raise_if_not_found=False)
        new_act = action_obj.create({
            'name': name,
            'type': 'ir.actions.act_window',
            'res_model': WIZARD_NAME,
            'src_model': group_model,
            'view_type': 'form',
            'view_mode': 'form',
            'target': 'new',
            'groups_id': LINK_RELATED(rol.id) if rol else False,
            'context': {
                'strategy_field_id': strategy_field_id,
                'field_to_show': FIELD_NAME_TO_SHOW_ON_WIZARD(group_model)
            }
        })
        self.create_ir_model_data_reference('ir.actions.act_window',
                                            new_act.id, name)
        new_val = value_obj.create({
            'name': name,
            'model': group_model,
            'key2': 'client_action_multi',
            'value': "ir.actions.act_window," + str(new_act.id)
        })
        self.create_ir_model_data_reference('ir.values',
                                            new_val.id, name)
        return new_act.id

    def create_ir_model_data_reference(self, model, res_id, name):
        '''Create ir.model.data entry for each field, action or value
        created on run time, to ensure it be removed at module
        uninstall.
        '''
        self.env['ir.model.data'].create({
            'model': model,
            'res_id': res_id,
            'module': 'xopgi_work_distributor',
            'name': '%s-%s' % (model, name),
            'noupdate': True
        })

    def unlink(self):
        """ Unlink action and field associated.

        """
        actions_to_unlink = [i.action.id for i in self if i.action]
        fields_to_unlink = [i.strategy_field.id for i in self
                            if i.strategy_field]
        self.update_translations(force_delete=True)
        result = super(WorkDistributionModel, self).unlink()
        self.sudo().unlink_actions(actions_to_unlink)
        self.sudo().unlink_fields(fields_to_unlink)
        return result

    def unlink_actions(self, actions_to_unlink):
        '''Remove actions of distributions model unlinked.

        '''
        if not actions_to_unlink:
            return
        model = 'ir.actions.act_window'
        self.unlink_ir_model_data_reference(model, actions_to_unlink)
        self.env[model].browse(actions_to_unlink).unlink()
        for action_id in actions_to_unlink:
            args = [('value', '=', "%s,%d" % (model, action_id))]
            values = self.env['ir.values'].search(args)
            if values:
                self.unlink_ir_model_data_reference('ir.values', values.ids)
                values.unlink()

    def unlink_fields(self, fields_to_unlink):
        '''Remove fields of distributions model unlinked.

        '''
        if not fields_to_unlink:
            return
        model = 'ir.model.fields'
        self.unlink_ir_model_data_reference(model, fields_to_unlink)
        self.env[model].browse(fields_to_unlink).unlink()

    def unlink_ir_model_data_reference(self, model, ids):
        self.env['ir.model.data'].search([
            ('model', '=', model),
            ('res_id', 'in', ids),
            ('module', '=', 'xopgi_work_distributor')
        ]).unlink()

    @api.multi
    def write(self, values):
        temp_fields = ['destination_field', 'group_field', 'model']
        if any(f in values for f in temp_fields):
            actions_to_unlink = [i.action.id for i in self if i.action]
            fields_to_unlink = [i.strategy_field.id for i in self
                                if i.strategy_field]
            self.sudo().unlink_actions(actions_to_unlink)
            self.sudo().unlink_fields(fields_to_unlink)
            for item in self.sudo():
                if item.translations:
                    item.translations.unlink()
        result = super(WorkDistributionModel, self).write(values)
        group_field = values.get('group_field', False)
        if any(values.get(f, False) for f in temp_fields):
            for item in self:
                temp_fields = ['destination_field', 'group_field', 'model']
                vals = {f: getattr(item, f).id for f in temp_fields}
                self.create_related(vals)
                for f in temp_fields:
                    vals.pop(f, None)
                item.write(vals)
        if any(f in values for f in temp_fields):
            self.update_translations(force_create=group_field)
        return result

    @api.multi
    def update_translations(self, force_create=False, force_delete=False):
        to_unlink = self.env['ir.translation']
        for item in self:
            if not force_delete and item.group_field:
                if force_create or not item.translations:
                    translations = self.create_translations(
                        item.group_field.relation, item.strategy_field.name,
                        item.strategy_field.field_description,
                        type='field')
                    translations |= self.create_translations(
                        'ir.actions.act_window', 'name', item.action.name,
                        res_id=item.action.id)
                    item.write(dict(
                        translations=[REPLACEWITH_RELATED(*translations.ids)]
                    ))
            if item.translations and (force_delete or not item.group_field):
                to_unlink |= item.translations
        if to_unlink:
            to_unlink.unlink()

    def create_translations(self, model, field, src, res_id=0, type='model'):
        result = self.env['ir.translation']
        for lang in self.env['res.lang'].search([]):
            result |= result.create({
                'type': type,
                'res_id': res_id,
                'module': 'xopgi_work_distributor',
                'name': '%s,%s' % (model, field),
                'src': src,
                'value': src,
                'lang': lang.code
            })
        return result
示例#8
0
class WorkDistributorWizard(models.TransientModel):
    _name = WIZARD_NAME

    name = fields.Char()
    strategy_id = fields.Many2one(
        'work.distribution.strategy', 'Strategy',
        help='Strategy of work distribution to apply to this items.')
    info = fields.Text()

    @api.model
    def fields_view_get(self, view_id=None, view_type='form',
                        toolbar=False, submenu=False):
        result = super(WorkDistributorWizard, self).fields_view_get(
            view_id=view_id, view_type=view_type, toolbar=toolbar,
            submenu=submenu)
        if view_type != 'form' or not result.get('fields', {}).get(
                'strategy_id', False):
            return result
        active_model = self.env.context.get('active_model', False)
        strategy_field = self.env.context.get('strategy_field_id', False)
        model = self.env[WORKDIST_MODELNAME].search(
            [
                ('group_field.relation', '=', active_model),
                ('strategy_field', '=', strategy_field)
            ],
            limit=1
        )
        result['fields']['strategy_id']['domain'] = [
            ('id', 'in', model.strategy_ids.ids)]
        return result

    @api.model
    def default_get(self, fields_list):
        values = super(WorkDistributorWizard, self).default_get(fields_list)
        if 'info' in fields_list:
            active_ids = self.env.context.get('active_ids', False)
            active_model = self.env.context.get('active_model', False)
            ir_model = self.env['ir.model']
            model = ir_model.search([('model', '=', active_model)])[0]
            field = self.env['ir.model.fields'].browse(
                self.env.context.get('strategy_field_id'))
            names = [_('%s\n       Strategy: %s') %
                     (item.name_get()[0][1],
                      getattr(item, field.name).name or '')
                     for item in self.env[active_model].browse(active_ids)]
            info = _("%s(s) to set work distribution strategy:\n"
                     "     * %s") % (model.name, '\n     * '.join(names))
            values.update({'info': info})
        return values

    @api.guess
    def action_config(self, *args, **Kargs):
        return {'type': 'ir.actions.act_window_close'}

    @api.model
    @api.returns('self', lambda value: value.id)
    def create(self, vals):
        res = super(WorkDistributorWizard, self).create(vals)
        active_ids = self.env.context.get('active_ids', False)
        active_model = self.env.context.get('active_model', False)
        field = self.env['ir.model.fields'].browse(
            self.env.context.get('strategy_field_id'))
        if not active_model:
            raise Warning(_('Configuration Error!'),
                          _('The is no active model defined!'))
        self.env[active_model].browse(active_ids).write(
            {field.name: res.strategy_id.id})
        return res
示例#9
0
class WorkDistributionStrategy(models.Model):
    _name = 'work.distribution.strategy'

    name = fields.Char(required=True, translate=True)
    predefine = fields.Boolean()
    code = fields.Text(required=True, default='''
        #  Python code to return on result var value to set on
        #  destination field or None to no update it.
        #  E.g: result = False
        #  self, dist_model, values, candidates and **kwargs are able to use:
        #  self => active strategy (on new api).
        #  dist_model => active model name.
        #  values => python dict to passed to create method.
        #  **kwargs => python dict set on field ``other fields``.
        ''')
    other_fields = fields.Char(
        help='Python List with others variables'
             'needed on this distribution strategy.\n '
             'Eg: ["date", "qtty"]', default='[]')

    _sql_constraints = [
        ('name_unique', 'unique (name)', 'Strategy must be unique!')
    ]

    def apply(self, dist_model, values, **kwargs):
        method = (getattr(self, self.code, None)
                  if self.predefine else self.custom)
        candidates = _evaluate_domain(dist_model, values)
        if method and candidates:
            return method(dist_model, candidates, values, **kwargs)

    def uniform(self, dist_model, candidates, values, **kwargs):
        """Detect the next corresponding domain id and update values with it.

        """
        table = self.env[dist_model.model.model]._table
        if dist_model.group_field:
            query = ("SELECT %s FROM %s WHERE %s = %%s ORDER BY id DESC" %
                     (dist_model.destination_field.name, table,
                      dist_model.group_field.name))
            params = (values.get(dist_model.group_field.name, False),)
        else:
            query = ("SELECT %s FROM %s WHERE %s in %%s ORDER BY id DESC" %
                     (dist_model.destination_field.name, table,
                      dist_model.destination_field.name))
            params = (tuple(candidates.ids),)
        self.env.cr.execute(query, params=params)
        last_dist = self.env.cr.fetchone()
        last_dist = last_dist[0] if last_dist and last_dist[0] else 0
        candidates = candidates.sorted(key=lambda r: r.id)
        return next(
            (id for id in candidates.ids if not last_dist or id > last_dist),
            candidates.ids[0]
        )

    def effort(self, dist_model, candidates, values, **kwargs):
        return self._effort(dist_model, candidates, values)

    def _effort_commons(self, dist_model, **kwargs):
        model = self.env[dist_model.model.model]
        today = normalize_datetime(fields.Date.context_today(self))
        date_field = model._fields[kwargs.get('date_start')]
        to_str = date2str if isinstance(date_field, fields.Date) else dt2str
        return model, today, date_field, to_str

    def effort_month(self, dist_model, candidates, values, **kwargs):
        model, low_date, date_field, to_str = self._effort_commons(dist_model,
                                                                   **kwargs)
        DAYS = 30
        upp_date = low_date + timedelta(DAYS)
        strlow_date = to_str(low_date)
        strupp_date = to_str(upp_date)
        return self._effort(
            dist_model, candidates, values, date_field=date_field.name,
            date_start=strlow_date, date_end=strupp_date)

    def around_effort(self, dist_model, candidates, values, **kwargs):
        model, today, date_field, to_str = self._effort_commons(dist_model,
                                                                **kwargs)
        DAYS = 7
        TOTAL_DAYS = DAYS * 2 + 1
        item_date = values.get(kwargs.get('date_start'), False)
        item_date = normalize_datetime(item_date) if item_date else today
        low_date = (today
                    if item_date < today + timedelta(DAYS)
                    else item_date - timedelta(DAYS))
        upp_date = low_date + timedelta(TOTAL_DAYS)
        strlow_date = to_str(low_date)
        strupp_date = to_str(upp_date)
        return self._effort(
            dist_model, candidates, values,
            date_field=date_field.name, date_start=strlow_date,
            date_end=strupp_date
        )

    def future_effort(self, dist_model, candidates, values, **kwargs):
        model, today, date_field, to_str = self._effort_commons(dist_model,
                                                                **kwargs)
        return self._effort(
            dist_model, candidates, values,
            date_field=date_field.name, date_start=to_str(today)
        )

    def _effort(self, dist_model, candidates, values, date_field=False,
                date_start=False, date_end=False):
        model = self.env[dist_model.model.model]
        min_value = None
        next_dist = False
        group_field_name = (dist_model.group_field.name
                            if dist_model.group_field else False)
        args = ([(group_field_name, '=', values[group_field_name])]
                if group_field_name else [])
        args.extend(safe_eval(dist_model.effort_domain)
                    if dist_model.effort_domain else [])
        if date_field:
            if date_start:
                args.append((date_field, '>=', date_start))
            if date_end:
                args.append((date_field, '<=', date_end))
        for x in candidates.ids:
            current_effort = model.search_count(
                args + [(dist_model.destination_field.name, '=', x)])
            if min_value is None or min_value > current_effort:
                min_value = current_effort
                next_dist = x
        return next_dist

    def custom(self, dist_model, candidates, values, **kwargs):
        if self.code.strip().startswith('{'):
            return safe_eval(self.code or '{')
        else:
            local_dict = locals()
            local_dict.update(globals().get('__builtins__', {}))
            safe_eval(self.code, local_dict, mode='exec', nocopy=True)
            return local_dict.get('result', None)

    @api.model
    def get_fields_name(self, mixed=True):
        result = []
        method = getattr(result, 'extend' if mixed else 'append')
        for strategy in self:
            method(safe_eval(strategy.other_fields)
                   if strategy.other_fields else [])
        return set(result) if mixed else result