Public release from ruodoo-project: 19.0 - 2026-07-26 21:17:35 UTC
This commit is contained in:
156
tier_communications/controllers/send_notification.py
Normal file
156
tier_communications/controllers/send_notification.py
Normal file
@ -0,0 +1,156 @@
|
||||
import re
|
||||
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
|
||||
|
||||
class TierSendNotificationController(http.Controller):
|
||||
"""RPC endpoint for sending a message through an external channel.
|
||||
|
||||
Called from JS after message_post succeeds.
|
||||
Returns a status dict that JS uses to show a toast notification.
|
||||
"""
|
||||
|
||||
@http.route(
|
||||
'/tier_communications/send_via_channel',
|
||||
methods=['POST'],
|
||||
type='jsonrpc',
|
||||
auth='user',
|
||||
)
|
||||
def send_via_channel(self, message_id, channel_code, thread_model=None, thread_id=None):
|
||||
"""Send an already-created mail.message through the specified external channel.
|
||||
|
||||
Returns:
|
||||
{
|
||||
'status': 'success' | 'error' | 'no_data',
|
||||
'message': str, # human-readable status for the toast
|
||||
}
|
||||
"""
|
||||
message = request.env['mail.message'].browse(message_id)
|
||||
if not message.exists():
|
||||
return {'status': 'error', 'message': 'Сообщение не найдено'}
|
||||
|
||||
if channel_code == 'email':
|
||||
return _send_email(request.env, message, thread_model, thread_id)
|
||||
elif channel_code == 'matrix':
|
||||
return _send_matrix(request.env, message)
|
||||
else:
|
||||
return {'status': 'error', 'message': f'Неизвестный канал: {channel_code}'}
|
||||
|
||||
|
||||
def _send_email(env, message, thread_model, thread_id):
|
||||
"""Send message via email. Returns status dict."""
|
||||
recipient_email = None
|
||||
|
||||
# 1. Thread partner_id
|
||||
if thread_model and thread_id and thread_model not in ('mail.thread', 'discuss.channel'):
|
||||
thread_record = env[thread_model].browse(thread_id)
|
||||
if thread_record.exists() and hasattr(thread_record, 'partner_id'):
|
||||
partner = thread_record.partner_id
|
||||
if partner and partner.email:
|
||||
recipient_email = partner.email
|
||||
|
||||
# 2. Message partner_ids
|
||||
if not recipient_email and message.partner_ids:
|
||||
for partner in message.partner_ids:
|
||||
if partner.email:
|
||||
recipient_email = partner.email
|
||||
break
|
||||
|
||||
# 3. Last incoming message email_from
|
||||
if not recipient_email and message.model and message.res_id:
|
||||
last_incoming = env['mail.message'].search([
|
||||
('model', '=', message.model),
|
||||
('res_id', '=', message.res_id),
|
||||
('message_type', 'in', ['email', 'comment']),
|
||||
('email_from', '!=', False),
|
||||
('author_id', '!=', env.user.partner_id.id),
|
||||
], order='id desc', limit=1)
|
||||
if last_incoming and last_incoming.email_from:
|
||||
email_match = re.search(r'<([^>]+)>', last_incoming.email_from)
|
||||
recipient_email = email_match.group(1) if email_match else last_incoming.email_from
|
||||
|
||||
# 4. discuss.channel other member
|
||||
if not recipient_email and thread_model == 'discuss.channel' and thread_id:
|
||||
channel = env['discuss.channel'].browse(thread_id)
|
||||
if channel.exists():
|
||||
other_members = channel.channel_member_ids.filtered(
|
||||
lambda m: m.partner_id and m.partner_id != env.user.partner_id
|
||||
)
|
||||
for member in other_members:
|
||||
if member.partner_id.email:
|
||||
recipient_email = member.partner_id.email
|
||||
break
|
||||
|
||||
if not recipient_email:
|
||||
return {
|
||||
'status': 'no_data',
|
||||
'message': 'Не заполнен email получателя',
|
||||
}
|
||||
|
||||
try:
|
||||
mail_values = {
|
||||
'subject': message.subject or 'Сообщение из Odoo',
|
||||
'body_html': message.body or '',
|
||||
'email_to': recipient_email,
|
||||
'email_from': env.company.email or env.user.email or '',
|
||||
'auto_delete': True,
|
||||
}
|
||||
outgoing_mail = env['mail.mail'].sudo().create(mail_values)
|
||||
outgoing_mail.send()
|
||||
return {
|
||||
'status': 'success',
|
||||
'message': f'Сообщение отправлено на {recipient_email}',
|
||||
}
|
||||
except Exception as send_error:
|
||||
return {
|
||||
'status': 'error',
|
||||
'message': f'Ошибка отправки email: {send_error}',
|
||||
}
|
||||
|
||||
|
||||
def _send_matrix(env, message):
|
||||
"""Send message via Matrix. Returns status dict."""
|
||||
current_user = env.user
|
||||
|
||||
if not hasattr(current_user, 'tier_matrix_homeserver'):
|
||||
return {
|
||||
'status': 'no_data',
|
||||
'message': 'Модуль Matrix не установлен',
|
||||
}
|
||||
|
||||
homeserver_url = current_user.tier_matrix_homeserver
|
||||
access_token = current_user.tier_matrix_access_token
|
||||
room_id = current_user.tier_matrix_room_id
|
||||
|
||||
missing_fields = []
|
||||
if not homeserver_url:
|
||||
missing_fields.append('Homeserver URL')
|
||||
if not access_token:
|
||||
missing_fields.append('Access Token')
|
||||
if not room_id:
|
||||
missing_fields.append('Room ID')
|
||||
|
||||
if missing_fields:
|
||||
return {
|
||||
'status': 'no_data',
|
||||
'message': f'Не заполнены данные Matrix: {", ".join(missing_fields)}',
|
||||
}
|
||||
|
||||
if 'tier.channel.matrix.helper' not in env:
|
||||
return {
|
||||
'status': 'no_data',
|
||||
'message': 'Модуль Matrix не установлен',
|
||||
}
|
||||
|
||||
try:
|
||||
env['tier.channel.matrix.helper'].channel_send_message(message, user=current_user)
|
||||
return {
|
||||
'status': 'success',
|
||||
'message': f'Сообщение отправлено в Matrix (room: {room_id})',
|
||||
}
|
||||
except Exception as send_error:
|
||||
return {
|
||||
'status': 'error',
|
||||
'message': f'Ошибка отправки Matrix: {send_error}',
|
||||
}
|
||||
Reference in New Issue
Block a user