Example #1
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')
Example #2
0
class CommonThreadWizard(models.TransientModel):
    _name = 'common.thread.wizard'

    model_id = fields.Selection(
        string='Model',
        selection=lambda self: get_model_selection(self),
        required=True)
    view = fields.Many2one('xopgi.selectable.view')
    views_count = fields.Integer(compute='_get_views_count')

    @api.onchange('model_id')
    @api.depends('model_id')
    def _get_views_count(self):
        selectable_view = self.env['xopgi.selectable.view']
        for wizard in self:
            if wizard.model_id:
                conf_views = selectable_view.get_views(self.model_id)
                views_count = len(conf_views)
                self.views_count = views_count
                if views_count >= 1:
                    self.view = conf_views[0]
            else:
                self.views_count = 0
                self.view = False

    def get_thread_action(self, res_id=None):
        """ Returns the action that shows the form of this model
        """
        return self.view.get_action(model=self.model_id, res_id=res_id)
Example #3
0
class XopgiBoardWidgetRel(models.AbstractModel):
    _name = WIDGET_REL_MODEL_NAME
    _order = 'priority'

    widget = fields.Many2one(WIDGET_MODEL_NAME,
                             delegate=True,
                             required=True,
                             ondelete='cascade')
    priority = fields.Integer(default=1000)

    def get_widgets(self):
        """ Get all widget dicts for uid and sorts them by priority.

        """
        models = self.get_widget_capable_models()
        widgets = sorted(itertools.chain(
            *[list(model.get_user_widgets()) for model in models]),
                         key=operator.attrgetter('priority'))
        result = []
        # Adding missing widget
        for widget in widgets:
            widget.get_set_widgets(result)
        return result

    def get_user_widgets(self):
        """ It must be implemented on extended models.

        Should return a recordset of user's corresponding widgets.

        """
        raise NotImplementedError()

    def get_widget_capable_models(self):
        """ Get a list of models instances that have `get_user_widgets` item

        """
        result = []
        for model in self.env.registry.values():
            if hasattr(model, "get_user_widgets"):
                if model._name != WIDGET_REL_MODEL_NAME:
                    result.append(self.env[model._name])
        return result

    def get_set_widgets(self, result):
        """ Update in-place result adding missing widgets.

        """
        for widget in self.read(fields=[
                'name', 'category', 'template_name', 'xml_template',
                'python_code'
        ]):
            widget.pop('id', None)
            if widget not in result:
                result.append(widget)
Example #4
0
class SelectableView(models.Model):
    _name = 'xopgi.selectable.view'
    _rec_name = 'label'
    _order = 'priority'

    label = fields.Char(translate=True, required=True)
    model_id = fields.Selection(
        string='Model',
        selection=lambda self: get_model_selection(self),
        required=True)
    view = fields.Many2one('ir.ui.view', required=True)
    priority = fields.Integer(default=16)

    def get_views(self, model):
        domain = [('model_id', '=', model)]
        return self.search(domain)

    def get_action(self, model=None, target='current', res_id='None'):
        """ Return an ir.actions.act_window
        """
        res = dict(target=target)
        if self:
            view = self[0]
            model = view.model_id

        if res_id is not None:
            # If the recordset is empty in Odoo8 it returns an empty list.In
            # odoo10 gives error.
            values_action = self.env[model].browse(res_id).get_access_action()

            # If values_action contains a list it is because get_acess_action
            # was executed #in odoo8 and returns a [{}], in odoo10 returns a {}.
            if isinstance(values_action, list):
                values_action = values_action[0]
            res = dict(values_action, **res)
        else:
            values = {
                'type': 'ir.actions.act_window',
                'res_model': model,
                'view_type': 'form',
                'view_mode': 'form',
                'views': [(self.view.id, 'form')],
                'context': self._context
            }
            res = dict(values, **res)
        return res

    @api.multi
    def try_selected_view(self):
        return self.get_action(target='new')
