class PartnerClassification(models.Model):
    _name = 'res.partner.classification'

    name = fields.Char(required=True, translate=True)
    partners = fields.Many2many('res.partner',
                                'res_partner_classification_rel',
                                'classification_id', 'partner_id')
Exemple #2
0
class WorkDistributionSettings(models.TransientModel):
    _name = 'work.distribution.settings'
    _inherit = 'res.config.settings'

    @api.multi
    def _set_work_distribution(self):
        models = self.mapped('models_ids')
        models.unlink_rest()
        self.invalidate_cache()

    def _compute_work_distribution_models(self):
        for settings in self:
            settings.models_ids = self._get_work_distribution_models()

    @api.model
    def _get_work_distribution_models(self):
        return self.env[WORKDIST_MODELNAME].search([]).ids

    models_ids = fields.Many2many(
        WORKDIST_MODELNAME,
        string='Models',
        compute=_compute_work_distribution_models,
        inverse=_set_work_distribution,
        default=_get_work_distribution_models
    )

    @api.multi
    def install(self):
        self._set_work_distribution()
        return RELOAD_UI
Exemple #3
0
class B(models.Model):
    _name = 'model.b'

    name = fields.Char()
    modela_id = fields.Many2one('model.a', 'Merge')
    melda_ids = fields.Many2many(comodel_name='model.a',
                                 column1='meld_column1_id',
                                 column2='meld_column2_id',
                                 string='relation')
    partner_id = fields.Many2one('res.partner', 'Parent')
Exemple #4
0
class AccountPartnerLedger(models.TransientModel):
    _inherit = "account.report.partner.ledger"

    partner_ids = fields.Many2many(comodel_name='res.partner',
                                   string='Partners')

    def _print_report(self, data):
        if self.partner_ids:
            data['form'].update(partner_ids=self.partner_ids.ids)
        return super(AccountPartnerLedger, self)._print_report(data)
Exemple #5
0
class MailConfig(models.TransientModel):
    _inherit = 'base.config.settings'

    default_views = fields.Many2many(
        'xopgi.selectable.view',
        default=lambda self: self.env['xopgi.selectable.view'].search([]))

    @api.multi
    def execute(self):
        result = super(MailConfig, self).execute()
        self.default_views.search([('id', 'not in', self.default_views.ids)
                                   ]).unlink()
        return result
class ResPartner(models.Model):
    _inherit = 'res.partner'

    classifications = fields.Many2many('res.partner.classification',
                                       'res_partner_classification_rel',
                                       'partner_id', 'classification_id')
    employee = fields.Boolean(
        compute='_get_classification',
        inverse=lambda self: self._set_classification('employee'),
        store=True)
    customer = fields.Boolean(
        compute='_get_classification',
        inverse=lambda self: self._set_classification('customer'),
        store=True)
    supplier = fields.Boolean(
        compute='_get_classification',
        inverse=lambda self: self._set_classification('supplier'),
        store=True)

    @api.one
    @api.depends('classifications')
    def _get_classification(self):
        classes_ids = self.classifications.ids
        ref = lambda xml_id: self.env.ref(xml_id, raise_if_not_found=False)
        for attr, classname in ATTR2CLASSIFIER_MAPPING.items():
            classific = ref(classname)
            setattr(self, attr, classific.id in classes_ids)

    def _set_classification(self, attrname):
        ref = lambda xml_id: self.env.ref(xml_id, raise_if_not_found=False)
        classific = ref(ATTR2CLASSIFIER_MAPPING.get(attrname, 'null'))
        if classific:
            if getattr(self, attrname, False):
                self.write({'classifications': [LINK_RELATED(classific.id)]})
            else:
                self.write({'classifications': [FORGET_RELATED(classific.id)]})

    @api.model
    def migrate_classifications(self):
        """This is needed because a migration not occur on module installation.

        """
        ref = lambda xml_id: self.env.ref(xml_id, raise_if_not_found=False)
        partners = self.with_context(active_test=False)
        for attr, classname in ATTR2CLASSIFIER_MAPPING.items():
            partners = partners.search([(attr, '=', True)])
            classification = ref(classname)
            if partners and classification:
                partners.write(
                    {'classifications': [LINK_RELATED(classification.id)]})
Exemple #7
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')
class MoveLine(models.Model):
    _inherit = 'account.move.line'

    @api.multi
    @api.depends('move_id.line_ids')
    def _compute_counterpart_accounts(self):
        for line in self:
            line.counterpart_account_ids = line.move_id.mapped(
                'line_ids.account_id').filtered(
                    lambda account: account != line.account_id)

    def _search_counterpart_accounts(self, operator, value):
        # XXX: This will search in any of the accounts (included the line's
        # account).  This is because I can't express the predicate of being
        # not equal to the line's account_id.
        return [('move_id.line_ids.account_id', operator, value)]

    counterpart_account_ids = fields.Many2many(
        'account.account',
        string='Counterpart accounts',
        compute=_compute_counterpart_accounts,
        search=_search_counterpart_accounts,
    )
Exemple #9
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)
Exemple #10
0
class object_merger_settings(models.Model):
    _name = 'object.merger.settings'
    _inherit = 'res.config.settings'

    def _get_default_object_merger_models(self):
        return IrModel.sudo().search([('object_merger_model', '=', True)])

    models_ids = fields.Many2many('ir.model',
                                  'object_merger_settings_model_rel',
                                  'object_merger_id',
                                  'model_id',
                                  string='Models',
                                  domain=_NON_TRANSIENT_MODEL_DOMAIN,
                                  context={'object_merger_settings': True},
                                  default=_get_default_object_merger_models)

    informal_reference_ids = fields.Many2many(
        'informal.reference',
        'object_merger_informal_reference_rel',
        'object_merger_id',
        'informal_reference_id',
        'Informal References',
        help='Know cases of pair of field represented a '
        'reference to an specific object from '
        'especific model.',
        default=lambda s: s.env['informal.reference'].search([]))

    @api.multi
    def update_field(self):
        model_obj = self.env['ir.model']
        action_obj = self.env['ir.actions.act_window']
        value_obj = self.env['ir.values']
        field_obj = self.env['ir.model.fields']
        template_action = self.sudo().env.ref(
            'xopgi_object_merger.act_merge_template', raise_if_not_found=False)
        if not self:
            return False
        # Unlink Previous Actions
        unlink_records = action_obj.search([('res_model', '=',
                                             'object.merger'),
                                            ('id', '!=', template_action.id)])
        for unlink_id in unlink_records:
            unlink_id.unlink()
            un_val = value_obj.search([
                ('value', '=', "ir.actions.act_window," + str(unlink_id.id))
            ])
            un_val.unlink()
        # Put all models which were selected before back to not an object_merger
        model_not_merge = model_obj.search([
            ('id', 'not in', self.models_ids.ids),
            ('object_merger_model', '=', True)
        ])
        model_not_merge.write({'object_merger_model': False})
        # Put all models which are selected to be an object_merger
        self.models_ids.write({'object_merger_model': True})
        object_merger = self.models_ids.search(
            [('model', '=', 'object.merger')], limit=1)
        for model in self.models_ids:
            field_name = 'x_' + model.model.replace('.', '_') + '_id'
            name = "Merge"
            default = {
                'src_model': model.model,
                'context': {
                    'field_to_read': field_name
                }
            }
            temp_acc = template_action.copy(default=default)
            value_obj.create({
                'name':
                name,
                'model':
                model.model,
                'key2':
                'client_action_multi',
                'value':
                "ir.actions.act_window," + str(temp_acc.id)
            })
            found = field_obj.search([('name', '=', field_name),
                                      ('model', '=', 'object.merger')])
            if not found:
                field_data = {
                    'model': 'object.merger',
                    'model_id': object_merger.id,
                    'name': field_name,
                    'relation': model.model,
                    'field_description': _('To keep'),
                    'state': 'manual',
                    'ttype': 'many2one',
                }
                field_obj.sudo().create(field_data)
        return True

    @api.multi
    def install(self):
        self.update_field()
        return {
            'type': 'ir.actions.client',
            'tag': 'reload',
        }
class MergePartnerGroup(models.Model):
    """A group of partner which are deemed duplicates.

    - Is a partner when `parent_id` points to another instance of the same
      type representing the group.

    - Is a group when has no `parent_id`  and several partners point to here.
      In this case the referenced partner is the destination partner.

    """
    _name = 'xopgi.partner.merge.group'
    _order = "name asc"

    dest_partner_id = fields.Many2one(
        'res.partner',
        string='Destination partner'
    )

    partner_ids = fields.Many2many(
        comodel_name='res.partner',
        relation='xopgi_partner_merge_group_partners',
        column1='category_id',
        column2='partner_id',
        string='Partners'
    )

    name = fields.Char(
        related=('dest_partner_id', 'name'),
        string='Name',
        readonly=True,
        store=True,
    )

    @api.multi
    @mute_logger('openerp.osv.expression', 'openerp.models')
    def merge(self):
        """Merge several `partners` into a single destination partner.

        Original `partners` will be removed from the DB afterwards.  Only
        target will remain.  All references to the original partners
        will be re-establish to the target partner.

        If `partners` constains less that 2 partners, do nothing.  All
        partners must have the same email.

        If sources `partner` is none, the target partner defaults to the last
        created record in `partners`.

        :param sources: The source partners.
        :type sources: A recordset of 'res.partners'.

        :param target: The target partner.
        :type target: A singleton recordset of 'res.partners' or None.

        """
        sources = self.partner_ids
        target = self.dest_partner_id
        if sources.sudo().exists() and len(sources) < 2:
            raise UserError(_("Constains less that 2 partners, do nothing"))
        partner_different_emails = {
            p.email
            for p in sources
            if p.email and p.email.strip()
        }
        if len(partner_different_emails) > 1:
            user = self.env.user
            if user.has_group('xopgi_partner_merge.base_parter_merger'):
                object_merger = self.env['object.merger']
                object_merger.merge(sources, target)
            else:
                raise UserError(
                    _("All contacts must have the same email. Only the "
                      "users with Partner Merge rights can merge contacts "
                      "with different emails.")
                )
        object_merger = self.env['object.merger']
        object_merger.merge(sources, target)
        self.unlink()
Exemple #12
0
class AccountInvoice(models.Model):
    _inherit = 'account.invoice'

    partner_tags = fields.Many2many(related='partner_id.category_id',
                                    string="Partner's Tags")
