[IMP] removed needaction_pending, some cleaning in messages mail

bzr revid: fp@openerp.com-20120815133643-loyzmyp6azs5lr47
This commit is contained in:
Fabien Pinckaers
2012-08-15 15:36:43 +02:00
parent 8b61ed737c
commit eb0669850d
16 changed files with 246 additions and 350 deletions
+12 -13
View File
@@ -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>
+8 -8
View File
@@ -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 &lt; current_date)">
<tree string="Opportunities" fonts="bold:message_state==True" colors="gray:state in ('cancel', 'done');red:date_deadline and (date_deadline &lt; 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')]"/>
+2 -6
View File
@@ -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/>
+6 -6
View File
@@ -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&gt;register_current) or (register_max and register_max&lt;register_current);grey:state=='cancel'">
<tree string="Events" fonts="bold:message_state==True" colors="red:(register_min and register_min&gt;register_current) or (register_max and register_max&lt;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"/>
+3 -7
View File
@@ -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
View File
@@ -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',
+40
View File
@@ -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
View File
@@ -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:
+1 -2
View File
@@ -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 "\
+2 -2
View File
@@ -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&lt;current_date and state not in ('done','cancel');black:date_planned&gt;=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&lt;current_date and state not in ('done','cancel');black:date_planned&gt;=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"/>
+7 -7
View File
@@ -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&lt;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&lt;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&lt;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&lt;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"/>
+5 -5
View File
@@ -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"/>
+3 -3
View File
@@ -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&lt;current_date;black:date_end&gt;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&lt;current_date;black:date_end&gt;current_date;" string="Purchase Requisition">
<field name="message_state" invisible="1"/>
<field name="name"/>
<field name="date_start"/>
<field name="user_id"/>
+3 -3
View File
@@ -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'))]"/>