Example #5
0
class ir_model(models.Model):
    _inherit = 'ir.model'

    _sql_constraints = [
        ('positive_merge_limit', 'check (merge_limit >= 0)',
         'The limit quantity of objects to allow merge at one time must be '
         'positive number!'),
    ]

    object_merger_model = fields.Boolean(
        'Object Merger',
        help=('If checked, by default the Object Merger configuration will '
              'get this module in the list'))
    merge_limit = fields.Integer(
        'Merge Limit',
        default=0,
        help='Limit quantity of objects to allow merge at one time.')
    field_merge_way_ids = fields.One2many(
        'field.merge.way.rel',
        'model',
        string='Specific Merge Ways',
        help='Specify how to merge the fields')

    @api.model
    def fields_view_get(self,
                        view_id=None,
                        view_type='form',
                        toolbar=False,
                        submenu=False):
        if (view_type == 'form'
                and self._context.get('object_merger_settings', False)):
            _, view_id = self.env['ir.model.data'].get_object_reference(
                'xopgi_object_merger', 'view_ir_model_merge_form')
        res = super(ir_model, self).fields_view_get(view_id=view_id,
                                                    view_type=view_type,
                                                    toolbar=toolbar,
                                                    submenu=submenu)
        return res

    @api.requires_singleton
    def _merge(self, sources, target):
        if self.field_merge_way_ids:
            values = self.field_merge_way_ids.meld(sources, target)
        else:
            values = {}
        if values:
            target.write(values)
Example #6
0
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
Example #7
0
class SystemEvent(models.Model):
    '''Generic CDR event definition. For specifics CDR events
    implementations just need to inherit by delegation of this model and
    override evaluate method.

    Recommendation: define _description for specific event implementations
    to allow correct user identification.

    '''

    _name = 'cdr.system.event'
    _description = "Generic CDR event"

    _order = 'priority'

    name = fields.Char(translate=True)

    definition = fields.Char(
        required=True,
        help=("Boolean expression combining evidences and operators.  "
              "For example: evidence1 or evidence2 and evidence3"))

    next_call = fields.Datetime(
        default=fields.Datetime.now(),
        help=("The date and time at which this event will be checked again.  "
              "This is when the evidences and its variables will be computed "
              "again."))

    priority = fields.Integer(
        default=10,
        help=("Priority in which events are to be evaluated in an evaluation "
              "cycle. When you run a search they will come sorted according "
              "to your priority."))

    active = fields.Boolean(default=True)

    evidences = fields.Many2many('cdr.evidence',
                                 'event_evidence_rel',
                                 'event_id',
                                 'evidence_id',
                                 compute='get_evidences',
                                 store=True)

    specific_event = fields.Reference(
        [],
        compute='_get_specific_event',
        help='Reference at specific event: basic or recurrent event')

    state = fields.Selection(EVENT_STATES,
                             help='State of the event: Raising or Not raising')

    action = fields.Selection(EVENT_ACTIONS_SELECTION, string="Last action")

    def get_specific_event_models(self):
        '''Get models that look like specific event.

        '''
        result = []
        for model_name in self.env.registry.keys():
            model = self.env[model_name]
            if 'cdr.system.event' in getattr(model, '_inherits', {}):
                result.append(model)
        return result

    def _get_specific_event(self):
        '''Get specific event reference from it's generic one.

        '''
        for event in self:
            for model in self.get_specific_event_models():
                field = model._inherits.get('cdr.system.event')
                result = model.search([(field, '=', event.id)], limit=1)
                if result:
                    event.specific_event = "%s,%d" % (result._name, result.id)

    @api.depends('definition')
    @api.onchange('definition')
    def get_evidences(self):
        '''Get evidences referenced on event definition.

        '''
        evidences = self.env['cdr.evidence']
        for event in self:
            if event.active and event.definition:
                domain = [('name', 'in',
                           tuple(get_free_names(event.definition)))]
                event.evidences = evidences.search(domain)
            else:
                event.evidences = evidences

    def _get_evidences_to_evaluate(self):
        return self.mapped('evidences')

    def _evaluate(self):
        return evaluate(self.definition, **self.evidences.get_bool_value())

    @api.constrains('definition')
    def _check_definition(self):
        for record in self:
            try:
                record._evaluate()
            except Exception as e:
                raise exceptions.ValidationError(
                    _("Wrong definition: %s") % e.message)

    def evaluate(self, cycle):
        if isinstance(cycle, int):
            cycle = self.env['cdr.evaluation.cycle'].browse(cycle)
        for event in self:
            # call specific event evaluate method to get each
            # corresponding behavior.
            event.specific_event.evaluate(cycle)
        for signalname, signal in EVENT_SIGNALS.items():
            # Do not use groupby because a recordset is needed on signaling
            # send.
            sender = self.filtered(lambda event: event.action == signalname)
            if sender:
                logger.debug('Sending signal (%s) for Events: (%s)',
                             signalname, ', '.join(e.name for e in sender))
                signal.send(sender=sender)
Example #8
0
class BasicEvent(models.Model):
    _name = 'cdr.basic.event'
    _description = 'Basic CDR event'

    _inherits = {'cdr.system.event': 'event_id'}

    event_id = fields.Many2one('cdr.system.event',
                               required=True,
                               ondelete='cascade')

    interval = fields.Float(
        required=True,
        help='Time (in hours:minutes format) between evaluations.')

    time_to_wait = fields.Float(
        required=True,
        help='Time (in hours:minutes format) getting '
        'consecutive positive evaluations before raise.')

    times_to_raise = fields.Integer(
        help='Waiting time to launch an event while an evidence is true in a '
        'time interval')

    @api.depends('interval')
    def get_next_call(self):
        '''Compute the next evaluation date.

        '''
        for event in self:
            if event.active and event.interval:
                event.next_call = datetime.now() + timedelta(
                    hours=event.interval)
            else:
                event.next_call = False

    def update_event(self, value, cycle):
        '''Update the fields next call, state and action for an event.
        When an event is evaluated is necessary to update its values.

        '''
        next_call = str2dt(cycle.create_date) + timedelta(hours=self.interval)
        # If the interval is less or equal zero that means that the event does
        # not wait any time to launch.
        if self.interval <= 0:
            times_to_raise = -1
        else:
            times_to_raise = ((self.time_to_wait / self.interval)
                              if not value else self.times_to_raise - 1)
        state = 'raising' if value and times_to_raise < 1 else 'not_raising'
        if self.state == 'raising':
            action = 'continue_raising' if state == 'raising' else 'stop_raising'
        else:
            action = 'raise' if state == 'raising' else 'do_nothing'
        values = dict(next_call=next_call, state=state, action=action)
        self.write(values)

    def evaluate(self, cycle):
        '''Evaluate the basic event in a evaluation cycle.

        '''
        if isinstance(cycle, int):
            cycle = self.env['cdr.evaluation.cycle'].browse(cycle)
        try:
            value = self.event_id._evaluate()
        except Exception:
            logger.exception('Error evaluating event %s defined as: ',
                             self.name, self.definition)
            return None
        else:
            self.update_event(value, cycle)
Example #9
0
class ResPartner(models.Model):
    _inherit = 'res.partner'

    id = fields.Integer('Id', readonly=True)
    create_date = fields.Datetime('Create Date', readonly=True)
Example #10
0
class RecurrentRuleDefinition(models.AbstractModel):
    '''A recurrence definition mixin.

    The model behind this definition is that of the python module
    `dateutil.rrule`:mod:.

    '''
    _name = RECURRENT_DESCRIPTION_MODEL
    _inherit = ['recurrence.abs.day_of_week']

    date_from = fields.Date(
        'Initial date',
        required=True,
        default=fields.Date.today,
        # XXX: When we return an occurrence this matches the date of the
        # occurrence.
        help='Date at which this recurrent event starts.')

    duration = fields.Integer('Duration',
                              default=1,
                              help='Duration (days) of each occurrence')

    allday = fields.Boolean(
        'All Day',
        default=True,
        help='Is this a day-long occurrence?',
    )

    freq = fields.Selection(
        FREQ,
        'Frequency type',
        default=DEFAULT_FREQ,
        # XXX: Don't put this, because there's an error in the JS client that
        # messes up with the invisible toggling we have there.
        # help='Frecuency type (Daily/Weekly/Monthly/Yearly)'
    )

    interval = fields.Integer(
        'Repeat Every',
        default=DEFAULT_INTERVAL,
        help='Repeat every ...',
    )

    # Recurrence by month data.
    days_option = fields.Selection(
        SELECT_WEEKDAY_MONTHDAY,
        'Option',
        default=DEFAULT_WEEK_MONTH,
        help='Does this occur on the same day of the month, or the week',
    )

    monthly_day = fields.Integer(
        'Days of month', default=lambda *args: datetime.date.today().day)

    by_week_day = fields.Selection(
        BYWEEKDAY,
        'Reference',
        default=DEFAULT_BYWEEKDAY,
        help=("Used in combination with each week day selection.  If you "
              "check Monday, then this can mean: every Monday, the first "
              "Monday, the last Monday, etc... You may choose several week "
              "days."))

    months = fields.Selection(
        MONTHS,
        'Month',
        deafault=lambda *args: str(datetime.date.today().month),
        help="The month of the year at which this event reoccurs.")

    is_easterly = fields.Boolean(
        'By easter',
        help="For events that reoccurs based on Western Easter Sunday.")

    byeaster = fields.Integer(
        'By easter',
        default=0,
        help='Number of days from Western Easter Sunday.')

    # In this model, the end of recurrence is EITHER: a) does not have and
    # end, b) after many instances,  c) after a given date.
    end_type = fields.Selection(
        END_TYPE,
        'Recurrence Termination',
        default=DOES_NOT_END,
        help="How this recurrence stops from happening.")

    count = fields.Integer('Repeat',
                           default=5,
                           help='Repeat recurrent event by x times')

    until = fields.Date('Repeat Until',
                        help='Date end for the recurrent termination')

    # TODO: Should we need to store this in the DB?
    rrule = fields.Char(
        'RRULE',
        size=124,
        readonly=True,
        default='',
        compute='_compute_rrule_string',
        help=(
            'This field is update after to creates or to update the recurrent'
            ' model by the function  _update_rrule. By default it is taken'
            ' value but then it is calculated and takes a similar value.'
            ' E.g. rrule=FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,MO'),
    )

    @api.depends('count', 'until', 'end_type', 'mo', 'tu', 'we', 'th', 'fr',
                 'sa', 'su', 'is_easterly', 'byeaster', 'months',
                 'monthly_day', 'by_week_day', 'freq', 'days_option',
                 'interval')
    def _compute_rrule_string(self):
        for record in self:
            record.rrule = str(record.get_rrule_from_description())

    @api.requires_singleton
    def get_rrule_from_description(self):
        '''The recurrent rule that describes this recurrent event.

        :returns: `dateutil.rrule.rrule`:class:.

        '''
        from xoeuf.tools import normalize_date
        kwargs = dict(
            dtstart=normalize_date(self.date_from),
            interval=max(1, self.interval or 0),
        )
        if self.end_type == ENDS_AT:
            kwargs['until'] = max(normalize_date(self.date_from),
                                  normalize_date(self.until))  # or date_to?
        elif self.end_type == ENDS_AFTER_MANY:
            kwargs['count'] = min(1, self.count)
        else:
            assert self.end_type == DOES_NOT_END
        if self.days_option == USE_WEEK_DAY:
            kwargs['byweekday'] = self.byweekday
        elif self.days_option == USE_MONTH_DAY:
            kwargs['bymonthday'] = self.monthly_day
        else:
            assert False
        if self.is_easterly:
            kwargs['byeaster'] = self.byeaster
        else:
            kwargs['bymonth'] = int(self.months)
        return _rrule.rrule(FREQ_TO_RULE[self.freq], **kwargs)

    @fields.Property
    def byweekday(self):
        return self._weekno

    @api.constrains('monthly_day')
    def _check_monthly_day_no_longer_than_month(self):
        for record in self:
            if not (-31 <= record.monthly_day <= 31):
                raise ValidationError(
                    'You must provide a valid day of the month')

    @api.constrains('byeaster', 'is_easterly')
    def _check_byeaster_no_longer_than_year(self):
        for record in self:
            if record.is_easterly:
                if not (-365 <= record.byeaster <= 365):
                    raise ValidationError(
                        'By Easter must not extend longer than a year')

    @api.requires_singleton
    def iter_from(self, start=None):
        '''Return an iterator that yields each occurrence after `start` date.

        If `start` is None, start at the first `date` (field ``date_from``).

        :returns: A generator of the dates of the occurrences.

        .. warning:: This can be an infinite iterator.

        '''
        from xoeuf.tools import normalize_date
        if start is None:
            start = normalize_date(self.date_from)
        return self.get_rrule_from_description().xafter(start)