File: test_mail_models.py

package info (click to toggle)
odoo 18.0.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 878,716 kB
  • sloc: javascript: 927,937; python: 685,670; xml: 388,524; sh: 1,033; sql: 415; makefile: 26
file content (483 lines) | stat: -rw-r--r-- 18,723 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo import api, fields, models, _
from odoo.tools import email_normalize


class MailTestSimple(models.Model):
    """ A very simple model only inheriting from mail.thread when only
    communication history is necessary. """
    _description = 'Simple Chatter Model'
    _name = 'mail.test.simple'
    _inherit = ['mail.thread']

    name = fields.Char()
    email_from = fields.Char()

    def _message_compute_subject(self):
        """ To ease mocks """
        _a = super()._message_compute_subject()
        return _a

    def _notify_by_email_get_final_mail_values(self, *args, **kwargs):
        """ To ease mocks """
        _a = super()._notify_by_email_get_final_mail_values(*args, **kwargs)
        return _a

    def _notify_by_email_get_headers(self, headers=None):
        headers = super()._notify_by_email_get_headers(headers=headers)
        headers['X-Custom'] = 'Done'
        return headers


class MailTestSimpleWithMainAttachment(models.Model):
    _description = 'Simple Chatter Model With Main Attachment Management'
    _name = 'mail.test.simple.main.attachment'
    _inherit = ['mail.test.simple', 'mail.thread.main.attachment']


class MailTestSimpleUnfollow(models.Model):
    """ A very simple model only inheriting from mail.thread when only
    communication history is necessary with unfollow link enabled in
    notification emails even for non-internal user. """
    _description = 'Simple Chatter Model'
    _name = 'mail.test.simple.unfollow'
    _inherit = ['mail.thread']
    _partner_unfollow_enabled = True

    name = fields.Char()
    company_id = fields.Many2one('res.company')
    email_from = fields.Char()


class MailTestAliasOptional(models.Model):
    """ A chatter model inheriting from the alias mixin using optional alias_id
    field, hence no inherits. """
    _description = 'Chatter Model using Optional Alias Mixin'
    _name = 'mail.test.alias.optional'
    _inherit = ['mail.alias.mixin.optional']

    name = fields.Char()
    company_id = fields.Many2one('res.company', default=lambda self: self.env.company)
    email_from = fields.Char()

    def _alias_get_creation_values(self):
        """ Updates itself """
        values = super()._alias_get_creation_values()
        values['alias_model_id'] = self.env['ir.model']._get_id('mail.test.alias.optional')
        if self.id:
            values['alias_force_thread_id'] = self.id
            values['alias_defaults'] = {'company_id': self.company_id.id}
        return values


class MailTestGateway(models.Model):
    """ A very simple model only inheriting from mail.thread to test pure mass
    mailing features and base performances. """
    _description = 'Simple Chatter Model for Mail Gateway'
    _name = 'mail.test.gateway'
    _inherit = ['mail.thread.blacklist']
    _primary_email = 'email_from'

    name = fields.Char()
    email_from = fields.Char()
    custom_field = fields.Char()

    @api.model
    def message_new(self, msg_dict, custom_values=None):
        """ Check override of 'message_new' allowing to update record values
        base on incoming email. """
        defaults = {
            'email_from': msg_dict.get('from'),
        }
        defaults.update(custom_values or {})
        return super().message_new(msg_dict, custom_values=defaults)


class MailTestGatewayCompany(models.Model):
    """ A very simple model only inheriting from mail.thread to test pure mass
    mailing features and base performances, with a company field. """
    _description = 'Simple Chatter Model for Mail Gateway with company'
    _name = 'mail.test.gateway.company'
    _inherit = ['mail.test.gateway']

    company_id = fields.Many2one('res.company', 'Company')


class MailTestGatewayMainAttachment(models.Model):
    """ A very simple model only inheriting from mail.thread to test pure mass
    mailing features and base performances, with a company field and main
    attachment management. """
    _description = 'Simple Chatter Model for Mail Gateway with company'
    _name = 'mail.test.gateway.main.attachment'
    _inherit = ['mail.test.gateway', 'mail.thread.main.attachment']

    company_id = fields.Many2one('res.company', 'Company')