Exemple #13
0
class CreateInvoiceWizard(models.TransientModel):
    _name = "xopgi.salesperson_wizard"
    _description = "Create supplier invoice in form of commission"

    def _get_salesperson(self):
        return self.env["account.analytic.account"].browse(
            self._context.get("active_id")).primary_salesperson_id

    primary_salesperson_id = fields.Many2one("res.users",
                                             string="Salesperson",
                                             required=True,
                                             default=_get_salesperson)
    analytic_account_ids = fields.Many2many("account.analytic.account",
                                            string="Operations",
                                            required=True,
                                            domain=[("state", "=", "close"),
                                                    ("supplier_invoice_id",
                                                     "=", False)])

    @api.multi
    def onchange(self, values, field_name, field_onchange):
        # Sanitize the result of the onchange.  Odoo and the Web Client seems
        # not to look eye to eye when dealing with x2many.  Odoo sends
        # UNLINKALL and the UPDATE commands.  I thought that if Odoo would
        # send the LINK_RELATED before, it would fix all the issues.  However,
        # it does not work.
        #
        # This hack solves this for this specific case: Replace all
        # UPDATE_RELATED by LINK_RELATED.  We can do this at this point,
        # because we're no editing any of the values of the accounts.
        def correct(cmd):
            if cmd[COMMAND_INDEX] == UPDATE_RELATED:
                return LINK_RELATED(cmd[ID_INDEX])
            else:
                return cmd

        result = super(CreateInvoiceWizard,
                       self).onchange(values, field_name, field_onchange)
        value = result.setdefault('value', {})
        links = value.setdefault('analytic_account_ids', [])
        if links and links[0] == (UNLINKALL_RELATED, ):
            links[1:] = [correct(cmd) for cmd in links[1:]]
        return result

    @api.onchange('primary_salesperson_id')
    def _update_accounts(self):
        accounts = self.env["account.analytic.account"].search([
            ("primary_salesperson_id.id", "=", self.primary_salesperson_id.id),
            ("state", "=", "close"), ("supplier_invoice_id", "=", False)
        ])
        self.analytic_account_ids = accounts

    @api.requires_singleton
    def generate_supplier_invoice(self):
        partner = self.primary_salesperson_id.partner_id
        account = partner.property_account_payable_id
        invoice = self._supplier_invoice_generator(partner, account,
                                                   self.analytic_account_ids)
        return invoice.get_formview_action()

    @api.model
    def enqueue_generate_supplier_invoice_cron(self):
        from xoeuf.odoo.jobs import Deferred
        # Avoid performing a big computation within the WorkerCron process
        # which is under tight timeout restriction (because the same
        # restriction applies to Cron and HTTP workers).  Jobs are allowed to
        # take longer.
        Deferred(self.generate_supplier_invoice_cron)

    @api.model
    def generate_supplier_invoice_cron(self):
        Account = self.env["account.analytic.account"]
        accounts = Account.search([('state', '=', 'close'),
                                   ('supplier_invoice_id', '=', False),
                                   ('primary_salesperson_id', '!=', False)],
                                  order='primary_salesperson_id')
        for user, partner_accounts in groupby(
                accounts, attrgetter('primary_salesperson_id')):
            self._supplier_invoice_generator(
                user.partner_id, user.property_account_payable_id,
                reduce(operator.or_, partner_accounts, Account))

    def _supplier_invoice_generator(self, partner, account,
                                    analytic_account_ids):
        d = date.today()
        company = self._context.get('company_id', self.env.user.company_id)
        journal = self.env['account.journal'].search(
            [('type', '=', 'purchase'), ('company_id', '=', company.id)],
            limit=1)
        # The context allows Odoo to compute the defaults we're missing here.
        result = Invoice.sudo().with_context(journal_id=journal.id).create(
            dict(
                partner_id=partner.id,
                account_id=account.id,
                type='in_invoice',  # supplier invoice
                name=_(u"Commission. ") + safe_decode(d.strftime("%B")) +
                u" / " + safe_decode(partner.name),
                origin=_(u"Commission. ") + safe_decode(d.strftime("%B")) +
                u" / " + safe_decode(partner.name),
                journal_id=journal.id,
                invoice_line_ids=[
                    CREATE_RELATED(quantity=1,
                                   account_analytic_id=analytic_account.id,
                                   name=_("Operation") +
                                   safe_decode(analytic_account.name),
                                   price_unit=analytic_account.commission)
                    for analytic_account in analytic_account_ids
                ]))
        analytic_account_ids.write(dict(supplier_invoice_id=result.id))
        followers = [partner.id]
        employees = self.env["hr.employee"].search([("user_id.partner_id", "=",
                                                     partner.id)])
        for employee in employees:
            if employee.parent_id:
                manager = employee.parent_id.user_id.partner_id
                if any(manager):
                    followers.append(manager.id)
        result.message_subscribe(partner_ids=followers)
        return result
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
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
Exemple #16
0
class MoveMessageWizard(models.TransientModel):
    _name = 'move.message.wizard'
    _inherit = 'common.thread.wizard'

    thread_id = fields.Reference(
        string='Destination Mail Thread',
        size=128,
        selection=lambda self: get_model_selection(self),
        required=True)
    message_ids = fields.Many2many('mail.message',
                                   'message_move_rel',
                                   'move_id',
                                   'message_id',
                                   'Messages',
                                   readonly=True)
    leave_msg = fields.Boolean(
        'Preserve original messages',
        help="Check for no remove message from original thread.",
        default=True)

    @api.model
    def fields_view_get(self,
                        view_id=None,
                        view_type='form',
                        toolbar=False,
                        submenu=False):
        if self._uid != SUPERUSER_ID and not self.env['res.users'].has_group(
                'xopgi_mail_move_message.group_move_message'):
            raise AccessError(_('Access denied.'))
        result = super(MoveMessageWizard,
                       self).fields_view_get(view_id=view_id,
                                             view_type=view_type,
                                             toolbar=toolbar,
                                             submenu=submenu)
        return result

    @api.onchange('thread_id')
    @api.depends('thread_id')
    def onchange_thread_id(self):
        if self.thread_id:
            self.model_id = self.thread_id._name

    @api.model
    def default_get(self, fields_list):
        values = super(MoveMessageWizard, self).default_get(fields_list)
        if 'message_ids' in fields_list:
            values['message_ids'] = self._context.get('active_ids', [])
        return values

    @api.multi
    def confirm(self):
        '''Create a new mail thread, remove original message if not
        leave_msg  and open new thread on edit form.

        '''
        self.message_ids.do_move_message(self.thread_id._name,
                                         self.thread_id.id, self.leave_msg)
        try:
            # Can I read the thread model?  If not, the message it's there but
            # I cannot be redirected to the model's view.
            self.thread_id.read([])
        except AccessError:
            return RELOAD_UI
        else:
            # Returns an ir.actions.act_window given an res_id
            return self.get_thread_action(res_id=self.thread_id.id)