Odoo реализует некоторые полезные классы и смеси, которые упрощают добавление часто используемых поведений к вашим объектам. В этом руководстве подробно описываются большинство из них, примеры и варианты использования.
Функции обмена сообщениями
Интеграция сообщений
Базовая система обмена сообщениями
Интеграция функций обмена сообщениями в вашу модель чрезвычайно проста. Просто наследуя модель `` mail.thread`` и добавляя поля сообщений (и соответствующие им виджеты) в ваше представление формы, вы сразу же получите и заработаете.
Пример
Давайте создадим упрощенную модель, представляющую командировку. Поскольку организация такого рода поездок обычно включает в себя много людей и много дискуссий, давайте добавим поддержку обмена сообщениями по модели.
class BusinessTrip(models.Model):
_name = 'business.trip'
_inherit = ['mail.thread']
_description = 'Business Trip'
name = fields.Char()
partner_id = fields.Many2one('res.partner', 'Responsible')
guest_ids = fields.Many2many('res.partner', 'Participants')
В представлении формы:
<record id="businness_trip_form" model="ir.ui.view">
<field name="name">business.trip.form</field>
<field name="model">business.trip</field>
<field name="arch" type="xml">
<form string="Business Trip">
<!-- Your usual form view goes here
...
Then comes chatter integration -->
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
После того, как вы добавили поддержку болтовни в свою модель, пользователи могут легко добавлять сообщения или внутренние заметки на любую запись вашей модели; Каждый из них отправит уведомление (всем последователям для сообщений, сотрудникам (* base.group_user [UNKNOWN NODE problematic]) для внутренних заметок). Если ваш почтовый шлюз и полный адрес настроены правильно, эти уведомления будут отправляться по электронной почте и могут быть отправлены прямо из вашего почтового клиента; Автоматическая система маршрутизации направит ответ на правильный поток.
На стороне сервера есть несколько вспомогательных функций, которые помогут вам легко отправлять сообщения и управлять подписчиками на вашей записи:
Отправка сообщений
message_post(self, body='', subject=None, message_type='notification', subtype=None, parent_id=False, attachments=None, content_subtype='html', **kwargs)
Опубликуйте новое сообщение в существующем потоке, возвратив новый идентификатор mail.message.
- body (
str
) -- Тело сообщения, обычно необработанный HTML, который будет дезинфицирован - message_type (
str
) -- См. Поле mail_message.type - content_subtype (
str
) -- If plaintext: преобразовать тело в html - parent_id (
int
) -- Обработать ответ на предыдущее сообщение, добавив родительских партнеров в сообщение в случае личного обсуждения - attachments (
list(tuple(str,str))
) -- Список наборов вложений в форме `` (name, content) [UNKNOWN NODE problematic], где контент НЕ кодируется base64 - **kwargs -- Дополнительные аргументы ключевого слова будут использоваться как значения столбца по умолчанию для новой записи mail.message
message_post_with_view(views_or_xmlid, **kwargs):
Вспомогательный метод для отправки почты / публикации сообщения с использованием view_id для визуализации с использованием движка ir.qweb. Этот метод является самостоятельным, потому что в шаблоне и композиторе нет ничего, что позволяет обрабатывать представления в пакетном режиме. Этот метод, вероятно, исчезнет, когда шаблоны обрабатывают ir ui views.
str
) -- Внешний идентификатор или запись представления, которое должно быть отправленоmessage_post_with_template(template_id, **kwargs)
Вспомогательный метод для отправки почты с шаблоном
- template_id -- Идентификатор шаблона, отображаемого для создания тела сообщения.
- **kwargs -- Параметр для создания mail.compose.message wizzard (который унаследован от mail.message)
Получение сообщений
Эти методы вызывают, когда новое электронное письмо обрабатывается почтовым шлюзом. Эти электронные письма могут быть либо новым потоком (если они поступают через: ref: alias <reference / mixins / mail / alias>
), или просто ответы из существующего потока. Их переопределение позволяет вам устанавливать значения в записи потока в зависимости от некоторых значений из самого сообщения (например, обновлять дату или адрес электронной почты, добавлять адреса CC в качестве подписчиков и т. Д.).
message_new(msg_dict, custom_values=None)
Вызывается `` message_process`` при получении нового сообщения для данной модели потока, если сообщение не принадлежало существующему потоку.
Поведением по умолчанию является создание новой записи соответствующей модели (на основе очень простой информации, извлеченной из сообщения). Дополнительное поведение может быть реализовано переопределением этого метода.
- msg_dict (
dict
) -- Карту, содержащую данные электронной почты и вложения. Смотрите `` message_process`` и `` mail.message.parse`` для деталей - custom_values (
dict
) -- Дополнительный словарь дополнительных значений полей для перехода к create () при создании новой записи потока; Будьте внимательны, эти значения могут переопределять любые другие значения, поступающие из сообщения
message_update(msg_dict, update_vals=None)
Вызывается `` message_process`` при получении нового сообщения для существующего потока. По умолчанию используется обновление `` update_vals``, взятое из входящего сообщения.
Дополнительное поведение может быть реализовано переопределением этого метода.
Управление подписчиками
message_subscribe(partner_ids=None, channel_ids=None, subtype_ids=None, force=True)
Добавьте партнеров к подписчикам записей.
- partner_ids (
list(int)
) -- Идентификаторы партнеров, которые будут подписаны на запись - channel_ids (
list(int)
) -- Идентификаторы каналов, которые будут подписаны на запись - subtype_ids (
list(int)
) -- Идентификаторы подтипов, на которые будут подписаны каналы / партнеры (по умолчанию используются подтипы по умолчанию, если `` Нет``) - force -- Если «Истина», удалите существующих подписчиков перед созданием нового, используя подтипы, указанные в параметрах
message_subscribe_users(user_ids=None, subtype_ids=None)
Wrapper на message_subscribe, используя пользователей вместо партнеров.
- user_ids (
list(int)
) -- Идентификаторы пользователей, которые будут подписаны на запись; Если `` Нет``, подпишитесь на текущего пользователя. - subtype_ids (
list(int)
) -- Идентификаторы подтипов, на которые будут подписаны каналы / партнеры
message_unsubscribe(partner_ids=None, channel_ids=None)
Удалите партнеров из подписчиков записи.
- partner_ids (
list(int)
) -- Идентификаторы партнеров, которые будут подписаны на запись - channel_ids (
list(int)
) -- Идентификаторы каналов, которые будут подписаны на запись
message_unsubscribe_users(user_ids=None)
Обертка на message_subscribe, используя пользователей.
list(int)
) -- Идентификаторы пользователей, которые будут отписаны для записи; Если нет, отмените подписку на текущего пользователя.Регистрация изменений
Модуль `` mail`` добавляет мощную систему отслеживания в поля, позволяя вам записывать изменения в определенные поля в болтовне записи.
Чтобы добавить отслеживание в поле, просто добавьте атрибут track_visibility со значением `` onchange`` (если он должен отображаться в уведомлении только в случае изменения поля) или `` всегда`` (если значение всегда должно отображаться в Изменять уведомления, даже если это конкретное поле не изменилось - полезно сделать пояснение более пояснительным, например, всегда добавляя поле имени).
Пример
Отслеживаем изменения имени и ответственных за наши командировки:
class BusinessTrip(models.Model):
_name = 'business.trip'
_inherit = ['mail.thread']
_description = 'Business Trip'
name = fields.Char(track_visibility='always')
partner_id = fields.Many2one('res.partner', 'Responsible',
track_visibility='onchange')
guest_ids = fields.Many2many('res.partner', 'Participants')
Отныне каждое изменение имени или ответственного лица, проводящего поездку, будет записывать запись в протокол. Поле `` name`` будет отображаться в уведомлении также, чтобы дать больше контекста об уведомлении (даже если имя не изменилось).
Подтипы
Подтипы дают вам более детальный контроль над сообщениями. Подтипы действуют как система классификации уведомлений, что позволяет подписчикам документа настраивать подтип уведомлений, которые они хотят получать.
Подтипы создаются как данные в вашем модуле; Модель имеет следующие поля:
- `` Имя`` (обязательно) -: класс:
~ odoo.fields.Char
Имя подтипа, отобразится во всплывающем меню настройки уведомлений
- `` Описание`` -: класс:
~ odoo.fields.Char
Описание, которое будет добавлено в сообщение, отправленное для этого подтипа. Если void, имя будет добавлено вместо
- `` Internal`` -: class:
~ odoo.fields.Boolean
Сообщения с внутренними подтипами будут видны только сотрудникам, а также членам группы `` base.group_user``
- `` Parent_id`` -: класс:
~ odoo.fields.Many2one
Подтипы ссылок для автоматической подписки; Например, подтипы проекта связаны с подтипами задач через эту ссылку. Когда кто-то подписывается на проект, он подписывается на все задачи этого проекта с подтипами, найденными с использованием родительского подтипа
- `` Relation_field`` -: class:
~ odoo.fields.Char
В качестве примера, при связывании подтипов проектов и задач поле отношений является полем project_id задач
- `` Res_model`` -: класс:
~ odoo.fields.Char
Модель, к которой относится подтип; Если False, этот подтип применяется ко всем моделям
- `` Default`` -: class:
~ odoo.fields.Boolean
Если подтип активирован по умолчанию при подписке
- `` Sequence`` -: class:
~ odoo.fields.Integer
Используется для упорядочивания подтипов во всплывающем меню настройки уведомлений
- `` Hidden`` -: класс:
~ odoo.fields.Boolean
Если подтип скрыт в всплывающем окне настройки уведомлений
Взаимодействие подтипов с отслеживанием поля позволяет подписаться на различные виды уведомлений в зависимости от того, что может заинтересовать пользователей. Чтобы сделать это, вы можете переопределить функцию `` _track_subtype () [UNKNOWN NODE problematic]:
_track_subtype(init_values)
Дайте подтип, вызванный изменениями записи в соответствии с обновленными значениями.
dict
) -- Исходные значения записи; Только модифицированные поля присутствуют в dictПример
Давайте добавим поле `` state`` в нашем классе-примере и инициируем уведомление с конкретным подтипом, когда значения этого поля изменятся.
Сначала давайте определим наш подтип:
<record id="mt_state_change" model="mail.message.subtype">
<field name="name">Trip confirmed</field>
<field name="res_model">business.trip</field>
<field name="default" eval="True"/>
<field name="description">Business Trip confirmed!</field>
</record>
Затем нам нужно переопределить функцию `` track_subtype () . Эта функция вызывается системой отслеживания, чтобы узнать, какой подтип должен использоваться в зависимости от применяемого в настоящее время изменения. В нашем случае мы хотим использовать наш новый новый подтип, когда поле `
state`` меняется с * draft * на * confirmed [UNKNOWN NODE problematic]:
class BusinessTrip(models.Model):
_name = 'business.trip'
_inherit = ['mail.thread']
_description = 'Business Trip'
name = fields.Char(track_visibility='onchange')
partner_id = fields.Many2one('res.partner', 'Responsible',
track_visibility='onchange')
guest_ids = fields.Many2many('res.partner', 'Participants')
state = fields.Selection([('draft', 'New'), ('confirmed', 'Confirmed')],
track_visibility='onchange')
def _track_subtype(self, init_values):
# init_values contains the modified fields' values before the changes
#
# the applied values can be accessed on the record as they are already
# in cache
self.ensure_one()
if 'state' in init_values and self.state == 'confirmed':
return 'my_module.mt_state_change' # Full external id
return super(BusinessTrip, self)._track_subtype(init_values)
Настройка уведомлений
При отправке уведомлений подписчикам очень удобно добавлять кнопки в шаблон, чтобы разрешить быстрые действия непосредственно из электронной почты. Может оказаться полезной даже простая кнопка для прямой ссылки на вид формы записи; Однако в большинстве случаев вы не хотите отображать эти кнопки для пользователей портала.
Система уведомлений позволяет настраивать шаблоны уведомлений следующими способами:
Дисплей * Кнопки доступа [UNKNOWN NODE problematic]: эти кнопки видны в верхней части уведомления по электронной почте и позволяют получателю напрямую обращаться к виду формы записи
Дисплей * Follow Buttons [UNKNOWN NODE problematic]: эти кнопки позволяют получателю непосредственно быстро подписаться на запись
Дисплей * Отменить подписку на кнопки [UNKNOWN NODE problematic]: эти кнопки позволяют получателю сразу быстро отписаться от записи
Дисплей * Кнопки пользовательского действия [UNKNOWN NODE problematic]: эти кнопки являются вызовами определенных маршрутов и позволяют вам делать некоторые полезные действия, непосредственно доступные из электронной почты (то есть, преобразовывая опцию в возможность, проверяя лист расходов для диспетчера расходов и т. Д.),
Эти настройки кнопок можно применять к различным группам, которые вы можете определить самостоятельно, переопределив функцию `` _notification_recipients``.
_notification_recipients(message, groups)
Дайте подтип, вызванный изменениями записи в соответствии с обновленными значениями.
- message (
record
) -- В настоящее время отправляется запись `` mail.message`` - groups (
list(tuple)
) -- Список кортежей формы (group_name, group_func, group_data) where: group_name - это идентификатор, используемый только для возможности переопределения и манипулирования группами. Группы по умолчанию - это «пользователь» (получатели, связанные с пользователем-сотрудником), «портал» (получатели, связанные с пользователем портала) и «клиент» (получатели не связаны ни с одним пользователем). Примером переопределения может быть добавление группы, связанной с res.groups, например Hr Officers, для установки на них специальных кнопок действий. Group_func - это указатель на функцию, принимающий запись партнера как параметр. Этот метод будет применяться к получателям, чтобы знать, принадлежат они к данной группе или нет. Сохраняется только первая совпадающая группа. Порядок оценки - это порядок списка. Group_data - это dict, содержащий параметры для электронной почты уведомления со следующими возможными ключами - values: - has_button_access отображать ли Access <Document> в электронной почте. Истина по умолчанию для новых групп, False для портала / клиента. - button_access dict с url и названием кнопки - has_button_follow отображать ли сообщение Follow в электронной почте (если получатель в данный момент не следует за потоком). Истина по умолчанию для новых групп, False для портала / клиента. - button_follow dict с url и названием кнопки - has_button_unfollow отображать ли Unfollow в электронной почте (если получатель в настоящее время следует за потоком). Истина по умолчанию для новых групп, False для портала / клиента. - button_unfollow dict с url и названием кнопки - список действий кнопок действий для отображения в уведомлении по электронной почте. Каждое действие - это текст, содержащий URL и заголовок кнопки.
URL-адреса в списке действий могут быть сгенерированы автоматически, вызывая функцию `` _notification_link_helper () [UNKNOWN NODE problematic]:
_notification_link_helper(self, link_type, **kwargs)
Создайте ссылку для данного типа на текущей записи (или на определенной записи, если заданы kwargs `` model`` и `` res_id``).
str
) -- Тип связи, которая будет создана; Может быть любым из следующих значений:
- Посмотреть
Ссылка для формирования вида записи
assign
Назначить зарегистрированного пользователя в поле `` user_id`` записи (если оно существует)
- [UNKNOWN NODE problematic]follow`
сам за себя
Unfollow
сам за себя
- МЕТОД
Вызов метода в записи; Имя метода должно быть указано как метод
kwarg`
new
Открыть пустой вид формы для новой записи; Вы можете указать конкретное действие, указав его id (идентификатор базы данных или полностью разрешенный внешний идентификатор) в kwarg `` action_id``
Пример
Давайте добавим пользовательскую кнопку в уведомление об изменении состояния командировки; Эта кнопка сбросит состояние в черновик и будет видна только члену группы (воображаемой) Travel Manager (`` business.group_trip_manager``)
class BusinessTrip(models.Model):
_name = 'business.trip'
_inherit = ['mail.thread', 'mail.alias.mixin']
_description = 'Business Trip'
# Pevious code goes here
def action_cancel(self):
self.write({'state': 'draft'})
def _notification_recipients(self, message, groups):
""" Handle Trip Manager recipients that can cancel the trip at the last
minute and kill all the fun. """
groups = super(BusinessTrip, self)._notification_recipients(message, groups)
self.ensure_one()
if self.state == 'confirmed':
app_action = self._notification_link_helper('method',
method='action_cancel')
trip_actions = [{'url': app_action, 'title': _('Cancel')}]
new_group = (
'group_trip_manager',
lambda partner: bool(partner.user_ids) and
any(user.has_group('business.group_trip_manager')
for user in partner.user_ids),
{
'actions': trip_actions,
})
return [new_group] + groups
Обратите внимание, что я мог бы определить свою оценочную функцию вне этого метода и определить глобальную функцию, чтобы сделать это вместо лямбда, но для того, чтобы быть более кратким и менее многословным в этих файлах документации, которые иногда могут быть скучными, я выбираю Первый вместо последнего.
Переопределение значений по умолчанию
Существует несколько способов настроить поведение моделей `` mail.thread``, включая (но не ограничиваясь ими):
- Атрибут `` _mail_post_access``:: class:
~ odoo.models.Model
Требуемые права доступа, чтобы иметь возможность публиковать сообщение на модели; По умолчанию необходим доступ `` write``, можно также установить `` read``
- Контекстные клавиши:
Эти ключи контекста можно использовать для частичного контроля функций `` mail.thread``, таких как автоподписка или отслеживание полей во время вызовов `` create ()
или
write ()
[UNKNOWN NODE problematic](или любого другого метода, где он может быть полезным).`` Mail_create_nosubscribe``: при создании или message_post не подписывайте текущего пользователя на поток записи
`` Mail_create_nolog``: при создании не записывайте автоматическое сообщение «<Документ> создано»
`` Mail_notrack``: при создании и записи не выполняйте отслеживание значений, создавая сообщения
`` Tracking_disable``: при создании и записи не выполняйте никаких функций MailThread (автоматическая подписка, отслеживание, публикация, ...)
`` Mail_auto_delete``: автоматическое удаление почтовых уведомлений; Истина по умолчанию
`` Mail_notify_force_send``: если менее 50 уведомлений электронной почты для отправки, отправьте их напрямую вместо использования очереди; Истина по умолчанию
`` Mail_notify_user_signature``: добавить текущую подпись пользователя в уведомлениях по электронной почте; Истина по умолчанию
Почтовый псевдоним
Псевдонимы - настраиваемые адреса электронной почты, которые связаны с определенной записью (которая обычно наследует модель `` mail.alias.mixin`), которая будет создавать новые записи при обращении по электронной почте. Это простой способ сделать вашу систему доступной извне, что позволяет пользователям или клиентам быстро создавать записи в базе данных без необходимости прямого подключения к Odoo.
Псевдонимы и входящий почтовый шлюз
Некоторые люди используют этот шлюз для этой же цели. Для использования псевдонимов вам по-прежнему нужен правильно сконфигурированный почтовый шлюз, однако достаточно одного единого домена, так как вся маршрутизация будет производиться внутри Odoo. Псевдонимы имеют несколько преимуществ по сравнению с Mail Gateways:
- Легче настроить
Один входящий шлюз может использоваться многими псевдонимами; Это избавляет от необходимости настраивать несколько электронных писем на вашем доменном имени (вся конфигурация выполняется внутри Odoo)
Нет необходимости в правах доступа к системе для настройки псевдонимов
- Более последовательная
Настраивается в связанной записи, а не в подменю Параметры.
- Легче переопределить серверную часть
Модель Mixin построена для расширения с самого начала, что позволяет извлекать полезные данные из входящих сообщений электронной почты легче, чем с помощью почтового шлюза.
Поддержка интеграции псевдонимов
Aliases are usually configured on a parent model which will then create specific record when contacted by e-mail. For example, Project have aliases to create tasks or issues, Sales Channel have aliases to generate Leads.
Примечание
Модель, которая будет создана псевдонимом [UNKNOWN NODE problematic], должна ** наследовать модель `` mail_thread``.
Поддержка псевдонимов добавляется наследованием `` mail.alias.mixin``; Этот mixin будет генерировать новую запись `` mail.alias`` для каждой записи родительского класса, который будет создан (например, каждая запись project.project`
, имеющая свою запись` mail.alias`
, инициализированную при создании ).
Примечание
Псевдонимы также могут быть созданы вручную и поддерживаться простым: class: ~ odoo.fields.Many2one
. В этом руководстве предполагается, что вам нужна более полная интеграция с автоматическим созданием псевдонима, значений по умолчанию для записи и т. Д.
В отличие от наследования `` mail.thread``, `` mail.alias.mixin`` ** требует ** некоторых определенных переопределений для правильной работы. Эти переопределения будут указывать значения созданного псевдонима, такие как тип записи, которую он должен создать, и, возможно, некоторые значения по умолчанию, которые могут иметь эти записи в зависимости от родительского объекта:
get_alias_model_name(vals)
Верните имя модели для псевдонима. Входящие письма, которые не отвечают на существующие записи, приведут к созданию новой записи этой модели псевдонимов. Значение может зависеть от `` vals``, dict значений, переданных `` create``, когда запись этой модели создана.
vals
) -- Значения вновь созданной записи, которые будут содержать псевдонимget_alias_values()
Возвращает значения для создания псевдонима или для записи в псевдониме после его создания. Хотя это и не является полностью обязательным, обычно требуется убедиться, что вновь созданные записи будут связаны с родительским псевдонимом (т.е. задачами, создаваемыми в правильном проекте), путем установки словаря значений по умолчанию в псевдониме `` alias_defaults`
поле.
Переопределение `` get_alias_values () `` особенно интересно, так как оно позволяет вам легко изменять поведение ваших псевдонимов. Среди полей, которые могут быть установлены в псевдониме, особый интерес представляют следующие:
- `` Alias_name`` -: class:
~ odoo.fields.Char
Имя псевдонима электронной почты, например, «jobs», если вы хотите перехватывать электронные сообщения для <jobs@example.odoo.com>
- `` Alias_user_id`` -: class:
~ odoo.fields.Many2one
(`res.users`
) Владелец записей, созданных при получении электронных писем по этому псевдониму; Если это поле не установлено, система попытается найти подходящего владельца на основе адреса отправителя (From) или будет использовать учетную запись администратора, если для этого адреса не найден ни один пользователь системы
- `` Alias_defaults``:: class:
~ odoo.fields.Text
Словарь Python, который будет оцениваться для предоставления значений по умолчанию при создании новых записей для этого псевдонима
- `` Alias_force_thread_id`` -: class:
~ odoo.fields.Integer
Необязательный идентификатор потока (записи), к которому будут прикреплены все входящие сообщения, даже если они не ответили на него; Если установлено, это полностью отключит создание новых записей
- `` Alias_contact``:: class:
~ odoo.fields.Selection
Политика отправки сообщения в документ с помощью mailgateway
- everyone: everyone can post
- partners: only authenticated partners
- followers: only followers of the related document or members of following channels
Обратите внимание, что псевдонимы используют: ref: delegant inheritance <reference / orm / inheritance>
, что означает, что, хотя псевдоним хранится в другой таблице, у вас есть доступ ко всем этим полям непосредственно из вашего родительского объекта. Это позволяет вам легко настроить ваш псевдоним из вида формы записи.
Пример
Давайте добавим псевдонимы в наш класс командировки для создания расходов «на лету» по электронной почте.
class BusinessTrip(models.Model):
_name = 'business.trip'
_inherit = ['mail.thread', 'mail.alias.mixin']
_description = 'Business Trip'
name = fields.Char(track_visibility='onchange')
partner_id = fields.Many2one('res.partner', 'Responsible',
track_visibility='onchange')
guest_ids = fields.Many2many('res.partner', 'Participants')
state = fields.Selection([('draft', 'New'), ('confirmed', 'Confirmed')],
track_visibility='onchange')
expense_ids = fields.One2many('business.expense', 'trip_id', 'Expenses')
alias_id = fields.Many2one('mail.alias', string='Alias', ondelete="restrict",
required=True)
def get_alias_model_name(self, vals):
""" Specify the model that will get created when the alias receives a message """
return 'business.expense'
def get_alias_values(self):
""" Specify some default values that will be set in the alias at its creation """
values = super(BusinessTrip, self).get_alias_values()
# alias_defaults holds a dictionnary that will be written
# to all records created by this alias
#
# in this case, we want all expense records sent to a trip alias
# to be linked to the corresponding business trip
values['alias_defaults'] = {'trip_id': self.id}
# we only want followers of the trip to be able to post expenses
# by default
values['alias_contact'] = 'followers'
return values
class BusinessExpense(models.Model):
_name = 'business.expense'
_inherit = ['mail.thread']
_description = 'Business Expense'
name = fields.Char()
amount = fields.Float('Amount')
trip_id = fields.Many2one('business.trip', 'Business Trip')
partner_id = fields.Many2one('res.partner', 'Created by')
Мы хотели бы, чтобы наш псевдоним легко настраивался из формы в наших командировках, поэтому добавим следующее в наш вид формы:
<page string="Emails">
<group name="group_alias">
<label for="alias_name" string="Email Alias"/>
<div name="alias_def">
<!-- display a link while in view mode and a configurable field
while in edit mode -->
<field name="alias_id" class="oe_read_only oe_inline"
string="Email Alias" required="0"/>
<div class="oe_edit_only oe_inline" name="edit_alias"
style="display: inline;" >
<field name="alias_name" class="oe_inline"/>
@
<field name="alias_domain" class="oe_inline" readonly="1"/>
</div>
</div>
<field name="alias_contact" class="oe_inline"
string="Accept Emails From"/>
</group>
</page>
Теперь мы можем изменить адрес псевдонима непосредственно из формы и изменить, кто может отправлять электронные письма в псевдоним.
Затем мы можем переопределить `` message_new () `` в нашей модели расхода, чтобы получать значения из нашей электронной почты, когда будут созданы расходы:
class BusinessExpense(models.Model):
# Previous code goes here
# ...
def message_new(self, msg, custom_values=None):
""" Override to set values according to the email.
In this simple example, we simply use the email title as the name
of the expense, try to find a partner with this email address and
do a regex match to find the amount of the expense."""
name = msg_dict.get('subject', 'New Expense')
# Match the last occurence of a float in the string
# Example: '50.3 bar 34.5' becomes '34.5'. This is potentially the price
# to encode on the expense. If not, take 1.0 instead
amount_pattern = '(\d+(\.\d*)?|\.\d+)'
expense_price = re.findall(amount_pattern, name)
price = expense_price and float(expense_price[-1][0]) or 1.0
# find the partner by looking for it's email
partner = self.env['res.partner'].search([('email', 'ilike', email_address)],
limit=1)
defaults = {
'name': name,
'amount': price,
'partner_id': partner.id
}
defaults.update(custom_values or {})
res = super(BusinessExpense, self).message_new(msg, custom_values=defaults)
return res
Activities tracking
Activities are actions users have to take on a document like making a phone call
or organizing a meeting. Activities come with the mail module as they are
integrated in the Chatter but are not bundled with mail.thread. Activities
are records of the mail.activity
class, which have a type (mail.activity.type
),
name, description, scheduled time (among others). Pending activities are visible
above the message history in the chatter widget.
You can integrate activities using the mail.activity.mixin
class on your object
and the specific widgets to display them (via the field activity_ids
) in the form
view and kanban view of your records (mail_activity
and kanban_activity
widgets, respectively).
Пример
Organizing a business trip is a tedious process and tracking needed activities like ordering plane tickets or a cab for the airport could be useful. To do so, we will add the activities mixin on our model and display the next planned activities in the message history of our trip.
class BusinessTrip(models.Model):
_name = 'business.trip'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'Business Trip'
name = fields.Char()
# [...]
We modify the form view of our trips to display their next activites:
<record id="businness_trip_form" model="ir.ui.view">
<field name="name">business.trip.form</field>
<field name="model">business.trip</field>
<field name="arch" type="xml">
<form string="Business Trip">
<!-- Your usual form view goes here -->
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="activity_ids" widget="mail_activity"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
Вы можете найти конкретные примеры интеграции в следующих моделях:
`` Crm.lead`` в приложении CRM (* crm [UNKNOWN NODE problematic])
sale.order
in the Sales (sale) Applicationproject.task
in the Project (poject) Application
Возможности веб-сайта
Отслеживание посетителей
Класс `` utm.mixin`` можно использовать для отслеживания онлайновых маркетинговых / коммуникационных кампаний с помощью аргументов в ссылках на указанные ресурсы. Mixin добавляет 3 поля к вашей модели:
Поле `` campaign_id``:: class:
~ odoo.fields.Many2one
добавляется к объекту`utm.campaign`
(т.е. Christmas_Special, Fall_Collection и т. Д.).`` Source_id``:: class:
~ odoo.fields.Many2one
в объект`utm.source`
(т.е. поисковая система, список рассылки и т. Д.),Medium_id`
:: class:` ~ odoo.fields.Many2one` на объект `` utm.medium`` (т.е. Уличная почта, электронная почта, обновление социальной сети и т. Д.)
Эти модели имеют одно поле `` name`` (т.е. они просто существуют, чтобы отличать кампании, но не имеют определенного поведения).
Когда клиент посещает ваш сайт с указанными в URL-адресе параметрами (например, http://www.odoo.com/?campaign_id=mixin_talk&source_id=www.odoo.com&medium_id=website), на веб-сайте посетителя для этих параметров устанавливаются три куки-файла , Как только объект, который наследует utm.mixin, создается с веб-сайта (например, ведущая форма, приложение задания и т. Д.), Код utm.mixin запускается и извлекает значения из файлов cookie, чтобы установить их в новой записи. После этого вы можете использовать поля кампании / источника / среды как любое другое поле при определении отчетов и представлений (группировка по и т. Д.).
Чтобы расширить это поведение, просто добавьте реляционное поле в простую модель (модель должна поддерживать * быстрое создание * (то есть вызов `` create () `` с единственным значением `` name``) и расширить функцию ` tracking_fields ()
[UNKNOWN NODE problematic]:
class UtmMyTrack(models.Model):
_name = 'my_module.my_track'
_description = 'My Tracking Object'
name = fields.Char(string='Name', required=True)
class MyModel(models.Models):
_name = 'my_module.my_model'
_inherit = ['utm.mixin']
_description = 'My Tracked Object'
my_field = fields.Many2one('my_module.my_track', 'My Field')
@api.model
def tracking_fields(self):
result = super(MyModel, self).tracking_fields()
result.append([
# ("URL_PARAMETER", "FIELD_NAME_MIXIN", "NAME_IN_COOKIES")
('my_field', 'my_field', 'odoo_utm_my_field')
])
return result
Это скажет системе создать cookie с именем * odoo_utm_my_field * со значением, найденным в параметре url `` my_field``; Как только новая запись этой модели создается вызовом из формы веб-сайта, общее переопределение метода `` create () `` utm.mixin`` будет получать значения по умолчанию для этого поля из файла cookie ( И запись `` my_module.my_track`` будет создаваться на лету, если она еще не существует).
Вы можете найти конкретные примеры интеграции в следующих моделях:
`` Crm.lead`` в приложении CRM (* crm [UNKNOWN NODE problematic])
`` Hr.applicant`` в Заявлении о приеме на работу (* hr_recruitment [UNKNOWN NODE problematic])
`` Helpdesk.ticket`` в приложении Helpdesk (* helpdesk * - только для приложения «Одо»).
Видимость веб-сайта
Вы можете легко добавить видимость на сайте для любой записи. Хотя этот mixin довольно легко реализовать вручную, он наиболее часто используется после наследования `` mail.thread``; Свидетельствует о его полезности. Типичным примером использования этого mixin является любой объект, который имеет интерфейсную страницу; Возможность контролировать видимость страницы позволяет вам не торопиться при редактировании страницы и публиковать ее только тогда, когда вы удовлетворены.
Чтобы включить функциональность, вам нужно только наследовать `` website.published.mixin``:
class BlogPost(models.Model):
_name = "blog.post"
_description = "Blog Post"
_inherit = ['website.published.mixin']
Этот mixin добавляет 2 поля на вашей модели:
`` Site_published``:: класс: поле `` odoo.fields.Boolean`, которое представляет статус публикации
Поле `` website_url``:: class:
~ odoo.fields.Char
, которое представляет URL-адрес, по которому осуществляется доступ к объекту
Обратите внимание, что это последнее поле является вычисляемым полем и должно быть реализовано для вашего класса:
def _compute_website_url(self):
for blog_post in self:
blog_post.website_url = "/blog/%s" % (log_post.blog_id)
Как только механизм на месте, вам просто нужно адаптировать ваши интерфейсы и backend view, чтобы сделать его доступным. В бэкэнд, добавление кнопки в окошке кнопки обычно - путь:
<button class="oe_stat_button" name="website_publish_button"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
Во внешнем интерфейсе необходимы некоторые проверки безопасности, чтобы избежать появления кнопок «Издание» для посетителей сайта:
<div id="website_published_button" class="pull-right"
groups="base.group_website_publisher"> <!-- or any other meaningful group -->
<t t-call="website.publish_management">
<t t-set="object" t-value="blog_post"/>
<t t-set="publish_edit" t-value="True"/>
<t t-set="action" t-value="'blog.blog_post_action'"/>
</t>
</div>
Обратите внимание, что вы должны передать свой объект в качестве переменной `` object`` в шаблон; В этом примере запись `` blog.post`` была передана в качестве переменной `` blog_post`` в механизм визуализации `` qweb``, необходимо указать это для шаблона управления публикацией. Переменная `` publish_edit`` позволяет интерфейсной кнопке связываться с бэкэнд (позволяя легко переключаться между интерфейсом и бэкэнд и наоборот); Если установлено, вы должны указать полный внешний идентификатор действия, которое вы хотите вызвать в бэкэнд в переменной `` action`` (обратите внимание, что для модели должен существовать Form View).
Действие `` website_publish_button`` определено в mixin и адаптирует его поведение к вашему объекту: если у класса есть действительная вычислительная функция `` website_url``, пользователь перенаправляется на интерфейс, когда нажимает на кнопку; Пользователь может затем опубликовать страницу непосредственно из интерфейса. Это гарантирует, что никакая онлайн-публикация не может произойти случайно. Если нет вычислительной функции, булевое `` web_published`` просто запускается.
Метаданные веб-сайта
Этот простой mixin просто позволяет вам легко вводить метаданные в ваши интерфейсные страницы.
class BlogPost(models.Model):
_name = "blog.post"
_description = "Blog Post"
_inherit = ['website.seo.metadata', 'website.published.mixin']
Этот mixin добавляет 3 поля на вашей модели:
`` Website_meta_title``:: класс:
~ odoo.fields.Char
поле, которое позволяет вам установить дополнительный заголовок на свою страницу`` Website_meta_description``:: класс: поле `` odoo.fields.Char`, которое содержит краткое описание страницы (иногда используется в результатах поисковых систем)
`` Site_meta_keywords``:: класс: поле `` odoo.fields.Char`, которое содержит несколько ключевых слов, чтобы помочь вашей странице более точно классифицироваться поисковыми системами; Инструмент «Повысить» поможет вам легко выбрать лексически связанные ключевые слова.
Эти поля можно редактировать во внешнем интерфейсе с помощью инструмента «Повысить» на панели инструментов «Редактор». Настройка этих полей может помочь поисковым системам лучше индексировать ваши страницы. Обратите внимание, что поисковые системы не основывают свои результаты только на этих метаданных; Лучшая практика SEO должна все еще быть, чтобы быть отсылаемой надежными источниками.
Другие
Рейтинг клиентов
Микширование рейтинга позволяет отправлять электронную почту для запроса рейтинга клиента, автоматического перехода в процессы канбана и агрегирования статистики по вашим рейтингам.
Добавление рейтинга вашей модели
Чтобы добавить поддержку рейтинга, просто наследуйте модель `` rating.mixin``:
class MyModel(models.Models):
_name = 'my_module.my_model'
_inherit = ['rating.mixin', 'mail.thread']
user_id = fields.Many2one('res.users', 'Responsible')
partner_id = fields.Many2one('res.partner', 'Customer')
Поведение mixin адаптируется к вашей модели:
Запись
rating.rating`
будет связана с полем`partner_id`
вашей модели (если это поле присутствует).Это поведение может быть переопределено функцией `` rating_get_partner_id ()
, если вы используете другое поле, чем `` partner_id
Запись `` rating.rating`` будет связана с партнером поля `` user_id`` вашей модели (если поле присутствует) (то есть, партнер, который оценивается)
Это поведение может быть переопределено функцией `` rating_get_rated_partner_id ()
, если вы используете другое поле, чем `` user_id
(обратите внимание, что функция должна возвращатьres.partner`
, для`user_id`
системы Автоматически выбирает партнера пользователя)
История чата будет отображать рейтинговое событие (если ваша модель наследует от `` mail.thread``)
Отправить запрос на оценку по электронной почте
Если вы хотите отправить электронную почту для запроса рейтинга, просто сгенерируйте сообщение электронной почты со ссылками на объект рейтинга. Самый простой шаблон электронной почты может выглядеть так:
<record id="rating_my_model_email_template" model="mail.template">
<field name="name">My Model: Rating Request</field>
<field name="email_from">${object.rating_get_rated_partner_id().email or '' | safe}</field>
<field name="subject">Service Rating Request</field>
<field name="model_id" ref="my_module.model_my_model"/>
<field name="partner_to" >${object.rating_get_partner_id().id}</field>
<field name="auto_delete" eval="True"/>
<field name="body_html"><![CDATA[
% set access_token = object.rating_get_access_token()
<p>Hi,</p>
<p>How satsified are you?</p>
<ul>
<li><a href="/rating/${access_token}/10">Satisfied</a></li>
<li><a href="/rating/${access_token}/5">Not satisfied</a></li>
<li><a href="/rating/${access_token}/1">Very unsatisfied</a></li>
</ul>
]]></field>
</record>
Затем ваш клиент получит электронное письмо со ссылками на простой веб-сайт, позволяющий им предоставить обратную связь об их взаимодействии с вашими пользователями (включая бесплатное текстовое сообщение с отзывами).
Затем вы можете легко интегрировать свои рейтинги в представление формы, определив действие для рейтингов:
<record id="rating_rating_action_my_model" model="ir.actions.act_window">
<field name="name">Customer Ratings</field>
<field name="res_model">rating.rating</field>
<field name="view_mode">kanban,pivot,graph</field>
<field name="domain">[('res_model', '=', 'my_module.my_model'), ('res_id', '=', active_id), ('consumed', '=', True)]</field>
</record>
<record id="my_module_my_model_view_form_inherit_rating" model="ir.ui.view">
<field name="name">my_module.my_model.view.form.inherit.rating</field>
<field name="model">my_module.my_model</field>
<field name="inherit_id" ref="my_module.my_model_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button name="%(rating_rating_action_my_model)d" type="action"
class="oe_stat_button" icon="fa-smile-o">
<field name="rating_count" string="Rating" widget="statinfo"/>
</button>
</xpath>
</field>
</record>
Обратите внимание, что существуют рейтинги по умолчанию (канбан, стержень, график) для рейтингов, которые позволяют вам быстро просматривать свои оценки клиентов с высоты птичьего полета.
Вы можете найти конкретные примеры интеграции в следующих моделях:
`` Project.task`` в приложении Project (* rating_project [UNKNOWN NODE problematic])
`` Helpdesk.ticket`` в приложении Helpdesk (* helpdesk * - только для приложения «Одо»).