class MailTestGatewayGroups(models.Model):
    """ A model looking like discussion channels / groups (flat thread and
    alias). Used notably for advanced gatewxay tests. """
    _description = 'Channel/Group-like Chatter Model for Mail Gateway'
    _name = 'mail.test.gateway.groups'
    _inherit = ['mail.thread.blacklist', 'mail.alias.mixin']
    _mail_flat_thread = False
    _primary_email = 'email_from'

    name = fields.Char()
    email_from = fields.Char()
    custom_field = fields.Char()
    customer_id = fields.Many2one('res.partner', 'Customer')

    def _alias_get_creation_values(self):
        values = super(MailTestGatewayGroups, self)._alias_get_creation_values()
        values['alias_model_id'] = self.env['ir.model']._get('mail.test.gateway.groups').id
        if self.id:
            values['alias_force_thread_id'] = self.id
            values['alias_parent_thread_id'] = self.id
        return values

    def _mail_get_partner_fields(self, introspect_fields=False):
        return ['customer_id']

    def _message_get_default_recipients(self):
        return dict(
            (record.id, {
                'email_cc': False,
                'email_to': record.email_from if not record.customer_id.ids else False,
                'partner_ids': record.customer_id.ids,
            })
            for record in self
        )


class MailTestStandard(models.Model):
    """ This model can be used in tests when automatic subscription and simple
    tracking is necessary. Most features are present in a simple way. """
    _description = 'Standard Chatter Model'
    _name = 'mail.test.track'
    _inherit = ['mail.thread']

    name = fields.Char()
    email_from = fields.Char()
    user_id = fields.Many2one('res.users', 'Responsible', tracking=True)
    container_id = fields.Many2one('mail.test.container', tracking=True)
    company_id = fields.Many2one('res.company')
    track_fields_tofilter = fields.Char()  # comma-separated list of field names
    track_enable_default_log = fields.Boolean(default=False)

    def _track_filter_for_display(self, tracking_values):
        values = super()._track_filter_for_display(tracking_values)
        filtered_fields = set(self.track_fields_tofilter.split(',') if self.track_fields_tofilter else '')
        return values.filtered(lambda val: val.field_id.name not in filtered_fields)

    def _track_get_default_log_message(self, changes):
        filtered_fields = set(self.track_fields_tofilter.split(',') if self.track_fields_tofilter else '')
        if self.track_enable_default_log and not all(change in filtered_fields for change in changes):
            return f'There was a change on {self.name} for fields "{",".join(changes)}"'
        return super()._track_get_default_log_message(changes)

class MailTestActivity(models.Model):
    """ This model can be used to test activities in addition to simple chatter
    features. """
    _description = 'Activity Model'
    _name = 'mail.test.activity'
    _inherit = ['mail.thread', 'mail.activity.mixin']

    name = fields.Char()
    date = fields.Date()
    email_from = fields.Char()
    active = fields.Boolean(default=True)

    def action_start(self, action_summary):
        return self.activity_schedule(
            'test_mail.mail_act_test_todo',
            summary=action_summary
        )

    def action_close(self, action_feedback, attachment_ids=None):
        self.activity_feedback(['test_mail.mail_act_test_todo'],
                               feedback=action_feedback,
                               attachment_ids=attachment_ids)


class MailTestTicket(models.Model):
    """ This model can be used in tests when complex chatter features are
    required like modeling tasks or tickets. """
    _description = 'Ticket-like model'
    _name = 'mail.test.ticket'
    _inherit = ['mail.thread']
    _primary_email = 'email_from'

    name = fields.Char()
    email_from = fields.Char(tracking=True)
    mobile_number = fields.Char()
    phone_number = fields.Char()
    count = fields.Integer(default=1)
    datetime = fields.Datetime(default=fields.Datetime.now)
    mail_template = fields.Many2one('mail.template', 'Template')
    customer_id = fields.Many2one('res.partner', 'Customer', tracking=2)
    user_id = fields.Many2one('res.users', 'Responsible', tracking=1)
    container_id = fields.Many2one('mail.test.container', tracking=True)

    def _mail_get_partner_fields(self, introspect_fields=False):
        return ['customer_id']

    def _message_compute_subject(self):
        self.ensure_one()
        return f"Ticket for {self.name} on {self.datetime.strftime('%m/%d/%Y, %H:%M:%S')}"

    def _message_get_default_recipients(self):
        return dict(
            (record.id, {
                'email_cc': False,
                'email_to': record.email_from if not record.customer_id.ids else False,
                'partner_ids': record.customer_id.ids,
            })
            for record in self
        )

    def _notify_get_recipients_groups(self, message, model_description, msg_vals=None):
        """ Activate more groups to test query counters notably (and be backward
        compatible for tests). """
        local_msg_vals = dict(msg_vals or {})
        groups = super()._notify_get_recipients_groups(
            message, model_description, msg_vals=msg_vals
        )
        for group_name, _group_method, group_data in groups:
            if group_name == 'portal':
                group_data['active'] = True
            elif group_name == 'customer':
                group_data['active'] = True
                group_data['has_button_access'] = True
                group_data['actions'] = [{
                    'url': self._notify_get_action_link(
                        'controller',
                        controller='/test_mail/do_stuff',
                        **local_msg_vals
                    ),
                    'title': _('NotificationButtonTitle')
                }]

        return groups

    def _track_template(self, changes):
        res = super(MailTestTicket, self)._track_template(changes)
        record = self[0]
        if 'customer_id' in changes and record.mail_template:
            res['customer_id'] = (
                record.mail_template,
                {
                    'composition_mode': 'mass_mail',
                    'subtype_id': self.env['ir.model.data']._xmlid_to_res_id('mail.mt_note'),
                }
            )
        elif 'datetime' in changes:
            res['datetime'] = (
                'test_mail.mail_test_ticket_tracking_view',
                {
                    'composition_mode': 'mass_mail',
                    'subtype_id': self.env['ir.model.data']._xmlid_to_res_id('mail.mt_note'),
                }
            )
        return res

    def _creation_subtype(self):
        if self.container_id:
            return self.env.ref('test_mail.st_mail_test_ticket_container_upd')
        return super(MailTestTicket, self)._creation_subtype()

    def _track_subtype(self, init_values):
        self.ensure_one()
        if 'container_id' in init_values and self.container_id:
            return self.env.ref('test_mail.st_mail_test_ticket_container_upd')
        return super(MailTestTicket, self)._track_subtype(init_values)

    def _get_customer_information(self):
        email_normalized_to_values = super()._get_customer_information()

        for record in self.filtered('email_from'):
            email_from_normalized = email_normalize(record.email_from)
            if not email_from_normalized:  # do not fill Falsy with random data
                continue
            values = email_normalized_to_values.setdefault(email_from_normalized, {})
            if not values.get('mobile'):
                values['mobile'] = record.mobile_number
            if not values.get('phone'):
                values['phone'] = record.phone_number
        return email_normalized_to_values

    def _message_get_suggested_recipients(self):
        recipients = super()._message_get_suggested_recipients()
        if self.customer_id:
            self.customer_id._message_add_suggested_recipient(
                recipients,
                partner=self.customer_id,
                lang=None,
                reason=_('Customer'),
            )
        elif self.email_from:
            self._message_add_suggested_recipient(
                recipients,
                partner=None,
                email=self.email_from,
                lang=None,
                reason=_('Customer Email'),
            )
        return recipients

class MailTestTicketEL(models.Model):
    """ Just mail.test.ticket, but exclusion-list enabled. Kept as different
    model to avoid messing with existing tests, notably performance, and ease
    backward comparison. """
    _description = 'Ticket-like model with exclusion list'
    _name = 'mail.test.ticket.el'
    _inherit = [
        'mail.test.ticket',
        'mail.thread.blacklist',
    ]
    _primary_email = 'email_from'

    email_from = fields.Char(
        'Email',
        compute='_compute_email_from', readonly=False, store=True)

    @api.depends('customer_id')
    def _compute_email_from(self):
        for ticket in self.filtered(lambda r: r.customer_id and not r.email_from):
            ticket.email_from = ticket.customer_id.email_formatted


class MailTestTicketMC(models.Model):
    """ Just mail.test.ticket, but multi company. Kept as different model to
    avoid messing with existing tests, notably performance, and ease backward
    comparison. """
    _description = 'Ticket-like model'
    _name = 'mail.test.ticket.mc'
    _inherit = ['mail.test.ticket']
    _primary_email = 'email_from'

    company_id = fields.Many2one('res.company', 'Company', default=lambda self: self.env.company)
    container_id = fields.Many2one('mail.test.container.mc', tracking=True)


class MailTestContainer(models.Model):
    """ This model can be used in tests when container records like projects
    or teams are required. """
    _description = 'Project-like model with alias'
    _name = 'mail.test.container'
    _mail_post_access = 'read'
    _inherit = ['mail.thread', 'mail.alias.mixin']

    name = fields.Char()
    description = fields.Text()
    customer_id = fields.Many2one('res.partner', 'Customer')

    def _mail_get_partner_fields(self, introspect_fields=False):
        return ['customer_id']

    def _message_get_default_recipients(self):
        return dict(
            (record.id, {
                'email_cc': False,
                'email_to': False,
                'partner_ids': record.customer_id.ids,
            })
            for record in self
        )

    def _notify_get_recipients_groups(self, message, model_description, msg_vals=None):
        """ Activate more groups to test query counters notably (and be backward
        compatible for tests). """
        groups = super()._notify_get_recipients_groups(
            message, model_description, msg_vals=msg_vals
        )
        for group_name, _group_method, group_data in groups:
            if group_name == 'portal':
                group_data['active'] = True

        return groups

    def _alias_get_creation_values(self):
        values = super(MailTestContainer, self)._alias_get_creation_values()
        values['alias_model_id'] = self.env['ir.model']._get('mail.test.container').id
        if self.id:
            values['alias_force_thread_id'] = self.id
            values['alias_parent_thread_id'] = self.id
        return values

class MailTestContainerMC(models.Model):
    """ Just mail.test.container, but multi company. Kept as different model to
    avoid messing with existing tests, notably performance, and ease backward
    comparison. """
    _description = 'Project-like model with alias (MC)'
    _name = 'mail.test.container.mc'
    _mail_post_access = 'read'
    _inherit = ['mail.test.container']

    company_id = fields.Many2one('res.company', 'Company', default=lambda self: self.env.company)


class MailTestComposerMixin(models.Model):
    """ A simple invite-like wizard using the composer mixin, rendering on
    composer source test model. Purpose is to have a minimal composer which
    runs on other records and check notably dynamic template support and
    translations. """
    _description = 'Invite-like Wizard'
    _name = 'mail.test.composer.mixin'
    _inherit = ['mail.composer.mixin']

    name = fields.Char('Name')
    author_id = fields.Many2one('res.partner')
    description = fields.Html('Description', render_engine="qweb", render_options={"post_process": True}, sanitize='email_outgoing')
    source_ids = fields.Many2many('mail.test.composer.source', string='Invite source')

    def _compute_render_model(self):
        self.render_model = 'mail.test.composer.source'


class MailTestComposerSource(models.Model):
    """ A simple model on which invites are sent. """
    _description = 'Invite-like Source'
    _name = 'mail.test.composer.source'
    _inherit = ['mail.thread.blacklist']
    _primary_email = 'email_from'

    name = fields.Char('Name')
    customer_id = fields.Many2one('res.partner', 'Main customer')
    email_from = fields.Char(
        'Email',
        compute='_compute_email_from', readonly=False, store=True)

    @api.depends('customer_id')
    def _compute_email_from(self):
        for source in self.filtered(lambda r: r.customer_id and not r.email_from):
            source.email_from = source.customer_id.email_formatted

    def _mail_get_partner_fields(self, introspect_fields=False):
        return ['customer_id']


class MailTestMailTrackingDuration(models.Model):
    _description = 'Fake model to test the mixin mail.tracking.duration.mixin'
    _name = 'mail.test.mail.tracking.duration'
    _track_duration_field = 'customer_id'
    _inherit = ['mail.thread', 'mail.tracking.duration.mixin']

    name = fields.Char()
    customer_id = fields.Many2one('res.partner', 'Customer', tracking=True)

    def _mail_get_partner_fields(self, introspect_fields=False):
        return ['customer_id']


class MailTestPublicThread(models.Model):
    """A model inheriting from mail.thread with public read and write access
    to test some public and guest interactions."""

    _description = "Portal Public Thread"
    _name = "mail.test.public"
    _inherit = ["mail.thread"]

    name = fields.Char("Name")