[IMP] removed needaction_pending, some cleaning in messages mail
bzr revid: fp@openerp.com-20120815133643-loyzmyp6azs5lr47
This commit is contained in:
@@ -170,7 +170,7 @@
|
||||
<page string="Invitation Detail">
|
||||
<button string="Invite People"
|
||||
name="%(base_calendar.action_view_calendar_invite_attendee_wizard)d"
|
||||
icon="terp-partner" type="action"
|
||||
type="action"
|
||||
attrs="{'readonly': [('state', '=', 'done')]}"
|
||||
context="{'model' : 'crm.meeting', 'attendee_field':'attendee_ids'}" colspan="2"/>
|
||||
<field name="attendee_ids" widget="one2many" mode="tree">
|
||||
@@ -183,17 +183,16 @@
|
||||
<button name="do_tentative"
|
||||
states="needs-action,declined,accepted"
|
||||
string="Uncertain" type="object"
|
||||
icon="terp-crm" />
|
||||
/>
|
||||
<button name="do_accept" string="Accept"
|
||||
states="needs-action,tentative,declined"
|
||||
type="object" icon="gtk-apply" />
|
||||
type="object" />
|
||||
<button name="do_decline" string="Decline"
|
||||
states="needs-action,tentative,accepted"
|
||||
type="object" icon="gtk-cancel" />
|
||||
type="object" />
|
||||
<button
|
||||
name="%(base_calendar.action_view_calendar_invite_attendee_wizard)d"
|
||||
string="Delegate" type="action"
|
||||
icon="gtk-sort-descending"
|
||||
states="needs-action,tentative,declined,accepted"
|
||||
context="{'model' : 'calendar.attendee', 'attendee_field' : 'child_ids'}" />
|
||||
</tree>
|
||||
@@ -201,16 +200,16 @@
|
||||
<header>
|
||||
<button name="do_tentative" type="object"
|
||||
states="needs-action,declined,accepted"
|
||||
string="Uncertain" icon="terp-crm" />
|
||||
string="Uncertain" />
|
||||
<button name="do_accept" type="object"
|
||||
states="needs-action,tentative,declined"
|
||||
string="Accept" icon="gtk-apply" />
|
||||
string="Accept" />
|
||||
<button name="do_decline" type="object"
|
||||
states="needs-action,tentative,accepted"
|
||||
string="Decline" icon="gtk-cancel" />
|
||||
string="Decline" />
|
||||
<button name="%(base_calendar.action_view_calendar_invite_attendee_wizard)d" type="action"
|
||||
states="needs-action,tentative,declined,accepted"
|
||||
string="Delegate" icon="gtk-sort-descending"
|
||||
string="Delegate"
|
||||
context="{'model' : 'calendar.attendee', 'attendee_field' : 'child_ids'}" />
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,open,done"/>
|
||||
</header>
|
||||
@@ -244,14 +243,14 @@
|
||||
<field name="name">CRM - Meetings Tree</field>
|
||||
<field name="model">crm.meeting</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Meetings" fonts="bold:needaction_pending==True"
|
||||
<tree string="Meetings" fonts="bold:message_state==True"
|
||||
colors="red:state=='open';black:state in ('draft', 'cancel','done','pending')">
|
||||
<field name="name" string="Subject" />
|
||||
<field name="user_id"/>
|
||||
<field name="date"/>
|
||||
<field name="state"/>
|
||||
<field name="duration" />
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<field name="message_state" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -288,9 +287,9 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Meetings">
|
||||
<field name="name" string="Meeting" filter_domain="[('name','ilike',self)]"/>
|
||||
<filter string="Inbox" help="Unread messages" icon="terp-mail-message-new" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
|
||||
<filter string="Inbox" help="Unread messages" name="message_state" domain="[('message_state','=',True)]"/>
|
||||
<separator/>
|
||||
<filter string="My Meetings" help="My Meetings" icon="terp-personal" domain="[('user_id','=',uid)]"/>
|
||||
<filter string="My Meetings" help="My Meetings" domain="[('user_id','=',uid)]"/>
|
||||
<field name="user_id"/>
|
||||
<field name="partner_ids"/>
|
||||
</search>
|
||||
|
||||
@@ -245,7 +245,7 @@
|
||||
<field name="name">Leads</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Leads" fonts="bold:needaction_pending==True" colors="grey:state in ('cancel', 'done')">
|
||||
<tree string="Leads" fonts="bold:message_state==True" colors="grey:state in ('cancel', 'done')">
|
||||
<field name="date_deadline" invisible="1"/>
|
||||
<field name="create_date" groups="base.group_no_one"/>
|
||||
<field name="name"/>
|
||||
@@ -261,7 +261,7 @@
|
||||
<field name="referred" invisible="1"/>
|
||||
<field name="channel_id" invisible="1"/>
|
||||
<field name="subjects" invisible="1"/>
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<field name="message_state" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -294,7 +294,7 @@
|
||||
<field name="user_id"/>
|
||||
<field name="partner_address_email"/>
|
||||
<field name="message_summary"/>
|
||||
<field name="needaction_pending"/>
|
||||
<field name="message_state"/>
|
||||
<templates>
|
||||
<t t-name="lead_details">
|
||||
<ul class="oe_kanban_tooltip">
|
||||
@@ -340,7 +340,7 @@
|
||||
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
|
||||
</div>
|
||||
<div class="oe_kanban_footer_left">
|
||||
<t t-if="record.needaction_pending.raw_value"><span class="oe_kanban_mail_new">New</span></t>
|
||||
<t t-if="record.message_state.raw_value"><span class="oe_kanban_mail_new">New</span></t>
|
||||
<t t-raw="record.message_summary.raw_value"/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -363,7 +363,7 @@
|
||||
<!-- subjects is not set as store=True so, it is placed outside filter_domain-->
|
||||
<field name="subjects"/>
|
||||
<field name="create_date"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_state" domain="[('message_state','=',True)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-check" string="New" name="new" help="New Leads" domain="[('state','=','draft')]"/>
|
||||
<filter icon="terp-camera_test" string="Open" name="open" domain="[('state','=','open')]"/>
|
||||
@@ -542,7 +542,7 @@
|
||||
<field name="name">Opportunities Tree</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Opportunities" fonts="bold:needaction_pending==True" colors="gray:state in ('cancel', 'done');red:date_deadline and (date_deadline < current_date)">
|
||||
<tree string="Opportunities" fonts="bold:message_state==True" colors="gray:state in ('cancel', 'done');red:date_deadline and (date_deadline < current_date)">
|
||||
<field name="date_deadline" invisible="1"/>
|
||||
<field name="create_date" groups="base.group_no_one"/>
|
||||
<field name="name" string="Opportunity"/>
|
||||
@@ -560,7 +560,7 @@
|
||||
<field name="user_id"/>
|
||||
<field name="priority" invisible="1"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<field name="message_state" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -575,7 +575,7 @@
|
||||
<field name="name" string="Opportunity / Customer"
|
||||
filter_domain="['|','|','|',('partner_id','ilike',self),('partner_name','ilike',self),('email_from','ilike',self),('name', 'ilike', self)]"/>
|
||||
<field name="categ_ids" string="Category" filter_domain="[('categ_ids','ilike', self)]" />
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_state" domain="[('message_state','=',True)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-check" string="New" help="New Opportunities" name="new" domain="[('state','=','draft')]"/>
|
||||
<filter icon="terp-camera_test" string="Open" help="Open Opportunities" name="open" domain="[('state','=','open')]"/>
|
||||
|
||||
@@ -66,8 +66,7 @@
|
||||
<field name="name">CRM - Phone Calls Tree</field>
|
||||
<field name="model">crm.phonecall</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree fonts="bold:needaction_pending==True" colors="gray:state in ('cancel','done');blue:state in ('pending',)" string="Phone Calls">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<tree colors="gray:state in ('cancel','done');blue:state in ('pending',)" string="Phone Calls">
|
||||
<field name="date"/>
|
||||
<field name="name"/>
|
||||
<field name="partner_id"/>
|
||||
@@ -76,7 +75,6 @@
|
||||
<field name="categ_id" invisible="1"/>
|
||||
<field name="create_date" invisible="1"/>
|
||||
<field name="opportunity_id" invisible="1"/>
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<button string="Convert to Opportunity"
|
||||
name="%(phonecall2opportunity_act)d"
|
||||
states="open,pending"
|
||||
@@ -165,7 +163,7 @@
|
||||
<field name="name">CRM - Logged Phone Calls Tree</field>
|
||||
<field name="model">crm.phonecall</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Phone Calls" fonts="bold:needaction_pending==True" editable="top">
|
||||
<tree string="Phone Calls" editable="top">
|
||||
<field name="date"/>
|
||||
<field name="name"/>
|
||||
<field name="partner_id"
|
||||
@@ -179,7 +177,6 @@
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="create_date" invisible="1"/>
|
||||
<field name="opportunity_id" invisible="1"/>
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<button string="Schedule Other Call"
|
||||
icon="terp-call-start"
|
||||
name="%(phonecall_to_phonecall_act)d"
|
||||
@@ -218,7 +215,6 @@
|
||||
<search string="Search Phonecalls">
|
||||
<field name="name" string="Phonecalls"/>
|
||||
<field name="date"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-gtk-go-back-rtl" string="To Do" name="current" domain="[('state','=','open')]"/>
|
||||
<separator/>
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
<field name="name">event.event.tree</field>
|
||||
<field name="model">event.event</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Events" fonts="bold:needaction_pending==True" colors="red:(register_min and register_min>register_current) or (register_max and register_max<register_current);grey:state=='cancel'">
|
||||
<tree string="Events" fonts="bold:message_state==True" colors="red:(register_min and register_min>register_current) or (register_max and register_max<register_current);grey:state=='cancel'">
|
||||
<field name="name" string="Name"/>
|
||||
<field name="type"/>
|
||||
<field name="date_begin"/>
|
||||
@@ -218,7 +218,7 @@
|
||||
<field name="main_speaker_id" groups="base.extended"/>
|
||||
<field name="user_id"/>
|
||||
<field name="state"/>
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<field name="message_state" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -325,7 +325,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Events">
|
||||
<field name="name" string="Events"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_state" domain="[('message_state','=',True)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-check" string="Unconfirmed" name="draft" domain="[('state','=','draft')]" help="Events in New state"/>
|
||||
<filter icon="terp-camera_test" string="Confirmed" domain="[('state','=','confirm')]" help="Confirmed events"/>
|
||||
@@ -420,7 +420,7 @@
|
||||
<field name="name">event.registration.tree</field>
|
||||
<field name="model">event.registration</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Registration" fonts="bold:needaction_pending==True">
|
||||
<tree string="Registration" fonts="bold:message_state==True">
|
||||
<field name="create_date"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="name"/>
|
||||
@@ -430,7 +430,7 @@
|
||||
<field name="user_id"/>
|
||||
<field name="origin"/>
|
||||
<field name="state"/>
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<field name="message_state" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -514,7 +514,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Event Registration">
|
||||
<field name="name" string="Participant" filter_domain="['|','|','|',('name','ilike',self),('partner_id','ilike',self),('email','ilike',self),('origin','ilike',self)]"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_state" domain="[('message_state','=',True)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-check" string="New" name="draft" domain="[('state','=','draft')]" help="Registrations in unconfirmed state"/>
|
||||
<filter icon="terp-camera_test" string="Confirmed" domain="[('state','=','open')]" help="Confirmed registrations"/>
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Leave">
|
||||
<field name="date_from"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-check" domain="[('state','=','draft')]" string="To Confirm"/>
|
||||
<filter icon="terp-camera_test" domain="[('state','=','confirm')]" string="To Approve" name="approve"/>
|
||||
@@ -192,8 +191,7 @@
|
||||
<field name="name">hr.holidays.allocation.tree</field>
|
||||
<field name="model">hr.holidays</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree fonts="bold:needaction_pending==True" colors="red:state == 'refuse';blue:state == 'draft';black:state in ('confirm','validate','validate1')" string="Allocation Requests">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<tree colors="red:state == 'refuse';blue:state == 'draft';black:state in ('confirm','validate','validate1')" string="Allocation Requests">
|
||||
<field name="employee_id"/>
|
||||
<field name="holiday_type"/>
|
||||
<field name="category_id"/>
|
||||
@@ -241,8 +239,7 @@
|
||||
<field name="model">hr.holidays</field>
|
||||
<field name="priority">20</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree fonts="bold:needaction_pending==True" colors="red:state == 'refuse';blue:state == ' draft';black:state in ('confirm','validate','validate1')" string="Leaves Summary">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<tree colors="red:state == 'refuse';blue:state == ' draft';black:state in ('confirm','validate','validate1')" string="Leaves Summary">
|
||||
<field name="employee_id"/>
|
||||
<field name="category_id" invisible="1"/>
|
||||
<field name="department_id" invisible="1"/>
|
||||
@@ -264,8 +261,7 @@
|
||||
<field name="name">hr.holidays.tree</field>
|
||||
<field name="model">hr.holidays</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree fonts="bold:needaction_pending==True" colors="red:state == 'refuse';blue:state == ' draft';black:state in ('confirm','validate','validate1')" string="Leave Requests">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<tree colors="red:state == 'refuse';blue:state == ' draft';black:state in ('confirm','validate','validate1')" string="Leave Requests">
|
||||
<field name="employee_id"/>
|
||||
<field name="holiday_type" string="Mode" groups="base.group_hr_user"/>
|
||||
<field name="name"/>
|
||||
|
||||
@@ -76,8 +76,8 @@
|
||||
<field name="name">Applicants</field>
|
||||
<field name="model">hr.applicant</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Applicants" fonts="bold:needaction_pending==True" colors="grey:state in ('cancel','done');blue:state=='pending'">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<tree string="Applicants" fonts="bold:message_state==True" colors="grey:state in ('cancel','done');blue:state=='pending'">
|
||||
<field name="message_state" invisible="1"/>
|
||||
<field name="create_date" groups="base.group_no_one"/>
|
||||
<field name="name" string="Subject"/>
|
||||
<field name="partner_name"/>
|
||||
@@ -204,7 +204,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Jobs">
|
||||
<field name="partner_name" filter_domain="['|','|',('name','ilike',self),('partner_name','ilike',self),('email_from','ilike',self)]" string="Subject / Applicant"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_state" domain="[('message_state','=',True)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-document-new" string="New" domain="[('state','=','draft')]" help="All Initial Jobs"/>
|
||||
<filter icon="terp-camera_test" string="In Progress" domain="[('state','=','open')]" help="Open Jobs"/>
|
||||
|
||||
+48
-42
@@ -19,6 +19,8 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# FP Note: can we remove some dependencies ? Use lint
|
||||
|
||||
import ast
|
||||
import base64
|
||||
import dateutil.parser
|
||||
@@ -56,6 +58,9 @@ def mail_tools_to_email(text):
|
||||
def to_email(text):
|
||||
return mail_tools_to_email(text)
|
||||
|
||||
# FP Note: I propose to merge mail.message and mail.message.common
|
||||
# there is a conflict for the field parent_id
|
||||
# I don't understand the usage of mail.message.common
|
||||
class mail_message_common(osv.TransientModel):
|
||||
""" Common abstract class for holding the main attributes of a
|
||||
message object. It could be reused as parent model for any
|
||||
@@ -65,25 +70,6 @@ class mail_message_common(osv.TransientModel):
|
||||
model holds the basics of a message. For example, a wizard for writing
|
||||
emails should inherit from this class and not from mail.message."""
|
||||
|
||||
def get_body(self, cr, uid, ids, name, arg, context=None):
|
||||
""" get correct body version: body_html for html messages, and
|
||||
body_text for plain text messages
|
||||
"""
|
||||
result = dict.fromkeys(ids, '')
|
||||
for message in self.browse(cr, uid, ids, context=context):
|
||||
if message.content_subtype == 'html':
|
||||
result[message.id] = message.body_html
|
||||
else:
|
||||
result[message.id] = message.body_text
|
||||
return result
|
||||
|
||||
def search_body(self, cr, uid, obj, name, args, context=None):
|
||||
# will receive:
|
||||
# - obj: mail.message object
|
||||
# - name: 'body'
|
||||
# - args: [('body', 'ilike', 'blah')]
|
||||
return ['|', '&', ('content_subtype', '=', 'html'), ('body_html', args[0][1], args[0][2]), ('body_text', args[0][1], args[0][2])]
|
||||
|
||||
def get_record_name(self, cr, uid, ids, name, arg, context=None):
|
||||
result = dict.fromkeys(ids, '')
|
||||
for message in self.browse(cr, uid, ids, context=context):
|
||||
@@ -99,43 +85,41 @@ class mail_message_common(osv.TransientModel):
|
||||
if message.subject:
|
||||
name = '%s: ' % (message.subject)
|
||||
if message.body_text:
|
||||
name = '%s%s ' % (name, message.body_text[0:20])
|
||||
if message.date:
|
||||
name = '%s(%s)' % (name, message.date)
|
||||
name = name + message.body_text[0:20]
|
||||
res.append((message.id, name))
|
||||
return res
|
||||
|
||||
_name = 'mail.message.common'
|
||||
_rec_name = 'subject'
|
||||
_columns = {
|
||||
'subject': fields.char('Subject', size=512),
|
||||
'model': fields.char('Related Document Model', size=128, select=1),
|
||||
'res_id': fields.integer('Related Document ID', select=1),
|
||||
'record_name': fields.function(get_record_name, type='string',
|
||||
string='Message Record Name',
|
||||
help="Name get of the related document."),
|
||||
|
||||
'subject': fields.char('Subject', size=128),
|
||||
'date': fields.datetime('Date'),
|
||||
|
||||
# FP Note: I propose to remove these fields and put email in attachment as an option
|
||||
'email_from': fields.char('From', size=128, help='Message sender, taken from user preferences.'),
|
||||
'email_to': fields.char('To', size=256, help='Message recipients'),
|
||||
'email_to': fields.text('To', help='Message recipients'),
|
||||
'email_cc': fields.char('Cc', size=256, help='Carbon copy message recipients'),
|
||||
'email_bcc': fields.char('Bcc', size=256, help='Blind carbon copy message recipients'),
|
||||
'reply_to':fields.char('Reply-To', size=256, help='Preferred response address for the message'),
|
||||
'headers': fields.text('Message Headers', readonly=1,
|
||||
help="Full message headers, e.g. SMTP session headers (usually available on inbound messages only)"),
|
||||
'message_id': fields.char('Message-Id', size=256, help='Message unique identifier', select=1, readonly=1),
|
||||
'references': fields.text('References', help='Message references, such as identifiers of previous messages', readonly=1),
|
||||
'content_subtype': fields.char('Message content subtype', size=32,
|
||||
oldname="subtype", readonly=1,
|
||||
help="Type of message, usually 'html' or 'plain', used to select "\
|
||||
"plain-text or rich-text contents accordingly"),
|
||||
'body_text': fields.text('Text Contents', help="Plain-text version of the message"),
|
||||
'body_html': fields.html('Rich-text Contents', help="Rich-text/HTML version of the message"),
|
||||
'body': fields.function(get_body, fnct_search = search_body, type='text',
|
||||
string='Message Content', store=True,
|
||||
help="Content of the message. This content equals the body_text field "\
|
||||
"for plain-test messages, and body_html for rich-text/HTML "\
|
||||
"messages. This allows having one field if we want to access "\
|
||||
"the content matching the message content_subtype."),
|
||||
# END FP Note
|
||||
|
||||
'message_id': fields.char('Message-Id', size=256, help='Message unique identifier', select=1, readonly=1),
|
||||
'body': fields.text('Text Contents', help="Plain-text version of the message", required=True),
|
||||
|
||||
'parent_id': fields.many2one('mail.message.common', 'Parent Message',
|
||||
select=True, ondelete='set null',
|
||||
help="Parent message, used for displaying as threads with hierarchy"),
|
||||
@@ -158,6 +142,7 @@ class mail_message(osv.Model):
|
||||
_description = 'Mail Message (email, comment, notification)'
|
||||
_order = 'date desc'
|
||||
|
||||
# FP Note: can we remove these two methods ?
|
||||
def open_document(self, cr, uid, ids, context=None):
|
||||
""" Open the message related document. Note that only the document of
|
||||
ids[0] will be opened.
|
||||
@@ -196,7 +181,8 @@ class mail_message(osv.Model):
|
||||
'nodestroy': True
|
||||
})
|
||||
return action_data
|
||||
|
||||
# END FP Note
|
||||
|
||||
_columns = {
|
||||
'type': fields.selection([
|
||||
('email', 'email'),
|
||||
@@ -205,14 +191,17 @@ class mail_message(osv.Model):
|
||||
], 'Type',
|
||||
help="Message type: email for email message, notification for system "\
|
||||
"message, comment for other messages such as user replies"),
|
||||
# FP Note: ro be removed
|
||||
'partner_id': fields.many2one('res.partner', 'Related partner',
|
||||
help="Deprecated field. Use partner_ids instead."),
|
||||
# END FP Note
|
||||
|
||||
'partner_ids': fields.many2many('res.partner',
|
||||
'mail_message_destination_partner_rel',
|
||||
'message_id', 'partner_id', 'Destination partners',
|
||||
help="When sending emails through the social network composition wizard"\
|
||||
"you may choose to send a copy of the mail to partners."),
|
||||
'user_id': fields.many2one('res.users', 'Related User', readonly=1),
|
||||
'user_id': fields.many2one('res.users', 'Author', readonly=1),
|
||||
'attachment_ids': fields.many2many('ir.attachment', 'message_attachment_rel', 'message_id', 'attachment_id', 'Attachments'),
|
||||
'mail_server_id': fields.many2one('ir.mail_server', 'Outgoing mail server', readonly=1),
|
||||
'state': fields.selection([
|
||||
@@ -224,8 +213,12 @@ class mail_message(osv.Model):
|
||||
], 'Status', readonly=True),
|
||||
'auto_delete': fields.boolean('Auto Delete',
|
||||
help="Permanently delete this email after sending it, to save space"),
|
||||
|
||||
# FP Note: to be removed, in attachment if needed
|
||||
'original': fields.binary('Original', readonly=1,
|
||||
help="Original version of the message, as it was sent on the network"),
|
||||
# End FP Note
|
||||
|
||||
'parent_id': fields.many2one('mail.message', 'Parent Message',
|
||||
select=True, ondelete='set null',
|
||||
help="Parent message, used for displaying as threads with hierarchy"),
|
||||
@@ -246,7 +239,7 @@ class mail_message(osv.Model):
|
||||
if not cr.fetchone():
|
||||
cr.execute("""CREATE INDEX mail_message_model_res_id_idx ON mail_message (model, res_id)""")
|
||||
|
||||
def check(self, cr, uid, ids, mode, context=None, values=None):
|
||||
def check(self, cr, uid, ids, mode, context=None):
|
||||
"""Restricts the access to a mail.message, according to referred model
|
||||
"""
|
||||
if not ids:
|
||||
@@ -259,9 +252,6 @@ class mail_message(osv.Model):
|
||||
if not (rmod and rid):
|
||||
continue
|
||||
res_ids.setdefault(rmod,set()).add(rid)
|
||||
if values:
|
||||
if 'res_model' in values and 'res_id' in values:
|
||||
res_ids.setdefault(values['res_model'],set()).add(values['res_id'])
|
||||
|
||||
ima_obj = self.pool.get('ir.model.access')
|
||||
for model, mids in res_ids.items():
|
||||
@@ -272,8 +262,21 @@ class mail_message(osv.Model):
|
||||
self.pool.get(model).check_access_rule(cr, uid, mids, mode, context=context)
|
||||
|
||||
def create(self, cr, uid, values, context=None):
|
||||
self.check(cr, uid, [], mode='create', context=context, values=values)
|
||||
return super(mail_message, self).create(cr, uid, values, context)
|
||||
newid = super(mail_message, self).create(cr, uid, values, context)
|
||||
self.check(cr, uid, [newid], mode='create', context=context)
|
||||
|
||||
# notify all followers
|
||||
if values.get('model') and values.get('res_id'):
|
||||
notification_obj = self.pool.get('mail.notification')
|
||||
modobj = self.pool.get(values.get('model'))
|
||||
follower_notify = []
|
||||
for follower in modobj.follower_ids:
|
||||
if follower.id <> uid:
|
||||
follower_notify.append(follower.id)
|
||||
|
||||
self.pool.get('mail.notification').notify(cr, uid, follower_notify, newid, context=context)
|
||||
|
||||
return newid
|
||||
|
||||
def read(self, cr, uid, ids, fields_to_read=None, context=None, load='_classic_read'):
|
||||
self.check(cr, uid, ids, 'read', context=context)
|
||||
@@ -288,13 +291,16 @@ class mail_message(osv.Model):
|
||||
return super(mail_message,self).copy(cr, uid, id, default=default, context=context)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
self.check(cr, uid, ids, 'write', context=context, values=vals)
|
||||
return super(mail_message, self).write(cr, uid, ids, vals, context)
|
||||
result = super(mail_message, self).write(cr, uid, ids, vals, context)
|
||||
self.check(cr, uid, ids, 'write', context=context)
|
||||
return result
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
self.check(cr, uid, ids, 'unlink', context=context)
|
||||
return super(mail_message, self).unlink(cr, uid, ids, context)
|
||||
|
||||
# FP Note: do we need this method ?
|
||||
# We should just ask to create the message before scheduling it
|
||||
def schedule_with_attach(self, cr, uid, email_from, email_to, subject, body, model=False, type='email',
|
||||
email_cc=None, email_bcc=None, reply_to=False, partner_ids=None, attachments=None,
|
||||
message_id=False, references=False, res_id=False, content_subtype='plain',
|
||||
|
||||
@@ -65,3 +65,43 @@ class mail_notification(osv.osv):
|
||||
_defaults = {
|
||||
'read': False,
|
||||
}
|
||||
# Create notification in the wall of each user
|
||||
# Send by email the notification depending on the user preferences
|
||||
def notify(self, cr, uid, user_ids, msg_id, context=context):
|
||||
user_obj = self.pool.get('res.users')
|
||||
msg_obj = self.pool.get('mail.message')
|
||||
msg = msg_obj.browse(cr, uid, msg_id, context=context)
|
||||
|
||||
towrite = {
|
||||
'email_to': msg.email_to,
|
||||
'subject': msg.subject
|
||||
}
|
||||
for user in user_obj.browse(cr, uid, user_ids, context=context):
|
||||
notification_obj.create(cr, uid, {
|
||||
'user_id': user.id,
|
||||
'message_id': msg_id
|
||||
}, context=context)
|
||||
if user.notification_email_pref=='none' or not user.user_email:
|
||||
continue
|
||||
|
||||
if user.notification_email_pref=='comment' and msg.type in ('email','comment'):
|
||||
continue
|
||||
|
||||
if not msg.email_from:
|
||||
current_user = res_users_obj.browse(cr, uid, uid, context=context)
|
||||
towrite['email_from'] = current_user.user_email
|
||||
|
||||
towrite['state'] = 'outgoing'
|
||||
if not towrite.get('email_to', False):
|
||||
towrite['email_to'] = email_to
|
||||
else:
|
||||
if email_to not in towrite['email_to']:
|
||||
towrite['email_to'] = towrite['email_to'] + ', ' + email_to
|
||||
|
||||
if towrite.get('subject', False):
|
||||
towrite['subject'] = msg.name_get(cr, uid, [msg.id], context=context)[0][1]
|
||||
if towrite.get('state', False):
|
||||
msg_obj.write(cr, uid, [msg.id], towrite, context=context)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
+101
-241
@@ -68,41 +68,52 @@ class mail_thread(osv.Model):
|
||||
'''
|
||||
_name = 'mail.thread'
|
||||
_description = 'Email Thread'
|
||||
# TODO: may be we should make it _inherit ir.needaction
|
||||
|
||||
def _get_message_ids(self, cr, uid, ids, name, args, context=None):
|
||||
def _get_message_data(self, cr, uid, ids, name, args, context=None):
|
||||
res = {}
|
||||
for id in ids:
|
||||
message_ids = self.message_search(cr, uid, [id], context=context)
|
||||
subscriber_ids = self.message_get_subscribers(cr, uid, [id], context=context)
|
||||
res[id] = {
|
||||
'message_ids': message_ids,
|
||||
'message_summary': "<span><span class='oe_e'>9</span> %d</span> <span><span class='oe_e'>+</span> %d</span>" % (len(message_ids), len(subscriber_ids)),
|
||||
'message_state': False,
|
||||
'message_Summary': ''
|
||||
}
|
||||
nobj = self.pool.get('mail.notification')
|
||||
notifs = nobj.search(cr, uid, [
|
||||
('user_id','=',uid),
|
||||
('message_id.res_id','in', ids),
|
||||
('message_id.model','=', self._name),
|
||||
('read','=',False)
|
||||
], context=context)
|
||||
for notif in nobj.browse(cr, uid, nids, context=context):
|
||||
res[notif.message_id.id]['message_state'] = True
|
||||
|
||||
for thread in self.browse(cr, uid, ids, context=context):
|
||||
message_ids = thread.message_ids
|
||||
subscriber_ids = thread.message_follower_ids
|
||||
res[id]['message_summary'] = "<span><span class='oe_e'>9</span> %d</span> <span><span class='oe_e'>+</span> %d</span>" % (len(message_ids), len(subscriber_ids)),
|
||||
return res
|
||||
|
||||
def _search_message_ids(self, cr, uid, obj, name, args, context=None):
|
||||
msg_obj = self.pool.get('mail.message')
|
||||
msg_ids = msg_obj.search(cr, uid, ['&', ('res_id', 'in', args[0][2]), ('model', '=', self._name)], context=context)
|
||||
return [('id', 'in', msg_ids)]
|
||||
# FP Note: todo
|
||||
def _search_state(self, tobj, cr, uid, obj=None, name=None, domain=None, context=None):
|
||||
return [('id','in',[])]
|
||||
|
||||
_columns = {
|
||||
'message_ids': fields.function(_get_message_ids,
|
||||
fnct_search=_search_message_ids,
|
||||
type='one2many', obj='mail.message', _fields_id = 'res_id',
|
||||
string='Temp messages', multi="_get_message_ids",
|
||||
help="Functional field holding messages related to the current document."),
|
||||
'message_state': fields.boolean('Read',
|
||||
help="When checked, new messages require your attention."),
|
||||
'message_summary': fields.function(_get_message_ids, method=True,
|
||||
type='text', string='Summary', multi="_get_message_ids",
|
||||
'message_follower_ids': fields.one2many('mail.subscription', 'res_id',
|
||||
domain=lambda self: [('res_model','=',self._name)],
|
||||
string='Followers')
|
||||
'message_ids': fields.one2many('mail.message', 'res_id',
|
||||
domain=lambda self: [('model','=',self._name)],
|
||||
string='Related Messages',
|
||||
help="All messages related to the current document."),
|
||||
'message_state': fields.function(_get_message_data, fnct_search=_search_state, 'Message Read',
|
||||
help="When checked, new messages require your attention.",
|
||||
multi="_get_message_data"),
|
||||
'message_summary': fields.function(_get_message_data, method=True,
|
||||
type='text', string='Summary', multi="_get_message_data",
|
||||
help="Holds the Chatter summary (number of messages, ...). "\
|
||||
"This summary is directly in html format in order to "\
|
||||
"be inserted in kanban views."),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'message_state': True,
|
||||
}
|
||||
|
||||
#------------------------------------------------------
|
||||
# Automatic subscription when creating/reading
|
||||
@@ -111,19 +122,9 @@ class mail_thread(osv.Model):
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
"""Automatically subscribe the creator """
|
||||
thread_id = super(mail_thread, self).create(cr, uid, vals, context=context)
|
||||
if thread_id:
|
||||
self.message_subscribe(cr, uid, [thread_id], [uid], context=context)
|
||||
self.message_subscribe(cr, uid, [thread_id], [uid], context=context)
|
||||
return thread_id
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
"""Automatically subscribe the writer"""
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
write_res = super(mail_thread, self).write(cr, uid, ids, vals, context=context);
|
||||
if write_res:
|
||||
self.message_subscribe(cr, uid, ids, [uid], context=context)
|
||||
return write_res;
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
"""Override unlink, to automatically delete
|
||||
- subscriptions
|
||||
@@ -140,7 +141,6 @@ class mail_thread(osv.Model):
|
||||
# delete messages and notifications
|
||||
msg_to_del_ids = msg_obj.search(cr, uid, [('model', '=', self._name), ('res_id', 'in', ids)], context=context)
|
||||
msg_obj.unlink(cr, uid, msg_to_del_ids, context=context)
|
||||
|
||||
return super(mail_thread, self).unlink(cr, uid, ids, context=context)
|
||||
|
||||
#------------------------------------------------------
|
||||
@@ -153,73 +153,17 @@ class mail_thread(osv.Model):
|
||||
- automatically subscribe the message writer
|
||||
- push the message to subscribed users
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
context = context or {}
|
||||
message_obj = self.pool.get('mail.message')
|
||||
notification_obj = self.pool.get('mail.notification')
|
||||
|
||||
# automatically subscribe the writer of the message
|
||||
if vals.get('user_id'):
|
||||
self.message_subscribe(cr, uid, [thread_id], [vals['user_id']], context=context)
|
||||
|
||||
# create message
|
||||
vals['model'] = self._name
|
||||
vals['res_id'] = thread_id
|
||||
msg_id = message_obj.create(cr, uid, vals, context=context)
|
||||
|
||||
# Set as unread if writer is not the document responsible
|
||||
self.message_create_set_unread(cr, uid, [thread_id], context=context)
|
||||
|
||||
# special: if install mode, do not push demo data
|
||||
if context.get('install_mode', False):
|
||||
return msg_id
|
||||
|
||||
# get users that will get a notification pushed
|
||||
user_to_push_ids = self.message_get_user_ids_to_notify(cr, uid, [thread_id], vals, context=context)
|
||||
for id in user_to_push_ids:
|
||||
notification_obj.create(cr, uid, {'user_id': id, 'message_id': msg_id}, context=context)
|
||||
|
||||
# create the email to send
|
||||
self.message_create_notify_by_email(cr, uid, vals, user_to_push_ids, context=context)
|
||||
|
||||
return msg_id
|
||||
|
||||
def message_get_user_ids_to_notify(self, cr, uid, thread_ids, new_msg_vals, context=None):
|
||||
# get body
|
||||
body = new_msg_vals.get('body_html', '') if new_msg_vals.get('content_subtype') == 'html' else new_msg_vals.get('body_text', '')
|
||||
|
||||
# get subscribers
|
||||
notif_user_ids = self.message_get_subscribers(cr, uid, thread_ids, context=context)
|
||||
|
||||
# add users requested via parsing message (@login)
|
||||
notif_user_ids += self.message_parse_users(cr, uid, body, context=context)
|
||||
|
||||
# add users requested to perform an action (need_action mechanism)
|
||||
if hasattr(self, 'get_needaction_user_ids') and self._columns.get('user_id'):
|
||||
user_ids_dict = self.get_needaction_user_ids(cr, uid, thread_ids, context=context)
|
||||
for id, user_ids in user_ids_dict.iteritems():
|
||||
notif_user_ids += user_ids
|
||||
|
||||
# add users notified of the parent messages (because: if parent message contains @login, login must receive the replies)
|
||||
if new_msg_vals.get('parent_id'):
|
||||
notif_obj = self.pool.get('mail.notification')
|
||||
parent_notif_ids = notif_obj.search(cr, uid, [('message_id', '=', new_msg_vals.get('parent_id'))], context=context)
|
||||
parent_notifs = notif_obj.read(cr, uid, parent_notif_ids, context=context)
|
||||
notif_user_ids += [parent_notif['user_id'][0] for parent_notif in parent_notifs]
|
||||
|
||||
# remove duplicate entries
|
||||
notif_user_ids = list(set(notif_user_ids))
|
||||
return notif_user_ids
|
||||
|
||||
def message_parse_users(self, cr, uid, string, context=None):
|
||||
"""Parse message content
|
||||
- if find @login -(^|\s)@((\w|@|\.)*)-: returns the related ids
|
||||
this supports login that are emails (such as @raoul@grobedon.net)
|
||||
"""
|
||||
regex = re.compile('(^|\s)@((\w|@|\.)*)')
|
||||
login_lst = [item[1] for item in regex.findall(string)]
|
||||
if not login_lst: return []
|
||||
user_ids = self.pool.get('res.users').search(cr, uid, [('login', 'in', login_lst)], context=context)
|
||||
return user_ids
|
||||
def _needaction_domain_get(self, cr, uid, context={}):
|
||||
if self._needaction:
|
||||
return [('message_state','=',True)]
|
||||
return []
|
||||
|
||||
#------------------------------------------------------
|
||||
# Generic message api
|
||||
@@ -241,15 +185,15 @@ class mail_thread(osv.Model):
|
||||
headers=None, message_id=False, references=None,
|
||||
attachments=None, original=None, context=None):
|
||||
""" Creates a new mail.message through message_create. The new message
|
||||
is attached to the current mail.thread, containing all the details
|
||||
passed as parameters. All attachments will be attached to the
|
||||
is attached to the current mail.thread, containing all the details
|
||||
passed as parameters. All attachments will be attached to the
|
||||
thread record as well as to the actual message.
|
||||
|
||||
|
||||
This method calls message_create that will handle management of
|
||||
subscription and notifications, and effectively create the message.
|
||||
|
||||
|
||||
If ``email_from`` is not set or ``type`` not set as 'email',
|
||||
a note message is created (comment or system notification),
|
||||
a note message is created (comment or system notification),
|
||||
without the usual envelope attributes (sender, recipients, etc.).
|
||||
|
||||
:param threads: list of thread ids, or list of browse_records
|
||||
@@ -454,11 +398,11 @@ class mail_thread(osv.Model):
|
||||
"""
|
||||
return ['&', ('res_id', 'in', ids), ('model', '=', self._name)]
|
||||
|
||||
def message_search(self, cr, uid, ids, fetch_ancestors=False, ancestor_ids=None,
|
||||
def message_search(self, cr, uid, ids, fetch_ancestors=False, ancestor_ids=None,
|
||||
limit=100, offset=0, domain=None, count=False, context=None):
|
||||
""" OpenChatter feature: return thread messages ids according to the
|
||||
search domain given by ``message_search_get_domain``.
|
||||
|
||||
|
||||
It is possible to add in the search the parent of messages by
|
||||
setting the fetch_ancestors flag to True. In that case, using
|
||||
the parent_id relationship, the method returns the id list according
|
||||
@@ -466,19 +410,19 @@ class mail_thread(osv.Model):
|
||||
that will add to the list the ancestors ids. The search is limited
|
||||
to parent messages having an id in ancestor_ids or having
|
||||
parent_id set to False.
|
||||
|
||||
|
||||
If ``count==True``, the number of ids is returned instead of the
|
||||
id list. The count is done by hand instead of passing it as an
|
||||
id list. The count is done by hand instead of passing it as an
|
||||
argument to the search call because we might want to perform
|
||||
a research including parent messages until some ancestor_ids.
|
||||
|
||||
:param fetch_ancestors: performs an ascended search; will add
|
||||
|
||||
:param fetch_ancestors: performs an ascended search; will add
|
||||
to fetched msgs all their parents until
|
||||
ancestor_ids
|
||||
:param ancestor_ids: used when fetching ancestors
|
||||
:param domain: domain to add to the search; especially child_of
|
||||
is interesting when dealing with threaded display.
|
||||
Note that the added domain is anded with the
|
||||
Note that the added domain is anded with the
|
||||
default domain.
|
||||
:param limit, offset, count, context: as usual
|
||||
"""
|
||||
@@ -488,10 +432,10 @@ class mail_thread(osv.Model):
|
||||
message_obj = self.pool.get('mail.message')
|
||||
message_res = message_obj.search(cr, uid, search_domain, limit=limit, offset=offset, count=count, context=context)
|
||||
if not count and fetch_ancestors:
|
||||
message_res += self._message_search_ancestor_ids(cr, uid, ids, message_res, ancestor_ids, context=context)
|
||||
message_res += self._message_search_ancestor_ids(cr, uid, ids, message_res, ancestor_ids, context=context)
|
||||
return message_res
|
||||
|
||||
def message_read(self, cr, uid, ids, fetch_ancestors=False, ancestor_ids=None,
|
||||
def message_read(self, cr, uid, ids, fetch_ancestors=False, ancestor_ids=None,
|
||||
limit=100, offset=0, domain=None, context=None):
|
||||
""" OpenChatter feature: read the messages related to some threads.
|
||||
This method is used mainly the Chatter widget, to directly have
|
||||
@@ -508,18 +452,18 @@ class mail_thread(osv.Model):
|
||||
|
||||
ids = map_id_to_name.keys()
|
||||
names = self.pool.get('ir.attachment').name_get(cr, uid, ids, context=context)
|
||||
|
||||
|
||||
# convert the list of tuples into a dictionnary
|
||||
for name in names:
|
||||
for name in names:
|
||||
map_id_to_name[name[0]] = name[1]
|
||||
|
||||
|
||||
# give corresponding ids and names to each message
|
||||
for msg in messages:
|
||||
msg["attachments"] = []
|
||||
|
||||
|
||||
for attach_id in msg["attachment_ids"]:
|
||||
msg["attachments"].append({'id': attach_id, 'name': map_id_to_name[attach_id]})
|
||||
|
||||
|
||||
# Set the threads as read
|
||||
self.message_check_and_set_read(cr, uid, ids, context=context)
|
||||
# Sort and return the messages
|
||||
@@ -530,7 +474,7 @@ class mail_thread(osv.Model):
|
||||
limit=100, offset=0, msg_search_domain=[], context=None):
|
||||
""" OpenChatter: wall: get the pushed notifications and used them
|
||||
to fetch messages to display on the wall.
|
||||
|
||||
|
||||
:param fetch_ancestors: performs an ascended search; will add
|
||||
to fetched msgs all their parents until
|
||||
ancestor_ids
|
||||
@@ -577,11 +521,11 @@ class mail_thread(osv.Model):
|
||||
Multiple values may be returned, if a message had multiple
|
||||
recipients matching existing mail.aliases, for example.
|
||||
|
||||
The following heuristics are used, in this order:
|
||||
The following heuristics are used, in this order:
|
||||
1. If the message replies to an existing thread_id, and
|
||||
properly contains the thread model in the 'In-Reply-To'
|
||||
header, use this model/thread_id pair, and ignore
|
||||
custom_value (not needed as no creation will take place)
|
||||
custom_value (not needed as no creation will take place)
|
||||
2. Look for a mail.alias entry matching the message
|
||||
recipient, and use the corresponding model, thread_id,
|
||||
custom_values and user_id.
|
||||
@@ -617,7 +561,7 @@ class mail_thread(osv.Model):
|
||||
_logger.debug('Routing mail with Message-Id %s: direct reply to model: %s, thread_id: %s, custom_values: %s, uid: %s',
|
||||
message_id, model, thread_id, custom_values, uid)
|
||||
return [(model, thread_id, custom_values, uid)]
|
||||
|
||||
|
||||
# 2. Look for a matching mail.alias entry
|
||||
# Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values
|
||||
# for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value.
|
||||
@@ -640,7 +584,7 @@ class mail_thread(osv.Model):
|
||||
eval(alias.alias_defaults), user_id))
|
||||
_logger.debug('Routing mail with Message-Id %s: direct alias match: %r', message_id, routes)
|
||||
return routes
|
||||
|
||||
|
||||
# 3. Fallback to the provided parameters, if they work
|
||||
model_pool = self.pool.get(model)
|
||||
if not thread_id:
|
||||
@@ -664,8 +608,8 @@ class mail_thread(osv.Model):
|
||||
thread_id=None, context=None):
|
||||
"""Process an incoming RFC2822 email message, relying on
|
||||
``mail.message.parse()`` for the parsing operation,
|
||||
and ``message_route()`` to figure out the target model.
|
||||
|
||||
and ``message_route()`` to figure out the target model.
|
||||
|
||||
Once the target model is known, its ``message_new`` method
|
||||
is called with the new message (if the thread record did not exist)
|
||||
or its ``message_update`` method (if it did). Finally,
|
||||
@@ -706,10 +650,10 @@ class mail_thread(osv.Model):
|
||||
thread_id, custom_values,
|
||||
context=context)
|
||||
msg = self.pool.get('mail.message').parse_message(msg_txt, save_original=save_original, context=context)
|
||||
msg['state'] = 'received'
|
||||
msg['state'] = 'received'
|
||||
if strip_attachments and 'attachments' in msg:
|
||||
del msg['attachments']
|
||||
for model, thread_id, custom_values, user_id in routes:
|
||||
for model, thread_id, custom_values, user_id in routes:
|
||||
if self._name != model:
|
||||
context.update({'thread_model': model})
|
||||
model_pool = self.pool.get(model)
|
||||
@@ -720,7 +664,7 @@ class mail_thread(osv.Model):
|
||||
model_pool.message_update(cr, user_id, [thread_id], msg, context=context)
|
||||
else:
|
||||
thread_id = model_pool.message_new(cr, user_id, msg, custom_values, context=context)
|
||||
|
||||
|
||||
# Forward the email to other followers
|
||||
self.message_forward(cr, uid, model, [thread_id], msg_txt, context=context)
|
||||
model_pool.message_mark_as_unread(cr, uid, [thread_id], context=context)
|
||||
@@ -903,17 +847,8 @@ class mail_thread(osv.Model):
|
||||
# Subscription mechanism
|
||||
#------------------------------------------------------
|
||||
|
||||
def message_get_subscribers(self, cr, uid, ids, context=None):
|
||||
""" Returns the current document followers. Basically this method
|
||||
checks in mail.subscription for entries with matching res_model,
|
||||
res_id.
|
||||
This method can be overriden to add implicit subscribers, such
|
||||
as project managers, by adding their user_id to the list of
|
||||
ids returned by this method.
|
||||
"""
|
||||
subscr_obj = self.pool.get('mail.subscription')
|
||||
subscr_ids = subscr_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', 'in', ids)], context=context)
|
||||
return [sub['user_id'][0] for sub in subscr_obj.read(cr, uid, subscr_ids, ['user_id'], context=context)]
|
||||
# FP Note: replaced by message_follower_ids
|
||||
# def message_get_subscribers(self, cr, uid, ids, context=None):
|
||||
|
||||
def message_read_subscribers(self, cr, uid, ids, fields=['id', 'name', 'image_small'], context=None):
|
||||
""" Returns the current document followers as a read result. Used
|
||||
@@ -926,7 +861,7 @@ class mail_thread(osv.Model):
|
||||
def message_is_subscriber(self, cr, uid, ids, user_id = None, context=None):
|
||||
""" Check if uid or user_id (if set) is a subscriber to the current
|
||||
document.
|
||||
|
||||
|
||||
:param user_id: if set, check is done on user_id; if not set
|
||||
check is done on uid
|
||||
"""
|
||||
@@ -937,7 +872,7 @@ class mail_thread(osv.Model):
|
||||
|
||||
def message_subscribe(self, cr, uid, ids, user_ids = None, context=None):
|
||||
""" Subscribe the user (or user_ids) to the current document.
|
||||
|
||||
|
||||
:param user_ids: a list of user_ids; if not set, subscribe
|
||||
uid instead
|
||||
"""
|
||||
@@ -953,7 +888,7 @@ class mail_thread(osv.Model):
|
||||
|
||||
def message_unsubscribe(self, cr, uid, ids, user_ids = None, context=None):
|
||||
""" Unsubscribe the user (or user_ids) from the current document.
|
||||
|
||||
|
||||
:param user_ids: a list of user_ids; if not set, subscribe
|
||||
uid instead
|
||||
"""
|
||||
@@ -972,85 +907,6 @@ class mail_thread(osv.Model):
|
||||
# Notification API
|
||||
#------------------------------------------------------
|
||||
|
||||
def message_create_notify_by_email(self, cr, uid, new_msg_values, user_to_notify_ids, context=None):
|
||||
""" When creating a new message and pushing notifications, emails
|
||||
must be send if users have chosen to receive notifications
|
||||
by email via the notification_email_pref field.
|
||||
|
||||
``notification_email_pref`` can have 3 values :
|
||||
- all: receive all notification by email (for example for shared
|
||||
users)
|
||||
- to_me: messages send directly to me (@login, messages on res.users)
|
||||
- never: never receive notifications
|
||||
Note that an user should never receive notifications for messages
|
||||
he has created.
|
||||
|
||||
:param new_msg_values: dictionary of message values, those that
|
||||
are given to the create method
|
||||
:param user_to_notify_ids: list of user_ids, user that will
|
||||
receive a notification on their Wall
|
||||
"""
|
||||
message_obj = self.pool.get('mail.message')
|
||||
res_users_obj = self.pool.get('res.users')
|
||||
body = new_msg_values.get('body_html', '') if new_msg_values.get('content_subtype') == 'html' else new_msg_values.get('body_text', '')
|
||||
|
||||
# remove message writer
|
||||
if user_to_notify_ids.count(new_msg_values.get('user_id')) > 0:
|
||||
user_to_notify_ids.remove(new_msg_values.get('user_id'))
|
||||
|
||||
# get user_ids directly asked
|
||||
user_to_push_from_parse_ids = self.message_parse_users(cr, uid, body, context=context)
|
||||
|
||||
# try to find an email_to
|
||||
email_to = ''
|
||||
for user in res_users_obj.browse(cr, uid, user_to_notify_ids, context=context):
|
||||
if not user.notification_email_pref == 'all' and \
|
||||
not (user.notification_email_pref == 'to_me' and user.id in user_to_push_from_parse_ids):
|
||||
continue
|
||||
if not user.user_email:
|
||||
continue
|
||||
email_to = '%s, %s' % (email_to, user.user_email)
|
||||
email_to = email_to.lstrip(', ')
|
||||
|
||||
# did not find any email address: not necessary to create an email
|
||||
if not email_to:
|
||||
return
|
||||
|
||||
# try to find an email_from
|
||||
current_user = res_users_obj.browse(cr, uid, [uid], context=context)[0]
|
||||
email_from = new_msg_values.get('email_from')
|
||||
if not email_from:
|
||||
email_from = current_user.user_email
|
||||
|
||||
# get email content, create it (with mail_message.create)
|
||||
email_values = self.message_create_notify_get_email_dict(cr, uid, new_msg_values, email_from, email_to, context)
|
||||
email_id = message_obj.create(cr, uid, email_values, context=context)
|
||||
return email_id
|
||||
|
||||
def message_create_notify_get_email_dict(self, cr, uid, new_msg_values, email_from, email_to, context=None):
|
||||
values = dict(new_msg_values)
|
||||
|
||||
body_html = new_msg_values.get('body_html', '')
|
||||
if body_html:
|
||||
body_html += '\n\n----------\nThis email was send automatically by OpenERP, because you have subscribed to a document.'
|
||||
body_text = new_msg_values.get('body_text', '')
|
||||
if body_text:
|
||||
body_text += '\n\n----------\nThis email was send automatically by OpenERP, because you have subscribed to a document.'
|
||||
values.update({
|
||||
'type': 'email',
|
||||
'state': 'outgoing',
|
||||
'email_from': email_from,
|
||||
'email_to': email_to,
|
||||
'subject': 'New message',
|
||||
'content_subtype': new_msg_values.get('content_subtype', 'plain'),
|
||||
'body_html': body_html,
|
||||
'body_text': body_text,
|
||||
'auto_delete': True,
|
||||
'res_model': '',
|
||||
'res_id': False,
|
||||
})
|
||||
return values
|
||||
|
||||
def message_remove_pushed_notifications(self, cr, uid, ids, msg_ids, remove_childs=True, context=None):
|
||||
notif_obj = self.pool.get('mail.notification')
|
||||
msg_obj = self.pool.get('mail.message')
|
||||
@@ -1065,33 +921,37 @@ class mail_thread(osv.Model):
|
||||
# Thread_state
|
||||
#------------------------------------------------------
|
||||
|
||||
def message_create_set_unread(self, cr, uid, ids, context=None):
|
||||
""" When creating a new message, set as unread if uid is not the
|
||||
object responsible. """
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
if obj.message_state and self._columns.get('user_id') and (not obj.user_id or obj.user_id.id != uid):
|
||||
self.message_mark_as_unread(cr, uid, [obj.id], context=context)
|
||||
# FP Note: should be removed ?
|
||||
# def message_check_and_set_unread(self, cr, uid, ids, context=None):
|
||||
# """ Set unread if uid is the object responsible or if the object has
|
||||
# no responsible. """
|
||||
# for obj in self.browse(cr, uid, ids, context=context):
|
||||
# if obj.message_state and self._columns.get('user_id') and (not obj.user_id or obj.user_id.id == uid):
|
||||
# self.message_mark_as_unread(cr, uid, [obj.id], context=context)
|
||||
|
||||
def message_check_and_set_unread(self, cr, uid, ids, context=None):
|
||||
""" Set unread if uid is the object responsible or if the object has
|
||||
no responsible. """
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
if obj.message_state and self._columns.get('user_id') and (not obj.user_id or obj.user_id.id == uid):
|
||||
self.message_mark_as_unread(cr, uid, [obj.id], context=context)
|
||||
# FP Note: should be removed ?
|
||||
# def message_check_and_set_read(self, cr, uid, ids, context=None):
|
||||
# """ Set read if uid is the object responsible. """
|
||||
# for obj in self.browse(cr, uid, ids, context=context):
|
||||
# if not obj.message_state and self._columns.get('user_id') and obj.user_id and obj.user_id.id == uid:
|
||||
# self.message_mark_as_read(cr, uid, [obj.id], context=context)
|
||||
|
||||
def message_mark_as_unread(self, cr, uid, ids, context=None):
|
||||
""" Set as unread. """
|
||||
return self.write(cr, uid, ids, {'message_state': False}, context=context)
|
||||
|
||||
def message_check_and_set_read(self, cr, uid, ids, context=None):
|
||||
""" Set read if uid is the object responsible. """
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
if not obj.message_state and self._columns.get('user_id') and obj.user_id and obj.user_id.id == uid:
|
||||
self.message_mark_as_read(cr, uid, [obj.id], context=context)
|
||||
|
||||
# FP Note: this should be a invert function on message_state field
|
||||
def message_mark_as_read(self, cr, uid, ids, context=None):
|
||||
""" Set as read. """
|
||||
return self.write(cr, uid, ids, {'message_state': True}, context=context)
|
||||
|
||||
def message_mark_as_unread(self, cr, uid, ids, context=None):
|
||||
""" Set as unread. """
|
||||
notobj = self.pool.get('mail.notification')
|
||||
cr.execute('''
|
||||
update mail_notification set
|
||||
read=true
|
||||
where
|
||||
message_id in (select id from mail_message where res_id in %s and model=%s)
|
||||
user_id = %s
|
||||
''', (ids, self._name, uid)
|
||||
return True
|
||||
# END FP note
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -41,8 +41,7 @@ class res_users(osv.osv):
|
||||
_columns = {
|
||||
'notification_email_pref': fields.selection([
|
||||
('all', 'All feeds'),
|
||||
('comments', 'Only comments'),
|
||||
('to_me', 'Only when sent directly to me'),
|
||||
('comment', 'Comments and emails'),
|
||||
('none', 'Never')
|
||||
], 'Receive Feeds by Email', required=True,
|
||||
help="Choose in which case you want to receive an email when you "\
|
||||
|
||||
@@ -574,8 +574,8 @@
|
||||
<field name="name">mrp.production.tree</field>
|
||||
<field name="model">mrp.production</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree fonts="bold:needaction_pending==True" colors="blue:state in ('draft','confirmed');red:date_planned<current_date and state not in ('done','cancel');black:date_planned>=current_date;gray:state in ('done','cancel') " string="Manufacturing Orders">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<tree fonts="bold:message_state==True" colors="blue:state in ('draft','confirmed');red:date_planned<current_date and state not in ('done','cancel');black:date_planned>=current_date;gray:state in ('done','cancel') " string="Manufacturing Orders">
|
||||
<field name="message_state" invisible="1"/>
|
||||
<field name="name"/>
|
||||
<field name="date_planned"/>
|
||||
<field name="product_id"/>
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Project">
|
||||
<field name="complete_name" string="Project Name"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_state" domain="[('message_state','=',True)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-check" string="Open" name="Current" domain="[('state', '=','open')]" help="Open Projects"/>
|
||||
<filter icon="gtk-media-pause" string="Pending" name="Pending" domain="[('state', '=','pending')]" help="Pending Projects"/>
|
||||
@@ -184,9 +184,9 @@
|
||||
<field name="model">project.project</field>
|
||||
<field name="field_parent">child_ids</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree fonts="bold:needaction_pending==True" colors="red:date and (date<current_date) and (state == 'open');blue:state in ('draft','pending');grey: state in ('close','cancelled')" string="Projects">
|
||||
<tree fonts="bold:message_state==True" colors="red:date and (date<current_date) and (state == 'open');blue:state in ('draft','pending');grey: state in ('close','cancelled')" string="Projects">
|
||||
<field name="sequence" invisible="1"/>
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<field name="message_state" invisible="1"/>
|
||||
<field name="date" invisible="1"/>
|
||||
<field name="name" string="Project Name"/>
|
||||
<field name="user_id" string="Project Manager"/>
|
||||
@@ -504,7 +504,7 @@
|
||||
<field name="remaining_hours" sum="Remaining Time" groups="project.group_time_work_estimation_tasks"/>
|
||||
<field name="date_deadline"/>
|
||||
<field name="message_summary"/>
|
||||
<field name="needaction_pending"/>
|
||||
<field name="message_state"/>
|
||||
<field name="categ_ids"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
@@ -569,8 +569,8 @@
|
||||
<field name="model">project.task</field>
|
||||
<field eval="2" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<tree fonts="bold:needaction_pending==True" colors="grey:state in ('cancelled','done');blue:state == 'pending';red:date_deadline and (date_deadline<current_date) and (state in ('draft','pending','open'))" string="Tasks">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<tree fonts="bold:message_state==True" colors="grey:state in ('cancelled','done');blue:state == 'pending';red:date_deadline and (date_deadline<current_date) and (state in ('draft','pending','open'))" string="Tasks">
|
||||
<field name="message_state" invisible="1"/>
|
||||
<field name="sequence" invisible="not context.get('seq_visible', False)"/>
|
||||
<field name="name"/>
|
||||
<field name="project_id" icon="gtk-indent" invisible="context.get('user_invisible', False)"/>
|
||||
@@ -630,7 +630,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Tasks">
|
||||
<field name="name" string="Tasks"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_state" domain="[('message_state','=',True)]"/>
|
||||
<separator/>
|
||||
<filter name="draft" string="New" domain="[('state','=','draft')]" help="New Tasks" icon="terp-check"/>
|
||||
<filter name="open" string="In Progress" domain="[('state','=','open')]" help="In Progress Tasks" icon="terp-camera_test"/>
|
||||
|
||||
@@ -169,8 +169,8 @@
|
||||
<field name="name">Project Issue Tracker Tree</field>
|
||||
<field name="model">project.issue</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Issue Tracker Tree" fonts="bold:needaction_pending==True" colors="black:state=='open';blue:state=='pending';grey:state in ('cancel', 'done')">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<tree string="Issue Tracker Tree" fonts="bold:message_state==True" colors="black:state=='open';blue:state=='pending';grey:state in ('cancel', 'done')">
|
||||
<field name="message_state" invisible="1"/>
|
||||
<field name="id"/>
|
||||
<field name="create_date" groups="base.group_no_one"/>
|
||||
<field name="name"/>
|
||||
@@ -195,7 +195,7 @@
|
||||
<search string="Issue Tracker Search">
|
||||
<field name="name" string="Issue" filter_domain="['|', '|',('partner_id','ilike',self),('email_from','ilike',self),('name','ilike',self)]"/>
|
||||
<field name="id"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_state" domain="[('message_state','=',True)]"/>
|
||||
<separator/>
|
||||
<filter string="New" icon="terp-document-new" domain="[('state','=','draft')]" help="New Issues"/>
|
||||
<filter string="To Do" domain="[('state','=','open')]" help="To Do Issues" icon="terp-check"/>
|
||||
@@ -309,9 +309,9 @@
|
||||
<field name="name">Project Issue- Feature Tracker Tree</field>
|
||||
<field name="model">project.issue</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Feature Tracker Tree" fonts="bold:needaction_pending==True" colors="red:state=='open';black:state in ('draft', 'cancel','done','pending')">
|
||||
<tree string="Feature Tracker Tree" fonts="bold:message_state==True" colors="red:state=='open';black:state in ('draft', 'cancel','done','pending')">
|
||||
<field name="id"/>
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<field name="message_state" invisible="1"/>
|
||||
<field name="name" string="Feature description"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="priority" string="Priority"/>
|
||||
|
||||
@@ -298,7 +298,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Purchase Order">
|
||||
<field name="name" string="Reference"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_state" domain="[('message_state','=',True)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-document-new" name="draft" string="Quotations" domain="[('state','=','draft')]" help="Purchase orders which are in draft state"/>
|
||||
<filter icon="terp-check" name="approved" string="Purchase Orders" domain="[('state','not in',('draft','cancel'))]" help="Approved purchase orders"/>
|
||||
@@ -323,8 +323,8 @@
|
||||
<field name="name">purchase.order.tree</field>
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree fonts="bold:needaction_pending==True" colors="grey:state=='cancel';blue:state in ('wait','confirmed');red:state in ('except_invoice','except_picking')" string="Purchase Order">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<tree fonts="bold:message_state==True" colors="grey:state=='cancel';blue:state in ('wait','confirmed');red:state in ('except_invoice','except_picking')" string="Purchase Order">
|
||||
<field name="message_state" invisible="1"/>
|
||||
<field name="name" string="Reference"/>
|
||||
<field name="date_order" />
|
||||
<field name="partner_id"/>
|
||||
|
||||
@@ -111,8 +111,8 @@
|
||||
<field name="name">purchase.requisition.tree</field>
|
||||
<field name="model">purchase.requisition</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree fonts="bold:needaction_pending==True" colors="grey:state == 'cancel';red:date_end and date_end<current_date;black:date_end>current_date;" string="Purchase Requisition">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<tree fonts="bold:message_state==True" colors="grey:state == 'cancel';red:date_end and date_end<current_date;black:date_end>current_date;" string="Purchase Requisition">
|
||||
<field name="message_state" invisible="1"/>
|
||||
<field name="name"/>
|
||||
<field name="date_start"/>
|
||||
<field name="user_id"/>
|
||||
|
||||
@@ -133,8 +133,8 @@
|
||||
<field name="model">sale.order</field>
|
||||
<field name="priority">2</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Sales Orders" fonts="bold:needaction_pending==True" colors="grey:state=='cancel';blue:state in ('waiting_date','manual');red:state in ('invoice_except','shipping_except')">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<tree string="Sales Orders" fonts="bold:message_state==True" colors="grey:state=='cancel';blue:state in ('waiting_date','manual');red:state in ('invoice_except','shipping_except')">
|
||||
<field name="message_state" invisible="1"/>
|
||||
<field name="name"/>
|
||||
<field name="date_order"/>
|
||||
<field name="partner_id"/>
|
||||
@@ -362,7 +362,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Sales Order">
|
||||
<field name="name" string="Sales Order" filter_domain="['|',('name','ilike',self),('client_order_ref','ilike',self)]"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
|
||||
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_state" domain="[('message_state','=',True)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-document-new" string="Quotations" name="draft" domain="[('state','in',('draft','sent'))]" help="Sales Order that haven't yet been confirmed"/>
|
||||
<filter icon="terp-check" string="Sales" name="sales" domain="[('state','in',('manual','progress'))]"/>
|
||||
|
||||
Reference in New Issue
Block a user