Ildar Nasyrov
7 years ago
No known key found for this signature in database
GPG Key ID: D1FDACDF9B83578
15 changed files with 483 additions and 0 deletions
-
13im_notif/README.rst
-
9im_notif/__init__.py
-
19im_notif/__openerp__.py
-
4im_notif/doc/changelog.rst
-
19im_notif/im_notif_data.xml
-
160im_notif/im_notif_models.py
-
12im_notif/im_notif_views.xml
-
BINim_notif/images/my-pref.png
-
BINim_notif/static/description/icon.png
-
BINim_notif/static/description/im-chat.png
-
69im_notif/static/description/index.html
-
BINim_notif/static/description/my-pref-button.png
-
44im_notif/static/src/js/im_notif.js
-
67mail_sent/i18n/pt.po
-
67mail_sent/i18n/pt_BR.po
@ -0,0 +1,13 @@ |
|||||
|
IM Notifications |
||||
|
================ |
||||
|
|
||||
|
Description: https://apps.odoo.com/apps/modules/8.0/im_notif/ |
||||
|
|
||||
|
Further information and discussion: https://yelizariev.github.io/odoo/module/2015/02/18/im-notifications.html |
||||
|
|
||||
|
Tested on Odoo 8.0 ab7b5d7732a7c222a0aea45bd173742acd47242d |
||||
|
|
||||
|
Odoo 9.0+ |
||||
|
========= |
||||
|
|
||||
|
For newer version the module is not needed, cause there is similar built-in feature |
@ -0,0 +1,9 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
from . import im_notif_models |
||||
|
|
||||
|
|
||||
|
def pre_uninstall(cr, registry): |
||||
|
query = ("UPDATE res_partner " |
||||
|
"SET notify_email = 'always' " |
||||
|
"WHERE notify_email LIKE 'im%';") |
||||
|
cr.execute(query) |
@ -0,0 +1,19 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
{ |
||||
|
'name': 'IM Notifications', |
||||
|
'version': '1.0.1', |
||||
|
'author': 'IT-Projects LLC, Ivan Yelizariev', |
||||
|
'license': 'GPL-3', |
||||
|
'category': 'Tools', |
||||
|
'website': 'https://twitter.com/yelizariev', |
||||
|
'price': 9.00, |
||||
|
'currency': 'EUR', |
||||
|
'depends': ['im_chat', 'mail'], |
||||
|
'images': ['images/my-pref.png'], |
||||
|
'data': [ |
||||
|
'im_notif_data.xml', |
||||
|
'im_notif_views.xml', |
||||
|
], |
||||
|
'installable': True, |
||||
|
'uninstall_hook': 'pre_uninstall', |
||||
|
} |
@ -0,0 +1,4 @@ |
|||||
|
`1.0.1` |
||||
|
------- |
||||
|
|
||||
|
- Hide Notifications user |
@ -0,0 +1,19 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<record id="notif_partner" model="res.partner"> |
||||
|
<field name="name">Notifications</field> |
||||
|
<field name="active" eval="False"/> |
||||
|
<field name="comment">Technical profile. You should not delete it.</field> |
||||
|
</record> |
||||
|
<record id="notif_user" model="res.users"> |
||||
|
<field name="name">Notifications</field> |
||||
|
<field name="login">notifications</field> |
||||
|
<field name="password"></field> |
||||
|
<field name="groups_id" eval="[(6,0,[ref('base.group_user')])]"/> |
||||
|
<!--<field name="image" type="base64" file="base/static/img/public_user-image.png"/>--> |
||||
|
<field name="partner_id" ref="notif_partner"/> |
||||
|
<field name="active" eval="True"/> |
||||
|
</record> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,160 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
from openerp import SUPERUSER_ID |
||||
|
from openerp import models |
||||
|
from openerp import tools |
||||
|
from openerp.osv import fields as old_fields |
||||
|
|
||||
|
|
||||
|
class ResPartner(models.Model): |
||||
|
_inherit = 'res.partner' |
||||
|
_columns = { |
||||
|
'notify_email': old_fields.selection([ |
||||
|
('none', 'Never'), |
||||
|
('im', 'Only IM (if online)'), |
||||
|
('im_xor_email', 'IM (if online) + email (if offline)'), |
||||
|
('im_and_email', 'IM (if online) + email'), |
||||
|
('always', 'Only emails'), |
||||
|
], 'Receive Inbox Notifications by Email, IM', required=True, |
||||
|
oldname='notification_email_send', |
||||
|
help="Policy to receive emails, IM for new messages pushed to your personal Inbox. IM can be used only for partners with odoo user account" |
||||
|
), |
||||
|
} |
||||
|
|
||||
|
|
||||
|
class MailNotification(models.Model): |
||||
|
_inherit = 'mail.notification' |
||||
|
|
||||
|
def get_recipients(self, cr, uid, ids, message, context=None): |
||||
|
# based on addons/mail/mail_followers.py::get_partners_to_email |
||||
|
""" Return the list of partners to notify, based on their preferences. |
||||
|
|
||||
|
:param browse_record message: mail.message to notify |
||||
|
:param list partners_to_notify: optional list of partner ids restricting |
||||
|
the notifications to process |
||||
|
""" |
||||
|
email_pids = [] |
||||
|
im_uids = [] |
||||
|
for notification in self.browse(cr, uid, ids, context=context): |
||||
|
if notification.is_read: |
||||
|
continue |
||||
|
partner = notification.partner_id |
||||
|
# Do not send to partners without email address defined |
||||
|
if not partner.email: |
||||
|
continue |
||||
|
# Do not send to partners having same email address than the author (can cause loops or bounce effect due to messy database) |
||||
|
if message.author_id and message.author_id.email == partner.email: |
||||
|
continue |
||||
|
# Partner does not want to receive any emails or is opt-out |
||||
|
n = partner.notify_email |
||||
|
if n == 'none': |
||||
|
continue |
||||
|
if n == 'always': |
||||
|
email_pids.append(partner.id) |
||||
|
continue |
||||
|
send_email = False |
||||
|
for user in partner.user_ids: |
||||
|
if user.im_status == 'offline': |
||||
|
if n != 'im': |
||||
|
send_email = True |
||||
|
else: |
||||
|
im_uids.append(user.id) |
||||
|
if n == 'im_and_email': |
||||
|
send_email = True |
||||
|
|
||||
|
if not len(partner.user_ids): |
||||
|
# send notification to partner, that doesn't have odoo account, but has "im*" value in notify_email |
||||
|
send_email = True |
||||
|
|
||||
|
if send_email: |
||||
|
email_pids.append(partner.id) |
||||
|
|
||||
|
return email_pids, im_uids |
||||
|
|
||||
|
def _message2im(self, cr, uid, message): |
||||
|
inbox_action = self.pool['ir.model.data'].xmlid_to_res_id(cr, SUPERUSER_ID, 'mail.mail_inboxfeeds') |
||||
|
inbox_url = '#menu_id=%s' % inbox_action |
||||
|
url = None |
||||
|
if message.res_id: |
||||
|
url = '#id=%s&model=%s&view_type=form' % ( |
||||
|
message.res_id, |
||||
|
message.model |
||||
|
) |
||||
|
author = message.author_id and message.author_id.name_get() |
||||
|
author = author and author[0][1] or message.email_from |
||||
|
|
||||
|
about = message.subject or message.record_name or 'UNDEFINED' |
||||
|
about = '[ABOUT] %s' % about |
||||
|
if url: |
||||
|
about = '<a href="%s">%s</a>' % (url, about) |
||||
|
im_text = [ |
||||
|
'_____________________', |
||||
|
'<a href="%s">_____[open_inbox]_____</a>' % inbox_url, |
||||
|
'%s [FROM] %s' % (message.type, author), |
||||
|
about, |
||||
|
] |
||||
|
# im_text = im_text + body.split('\n') |
||||
|
return im_text |
||||
|
|
||||
|
def _notify_email(self, cr, uid, ids, message_id, force_send=False, user_signature=True, context=None): |
||||
|
# based on addons/mail/mail_followers.py::_notify_email |
||||
|
message = self.pool['mail.message'].browse(cr, SUPERUSER_ID, message_id, context=context) |
||||
|
|
||||
|
# compute partners |
||||
|
email_pids, im_uids = self.get_recipients(cr, uid, ids, message, context=None) |
||||
|
if email_pids: |
||||
|
self._do_notify_email(cr, uid, email_pids, message, force_send, user_signature, context) |
||||
|
|
||||
|
if im_uids: |
||||
|
self._do_notify_im(cr, uid, im_uids, message, context) |
||||
|
|
||||
|
return True |
||||
|
|
||||
|
def _do_notify_im(self, cr, uid, im_uids, message, context=None): |
||||
|
im_text = self._message2im(cr, uid, message) |
||||
|
|
||||
|
user_from = self.pool['ir.model.data'].xmlid_to_res_id(cr, SUPERUSER_ID, 'im_notif.notif_user') |
||||
|
|
||||
|
session_obj = self.pool['im_chat.session'] |
||||
|
message_type = 'message' |
||||
|
for user_to in im_uids: |
||||
|
session = session_obj.session_get(cr, user_from, user_to, context=context) |
||||
|
uuid = session.get('uuid') |
||||
|
message_content = '\n'.join(im_text) |
||||
|
self.pool["im_chat.message"].post(cr, SUPERUSER_ID, user_from, uuid, message_type, message_content, context=context) |
||||
|
|
||||
|
return True |
||||
|
|
||||
|
def _do_notify_email(self, cr, uid, email_pids, message, force_send=False, user_signature=True, context=None): |
||||
|
|
||||
|
# compute email body (signature, company data) |
||||
|
body_html = message.body |
||||
|
# add user signature except for mail groups, where users are usually adding their own signatures already |
||||
|
user_id = message.author_id and message.author_id.user_ids and message.author_id.user_ids[0] and message.author_id.user_ids[0].id or None |
||||
|
signature_company = self.get_signature_footer(cr, uid, user_id, res_model=message.model, res_id=message.res_id, context=context, user_signature=(user_signature and message.model != 'mail.group')) |
||||
|
if signature_company: |
||||
|
body_html = tools.append_content_to_html(body_html, signature_company, plaintext=False, container_tag='div') |
||||
|
# compute email references |
||||
|
references = message.parent_id.message_id if message.parent_id else False |
||||
|
|
||||
|
# custom values |
||||
|
custom_values = dict() |
||||
|
if message.model and message.res_id and self.pool.get(message.model) and hasattr(self.pool[message.model], 'message_get_email_values'): |
||||
|
custom_values = self.pool[message.model].message_get_email_values(cr, uid, message.res_id, message, context=context) |
||||
|
|
||||
|
# create email values |
||||
|
max_recipients = 50 |
||||
|
chunks = [email_pids[x:x + max_recipients] for x in xrange(0, len(email_pids), max_recipients)] |
||||
|
email_ids = [] |
||||
|
for chunk in chunks: |
||||
|
mail_values = { |
||||
|
'mail_message_id': message.id, |
||||
|
'auto_delete': True, |
||||
|
'body_html': body_html, |
||||
|
'recipient_ids': [(4, id) for id in chunk], |
||||
|
'references': references, |
||||
|
} |
||||
|
mail_values.update(custom_values) |
||||
|
email_ids.append(self.pool.get('mail.mail').create(cr, uid, mail_values, context=context)) |
||||
|
if force_send and len(chunks) < 2: # for more than 50 followers, use the queue system |
||||
|
self.pool.get('mail.mail').send(cr, uid, email_ids, context=context) |
||||
|
return True |
@ -0,0 +1,12 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<template id="assets_backend" name="im_notif assets" inherit_id="web.assets_backend"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<!--<link rel="stylesheet" href="/im_notif/static/src/css/im_notif.css"/>--> |
||||
|
<script type="text/javascript" src="/im_notif/static/src/js/im_notif.js"></script> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
|
||||
|
</data> |
||||
|
</openerp> |
After Width: 748 | Height: 400 | Size: 37 KiB |
After Width: 100 | Height: 100 | Size: 3.0 KiB |
After Width: 240 | Height: 342 | Size: 28 KiB |
@ -0,0 +1,69 @@ |
|||||
|
<section class="oe_container"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<div class="oe_span12"> |
||||
|
<h2 class="oe_slogan">IM Notifications</h2> |
||||
|
<h3 class="oe_slogan">Get instant notification inside odoo</h3> |
||||
|
</div> |
||||
|
|
||||
|
<div class="oe_span6"> |
||||
|
<p class="oe_mt32"> |
||||
|
A user is able to select option for notifications: |
||||
|
|
||||
|
<ul class="org-ul"> |
||||
|
<li>Never </li> |
||||
|
<li>Only IM (if online) </li> |
||||
|
<li>IM (if online) + email (if offline) </li> |
||||
|
<li>IM (if online) + email </li> |
||||
|
<li>Only Emails </li></ul> |
||||
|
</p> |
||||
|
</div> |
||||
|
|
||||
|
<div class="oe_span6"> |
||||
|
<div class="oe_picture"> |
||||
|
<img src="my-pref-button.png"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
<section class="oe_container oe_dark"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<div class="oe_span6"> |
||||
|
<p class="oe_mt32"> |
||||
|
Each notification includes: |
||||
|
<ul> |
||||
|
<li>Message type: email, comment or notification </li> |
||||
|
<li>Author's name </li> |
||||
|
<li>Subject with a link to related record (if exists) </li> |
||||
|
<li>Link to inbox </li> |
||||
|
</ul> |
||||
|
</p> |
||||
|
</div> |
||||
|
|
||||
|
<div class="oe_span6"> |
||||
|
<div class="oe_picture"> |
||||
|
<img src="im-chat.png?3"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="oe_span12"> |
||||
|
<p class="oe_mt32"> |
||||
|
Further information and discussion: <a href="https://yelizariev.github.io/odoo/module/2015/02/18/im-notifications.html">https://yelizariev.github.io/odoo/module/2015/02/18/im-notifications.html</a> |
||||
|
</p> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
<section class="oe_container"> |
||||
|
<div class="oe_row oe_spaced"> |
||||
|
<div class="oe_span12"> |
||||
|
<h2>Need our service?</h2> |
||||
|
<p class="oe_mt32">Contact us by <a href="mailto:it@it-projects.info">email</a> or fill out <a href="https://www.it-projects.info/page/website.contactus " target="_blank">request form</a></p> |
||||
|
<ul> |
||||
|
<li><a href="mailto:it@it-projects.info">it@it-projects.info <i class="fa fa-envelope-o"></i></a></li> |
||||
|
<li><a href="https://www.it-projects.info/page/website.contactus " target="_blank"> |
||||
|
https://www.it-projects.info/page/website.contactus <i class="fa fa-list-alt"></i></a></li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
After Width: 260 | Height: 220 | Size: 16 KiB |
@ -0,0 +1,44 @@ |
|||||
|
(function(){ |
||||
|
|
||||
|
"use strict"; |
||||
|
|
||||
|
var _t = openerp._t; |
||||
|
var _lt = openerp._lt; |
||||
|
var QWeb = openerp.qweb; |
||||
|
|
||||
|
openerp.im_chat.Conversation.include({ |
||||
|
escape_keep_url: function(str){ |
||||
|
//var url_regex = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/gi;
|
||||
|
var url_regex = /((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?|(<a)[^>]*href="([^"]*)"[^>]*>([^<]*)<\/a>)/gi; |
||||
|
var last = 0; |
||||
|
var txt = ""; |
||||
|
while (true) { |
||||
|
var result = url_regex.exec(str); |
||||
|
if (! result) |
||||
|
break; |
||||
|
txt += _.escape(str.slice(last, result.index)); |
||||
|
last = url_regex.lastIndex; |
||||
|
var href = ''; |
||||
|
var content = ''; |
||||
|
var is_odoo_ref = false; |
||||
|
if (result[8]=='<a'){ |
||||
|
href = result[9]; |
||||
|
if (href[0]=='#'){ |
||||
|
href += '&rnd='+parseInt(Math.random()*1000); |
||||
|
content = result[10]; |
||||
|
is_odoo_ref = true; |
||||
|
} else { |
||||
|
//only internal urls are allowed
|
||||
|
href = ''; |
||||
|
} |
||||
|
}else{ |
||||
|
href = _.escape(result[0]); |
||||
|
content = href; |
||||
|
} |
||||
|
txt += '<a href="' + href + '"' + (is_odoo_ref?'':' target="_blank"')+'>' + content + '</a>'; |
||||
|
} |
||||
|
txt += _.escape(str.slice(last, str.length)); |
||||
|
return txt; |
||||
|
}, |
||||
|
}); |
||||
|
})(); |
@ -0,0 +1,67 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * mail_sent |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 8.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2017-03-29 18:57+0000\n" |
||||
|
"PO-Revision-Date: 2017-03-29 18:57+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: \n" |
||||
|
|
||||
|
#. module: mail_sent |
||||
|
#: model:ir.actions.client,help:mail_sent.action_mail_sent_feeds |
||||
|
msgid "<p>\n" |
||||
|
" No message found and no message sent yet.\n" |
||||
|
" </p><p>\n" |
||||
|
" Click on the top-right icon to compose a message. This\n" |
||||
|
" message will be sent by email if it's an internal contact.\n" |
||||
|
" </p>\n" |
||||
|
" " |
||||
|
msgstr "<p>\n" |
||||
|
" Nenhuma mensagem encontrada e nenhuma enviada ainda.\n" |
||||
|
" </p><p>\n" |
||||
|
" Clique no ícone no canto superior direito para compor uma nova mensagem.\n" |
||||
|
" Esta mensagem será enviada por e-mail se não for um contato interno.\n" |
||||
|
" </p>\n" |
||||
|
" " |
||||
|
|
||||
|
#. module: mail_sent |
||||
|
#: model:ir.model,name:mail_sent.model_mail_compose_message |
||||
|
msgid "Email composition wizard" |
||||
|
msgstr "Assistente de composição de Email" |
||||
|
|
||||
|
#. module: mail_sent |
||||
|
#: model:ir.model,name:mail_sent.model_mail_message |
||||
|
msgid "Message" |
||||
|
msgstr "Mensagem" |
||||
|
|
||||
|
#. module: mail_sent |
||||
|
#: model:ir.model,name:mail_sent.model_mail_notification |
||||
|
msgid "Notifications" |
||||
|
msgstr "Notificações" |
||||
|
|
||||
|
#. module: mail_sent |
||||
|
#: model:ir.actions.client,name:mail_sent.action_mail_sent_feeds |
||||
|
#: model:ir.ui.menu,name:mail_sent.mail_sentfeeds |
||||
|
#: field:mail.compose.message,sent:0 |
||||
|
#: field:mail.message,sent:0 |
||||
|
msgid "Sent" |
||||
|
msgstr "Enviados" |
||||
|
|
||||
|
#. module: mail_sent |
||||
|
#: help:mail.message,sent:0 |
||||
|
msgid "Was message sent to someone" |
||||
|
msgstr "Foi enviada mensagem para alguém" |
||||
|
|
||||
|
#. module: mail_sent |
||||
|
#: help:mail.compose.message,sent:0 |
||||
|
msgid "dummy field to fix inherit error" |
||||
|
msgstr "campo fictício para corrigir o erro da herança" |
||||
|
|
@ -0,0 +1,67 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * mail_sent |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 8.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2017-03-29 18:57+0000\n" |
||||
|
"PO-Revision-Date: 2017-03-29 18:57+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: \n" |
||||
|
|
||||
|
#. module: mail_sent |
||||
|
#: model:ir.actions.client,help:mail_sent.action_mail_sent_feeds |
||||
|
msgid "<p>\n" |
||||
|
" No message found and no message sent yet.\n" |
||||
|
" </p><p>\n" |
||||
|
" Click on the top-right icon to compose a message. This\n" |
||||
|
" message will be sent by email if it's an internal contact.\n" |
||||
|
" </p>\n" |
||||
|
" " |
||||
|
msgstr "<p>\n" |
||||
|
" Nenhuma mensagem encontrada e nenhuma enviada ainda.\n" |
||||
|
" </p><p>\n" |
||||
|
" Clique no ícone no canto superior direito para compor uma nova mensagem.\n" |
||||
|
" Esta mensagem será enviada por e-mail se não for um contato interno.\n" |
||||
|
" </p>\n" |
||||
|
" " |
||||
|
|
||||
|
#. module: mail_sent |
||||
|
#: model:ir.model,name:mail_sent.model_mail_compose_message |
||||
|
msgid "Email composition wizard" |
||||
|
msgstr "Assistente de Composição de Email" |
||||
|
|
||||
|
#. module: mail_sent |
||||
|
#: model:ir.model,name:mail_sent.model_mail_message |
||||
|
msgid "Message" |
||||
|
msgstr "Mensagem" |
||||
|
|
||||
|
#. module: mail_sent |
||||
|
#: model:ir.model,name:mail_sent.model_mail_notification |
||||
|
msgid "Notifications" |
||||
|
msgstr "Notificações" |
||||
|
|
||||
|
#. module: mail_sent |
||||
|
#: model:ir.actions.client,name:mail_sent.action_mail_sent_feeds |
||||
|
#: model:ir.ui.menu,name:mail_sent.mail_sentfeeds |
||||
|
#: field:mail.compose.message,sent:0 |
||||
|
#: field:mail.message,sent:0 |
||||
|
msgid "Sent" |
||||
|
msgstr "Enviados" |
||||
|
|
||||
|
#. module: mail_sent |
||||
|
#: help:mail.message,sent:0 |
||||
|
msgid "Was message sent to someone" |
||||
|
msgstr "Foi enviada mensagem para alguém" |
||||
|
|
||||
|
#. module: mail_sent |
||||
|
#: help:mail.compose.message,sent:0 |
||||
|
msgid "dummy field to fix inherit error" |
||||
|
msgstr "campo fictício para corrigir o erro da herança" |
||||
|
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue